##// END OF EJS Templates
BUG: Explicitly merge the __init__ and __new__ metaclass methods for MetaQObjectHasTraits. The MetaHasTraits code was not being executed previously.
BUG: Explicitly merge the __init__ and __new__ metaclass methods for MetaQObjectHasTraits. The MetaHasTraits code was not being executed previously.

File last commit:

r3193:c9d73807
r3213:6fb70e17
Show More
console_widget.py
1895 lines | 74.3 KiB | text/x-python | PythonLexer
epatters
Integrated the heart beat pausing/unpausing logic with the (Qt)KernelManager.
r3032 """ An abstract base class for console-type widgets.
Fernando Perez
Centralize Qt font selection into a generic utility....
r2986 """
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
epatters
Initial checkin of Qt frontend code.
r2602 # Standard library imports
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 from os.path import commonprefix
epatters
The ConsoleWidget now only pages text if it exceeds the height of the visible window.
r2843 import re
MinRK
html export fixes
r3154 import os
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 import sys
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 from textwrap import dedent
epatters
Initial checkin of Qt frontend code.
r2602
# System library imports
from PyQt4 import QtCore, QtGui
# Local imports
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 from IPython.config.configurable import Configurable
Fernando Perez
Centralize Qt font selection into a generic utility....
r2986 from IPython.frontend.qt.util import MetaQObjectHasTraits, get_font
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 from IPython.utils.traitlets import Bool, Enum, Int
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 from ansi_code_processor import QtAnsiCodeProcessor
epatters
Initial checkin of Qt frontend code.
r2602 from completion_widget import CompletionWidget
Fernando Perez
Centralize Qt font selection into a generic utility....
r2986 #-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
epatters
Initial checkin of Qt frontend code.
r2602
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 class ConsoleWidget(Configurable, QtGui.QWidget):
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 """ An abstract base class for console-type widgets. This class has
functionality for:
* Maintaining a prompt and editing region
* Providing the traditional Unix-style console keyboard shortcuts
* Performing tab completion
* Paging text
* Handling ANSI escape codes
ConsoleWidget also provides a number of utility methods that will be
convenient to implementors of a console-style widget.
epatters
Initial checkin of Qt frontend code.
r2602 """
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 __metaclass__ = MetaQObjectHasTraits
epatters
Initial checkin of Qt frontend code.
r2602
epatters
Fixed font changes not being propagated to CallTipWidget.
r3031 #------ Configuration ------------------------------------------------------
epatters
* Added option (disabled by default) to ConsoleWidget for overriding global/window-level shortcuts....
r2668 # Whether to process ANSI escape codes.
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 ansi_codes = Bool(True, config=True)
epatters
* Added option (disabled by default) to ConsoleWidget for overriding global/window-level shortcuts....
r2668
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 # The maximum number of lines of text before truncation. Specifying a
# non-positive number disables text truncation (not recommended).
buffer_size = Int(500, config=True)
epatters
* Added option (disabled by default) to ConsoleWidget for overriding global/window-level shortcuts....
r2668
epatters
Cleanup and minor UI fixes.
r2772 # Whether to use a list widget or plain text output for tab completion.
epatters
Changed the default completion style to text. Text completion now uses the pager.
r2917 gui_completion = Bool(False, config=True)
epatters
Made IPythonWidget and its subclasses Configurable.
r2884
# The type of underlying text widget to use. Valid values are 'plain', which
# specifies a QPlainTextEdit, and 'rich', which specifies a QTextEdit.
# NOTE: this value can only be specified during initialization.
kind = Enum(['plain', 'rich'], default_value='plain', config=True)
# The type of paging to use. Valid values are:
epatters
Integrated the heart beat pausing/unpausing logic with the (Qt)KernelManager.
r3032 # 'inside' : The widget pages like a traditional terminal.
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 # 'hsplit' : When paging is requested, the widget is split
# horizontally. The top pane contains the console, and the
# bottom pane contains the paged text.
# 'vsplit' : Similar to 'hsplit', except that a vertical splitter used.
# 'custom' : No action is taken by the widget beyond emitting a
# 'custom_page_requested(str)' signal.
# 'none' : The text is written directly to the console.
# NOTE: this value can only be specified during initialization.
paging = Enum(['inside', 'hsplit', 'vsplit', 'custom', 'none'],
default_value='inside', config=True)
epatters
* Added option (disabled by default) to ConsoleWidget for overriding global/window-level shortcuts....
r2668
# Whether to override ShortcutEvents for the keybindings defined by this
# widget (Ctrl+n, Ctrl+a, etc). Enable this if you want this widget to take
# priority (when it has focus) over, e.g., window-level menu shortcuts.
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 override_shortcuts = Bool(False)
epatters
* Added option (disabled by default) to ConsoleWidget for overriding global/window-level shortcuts....
r2668
epatters
Fixed font changes not being propagated to CallTipWidget.
r3031 #------ Signals ------------------------------------------------------------
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 # Signals that indicate ConsoleWidget state.
copy_available = QtCore.pyqtSignal(bool)
redo_available = QtCore.pyqtSignal(bool)
undo_available = QtCore.pyqtSignal(bool)
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 # Signal emitted when paging is needed and the paging style has been
# specified as 'custom'.
epatters
Added preliminary editor support to IPythonWidget.
r2793 custom_page_requested = QtCore.pyqtSignal(object)
epatters
* Added a pager with several different options to ConsoleWidget....
r2776
epatters
Fixed font changes not being propagated to CallTipWidget.
r3031 # Signal emitted when the font is changed.
font_changed = QtCore.pyqtSignal(QtGui.QFont)
#------ Protected class variables ------------------------------------------
epatters
Initial checkin of Qt frontend code.
r2602 _ctrl_down_remap = { QtCore.Qt.Key_B : QtCore.Qt.Key_Left,
QtCore.Qt.Key_F : QtCore.Qt.Key_Right,
QtCore.Qt.Key_A : QtCore.Qt.Key_Home,
QtCore.Qt.Key_E : QtCore.Qt.Key_End,
QtCore.Qt.Key_P : QtCore.Qt.Key_Up,
QtCore.Qt.Key_N : QtCore.Qt.Key_Down,
QtCore.Qt.Key_D : QtCore.Qt.Key_Delete, }
epatters
Fixed font changes not being propagated to CallTipWidget.
r3031
epatters
* Added ability to interrupt a kernel to FrontendWidget...
r2687 _shortcuts = set(_ctrl_down_remap.keys() +
epatters
* Ctrl-G and Escape now clear the input buffer....
r2924 [ QtCore.Qt.Key_C, QtCore.Qt.Key_G, QtCore.Qt.Key_O,
QtCore.Qt.Key_V ])
epatters
Initial checkin of Qt frontend code.
r2602
#---------------------------------------------------------------------------
epatters
Minor comment cleanup.
r2669 # 'QObject' interface
epatters
Initial checkin of Qt frontend code.
r2602 #---------------------------------------------------------------------------
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 def __init__(self, parent=None, **kw):
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """ Create a ConsoleWidget.
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 Parameters:
-----------
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 parent : QWidget, optional [default None]
The parent for this widget.
"""
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 QtGui.QWidget.__init__(self, parent)
Configurable.__init__(self, **kw)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 # Create the layout and underlying text widget.
layout = QtGui.QStackedLayout(self)
epatters
Improved the size hint for ConsoleWidget. We now acheive a width of 80 characters, through a mixture of better margin calculation and, well, fudging a little bit.
r2882 layout.setContentsMargins(0, 0, 0, 0)
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 self._control = self._create_control()
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 self._page_control = None
self._splitter = None
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 if self.paging in ('hsplit', 'vsplit'):
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 self._splitter = QtGui.QSplitter()
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 if self.paging == 'hsplit':
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 self._splitter.setOrientation(QtCore.Qt.Horizontal)
else:
self._splitter.setOrientation(QtCore.Qt.Vertical)
self._splitter.addWidget(self._control)
layout.addWidget(self._splitter)
else:
layout.addWidget(self._control)
# Create the paging widget, if necessary.
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 if self.paging in ('inside', 'hsplit', 'vsplit'):
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 self._page_control = self._create_page_control()
if self._splitter:
self._page_control.hide()
self._splitter.addWidget(self._page_control)
else:
layout.addWidget(self._page_control)
epatters
Initial checkin of Qt frontend code.
r2602
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 # Initialize protected variables. Some variables contain useful state
# information for subclasses; they should be considered read-only.
epatters
Initial checkin of Qt frontend code.
r2602 self._ansi_processor = QtAnsiCodeProcessor()
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._completion_widget = CompletionWidget(self._control)
epatters
* Added 'started_listening' and 'stopped_listening' signals to QtKernelManager. The FrontendWidget listens for these signals....
r2643 self._continuation_prompt = '> '
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 self._continuation_prompt_html = None
epatters
Initial checkin of Qt frontend code.
r2602 self._executing = False
epatters
Fixed resize flicker and drag safety.
r3043 self._filter_drag = False
self._filter_resize = False
epatters
Initial checkin of Qt frontend code.
r2602 self._prompt = ''
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 self._prompt_html = None
epatters
Initial checkin of Qt frontend code.
r2602 self._prompt_pos = 0
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 self._prompt_sep = ''
epatters
Initial checkin of Qt frontend code.
r2602 self._reading = False
epatters
Reading a line is now correctly implemented in ConsoleWidget.
r2706 self._reading_callback = None
epatters
* ConsoleWidget now has better support for non-GUI tab completion. Multiple matches are formatted into columns....
r2723 self._tab_width = 8
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 self._text_completing_pos = 0
MinRK
added 'don't ask again' option to HTML+PNG inline/external save dialog
r3174 self._filename = 'ipython.html'
self._png_mode=None
epatters
Initial checkin of Qt frontend code.
r2602
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 # Set a monospaced font.
self.reset_font()
epatters
Initial checkin of Qt frontend code.
r2602
MinRK
HTML/XML export now single menu entry...
r3162 # Configure actions.
action = QtGui.QAction('Print', None)
action.setEnabled(True)
MinRK
print shortcut -> ctrl+shift+P if there is a collision with ctrl+P
r3193 printkey = QtGui.QKeySequence(QtGui.QKeySequence.Print)
if printkey.matches("Ctrl+P") and sys.platform != 'darwin':
# only override if there is a collision
# Qt ctrl = cmd on OSX, so the match gets a false positive on darwin
printkey = "Ctrl+Shift+P"
action.setShortcut(printkey)
MinRK
HTML/XML export now single menu entry...
r3162 action.triggered.connect(self.print_)
self.addAction(action)
self._print_action = action
action = QtGui.QAction('Save as HTML/XML', None)
action.setEnabled(self.can_export())
action.setShortcut(QtGui.QKeySequence.Save)
action.triggered.connect(self.export)
self.addAction(action)
self._export_action = action
action = QtGui.QAction('Select All', None)
action.setEnabled(True)
action.setShortcut(QtGui.QKeySequence.SelectAll)
action.triggered.connect(self.select_all)
self.addAction(action)
self._select_all_action = action
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 def eventFilter(self, obj, event):
""" Reimplemented to ensure a console-like behavior in the underlying
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897 text widgets.
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """
epatters
Cleanup and minor UI fixes.
r2772 etype = event.type()
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897 if etype == QtCore.QEvent.KeyPress:
# Re-map keys for all filtered widgets.
key = event.key()
if self._control_key_down(event.modifiers()) and \
key in self._ctrl_down_remap:
new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
self._ctrl_down_remap[key],
QtCore.Qt.NoModifier)
QtGui.qApp.sendEvent(obj, new_event)
return True
elif obj == self._control:
return self._event_filter_console_keypress(event)
elif obj == self._page_control:
return self._event_filter_page_keypress(event)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937 # Make middle-click paste safe.
elif etype == QtCore.QEvent.MouseButtonRelease and \
event.button() == QtCore.Qt.MidButton and \
obj == self._control.viewport():
epatters
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
r2939 cursor = self._control.cursorForPosition(event.pos())
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937 self._control.setTextCursor(cursor)
self.paste(QtGui.QClipboard.Selection)
return True
epatters
Minor bug fix to ConsoleWidget scrollbar management.
r3009 # Manually adjust the scrollbars *after* a resize event is dispatched.
epatters
Fixed resize flicker and drag safety.
r3043 elif etype == QtCore.QEvent.Resize and not self._filter_resize:
self._filter_resize = True
QtGui.qApp.sendEvent(obj, event)
self._adjust_scrollbars()
self._filter_resize = False
return True
epatters
Minor bug fix to ConsoleWidget scrollbar management.
r3009
epatters
Cmd-C will no longer interrupt the kernel in Mac OS (only Ctrl-C will do this).
r2941 # Override shortcuts for all filtered widgets.
epatters
Cleanup and minor UI fixes.
r2772 elif etype == QtCore.QEvent.ShortcutOverride and \
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 self.override_shortcuts and \
epatters
Cleanup and minor UI fixes.
r2772 self._control_key_down(event.modifiers()) and \
event.key() in self._shortcuts:
event.accept()
epatters
Fixed resize flicker and drag safety.
r3043 # Ensure that drags are safe. The problem is that the drag starting
# logic, which determines whether the drag is a Copy or Move, is locked
# down in QTextControl. If the widget is editable, which it must be if
# we're not executing, the drag will be a Move. The following hack
# prevents QTextControl from deleting the text by clearing the selection
# when a drag leave event originating from this widget is dispatched.
# The fact that we have to clear the user's selection is unfortunate,
# but the alternative--trying to prevent Qt from using its hardwired
# drag logic and writing our own--is worse.
elif etype == QtCore.QEvent.DragEnter and \
obj == self._control.viewport() and \
event.source() == self._control.viewport():
self._filter_drag = True
elif etype == QtCore.QEvent.DragLeave and \
obj == self._control.viewport() and \
self._filter_drag:
cursor = self._control.textCursor()
cursor.clearSelection()
self._control.setTextCursor(cursor)
self._filter_drag = False
epatters
ConsoleWidget now supports drag and drop.
r3042 # Ensure that drops are safe.
elif etype == QtCore.QEvent.Drop and obj == self._control.viewport():
cursor = self._control.cursorForPosition(event.pos())
if self._in_buffer(cursor.position()):
text = unicode(event.mimeData().text())
epatters
Fixed bug reported by fperez and removed code with duplicated functionality.
r3048 self._insert_plain_text_into_buffer(cursor, text)
epatters
ConsoleWidget now supports drag and drop.
r3042
# Qt is expecting to get something here--drag and drop occurs in its
# own event loop. Send a DragLeave event to end it.
QtGui.qApp.sendEvent(obj, QtGui.QDragLeaveEvent())
epatters
* Added "smart copy" support to FrontendWidget and ConsoleWidget. Tabs are expanded and prompts are stripped....
r2971 return True
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 return super(ConsoleWidget, self).eventFilter(obj, event)
epatters
* Added option (disabled by default) to ConsoleWidget for overriding global/window-level shortcuts....
r2668
epatters
Minor comment cleanup.
r2669 #---------------------------------------------------------------------------
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 # 'QWidget' interface
#---------------------------------------------------------------------------
def sizeHint(self):
""" Reimplemented to suggest a size that is 80 characters wide and
25 lines high.
"""
font_metrics = QtGui.QFontMetrics(self.font)
epatters
Improved the size hint for ConsoleWidget. We now acheive a width of 80 characters, through a mixture of better margin calculation and, well, fudging a little bit.
r2882 margin = (self._control.frameWidth() +
self._control.document().documentMargin()) * 2
style = self.style()
splitwidth = style.pixelMetric(QtGui.QStyle.PM_SplitterWidth)
epatters
* Added a pager with several different options to ConsoleWidget....
r2776
epatters
Font width calculation fix for certain Mac OS systems.
r2935 # Note 1: Despite my best efforts to take the various margins into
# account, the width is still coming out a bit too small, so we include
# a fudge factor of one character here.
# Note 2: QFontMetrics.maxWidth is not used here or anywhere else due
# to a Qt bug on certain Mac OS systems where it returns 0.
width = font_metrics.width(' ') * 81 + margin
epatters
Improved the size hint for ConsoleWidget. We now acheive a width of 80 characters, through a mixture of better margin calculation and, well, fudging a little bit.
r2882 width += style.pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 if self.paging == 'hsplit':
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 width = width * 2 + splitwidth
epatters
Improved the size hint for ConsoleWidget. We now acheive a width of 80 characters, through a mixture of better margin calculation and, well, fudging a little bit.
r2882 height = font_metrics.height() * 25 + margin
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 if self.paging == 'vsplit':
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 height = height * 2 + splitwidth
return QtCore.QSize(width, height)
#---------------------------------------------------------------------------
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 # 'ConsoleWidget' public interface
epatters
Minor comment cleanup.
r2669 #---------------------------------------------------------------------------
epatters
* Added support to KernelManager for starting a subset of the four channels....
r2994 def can_copy(self):
""" Returns whether text can be copied to the clipboard.
"""
return self._control.textCursor().hasSelection()
epatters
* Added Cut support to ConsoleWidget....
r2990 def can_cut(self):
""" Returns whether text can be cut to the clipboard.
"""
cursor = self._control.textCursor()
return (cursor.hasSelection() and
self._in_buffer(cursor.anchor()) and
self._in_buffer(cursor.position()))
epatters
* Fixed bug where ConsoleWidget accepted non-ASCII characters on paste (and also rich text in 'rich' mode)...
r2762 def can_paste(self):
""" Returns whether text can be pasted from the clipboard.
"""
if self._control.textInteractionFlags() & QtCore.Qt.TextEditable:
epatters
First pass at unicode support in ConsoleWidget....
r3029 return not QtGui.QApplication.clipboard().text().isEmpty()
epatters
* Fixed bug where ConsoleWidget accepted non-ASCII characters on paste (and also rich text in 'rich' mode)...
r2762 return False
MinRK
HTML/XML export now single menu entry...
r3162 def can_export(self):
"""Returns whether we can export. Currently only rich widgets
can export html.
"""
return self.kind == "rich"
epatters
Fixed bug where the banner message was syntax highlighted when the frontend connected to a new kernel.
r2842 def clear(self, keep_input=True):
epatters
Cleaned up frontend-level kernel restart logic.
r3033 """ Clear the console.
Parameters:
-----------
keep_input : bool, optional (default True)
If set, restores the old input buffer if a new prompt is written.
epatters
* Added 'started_listening' and 'stopped_listening' signals to QtKernelManager. The FrontendWidget listens for these signals....
r2643 """
epatters
Cleaned up frontend-level kernel restart logic.
r3033 if self._executing:
self._control.clear()
else:
if keep_input:
input_buffer = self.input_buffer
self._control.clear()
self._show_prompt()
if keep_input:
self.input_buffer = input_buffer
epatters
* Added 'started_listening' and 'stopped_listening' signals to QtKernelManager. The FrontendWidget listens for these signals....
r2643
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 def copy(self):
epatters
* Added "smart copy" support to FrontendWidget and ConsoleWidget. Tabs are expanded and prompts are stripped....
r2971 """ Copy the currently selected text to the clipboard.
epatters
Initial checkin of Qt frontend code.
r2602 """
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.copy()
epatters
Initial checkin of Qt frontend code.
r2602
epatters
* Added Cut support to ConsoleWidget....
r2990 def cut(self):
""" Copy the currently selected text to the clipboard and delete it
if it's inside the input buffer.
"""
self.copy()
if self.can_cut():
self._control.textCursor().removeSelectedText()
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 def execute(self, source=None, hidden=False, interactive=False):
""" Executes source or the input buffer, possibly prompting for more
input.
Parameters:
-----------
source : str, optional
The source to execute. If not specified, the input buffer will be
used. If specified and 'hidden' is False, the input buffer will be
replaced with the source before execution.
hidden : bool, optional (default False)
If set, no output will be shown and the prompt will not be modified.
In other words, it will be completely invisible to the user that
an execution has occurred.
interactive : bool, optional (default False)
Whether the console is to treat the source as having been manually
entered by the user. The effect of this parameter depends on the
subclass implementation.
epatters
* Fixed history breakage due to recent refactoring....
r2689 Raises:
-------
RuntimeError
If incomplete input is given and 'hidden' is True. In this case,
epatters
Minor cleanup and bug fix.
r2771 it is not possible to prompt for more input.
epatters
* Fixed history breakage due to recent refactoring....
r2689
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 Returns:
--------
A boolean indicating whether the source was executed.
"""
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 # 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!
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 # Decide what to execute.
if source is None:
source = self.input_buffer
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 if not hidden:
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 # 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()
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 # The maximum block count is only in effect during execution.
# This ensures that _prompt_pos does not become invalid due to
# text truncation.
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.document().setMaximumBlockCount(self.buffer_size)
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864
# Setting a positive maximum block count will automatically
# disable the undo/redo history, but just to be safe:
self._control.setUndoRedoEnabled(False)
epatters
Form feeds are now properly supported by ConsoleWidget.
r3006 # Perform actual execution.
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 self._execute(source, hidden)
else:
# Do this inside an edit block so continuation prompts are
# removed seamlessly via undo/redo.
epatters
Fixed several bugs involving the insertion of new lines. Pressing Enter in the ConsoleWidget now works as expected.
r2896 cursor = self._get_end_cursor()
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 cursor.beginEditBlock()
epatters
Fixed several bugs involving the insertion of new lines. Pressing Enter in the ConsoleWidget now works as expected.
r2896 cursor.insertText('\n')
self._insert_continuation_prompt(cursor)
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 cursor.endEditBlock()
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864
epatters
Fixed scrolling bugs when using rich text mode. (Work around probable bug in Qt.)
r2914 # Do not do this inside the edit block. It works as expected
# when using a QPlainTextEdit control, but does not have an
# effect when using a QTextEdit. I believe this is a Qt bug.
self._control.moveCursor(QtGui.QTextCursor.End)
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 return complete
epatters
Initial checkin of Qt frontend code.
r2602
def _get_input_buffer(self):
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 """ The text that the user has entered entered at the current prompt.
"""
# If we're executing, the input buffer may not even exist anymore due to
epatters
* Added undo/redo support to ConsoleWidget...
r2615 # the limit imposed by 'buffer_size'. Therefore, we store it.
if self._executing:
return self._executing_input_buffer
epatters
Initial checkin of Qt frontend code.
r2602 cursor = self._get_end_cursor()
cursor.setPosition(self._prompt_pos, QtGui.QTextCursor.KeepAnchor)
epatters
First pass at unicode support in ConsoleWidget....
r3029 input_buffer = unicode(cursor.selection().toPlainText())
epatters
Initial checkin of Qt frontend code.
r2602
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 # Strip out continuation prompts.
epatters
* Added 'started_listening' and 'stopped_listening' signals to QtKernelManager. The FrontendWidget listens for these signals....
r2643 return input_buffer.replace('\n' + self._continuation_prompt, '\n')
epatters
Initial checkin of Qt frontend code.
r2602
def _set_input_buffer(self, string):
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 """ Replaces the text in the input buffer with 'string'.
"""
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 # For now, it is an error to modify the input buffer during execution.
if self._executing:
raise RuntimeError("Cannot change input buffer during execution.")
epatters
Setting the input buffer now respects HTML continuation prompts.
r2717 # Remove old text.
epatters
Initial checkin of Qt frontend code.
r2602 cursor = self._get_end_cursor()
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 cursor.beginEditBlock()
epatters
Initial checkin of Qt frontend code.
r2602 cursor.setPosition(self._prompt_pos, QtGui.QTextCursor.KeepAnchor)
epatters
Setting the input buffer now respects HTML continuation prompts.
r2717 cursor.removeSelectedText()
# Insert new text with continuation prompts.
epatters
Fixed bug reported by fperez and removed code with duplicated functionality.
r3048 self._insert_plain_text_into_buffer(self._get_prompt_cursor(), string)
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 cursor.endEditBlock()
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.moveCursor(QtGui.QTextCursor.End)
epatters
Initial checkin of Qt frontend code.
r2602
input_buffer = property(_get_input_buffer, _set_input_buffer)
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 def _get_font(self):
""" The base font being used by the ConsoleWidget.
"""
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 return self._control.document().defaultFont()
epatters
* Added API for setting the font of a ConsoleWidget....
r2665
def _set_font(self, font):
""" Sets the base font for the ConsoleWidget to the specified QFont.
"""
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 font_metrics = QtGui.QFontMetrics(font)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.setTabStopWidth(self.tab_width * font_metrics.width(' '))
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 self._completion_widget.setFont(font)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.document().setDefaultFont(font)
epatters
Fix to ensure that the paging widget is styled appropriately.
r2779 if self._page_control:
self._page_control.document().setDefaultFont(font)
epatters
* Added API for setting the font of a ConsoleWidget....
r2665
epatters
Fixed font changes not being propagated to CallTipWidget.
r3031 self.font_changed.emit(font)
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 font = property(_get_font, _set_font)
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937 def paste(self, mode=QtGui.QClipboard.Clipboard):
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """ Paste the contents of the clipboard into the input region.
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937
Parameters:
-----------
mode : QClipboard::Mode, optional [default QClipboard::Clipboard]
Controls which part of the system clipboard is used. This can be
used to access the selection clipboard in X11 and the Find buffer
in Mac OS. By default, the regular clipboard is used.
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 if self._control.textInteractionFlags() & QtCore.Qt.TextEditable:
epatters
Fixed bug reported by fperez and removed code with duplicated functionality.
r3048 # Make sure the paste is safe.
self._keep_cursor_in_buffer()
cursor = self._control.textCursor()
epatters
First pass at unicode support in ConsoleWidget....
r3029 # Remove any trailing newline, which confuses the GUI and forces the
# user to backspace.
text = unicode(QtGui.QApplication.clipboard().text(mode)).rstrip()
epatters
Fixed bug reported by fperez and removed code with duplicated functionality.
r3048 self._insert_plain_text_into_buffer(cursor, dedent(text))
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
Mark Voorhies
Add printing support....
r3091 def print_(self, printer = None):
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """ Print the contents of the ConsoleWidget to the specified QPrinter.
"""
MinRK
HTML/XML export now single menu entry...
r3162 if (not printer):
Mark Voorhies
Add printing support....
r3091 printer = QtGui.QPrinter()
if(QtGui.QPrintDialog(printer).exec_() != QtGui.QDialog.Accepted):
return
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.print_(printer)
MinRK
HTML/XML export now single menu entry...
r3162 def export(self, parent = None):
"""Export HTML/XML in various modes from one Dialog."""
parent = parent or None # sometimes parent is False
dialog = QtGui.QFileDialog(parent, 'Save Console as...')
dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
filters = [
MinRK
single HTML option, inline only asked if images present
r3165 'HTML with PNG figures (*.html *.htm)',
'XHTML with inline SVG figures (*.xhtml *.xml)'
MinRK
HTML/XML export now single menu entry...
r3162 ]
dialog.setNameFilters(filters)
if self._filename:
dialog.selectFile(self._filename)
root,ext = os.path.splitext(self._filename)
if ext.lower() in ('.xml', '.xhtml'):
dialog.selectNameFilter(filters[-1])
if dialog.exec_():
filename = str(dialog.selectedFiles()[0])
self._filename = filename
choice = str(dialog.selectedNameFilter())
if choice.startswith('XHTML'):
exporter = self.export_xhtml
else:
MinRK
single HTML option, inline only asked if images present
r3165 exporter = self.export_html
MinRK
HTML/XML export now single menu entry...
r3162
try:
return exporter(filename)
except Exception, e:
title = self.window().windowTitle()
msg = "Error while saving to: %s\n"%filename+str(e)
reply = QtGui.QMessageBox.warning(self, title, msg,
QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)
return None
MinRK
single HTML option, inline only asked if images present
r3165 def export_html(self, filename):
Mark Voorhies
Updated docstrings, following the convention in kernelmanager.py.
r3132 """ Export the contents of the ConsoleWidget as HTML.
Mark Voorhies
Add HTML export options...
r3125
Mark Voorhies
Updated docstrings, following the convention in kernelmanager.py.
r3132 Parameters:
-----------
MinRK
HTML/XML export now single menu entry...
r3162 filename : str
The file to be saved.
Mark Voorhies
Updated docstrings, following the convention in kernelmanager.py.
r3132 inline : bool, optional [default True]
If True, include images as inline PNGs. Otherwise,
include them as links to external PNG files, mimicking
MinRK
HTML/XML export now single menu entry...
r3162 web browsers' "Web Page, Complete" behavior.
Mark Voorhies
Add HTML export options...
r3125 """
MinRK
single HTML option, inline only asked if images present
r3165 # N.B. this is overly restrictive, but Qt's output is
# predictable...
img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
html = self.fix_html_encoding(
str(self._control.toHtml().toUtf8()))
MinRK
added 'don't ask again' option to HTML+PNG inline/external save dialog
r3174 if self._png_mode:
# preference saved, don't ask again
if img_re.search(html):
inline = (self._png_mode == 'inline')
else:
inline = True
elif img_re.search(html):
MinRK
single HTML option, inline only asked if images present
r3165 # there are images
MinRK
added 'don't ask again' option to HTML+PNG inline/external save dialog
r3174 widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout(widget)
MinRK
single HTML option, inline only asked if images present
r3165 title = self.window().windowTitle()
MinRK
added 'don't ask again' option to HTML+PNG inline/external save dialog
r3174 msg = "Exporting HTML with PNGs"
info = "Would you like inline PNGs (single large html file) or "+\
"external image files?"
checkbox = QtGui.QCheckBox("&Don't ask again")
checkbox.setShortcut('D')
ib = QtGui.QPushButton("&Inline", self)
ib.setShortcut('I')
eb = QtGui.QPushButton("&External", self)
eb.setShortcut('E')
box = QtGui.QMessageBox(QtGui.QMessageBox.Question, title, msg)
box.setInformativeText(info)
box.addButton(ib,QtGui.QMessageBox.NoRole)
box.addButton(eb,QtGui.QMessageBox.YesRole)
box.setDefaultButton(ib)
layout.setSpacing(0)
layout.addWidget(box)
layout.addWidget(checkbox)
widget.setLayout(layout)
widget.show()
reply = box.exec_()
MinRK
single HTML option, inline only asked if images present
r3165 inline = (reply == 0)
MinRK
added 'don't ask again' option to HTML+PNG inline/external save dialog
r3174 if checkbox.checkState():
# don't ask anymore, always use this choice
if inline:
self._png_mode='inline'
else:
self._png_mode='external'
MinRK
single HTML option, inline only asked if images present
r3165 else:
MinRK
added 'don't ask again' option to HTML+PNG inline/external save dialog
r3174 # no images
MinRK
single HTML option, inline only asked if images present
r3165 inline = True
MinRK
added 'don't ask again' option to HTML+PNG inline/external save dialog
r3174
MinRK
single HTML option, inline only asked if images present
r3165 if inline:
MinRK
HTML/XML export now single menu entry...
r3162 path = None
else:
root,ext = os.path.splitext(filename)
path = root+"_files"
if os.path.isfile(path):
raise OSError("%s exists, but is not a directory."%path)
f = open(filename, 'w')
try:
f.write(img_re.sub(
lambda x: self.image_tag(x, path = path, format = "png"),
html))
except Exception, e:
f.close()
raise e
else:
f.close()
return filename
Mark Voorhies
Add HTML export options...
r3125
MinRK
HTML/XML export now single menu entry...
r3162 def export_xhtml(self, filename):
Mark Voorhies
Updated docstrings, following the convention in kernelmanager.py.
r3132 """ Export the contents of the ConsoleWidget as XHTML with inline SVGs.
Mark Voorhies
Add HTML export options...
r3125 """
MinRK
HTML/XML export now single menu entry...
r3162 f = open(filename, 'w')
try:
# N.B. this is overly restrictive, but Qt's output is
# predictable...
img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
html = str(self._control.toHtml().toUtf8())
# Hack to make xhtml header -- note that we are not doing
# any check for valid xml
offset = html.find("<html>")
assert(offset > -1)
html = ('<html xmlns="http://www.w3.org/1999/xhtml">\n'+
html[offset+6:])
# And now declare UTF-8 encoding
html = self.fix_html_encoding(html)
f.write(img_re.sub(
lambda x: self.image_tag(x, path = None, format = "svg"),
html))
except Exception, e:
f.close()
raise e
else:
f.close()
return filename
Mark Voorhies
Add HTML export options...
r3125
Mark Voorhies
Specify character encoding in HTML HEAD...
r3149 def fix_html_encoding(self, html):
""" Return html string, with a UTF-8 declaration added to <HEAD>.
Assumes that html is Qt generated and has already been UTF-8 encoded
and coerced to a python string. If the expected head element is
not found, the given object is returned unmodified.
This patching is needed for proper rendering of some characters
(e.g., indented commands) when viewing exported HTML on a local
system (i.e., without seeing an encoding declaration in an HTTP
header).
C.f. http://www.w3.org/International/O-charset for details.
"""
offset = html.find("<head>")
if(offset > -1):
html = (html[:offset+6]+
'\n<meta http-equiv="Content-Type" '+
'content="text/html; charset=utf-8" />\n'+
html[offset+6:])
return html
Mark Voorhies
Updated docstrings, following the convention in kernelmanager.py.
r3132 def image_tag(self, match, path = None, format = "png"):
""" Return (X)HTML mark-up for the image-tag given by match.
Parameters
----------
match : re.SRE_Match
A match to an HTML image tag as exported by Qt, with
match.group("Name") containing the matched image ID.
path : string|None, optional [default None]
If not None, specifies a path to which supporting files
may be written (e.g., for linked images).
If None, all images are to be included inline.
format : "png"|"svg", optional [default "png"]
Format for returned or referenced images.
Subclasses supporting image display should override this
method.
"""
Mark Voorhies
Add HTML export options...
r3125
# Default case -- not enough information to generate tag
return ""
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 def prompt_to_top(self):
""" Moves the prompt to the top of the viewport.
"""
if not self._executing:
epatters
Fixed more issues with ConsoleWidget scrollbar management.
r3017 prompt_cursor = self._get_prompt_cursor()
if self._get_cursor().blockNumber() < prompt_cursor.blockNumber():
self._set_cursor(prompt_cursor)
self._set_top_cursor(prompt_cursor)
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 def redo(self):
""" Redo the last operation. If there is no operation to redo, nothing
happens.
"""
self._control.redo()
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 def reset_font(self):
""" Sets the font to the default fixed-width font for this platform.
"""
if sys.platform == 'win32':
Fernando Perez
Centralize Qt font selection into a generic utility....
r2986 # Consolas ships with Vista/Win7, fallback to Courier if needed
family, fallback = 'Consolas', 'Courier'
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 elif sys.platform == 'darwin':
Fernando Perez
Centralize Qt font selection into a generic utility....
r2986 # OSX always has Monaco, no need for a fallback
family, fallback = 'Monaco', None
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 else:
Fernando Perez
Note Consolas on linux will be used only until we have font configuration.
r2989 # FIXME: remove Consolas as a default on Linux once our font
# selections are configurable by the user.
Fernando Perez
Centralize Qt font selection into a generic utility....
r2986 family, fallback = 'Consolas', 'Monospace'
font = get_font(family, fallback)
epatters
ConsoleWidget now prefers Consolas to Courier in Windows.
r2981 font.setPointSize(QtGui.qApp.font().pointSize())
epatters
* Added API for setting the font of a ConsoleWidget....
r2665 font.setStyleHint(QtGui.QFont.TypeWriter)
self._set_font(font)
epatters
* ConsoleWidget now has better support for non-GUI tab completion. Multiple matches are formatted into columns....
r2723
Fernando Perez
Add Ctrl-+/- to increase/decrease font size....
r3081 def change_font_size(self, delta):
"""Change the font size by the specified amount (in points).
"""
font = self.font
font.setPointSize(font.pointSize() + delta)
self._set_font(font)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 def select_all(self):
""" Selects all the text in the buffer.
"""
self._control.selectAll()
epatters
* ConsoleWidget now has better support for non-GUI tab completion. Multiple matches are formatted into columns....
r2723 def _get_tab_width(self):
""" The width (in terms of space characters) for tab characters.
"""
return self._tab_width
def _set_tab_width(self, tab_width):
""" Sets the width (in terms of space characters) for tab characters.
"""
font_metrics = QtGui.QFontMetrics(self.font)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.setTabStopWidth(tab_width * font_metrics.width(' '))
epatters
* ConsoleWidget now has better support for non-GUI tab completion. Multiple matches are formatted into columns....
r2723
self._tab_width = tab_width
tab_width = property(_get_tab_width, _set_tab_width)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
def undo(self):
""" Undo the last operation. If there is no operation to undo, nothing
happens.
"""
self._control.undo()
epatters
Initial checkin of Qt frontend code.
r2602 #---------------------------------------------------------------------------
# 'ConsoleWidget' abstract interface
#---------------------------------------------------------------------------
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 def _is_complete(self, source, interactive):
""" Returns whether 'source' can be executed. When triggered by an
Enter/Return key press, 'interactive' is True; otherwise, it is
False.
"""
raise NotImplementedError
def _execute(self, source, hidden):
""" Execute 'source'. If 'hidden', do not show any output.
epatters
Initial checkin of Qt frontend code.
r2602 """
raise NotImplementedError
def _prompt_started_hook(self):
""" Called immediately after a new prompt is displayed.
"""
pass
def _prompt_finished_hook(self):
""" Called immediately after a prompt is finished, i.e. when some input
will be processed and a new prompt displayed.
"""
pass
def _up_pressed(self):
""" Called when the up key is pressed. Returns whether to continue
processing the event.
"""
return True
def _down_pressed(self):
""" Called when the down key is pressed. Returns whether to continue
processing the event.
"""
return True
def _tab_pressed(self):
""" Called when the tab key is pressed. Returns whether to continue
processing the event.
"""
return False
#--------------------------------------------------------------------------
# 'ConsoleWidget' protected interface
#--------------------------------------------------------------------------
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 def _append_html(self, html):
""" Appends html at the end of the console buffer.
"""
cursor = self._get_end_cursor()
self._insert_html(cursor, html)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 def _append_html_fetching_plain_text(self, html):
""" Appends 'html', then returns the plain text version of it.
"""
cursor = self._get_end_cursor()
epatters
Fixed bug with ConsoleWidget smart paste.
r2787 return self._insert_html_fetching_plain_text(cursor, html)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 def _append_plain_text(self, text):
""" Appends plain text at the end of the console buffer, processing
ANSI codes if enabled.
"""
cursor = self._get_end_cursor()
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 self._insert_plain_text(cursor, text)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 def _append_plain_text_keeping_prompt(self, text):
""" Writes 'text' after the current prompt, then restores the old prompt
with its old input buffer.
"""
input_buffer = self.input_buffer
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._append_plain_text('\n')
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 self._prompt_finished()
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._append_plain_text(text)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 self._show_prompt()
self.input_buffer = input_buffer
epatters
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
r2939 def _cancel_text_completion(self):
""" If text completion is progress, cancel it.
"""
if self._text_completing_pos:
self._clear_temporary_buffer()
self._text_completing_pos = 0
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 def _clear_temporary_buffer(self):
""" Clears the "temporary text" buffer, i.e. all the text following
the prompt region.
"""
epatters
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
r2939 # Select and remove all text below the input buffer.
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 cursor = self._get_prompt_cursor()
epatters
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
r2939 prompt = self._continuation_prompt.lstrip()
while cursor.movePosition(QtGui.QTextCursor.NextBlock):
temp_cursor = QtGui.QTextCursor(cursor)
temp_cursor.select(QtGui.QTextCursor.BlockUnderCursor)
epatters
First pass at unicode support in ConsoleWidget....
r3029 text = unicode(temp_cursor.selection().toPlainText()).lstrip()
epatters
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
r2939 if not text.startswith(prompt):
break
else:
# We've reached the end of the input buffer and no text follows.
return
cursor.movePosition(QtGui.QTextCursor.Left) # Grab the newline.
cursor.movePosition(QtGui.QTextCursor.End,
QtGui.QTextCursor.KeepAnchor)
cursor.removeSelectedText()
# After doing this, we have no choice but to clear the undo/redo
# history. Otherwise, the text is not "temporary" at all, because it
# can be recalled with undo/redo. Unfortunately, Qt does not expose
# fine-grained control to the undo/redo system.
if self._control.isUndoRedoEnabled():
self._control.setUndoRedoEnabled(False)
self._control.setUndoRedoEnabled(True)
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 def _complete_with_items(self, cursor, items):
""" Performs completion with 'items' at the specified cursor location.
"""
epatters
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
r2939 self._cancel_text_completion()
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 if len(items) == 1:
cursor.setPosition(self._control.textCursor().position(),
QtGui.QTextCursor.KeepAnchor)
cursor.insertText(items[0])
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 elif len(items) > 1:
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 current_pos = self._control.textCursor().position()
prefix = commonprefix(items)
if prefix:
cursor.setPosition(current_pos, QtGui.QTextCursor.KeepAnchor)
cursor.insertText(prefix)
current_pos = cursor.position()
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 if self.gui_completion:
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 cursor.movePosition(QtGui.QTextCursor.Left, n=len(prefix))
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._completion_widget.show_items(cursor, items)
else:
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 cursor.beginEditBlock()
self._append_plain_text('\n')
epatters
Changed the default completion style to text. Text completion now uses the pager.
r2917 self._page(self._format_as_columns(items))
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 cursor.endEditBlock()
cursor.setPosition(current_pos)
self._control.moveCursor(QtGui.QTextCursor.End)
self._control.setTextCursor(cursor)
self._text_completing_pos = current_pos
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
epatters
* Added Cut support to ConsoleWidget....
r2990 def _context_menu_make(self, pos):
""" Creates a context menu for the given QPoint (in widget coordinates).
"""
MinRK
HTML/XML export now single menu entry...
r3162 menu = QtGui.QMenu(self)
epatters
* Added Cut support to ConsoleWidget....
r2990
cut_action = menu.addAction('Cut', self.cut)
cut_action.setEnabled(self.can_cut())
cut_action.setShortcut(QtGui.QKeySequence.Cut)
copy_action = menu.addAction('Copy', self.copy)
copy_action.setEnabled(self.can_copy())
copy_action.setShortcut(QtGui.QKeySequence.Copy)
paste_action = menu.addAction('Paste', self.paste)
paste_action.setEnabled(self.can_paste())
paste_action.setShortcut(QtGui.QKeySequence.Paste)
menu.addSeparator()
MinRK
HTML/XML export now single menu entry...
r3162 menu.addAction(self._select_all_action)
menu.addSeparator()
menu.addAction(self._export_action)
menu.addAction(self._print_action)
epatters
* Added Cut support to ConsoleWidget....
r2990 return menu
MinRK
command should not be aliased to control by default
r3163 def _control_key_down(self, modifiers, include_command=False):
epatters
Fixed wonky ConsoleWidget keyboard shortcuts on Mac OS.
r2671 """ Given a KeyboardModifiers flags object, return whether the Control
epatters
Cmd-C will no longer interrupt the kernel in Mac OS (only Ctrl-C will do this).
r2941 key is down.
epatters
Fixed wonky ConsoleWidget keyboard shortcuts on Mac OS.
r2671
epatters
Cmd-C will no longer interrupt the kernel in Mac OS (only Ctrl-C will do this).
r2941 Parameters:
-----------
include_command : bool, optional (default True)
Whether to treat the Command key as a (mutually exclusive) synonym
for Control when in Mac OS.
"""
# Note that on Mac OS, ControlModifier corresponds to the Command key
# while MetaModifier corresponds to the Control key.
epatters
Fixed wonky ConsoleWidget keyboard shortcuts on Mac OS.
r2671 if sys.platform == 'darwin':
epatters
Cmd-C will no longer interrupt the kernel in Mac OS (only Ctrl-C will do this).
r2941 down = include_command and (modifiers & QtCore.Qt.ControlModifier)
return bool(down) ^ bool(modifiers & QtCore.Qt.MetaModifier)
else:
return bool(modifiers & QtCore.Qt.ControlModifier)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 def _create_control(self):
epatters
Cleanup and minor UI fixes.
r2772 """ Creates and connects the underlying text widget.
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937 # Create the underlying control.
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 if self.kind == 'plain':
epatters
* Added "smart copy" support to FrontendWidget and ConsoleWidget. Tabs are expanded and prompts are stripped....
r2971 control = QtGui.QPlainTextEdit()
epatters
Made IPythonWidget and its subclasses Configurable.
r2884 elif self.kind == 'rich':
epatters
* Added "smart copy" support to FrontendWidget and ConsoleWidget. Tabs are expanded and prompts are stripped....
r2971 control = QtGui.QTextEdit()
epatters
* Fixed bug where ConsoleWidget accepted non-ASCII characters on paste (and also rich text in 'rich' mode)...
r2762 control.setAcceptRichText(False)
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937
# Install event filters. The filter on the viewport is needed for
epatters
* Added "smart copy" support to FrontendWidget and ConsoleWidget. Tabs are expanded and prompts are stripped....
r2971 # mouse events and drag events.
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 control.installEventFilter(self)
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937 control.viewport().installEventFilter(self)
# Connect signals.
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 control.cursorPositionChanged.connect(self._cursor_position_changed)
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 control.customContextMenuRequested.connect(
self._custom_context_menu_requested)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 control.copyAvailable.connect(self.copy_available)
control.redoAvailable.connect(self.redo_available)
control.undoAvailable.connect(self.undo_available)
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 # Hijack the document size change signal to prevent Qt from adjusting
# the viewport's scrollbar. We are relying on an implementation detail
# of Q(Plain)TextEdit here, which is potentially dangerous, but without
# this functionality we cannot create a nice terminal interface.
layout = control.document().documentLayout()
layout.documentSizeChanged.disconnect()
layout.documentSizeChanged.connect(self._adjust_scrollbars)
epatters
Made middle-click paste safe. Fixes bug reported by fperez.
r2937 # Configure the control.
control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
epatters
* Added support for prompt and history requests to the kernel manager and Qt console frontend....
r2844 control.setReadOnly(True)
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864 control.setUndoRedoEnabled(False)
epatters
Cleanup and minor UI fixes.
r2772 control.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 return control
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 def _create_page_control(self):
""" Creates and connects the underlying paging widget.
"""
epatters
Added support for HTML paging and HTML page payloads.
r3014 if self.kind == 'plain':
control = QtGui.QPlainTextEdit()
elif self.kind == 'rich':
control = QtGui.QTextEdit()
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 control.installEventFilter(self)
control.setReadOnly(True)
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864 control.setUndoRedoEnabled(False)
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 control.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
return control
def _event_filter_console_keypress(self, event):
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """ Filter key events for the underlying text widget to create a
console-like interface.
"""
intercepted = False
cursor = self._control.textCursor()
position = cursor.position()
epatters
Cleanup and minor UI fixes.
r2772 key = event.key()
ctrl_down = self._control_key_down(event.modifiers())
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 alt_down = event.modifiers() & QtCore.Qt.AltModifier
shift_down = event.modifiers() & QtCore.Qt.ShiftModifier
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 #------ Special sequences ----------------------------------------------
epatters
* Added "smart copy" support to FrontendWidget and ConsoleWidget. Tabs are expanded and prompts are stripped....
r2971 if event.matches(QtGui.QKeySequence.Copy):
self.copy()
intercepted = True
epatters
* Added Cut support to ConsoleWidget....
r2990 elif event.matches(QtGui.QKeySequence.Cut):
self.cut()
intercepted = True
epatters
* Added "smart copy" support to FrontendWidget and ConsoleWidget. Tabs are expanded and prompts are stripped....
r2971 elif event.matches(QtGui.QKeySequence.Paste):
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self.paste()
intercepted = True
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 #------ Special modifier logic -----------------------------------------
elif key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
intercepted = True
# Special handling when tab completing in text mode.
self._cancel_text_completion()
if self._in_buffer(position):
if self._reading:
self._append_plain_text('\n')
self._reading = False
if self._reading_callback:
self._reading_callback()
epatters
Pressing Enter now always executes when the input buffer has one line.
r3021 # If the input buffer is a single line or there is only
# whitespace after the cursor, execute. Otherwise, split the
# line with a continuation prompt.
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 elif not self._executing:
cursor.movePosition(QtGui.QTextCursor.End,
QtGui.QTextCursor.KeepAnchor)
at_end = cursor.selectedText().trimmed().isEmpty()
epatters
Pressing Enter now always executes when the input buffer has one line.
r3021 single_line = (self._get_end_cursor().blockNumber() ==
self._get_prompt_cursor().blockNumber())
if (at_end or shift_down or single_line) and not ctrl_down:
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 self.execute(interactive = not shift_down)
else:
# Do this inside an edit block for clean undo/redo.
cursor.beginEditBlock()
cursor.setPosition(position)
cursor.insertText('\n')
self._insert_continuation_prompt(cursor)
cursor.endEditBlock()
# Ensure that the whole input buffer is visible.
# FIXME: This will not be usable if the input buffer is
# taller than the console widget.
self._control.moveCursor(QtGui.QTextCursor.End)
self._control.setTextCursor(cursor)
#------ Control/Cmd modifier -------------------------------------------
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 elif ctrl_down:
epatters
* Ctrl-G and Escape now clear the input buffer....
r2924 if key == QtCore.Qt.Key_G:
self._keyboard_quit()
intercepted = True
elif key == QtCore.Qt.Key_K:
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 if self._in_buffer(position):
cursor.movePosition(QtGui.QTextCursor.EndOfLine,
QtGui.QTextCursor.KeepAnchor)
epatters
Pressing Ctrl-K at the end of a line now deletes the newline, as expected.
r2886 if not cursor.hasSelection():
# Line deletion (remove continuation prompt)
cursor.movePosition(QtGui.QTextCursor.NextBlock,
QtGui.QTextCursor.KeepAnchor)
cursor.movePosition(QtGui.QTextCursor.Right,
QtGui.QTextCursor.KeepAnchor,
len(self._continuation_prompt))
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor.removeSelectedText()
intercepted = True
epatters
* Added support for Ctrl-L per Fernando's request....
r2880 elif key == QtCore.Qt.Key_L:
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 self.prompt_to_top()
epatters
* Added support for Ctrl-L per Fernando's request....
r2880 intercepted = True
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897 elif key == QtCore.Qt.Key_O:
if self._page_control and self._page_control.isVisible():
self._page_control.setFocus()
Fernando Perez
Add Ctrl-+/- to increase/decrease font size....
r3081 intercepted = True
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 elif key == QtCore.Qt.Key_Y:
self.paste()
intercepted = True
epatters
Fixed bugs reported by minrk involving deletion of the input prompt.
r2936 elif key in (QtCore.Qt.Key_Backspace, QtCore.Qt.Key_Delete):
intercepted = True
Fernando Perez
Add Ctrl-+/- to increase/decrease font size....
r3081 elif key == QtCore.Qt.Key_Plus:
self.change_font_size(1)
intercepted = True
elif key == QtCore.Qt.Key_Minus:
self.change_font_size(-1)
intercepted = True
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 #------ Alt modifier ---------------------------------------------------
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 elif alt_down:
if key == QtCore.Qt.Key_B:
self._set_cursor(self._get_word_start_cursor(position))
intercepted = True
elif key == QtCore.Qt.Key_F:
self._set_cursor(self._get_word_end_cursor(position))
intercepted = True
elif key == QtCore.Qt.Key_Backspace:
cursor = self._get_word_start_cursor(position)
cursor.setPosition(position, QtGui.QTextCursor.KeepAnchor)
cursor.removeSelectedText()
intercepted = True
elif key == QtCore.Qt.Key_D:
cursor = self._get_word_end_cursor(position)
cursor.setPosition(position, QtGui.QTextCursor.KeepAnchor)
cursor.removeSelectedText()
intercepted = True
epatters
Fixed bugs reported by minrk involving deletion of the input prompt.
r2936 elif key == QtCore.Qt.Key_Delete:
intercepted = True
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897 elif key == QtCore.Qt.Key_Greater:
self._control.moveCursor(QtGui.QTextCursor.End)
intercepted = True
elif key == QtCore.Qt.Key_Less:
self._control.setTextCursor(self._get_prompt_cursor())
intercepted = True
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 #------ No modifiers ---------------------------------------------------
epatters
* Ctrl-G and Escape now clear the input buffer....
r2924
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 else:
MinRK
fixed some cursor selection behavior
r3082 if shift_down:
anchormode=QtGui.QTextCursor.KeepAnchor
else:
anchormode=QtGui.QTextCursor.MoveAnchor
epatters
Added support for Ctrl-Enter (unconditionally enter a newline) to ConsoleWidget....
r2985 if key == QtCore.Qt.Key_Escape:
epatters
* Ctrl-G and Escape now clear the input buffer....
r2924 self._keyboard_quit()
intercepted = True
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 elif key == QtCore.Qt.Key_Up:
if self._reading or not self._up_pressed():
intercepted = True
else:
prompt_line = self._get_prompt_cursor().blockNumber()
intercepted = cursor.blockNumber() <= prompt_line
elif key == QtCore.Qt.Key_Down:
if self._reading or not self._down_pressed():
intercepted = True
else:
end_line = self._get_end_cursor().blockNumber()
intercepted = cursor.blockNumber() == end_line
elif key == QtCore.Qt.Key_Tab:
epatters
Minor cleanup (again).
r2849 if not self._reading:
intercepted = not self._tab_pressed()
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
elif key == QtCore.Qt.Key_Left:
epatters
The Left and Right arrow keys now traverse the input buffer as expected.
r3016
# Move to the previous line
line, col = cursor.blockNumber(), cursor.columnNumber()
if line > self._get_prompt_cursor().blockNumber() and \
col == len(self._continuation_prompt):
MinRK
fixed some cursor selection behavior
r3082 self._control.moveCursor(QtGui.QTextCursor.PreviousBlock,
mode=anchormode)
self._control.moveCursor(QtGui.QTextCursor.EndOfBlock,
mode=anchormode)
epatters
The Left and Right arrow keys now traverse the input buffer as expected.
r3016 intercepted = True
# Regular left movement
else:
intercepted = not self._in_buffer(position - 1)
elif key == QtCore.Qt.Key_Right:
original_block_number = cursor.blockNumber()
MinRK
fixed some cursor selection behavior
r3082 cursor.movePosition(QtGui.QTextCursor.Right,
mode=anchormode)
epatters
The Left and Right arrow keys now traverse the input buffer as expected.
r3016 if cursor.blockNumber() != original_block_number:
cursor.movePosition(QtGui.QTextCursor.Right,
MinRK
fixed some cursor selection behavior
r3082 n=len(self._continuation_prompt),
mode=anchormode)
epatters
The Left and Right arrow keys now traverse the input buffer as expected.
r3016 self._set_cursor(cursor)
intercepted = True
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
elif key == QtCore.Qt.Key_Home:
start_line = cursor.blockNumber()
if start_line == self._get_prompt_cursor().blockNumber():
start_pos = self._prompt_pos
else:
epatters
Pressing Ctrl-K at the end of a line now deletes the newline, as expected.
r2886 cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
QtGui.QTextCursor.KeepAnchor)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 start_pos = cursor.position()
start_pos += len(self._continuation_prompt)
epatters
Pressing Ctrl-K at the end of a line now deletes the newline, as expected.
r2886 cursor.setPosition(position)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 if shift_down and self._in_buffer(position):
epatters
Pressing Ctrl-K at the end of a line now deletes the newline, as expected.
r2886 cursor.setPosition(start_pos, QtGui.QTextCursor.KeepAnchor)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 else:
epatters
Pressing Ctrl-K at the end of a line now deletes the newline, as expected.
r2886 cursor.setPosition(start_pos)
self._set_cursor(cursor)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 intercepted = True
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 elif key == QtCore.Qt.Key_Backspace:
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
# Line deletion (remove continuation prompt)
epatters
Fixed bugs reported by minrk involving deletion of the input prompt.
r2936 line, col = cursor.blockNumber(), cursor.columnNumber()
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 if not self._reading and \
epatters
Fixed bugs reported by minrk involving deletion of the input prompt.
r2936 col == len(self._continuation_prompt) and \
line > self._get_prompt_cursor().blockNumber():
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864 cursor.beginEditBlock()
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
QtGui.QTextCursor.KeepAnchor)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor.removeSelectedText()
epatters
Fixed rare bug with continuation prompt deletion.
r2785 cursor.deletePreviousChar()
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864 cursor.endEditBlock()
epatters
Fixed rare bug with continuation prompt deletion.
r2785 intercepted = True
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
# Regular backwards deletion
else:
anchor = cursor.anchor()
if anchor == position:
intercepted = not self._in_buffer(position - 1)
else:
intercepted = not self._in_buffer(min(anchor, position))
elif key == QtCore.Qt.Key_Delete:
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864
# Line deletion (remove continuation prompt)
epatters
Fixed bugs reported by minrk involving deletion of the input prompt.
r2936 if not self._reading and self._in_buffer(position) and \
cursor.atBlockEnd() and not cursor.hasSelection():
epatters
* The ConsoleWidget now has full undo/redo support. Previously, the undo/redo history was cleared after every continuation prompt. This is no longer the case....
r2864 cursor.movePosition(QtGui.QTextCursor.NextBlock,
QtGui.QTextCursor.KeepAnchor)
cursor.movePosition(QtGui.QTextCursor.Right,
QtGui.QTextCursor.KeepAnchor,
len(self._continuation_prompt))
cursor.removeSelectedText()
intercepted = True
# Regular forwards deletion:
else:
anchor = cursor.anchor()
intercepted = (not self._in_buffer(anchor) or
not self._in_buffer(position))
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
epatters
* Fixed context menu breakge after previous commit....
r2737 # Don't move the cursor if control is down to allow copy-paste using
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 # the keyboard in any part of the buffer.
if not ctrl_down:
self._keep_cursor_in_buffer()
return intercepted
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 def _event_filter_page_keypress(self, event):
""" Filter key events for the paging widget to create console-like
interface.
"""
key = event.key()
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897 ctrl_down = self._control_key_down(event.modifiers())
alt_down = event.modifiers() & QtCore.Qt.AltModifier
if ctrl_down:
if key == QtCore.Qt.Key_O:
self._control.setFocus()
intercept = True
epatters
* Added a pager with several different options to ConsoleWidget....
r2776
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897 elif alt_down:
if key == QtCore.Qt.Key_Greater:
self._page_control.moveCursor(QtGui.QTextCursor.End)
intercepted = True
elif key == QtCore.Qt.Key_Less:
self._page_control.moveCursor(QtGui.QTextCursor.Start)
intercepted = True
elif key in (QtCore.Qt.Key_Q, QtCore.Qt.Key_Escape):
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 if self._splitter:
self._page_control.hide()
else:
self.layout().setCurrentWidget(self._control)
return True
elif key in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
epatters
Numerous usability enhancements to the Qt console widget, particularly with regard to key bindings.
r2897 QtCore.Qt.Key_PageDown,
QtCore.Qt.NoModifier)
QtGui.qApp.sendEvent(self._page_control, new_event)
return True
elif key == QtCore.Qt.Key_Backspace:
new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
QtCore.Qt.Key_PageUp,
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 QtCore.Qt.NoModifier)
QtGui.qApp.sendEvent(self._page_control, new_event)
return True
return False
epatters
* Fleshed out IPythonWidget's style control....
r2725 def _format_as_columns(self, items, separator=' '):
epatters
* ConsoleWidget now has better support for non-GUI tab completion. Multiple matches are formatted into columns....
r2723 """ Transform a list of strings into a single string with columns.
Parameters
----------
epatters
* Fleshed out IPythonWidget's style control....
r2725 items : sequence of strings
epatters
* ConsoleWidget now has better support for non-GUI tab completion. Multiple matches are formatted into columns....
r2723 The strings to process.
separator : str, optional [default is two spaces]
The string that separates columns.
Returns
-------
The formatted string.
"""
epatters
Replaced external module for formatting columns with adapted code.
r2724 # Note: this code is adapted from columnize 0.3.2.
# See http://code.google.com/p/pycolumnize/
epatters
Fixed regressions in the pure Python kernel.
r2867 # Calculate the number of characters available.
epatters
Cleanup and minor UI fixes.
r2772 width = self._control.viewport().width()
epatters
Font width calculation fix for certain Mac OS systems.
r2935 char_width = QtGui.QFontMetrics(self.font).width(' ')
epatters
Fixed regressions in the pure Python kernel.
r2867 displaywidth = max(10, (width / char_width) - 1)
epatters
Replaced external module for formatting columns with adapted code.
r2724
epatters
* Fleshed out IPythonWidget's style control....
r2725 # Some degenerate cases.
epatters
Replaced external module for formatting columns with adapted code.
r2724 size = len(items)
if size == 0:
epatters
* Fleshed out IPythonWidget's style control....
r2725 return '\n'
epatters
Replaced external module for formatting columns with adapted code.
r2724 elif size == 1:
epatters
First pass at unicode support in ConsoleWidget....
r3029 return '%s\n' % items[0]
epatters
Replaced external module for formatting columns with adapted code.
r2724
# Try every row count from 1 upwards
array_index = lambda nrows, row, col: nrows*col + row
for nrows in range(1, size):
ncols = (size + nrows - 1) // nrows
colwidths = []
totwidth = -len(separator)
for col in range(ncols):
# Get max column width for this column
colwidth = 0
for row in range(nrows):
i = array_index(nrows, row, col)
if i >= size: break
x = items[i]
colwidth = max(colwidth, len(x))
colwidths.append(colwidth)
totwidth += colwidth + len(separator)
if totwidth > displaywidth:
break
if totwidth <= displaywidth:
break
# The smallest number of rows computed and the max widths for each
# column has been obtained. Now we just have to format each of the rows.
string = ''
for row in range(nrows):
texts = []
for col in range(ncols):
i = row + nrows*col
if i >= size:
texts.append('')
else:
texts.append(items[i])
while texts and not texts[-1]:
del texts[-1]
for col in range(len(texts)):
texts[col] = texts[col].ljust(colwidths[col])
epatters
First pass at unicode support in ConsoleWidget....
r3029 string += '%s\n' % separator.join(texts)
epatters
Replaced external module for formatting columns with adapted code.
r2724 return string
epatters
* ConsoleWidget now has better support for non-GUI tab completion. Multiple matches are formatted into columns....
r2723
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 def _get_block_plain_text(self, block):
""" Given a QTextBlock, return its unformatted text.
"""
cursor = QtGui.QTextCursor(block)
cursor.movePosition(QtGui.QTextCursor.StartOfBlock)
cursor.movePosition(QtGui.QTextCursor.EndOfBlock,
QtGui.QTextCursor.KeepAnchor)
epatters
First pass at unicode support in ConsoleWidget....
r3029 return unicode(cursor.selection().toPlainText())
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
def _get_cursor(self):
""" Convenience method that returns a cursor for the current position.
"""
return self._control.textCursor()
epatters
Initial checkin of Qt frontend code.
r2602
def _get_end_cursor(self):
""" Convenience method that returns a cursor for the last character.
"""
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor = self._control.textCursor()
epatters
Initial checkin of Qt frontend code.
r2602 cursor.movePosition(QtGui.QTextCursor.End)
return cursor
epatters
* Tab completion now uses the correct cursor position....
r2841 def _get_input_buffer_cursor_column(self):
""" Returns the column of the cursor in the input buffer, excluding the
contribution by the prompt, or -1 if there is no such column.
"""
prompt = self._get_input_buffer_cursor_prompt()
if prompt is None:
return -1
else:
cursor = self._control.textCursor()
return cursor.columnNumber() - len(prompt)
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 def _get_input_buffer_cursor_line(self):
epatters
Removed use of hard tabs in FrontendWidget and implemented "smart" backspace.
r3022 """ Returns the text of the line of the input buffer that contains the
cursor, or None if there is no such line.
epatters
* Tab completion now uses the correct cursor position....
r2841 """
prompt = self._get_input_buffer_cursor_prompt()
if prompt is None:
return None
else:
cursor = self._control.textCursor()
text = self._get_block_plain_text(cursor.block())
return text[len(prompt):]
def _get_input_buffer_cursor_prompt(self):
""" Returns the (plain text) prompt for line of the input buffer that
contains the cursor, or None if there is no such line.
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 """
if self._executing:
return None
cursor = self._control.textCursor()
if cursor.position() >= self._prompt_pos:
if cursor.blockNumber() == self._get_prompt_cursor().blockNumber():
epatters
* Tab completion now uses the correct cursor position....
r2841 return self._prompt
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 else:
epatters
* Tab completion now uses the correct cursor position....
r2841 return self._continuation_prompt
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 else:
return None
epatters
Initial checkin of Qt frontend code.
r2602 def _get_prompt_cursor(self):
""" Convenience method that returns a cursor for the prompt position.
"""
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor = self._control.textCursor()
epatters
Initial checkin of Qt frontend code.
r2602 cursor.setPosition(self._prompt_pos)
return cursor
def _get_selection_cursor(self, start, end):
""" Convenience method that returns a cursor with text selected between
the positions 'start' and 'end'.
"""
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor = self._control.textCursor()
epatters
Initial checkin of Qt frontend code.
r2602 cursor.setPosition(start)
cursor.setPosition(end, QtGui.QTextCursor.KeepAnchor)
return cursor
def _get_word_start_cursor(self, position):
""" Find the start of the word to the left the given position. If a
sequence of non-word characters precedes the first word, skip over
them. (This emulates the behavior of bash, emacs, etc.)
"""
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 document = self._control.document()
epatters
Initial checkin of Qt frontend code.
r2602 position -= 1
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 while position >= self._prompt_pos and \
epatters
Initial checkin of Qt frontend code.
r2602 not document.characterAt(position).isLetterOrNumber():
position -= 1
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 while position >= self._prompt_pos and \
epatters
Initial checkin of Qt frontend code.
r2602 document.characterAt(position).isLetterOrNumber():
position -= 1
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor = self._control.textCursor()
epatters
Initial checkin of Qt frontend code.
r2602 cursor.setPosition(position + 1)
return cursor
def _get_word_end_cursor(self, position):
""" Find the end of the word to the right the given position. If a
sequence of non-word characters precedes the first word, skip over
them. (This emulates the behavior of bash, emacs, etc.)
"""
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 document = self._control.document()
epatters
Initial checkin of Qt frontend code.
r2602 end = self._get_end_cursor().position()
while position < end and \
not document.characterAt(position).isLetterOrNumber():
position += 1
while position < end and \
document.characterAt(position).isLetterOrNumber():
position += 1
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor = self._control.textCursor()
epatters
Initial checkin of Qt frontend code.
r2602 cursor.setPosition(position)
return cursor
epatters
Fixed several bugs involving the insertion of new lines. Pressing Enter in the ConsoleWidget now works as expected.
r2896 def _insert_continuation_prompt(self, cursor):
""" Inserts new continuation prompt using the specified cursor.
"""
if self._continuation_prompt_html is None:
self._insert_plain_text(cursor, self._continuation_prompt)
else:
self._continuation_prompt = self._insert_html_fetching_plain_text(
cursor, self._continuation_prompt_html)
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 def _insert_html(self, cursor, html):
epatters
Fixed bug with ConsoleWidget smart paste.
r2787 """ Inserts HTML using the specified cursor in such a way that future
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 formatting is unaffected.
"""
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 cursor.beginEditBlock()
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 cursor.insertHtml(html)
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 # 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
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 # 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,
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 QtGui.QTextCursor.KeepAnchor)
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 if cursor.selection().toPlainText() == ' ':
cursor.removeSelectedText()
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 else:
cursor.movePosition(QtGui.QTextCursor.Right)
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 cursor.insertText(' ', QtGui.QTextCharFormat())
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 cursor.endEditBlock()
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763
epatters
Fixed bug with ConsoleWidget smart paste.
r2787 def _insert_html_fetching_plain_text(self, cursor, html):
""" Inserts HTML using the specified cursor, then returns its plain text
version.
"""
epatters
* Fixed bug where syntax highlighting was lost after updating a prompt with a bad number....
r2800 cursor.beginEditBlock()
cursor.removeSelectedText()
epatters
Fixed bug with ConsoleWidget smart paste.
r2787 start = cursor.position()
self._insert_html(cursor, html)
end = cursor.position()
cursor.setPosition(start, QtGui.QTextCursor.KeepAnchor)
epatters
First pass at unicode support in ConsoleWidget....
r3029 text = unicode(cursor.selection().toPlainText())
epatters
* Fixed bug where syntax highlighting was lost after updating a prompt with a bad number....
r2800
epatters
Fixed bug with ConsoleWidget smart paste.
r2787 cursor.setPosition(end)
epatters
* Fixed bug where syntax highlighting was lost after updating a prompt with a bad number....
r2800 cursor.endEditBlock()
epatters
Fixed bug with ConsoleWidget smart paste.
r2787 return text
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 def _insert_plain_text(self, cursor, text):
""" Inserts plain text using the specified cursor, processing ANSI codes
if enabled.
"""
cursor.beginEditBlock()
if self.ansi_codes:
for substring in self._ansi_processor.split_string(text):
epatters
Added support for scroll sequences and form feeds to AnsiCodeProcessor....
r2998 for act in self._ansi_processor.actions:
epatters
Form feeds are now properly supported by ConsoleWidget.
r3006
# Unlike real terminal emulators, we don't distinguish
# between the screen and the scrollback buffer. A screen
# erase request clears everything.
if act.action == 'erase' and act.area == 'screen':
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 cursor.select(QtGui.QTextCursor.Document)
cursor.removeSelectedText()
epatters
Form feeds are now properly supported by ConsoleWidget.
r3006
# Simulate a form feed by scrolling just past the last line.
elif act.action == 'scroll' and act.unit == 'page':
cursor.insertText('\n')
cursor.endEditBlock()
self._set_top_cursor(cursor)
cursor.joinPreviousEditBlock()
cursor.deletePreviousChar()
epatters
* Added a pager with several different options to ConsoleWidget....
r2776 format = self._ansi_processor.get_format()
cursor.insertText(substring, format)
else:
cursor.insertText(text)
cursor.endEditBlock()
epatters
Fixed bug reported by fperez and removed code with duplicated functionality.
r3048 def _insert_plain_text_into_buffer(self, cursor, text):
""" Inserts text into the input buffer using the specified cursor (which
must be in the input buffer), ensuring that continuation prompts are
inserted as necessary.
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 """
epatters
First pass at unicode support in ConsoleWidget....
r3029 lines = unicode(text).splitlines(True)
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 if lines:
cursor.beginEditBlock()
cursor.insertText(lines[0])
for line in lines[1:]:
if self._continuation_prompt_html is None:
cursor.insertText(self._continuation_prompt)
else:
epatters
Fixed bug with ConsoleWidget smart paste.
r2787 self._continuation_prompt = \
self._insert_html_fetching_plain_text(
cursor, self._continuation_prompt_html)
epatters
* Implemented "smart paste" for ConsoleWidget. Continuation prompts are now inserted automatically on paste....
r2763 cursor.insertText(line)
cursor.endEditBlock()
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733
epatters
The FrontendWidget now performs tab-completion more aggressively.
r2847 def _in_buffer(self, position=None):
""" Returns whether the current cursor (or, if specified, a position) is
inside the editing region.
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 """
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 cursor = self._control.textCursor()
epatters
The FrontendWidget now performs tab-completion more aggressively.
r2847 if position is None:
position = cursor.position()
else:
cursor.setPosition(position)
epatters
Numerous fixes to ConsoleWidget editing region maintenence code. It now impossible (or at least very difficult :) to break the input region.
r2764 line = cursor.blockNumber()
prompt_line = self._get_prompt_cursor().blockNumber()
if line == prompt_line:
return position >= self._prompt_pos
elif line > prompt_line:
cursor.movePosition(QtGui.QTextCursor.StartOfBlock)
prompt_pos = cursor.position() + len(self._continuation_prompt)
return position >= prompt_pos
return False
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
def _keep_cursor_in_buffer(self):
""" Ensures that the cursor is inside the editing region. Returns
whether the cursor was moved.
"""
epatters
The FrontendWidget now performs tab-completion more aggressively.
r2847 moved = not self._in_buffer()
if moved:
cursor = self._control.textCursor()
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 cursor.movePosition(QtGui.QTextCursor.End)
self._control.setTextCursor(cursor)
epatters
The FrontendWidget now performs tab-completion more aggressively.
r2847 return moved
epatters
* Ctrl-G and Escape now clear the input buffer....
r2924
def _keyboard_quit(self):
""" Cancels the current editing task ala Ctrl-G in Emacs.
"""
if self._text_completing_pos:
epatters
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
r2939 self._cancel_text_completion()
epatters
* Ctrl-G and Escape now clear the input buffer....
r2924 else:
self.input_buffer = ''
epatters
* Added a pager with several different options to ConsoleWidget....
r2776
epatters
Added support for HTML paging and HTML page payloads.
r3014 def _page(self, text, html=False):
epatters
Fixed more issues with ConsoleWidget scrollbar management.
r3017 """ Displays text using the pager if it exceeds the height of the
viewport.
epatters
Added support for HTML paging and HTML page payloads.
r3014
Parameters:
-----------
html : bool, optional (default False)
If set, the text will be interpreted as HTML instead of plain text.
"""
line_height = QtGui.QFontMetrics(self.font).height()
minlines = self._control.viewport().height() / line_height
epatters
Fixed more issues with ConsoleWidget scrollbar management.
r3017 if self.paging != 'none' and \
re.match("(?:[^\n]*\n){%i}" % minlines, text):
epatters
Added support for HTML paging and HTML page payloads.
r3014 if self.paging == 'custom':
self.custom_page_requested.emit(text)
else:
self._page_control.clear()
cursor = self._page_control.textCursor()
if html:
self._insert_html(cursor, text)
epatters
The ConsoleWidget now only pages text if it exceeds the height of the visible window.
r2843 else:
self._insert_plain_text(cursor, text)
epatters
Added support for HTML paging and HTML page payloads.
r3014 self._page_control.moveCursor(QtGui.QTextCursor.Start)
epatters
The ConsoleWidget now only pages text if it exceeds the height of the visible window.
r2843
epatters
Added support for HTML paging and HTML page payloads.
r3014 self._page_control.viewport().resize(self._control.size())
if self._splitter:
self._page_control.show()
self._page_control.setFocus()
else:
self.layout().setCurrentWidget(self._page_control)
elif html:
self._append_plain_html(text)
else:
self._append_plain_text(text)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 def _prompt_finished(self):
""" Called immediately after a prompt is finished, i.e. when some input
will be processed and a new prompt displayed.
"""
epatters
Form feeds are now properly supported by ConsoleWidget.
r3006 # Flush all state from the input splitter so the next round of
# reading input starts with a clean buffer.
self._input_splitter.reset()
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 self._control.setReadOnly(True)
self._prompt_finished_hook()
epatters
Initial checkin of Qt frontend code.
r2602 def _prompt_started(self):
""" Called immediately after a new prompt is displayed.
"""
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 # Temporarily disable the maximum block count to permit undo/redo and
# to ensure that the prompt position does not change due to truncation.
epatters
Form feeds are now properly supported by ConsoleWidget.
r3006 self._control.document().setMaximumBlockCount(0)
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.setUndoRedoEnabled(True)
epatters
* Added undo/redo support to ConsoleWidget...
r2615
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._control.setReadOnly(False)
self._control.moveCursor(QtGui.QTextCursor.End)
epatters
Initial checkin of Qt frontend code.
r2602 self._executing = False
self._prompt_started_hook()
epatters
Reading a line is now correctly implemented in ConsoleWidget.
r2706 def _readline(self, prompt='', callback=None):
""" Reads one line of input from the user.
Parameters
----------
prompt : str, optional
The prompt to print before reading the line.
callback : callable, optional
A callback to execute with the read line. If not specified, input is
read *synchronously* and this method does not return until it has
been read.
Returns
-------
If a callback is specified, returns nothing. Otherwise, returns the
input string with the trailing newline stripped.
epatters
Progress on raw_input.
r2705 """
epatters
Reading a line is now correctly implemented in ConsoleWidget.
r2706 if self._reading:
raise RuntimeError('Cannot read a line. Widget is already reading.')
if not callback and not self.isVisible():
# If the user cannot see the widget, this function cannot return.
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 raise RuntimeError('Cannot synchronously read a line if the widget '
epatters
Reading a line is now correctly implemented in ConsoleWidget.
r2706 'is not visible!')
epatters
Progress on raw_input.
r2705
self._reading = True
epatters
Fixed bugs with raw_input and finished and implementing InStream.
r2708 self._show_prompt(prompt, newline=False)
epatters
Reading a line is now correctly implemented in ConsoleWidget.
r2706
if callback is None:
self._reading_callback = None
while self._reading:
QtCore.QCoreApplication.processEvents()
return self.input_buffer.rstrip('\n')
else:
self._reading_callback = lambda: \
callback(self.input_buffer.rstrip('\n'))
epatters
Progress on raw_input.
r2705
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 def _set_continuation_prompt(self, prompt, html=False):
""" Sets the continuation prompt.
Parameters
----------
prompt : str
The prompt to show when more input is needed.
html : bool, optional (default False)
If set, the prompt will be inserted as formatted HTML. Otherwise,
the prompt will be treated as plain text, though ANSI color codes
will be handled.
"""
if html:
self._continuation_prompt_html = prompt
else:
self._continuation_prompt = prompt
self._continuation_prompt_html = None
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736
def _set_cursor(self, cursor):
""" Convenience method to set the current cursor.
"""
self._control.setTextCursor(cursor)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715
epatters
Form feeds are now properly supported by ConsoleWidget.
r3006 def _set_top_cursor(self, cursor):
""" Scrolls the viewport so that the specified cursor is at the top.
"""
scrollbar = self._control.verticalScrollBar()
scrollbar.setValue(scrollbar.maximum())
original_cursor = self._control.textCursor()
self._control.setTextCursor(cursor)
self._control.ensureCursorVisible()
self._control.setTextCursor(original_cursor)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 def _show_prompt(self, prompt=None, html=False, newline=True):
epatters
Fixed bugs with raw_input and finished and implementing InStream.
r2708 """ Writes a new prompt at the end of the buffer.
Parameters
----------
prompt : str, optional
The prompt to show. If not specified, the previous prompt is used.
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 html : bool, optional (default False)
Only relevant when a prompt is specified. If set, the prompt will
be inserted as formatted HTML. Otherwise, the prompt will be treated
as plain text, though ANSI color codes will be handled.
epatters
Fixed bugs with raw_input and finished and implementing InStream.
r2708 newline : bool, optional (default True)
If set, a new line will be written before showing the prompt if
there is not already a newline at the end of the buffer.
"""
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 # Insert a preliminary newline, if necessary.
epatters
Fixed bugs with raw_input and finished and implementing InStream.
r2708 if newline:
cursor = self._get_end_cursor()
if cursor.position() > 0:
cursor.movePosition(QtGui.QTextCursor.Left,
QtGui.QTextCursor.KeepAnchor)
epatters
First pass at unicode support in ConsoleWidget....
r3029 if unicode(cursor.selection().toPlainText()) != '\n':
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._append_plain_text('\n')
epatters
Progress on raw_input.
r2705
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 # Write the prompt.
epatters
* Fixed regression from last commit: syntax highlighting works robustly again....
r2866 self._append_plain_text(self._prompt_sep)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 if prompt is None:
if self._prompt_html is None:
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._append_plain_text(self._prompt)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 else:
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._append_html(self._prompt_html)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 else:
if html:
self._prompt = self._append_html_fetching_plain_text(prompt)
self._prompt_html = prompt
else:
epatters
Refactored ConsoleWidget to encapsulate, rather than inherit from, QPlainTextEdit. This permits a QTextEdit to be substituted for a QPlainTextEdit if desired. It also makes it more clear what is the public interface of ConsoleWidget.
r2736 self._append_plain_text(prompt)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 self._prompt = prompt
self._prompt_html = None
epatters
Progress on raw_input.
r2705
epatters
Initial checkin of Qt frontend code.
r2602 self._prompt_pos = self._get_end_cursor().position()
self._prompt_started()
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 #------ Signal handlers ----------------------------------------------------
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 def _adjust_scrollbars(self):
""" Expands the vertical scrollbar beyond the range set by Qt.
"""
# This code is adapted from _q_adjustScrollbars in qplaintextedit.cpp
# and qtextedit.cpp.
document = self._control.document()
scrollbar = self._control.verticalScrollBar()
viewport_height = self._control.viewport().height()
if isinstance(self._control, QtGui.QPlainTextEdit):
epatters
Fixed bug with scrollbar adjustment when buffer size exceeds maximumBlockCount.
r3007 maximum = max(0, document.lineCount() - 1)
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 step = viewport_height / self._control.fontMetrics().lineSpacing()
else:
epatters
Fixed bug with scrollbar adjustment when buffer size exceeds maximumBlockCount.
r3007 # QTextEdit does not do line-based layout and blocks will not in
# general have the same height. Therefore it does not make sense to
# attempt to scroll in line height increments.
maximum = document.size().height()
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 step = viewport_height
epatters
Fixed bug with scrollbar adjustment when buffer size exceeds maximumBlockCount.
r3007 diff = maximum - scrollbar.maximum()
scrollbar.setRange(0, maximum)
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001 scrollbar.setPageStep(step)
epatters
Fixed bug with scrollbar adjustment when buffer size exceeds maximumBlockCount.
r3007 # Compensate for undesirable scrolling that occurs automatically due to
# maximumBlockCount() text truncation.
epatters
Fixed more issues with ConsoleWidget scrollbar management.
r3017 if diff < 0 and document.blockCount() == document.maximumBlockCount():
epatters
Fixed bug with scrollbar adjustment when buffer size exceeds maximumBlockCount.
r3007 scrollbar.setValue(scrollbar.value() + diff)
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001
epatters
Major improvements to terminal-style tab completion. Still work to be done, but a decent start.
r2919 def _cursor_position_changed(self):
""" Clears the temporary buffer based on the cursor position.
"""
if self._text_completing_pos:
document = self._control.document()
if self._text_completing_pos < document.characterCount():
cursor = self._control.textCursor()
pos = cursor.position()
text_cursor = self._control.textCursor()
text_cursor.setPosition(self._text_completing_pos)
if pos < self._text_completing_pos or \
cursor.blockNumber() > text_cursor.blockNumber():
self._clear_temporary_buffer()
self._text_completing_pos = 0
else:
self._clear_temporary_buffer()
self._text_completing_pos = 0
epatters
ConsoleWidget now manually controls the vertical scrollbar....
r3001
def _custom_context_menu_requested(self, pos):
""" Shows a context menu at the given QPoint (in widget coordinates).
"""
menu = self._context_menu_make(pos)
menu.exec_(self._control.mapToGlobal(pos))