diff --git a/src/textual/document/_edit.py b/src/textual/document/_edit.py index d0bd5ad83d..dc9c04aeba 100644 --- a/src/textual/document/_edit.py +++ b/src/textual/document/_edit.py @@ -81,8 +81,16 @@ def do(self, text_area: TextArea, record_selection: bool = True) -> EditResult: ) row_offset = new_edit_to_row - edit_bottom_row - target_selection_start_row = selection_start_row + row_offset - target_selection_end_row = selection_end_row + row_offset + target_selection_start_row = ( + selection_start_row + row_offset + if edit_bottom_row <= selection_start_row + else selection_start_row + ) + target_selection_end_row = ( + selection_end_row + row_offset + if edit_bottom_row <= selection_end_row + else selection_end_row + ) if self.maintain_selection_offset: self._updated_selection = Selection( diff --git a/tests/text_area/test_edit_via_api.py b/tests/text_area/test_edit_via_api.py index e217bfa210..e732680f0f 100644 --- a/tests/text_area/test_edit_via_api.py +++ b/tests/text_area/test_edit_via_api.py @@ -106,6 +106,27 @@ async def test_insert_character_near_cursor_maintain_selection_offset( assert text_area.selection == Selection.cursor(cursor_destination) +@pytest.mark.parametrize( + "cursor_location,insert_location,cursor_destination", + [ + ((1, 0), (0, 0), (2, 0)), # API insert before cursor row + ((0, 0), (0, 0), (1, 0)), # API insert right at cursor row + ((0, 0), (1, 0), (0, 0)), # API insert after cursor row + ], +) +async def test_insert_newline_around_cursor_maintain_selection_offset( + cursor_location, + insert_location, + cursor_destination +): + app = TextAreaApp() + async with app.run_test(): + text_area = app.query_one(TextArea) + text_area.move_cursor(cursor_location) + text_area.insert("X\n", location=insert_location) + assert text_area.selection == Selection.cursor(cursor_destination) + + async def test_insert_newlines_start(): app = TextAreaApp() async with app.run_test():