Skip to content

Commit

Permalink
fix: respect client's preferred encoding when possible
Browse files Browse the repository at this point in the history
Previously, `pygls` would always use `UTF-16` except when the client
tried to hide the fact that it supports `UTF-16` (which the LSP spec
requires it to do in all cases). Now, `pygls` will choose the editor's
preferred encoding.

When it is `UTF-32`, `pygls` saves a bit of computation in most
position codec related operations (`X_to_client_units` +
`client_num_units` are faster, `X_from_client_units` is about the
same), which is great. When it is `UTF-16` or `UTF-8`, the
computational load is about the same.

Closes: openlawlibrary#445
  • Loading branch information
nthykier committed Apr 6, 2024
1 parent 850b86c commit d4395e1
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
25 changes: 14 additions & 11 deletions pygls/capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# limitations under the License. #
############################################################################
from functools import reduce
from typing import Any, Dict, List, Optional, Set, Union, TypeVar
from typing import Any, Dict, List, Optional, Set, Union, TypeVar, FrozenSet
import logging

from lsprotocol import types
Expand All @@ -24,6 +24,14 @@
logger = logging.getLogger(__name__)
T = TypeVar("T")

_SUPPORTED_ENCODINGS = frozenset(
[
types.PositionEncodingKind.Utf8,
types.PositionEncodingKind.Utf16,
types.PositionEncodingKind.Utf32,
]
)


def get_capability(
client_capabilities: types.ClientCapabilities, field: str, default: Any = None
Expand Down Expand Up @@ -401,16 +409,11 @@ def _with_position_encodings(self):
if encodings is None:
return self

if types.PositionEncodingKind.Utf16 in encodings:
return self

if types.PositionEncodingKind.Utf32 in encodings:
self.server_cap.position_encoding = types.PositionEncodingKind.Utf32
return self

if types.PositionEncodingKind.Utf8 in encodings:
self.server_cap.position_encoding = types.PositionEncodingKind.Utf8
return self
# We match client preference where this an overlap between its and our supported encodings.
for encoding in encodings:
if encoding in _SUPPORTED_ENCODINGS:
self.server_cap.position_encoding = encoding
return self

logger.warning(f"Unknown `PositionEncoding`s: {encodings}")

Expand Down
13 changes: 13 additions & 0 deletions tests/test_feature_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,19 @@ def server_capabilities(**kwargs):
]
)
),
server_capabilities(position_encoding=lsp.PositionEncodingKind.Utf8),
),
(
lsp.INITIALIZE,
None,
lsp.ClientCapabilities(
general=lsp.GeneralClientCapabilities(
position_encodings=[
lsp.PositionEncodingKind.Utf32,
lsp.PositionEncodingKind.Utf8,
]
)
),
server_capabilities(position_encoding=lsp.PositionEncodingKind.Utf32),
),
(
Expand Down

0 comments on commit d4395e1

Please sign in to comment.