##// END OF EJS Templates
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
epatters -
Show More
@@ -192,7 +192,7 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
192 192 elif etype == QtCore.QEvent.MouseButtonRelease and \
193 193 event.button() == QtCore.Qt.MidButton and \
194 194 obj == self._control.viewport():
195 cursor = self._control.cursorForPosition(event.pos());
195 cursor = self._control.cursorForPosition(event.pos())
196 196 self._control.setTextCursor(cursor)
197 197 self.paste(QtGui.QClipboard.Selection)
198 198 return True
@@ -578,31 +578,46 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
578 578 self._show_prompt()
579 579 self.input_buffer = input_buffer
580 580
581 def _cancel_text_completion(self):
582 """ If text completion is progress, cancel it.
583 """
584 if self._text_completing_pos:
585 self._clear_temporary_buffer()
586 self._text_completing_pos = 0
587
581 588 def _clear_temporary_buffer(self):
582 589 """ Clears the "temporary text" buffer, i.e. all the text following
583 590 the prompt region.
584 591 """
592 # Select and remove all text below the input buffer.
585 593 cursor = self._get_prompt_cursor()
586 if cursor.movePosition(QtGui.QTextCursor.NextBlock):
587 prompt = self._continuation_prompt.lstrip()
588 while True:
589 temp_cursor = QtGui.QTextCursor(cursor)
590 temp_cursor.select(QtGui.QTextCursor.BlockUnderCursor)
591 text = str(temp_cursor.selection().toPlainText()).lstrip()
592 if not text.startswith(prompt) or \
593 not cursor.movePosition(QtGui.QTextCursor.NextBlock):
594 break
595 cursor.movePosition(QtGui.QTextCursor.Left) # Grab the newline.
596 cursor.movePosition(QtGui.QTextCursor.End,
597 QtGui.QTextCursor.KeepAnchor)
598 cursor.removeSelectedText()
594 prompt = self._continuation_prompt.lstrip()
595 while cursor.movePosition(QtGui.QTextCursor.NextBlock):
596 temp_cursor = QtGui.QTextCursor(cursor)
597 temp_cursor.select(QtGui.QTextCursor.BlockUnderCursor)
598 text = str(temp_cursor.selection().toPlainText()).lstrip()
599 if not text.startswith(prompt):
600 break
601 else:
602 # We've reached the end of the input buffer and no text follows.
603 return
604 cursor.movePosition(QtGui.QTextCursor.Left) # Grab the newline.
605 cursor.movePosition(QtGui.QTextCursor.End,
606 QtGui.QTextCursor.KeepAnchor)
607 cursor.removeSelectedText()
608
609 # After doing this, we have no choice but to clear the undo/redo
610 # history. Otherwise, the text is not "temporary" at all, because it
611 # can be recalled with undo/redo. Unfortunately, Qt does not expose
612 # fine-grained control to the undo/redo system.
613 if self._control.isUndoRedoEnabled():
614 self._control.setUndoRedoEnabled(False)
615 self._control.setUndoRedoEnabled(True)
599 616
600 617 def _complete_with_items(self, cursor, items):
601 618 """ Performs completion with 'items' at the specified cursor location.
602 619 """
603 if self._text_completing_pos:
604 self._clear_temporary_buffer()
605 self._text_completing_pos = 0
620 self._cancel_text_completion()
606 621
607 622 if len(items) == 1:
608 623 cursor.setPosition(self._control.textCursor().position(),
@@ -785,9 +800,7 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
785 800 intercepted = True
786 801
787 802 # Special handling when tab completing in text mode.
788 if self._text_completing_pos:
789 self._clear_temporary_buffer()
790 self._text_completing_pos = 0
803 self._cancel_text_completion()
791 804
792 805 if self._in_buffer(position):
793 806 if self._reading:
@@ -1251,8 +1264,7 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
1251 1264 """ Cancels the current editing task ala Ctrl-G in Emacs.
1252 1265 """
1253 1266 if self._text_completing_pos:
1254 self._clear_temporary_buffer()
1255 self._text_completing_pos = 0
1267 self._cancel_text_completion()
1256 1268 else:
1257 1269 self.input_buffer = ''
1258 1270
@@ -138,17 +138,22 b' class IPythonWidget(FrontendWidget):'
138 138 info.pos == cursor.position():
139 139 matches = rep['content']['matches']
140 140 text = rep['content']['matched_text']
141
142 # Clean up matches with '.'s and path separators.
143 parts = re.split(r'[./\\]', text)
144 sep_count = len(parts) - 1
145 if sep_count:
146 chop_length = sum(map(len, parts[:sep_count])) + sep_count
147 matches = [ match[chop_length:] for match in matches ]
148 text = text[chop_length:]
141 offset = len(text)
142
143 # Clean up matches with period and path separators if the matched
144 # text has not been transformed. This is done by truncating all
145 # but the last component and then suitably decreasing the offset
146 # between the current cursor position and the start of completion.
147 if len(matches) > 1 and matches[0][:offset] == text:
148 parts = re.split(r'[./\\]', text)
149 sep_count = len(parts) - 1
150 if sep_count:
151 chop_length = sum(map(len, parts[:sep_count])) + sep_count
152 matches = [ match[chop_length:] for match in matches ]
153 offset -= chop_length
149 154
150 155 # Move the cursor to the start of the match and complete.
151 cursor.movePosition(QtGui.QTextCursor.Left, n=len(text))
156 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
152 157 self._complete_with_items(cursor, matches)
153 158
154 159 def _handle_execute_reply(self, msg):
General Comments 0
You need to be logged in to leave comments. Login now