Skip to content

Commit a77700c

Browse files
authored
Merge pull request #6148 from Textualize/fix-copy-focus
skip copy in input/textarea if there is nothing to copy
2 parents c0e7fe3 + 08c88fc commit a77700c

File tree

7 files changed

+41
-5
lines changed

7 files changed

+41
-5
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [6.2.1] - 2025-10-01
9+
10+
- Fix inability to copy text outside of an input/textarea when it was focused https://github.com/Textualize/textual/pull/6148
11+
- Fix issue when copying text after a double click https://github.com/Textualize/textual/pull/6148
12+
813
## [6.2.0] - 2025-09-30
914

1015
### Changed
@@ -3129,6 +3134,7 @@ https://textual.textualize.io/blog/2022/11/08/version-040/#version-040
31293134
- New handler system for messages that doesn't require inheritance
31303135
- Improved traceback handling
31313136

3137+
[6.2.1]: https://github.com/Textualize/textual/compare/v6.2.0...v6.2.1
31323138
[6.2.0]: https://github.com/Textualize/textual/compare/v6.1.0...v6.2.0
31333139
[6.1.0]: https://github.com/Textualize/textual/compare/v6.0.0...v6.1.0
31343140
[6.0.0]: https://github.com/Textualize/textual/compare/v5.3.0...v6.0.0

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "textual"
3-
version = "6.2.0"
3+
version = "6.2.1"
44
homepage = "https://github.com/Textualize/textual"
55
repository = "https://github.com/Textualize/textual"
66
documentation = "https://textual.textualize.io/"

src/textual/screen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ def get_selected_text(self) -> str | None:
924924
if selected_text_in_widget is not None:
925925
widget_text.extend(selected_text_in_widget)
926926

927-
selected_text = "".join(widget_text)
927+
selected_text = "".join(widget_text).rstrip("\n")
928928
return selected_text
929929

930930
def action_copy_text(self) -> None:

src/textual/selection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ def extract(self, text: str) -> str:
4646
start_line, start_offset = self.start.transpose
4747

4848
if self.end is None:
49-
end_line = len(lines) - 1
50-
end_offset = len(lines[end_line])
49+
end_line = len(lines)
50+
end_offset = len(lines[-1])
5151
else:
5252
end_line, end_offset = self.end.transpose
5353
end_line = min(len(lines), end_line)

src/textual/widgets/_input.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from typing_extensions import Literal
1212

1313
from textual import events
14+
from textual.actions import SkipAction
1415
from textual.expand_tabs import expand_tabs_inline
1516
from textual.screen import Screen
1617
from textual.scroll_view import ScrollView
@@ -1106,7 +1107,11 @@ def action_cut(self) -> None:
11061107

11071108
def action_copy(self) -> None:
11081109
"""Copy the current selection to the clipboard."""
1109-
self.app.copy_to_clipboard(self.selected_text)
1110+
selected_text = self.selected_text
1111+
if selected_text:
1112+
self.app.copy_to_clipboard(selected_text)
1113+
else:
1114+
raise SkipAction()
11101115

11111116
def action_paste(self) -> None:
11121117
"""Paste from the local clipboard."""

src/textual/widgets/_text_area.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from textual._text_area_theme import TextAreaTheme
1818
from textual._tree_sitter import TREE_SITTER, get_language
19+
from textual.actions import SkipAction
1920
from textual.cache import LRUCache
2021
from textual.color import Color
2122
from textual.content import Content
@@ -2513,6 +2514,8 @@ def action_copy(self) -> None:
25132514
selected_text = self.selected_text
25142515
if selected_text:
25152516
self.app.copy_to_clipboard(selected_text)
2517+
else:
2518+
raise SkipAction()
25162519

25172520
def action_paste(self) -> None:
25182521
"""Paste from local clipboard."""

tests/test_selection.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
3+
from textual.geometry import Offset
4+
from textual.selection import Selection
5+
6+
7+
@pytest.mark.parametrize(
8+
"text,selection,expected",
9+
[
10+
("Hello", Selection(None, None), "Hello"),
11+
("Hello\nWorld", Selection(None, None), "Hello\nWorld"),
12+
("Hello\nWorld", Selection(Offset(0, 1), None), "World"),
13+
("Hello\nWorld", Selection(None, Offset(5, 0)), "Hello"),
14+
("Foo", Selection(Offset(0, 0), Offset(1, 0)), "F"),
15+
("Foo", Selection(Offset(1, 0), Offset(2, 0)), "o"),
16+
("Foo", Selection(Offset(0, 0), Offset(2, 0)), "Fo"),
17+
("Foo", Selection(Offset(0, 0), None), "Foo"),
18+
],
19+
)
20+
def test_extract(text: str, selection: Selection, expected: str) -> None:
21+
"""Test Selection.extract"""
22+
assert selection.extract(text) == expected

0 commit comments

Comments
 (0)