mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-17 00:14:56 +00:00
fix(editing): delete last line of a file without a trailing newline
delete_lines/replace_lines address the position one line past the last line (line == number of lines, col 0). get_index_from_line_col cannot resolve that position when the file has no trailing newline (no closing newline to count), so delete_text_between_positions raised InvalidTextLocationError and the delete crashed on a very common file shape. Clamp that past-EOF end position to end-of-file in delete_text_between_positions, mirroring the guard insert_text_at_position already has. A file with no trailing newline now deletes its last line identically to one with a trailing newline. Adds TextUtils unit tests and a CHANGELOG entry.
This commit is contained in:
1 parent
755de59f16
commit
cb38f6f82a
3 files changed
+48
-2
No files matched your search
@@ -1,4 +1,6 @@
|
||||
from solidlsp.ls_utils import TextUtils
|
||||
import pytest
|
||||
|
||||
from solidlsp.ls_utils import InvalidTextLocationError, TextUtils
|
||||
|
||||
|
||||
class TestTextUtils:
|
||||
@@ -48,3 +50,29 @@ class TestTextUtils:
|
||||
new_text, l, c = TextUtils.insert_text_at_position(self.TEXT, 4, 0, insertion)
|
||||
assert (l, c) == (4, len(insertion))
|
||||
assert new_text == self.TEXT + "\n" + insertion
|
||||
|
||||
def test_delete_text_deletes_last_line_without_trailing_newline(self) -> None:
|
||||
"""Deleting the final line must work whether or not the file ends in a newline.
|
||||
|
||||
delete_lines(k, N-1) addresses the position one line past the last line
|
||||
(line N, col 0). With no trailing newline there is no closing newline to
|
||||
count, so get_index_from_line_col cannot resolve it; the delete must still
|
||||
remove the last line instead of raising InvalidTextLocationError.
|
||||
"""
|
||||
# File with 3 lines, no trailing newline: read_file (splitlines) shows 0='a',1='b',2='c'.
|
||||
text = "a\nb\nc"
|
||||
new_text, deleted = TextUtils.delete_text_between_positions(text, 2, 0, 3, 0)
|
||||
assert new_text == "a\nb\n"
|
||||
assert deleted == "c"
|
||||
|
||||
def test_delete_text_last_line_matches_trailing_newline_variant(self) -> None:
|
||||
"""Deleting the last line yields the same result with or without a trailing newline."""
|
||||
without_nl, _ = TextUtils.delete_text_between_positions("a\nb\nc", 2, 0, 3, 0)
|
||||
with_nl, _ = TextUtils.delete_text_between_positions("a\nb\nc\n", 2, 0, 3, 0)
|
||||
assert without_nl == with_nl == "a\nb\n"
|
||||
|
||||
def test_delete_text_still_raises_for_out_of_range_end(self) -> None:
|
||||
"""A genuinely out-of-range end position (beyond one-past-EOF) still raises."""
|
||||
with pytest.raises(InvalidTextLocationError):
|
||||
# end_line = 5 is well past the one-line-past-EOF position (3) for a 3-line file.
|
||||
TextUtils.delete_text_between_positions("a\nb\nc", 0, 0, 5, 0)
|
||||
Reference in new issue
Block a user