Skip to content

Commit ecefb73

Browse files
authored
Fix renaming when file has no EOLs (#450)
1 parent 76ea9ae commit ecefb73

File tree

4 files changed

+68
-10
lines changed

4 files changed

+68
-10
lines changed

pylsp/plugins/jedi_rename.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,6 @@ def pylsp_rename(
5454

5555
def _num_lines(file_contents):
5656
"Count the number of lines in the given string."
57-
return len(file_contents.splitlines())
57+
if _utils.get_eol_chars(file_contents):
58+
return len(file_contents.splitlines())
59+
return 0

pylsp/plugins/rope_rename.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from rope.base import libutils
77
from rope.refactor.rename import Rename
88

9-
from pylsp import hookimpl, uris
9+
from pylsp import hookimpl, uris, _utils
1010

1111
log = logging.getLogger(__name__)
1212

@@ -59,4 +59,8 @@ def pylsp_rename(config, workspace, document, position, new_name):
5959

6060
def _num_lines(resource):
6161
"Count the number of lines in a `File` resource."
62-
return len(resource.read().splitlines())
62+
text = resource.read()
63+
64+
if _utils.get_eol_chars(text):
65+
return len(text.splitlines())
66+
return 0

test/plugins/test_jedi_rename.py

+32-6
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22
# Copyright 2021- Python Language Server Contributors.
33

44
import os
5-
import sys
65

76
import pytest
87
from pylsp import uris
98
from pylsp.plugins.jedi_rename import pylsp_rename
109
from pylsp.workspace import Document
1110

12-
LT_PY36 = sys.version_info.major < 3 or (
13-
sys.version_info.major == 3 and sys.version_info.minor < 6
14-
)
1511

1612
DOC_NAME = "test1.py"
1713
DOC = """class Test1():
@@ -26,13 +22,17 @@ class Test2(Test1):
2622
x = Test1()
2723
"""
2824

25+
DOC_NAME_SIMPLE = "test3.py"
26+
DOC_SIMPLE = "foo = 12"
27+
2928

3029
@pytest.fixture
3130
def tmp_workspace(temp_workspace_factory):
32-
return temp_workspace_factory({DOC_NAME: DOC, DOC_NAME_EXTRA: DOC_EXTRA})
31+
return temp_workspace_factory(
32+
{DOC_NAME: DOC, DOC_NAME_EXTRA: DOC_EXTRA, DOC_NAME_SIMPLE: DOC_SIMPLE}
33+
)
3334

3435

35-
@pytest.mark.skipif(LT_PY36, reason="Jedi refactoring isnt supported on Python 2.x/3.5")
3636
def test_jedi_rename(tmp_workspace, config): # pylint: disable=redefined-outer-name
3737
# rename the `Test1` class
3838
position = {"line": 0, "character": 6}
@@ -56,13 +56,15 @@ def test_jedi_rename(tmp_workspace, config): # pylint: disable=redefined-outer-
5656
"newText": "class ShouldBeRenamed():\n pass\n\nclass Test2(ShouldBeRenamed):\n pass\n",
5757
}
5858
]
59+
5960
path = os.path.join(tmp_workspace.root_path, DOC_NAME_EXTRA)
6061
uri_extra = uris.from_fs_path(path)
6162
assert changes[1]["textDocument"]["uri"] == uri_extra
6263
# This also checks whether documents not yet added via textDocument/didOpen
6364
# but that do need to be renamed in the project have a `null` version
6465
# number.
6566
assert changes[1]["textDocument"]["version"] is None
67+
6668
expected = "from test1 import ShouldBeRenamed\nx = ShouldBeRenamed()\n"
6769
if os.name == "nt":
6870
# The .write method in the temp_workspace_factory functions writes
@@ -77,3 +79,27 @@ def test_jedi_rename(tmp_workspace, config): # pylint: disable=redefined-outer-
7779
"newText": expected,
7880
}
7981
]
82+
83+
# Regression test for issue python-lsp/python-lsp-server#413
84+
# rename foo
85+
position = {"line": 0, "character": 0}
86+
DOC_URI = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC_NAME_SIMPLE))
87+
doc = Document(DOC_URI, tmp_workspace)
88+
89+
result = pylsp_rename(config, tmp_workspace, doc, position, "bar")
90+
assert len(result.keys()) == 1
91+
92+
changes = result.get("documentChanges")
93+
assert len(changes) == 1
94+
95+
assert changes[0]["textDocument"]["uri"] == doc.uri
96+
assert changes[0]["textDocument"]["version"] == doc.version
97+
assert changes[0].get("edits") == [
98+
{
99+
"range": {
100+
"start": {"line": 0, "character": 0},
101+
"end": {"line": 0, "character": 0},
102+
},
103+
"newText": "bar = 12",
104+
}
105+
]

test/plugins/test_rope_rename.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from pylsp.plugins.rope_rename import pylsp_rename
99
from pylsp.workspace import Document
1010

11+
1112
DOC_NAME = "test1.py"
1213
DOC = """class Test1():
1314
pass
@@ -16,10 +17,13 @@ class Test2(Test1):
1617
pass
1718
"""
1819

20+
DOC_NAME_SIMPLE = "test2.py"
21+
DOC_SIMPLE = "foo = 12"
22+
1923

2024
@pytest.fixture
2125
def tmp_workspace(temp_workspace_factory):
22-
return temp_workspace_factory({DOC_NAME: DOC})
26+
return temp_workspace_factory({DOC_NAME: DOC, DOC_NAME_SIMPLE: DOC_SIMPLE})
2327

2428

2529
def test_rope_rename(tmp_workspace, config): # pylint: disable=redefined-outer-name
@@ -45,3 +49,25 @@ def test_rope_rename(tmp_workspace, config): # pylint: disable=redefined-outer-
4549
"newText": "class ShouldBeRenamed():\n pass\n\nclass Test2(ShouldBeRenamed):\n pass\n",
4650
}
4751
]
52+
53+
# Regression test for issue python-lsp/python-lsp-server#413
54+
# rename foo
55+
position = {"line": 0, "character": 0}
56+
DOC_URI = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC_NAME_SIMPLE))
57+
doc = Document(DOC_URI, tmp_workspace)
58+
59+
result = pylsp_rename(config, tmp_workspace, doc, position, "bar")
60+
assert len(result.keys()) == 1
61+
62+
changes = result.get("documentChanges")
63+
assert len(changes) == 1
64+
65+
assert changes[0].get("edits") == [
66+
{
67+
"range": {
68+
"start": {"line": 0, "character": 0},
69+
"end": {"line": 0, "character": 0},
70+
},
71+
"newText": "bar = 12",
72+
}
73+
]

0 commit comments

Comments
 (0)