Coverage for src/debputy/lsp/languages/lsp_debian_copyright.py: 82%
71 statements
« prev ^ index » next coverage.py v7.8.2, created at 2026-02-28 21:56 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2026-02-28 21:56 +0000
1import re
2from typing import (
3 Union,
4 Optional,
5 List,
6)
7from collections.abc import Sequence
9from debputy.linting.lint_util import LintState, with_range_in_continuous_parts
10from debputy.lsp.debputy_ls import DebputyLanguageServer
11from debputy.lsp.lsp_debian_control_reference_data import (
12 Dep5FileMetadata,
13)
14from debputy.lsp.lsp_features import (
15 lint_diagnostics,
16 lsp_completer,
17 lsp_hover,
18 lsp_standard_handler,
19 lsp_folding_ranges,
20 lsp_semantic_tokens_full,
21 lsp_will_save_wait_until,
22 lsp_format_document,
23 SecondaryLanguage,
24 LanguageDispatchRule,
25 lsp_cli_reformat_document,
26)
27from debputy.lsp.lsp_generic_deb822 import (
28 deb822_completer,
29 deb822_hover,
30 deb822_folding_ranges,
31 deb822_semantic_tokens_full,
32 deb822_format_file,
33 scan_for_syntax_errors_and_token_level_diagnostics,
34)
35from debian._deb822_repro import (
36 Deb822ParagraphElement,
37)
38from debputy.lsprotocol.types import (
39 CompletionItem,
40 CompletionList,
41 CompletionParams,
42 HoverParams,
43 Hover,
44 TEXT_DOCUMENT_CODE_ACTION,
45 SemanticTokens,
46 SemanticTokensParams,
47 FoldingRangeParams,
48 FoldingRange,
49 WillSaveTextDocumentParams,
50 TextEdit,
51 DocumentFormattingParams,
52)
54try:
55 from debian._deb822_repro.locatable import (
56 Position as TEPosition,
57 Range as TERange,
58 )
60 from pygls.server import LanguageServer
61 from pygls.workspace import TextDocument
62except ImportError:
63 pass
66_CONTAINS_SPACE_OR_COLON = re.compile(r"[\s:]")
68_DISPATCH_RULE = LanguageDispatchRule.new_rule(
69 "debian/copyright",
70 None,
71 "debian/copyright",
72 [
73 # emacs's name
74 SecondaryLanguage("debian-copyright"),
75 # vim's name
76 SecondaryLanguage("debcopyright"),
77 ],
78)
80_DEP5_FILE_METADATA = Dep5FileMetadata()
82lsp_standard_handler(_DISPATCH_RULE, TEXT_DOCUMENT_CODE_ACTION)
85@lsp_hover(_DISPATCH_RULE)
86def _debian_copyright_hover(
87 ls: "DebputyLanguageServer",
88 params: HoverParams,
89) -> Hover | None:
90 return deb822_hover(ls, params, _DEP5_FILE_METADATA)
93@lsp_completer(_DISPATCH_RULE)
94def _debian_copyright_completions(
95 ls: "DebputyLanguageServer",
96 params: CompletionParams,
97) -> CompletionList | Sequence[CompletionItem] | None:
98 return deb822_completer(ls, params, _DEP5_FILE_METADATA)
101@lsp_folding_ranges(_DISPATCH_RULE)
102def _debian_copyright_folding_ranges(
103 ls: "DebputyLanguageServer",
104 params: FoldingRangeParams,
105) -> Sequence[FoldingRange] | None:
106 return deb822_folding_ranges(ls, params, _DEP5_FILE_METADATA)
109@lint_diagnostics(_DISPATCH_RULE)
110async def _lint_debian_copyright(lint_state: LintState) -> None:
111 deb822_file = lint_state.parsed_deb822_file_content
113 if not _DEP5_FILE_METADATA.file_metadata_applies_to_file(deb822_file):
114 return
116 first_error = await scan_for_syntax_errors_and_token_level_diagnostics(
117 deb822_file,
118 lint_state,
119 )
120 header_stanza, files_stanza, _ = _DEP5_FILE_METADATA.stanza_types()
121 stanza_no = 0
123 async for stanza_range, stanza in lint_state.slow_iter(
124 with_range_in_continuous_parts(deb822_file.iter_parts())
125 ):
126 if not isinstance(stanza, Deb822ParagraphElement):
127 continue
128 stanza_position = stanza_range.start_pos
129 if stanza_position.line_position >= first_error: 129 ↛ 130line 129 didn't jump to line 130 because the condition on line 129 was never true
130 break
131 stanza_no += 1
132 is_files_or_license_stanza = stanza_no != 1
133 if is_files_or_license_stanza:
134 stanza_metadata = _DEP5_FILE_METADATA.classify_stanza(
135 stanza,
136 stanza_no,
137 )
138 other_stanza_metadata = header_stanza
139 other_stanza_name = "Header"
140 elif "Format" in stanza: 140 ↛ 145line 140 didn't jump to line 145 because the condition on line 140 was always true
141 stanza_metadata = header_stanza
142 other_stanza_metadata = files_stanza
143 other_stanza_name = "Files/License"
144 else:
145 break
147 await stanza_metadata.stanza_diagnostics(
148 deb822_file,
149 stanza,
150 stanza_position,
151 lint_state,
152 confusable_with_stanza_name=other_stanza_name,
153 confusable_with_stanza_metadata=other_stanza_metadata,
154 )
157@lsp_will_save_wait_until(_DISPATCH_RULE)
158def _debian_copyright_on_save_formatting(
159 ls: "DebputyLanguageServer",
160 params: WillSaveTextDocumentParams,
161) -> Sequence[TextEdit] | None:
162 doc = ls.workspace.get_text_document(params.text_document.uri)
163 lint_state = ls.lint_state(doc)
164 return deb822_format_file(lint_state, _DEP5_FILE_METADATA)
167@lsp_cli_reformat_document(_DISPATCH_RULE)
168def _reformat_debian_copyright(
169 lint_state: LintState,
170) -> Sequence[TextEdit] | None:
171 return deb822_format_file(lint_state, _DEP5_FILE_METADATA)
174@lsp_format_document(_DISPATCH_RULE)
175def _debian_copyright_format_document(
176 ls: "DebputyLanguageServer",
177 params: DocumentFormattingParams,
178) -> Sequence[TextEdit] | None:
179 doc = ls.workspace.get_text_document(params.text_document.uri)
180 lint_state = ls.lint_state(doc)
181 return deb822_format_file(lint_state, _DEP5_FILE_METADATA)
184@lsp_semantic_tokens_full(_DISPATCH_RULE)
185async def _debian_copyright_semantic_tokens_full(
186 ls: "DebputyLanguageServer",
187 request: SemanticTokensParams,
188) -> SemanticTokens | None:
189 return await deb822_semantic_tokens_full(
190 ls,
191 request,
192 _DEP5_FILE_METADATA,
193 )