From 603632ea703d6296348680890859c148ac85229a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Ch=C5=82odnicki?= Date: Sun, 29 Sep 2024 13:29:09 +0200 Subject: [PATCH] update LSP types and pyright (#2519) --- .github/workflows/main.yml | 2 +- plugin/core/input_handlers.py | 4 +- plugin/core/protocol.py | 132 ++++++++++++++++++++++++++++------ plugin/core/types.py | 10 +-- tox.ini | 2 +- 5 files changed, 120 insertions(+), 30 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bc9e25c4d..268c9241a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,7 +41,7 @@ jobs: python-version: '3.8' - run: sudo apt update - run: sudo apt install --no-install-recommends -y x11-xserver-utils - - run: pip3 install mypy==1.7.1 flake8==5.0.4 pyright==1.1.339 --user + - run: pip3 install mypy==1.7.1 flake8==5.0.4 pyright==1.1.381 --user - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - run: mypy stubs - run: flake8 plugin tests diff --git a/plugin/core/input_handlers.py b/plugin/core/input_handlers.py index 54b2f4285..f68ece81f 100644 --- a/plugin/core/input_handlers.py +++ b/plugin/core/input_handlers.py @@ -70,7 +70,7 @@ def __init__( def list_items(self) -> ListItemsReturn: if self._initial_value is not None: sublime.set_timeout(self._select_and_reset) - return [self._initial_value], 0 # pyright: ignore[reportGeneralTypeIssues] + return [self._initial_value], 0 # pyright: ignore[reportReturnType] else: return self.get_list_items() @@ -123,7 +123,7 @@ def attach_listener(self) -> None: raise RuntimeError('Could not find the Command Palette input field view') self.listener = InputListener(self) self.listener.attach(buffer) - if ST_VERSION < 4161: + if ST_VERSION < 4161 and self.input_view: # Workaround for initial_selection not working; see https://github.com/sublimehq/sublime_text/issues/6175 selection = self.input_view.sel() selection.clear() diff --git a/plugin/core/protocol.py b/plugin/core/protocol.py index 69a440f72..09b2bf972 100644 --- a/plugin/core/protocol.py +++ b/plugin/core/protocol.py @@ -49,6 +49,8 @@ class SemanticTokenTypes(StrEnum): Operator = 'operator' Decorator = 'decorator' """ @since 3.17.0 """ + Label = 'label' + """ @since 3.18.0 """ class SemanticTokenModifiers(StrEnum): @@ -118,7 +120,7 @@ class LSPErrorCodes(IntEnum): If a client decides that a result is not of any use anymore the client should cancel the request. """ RequestCancelled = -32800 - """ The client has canceled a request and a server as detected + """ The client has canceled a request and a server has detected the cancel. """ @@ -1780,6 +1782,48 @@ class InlineCompletionRegistrationOptions(TypedDict): the request again. See also Registration#id. """ +class TextDocumentContentParams(TypedDict): + """ Parameters for the `workspace/textDocumentContent` request. + + @since 3.18.0 + @proposed """ + uri: 'DocumentUri' + """ The uri of the text document. """ + + +class TextDocumentContentResult(TypedDict): + """ Result of the `workspace/textDocumentContent` request. + + @since 3.18.0 + @proposed """ + text: str + """ The text content of the text document. Please note, that the content of + any subsequent open notifications for the text document might differ + from the returned content due to whitespace and line ending + normalizations done on the client """ + + +class TextDocumentContentRegistrationOptions(TypedDict): + """ Text document content provider registration options. + + @since 3.18.0 + @proposed """ + schemes: List[str] + """ The schemes for which the server provides content. """ + id: NotRequired[str] + """ The id used to register the request. The id can be used to deregister + the request again. See also Registration#id. """ + + +class TextDocumentContentRefreshParams(TypedDict): + """ Parameters for the `workspace/textDocumentContent/refresh` request. + + @since 3.18.0 + @proposed """ + uri: 'DocumentUri' + """ The uri of the text document to refresh. """ + + class RegistrationParams(TypedDict): registrations: List['Registration'] @@ -2567,7 +2611,13 @@ class WorkspaceSymbolParams(TypedDict): """ The parameters of a {@link WorkspaceSymbolRequest}. """ query: str """ A query string to filter symbols by. Clients may send an empty - string here to request all symbols. """ + string here to request all symbols. + + The `query`-parameter should be interpreted in a *relaxed way* as editors + will apply their own highlighting and scoring on the results. A good rule + of thumb is to match case-insensitive and to simply check that the + characters of *query* appear in their order in a candidate symbol. + Servers shouldn't use prefix, substring, or similar strict matching. """ workDoneToken: NotRequired['ProgressToken'] """ An optional token that a server can use to report work done progress. """ partialResultToken: NotRequired['ProgressToken'] @@ -3077,18 +3127,12 @@ class Position(TypedDict): @since 3.17.0 - support for negotiated position encoding. """ line: Uint - """ Line position in a document (zero-based). - - If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. - If a line number is negative, it defaults to 0. """ + """ Line position in a document (zero-based). """ character: Uint """ Character offset on a line in a document (zero-based). The meaning of this offset is determined by the negotiated - `PositionEncodingKind`. - - If the character value is greater than the line length it defaults back to the - line length. """ + `PositionEncodingKind`. """ class SelectionRangeOptions(TypedDict): @@ -3597,6 +3641,15 @@ class InlineCompletionOptions(TypedDict): workDoneProgress: NotRequired[bool] +class TextDocumentContentOptions(TypedDict): + """ Text document content provider options. + + @since 3.18.0 + @proposed """ + schemes: List[str] + """ The schemes for which the server provides content. """ + + class Registration(TypedDict): """ General parameters to register for a notification or to register a provider. """ id: str @@ -3790,8 +3843,9 @@ class Diagnostic(TypedDict): range: 'Range' """ The range at which the message applies """ severity: NotRequired['DiagnosticSeverity'] - """ The diagnostic's severity. Can be omitted. If omitted it is up to the - client to interpret diagnostics as error, warning, info or hint. """ + """ The diagnostic's severity. To avoid interpretation mismatches when a + server is used with different clients it is highly recommended that servers + always provide a severity value. """ code: NotRequired[Union[int, str]] """ The diagnostic's code, which usually appear in the user interface. """ codeDescription: NotRequired['CodeDescription'] @@ -4482,6 +4536,11 @@ class WorkspaceOptions(TypedDict): """ The server is interested in notifications/requests for operations on files. @since 3.16.0 """ + textDocumentContent: NotRequired[Union['TextDocumentContentOptions', 'TextDocumentContentRegistrationOptions']] + """ The server supports the `workspace/textDocumentContent` request. + + @since 3.18.0 + @proposed """ class TextDocumentContentChangePartial(TypedDict): @@ -4701,6 +4760,11 @@ class WorkspaceClientCapabilities(TypedDict): @since 3.18.0 @proposed """ + textDocumentContent: NotRequired['TextDocumentContentClientCapabilities'] + """ Capabilities specific to the `workspace/textDocumentContent` request. + + @since 3.18.0 + @proposed """ class TextDocumentClientCapabilities(TypedDict): @@ -4924,8 +4988,10 @@ class TextDocumentFilterLanguage(TypedDict): """ A language id, like `typescript`. """ scheme: NotRequired[str] """ A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. """ - pattern: NotRequired[str] - """ A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. """ + pattern: NotRequired['GlobPattern'] + """ A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. + + @since 3.18.0 - support for relative patterns. """ class TextDocumentFilterScheme(TypedDict): @@ -4936,8 +5002,10 @@ class TextDocumentFilterScheme(TypedDict): """ A language id, like `typescript`. """ scheme: str """ A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. """ - pattern: NotRequired[str] - """ A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. """ + pattern: NotRequired['GlobPattern'] + """ A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. + + @since 3.18.0 - support for relative patterns. """ class TextDocumentFilterPattern(TypedDict): @@ -4948,8 +5016,10 @@ class TextDocumentFilterPattern(TypedDict): """ A language id, like `typescript`. """ scheme: NotRequired[str] """ A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. """ - pattern: str - """ A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. """ + pattern: 'GlobPattern' + """ A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. + + @since 3.18.0 - support for relative patterns. """ class NotebookDocumentFilterNotebookType(TypedDict): @@ -4960,7 +5030,7 @@ class NotebookDocumentFilterNotebookType(TypedDict): """ The type of the enclosing notebook. """ scheme: NotRequired[str] """ A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. """ - pattern: NotRequired[str] + pattern: NotRequired['GlobPattern'] """ A glob pattern. """ @@ -4972,7 +5042,7 @@ class NotebookDocumentFilterScheme(TypedDict): """ The type of the enclosing notebook. """ scheme: str """ A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. """ - pattern: NotRequired[str] + pattern: NotRequired['GlobPattern'] """ A glob pattern. """ @@ -4984,7 +5054,7 @@ class NotebookDocumentFilterPattern(TypedDict): """ The type of the enclosing notebook. """ scheme: NotRequired[str] """ A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. """ - pattern: str + pattern: 'GlobPattern' """ A glob pattern. """ @@ -5188,6 +5258,15 @@ class FoldingRangeWorkspaceClientCapabilities(TypedDict): @proposed """ +class TextDocumentContentClientCapabilities(TypedDict): + """ Client capabilities for a text document content provider. + + @since 3.18.0 + @proposed """ + dynamicRegistration: NotRequired[bool] + """ Text document content provider supports dynamic registration. """ + + class TextDocumentSyncClientCapabilities(TypedDict): dynamicRegistration: NotRequired[bool] """ Whether text document synchronization supports dynamic registration. """ @@ -5376,6 +5455,11 @@ class CodeLensClientCapabilities(TypedDict): """ The client capabilities of a {@link CodeLensRequest}. """ dynamicRegistration: NotRequired[bool] """ Whether code lens supports dynamic registration. """ + resolveSupport: NotRequired['ClientCodeLensResolveOptions'] + """ Whether the client supports resolving additional code lens + properties via a separate `codeLens/resolve` request. + + @since 3.18.0 """ class DocumentLinkClientCapabilities(TypedDict): @@ -5847,6 +5931,12 @@ class ClientCodeActionResolveOptions(TypedDict): """ The properties that a client can resolve lazily. """ +class ClientCodeLensResolveOptions(TypedDict): + """ @since 3.18.0 """ + properties: List[str] + """ The properties that a client can resolve lazily. """ + + class ClientFoldingRangeKindOptions(TypedDict): """ @since 3.18.0 """ valueSet: NotRequired[List['FoldingRangeKind']] diff --git a/plugin/core/types.py b/plugin/core/types.py index 46d7efa7b..eef8d040e 100644 --- a/plugin/core/types.py +++ b/plugin/core/types.py @@ -2,7 +2,7 @@ from .collections import DottedDict from .file_watcher import FileWatcherEventType from .logging import debug, set_debug_logging -from .protocol import TextDocumentSyncKind +from .protocol import ServerCapabilities, TextDocumentSyncKind, TextDocumentSyncOptions from .url import filename_to_uri from .url import parse_uri from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, TypedDict, TypeVar, Union @@ -478,13 +478,13 @@ def method_to_capability(method: str) -> tuple[str, str]: return capability_path, registration_path -def normalize_text_sync(textsync: None | int | dict[str, Any]) -> dict[str, Any]: +def normalize_text_sync(textsync: TextDocumentSyncOptions | TextDocumentSyncKind | None) -> dict[str, Any]: """ Brings legacy text sync capabilities to the most modern format """ result: dict[str, Any] = {} if isinstance(textsync, int): - change: dict[str, Any] | None = {"syncKind": textsync} + change = {"syncKind": textsync} result["textDocumentSync"] = {"didOpen": {}, "save": {}, "didClose": {}, "change": change} elif isinstance(textsync, dict): new = {} @@ -560,9 +560,9 @@ def unregister( self.remove(registration_path) return discarded - def assign(self, d: dict[str, Any]) -> None: + def assign(self, d: ServerCapabilities) -> None: textsync = normalize_text_sync(d.pop("textDocumentSync", None)) - super().assign(d) + super().assign(cast(dict, d)) if textsync: self.update(textsync) diff --git a/tox.ini b/tox.ini index f54a0a228..c00122615 100644 --- a/tox.ini +++ b/tox.ini @@ -22,7 +22,7 @@ per-file-ignores = deps = mypy==1.7.1 flake8==5.0.4 - pyright==1.1.339 + pyright==1.1.381 commands = # mypy disabled for main code as it doesn't currently support cyclic definitions - https://github.com/python/mypy/issues/731 mypy stubs