|
4 | 4 | initialization options.
|
5 | 5 | """
|
6 | 6 |
|
7 |
| -from typing import List, Optional, Pattern, Set |
| 7 | +import re |
| 8 | +import sys |
| 9 | +from dataclasses import dataclass, field, fields, is_dataclass |
| 10 | +from typing import Any, List, Optional, Pattern, Set |
8 | 11 |
|
| 12 | +from cattrs import Converter |
| 13 | +from cattrs.gen import make_dict_structure_fn, override |
9 | 14 | from lsprotocol.types import MarkupKind
|
10 |
| -from pydantic import BaseModel, ConfigDict, Field |
11 | 15 |
|
12 | 16 | # pylint: disable=missing-class-docstring
|
13 | 17 | # pylint: disable=too-few-public-methods
|
14 | 18 |
|
15 |
| - |
16 |
| -def snake_to_camel(string: str) -> str: |
17 |
| - """Convert from snake_case to camelCase.""" |
18 |
| - return "".join( |
19 |
| - word.capitalize() if idx > 0 else word |
20 |
| - for idx, word in enumerate(string.split("_")) |
21 |
| - ) |
| 19 | +if sys.version_info >= (3, 10): |
| 20 | + # pylint: disable-next=unexpected-keyword-arg |
| 21 | + light_dataclass = dataclass(kw_only=True, eq=False, match_args=False) |
| 22 | +else: |
| 23 | + light_dataclass = dataclass(eq=False) |
22 | 24 |
|
23 | 25 |
|
24 |
| -class Model(BaseModel): |
25 |
| - model_config = ConfigDict(alias_generator=snake_to_camel) |
26 |
| - |
27 |
| - |
28 |
| -class CodeAction(Model): |
| 26 | +@light_dataclass |
| 27 | +class CodeAction: |
29 | 28 | name_extract_variable: str = "jls_extract_var"
|
30 | 29 | name_extract_function: str = "jls_extract_def"
|
31 | 30 |
|
32 | 31 |
|
33 |
| -class Completion(Model): |
| 32 | +@light_dataclass |
| 33 | +class Completion: |
34 | 34 | disable_snippets: bool = False
|
35 | 35 | resolve_eagerly: bool = False
|
36 |
| - ignore_patterns: List[Pattern[str]] = [] |
| 36 | + ignore_patterns: List[Pattern[str]] = field(default_factory=list) |
37 | 37 |
|
38 | 38 |
|
39 |
| -class Diagnostics(Model): |
| 39 | +@light_dataclass |
| 40 | +class Diagnostics: |
40 | 41 | enable: bool = True
|
41 | 42 | did_open: bool = True
|
42 | 43 | did_save: bool = True
|
43 | 44 | did_change: bool = True
|
44 | 45 |
|
45 | 46 |
|
46 |
| -class HoverDisableOptions(Model): |
| 47 | +@light_dataclass |
| 48 | +class HoverDisableOptions: |
47 | 49 | all: bool = False
|
48 |
| - names: Set[str] = set() |
49 |
| - full_names: Set[str] = set() |
| 50 | + names: Set[str] = field(default_factory=set) |
| 51 | + full_names: Set[str] = field(default_factory=set) |
50 | 52 |
|
51 | 53 |
|
52 |
| -class HoverDisable(Model): |
| 54 | +@light_dataclass |
| 55 | +class HoverDisable: |
53 | 56 | """All Attributes have _ appended to avoid syntax conflicts.
|
54 | 57 |
|
55 | 58 | For example, the keyword class would have required a special case.
|
56 | 59 | To get around this, I decided it's simpler to always assume an
|
57 | 60 | underscore at the end.
|
58 | 61 | """
|
59 | 62 |
|
60 |
| - keyword_: HoverDisableOptions = Field( |
61 |
| - default=HoverDisableOptions(), alias="keyword" |
62 |
| - ) |
63 |
| - module_: HoverDisableOptions = Field( |
64 |
| - default=HoverDisableOptions(), alias="module" |
65 |
| - ) |
66 |
| - class_: HoverDisableOptions = Field( |
67 |
| - default=HoverDisableOptions(), alias="class" |
68 |
| - ) |
69 |
| - instance_: HoverDisableOptions = Field( |
70 |
| - default=HoverDisableOptions(), alias="instance" |
71 |
| - ) |
72 |
| - function_: HoverDisableOptions = Field( |
73 |
| - default=HoverDisableOptions(), alias="function" |
74 |
| - ) |
75 |
| - param_: HoverDisableOptions = Field( |
76 |
| - default=HoverDisableOptions(), alias="param" |
77 |
| - ) |
78 |
| - path_: HoverDisableOptions = Field( |
79 |
| - default=HoverDisableOptions(), alias="path" |
80 |
| - ) |
81 |
| - property_: HoverDisableOptions = Field( |
82 |
| - default=HoverDisableOptions(), alias="property" |
83 |
| - ) |
84 |
| - statement_: HoverDisableOptions = Field( |
85 |
| - default=HoverDisableOptions(), alias="statement" |
| 63 | + keyword_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 64 | + module_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 65 | + class_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 66 | + instance_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 67 | + function_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 68 | + param_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 69 | + path_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 70 | + property_: HoverDisableOptions = field(default_factory=HoverDisableOptions) |
| 71 | + statement_: HoverDisableOptions = field( |
| 72 | + default_factory=HoverDisableOptions |
86 | 73 | )
|
87 | 74 |
|
88 | 75 |
|
89 |
| -class Hover(Model): |
| 76 | +@light_dataclass |
| 77 | +class Hover: |
90 | 78 | enable: bool = True
|
91 |
| - disable: HoverDisable = HoverDisable() |
| 79 | + disable: HoverDisable = field(default_factory=HoverDisable) |
92 | 80 |
|
93 | 81 |
|
94 |
| -class JediSettings(Model): |
95 |
| - auto_import_modules: List[str] = [] |
| 82 | +@light_dataclass |
| 83 | +class JediSettings: |
| 84 | + auto_import_modules: List[str] = field(default_factory=list) |
96 | 85 | case_insensitive_completion: bool = True
|
97 | 86 | debug: bool = False
|
98 | 87 |
|
99 | 88 |
|
100 |
| -class Symbols(Model): |
101 |
| - ignore_folders: List[str] = [".nox", ".tox", ".venv", "__pycache__"] |
| 89 | +@light_dataclass |
| 90 | +class Symbols: |
| 91 | + ignore_folders: List[str] = field( |
| 92 | + default_factory=lambda: [".nox", ".tox", ".venv", "__pycache__"] |
| 93 | + ) |
102 | 94 | max_symbols: int = 20
|
103 | 95 |
|
104 | 96 |
|
105 |
| -class Workspace(Model): |
| 97 | +@light_dataclass |
| 98 | +class Workspace: |
106 | 99 | environment_path: Optional[str] = None
|
107 |
| - extra_paths: List[str] = [] |
108 |
| - symbols: Symbols = Symbols() |
| 100 | + extra_paths: List[str] = field(default_factory=list) |
| 101 | + symbols: Symbols = field(default_factory=Symbols) |
109 | 102 |
|
110 | 103 |
|
111 |
| -class InitializationOptions(Model): |
112 |
| - code_action: CodeAction = CodeAction() |
113 |
| - completion: Completion = Completion() |
114 |
| - diagnostics: Diagnostics = Diagnostics() |
115 |
| - hover: Hover = Hover() |
116 |
| - jedi_settings: JediSettings = JediSettings() |
| 104 | +@light_dataclass |
| 105 | +class InitializationOptions: |
| 106 | + code_action: CodeAction = field(default_factory=CodeAction) |
| 107 | + completion: Completion = field(default_factory=Completion) |
| 108 | + diagnostics: Diagnostics = field(default_factory=Diagnostics) |
| 109 | + hover: Hover = field(default_factory=Hover) |
| 110 | + jedi_settings: JediSettings = field(default_factory=JediSettings) |
117 | 111 | markup_kind_preferred: Optional[MarkupKind] = None
|
118 |
| - workspace: Workspace = Workspace() |
| 112 | + workspace: Workspace = field(default_factory=Workspace) |
| 113 | + |
| 114 | + |
| 115 | +initialization_options_converter = Converter() |
| 116 | + |
| 117 | +WEIRD_NAMES = { |
| 118 | + "keyword_": "keyword", |
| 119 | + "module_": "module", |
| 120 | + "class_": "class", |
| 121 | + "instance_": "instance", |
| 122 | + "function_": "function", |
| 123 | + "param_": "param", |
| 124 | + "path_": "path", |
| 125 | + "property_": "property", |
| 126 | + "statement_ ": "statement", |
| 127 | +} |
| 128 | + |
| 129 | + |
| 130 | +def convert_class_keys(string: str) -> str: |
| 131 | + """Convert from snake_case to camelCase. |
| 132 | +
|
| 133 | + Also handles random special cases for keywords. |
| 134 | + """ |
| 135 | + if string in WEIRD_NAMES: |
| 136 | + return WEIRD_NAMES[string] |
| 137 | + return "".join( |
| 138 | + word.capitalize() if idx > 0 else word |
| 139 | + for idx, word in enumerate(string.split("_")) |
| 140 | + ) |
| 141 | + |
| 142 | + |
| 143 | +def structure(cls: type) -> Any: |
| 144 | + """Hook to convert names when marshalling initialization_options.""" |
| 145 | + return make_dict_structure_fn( |
| 146 | + cls, |
| 147 | + initialization_options_converter, |
| 148 | + **{ |
| 149 | + a.name: override(rename=convert_class_keys(a.name)) |
| 150 | + for a in fields(cls) |
| 151 | + } |
| 152 | + ) |
| 153 | + |
| 154 | + |
| 155 | +initialization_options_converter.register_structure_hook_factory( |
| 156 | + is_dataclass, structure |
| 157 | +) |
| 158 | + |
| 159 | + |
| 160 | +initialization_options_converter.register_structure_hook_factory( |
| 161 | + lambda x: x == Pattern[str], |
| 162 | + lambda _: lambda x, _: re.compile(x), |
| 163 | +) |
| 164 | + |
| 165 | +initialization_options_converter.register_unstructure_hook_factory( |
| 166 | + lambda x: x == Pattern[str], |
| 167 | + lambda _: lambda x: x.pattern, |
| 168 | +) |
0 commit comments