diff options
Diffstat (limited to 'src/prompt_toolkit/contrib/regular_languages')
6 files changed, 29 insertions, 22 deletions
diff --git a/src/prompt_toolkit/contrib/regular_languages/__init__.py b/src/prompt_toolkit/contrib/regular_languages/__init__.py index c947fd5..38b027c 100644 --- a/src/prompt_toolkit/contrib/regular_languages/__init__.py +++ b/src/prompt_toolkit/contrib/regular_languages/__init__.py @@ -72,6 +72,7 @@ TODO: some examples of: - How to create an autocompleter from this grammar. - How to create a parser from this grammar. """ + from __future__ import annotations from .compiler import compile diff --git a/src/prompt_toolkit/contrib/regular_languages/compiler.py b/src/prompt_toolkit/contrib/regular_languages/compiler.py index 474f6cf..dd558a6 100644 --- a/src/prompt_toolkit/contrib/regular_languages/compiler.py +++ b/src/prompt_toolkit/contrib/regular_languages/compiler.py @@ -38,6 +38,7 @@ Partial matches are possible:: m.variables().get('operator2') # Returns "add" """ + from __future__ import annotations import re @@ -96,13 +97,13 @@ class _CompiledGrammar: counter = [0] def create_group_func(node: Variable) -> str: - name = "n%s" % counter[0] + name = f"n{counter[0]}" self._group_names_to_nodes[name] = node.varname counter[0] += 1 return name # Compile regex strings. - self._re_pattern = "^%s$" % self._transform(root_node, create_group_func) + self._re_pattern = f"^{self._transform(root_node, create_group_func)}$" self._re_prefix_patterns = list( self._transform_prefix(root_node, create_group_func) ) @@ -153,7 +154,7 @@ class _CompiledGrammar: def transform(node: Node) -> str: # Turn `AnyNode` into an OR. if isinstance(node, AnyNode): - return "(?:%s)" % "|".join(transform(c) for c in node.children) + return "(?:{})".format("|".join(transform(c) for c in node.children)) # Concatenate a `NodeSequence` elif isinstance(node, NodeSequence): @@ -311,11 +312,11 @@ class _CompiledGrammar: yield "".join(result) elif isinstance(node, Regex): - yield "(?:%s)?" % node.regex + yield f"(?:{node.regex})?" elif isinstance(node, Lookahead): if node.negative: - yield "(?!%s)" % cls._transform(node.childnode, create_group_func) + yield f"(?!{cls._transform(node.childnode, create_group_func)})" else: # Not sure what the correct semantics are in this case. # (Probably it's not worth implementing this.) @@ -349,10 +350,10 @@ class _CompiledGrammar: ) else: - raise TypeError("Got %r" % node) + raise TypeError(f"Got {node!r}") for r in transform(root_node): - yield "^(?:%s)$" % r + yield f"^(?:{r})$" def match(self, string: str) -> Match | None: """ diff --git a/src/prompt_toolkit/contrib/regular_languages/completion.py b/src/prompt_toolkit/contrib/regular_languages/completion.py index 2e353e8..19ebaad 100644 --- a/src/prompt_toolkit/contrib/regular_languages/completion.py +++ b/src/prompt_toolkit/contrib/regular_languages/completion.py @@ -1,6 +1,7 @@ """ Completer for a regular grammar. """ + from __future__ import annotations from typing import Iterable @@ -37,12 +38,10 @@ class GrammarCompleter(Completer): m = self.compiled_grammar.match_prefix(document.text_before_cursor) if m: - completions = self._remove_duplicates( + yield from 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]: @@ -81,14 +80,21 @@ class GrammarCompleter(Completer): display_meta=completion.display_meta, ) - def _remove_duplicates(self, items: Iterable[Completion]) -> list[Completion]: + def _remove_duplicates(self, items: Iterable[Completion]) -> Iterable[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 + + def hash_completion(completion: Completion) -> tuple[str, int]: + return completion.text, completion.start_position + + yielded_so_far: set[tuple[str, int]] = set() + + for completion in items: + hash_value = hash_completion(completion) + + if hash_value not in yielded_so_far: + yielded_so_far.add(hash_value) + yield completion diff --git a/src/prompt_toolkit/contrib/regular_languages/lexer.py b/src/prompt_toolkit/contrib/regular_languages/lexer.py index b0a4deb..c5434cf 100644 --- a/src/prompt_toolkit/contrib/regular_languages/lexer.py +++ b/src/prompt_toolkit/contrib/regular_languages/lexer.py @@ -2,6 +2,7 @@ `GrammarLexer` is compatible with other lexers and can be used to highlight the input using a regular grammar with annotations. """ + from __future__ import annotations from typing import Callable diff --git a/src/prompt_toolkit/contrib/regular_languages/regex_parser.py b/src/prompt_toolkit/contrib/regular_languages/regex_parser.py index a365ba8..353e54f 100644 --- a/src/prompt_toolkit/contrib/regular_languages/regex_parser.py +++ b/src/prompt_toolkit/contrib/regular_languages/regex_parser.py @@ -14,6 +14,7 @@ Remarks: Limitations: - Lookahead is not supported. """ + from __future__ import annotations import re @@ -115,11 +116,7 @@ class Variable(Node): self.varname = varname def __repr__(self) -> str: - return "{}(childnode={!r}, varname={!r})".format( - self.__class__.__name__, - self.childnode, - self.varname, - ) + return f"{self.__class__.__name__}(childnode={self.childnode!r}, varname={self.varname!r})" class Repeat(Node): @@ -265,7 +262,7 @@ def parse_regex(regex_tokens: list[str]) -> Node: raise Exception(f"{t}-style repetition not yet supported") elif t.startswith("(?"): - raise Exception("%r not supported" % t) + raise Exception(f"{t!r} not supported") elif t.isspace(): pass diff --git a/src/prompt_toolkit/contrib/regular_languages/validation.py b/src/prompt_toolkit/contrib/regular_languages/validation.py index 8e56e05..e6cfd74 100644 --- a/src/prompt_toolkit/contrib/regular_languages/validation.py +++ b/src/prompt_toolkit/contrib/regular_languages/validation.py @@ -1,6 +1,7 @@ """ Validator for a regular language. """ + from __future__ import annotations from prompt_toolkit.document import Document |