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