diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py index 1cf551e..276a0fa 100644 --- a/IPython/frontend/qt/console/console_widget.py +++ b/IPython/frontend/qt/console/console_widget.py @@ -878,12 +878,14 @@ class ConsoleWidget(QtGui.QWidget): # After inserting HTML, the text document "remembers" it's in "html # mode", which means that subsequent calls adding plain text will result # in unwanted formatting, lost tab characters, etc. The following code - # hacks around this behavior, which I consider to be a bug in Qt. - cursor.movePosition(QtGui.QTextCursor.Left, + # hacks around this behavior, which I consider to be a bug in Qt, by + # (crudely) resetting the document's style state. + cursor.movePosition(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor) if cursor.selection().toPlainText() == ' ': cursor.removeSelectedText() - cursor.movePosition(QtGui.QTextCursor.Right) + else: + cursor.movePosition(QtGui.QTextCursor.Right) cursor.insertText(' ', QtGui.QTextCharFormat()) cursor.endEditBlock() diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py index b2e5500..35419d5 100644 --- a/IPython/frontend/qt/console/frontend_widget.py +++ b/IPython/frontend/qt/console/frontend_widget.py @@ -184,7 +184,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): self._process_execute_abort(msg) self._hidden = True - self._show_interpreter_prompt() + self._show_interpreter_prompt_for_reply(msg) self.executed.emit(msg) def _handle_input_request(self, msg): @@ -335,6 +335,11 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): """ self._show_prompt('>>> ') + def _show_interpreter_prompt_for_reply(self, msg): + """ Shows a prompt for the interpreter given an 'execute_reply' message. + """ + self._show_interpreter_prompt() + #------ Signal handlers ---------------------------------------------------- def _document_contents_change(self, position, removed, added): diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py index 5dbb636..cf8d230 100644 --- a/IPython/frontend/qt/console/ipython_widget.py +++ b/IPython/frontend/qt/console/ipython_widget.py @@ -10,6 +10,15 @@ from IPython.core.usage import default_banner from frontend_widget import FrontendWidget +class IPythonPromptBlock(object): + """ An internal storage object for IPythonWidget. + """ + def __init__(self, block, length, number): + self.block = block + self.length = length + self.number = number + + class IPythonWidget(FrontendWidget): """ A FrontendWidget for an IPython kernel. """ @@ -53,8 +62,7 @@ class IPythonWidget(FrontendWidget): #self._input_splitter = IPythonInputSplitter(input_mode='replace') # IPythonWidget protected variables. - self._previous_prompt_blocks = [] - self._prompt_count = 0 + self._previous_prompt_obj = None # Set a default editor and stylesheet. self.set_editor('default') @@ -70,7 +78,6 @@ class IPythonWidget(FrontendWidget): prompt_number = omsg['content']['prompt_number'] data = omsg['content']['data'] self._append_html(self._make_out_prompt(prompt_number)) - self._save_prompt_block() self._append_plain_text(data + '\n') #--------------------------------------------------------------------------- @@ -106,33 +113,45 @@ class IPythonWidget(FrontendWidget): self._append_html(traceback) - def _show_interpreter_prompt(self): + def _show_interpreter_prompt(self, number=None): """ Reimplemented for IPython-style prompts. """ - # Update old prompt numbers if necessary. - previous_prompt_number = self._prompt_count - if previous_prompt_number != self._prompt_count: - for i, (block, length) in enumerate(self._previous_prompt_blocks): - if block.isValid(): - cursor = QtGui.QTextCursor(block) - cursor.movePosition(QtGui.QTextCursor.Right, - QtGui.QTextCursor.KeepAnchor, length-1) - if i == 0: - prompt = self._make_in_prompt(previous_prompt_number) - else: - prompt = self._make_out_prompt(previous_prompt_number) - self._insert_html(cursor, prompt) - self._previous_prompt_blocks = [] - - # Show a new prompt. - self._prompt_count += 1 - self._show_prompt(self._make_in_prompt(self._prompt_count), html=True) - self._save_prompt_block() + # TODO: If a number was not specified, make a prompt number request. + if number is None: + number = 0 + + # Show a new prompt and save information about it so it can be updated + # later if its number needs to be re-written. + block = self._control.document().lastBlock() + self._show_prompt(self._make_in_prompt(number), html=True) + self._previous_prompt_obj = IPythonPromptBlock( + block.next(), len(self._prompt), number) # Update continuation prompt to reflect (possibly) new prompt length. self._set_continuation_prompt( self._make_continuation_prompt(self._prompt), html=True) + def _show_interpreter_prompt_for_reply(self, msg): + """ Reimplemented for IPython-style prompts. + """ + # Update the old prompt number if necessary. + content = msg['content'] + previous_prompt_number = content['prompt_number'] + if self._previous_prompt_obj and \ + self._previous_prompt_obj.number != previous_prompt_number: + block = self._previous_prompt_obj.block + if block.isValid(): + cursor = QtGui.QTextCursor(block) + cursor.movePosition(QtGui.QTextCursor.Right, + QtGui.QTextCursor.KeepAnchor, + self._previous_prompt_obj.length) + prompt = self._make_in_prompt(previous_prompt_number) + self._insert_html(cursor, prompt) + self._previous_prompt_obj = None + + # Show a new prompt with the kernel's estimated prompt number. + self._show_interpreter_prompt(content['next_prompt']['prompt_number']) + #--------------------------------------------------------------------------- # 'IPythonWidget' interface #--------------------------------------------------------------------------- @@ -239,10 +258,3 @@ class IPythonWidget(FrontendWidget): """ body = self.out_prompt % number return '%s' % body - - def _save_prompt_block(self): - """ Assuming a prompt has just been written at the end of the buffer, - store the QTextBlock that contains it and its length. - """ - block = self._control.document().lastBlock() - self._previous_prompt_blocks.append((block, block.length()))