[Python-modules-commits] [python-qtconsole] 01/03: New upstream version 4.3.1
Frédéric-Emmanuel Picca
picca at moszumanska.debian.org
Sun Oct 8 18:34:18 UTC 2017
This is an automated email from the git hooks/post-receive script.
picca pushed a commit to branch master
in repository python-qtconsole.
commit feab0a6421a10c1ac90d295ca96e0fc1e34afdf9
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date: Sun Oct 8 12:14:42 2017 +0200
New upstream version 4.3.1
---
PKG-INFO | 4 +-
README.md | 10 +-
docs/autogen_config.py | 19 +++-
docs/conda-env.yml | 12 ---
docs/environment.yml | 12 +++
docs/requirements.txt | 4 -
docs/source/changelog.rst | 59 ++++++++++-
docs/source/conf.py | 13 ++-
docs/source/index.rst | 51 +++++++---
docs/source/installation.rst | 4 +-
qtconsole/_version.py | 2 +-
qtconsole/ansi_code_processor.py | 51 ++++++----
qtconsole/console_widget.py | 148 ++++++++++++++++++++--------
qtconsole/frontend_widget.py | 10 +-
qtconsole/history_console_widget.py | 20 ++--
qtconsole/jupyter_widget.py | 36 +++++--
qtconsole/mainwindow.py | 107 +++++++++++++++-----
qtconsole/pygments_highlighter.py | 19 +++-
qtconsole/qt.py | 10 +-
qtconsole/qt_loaders.py | 126 +++++++++++++++++++----
qtconsole/qtconsoleapp.py | 26 +++++
qtconsole/rich_jupyter_widget.py | 5 +-
qtconsole/styles.py | 51 +++++-----
qtconsole/svg.py | 1 +
qtconsole/tests/test_ansi_code_processor.py | 8 ++
qtconsole/tests/test_completion_widget.py | 12 +--
qtconsole/tests/test_console_widget.py | 96 ++++++++++++++++++
qtconsole/tests/test_jupyter_widget.py | 39 ++++++++
qtconsole/tests/test_styles.py | 14 +++
setup.py | 7 +-
30 files changed, 748 insertions(+), 228 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index 1369710..7efb0b8 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: qtconsole
-Version: 4.2.1
+Version: 4.3.1
Summary: Jupyter Qt console
Home-page: http://jupyter.org
Author: Jupyter Development Team
@@ -19,3 +19,5 @@ Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
diff --git a/README.md b/README.md
index dcf8f4a..c611eb0 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[](https://groups.google.com/forum/#!forum/jupyter)
[](https://travis-ci.org/jupyter/qtconsole)
-[](http://qtconsole.readthedocs.org/en/stable/)
+[](https://qtconsole.readthedocs.io/en/stable/)
A rich Qt-based console for working with Jupyter kernels,
supporting rich media output, session export, and more.
@@ -50,7 +50,7 @@ or with a system package manager. For Windows, PyQt binary packages may be
used.
**Note:** Additional information about using a system package manager may be
-found in the [qtconsole documentation](https://qtconsole.readthedocs.org). For
+found in the [qtconsole documentation](https://qtconsole.readthedocs.io). For
example, on Linux Debian/Ubuntu, use ``sudo apt-get install python3-pyqt5`` to
install PyQt5, ``sudo apt-get install python-qt4`` or
``sudo apt-get install python3-pyqt4`` to install PyQt4.
@@ -63,8 +63,8 @@ To run the Qt console:
## Resources
- [Project Jupyter website](https://jupyter.org)
- Documentation for the Qt console
- * [latest version](http://qtconsole.readthedocs.org/en/latest/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/latest/qtconsole.pdf)]
- * [stable version](http://qtconsole.readthedocs.org/en/stable/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/stable/qtconsole.pdf)]
-- [Documentation for Project Jupyter](http://jupyter.readthedocs.org/en/latest/index.html) [[PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)]
+ * [latest version](https://qtconsole.readthedocs.io/en/latest/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/latest/qtconsole.pdf)]
+ * [stable version](https://qtconsole.readthedocs.io/en/stable/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/stable/qtconsole.pdf)]
+- [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html) [[PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)]
- [Issues](https://github.com/jupyter/qtconsole/issues)
- [Technical support - Jupyter Google Group](https://groups.google.com/forum/#!forum/jupyter)
diff --git a/docs/autogen_config.py b/docs/autogen_config.py
index 56c88b4..57f8173 100755
--- a/docs/autogen_config.py
+++ b/docs/autogen_config.py
@@ -1,5 +1,13 @@
#!/usr/bin/env python
+"""Generates a configuration options document for Sphinx.
+
+Using this helper tool, a reStructuredText document can be created from
+reading the config options from the JupyterQtConsole source code that may
+be set in config file, `jupyter_qtconsole_config.py`, and writing to the rST
+doc, `config_options.rst`.
+
+"""
import os.path
from qtconsole.qtconsoleapp import JupyterQtConsoleApp
@@ -7,8 +15,15 @@ header = """\
Configuration options
=====================
-These options can be set in ``~/.jupyter/jupyter_qtconsole_config.py``, or
-at the command line when you start it.
+These options can be set in the configuration file,
+``~/.jupyter/jupyter_qtconsole_config.py``, or
+at the command line when you start Qt console.
+
+You may enter ``jupyter qtconsole --help-all`` to get information
+about all available configuration options.
+
+Options
+-------
"""
destination = os.path.join(os.path.dirname(__file__), 'source/config_options.rst')
diff --git a/docs/conda-env.yml b/docs/conda-env.yml
deleted file mode 100644
index 0006585..0000000
--- a/docs/conda-env.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-name: qtconsole_docs
-channels:
-- asmeurer
-dependencies:
-- ipykernel
-- numpydoc # we seem to not use that, but removing break readthedocs conda (for now)
-- pexpect
-- pygments
-- pyqt
-- pip:
- - recommonmark # we seem to not use that, but removing break readthedocs conda (for now)
- - readthedocs-sphinx-ext # we seem to not use that, but removing break readthedocs conda (for now)
diff --git a/docs/environment.yml b/docs/environment.yml
new file mode 100644
index 0000000..e80a1b6
--- /dev/null
+++ b/docs/environment.yml
@@ -0,0 +1,12 @@
+name: qtconsole_docs
+channels:
+ - conda-forge
+ - defaults
+dependencies:
+ - python=3.5
+ - ipykernel
+ - pexpect
+ - pygments
+ - pyqt
+ - sphinx
+ - sphinx_rtd_theme
diff --git a/docs/requirements.txt b/docs/requirements.txt
deleted file mode 100644
index fcaec22..0000000
--- a/docs/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-pygments
--e git+https://github.com/jupyter/jupyter_client.git#egg=jupyter_client
--e git+https://github.com/ipython/ipython.git#egg=ipython
--e git+https://github.com/ipython/ipykernel.git#egg=ipykernel
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index c1eb6df..a9c81b8 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -3,14 +3,63 @@
Changes in Jupyter Qt console
=============================
-.. _4.2:
+.. _4.3.1:
-4.2.1
------
+`4.3.1 on GitHub <https://github.com/jupyter/qtconsole/milestones/4.3.1>`__
+
+- Make %clear to delete previous output on Windows.
+- Fix SVG rendering.
-`4.2.1 on GitHub <https://github.com/jupyter/qtconsole/milestones/4.2.1>`__
-Fix compatibility with some Qt bindings and traitlets ≥ 4.2.
+.. _4.3:
+
+4.3
+---
+
+`4.3 on GitHub <https://github.com/jupyter/qtconsole/milestones/4.3>`__
+
+- Rename `ConsoleWidget.width/height` traits to `console_width/console_height`
+ to avoid a name clash with the `QWidget` properties. Note: the name change
+ could be, in rare cases if a name collision exists, a code-breaking
+ change.
+
+Additions
+~~~~~~~~~
+- Add :kbd:`Shift-Tab` shortcut to unindent text
+- Add :kbd:`Control-R` shortcut to rename the current tab
+- Add :kbd:`Alt-R` shortcut to set the main window title
+- Add :kbd:`Command-Alt-Left` and :kbd:`Command-Alt-Right` shortcut to switch
+ tabs on macOS
+- Add support for PySide2
+- Add support for Python 3.5
+- Add support for 24 bit ANSI color codes
+- Add option to create new tab connected to the existing kernel
+
+Changes
+~~~~~~~
+- Change :kbd:`Tab` key behavior to always indent to the next increment of 4 spaces
+- Change :kbd:`Home` key behavior to alternate cursor between the beginning of text
+ (ignoring leading spaces) and beginning of the line
+- Improve documentation of various options and clarified the docs in some places
+- Move documentation to ReadTheDocs
+
+Fixes
+~~~~~
+- Fix automatic indentation of new lines that are inserted in the middle of a
+ cell
+- Fix regression where prompt would never be shown for `--existing` consoles
+- Fix `python.exe -m qtconsole` on Windows
+- Fix showing error messages when running a script using `%run`
+- Fix `invalid cursor position` error and subsequent freezing of user input
+- Fix syntax coloring when attaching to non-IPython kernels
+- Fix printing when using QT5
+- Fix :kbd:`Control-K` shortcut (delete until end of line) on macOS
+- Fix history browsing (:kbd:`Up`/:kbd:`Down` keys) when lines are longer than
+ the terminal width
+- Fix saving HTML with inline PNG for Python 3
+- Various internal bugfixes
+
+.. _4.2:
4.2
---
diff --git a/docs/source/conf.py b/docs/source/conf.py
index a07ef2e..a46f99f 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -20,7 +20,6 @@ exec(compile(open('../../qtconsole/_version.py').read(), '../../qtconsole/_versi
import os
if os.environ.get('READTHEDOCS', None) == 'True':
print('On RTD, regen API')
- #from ..autogen_config import main
ns = {'__file__':'../autogen_config.py'}
exec(compile(open('../autogen_config.py').read(), '../autogen_config.py', 'exec'), ns )
ns['main']()
@@ -66,9 +65,9 @@ project = 'Jupyter Qt Console'
copyright = 'The Jupyter Development Team'
author = 'The Jupyter Development Team'
-# numpydoc config
-numpydoc_show_class_members = False # Otherwise Sphinx emits thousands of warnings
-numpydoc_class_members_toctree = False
+# numpydoc config TODO remove this block if really not being used
+#numpydoc_show_class_members = True
+#numpydoc_class_members_toctree = True
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -131,7 +130,7 @@ pygments_style = 'sphinx'
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = False
+#todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
@@ -167,7 +166,7 @@ html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+#html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
@@ -315,4 +314,4 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'https://docs.python.org/': None}
+intersphinx_mapping = {'https://docs.python.org/3/': None}
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 040110e..acfc565 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -22,7 +22,7 @@ Overview
========
The Qt console is a very lightweight application that largely feels like a
terminal, but provides a number of enhancements only possible in a GUI, such as
-inline figures, proper multiline editing with syntax highlighting, graphical
+inline figures, proper multi-line editing with syntax highlighting, graphical
calltips, and much more. The Qt console can use any Jupyter kernel.
.. figure:: _images/qtconsole.png
@@ -40,9 +40,9 @@ navigation. This is not yet configurable.
Since the Qt console tries hard to behave like a terminal, by default it
immediately executes single lines of input that are complete. If you want
- to force multiline input, hit :kbd:`Ctrl-Enter` at the end of the first line
+ to force multi-line input, hit :kbd:`Ctrl-Enter` at the end of the first line
instead of :kbd:`Enter`, and it will open a new line for input. At any
- point in a multiline block, you can force its execution (without having to
+ point in a multi-line block, you can force its execution (without having to
go to the bottom) with :kbd:`Shift-Enter`.
@@ -375,13 +375,30 @@ Rules:
the Kernel has been shutdown.
* Remote Consoles may not restart or shutdown the kernel.
-Qt and the Qt console
-=====================
+Qt and the REPL
+===============
+
+.. note::
+
+ This section is relevant regardless of the frontend you use to write Qt
+ Code. This section is mostly there as it is easy to get confused and assume
+ that writing Qt code in the QtConsole should change from usual Qt code. It
+ should not. If you get confused, take a step back, and try writing your
+ code using the pure terminal based ``jupyter console`` that does not
+ involve Qt.
+
+An important part of working with the REPL – QtConsole, Jupyter notebook,
+IPython terminal – when you are writing your own Qt code is to remember that
+user code (in the kernel) is *not* in the same process as the frontend. This
+means that there is not necessarily any Qt code running in the kernel, and
+under most normal circumstances there isn't. This is true even if you are
+running the QtConsole.
+
+.. warning::
+
+ When executing code from the qtconsole prompt, it is **not possible** to
+ access the QtApplication instance of the QtConsole itself.
-An important part of working with the Qt console when you are writing your own
-Qt code is to remember that user code (in the kernel) is *not* in the same
-process as the frontend. This means that there is not necessarily any Qt code
-running in the kernel, and under most normal circumstances there isn't.
A common problem listed in the PyQt4 Gotchas_ is the fact that Python's garbage
collection will destroy Qt objects (Windows, etc.) once there is no longer a
@@ -389,6 +406,8 @@ Python reference to them, so you have to hold on to them. For instance, in:
.. sourcecode:: python
+ from PyQt4 import QtGui
+
def make_window():
win = QtGui.QMainWindow()
@@ -400,22 +419,28 @@ Python reference to them, so you have to hold on to them. For instance, in:
destroy it before it is drawn, whereas :func:`make_and_return_window` lets the
caller decide when the window object should be destroyed. If, as a developer,
you know that you always want your objects to last as long as the process, you
-can attach them to the QApplication instance itself:
+can attach them to the ``QApplication`` instance itself:
.. sourcecode:: python
+ from PyQt4 import QtGui, QtCore
+
# do this just once:
app = QtCore.QCoreApplication.instance()
+ if not app:
+ # we are in the kernel in most of the case there is NO qt code running.
+ # we need to create a Gui APP.
+ app = QtGui.QApplication([])
app.references = set()
# then when you create Windows, add them to the set
def make_window():
win = QtGui.QMainWindow()
app.references.add(win)
-Now the QApplication itself holds a reference to ``win``, so it will never be
+Now the ``QApplication`` itself holds a reference to ``win``, so it will never be
garbage collected until the application itself is destroyed.
-.. _Gotchas: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/gotchas.html#garbage-collection
+.. _Gotchas: http://pyqt.sourceforge.net/Docs/PyQt4/gotchas.html#garbage-collection
Embedding the QtConsole in a Qt application
-------------------------------------------
@@ -458,5 +483,5 @@ frontend:
will not be fixed, as abandoning pexpect would significantly degrade the
console experience.
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/download
+.. _PyQt: https://www.riverbankcomputing.com/software/pyqt/download
.. _pygments: http://pygments.org/
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
index 2e24a24..e36719a 100644
--- a/docs/source/installation.rst
+++ b/docs/source/installation.rst
@@ -1,7 +1,7 @@
Installation
============
The Qt console requires Qt, such as
-`PyQt5 <http://www.riverbankcomputing.com/software/pyqt/intro>`_,
+`PyQt5 <https://www.riverbankcomputing.com/software/pyqt/intro>`_,
`PyQt4 <https://www.riverbankcomputing.com/software/pyqt/download>`_, or
`PySide <http://pyside.github.io/docs/pyside>`_.
@@ -50,5 +50,5 @@ For example with Linux Debian's system package manager, use::
.. seealso::
- `Installing Jupyter <http://jupyter.readthedocs.org/en/latest/install.html>`_
+ `Installing Jupyter <https://jupyter.readthedocs.io/en/latest/install.html>`_
The Qt console is part of the Jupyter ecosystem.
diff --git a/qtconsole/_version.py b/qtconsole/_version.py
index 4b49b77..6df6c0a 100644
--- a/qtconsole/_version.py
+++ b/qtconsole/_version.py
@@ -1,2 +1,2 @@
-version_info = (4, 2, 1)
+version_info = (4, 3, 1)
__version__ = '.'.join(map(str, version_info))
diff --git a/qtconsole/ansi_code_processor.py b/qtconsole/ansi_code_processor.py
index ac89dcb..eb02866 100644
--- a/qtconsole/ansi_code_processor.py
+++ b/qtconsole/ansi_code_processor.py
@@ -13,6 +13,7 @@ from qtconsole.qt import QtGui
# Local imports
from ipython_genutils.py3compat import string_types
+from qtconsole.styles import dark_style
#-----------------------------------------------------------------------------
# Constants and datatypes
@@ -244,18 +245,28 @@ class AnsiCodeProcessor(object):
self.underline = False
elif code >= 30 and code <= 37:
self.foreground_color = code - 30
- elif code == 38 and params and params.pop(0) == 5:
- # xterm-specific: 256 color support.
- if params:
+ elif code == 38 and params:
+ _color_type = params.pop(0)
+ if _color_type == 5 and params:
+ # xterm-specific: 256 color support.
self.foreground_color = params.pop(0)
+ elif _color_type == 2:
+ # 24bit true colour support.
+ self.foreground_color = params[:3]
+ params[:3] = []
elif code == 39:
self.foreground_color = None
elif code >= 40 and code <= 47:
self.background_color = code - 40
- elif code == 48 and params and params.pop(0) == 5:
- # xterm-specific: 256 color support.
- if params:
+ elif code == 48 and params:
+ _color_type = params.pop(0)
+ if _color_type == 5 and params:
+ # xterm-specific: 256 color support.
self.background_color = params.pop(0)
+ elif _color_type == 2:
+ # 24bit true colour support.
+ self.background_color = params[:3]
+ params[:3] = []
elif code == 49:
self.background_color = None
@@ -310,17 +321,20 @@ class QtAnsiCodeProcessor(AnsiCodeProcessor):
default_color_map = darkbg_color_map.copy()
def get_color(self, color, intensity=0):
- """ Returns a QColor for a given color code, or None if one cannot be
- constructed.
+ """ Returns a QColor for a given color code or rgb list, or None if one
+ cannot be constructed.
"""
- if color is None:
- return None
- # Adjust for intensity, if possible.
- if color < 8 and intensity > 0:
- color += 8
+ if isinstance(color, int):
+ # Adjust for intensity, if possible.
+ if color < 8 and intensity > 0:
+ color += 8
+ constructor = self.color_map.get(color, None)
+ elif isinstance(color, (tuple, list)):
+ constructor = color
+ else:
+ return None
- constructor = self.color_map.get(color, None)
if isinstance(constructor, string_types):
# If this is an X11 color name, we just hope there is a close SVG
# color name. We could use QColor's static method
@@ -358,14 +372,15 @@ class QtAnsiCodeProcessor(AnsiCodeProcessor):
return format
- def set_background_color(self, color):
- """ Given a background color (a QColor), attempt to set a color map
- that will be aesthetically pleasing.
+ def set_background_color(self, style):
+ """
+ Given a syntax style, attempt to set a color map that will be
+ aesthetically pleasing.
"""
# Set a new default color map.
self.default_color_map = self.darkbg_color_map.copy()
- if color.value() >= 127:
+ if not dark_style(style):
# Colors appropriate for a terminal with a light background. For
# now, only use non-bright colors...
for i in range(8):
diff --git a/qtconsole/console_widget.py b/qtconsole/console_widget.py
index cd7a01b..8daa044 100644
--- a/qtconsole/console_widget.py
+++ b/qtconsole/console_widget.py
@@ -3,6 +3,7 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
+import os
import os.path
import re
import sys
@@ -132,12 +133,12 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
with the size of the font.
""")
- width = Integer(81, config=True,
+ console_width = Integer(81, config=True,
help="""The width of the console at start time in number
of characters (will double with `hsplit` paging)
""")
- height = Integer(25, config=True,
+ console_height = Integer(25, config=True,
help="""The height of the console at start time in number
of characters (will double with `vsplit` paging)
""")
@@ -244,7 +245,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
# Initialize protected variables. Some variables contain useful state
# information for subclasses; they should be considered read-only.
- self._append_before_prompt_pos = 0
+ self._append_before_prompt_cursor = self._control.textCursor()
self._ansi_processor = QtAnsiCodeProcessor()
if self.gui_completion == 'ncurses':
self._completion_widget = CompletionHtml(self)
@@ -263,7 +264,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
self._kill_ring = QtKillRing(self._control)
self._prompt = ''
self._prompt_html = None
- self._prompt_pos = 0
+ self._prompt_cursor = self._control.textCursor()
self._prompt_sep = ''
self._reading = False
self._reading_callback = None
@@ -426,7 +427,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
# Manually adjust the scrollbars *after* a resize event is dispatched.
elif etype == QtCore.QEvent.Resize and not self._filter_resize:
self._filter_resize = True
- QtGui.qApp.sendEvent(obj, event)
+ QtGui.QApplication.instance().sendEvent(obj, event)
self._adjust_scrollbars()
self._filter_resize = False
return True
@@ -472,12 +473,12 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
# 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(' ') * self.width + margin
+ width = font_metrics.width(' ') * self.console_width + margin
width += style.pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)
if self.paging == 'hsplit':
width = width * 2 + splitwidth
- height = font_metrics.height() * self.height + margin
+ height = font_metrics.height() * self.console_height + margin
if self.paging == 'vsplit':
height = height * 2 + splitwidth
@@ -780,7 +781,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
if self.font_size:
font.setPointSize(self.font_size)
else:
- font.setPointSize(QtGui.qApp.font().pointSize())
+ font.setPointSize(QtGui.QApplication.instance().font().pointSize())
font.setStyleHint(QtGui.QFont.TypeWriter)
self._set_font(font)
@@ -888,18 +889,10 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
if insert != self._insert_plain_text:
self._flush_pending_stream()
cursor.movePosition(QtGui.QTextCursor.End)
- start_pos = cursor.position()
# Perform the insertion.
result = insert(cursor, input, *args, **kwargs)
- # Adjust the prompt position if we have inserted before it. This is safe
- # because buffer truncation is disabled when not executing.
- if before_prompt and (self._reading or not self._executing):
- diff = cursor.position() - start_pos
- self._append_before_prompt_pos += diff
- self._prompt_pos += diff
-
return result
def _append_block(self, block_format=None, before_prompt=False):
@@ -1124,23 +1117,9 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
alt_down = event.modifiers() & QtCore.Qt.AltModifier
shift_down = event.modifiers() & QtCore.Qt.ShiftModifier
- #------ Special sequences ----------------------------------------------
-
- if event.matches(QtGui.QKeySequence.Copy):
- self.copy()
- intercepted = True
-
- elif event.matches(QtGui.QKeySequence.Cut):
- self.cut()
- intercepted = True
-
- elif event.matches(QtGui.QKeySequence.Paste):
- self.paste()
- intercepted = True
-
#------ Special modifier logic -----------------------------------------
- elif key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
+ if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
intercepted = True
# Special handling when tab completing in text mode.
@@ -1167,10 +1146,15 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
self.execute(interactive = not shift_down)
else:
# Do this inside an edit block for clean undo/redo.
+ pos = self._get_input_buffer_cursor_pos()
+ complete, indent = self._is_complete(
+ self._get_input_buffer()[:pos], True)
cursor.beginEditBlock()
cursor.setPosition(position)
cursor.insertText('\n')
self._insert_continuation_prompt(cursor)
+ if indent:
+ cursor.insertText(indent)
cursor.endEditBlock()
# Ensure that the whole input buffer is visible.
@@ -1319,9 +1303,25 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
if not self._reading:
if self._tab_pressed():
# real tab-key, insert four spaces
- cursor.insertText(' '*4)
+ step = 4 - (self._get_cursor().columnNumber() -
+ len(self._continuation_prompt)) % 4
+ cursor.insertText(' '*step)
intercepted = True
+ elif key == QtCore.Qt.Key_Backtab:
+ cur = self._get_cursor()
+ cur.movePosition(QtGui.QTextCursor.StartOfLine)
+ cur.movePosition(QtGui.QTextCursor.Right,
+ QtGui.QTextCursor.MoveAnchor,
+ self._get_prompt_cursor().columnNumber())
+ spaces = self._get_leading_spaces()
+ step = spaces % 4
+ cur.movePosition(QtGui.QTextCursor.Right,
+ QtGui.QTextCursor.KeepAnchor,
+ min(spaces, step if step != 0 else 4))
+ cur.removeSelectedText()
+ intercepted = True
+
elif key == QtCore.Qt.Key_Left:
# Move to the previous line
@@ -1358,7 +1358,18 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
start_pos = cursor.position()
start_pos += len(self._continuation_prompt)
cursor.setPosition(position)
+
+ c = self._get_cursor()
+ spaces = self._get_leading_spaces()
+ if (c.position() > start_pos + spaces or
+ c.columnNumber() == len(self._continuation_prompt)):
+ start_pos += spaces # Beginning of text
+
if shift_down and self._in_buffer(position):
+ if c.selectedText():
+ sel_max = max(c.selectionStart(), c.selectionEnd())
+ cursor.setPosition(sel_max,
+ QtGui.QTextCursor.MoveAnchor)
cursor.setPosition(start_pos, QtGui.QTextCursor.KeepAnchor)
else:
cursor.setPosition(start_pos)
@@ -1407,6 +1418,21 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
intercepted = (not self._in_buffer(anchor) or
not self._in_buffer(position))
+ #------ Special sequences ----------------------------------------------
+
+ if not intercepted:
+ if event.matches(QtGui.QKeySequence.Copy):
+ self.copy()
+ intercepted = True
+
+ elif event.matches(QtGui.QKeySequence.Cut):
+ self.cut()
+ intercepted = True
+
+ elif event.matches(QtGui.QKeySequence.Paste):
+ self.paste()
+ intercepted = True
+
# Don't move the cursor if Control/Cmd is pressed to allow copy-paste
# using the keyboard in any part of the buffer. Also, permit scrolling
# with Page Up/Down keys. Finally, if we're executing, don't move the
@@ -1493,10 +1519,6 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
pos = cursor.position()
self._flush_pending_stream()
cursor.movePosition(QtGui.QTextCursor.End)
- diff = cursor.position() - pos
- if diff > 0:
- self._prompt_pos += diff
- self._append_before_prompt_pos += diff
def _flush_pending_stream(self):
""" Flush out pending text into the widget. """
@@ -1555,6 +1577,11 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
cursor.movePosition(QtGui.QTextCursor.End)
return cursor
+ def _get_end_pos(self):
+ """ Convenience method that returns the position of the last character.
+ """
+ return self._get_end_cursor().position()
+
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.
@@ -1639,6 +1666,26 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
break
return ret[::-1]
+ def _get_leading_spaces(self):
+ """ Convenience method that returns the number of leading spaces.
+ """
+ cur = self._get_cursor()
+ cur.select(QtGui.QTextCursor.LineUnderCursor)
+ text = cur.selectedText()[len(self._continuation_prompt):]
+ return len(text) - len(text.lstrip())
+
+
+ @property
+ def _prompt_pos(self):
+ """Find the position in the text right after the prompt"""
+ return min(self._prompt_cursor.position() + 1, self._get_end_pos())
+
+ @property
+ def _append_before_prompt_pos(self):
+ """Find the position in the text right before the prompt"""
+ return min(self._append_before_prompt_cursor.position(),
+ self._get_end_pos())
+
def _get_prompt_cursor(self):
""" Convenience method that returns a cursor for the prompt position.
"""
@@ -1678,7 +1725,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
them. (This emulates the behavior of bash, emacs, etc.)
"""
document = self._control.document()
- end = self._get_end_cursor().position()
+ end = self._get_end_pos()
while position < end and \
not is_letter_or_number(document.characterAt(position)):
position += 1
@@ -1753,7 +1800,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
if (self._executing and not flush and
self._pending_text_flush_interval.isActive() and
- cursor.position() == self._get_end_cursor().position()):
+ cursor.position() == self._get_end_pos()):
# Queue the text to insert in case it is being inserted at end
self._pending_insert_text.append(text)
if buffer_size > 0:
@@ -1788,6 +1835,10 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
cursor.joinPreviousEditBlock()
cursor.deletePreviousChar()
+ if os.name == 'nt':
+ cursor.select(QtGui.QTextCursor.Document)
+ cursor.removeSelectedText()
+
elif act.action == 'carriage-return':
cursor.movePosition(
cursor.StartOfLine, cursor.KeepAnchor)
@@ -2070,10 +2121,20 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
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.
"""
- # Save the current end position to support _append*(before_prompt=True).
self._flush_pending_stream()
cursor = self._get_end_cursor()
- self._append_before_prompt_pos = cursor.position()
+
+ # Save the current position to support _append*(before_prompt=True).
+ # We can't leave the cursor at the end of the document though, because
+ # that would cause any further additions to move the cursor. Therefore,
+ # we move it back one place and move it forward again at the end of
+ # this method. However, we only do this if the cursor isn't already
+ # at the start of the text.
+ if cursor.position() == 0:
+ move_forward = False
+ else:
+ move_forward = True
+ self._append_before_prompt_cursor.setPosition(cursor.position() - 1)
# Insert a preliminary newline, if necessary.
if newline and cursor.position() > 0:
@@ -2081,7 +2142,6 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
QtGui.QTextCursor.KeepAnchor)
if cursor.selection().toPlainText() != '\n':
self._append_block()
- self._append_before_prompt_pos += 1
# Write the prompt.
self._append_plain_text(self._prompt_sep)
@@ -2100,7 +2160,11 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
self._prompt_html = None
self._flush_pending_stream()
- self._prompt_pos = self._get_end_cursor().position()
+ self._prompt_cursor.setPosition(self._get_end_pos() - 1)
+
+ if move_forward:
+ self._append_before_prompt_cursor.setPosition(
+ self._append_before_prompt_cursor.position() + 1)
self._prompt_started()
#------ Signal handlers ----------------------------------------------------
diff --git a/qtconsole/frontend_widget.py b/qtconsole/frontend_widget.py
index 12f948d..22d9213 100644
--- a/qtconsole/frontend_widget.py
+++ b/qtconsole/frontend_widget.py
@@ -447,9 +447,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
of the value of corresponding `user_expressions` as argument.
`callback` is then removed from the known list so that any message
coming again with the same id won't trigger it.
-
"""
-
user_exp = msg['content'].get('user_expressions')
if not user_exp:
return
@@ -482,8 +480,6 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
status = content['status']
if status == 'ok':
self._process_execute_ok(msg)
- elif status == 'error':
- self._process_execute_error(msg)
elif status == 'aborted':
self._process_execute_abort(msg)
@@ -496,6 +492,11 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
elif info and not self._hidden:
raise RuntimeError("Unknown handler for %s" % info.kind)
+ def _handle_error(self, msg):
+ """ Handle error messages.
+ """
+ self._process_execute_error(msg)
+
def _handle_input_request(self, msg):
""" Handle requests for raw_input.
"""
@@ -661,7 +662,6 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
# update output marker for stdout/stderr, so that startup
# messages appear after banner:
- self._append_before_prompt_pos = self._get_cursor().position()
self._show_interpreter_prompt()
def restart_kernel(self, message, now=False):
diff --git a/qtconsole/history_console_widget.py b/qtconsole/history_console_widget.py
index 46a08b5..35e4db9 100644
--- a/qtconsole/history_console_widget.py
+++ b/qtconsole/history_console_widget.py
@@ -76,31 +76,31 @@ class HistoryConsoleWidget(ConsoleWidget):
return False
# Set a search prefix based on the cursor position.
- col = self._get_input_buffer_cursor_column()
+ pos = self._get_input_buffer_cursor_pos()
input_buffer = self.input_buffer
# use the *shortest* of the cursor column and the history prefix
# to determine if the prefix has changed
- n = min(col, len(self._history_prefix))
-
+ n = min(pos, len(self._history_prefix))
+
# prefix changed, restart search from the beginning
if (self._history_prefix[:n] != input_buffer[:n]):
self._history_index = len(self._history)
-
+
# the only time we shouldn't set the history prefix
# to the line up to the cursor is if we are already
# in a simple scroll (no prefix),
# and the cursor is at the end of the first line
-
+
# check if we are at the end of the first line
c = self._get_cursor()
current_pos = c.position()
- c.movePosition(QtGui.QTextCursor.EndOfLine)
+ c.movePosition(QtGui.QTextCursor.EndOfBlock)
at_eol = (c.position() == current_pos)
-
+
if self._history_index == len(self._history) or \
not (self._history_prefix == '' and at_eol) or \
- not (self._get_edited_history(self._history_index)[:col] == input_buffer[:col]):
- self._history_prefix = input_buffer[:col]
+ not (self._get_edited_history(self._history_index)[:pos] == input_buffer[:pos]):
+ self._history_prefix = input_buffer[:pos]
# Perform the search.
self.history_previous(self._history_prefix,
@@ -114,7 +114,7 @@ class HistoryConsoleWidget(ConsoleWidget):
cursor.movePosition(QtGui.QTextCursor.Right,
n=len(self._history_prefix))
else:
- cursor.movePosition(QtGui.QTextCursor.EndOfLine)
+ cursor.movePosition(QtGui.QTextCursor.EndOfBlock)
self._set_cursor(cursor)
return False
diff --git a/qtconsole/jupyter_widget.py b/qtconsole/jupyter_widget.py
index ac3771b..8d5a508 100644
--- a/qtconsole/jupyter_widget.py
+++ b/qtconsole/jupyter_widget.py
@@ -16,6 +16,9 @@ from textwrap import dedent
from qtconsole.qt import QtCore, QtGui
+from IPython.lib.lexers import IPythonLexer, IPython3Lexer
+from pygments.lexers import get_lexer_by_name
+from pygments.util import ClassNotFound
from qtconsole import __version__
from traitlets import Bool, Unicode
from .frontend_widget import FrontendWidget
@@ -233,7 +236,6 @@ class JupyterWidget(IPythonWidget):
if self.include_output(msg):
self._append_custom(self._insert_other_input, msg['content'], before_prompt=True)
-
def _handle_execute_result(self, msg):
"""Handle an execute_result message"""
if self.include_output(msg):
@@ -271,6 +273,21 @@ class JupyterWidget(IPythonWidget):
def _handle_kernel_info_reply(self, rep):
"""Handle kernel info replies."""
content = rep['content']
+ language_name = content['language_info']['name']
+ pygments_lexer = content['language_info'].get('pygments_lexer', '')
+
+ try:
+ # Other kernels with pygments_lexer info will have to be
+ # added here by hand.
+ if pygments_lexer == 'ipython3':
+ lexer = IPython3Lexer()
+ elif pygments_lexer == 'ipython2':
+ lexer = IPythonLexer()
+ else:
+ lexer = get_lexer_by_name(language_name)
+ self._highlighter._lexer = lexer
+ except ClassNotFound:
+ pass
self.kernel_banner = content.get('banner', '')
if self._starting:
@@ -281,6 +298,7 @@ class JupyterWidget(IPythonWidget):
def _started_channels(self):
... 1069 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-qtconsole.git
More information about the Python-modules-commits
mailing list