completion.py 2.9 KB

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