Coverage for src/debputy/lsp/text_util.py: 67%
59 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-07 12:14 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-07 12:14 +0200
1from typing import List, Optional, Sequence, Union, Iterable
3from lsprotocol.types import (
4 TextEdit,
5 Position,
6 Range,
7 WillSaveTextDocumentParams,
8)
10from debputy.linting.lint_util import LinterPositionCodec
12try:
13 from debian._deb822_repro.locatable import Position as TEPosition, Range as TERange
14except ImportError:
15 pass
17try:
18 from pygls.workspace import LanguageServer, TextDocument, PositionCodec
20 LintCapablePositionCodec = Union[LinterPositionCodec, PositionCodec]
21except ImportError:
22 LintCapablePositionCodec = LinterPositionCodec
25try:
26 from Levenshtein import distance
27except ImportError:
29 def detect_possible_typo(
30 provided_value: str,
31 known_values: Iterable[str],
32 ) -> Sequence[str]:
33 return tuple()
35else:
37 def detect_possible_typo(
38 provided_value: str,
39 known_values: Iterable[str],
40 ) -> Sequence[str]:
41 k_len = len(provided_value)
42 candidates = []
43 for known_value in known_values:
44 if abs(k_len - len(known_value)) > 2:
45 continue
46 d = distance(provided_value, known_value)
47 if d > 2:
48 continue
49 candidates.append(known_value)
50 return candidates
53def normalize_dctrl_field_name(f: str) -> str:
54 if not f or not f.startswith(("x", "X")):
55 return f
56 i = 0
57 for i in range(1, len(f)): 57 ↛ 63line 57 didn't jump to line 63, because the loop on line 57 didn't complete
58 if f[i] == "-":
59 i += 1
60 break
61 if f[i] not in ("b", "B", "s", "S", "c", "C"): 61 ↛ 62line 61 didn't jump to line 62, because the condition on line 61 was never true
62 return f
63 assert i > 0
64 return f[i:]
67def on_save_trim_end_of_line_whitespace(
68 ls: "LanguageServer",
69 params: WillSaveTextDocumentParams,
70) -> Optional[Sequence[TextEdit]]:
71 doc = ls.workspace.get_text_document(params.text_document.uri)
72 return trim_end_of_line_whitespace(doc, doc.lines)
75def trim_end_of_line_whitespace(
76 doc: "TextDocument",
77 lines: List[str],
78) -> Optional[Sequence[TextEdit]]:
79 edits = []
80 for line_no, orig_line in enumerate(lines):
81 orig_len = len(orig_line)
82 if orig_line.endswith("\n"):
83 orig_len -= 1
84 stripped_len = len(orig_line.rstrip())
85 if stripped_len == orig_len:
86 continue
88 edit_range = doc.position_codec.range_to_client_units(
89 lines,
90 Range(
91 Position(
92 line_no,
93 stripped_len,
94 ),
95 Position(
96 line_no,
97 orig_len,
98 ),
99 ),
100 )
101 edits.append(
102 TextEdit(
103 edit_range,
104 "",
105 )
106 )
108 return edits
111def te_position_to_lsp(te_position: "TEPosition") -> Position:
112 return Position(
113 te_position.line_position,
114 te_position.cursor_position,
115 )
118def te_range_to_lsp(te_range: "TERange") -> Range:
119 return Range(
120 te_position_to_lsp(te_range.start_pos),
121 te_position_to_lsp(te_range.end_pos),
122 )