Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/prompt_toolkit/auto_suggest.py: 52%
58 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
1"""
2`Fish-style <http://fishshell.com/>`_ like auto-suggestion.
4While a user types input in a certain buffer, suggestions are generated
5(asynchronously.) Usually, they are displayed after the input. When the cursor
6presses the right arrow and the cursor is at the end of the input, the
7suggestion will be inserted.
9If you want the auto suggestions to be asynchronous (in a background thread),
10because they take too much time, and could potentially block the event loop,
11then wrap the :class:`.AutoSuggest` instance into a
12:class:`.ThreadedAutoSuggest`.
13"""
14from __future__ import annotations
16from abc import ABCMeta, abstractmethod
17from typing import TYPE_CHECKING, Callable
19from prompt_toolkit.eventloop import run_in_executor_with_context
21from .document import Document
22from .filters import Filter, to_filter
24if TYPE_CHECKING:
25 from .buffer import Buffer
27__all__ = [
28 "Suggestion",
29 "AutoSuggest",
30 "ThreadedAutoSuggest",
31 "DummyAutoSuggest",
32 "AutoSuggestFromHistory",
33 "ConditionalAutoSuggest",
34 "DynamicAutoSuggest",
35]
38class Suggestion:
39 """
40 Suggestion returned by an auto-suggest algorithm.
42 :param text: The suggestion text.
43 """
45 def __init__(self, text: str) -> None:
46 self.text = text
48 def __repr__(self) -> str:
49 return "Suggestion(%s)" % self.text
52class AutoSuggest(metaclass=ABCMeta):
53 """
54 Base class for auto suggestion implementations.
55 """
57 @abstractmethod
58 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None:
59 """
60 Return `None` or a :class:`.Suggestion` instance.
62 We receive both :class:`~prompt_toolkit.buffer.Buffer` and
63 :class:`~prompt_toolkit.document.Document`. The reason is that auto
64 suggestions are retrieved asynchronously. (Like completions.) The
65 buffer text could be changed in the meantime, but ``document`` contains
66 the buffer document like it was at the start of the auto suggestion
67 call. So, from here, don't access ``buffer.text``, but use
68 ``document.text`` instead.
70 :param buffer: The :class:`~prompt_toolkit.buffer.Buffer` instance.
71 :param document: The :class:`~prompt_toolkit.document.Document` instance.
72 """
74 async def get_suggestion_async(
75 self, buff: Buffer, document: Document
76 ) -> Suggestion | None:
77 """
78 Return a :class:`.Future` which is set when the suggestions are ready.
79 This function can be overloaded in order to provide an asynchronous
80 implementation.
81 """
82 return self.get_suggestion(buff, document)
85class ThreadedAutoSuggest(AutoSuggest):
86 """
87 Wrapper that runs auto suggestions in a thread.
88 (Use this to prevent the user interface from becoming unresponsive if the
89 generation of suggestions takes too much time.)
90 """
92 def __init__(self, auto_suggest: AutoSuggest) -> None:
93 self.auto_suggest = auto_suggest
95 def get_suggestion(self, buff: Buffer, document: Document) -> Suggestion | None:
96 return self.auto_suggest.get_suggestion(buff, document)
98 async def get_suggestion_async(
99 self, buff: Buffer, document: Document
100 ) -> Suggestion | None:
101 """
102 Run the `get_suggestion` function in a thread.
103 """
105 def run_get_suggestion_thread() -> Suggestion | None:
106 return self.get_suggestion(buff, document)
108 return await run_in_executor_with_context(run_get_suggestion_thread)
111class DummyAutoSuggest(AutoSuggest):
112 """
113 AutoSuggest class that doesn't return any suggestion.
114 """
116 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None:
117 return None # No suggestion
120class AutoSuggestFromHistory(AutoSuggest):
121 """
122 Give suggestions based on the lines in the history.
123 """
125 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None:
126 history = buffer.history
128 # Consider only the last line for the suggestion.
129 text = document.text.rsplit("\n", 1)[-1]
131 # Only create a suggestion when this is not an empty line.
132 if text.strip():
133 # Find first matching line in history.
134 for string in reversed(list(history.get_strings())):
135 for line in reversed(string.splitlines()):
136 if line.startswith(text):
137 return Suggestion(line[len(text) :])
139 return None
142class ConditionalAutoSuggest(AutoSuggest):
143 """
144 Auto suggest that can be turned on and of according to a certain condition.
145 """
147 def __init__(self, auto_suggest: AutoSuggest, filter: bool | Filter) -> None:
148 self.auto_suggest = auto_suggest
149 self.filter = to_filter(filter)
151 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None:
152 if self.filter():
153 return self.auto_suggest.get_suggestion(buffer, document)
155 return None
158class DynamicAutoSuggest(AutoSuggest):
159 """
160 Validator class that can dynamically returns any Validator.
162 :param get_validator: Callable that returns a :class:`.Validator` instance.
163 """
165 def __init__(self, get_auto_suggest: Callable[[], AutoSuggest | None]) -> None:
166 self.get_auto_suggest = get_auto_suggest
168 def get_suggestion(self, buff: Buffer, document: Document) -> Suggestion | None:
169 auto_suggest = self.get_auto_suggest() or DummyAutoSuggest()
170 return auto_suggest.get_suggestion(buff, document)
172 async def get_suggestion_async(
173 self, buff: Buffer, document: Document
174 ) -> Suggestion | None:
175 auto_suggest = self.get_auto_suggest() or DummyAutoSuggest()
176 return await auto_suggest.get_suggestion_async(buff, document)