Coverage for src/debputy/lsp/languages/lsp_debian_copyright.py: 82%

70 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-09-07 09:27 +0000

1import re 

2from typing import ( 

3 Union, 

4 Sequence, 

5 Optional, 

6 List, 

7) 

8 

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 debputy.lsp.vendoring._deb822_repro import ( 

36 Deb822FileElement, 

37 Deb822ParagraphElement, 

38) 

39from debputy.lsprotocol.types import ( 

40 CompletionItem, 

41 CompletionList, 

42 CompletionParams, 

43 HoverParams, 

44 Hover, 

45 TEXT_DOCUMENT_CODE_ACTION, 

46 SemanticTokens, 

47 SemanticTokensParams, 

48 FoldingRangeParams, 

49 FoldingRange, 

50 WillSaveTextDocumentParams, 

51 TextEdit, 

52 DocumentFormattingParams, 

53) 

54 

55try: 

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

57 Position as TEPosition, 

58 Range as TERange, 

59 ) 

60 

61 from pygls.server import LanguageServer 

62 from pygls.workspace import TextDocument 

63except ImportError: 

64 pass 

65 

66 

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

68 

69_DISPATCH_RULE = LanguageDispatchRule.new_rule( 

70 "debian/copyright", 

71 None, 

72 "debian/copyright", 

73 [ 

74 # emacs's name 

75 SecondaryLanguage("debian-copyright"), 

76 # vim's name 

77 SecondaryLanguage("debcopyright"), 

78 ], 

79) 

80 

81_DEP5_FILE_METADATA = Dep5FileMetadata() 

82 

83lsp_standard_handler(_DISPATCH_RULE, TEXT_DOCUMENT_CODE_ACTION) 

84 

85 

86@lsp_hover(_DISPATCH_RULE) 

87def _debian_copyright_hover( 

88 ls: "DebputyLanguageServer", 

89 params: HoverParams, 

90) -> Optional[Hover]: 

91 return deb822_hover(ls, params, _DEP5_FILE_METADATA) 

92 

93 

94@lsp_completer(_DISPATCH_RULE) 

95def _debian_copyright_completions( 

96 ls: "DebputyLanguageServer", 

97 params: CompletionParams, 

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

99 return deb822_completer(ls, params, _DEP5_FILE_METADATA) 

100 

101 

102@lsp_folding_ranges(_DISPATCH_RULE) 

103def _debian_copyright_folding_ranges( 

104 ls: "DebputyLanguageServer", 

105 params: FoldingRangeParams, 

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

107 return deb822_folding_ranges(ls, params, _DEP5_FILE_METADATA) 

108 

109 

110@lint_diagnostics(_DISPATCH_RULE) 

111async def _lint_debian_copyright(lint_state: LintState) -> None: 

112 deb822_file = lint_state.parsed_deb822_file_content 

113 

114 if not _DEP5_FILE_METADATA.file_metadata_applies_to_file(deb822_file): 

115 return 

116 

117 first_error = await scan_for_syntax_errors_and_token_level_diagnostics( 

118 deb822_file, 

119 lint_state, 

120 ) 

121 header_stanza, files_stanza, _ = _DEP5_FILE_METADATA.stanza_types() 

122 stanza_no = 0 

123 

124 async for stanza_range, stanza in lint_state.slow_iter( 

125 with_range_in_continuous_parts(deb822_file.iter_parts()) 

126 ): 

127 if not isinstance(stanza, Deb822ParagraphElement): 

128 continue 

129 stanza_position = stanza_range.start_pos 

130 if stanza_position.line_position >= first_error: 130 ↛ 131line 130 didn't jump to line 131 because the condition on line 130 was never true

131 break 

132 stanza_no += 1 

133 is_files_or_license_stanza = stanza_no != 1 

134 if is_files_or_license_stanza: 

135 stanza_metadata = _DEP5_FILE_METADATA.classify_stanza( 

136 stanza, 

137 stanza_no, 

138 ) 

139 other_stanza_metadata = header_stanza 

140 other_stanza_name = "Header" 

141 elif "Format" in stanza: 141 ↛ 146line 141 didn't jump to line 146 because the condition on line 141 was always true

142 stanza_metadata = header_stanza 

143 other_stanza_metadata = files_stanza 

144 other_stanza_name = "Files/License" 

145 else: 

146 break 

147 

148 await stanza_metadata.stanza_diagnostics( 

149 deb822_file, 

150 stanza, 

151 stanza_position, 

152 lint_state, 

153 confusable_with_stanza_name=other_stanza_name, 

154 confusable_with_stanza_metadata=other_stanza_metadata, 

155 ) 

156 

157 

158@lsp_will_save_wait_until(_DISPATCH_RULE) 

159def _debian_copyright_on_save_formatting( 

160 ls: "DebputyLanguageServer", 

161 params: WillSaveTextDocumentParams, 

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

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

164 lint_state = ls.lint_state(doc) 

165 return deb822_format_file(lint_state, _DEP5_FILE_METADATA) 

166 

167 

168@lsp_cli_reformat_document(_DISPATCH_RULE) 

169def _reformat_debian_copyright( 

170 lint_state: LintState, 

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

172 return deb822_format_file(lint_state, _DEP5_FILE_METADATA) 

173 

174 

175@lsp_format_document(_DISPATCH_RULE) 

176def _debian_copyright_format_document( 

177 ls: "DebputyLanguageServer", 

178 params: DocumentFormattingParams, 

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

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

181 lint_state = ls.lint_state(doc) 

182 return deb822_format_file(lint_state, _DEP5_FILE_METADATA) 

183 

184 

185@lsp_semantic_tokens_full(_DISPATCH_RULE) 

186async def _debian_copyright_semantic_tokens_full( 

187 ls: "DebputyLanguageServer", 

188 request: SemanticTokensParams, 

189) -> Optional[SemanticTokens]: 

190 return await deb822_semantic_tokens_full( 

191 ls, 

192 request, 

193 _DEP5_FILE_METADATA, 

194 )