Skip to content
This repository was archived by the owner on Dec 16, 2025. It is now read-only.

Commit 3b59a36

Browse files
committed
Narrow text edits
1 parent f76c5bf commit 3b59a36

2 files changed

Lines changed: 40 additions & 5 deletions

File tree

ruff_lsp/server.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from pathlib import Path
1717
from typing import Any, List, NamedTuple, Sequence, Union, cast
1818

19-
from lsprotocol import validators
2019
from lsprotocol.types import (
2120
CODE_ACTION_RESOLVE,
2221
INITIALIZE,
@@ -1379,13 +1378,45 @@ def _fixed_source_to_edits(
13791378
if new_source == original_source:
13801379
return []
13811380

1381+
# Reduce the text edit by omitting the common suffix and postfix (lines)
1382+
# from the text edit. I chose this basic diffing because "proper" diffing has
1383+
# the downside that it can be very slow in some cases. Black uses a diffing approach
1384+
# that takes time into consideration, but it requires spawning a thread to stop
1385+
# the diffing after a given time, which feels very heavy weight.
1386+
# This basic "diffing" has a guaranteed `O(n)` runtime and is sufficient to
1387+
# prevent transmitting the entire source document when formatting a range
1388+
# or formatting a document where most of the code remains unchanged.
1389+
#
1390+
# https://github.com/microsoft/vscode-black-formatter/blob/main/bundled/tool/lsp_edit_utils.py
1391+
new_lines = new_source.splitlines(True)
1392+
original_lines = original_source.splitlines(True)
1393+
1394+
start_offset = 0
1395+
end_offset = 0
1396+
1397+
for new_line, original_line in zip(new_lines, original_lines):
1398+
if new_line == original_line:
1399+
start_offset += 1
1400+
else:
1401+
break
1402+
1403+
for new_line, original_line in zip(
1404+
reversed(new_lines[start_offset:]), reversed(original_lines[start_offset:])
1405+
):
1406+
if new_line == original_line:
1407+
end_offset += 1
1408+
else:
1409+
break
1410+
1411+
trimmed_new_source = "".join(new_lines[start_offset : len(new_lines) - end_offset])
1412+
13821413
return [
13831414
TextEdit(
13841415
range=Range(
1385-
start=Position(line=0, character=0),
1386-
end=Position(line=validators.UINTEGER_MAX_VALUE, character=0),
1416+
start=Position(line=start_offset, character=0),
1417+
end=Position(line=len(original_lines) - end_offset, character=0),
13871418
),
1388-
new_text=new_source,
1419+
new_text=trimmed_new_source,
13891420
)
13901421
]
13911422

tests/test_format.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from contextlib import nullcontext
44

55
import pytest
6+
from lsprotocol.types import Position, Range
67
from packaging.version import Version
78
from pygls.workspace import Workspace
89

@@ -46,7 +47,10 @@ async def test_format(tmp_path, ruff_version: Version):
4647
[edit] = _fixed_source_to_edits(
4748
original_source=document.source, fixed_source=result.stdout.decode("utf-8")
4849
)
49-
assert edit.new_text == expected
50+
assert edit.new_text == ""
51+
assert edit.range == Range(
52+
start=Position(line=0, character=0), end=Position(line=1, character=0)
53+
)
5054

5155

5256
@pytest.mark.asyncio

0 commit comments

Comments
 (0)