Show More
@@ -652,13 +652,13 b' class ConsoleWidget(Configurable, QtGui.QWidget):' | |||||
652 | """ |
|
652 | """ | |
653 | pass |
|
653 | pass | |
654 |
|
654 | |||
655 | def _up_pressed(self): |
|
655 | def _up_pressed(self, shift_modifier): | |
656 | """ Called when the up key is pressed. Returns whether to continue |
|
656 | """ Called when the up key is pressed. Returns whether to continue | |
657 | processing the event. |
|
657 | processing the event. | |
658 | """ |
|
658 | """ | |
659 | return True |
|
659 | return True | |
660 |
|
660 | |||
661 | def _down_pressed(self): |
|
661 | def _down_pressed(self, shift_modifier): | |
662 | """ Called when the down key is pressed. Returns whether to continue |
|
662 | """ Called when the down key is pressed. Returns whether to continue | |
663 | processing the event. |
|
663 | processing the event. | |
664 | """ |
|
664 | """ | |
@@ -1040,14 +1040,14 b' class ConsoleWidget(Configurable, QtGui.QWidget):' | |||||
1040 | intercepted = True |
|
1040 | intercepted = True | |
1041 |
|
1041 | |||
1042 | elif key == QtCore.Qt.Key_Up: |
|
1042 | elif key == QtCore.Qt.Key_Up: | |
1043 | if self._reading or not self._up_pressed(): |
|
1043 | if self._reading or not self._up_pressed(shift_down): | |
1044 | intercepted = True |
|
1044 | intercepted = True | |
1045 | else: |
|
1045 | else: | |
1046 | prompt_line = self._get_prompt_cursor().blockNumber() |
|
1046 | prompt_line = self._get_prompt_cursor().blockNumber() | |
1047 | intercepted = cursor.blockNumber() <= prompt_line |
|
1047 | intercepted = cursor.blockNumber() <= prompt_line | |
1048 |
|
1048 | |||
1049 | elif key == QtCore.Qt.Key_Down: |
|
1049 | elif key == QtCore.Qt.Key_Down: | |
1050 | if self._reading or not self._down_pressed(): |
|
1050 | if self._reading or not self._down_pressed(shift_down): | |
1051 | intercepted = True |
|
1051 | intercepted = True | |
1052 | else: |
|
1052 | else: | |
1053 | end_line = self._get_end_cursor().blockNumber() |
|
1053 | end_line = self._get_end_cursor().blockNumber() |
@@ -2,6 +2,7 b'' | |||||
2 | from IPython.external.qt import QtGui |
|
2 | from IPython.external.qt import QtGui | |
3 |
|
3 | |||
4 | # Local imports |
|
4 | # Local imports | |
|
5 | from IPython.utils.traitlets import Bool | |||
5 | from console_widget import ConsoleWidget |
|
6 | from console_widget import ConsoleWidget | |
6 |
|
7 | |||
7 |
|
8 | |||
@@ -9,6 +10,13 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
9 | """ A ConsoleWidget that keeps a history of the commands that have been |
|
10 | """ A ConsoleWidget that keeps a history of the commands that have been | |
10 | executed and provides a readline-esque interface to this history. |
|
11 | executed and provides a readline-esque interface to this history. | |
11 | """ |
|
12 | """ | |
|
13 | ||||
|
14 | #------ Configuration ------------------------------------------------------ | |||
|
15 | ||||
|
16 | # If enabled, the input buffer will become "locked" to history movement when | |||
|
17 | # an edit is made to a multi-line input buffer. To override the lock, use | |||
|
18 | # Shift in conjunction with the standard history cycling keys. | |||
|
19 | history_lock = Bool(False, config=True) | |||
12 |
|
20 | |||
13 | #--------------------------------------------------------------------------- |
|
21 | #--------------------------------------------------------------------------- | |
14 | # 'object' interface |
|
22 | # 'object' interface | |
@@ -55,12 +63,15 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
55 | # 'ConsoleWidget' abstract interface |
|
63 | # 'ConsoleWidget' abstract interface | |
56 | #--------------------------------------------------------------------------- |
|
64 | #--------------------------------------------------------------------------- | |
57 |
|
65 | |||
58 | def _up_pressed(self): |
|
66 | def _up_pressed(self, shift_modifier): | |
59 | """ Called when the up key is pressed. Returns whether to continue |
|
67 | """ Called when the up key is pressed. Returns whether to continue | |
60 | processing the event. |
|
68 | processing the event. | |
61 | """ |
|
69 | """ | |
62 | prompt_cursor = self._get_prompt_cursor() |
|
70 | prompt_cursor = self._get_prompt_cursor() | |
63 | if self._get_cursor().blockNumber() == prompt_cursor.blockNumber(): |
|
71 | if self._get_cursor().blockNumber() == prompt_cursor.blockNumber(): | |
|
72 | # Bail out if we're locked. | |||
|
73 | if self._history_locked() and not shift_modifier: | |||
|
74 | return False | |||
64 |
|
75 | |||
65 | # Set a search prefix based on the cursor position. |
|
76 | # Set a search prefix based on the cursor position. | |
66 | col = self._get_input_buffer_cursor_column() |
|
77 | col = self._get_input_buffer_cursor_column() | |
@@ -88,21 +99,24 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
88 |
|
99 | |||
89 | return True |
|
100 | return True | |
90 |
|
101 | |||
91 | def _down_pressed(self): |
|
102 | def _down_pressed(self, shift_modifier): | |
92 | """ Called when the down key is pressed. Returns whether to continue |
|
103 | """ Called when the down key is pressed. Returns whether to continue | |
93 | processing the event. |
|
104 | processing the event. | |
94 | """ |
|
105 | """ | |
95 | end_cursor = self._get_end_cursor() |
|
106 | end_cursor = self._get_end_cursor() | |
96 | if self._get_cursor().blockNumber() == end_cursor.blockNumber(): |
|
107 | if self._get_cursor().blockNumber() == end_cursor.blockNumber(): | |
|
108 | # Bail out if we're locked. | |||
|
109 | if self._history_locked() and not shift_modifier: | |||
|
110 | return False | |||
97 |
|
111 | |||
98 | # Perform the search. |
|
112 | # Perform the search. | |
99 | self.history_next(self._history_prefix) |
|
113 | replaced = self.history_next(self._history_prefix) | |
100 |
|
114 | |||
101 | # Emulate readline: keep the cursor position fixed for a prefix |
|
115 | # Emulate readline: keep the cursor position fixed for a prefix | |
102 | # search. (We don't need to move the cursor to the end of the buffer |
|
116 | # search. (We don't need to move the cursor to the end of the buffer | |
103 | # in the other case because this happens automatically when the |
|
117 | # in the other case because this happens automatically when the | |
104 | # input buffer is set.) |
|
118 | # input buffer is set.) | |
105 | if self._history_prefix: |
|
119 | if self._history_prefix and replaced: | |
106 | cursor = self._get_prompt_cursor() |
|
120 | cursor = self._get_prompt_cursor() | |
107 | cursor.movePosition(QtGui.QTextCursor.Right, |
|
121 | cursor.movePosition(QtGui.QTextCursor.Right, | |
108 | n=len(self._history_prefix)) |
|
122 | n=len(self._history_prefix)) | |
@@ -123,19 +137,26 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
123 | ----------- |
|
137 | ----------- | |
124 | prefix : str, optional |
|
138 | prefix : str, optional | |
125 | If specified, search for an item with this prefix. |
|
139 | If specified, search for an item with this prefix. | |
|
140 | ||||
|
141 | Returns: | |||
|
142 | -------- | |||
|
143 | Whether the input buffer was changed. | |||
126 | """ |
|
144 | """ | |
127 | index = self._history_index |
|
145 | index = self._history_index | |
|
146 | replace = False | |||
128 | while index > 0: |
|
147 | while index > 0: | |
129 | index -= 1 |
|
148 | index -= 1 | |
130 | history = self._get_edited_history(index) |
|
149 | history = self._get_edited_history(index) | |
131 | if history.startswith(prefix): |
|
150 | if history.startswith(prefix): | |
|
151 | replace = True | |||
132 | break |
|
152 | break | |
133 | else: |
|
|||
134 | history = None |
|
|||
135 |
|
153 | |||
136 | if history is not None: |
|
154 | if replace: | |
137 |
self._s |
|
155 | self._store_edits() | |
138 | self._history_index = index |
|
156 | self._history_index = index | |
|
157 | self.input_buffer = history | |||
|
158 | ||||
|
159 | return replace | |||
139 |
|
160 | |||
140 | def history_next(self, prefix=''): |
|
161 | def history_next(self, prefix=''): | |
141 | """ If possible, set the input buffer to a subsequent history item. |
|
162 | """ If possible, set the input buffer to a subsequent history item. | |
@@ -144,19 +165,26 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
144 | ----------- |
|
165 | ----------- | |
145 | prefix : str, optional |
|
166 | prefix : str, optional | |
146 | If specified, search for an item with this prefix. |
|
167 | If specified, search for an item with this prefix. | |
|
168 | ||||
|
169 | Returns: | |||
|
170 | -------- | |||
|
171 | Whether the input buffer was changed. | |||
147 | """ |
|
172 | """ | |
148 | index = self._history_index |
|
173 | index = self._history_index | |
|
174 | replace = False | |||
149 | while self._history_index < len(self._history): |
|
175 | while self._history_index < len(self._history): | |
150 | index += 1 |
|
176 | index += 1 | |
151 | history = self._get_edited_history(index) |
|
177 | history = self._get_edited_history(index) | |
152 | if history.startswith(prefix): |
|
178 | if history.startswith(prefix): | |
|
179 | replace = True | |||
153 | break |
|
180 | break | |
154 |
|
|
181 | ||
155 | history = None |
|
182 | if replace: | |
156 |
|
183 | self._store_edits() | ||
157 | if history is not None: |
|
|||
158 | self._set_edited_input_buffer(history) |
|
|||
159 | self._history_index = index |
|
184 | self._history_index = index | |
|
185 | self.input_buffer = history | |||
|
186 | ||||
|
187 | return replace | |||
160 |
|
188 | |||
161 | def history_tail(self, n=10): |
|
189 | def history_tail(self, n=10): | |
162 | """ Get the local history list. |
|
190 | """ Get the local history list. | |
@@ -172,23 +200,35 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
172 | # 'HistoryConsoleWidget' protected interface |
|
200 | # 'HistoryConsoleWidget' protected interface | |
173 | #--------------------------------------------------------------------------- |
|
201 | #--------------------------------------------------------------------------- | |
174 |
|
202 | |||
|
203 | def _history_locked(self): | |||
|
204 | """ Returns whether history movement is locked. | |||
|
205 | """ | |||
|
206 | return (self.history_lock and | |||
|
207 | (self._get_edited_history(self._history_index) != | |||
|
208 | self.input_buffer) and | |||
|
209 | (self._get_prompt_cursor().blockNumber() != | |||
|
210 | self._get_end_cursor().blockNumber())) | |||
|
211 | ||||
175 | def _get_edited_history(self, index): |
|
212 | def _get_edited_history(self, index): | |
176 | """ Retrieves a history item, possibly with temporary edits. |
|
213 | """ Retrieves a history item, possibly with temporary edits. | |
177 | """ |
|
214 | """ | |
178 | if index in self._history_edits: |
|
215 | if index in self._history_edits: | |
179 | return self._history_edits[index] |
|
216 | return self._history_edits[index] | |
|
217 | elif index == len(self._history): | |||
|
218 | return unicode() | |||
180 | return self._history[index] |
|
219 | return self._history[index] | |
181 |
|
220 | |||
182 | def _set_edited_input_buffer(self, source): |
|
|||
183 | """ Sets the input buffer to 'source', saving the current input buffer |
|
|||
184 | as a temporary history edit. |
|
|||
185 | """ |
|
|||
186 | self._history_edits[self._history_index] = self.input_buffer |
|
|||
187 | self.input_buffer = source |
|
|||
188 |
|
||||
189 | def _set_history(self, history): |
|
221 | def _set_history(self, history): | |
190 | """ Replace the current history with a sequence of history items. |
|
222 | """ Replace the current history with a sequence of history items. | |
191 | """ |
|
223 | """ | |
192 | self._history = list(history) |
|
224 | self._history = list(history) | |
193 | self._history_edits = {} |
|
225 | self._history_edits = {} | |
194 | self._history_index = len(self._history) |
|
226 | self._history_index = len(self._history) | |
|
227 | ||||
|
228 | def _store_edits(self): | |||
|
229 | """ If there are edits to the current input buffer, store them. | |||
|
230 | """ | |||
|
231 | current = self.input_buffer | |||
|
232 | if self._history_index == len(self._history) or \ | |||
|
233 | self._history[self._history_index] != current: | |||
|
234 | self._history_edits[self._history_index] = current |
General Comments 0
You need to be logged in to leave comments.
Login now