Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/textual/widgets/_text_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -907,11 +907,10 @@ def _watch_read_only(self, read_only: bool) -> None:
self.set_class(read_only, "-read-only")
self._set_theme(self._theme.name)

def _recompute_cursor_offset(self):
def _recompute_cursor_offset(self) -> None:
"""Recompute the (x, y) coordinate of the cursor in the wrapped document."""
self._cursor_offset = self.wrapped_document.location_to_offset(
self.cursor_location
)
cursor_location = self.clamp_visitable(self.cursor_location)
self._cursor_offset = self.wrapped_document.location_to_offset(cursor_location)

def find_matching_bracket(
self, bracket: str, search_from: Location
Expand Down
23 changes: 23 additions & 0 deletions tests/text_area/test_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,29 @@ async def test_paste_is_an_isolated_batch():
assert text_area.text == ""


async def test_undo_multiline_paste_with_stale_cursor_location():
class MultilinePasteApp(App[None]):
CSS = "TextArea { height: 8; }"

def compose(self) -> ComposeResult:
yield TextArea("line0\nline1\n")

def on_mount(self) -> None:
self.copy_to_clipboard("\n".join(f"line{i}" for i in range(2, 50)))
self.query_one(TextArea).focus()

app = MultilinePasteApp()
async with app.run_test(size=(120, 40)) as pilot:
text_area = app.query_one(TextArea)

await pilot.press("ctrl+v")
assert text_area.cursor_location == (47, 6)

await pilot.press("ctrl+z")
assert text_area.text == "line0\nline1\n"
assert text_area.selection == Selection.cursor((0, 0))


async def test_focus_creates_checkpoint():
app = TextAreaApp()
async with app.run_test() as pilot:
Expand Down