Merge pull request #6148 from Textualize/fix-copy-focus

skip copy in input/textarea if there is nothing to copy
This commit is contained in:
Will McGugan
2025-10-01 17:10:53 +01:00
committed by GitHub
7 changed files with 41 additions and 5 deletions

View File

@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [6.2.1] - 2025-10-01
- Fix inability to copy text outside of an input/textarea when it was focused https://github.com/Textualize/textual/pull/6148
- Fix issue when copying text after a double click https://github.com/Textualize/textual/pull/6148
## [6.2.0] - 2025-09-30
### Changed
@@ -3129,6 +3134,7 @@ https://textual.textualize.io/blog/2022/11/08/version-040/#version-040
- New handler system for messages that doesn't require inheritance
- Improved traceback handling
[6.2.1]: https://github.com/Textualize/textual/compare/v6.2.0...v6.2.1
[6.2.0]: https://github.com/Textualize/textual/compare/v6.1.0...v6.2.0
[6.1.0]: https://github.com/Textualize/textual/compare/v6.0.0...v6.1.0
[6.0.0]: https://github.com/Textualize/textual/compare/v5.3.0...v6.0.0

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "textual"
version = "6.2.0"
version = "6.2.1"
homepage = "https://github.com/Textualize/textual"
repository = "https://github.com/Textualize/textual"
documentation = "https://textual.textualize.io/"

View File

@@ -924,7 +924,7 @@ class Screen(Generic[ScreenResultType], Widget):
if selected_text_in_widget is not None:
widget_text.extend(selected_text_in_widget)
selected_text = "".join(widget_text)
selected_text = "".join(widget_text).rstrip("\n")
return selected_text
def action_copy_text(self) -> None:

View File

@@ -46,8 +46,8 @@ class Selection(NamedTuple):
start_line, start_offset = self.start.transpose
if self.end is None:
end_line = len(lines) - 1
end_offset = len(lines[end_line])
end_line = len(lines)
end_offset = len(lines[-1])
else:
end_line, end_offset = self.end.transpose
end_line = min(len(lines), end_line)

View File

@@ -11,6 +11,7 @@ from rich.text import Text
from typing_extensions import Literal
from textual import events
from textual.actions import SkipAction
from textual.expand_tabs import expand_tabs_inline
from textual.screen import Screen
from textual.scroll_view import ScrollView
@@ -1106,7 +1107,11 @@ class Input(ScrollView):
def action_copy(self) -> None:
"""Copy the current selection to the clipboard."""
self.app.copy_to_clipboard(self.selected_text)
selected_text = self.selected_text
if selected_text:
self.app.copy_to_clipboard(selected_text)
else:
raise SkipAction()
def action_paste(self) -> None:
"""Paste from the local clipboard."""

View File

@@ -16,6 +16,7 @@ from typing_extensions import Literal
from textual._text_area_theme import TextAreaTheme
from textual._tree_sitter import TREE_SITTER, get_language
from textual.actions import SkipAction
from textual.cache import LRUCache
from textual.color import Color
from textual.content import Content
@@ -2513,6 +2514,8 @@ TextArea {
selected_text = self.selected_text
if selected_text:
self.app.copy_to_clipboard(selected_text)
else:
raise SkipAction()
def action_paste(self) -> None:
"""Paste from local clipboard."""

22
tests/test_selection.py Normal file
View File

@@ -0,0 +1,22 @@
import pytest
from textual.geometry import Offset
from textual.selection import Selection
@pytest.mark.parametrize(
"text,selection,expected",
[
("Hello", Selection(None, None), "Hello"),
("Hello\nWorld", Selection(None, None), "Hello\nWorld"),
("Hello\nWorld", Selection(Offset(0, 1), None), "World"),
("Hello\nWorld", Selection(None, Offset(5, 0)), "Hello"),
("Foo", Selection(Offset(0, 0), Offset(1, 0)), "F"),
("Foo", Selection(Offset(1, 0), Offset(2, 0)), "o"),
("Foo", Selection(Offset(0, 0), Offset(2, 0)), "Fo"),
("Foo", Selection(Offset(0, 0), None), "Foo"),
],
)
def test_extract(text: str, selection: Selection, expected: str) -> None:
"""Test Selection.extract"""
assert selection.extract(text) == expected