From 8929a7d44f17d801773fb667e9c772a94030cd79 Mon Sep 17 00:00:00 2001 From: Ross Bencina Date: Fri, 29 Sep 2023 18:41:21 +1000 Subject: [PATCH] refactor: rename server Position to PositionCodec, instantiate it in Workspace --- pygls/workspace/__init__.py | 56 ++++++++++--------- .../{position.py => position_codec.py} | 6 +- pygls/workspace/text_document.py | 24 ++++---- pygls/workspace/workspace.py | 12 +++- tests/test_document.py | 34 ++++++----- 5 files changed, 81 insertions(+), 51 deletions(-) rename pygls/workspace/{position.py => position_codec.py} (98%) diff --git a/pygls/workspace/__init__.py b/pygls/workspace/__init__.py index afa25901..a18f9d5d 100644 --- a/pygls/workspace/__init__.py +++ b/pygls/workspace/__init__.py @@ -5,11 +5,11 @@ from .workspace import Workspace from .text_document import TextDocument -from .position import Position +from .position_codec import PositionCodec Workspace = Workspace TextDocument = TextDocument -Position = Position +PositionCodec = PositionCodec # For backwards compatibility Document = TextDocument @@ -18,64 +18,70 @@ def utf16_unit_offset(chars: str): warnings.warn( "'utf16_unit_offset' has been deprecated, use " - "'Position.utf16_unit_offset' instead", + "'PositionCodec.utf16_unit_offset' via 'workspace.position_codec' " + "or 'text_document.position_codec' instead", DeprecationWarning, stacklevel=2, ) - _position = Position() - return _position.utf16_unit_offset(chars) + _codec = PositionCodec() + return _codec.utf16_unit_offset(chars) def utf16_num_units(chars: str): warnings.warn( - "'utf16_num_units' has been deprecated, use " - "'Position.client_num_units' instead", + "'utf16_num_units' has been deprecated, instead use " + "'PositionCodec.client_num_units' via 'workspace.position_codec' " + "or 'text_document.position_codec'", DeprecationWarning, stacklevel=2, ) - _position = Position() - return _position.client_num_units(chars) + _codec = PositionCodec() + return _codec.client_num_units(chars) def position_from_utf16(lines: List[str], position: types.Position): warnings.warn( - "'position_from_utf16' has been deprecated, use " - "'Position.position_from_client_units' instead", + "'position_from_utf16' has been deprecated, instead use " + "'PositionCodec.position_from_client_units' via " + "'workspace.position_codec' or 'text_document.position_codec'", DeprecationWarning, stacklevel=2, ) - _position = Position() - return _position.position_from_client_units(lines, position) + _codec = PositionCodec() + return _codec.position_from_client_units(lines, position) def position_to_utf16(lines: List[str], position: types.Position): warnings.warn( - "'position_to_utf16' has been deprecated, use " - "'Position.position_to_client_units' instead", + "'position_to_utf16' has been deprecated, instead use " + "'PositionCodec.position_to_client_units' via " + "'workspace.position_codec' or 'text_document.position_codec'", DeprecationWarning, stacklevel=2, ) - _position = Position() - return _position.position_to_client_units(lines, position) + _codec = PositionCodec() + return _codec.position_to_client_units(lines, position) def range_from_utf16(lines: List[str], range: types.Range): warnings.warn( - "'range_from_utf16' has been deprecated, use " - "'Position.range_from_client_units' instead", + "'range_from_utf16' has been deprecated, instead use " + "'PositionCodec.range_from_client_units' via " + "'workspace.position_codec' or 'text_document.position_codec'", DeprecationWarning, stacklevel=2, ) - _position = Position() - return _position.range_from_client_units(lines, range) + _codec = PositionCodec() + return _codec.range_from_client_units(lines, range) def range_to_utf16(lines: List[str], range: types.Range): warnings.warn( - "'range_to_utf16' has been deprecated, use " - "'Position.range_to_client_units' instead", + "'range_to_utf16' has been deprecated, instead use " + "'PositionCodec.range_to_client_units' via 'workspace.position_codec' " + "or 'text_document.position_codec'", DeprecationWarning, stacklevel=2, ) - _position = Position() - return _position.range_to_client_units(lines, range) + _codec = PositionCodec() + return _codec.range_to_client_units(lines, range) diff --git a/pygls/workspace/position.py b/pygls/workspace/position_codec.py similarity index 98% rename from pygls/workspace/position.py rename to pygls/workspace/position_codec.py index 0f4616d5..8189cfb9 100644 --- a/pygls/workspace/position.py +++ b/pygls/workspace/position_codec.py @@ -25,7 +25,7 @@ log = logging.getLogger(__name__) -class Position: +class PositionCodec: def __init__( self, encoding: Optional[ @@ -121,7 +121,9 @@ def position_from_client_units( break _current_char = _line[utf32_index] - _is_double_width = Position.is_char_beyond_multilingual_plane(_current_char) + _is_double_width = PositionCodec.is_char_beyond_multilingual_plane( + _current_char + ) if _is_double_width: if self.encoding == types.PositionEncodingKind.Utf32: _client_index += 1 diff --git a/pygls/workspace/text_document.py b/pygls/workspace/text_document.py index 27b300ab..d62c6aa9 100644 --- a/pygls/workspace/text_document.py +++ b/pygls/workspace/text_document.py @@ -20,12 +20,12 @@ import logging import os import re -from typing import List, Optional, Pattern, Union +from typing import List, Optional, Pattern from lsprotocol import types from pygls.uris import to_fs_path -from .position import Position +from .position_codec import PositionCodec # TODO: this is not the best e.g. we capture numbers RE_END_WORD = re.compile("^[A-Za-z_0-9]*") @@ -43,9 +43,7 @@ def __init__( language_id: Optional[str] = None, local: bool = True, sync_kind: types.TextDocumentSyncKind = types.TextDocumentSyncKind.Incremental, - position_encoding: Optional[ - Union[types.PositionEncodingKind, str] - ] = types.PositionEncodingKind.Utf16, + position_codec: Optional[PositionCodec] = None, ): self.uri = uri self.version = version @@ -65,11 +63,15 @@ def __init__( ) self._is_sync_kind_none = sync_kind == types.TextDocumentSyncKind.None_ - self.position = Position(encoding=position_encoding) + self._position_codec = position_codec if position_codec else PositionCodec() def __str__(self): return str(self.uri) + @property + def position_codec(self) -> PositionCodec: + return self._position_codec + def _apply_incremental_change( self, change: types.TextDocumentContentChangeEvent_Type1 ) -> None: @@ -78,7 +80,7 @@ def _apply_incremental_change( text = change.text change_range = change.range - range = self.position.range_from_client_units(lines, change_range) + range = self._position_codec.range_from_client_units(lines, change_range) start_line = range.start.line start_col = range.start.character end_line = range.end.line @@ -165,11 +167,13 @@ def lines(self) -> List[str]: def offset_at_position(self, client_position: types.Position) -> int: """Return the character offset pointed at by the given client_position.""" lines = self.lines - server_position = self.position.position_from_client_units( + server_position = self._position_codec.position_from_client_units( lines, client_position ) row, col = server_position.line, server_position.character - return col + sum(self.position.client_num_units(line) for line in lines[:row]) + return col + sum( + self._position_codec.client_num_units(line) for line in lines[:row] + ) @property def source(self) -> str: @@ -217,7 +221,7 @@ def word_at_position( if client_position.line >= len(lines): return "" - server_position = self.position.position_from_client_units( + server_position = self._position_codec.position_from_client_units( lines, client_position ) row, col = server_position.line, server_position.character diff --git a/pygls/workspace/workspace.py b/pygls/workspace/workspace.py index 1ae25283..746c1bab 100644 --- a/pygls/workspace/workspace.py +++ b/pygls/workspace/workspace.py @@ -30,6 +30,7 @@ ) from pygls.uris import to_fs_path, uri_scheme from pygls.workspace.text_document import TextDocument +from pygls.workspace.position_codec import PositionCodec logger = logging.getLogger(__name__) @@ -60,11 +61,20 @@ def __init__( self._folders: Dict[str, WorkspaceFolder] = {} self._docs: Dict[str, TextDocument] = {} self._position_encoding = position_encoding + self._position_codec = PositionCodec(encoding=position_encoding) if workspace_folders is not None: for folder in workspace_folders: self.add_folder(folder) + @property + def position_encoding(self) -> Optional[Union[PositionEncodingKind, str]]: + return self._position_encoding + + @property + def position_codec(self) -> PositionCodec: + return self._position_codec + def _create_text_document( self, doc_uri: str, @@ -78,7 +88,7 @@ def _create_text_document( version=version, language_id=language_id, sync_kind=self._sync_kind, - position_encoding=self._position_encoding, + position_codec=self._position_codec, ) def add_folder(self, folder: WorkspaceFolder): diff --git a/tests/test_document.py b/tests/test_document.py index 859f5084..e8ef56f2 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -19,7 +19,7 @@ import re from lsprotocol import types -from pygls.workspace import TextDocument, Position +from pygls.workspace import TextDocument, PositionCodec from .conftest import DOC, DOC_URI @@ -174,7 +174,7 @@ def test_document_source_unicode(): def test_position_from_utf16(): - position = Position(encoding=types.PositionEncodingKind.Utf16) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf16) assert position.position_from_client_units( ['x="😋"'], types.Position(line=0, character=3) ) == types.Position(line=0, character=3) @@ -184,7 +184,7 @@ def test_position_from_utf16(): def test_position_from_utf32(): - position = Position(encoding=types.PositionEncodingKind.Utf32) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf32) assert position.position_from_client_units( ['x="😋"'], types.Position(line=0, character=3) ) == types.Position(line=0, character=3) @@ -194,7 +194,7 @@ def test_position_from_utf32(): def test_position_from_utf8(): - position = Position(encoding=types.PositionEncodingKind.Utf8) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf8) assert position.position_from_client_units( ['x="😋"'], types.Position(line=0, character=3) ) == types.Position(line=0, character=3) @@ -204,7 +204,7 @@ def test_position_from_utf8(): def test_position_to_utf16(): - position = Position(encoding=types.PositionEncodingKind.Utf16) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf16) assert position.position_to_client_units( ['x="😋"'], types.Position(line=0, character=3) ) == types.Position(line=0, character=3) @@ -215,7 +215,7 @@ def test_position_to_utf16(): def test_position_to_utf32(): - position = Position(encoding=types.PositionEncodingKind.Utf32) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf32) assert position.position_to_client_units( ['x="😋"'], types.Position(line=0, character=3) ) == types.Position(line=0, character=3) @@ -226,7 +226,7 @@ def test_position_to_utf32(): def test_position_to_utf8(): - position = Position(encoding=types.PositionEncodingKind.Utf8) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf8) assert position.position_to_client_units( ['x="😋"'], types.Position(line=0, character=3) ) == types.Position(line=0, character=3) @@ -237,7 +237,7 @@ def test_position_to_utf8(): def test_range_from_utf16(): - position = Position(encoding=types.PositionEncodingKind.Utf16) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf16) assert position.range_from_client_units( ['x="😋"'], types.Range( @@ -262,7 +262,7 @@ def test_range_from_utf16(): def test_range_to_utf16(): - position = Position(encoding=types.PositionEncodingKind.Utf16) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf16) assert position.range_to_client_units( ['x="😋"'], types.Range( @@ -300,19 +300,27 @@ def test_offset_at_position_utf16(): def test_offset_at_position_utf32(): - doc = TextDocument(DOC_URI, DOC, position_encoding=types.PositionEncodingKind.Utf32) + doc = TextDocument( + DOC_URI, + DOC, + position_codec=PositionCodec(encoding=types.PositionEncodingKind.Utf32), + ) assert doc.offset_at_position(types.Position(line=0, character=8)) == 8 assert doc.offset_at_position(types.Position(line=5, character=0)) == 39 def test_offset_at_position_utf8(): - doc = TextDocument(DOC_URI, DOC, position_encoding=types.PositionEncodingKind.Utf8) + doc = TextDocument( + DOC_URI, + DOC, + position_codec=PositionCodec(encoding=types.PositionEncodingKind.Utf8), + ) assert doc.offset_at_position(types.Position(line=0, character=8)) == 8 assert doc.offset_at_position(types.Position(line=5, character=0)) == 41 def test_utf16_to_utf32_position_cast(): - position = Position(encoding=types.PositionEncodingKind.Utf16) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf16) lines = ["", "😋😋", ""] assert position.position_from_client_units( lines, types.Position(line=0, character=0) @@ -344,7 +352,7 @@ def test_utf16_to_utf32_position_cast(): def test_position_for_line_endings(): - position = Position(encoding=types.PositionEncodingKind.Utf16) + position = PositionCodec(encoding=types.PositionEncodingKind.Utf16) lines = ["x\r\n", "y\n"] assert position.position_from_client_units( lines, types.Position(line=0, character=10)