completion.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. """
  2. """
  3. from __future__ import unicode_literals
  4. from abc import ABCMeta, abstractmethod
  5. from six import with_metaclass
  6. __all__ = (
  7. 'Completion',
  8. 'Completer',
  9. 'CompleteEvent',
  10. 'get_common_complete_suffix',
  11. )
  12. class Completion(object):
  13. """
  14. :param text: The new string that will be inserted into the document.
  15. :param start_position: Position relative to the cursor_position where the
  16. new text will start. The text will be inserted between the
  17. start_position and the original cursor position.
  18. :param display: (optional string) If the completion has to be displayed
  19. differently in the completion menu.
  20. :param display_meta: (Optional string) Meta information about the
  21. completion, e.g. the path or source where it's coming from.
  22. :param get_display_meta: Lazy `display_meta`. Retrieve meta information
  23. only when meta is displayed.
  24. """
  25. def __init__(self, text, start_position=0, display=None, display_meta=None,
  26. get_display_meta=None):
  27. self.text = text
  28. self.start_position = start_position
  29. self._display_meta = display_meta
  30. self._get_display_meta = get_display_meta
  31. if display is None:
  32. self.display = text
  33. else:
  34. self.display = display
  35. assert self.start_position <= 0
  36. def __repr__(self):
  37. if self.display == self.text:
  38. return '%s(text=%r, start_position=%r)' % (
  39. self.__class__.__name__, self.text, self.start_position)
  40. else:
  41. return '%s(text=%r, start_position=%r, display=%r)' % (
  42. self.__class__.__name__, self.text, self.start_position,
  43. self.display)
  44. def __eq__(self, other):
  45. return (
  46. self.text == other.text and
  47. self.start_position == other.start_position and
  48. self.display == other.display and
  49. self.display_meta == other.display_meta)
  50. def __hash__(self):
  51. return hash((self.text, self.start_position, self.display, self.display_meta))
  52. @property
  53. def display_meta(self):
  54. # Return meta-text. (This is lazy when using "get_display_meta".)
  55. if self._display_meta is not None:
  56. return self._display_meta
  57. elif self._get_display_meta:
  58. self._display_meta = self._get_display_meta()
  59. return self._display_meta
  60. else:
  61. return ''
  62. def new_completion_from_position(self, position):
  63. """
  64. (Only for internal use!)
  65. Get a new completion by splitting this one. Used by
  66. `CommandLineInterface` when it needs to have a list of new completions
  67. after inserting the common prefix.
  68. """
  69. assert isinstance(position, int) and position - self.start_position >= 0
  70. return Completion(
  71. text=self.text[position - self.start_position:],
  72. display=self.display,
  73. display_meta=self._display_meta,
  74. get_display_meta=self._get_display_meta)
  75. class CompleteEvent(object):
  76. """
  77. Event that called the completer.
  78. :param text_inserted: When True, it means that completions are requested
  79. because of a text insert. (`Buffer.complete_while_typing`.)
  80. :param completion_requested: When True, it means that the user explicitely
  81. pressed the `Tab` key in order to view the completions.
  82. These two flags can be used for instance to implemented a completer that
  83. shows some completions when ``Tab`` has been pressed, but not
  84. automatically when the user presses a space. (Because of
  85. `complete_while_typing`.)
  86. """
  87. def __init__(self, text_inserted=False, completion_requested=False):
  88. assert not (text_inserted and completion_requested)
  89. #: Automatic completion while typing.
  90. self.text_inserted = text_inserted
  91. #: Used explicitely requested completion by pressing 'tab'.
  92. self.completion_requested = completion_requested
  93. def __repr__(self):
  94. return '%s(text_inserted=%r, completion_requested=%r)' % (
  95. self.__class__.__name__, self.text_inserted, self.completion_requested)
  96. class Completer(with_metaclass(ABCMeta, object)):
  97. """
  98. Base class for completer implementations.
  99. """
  100. @abstractmethod
  101. def get_completions(self, document, complete_event):
  102. """
  103. Yield :class:`.Completion` instances.
  104. :param document: :class:`~prompt_toolkit.document.Document` instance.
  105. :param complete_event: :class:`.CompleteEvent` instance.
  106. """
  107. while False:
  108. yield
  109. def get_common_complete_suffix(document, completions):
  110. """
  111. Return the common prefix for all completions.
  112. """
  113. # Take only completions that don't change the text before the cursor.
  114. def doesnt_change_before_cursor(completion):
  115. end = completion.text[:-completion.start_position]
  116. return document.text_before_cursor.endswith(end)
  117. completions2 = [c for c in completions if doesnt_change_before_cursor(c)]
  118. # When there is at least one completion that changes the text before the
  119. # cursor, don't return any common part.
  120. if len(completions2) != len(completions):
  121. return ''
  122. # Return the common prefix.
  123. def get_suffix(completion):
  124. return completion.text[-completion.start_position:]
  125. return _commonprefix([get_suffix(c) for c in completions2])
  126. def _commonprefix(strings):
  127. # Similar to os.path.commonprefix
  128. if not strings:
  129. return ''
  130. else:
  131. s1 = min(strings)
  132. s2 = max(strings)
  133. for i, c in enumerate(s1):
  134. if c != s2[i]:
  135. return s1[:i]
  136. return s1