##// END OF EJS Templates
First cut at support readline-esque history filtering in ConsoleWidget.
epatters -
Show More
@@ -1,108 +1,159 b''
1 # System library imports
1 # System library imports
2 from PyQt4 import QtGui
2 from PyQt4 import QtGui
3
3
4 # Local imports
4 # Local imports
5 from console_widget import ConsoleWidget
5 from console_widget import ConsoleWidget
6
6
7
7
8 class HistoryConsoleWidget(ConsoleWidget):
8 class HistoryConsoleWidget(ConsoleWidget):
9 """ A ConsoleWidget that keeps a history of the commands that have been
9 """ A ConsoleWidget that keeps a history of the commands that have been
10 executed.
10 executed and provides a readline-esque interface to this history.
11 """
11 """
12
12
13 #---------------------------------------------------------------------------
13 #---------------------------------------------------------------------------
14 # 'object' interface
14 # 'object' interface
15 #---------------------------------------------------------------------------
15 #---------------------------------------------------------------------------
16
16
17 def __init__(self, *args, **kw):
17 def __init__(self, *args, **kw):
18 super(HistoryConsoleWidget, self).__init__(*args, **kw)
18 super(HistoryConsoleWidget, self).__init__(*args, **kw)
19
20 # HistoryConsoleWidget protected variables.
19 self._history = []
21 self._history = []
20 self._history_index = 0
22 self._history_index = 0
23 self._history_prefix = ''
21
24
22 #---------------------------------------------------------------------------
25 #---------------------------------------------------------------------------
23 # 'ConsoleWidget' public interface
26 # 'ConsoleWidget' public interface
24 #---------------------------------------------------------------------------
27 #---------------------------------------------------------------------------
25
28
26 def execute(self, source=None, hidden=False, interactive=False):
29 def execute(self, source=None, hidden=False, interactive=False):
27 """ Reimplemented to the store history.
30 """ Reimplemented to the store history.
28 """
31 """
29 if not hidden:
32 if not hidden:
30 history = self.input_buffer if source is None else source
33 history = self.input_buffer if source is None else source
31
34
32 executed = super(HistoryConsoleWidget, self).execute(
35 executed = super(HistoryConsoleWidget, self).execute(
33 source, hidden, interactive)
36 source, hidden, interactive)
34
37
35 if executed and not hidden:
38 if executed and not hidden:
36 # Save the command unless it was an empty string or was identical
39 # Save the command unless it was an empty string or was identical
37 # to the previous command.
40 # to the previous command.
38 history = history.rstrip()
41 history = history.rstrip()
39 if history and (not self._history or self._history[-1] != history):
42 if history and (not self._history or self._history[-1] != history):
40 self._history.append(history)
43 self._history.append(history)
41
44
42 # Move the history index to the most recent item.
45 # Move the history index to the most recent item.
43 self._history_index = len(self._history)
46 self._history_index = len(self._history)
44
47
45 return executed
48 return executed
46
49
47 #---------------------------------------------------------------------------
50 #---------------------------------------------------------------------------
48 # 'ConsoleWidget' abstract interface
51 # 'ConsoleWidget' abstract interface
49 #---------------------------------------------------------------------------
52 #---------------------------------------------------------------------------
50
53
51 def _up_pressed(self):
54 def _up_pressed(self):
52 """ Called when the up key is pressed. Returns whether to continue
55 """ Called when the up key is pressed. Returns whether to continue
53 processing the event.
56 processing the event.
54 """
57 """
55 prompt_cursor = self._get_prompt_cursor()
58 prompt_cursor = self._get_prompt_cursor()
56 if self._get_cursor().blockNumber() == prompt_cursor.blockNumber():
59 if self._get_cursor().blockNumber() == prompt_cursor.blockNumber():
57 self.history_previous()
58
60
59 # Go to the first line of prompt for seemless history scrolling.
61 # Set a search prefix based on the cursor position.
62 col = self._get_input_buffer_cursor_column()
63 input_buffer = self.input_buffer
64 if self._history_index == len(self._history) or \
65 (self._history_prefix and col != len(self._history_prefix)):
66 self._history_index = len(self._history)
67 self._history_prefix = input_buffer[:col]
68
69 # Perform the search.
70 self.history_previous(self._history_prefix)
71
72 # Go to the first line of the prompt for seemless history scrolling.
73 # Emulate readline: keep the cursor position fixed for a prefix
74 # search.
60 cursor = self._get_prompt_cursor()
75 cursor = self._get_prompt_cursor()
61 cursor.movePosition(QtGui.QTextCursor.EndOfLine)
76 if self._history_prefix:
77 cursor.movePosition(QtGui.QTextCursor.Right,
78 n=len(self._history_prefix))
79 else:
80 cursor.movePosition(QtGui.QTextCursor.EndOfLine)
62 self._set_cursor(cursor)
81 self._set_cursor(cursor)
63
82
64 return False
83 return False
84
65 return True
85 return True
66
86
67 def _down_pressed(self):
87 def _down_pressed(self):
68 """ Called when the down key is pressed. Returns whether to continue
88 """ Called when the down key is pressed. Returns whether to continue
69 processing the event.
89 processing the event.
70 """
90 """
71 end_cursor = self._get_end_cursor()
91 end_cursor = self._get_end_cursor()
72 if self._get_cursor().blockNumber() == end_cursor.blockNumber():
92 if self._get_cursor().blockNumber() == end_cursor.blockNumber():
73 self.history_next()
93
94 # Perform the search.
95 self.history_next(self._history_prefix)
96
97 # Emulate readline: keep the cursor position fixed for a prefix
98 # search. (We don't need to move the cursor to the end of the buffer
99 # in the other case because this happens automatically when the
100 # input buffer is set.)
101 if self._history_prefix:
102 cursor = self._get_prompt_cursor()
103 cursor.movePosition(QtGui.QTextCursor.Right,
104 n=len(self._history_prefix))
105 self._set_cursor(cursor)
106
74 return False
107 return False
108
75 return True
109 return True
76
110
77 #---------------------------------------------------------------------------
111 #---------------------------------------------------------------------------
78 # 'HistoryConsoleWidget' public interface
112 # 'HistoryConsoleWidget' public interface
79 #---------------------------------------------------------------------------
113 #---------------------------------------------------------------------------
80
114
81 def history_previous(self):
115 def history_previous(self, prefix=''):
82 """ If possible, set the input buffer to the previous item in the
116 """ If possible, set the input buffer to a previous item in the history.
83 history.
84 """
85 if self._history_index > 0:
86 self._history_index -= 1
87 self.input_buffer = self._history[self._history_index]
88
117
89 def history_next(self):
118 Parameters:
90 """ Set the input buffer to the next item in the history, or a blank
119 -----------
91 line if there is no subsequent item.
120 prefix : str, optional
121 If specified, search for an item with this prefix.
92 """
122 """
93 if self._history_index < len(self._history):
123 index = self._history_index
124 while index > 0:
125 index -= 1
126 history = self._history[index]
127 if history.startswith(prefix):
128 break
129 else:
130 history = None
131
132 if history is not None:
133 self._history_index = index
134 self.input_buffer = history
135
136 def history_next(self, prefix=''):
137 """ Set the input buffer to a subsequent item in the history, or to the
138 original search prefix if there is no such item.
139
140 Parameters:
141 -----------
142 prefix : str, optional
143 If specified, search for an item with this prefix.
144 """
145 while self._history_index < len(self._history) - 1:
94 self._history_index += 1
146 self._history_index += 1
95 if self._history_index < len(self._history):
147 history = self._history[self._history_index]
96 self.input_buffer = self._history[self._history_index]
148 if history.startswith(prefix):
97 else:
149 break
98 self.input_buffer = ''
150 else:
99
151 self._history_index = len(self._history)
100 #---------------------------------------------------------------------------
152 history = prefix
101 # 'HistoryConsoleWidget' protected interface
153 self.input_buffer = history
102 #---------------------------------------------------------------------------
103
154
104 def _set_history(self, history):
155 def set_history(self, history):
105 """ Replace the current history with a sequence of history items.
156 """ Replace the current history with a sequence of history items.
106 """
157 """
107 self._history = list(history)
158 self._history = list(history)
108 self._history_index = len(self._history)
159 self._history_index = len(self._history)
General Comments 0
You need to be logged in to leave comments. Login now