diff options
Diffstat (limited to 'packages/python/lsprotocol/_hooks.py')
-rw-r--r-- | packages/python/lsprotocol/_hooks.py | 1233 |
1 files changed, 1233 insertions, 0 deletions
diff --git a/packages/python/lsprotocol/_hooks.py b/packages/python/lsprotocol/_hooks.py new file mode 100644 index 0000000..e1ba9d6 --- /dev/null +++ b/packages/python/lsprotocol/_hooks.py @@ -0,0 +1,1233 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +import sys +from typing import Any, List, Optional, Tuple, Union + +import attrs +import cattrs + +from . import types as lsp_types + +LSPAny = lsp_types.LSPAny +OptionalPrimitive = Optional[Union[bool, int, str, float]] + +# Flag to ensure we only resolve forward references once. +_resolved_forward_references = False + + +def _resolve_forward_references() -> None: + """Resolve forward references for faster processing with cattrs.""" + global _resolved_forward_references + if not _resolved_forward_references: + + def _filter(p: Tuple[str, object]) -> bool: + return isinstance(p[1], type) and attrs.has(p[1]) + + # Creating a concrete list here because `resolve_types` mutates the provided map. + items = list(filter(_filter, lsp_types.ALL_TYPES_MAP.items())) + for _, value in items: + if isinstance(value, type): + attrs.resolve_types(value, lsp_types.ALL_TYPES_MAP, {}) # type: ignore + _resolved_forward_references = True + + +def register_hooks(converter: cattrs.Converter) -> cattrs.Converter: + _resolve_forward_references() + converter = _register_capabilities_hooks(converter) + converter = _register_required_structure_hooks(converter) + return _register_custom_property_hooks(converter) + + +def _register_capabilities_hooks(converter: cattrs.Converter) -> cattrs.Converter: + def _text_document_sync_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.TextDocumentSyncOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.TextDocumentSyncOptions) + + def _notebook_document_sync_hook( + object_: Any, _: type + ) -> Optional[ + Union[ + lsp_types.NotebookDocumentSyncRegistrationOptions, + lsp_types.NotebookDocumentSyncOptions, + ] + ]: + if object_ is None: + return None + if "id" in object_: + return converter.structure( + object_, lsp_types.NotebookDocumentSyncRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.NotebookDocumentSyncOptions) + + def _hover_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.HoverOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.HoverOptions) + + def _declaration_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.DeclarationRegistrationOptions, + lsp_types.DeclarationOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.DeclarationRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.DeclarationOptions) + + def _definition_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.DefinitionOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.DefinitionOptions) + + def _type_definition_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.TypeDefinitionRegistrationOptions, + lsp_types.TypeDefinitionOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.TypeDefinitionRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.TypeDefinitionOptions) + + def _implementation_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.ImplementationRegistrationOptions, + lsp_types.ImplementationOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.ImplementationRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.ImplementationOptions) + + def _references_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.ReferenceOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.ReferenceOptions) + + def _position_encoding_hook( + object_: Union[lsp_types.PositionEncodingKind, OptionalPrimitive], _: type + ) -> Union[lsp_types.PositionEncodingKind, OptionalPrimitive]: + return object_ + + def _document_highlight_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.DocumentHighlightOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.DocumentHighlightOptions) + + def _document_symbol_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.DocumentSymbolOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.DocumentSymbolOptions) + + def _code_action_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.CodeActionOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.CodeActionOptions) + + def _color_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.DocumentColorRegistrationOptions, + lsp_types.DocumentColorOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.DocumentColorRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.DocumentColorOptions) + + def _workspace_symbol_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.WorkspaceSymbolOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.WorkspaceSymbolOptions) + + def _document_formatting_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.DocumentFormattingOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.DocumentFormattingOptions) + + def _document_range_formatting_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.DocumentRangeFormattingOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.DocumentRangeFormattingOptions) + + def _rename_provider_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.RenameOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.RenameOptions) + + def _folding_range_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.FoldingRangeRegistrationOptions, + lsp_types.FoldingRangeOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.FoldingRangeRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.FoldingRangeOptions) + + def _selection_range_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.SelectionRangeRegistrationOptions, + lsp_types.SelectionRangeOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.SelectionRangeRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.SelectionRangeOptions) + + def _call_hierarchy_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.CallHierarchyRegistrationOptions, + lsp_types.CallHierarchyOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.CallHierarchyRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.CallHierarchyOptions) + + def _linked_editing_range_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.LinkedEditingRangeRegistrationOptions, + lsp_types.LinkedEditingRangeOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.LinkedEditingRangeRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.LinkedEditingRangeOptions) + + def _semantic_tokens_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.SemanticTokensRegistrationOptions, + lsp_types.SemanticTokensOptions, + ]: + if object_ is None: + return None + if "id" in object_: + return converter.structure( + object_, lsp_types.SemanticTokensRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.SemanticTokensOptions) + + def _moniker_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.MonikerRegistrationOptions, + lsp_types.MonikerOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure(object_, lsp_types.MonikerRegistrationOptions) + else: + return converter.structure(object_, lsp_types.MonikerOptions) + + def _type_hierarchy_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.TypeHierarchyRegistrationOptions, + lsp_types.TypeHierarchyOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.TypeHierarchyRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.TypeHierarchyOptions) + + def _inline_value_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.InlineValueRegistrationOptions, + lsp_types.InlineValueOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure( + object_, lsp_types.InlineValueRegistrationOptions + ) + else: + return converter.structure(object_, lsp_types.InlineValueOptions) + + def _inlay_hint_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.InlayHintRegistrationOptions, + lsp_types.InlayHintOptions, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if "id" in object_: + return converter.structure(object_, lsp_types.InlayHintRegistrationOptions) + else: + return converter.structure(object_, lsp_types.InlayHintOptions) + + def _inlay_hint_label_part_hook( + object_: Any, _: type + ) -> Union[str, List[lsp_types.InlayHintLabelPart]]: + if isinstance(object_, str): + return object_ + + return [ + converter.structure(item, lsp_types.InlayHintLabelPart) for item in object_ + ] + + def _diagnostic_provider_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.DiagnosticRegistrationOptions, + lsp_types.DiagnosticOptions, + ]: + if object_ is None: + return None + if "id" in object_: + return converter.structure(object_, lsp_types.DiagnosticRegistrationOptions) + else: + return converter.structure(object_, lsp_types.DiagnosticOptions) + + def _save_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.SaveOptions]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.SaveOptions) + + def _code_action_hook( + object_: Any, _: type + ) -> Union[lsp_types.Command, lsp_types.CodeAction]: + if "command" in object_: + return converter.structure(object_, lsp_types.Command) + else: + return converter.structure(object_, lsp_types.CodeAction) + + def _completion_list_hook( + object_: Any, _: type + ) -> Optional[Union[lsp_types.CompletionList, List[lsp_types.CompletionItem]]]: + if object_ is None: + return None + if isinstance(object_, list): + return [ + converter.structure(item, lsp_types.CompletionItem) for item in object_ + ] + else: + return converter.structure(object_, lsp_types.CompletionList) + + def _location_hook( + object_: Any, _: type + ) -> Optional[ + Union[ + lsp_types.Location, + List[lsp_types.Location], + List[lsp_types.LocationLink], + ] + ]: + if object_ is None: + return None + if isinstance(object_, list): + if len(object_) == 0: + return [] # type: ignore[return-value] + if "targetUri" in object_[0]: + return [ + converter.structure(item, lsp_types.LocationLink) + for item in object_ + ] + else: + return [ + converter.structure(item, lsp_types.Location) for item in object_ + ] + else: + return converter.structure(object_, lsp_types.Location) + + def _symbol_hook( + object_: Any, _: type + ) -> Optional[ + Union[List[lsp_types.DocumentSymbol], List[lsp_types.SymbolInformation]] + ]: + if object_ is None: + return None + if isinstance(object_, list): + if len(object_) == 0: + return [] # type: ignore[return-value] + if "location" in object_[0]: + return [ + converter.structure(item, lsp_types.SymbolInformation) + for item in object_ + ] + else: + return [ + converter.structure(item, lsp_types.DocumentSymbol) + for item in object_ + ] + else: + return None + + def _markup_content_hook( + object_: Any, _: type + ) -> Optional[ + Union[ + OptionalPrimitive, + lsp_types.MarkupContent, + lsp_types.MarkedString_Type1, + List[Union[OptionalPrimitive, lsp_types.MarkedString_Type1]], + ] + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + if isinstance(object_, list): + return [ + ( + item + if isinstance(item, (bool, int, str, float)) + else converter.structure(item, lsp_types.MarkedString_Type1) + ) + for item in object_ + ] + if "kind" in object_: + return converter.structure(object_, lsp_types.MarkupContent) + else: + return converter.structure(object_, lsp_types.MarkedString_Type1) + + def _document_edit_hook( + object_: Any, _: type + ) -> Optional[ + Union[ + lsp_types.TextDocumentEdit, + lsp_types.CreateFile, + lsp_types.RenameFile, + lsp_types.DeleteFile, + ] + ]: + if object_ is None: + return None + if "kind" in object_: + if object_["kind"] == "create": + return converter.structure(object_, lsp_types.CreateFile) + elif object_["kind"] == "rename": + return converter.structure(object_, lsp_types.RenameFile) + elif object_["kind"] == "delete": + return converter.structure(object_, lsp_types.DeleteFile) + else: + raise ValueError("Unknown edit kind: ", object_) + else: + return converter.structure(object_, lsp_types.TextDocumentEdit) + + def _semantic_tokens_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.SemanticTokensOptionsFullType1]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.SemanticTokensOptionsFullType1) + + def _semantic_tokens_capabilities_hook( + object_: Any, _: type + ) -> Union[ + OptionalPrimitive, + lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1, + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure( + object_, lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1 + ) + + def _code_action_kind_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.CodeActionKind]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.CodeActionKind) + + def _position_encoding_kind_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.PositionEncodingKind]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.PositionEncodingKind) + + def _folding_range_kind_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.FoldingRangeKind]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.FoldingRangeKind) + + def _semantic_token_types_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.SemanticTokenTypes]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.SemanticTokenTypes) + + def _semantic_token_modifiers_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.SemanticTokenModifiers]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.SemanticTokenModifiers) + + def _watch_kind_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.WatchKind]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.WatchKind) + + def _notebook_sync_option_selector_hook( + object_: Any, _: type + ) -> Union[ + lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType1, + lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType2, + ]: + if "notebook" in object_: + return converter.structure( + object_, lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType1 + ) + else: + return converter.structure( + object_, lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType2 + ) + + def _semantic_token_registration_options_hook( + object_: Any, _: type + ) -> Optional[ + Union[OptionalPrimitive, lsp_types.SemanticTokensRegistrationOptionsFullType1] + ]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure( + object_, lsp_types.SemanticTokensRegistrationOptionsFullType1 + ) + + def _inline_completion_provider_hook( + object_: Any, _: type + ) -> Optional[Union[OptionalPrimitive, lsp_types.InlineCompletionOptions]]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.InlineCompletionOptions) + + def _inline_completion_list_hook( + object_: Any, _: type + ) -> Optional[ + Union[lsp_types.InlineCompletionList, List[lsp_types.InlineCompletionItem]] + ]: + if object_ is None: + return None + if isinstance(object_, list): + return [ + converter.structure(item, lsp_types.InlineCompletionItem) + for item in object_ + ] + return converter.structure(object_, lsp_types.InlineCompletionList) + + def _string_value_hook( + object_: Any, _: type + ) -> Union[OptionalPrimitive, lsp_types.StringValue]: + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure(object_, lsp_types.StringValue) + + def _symbol_list_hook( + object_: Any, _: type + ) -> Optional[ + Union[List[lsp_types.SymbolInformation], List[lsp_types.WorkspaceSymbol]] + ]: + if object_ is None: + return None + assert isinstance(object_, list) + if len(object_) == 0: + return [] # type: ignore[return-value] + if "location" in object_[0]: + return [ + converter.structure(item, lsp_types.SymbolInformation) + for item in object_ + ] + else: + return [ + converter.structure(item, lsp_types.WorkspaceSymbol) for item in object_ + ] + + def _notebook_sync_registration_option_selector_hook( + object_: Any, _: type + ) -> Union[ + lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1, + lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2, + ]: + if "notebook" in object_: + return converter.structure( + object_, + lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1, + ) + else: + return converter.structure( + object_, + lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2, + ) + + structure_hooks = [ + ( + Optional[ + Union[lsp_types.TextDocumentSyncOptions, lsp_types.TextDocumentSyncKind] + ], + _text_document_sync_hook, + ), + ( + Optional[ + Union[ + lsp_types.NotebookDocumentSyncOptions, + lsp_types.NotebookDocumentSyncRegistrationOptions, + ] + ], + _notebook_document_sync_hook, + ), + (Optional[Union[bool, lsp_types.HoverOptions]], _hover_provider_hook), + ( + Optional[ + Union[ + bool, + lsp_types.DeclarationOptions, + lsp_types.DeclarationRegistrationOptions, + ] + ], + _declaration_provider_hook, + ), + (Optional[Union[bool, lsp_types.DefinitionOptions]], _definition_provider_hook), + ( + Optional[ + Union[ + bool, + lsp_types.TypeDefinitionOptions, + lsp_types.TypeDefinitionRegistrationOptions, + ] + ], + _type_definition_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.ImplementationOptions, + lsp_types.ImplementationRegistrationOptions, + ] + ], + _implementation_provider_hook, + ), + (Optional[Union[bool, lsp_types.ReferenceOptions]], _references_provider_hook), + ( + Optional[Union[bool, lsp_types.DocumentHighlightOptions]], + _document_highlight_provider_hook, + ), + ( + Optional[Union[bool, lsp_types.DocumentSymbolOptions]], + _document_symbol_provider_hook, + ), + ( + Optional[Union[bool, lsp_types.CodeActionOptions]], + _code_action_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.DocumentColorOptions, + lsp_types.DocumentColorRegistrationOptions, + ] + ], + _color_provider_hook, + ), + ( + Optional[Union[bool, lsp_types.WorkspaceSymbolOptions]], + _workspace_symbol_provider_hook, + ), + ( + Optional[Union[bool, lsp_types.DocumentFormattingOptions]], + _document_formatting_provider_hook, + ), + ( + Optional[Union[bool, lsp_types.DocumentRangeFormattingOptions]], + _document_range_formatting_provider_hook, + ), + (Optional[Union[bool, lsp_types.RenameOptions]], _rename_provider_hook), + ( + Optional[ + Union[ + bool, + lsp_types.FoldingRangeOptions, + lsp_types.FoldingRangeRegistrationOptions, + ] + ], + _folding_range_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.SelectionRangeOptions, + lsp_types.SelectionRangeRegistrationOptions, + ] + ], + _selection_range_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.CallHierarchyOptions, + lsp_types.CallHierarchyRegistrationOptions, + ] + ], + _call_hierarchy_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.LinkedEditingRangeOptions, + lsp_types.LinkedEditingRangeRegistrationOptions, + ] + ], + _linked_editing_range_provider_hook, + ), + ( + Optional[ + Union[ + lsp_types.SemanticTokensOptions, + lsp_types.SemanticTokensRegistrationOptions, + ] + ], + _semantic_tokens_provider_hook, + ), + ( + Optional[ + Union[ + bool, lsp_types.MonikerOptions, lsp_types.MonikerRegistrationOptions + ] + ], + _moniker_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.TypeHierarchyOptions, + lsp_types.TypeHierarchyRegistrationOptions, + ] + ], + _type_hierarchy_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.InlineValueOptions, + lsp_types.InlineValueRegistrationOptions, + ] + ], + _inline_value_provider_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.InlayHintOptions, + lsp_types.InlayHintRegistrationOptions, + ] + ], + _inlay_hint_provider_hook, + ), + ( + Union[str, List[lsp_types.InlayHintLabelPart]], + _inlay_hint_label_part_hook, + ), + ( + Optional[ + Union[ + lsp_types.DiagnosticOptions, lsp_types.DiagnosticRegistrationOptions + ] + ], + _diagnostic_provider_hook, + ), + ( + Optional[Union[lsp_types.SaveOptions, bool]], + _save_hook, + ), + ( + Union[lsp_types.Command, lsp_types.CodeAction], + _code_action_hook, + ), + ( + Optional[Union[List[lsp_types.CompletionItem], lsp_types.CompletionList]], + _completion_list_hook, + ), + ( + Optional[ + Union[ + lsp_types.Location, + List[lsp_types.Location], + List[lsp_types.LocationLink], + ] + ], + _location_hook, + ), + ( + Optional[ + Union[List[lsp_types.SymbolInformation], List[lsp_types.DocumentSymbol]] + ], + _symbol_hook, + ), + ( + Union[ + lsp_types.MarkupContent, + str, + lsp_types.MarkedString_Type1, + List[Union[str, lsp_types.MarkedString_Type1]], + ], + _markup_content_hook, + ), + ( + Union[ + lsp_types.TextDocumentEdit, + lsp_types.CreateFile, + lsp_types.RenameFile, + lsp_types.DeleteFile, + ], + _document_edit_hook, + ), + ( + Optional[Union[bool, lsp_types.SemanticTokensOptionsFullType1]], + _semantic_tokens_hook, + ), + ( + Optional[ + Union[ + bool, + lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1, + ] + ], + _semantic_tokens_capabilities_hook, + ), + ( + Optional[Union[str, lsp_types.MarkupContent]], + _markup_content_hook, + ), + ( + Optional[Union[lsp_types.CodeActionKind, str]], + _code_action_kind_hook, + ), + ( + Union[lsp_types.CodeActionKind, str], + _code_action_kind_hook, + ), + ( + Union[lsp_types.PositionEncodingKind, str], + _position_encoding_kind_hook, + ), + ( + Optional[Union[lsp_types.FoldingRangeKind, str]], + _folding_range_kind_hook, + ), + ( + Union[lsp_types.FoldingRangeKind, str], + _folding_range_kind_hook, + ), + ( + Union[lsp_types.SemanticTokenTypes, str], + _semantic_token_types_hook, + ), + ( + Optional[Union[lsp_types.SemanticTokenTypes, str]], + _semantic_token_types_hook, + ), + ( + Union[lsp_types.SemanticTokenModifiers, str], + _semantic_token_modifiers_hook, + ), + ( + Optional[Union[lsp_types.SemanticTokenModifiers, str]], + _semantic_token_modifiers_hook, + ), + ( + Union[lsp_types.WatchKind, int], + _watch_kind_hook, + ), + ( + Optional[Union[lsp_types.WatchKind, int]], + _watch_kind_hook, + ), + ( + Union[ + lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType1, + lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType2, + ], + _notebook_sync_option_selector_hook, + ), + ( + Optional[ + Union[ + lsp_types.PositionEncodingKind, + str, + ] + ], + _position_encoding_hook, + ), + ( + Optional[Union[bool, lsp_types.SemanticTokensRegistrationOptionsFullType1]], + _semantic_token_registration_options_hook, + ), + ( + Optional[Union[bool, lsp_types.InlineCompletionOptions]], + _inline_completion_provider_hook, + ), + ( + Optional[ + Union[ + lsp_types.InlineCompletionList, List[lsp_types.InlineCompletionItem] + ] + ], + _inline_completion_list_hook, + ), + ( + Union[str, lsp_types.StringValue], + _string_value_hook, + ), + ( + Optional[ + Union[ + List[lsp_types.SymbolInformation], List[lsp_types.WorkspaceSymbol] + ] + ], + _symbol_list_hook, + ), + ( + Union[ + lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1, + lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2, + ], + _notebook_sync_registration_option_selector_hook, + ), + ] + for type_, hook in structure_hooks: + converter.register_structure_hook(type_, hook) + return converter + + +def _register_required_structure_hooks( + converter: cattrs.Converter, +) -> cattrs.Converter: + def _lsp_object_hook(object_: Any, type_: type) -> Any: + return object_ + + def _parameter_information_label_hook( + object_: Any, type: type + ) -> Union[str, Tuple[int, int]]: + if isinstance(object_, str): + return object_ + else: + return (int(object_[0]), int(object_[1])) + + def _text_document_filter_hook( + object_: Any, _: type + ) -> Union[ + str, + lsp_types.TextDocumentFilter_Type1, + lsp_types.TextDocumentFilter_Type2, + lsp_types.TextDocumentFilter_Type3, + lsp_types.NotebookCellTextDocumentFilter, + ]: + if isinstance(object_, str): + return str(object_) + elif "notebook" in object_: + return converter.structure( + object_, lsp_types.NotebookCellTextDocumentFilter + ) + elif "language" in object_: + return converter.structure(object_, lsp_types.TextDocumentFilter_Type1) + elif "scheme" in object_: + return converter.structure(object_, lsp_types.TextDocumentFilter_Type2) + else: + return converter.structure(object_, lsp_types.TextDocumentFilter_Type3) + + def _notebook_filter_hook( + object_: Any, _: type + ) -> Union[ + str, + lsp_types.NotebookDocumentFilter_Type1, + lsp_types.NotebookDocumentFilter_Type2, + lsp_types.NotebookDocumentFilter_Type3, + ]: + if isinstance(object_, str): + return str(object_) + elif "notebookType" in object_: + return converter.structure(object_, lsp_types.NotebookDocumentFilter_Type1) + elif "scheme" in object_: + return converter.structure(object_, lsp_types.NotebookDocumentFilter_Type2) + else: + return converter.structure(object_, lsp_types.NotebookDocumentFilter_Type3) + + # TODO: Remove the ignore after this issue with attrs is addressed in either attrs or mypy + NotebookSelectorItem = attrs.fields( + lsp_types.NotebookCellTextDocumentFilter + ).notebook.type + STRUCTURE_HOOKS = [ + (type(None), lambda object_, _type: object_), + (Optional[Union[int, str]], lambda object_, _type: object_), + (Union[int, str], lambda object_, _type: object_), + (lsp_types.LSPAny, _lsp_object_hook), + (Optional[Union[str, bool]], lambda object_, _type: object_), + (Optional[Union[bool, Any]], lambda object_, _type: object_), + ( + Union[ + lsp_types.TextDocumentFilter_Type1, + lsp_types.TextDocumentFilter_Type2, + lsp_types.TextDocumentFilter_Type3, + lsp_types.NotebookCellTextDocumentFilter, + ], + _text_document_filter_hook, + ), + (lsp_types.DocumentFilter, _text_document_filter_hook), + ( + Union[ + str, + lsp_types.NotebookDocumentFilter_Type1, + lsp_types.NotebookDocumentFilter_Type2, + lsp_types.NotebookDocumentFilter_Type3, + ], + _notebook_filter_hook, + ), + (NotebookSelectorItem, _notebook_filter_hook), + ( + Union[lsp_types.LSPObject, List["LSPAny"], str, int, float, bool, None], + _lsp_object_hook, + ), + ( + Union[ + lsp_types.LSPObject, List[lsp_types.LSPAny], str, int, float, bool, None + ], + _lsp_object_hook, + ), + ( + Union[str, Tuple[int, int]], + _parameter_information_label_hook, + ), + (lsp_types.LSPObject, _lsp_object_hook), + ] + + if sys.version_info > (3, 8): + STRUCTURE_HOOKS += [ + ( + Union[ + lsp_types.LSPObject, + List[ + Union[ + lsp_types.LSPObject, + List["LSPAny"], + str, + int, + float, + bool, + None, + ] + ], + str, + int, + float, + bool, + None, + ], + _lsp_object_hook, + ) + ] + + for type_, hook in STRUCTURE_HOOKS: + converter.register_structure_hook(type_, hook) + + return converter + + +def _register_custom_property_hooks(converter: cattrs.Converter) -> cattrs.Converter: + def _to_camel_case(name: str) -> str: + # TODO: when min Python becomes >= 3.9, then update this to: + # `return name.removesuffix("_")`. + new_name = name[:-1] if name.endswith("_") else name + parts = new_name.split("_") + return parts[0] + "".join(p.title() for p in parts[1:]) + + def _omit(cls: type, prop: str) -> bool: + special = lsp_types.is_special_property(cls, prop) + return not special + + def _with_custom_unstructure(cls: type) -> Any: + attributes = { + a.name: cattrs.gen.override( + rename=_to_camel_case(a.name), + omit_if_default=_omit(cls, a.name), + ) + for a in attrs.fields(cls) # type: ignore + } + return cattrs.gen.make_dict_unstructure_fn(cls, converter, **attributes) + + def _with_custom_structure(cls: type) -> Any: + attributes = { + a.name: cattrs.gen.override( + rename=_to_camel_case(a.name), + omit_if_default=_omit(cls, a.name), + ) + for a in attrs.fields(cls) # type: ignore + } + return cattrs.gen.make_dict_structure_fn(cls, converter, **attributes) + + converter.register_unstructure_hook_factory(attrs.has, _with_custom_unstructure) + converter.register_structure_hook_factory(attrs.has, _with_custom_structure) + return converter |