1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
"""
Completer for a regular grammar.
"""
from typing import Dict, Iterable, List
from prompt_toolkit.completion import CompleteEvent, Completer, Completion
from prompt_toolkit.document import Document
from .compiler import Match, _CompiledGrammar
__all__ = [
"GrammarCompleter",
]
class GrammarCompleter(Completer):
"""
Completer which can be used for autocompletion according to variables in
the grammar. Each variable can have a different autocompleter.
:param compiled_grammar: `GrammarCompleter` instance.
:param completers: `dict` mapping variable names of the grammar to the
`Completer` instances to be used for each variable.
"""
def __init__(
self, compiled_grammar: _CompiledGrammar, completers: Dict[str, Completer]
) -> None:
self.compiled_grammar = compiled_grammar
self.completers = completers
def get_completions(
self, document: Document, complete_event: CompleteEvent
) -> Iterable[Completion]:
m = self.compiled_grammar.match_prefix(document.text_before_cursor)
if m:
completions = self._remove_duplicates(
self._get_completions_for_match(m, complete_event)
)
yield from completions
def _get_completions_for_match(
self, match: Match, complete_event: CompleteEvent
) -> Iterable[Completion]:
"""
Yield all the possible completions for this input string.
(The completer assumes that the cursor position was at the end of the
input string.)
"""
for match_variable in match.end_nodes():
varname = match_variable.varname
start = match_variable.start
completer = self.completers.get(varname)
if completer:
text = match_variable.value
# Unwrap text.
unwrapped_text = self.compiled_grammar.unescape(varname, text)
# Create a document, for the completions API (text/cursor_position)
document = Document(unwrapped_text, len(unwrapped_text))
# Call completer
for completion in completer.get_completions(document, complete_event):
new_text = (
unwrapped_text[: len(text) + completion.start_position]
+ completion.text
)
# Wrap again.
yield Completion(
text=self.compiled_grammar.escape(varname, new_text),
start_position=start - len(match.string),
display=completion.display,
display_meta=completion.display_meta,
)
def _remove_duplicates(self, items: Iterable[Completion]) -> List[Completion]:
"""
Remove duplicates, while keeping the order.
(Sometimes we have duplicates, because the there several matches of the
same grammar, each yielding similar completions.)
"""
result: List[Completion] = []
for i in items:
if i not in result:
result.append(i)
return result
|