Coverage for src/debputy/lsp/lsp_debian_tests_control.py: 70%

78 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2025-01-27 13:59 +0000

1import re 

2from typing import ( 

3 Union, 

4 Sequence, 

5 Tuple, 

6 Optional, 

7 List, 

8 Dict, 

9) 

10 

11from debputy.linting.lint_util import LintState 

12from debputy.lsp.debputy_ls import DebputyLanguageServer 

13from debputy.lsp.lsp_debian_control_reference_data import ( 

14 Deb822KnownField, 

15 DTestsCtrlFileMetadata, 

16 StanzaMetadata, 

17) 

18from debputy.lsp.lsp_features import ( 

19 lint_diagnostics, 

20 lsp_completer, 

21 lsp_hover, 

22 lsp_standard_handler, 

23 lsp_folding_ranges, 

24 lsp_semantic_tokens_full, 

25 lsp_will_save_wait_until, 

26 lsp_format_document, 

27 SecondaryLanguage, 

28 LanguageDispatchRule, 

29) 

30from debputy.lsp.lsp_generic_deb822 import ( 

31 deb822_completer, 

32 deb822_hover, 

33 deb822_folding_ranges, 

34 deb822_semantic_tokens_full, 

35 deb822_token_iter, 

36 deb822_format_file, 

37) 

38from debputy.lsp.quickfixes import ( 

39 propose_correct_text_quick_fix, 

40) 

41from debputy.lsp.vendoring._deb822_repro import ( 

42 Deb822FileElement, 

43 Deb822ParagraphElement, 

44) 

45from debputy.lsp.vendoring._deb822_repro.parsing import ( 

46 Deb822KeyValuePairElement, 

47) 

48from debputy.lsprotocol.types import ( 

49 Range, 

50 CompletionItem, 

51 CompletionList, 

52 CompletionParams, 

53 DiagnosticRelatedInformation, 

54 Location, 

55 HoverParams, 

56 Hover, 

57 TEXT_DOCUMENT_CODE_ACTION, 

58 SemanticTokens, 

59 SemanticTokensParams, 

60 FoldingRangeParams, 

61 FoldingRange, 

62 WillSaveTextDocumentParams, 

63 TextEdit, 

64 DocumentFormattingParams, 

65) 

66from debputy.util import detect_possible_typo 

67 

68try: 

69 from debputy.lsp.vendoring._deb822_repro.locatable import ( 

70 Position as TEPosition, 

71 Range as TERange, 

72 START_POSITION, 

73 ) 

74 

75 from pygls.server import LanguageServer 

76 from pygls.workspace import TextDocument 

77except ImportError: 

78 pass 

79 

80 

81_CONTAINS_SPACE_OR_COLON = re.compile(r"[\s:]") 

82_DISPATCH_RULE = LanguageDispatchRule.new_rule( 

83 "debian/tests/control", 

84 "debian/tests/control", 

85 [ 

86 # emacs's name - from elpa-dpkg-dev-el (>> 37.11) 

87 SecondaryLanguage("debian-autopkgtest-control-mode"), 

88 # Likely to be vim's name if it had support 

89 SecondaryLanguage("debtestscontrol"), 

90 ], 

91) 

92 

93_DTESTS_CTRL_FILE_METADATA = DTestsCtrlFileMetadata() 

94 

95lsp_standard_handler(_DISPATCH_RULE, TEXT_DOCUMENT_CODE_ACTION) 

96 

97 

98@lsp_hover(_DISPATCH_RULE) 

99def debian_tests_control_hover( 

100 ls: "DebputyLanguageServer", 

101 params: HoverParams, 

102) -> Optional[Hover]: 

103 return deb822_hover(ls, params, _DTESTS_CTRL_FILE_METADATA) 

104 

105 

106@lsp_completer(_DISPATCH_RULE) 

107def debian_tests_control_completions( 

108 ls: "DebputyLanguageServer", 

109 params: CompletionParams, 

110) -> Optional[Union[CompletionList, Sequence[CompletionItem]]]: 

111 return deb822_completer(ls, params, _DTESTS_CTRL_FILE_METADATA) 

112 

113 

114@lsp_folding_ranges(_DISPATCH_RULE) 

115def debian_tests_control_folding_ranges( 

116 ls: "DebputyLanguageServer", 

117 params: FoldingRangeParams, 

118) -> Optional[Sequence[FoldingRange]]: 

119 return deb822_folding_ranges(ls, params, _DTESTS_CTRL_FILE_METADATA) 

120 

121 

122def _scan_for_syntax_errors_and_token_level_diagnostics( 

123 deb822_file: Deb822FileElement, 

124 lint_state: LintState, 

125) -> int: 

126 first_error = len(lint_state.lines) + 1 

127 spell_checker = lint_state.spellchecker() 

128 for ( 

129 token, 

130 start_line, 

131 start_offset, 

132 end_line, 

133 end_offset, 

134 ) in deb822_token_iter(deb822_file.iter_tokens()): 

135 if token.is_error: 135 ↛ 136line 135 didn't jump to line 136 because the condition on line 135 was never true

136 first_error = min(first_error, start_line) 

137 start_pos = TEPosition( 

138 start_line, 

139 start_offset, 

140 ) 

141 end_pos = TEPosition( 

142 end_line, 

143 end_offset, 

144 ) 

145 token_range = TERange.between(start_pos, end_pos) 

146 lint_state.emit_diagnostic( 

147 token_range, 

148 "Syntax error", 

149 "error", 

150 "debputy", 

151 ) 

152 elif token.is_comment: 152 ↛ 153line 152 didn't jump to line 153 because the condition on line 152 was never true

153 for word, col_pos, end_col_pos in spell_checker.iter_words(token.text): 

154 corrections = spell_checker.provide_corrections_for(word) 

155 if not corrections: 

156 continue 

157 start_pos = TEPosition( 

158 start_line, 

159 col_pos, 

160 ) 

161 end_pos = TEPosition( 

162 start_line, 

163 end_col_pos, 

164 ) 

165 word_range = TERange.between(start_pos, end_pos) 

166 lint_state.emit_diagnostic( 

167 word_range, 

168 f'Spelling "{word}"', 

169 "spelling", 

170 "debputy", 

171 quickfixes=[propose_correct_text_quick_fix(c) for c in corrections], 

172 enable_non_interactive_auto_fix=False, 

173 ) 

174 return first_error 

175 

176 

177@lint_diagnostics(_DISPATCH_RULE) 

178def _lint_debian_tests_control(lint_state: LintState) -> None: 

179 doc_reference = lint_state.doc_uri 

180 deb822_file = lint_state.parsed_deb822_file_content 

181 

182 first_error = _scan_for_syntax_errors_and_token_level_diagnostics( 

183 deb822_file, 

184 lint_state, 

185 ) 

186 

187 paragraphs = list(deb822_file) 

188 

189 for paragraph_no, paragraph in enumerate(paragraphs, start=1): 

190 paragraph_pos = paragraph.position_in_file() 

191 if paragraph_pos.line_position >= first_error: 191 ↛ 192line 191 didn't jump to line 192 because the condition on line 191 was never true

192 break 

193 stanza_metadata = _DTESTS_CTRL_FILE_METADATA.classify_stanza( 

194 paragraph, 

195 paragraph_no, 

196 ) 

197 stanza_metadata.stanza_diagnostics( 

198 deb822_file, 

199 paragraph, 

200 paragraph_pos, 

201 doc_reference, 

202 lint_state, 

203 ) 

204 

205 

206@lsp_will_save_wait_until(_DISPATCH_RULE) 

207def _debian_tests_control_on_save_formatting( 

208 ls: "DebputyLanguageServer", 

209 params: WillSaveTextDocumentParams, 

210) -> Optional[Sequence[TextEdit]]: 

211 doc = ls.workspace.get_text_document(params.text_document.uri) 

212 lint_state = ls.lint_state(doc) 

213 return deb822_format_file(lint_state, _DTESTS_CTRL_FILE_METADATA) 

214 

215 

216def _reformat_debian_tests_control( 

217 lint_state: LintState, 

218) -> Optional[Sequence[TextEdit]]: 

219 return deb822_format_file(lint_state, _DTESTS_CTRL_FILE_METADATA) 

220 

221 

222@lsp_format_document(_DISPATCH_RULE) 

223def _debian_tests_control_on_save_formatting( 

224 ls: "DebputyLanguageServer", 

225 params: DocumentFormattingParams, 

226) -> Optional[Sequence[TextEdit]]: 

227 doc = ls.workspace.get_text_document(params.text_document.uri) 

228 lint_state = ls.lint_state(doc) 

229 return deb822_format_file(lint_state, _DTESTS_CTRL_FILE_METADATA) 

230 

231 

232@lsp_semantic_tokens_full(_DISPATCH_RULE) 

233def _debian_tests_control_semantic_tokens_full( 

234 ls: "DebputyLanguageServer", 

235 request: SemanticTokensParams, 

236) -> Optional[SemanticTokens]: 

237 return deb822_semantic_tokens_full( 

238 ls, 

239 request, 

240 _DTESTS_CTRL_FILE_METADATA, 

241 )