Skip to content

Commit 42005ae

Browse files
authored
Merge pull request #28 from ccordoba12/fix-eols
Correctly format files and ranges with line endings other than LF
2 parents 26cfadf + 30571e3 commit 42005ae

File tree

6 files changed

+64
-5
lines changed

6 files changed

+64
-5
lines changed

.github/workflows/python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: [3.6, 3.7, 3.8, 3.9, "3.10"]
14+
python-version: [3.7, 3.8, 3.9, "3.10"]
1515
steps:
1616
- uses: actions/checkout@v2
1717
- name: Set up Python ${{ matrix.python-version }}

pylsp_black/plugin.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import black
77
import toml
88
from pylsp import hookimpl
9+
from pylsp._utils import get_eol_chars
910

1011
logger = logging.getLogger(__name__)
1112

13+
1214
GLOBAL_CONFIG: Optional[Path] = None
1315
try:
1416
if os.name == "nt":
@@ -68,8 +70,25 @@ def format_text(*, text, config):
6870
string_normalization=not config["skip_string_normalization"],
6971
)
7072
try:
71-
# will raise black.NothingChanged, we want to bubble that exception up
72-
return black.format_file_contents(text, fast=config["fast"], mode=mode)
73+
# Black's format_file_contents only works reliably when eols are '\n'. It gives
74+
# an error for '\r' and produces wrong formatting for '\r\n'. So we replace
75+
# those eols by '\n' before formatting and restore them afterwards.
76+
replace_eols = False
77+
eol_chars = get_eol_chars(text)
78+
if eol_chars is not None and eol_chars != "\n":
79+
replace_eols = True
80+
text = text.replace(eol_chars, "\n")
81+
82+
# Will raise black.NothingChanged, we want to bubble that exception up
83+
formatted_text = black.format_file_contents(
84+
text, fast=config["fast"], mode=mode
85+
)
86+
87+
# Restore eols if necessary.
88+
if replace_eols:
89+
formatted_text = formatted_text.replace("\n", eol_chars)
90+
91+
return formatted_text
7392
except (
7493
# raised when the file has syntax errors
7594
ValueError,

setup.cfg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ classifiers =
1818

1919
[options]
2020
packages = find:
21-
install_requires = python-lsp-server; black>=19.3b0; toml
22-
python_requires = >= 3.6
21+
install_requires = python-lsp-server>=1.4.0; black>=19.3b0; toml
22+
python_requires = >= 3.7
2323

2424
[options.entry_points]
2525
pylsp = pylsp_black = pylsp_black.plugin

tests/fixtures/formatted-crlf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
if True:
2+
print("foo")
3+
4+
print("bar") # noqa

tests/fixtures/unformatted-crlf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
if True:
2+
print("foo")
3+
4+
print("bar") # noqa

tests/test_plugin.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ def unformatted_pyi_document(workspace):
3939
return Document(uri, workspace)
4040

4141

42+
@pytest.fixture
43+
def unformatted_crlf_document(workspace):
44+
path = fixtures_dir / "unformatted-crlf.py"
45+
uri = f"file:/{path}"
46+
with open(path, "r", newline="") as f:
47+
source = f.read()
48+
return Document(uri, workspace, source=source)
49+
50+
4251
@pytest.fixture
4352
def formatted_document(workspace):
4453
path = fixtures_dir / "formatted.txt"
@@ -53,6 +62,15 @@ def formatted_pyi_document(workspace):
5362
return Document(uri, workspace)
5463

5564

65+
@pytest.fixture
66+
def formatted_crlf_document(workspace):
67+
path = fixtures_dir / "formatted-crlf.py"
68+
uri = f"file:/{path}"
69+
with open(path, "r", newline="") as f:
70+
source = f.read()
71+
return Document(uri, workspace, source=source)
72+
73+
5674
@pytest.fixture
5775
def invalid_document(workspace):
5876
path = fixtures_dir / "invalid.txt"
@@ -225,3 +243,17 @@ def test_entry_point():
225243

226244
module = entry_point.load()
227245
assert isinstance(module, types.ModuleType)
246+
247+
248+
def test_pylsp_format_crlf_document(unformatted_crlf_document, formatted_crlf_document):
249+
result = pylsp_format_document(unformatted_crlf_document)
250+
251+
assert result == [
252+
{
253+
"range": {
254+
"start": {"line": 0, "character": 0},
255+
"end": {"line": 4, "character": 0},
256+
},
257+
"newText": formatted_crlf_document.source,
258+
}
259+
]

0 commit comments

Comments
 (0)