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

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

14from __future__ import annotations 

15 

16from abc import ABCMeta, abstractmethod 

17from typing import TYPE_CHECKING, Callable 

18 

19from prompt_toolkit.eventloop import run_in_executor_with_context 

20 

21from .document import Document 

22from .filters import Filter, to_filter 

23 

24if TYPE_CHECKING: 

25 from .buffer import Buffer 

26 

27__all__ = [ 

28 "Suggestion", 

29 "AutoSuggest", 

30 "ThreadedAutoSuggest", 

31 "DummyAutoSuggest", 

32 "AutoSuggestFromHistory", 

33 "ConditionalAutoSuggest", 

34 "DynamicAutoSuggest", 

35] 

36 

37 

38class Suggestion: 

39 """ 

40 Suggestion returned by an auto-suggest algorithm. 

41 

42 :param text: The suggestion text. 

43 """ 

44 

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

46 self.text = text 

47 

48 def __repr__(self) -> str: 

49 return "Suggestion(%s)" % self.text 

50 

51 

52class AutoSuggest(metaclass=ABCMeta): 

53 """ 

54 Base class for auto suggestion implementations. 

55 """ 

56 

57 @abstractmethod 

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

59 """ 

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

61 

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. 

69 

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

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

72 """ 

73 

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) 

83 

84 

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

91 

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

93 self.auto_suggest = auto_suggest 

94 

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

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

97 

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

104 

105 def run_get_suggestion_thread() -> Suggestion | None: 

106 return self.get_suggestion(buff, document) 

107 

108 return await run_in_executor_with_context(run_get_suggestion_thread) 

109 

110 

111class DummyAutoSuggest(AutoSuggest): 

112 """ 

113 AutoSuggest class that doesn't return any suggestion. 

114 """ 

115 

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

117 return None # No suggestion 

118 

119 

120class AutoSuggestFromHistory(AutoSuggest): 

121 """ 

122 Give suggestions based on the lines in the history. 

123 """ 

124 

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

126 history = buffer.history 

127 

128 # Consider only the last line for the suggestion. 

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

130 

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) :]) 

138 

139 return None 

140 

141 

142class ConditionalAutoSuggest(AutoSuggest): 

143 """ 

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

145 """ 

146 

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

148 self.auto_suggest = auto_suggest 

149 self.filter = to_filter(filter) 

150 

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

152 if self.filter(): 

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

154 

155 return None 

156 

157 

158class DynamicAutoSuggest(AutoSuggest): 

159 """ 

160 Validator class that can dynamically returns any Validator. 

161 

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

163 """ 

164 

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

166 self.get_auto_suggest = get_auto_suggest 

167 

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) 

171 

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)