Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/prompt_toolkit/auto_suggest.py: 53%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

60 statements  

1""" 

2`Fish-style <http://fishshell.com/>`_ like auto-suggestion. 

3 

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. 

8 

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""" 

14 

15from __future__ import annotations 

16 

17from abc import ABCMeta, abstractmethod 

18from collections.abc import Callable 

19from typing import TYPE_CHECKING 

20 

21from prompt_toolkit.eventloop import run_in_executor_with_context 

22 

23from .document import Document 

24from .filters import Filter, to_filter 

25 

26if TYPE_CHECKING: 

27 from .buffer import Buffer 

28 

29__all__ = [ 

30 "Suggestion", 

31 "AutoSuggest", 

32 "ThreadedAutoSuggest", 

33 "DummyAutoSuggest", 

34 "AutoSuggestFromHistory", 

35 "ConditionalAutoSuggest", 

36 "DynamicAutoSuggest", 

37] 

38 

39 

40class Suggestion: 

41 """ 

42 Suggestion returned by an auto-suggest algorithm. 

43 

44 :param text: The suggestion text. 

45 """ 

46 

47 def __init__(self, text: str) -> None: 

48 self.text = text 

49 

50 def __repr__(self) -> str: 

51 return f"Suggestion({self.text})" 

52 

53 

54class AutoSuggest(metaclass=ABCMeta): 

55 """ 

56 Base class for auto suggestion implementations. 

57 """ 

58 

59 @abstractmethod 

60 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None: 

61 """ 

62 Return `None` or a :class:`.Suggestion` instance. 

63 

64 We receive both :class:`~prompt_toolkit.buffer.Buffer` and 

65 :class:`~prompt_toolkit.document.Document`. The reason is that auto 

66 suggestions are retrieved asynchronously. (Like completions.) The 

67 buffer text could be changed in the meantime, but ``document`` contains 

68 the buffer document like it was at the start of the auto suggestion 

69 call. So, from here, don't access ``buffer.text``, but use 

70 ``document.text`` instead. 

71 

72 :param buffer: The :class:`~prompt_toolkit.buffer.Buffer` instance. 

73 :param document: The :class:`~prompt_toolkit.document.Document` instance. 

74 """ 

75 

76 async def get_suggestion_async( 

77 self, buff: Buffer, document: Document 

78 ) -> Suggestion | None: 

79 """ 

80 Return a :class:`.Future` which is set when the suggestions are ready. 

81 This function can be overloaded in order to provide an asynchronous 

82 implementation. 

83 """ 

84 return self.get_suggestion(buff, document) 

85 

86 

87class ThreadedAutoSuggest(AutoSuggest): 

88 """ 

89 Wrapper that runs auto suggestions in a thread. 

90 (Use this to prevent the user interface from becoming unresponsive if the 

91 generation of suggestions takes too much time.) 

92 """ 

93 

94 def __init__(self, auto_suggest: AutoSuggest) -> None: 

95 self.auto_suggest = auto_suggest 

96 

97 def get_suggestion(self, buff: Buffer, document: Document) -> Suggestion | None: 

98 return self.auto_suggest.get_suggestion(buff, document) 

99 

100 async def get_suggestion_async( 

101 self, buff: Buffer, document: Document 

102 ) -> Suggestion | None: 

103 """ 

104 Run the `get_suggestion` function in a thread. 

105 """ 

106 

107 def run_get_suggestion_thread() -> Suggestion | None: 

108 return self.get_suggestion(buff, document) 

109 

110 return await run_in_executor_with_context(run_get_suggestion_thread) 

111 

112 

113class DummyAutoSuggest(AutoSuggest): 

114 """ 

115 AutoSuggest class that doesn't return any suggestion. 

116 """ 

117 

118 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None: 

119 return None # No suggestion 

120 

121 

122class AutoSuggestFromHistory(AutoSuggest): 

123 """ 

124 Give suggestions based on the lines in the history. 

125 """ 

126 

127 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None: 

128 history = buffer.history 

129 

130 # Consider only the last line for the suggestion. 

131 text = document.text.rsplit("\n", 1)[-1] 

132 

133 # Only create a suggestion when this is not an empty line. 

134 if text.strip(): 

135 # Find first matching line in history. 

136 for string in reversed(list(history.get_strings())): 

137 for line in reversed(string.splitlines()): 

138 if line.startswith(text): 

139 return Suggestion(line[len(text) :]) 

140 

141 return None 

142 

143 

144class ConditionalAutoSuggest(AutoSuggest): 

145 """ 

146 Auto suggest that can be turned on and of according to a certain condition. 

147 """ 

148 

149 def __init__(self, auto_suggest: AutoSuggest, filter: bool | Filter) -> None: 

150 self.auto_suggest = auto_suggest 

151 self.filter = to_filter(filter) 

152 

153 def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None: 

154 if self.filter(): 

155 return self.auto_suggest.get_suggestion(buffer, document) 

156 

157 return None 

158 

159 

160class DynamicAutoSuggest(AutoSuggest): 

161 """ 

162 Validator class that can dynamically returns any Validator. 

163 

164 :param get_validator: Callable that returns a :class:`.Validator` instance. 

165 """ 

166 

167 def __init__(self, get_auto_suggest: Callable[[], AutoSuggest | None]) -> None: 

168 self.get_auto_suggest = get_auto_suggest 

169 

170 def get_suggestion(self, buff: Buffer, document: Document) -> Suggestion | None: 

171 auto_suggest = self.get_auto_suggest() or DummyAutoSuggest() 

172 return auto_suggest.get_suggestion(buff, document) 

173 

174 async def get_suggestion_async( 

175 self, buff: Buffer, document: Document 

176 ) -> Suggestion | None: 

177 auto_suggest = self.get_auto_suggest() or DummyAutoSuggest() 

178 return await auto_suggest.get_suggestion_async(buff, document)