Repository: Textualize/textual

Issue:
Pasting in Input with an empty string crashes the program
Pressing middle mouse button to paste causes this error in `Input._on_paste` if the clipboard is empty of text:

```
╭───────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────────────────╮
│ /home/io/Projects/textual-paint/.venv/lib/python3.10/site-packages/textual/widgets/_input.py:335 in _on_paste                                                                       │
│                                                                                                                                                                                     │
│   332 │   │   │   event.prevent_default()                                                                                                                                           │
│   333 │                                                                                                                                                                             │
│   334 │   def _on_paste(self, event: events.Paste) -> None:                                                                                                                         │
│ ❱ 335 │   │   line = event.text.splitlines()[0]                                                                                                                                     │
│   336 │   │   self.insert_text_at_cursor(line)                                                                                                                                      │
│   337 │   │   event.stop()                                                                                                                                                          │
│   338                                                                                                                                                                               │
│                                                                                                                                                                                     │
│ ╭──────────────────────────────────────────────────────────── locals ────────────────────────────────────────────────────────────╮                                                  │
│ │ event = Paste(text='')                                                                                                         │                                                  │
│ │  self = CharInput(id='selected_color_char_input', classes={'color_well'}, pseudo_classes={'focus', 'focus-within', 'enabled'}) │                                                  │
│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯                                                  │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
IndexError: list index out of range
```

To reproduce, use `printf "" | xsel` before pasting with MMB.

# Textual Diagnostics

## Versions

| Name    | Value  |
|---------|--------|
| Textual | 0.22.3 |
| Rich    | 13.3.5 |

## Python

| Name           | Value                                            |
|----------------|--------------------------------------------------|
| Version        | 3.10.6                                           |
| Implementation | CPython                                          |
| Compiler       | GCC 11.3.0                                       |
| Executable     | /home/io/Projects/textual-paint/.venv/bin/python |

## Operating System

| Name    | Value                                                            |
|---------|------------------------------------------------------------------|
| System  | Linux                                                            |
| Release | 5.19.0-41-generic                                                |
| Version | #42~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 18 17:40:00 UTC 2 |

## Terminal

| Name                 | Value           |
|----------------------|-----------------|
| Terminal Application | vscode (1.77.3) |
| TERM                 | xterm-256color  |
| COLORTERM            | truecolor       |
| FORCE_COLOR          | *Not set*       |
| NO_COLOR             | *Not set*       |

## Rich Console options

| Name           | Value                |
|----------------|----------------------|
| size           | width=183, height=32 |
| legacy_windows | False                |
| min_width      | 1                    |
| max_width      | 183                  |
| is_terminal    | True                 |
| encoding       | utf-8                |
| max_height     | 32                   |
| justify        | None                 |
| overflow       | None                 |
| no_wrap        | False                |
| highlight      | None                 |
| markup         | None                 |
| height         | None                 |




Comments:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e7cdebf4..5991f818d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 - Fixed `TreeNode.collapse` and `TreeNode.collapse_all` not posting a `Tree.NodeCollapsed` message https://github.com/Textualize/textual/issues/2535
 - Fixed `TreeNode.toggle` and `TreeNode.toggle_all` not posting a `Tree.NodeExpanded` or `Tree.NodeCollapsed` message https://github.com/Textualize/textual/issues/2535
 - `footer--description` component class was being ignored https://github.com/Textualize/textual/issues/2544
+- Pasting empty selection in `Input` would raise an exception https://github.com/Textualize/textual/issues/2563
 
 ### Added
 
diff --git a/src/textual/widgets/_input.py b/src/textual/widgets/_input.py
index 9e5bf2d07..e14dcdf10 100644
--- a/src/textual/widgets/_input.py
+++ b/src/textual/widgets/_input.py
@@ -332,8 +332,9 @@ class Input(Widget, can_focus=True):
             event.prevent_default()
 
     def _on_paste(self, event: events.Paste) -> None:
-        line = event.text.splitlines()[0]
-        self.insert_text_at_cursor(line)
+        if event.text:
+            line = event.text.splitlines()[0]
+            self.insert_text_at_cursor(line)
         event.stop()
 
     async def _on_click(self, event: events.Click) -> None:


Test patch:
diff --git a/tests/test_paste.py b/tests/test_paste.py
index 774ad5038..45be6d536 100644
--- a/tests/test_paste.py
+++ b/tests/test_paste.py
@@ -1,5 +1,6 @@
 from textual import events
 from textual.app import App
+from textual.widgets import Input
 
 
 async def test_paste_app():
@@ -16,3 +17,28 @@ async def test_paste_app():
 
     assert len(paste_events) == 1
     assert paste_events[0].text == "Hello"
+
+
+async def test_empty_paste():
+    """Regression test for https://github.com/Textualize/textual/issues/2563."""
+
+    paste_events = []
+
+    class MyInput(Input):
+        def on_paste(self, event):
+            super()._on_paste(event)
+            paste_events.append(event)
+
+    class PasteApp(App):
+        def compose(self):
+            yield MyInput()
+
+        def key_p(self):
+            self.query_one(MyInput).post_message(events.Paste(""))
+
+    app = PasteApp()
+    async with app.run_test() as pilot:
+        await pilot.press("p")
+        assert app.query_one(MyInput).value == ""
+        assert len(paste_events) == 1
+        assert paste_events[0].text == ""