##// END OF EJS Templates
wrong cursor
MinRK -
Show More
@@ -1,302 +1,302 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
92 92 # check if we are at the end of the first line
93 c = self._get_prompt_cursor()
93 c = self._get_cursor()
94 94 current_pos = c.position()
95 95 c.movePosition(QtGui.QTextCursor.EndOfLine)
96 96 at_eol = (c.position() == current_pos)
97 97
98 98 if self._history_index == len(self._history) or \
99 99 not (self._history_prefix == '' and at_eol) or \
100 100 not (self._get_edited_history(self._history_index)[:col] == input_buffer[:col]):
101 101 self._history_prefix = input_buffer[:col]
102 102
103 103 # Perform the search.
104 104 self.history_previous(self._history_prefix,
105 105 as_prefix=not shift_modifier)
106 106
107 107 # Go to the first line of the prompt for seemless history scrolling.
108 108 # Emulate readline: keep the cursor position fixed for a prefix
109 109 # search.
110 110 cursor = self._get_prompt_cursor()
111 111 if self._history_prefix:
112 112 cursor.movePosition(QtGui.QTextCursor.Right,
113 113 n=len(self._history_prefix))
114 114 else:
115 115 cursor.movePosition(QtGui.QTextCursor.EndOfLine)
116 116 self._set_cursor(cursor)
117 117
118 118 return False
119 119
120 120 return True
121 121
122 122 def _down_pressed(self, shift_modifier):
123 123 """ Called when the down key is pressed. Returns whether to continue
124 124 processing the event.
125 125 """
126 126 end_cursor = self._get_end_cursor()
127 127 if self._get_cursor().blockNumber() == end_cursor.blockNumber():
128 128 # Bail out if we're locked.
129 129 if self._history_locked() and not shift_modifier:
130 130 return False
131 131
132 132 # Perform the search.
133 133 replaced = self.history_next(self._history_prefix,
134 134 as_prefix=not shift_modifier)
135 135
136 136 # Emulate readline: keep the cursor position fixed for a prefix
137 137 # search. (We don't need to move the cursor to the end of the buffer
138 138 # in the other case because this happens automatically when the
139 139 # input buffer is set.)
140 140 if self._history_prefix and replaced:
141 141 cursor = self._get_prompt_cursor()
142 142 cursor.movePosition(QtGui.QTextCursor.Right,
143 143 n=len(self._history_prefix))
144 144 self._set_cursor(cursor)
145 145
146 146 return False
147 147
148 148 return True
149 149
150 150 #---------------------------------------------------------------------------
151 151 # 'HistoryConsoleWidget' public interface
152 152 #---------------------------------------------------------------------------
153 153
154 154 def history_previous(self, substring='', as_prefix=True):
155 155 """ If possible, set the input buffer to a previous history item.
156 156
157 157 Parameters:
158 158 -----------
159 159 substring : str, optional
160 160 If specified, search for an item with this substring.
161 161 as_prefix : bool, optional
162 162 If True, the substring must match at the beginning (default).
163 163
164 164 Returns:
165 165 --------
166 166 Whether the input buffer was changed.
167 167 """
168 168 index = self._history_index
169 169 replace = False
170 170 while index > 0:
171 171 index -= 1
172 172 history = self._get_edited_history(index)
173 173 if (as_prefix and history.startswith(substring)) \
174 174 or (not as_prefix and substring in history):
175 175 replace = True
176 176 break
177 177
178 178 if replace:
179 179 self._store_edits()
180 180 self._history_index = index
181 181 self.input_buffer = history
182 182
183 183 return replace
184 184
185 185 def history_next(self, substring='', as_prefix=True):
186 186 """ If possible, set the input buffer to a subsequent history item.
187 187
188 188 Parameters:
189 189 -----------
190 190 substring : str, optional
191 191 If specified, search for an item with this substring.
192 192 as_prefix : bool, optional
193 193 If True, the substring must match at the beginning (default).
194 194
195 195 Returns:
196 196 --------
197 197 Whether the input buffer was changed.
198 198 """
199 199 index = self._history_index
200 200 replace = False
201 201 while index < len(self._history):
202 202 index += 1
203 203 history = self._get_edited_history(index)
204 204 if (as_prefix and history.startswith(substring)) \
205 205 or (not as_prefix and substring in history):
206 206 replace = True
207 207 break
208 208
209 209 if replace:
210 210 self._store_edits()
211 211 self._history_index = index
212 212 self.input_buffer = history
213 213
214 214 return replace
215 215
216 216 def history_tail(self, n=10):
217 217 """ Get the local history list.
218 218
219 219 Parameters:
220 220 -----------
221 221 n : int
222 222 The (maximum) number of history items to get.
223 223 """
224 224 return self._history[-n:]
225 225
226 226 def _request_update_session_history_length(self):
227 227 msg_id = self.kernel_manager.shell_channel.execute('',
228 228 silent=True,
229 229 user_expressions={
230 230 'hlen':'len(get_ipython().history_manager.input_hist_raw)',
231 231 }
232 232 )
233 233 self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'save_magic')
234 234
235 235 def _handle_execute_reply(self, msg):
236 236 """ Handles replies for code execution, here only session history length
237 237 """
238 238 msg_id = msg['parent_header']['msg_id']
239 239 info = self._request_info['execute'].pop(msg_id,None)
240 240 if info and info.kind == 'save_magic' and not self._hidden:
241 241 content = msg['content']
242 242 status = content['status']
243 243 if status == 'ok':
244 244 self._max_session_history=(int(content['user_expressions']['hlen']))
245 245
246 246 def save_magic(self):
247 247 # update the session history length
248 248 self._request_update_session_history_length()
249 249
250 250 file_name,extFilter = QtGui.QFileDialog.getSaveFileName(self,
251 251 "Enter A filename",
252 252 filter='Python File (*.py);; All files (*.*)'
253 253 )
254 254
255 255 # let's the user search/type for a file name, while the history length
256 256 # is fetched
257 257
258 258 if file_name:
259 259 hist_range, ok = QtGui.QInputDialog.getText(self,
260 260 'Please enter an interval of command to save',
261 261 'Saving commands:',
262 262 text=str('1-'+str(self._max_session_history))
263 263 )
264 264 if ok:
265 265 self.execute("%save"+" "+file_name+" "+str(hist_range))
266 266
267 267 #---------------------------------------------------------------------------
268 268 # 'HistoryConsoleWidget' protected interface
269 269 #---------------------------------------------------------------------------
270 270
271 271 def _history_locked(self):
272 272 """ Returns whether history movement is locked.
273 273 """
274 274 return (self.history_lock and
275 275 (self._get_edited_history(self._history_index) !=
276 276 self.input_buffer) and
277 277 (self._get_prompt_cursor().blockNumber() !=
278 278 self._get_end_cursor().blockNumber()))
279 279
280 280 def _get_edited_history(self, index):
281 281 """ Retrieves a history item, possibly with temporary edits.
282 282 """
283 283 if index in self._history_edits:
284 284 return self._history_edits[index]
285 285 elif index == len(self._history):
286 286 return unicode()
287 287 return self._history[index]
288 288
289 289 def _set_history(self, history):
290 290 """ Replace the current history with a sequence of history items.
291 291 """
292 292 self._history = list(history)
293 293 self._history_edits = {}
294 294 self._history_index = len(self._history)
295 295
296 296 def _store_edits(self):
297 297 """ If there are edits to the current input buffer, store them.
298 298 """
299 299 current = self.input_buffer
300 300 if self._history_index == len(self._history) or \
301 301 self._history[self._history_index] != current:
302 302 self._history_edits[self._history_index] = current
General Comments 0
You need to be logged in to leave comments. Login now