Coverage for src/debputy/lsp/languages/lsp_debian_debputy_manifest.py: 79%
53 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-09-07 09:27 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-09-07 09:27 +0000
1from typing import (
2 Optional,
3 Any,
4 Tuple,
5 Union,
6 Sequence,
7 Container,
8)
10from debputy.linting.lint_util import LintState, DebputyMetadata
11from debputy.lsp.lsp_features import (
12 lint_diagnostics,
13 lsp_standard_handler,
14 lsp_hover,
15 lsp_completer,
16 SecondaryLanguage,
17 LanguageDispatchRule,
18)
19from debputy.lsp.lsp_generic_yaml import (
20 yaml_key_range,
21 generic_yaml_hover,
22 LSPYAMLHelper,
23 generic_yaml_lint,
24 generic_yaml_completer,
25 _is_empty_range,
26)
27from debputy.lsprotocol.types import (
28 TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL,
29 HoverParams,
30 Hover,
31 TEXT_DOCUMENT_CODE_ACTION,
32 CompletionParams,
33 CompletionList,
34 CompletionItem,
35)
36from debputy.plugin.api.impl_types import (
37 PluginProvidedParser,
38)
39from debputy.plugin.api.parser_tables import OPARSER_MANIFEST_ROOT
40from debputy.plugin.api.spec import DebputyIntegrationMode
41from debputy.plugins.debputy.private_api import Capability, load_libcap
43try:
44 from pygls.server import LanguageServer
45 from debputy.lsp.debputy_ls import DebputyLanguageServer
46except ImportError:
47 pass
50_DISPATCH_RULE = LanguageDispatchRule.new_rule(
51 "debian/debputy.manifest",
52 "debputy.manifest",
53 "debian/debputy.manifest",
54 [
55 SecondaryLanguage("debputy.manifest"),
56 # LSP's official language ID for YAML files
57 SecondaryLanguage("yaml", secondary_lookup="path-name"),
58 ],
59)
62lsp_standard_handler(_DISPATCH_RULE, TEXT_DOCUMENT_CODE_ACTION)
63lsp_standard_handler(_DISPATCH_RULE, TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL)
66class DebputyManifestLSPYAMLHelper(LSPYAMLHelper[DebputyMetadata]):
68 def _validate_subparser_is_valid_here(
69 self,
70 subparser: PluginProvidedParser,
71 orig_key: str,
72 line: int,
73 col: int,
74 ) -> None:
75 _integration_mode_allows_key(
76 self.lint_state,
77 self.custom_data.debputy_integration_mode,
78 subparser.parser.expected_debputy_integration_mode,
79 orig_key,
80 line,
81 col,
82 )
84 def _type_based_value_check(
85 self,
86 target_attr_type: type,
87 value: Any,
88 value_pos: Tuple[int, int],
89 *,
90 key: Optional[Union[str, int]] = None,
91 ) -> bool:
92 if issubclass(target_attr_type, Capability): 92 ↛ 93line 92 didn't jump to line 93 because the condition on line 92 was never true
93 has_libcap, _, is_valid_cap = load_libcap()
94 if has_libcap and not is_valid_cap(value):
95 line_no, cursor_pos = value_pos
96 cap_range = self._remaining_line(line_no, cursor_pos)
97 if _is_empty_range(cap_range):
98 # FIXME: We cannot report an empty range, but there is still a problem here.
99 return True
100 self.lint_state.emit_diagnostic(
101 cap_range,
102 "The value could not be parsed as a capability via cap_from_text on this system",
103 "warning",
104 "debputy",
105 )
106 return True
108 return super()._type_based_value_check(
109 target_attr_type,
110 value,
111 value_pos,
112 key=key,
113 )
116def _initialize_yaml_helper(lint_state: LintState) -> DebputyManifestLSPYAMLHelper:
117 return DebputyManifestLSPYAMLHelper(
118 lint_state,
119 lint_state.plugin_feature_set.manifest_parser_generator,
120 lint_state.debputy_metadata,
121 )
124@lint_diagnostics(_DISPATCH_RULE)
125async def _lint_debian_debputy_manifest(lint_state: LintState) -> None:
126 pg = lint_state.plugin_feature_set.manifest_parser_generator
127 root_parser = pg.dispatchable_object_parsers[OPARSER_MANIFEST_ROOT]
128 await generic_yaml_lint(
129 lint_state,
130 root_parser,
131 _initialize_yaml_helper,
132 )
135def _integration_mode_allows_key(
136 lint_state: LintState,
137 debputy_integration_mode: Optional[DebputyIntegrationMode],
138 expected_debputy_integration_modes: Optional[Container[DebputyIntegrationMode]],
139 key: str,
140 line: int,
141 col: int,
142) -> None:
143 if debputy_integration_mode is None or expected_debputy_integration_modes is None:
144 return
145 if debputy_integration_mode in expected_debputy_integration_modes:
146 return
147 key_range = yaml_key_range(key, line, col)
148 lint_state.emit_diagnostic(
149 key_range,
150 f'Feature "{key}" not supported in integration mode {debputy_integration_mode}',
151 "error",
152 "debputy",
153 )
156@lsp_completer(_DISPATCH_RULE)
157def debputy_manifest_completer(
158 ls: "DebputyLanguageServer",
159 params: CompletionParams,
160) -> Optional[Union[CompletionList, Sequence[CompletionItem]]]:
161 pg = ls.plugin_feature_set.manifest_parser_generator
162 root_parser = pg.dispatchable_object_parsers[OPARSER_MANIFEST_ROOT]
163 return generic_yaml_completer(
164 ls,
165 params,
166 root_parser,
167 )
170@lsp_hover(_DISPATCH_RULE)
171def debputy_manifest_hover(
172 ls: "DebputyLanguageServer",
173 params: HoverParams,
174) -> Optional[Hover]:
175 return generic_yaml_hover(
176 ls,
177 params,
178 lambda pg: pg.dispatchable_object_parsers[OPARSER_MANIFEST_ROOT],
179 show_integration_mode=True,
180 )