Repository: openlawlibrary/pygls
Pull request #446 (2024-04-06 12:13:22)

Respect client's preferred encoding when possible
## Description (e.g. "Related to ...", etc.)

Related to #445 

This change would make `pygls` accept the client's preferred encoding rather than preferring `UTF-16` blindly. For editors that prefer `UTF-32` this is advantageous for `pygls` since the position encoding/decoding becomes simpler.

## Code review checklist (for code reviewer to complete)

- [X] Pull request represents a single change (i.e. not fixing disparate/unrelated things in a single PR)
- [X] Title summarizes what is changing
- [X] Commit messages are meaningful (see [this][commit messages] for details)
- [X] Tests have been included and/or updated, as appropriate
- [X] Docstrings have been included and/or updated, as appropriate
- [X] Standalone docs have been updated accordingly

[commit messages]: https://conventionalcommits.org/


tombh: Thank you. I'll merge it now so it's available on the main branch. I won't cut a release immediately. But if you want a release soonder, please feel free to let us know.

Patch:
diff --git a/pygls/capabilities.py b/pygls/capabilities.py
index 975e5e2..44a6d2e 100644
--- a/pygls/capabilities.py
+++ b/pygls/capabilities.py
@@ -24,6 +24,14 @@ from lsprotocol import types
 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
@@ -401,16 +409,11 @@ class ServerCapabilitiesBuilder:
         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}")
 


Test patch:
diff --git a/tests/test_feature_manager.py b/tests/test_feature_manager.py
index f69f12a..744fcdb 100644
--- a/tests/test_feature_manager.py
+++ b/tests/test_feature_manager.py
@@ -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),
         ),
         (