Skip to content

Commit

Permalink
refactor: rename server Position to PositionCodec, instantiate it in …
Browse files Browse the repository at this point in the history
…Workspace
  • Loading branch information
RossBencina committed Sep 29, 2023
1 parent ec342a3 commit 8929a7d
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 51 deletions.
56 changes: 31 additions & 25 deletions pygls/workspace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
log = logging.getLogger(__name__)


class Position:
class PositionCodec:
def __init__(
self,
encoding: Optional[
Expand Down Expand Up @@ -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
Expand Down
24 changes: 14 additions & 10 deletions pygls/workspace/text_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]*")
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion pygls/workspace/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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,
Expand All @@ -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):
Expand Down
34 changes: 21 additions & 13 deletions tests/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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(
Expand All @@ -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(
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 8929a7d

Please sign in to comment.