##// END OF EJS Templates
The ConsoleWidget now only pages text if it exceeds the height of the visible window.
The ConsoleWidget now only pages text if it exceeds the height of the visible window.

File last commit:

r2841:58941baa
r2843:f97e4c24
Show More
ipython_widget.py
299 lines | 11.5 KiB | text/x-python | PythonLexer
epatters
Added preliminary editor support to IPythonWidget.
r2793 # Standard library imports
from subprocess import Popen
epatters
* Updated FrontendWidget to use BlockBreaker for parsing input...
r2630 # System library imports
from PyQt4 import QtCore, QtGui
# Local imports
epatters
Integrated new IPythonInputSplitter into IPythonWidget.
r2789 from IPython.core.inputsplitter import IPythonInputSplitter
epatters
Added banners to FrontendWidget and IPythonWidget.
r2714 from IPython.core.usage import default_banner
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627 from frontend_widget import FrontendWidget
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 class IPythonPromptBlock(object):
""" An internal storage object for IPythonWidget.
"""
def __init__(self, block, length, number):
self.block = block
self.length = length
self.number = number
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627 class IPythonWidget(FrontendWidget):
""" A FrontendWidget for an IPython kernel.
"""
epatters
Added preliminary editor support to IPythonWidget.
r2793 # Signal emitted when an editor is needed for a file and the editor has been
epatters
* Refactored payload handling mechanism....
r2835 # specified as 'custom'. See 'set_editor' for more information.
epatters
Fixed line_number being inserted as a string into the %edit payload.
r2836 custom_edit_requested = QtCore.pyqtSignal(object, object)
epatters
Added preliminary editor support to IPythonWidget.
r2793
epatters
* Fleshed out IPythonWidget's style control....
r2725 # The default stylesheet: black text on a white background.
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 default_stylesheet = """
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 .error { color: red; }
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 .in-prompt { color: navy; }
.in-prompt-number { font-weight: bold; }
.out-prompt { color: darkred; }
.out-prompt-number { font-weight: bold; }
"""
epatters
* Fleshed out IPythonWidget's style control....
r2725 # A dark stylesheet: white text on a black background.
dark_stylesheet = """
epatters
Clean up styling information.
r2822 QPlainTextEdit, QTextEdit { background-color: black; color: white }
epatters
* Fleshed out IPythonWidget's style control....
r2725 QFrame { border: 1px solid grey; }
.error { color: red; }
.in-prompt { color: lime; }
.in-prompt-number { color: lime; font-weight: bold; }
.out-prompt { color: red; }
.out-prompt-number { color: red; font-weight: bold; }
"""
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 # Default prompts.
epatters
IPythonWidget now supports 'input_sep'.
r2806 in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
epatters
* Refactored payload handling mechanism....
r2835 # FrontendWidget protected class variables.
epatters
* Fixed bug where syntax highlighting was lost after updating a prompt with a bad number....
r2800 #_input_splitter_class = IPythonInputSplitter
epatters
* Refactored payload handling mechanism....
r2835 # IPythonWidget protected class variables.
_payload_source_edit = 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic'
_payload_source_page = 'IPython.zmq.page.page'
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627 #---------------------------------------------------------------------------
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 # 'object' interface
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627 #---------------------------------------------------------------------------
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 __init__(self, *args, **kw):
super(IPythonWidget, self).__init__(*args, **kw)
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627
epatters
Integrated new IPythonInputSplitter into IPythonWidget.
r2789 # IPythonWidget protected variables.
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 self._previous_prompt_obj = None
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715
epatters
Added preliminary editor support to IPythonWidget.
r2793 # Set a default editor and stylesheet.
self.set_editor('default')
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 self.reset_styling()
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688
#---------------------------------------------------------------------------
epatters
* Moved KernelManager attribute management code in FrontendWidget into a mixin class usable in any Qt frontend. Registering handlers for message types is now trivial....
r2770 # 'BaseFrontendMixin' abstract interface
#---------------------------------------------------------------------------
epatters
IPythonWidget now supports 'input_sep'.
r2806 def _handle_pyout(self, msg):
epatters
* Moved KernelManager attribute management code in FrontendWidget into a mixin class usable in any Qt frontend. Registering handlers for message types is now trivial....
r2770 """ Reimplemented for IPython-style "display hook".
"""
epatters
* The Qt console frontend now ignores cross chatter from other frontends....
r2824 if not self._hidden and self._is_from_this_session(msg):
content = msg['content']
prompt_number = content['prompt_number']
self._append_plain_text(content['output_sep'])
self._append_html(self._make_out_prompt(prompt_number))
self._append_plain_text(content['data'] + '\n' +
content['output_sep2'])
epatters
* Moved KernelManager attribute management code in FrontendWidget into a mixin class usable in any Qt frontend. Registering handlers for message types is now trivial....
r2770
#---------------------------------------------------------------------------
epatters
* Refactored ConsoleWidget execution API for greater flexibility and clarity....
r2688 # 'FrontendWidget' interface
#---------------------------------------------------------------------------
def execute_file(self, path, hidden=False):
""" Reimplemented to use the 'run' magic.
"""
Fernando Perez
Improvements to exception handling to transport structured tracebacks....
r2838 self.execute('%%run %s' % path, hidden=hidden)
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627
#---------------------------------------------------------------------------
epatters
Added banners to FrontendWidget and IPythonWidget.
r2714 # 'FrontendWidget' protected interface
#---------------------------------------------------------------------------
def _get_banner(self):
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 """ Reimplemented to return IPython's default banner.
epatters
Added banners to FrontendWidget and IPythonWidget.
r2714 """
epatters
IPythonWidget now supports 'input_sep'.
r2806 return default_banner + '\n'
epatters
Added banners to FrontendWidget and IPythonWidget.
r2714
epatters
* Moved KernelManager attribute management code in FrontendWidget into a mixin class usable in any Qt frontend. Registering handlers for message types is now trivial....
r2770 def _process_execute_error(self, msg):
""" Reimplemented for IPython-style traceback formatting.
"""
content = msg['content']
epatters
* Tab completion now uses the correct cursor position....
r2841 traceback = '\n'.join(content['traceback']) + '\n'
if False:
# FIXME: For now, tracebacks come as plain text, so we can't use
Fernando Perez
Improvements to exception handling to transport structured tracebacks....
r2838 # the html renderer yet. Once we refactor ultratb to produce
# properly styled tracebacks, this branch should be the default
traceback = traceback.replace(' ', '&nbsp;')
traceback = traceback.replace('\n', '<br/>')
ename = content['ename']
ename_styled = '<span class="error">%s</span>' % ename
traceback = traceback.replace(ename, ename_styled)
self._append_html(traceback)
else:
# This is the fallback for now, using plain text with ansi escapes
self._append_plain_text(traceback)
epatters
* Moved KernelManager attribute management code in FrontendWidget into a mixin class usable in any Qt frontend. Registering handlers for message types is now trivial....
r2770
epatters
* Refactored payload handling mechanism....
r2835 def _process_execute_payload(self, item):
""" Reimplemented to handle %edit and paging payloads.
"""
if item['source'] == self._payload_source_edit:
self.edit(item['filename'], item['line_number'])
return True
elif item['source'] == self._payload_source_page:
self._page(item['data'])
return True
else:
return False
epatters
IPythonWidget now supports 'input_sep'.
r2806 def _show_interpreter_prompt(self, number=None, input_sep='\n'):
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 """ Reimplemented for IPython-style prompts.
"""
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 # TODO: If a number was not specified, make a prompt number request.
if number is None:
number = 0
epatters
IPythonWidget now supports 'input_sep'.
r2806 # Show a new prompt and save information about it so that it can be
# updated later if the prompt number turns out to be wrong.
self._append_plain_text(input_sep)
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 self._show_prompt(self._make_in_prompt(number), html=True)
epatters
IPythonWidget now supports 'input_sep'.
r2806 block = self._control.document().lastBlock()
length = len(self._prompt)
self._previous_prompt_obj = IPythonPromptBlock(block, length, number)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715
# Update continuation prompt to reflect (possibly) new prompt length.
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 self._set_continuation_prompt(
self._make_continuation_prompt(self._prompt), html=True)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 def _show_interpreter_prompt_for_reply(self, msg):
""" Reimplemented for IPython-style prompts.
"""
# Update the old prompt number if necessary.
content = msg['content']
previous_prompt_number = content['prompt_number']
if self._previous_prompt_obj and \
self._previous_prompt_obj.number != previous_prompt_number:
block = self._previous_prompt_obj.block
if block.isValid():
epatters
* Fixed bug where syntax highlighting was lost after updating a prompt with a bad number....
r2800
# Remove the old prompt and insert a new prompt.
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 cursor = QtGui.QTextCursor(block)
cursor.movePosition(QtGui.QTextCursor.Right,
QtGui.QTextCursor.KeepAnchor,
self._previous_prompt_obj.length)
prompt = self._make_in_prompt(previous_prompt_number)
epatters
* Fixed bug where syntax highlighting was lost after updating a prompt with a bad number....
r2800 self._prompt = self._insert_html_fetching_plain_text(
cursor, prompt)
epatters
Minor cleanup.
r2825 # When the HTML is inserted, Qt blows away the syntax
# highlighting for the line, so we need to rehighlight it.
epatters
* Fixed bug where syntax highlighting was lost after updating a prompt with a bad number....
r2800 self._highlighter.rehighlightBlock(cursor.block())
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797 self._previous_prompt_obj = None
# Show a new prompt with the kernel's estimated prompt number.
epatters
IPythonWidget now supports 'input_sep'.
r2806 next_prompt = content['next_prompt']
self._show_interpreter_prompt(next_prompt['prompt_number'],
next_prompt['input_sep'])
epatters
Updated IPythonWidget to use new prompt information. Initial prompt requests are not implemented.
r2797
epatters
Added banners to FrontendWidget and IPythonWidget.
r2714 #---------------------------------------------------------------------------
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627 # 'IPythonWidget' interface
#---------------------------------------------------------------------------
epatters
* Refactored payload handling mechanism....
r2835 def edit(self, filename, line=None):
epatters
Added preliminary editor support to IPythonWidget.
r2793 """ Opens a Python script for editing.
Parameters:
-----------
filename : str
A path to a local system file.
epatters
* Refactored payload handling mechanism....
r2835
line : int, optional
A line of interest in the file.
epatters
Added preliminary editor support to IPythonWidget.
r2793
Raises:
-------
OSError
If the editor command cannot be executed.
"""
if self._editor == 'default':
url = QtCore.QUrl.fromLocalFile(filename)
if not QtGui.QDesktopServices.openUrl(url):
message = 'Failed to open %s with the default application'
raise OSError(message % repr(filename))
elif self._editor is None:
epatters
* Refactored payload handling mechanism....
r2835 self.custom_edit_requested.emit(filename, line)
epatters
Added preliminary editor support to IPythonWidget.
r2793 else:
Popen(self._editor + [filename])
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 def reset_styling(self):
""" Restores the default IPythonWidget styling.
epatters
* Created an IPythonWidget subclass of FrontendWidget to contain IPython specific functionality....
r2627 """
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 self.set_styling(self.default_stylesheet, syntax_style='default')
epatters
Clean up styling information.
r2822 #self.set_styling(self.dark_stylesheet, syntax_style='monokai')
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728
epatters
Added preliminary editor support to IPythonWidget.
r2793 def set_editor(self, editor):
""" Sets the editor to use with the %edit magic.
Parameters:
-----------
editor : str or sequence of str
A command suitable for use with Popen. This command will be executed
with a single argument--a filename--when editing is requested.
This parameter also takes two special values:
'default' : Files will be edited with the system default
application for Python files.
epatters
* Refactored payload handling mechanism....
r2835 'custom' : Emit a 'custom_edit_requested(str, int)' signal
instead of opening an editor.
epatters
Added preliminary editor support to IPythonWidget.
r2793 """
if editor == 'default':
self._editor = 'default'
elif editor == 'custom':
self._editor = None
elif isinstance(editor, basestring):
self._editor = [ editor ]
else:
self._editor = list(editor)
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 def set_styling(self, stylesheet, syntax_style=None):
""" Sets the IPythonWidget styling.
Parameters:
-----------
stylesheet : str
A CSS stylesheet. The stylesheet can contain classes for:
1. Qt: QPlainTextEdit, QFrame, QWidget, etc
2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
3. IPython: .error, .in-prompt, .out-prompt, etc.
syntax_style : str or None [default None]
If specified, use the Pygments style with given name. Otherwise,
the stylesheet is queried for Pygments style information.
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 """
epatters
* Fleshed out IPythonWidget's style control....
r2725 self.setStyleSheet(stylesheet)
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().setDefaultStyleSheet(stylesheet)
epatters
Fix to ensure that the paging widget is styled appropriately.
r2779 if self._page_control:
self._page_control.document().setDefaultStyleSheet(stylesheet)
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 if syntax_style is None:
self._highlighter.set_style_sheet(stylesheet)
else:
self._highlighter.set_style(syntax_style)
epatters
Added machinery to IPythonWidget for updating the previous prompt number.
r2733 #---------------------------------------------------------------------------
# 'IPythonWidget' protected interface
#---------------------------------------------------------------------------
def _make_in_prompt(self, number):
""" Given a prompt number, returns an HTML In prompt.
"""
body = self.in_prompt % number
return '<span class="in-prompt">%s</span>' % body
def _make_continuation_prompt(self, prompt):
""" Given a plain text version of an In prompt, returns an HTML
continuation prompt.
"""
end_chars = '...: '
space_count = len(prompt.lstrip('\n')) - len(end_chars)
body = '&nbsp;' * space_count + end_chars
return '<span class="in-prompt">%s</span>' % body
def _make_out_prompt(self, number):
""" Given a prompt number, returns an HTML Out prompt.
"""
body = self.out_prompt % number
return '<span class="out-prompt">%s</span>' % body