Coverage for src/debputy/lsp/lsp_reference_keyword.py: 95%

49 statements  

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

1import dataclasses 

2import textwrap 

3from typing import ( 

4 Optional, 

5 Union, 

6 Mapping, 

7 Sequence, 

8 Callable, 

9 Iterable, 

10 Any, 

11 Self, 

12 TYPE_CHECKING, 

13) 

14 

15from debputy.lsp.ref_models.deb822_reference_parse_models import UsageHint 

16from debputy.lsp.vendoring._deb822_repro import Deb822ParagraphElement 

17 

18if TYPE_CHECKING: 

19 from debputy.linting.lint_util import LintState 

20 from debputy.lsp.debputy_ls import DebputyLanguageServer 

21 

22LSP_DATA_DOMAIN = "debputy-lsp-data" 

23 

24 

25def format_comp_item_synopsis_doc( 

26 usage_hint: Optional[UsageHint], 

27 synopsis_doc: Optional[str], 

28 is_deprecated: bool, 

29) -> str: 

30 if is_deprecated: 

31 return ( 

32 f"[OBSOLETE]: {synopsis_doc}" 

33 if synopsis_doc is not None and not synopsis_doc.isspace() 

34 else f"[OBSOLETE]" 

35 ) 

36 if usage_hint is not None: 

37 return ( 

38 f"[{usage_hint.upper()}]: {synopsis_doc}" 

39 if synopsis_doc is not None and not synopsis_doc.isspace() 

40 else f"[{usage_hint.upper()}]" 

41 ) 

42 return synopsis_doc 

43 

44 

45@dataclasses.dataclass(slots=True, frozen=True) 

46class Keyword: 

47 value: str 

48 synopsis: Optional[str] = None 

49 long_description: Optional[str] = None 

50 translation_context: str = "" 

51 is_obsolete: bool = False 

52 replaced_by: Optional[str] = None 

53 is_exclusive: bool = False 

54 sort_text: Optional[ 

55 Union[ 

56 str, 

57 Callable[ 

58 ["Keyword", "LintState", Sequence[Deb822ParagraphElement], str], str 

59 ], 

60 ] 

61 ] = None 

62 usage_hint: Optional[UsageHint] = None 

63 can_complete_keyword_in_stanza: Optional[ 

64 Callable[[Iterable[Deb822ParagraphElement]], bool] 

65 ] = None 

66 """For keywords in fields that allow multiple keywords, the `is_exclusive` can be 

67 used for keywords that cannot be used with other keywords. As an example, the `all` 

68 value in `Architecture` of `debian/control` cannot be used with any other architecture. 

69 """ 

70 

71 @property 

72 def is_deprecated(self) -> bool: 

73 return self.is_obsolete or self.replaced_by is not None 

74 

75 def resolve_sort_text( 

76 self, 

77 lint_state: "LintState", 

78 stanza_parts: Sequence[Deb822ParagraphElement], 

79 value_being_completed: str, 

80 ) -> Optional[str]: 

81 sort_text = self.sort_text 

82 if sort_text is None: 

83 return None 

84 if not isinstance(sort_text, str): 84 ↛ 91line 84 didn't jump to line 91 because the condition on line 84 was always true

85 return sort_text( 

86 self, 

87 lint_state, 

88 stanza_parts, 

89 value_being_completed, 

90 ) 

91 return sort_text 

92 

93 def is_keyword_valid_completion_in_stanza( 

94 self, 

95 stanza_parts: Sequence[Deb822ParagraphElement], 

96 ) -> bool: 

97 return ( 

98 self.can_complete_keyword_in_stanza is None 

99 or self.can_complete_keyword_in_stanza(stanza_parts) 

100 ) 

101 

102 def replace(self, **changes: Any) -> "Self": 

103 return dataclasses.replace(self, **changes) 

104 

105 def synopsis_translated( 

106 self, translation_provider: Union["DebputyLanguageServer", "LintState"] 

107 ) -> str: 

108 return translation_provider.translation(LSP_DATA_DOMAIN).pgettext( 

109 self.translation_context, 

110 self.synopsis, 

111 ) 

112 

113 def long_description_translated( 

114 self, translation_provider: Union["DebputyLanguageServer", "LintState"] 

115 ) -> str: 

116 return translation_provider.translation(LSP_DATA_DOMAIN).pgettext( 

117 self.translation_context, 

118 self.long_description, 

119 ) 

120 

121 

122def allowed_values(*values: Union[str, Keyword]) -> Mapping[str, Keyword]: 

123 as_keywords = [k if isinstance(k, Keyword) else Keyword(k) for k in values] 

124 as_mapping = {k.value: k for k in as_keywords if k.value} 

125 # Simple bug check 

126 assert len(as_keywords) == len(as_mapping) 

127 return as_mapping 

128 

129 

130# This is the set of styles that `debputy` explicitly supports, which is more narrow than 

131# the ones in the config file. 

132ALL_PUBLIC_NAMED_STYLES = allowed_values( 

133 Keyword( 

134 "black", 

135 long_description=textwrap.dedent( 

136 """\ 

137 Uncompromising file formatting of Debian packaging files 

138 

139 By using it, you agree to cede control over minutiae of hand-formatting. In 

140 return, the formatter gives you speed, determinism, and freedom from style 

141 discussions about formatting. 

142 

143 The `black` style is inspired by the `black` Python code formatter. Like with 

144 `black`, the style will evolve over time. 

145 """ 

146 ), 

147 ), 

148)