##// END OF EJS Templates
check whether line was edited in qt history scroll...
MinRK -
Show More
@@ -1,295 +1,296 b''
1 1 # System library imports
2 2 from IPython.external.qt import QtGui
3 3
4 4 # Local imports
5 5 from IPython.utils.traitlets import Bool
6 6 from console_widget import ConsoleWidget
7 7
8 8
9 9 class HistoryConsoleWidget(ConsoleWidget):
10 10 """ A ConsoleWidget that keeps a history of the commands that have been
11 11 executed and provides a readline-esque interface to this history.
12 12 """
13 13
14 14 #------ Configuration ------------------------------------------------------
15 15
16 16 # If enabled, the input buffer will become "locked" to history movement when
17 17 # an edit is made to a multi-line input buffer. To override the lock, use
18 18 # Shift in conjunction with the standard history cycling keys.
19 19 history_lock = Bool(False, config=True)
20 20
21 21 #---------------------------------------------------------------------------
22 22 # 'object' interface
23 23 #---------------------------------------------------------------------------
24 24
25 25 def __init__(self, *args, **kw):
26 26 super(HistoryConsoleWidget, self).__init__(*args, **kw)
27 27
28 28 # HistoryConsoleWidget protected variables.
29 29 self._history = []
30 30 self._history_edits = {}
31 31 self._history_index = 0
32 32 self._history_prefix = ''
33 33
34 34 #---------------------------------------------------------------------------
35 35 # 'ConsoleWidget' public interface
36 36 #---------------------------------------------------------------------------
37 37
38 38 def execute(self, source=None, hidden=False, interactive=False):
39 39 """ Reimplemented to the store history.
40 40 """
41 41 if not hidden:
42 42 history = self.input_buffer if source is None else source
43 43
44 44 executed = super(HistoryConsoleWidget, self).execute(
45 45 source, hidden, interactive)
46 46
47 47 if executed and not hidden:
48 48 # Save the command unless it was an empty string or was identical
49 49 # to the previous command.
50 50 history = history.rstrip()
51 51 if history and (not self._history or self._history[-1] != history):
52 52 self._history.append(history)
53 53
54 54 # Emulate readline: reset all history edits.
55 55 self._history_edits = {}
56 56
57 57 # Move the history index to the most recent item.
58 58 self._history_index = len(self._history)
59 59
60 60 return executed
61 61
62 62 #---------------------------------------------------------------------------
63 63 # 'ConsoleWidget' abstract interface
64 64 #---------------------------------------------------------------------------
65 65
66 66 def _up_pressed(self, shift_modifier):
67 67 """ Called when the up key is pressed. Returns whether to continue
68 68 processing the event.
69 69 """
70 70 prompt_cursor = self._get_prompt_cursor()
71 71 if self._get_cursor().blockNumber() == prompt_cursor.blockNumber():
72 72 # Bail out if we're locked.
73 73 if self._history_locked() and not shift_modifier:
74 74 return False
75 75
76 76 # Set a search prefix based on the cursor position.
77 77 col = self._get_input_buffer_cursor_column()
78 78 input_buffer = self.input_buffer
79 79 # use the *shortest* of the cursor column and the history prefix
80 80 # to determine if the prefix has changed
81 81 n = min(col, len(self._history_prefix))
82 82
83 83 # prefix changed, restart search from the beginning
84 84 if (self._history_prefix[:n] != input_buffer[:n]):
85 85 self._history_index = len(self._history)
86 86
87 87 # the only time we shouldn't set the history prefix
88 88 # to the line up to the cursor is if we are already
89 89 # in a simple scroll (no prefix),
90 90 # and the cursor is at the end of the first line
91 91 first_line = input_buffer.split('\n', 1)[0]
92 92 if self._history_index == len(self._history) or \
93 not (self._history_prefix == '' and col == len(first_line)):
93 not (self._history_prefix == '' and col == len(first_line)) or \
94 not (self._get_edited_history(self._history_index)[:col] == input_buffer[:col]):
94 95 self._history_prefix = input_buffer[:col]
95 96
96 97 # Perform the search.
97 98 self.history_previous(self._history_prefix,
98 99 as_prefix=not shift_modifier)
99 100
100 101 # Go to the first line of the prompt for seemless history scrolling.
101 102 # Emulate readline: keep the cursor position fixed for a prefix
102 103 # search.
103 104 cursor = self._get_prompt_cursor()
104 105 if self._history_prefix:
105 106 cursor.movePosition(QtGui.QTextCursor.Right,
106 107 n=len(self._history_prefix))
107 108 else:
108 109 cursor.movePosition(QtGui.QTextCursor.EndOfLine)
109 110 self._set_cursor(cursor)
110 111
111 112 return False
112 113
113 114 return True
114 115
115 116 def _down_pressed(self, shift_modifier):
116 117 """ Called when the down key is pressed. Returns whether to continue
117 118 processing the event.
118 119 """
119 120 end_cursor = self._get_end_cursor()
120 121 if self._get_cursor().blockNumber() == end_cursor.blockNumber():
121 122 # Bail out if we're locked.
122 123 if self._history_locked() and not shift_modifier:
123 124 return False
124 125
125 126 # Perform the search.
126 127 replaced = self.history_next(self._history_prefix,
127 128 as_prefix=not shift_modifier)
128 129
129 130 # Emulate readline: keep the cursor position fixed for a prefix
130 131 # search. (We don't need to move the cursor to the end of the buffer
131 132 # in the other case because this happens automatically when the
132 133 # input buffer is set.)
133 134 if self._history_prefix and replaced:
134 135 cursor = self._get_prompt_cursor()
135 136 cursor.movePosition(QtGui.QTextCursor.Right,
136 137 n=len(self._history_prefix))
137 138 self._set_cursor(cursor)
138 139
139 140 return False
140 141
141 142 return True
142 143
143 144 #---------------------------------------------------------------------------
144 145 # 'HistoryConsoleWidget' public interface
145 146 #---------------------------------------------------------------------------
146 147
147 148 def history_previous(self, substring='', as_prefix=True):
148 149 """ If possible, set the input buffer to a previous history item.
149 150
150 151 Parameters:
151 152 -----------
152 153 substring : str, optional
153 154 If specified, search for an item with this substring.
154 155 as_prefix : bool, optional
155 156 If True, the substring must match at the beginning (default).
156 157
157 158 Returns:
158 159 --------
159 160 Whether the input buffer was changed.
160 161 """
161 162 index = self._history_index
162 163 replace = False
163 164 while index > 0:
164 165 index -= 1
165 166 history = self._get_edited_history(index)
166 167 if (as_prefix and history.startswith(substring)) \
167 168 or (not as_prefix and substring in history):
168 169 replace = True
169 170 break
170 171
171 172 if replace:
172 173 self._store_edits()
173 174 self._history_index = index
174 175 self.input_buffer = history
175 176
176 177 return replace
177 178
178 179 def history_next(self, substring='', as_prefix=True):
179 180 """ If possible, set the input buffer to a subsequent history item.
180 181
181 182 Parameters:
182 183 -----------
183 184 substring : str, optional
184 185 If specified, search for an item with this substring.
185 186 as_prefix : bool, optional
186 187 If True, the substring must match at the beginning (default).
187 188
188 189 Returns:
189 190 --------
190 191 Whether the input buffer was changed.
191 192 """
192 193 index = self._history_index
193 194 replace = False
194 195 while index < len(self._history):
195 196 index += 1
196 197 history = self._get_edited_history(index)
197 198 if (as_prefix and history.startswith(substring)) \
198 199 or (not as_prefix and substring in history):
199 200 replace = True
200 201 break
201 202
202 203 if replace:
203 204 self._store_edits()
204 205 self._history_index = index
205 206 self.input_buffer = history
206 207
207 208 return replace
208 209
209 210 def history_tail(self, n=10):
210 211 """ Get the local history list.
211 212
212 213 Parameters:
213 214 -----------
214 215 n : int
215 216 The (maximum) number of history items to get.
216 217 """
217 218 return self._history[-n:]
218 219
219 220 def _request_update_session_history_length(self):
220 221 msg_id = self.kernel_manager.shell_channel.execute('',
221 222 silent=True,
222 223 user_expressions={
223 224 'hlen':'len(get_ipython().history_manager.input_hist_raw)',
224 225 }
225 226 )
226 227 self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'save_magic')
227 228
228 229 def _handle_execute_reply(self, msg):
229 230 """ Handles replies for code execution, here only session history length
230 231 """
231 232 msg_id = msg['parent_header']['msg_id']
232 233 info = self._request_info['execute'].pop(msg_id,None)
233 234 if info and info.kind == 'save_magic' and not self._hidden:
234 235 content = msg['content']
235 236 status = content['status']
236 237 if status == 'ok':
237 238 self._max_session_history=(int(content['user_expressions']['hlen']))
238 239
239 240 def save_magic(self):
240 241 # update the session history length
241 242 self._request_update_session_history_length()
242 243
243 244 file_name,extFilter = QtGui.QFileDialog.getSaveFileName(self,
244 245 "Enter A filename",
245 246 filter='Python File (*.py);; All files (*.*)'
246 247 )
247 248
248 249 # let's the user search/type for a file name, while the history length
249 250 # is fetched
250 251
251 252 if file_name:
252 253 hist_range, ok = QtGui.QInputDialog.getText(self,
253 254 'Please enter an interval of command to save',
254 255 'Saving commands:',
255 256 text=str('1-'+str(self._max_session_history))
256 257 )
257 258 if ok:
258 259 self.execute("%save"+" "+file_name+" "+str(hist_range))
259 260
260 261 #---------------------------------------------------------------------------
261 262 # 'HistoryConsoleWidget' protected interface
262 263 #---------------------------------------------------------------------------
263 264
264 265 def _history_locked(self):
265 266 """ Returns whether history movement is locked.
266 267 """
267 268 return (self.history_lock and
268 269 (self._get_edited_history(self._history_index) !=
269 270 self.input_buffer) and
270 271 (self._get_prompt_cursor().blockNumber() !=
271 272 self._get_end_cursor().blockNumber()))
272 273
273 274 def _get_edited_history(self, index):
274 275 """ Retrieves a history item, possibly with temporary edits.
275 276 """
276 277 if index in self._history_edits:
277 278 return self._history_edits[index]
278 279 elif index == len(self._history):
279 280 return unicode()
280 281 return self._history[index]
281 282
282 283 def _set_history(self, history):
283 284 """ Replace the current history with a sequence of history items.
284 285 """
285 286 self._history = list(history)
286 287 self._history_edits = {}
287 288 self._history_index = len(self._history)
288 289
289 290 def _store_edits(self):
290 291 """ If there are edits to the current input buffer, store them.
291 292 """
292 293 current = self.input_buffer
293 294 if self._history_index == len(self._history) or \
294 295 self._history[self._history_index] != current:
295 296 self._history_edits[self._history_index] = current
General Comments 0
You need to be logged in to leave comments. Login now