diff --git a/bundled/tool/lsp_edit_utils.py b/bundled/tool/lsp_edit_utils.py index be635d1..483313d 100644 --- a/bundled/tool/lsp_edit_utils.py +++ b/bundled/tool/lsp_edit_utils.py @@ -8,6 +8,7 @@ from typing import List, Optional from lsprotocol import types as lsp +from pygls.workspace.position_codec import PositionCodec DIFF_TIMEOUT = 1 # 1 second @@ -29,28 +30,16 @@ def get_text_edits( ) -> List[lsp.TextEdit]: """Return a list of text edits to transform old_text into new_text.""" - def code_units(c: str) -> int: - if position_encoding == lsp.PositionEncodingKind.Utf16: - return len(c.encode("utf-16-le")) // 2 - elif position_encoding == lsp.PositionEncodingKind.Utf8: - return len(c.encode("utf-8")) - return len(c.encode("utf-32-le")) // 4 + lines = old_text.splitlines(True) + codec = PositionCodec(position_encoding) line_offsets = [0] - code_unit_offsets = [] - - for line in old_text.splitlines(True): - col_offset = [0] - for c in line: - col_offset.append(col_offset[-1] + code_units(c)) - code_unit_offsets.append(col_offset) + for line in lines: line_offsets.append(line_offsets[-1] + len(line)) - code_unit_offsets.append([0]) def from_offset(offset: int) -> lsp.Position: line = bisect.bisect_right(line_offsets, offset) - 1 - col = offset - line_offsets[line] - character = code_unit_offsets[line][col] + character = offset - line_offsets[line] return lsp.Position(line=line, character=character) sequences = [] @@ -64,7 +53,13 @@ def from_offset(offset: int) -> lsp.Position: if sequences: edits = [ lsp.TextEdit( - range=lsp.Range(start=from_offset(old_start), end=from_offset(old_end)), + range=codec.range_to_client_units( + lines=lines, + range=lsp.Range( + start=from_offset(old_start), + end=from_offset(old_end), + ), + ), new_text=new_text[new_start:new_end], ) for opcode, old_start, old_end, new_start, new_end in sequences diff --git a/src/test/python_tests/test_edit_utils.py b/src/test/python_tests/test_edit_utils.py index f332708..db8ed1f 100644 --- a/src/test/python_tests/test_edit_utils.py +++ b/src/test/python_tests/test_edit_utils.py @@ -34,7 +34,7 @@ new_text='"', ), lsp.TextEdit( - range=lsp.Range(lsp.Position(0, 9), lsp.Position(0, 10)), + range=lsp.Range(lsp.Position(0, 8), lsp.Position(0, 9)), new_text='"', ), ], @@ -85,11 +85,11 @@ def test_with_emojis(encoding: lsp.PositionEncodingKind, expected: List[lsp.Text lsp.PositionEncodingKind.Utf8, [ lsp.TextEdit( - range=lsp.Range(lsp.Position(1, 179), lsp.Position(1, 179)), + range=lsp.Range(lsp.Position(1, 136), lsp.Position(1, 136)), new_text="\n ", ), lsp.TextEdit( - range=lsp.Range(lsp.Position(1, 354), lsp.Position(1, 354)), + range=lsp.Range(lsp.Position(1, 268), lsp.Position(1, 268)), new_text=",", ), ],