Skip to content

Commit e57e9c7

Browse files
committed
Fix rename replacement ranges for files without a final newline
1 parent a362006 commit e57e9c7

2 files changed

Lines changed: 36 additions & 10 deletions

File tree

‎pylsp/plugins/jedi_rename.py‎

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,15 @@ def pylsp_rename(config, workspace, document, position, new_name):
2929
for file_path, changed_file in changed_files.items():
3030
uri = uris.from_fs_path(str(file_path))
3131
doc = workspace.get_maybe_document(uri)
32+
source = workspace.get_document(uri).source
3233
changes.append(
3334
{
3435
"textDocument": {"uri": uri, "version": doc.version if doc else None},
3536
"edits": [
3637
{
3738
"range": {
3839
"start": {"line": 0, "character": 0},
39-
"end": {
40-
"line": _num_lines(changed_file.get_new_code()),
41-
"character": 0,
42-
},
40+
"end": _end_position(source),
4341
},
4442
"newText": changed_file.get_new_code(),
4543
}
@@ -49,8 +47,9 @@ def pylsp_rename(config, workspace, document, position, new_name):
4947
return {"documentChanges": changes}
5048

5149

52-
def _num_lines(file_contents):
53-
"Count the number of lines in the given string."
54-
if _utils.get_eol_chars(file_contents):
55-
return len(file_contents.splitlines())
56-
return 0
50+
def _end_position(file_contents):
51+
lines = file_contents.replace("\r\n", "\n").replace("\r", "\n").split("\n")
52+
return {
53+
"line": len(lines) - 1,
54+
"character": len(lines[-1].encode("utf-16-le")) // 2,
55+
}

‎test/plugins/test_jedi_rename.py‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from pylsp import uris
99
from pylsp.plugins.jedi_rename import pylsp_rename
10+
from pylsp.text_edit import apply_text_edits
1011
from pylsp.workspace import Document
1112

1213
DOC_NAME = "test1.py"
@@ -33,6 +34,32 @@ def tmp_workspace(temp_workspace_factory):
3334
)
3435

3536

37+
@pytest.mark.parametrize(
38+
("source", "end"),
39+
[
40+
("foo = 12", {"line": 0, "character": 8}),
41+
("foo = 12\nfoo", {"line": 1, "character": 3}),
42+
("foo = 12\r\nfoo", {"line": 1, "character": 3}),
43+
("foo = 12\n", {"line": 1, "character": 0}),
44+
('foo = "\U0001f600\u2028"', {"line": 0, "character": 11}),
45+
],
46+
)
47+
def test_jedi_rename_replaces_entire_document(
48+
temp_workspace_factory, config, source, end
49+
):
50+
workspace = temp_workspace_factory({"rename.py": source})
51+
uri = uris.from_fs_path(os.path.join(workspace.root_path, "rename.py"))
52+
doc = workspace.get_document(uri)
53+
54+
result = pylsp_rename(
55+
config, workspace, doc, {"line": 0, "character": 0}, "renamed"
56+
)
57+
58+
edits = result["documentChanges"][0]["edits"]
59+
assert apply_text_edits(doc, edits) == source.replace("foo", "renamed")
60+
assert edits[0]["range"]["end"] == end
61+
62+
3663
def test_jedi_rename(tmp_workspace, config) -> None:
3764
# rename the `Test1` class
3865
position = {"line": 0, "character": 6}
@@ -98,7 +125,7 @@ def test_jedi_rename(tmp_workspace, config) -> None:
98125
{
99126
"range": {
100127
"start": {"line": 0, "character": 0},
101-
"end": {"line": 0, "character": 0},
128+
"end": {"line": 0, "character": 8},
102129
},
103130
"newText": "bar = 12",
104131
}

0 commit comments

Comments
 (0)