diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py index f343045..03c3f8b 100644 --- a/IPython/frontend/qt/console/console_widget.py +++ b/IPython/frontend/qt/console/console_widget.py @@ -718,36 +718,46 @@ class ConsoleWidget(Configurable, QtGui.QWidget): # 'ConsoleWidget' protected interface #-------------------------------------------------------------------------- - def _append_html(self, html): - """ Appends html at the end of the console buffer. + def _append_custom(self, insert, input, before_prompt=False): + """ A low-level method for appending content to the end of the buffer. + + If 'before_prompt' is enabled, the content will be inserted before the + current prompt, if there is one. """ - cursor = self._get_end_cursor() - self._insert_html(cursor, html) + # Determine where to insert the content. + cursor = self._control.textCursor() + if before_prompt and not self._executing: + cursor.setPosition(self._prompt_pos) + cursor.movePosition(QtGui.QTextCursor.Left, n=len(self._prompt)) + else: + cursor.movePosition(QtGui.QTextCursor.End) + start_pos = cursor.position() - def _append_html_fetching_plain_text(self, html): - """ Appends 'html', then returns the plain text version of it. - """ - cursor = self._get_end_cursor() - return self._insert_html_fetching_plain_text(cursor, html) + # Perform the insertion. + result = insert(cursor, input) + + # Adjust the prompt position if we have inserted before it. This is safe + # because buffer truncation is disabled when not executing. + if before_prompt and not self._executing: + self._prompt_pos += cursor.position() - start_pos + + return result - def _append_plain_text(self, text): - """ Appends plain text at the end of the console buffer, processing - ANSI codes if enabled. + def _append_html(self, html, before_prompt=False): + """ Appends HTML at the end of the console buffer. """ - cursor = self._get_end_cursor() - self._insert_plain_text(cursor, text) + self._append_custom(self._insert_html, html, before_prompt) - def _append_plain_text_keeping_prompt(self, text): - """ Writes 'text' after the current prompt, then restores the old prompt - with its old input buffer. + def _append_html_fetching_plain_text(self, html, before_prompt=False): + """ Appends HTML, then returns the plain text version of it. """ - input_buffer = self.input_buffer - self._append_plain_text('\n') - self._prompt_finished() + return self._append_custom(self._insert_html_fetching_plain_text, + html, before_prompt) - self._append_plain_text(text) - self._show_prompt() - self.input_buffer = input_buffer + def _append_plain_text(self, text, before_prompt=False): + """ Appends plain text, processing ANSI codes if enabled. + """ + self._append_custom(self._insert_plain_text, text, before_prompt) def _cancel_text_completion(self): """ If text completion is progress, cancel it. diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py index 9b6b6df..998cce6 100644 --- a/IPython/frontend/qt/console/frontend_widget.py +++ b/IPython/frontend/qt/console/frontend_widget.py @@ -372,14 +372,8 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): """ Handle display hook output. """ if not self._hidden and self._is_from_this_session(msg): - data = msg['content']['data'] - if isinstance(data, basestring): - # plaintext data from pure Python kernel - text = data - else: - # formatted output from DisplayFormatter (IPython kernel) - text = data.get('text/plain', '') - self._append_plain_text(text + '\n') + text = msg['content']['data'] + self._append_plain_text(text + '\n', before_prompt=True) def _handle_stream(self, msg): """ Handle stdout, stderr, and stdin. @@ -390,7 +384,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): # widget's tab width. text = msg['content']['data'].expandtabs(8) - self._append_plain_text(text) + self._append_plain_text(text, before_prompt=True) self._control.moveCursor(QtGui.QTextCursor.End) def _handle_shutdown_reply(self, msg): diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py index a2c12b3..2215024 100644 --- a/IPython/frontend/qt/console/ipython_widget.py +++ b/IPython/frontend/qt/console/ipython_widget.py @@ -62,16 +62,16 @@ class IPythonWidget(FrontendWidget): editor = Unicode(default_editor, config=True, help=""" A command for invoking a system text editor. If the string contains a - {filename} format specifier, it will be used. Otherwise, the filename will - be appended to the end the command. + {filename} format specifier, it will be used. Otherwise, the filename + will be appended to the end the command. """) editor_line = Unicode(config=True, help=""" The editor command to use when a specific line number is requested. The string should contain two format specifiers: {line} and {filename}. If - this parameter is not specified, the line number option to the %edit magic - will be ignored. + this parameter is not specified, the line number option to the %edit + magic will be ignored. """) style_sheet = Unicode(config=True, @@ -85,8 +85,9 @@ class IPythonWidget(FrontendWidget): syntax_style = Str(config=True, help=""" - If not empty, use this Pygments style for syntax highlighting. Otherwise, - the style sheet is queried for Pygments style information. + If not empty, use this Pygments style for syntax highlighting. + Otherwise, the style sheet is queried for Pygments style + information. """) # Prompts. @@ -187,20 +188,20 @@ class IPythonWidget(FrontendWidget): prompt_number = content['execution_count'] data = content['data'] if data.has_key('text/html'): - self._append_plain_text(self.output_sep) - self._append_html(self._make_out_prompt(prompt_number)) + self._append_plain_text(self.output_sep, True) + self._append_html(self._make_out_prompt(prompt_number), True) html = data['text/html'] - self._append_plain_text('\n') - self._append_html(html + self.output_sep2) + self._append_plain_text('\n', True) + self._append_html(html + self.output_sep2, True) elif data.has_key('text/plain'): - self._append_plain_text(self.output_sep) - self._append_html(self._make_out_prompt(prompt_number)) + self._append_plain_text(self.output_sep, True) + self._append_html(self._make_out_prompt(prompt_number), True) text = data['text/plain'] # If the repr is multiline, make sure we start on a new line, # so that its lines are aligned. if "\n" in text and not self.output_sep.endswith("\n"): - self._append_plain_text('\n') - self._append_plain_text(text + self.output_sep2) + self._append_plain_text('\n', True) + self._append_plain_text(text + self.output_sep2, True) def _handle_display_data(self, msg): """ The base handler for the ``display_data`` message. @@ -216,19 +217,19 @@ class IPythonWidget(FrontendWidget): # representation. if data.has_key('text/html'): html = data['text/html'] - self._append_html(html) + self._append_html(html, before_prompt=True) elif data.has_key('text/plain'): text = data['text/plain'] - self._append_plain_text(text) + self._append_plain_text(text, before_prompt=True) # This newline seems to be needed for text and html output. - self._append_plain_text(u'\n') + self._append_plain_text(u'\n', before_prompt=True) def _started_channels(self): """ Reimplemented to make a history request. """ super(IPythonWidget, self)._started_channels() - self.kernel_manager.shell_channel.history(hist_access_type='tail', n=1000) - + self.kernel_manager.shell_channel.history(hist_access_type='tail', + n=1000) #--------------------------------------------------------------------------- # 'ConsoleWidget' public interface #--------------------------------------------------------------------------- @@ -413,8 +414,8 @@ class IPythonWidget(FrontendWidget): self.custom_edit_requested.emit(filename, line) elif not self.editor: self._append_plain_text('No default editor available.\n' - 'Specify a GUI text editor in the `IPythonWidget.editor` configurable\n' - 'to enable the %edit magic') + 'Specify a GUI text editor in the `IPythonWidget.editor` ' + 'configurable to enable the %edit magic') else: try: filename = '"%s"' % filename