diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py index 9b4c270..4680616 100644 --- a/IPython/frontend/qt/console/console_widget.py +++ b/IPython/frontend/qt/console/console_widget.py @@ -150,6 +150,7 @@ class ConsoleWidget(QtGui.QWidget): self._prompt = '' self._prompt_html = None self._prompt_pos = 0 + self._prompt_sep = '' self._reading = False self._reading_callback = None self._tab_width = 8 @@ -282,24 +283,35 @@ class ConsoleWidget(QtGui.QWidget): -------- A boolean indicating whether the source was executed. """ - if not hidden: - # Do everything here inside an edit block so continuation prompts - # are removed seamlessly via undo/redo. - cursor = self._control.textCursor() - cursor.beginEditBlock() - - if source is not None: - self.input_buffer = source - - self._append_plain_text('\n') - self._executing_input_buffer = self.input_buffer - self._executing = True - self._prompt_finished() + # WARNING: The order in which things happen here is very particular, in + # large part because our syntax highlighting is fragile. If you change + # something, test carefully! - real_source = self.input_buffer if source is None else source - complete = self._is_complete(real_source, interactive) - if complete: + # Decide what to execute. + if source is None: + source = self.input_buffer if not hidden: + # A newline is appended later, but it should be considered part + # of the input buffer. + source += '\n' + elif not hidden: + self.input_buffer = source + + # Execute the source or show a continuation prompt if it is incomplete. + complete = self._is_complete(source, interactive) + if hidden: + if complete: + self._execute(source, hidden) + else: + error = 'Incomplete noninteractive input: "%s"' + raise RuntimeError(error % source) + else: + if complete: + self._append_plain_text('\n') + self._executing_input_buffer = self.input_buffer + self._executing = True + self._prompt_finished() + # The maximum block count is only in effect during execution. # This ensures that _prompt_pos does not become invalid due to # text truncation. @@ -309,14 +321,18 @@ class ConsoleWidget(QtGui.QWidget): # disable the undo/redo history, but just to be safe: self._control.setUndoRedoEnabled(False) - self._execute(real_source, hidden) - elif hidden: - raise RuntimeError('Incomplete noninteractive input: "%s"' % source) - else: - self._show_continuation_prompt() + self._execute(source, hidden) + + else: + # Do this inside an edit block so continuation prompts are + # removed seamlessly via undo/redo. + cursor = self._control.textCursor() + cursor.beginEditBlock() - if not hidden: - cursor.endEditBlock() + self._append_plain_text('\n') + self._show_continuation_prompt() + + cursor.endEditBlock() return complete @@ -1115,7 +1131,7 @@ class ConsoleWidget(QtGui.QWidget): if not callback and not self.isVisible(): # If the user cannot see the widget, this function cannot return. - raise RuntimeError('Cannot synchronously read a line if the widget' + raise RuntimeError('Cannot synchronously read a line if the widget ' 'is not visible!') self._reading = True @@ -1212,6 +1228,7 @@ class ConsoleWidget(QtGui.QWidget): self._append_plain_text('\n') # Write the prompt. + self._append_plain_text(self._prompt_sep) if prompt is None: if self._prompt_html is None: self._append_plain_text(self._prompt) @@ -1238,8 +1255,6 @@ class ConsoleWidget(QtGui.QWidget): self._continuation_prompt = self._append_html_fetching_plain_text( self._continuation_prompt_html) - self._prompt_started() - class HistoryConsoleWidget(ConsoleWidget): """ A ConsoleWidget that keeps a history of the commands that have been diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py index 044e9b7..6ec6b23 100644 --- a/IPython/frontend/qt/console/ipython_widget.py +++ b/IPython/frontend/qt/console/ipython_widget.py @@ -179,7 +179,7 @@ class IPythonWidget(FrontendWidget): # Show a new prompt and save information about it so that it can be # updated later if the prompt number turns out to be wrong. - self._append_plain_text(input_sep) + self._prompt_sep = input_sep self._show_prompt(self._make_in_prompt(number), html=True) block = self._control.document().lastBlock() length = len(self._prompt) diff --git a/IPython/frontend/qt/console/scripts/ipythonqt.py b/IPython/frontend/qt/console/scripts/ipythonqt.py index f4409aa..f02d8d7 100755 --- a/IPython/frontend/qt/console/scripts/ipythonqt.py +++ b/IPython/frontend/qt/console/scripts/ipythonqt.py @@ -22,7 +22,12 @@ def main(): """ # Parse command line arguments. parser = ArgumentParser() - parser.add_argument('-e', '--existing', action='store_true', + parser.add_argument('-r', '--rich', action='store_true', + help='use a rich text frontend') + parser.add_argument('-t', '--tab-simple', action='store_true', + help='do tab completion ala a Unix terminal') + + parser.add_argument('--existing', action='store_true', help='connect to an existing kernel') parser.add_argument('--ip', type=str, default=LOCALHOST, help='set the kernel\'s IP address [default localhost]') @@ -32,13 +37,13 @@ def main(): help='set the SUB channel port [default random]') parser.add_argument('--rep', type=int, metavar='PORT', default=0, help='set the REP channel port [default random]') + group = parser.add_mutually_exclusive_group() group.add_argument('--pure', action='store_true', help = \ 'use a pure Python kernel instead of an IPython kernel') group.add_argument('--pylab', action='store_true', help='use a kernel with PyLab enabled') - parser.add_argument('--rich', action='store_true', - help='use a rich text frontend') + args = parser.parse_args() # Don't let Qt or ZMQ swallow KeyboardInterupts. @@ -70,6 +75,7 @@ def main(): widget = RichIPythonWidget() else: widget = IPythonWidget() + widget.gui_completion = not args.tab_simple widget.kernel_manager = kernel_manager widget.setWindowTitle('Python' if args.pure else 'IPython') widget.show()