diff options
author | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/python/prompt-toolkit/py2 | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
download | ydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz |
fix ya.make
Diffstat (limited to 'contrib/python/prompt-toolkit/py2')
123 files changed, 0 insertions, 26831 deletions
diff --git a/contrib/python/prompt-toolkit/py2/.dist-info/METADATA b/contrib/python/prompt-toolkit/py2/.dist-info/METADATA deleted file mode 100644 index 24d0343b30..0000000000 --- a/contrib/python/prompt-toolkit/py2/.dist-info/METADATA +++ /dev/null @@ -1,198 +0,0 @@ -Metadata-Version: 2.1 -Name: prompt-toolkit -Version: 1.0.18 -Summary: Library for building powerful interactive command lines in Python -Home-page: https://github.com/jonathanslenders/python-prompt-toolkit -Author: Jonathan Slenders -Author-email: UNKNOWN -License: UNKNOWN -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -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 -Classifier: Programming Language :: Python -Classifier: Topic :: Software Development -Requires-Dist: six (>=1.9.0) -Requires-Dist: wcwidth - -Python Prompt Toolkit -===================== - -|Build Status| |PyPI| - -``prompt_toolkit`` is a library for building powerful interactive command lines -and terminal applications in Python. - -Read the `documentation on readthedocs -<http://python-prompt-toolkit.readthedocs.io/en/stable/>`_. - - -Ptpython -******** - -`ptpython <http://github.com/jonathanslenders/ptpython/>`_ is an interactive -Python Shell, build on top of prompt_toolkit. - -.. image :: https://github.com/jonathanslenders/python-prompt-toolkit/raw/master/docs/images/ptpython.png - - -prompt_toolkit features -*********************** - -``prompt_toolkit`` could be a replacement for `GNU readline -<http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html>`_, but it can be much -more than that. - -Some features: - -- Pure Python. -- Syntax highlighting of the input while typing. (For instance, with a Pygments lexer.) -- Multi-line input editing. -- Advanced code completion. -- Both Emacs and Vi key bindings. (Similar to readline.) -- Even some advanced Vi functionality, like named registers and digraphs. -- Reverse and forward incremental search. -- Runs on all Python versions from 2.6 up to 3.5. -- Works well with Unicode double width characters. (Chinese input.) -- Selecting text for copy/paste. (Both Emacs and Vi style.) -- Support for `bracketed paste <https://cirw.in/blog/bracketed-paste>`_. -- Mouse support for cursor positioning and scrolling. -- Auto suggestions. (Like `fish shell <http://fishshell.com/>`_.) -- Multiple input buffers. -- No global state. -- Lightweight, the only dependencies are Pygments, six and wcwidth. -- Runs on Linux, OS X, FreeBSD, OpenBSD and Windows systems. -- And much more... - -Feel free to create tickets for bugs and feature requests, and create pull -requests if you have nice patches that you would like to share with others. - - -About Windows support -********************* - -``prompt_toolkit`` is cross platform, and everything that you build on top -should run fine on both Unix and Windows systems. On Windows, it uses a -different event loop (``WaitForMultipleObjects`` instead of ``select``), and -another input and output system. (Win32 APIs instead of pseudo-terminals and -VT100.) - -It's worth noting that the implementation is a "best effort of what is -possible". Both Unix and Windows terminals have their limitations. But in -general, the Unix experience will still be a little better. - -For Windows, it's recommended to use either `cmder -<http://cmder.net/>`_ or `conemu <https://conemu.github.io/>`_. - - -Installation -************ - -:: - - pip install prompt_toolkit - -For Conda, do: - -:: - - conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit - - -Getting started -*************** - -The most simple example of the library would look like this: - -.. code:: python - - from prompt_toolkit import prompt - - if __name__ == '__main__': - answer = prompt('Give me some input: ') - print('You said: %s' % answer) - -For more complex examples, have a look in the ``examples`` directory. All -examples are chosen to demonstrate only one thing. Also, don't be afraid to -look at the source code. The implementation of the ``prompt`` function could be -a good start. - -Note for Python 2: all strings are expected to be unicode strings. So, either -put a small ``u`` in front of every string or put ``from __future__ import -unicode_literals`` at the start of the above example. - - -Projects using prompt_toolkit -***************************** - -Shells: - -- `ptpython <http://github.com/jonathanslenders/ptpython/>`_: Python REPL -- `ptpdb <http://github.com/jonathanslenders/ptpdb/>`_: Python debugger (pdb replacement) -- `pgcli <http://pgcli.com/>`_: Postgres client. -- `mycli <http://mycli.net>`_: MySql client. -- `wharfee <http://wharfee.com/>`_: A Docker command line. -- `xonsh <http://xon.sh/>`_: A Python-ish, BASHwards-compatible shell. -- `saws <https://github.com/donnemartin/saws>`_: A Supercharged AWS Command Line Interface. -- `cycli <https://github.com/nicolewhite/cycli>`_: A Command Line Interface for Cypher. -- `crash <https://github.com/crate/crash>`_: Crate command line client. -- `vcli <https://github.com/dbcli/vcli>`_: Vertica client. -- `aws-shell <https://github.com/awslabs/aws-shell>`_: An integrated shell for working with the AWS CLI. -- `softlayer-python <https://github.com/softlayer/softlayer-python>`_: A command-line interface to manage various SoftLayer products and services. -- `ipython <http://github.com/ipython/ipython/>`_: The IPython REPL -- `click-repl <https://github.com/click-contrib/click-repl>`_: Subcommand REPL for click apps. -- `haxor-news <https://github.com/donnemartin/haxor-news>`_: A Hacker News CLI. -- `gitsome <https://github.com/donnemartin/gitsome>`_: A Git/Shell Autocompleter with GitHub Integration. -- `http-prompt <https://github.com/eliangcs/http-prompt>`_: An interactive command-line HTTP client. -- `coconut <http://coconut-lang.org/>`_: Functional programming in Python. -- `Ergonomica <https://ergonomica.github.io/>`_: A Bash alternative written in Python. -- `Kube-shell <https://github.com/cloudnativelabs/kube-shell>`_: Kubernetes shell: An integrated shell for working with the Kubernetes CLI - -Full screen applications: - -- `pymux <http://github.com/jonathanslenders/pymux/>`_: A terminal multiplexer (like tmux) in pure Python. -- `pyvim <http://github.com/jonathanslenders/pyvim/>`_: A Vim clone in pure Python. - -(Want your own project to be listed here? Please create a GitHub issue.) - - -Philosophy -********** - -The source code of ``prompt_toolkit`` should be readable, concise and -efficient. We prefer short functions focussing each on one task and for which -the input and output types are clearly specified. We mostly prefer composition -over inheritance, because inheritance can result in too much functionality in -the same object. We prefer immutable objects where possible (objects don't -change after initialisation). Reusability is important. We absolutely refrain -from having a changing global state, it should be possible to have multiple -independent instances of the same code in the same process. The architecture -should be layered: the lower levels operate on primitive operations and data -structures giving -- when correctly combined -- all the possible flexibility; -while at the higher level, there should be a simpler API, ready-to-use and -sufficient for most use cases. Thinking about algorithms and efficiency is -important, but avoid premature optimization. - - -Special thanks to -***************** - -- `Pygments <http://pygments.org/>`_: Syntax highlighter. -- `wcwidth <https://github.com/jquast/wcwidth>`_: Determine columns needed for a wide characters. - -.. |Build Status| image:: https://api.travis-ci.org/jonathanslenders/python-prompt-toolkit.svg?branch=master - :target: https://travis-ci.org/jonathanslenders/python-prompt-toolkit# - -.. |PyPI| image:: https://img.shields.io/pypi/v/prompt_toolkit.svg - :target: https://pypi.python.org/pypi/prompt-toolkit/ - :alt: Latest Version - - diff --git a/contrib/python/prompt-toolkit/py2/.dist-info/top_level.txt b/contrib/python/prompt-toolkit/py2/.dist-info/top_level.txt deleted file mode 100644 index 29392dfc5b..0000000000 --- a/contrib/python/prompt-toolkit/py2/.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -prompt_toolkit diff --git a/contrib/python/prompt-toolkit/py2/AUTHORS.rst b/contrib/python/prompt-toolkit/py2/AUTHORS.rst deleted file mode 100644 index f7c8f60f40..0000000000 --- a/contrib/python/prompt-toolkit/py2/AUTHORS.rst +++ /dev/null @@ -1,11 +0,0 @@ -Authors -======= - -Creator -------- -Jonathan Slenders <jonathan AT slenders.be> - -Contributors ------------- - -- Amjith Ramanujam <amjith.r AT gmail.com> diff --git a/contrib/python/prompt-toolkit/py2/LICENSE b/contrib/python/prompt-toolkit/py2/LICENSE deleted file mode 100644 index e1720e0fb7..0000000000 --- a/contrib/python/prompt-toolkit/py2/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014, Jonathan Slenders -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - -* Neither the name of the {organization} nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/python/prompt-toolkit/py2/README.rst b/contrib/python/prompt-toolkit/py2/README.rst deleted file mode 100644 index 35b1745614..0000000000 --- a/contrib/python/prompt-toolkit/py2/README.rst +++ /dev/null @@ -1,171 +0,0 @@ -Python Prompt Toolkit -===================== - -|Build Status| |PyPI| - -``prompt_toolkit`` is a library for building powerful interactive command lines -and terminal applications in Python. - -Read the `documentation on readthedocs -<http://python-prompt-toolkit.readthedocs.io/en/stable/>`_. - - -Ptpython -******** - -`ptpython <http://github.com/jonathanslenders/ptpython/>`_ is an interactive -Python Shell, build on top of prompt_toolkit. - -.. image :: https://github.com/jonathanslenders/python-prompt-toolkit/raw/master/docs/images/ptpython.png - - -prompt_toolkit features -*********************** - -``prompt_toolkit`` could be a replacement for `GNU readline -<http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html>`_, but it can be much -more than that. - -Some features: - -- Pure Python. -- Syntax highlighting of the input while typing. (For instance, with a Pygments lexer.) -- Multi-line input editing. -- Advanced code completion. -- Both Emacs and Vi key bindings. (Similar to readline.) -- Even some advanced Vi functionality, like named registers and digraphs. -- Reverse and forward incremental search. -- Runs on all Python versions from 2.6 up to 3.5. -- Works well with Unicode double width characters. (Chinese input.) -- Selecting text for copy/paste. (Both Emacs and Vi style.) -- Support for `bracketed paste <https://cirw.in/blog/bracketed-paste>`_. -- Mouse support for cursor positioning and scrolling. -- Auto suggestions. (Like `fish shell <http://fishshell.com/>`_.) -- Multiple input buffers. -- No global state. -- Lightweight, the only dependencies are Pygments, six and wcwidth. -- Runs on Linux, OS X, FreeBSD, OpenBSD and Windows systems. -- And much more... - -Feel free to create tickets for bugs and feature requests, and create pull -requests if you have nice patches that you would like to share with others. - - -About Windows support -********************* - -``prompt_toolkit`` is cross platform, and everything that you build on top -should run fine on both Unix and Windows systems. On Windows, it uses a -different event loop (``WaitForMultipleObjects`` instead of ``select``), and -another input and output system. (Win32 APIs instead of pseudo-terminals and -VT100.) - -It's worth noting that the implementation is a "best effort of what is -possible". Both Unix and Windows terminals have their limitations. But in -general, the Unix experience will still be a little better. - -For Windows, it's recommended to use either `cmder -<http://cmder.net/>`_ or `conemu <https://conemu.github.io/>`_. - - -Installation -************ - -:: - - pip install prompt_toolkit - -For Conda, do: - -:: - - conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit - - -Getting started -*************** - -The most simple example of the library would look like this: - -.. code:: python - - from prompt_toolkit import prompt - - if __name__ == '__main__': - answer = prompt('Give me some input: ') - print('You said: %s' % answer) - -For more complex examples, have a look in the ``examples`` directory. All -examples are chosen to demonstrate only one thing. Also, don't be afraid to -look at the source code. The implementation of the ``prompt`` function could be -a good start. - -Note for Python 2: all strings are expected to be unicode strings. So, either -put a small ``u`` in front of every string or put ``from __future__ import -unicode_literals`` at the start of the above example. - - -Projects using prompt_toolkit -***************************** - -Shells: - -- `ptpython <http://github.com/jonathanslenders/ptpython/>`_: Python REPL -- `ptpdb <http://github.com/jonathanslenders/ptpdb/>`_: Python debugger (pdb replacement) -- `pgcli <http://pgcli.com/>`_: Postgres client. -- `mycli <http://mycli.net>`_: MySql client. -- `wharfee <http://wharfee.com/>`_: A Docker command line. -- `xonsh <http://xon.sh/>`_: A Python-ish, BASHwards-compatible shell. -- `saws <https://github.com/donnemartin/saws>`_: A Supercharged AWS Command Line Interface. -- `cycli <https://github.com/nicolewhite/cycli>`_: A Command Line Interface for Cypher. -- `crash <https://github.com/crate/crash>`_: Crate command line client. -- `vcli <https://github.com/dbcli/vcli>`_: Vertica client. -- `aws-shell <https://github.com/awslabs/aws-shell>`_: An integrated shell for working with the AWS CLI. -- `softlayer-python <https://github.com/softlayer/softlayer-python>`_: A command-line interface to manage various SoftLayer products and services. -- `ipython <http://github.com/ipython/ipython/>`_: The IPython REPL -- `click-repl <https://github.com/click-contrib/click-repl>`_: Subcommand REPL for click apps. -- `haxor-news <https://github.com/donnemartin/haxor-news>`_: A Hacker News CLI. -- `gitsome <https://github.com/donnemartin/gitsome>`_: A Git/Shell Autocompleter with GitHub Integration. -- `http-prompt <https://github.com/eliangcs/http-prompt>`_: An interactive command-line HTTP client. -- `coconut <http://coconut-lang.org/>`_: Functional programming in Python. -- `Ergonomica <https://ergonomica.github.io/>`_: A Bash alternative written in Python. -- `Kube-shell <https://github.com/cloudnativelabs/kube-shell>`_: Kubernetes shell: An integrated shell for working with the Kubernetes CLI - -Full screen applications: - -- `pymux <http://github.com/jonathanslenders/pymux/>`_: A terminal multiplexer (like tmux) in pure Python. -- `pyvim <http://github.com/jonathanslenders/pyvim/>`_: A Vim clone in pure Python. - -(Want your own project to be listed here? Please create a GitHub issue.) - - -Philosophy -********** - -The source code of ``prompt_toolkit`` should be readable, concise and -efficient. We prefer short functions focussing each on one task and for which -the input and output types are clearly specified. We mostly prefer composition -over inheritance, because inheritance can result in too much functionality in -the same object. We prefer immutable objects where possible (objects don't -change after initialisation). Reusability is important. We absolutely refrain -from having a changing global state, it should be possible to have multiple -independent instances of the same code in the same process. The architecture -should be layered: the lower levels operate on primitive operations and data -structures giving -- when correctly combined -- all the possible flexibility; -while at the higher level, there should be a simpler API, ready-to-use and -sufficient for most use cases. Thinking about algorithms and efficiency is -important, but avoid premature optimization. - - -Special thanks to -***************** - -- `Pygments <http://pygments.org/>`_: Syntax highlighter. -- `wcwidth <https://github.com/jquast/wcwidth>`_: Determine columns needed for a wide characters. - -.. |Build Status| image:: https://api.travis-ci.org/jonathanslenders/python-prompt-toolkit.svg?branch=master - :target: https://travis-ci.org/jonathanslenders/python-prompt-toolkit# - -.. |PyPI| image:: https://img.shields.io/pypi/v/prompt_toolkit.svg - :target: https://pypi.python.org/pypi/prompt-toolkit/ - :alt: Latest Version diff --git a/contrib/python/prompt-toolkit/py2/patches/01-fix-tests.patch b/contrib/python/prompt-toolkit/py2/patches/01-fix-tests.patch deleted file mode 100644 index 2830ea41db..0000000000 --- a/contrib/python/prompt-toolkit/py2/patches/01-fix-tests.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- contrib/python/prompt-toolkit/py2/tests/test_contrib.py (index) -+++ contrib/python/prompt-toolkit/py2/tests/test_contrib.py (working tree) -@@ -194,7 +194,8 @@ def test_pathcompleter_does_not_expanduser_by_default(): - assert [] == completions - - --def test_pathcompleter_can_expanduser(): -+def test_pathcompleter_can_expanduser(monkeypatch): -+ monkeypatch.setenv('HOME', '/tmp') - completer = PathCompleter(expanduser=True) - doc_text = '~' - doc = Document(doc_text, len(doc_text)) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py deleted file mode 100644 index 6478ba4f9a..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -prompt_toolkit -============== - -Author: Jonathan Slenders - -Description: prompt_toolkit is a Library for building powerful interactive - command lines in Python. It can be a replacement for GNU - readline, but it can be much more than that. - -See the examples directory to learn about the usage. - -Probably, to get started, you meight also want to have a look at -`prompt_toolkit.shortcuts.prompt`. -""" -from .interface import CommandLineInterface -from .application import AbortAction, Application -from .shortcuts import prompt, prompt_async - - -# Don't forget to update in `docs/conf.py`! -__version__ = '1.0.18' diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py deleted file mode 100644 index 272d8bbcbb..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py +++ /dev/null @@ -1,192 +0,0 @@ -from __future__ import unicode_literals - -from .buffer import Buffer, AcceptAction -from .buffer_mapping import BufferMapping -from .clipboard import Clipboard, InMemoryClipboard -from .enums import DEFAULT_BUFFER, EditingMode -from .filters import CLIFilter, to_cli_filter -from .key_binding.bindings.basic import load_basic_bindings -from .key_binding.bindings.emacs import load_emacs_bindings -from .key_binding.bindings.vi import load_vi_bindings -from .key_binding.registry import BaseRegistry -from .key_binding.defaults import load_key_bindings -from .layout import Window -from .layout.containers import Container -from .layout.controls import BufferControl -from .styles import DEFAULT_STYLE, Style -import six - -__all__ = ( - 'AbortAction', - 'Application', -) - - -class AbortAction(object): - """ - Actions to take on an Exit or Abort exception. - """ - RETRY = 'retry' - RAISE_EXCEPTION = 'raise-exception' - RETURN_NONE = 'return-none' - - _all = (RETRY, RAISE_EXCEPTION, RETURN_NONE) - - -class Application(object): - """ - Application class to be passed to a - :class:`~prompt_toolkit.interface.CommandLineInterface`. - - This contains all customizable logic that is not I/O dependent. - (So, what is independent of event loops, input and output.) - - This way, such an :class:`.Application` can run easily on several - :class:`~prompt_toolkit.interface.CommandLineInterface` instances, each - with a different I/O backends. that runs for instance over telnet, SSH or - any other I/O backend. - - :param layout: A :class:`~prompt_toolkit.layout.containers.Container` instance. - :param buffer: A :class:`~prompt_toolkit.buffer.Buffer` instance for the default buffer. - :param initial_focussed_buffer: Name of the buffer that is focussed during start-up. - :param key_bindings_registry: - :class:`~prompt_toolkit.key_binding.registry.BaseRegistry` instance for - the key bindings. - :param clipboard: :class:`~prompt_toolkit.clipboard.base.Clipboard` to use. - :param on_abort: What to do when Control-C is pressed. - :param on_exit: What to do when Control-D is pressed. - :param use_alternate_screen: When True, run the application on the alternate screen buffer. - :param get_title: Callable that returns the current title to be displayed in the terminal. - :param erase_when_done: (bool) Clear the application output when it finishes. - :param reverse_vi_search_direction: Normally, in Vi mode, a '/' searches - forward and a '?' searches backward. In readline mode, this is usually - reversed. - - Filters: - - :param mouse_support: (:class:`~prompt_toolkit.filters.CLIFilter` or - boolean). When True, enable mouse support. - :param paste_mode: :class:`~prompt_toolkit.filters.CLIFilter` or boolean. - :param ignore_case: :class:`~prompt_toolkit.filters.CLIFilter` or boolean. - :param editing_mode: :class:`~prompt_toolkit.enums.EditingMode`. - - Callbacks (all of these should accept a - :class:`~prompt_toolkit.interface.CommandLineInterface` object as input.) - - :param on_input_timeout: Called when there is no input for x seconds. - (Fired when any eventloop.onInputTimeout is fired.) - :param on_start: Called when reading input starts. - :param on_stop: Called when reading input ends. - :param on_reset: Called during reset. - :param on_buffer_changed: Called when the content of a buffer has been changed. - :param on_initialize: Called after the - :class:`~prompt_toolkit.interface.CommandLineInterface` initializes. - :param on_render: Called right after rendering. - :param on_invalidate: Called when the UI has been invalidated. - """ - def __init__(self, layout=None, buffer=None, buffers=None, - initial_focussed_buffer=DEFAULT_BUFFER, - style=None, - key_bindings_registry=None, clipboard=None, - on_abort=AbortAction.RAISE_EXCEPTION, on_exit=AbortAction.RAISE_EXCEPTION, - use_alternate_screen=False, mouse_support=False, - get_title=None, - - paste_mode=False, ignore_case=False, editing_mode=EditingMode.EMACS, - erase_when_done=False, - reverse_vi_search_direction=False, - - on_input_timeout=None, on_start=None, on_stop=None, - on_reset=None, on_initialize=None, on_buffer_changed=None, - on_render=None, on_invalidate=None): - - paste_mode = to_cli_filter(paste_mode) - ignore_case = to_cli_filter(ignore_case) - mouse_support = to_cli_filter(mouse_support) - reverse_vi_search_direction = to_cli_filter(reverse_vi_search_direction) - - assert layout is None or isinstance(layout, Container) - assert buffer is None or isinstance(buffer, Buffer) - assert buffers is None or isinstance(buffers, (dict, BufferMapping)) - assert key_bindings_registry is None or isinstance(key_bindings_registry, BaseRegistry) - assert clipboard is None or isinstance(clipboard, Clipboard) - assert on_abort in AbortAction._all - assert on_exit in AbortAction._all - assert isinstance(use_alternate_screen, bool) - assert get_title is None or callable(get_title) - assert isinstance(paste_mode, CLIFilter) - assert isinstance(ignore_case, CLIFilter) - assert isinstance(editing_mode, six.string_types) - assert on_input_timeout is None or callable(on_input_timeout) - assert style is None or isinstance(style, Style) - assert isinstance(erase_when_done, bool) - - assert on_start is None or callable(on_start) - assert on_stop is None or callable(on_stop) - assert on_reset is None or callable(on_reset) - assert on_buffer_changed is None or callable(on_buffer_changed) - assert on_initialize is None or callable(on_initialize) - assert on_render is None or callable(on_render) - assert on_invalidate is None or callable(on_invalidate) - - self.layout = layout or Window(BufferControl()) - - # Make sure that the 'buffers' dictionary is a BufferMapping. - # NOTE: If no buffer is given, we create a default Buffer, with IGNORE as - # default accept_action. This is what makes sense for most users - # creating full screen applications. Doing nothing is the obvious - # default. Those creating a REPL would use the shortcuts module that - # passes in RETURN_DOCUMENT. - self.buffer = buffer or Buffer(accept_action=AcceptAction.IGNORE) - if not buffers or not isinstance(buffers, BufferMapping): - self.buffers = BufferMapping(buffers, initial=initial_focussed_buffer) - else: - self.buffers = buffers - - if buffer: - self.buffers[DEFAULT_BUFFER] = buffer - - self.initial_focussed_buffer = initial_focussed_buffer - - self.style = style or DEFAULT_STYLE - - if key_bindings_registry is None: - key_bindings_registry = load_key_bindings() - - if get_title is None: - get_title = lambda: None - - self.key_bindings_registry = key_bindings_registry - self.clipboard = clipboard or InMemoryClipboard() - self.on_abort = on_abort - self.on_exit = on_exit - self.use_alternate_screen = use_alternate_screen - self.mouse_support = mouse_support - self.get_title = get_title - - self.paste_mode = paste_mode - self.ignore_case = ignore_case - self.editing_mode = editing_mode - self.erase_when_done = erase_when_done - self.reverse_vi_search_direction = reverse_vi_search_direction - - def dummy_handler(cli): - " Dummy event handler. " - - self.on_input_timeout = on_input_timeout or dummy_handler - self.on_start = on_start or dummy_handler - self.on_stop = on_stop or dummy_handler - self.on_reset = on_reset or dummy_handler - self.on_initialize = on_initialize or dummy_handler - self.on_buffer_changed = on_buffer_changed or dummy_handler - self.on_render = on_render or dummy_handler - self.on_invalidate = on_invalidate or dummy_handler - - # List of 'extra' functions to execute before a CommandLineInterface.run. - # Note: It's important to keep this here, and not in the - # CommandLineInterface itself. shortcuts.run_application creates - # a new Application instance everytime. (Which is correct, it - # could be that we want to detach from one IO backend and attach - # the UI on a different backend.) But important is to keep as - # much state as possible between runs. - self.pre_run_callables = [] diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py deleted file mode 100644 index 1d5130521f..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -`Fish-style <http://fishshell.com/>`_ like auto-suggestion. - -While a user types input in a certain buffer, suggestions are generated -(asynchronously.) Usually, they are displayed after the input. When the cursor -presses the right arrow and the cursor is at the end of the input, the -suggestion will be inserted. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -from .filters import to_cli_filter - -__all__ = ( - 'Suggestion', - 'AutoSuggest', - 'AutoSuggestFromHistory', - 'ConditionalAutoSuggest', -) - - -class Suggestion(object): - """ - Suggestion returned by an auto-suggest algorithm. - - :param text: The suggestion text. - """ - def __init__(self, text): - self.text = text - - def __repr__(self): - return 'Suggestion(%s)' % self.text - - -class AutoSuggest(with_metaclass(ABCMeta, object)): - """ - Base class for auto suggestion implementations. - """ - @abstractmethod - def get_suggestion(self, cli, buffer, document): - """ - Return `None` or a :class:`.Suggestion` instance. - - We receive both ``buffer`` and ``document``. The reason is that auto - suggestions are retrieved asynchronously. (Like completions.) The - buffer text could be changed in the meantime, but ``document`` contains - the buffer document like it was at the start of the auto suggestion - call. So, from here, don't access ``buffer.text``, but use - ``document.text`` instead. - - :param buffer: The :class:`~prompt_toolkit.buffer.Buffer` instance. - :param document: The :class:`~prompt_toolkit.document.Document` instance. - """ - - -class AutoSuggestFromHistory(AutoSuggest): - """ - Give suggestions based on the lines in the history. - """ - def get_suggestion(self, cli, buffer, document): - history = buffer.history - - # Consider only the last line for the suggestion. - text = document.text.rsplit('\n', 1)[-1] - - # Only create a suggestion when this is not an empty line. - if text.strip(): - # Find first matching line in history. - for string in reversed(list(history)): - for line in reversed(string.splitlines()): - if line.startswith(text): - return Suggestion(line[len(text):]) - - -class ConditionalAutoSuggest(AutoSuggest): - """ - Auto suggest that can be turned on and of according to a certain condition. - """ - def __init__(self, auto_suggest, filter): - assert isinstance(auto_suggest, AutoSuggest) - - self.auto_suggest = auto_suggest - self.filter = to_cli_filter(filter) - - def get_suggestion(self, cli, buffer, document): - if self.filter(cli): - return self.auto_suggest.get_suggestion(cli, buffer, document) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py deleted file mode 100644 index f5df289827..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py +++ /dev/null @@ -1,1415 +0,0 @@ -""" -Data structures for the Buffer. -It holds the text, cursor position, history, etc... -""" -from __future__ import unicode_literals - -from .auto_suggest import AutoSuggest -from .clipboard import ClipboardData -from .completion import Completer, Completion, CompleteEvent -from .document import Document -from .enums import IncrementalSearchDirection -from .filters import to_simple_filter -from .history import History, InMemoryHistory -from .search_state import SearchState -from .selection import SelectionType, SelectionState, PasteMode -from .utils import Event -from .cache import FastDictCache -from .validation import ValidationError - -from six.moves import range - -import os -import re -import shlex -import six -import subprocess -import tempfile - -__all__ = ( - 'EditReadOnlyBuffer', - 'AcceptAction', - 'Buffer', - 'indent', - 'unindent', - 'reshape_text', -) - - -class EditReadOnlyBuffer(Exception): - " Attempt editing of read-only :class:`.Buffer`. " - - -class AcceptAction(object): - """ - What to do when the input is accepted by the user. - (When Enter was pressed in the command line.) - - :param handler: (optional) A callable which takes a - :class:`~prompt_toolkit.interface.CommandLineInterface` and - :class:`~prompt_toolkit.document.Document`. It is called when the user - accepts input. - """ - def __init__(self, handler=None): - assert handler is None or callable(handler) - self.handler = handler - - @classmethod - def run_in_terminal(cls, handler, render_cli_done=False): - """ - Create an :class:`.AcceptAction` that runs the given handler in the - terminal. - - :param render_cli_done: When True, render the interface in the 'Done' - state first, then execute the function. If False, erase the - interface instead. - """ - def _handler(cli, buffer): - cli.run_in_terminal(lambda: handler(cli, buffer), render_cli_done=render_cli_done) - return AcceptAction(handler=_handler) - - @property - def is_returnable(self): - """ - True when there is something handling accept. - """ - return bool(self.handler) - - def validate_and_handle(self, cli, buffer): - """ - Validate buffer and handle the accept action. - """ - if buffer.validate(): - if self.handler: - self.handler(cli, buffer) - - buffer.append_to_history() - - -def _return_document_handler(cli, buffer): - # Set return value. - cli.set_return_value(buffer.document) - - # Make sure that if we run this UI again, that we reset this buffer, next - # time. - def reset_this_buffer(): - buffer.reset() - cli.pre_run_callables.append(reset_this_buffer) - - -AcceptAction.RETURN_DOCUMENT = AcceptAction(_return_document_handler) -AcceptAction.IGNORE = AcceptAction(handler=None) - - -class ValidationState(object): - " The validation state of a buffer. This is set after the validation. " - VALID = 'VALID' - INVALID = 'INVALID' - UNKNOWN = 'UNKNOWN' - - -class CompletionState(object): - """ - Immutable class that contains a completion state. - """ - def __init__(self, original_document, current_completions=None, complete_index=None): - #: Document as it was when the completion started. - self.original_document = original_document - - #: List of all the current Completion instances which are possible at - #: this point. - self.current_completions = current_completions or [] - - #: Position in the `current_completions` array. - #: This can be `None` to indicate "no completion", the original text. - self.complete_index = complete_index # Position in the `_completions` array. - - def __repr__(self): - return '%s(%r, <%r> completions, index=%r)' % ( - self.__class__.__name__, - self.original_document, len(self.current_completions), self.complete_index) - - def go_to_index(self, index): - """ - Create a new :class:`.CompletionState` object with the new index. - """ - return CompletionState(self.original_document, self.current_completions, complete_index=index) - - def new_text_and_position(self): - """ - Return (new_text, new_cursor_position) for this completion. - """ - if self.complete_index is None: - return self.original_document.text, self.original_document.cursor_position - else: - original_text_before_cursor = self.original_document.text_before_cursor - original_text_after_cursor = self.original_document.text_after_cursor - - c = self.current_completions[self.complete_index] - if c.start_position == 0: - before = original_text_before_cursor - else: - before = original_text_before_cursor[:c.start_position] - - new_text = before + c.text + original_text_after_cursor - new_cursor_position = len(before) + len(c.text) - return new_text, new_cursor_position - - @property - def current_completion(self): - """ - Return the current completion, or return `None` when no completion is - selected. - """ - if self.complete_index is not None: - return self.current_completions[self.complete_index] - - -_QUOTED_WORDS_RE = re.compile(r"""(\s+|".*?"|'.*?')""") - - -class YankNthArgState(object): - """ - For yank-last-arg/yank-nth-arg: Keep track of where we are in the history. - """ - def __init__(self, history_position=0, n=-1, previous_inserted_word=''): - self.history_position = history_position - self.previous_inserted_word = previous_inserted_word - self.n = n - - def __repr__(self): - return '%s(history_position=%r, n=%r, previous_inserted_word=%r)' % ( - self.__class__.__name__, self.history_position, self.n, - self.previous_inserted_word) - - -class Buffer(object): - """ - The core data structure that holds the text and cursor position of the - current input line and implements all text manupulations on top of it. It - also implements the history, undo stack and the completion state. - - :param completer: :class:`~prompt_toolkit.completion.Completer` instance. - :param history: :class:`~prompt_toolkit.history.History` instance. - :param tempfile_suffix: Suffix to be appended to the tempfile for the 'open - in editor' function. - - Events: - - :param on_text_changed: When the buffer text changes. (Callable on None.) - :param on_text_insert: When new text is inserted. (Callable on None.) - :param on_cursor_position_changed: When the cursor moves. (Callable on None.) - - Filters: - - :param is_multiline: :class:`~prompt_toolkit.filters.SimpleFilter` to - indicate whether we should consider this buffer a multiline input. If - so, key bindings can decide to insert newlines when pressing [Enter]. - (Instead of accepting the input.) - :param complete_while_typing: :class:`~prompt_toolkit.filters.SimpleFilter` - instance. Decide whether or not to do asynchronous autocompleting while - typing. - :param enable_history_search: :class:`~prompt_toolkit.filters.SimpleFilter` - to indicate when up-arrow partial string matching is enabled. It is - adviced to not enable this at the same time as `complete_while_typing`, - because when there is an autocompletion found, the up arrows usually - browse through the completions, rather than through the history. - :param read_only: :class:`~prompt_toolkit.filters.SimpleFilter`. When True, - changes will not be allowed. - """ - def __init__(self, completer=None, auto_suggest=None, history=None, - validator=None, tempfile_suffix='', - is_multiline=False, complete_while_typing=False, - enable_history_search=False, initial_document=None, - accept_action=AcceptAction.IGNORE, read_only=False, - on_text_changed=None, on_text_insert=None, on_cursor_position_changed=None): - - # Accept both filters and booleans as input. - enable_history_search = to_simple_filter(enable_history_search) - is_multiline = to_simple_filter(is_multiline) - complete_while_typing = to_simple_filter(complete_while_typing) - read_only = to_simple_filter(read_only) - - # Validate input. - assert completer is None or isinstance(completer, Completer) - assert auto_suggest is None or isinstance(auto_suggest, AutoSuggest) - assert history is None or isinstance(history, History) - assert on_text_changed is None or callable(on_text_changed) - assert on_text_insert is None or callable(on_text_insert) - assert on_cursor_position_changed is None or callable(on_cursor_position_changed) - - self.completer = completer - self.auto_suggest = auto_suggest - self.validator = validator - self.tempfile_suffix = tempfile_suffix - self.accept_action = accept_action - - # Filters. (Usually, used by the key bindings to drive the buffer.) - self.is_multiline = is_multiline - self.complete_while_typing = complete_while_typing - self.enable_history_search = enable_history_search - self.read_only = read_only - - # Text width. (For wrapping, used by the Vi 'gq' operator.) - self.text_width = 0 - - #: The command buffer history. - # Note that we shouldn't use a lazy 'or' here. bool(history) could be - # False when empty. - self.history = InMemoryHistory() if history is None else history - - self.__cursor_position = 0 - - # Events - self.on_text_changed = Event(self, on_text_changed) - self.on_text_insert = Event(self, on_text_insert) - self.on_cursor_position_changed = Event(self, on_cursor_position_changed) - - # Document cache. (Avoid creating new Document instances.) - self._document_cache = FastDictCache(Document, size=10) - - self.reset(initial_document=initial_document) - - def reset(self, initial_document=None, append_to_history=False): - """ - :param append_to_history: Append current input to history first. - """ - assert initial_document is None or isinstance(initial_document, Document) - - if append_to_history: - self.append_to_history() - - initial_document = initial_document or Document() - - self.__cursor_position = initial_document.cursor_position - - # `ValidationError` instance. (Will be set when the input is wrong.) - self.validation_error = None - self.validation_state = ValidationState.UNKNOWN - - # State of the selection. - self.selection_state = None - - # Multiple cursor mode. (When we press 'I' or 'A' in visual-block mode, - # we can insert text on multiple lines at once. This is implemented by - # using multiple cursors.) - self.multiple_cursor_positions = [] - - # When doing consecutive up/down movements, prefer to stay at this column. - self.preferred_column = None - - # State of complete browser - self.complete_state = None # For interactive completion through Ctrl-N/Ctrl-P. - - # State of Emacs yank-nth-arg completion. - self.yank_nth_arg_state = None # for yank-nth-arg. - - # Remember the document that we had *right before* the last paste - # operation. This is used for rotating through the kill ring. - self.document_before_paste = None - - # Current suggestion. - self.suggestion = None - - # The history search text. (Used for filtering the history when we - # browse through it.) - self.history_search_text = None - - # Undo/redo stacks - self._undo_stack = [] # Stack of (text, cursor_position) - self._redo_stack = [] - - #: The working lines. Similar to history, except that this can be - #: modified. The user can press arrow_up and edit previous entries. - #: Ctrl-C should reset this, and copy the whole history back in here. - #: Enter should process the current command and append to the real - #: history. - self._working_lines = self.history.strings[:] - self._working_lines.append(initial_document.text) - self.__working_index = len(self._working_lines) - 1 - - # <getters/setters> - - def _set_text(self, value): - """ set text at current working_index. Return whether it changed. """ - working_index = self.working_index - working_lines = self._working_lines - - original_value = working_lines[working_index] - working_lines[working_index] = value - - # Return True when this text has been changed. - if len(value) != len(original_value): - # For Python 2, it seems that when two strings have a different - # length and one is a prefix of the other, Python still scans - # character by character to see whether the strings are different. - # (Some benchmarking showed significant differences for big - # documents. >100,000 of lines.) - return True - elif value != original_value: - return True - return False - - def _set_cursor_position(self, value): - """ Set cursor position. Return whether it changed. """ - original_position = self.__cursor_position - self.__cursor_position = max(0, value) - - return value != original_position - - @property - def text(self): - return self._working_lines[self.working_index] - - @text.setter - def text(self, value): - """ - Setting text. (When doing this, make sure that the cursor_position is - valid for this text. text/cursor_position should be consistent at any time, - otherwise set a Document instead.) - """ - assert isinstance(value, six.text_type), 'Got %r' % value - assert self.cursor_position <= len(value) - - # Don't allow editing of read-only buffers. - if self.read_only(): - raise EditReadOnlyBuffer() - - changed = self._set_text(value) - - if changed: - self._text_changed() - - # Reset history search text. - self.history_search_text = None - - @property - def cursor_position(self): - return self.__cursor_position - - @cursor_position.setter - def cursor_position(self, value): - """ - Setting cursor position. - """ - assert isinstance(value, int) - assert value <= len(self.text) - - changed = self._set_cursor_position(value) - - if changed: - self._cursor_position_changed() - - @property - def working_index(self): - return self.__working_index - - @working_index.setter - def working_index(self, value): - if self.__working_index != value: - self.__working_index = value - self._text_changed() - - def _text_changed(self): - # Remove any validation errors and complete state. - self.validation_error = None - self.validation_state = ValidationState.UNKNOWN - self.complete_state = None - self.yank_nth_arg_state = None - self.document_before_paste = None - self.selection_state = None - self.suggestion = None - self.preferred_column = None - - # fire 'on_text_changed' event. - self.on_text_changed.fire() - - def _cursor_position_changed(self): - # Remove any validation errors and complete state. - self.validation_error = None - self.validation_state = ValidationState.UNKNOWN - self.complete_state = None - self.yank_nth_arg_state = None - self.document_before_paste = None - - # Unset preferred_column. (Will be set after the cursor movement, if - # required.) - self.preferred_column = None - - # Note that the cursor position can change if we have a selection the - # new position of the cursor determines the end of the selection. - - # fire 'on_cursor_position_changed' event. - self.on_cursor_position_changed.fire() - - @property - def document(self): - """ - Return :class:`~prompt_toolkit.document.Document` instance from the - current text, cursor position and selection state. - """ - return self._document_cache[ - self.text, self.cursor_position, self.selection_state] - - @document.setter - def document(self, value): - """ - Set :class:`~prompt_toolkit.document.Document` instance. - - This will set both the text and cursor position at the same time, but - atomically. (Change events will be triggered only after both have been set.) - """ - self.set_document(value) - - def set_document(self, value, bypass_readonly=False): - """ - Set :class:`~prompt_toolkit.document.Document` instance. Like the - ``document`` property, but accept an ``bypass_readonly`` argument. - - :param bypass_readonly: When True, don't raise an - :class:`.EditReadOnlyBuffer` exception, even - when the buffer is read-only. - """ - assert isinstance(value, Document) - - # Don't allow editing of read-only buffers. - if not bypass_readonly and self.read_only(): - raise EditReadOnlyBuffer() - - # Set text and cursor position first. - text_changed = self._set_text(value.text) - cursor_position_changed = self._set_cursor_position(value.cursor_position) - - # Now handle change events. (We do this when text/cursor position is - # both set and consistent.) - if text_changed: - self._text_changed() - - if cursor_position_changed: - self._cursor_position_changed() - - # End of <getters/setters> - - def save_to_undo_stack(self, clear_redo_stack=True): - """ - Safe current state (input text and cursor position), so that we can - restore it by calling undo. - """ - # Safe if the text is different from the text at the top of the stack - # is different. If the text is the same, just update the cursor position. - if self._undo_stack and self._undo_stack[-1][0] == self.text: - self._undo_stack[-1] = (self._undo_stack[-1][0], self.cursor_position) - else: - self._undo_stack.append((self.text, self.cursor_position)) - - # Saving anything to the undo stack, clears the redo stack. - if clear_redo_stack: - self._redo_stack = [] - - def transform_lines(self, line_index_iterator, transform_callback): - """ - Transforms the text on a range of lines. - When the iterator yield an index not in the range of lines that the - document contains, it skips them silently. - - To uppercase some lines:: - - new_text = transform_lines(range(5,10), lambda text: text.upper()) - - :param line_index_iterator: Iterator of line numbers (int) - :param transform_callback: callable that takes the original text of a - line, and return the new text for this line. - - :returns: The new text. - """ - # Split lines - lines = self.text.split('\n') - - # Apply transformation - for index in line_index_iterator: - try: - lines[index] = transform_callback(lines[index]) - except IndexError: - pass - - return '\n'.join(lines) - - def transform_current_line(self, transform_callback): - """ - Apply the given transformation function to the current line. - - :param transform_callback: callable that takes a string and return a new string. - """ - document = self.document - a = document.cursor_position + document.get_start_of_line_position() - b = document.cursor_position + document.get_end_of_line_position() - self.text = ( - document.text[:a] + - transform_callback(document.text[a:b]) + - document.text[b:]) - - def transform_region(self, from_, to, transform_callback): - """ - Transform a part of the input string. - - :param from_: (int) start position. - :param to: (int) end position. - :param transform_callback: Callable which accepts a string and returns - the transformed string. - """ - assert from_ < to - - self.text = ''.join([ - self.text[:from_] + - transform_callback(self.text[from_:to]) + - self.text[to:] - ]) - - def cursor_left(self, count=1): - self.cursor_position += self.document.get_cursor_left_position(count=count) - - def cursor_right(self, count=1): - self.cursor_position += self.document.get_cursor_right_position(count=count) - - def cursor_up(self, count=1): - """ (for multiline edit). Move cursor to the previous line. """ - original_column = self.preferred_column or self.document.cursor_position_col - self.cursor_position += self.document.get_cursor_up_position( - count=count, preferred_column=original_column) - - # Remember the original column for the next up/down movement. - self.preferred_column = original_column - - def cursor_down(self, count=1): - """ (for multiline edit). Move cursor to the next line. """ - original_column = self.preferred_column or self.document.cursor_position_col - self.cursor_position += self.document.get_cursor_down_position( - count=count, preferred_column=original_column) - - # Remember the original column for the next up/down movement. - self.preferred_column = original_column - - def auto_up(self, count=1, go_to_start_of_line_if_history_changes=False): - """ - If we're not on the first line (of a multiline input) go a line up, - otherwise go back in history. (If nothing is selected.) - """ - if self.complete_state: - self.complete_previous(count=count) - elif self.document.cursor_position_row > 0: - self.cursor_up(count=count) - elif not self.selection_state: - self.history_backward(count=count) - - # Go to the start of the line? - if go_to_start_of_line_if_history_changes: - self.cursor_position += self.document.get_start_of_line_position() - - def auto_down(self, count=1, go_to_start_of_line_if_history_changes=False): - """ - If we're not on the last line (of a multiline input) go a line down, - otherwise go forward in history. (If nothing is selected.) - """ - if self.complete_state: - self.complete_next(count=count) - elif self.document.cursor_position_row < self.document.line_count - 1: - self.cursor_down(count=count) - elif not self.selection_state: - self.history_forward(count=count) - - # Go to the start of the line? - if go_to_start_of_line_if_history_changes: - self.cursor_position += self.document.get_start_of_line_position() - - def delete_before_cursor(self, count=1): - """ - Delete specified number of characters before cursor and return the - deleted text. - """ - assert count >= 0 - deleted = '' - - if self.cursor_position > 0: - deleted = self.text[self.cursor_position - count:self.cursor_position] - - new_text = self.text[:self.cursor_position - count] + self.text[self.cursor_position:] - new_cursor_position = self.cursor_position - len(deleted) - - # Set new Document atomically. - self.document = Document(new_text, new_cursor_position) - - return deleted - - def delete(self, count=1): - """ - Delete specified number of characters and Return the deleted text. - """ - if self.cursor_position < len(self.text): - deleted = self.document.text_after_cursor[:count] - self.text = self.text[:self.cursor_position] + \ - self.text[self.cursor_position + len(deleted):] - return deleted - else: - return '' - - def join_next_line(self, separator=' '): - """ - Join the next line to the current one by deleting the line ending after - the current line. - """ - if not self.document.on_last_line: - self.cursor_position += self.document.get_end_of_line_position() - self.delete() - - # Remove spaces. - self.text = (self.document.text_before_cursor + separator + - self.document.text_after_cursor.lstrip(' ')) - - def join_selected_lines(self, separator=' '): - """ - Join the selected lines. - """ - assert self.selection_state - - # Get lines. - from_, to = sorted([self.cursor_position, self.selection_state.original_cursor_position]) - - before = self.text[:from_] - lines = self.text[from_:to].splitlines() - after = self.text[to:] - - # Replace leading spaces with just one space. - lines = [l.lstrip(' ') + separator for l in lines] - - # Set new document. - self.document = Document(text=before + ''.join(lines) + after, - cursor_position=len(before + ''.join(lines[:-1])) - 1) - - def swap_characters_before_cursor(self): - """ - Swap the last two characters before the cursor. - """ - pos = self.cursor_position - - if pos >= 2: - a = self.text[pos - 2] - b = self.text[pos - 1] - - self.text = self.text[:pos-2] + b + a + self.text[pos:] - - def go_to_history(self, index): - """ - Go to this item in the history. - """ - if index < len(self._working_lines): - self.working_index = index - self.cursor_position = len(self.text) - - def complete_next(self, count=1, disable_wrap_around=False): - """ - Browse to the next completions. - (Does nothing if there are no completion.) - """ - if self.complete_state: - completions_count = len(self.complete_state.current_completions) - - if self.complete_state.complete_index is None: - index = 0 - elif self.complete_state.complete_index == completions_count - 1: - index = None - - if disable_wrap_around: - return - else: - index = min(completions_count-1, self.complete_state.complete_index + count) - self.go_to_completion(index) - - def complete_previous(self, count=1, disable_wrap_around=False): - """ - Browse to the previous completions. - (Does nothing if there are no completion.) - """ - if self.complete_state: - if self.complete_state.complete_index == 0: - index = None - - if disable_wrap_around: - return - elif self.complete_state.complete_index is None: - index = len(self.complete_state.current_completions) - 1 - else: - index = max(0, self.complete_state.complete_index - count) - - self.go_to_completion(index) - - def cancel_completion(self): - """ - Cancel completion, go back to the original text. - """ - if self.complete_state: - self.go_to_completion(None) - self.complete_state = None - - def set_completions(self, completions, go_to_first=True, go_to_last=False): - """ - Start completions. (Generate list of completions and initialize.) - """ - assert not (go_to_first and go_to_last) - - # Generate list of all completions. - if completions is None: - if self.completer: - completions = list(self.completer.get_completions( - self.document, - CompleteEvent(completion_requested=True) - )) - else: - completions = [] - - # Set `complete_state`. - if completions: - self.complete_state = CompletionState( - original_document=self.document, - current_completions=completions) - if go_to_first: - self.go_to_completion(0) - elif go_to_last: - self.go_to_completion(len(completions) - 1) - else: - self.go_to_completion(None) - - else: - self.complete_state = None - - def start_history_lines_completion(self): - """ - Start a completion based on all the other lines in the document and the - history. - """ - found_completions = set() - completions = [] - - # For every line of the whole history, find matches with the current line. - current_line = self.document.current_line_before_cursor.lstrip() - - for i, string in enumerate(self._working_lines): - for j, l in enumerate(string.split('\n')): - l = l.strip() - if l and l.startswith(current_line): - # When a new line has been found. - if l not in found_completions: - found_completions.add(l) - - # Create completion. - if i == self.working_index: - display_meta = "Current, line %s" % (j+1) - else: - display_meta = "History %s, line %s" % (i+1, j+1) - - completions.append(Completion( - l, - start_position=-len(current_line), - display_meta=display_meta)) - - self.set_completions(completions=completions[::-1]) - - def go_to_completion(self, index): - """ - Select a completion from the list of current completions. - """ - assert index is None or isinstance(index, int) - assert self.complete_state - - # Set new completion - state = self.complete_state.go_to_index(index) - - # Set text/cursor position - new_text, new_cursor_position = state.new_text_and_position() - self.document = Document(new_text, new_cursor_position) - - # (changing text/cursor position will unset complete_state.) - self.complete_state = state - - def apply_completion(self, completion): - """ - Insert a given completion. - """ - assert isinstance(completion, Completion) - - # If there was already a completion active, cancel that one. - if self.complete_state: - self.go_to_completion(None) - self.complete_state = None - - # Insert text from the given completion. - self.delete_before_cursor(-completion.start_position) - self.insert_text(completion.text) - - def _set_history_search(self): - """ Set `history_search_text`. """ - if self.enable_history_search(): - if self.history_search_text is None: - self.history_search_text = self.document.text_before_cursor - else: - self.history_search_text = None - - def _history_matches(self, i): - """ - True when the current entry matches the history search. - (when we don't have history search, it's also True.) - """ - return (self.history_search_text is None or - self._working_lines[i].startswith(self.history_search_text)) - - def history_forward(self, count=1): - """ - Move forwards through the history. - - :param count: Amount of items to move forward. - """ - self._set_history_search() - - # Go forward in history. - found_something = False - - for i in range(self.working_index + 1, len(self._working_lines)): - if self._history_matches(i): - self.working_index = i - count -= 1 - found_something = True - if count == 0: - break - - # If we found an entry, move cursor to the end of the first line. - if found_something: - self.cursor_position = 0 - self.cursor_position += self.document.get_end_of_line_position() - - def history_backward(self, count=1): - """ - Move backwards through history. - """ - self._set_history_search() - - # Go back in history. - found_something = False - - for i in range(self.working_index - 1, -1, -1): - if self._history_matches(i): - self.working_index = i - count -= 1 - found_something = True - if count == 0: - break - - # If we move to another entry, move cursor to the end of the line. - if found_something: - self.cursor_position = len(self.text) - - def yank_nth_arg(self, n=None, _yank_last_arg=False): - """ - Pick nth word from previous history entry (depending on current - `yank_nth_arg_state`) and insert it at current position. Rotate through - history if called repeatedly. If no `n` has been given, take the first - argument. (The second word.) - - :param n: (None or int), The index of the word from the previous line - to take. - """ - assert n is None or isinstance(n, int) - - if not len(self.history): - return - - # Make sure we have a `YankNthArgState`. - if self.yank_nth_arg_state is None: - state = YankNthArgState(n=-1 if _yank_last_arg else 1) - else: - state = self.yank_nth_arg_state - - if n is not None: - state.n = n - - # Get new history position. - new_pos = state.history_position - 1 - if -new_pos > len(self.history): - new_pos = -1 - - # Take argument from line. - line = self.history[new_pos] - - words = [w.strip() for w in _QUOTED_WORDS_RE.split(line)] - words = [w for w in words if w] - try: - word = words[state.n] - except IndexError: - word = '' - - # Insert new argument. - if state.previous_inserted_word: - self.delete_before_cursor(len(state.previous_inserted_word)) - self.insert_text(word) - - # Save state again for next completion. (Note that the 'insert' - # operation from above clears `self.yank_nth_arg_state`.) - state.previous_inserted_word = word - state.history_position = new_pos - self.yank_nth_arg_state = state - - def yank_last_arg(self, n=None): - """ - Like `yank_nth_arg`, but if no argument has been given, yank the last - word by default. - """ - self.yank_nth_arg(n=n, _yank_last_arg=True) - - def start_selection(self, selection_type=SelectionType.CHARACTERS): - """ - Take the current cursor position as the start of this selection. - """ - self.selection_state = SelectionState(self.cursor_position, selection_type) - - def copy_selection(self, _cut=False): - """ - Copy selected text and return :class:`.ClipboardData` instance. - """ - new_document, clipboard_data = self.document.cut_selection() - if _cut: - self.document = new_document - - self.selection_state = None - return clipboard_data - - def cut_selection(self): - """ - Delete selected text and return :class:`.ClipboardData` instance. - """ - return self.copy_selection(_cut=True) - - def paste_clipboard_data(self, data, paste_mode=PasteMode.EMACS, count=1): - """ - Insert the data from the clipboard. - """ - assert isinstance(data, ClipboardData) - assert paste_mode in (PasteMode.VI_BEFORE, PasteMode.VI_AFTER, PasteMode.EMACS) - - original_document = self.document - self.document = self.document.paste_clipboard_data(data, paste_mode=paste_mode, count=count) - - # Remember original document. This assignment should come at the end, - # because assigning to 'document' will erase it. - self.document_before_paste = original_document - - def newline(self, copy_margin=True): - """ - Insert a line ending at the current position. - """ - if copy_margin: - self.insert_text('\n' + self.document.leading_whitespace_in_current_line) - else: - self.insert_text('\n') - - def insert_line_above(self, copy_margin=True): - """ - Insert a new line above the current one. - """ - if copy_margin: - insert = self.document.leading_whitespace_in_current_line + '\n' - else: - insert = '\n' - - self.cursor_position += self.document.get_start_of_line_position() - self.insert_text(insert) - self.cursor_position -= 1 - - def insert_line_below(self, copy_margin=True): - """ - Insert a new line below the current one. - """ - if copy_margin: - insert = '\n' + self.document.leading_whitespace_in_current_line - else: - insert = '\n' - - self.cursor_position += self.document.get_end_of_line_position() - self.insert_text(insert) - - def insert_text(self, data, overwrite=False, move_cursor=True, fire_event=True): - """ - Insert characters at cursor position. - - :param fire_event: Fire `on_text_insert` event. This is mainly used to - trigger autocompletion while typing. - """ - # Original text & cursor position. - otext = self.text - ocpos = self.cursor_position - - # In insert/text mode. - if overwrite: - # Don't overwrite the newline itself. Just before the line ending, - # it should act like insert mode. - overwritten_text = otext[ocpos:ocpos + len(data)] - if '\n' in overwritten_text: - overwritten_text = overwritten_text[:overwritten_text.find('\n')] - - self.text = otext[:ocpos] + data + otext[ocpos + len(overwritten_text):] - else: - self.text = otext[:ocpos] + data + otext[ocpos:] - - if move_cursor: - self.cursor_position += len(data) - - # Fire 'on_text_insert' event. - if fire_event: - self.on_text_insert.fire() - - def undo(self): - # Pop from the undo-stack until we find a text that if different from - # the current text. (The current logic of `save_to_undo_stack` will - # cause that the top of the undo stack is usually the same as the - # current text, so in that case we have to pop twice.) - while self._undo_stack: - text, pos = self._undo_stack.pop() - - if text != self.text: - # Push current text to redo stack. - self._redo_stack.append((self.text, self.cursor_position)) - - # Set new text/cursor_position. - self.document = Document(text, cursor_position=pos) - break - - def redo(self): - if self._redo_stack: - # Copy current state on undo stack. - self.save_to_undo_stack(clear_redo_stack=False) - - # Pop state from redo stack. - text, pos = self._redo_stack.pop() - self.document = Document(text, cursor_position=pos) - - def validate(self): - """ - Returns `True` if valid. - """ - # Don't call the validator again, if it was already called for the - # current input. - if self.validation_state != ValidationState.UNKNOWN: - return self.validation_state == ValidationState.VALID - - # Validate first. If not valid, set validation exception. - if self.validator: - try: - self.validator.validate(self.document) - except ValidationError as e: - # Set cursor position (don't allow invalid values.) - cursor_position = e.cursor_position - self.cursor_position = min(max(0, cursor_position), len(self.text)) - - self.validation_state = ValidationState.INVALID - self.validation_error = e - return False - - self.validation_state = ValidationState.VALID - self.validation_error = None - return True - - def append_to_history(self): - """ - Append the current input to the history. - (Only if valid input.) - """ - # Validate first. If not valid, set validation exception. - if not self.validate(): - return - - # Save at the tail of the history. (But don't if the last entry the - # history is already the same.) - if self.text and (not len(self.history) or self.history[-1] != self.text): - self.history.append(self.text) - - def _search(self, search_state, include_current_position=False, count=1): - """ - Execute search. Return (working_index, cursor_position) tuple when this - search is applied. Returns `None` when this text cannot be found. - """ - assert isinstance(search_state, SearchState) - assert isinstance(count, int) and count > 0 - - text = search_state.text - direction = search_state.direction - ignore_case = search_state.ignore_case() - - def search_once(working_index, document): - """ - Do search one time. - Return (working_index, document) or `None` - """ - if direction == IncrementalSearchDirection.FORWARD: - # Try find at the current input. - new_index = document.find( - text, include_current_position=include_current_position, - ignore_case=ignore_case) - - if new_index is not None: - return (working_index, - Document(document.text, document.cursor_position + new_index)) - else: - # No match, go forward in the history. (Include len+1 to wrap around.) - # (Here we should always include all cursor positions, because - # it's a different line.) - for i in range(working_index + 1, len(self._working_lines) + 1): - i %= len(self._working_lines) - - document = Document(self._working_lines[i], 0) - new_index = document.find(text, include_current_position=True, - ignore_case=ignore_case) - if new_index is not None: - return (i, Document(document.text, new_index)) - else: - # Try find at the current input. - new_index = document.find_backwards( - text, ignore_case=ignore_case) - - if new_index is not None: - return (working_index, - Document(document.text, document.cursor_position + new_index)) - else: - # No match, go back in the history. (Include -1 to wrap around.) - for i in range(working_index - 1, -2, -1): - i %= len(self._working_lines) - - document = Document(self._working_lines[i], len(self._working_lines[i])) - new_index = document.find_backwards( - text, ignore_case=ignore_case) - if new_index is not None: - return (i, Document(document.text, len(document.text) + new_index)) - - # Do 'count' search iterations. - working_index = self.working_index - document = self.document - for _ in range(count): - result = search_once(working_index, document) - if result is None: - return # Nothing found. - else: - working_index, document = result - - return (working_index, document.cursor_position) - - def document_for_search(self, search_state): - """ - Return a :class:`~prompt_toolkit.document.Document` instance that has - the text/cursor position for this search, if we would apply it. This - will be used in the - :class:`~prompt_toolkit.layout.controls.BufferControl` to display - feedback while searching. - """ - search_result = self._search(search_state, include_current_position=True) - - if search_result is None: - return self.document - else: - working_index, cursor_position = search_result - - # Keep selection, when `working_index` was not changed. - if working_index == self.working_index: - selection = self.selection_state - else: - selection = None - - return Document(self._working_lines[working_index], - cursor_position, selection=selection) - - def get_search_position(self, search_state, include_current_position=True, count=1): - """ - Get the cursor position for this search. - (This operation won't change the `working_index`. It's won't go through - the history. Vi text objects can't span multiple items.) - """ - search_result = self._search( - search_state, include_current_position=include_current_position, count=count) - - if search_result is None: - return self.cursor_position - else: - working_index, cursor_position = search_result - return cursor_position - - def apply_search(self, search_state, include_current_position=True, count=1): - """ - Apply search. If something is found, set `working_index` and - `cursor_position`. - """ - search_result = self._search( - search_state, include_current_position=include_current_position, count=count) - - if search_result is not None: - working_index, cursor_position = search_result - self.working_index = working_index - self.cursor_position = cursor_position - - def exit_selection(self): - self.selection_state = None - - def open_in_editor(self, cli): - """ - Open code in editor. - - :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface` - instance. - """ - if self.read_only(): - raise EditReadOnlyBuffer() - - # Write to temporary file - descriptor, filename = tempfile.mkstemp(self.tempfile_suffix) - os.write(descriptor, self.text.encode('utf-8')) - os.close(descriptor) - - # Open in editor - # (We need to use `cli.run_in_terminal`, because not all editors go to - # the alternate screen buffer, and some could influence the cursor - # position.) - succes = cli.run_in_terminal(lambda: self._open_file_in_editor(filename)) - - # Read content again. - if succes: - with open(filename, 'rb') as f: - text = f.read().decode('utf-8') - - # Drop trailing newline. (Editors are supposed to add it at the - # end, but we don't need it.) - if text.endswith('\n'): - text = text[:-1] - - self.document = Document( - text=text, - cursor_position=len(text)) - - # Clean up temp file. - os.remove(filename) - - def _open_file_in_editor(self, filename): - """ - Call editor executable. - - Return True when we received a zero return code. - """ - # If the 'VISUAL' or 'EDITOR' environment variable has been set, use that. - # Otherwise, fall back to the first available editor that we can find. - visual = os.environ.get('VISUAL') - editor = os.environ.get('EDITOR') - - editors = [ - visual, - editor, - - # Order of preference. - '/usr/bin/editor', - '/usr/bin/nano', - '/usr/bin/pico', - '/usr/bin/vi', - '/usr/bin/emacs', - ] - - for e in editors: - if e: - try: - # Use 'shlex.split()', because $VISUAL can contain spaces - # and quotes. - returncode = subprocess.call(shlex.split(e) + [filename]) - return returncode == 0 - - except OSError: - # Executable does not exist, try the next one. - pass - - return False - - -def indent(buffer, from_row, to_row, count=1): - """ - Indent text of a :class:`.Buffer` object. - """ - current_row = buffer.document.cursor_position_row - line_range = range(from_row, to_row) - - # Apply transformation. - new_text = buffer.transform_lines(line_range, lambda l: ' ' * count + l) - buffer.document = Document( - new_text, - Document(new_text).translate_row_col_to_index(current_row, 0)) - - # Go to the start of the line. - buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True) - - -def unindent(buffer, from_row, to_row, count=1): - """ - Unindent text of a :class:`.Buffer` object. - """ - current_row = buffer.document.cursor_position_row - line_range = range(from_row, to_row) - - def transform(text): - remove = ' ' * count - if text.startswith(remove): - return text[len(remove):] - else: - return text.lstrip() - - # Apply transformation. - new_text = buffer.transform_lines(line_range, transform) - buffer.document = Document( - new_text, - Document(new_text).translate_row_col_to_index(current_row, 0)) - - # Go to the start of the line. - buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True) - - -def reshape_text(buffer, from_row, to_row): - """ - Reformat text, taking the width into account. - `to_row` is included. - (Vi 'gq' operator.) - """ - lines = buffer.text.splitlines(True) - lines_before = lines[:from_row] - lines_after = lines[to_row + 1:] - lines_to_reformat = lines[from_row:to_row + 1] - - if lines_to_reformat: - # Take indentation from the first line. - length = re.search(r'^\s*', lines_to_reformat[0]).end() - indent = lines_to_reformat[0][:length].replace('\n', '') - - # Now, take all the 'words' from the lines to be reshaped. - words = ''.join(lines_to_reformat).split() - - # And reshape. - width = (buffer.text_width or 80) - len(indent) - reshaped_text = [indent] - current_width = 0 - for w in words: - if current_width: - if len(w) + current_width + 1 > width: - reshaped_text.append('\n') - reshaped_text.append(indent) - current_width = 0 - else: - reshaped_text.append(' ') - current_width += 1 - - reshaped_text.append(w) - current_width += len(w) - - if reshaped_text[-1] != '\n': - reshaped_text.append('\n') - - # Apply result. - buffer.document = Document( - text=''.join(lines_before + reshaped_text + lines_after), - cursor_position=len(''.join(lines_before + reshaped_text))) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py deleted file mode 100644 index 34f443bd47..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -The BufferMapping contains all the buffers for a command line interface, and it -keeps track of which buffer gets the focus. -""" -from __future__ import unicode_literals -from .enums import DEFAULT_BUFFER, SEARCH_BUFFER, SYSTEM_BUFFER, DUMMY_BUFFER -from .buffer import Buffer, AcceptAction -from .history import InMemoryHistory - -import six - -__all__ = ( - 'BufferMapping', -) - - -class BufferMapping(dict): - """ - Dictionary that maps the name of the buffers to the - :class:`~prompt_toolkit.buffer.Buffer` instances. - - This mapping also keeps track of which buffer currently has the focus. - (Some methods receive a 'cli' parameter. This is useful for applications - where this `BufferMapping` is shared between several applications.) - """ - def __init__(self, buffers=None, initial=DEFAULT_BUFFER): - assert buffers is None or isinstance(buffers, dict) - - # Start with an empty dict. - super(BufferMapping, self).__init__() - - # Add default buffers. - self.update({ - # For the 'search' and 'system' buffers, 'returnable' is False, in - # order to block normal Enter/ControlC behaviour. - DEFAULT_BUFFER: Buffer(accept_action=AcceptAction.RETURN_DOCUMENT), - SEARCH_BUFFER: Buffer(history=InMemoryHistory(), accept_action=AcceptAction.IGNORE), - SYSTEM_BUFFER: Buffer(history=InMemoryHistory(), accept_action=AcceptAction.IGNORE), - DUMMY_BUFFER: Buffer(read_only=True), - }) - - # Add received buffers. - if buffers is not None: - self.update(buffers) - - # Focus stack. - self.focus_stack = [initial or DEFAULT_BUFFER] - - def current(self, cli): - """ - The active :class:`.Buffer`. - """ - return self[self.focus_stack[-1]] - - def current_name(self, cli): - """ - The name of the active :class:`.Buffer`. - """ - return self.focus_stack[-1] - - def previous(self, cli): - """ - Return the previously focussed :class:`.Buffer` or `None`. - """ - if len(self.focus_stack) > 1: - try: - return self[self.focus_stack[-2]] - except KeyError: - pass - - def focus(self, cli, buffer_name): - """ - Focus the buffer with the given name. - """ - assert isinstance(buffer_name, six.text_type) - self.focus_stack = [buffer_name] - - def push_focus(self, cli, buffer_name): - """ - Push buffer on the focus stack. - """ - assert isinstance(buffer_name, six.text_type) - self.focus_stack.append(buffer_name) - - def pop_focus(self, cli): - """ - Pop buffer from the focus stack. - """ - if len(self.focus_stack) > 1: - self.focus_stack.pop() - else: - raise IndexError('Cannot pop last item from the focus stack.') diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/cache.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/cache.py deleted file mode 100644 index 55c7369c9c..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/cache.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import unicode_literals -from collections import deque -from functools import wraps - -__all__ = ( - 'SimpleCache', - 'FastDictCache', - 'memoized', -) - - -class SimpleCache(object): - """ - Very simple cache that discards the oldest item when the cache size is - exceeded. - - :param maxsize: Maximum size of the cache. (Don't make it too big.) - """ - def __init__(self, maxsize=8): - assert isinstance(maxsize, int) and maxsize > 0 - - self._data = {} - self._keys = deque() - self.maxsize = maxsize - - def get(self, key, getter_func): - """ - Get object from the cache. - If not found, call `getter_func` to resolve it, and put that on the top - of the cache instead. - """ - # Look in cache first. - try: - return self._data[key] - except KeyError: - # Not found? Get it. - value = getter_func() - self._data[key] = value - self._keys.append(key) - - # Remove the oldest key when the size is exceeded. - if len(self._data) > self.maxsize: - key_to_remove = self._keys.popleft() - if key_to_remove in self._data: - del self._data[key_to_remove] - - return value - - def clear(self): - " Clear cache. " - self._data = {} - self._keys = deque() - - -class FastDictCache(dict): - """ - Fast, lightweight cache which keeps at most `size` items. - It will discard the oldest items in the cache first. - - The cache is a dictionary, which doesn't keep track of access counts. - It is perfect to cache little immutable objects which are not expensive to - create, but where a dictionary lookup is still much faster than an object - instantiation. - - :param get_value: Callable that's called in case of a missing key. - """ - # NOTE: This cache is used to cache `prompt_toolkit.layout.screen.Char` and - # `prompt_toolkit.Document`. Make sure to keep this really lightweight. - # Accessing the cache should stay faster than instantiating new - # objects. - # (Dictionary lookups are really fast.) - # SimpleCache is still required for cases where the cache key is not - # the same as the arguments given to the function that creates the - # value.) - def __init__(self, get_value=None, size=1000000): - assert callable(get_value) - assert isinstance(size, int) and size > 0 - - self._keys = deque() - self.get_value = get_value - self.size = size - - def __missing__(self, key): - # Remove the oldest key when the size is exceeded. - if len(self) > self.size: - key_to_remove = self._keys.popleft() - if key_to_remove in self: - del self[key_to_remove] - - result = self.get_value(*key) - self[key] = result - self._keys.append(key) - return result - - -def memoized(maxsize=1024): - """ - Momoization decorator for immutable classes and pure functions. - """ - cache = SimpleCache(maxsize=maxsize) - - def decorator(obj): - @wraps(obj) - def new_callable(*a, **kw): - def create_new(): - return obj(*a, **kw) - - key = (a, tuple(kw.items())) - return cache.get(key, create_new) - return new_callable - return decorator diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py deleted file mode 100644 index 56202ddd3b..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .base import Clipboard, ClipboardData -from .in_memory import InMemoryClipboard - - -# We are not importing `PyperclipClipboard` here, because it would require the -# `pyperclip` module to be present. - -#from .pyperclip import PyperclipClipboard diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py deleted file mode 100644 index 803c0b0e7d..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Clipboard for command line interface. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass -import six - -from prompt_toolkit.selection import SelectionType - -__all__ = ( - 'Clipboard', - 'ClipboardData', -) - - -class ClipboardData(object): - """ - Text on the clipboard. - - :param text: string - :param type: :class:`~prompt_toolkit.selection.SelectionType` - """ - def __init__(self, text='', type=SelectionType.CHARACTERS): - assert isinstance(text, six.string_types) - assert type in (SelectionType.CHARACTERS, SelectionType.LINES, SelectionType.BLOCK) - - self.text = text - self.type = type - - -class Clipboard(with_metaclass(ABCMeta, object)): - """ - Abstract baseclass for clipboards. - (An implementation can be in memory, it can share the X11 or Windows - keyboard, or can be persistent.) - """ - @abstractmethod - def set_data(self, data): - """ - Set data to the clipboard. - - :param data: :class:`~.ClipboardData` instance. - """ - - def set_text(self, text): # Not abstract. - """ - Shortcut for setting plain text on clipboard. - """ - assert isinstance(text, six.string_types) - self.set_data(ClipboardData(text)) - - def rotate(self): - """ - For Emacs mode, rotate the kill ring. - """ - - @abstractmethod - def get_data(self): - """ - Return clipboard data. - """ diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py deleted file mode 100644 index 081666ab80..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py +++ /dev/null @@ -1,42 +0,0 @@ -from .base import Clipboard, ClipboardData - -from collections import deque - -__all__ = ( - 'InMemoryClipboard', -) - - -class InMemoryClipboard(Clipboard): - """ - Default clipboard implementation. - Just keep the data in memory. - - This implements a kill-ring, for Emacs mode. - """ - def __init__(self, data=None, max_size=60): - assert data is None or isinstance(data, ClipboardData) - assert max_size >= 1 - - self.max_size = max_size - self._ring = deque() - if data is not None: - self.set_data(data) - - def set_data(self, data): - assert isinstance(data, ClipboardData) - self._ring.appendleft(data) - - while len(self._ring) > self.max_size: - self._ring.pop() - - def get_data(self): - if self._ring: - return self._ring[0] - else: - return ClipboardData() - - def rotate(self): - if self._ring: - # Add the very first item at the end. - self._ring.append(self._ring.popleft()) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py deleted file mode 100644 index 61ab3aac0a..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import absolute_import, unicode_literals -import pyperclip - -from prompt_toolkit.selection import SelectionType -from .base import Clipboard, ClipboardData - -__all__ = ( - 'PyperclipClipboard', -) - - -class PyperclipClipboard(Clipboard): - """ - Clipboard that synchronizes with the Windows/Mac/Linux system clipboard, - using the pyperclip module. - """ - def __init__(self): - self._data = None - - def set_data(self, data): - assert isinstance(data, ClipboardData) - self._data = data - pyperclip.copy(data.text) - - def get_data(self): - text = pyperclip.paste() - - # When the clipboard data is equal to what we copied last time, reuse - # the `ClipboardData` instance. That way we're sure to keep the same - # `SelectionType`. - if self._data and self._data.text == text: - return self._data - - # Pyperclip returned something else. Create a new `ClipboardData` - # instance. - else: - return ClipboardData( - text=text, - type=SelectionType.LINES if '\n' in text else SelectionType.LINES) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py deleted file mode 100644 index 339738ab97..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py +++ /dev/null @@ -1,170 +0,0 @@ -""" -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -__all__ = ( - 'Completion', - 'Completer', - 'CompleteEvent', - 'get_common_complete_suffix', -) - - -class Completion(object): - """ - :param text: The new string that will be inserted into the document. - :param start_position: Position relative to the cursor_position where the - new text will start. The text will be inserted between the - start_position and the original cursor position. - :param display: (optional string) If the completion has to be displayed - differently in the completion menu. - :param display_meta: (Optional string) Meta information about the - completion, e.g. the path or source where it's coming from. - :param get_display_meta: Lazy `display_meta`. Retrieve meta information - only when meta is displayed. - """ - def __init__(self, text, start_position=0, display=None, display_meta=None, - get_display_meta=None): - self.text = text - self.start_position = start_position - self._display_meta = display_meta - self._get_display_meta = get_display_meta - - if display is None: - self.display = text - else: - self.display = display - - assert self.start_position <= 0 - - def __repr__(self): - if self.display == self.text: - return '%s(text=%r, start_position=%r)' % ( - self.__class__.__name__, self.text, self.start_position) - else: - return '%s(text=%r, start_position=%r, display=%r)' % ( - self.__class__.__name__, self.text, self.start_position, - self.display) - - def __eq__(self, other): - return ( - self.text == other.text and - self.start_position == other.start_position and - self.display == other.display and - self.display_meta == other.display_meta) - - def __hash__(self): - return hash((self.text, self.start_position, self.display, self.display_meta)) - - @property - def display_meta(self): - # Return meta-text. (This is lazy when using "get_display_meta".) - if self._display_meta is not None: - return self._display_meta - - elif self._get_display_meta: - self._display_meta = self._get_display_meta() - return self._display_meta - - else: - return '' - - def new_completion_from_position(self, position): - """ - (Only for internal use!) - Get a new completion by splitting this one. Used by - `CommandLineInterface` when it needs to have a list of new completions - after inserting the common prefix. - """ - assert isinstance(position, int) and position - self.start_position >= 0 - - return Completion( - text=self.text[position - self.start_position:], - display=self.display, - display_meta=self._display_meta, - get_display_meta=self._get_display_meta) - - -class CompleteEvent(object): - """ - Event that called the completer. - - :param text_inserted: When True, it means that completions are requested - because of a text insert. (`Buffer.complete_while_typing`.) - :param completion_requested: When True, it means that the user explicitely - pressed the `Tab` key in order to view the completions. - - These two flags can be used for instance to implemented a completer that - shows some completions when ``Tab`` has been pressed, but not - automatically when the user presses a space. (Because of - `complete_while_typing`.) - """ - def __init__(self, text_inserted=False, completion_requested=False): - assert not (text_inserted and completion_requested) - - #: Automatic completion while typing. - self.text_inserted = text_inserted - - #: Used explicitely requested completion by pressing 'tab'. - self.completion_requested = completion_requested - - def __repr__(self): - return '%s(text_inserted=%r, completion_requested=%r)' % ( - self.__class__.__name__, self.text_inserted, self.completion_requested) - - -class Completer(with_metaclass(ABCMeta, object)): - """ - Base class for completer implementations. - """ - @abstractmethod - def get_completions(self, document, complete_event): - """ - Yield :class:`.Completion` instances. - - :param document: :class:`~prompt_toolkit.document.Document` instance. - :param complete_event: :class:`.CompleteEvent` instance. - """ - while False: - yield - - -def get_common_complete_suffix(document, completions): - """ - Return the common prefix for all completions. - """ - # Take only completions that don't change the text before the cursor. - def doesnt_change_before_cursor(completion): - end = completion.text[:-completion.start_position] - return document.text_before_cursor.endswith(end) - - completions2 = [c for c in completions if doesnt_change_before_cursor(c)] - - # When there is at least one completion that changes the text before the - # cursor, don't return any common part. - if len(completions2) != len(completions): - return '' - - # Return the common prefix. - def get_suffix(completion): - return completion.text[-completion.start_position:] - - return _commonprefix([get_suffix(c) for c in completions2]) - - -def _commonprefix(strings): - # Similar to os.path.commonprefix - if not strings: - return '' - - else: - s1 = min(strings) - s2 = max(strings) - - for i, c in enumerate(s1): - if c != s2[i]: - return s1[:i] - - return s1 diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/__init__.py +++ /dev/null diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py deleted file mode 100644 index 43893b8c8c..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import unicode_literals - -from .filesystem import PathCompleter -from .base import WordCompleter -from .system import SystemCompleter diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py deleted file mode 100644 index 65a69fede1..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import unicode_literals - -from six import string_types -from prompt_toolkit.completion import Completer, Completion - -__all__ = ( - 'WordCompleter', -) - - -class WordCompleter(Completer): - """ - Simple autocompletion on a list of words. - - :param words: List of words. - :param ignore_case: If True, case-insensitive completion. - :param meta_dict: Optional dict mapping words to their meta-information. - :param WORD: When True, use WORD characters. - :param sentence: When True, don't complete by comparing the word before the - cursor, but by comparing all the text before the cursor. In this case, - the list of words is just a list of strings, where each string can - contain spaces. (Can not be used together with the WORD option.) - :param match_middle: When True, match not only the start, but also in the - middle of the word. - """ - def __init__(self, words, ignore_case=False, meta_dict=None, WORD=False, - sentence=False, match_middle=False): - assert not (WORD and sentence) - - self.words = list(words) - self.ignore_case = ignore_case - self.meta_dict = meta_dict or {} - self.WORD = WORD - self.sentence = sentence - self.match_middle = match_middle - assert all(isinstance(w, string_types) for w in self.words) - - def get_completions(self, document, complete_event): - # Get word/text before cursor. - if self.sentence: - word_before_cursor = document.text_before_cursor - else: - word_before_cursor = document.get_word_before_cursor(WORD=self.WORD) - - if self.ignore_case: - word_before_cursor = word_before_cursor.lower() - - def word_matches(word): - """ True when the word before the cursor matches. """ - if self.ignore_case: - word = word.lower() - - if self.match_middle: - return word_before_cursor in word - else: - return word.startswith(word_before_cursor) - - for a in self.words: - if word_matches(a): - display_meta = self.meta_dict.get(a, '') - yield Completion(a, -len(word_before_cursor), display_meta=display_meta) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py deleted file mode 100644 index cbd74d8fea..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py +++ /dev/null @@ -1,105 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.completion import Completer, Completion -import os - -__all__ = ( - 'PathCompleter', - 'ExecutableCompleter', -) - - -class PathCompleter(Completer): - """ - Complete for Path variables. - - :param get_paths: Callable which returns a list of directories to look into - when the user enters a relative path. - :param file_filter: Callable which takes a filename and returns whether - this file should show up in the completion. ``None`` - when no filtering has to be done. - :param min_input_len: Don't do autocompletion when the input string is shorter. - """ - def __init__(self, only_directories=False, get_paths=None, file_filter=None, - min_input_len=0, expanduser=False): - assert get_paths is None or callable(get_paths) - assert file_filter is None or callable(file_filter) - assert isinstance(min_input_len, int) - assert isinstance(expanduser, bool) - - self.only_directories = only_directories - self.get_paths = get_paths or (lambda: ['.']) - self.file_filter = file_filter or (lambda _: True) - self.min_input_len = min_input_len - self.expanduser = expanduser - - def get_completions(self, document, complete_event): - text = document.text_before_cursor - - # Complete only when we have at least the minimal input length, - # otherwise, we can too many results and autocompletion will become too - # heavy. - if len(text) < self.min_input_len: - return - - try: - # Do tilde expansion. - if self.expanduser: - text = os.path.expanduser(text) - - # Directories where to look. - dirname = os.path.dirname(text) - if dirname: - directories = [os.path.dirname(os.path.join(p, text)) - for p in self.get_paths()] - else: - directories = self.get_paths() - - # Start of current file. - prefix = os.path.basename(text) - - # Get all filenames. - filenames = [] - for directory in directories: - # Look for matches in this directory. - if os.path.isdir(directory): - for filename in os.listdir(directory): - if filename.startswith(prefix): - filenames.append((directory, filename)) - - # Sort - filenames = sorted(filenames, key=lambda k: k[1]) - - # Yield them. - for directory, filename in filenames: - completion = filename[len(prefix):] - full_name = os.path.join(directory, filename) - - if os.path.isdir(full_name): - # For directories, add a slash to the filename. - # (We don't add them to the `completion`. Users can type it - # to trigger the autocompletion themself.) - filename += '/' - elif self.only_directories: - continue - - if not self.file_filter(full_name): - continue - - yield Completion(completion, 0, display=filename) - except OSError: - pass - - -class ExecutableCompleter(PathCompleter): - """ - Complete only excutable files in the current path. - """ - def __init__(self): - PathCompleter.__init__( - self, - only_directories=False, - min_input_len=1, - get_paths=lambda: os.environ.get('PATH', '').split(os.pathsep), - file_filter=lambda name: os.access(name, os.X_OK), - expanduser=True), diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py deleted file mode 100644 index 76d6c1f9b4..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.contrib.regular_languages.completion import GrammarCompleter -from prompt_toolkit.contrib.regular_languages.compiler import compile - -from .filesystem import PathCompleter, ExecutableCompleter - -__all__ = ( - 'SystemCompleter', -) - - -class SystemCompleter(GrammarCompleter): - """ - Completer for system commands. - """ - def __init__(self): - # Compile grammar. - g = compile( - r""" - # First we have an executable. - (?P<executable>[^\s]+) - - # Ignore literals in between. - ( - \s+ - ("[^"]*" | '[^']*' | [^'"]+ ) - )* - - \s+ - - # Filename as parameters. - ( - (?P<filename>[^\s]+) | - "(?P<double_quoted_filename>[^\s]+)" | - '(?P<single_quoted_filename>[^\s]+)' - ) - """, - escape_funcs={ - 'double_quoted_filename': (lambda string: string.replace('"', '\\"')), - 'single_quoted_filename': (lambda string: string.replace("'", "\\'")), - }, - unescape_funcs={ - 'double_quoted_filename': (lambda string: string.replace('\\"', '"')), # XXX: not enterily correct. - 'single_quoted_filename': (lambda string: string.replace("\\'", "'")), - }) - - # Create GrammarCompleter - super(SystemCompleter, self).__init__( - g, - { - 'executable': ExecutableCompleter(), - 'filename': PathCompleter(only_directories=False, expanduser=True), - 'double_quoted_filename': PathCompleter(only_directories=False, expanduser=True), - 'single_quoted_filename': PathCompleter(only_directories=False, expanduser=True), - }) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py deleted file mode 100644 index 314cb1f81d..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py +++ /dev/null @@ -1,76 +0,0 @@ -r""" -Tool for expressing the grammar of an input as a regular language. -================================================================== - -The grammar for the input of many simple command line interfaces can be -expressed by a regular language. Examples are PDB (the Python debugger); a -simple (bash-like) shell with "pwd", "cd", "cat" and "ls" commands; arguments -that you can pass to an executable; etc. It is possible to use regular -expressions for validation and parsing of such a grammar. (More about regular -languages: http://en.wikipedia.org/wiki/Regular_language) - -Example -------- - -Let's take the pwd/cd/cat/ls example. We want to have a shell that accepts -these three commands. "cd" is followed by a quoted directory name and "cat" is -followed by a quoted file name. (We allow quotes inside the filename when -they're escaped with a backslash.) We could define the grammar using the -following regular expression:: - - grammar = \s* ( - pwd | - ls | - (cd \s+ " ([^"]|\.)+ ") | - (cat \s+ " ([^"]|\.)+ ") - ) \s* - - -What can we do with this grammar? ---------------------------------- - -- Syntax highlighting: We could use this for instance to give file names - different colour. -- Parse the result: .. We can extract the file names and commands by using a - regular expression with named groups. -- Input validation: .. Don't accept anything that does not match this grammar. - When combined with a parser, we can also recursively do - filename validation (and accept only existing files.) -- Autocompletion: .... Each part of the grammar can have its own autocompleter. - "cat" has to be completed using file names, while "cd" - has to be completed using directory names. - -How does it work? ------------------ - -As a user of this library, you have to define the grammar of the input as a -regular expression. The parts of this grammar where autocompletion, validation -or any other processing is required need to be marked using a regex named -group. Like ``(?P<varname>...)`` for instance. - -When the input is processed for validation (for instance), the regex will -execute, the named group is captured, and the validator associated with this -named group will test the captured string. - -There is one tricky bit: - - Ofter we operate on incomplete input (this is by definition the case for - autocompletion) and we have to decide for the cursor position in which - possible state the grammar it could be and in which way variables could be - matched up to that point. - -To solve this problem, the compiler takes the original regular expression and -translates it into a set of other regular expressions which each match prefixes -of strings that would match the first expression. (We translate it into -multiple expression, because we want to have each possible state the regex -could be in -- in case there are several or-clauses with each different -completers.) - - -TODO: some examples of: - - How to create a highlighter from this grammar. - - How to create a validator from this grammar. - - How to create an autocompleter from this grammar. - - How to create a parser from this grammar. -""" -from .compiler import compile diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py deleted file mode 100644 index 01476bf626..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py +++ /dev/null @@ -1,408 +0,0 @@ -r""" -Compiler for a regular grammar. - -Example usage:: - - # Create and compile grammar. - p = compile('add \s+ (?P<var1>[^\s]+) \s+ (?P<var2>[^\s]+)') - - # Match input string. - m = p.match('add 23 432') - - # Get variables. - m.variables().get('var1') # Returns "23" - m.variables().get('var2') # Returns "432" - - -Partial matches are possible:: - - # Create and compile grammar. - p = compile(''' - # Operators with two arguments. - ((?P<operator1>[^\s]+) \s+ (?P<var1>[^\s]+) \s+ (?P<var2>[^\s]+)) | - - # Operators with only one arguments. - ((?P<operator2>[^\s]+) \s+ (?P<var1>[^\s]+)) - ''') - - # Match partial input string. - m = p.match_prefix('add 23') - - # Get variables. (Notice that both operator1 and operator2 contain the - # value "add".) This is because our input is incomplete, and we don't know - # yet in which rule of the regex we we'll end up. It could also be that - # `operator1` and `operator2` have a different autocompleter and we want to - # call all possible autocompleters that would result in valid input.) - m.variables().get('var1') # Returns "23" - m.variables().get('operator1') # Returns "add" - m.variables().get('operator2') # Returns "add" - -""" -from __future__ import unicode_literals -import re - -from six.moves import range -from .regex_parser import Any, Sequence, Regex, Variable, Repeat, Lookahead -from .regex_parser import parse_regex, tokenize_regex - -__all__ = ( - 'compile', -) - - -# Name of the named group in the regex, matching trailing input. -# (Trailing input is when the input contains characters after the end of the -# expression has been matched.) -_INVALID_TRAILING_INPUT = 'invalid_trailing' - - -class _CompiledGrammar(object): - """ - Compiles a grammar. This will take the parse tree of a regular expression - and compile the grammar. - - :param root_node: :class~`.regex_parser.Node` instance. - :param escape_funcs: `dict` mapping variable names to escape callables. - :param unescape_funcs: `dict` mapping variable names to unescape callables. - """ - def __init__(self, root_node, escape_funcs=None, unescape_funcs=None): - self.root_node = root_node - self.escape_funcs = escape_funcs or {} - self.unescape_funcs = unescape_funcs or {} - - #: Dictionary that will map the redex names to Node instances. - self._group_names_to_nodes = {} # Maps regex group names to varnames. - counter = [0] - - def create_group_func(node): - name = 'n%s' % counter[0] - self._group_names_to_nodes[name] = node.varname - counter[0] += 1 - return name - - # Compile regex strings. - self._re_pattern = '^%s$' % self._transform(root_node, create_group_func) - self._re_prefix_patterns = list(self._transform_prefix(root_node, create_group_func)) - - # Compile the regex itself. - flags = re.DOTALL # Note that we don't need re.MULTILINE! (^ and $ - # still represent the start and end of input text.) - self._re = re.compile(self._re_pattern, flags) - self._re_prefix = [re.compile(t, flags) for t in self._re_prefix_patterns] - - # We compile one more set of regexes, similar to `_re_prefix`, but accept any trailing - # input. This will ensure that we can still highlight the input correctly, even when the - # input contains some additional characters at the end that don't match the grammar.) - self._re_prefix_with_trailing_input = [ - re.compile(r'(?:%s)(?P<%s>.*?)$' % (t.rstrip('$'), _INVALID_TRAILING_INPUT), flags) - for t in self._re_prefix_patterns] - - def escape(self, varname, value): - """ - Escape `value` to fit in the place of this variable into the grammar. - """ - f = self.escape_funcs.get(varname) - return f(value) if f else value - - def unescape(self, varname, value): - """ - Unescape `value`. - """ - f = self.unescape_funcs.get(varname) - return f(value) if f else value - - @classmethod - def _transform(cls, root_node, create_group_func): - """ - Turn a :class:`Node` object into a regular expression. - - :param root_node: The :class:`Node` instance for which we generate the grammar. - :param create_group_func: A callable which takes a `Node` and returns the next - free name for this node. - """ - def transform(node): - # Turn `Any` into an OR. - if isinstance(node, Any): - return '(?:%s)' % '|'.join(transform(c) for c in node.children) - - # Concatenate a `Sequence` - elif isinstance(node, Sequence): - return ''.join(transform(c) for c in node.children) - - # For Regex and Lookahead nodes, just insert them literally. - elif isinstance(node, Regex): - return node.regex - - elif isinstance(node, Lookahead): - before = ('(?!' if node.negative else '(=') - return before + transform(node.childnode) + ')' - - # A `Variable` wraps the children into a named group. - elif isinstance(node, Variable): - return '(?P<%s>%s)' % (create_group_func(node), transform(node.childnode)) - - # `Repeat`. - elif isinstance(node, Repeat): - return '(?:%s){%i,%s}%s' % ( - transform(node.childnode), node.min_repeat, - ('' if node.max_repeat is None else str(node.max_repeat)), - ('' if node.greedy else '?') - ) - else: - raise TypeError('Got %r' % (node, )) - - return transform(root_node) - - @classmethod - def _transform_prefix(cls, root_node, create_group_func): - """ - Yield all the regular expressions matching a prefix of the grammar - defined by the `Node` instance. - - This can yield multiple expressions, because in the case of on OR - operation in the grammar, we can have another outcome depending on - which clause would appear first. E.g. "(A|B)C" is not the same as - "(B|A)C" because the regex engine is lazy and takes the first match. - However, because we the current input is actually a prefix of the - grammar which meight not yet contain the data for "C", we need to know - both intermediate states, in order to call the appropriate - autocompletion for both cases. - - :param root_node: The :class:`Node` instance for which we generate the grammar. - :param create_group_func: A callable which takes a `Node` and returns the next - free name for this node. - """ - def transform(node): - # Generate regexes for all permutations of this OR. Each node - # should be in front once. - if isinstance(node, Any): - for c in node.children: - for r in transform(c): - yield '(?:%s)?' % r - - # For a sequence. We can either have a match for the sequence - # of all the children, or for an exact match of the first X - # children, followed by a partial match of the next children. - elif isinstance(node, Sequence): - for i in range(len(node.children)): - a = [cls._transform(c, create_group_func) for c in node.children[:i]] - for c in transform(node.children[i]): - yield '(?:%s)' % (''.join(a) + c) - - elif isinstance(node, Regex): - yield '(?:%s)?' % node.regex - - elif isinstance(node, Lookahead): - if node.negative: - yield '(?!%s)' % cls._transform(node.childnode, create_group_func) - else: - # Not sure what the correct semantics are in this case. - # (Probably it's not worth implementing this.) - raise Exception('Positive lookahead not yet supported.') - - elif isinstance(node, Variable): - # (Note that we should not append a '?' here. the 'transform' - # method will already recursively do that.) - for c in transform(node.childnode): - yield '(?P<%s>%s)' % (create_group_func(node), c) - - elif isinstance(node, Repeat): - # If we have a repetition of 8 times. That would mean that the - # current input could have for instance 7 times a complete - # match, followed by a partial match. - prefix = cls._transform(node.childnode, create_group_func) - - for c in transform(node.childnode): - if node.max_repeat: - repeat_sign = '{,%i}' % (node.max_repeat - 1) - else: - repeat_sign = '*' - yield '(?:%s)%s%s(?:%s)?' % ( - prefix, - repeat_sign, - ('' if node.greedy else '?'), - c) - - else: - raise TypeError('Got %r' % node) - - for r in transform(root_node): - yield '^%s$' % r - - def match(self, string): - """ - Match the string with the grammar. - Returns a :class:`Match` instance or `None` when the input doesn't match the grammar. - - :param string: The input string. - """ - m = self._re.match(string) - - if m: - return Match(string, [(self._re, m)], self._group_names_to_nodes, self.unescape_funcs) - - def match_prefix(self, string): - """ - Do a partial match of the string with the grammar. The returned - :class:`Match` instance can contain multiple representations of the - match. This will never return `None`. If it doesn't match at all, the "trailing input" - part will capture all of the input. - - :param string: The input string. - """ - # First try to match using `_re_prefix`. If nothing is found, use the patterns that - # also accept trailing characters. - for patterns in [self._re_prefix, self._re_prefix_with_trailing_input]: - matches = [(r, r.match(string)) for r in patterns] - matches = [(r, m) for r, m in matches if m] - - if matches != []: - return Match(string, matches, self._group_names_to_nodes, self.unescape_funcs) - - -class Match(object): - """ - :param string: The input string. - :param re_matches: List of (compiled_re_pattern, re_match) tuples. - :param group_names_to_nodes: Dictionary mapping all the re group names to the matching Node instances. - """ - def __init__(self, string, re_matches, group_names_to_nodes, unescape_funcs): - self.string = string - self._re_matches = re_matches - self._group_names_to_nodes = group_names_to_nodes - self._unescape_funcs = unescape_funcs - - def _nodes_to_regs(self): - """ - Return a list of (varname, reg) tuples. - """ - def get_tuples(): - for r, re_match in self._re_matches: - for group_name, group_index in r.groupindex.items(): - if group_name != _INVALID_TRAILING_INPUT: - reg = re_match.regs[group_index] - node = self._group_names_to_nodes[group_name] - yield (node, reg) - - return list(get_tuples()) - - def _nodes_to_values(self): - """ - Returns list of list of (Node, string_value) tuples. - """ - def is_none(slice): - return slice[0] == -1 and slice[1] == -1 - - def get(slice): - return self.string[slice[0]:slice[1]] - - return [(varname, get(slice), slice) for varname, slice in self._nodes_to_regs() if not is_none(slice)] - - def _unescape(self, varname, value): - unwrapper = self._unescape_funcs.get(varname) - return unwrapper(value) if unwrapper else value - - def variables(self): - """ - Returns :class:`Variables` instance. - """ - return Variables([(k, self._unescape(k, v), sl) for k, v, sl in self._nodes_to_values()]) - - def trailing_input(self): - """ - Get the `MatchVariable` instance, representing trailing input, if there is any. - "Trailing input" is input at the end that does not match the grammar anymore, but - when this is removed from the end of the input, the input would be a valid string. - """ - slices = [] - - # Find all regex group for the name _INVALID_TRAILING_INPUT. - for r, re_match in self._re_matches: - for group_name, group_index in r.groupindex.items(): - if group_name == _INVALID_TRAILING_INPUT: - slices.append(re_match.regs[group_index]) - - # Take the smallest part. (Smaller trailing text means that a larger input has - # been matched, so that is better.) - if slices: - slice = [max(i[0] for i in slices), max(i[1] for i in slices)] - value = self.string[slice[0]:slice[1]] - return MatchVariable('<trailing_input>', value, slice) - - def end_nodes(self): - """ - Yields `MatchVariable` instances for all the nodes having their end - position at the end of the input string. - """ - for varname, reg in self._nodes_to_regs(): - # If this part goes until the end of the input string. - if reg[1] == len(self.string): - value = self._unescape(varname, self.string[reg[0]: reg[1]]) - yield MatchVariable(varname, value, (reg[0], reg[1])) - - -class Variables(object): - def __init__(self, tuples): - #: List of (varname, value, slice) tuples. - self._tuples = tuples - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, ', '.join('%s=%r' % (k, v) for k, v, _ in self._tuples)) - - def get(self, key, default=None): - items = self.getall(key) - return items[0] if items else default - - def getall(self, key): - return [v for k, v, _ in self._tuples if k == key] - - def __getitem__(self, key): - return self.get(key) - - def __iter__(self): - """ - Yield `MatchVariable` instances. - """ - for varname, value, slice in self._tuples: - yield MatchVariable(varname, value, slice) - - -class MatchVariable(object): - """ - Represents a match of a variable in the grammar. - - :param varname: (string) Name of the variable. - :param value: (string) Value of this variable. - :param slice: (start, stop) tuple, indicating the position of this variable - in the input string. - """ - def __init__(self, varname, value, slice): - self.varname = varname - self.value = value - self.slice = slice - - self.start = self.slice[0] - self.stop = self.slice[1] - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self.varname, self.value) - - -def compile(expression, escape_funcs=None, unescape_funcs=None): - """ - Compile grammar (given as regex string), returning a `CompiledGrammar` - instance. - """ - return _compile_from_parse_tree( - parse_regex(tokenize_regex(expression)), - escape_funcs=escape_funcs, - unescape_funcs=unescape_funcs) - - -def _compile_from_parse_tree(root_node, *a, **kw): - """ - Compile grammar (given as parse tree), returning a `CompiledGrammar` - instance. - """ - return _CompiledGrammar(root_node, *a, **kw) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py deleted file mode 100644 index bb49986a03..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Completer for a regular grammar. -""" -from __future__ import unicode_literals - -from prompt_toolkit.completion import Completer, Completion -from prompt_toolkit.document import Document - -from .compiler import _CompiledGrammar - -__all__ = ( - 'GrammarCompleter', -) - - -class GrammarCompleter(Completer): - """ - Completer which can be used for autocompletion according to variables in - the grammar. Each variable can have a different autocompleter. - - :param compiled_grammar: `GrammarCompleter` instance. - :param completers: `dict` mapping variable names of the grammar to the - `Completer` instances to be used for each variable. - """ - def __init__(self, compiled_grammar, completers): - assert isinstance(compiled_grammar, _CompiledGrammar) - assert isinstance(completers, dict) - - self.compiled_grammar = compiled_grammar - self.completers = completers - - def get_completions(self, document, complete_event): - m = self.compiled_grammar.match_prefix(document.text_before_cursor) - - if m: - completions = self._remove_duplicates( - self._get_completions_for_match(m, complete_event)) - - for c in completions: - yield c - - def _get_completions_for_match(self, match, complete_event): - """ - Yield all the possible completions for this input string. - (The completer assumes that the cursor position was at the end of the - input string.) - """ - for match_variable in match.end_nodes(): - varname = match_variable.varname - start = match_variable.start - - completer = self.completers.get(varname) - - if completer: - text = match_variable.value - - # Unwrap text. - unwrapped_text = self.compiled_grammar.unescape(varname, text) - - # Create a document, for the completions API (text/cursor_position) - document = Document(unwrapped_text, len(unwrapped_text)) - - # Call completer - for completion in completer.get_completions(document, complete_event): - new_text = unwrapped_text[:len(text) + completion.start_position] + completion.text - - # Wrap again. - yield Completion( - text=self.compiled_grammar.escape(varname, new_text), - start_position=start - len(match.string), - display=completion.display, - display_meta=completion.display_meta) - - def _remove_duplicates(self, items): - """ - Remove duplicates, while keeping the order. - (Sometimes we have duplicates, because the there several matches of the - same grammar, each yielding similar completions.) - """ - result = [] - for i in items: - if i not in result: - result.append(i) - return result diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py deleted file mode 100644 index c166d84fd1..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -`GrammarLexer` is compatible with Pygments lexers and can be used to highlight -the input using a regular grammar with token annotations. -""" -from __future__ import unicode_literals -from prompt_toolkit.document import Document -from prompt_toolkit.layout.lexers import Lexer -from prompt_toolkit.layout.utils import split_lines -from prompt_toolkit.token import Token - -from .compiler import _CompiledGrammar -from six.moves import range - -__all__ = ( - 'GrammarLexer', -) - - -class GrammarLexer(Lexer): - """ - Lexer which can be used for highlighting of tokens according to variables in the grammar. - - (It does not actual lexing of the string, but it exposes an API, compatible - with the Pygments lexer class.) - - :param compiled_grammar: Grammar as returned by the `compile()` function. - :param lexers: Dictionary mapping variable names of the regular grammar to - the lexers that should be used for this part. (This can - call other lexers recursively.) If you wish a part of the - grammar to just get one token, use a - `prompt_toolkit.layout.lexers.SimpleLexer`. - """ - def __init__(self, compiled_grammar, default_token=None, lexers=None): - assert isinstance(compiled_grammar, _CompiledGrammar) - assert default_token is None or isinstance(default_token, tuple) - assert lexers is None or all(isinstance(v, Lexer) for k, v in lexers.items()) - assert lexers is None or isinstance(lexers, dict) - - self.compiled_grammar = compiled_grammar - self.default_token = default_token or Token - self.lexers = lexers or {} - - def _get_tokens(self, cli, text): - m = self.compiled_grammar.match_prefix(text) - - if m: - characters = [[self.default_token, c] for c in text] - - for v in m.variables(): - # If we have a `Lexer` instance for this part of the input. - # Tokenize recursively and apply tokens. - lexer = self.lexers.get(v.varname) - - if lexer: - document = Document(text[v.start:v.stop]) - lexer_tokens_for_line = lexer.lex_document(cli, document) - lexer_tokens = [] - for i in range(len(document.lines)): - lexer_tokens.extend(lexer_tokens_for_line(i)) - lexer_tokens.append((Token, '\n')) - if lexer_tokens: - lexer_tokens.pop() - - i = v.start - for t, s in lexer_tokens: - for c in s: - if characters[i][0] == self.default_token: - characters[i][0] = t - i += 1 - - # Highlight trailing input. - trailing_input = m.trailing_input() - if trailing_input: - for i in range(trailing_input.start, trailing_input.stop): - characters[i][0] = Token.TrailingInput - - return characters - else: - return [(Token, text)] - - def lex_document(self, cli, document): - lines = list(split_lines(self._get_tokens(cli, document.text))) - - def get_line(lineno): - try: - return lines[lineno] - except IndexError: - return [] - - return get_line diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py deleted file mode 100644 index e5909b241e..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py +++ /dev/null @@ -1,262 +0,0 @@ -""" -Parser for parsing a regular expression. -Take a string representing a regular expression and return the root node of its -parse tree. - -usage:: - - root_node = parse_regex('(hello|world)') - -Remarks: -- The regex parser processes multiline, it ignores all whitespace and supports - multiple named groups with the same name and #-style comments. - -Limitations: -- Lookahead is not supported. -""" -from __future__ import unicode_literals -import re - -__all__ = ( - 'Repeat', - 'Variable', - 'Regex', - 'Lookahead', - - 'tokenize_regex', - 'parse_regex', -) - - -class Node(object): - """ - Base class for all the grammar nodes. - (You don't initialize this one.) - """ - def __add__(self, other_node): - return Sequence([self, other_node]) - - def __or__(self, other_node): - return Any([self, other_node]) - - -class Any(Node): - """ - Union operation (OR operation) between several grammars. You don't - initialize this yourself, but it's a result of a "Grammar1 | Grammar2" - operation. - """ - def __init__(self, children): - self.children = children - - def __or__(self, other_node): - return Any(self.children + [other_node]) - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.children) - - -class Sequence(Node): - """ - Concatenation operation of several grammars. You don't initialize this - yourself, but it's a result of a "Grammar1 + Grammar2" operation. - """ - def __init__(self, children): - self.children = children - - def __add__(self, other_node): - return Sequence(self.children + [other_node]) - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.children) - - -class Regex(Node): - """ - Regular expression. - """ - def __init__(self, regex): - re.compile(regex) # Validate - - self.regex = regex - - def __repr__(self): - return '%s(/%s/)' % (self.__class__.__name__, self.regex) - - -class Lookahead(Node): - """ - Lookahead expression. - """ - def __init__(self, childnode, negative=False): - self.childnode = childnode - self.negative = negative - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.childnode) - - -class Variable(Node): - """ - Mark a variable in the regular grammar. This will be translated into a - named group. Each variable can have his own completer, validator, etc.. - - :param childnode: The grammar which is wrapped inside this variable. - :param varname: String. - """ - def __init__(self, childnode, varname=None): - self.childnode = childnode - self.varname = varname - - def __repr__(self): - return '%s(childnode=%r, varname=%r)' % ( - self.__class__.__name__, self.childnode, self.varname) - - -class Repeat(Node): - def __init__(self, childnode, min_repeat=0, max_repeat=None, greedy=True): - self.childnode = childnode - self.min_repeat = min_repeat - self.max_repeat = max_repeat - self.greedy = greedy - - def __repr__(self): - return '%s(childnode=%r)' % (self.__class__.__name__, self.childnode) - - -def tokenize_regex(input): - """ - Takes a string, representing a regular expression as input, and tokenizes - it. - - :param input: string, representing a regular expression. - :returns: List of tokens. - """ - # Regular expression for tokenizing other regular expressions. - p = re.compile(r'''^( - \(\?P\<[a-zA-Z0-9_-]+\> | # Start of named group. - \(\?#[^)]*\) | # Comment - \(\?= | # Start of lookahead assertion - \(\?! | # Start of negative lookahead assertion - \(\?<= | # If preceded by. - \(\?< | # If not preceded by. - \(?: | # Start of group. (non capturing.) - \( | # Start of group. - \(?[iLmsux] | # Flags. - \(?P=[a-zA-Z]+\) | # Back reference to named group - \) | # End of group. - \{[^{}]*\} | # Repetition - \*\? | \+\? | \?\?\ | # Non greedy repetition. - \* | \+ | \? | # Repetition - \#.*\n | # Comment - \\. | - - # Character group. - \[ - ( [^\]\\] | \\.)* - \] | - - [^(){}] | - . - )''', re.VERBOSE) - - tokens = [] - - while input: - m = p.match(input) - if m: - token, input = input[:m.end()], input[m.end():] - if not token.isspace(): - tokens.append(token) - else: - raise Exception('Could not tokenize input regex.') - - return tokens - - -def parse_regex(regex_tokens): - """ - Takes a list of tokens from the tokenizer, and returns a parse tree. - """ - # We add a closing brace because that represents the final pop of the stack. - tokens = [')'] + regex_tokens[::-1] - - def wrap(lst): - """ Turn list into sequence when it contains several items. """ - if len(lst) == 1: - return lst[0] - else: - return Sequence(lst) - - def _parse(): - or_list = [] - result = [] - - def wrapped_result(): - if or_list == []: - return wrap(result) - else: - or_list.append(result) - return Any([wrap(i) for i in or_list]) - - while tokens: - t = tokens.pop() - - if t.startswith('(?P<'): - variable = Variable(_parse(), varname=t[4:-1]) - result.append(variable) - - elif t in ('*', '*?'): - greedy = (t == '*') - result[-1] = Repeat(result[-1], greedy=greedy) - - elif t in ('+', '+?'): - greedy = (t == '+') - result[-1] = Repeat(result[-1], min_repeat=1, greedy=greedy) - - elif t in ('?', '??'): - if result == []: - raise Exception('Nothing to repeat.' + repr(tokens)) - else: - greedy = (t == '?') - result[-1] = Repeat(result[-1], min_repeat=0, max_repeat=1, greedy=greedy) - - elif t == '|': - or_list.append(result) - result = [] - - elif t in ('(', '(?:'): - result.append(_parse()) - - elif t == '(?!': - result.append(Lookahead(_parse(), negative=True)) - - elif t == '(?=': - result.append(Lookahead(_parse(), negative=False)) - - elif t == ')': - return wrapped_result() - - elif t.startswith('#'): - pass - - elif t.startswith('{'): - # TODO: implement! - raise Exception('{}-style repitition not yet supported' % t) - - elif t.startswith('(?'): - raise Exception('%r not supported' % t) - - elif t.isspace(): - pass - else: - result.append(Regex(t)) - - raise Exception("Expecting ')' token") - - result = _parse() - - if len(tokens) != 0: - raise Exception("Unmatched parantheses.") - else: - return result diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py deleted file mode 100644 index d5f8cfccc6..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Validator for a regular langage. -""" -from __future__ import unicode_literals - -from prompt_toolkit.validation import Validator, ValidationError -from prompt_toolkit.document import Document - -from .compiler import _CompiledGrammar - -__all__ = ( - 'GrammarValidator', -) - - -class GrammarValidator(Validator): - """ - Validator which can be used for validation according to variables in - the grammar. Each variable can have its own validator. - - :param compiled_grammar: `GrammarCompleter` instance. - :param validators: `dict` mapping variable names of the grammar to the - `Validator` instances to be used for each variable. - """ - def __init__(self, compiled_grammar, validators): - assert isinstance(compiled_grammar, _CompiledGrammar) - assert isinstance(validators, dict) - - self.compiled_grammar = compiled_grammar - self.validators = validators - - def validate(self, document): - # Parse input document. - # We use `match`, not `match_prefix`, because for validation, we want - # the actual, unambiguous interpretation of the input. - m = self.compiled_grammar.match(document.text) - - if m: - for v in m.variables(): - validator = self.validators.get(v.varname) - - if validator: - # Unescape text. - unwrapped_text = self.compiled_grammar.unescape(v.varname, v.value) - - # Create a document, for the completions API (text/cursor_position) - inner_document = Document(unwrapped_text, len(unwrapped_text)) - - try: - validator.validate(inner_document) - except ValidationError as e: - raise ValidationError( - cursor_position=v.start + e.cursor_position, - message=e.message) - else: - raise ValidationError(cursor_position=len(document.text), - message='Invalid command') diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py deleted file mode 100644 index 7b7aeec820..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .server import * -from .application import * diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py deleted file mode 100644 index 7fe6cc97b7..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Interface for Telnet applications. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -__all__ = ( - 'TelnetApplication', -) - - -class TelnetApplication(with_metaclass(ABCMeta, object)): - """ - The interface which has to be implemented for any telnet application. - An instance of this class has to be passed to `TelnetServer`. - """ - @abstractmethod - def client_connected(self, telnet_connection): - """ - Called when a new client was connected. - - Probably you want to call `telnet_connection.set_cli` here to set a - the CommandLineInterface instance to be used. - Hint: Use the following shortcut: `prompt_toolkit.shortcuts.create_cli` - """ - - @abstractmethod - def client_leaving(self, telnet_connection): - """ - Called when a client quits. - """ diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py deleted file mode 100644 index 10792ceed6..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -Python logger for the telnet server. -""" -from __future__ import unicode_literals -import logging - -logger = logging.getLogger(__package__) - -__all__ = ( - 'logger', -) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py deleted file mode 100644 index b1bb0ccbe8..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py +++ /dev/null @@ -1,181 +0,0 @@ -""" -Parser for the Telnet protocol. (Not a complete implementation of the telnet -specification, but sufficient for a command line interface.) - -Inspired by `Twisted.conch.telnet`. -""" -from __future__ import unicode_literals - -import struct -from six import int2byte, binary_type, iterbytes - -from .log import logger - -__all__ = ( - 'TelnetProtocolParser', -) - -# Telnet constants. -NOP = int2byte(0) -SGA = int2byte(3) - -IAC = int2byte(255) -DO = int2byte(253) -DONT = int2byte(254) -LINEMODE = int2byte(34) -SB = int2byte(250) -WILL = int2byte(251) -WONT = int2byte(252) -MODE = int2byte(1) -SE = int2byte(240) -ECHO = int2byte(1) -NAWS = int2byte(31) -LINEMODE = int2byte(34) -SUPPRESS_GO_AHEAD = int2byte(3) - -DM = int2byte(242) -BRK = int2byte(243) -IP = int2byte(244) -AO = int2byte(245) -AYT = int2byte(246) -EC = int2byte(247) -EL = int2byte(248) -GA = int2byte(249) - - -class TelnetProtocolParser(object): - """ - Parser for the Telnet protocol. - Usage:: - - def data_received(data): - print(data) - - def size_received(rows, columns): - print(rows, columns) - - p = TelnetProtocolParser(data_received, size_received) - p.feed(binary_data) - """ - def __init__(self, data_received_callback, size_received_callback): - self.data_received_callback = data_received_callback - self.size_received_callback = size_received_callback - - self._parser = self._parse_coroutine() - self._parser.send(None) - - def received_data(self, data): - self.data_received_callback(data) - - def do_received(self, data): - """ Received telnet DO command. """ - logger.info('DO %r', data) - - def dont_received(self, data): - """ Received telnet DONT command. """ - logger.info('DONT %r', data) - - def will_received(self, data): - """ Received telnet WILL command. """ - logger.info('WILL %r', data) - - def wont_received(self, data): - """ Received telnet WONT command. """ - logger.info('WONT %r', data) - - def command_received(self, command, data): - if command == DO: - self.do_received(data) - - elif command == DONT: - self.dont_received(data) - - elif command == WILL: - self.will_received(data) - - elif command == WONT: - self.wont_received(data) - - else: - logger.info('command received %r %r', command, data) - - def naws(self, data): - """ - Received NAWS. (Window dimensions.) - """ - if len(data) == 4: - # NOTE: the first parameter of struct.unpack should be - # a 'str' object. Both on Py2/py3. This crashes on OSX - # otherwise. - columns, rows = struct.unpack(str('!HH'), data) - self.size_received_callback(rows, columns) - else: - logger.warning('Wrong number of NAWS bytes') - - def negotiate(self, data): - """ - Got negotiate data. - """ - command, payload = data[0:1], data[1:] - assert isinstance(command, bytes) - - if command == NAWS: - self.naws(payload) - else: - logger.info('Negotiate (%r got bytes)', len(data)) - - def _parse_coroutine(self): - """ - Parser state machine. - Every 'yield' expression returns the next byte. - """ - while True: - d = yield - - if d == int2byte(0): - pass # NOP - - # Go to state escaped. - elif d == IAC: - d2 = yield - - if d2 == IAC: - self.received_data(d2) - - # Handle simple commands. - elif d2 in (NOP, DM, BRK, IP, AO, AYT, EC, EL, GA): - self.command_received(d2, None) - - # Handle IAC-[DO/DONT/WILL/WONT] commands. - elif d2 in (DO, DONT, WILL, WONT): - d3 = yield - self.command_received(d2, d3) - - # Subnegotiation - elif d2 == SB: - # Consume everything until next IAC-SE - data = [] - - while True: - d3 = yield - - if d3 == IAC: - d4 = yield - if d4 == SE: - break - else: - data.append(d4) - else: - data.append(d3) - - self.negotiate(b''.join(data)) - else: - self.received_data(d) - - def feed(self, data): - """ - Feed data to the parser. - """ - assert isinstance(data, binary_type) - for b in iterbytes(data): - self._parser.send(int2byte(b)) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py deleted file mode 100644 index d75a9572eb..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py +++ /dev/null @@ -1,407 +0,0 @@ -""" -Telnet server. - -Example usage:: - - class MyTelnetApplication(TelnetApplication): - def client_connected(self, telnet_connection): - # Set CLI with simple prompt. - telnet_connection.set_application( - telnet_connection.create_prompt_application(...)) - - def handle_command(self, telnet_connection, document): - # When the client enters a command, just reply. - telnet_connection.send('You said: %r\n\n' % document.text) - - ... - - a = MyTelnetApplication() - TelnetServer(application=a, host='127.0.0.1', port=23).run() -""" -from __future__ import unicode_literals - -import socket -import select - -import threading -import os -import fcntl - -from six import int2byte, text_type, binary_type -from codecs import getincrementaldecoder - -from prompt_toolkit.enums import DEFAULT_BUFFER -from prompt_toolkit.eventloop.base import EventLoop -from prompt_toolkit.interface import CommandLineInterface, Application -from prompt_toolkit.layout.screen import Size -from prompt_toolkit.shortcuts import create_prompt_application -from prompt_toolkit.terminal.vt100_input import InputStream -from prompt_toolkit.terminal.vt100_output import Vt100_Output - -from .log import logger -from .protocol import IAC, DO, LINEMODE, SB, MODE, SE, WILL, ECHO, NAWS, SUPPRESS_GO_AHEAD -from .protocol import TelnetProtocolParser -from .application import TelnetApplication - -__all__ = ( - 'TelnetServer', -) - - -def _initialize_telnet(connection): - logger.info('Initializing telnet connection') - - # Iac Do Linemode - connection.send(IAC + DO + LINEMODE) - - # Suppress Go Ahead. (This seems important for Putty to do correct echoing.) - # This will allow bi-directional operation. - connection.send(IAC + WILL + SUPPRESS_GO_AHEAD) - - # Iac sb - connection.send(IAC + SB + LINEMODE + MODE + int2byte(0) + IAC + SE) - - # IAC Will Echo - connection.send(IAC + WILL + ECHO) - - # Negotiate window size - connection.send(IAC + DO + NAWS) - - -class _ConnectionStdout(object): - """ - Wrapper around socket which provides `write` and `flush` methods for the - Vt100_Output output. - """ - def __init__(self, connection, encoding): - self._encoding = encoding - self._connection = connection - self._buffer = [] - - def write(self, data): - assert isinstance(data, text_type) - self._buffer.append(data.encode(self._encoding)) - self.flush() - - def flush(self): - try: - self._connection.send(b''.join(self._buffer)) - except socket.error as e: - logger.error("Couldn't send data over socket: %s" % e) - - self._buffer = [] - - -class TelnetConnection(object): - """ - Class that represents one Telnet connection. - """ - def __init__(self, conn, addr, application, server, encoding): - assert isinstance(addr, tuple) # (addr, port) tuple - assert isinstance(application, TelnetApplication) - assert isinstance(server, TelnetServer) - assert isinstance(encoding, text_type) # e.g. 'utf-8' - - self.conn = conn - self.addr = addr - self.application = application - self.closed = False - self.handling_command = True - self.server = server - self.encoding = encoding - self.callback = None # Function that handles the CLI result. - - # Create "Output" object. - self.size = Size(rows=40, columns=79) - - # Initialize. - _initialize_telnet(conn) - - # Create output. - def get_size(): - return self.size - self.stdout = _ConnectionStdout(conn, encoding=encoding) - self.vt100_output = Vt100_Output(self.stdout, get_size, write_binary=False) - - # Create an eventloop (adaptor) for the CommandLineInterface. - self.eventloop = _TelnetEventLoopInterface(server) - - # Set default CommandLineInterface. - self.set_application(create_prompt_application()) - - # Call client_connected - application.client_connected(self) - - # Draw for the first time. - self.handling_command = False - self.cli._redraw() - - def set_application(self, app, callback=None): - """ - Set ``CommandLineInterface`` instance for this connection. - (This can be replaced any time.) - - :param cli: CommandLineInterface instance. - :param callback: Callable that takes the result of the CLI. - """ - assert isinstance(app, Application) - assert callback is None or callable(callback) - - self.cli = CommandLineInterface( - application=app, - eventloop=self.eventloop, - output=self.vt100_output) - self.callback = callback - - # Create a parser, and parser callbacks. - cb = self.cli.create_eventloop_callbacks() - inputstream = InputStream(cb.feed_key) - - # Input decoder for stdin. (Required when working with multibyte - # characters, like chinese input.) - stdin_decoder_cls = getincrementaldecoder(self.encoding) - stdin_decoder = [stdin_decoder_cls()] # nonlocal - - # Tell the CLI that it's running. We don't start it through the run() - # call, but will still want _redraw() to work. - self.cli._is_running = True - - def data_received(data): - """ TelnetProtocolParser 'data_received' callback """ - assert isinstance(data, binary_type) - - try: - result = stdin_decoder[0].decode(data) - inputstream.feed(result) - except UnicodeDecodeError: - stdin_decoder[0] = stdin_decoder_cls() - return '' - - def size_received(rows, columns): - """ TelnetProtocolParser 'size_received' callback """ - self.size = Size(rows=rows, columns=columns) - cb.terminal_size_changed() - - self.parser = TelnetProtocolParser(data_received, size_received) - - def feed(self, data): - """ - Handler for incoming data. (Called by TelnetServer.) - """ - assert isinstance(data, binary_type) - - self.parser.feed(data) - - # Render again. - self.cli._redraw() - - # When a return value has been set (enter was pressed), handle command. - if self.cli.is_returning: - try: - return_value = self.cli.return_value() - except (EOFError, KeyboardInterrupt) as e: - # Control-D or Control-C was pressed. - logger.info('%s, closing connection.', type(e).__name__) - self.close() - return - - # Handle CLI command - self._handle_command(return_value) - - def _handle_command(self, command): - """ - Handle command. This will run in a separate thread, in order not - to block the event loop. - """ - logger.info('Handle command %r', command) - - def in_executor(): - self.handling_command = True - try: - if self.callback is not None: - self.callback(self, command) - finally: - self.server.call_from_executor(done) - - def done(): - self.handling_command = False - - # Reset state and draw again. (If the connection is still open -- - # the application could have called TelnetConnection.close() - if not self.closed: - self.cli.reset() - self.cli.buffers[DEFAULT_BUFFER].reset() - self.cli.renderer.request_absolute_cursor_position() - self.vt100_output.flush() - self.cli._redraw() - - self.server.run_in_executor(in_executor) - - def erase_screen(self): - """ - Erase output screen. - """ - self.vt100_output.erase_screen() - self.vt100_output.cursor_goto(0, 0) - self.vt100_output.flush() - - def send(self, data): - """ - Send text to the client. - """ - assert isinstance(data, text_type) - - # When data is send back to the client, we should replace the line - # endings. (We didn't allocate a real pseudo terminal, and the telnet - # connection is raw, so we are responsible for inserting \r.) - self.stdout.write(data.replace('\n', '\r\n')) - self.stdout.flush() - - def close(self): - """ - Close the connection. - """ - self.application.client_leaving(self) - - self.conn.close() - self.closed = True - - -class _TelnetEventLoopInterface(EventLoop): - """ - Eventloop object to be assigned to `CommandLineInterface`. - """ - def __init__(self, server): - self._server = server - - def close(self): - " Ignore. " - - def stop(self): - " Ignore. " - - def run_in_executor(self, callback): - self._server.run_in_executor(callback) - - def call_from_executor(self, callback, _max_postpone_until=None): - self._server.call_from_executor(callback) - - def add_reader(self, fd, callback): - raise NotImplementedError - - def remove_reader(self, fd): - raise NotImplementedError - - -class TelnetServer(object): - """ - Telnet server implementation. - """ - def __init__(self, host='127.0.0.1', port=23, application=None, encoding='utf-8'): - assert isinstance(host, text_type) - assert isinstance(port, int) - assert isinstance(application, TelnetApplication) - assert isinstance(encoding, text_type) - - self.host = host - self.port = port - self.application = application - self.encoding = encoding - - self.connections = set() - - self._calls_from_executor = [] - - # Create a pipe for inter thread communication. - self._schedule_pipe = os.pipe() - fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK) - - @classmethod - def create_socket(cls, host, port): - # Create and bind socket - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind((host, port)) - - s.listen(4) - return s - - def run_in_executor(self, callback): - threading.Thread(target=callback).start() - - def call_from_executor(self, callback): - self._calls_from_executor.append(callback) - - if self._schedule_pipe: - os.write(self._schedule_pipe[1], b'x') - - def _process_callbacks(self): - """ - Process callbacks from `call_from_executor` in eventloop. - """ - # Flush all the pipe content. - os.read(self._schedule_pipe[0], 1024) - - # Process calls from executor. - calls_from_executor, self._calls_from_executor = self._calls_from_executor, [] - for c in calls_from_executor: - c() - - def run(self): - """ - Run the eventloop for the telnet server. - """ - listen_socket = self.create_socket(self.host, self.port) - logger.info('Listening for telnet connections on %s port %r', self.host, self.port) - - try: - while True: - # Removed closed connections. - self.connections = set([c for c in self.connections if not c.closed]) - - # Ignore connections handling commands. - connections = set([c for c in self.connections if not c.handling_command]) - - # Wait for next event. - read_list = ( - [listen_socket, self._schedule_pipe[0]] + - [c.conn for c in connections]) - - read, _, _ = select.select(read_list, [], []) - - for s in read: - # When the socket itself is ready, accept a new connection. - if s == listen_socket: - self._accept(listen_socket) - - # If we receive something on our "call_from_executor" pipe, process - # these callbacks in a thread safe way. - elif s == self._schedule_pipe[0]: - self._process_callbacks() - - # Handle incoming data on socket. - else: - self._handle_incoming_data(s) - finally: - listen_socket.close() - - def _accept(self, listen_socket): - """ - Accept new incoming connection. - """ - conn, addr = listen_socket.accept() - connection = TelnetConnection(conn, addr, self.application, self, encoding=self.encoding) - self.connections.add(connection) - - logger.info('New connection %r %r', *addr) - - def _handle_incoming_data(self, conn): - """ - Handle incoming data on socket. - """ - connection = [c for c in self.connections if c.conn == conn][0] - data = conn.recv(1024) - if data: - connection.feed(data) - else: - self.connections.remove(connection) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/__init__.py +++ /dev/null diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py deleted file mode 100644 index 16c1539c52..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import unicode_literals -from prompt_toolkit.validation import Validator, ValidationError -from six import string_types - - -class SentenceValidator(Validator): - """ - Validate input only when it appears in this list of sentences. - - :param sentences: List of sentences. - :param ignore_case: If True, case-insensitive comparisons. - """ - def __init__(self, sentences, ignore_case=False, error_message='Invalid input', move_cursor_to_end=False): - assert all(isinstance(s, string_types) for s in sentences) - assert isinstance(ignore_case, bool) - assert isinstance(error_message, string_types) - - self.sentences = list(sentences) - self.ignore_case = ignore_case - self.error_message = error_message - self.move_cursor_to_end = move_cursor_to_end - - if ignore_case: - self.sentences = set([s.lower() for s in self.sentences]) - - def validate(self, document): - if document.text not in self.sentences: - if self.move_cursor_to_end: - index = len(document.text) - else: - index = 0 - - raise ValidationError(cursor_position=index, - message=self.error_message) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py deleted file mode 100644 index 25d817ddd0..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py +++ /dev/null @@ -1,1001 +0,0 @@ -""" -The `Document` that implements all the text operations/querying. -""" -from __future__ import unicode_literals - -import bisect -import re -import six -import string -import weakref -from six.moves import range, map - -from .selection import SelectionType, SelectionState, PasteMode -from .clipboard import ClipboardData - -__all__ = ('Document',) - - -# Regex for finding "words" in documents. (We consider a group of alnum -# characters a word, but also a group of special characters a word, as long as -# it doesn't contain a space.) -# (This is a 'word' in Vi.) -_FIND_WORD_RE = re.compile(r'([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)') -_FIND_CURRENT_WORD_RE = re.compile(r'^([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)') -_FIND_CURRENT_WORD_INCLUDE_TRAILING_WHITESPACE_RE = re.compile(r'^(([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)\s*)') - -# Regex for finding "WORDS" in documents. -# (This is a 'WORD in Vi.) -_FIND_BIG_WORD_RE = re.compile(r'([^\s]+)') -_FIND_CURRENT_BIG_WORD_RE = re.compile(r'^([^\s]+)') -_FIND_CURRENT_BIG_WORD_INCLUDE_TRAILING_WHITESPACE_RE = re.compile(r'^([^\s]+\s*)') - -# Share the Document._cache between all Document instances. -# (Document instances are considered immutable. That means that if another -# `Document` is constructed with the same text, it should have the same -# `_DocumentCache`.) -_text_to_document_cache = weakref.WeakValueDictionary() # Maps document.text to DocumentCache instance. - - -class _ImmutableLineList(list): - """ - Some protection for our 'lines' list, which is assumed to be immutable in the cache. - (Useful for detecting obvious bugs.) - """ - def _error(self, *a, **kw): - raise NotImplementedError('Attempt to modifiy an immutable list.') - - __setitem__ = _error - append = _error - clear = _error - extend = _error - insert = _error - pop = _error - remove = _error - reverse = _error - sort = _error - - -class _DocumentCache(object): - def __init__(self): - #: List of lines for the Document text. - self.lines = None - - #: List of index positions, pointing to the start of all the lines. - self.line_indexes = None - - -class Document(object): - """ - This is a immutable class around the text and cursor position, and contains - methods for querying this data, e.g. to give the text before the cursor. - - This class is usually instantiated by a :class:`~prompt_toolkit.buffer.Buffer` - object, and accessed as the `document` property of that class. - - :param text: string - :param cursor_position: int - :param selection: :class:`.SelectionState` - """ - __slots__ = ('_text', '_cursor_position', '_selection', '_cache') - - def __init__(self, text='', cursor_position=None, selection=None): - assert isinstance(text, six.text_type), 'Got %r' % text - assert selection is None or isinstance(selection, SelectionState) - - # Check cursor position. It can also be right after the end. (Where we - # insert text.) - assert cursor_position is None or cursor_position <= len(text), AssertionError( - 'cursor_position=%r, len_text=%r' % (cursor_position, len(text))) - - # By default, if no cursor position was given, make sure to put the - # cursor position is at the end of the document. This is what makes - # sense in most places. - if cursor_position is None: - cursor_position = len(text) - - # Keep these attributes private. A `Document` really has to be - # considered to be immutable, because otherwise the caching will break - # things. Because of that, we wrap these into read-only properties. - self._text = text - self._cursor_position = cursor_position - self._selection = selection - - # Cache for lines/indexes. (Shared with other Document instances that - # contain the same text. - try: - self._cache = _text_to_document_cache[self.text] - except KeyError: - self._cache = _DocumentCache() - _text_to_document_cache[self.text] = self._cache - - # XX: For some reason, above, we can't use 'WeakValueDictionary.setdefault'. - # This fails in Pypy3. `self._cache` becomes None, because that's what - # 'setdefault' returns. - # self._cache = _text_to_document_cache.setdefault(self.text, _DocumentCache()) - # assert self._cache - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self.text, self.cursor_position) - - @property - def text(self): - " The document text. " - return self._text - - @property - def cursor_position(self): - " The document cursor position. " - return self._cursor_position - - @property - def selection(self): - " :class:`.SelectionState` object. " - return self._selection - - @property - def current_char(self): - """ Return character under cursor or an empty string. """ - return self._get_char_relative_to_cursor(0) or '' - - @property - def char_before_cursor(self): - """ Return character before the cursor or an empty string. """ - return self._get_char_relative_to_cursor(-1) or '' - - @property - def text_before_cursor(self): - return self.text[:self.cursor_position:] - - @property - def text_after_cursor(self): - return self.text[self.cursor_position:] - - @property - def current_line_before_cursor(self): - """ Text from the start of the line until the cursor. """ - _, _, text = self.text_before_cursor.rpartition('\n') - return text - - @property - def current_line_after_cursor(self): - """ Text from the cursor until the end of the line. """ - text, _, _ = self.text_after_cursor.partition('\n') - return text - - @property - def lines(self): - """ - Array of all the lines. - """ - # Cache, because this one is reused very often. - if self._cache.lines is None: - self._cache.lines = _ImmutableLineList(self.text.split('\n')) - - return self._cache.lines - - @property - def _line_start_indexes(self): - """ - Array pointing to the start indexes of all the lines. - """ - # Cache, because this is often reused. (If it is used, it's often used - # many times. And this has to be fast for editing big documents!) - if self._cache.line_indexes is None: - # Create list of line lengths. - line_lengths = map(len, self.lines) - - # Calculate cumulative sums. - indexes = [0] - append = indexes.append - pos = 0 - - for line_length in line_lengths: - pos += line_length + 1 - append(pos) - - # Remove the last item. (This is not a new line.) - if len(indexes) > 1: - indexes.pop() - - self._cache.line_indexes = indexes - - return self._cache.line_indexes - - @property - def lines_from_current(self): - """ - Array of the lines starting from the current line, until the last line. - """ - return self.lines[self.cursor_position_row:] - - @property - def line_count(self): - r""" Return the number of lines in this document. If the document ends - with a trailing \n, that counts as the beginning of a new line. """ - return len(self.lines) - - @property - def current_line(self): - """ Return the text on the line where the cursor is. (when the input - consists of just one line, it equals `text`. """ - return self.current_line_before_cursor + self.current_line_after_cursor - - @property - def leading_whitespace_in_current_line(self): - """ The leading whitespace in the left margin of the current line. """ - current_line = self.current_line - length = len(current_line) - len(current_line.lstrip()) - return current_line[:length] - - def _get_char_relative_to_cursor(self, offset=0): - """ - Return character relative to cursor position, or empty string - """ - try: - return self.text[self.cursor_position + offset] - except IndexError: - return '' - - @property - def on_first_line(self): - """ - True when we are at the first line. - """ - return self.cursor_position_row == 0 - - @property - def on_last_line(self): - """ - True when we are at the last line. - """ - return self.cursor_position_row == self.line_count - 1 - - @property - def cursor_position_row(self): - """ - Current row. (0-based.) - """ - row, _ = self._find_line_start_index(self.cursor_position) - return row - - @property - def cursor_position_col(self): - """ - Current column. (0-based.) - """ - # (Don't use self.text_before_cursor to calculate this. Creating - # substrings and doing rsplit is too expensive for getting the cursor - # position.) - _, line_start_index = self._find_line_start_index(self.cursor_position) - return self.cursor_position - line_start_index - - def _find_line_start_index(self, index): - """ - For the index of a character at a certain line, calculate the index of - the first character on that line. - - Return (row, index) tuple. - """ - indexes = self._line_start_indexes - - pos = bisect.bisect_right(indexes, index) - 1 - return pos, indexes[pos] - - def translate_index_to_position(self, index): - """ - Given an index for the text, return the corresponding (row, col) tuple. - (0-based. Returns (0, 0) for index=0.) - """ - # Find start of this line. - row, row_index = self._find_line_start_index(index) - col = index - row_index - - return row, col - - - def translate_row_col_to_index(self, row, col): - """ - Given a (row, col) tuple, return the corresponding index. - (Row and col params are 0-based.) - - Negative row/col values are turned into zero. - """ - try: - result = self._line_start_indexes[row] - line = self.lines[row] - except IndexError: - if row < 0: - result = self._line_start_indexes[0] - line = self.lines[0] - else: - result = self._line_start_indexes[-1] - line = self.lines[-1] - - result += max(0, min(col, len(line))) - - # Keep in range. (len(self.text) is included, because the cursor can be - # right after the end of the text as well.) - result = max(0, min(result, len(self.text))) - return result - - @property - def is_cursor_at_the_end(self): - """ True when the cursor is at the end of the text. """ - return self.cursor_position == len(self.text) - - @property - def is_cursor_at_the_end_of_line(self): - """ True when the cursor is at the end of this line. """ - return self.current_char in ('\n', '') - - def has_match_at_current_position(self, sub): - """ - `True` when this substring is found at the cursor position. - """ - return self.text.find(sub, self.cursor_position) == self.cursor_position - - def find(self, sub, in_current_line=False, include_current_position=False, - ignore_case=False, count=1): - """ - Find `text` after the cursor, return position relative to the cursor - position. Return `None` if nothing was found. - - :param count: Find the n-th occurance. - """ - assert isinstance(ignore_case, bool) - - if in_current_line: - text = self.current_line_after_cursor - else: - text = self.text_after_cursor - - if not include_current_position: - if len(text) == 0: - return # (Otherwise, we always get a match for the empty string.) - else: - text = text[1:] - - flags = re.IGNORECASE if ignore_case else 0 - iterator = re.finditer(re.escape(sub), text, flags) - - try: - for i, match in enumerate(iterator): - if i + 1 == count: - if include_current_position: - return match.start(0) - else: - return match.start(0) + 1 - except StopIteration: - pass - - def find_all(self, sub, ignore_case=False): - """ - Find all occurances of the substring. Return a list of absolute - positions in the document. - """ - flags = re.IGNORECASE if ignore_case else 0 - return [a.start() for a in re.finditer(re.escape(sub), self.text, flags)] - - def find_backwards(self, sub, in_current_line=False, ignore_case=False, count=1): - """ - Find `text` before the cursor, return position relative to the cursor - position. Return `None` if nothing was found. - - :param count: Find the n-th occurance. - """ - if in_current_line: - before_cursor = self.current_line_before_cursor[::-1] - else: - before_cursor = self.text_before_cursor[::-1] - - flags = re.IGNORECASE if ignore_case else 0 - iterator = re.finditer(re.escape(sub[::-1]), before_cursor, flags) - - try: - for i, match in enumerate(iterator): - if i + 1 == count: - return - match.start(0) - len(sub) - except StopIteration: - pass - - def get_word_before_cursor(self, WORD=False): - """ - Give the word before the cursor. - If we have whitespace before the cursor this returns an empty string. - """ - if self.text_before_cursor[-1:].isspace(): - return '' - else: - return self.text_before_cursor[self.find_start_of_previous_word(WORD=WORD):] - - def find_start_of_previous_word(self, count=1, WORD=False): - """ - Return an index relative to the cursor position pointing to the start - of the previous word. Return `None` if nothing was found. - """ - # Reverse the text before the cursor, in order to do an efficient - # backwards search. - text_before_cursor = self.text_before_cursor[::-1] - - regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE - iterator = regex.finditer(text_before_cursor) - - try: - for i, match in enumerate(iterator): - if i + 1 == count: - return - match.end(1) - except StopIteration: - pass - - def find_boundaries_of_current_word(self, WORD=False, include_leading_whitespace=False, - include_trailing_whitespace=False): - """ - Return the relative boundaries (startpos, endpos) of the current word under the - cursor. (This is at the current line, because line boundaries obviously - don't belong to any word.) - If not on a word, this returns (0,0) - """ - text_before_cursor = self.current_line_before_cursor[::-1] - text_after_cursor = self.current_line_after_cursor - - def get_regex(include_whitespace): - return { - (False, False): _FIND_CURRENT_WORD_RE, - (False, True): _FIND_CURRENT_WORD_INCLUDE_TRAILING_WHITESPACE_RE, - (True, False): _FIND_CURRENT_BIG_WORD_RE, - (True, True): _FIND_CURRENT_BIG_WORD_INCLUDE_TRAILING_WHITESPACE_RE, - }[(WORD, include_whitespace)] - - match_before = get_regex(include_leading_whitespace).search(text_before_cursor) - match_after = get_regex(include_trailing_whitespace).search(text_after_cursor) - - # When there is a match before and after, and we're not looking for - # WORDs, make sure that both the part before and after the cursor are - # either in the [a-zA-Z_] alphabet or not. Otherwise, drop the part - # before the cursor. - if not WORD and match_before and match_after: - c1 = self.text[self.cursor_position - 1] - c2 = self.text[self.cursor_position] - alphabet = string.ascii_letters + '0123456789_' - - if (c1 in alphabet) != (c2 in alphabet): - match_before = None - - return ( - - match_before.end(1) if match_before else 0, - match_after.end(1) if match_after else 0 - ) - - def get_word_under_cursor(self, WORD=False): - """ - Return the word, currently below the cursor. - This returns an empty string when the cursor is on a whitespace region. - """ - start, end = self.find_boundaries_of_current_word(WORD=WORD) - return self.text[self.cursor_position + start: self.cursor_position + end] - - def find_next_word_beginning(self, count=1, WORD=False): - """ - Return an index relative to the cursor position pointing to the start - of the next word. Return `None` if nothing was found. - """ - if count < 0: - return self.find_previous_word_beginning(count=-count, WORD=WORD) - - regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE - iterator = regex.finditer(self.text_after_cursor) - - try: - for i, match in enumerate(iterator): - # Take first match, unless it's the word on which we're right now. - if i == 0 and match.start(1) == 0: - count += 1 - - if i + 1 == count: - return match.start(1) - except StopIteration: - pass - - def find_next_word_ending(self, include_current_position=False, count=1, WORD=False): - """ - Return an index relative to the cursor position pointing to the end - of the next word. Return `None` if nothing was found. - """ - if count < 0: - return self.find_previous_word_ending(count=-count, WORD=WORD) - - if include_current_position: - text = self.text_after_cursor - else: - text = self.text_after_cursor[1:] - - regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE - iterable = regex.finditer(text) - - try: - for i, match in enumerate(iterable): - if i + 1 == count: - value = match.end(1) - - if include_current_position: - return value - else: - return value + 1 - - except StopIteration: - pass - - def find_previous_word_beginning(self, count=1, WORD=False): - """ - Return an index relative to the cursor position pointing to the start - of the previous word. Return `None` if nothing was found. - """ - if count < 0: - return self.find_next_word_beginning(count=-count, WORD=WORD) - - regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE - iterator = regex.finditer(self.text_before_cursor[::-1]) - - try: - for i, match in enumerate(iterator): - if i + 1 == count: - return - match.end(1) - except StopIteration: - pass - - def find_previous_word_ending(self, count=1, WORD=False): - """ - Return an index relative to the cursor position pointing to the end - of the previous word. Return `None` if nothing was found. - """ - if count < 0: - return self.find_next_word_ending(count=-count, WORD=WORD) - - text_before_cursor = self.text_after_cursor[:1] + self.text_before_cursor[::-1] - - regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE - iterator = regex.finditer(text_before_cursor) - - try: - for i, match in enumerate(iterator): - # Take first match, unless it's the word on which we're right now. - if i == 0 and match.start(1) == 0: - count += 1 - - if i + 1 == count: - return -match.start(1) + 1 - except StopIteration: - pass - - def find_next_matching_line(self, match_func, count=1): - """ - Look downwards for empty lines. - Return the line index, relative to the current line. - """ - result = None - - for index, line in enumerate(self.lines[self.cursor_position_row + 1:]): - if match_func(line): - result = 1 + index - count -= 1 - - if count == 0: - break - - return result - - def find_previous_matching_line(self, match_func, count=1): - """ - Look upwards for empty lines. - Return the line index, relative to the current line. - """ - result = None - - for index, line in enumerate(self.lines[:self.cursor_position_row][::-1]): - if match_func(line): - result = -1 - index - count -= 1 - - if count == 0: - break - - return result - - def get_cursor_left_position(self, count=1): - """ - Relative position for cursor left. - """ - if count < 0: - return self.get_cursor_right_position(-count) - - return - min(self.cursor_position_col, count) - - def get_cursor_right_position(self, count=1): - """ - Relative position for cursor_right. - """ - if count < 0: - return self.get_cursor_left_position(-count) - - return min(count, len(self.current_line_after_cursor)) - - def get_cursor_up_position(self, count=1, preferred_column=None): - """ - Return the relative cursor position (character index) where we would be if the - user pressed the arrow-up button. - - :param preferred_column: When given, go to this column instead of - staying at the current column. - """ - assert count >= 1 - column = self.cursor_position_col if preferred_column is None else preferred_column - - return self.translate_row_col_to_index( - max(0, self.cursor_position_row - count), column) - self.cursor_position - - def get_cursor_down_position(self, count=1, preferred_column=None): - """ - Return the relative cursor position (character index) where we would be if the - user pressed the arrow-down button. - - :param preferred_column: When given, go to this column instead of - staying at the current column. - """ - assert count >= 1 - column = self.cursor_position_col if preferred_column is None else preferred_column - - return self.translate_row_col_to_index( - self.cursor_position_row + count, column) - self.cursor_position - - def find_enclosing_bracket_right(self, left_ch, right_ch, end_pos=None): - """ - Find the right bracket enclosing current position. Return the relative - position to the cursor position. - - When `end_pos` is given, don't look past the position. - """ - if self.current_char == right_ch: - return 0 - - if end_pos is None: - end_pos = len(self.text) - else: - end_pos = min(len(self.text), end_pos) - - stack = 1 - - # Look forward. - for i in range(self.cursor_position + 1, end_pos): - c = self.text[i] - - if c == left_ch: - stack += 1 - elif c == right_ch: - stack -= 1 - - if stack == 0: - return i - self.cursor_position - - def find_enclosing_bracket_left(self, left_ch, right_ch, start_pos=None): - """ - Find the left bracket enclosing current position. Return the relative - position to the cursor position. - - When `start_pos` is given, don't look past the position. - """ - if self.current_char == left_ch: - return 0 - - if start_pos is None: - start_pos = 0 - else: - start_pos = max(0, start_pos) - - stack = 1 - - # Look backward. - for i in range(self.cursor_position - 1, start_pos - 1, -1): - c = self.text[i] - - if c == right_ch: - stack += 1 - elif c == left_ch: - stack -= 1 - - if stack == 0: - return i - self.cursor_position - - def find_matching_bracket_position(self, start_pos=None, end_pos=None): - """ - Return relative cursor position of matching [, (, { or < bracket. - - When `start_pos` or `end_pos` are given. Don't look past the positions. - """ - - # Look for a match. - for A, B in '()', '[]', '{}', '<>': - if self.current_char == A: - return self.find_enclosing_bracket_right(A, B, end_pos=end_pos) or 0 - elif self.current_char == B: - return self.find_enclosing_bracket_left(A, B, start_pos=start_pos) or 0 - - return 0 - - def get_start_of_document_position(self): - """ Relative position for the start of the document. """ - return - self.cursor_position - - def get_end_of_document_position(self): - """ Relative position for the end of the document. """ - return len(self.text) - self.cursor_position - - def get_start_of_line_position(self, after_whitespace=False): - """ Relative position for the start of this line. """ - if after_whitespace: - current_line = self.current_line - return len(current_line) - len(current_line.lstrip()) - self.cursor_position_col - else: - return - len(self.current_line_before_cursor) - - def get_end_of_line_position(self): - """ Relative position for the end of this line. """ - return len(self.current_line_after_cursor) - - def last_non_blank_of_current_line_position(self): - """ - Relative position for the last non blank character of this line. - """ - return len(self.current_line.rstrip()) - self.cursor_position_col - 1 - - def get_column_cursor_position(self, column): - """ - Return the relative cursor position for this column at the current - line. (It will stay between the boundaries of the line in case of a - larger number.) - """ - line_length = len(self.current_line) - current_column = self.cursor_position_col - column = max(0, min(line_length, column)) - - return column - current_column - - def selection_range(self): # XXX: shouldn't this return `None` if there is no selection??? - """ - Return (from, to) tuple of the selection. - start and end position are included. - - This doesn't take the selection type into account. Use - `selection_ranges` instead. - """ - if self.selection: - from_, to = sorted([self.cursor_position, self.selection.original_cursor_position]) - else: - from_, to = self.cursor_position, self.cursor_position - - return from_, to - - def selection_ranges(self): - """ - Return a list of (from, to) tuples for the selection or none if nothing - was selected. start and end position are always included in the - selection. - - This will yield several (from, to) tuples in case of a BLOCK selection. - """ - if self.selection: - from_, to = sorted([self.cursor_position, self.selection.original_cursor_position]) - - if self.selection.type == SelectionType.BLOCK: - from_line, from_column = self.translate_index_to_position(from_) - to_line, to_column = self.translate_index_to_position(to) - from_column, to_column = sorted([from_column, to_column]) - lines = self.lines - - for l in range(from_line, to_line + 1): - line_length = len(lines[l]) - if from_column < line_length: - yield (self.translate_row_col_to_index(l, from_column), - self.translate_row_col_to_index(l, min(line_length - 1, to_column))) - else: - # In case of a LINES selection, go to the start/end of the lines. - if self.selection.type == SelectionType.LINES: - from_ = max(0, self.text.rfind('\n', 0, from_) + 1) - - if self.text.find('\n', to) >= 0: - to = self.text.find('\n', to) - else: - to = len(self.text) - 1 - - yield from_, to - - def selection_range_at_line(self, row): - """ - If the selection spans a portion of the given line, return a (from, to) tuple. - Otherwise, return None. - """ - if self.selection: - row_start = self.translate_row_col_to_index(row, 0) - row_end = self.translate_row_col_to_index(row, max(0, len(self.lines[row]) - 1)) - - from_, to = sorted([self.cursor_position, self.selection.original_cursor_position]) - - # Take the intersection of the current line and the selection. - intersection_start = max(row_start, from_) - intersection_end = min(row_end, to) - - if intersection_start <= intersection_end: - if self.selection.type == SelectionType.LINES: - intersection_start = row_start - intersection_end = row_end - elif self.selection.type == SelectionType.BLOCK: - _, col1 = self.translate_index_to_position(from_) - _, col2 = self.translate_index_to_position(to) - col1, col2 = sorted([col1, col2]) - intersection_start = self.translate_row_col_to_index(row, col1) - intersection_end = self.translate_row_col_to_index(row, col2) - - _, from_column = self.translate_index_to_position(intersection_start) - _, to_column = self.translate_index_to_position(intersection_end) - - return from_column, to_column - - def cut_selection(self): - """ - Return a (:class:`.Document`, :class:`.ClipboardData`) tuple, where the - document represents the new document when the selection is cut, and the - clipboard data, represents whatever has to be put on the clipboard. - """ - if self.selection: - cut_parts = [] - remaining_parts = [] - new_cursor_position = self.cursor_position - - last_to = 0 - for from_, to in self.selection_ranges(): - if last_to == 0: - new_cursor_position = from_ - - remaining_parts.append(self.text[last_to:from_]) - cut_parts.append(self.text[from_:to + 1]) - last_to = to + 1 - - remaining_parts.append(self.text[last_to:]) - - cut_text = '\n'.join(cut_parts) - remaining_text = ''.join(remaining_parts) - - # In case of a LINES selection, don't include the trailing newline. - if self.selection.type == SelectionType.LINES and cut_text.endswith('\n'): - cut_text = cut_text[:-1] - - return (Document(text=remaining_text, cursor_position=new_cursor_position), - ClipboardData(cut_text, self.selection.type)) - else: - return self, ClipboardData('') - - def paste_clipboard_data(self, data, paste_mode=PasteMode.EMACS, count=1): - """ - Return a new :class:`.Document` instance which contains the result if - we would paste this data at the current cursor position. - - :param paste_mode: Where to paste. (Before/after/emacs.) - :param count: When >1, Paste multiple times. - """ - assert isinstance(data, ClipboardData) - assert paste_mode in (PasteMode.VI_BEFORE, PasteMode.VI_AFTER, PasteMode.EMACS) - - before = (paste_mode == PasteMode.VI_BEFORE) - after = (paste_mode == PasteMode.VI_AFTER) - - if data.type == SelectionType.CHARACTERS: - if after: - new_text = (self.text[:self.cursor_position + 1] + data.text * count + - self.text[self.cursor_position + 1:]) - else: - new_text = self.text_before_cursor + data.text * count + self.text_after_cursor - - new_cursor_position = self.cursor_position + len(data.text) * count - if before: - new_cursor_position -= 1 - - elif data.type == SelectionType.LINES: - l = self.cursor_position_row - if before: - lines = self.lines[:l] + [data.text] * count + self.lines[l:] - new_text = '\n'.join(lines) - new_cursor_position = len(''.join(self.lines[:l])) + l - else: - lines = self.lines[:l + 1] + [data.text] * count + self.lines[l + 1:] - new_cursor_position = len(''.join(self.lines[:l + 1])) + l + 1 - new_text = '\n'.join(lines) - - elif data.type == SelectionType.BLOCK: - lines = self.lines[:] - start_line = self.cursor_position_row - start_column = self.cursor_position_col + (0 if before else 1) - - for i, line in enumerate(data.text.split('\n')): - index = i + start_line - if index >= len(lines): - lines.append('') - - lines[index] = lines[index].ljust(start_column) - lines[index] = lines[index][:start_column] + line * count + lines[index][start_column:] - - new_text = '\n'.join(lines) - new_cursor_position = self.cursor_position + (0 if before else 1) - - return Document(text=new_text, cursor_position=new_cursor_position) - - def empty_line_count_at_the_end(self): - """ - Return number of empty lines at the end of the document. - """ - count = 0 - for line in self.lines[::-1]: - if not line or line.isspace(): - count += 1 - else: - break - - return count - - def start_of_paragraph(self, count=1, before=False): - """ - Return the start of the current paragraph. (Relative cursor position.) - """ - def match_func(text): - return not text or text.isspace() - - line_index = self.find_previous_matching_line(match_func=match_func, count=count) - - if line_index: - add = 0 if before else 1 - return min(0, self.get_cursor_up_position(count=-line_index) + add) - else: - return -self.cursor_position - - def end_of_paragraph(self, count=1, after=False): - """ - Return the end of the current paragraph. (Relative cursor position.) - """ - def match_func(text): - return not text or text.isspace() - - line_index = self.find_next_matching_line(match_func=match_func, count=count) - - if line_index: - add = 0 if after else 1 - return max(0, self.get_cursor_down_position(count=line_index) - add) - else: - return len(self.text_after_cursor) - - # Modifiers. - - def insert_after(self, text): - """ - Create a new document, with this text inserted after the buffer. - It keeps selection ranges and cursor position in sync. - """ - return Document( - text=self.text + text, - cursor_position=self.cursor_position, - selection=self.selection) - - def insert_before(self, text): - """ - Create a new document, with this text inserted before the buffer. - It keeps selection ranges and cursor position in sync. - """ - selection_state = self.selection - - if selection_state: - selection_state = SelectionState( - original_cursor_position=selection_state.original_cursor_position + len(text), - type=selection_state.type) - - return Document( - text=text + self.text, - cursor_position=self.cursor_position + len(text), - selection=selection_state) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py deleted file mode 100644 index 6945f44c96..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import unicode_literals - - -class IncrementalSearchDirection(object): - FORWARD = 'FORWARD' - BACKWARD = 'BACKWARD' - - -class EditingMode(object): - # The set of key bindings that is active. - VI = 'VI' - EMACS = 'EMACS' - - -#: Name of the search buffer. -SEARCH_BUFFER = 'SEARCH_BUFFER' - -#: Name of the default buffer. -DEFAULT_BUFFER = 'DEFAULT_BUFFER' - -#: Name of the system buffer. -SYSTEM_BUFFER = 'SYSTEM_BUFFER' - -# Dummy buffer. This is the buffer returned by -# `CommandLineInterface.current_buffer` when the top of the `FocusStack` is -# `None`. This could be the case when there is some widget has the focus and no -# actual text editing is possible. This buffer should also never be displayed. -# (It will never contain any actual text.) -DUMMY_BUFFER = 'DUMMY_BUFFER' diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/__init__.py +++ /dev/null diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py deleted file mode 100644 index ace2b8db49..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Eventloop for integration with Python3 asyncio. - -Note that we can't use "yield from", because the package should be installable -under Python 2.6 as well, and it should contain syntactically valid Python 2.6 -code. -""" -from __future__ import unicode_literals - -__all__ = ( - 'AsyncioTimeout', -) - - -class AsyncioTimeout(object): - """ - Call the `timeout` function when the timeout expires. - Every call of the `reset` method, resets the timeout and starts a new - timer. - """ - def __init__(self, timeout, callback, loop): - self.timeout = timeout - self.callback = callback - self.loop = loop - - self.counter = 0 - self.running = True - - def reset(self): - """ - Reset the timeout. Starts a new timer. - """ - self.counter += 1 - local_counter = self.counter - - def timer_timeout(): - if self.counter == local_counter and self.running: - self.callback() - - self.loop.call_later(self.timeout, timer_timeout) - - def stop(self): - """ - Ignore timeout. Don't call the callback anymore. - """ - self.running = False diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py deleted file mode 100644 index 426ed96f67..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py +++ /dev/null @@ -1,113 +0,0 @@ -""" -Posix asyncio event loop. -""" -from __future__ import unicode_literals - -from ..terminal.vt100_input import InputStream -from .asyncio_base import AsyncioTimeout -from .base import EventLoop, INPUT_TIMEOUT -from .callbacks import EventLoopCallbacks -from .posix_utils import PosixStdinReader - -import asyncio -import signal - -__all__ = ( - 'PosixAsyncioEventLoop', -) - - -class PosixAsyncioEventLoop(EventLoop): - def __init__(self, loop=None): - self.loop = loop or asyncio.get_event_loop() - self.closed = False - - self._stopped_f = asyncio.Future(loop=self.loop) - - @asyncio.coroutine - def run_as_coroutine(self, stdin, callbacks): - """ - The input 'event loop'. - """ - assert isinstance(callbacks, EventLoopCallbacks) - - # Create reader class. - stdin_reader = PosixStdinReader(stdin.fileno()) - - if self.closed: - raise Exception('Event loop already closed.') - - inputstream = InputStream(callbacks.feed_key) - - try: - # Create a new Future every time. - self._stopped_f = asyncio.Future(loop=self.loop) - - # Handle input timouts - def timeout_handler(): - """ - When no input has been received for INPUT_TIMEOUT seconds, - flush the input stream and fire the timeout event. - """ - inputstream.flush() - - callbacks.input_timeout() - - timeout = AsyncioTimeout(INPUT_TIMEOUT, timeout_handler, self.loop) - - # Catch sigwinch - def received_winch(): - self.call_from_executor(callbacks.terminal_size_changed) - - self.loop.add_signal_handler(signal.SIGWINCH, received_winch) - - # Read input data. - def stdin_ready(): - data = stdin_reader.read() - inputstream.feed(data) - timeout.reset() - - # Quit when the input stream was closed. - if stdin_reader.closed: - self.stop() - - self.loop.add_reader(stdin.fileno(), stdin_ready) - - # Block this coroutine until stop() has been called. - for f in self._stopped_f: - yield f - - finally: - # Clean up. - self.loop.remove_reader(stdin.fileno()) - self.loop.remove_signal_handler(signal.SIGWINCH) - - # Don't trigger any timeout events anymore. - timeout.stop() - - def stop(self): - # Trigger the 'Stop' future. - self._stopped_f.set_result(True) - - def close(self): - # Note: we should not close the asyncio loop itself, because that one - # was not created here. - self.closed = True - - def run_in_executor(self, callback): - self.loop.run_in_executor(None, callback) - - def call_from_executor(self, callback, _max_postpone_until=None): - """ - Call this function in the main event loop. - Similar to Twisted's ``callFromThread``. - """ - self.loop.call_soon_threadsafe(callback) - - def add_reader(self, fd, callback): - " Start watching the file descriptor for read availability. " - self.loop.add_reader(fd, callback) - - def remove_reader(self, fd): - " Stop watching the file descriptor for read availability. " - self.loop.remove_reader(fd) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py deleted file mode 100644 index 45f5f52679..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -Win32 asyncio event loop. - -Windows notes: -- Somehow it doesn't seem to work with the 'ProactorEventLoop'. -""" -from __future__ import unicode_literals - -from .base import EventLoop, INPUT_TIMEOUT -from ..terminal.win32_input import ConsoleInputReader -from .callbacks import EventLoopCallbacks -from .asyncio_base import AsyncioTimeout - -import asyncio - -__all__ = ( - 'Win32AsyncioEventLoop', -) - - -class Win32AsyncioEventLoop(EventLoop): - def __init__(self, loop=None): - self._console_input_reader = ConsoleInputReader() - self.running = False - self.closed = False - self.loop = loop or asyncio.get_event_loop() - - @asyncio.coroutine - def run_as_coroutine(self, stdin, callbacks): - """ - The input 'event loop'. - """ - # Note: We cannot use "yield from", because this package also - # installs on Python 2. - assert isinstance(callbacks, EventLoopCallbacks) - - if self.closed: - raise Exception('Event loop already closed.') - - timeout = AsyncioTimeout(INPUT_TIMEOUT, callbacks.input_timeout, self.loop) - self.running = True - - try: - while self.running: - timeout.reset() - - # Get keys - try: - g = iter(self.loop.run_in_executor(None, self._console_input_reader.read)) - while True: - yield next(g) - except StopIteration as e: - keys = e.args[0] - - # Feed keys to input processor. - for k in keys: - callbacks.feed_key(k) - finally: - timeout.stop() - - def stop(self): - self.running = False - - def close(self): - # Note: we should not close the asyncio loop itself, because that one - # was not created here. - self.closed = True - - self._console_input_reader.close() - - def run_in_executor(self, callback): - self.loop.run_in_executor(None, callback) - - def call_from_executor(self, callback, _max_postpone_until=None): - self.loop.call_soon_threadsafe(callback) - - def add_reader(self, fd, callback): - " Start watching the file descriptor for read availability. " - self.loop.add_reader(fd, callback) - - def remove_reader(self, fd): - " Stop watching the file descriptor for read availability. " - self.loop.remove_reader(fd) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py deleted file mode 100644 index db86face66..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py +++ /dev/null @@ -1,85 +0,0 @@ -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -__all__ = ( - 'EventLoop', - 'INPUT_TIMEOUT', -) - - -#: When to trigger the `onInputTimeout` event. -INPUT_TIMEOUT = .5 - - -class EventLoop(with_metaclass(ABCMeta, object)): - """ - Eventloop interface. - """ - def run(self, stdin, callbacks): - """ - Run the eventloop until stop() is called. Report all - input/timeout/terminal-resize events to the callbacks. - - :param stdin: :class:`~prompt_toolkit.input.Input` instance. - :param callbacks: :class:`~prompt_toolkit.eventloop.callbacks.EventLoopCallbacks` instance. - """ - raise NotImplementedError("This eventloop doesn't implement synchronous 'run()'.") - - def run_as_coroutine(self, stdin, callbacks): - """ - Similar to `run`, but this is a coroutine. (For asyncio integration.) - """ - raise NotImplementedError("This eventloop doesn't implement 'run_as_coroutine()'.") - - @abstractmethod - def stop(self): - """ - Stop the `run` call. (Normally called by - :class:`~prompt_toolkit.interface.CommandLineInterface`, when a result - is available, or Abort/Quit has been called.) - """ - - @abstractmethod - def close(self): - """ - Clean up of resources. Eventloop cannot be reused a second time after - this call. - """ - - @abstractmethod - def add_reader(self, fd, callback): - """ - Start watching the file descriptor for read availability and then call - the callback. - """ - - @abstractmethod - def remove_reader(self, fd): - """ - Stop watching the file descriptor for read availability. - """ - - @abstractmethod - def run_in_executor(self, callback): - """ - Run a long running function in a background thread. (This is - recommended for code that could block the event loop.) - Similar to Twisted's ``deferToThread``. - """ - - @abstractmethod - def call_from_executor(self, callback, _max_postpone_until=None): - """ - Call this function in the main event loop. Similar to Twisted's - ``callFromThread``. - - :param _max_postpone_until: `None` or `time.time` value. For interal - use. If the eventloop is saturated, consider this task to be low - priority and postpone maximum until this timestamp. (For instance, - repaint is done using low priority.) - - Note: In the past, this used to be a datetime.datetime instance, - but apparently, executing `time.time` is more efficient: it - does fewer system calls. (It doesn't read /etc/localtime.) - """ diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py deleted file mode 100644 index 04adab6fd4..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -__all__ = ( - 'EventLoopCallbacks', -) - - -class EventLoopCallbacks(with_metaclass(ABCMeta, object)): - """ - This is the glue between the :class:`~prompt_toolkit.eventloop.base.EventLoop` - and :class:`~prompt_toolkit.interface.CommandLineInterface`. - - :meth:`~prompt_toolkit.eventloop.base.EventLoop.run` takes an - :class:`.EventLoopCallbacks` instance and operates on that one, driving the - interface. - """ - @abstractmethod - def terminal_size_changed(self): - pass - - @abstractmethod - def input_timeout(self): - pass - - @abstractmethod - def feed_key(self, key): - pass diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py deleted file mode 100644 index bab1f4c003..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -Similar to `PyOS_InputHook` of the Python API. Some eventloops can have an -inputhook to allow easy integration with other event loops. - -When the eventloop of prompt-toolkit is idle, it can call such a hook. This -hook can call another eventloop that runs for a short while, for instance to -keep a graphical user interface responsive. - -It's the responsibility of this hook to exit when there is input ready. -There are two ways to detect when input is ready: - -- Call the `input_is_ready` method periodically. Quit when this returns `True`. - -- Add the `fileno` as a watch to the external eventloop. Quit when file descriptor - becomes readable. (But don't read from it.) - - Note that this is not the same as checking for `sys.stdin.fileno()`. The - eventloop of prompt-toolkit allows thread-based executors, for example for - asynchronous autocompletion. When the completion for instance is ready, we - also want prompt-toolkit to gain control again in order to display that. - -An alternative to using input hooks, is to create a custom `EventLoop` class that -controls everything. -""" -from __future__ import unicode_literals -import os -import threading -from prompt_toolkit.utils import is_windows -from .select import select_fds - -__all__ = ( - 'InputHookContext', -) - - -class InputHookContext(object): - """ - Given as a parameter to the inputhook. - """ - def __init__(self, inputhook): - assert callable(inputhook) - - self.inputhook = inputhook - self._input_is_ready = None - - self._r, self._w = os.pipe() - - def input_is_ready(self): - """ - Return True when the input is ready. - """ - return self._input_is_ready(wait=False) - - def fileno(self): - """ - File descriptor that will become ready when the event loop needs to go on. - """ - return self._r - - def call_inputhook(self, input_is_ready_func): - """ - Call the inputhook. (Called by a prompt-toolkit eventloop.) - """ - self._input_is_ready = input_is_ready_func - - # Start thread that activates this pipe when there is input to process. - def thread(): - input_is_ready_func(wait=True) - os.write(self._w, b'x') - - threading.Thread(target=thread).start() - - # Call inputhook. - self.inputhook(self) - - # Flush the read end of the pipe. - try: - # Before calling 'os.read', call select.select. This is required - # when the gevent monkey patch has been applied. 'os.read' is never - # monkey patched and won't be cooperative, so that would block all - # other select() calls otherwise. - # See: http://www.gevent.org/gevent.os.html - - # Note: On Windows, this is apparently not an issue. - # However, if we would ever want to add a select call, it - # should use `windll.kernel32.WaitForMultipleObjects`, - # because `select.select` can't wait for a pipe on Windows. - if not is_windows(): - select_fds([self._r], timeout=None) - - os.read(self._r, 1024) - except OSError: - # This happens when the window resizes and a SIGWINCH was received. - # We get 'Error: [Errno 4] Interrupted system call' - # Just ignore. - pass - self._input_is_ready = None - - def close(self): - """ - Clean up resources. - """ - if self._r: - os.close(self._r) - os.close(self._w) - - self._r = self._w = None diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py deleted file mode 100644 index f631dbd891..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py +++ /dev/null @@ -1,306 +0,0 @@ -from __future__ import unicode_literals -import fcntl -import os -import signal -import threading -import time - -from prompt_toolkit.terminal.vt100_input import InputStream -from prompt_toolkit.utils import DummyContext, in_main_thread -from prompt_toolkit.input import Input -from .base import EventLoop, INPUT_TIMEOUT -from .callbacks import EventLoopCallbacks -from .inputhook import InputHookContext -from .posix_utils import PosixStdinReader -from .utils import TimeIt -from .select import AutoSelector, Selector, fd_to_int - -__all__ = ( - 'PosixEventLoop', -) - -_now = time.time - - -class PosixEventLoop(EventLoop): - """ - Event loop for posix systems (Linux, Mac os X). - """ - def __init__(self, inputhook=None, selector=AutoSelector): - assert inputhook is None or callable(inputhook) - assert issubclass(selector, Selector) - - self.running = False - self.closed = False - self._running = False - self._callbacks = None - - self._calls_from_executor = [] - self._read_fds = {} # Maps fd to handler. - self.selector = selector() - - # Create a pipe for inter thread communication. - self._schedule_pipe = os.pipe() - fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK) - - # Create inputhook context. - self._inputhook_context = InputHookContext(inputhook) if inputhook else None - - def run(self, stdin, callbacks): - """ - The input 'event loop'. - """ - assert isinstance(stdin, Input) - assert isinstance(callbacks, EventLoopCallbacks) - assert not self._running - - if self.closed: - raise Exception('Event loop already closed.') - - self._running = True - self._callbacks = callbacks - - inputstream = InputStream(callbacks.feed_key) - current_timeout = [INPUT_TIMEOUT] # Nonlocal - - # Create reader class. - stdin_reader = PosixStdinReader(stdin.fileno()) - - # Only attach SIGWINCH signal handler in main thread. - # (It's not possible to attach signal handlers in other threads. In - # that case we should rely on a the main thread to call this manually - # instead.) - if in_main_thread(): - ctx = call_on_sigwinch(self.received_winch) - else: - ctx = DummyContext() - - def read_from_stdin(): - " Read user input. " - # Feed input text. - data = stdin_reader.read() - inputstream.feed(data) - - # Set timeout again. - current_timeout[0] = INPUT_TIMEOUT - - # Quit when the input stream was closed. - if stdin_reader.closed: - self.stop() - - self.add_reader(stdin, read_from_stdin) - self.add_reader(self._schedule_pipe[0], None) - - with ctx: - while self._running: - # Call inputhook. - if self._inputhook_context: - with TimeIt() as inputhook_timer: - def ready(wait): - " True when there is input ready. The inputhook should return control. " - return self._ready_for_reading(current_timeout[0] if wait else 0) != [] - self._inputhook_context.call_inputhook(ready) - inputhook_duration = inputhook_timer.duration - else: - inputhook_duration = 0 - - # Calculate remaining timeout. (The inputhook consumed some of the time.) - if current_timeout[0] is None: - remaining_timeout = None - else: - remaining_timeout = max(0, current_timeout[0] - inputhook_duration) - - # Wait until input is ready. - fds = self._ready_for_reading(remaining_timeout) - - # When any of the FDs are ready. Call the appropriate callback. - if fds: - # Create lists of high/low priority tasks. The main reason - # for this is to allow painting the UI to happen as soon as - # possible, but when there are many events happening, we - # don't want to call the UI renderer 1000x per second. If - # the eventloop is completely saturated with many CPU - # intensive tasks (like processing input/output), we say - # that drawing the UI can be postponed a little, to make - # CPU available. This will be a low priority task in that - # case. - tasks = [] - low_priority_tasks = [] - now = None # Lazy load time. (Fewer system calls.) - - for fd in fds: - # For the 'call_from_executor' fd, put each pending - # item on either the high or low priority queue. - if fd == self._schedule_pipe[0]: - for c, max_postpone_until in self._calls_from_executor: - if max_postpone_until is None: - # Execute now. - tasks.append(c) - else: - # Execute soon, if `max_postpone_until` is in the future. - now = now or _now() - if max_postpone_until < now: - tasks.append(c) - else: - low_priority_tasks.append((c, max_postpone_until)) - self._calls_from_executor = [] - - # Flush all the pipe content. - os.read(self._schedule_pipe[0], 1024) - else: - handler = self._read_fds.get(fd) - if handler: - tasks.append(handler) - - # When there are high priority tasks, run all these. - # Schedule low priority tasks for the next iteration. - if tasks: - for t in tasks: - t() - - # Postpone low priority tasks. - for t, max_postpone_until in low_priority_tasks: - self.call_from_executor(t, _max_postpone_until=max_postpone_until) - else: - # Currently there are only low priority tasks -> run them right now. - for t, _ in low_priority_tasks: - t() - - else: - # Flush all pending keys on a timeout. (This is most - # important to flush the vt100 'Escape' key early when - # nothing else follows.) - inputstream.flush() - - # Fire input timeout event. - callbacks.input_timeout() - current_timeout[0] = None - - self.remove_reader(stdin) - self.remove_reader(self._schedule_pipe[0]) - - self._callbacks = None - - def _ready_for_reading(self, timeout=None): - """ - Return the file descriptors that are ready for reading. - """ - fds = self.selector.select(timeout) - return fds - - def received_winch(self): - """ - Notify the event loop that SIGWINCH has been received - """ - # Process signal asynchronously, because this handler can write to the - # output, and doing this inside the signal handler causes easily - # reentrant calls, giving runtime errors.. - - # Furthur, this has to be thread safe. When the CommandLineInterface - # runs not in the main thread, this function still has to be called - # from the main thread. (The only place where we can install signal - # handlers.) - def process_winch(): - if self._callbacks: - self._callbacks.terminal_size_changed() - - self.call_from_executor(process_winch) - - def run_in_executor(self, callback): - """ - Run a long running function in a background thread. - (This is recommended for code that could block the event loop.) - Similar to Twisted's ``deferToThread``. - """ - # Wait until the main thread is idle. - # We start the thread by using `call_from_executor`. The event loop - # favours processing input over `calls_from_executor`, so the thread - # will not start until there is no more input to process and the main - # thread becomes idle for an instant. This is good, because Python - # threading favours CPU over I/O -- an autocompletion thread in the - # background would cause a significantly slow down of the main thread. - # It is mostly noticable when pasting large portions of text while - # having real time autocompletion while typing on. - def start_executor(): - threading.Thread(target=callback).start() - self.call_from_executor(start_executor) - - def call_from_executor(self, callback, _max_postpone_until=None): - """ - Call this function in the main event loop. - Similar to Twisted's ``callFromThread``. - - :param _max_postpone_until: `None` or `time.time` value. For interal - use. If the eventloop is saturated, consider this task to be low - priority and postpone maximum until this timestamp. (For instance, - repaint is done using low priority.) - """ - assert _max_postpone_until is None or isinstance(_max_postpone_until, float) - self._calls_from_executor.append((callback, _max_postpone_until)) - - if self._schedule_pipe: - try: - os.write(self._schedule_pipe[1], b'x') - except (AttributeError, IndexError, OSError): - # Handle race condition. We're in a different thread. - # - `_schedule_pipe` could have become None in the meantime. - # - We catch `OSError` (actually BrokenPipeError), because the - # main thread could have closed the pipe already. - pass - - def stop(self): - """ - Stop the event loop. - """ - self._running = False - - def close(self): - self.closed = True - - # Close pipes. - schedule_pipe = self._schedule_pipe - self._schedule_pipe = None - - if schedule_pipe: - os.close(schedule_pipe[0]) - os.close(schedule_pipe[1]) - - if self._inputhook_context: - self._inputhook_context.close() - - def add_reader(self, fd, callback): - " Add read file descriptor to the event loop. " - fd = fd_to_int(fd) - self._read_fds[fd] = callback - self.selector.register(fd) - - def remove_reader(self, fd): - " Remove read file descriptor from the event loop. " - fd = fd_to_int(fd) - - if fd in self._read_fds: - del self._read_fds[fd] - - self.selector.unregister(fd) - - -class call_on_sigwinch(object): - """ - Context manager which Installs a SIGWINCH callback. - (This signal occurs when the terminal size changes.) - """ - def __init__(self, callback): - self.callback = callback - self.previous_callback = None - - def __enter__(self): - self.previous_callback = signal.signal(signal.SIGWINCH, lambda *a: self.callback()) - - def __exit__(self, *a, **kw): - if self.previous_callback is None: - # Normally, `signal.signal` should never return `None`. - # For some reason it happens here: - # https://github.com/jonathanslenders/python-prompt-toolkit/pull/174 - signal.signal(signal.SIGWINCH, 0) - else: - signal.signal(signal.SIGWINCH, self.previous_callback) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py deleted file mode 100644 index 320df438ca..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py +++ /dev/null @@ -1,82 +0,0 @@ -from __future__ import unicode_literals - -from codecs import getincrementaldecoder -import os -import six - -__all__ = ( - 'PosixStdinReader', -) - - -class PosixStdinReader(object): - """ - Wrapper around stdin which reads (nonblocking) the next available 1024 - bytes and decodes it. - - Note that you can't be sure that the input file is closed if the ``read`` - function returns an empty string. When ``errors=ignore`` is passed, - ``read`` can return an empty string if all malformed input was replaced by - an empty string. (We can't block here and wait for more input.) So, because - of that, check the ``closed`` attribute, to be sure that the file has been - closed. - - :param stdin_fd: File descriptor from which we read. - :param errors: Can be 'ignore', 'strict' or 'replace'. - On Python3, this can be 'surrogateescape', which is the default. - - 'surrogateescape' is preferred, because this allows us to transfer - unrecognised bytes to the key bindings. Some terminals, like lxterminal - and Guake, use the 'Mxx' notation to send mouse events, where each 'x' - can be any possible byte. - """ - # By default, we want to 'ignore' errors here. The input stream can be full - # of junk. One occurrence of this that I had was when using iTerm2 on OS X, - # with "Option as Meta" checked (You should choose "Option as +Esc".) - - def __init__(self, stdin_fd, - errors=('ignore' if six.PY2 else 'surrogateescape')): - assert isinstance(stdin_fd, int) - self.stdin_fd = stdin_fd - self.errors = errors - - # Create incremental decoder for decoding stdin. - # We can not just do `os.read(stdin.fileno(), 1024).decode('utf-8')`, because - # it could be that we are in the middle of a utf-8 byte sequence. - self._stdin_decoder_cls = getincrementaldecoder('utf-8') - self._stdin_decoder = self._stdin_decoder_cls(errors=errors) - - #: True when there is nothing anymore to read. - self.closed = False - - def read(self, count=1024): - # By default we choose a rather small chunk size, because reading - # big amounts of input at once, causes the event loop to process - # all these key bindings also at once without going back to the - # loop. This will make the application feel unresponsive. - """ - Read the input and return it as a string. - - Return the text. Note that this can return an empty string, even when - the input stream was not yet closed. This means that something went - wrong during the decoding. - """ - if self.closed: - return b'' - - # Note: the following works better than wrapping `self.stdin` like - # `codecs.getreader('utf-8')(stdin)` and doing `read(1)`. - # Somehow that causes some latency when the escape - # character is pressed. (Especially on combination with the `select`.) - try: - data = os.read(self.stdin_fd, count) - - # Nothing more to read, stream is closed. - if data == b'': - self.closed = True - return '' - except OSError: - # In case of SIGWINCH - data = b'' - - return self._stdin_decoder.decode(data) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/select.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/select.py deleted file mode 100644 index f678f84c55..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/select.py +++ /dev/null @@ -1,216 +0,0 @@ -""" -Selectors for the Posix event loop. -""" -from __future__ import unicode_literals, absolute_import -import sys -import abc -import errno -import select -import six - -__all__ = ( - 'AutoSelector', - 'PollSelector', - 'SelectSelector', - 'Selector', - 'fd_to_int', -) - -def fd_to_int(fd): - assert isinstance(fd, int) or hasattr(fd, 'fileno') - - if isinstance(fd, int): - return fd - else: - return fd.fileno() - - -class Selector(six.with_metaclass(abc.ABCMeta, object)): - @abc.abstractmethod - def register(self, fd): - assert isinstance(fd, int) - - @abc.abstractmethod - def unregister(self, fd): - assert isinstance(fd, int) - - @abc.abstractmethod - def select(self, timeout): - pass - - @abc.abstractmethod - def close(self): - pass - - -class AutoSelector(Selector): - def __init__(self): - self._fds = [] - - self._select_selector = SelectSelector() - self._selectors = [self._select_selector] - - # When 'select.poll' exists, create a PollSelector. - if hasattr(select, 'poll'): - self._poll_selector = PollSelector() - self._selectors.append(self._poll_selector) - else: - self._poll_selector = None - - # Use of the 'select' module, that was introduced in Python3.4. We don't - # use it before 3.5 however, because this is the point where this module - # retries interrupted system calls. - if sys.version_info >= (3, 5): - self._py3_selector = Python3Selector() - self._selectors.append(self._py3_selector) - else: - self._py3_selector = None - - def register(self, fd): - assert isinstance(fd, int) - - self._fds.append(fd) - - for sel in self._selectors: - sel.register(fd) - - def unregister(self, fd): - assert isinstance(fd, int) - - self._fds.remove(fd) - - for sel in self._selectors: - sel.unregister(fd) - - def select(self, timeout): - # Try Python 3 selector first. - if self._py3_selector: - try: - return self._py3_selector.select(timeout) - except PermissionError: - # We had a situation (in pypager) where epoll raised a - # PermissionError when a local file descriptor was registered, - # however poll and select worked fine. So, in that case, just - # try using select below. - pass - - try: - # Prefer 'select.select', if we don't have much file descriptors. - # This is more universal. - return self._select_selector.select(timeout) - except ValueError: - # When we have more than 1024 open file descriptors, we'll always - # get a "ValueError: filedescriptor out of range in select()" for - # 'select'. In this case, try, using 'poll' instead. - if self._poll_selector is not None: - return self._poll_selector.select(timeout) - else: - raise - - def close(self): - for sel in self._selectors: - sel.close() - - -class Python3Selector(Selector): - """ - Use of the Python3 'selectors' module. - - NOTE: Only use on Python 3.5 or newer! - """ - def __init__(self): - assert sys.version_info >= (3, 5) - - import selectors # Inline import: Python3 only! - self._sel = selectors.DefaultSelector() - - def register(self, fd): - assert isinstance(fd, int) - import selectors # Inline import: Python3 only! - self._sel.register(fd, selectors.EVENT_READ, None) - - def unregister(self, fd): - assert isinstance(fd, int) - self._sel.unregister(fd) - - def select(self, timeout): - events = self._sel.select(timeout=timeout) - return [key.fileobj for key, mask in events] - - def close(self): - self._sel.close() - - -class PollSelector(Selector): - def __init__(self): - self._poll = select.poll() - - def register(self, fd): - assert isinstance(fd, int) - self._poll.register(fd, select.POLLIN) - - def unregister(self, fd): - assert isinstance(fd, int) - - def select(self, timeout): - tuples = self._poll.poll(timeout) # Returns (fd, event) tuples. - return [t[0] for t in tuples] - - def close(self): - pass # XXX - - -class SelectSelector(Selector): - """ - Wrapper around select.select. - - When the SIGWINCH signal is handled, other system calls, like select - are aborted in Python. This wrapper will retry the system call. - """ - def __init__(self): - self._fds = [] - - def register(self, fd): - self._fds.append(fd) - - def unregister(self, fd): - self._fds.remove(fd) - - def select(self, timeout): - while True: - try: - return select.select(self._fds, [], [], timeout)[0] - except select.error as e: - # Retry select call when EINTR - if e.args and e.args[0] == errno.EINTR: - continue - else: - raise - - def close(self): - pass - - -def select_fds(read_fds, timeout, selector=AutoSelector): - """ - Wait for a list of file descriptors (`read_fds`) to become ready for - reading. This chooses the most appropriate select-tool for use in - prompt-toolkit. - """ - # Map to ensure that we return the objects that were passed in originally. - # Whether they are a fd integer or an object that has a fileno(). - # (The 'poll' implementation for instance, returns always integers.) - fd_map = dict((fd_to_int(fd), fd) for fd in read_fds) - - # Wait, using selector. - sel = selector() - try: - for fd in read_fds: - sel.register(fd) - - result = sel.select(timeout) - - if result is not None: - return [fd_map[fd_to_int(fd)] for fd in result] - finally: - sel.close() diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py deleted file mode 100644 index ff3a4cfd69..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import unicode_literals -import time - -__all__ = ( - 'TimeIt', -) - - -class TimeIt(object): - """ - Context manager that times the duration of the code body. - The `duration` attribute will contain the execution time in seconds. - """ - def __init__(self): - self.duration = None - - def __enter__(self): - self.start = time.time() - return self - - def __exit__(self, *args): - self.end = time.time() - self.duration = self.end - self.start diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py deleted file mode 100644 index 18e356f088..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py +++ /dev/null @@ -1,187 +0,0 @@ -""" -Win32 event loop. - -Windows notes: - - Somehow it doesn't seem to work with the 'ProactorEventLoop'. -""" -from __future__ import unicode_literals - -from ..terminal.win32_input import ConsoleInputReader -from ..win32_types import SECURITY_ATTRIBUTES -from .base import EventLoop, INPUT_TIMEOUT -from .inputhook import InputHookContext -from .utils import TimeIt - -from ctypes import windll, pointer -from ctypes.wintypes import DWORD, BOOL, HANDLE - -import msvcrt -import threading - -__all__ = ( - 'Win32EventLoop', -) - -WAIT_TIMEOUT = 0x00000102 -INPUT_TIMEOUT_MS = int(1000 * INPUT_TIMEOUT) - - -class Win32EventLoop(EventLoop): - """ - Event loop for Windows systems. - - :param recognize_paste: When True, try to discover paste actions and turn - the event into a BracketedPaste. - """ - def __init__(self, inputhook=None, recognize_paste=True): - assert inputhook is None or callable(inputhook) - - self._event = HANDLE(_create_event()) - self._console_input_reader = ConsoleInputReader(recognize_paste=recognize_paste) - self._calls_from_executor = [] - - self.closed = False - self._running = False - - # Additional readers. - self._read_fds = {} # Maps fd to handler. - - # Create inputhook context. - self._inputhook_context = InputHookContext(inputhook) if inputhook else None - - def run(self, stdin, callbacks): - if self.closed: - raise Exception('Event loop already closed.') - - current_timeout = INPUT_TIMEOUT_MS - self._running = True - - while self._running: - # Call inputhook. - with TimeIt() as inputhook_timer: - if self._inputhook_context: - def ready(wait): - " True when there is input ready. The inputhook should return control. " - return bool(self._ready_for_reading(current_timeout if wait else 0)) - self._inputhook_context.call_inputhook(ready) - - # Calculate remaining timeout. (The inputhook consumed some of the time.) - if current_timeout == -1: - remaining_timeout = -1 - else: - remaining_timeout = max(0, current_timeout - int(1000 * inputhook_timer.duration)) - - # Wait for the next event. - handle = self._ready_for_reading(remaining_timeout) - - if handle == self._console_input_reader.handle.value: - # When stdin is ready, read input and reset timeout timer. - keys = self._console_input_reader.read() - for k in keys: - callbacks.feed_key(k) - current_timeout = INPUT_TIMEOUT_MS - - elif handle == self._event.value: - # When the Windows Event has been trigger, process the messages in the queue. - windll.kernel32.ResetEvent(self._event) - self._process_queued_calls_from_executor() - - elif handle in self._read_fds: - callback = self._read_fds[handle] - callback() - else: - # Fire input timeout event. - callbacks.input_timeout() - current_timeout = -1 - - def _ready_for_reading(self, timeout=None): - """ - Return the handle that is ready for reading or `None` on timeout. - """ - handles = [self._event, self._console_input_reader.handle] - handles.extend(self._read_fds.keys()) - return _wait_for_handles(handles, timeout) - - def stop(self): - self._running = False - - def close(self): - self.closed = True - - # Clean up Event object. - windll.kernel32.CloseHandle(self._event) - - if self._inputhook_context: - self._inputhook_context.close() - - self._console_input_reader.close() - - def run_in_executor(self, callback): - """ - Run a long running function in a background thread. - (This is recommended for code that could block the event loop.) - Similar to Twisted's ``deferToThread``. - """ - # Wait until the main thread is idle for an instant before starting the - # executor. (Like in eventloop/posix.py, we start the executor using - # `call_from_executor`.) - def start_executor(): - threading.Thread(target=callback).start() - self.call_from_executor(start_executor) - - def call_from_executor(self, callback, _max_postpone_until=None): - """ - Call this function in the main event loop. - Similar to Twisted's ``callFromThread``. - """ - # Append to list of pending callbacks. - self._calls_from_executor.append(callback) - - # Set Windows event. - windll.kernel32.SetEvent(self._event) - - def _process_queued_calls_from_executor(self): - # Process calls from executor. - calls_from_executor, self._calls_from_executor = self._calls_from_executor, [] - for c in calls_from_executor: - c() - - def add_reader(self, fd, callback): - " Start watching the file descriptor for read availability. " - h = msvcrt.get_osfhandle(fd) - self._read_fds[h] = callback - - def remove_reader(self, fd): - " Stop watching the file descriptor for read availability. " - h = msvcrt.get_osfhandle(fd) - if h in self._read_fds: - del self._read_fds[h] - - -def _wait_for_handles(handles, timeout=-1): - """ - Waits for multiple handles. (Similar to 'select') Returns the handle which is ready. - Returns `None` on timeout. - - http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx - """ - arrtype = HANDLE * len(handles) - handle_array = arrtype(*handles) - - ret = windll.kernel32.WaitForMultipleObjects( - len(handle_array), handle_array, BOOL(False), DWORD(timeout)) - - if ret == WAIT_TIMEOUT: - return None - else: - h = handle_array[ret] - return h - - -def _create_event(): - """ - Creates a Win32 unnamed Event . - - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx - """ - return windll.kernel32.CreateEventA(pointer(SECURITY_ATTRIBUTES()), BOOL(True), BOOL(False), None) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py deleted file mode 100644 index d3f14efc1c..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Filters decide whether something is active or not (they decide about a boolean -state). This is used to enable/disable features, like key bindings, parts of -the layout and other stuff. For instance, we could have a `HasSearch` filter -attached to some part of the layout, in order to show that part of the user -interface only while the user is searching. - -Filters are made to avoid having to attach callbacks to all event in order to -propagate state. However, they are lazy, they don't automatically propagate the -state of what they are observing. Only when a filter is called (it's actually a -callable), it will calculate its value. So, its not really reactive -programming, but it's made to fit for this framework. - -One class of filters observe a `CommandLineInterface` instance. However, they -are not attached to such an instance. (We have to pass this instance to the -filter when calling it.) The reason for this is to allow declarative -programming: for key bindings, we can attach a filter to a key binding without -knowing yet which `CommandLineInterface` instance it will observe in the end. -Examples are `HasSearch` or `IsExiting`. - -Another class of filters doesn't take anything as input. And a third class of -filters are universal, for instance `Always` and `Never`. -It is impossible to mix the first and the second class, because that would mean -mixing filters with a different signature. - -Filters can be chained using ``&`` and ``|`` operations, and inverted using the -``~`` operator, for instance:: - - filter = HasFocus('default') & ~ HasSelection() -""" -from __future__ import unicode_literals - -from .base import * -from .cli import * -from .types import * -from .utils import * diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py deleted file mode 100644 index 6a1a1d0b10..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py +++ /dev/null @@ -1,234 +0,0 @@ -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -from prompt_toolkit.utils import test_callable_args - - -__all__ = ( - 'Filter', - 'Never', - 'Always', - 'Condition', -) - - -class Filter(with_metaclass(ABCMeta, object)): - """ - Filter to activate/deactivate a feature, depending on a condition. - The return value of ``__call__`` will tell if the feature should be active. - """ - @abstractmethod - def __call__(self, *a, **kw): - """ - The actual call to evaluate the filter. - """ - return True - - def __and__(self, other): - """ - Chaining of filters using the & operator. - """ - return _and_cache[self, other] - - def __or__(self, other): - """ - Chaining of filters using the | operator. - """ - return _or_cache[self, other] - - def __invert__(self): - """ - Inverting of filters using the ~ operator. - """ - return _invert_cache[self] - - def __bool__(self): - """ - By purpose, we don't allow bool(...) operations directly on a filter, - because because the meaning is ambigue. - - Executing a filter has to be done always by calling it. Providing - defaults for `None` values should be done through an `is None` check - instead of for instance ``filter1 or Always()``. - """ - raise TypeError - - __nonzero__ = __bool__ # For Python 2. - - def test_args(self, *args): - """ - Test whether this filter can be called with the following argument list. - """ - return test_callable_args(self.__call__, args) - - -class _AndCache(dict): - """ - Cache for And operation between filters. - (Filter classes are stateless, so we can reuse them.) - - Note: This could be a memory leak if we keep creating filters at runtime. - If that is True, the filters should be weakreffed (not the tuple of - filters), and tuples should be removed when one of these filters is - removed. In practise however, there is a finite amount of filters. - """ - def __missing__(self, filters): - a, b = filters - assert isinstance(b, Filter), 'Expecting filter, got %r' % b - - if isinstance(b, Always) or isinstance(a, Never): - return a - elif isinstance(b, Never) or isinstance(a, Always): - return b - - result = _AndList(filters) - self[filters] = result - return result - - -class _OrCache(dict): - """ Cache for Or operation between filters. """ - def __missing__(self, filters): - a, b = filters - assert isinstance(b, Filter), 'Expecting filter, got %r' % b - - if isinstance(b, Always) or isinstance(a, Never): - return b - elif isinstance(b, Never) or isinstance(a, Always): - return a - - result = _OrList(filters) - self[filters] = result - return result - - -class _InvertCache(dict): - """ Cache for inversion operator. """ - def __missing__(self, filter): - result = _Invert(filter) - self[filter] = result - return result - - -_and_cache = _AndCache() -_or_cache = _OrCache() -_invert_cache = _InvertCache() - - -class _AndList(Filter): - """ - Result of &-operation between several filters. - """ - def __init__(self, filters): - all_filters = [] - - for f in filters: - if isinstance(f, _AndList): # Turn nested _AndLists into one. - all_filters.extend(f.filters) - else: - all_filters.append(f) - - self.filters = all_filters - - def test_args(self, *args): - return all(f.test_args(*args) for f in self.filters) - - def __call__(self, *a, **kw): - return all(f(*a, **kw) for f in self.filters) - - def __repr__(self): - return '&'.join(repr(f) for f in self.filters) - - -class _OrList(Filter): - """ - Result of |-operation between several filters. - """ - def __init__(self, filters): - all_filters = [] - - for f in filters: - if isinstance(f, _OrList): # Turn nested _OrLists into one. - all_filters.extend(f.filters) - else: - all_filters.append(f) - - self.filters = all_filters - - def test_args(self, *args): - return all(f.test_args(*args) for f in self.filters) - - def __call__(self, *a, **kw): - return any(f(*a, **kw) for f in self.filters) - - def __repr__(self): - return '|'.join(repr(f) for f in self.filters) - - -class _Invert(Filter): - """ - Negation of another filter. - """ - def __init__(self, filter): - self.filter = filter - - def __call__(self, *a, **kw): - return not self.filter(*a, **kw) - - def __repr__(self): - return '~%r' % self.filter - - def test_args(self, *args): - return self.filter.test_args(*args) - - -class Always(Filter): - """ - Always enable feature. - """ - def __call__(self, *a, **kw): - return True - - def __invert__(self): - return Never() - - -class Never(Filter): - """ - Never enable feature. - """ - def __call__(self, *a, **kw): - return False - - def __invert__(self): - return Always() - - -class Condition(Filter): - """ - Turn any callable (which takes a cli and returns a boolean) into a Filter. - - This can be used as a decorator:: - - @Condition - def feature_is_active(cli): # `feature_is_active` becomes a Filter. - return True - - :param func: Callable which takes either a - :class:`~prompt_toolkit.interface.CommandLineInterface` or nothing and - returns a boolean. (Depending on what it takes, this will become a - :class:`.Filter` or :class:`~prompt_toolkit.filters.CLIFilter`.) - """ - def __init__(self, func): - assert callable(func) - self.func = func - - def __call__(self, *a, **kw): - return self.func(*a, **kw) - - def __repr__(self): - return 'Condition(%r)' % self.func - - def test_args(self, *a): - return test_callable_args(self.func, a) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py deleted file mode 100644 index c0b07317be..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py +++ /dev/null @@ -1,395 +0,0 @@ -""" -Filters that accept a `CommandLineInterface` as argument. -""" -from __future__ import unicode_literals -from .base import Filter -from prompt_toolkit.enums import EditingMode -from prompt_toolkit.key_binding.vi_state import InputMode as ViInputMode -from prompt_toolkit.cache import memoized - -__all__ = ( - 'HasArg', - 'HasCompletions', - 'HasFocus', - 'InFocusStack', - 'HasSearch', - 'HasSelection', - 'HasValidationError', - 'IsAborting', - 'IsDone', - 'IsMultiline', - 'IsReadOnly', - 'IsReturning', - 'RendererHeightIsKnown', - 'InEditingMode', - - # Vi modes. - 'ViMode', - 'ViNavigationMode', - 'ViInsertMode', - 'ViInsertMultipleMode', - 'ViReplaceMode', - 'ViSelectionMode', - 'ViWaitingForTextObjectMode', - 'ViDigraphMode', - - # Emacs modes. - 'EmacsMode', - 'EmacsInsertMode', - 'EmacsSelectionMode', -) - - -@memoized() -class HasFocus(Filter): - """ - Enable when this buffer has the focus. - """ - def __init__(self, buffer_name): - self._buffer_name = buffer_name - - @property - def buffer_name(self): - " The given buffer name. (Read-only) " - return self._buffer_name - - def __call__(self, cli): - return cli.current_buffer_name == self.buffer_name - - def __repr__(self): - return 'HasFocus(%r)' % self.buffer_name - - -@memoized() -class InFocusStack(Filter): - """ - Enable when this buffer appears on the focus stack. - """ - def __init__(self, buffer_name): - self._buffer_name = buffer_name - - @property - def buffer_name(self): - " The given buffer name. (Read-only) " - return self._buffer_name - - def __call__(self, cli): - return self.buffer_name in cli.buffers.focus_stack - - def __repr__(self): - return 'InFocusStack(%r)' % self.buffer_name - - -@memoized() -class HasSelection(Filter): - """ - Enable when the current buffer has a selection. - """ - def __call__(self, cli): - return bool(cli.current_buffer.selection_state) - - def __repr__(self): - return 'HasSelection()' - - -@memoized() -class HasCompletions(Filter): - """ - Enable when the current buffer has completions. - """ - def __call__(self, cli): - return cli.current_buffer.complete_state is not None - - def __repr__(self): - return 'HasCompletions()' - - -@memoized() -class IsMultiline(Filter): - """ - Enable in multiline mode. - """ - def __call__(self, cli): - return cli.current_buffer.is_multiline() - - def __repr__(self): - return 'IsMultiline()' - - -@memoized() -class IsReadOnly(Filter): - """ - True when the current buffer is read only. - """ - def __call__(self, cli): - return cli.current_buffer.read_only() - - def __repr__(self): - return 'IsReadOnly()' - - -@memoized() -class HasValidationError(Filter): - """ - Current buffer has validation error. - """ - def __call__(self, cli): - return cli.current_buffer.validation_error is not None - - def __repr__(self): - return 'HasValidationError()' - - -@memoized() -class HasArg(Filter): - """ - Enable when the input processor has an 'arg'. - """ - def __call__(self, cli): - return cli.input_processor.arg is not None - - def __repr__(self): - return 'HasArg()' - - -@memoized() -class HasSearch(Filter): - """ - Incremental search is active. - """ - def __call__(self, cli): - return cli.is_searching - - def __repr__(self): - return 'HasSearch()' - - -@memoized() -class IsReturning(Filter): - """ - When a return value has been set. - """ - def __call__(self, cli): - return cli.is_returning - - def __repr__(self): - return 'IsReturning()' - - -@memoized() -class IsAborting(Filter): - """ - True when aborting. (E.g. Control-C pressed.) - """ - def __call__(self, cli): - return cli.is_aborting - - def __repr__(self): - return 'IsAborting()' - - -@memoized() -class IsExiting(Filter): - """ - True when exiting. (E.g. Control-D pressed.) - """ - def __call__(self, cli): - return cli.is_exiting - - def __repr__(self): - return 'IsExiting()' - - -@memoized() -class IsDone(Filter): - """ - True when the CLI is returning, aborting or exiting. - """ - def __call__(self, cli): - return cli.is_done - - def __repr__(self): - return 'IsDone()' - - -@memoized() -class RendererHeightIsKnown(Filter): - """ - Only True when the renderer knows it's real height. - - (On VT100 terminals, we have to wait for a CPR response, before we can be - sure of the available height between the cursor position and the bottom of - the terminal. And usually it's nicer to wait with drawing bottom toolbars - until we receive the height, in order to avoid flickering -- first drawing - somewhere in the middle, and then again at the bottom.) - """ - def __call__(self, cli): - return cli.renderer.height_is_known - - def __repr__(self): - return 'RendererHeightIsKnown()' - - -@memoized() -class InEditingMode(Filter): - """ - Check whether a given editing mode is active. (Vi or Emacs.) - """ - def __init__(self, editing_mode): - self._editing_mode = editing_mode - - @property - def editing_mode(self): - " The given editing mode. (Read-only) " - return self._editing_mode - - def __call__(self, cli): - return cli.editing_mode == self.editing_mode - - def __repr__(self): - return 'InEditingMode(%r)' % (self.editing_mode, ) - - -@memoized() -class ViMode(Filter): - def __call__(self, cli): - return cli.editing_mode == EditingMode.VI - - def __repr__(self): - return 'ViMode()' - - -@memoized() -class ViNavigationMode(Filter): - """ - Active when the set for Vi navigation key bindings are active. - """ - def __call__(self, cli): - if (cli.editing_mode != EditingMode.VI - or cli.vi_state.operator_func - or cli.vi_state.waiting_for_digraph - or cli.current_buffer.selection_state): - return False - - return (cli.vi_state.input_mode == ViInputMode.NAVIGATION or - cli.current_buffer.read_only()) - - def __repr__(self): - return 'ViNavigationMode()' - - -@memoized() -class ViInsertMode(Filter): - def __call__(self, cli): - if (cli.editing_mode != EditingMode.VI - or cli.vi_state.operator_func - or cli.vi_state.waiting_for_digraph - or cli.current_buffer.selection_state - or cli.current_buffer.read_only()): - return False - - return cli.vi_state.input_mode == ViInputMode.INSERT - - def __repr__(self): - return 'ViInputMode()' - - -@memoized() -class ViInsertMultipleMode(Filter): - def __call__(self, cli): - if (cli.editing_mode != EditingMode.VI - or cli.vi_state.operator_func - or cli.vi_state.waiting_for_digraph - or cli.current_buffer.selection_state - or cli.current_buffer.read_only()): - return False - - return cli.vi_state.input_mode == ViInputMode.INSERT_MULTIPLE - - def __repr__(self): - return 'ViInsertMultipleMode()' - - -@memoized() -class ViReplaceMode(Filter): - def __call__(self, cli): - if (cli.editing_mode != EditingMode.VI - or cli.vi_state.operator_func - or cli.vi_state.waiting_for_digraph - or cli.current_buffer.selection_state - or cli.current_buffer.read_only()): - return False - - return cli.vi_state.input_mode == ViInputMode.REPLACE - - def __repr__(self): - return 'ViReplaceMode()' - - -@memoized() -class ViSelectionMode(Filter): - def __call__(self, cli): - if cli.editing_mode != EditingMode.VI: - return False - - return bool(cli.current_buffer.selection_state) - - def __repr__(self): - return 'ViSelectionMode()' - - -@memoized() -class ViWaitingForTextObjectMode(Filter): - def __call__(self, cli): - if cli.editing_mode != EditingMode.VI: - return False - - return cli.vi_state.operator_func is not None - - def __repr__(self): - return 'ViWaitingForTextObjectMode()' - - -@memoized() -class ViDigraphMode(Filter): - def __call__(self, cli): - if cli.editing_mode != EditingMode.VI: - return False - - return cli.vi_state.waiting_for_digraph - - def __repr__(self): - return 'ViDigraphMode()' - - -@memoized() -class EmacsMode(Filter): - " When the Emacs bindings are active. " - def __call__(self, cli): - return cli.editing_mode == EditingMode.EMACS - - def __repr__(self): - return 'EmacsMode()' - - -@memoized() -class EmacsInsertMode(Filter): - def __call__(self, cli): - if (cli.editing_mode != EditingMode.EMACS - or cli.current_buffer.selection_state - or cli.current_buffer.read_only()): - return False - return True - - def __repr__(self): - return 'EmacsInsertMode()' - - -@memoized() -class EmacsSelectionMode(Filter): - def __call__(self, cli): - return (cli.editing_mode == EditingMode.EMACS - and cli.current_buffer.selection_state) - - def __repr__(self): - return 'EmacsSelectionMode()' diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py deleted file mode 100644 index 3e89c39c01..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import unicode_literals -from six import with_metaclass -from collections import defaultdict -import weakref - -__all__ = ( - 'CLIFilter', - 'SimpleFilter', -) - -# Cache for _FilterTypeMeta. (Don't test the same __instancecheck__ twice as -# long as the object lives. -- We do this a lot and calling 'test_args' is -# expensive.) -_instance_check_cache = defaultdict(weakref.WeakKeyDictionary) - - -class _FilterTypeMeta(type): - def __instancecheck__(cls, instance): - cache = _instance_check_cache[tuple(cls.arguments_list)] - - def get(): - " The actual test. " - if not hasattr(instance, 'test_args'): - return False - return instance.test_args(*cls.arguments_list) - - try: - return cache[instance] - except KeyError: - result = get() - cache[instance] = result - return result - - -class _FilterType(with_metaclass(_FilterTypeMeta)): - def __new__(cls): - raise NotImplementedError('This class should not be initiated.') - - -class CLIFilter(_FilterType): - """ - Abstract base class for filters that accept a - :class:`~prompt_toolkit.interface.CommandLineInterface` argument. It cannot - be instantiated, it's only to be used for instance assertions, e.g.:: - - isinstance(my_filter, CliFilter) - """ - arguments_list = ['cli'] - - -class SimpleFilter(_FilterType): - """ - Abstract base class for filters that don't accept any arguments. - """ - arguments_list = [] diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py deleted file mode 100644 index 836d2956e7..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import unicode_literals -from .base import Always, Never -from .types import SimpleFilter, CLIFilter - -__all__ = ( - 'to_cli_filter', - 'to_simple_filter', -) - -_always = Always() -_never = Never() - - -def to_simple_filter(bool_or_filter): - """ - Accept both booleans and CLIFilters as input and - turn it into a SimpleFilter. - """ - if not isinstance(bool_or_filter, (bool, SimpleFilter)): - raise TypeError('Expecting a bool or a SimpleFilter instance. Got %r' % bool_or_filter) - - return { - True: _always, - False: _never, - }.get(bool_or_filter, bool_or_filter) - - -def to_cli_filter(bool_or_filter): - """ - Accept both booleans and CLIFilters as input and - turn it into a CLIFilter. - """ - if not isinstance(bool_or_filter, (bool, CLIFilter)): - raise TypeError('Expecting a bool or a CLIFilter instance. Got %r' % bool_or_filter) - - return { - True: _always, - False: _never, - }.get(bool_or_filter, bool_or_filter) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py deleted file mode 100644 index d1eb5f2730..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py +++ /dev/null @@ -1,120 +0,0 @@ -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -import datetime -import os - -__all__ = ( - 'FileHistory', - 'History', - 'InMemoryHistory', -) - - -class History(with_metaclass(ABCMeta, object)): - """ - Base ``History`` interface. - """ - @abstractmethod - def append(self, string): - " Append string to history. " - - @abstractmethod - def __getitem__(self, key): - " Return one item of the history. It should be accessible like a `list`. " - - @abstractmethod - def __iter__(self): - " Iterate through all the items of the history. Cronologically. " - - @abstractmethod - def __len__(self): - " Return the length of the history. " - - def __bool__(self): - """ - Never evaluate to False, even when the history is empty. - (Python calls __len__ if __bool__ is not implemented.) - This is mainly to allow lazy evaluation:: - - x = history or InMemoryHistory() - """ - return True - - __nonzero__ = __bool__ # For Python 2. - - -class InMemoryHistory(History): - """ - :class:`.History` class that keeps a list of all strings in memory. - """ - def __init__(self): - self.strings = [] - - def append(self, string): - self.strings.append(string) - - def __getitem__(self, key): - return self.strings[key] - - def __iter__(self): - return iter(self.strings) - - def __len__(self): - return len(self.strings) - - -class FileHistory(History): - """ - :class:`.History` class that stores all strings in a file. - """ - def __init__(self, filename): - self.strings = [] - self.filename = filename - - self._load() - - def _load(self): - lines = [] - - def add(): - if lines: - # Join and drop trailing newline. - string = ''.join(lines)[:-1] - - self.strings.append(string) - - if os.path.exists(self.filename): - with open(self.filename, 'rb') as f: - for line in f: - line = line.decode('utf-8') - - if line.startswith('+'): - lines.append(line[1:]) - else: - add() - lines = [] - - add() - - def append(self, string): - self.strings.append(string) - - # Save to file. - with open(self.filename, 'ab') as f: - def write(t): - f.write(t.encode('utf-8')) - - write('\n# %s\n' % datetime.datetime.now()) - for line in string.split('\n'): - write('+%s\n' % line) - - def __getitem__(self, key): - return self.strings[key] - - def __iter__(self): - return iter(self.strings) - - def __len__(self): - return len(self.strings) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py deleted file mode 100644 index f123732560..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py +++ /dev/null @@ -1,135 +0,0 @@ -""" -Abstraction of CLI Input. -""" -from __future__ import unicode_literals - -from .utils import DummyContext, is_windows -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -import io -import os -import sys - -if is_windows(): - from .terminal.win32_input import raw_mode, cooked_mode -else: - from .terminal.vt100_input import raw_mode, cooked_mode - -__all__ = ( - 'Input', - 'StdinInput', - 'PipeInput', -) - - -class Input(with_metaclass(ABCMeta, object)): - """ - Abstraction for any input. - - An instance of this class can be given to the constructor of a - :class:`~prompt_toolkit.interface.CommandLineInterface` and will also be - passed to the :class:`~prompt_toolkit.eventloop.base.EventLoop`. - """ - @abstractmethod - def fileno(self): - """ - Fileno for putting this in an event loop. - """ - - @abstractmethod - def read(self): - """ - Return text from the input. - """ - - @abstractmethod - def raw_mode(self): - """ - Context manager that turns the input into raw mode. - """ - - @abstractmethod - def cooked_mode(self): - """ - Context manager that turns the input into cooked mode. - """ - - -class StdinInput(Input): - """ - Simple wrapper around stdin. - """ - def __init__(self, stdin=None): - self.stdin = stdin or sys.stdin - - # The input object should be a TTY. - assert self.stdin.isatty() - - # Test whether the given input object has a file descriptor. - # (Idle reports stdin to be a TTY, but fileno() is not implemented.) - try: - # This should not raise, but can return 0. - self.stdin.fileno() - except io.UnsupportedOperation: - if 'idlelib.run' in sys.modules: - raise io.UnsupportedOperation( - 'Stdin is not a terminal. Running from Idle is not supported.') - else: - raise io.UnsupportedOperation('Stdin is not a terminal.') - - def __repr__(self): - return 'StdinInput(stdin=%r)' % (self.stdin,) - - def raw_mode(self): - return raw_mode(self.stdin.fileno()) - - def cooked_mode(self): - return cooked_mode(self.stdin.fileno()) - - def fileno(self): - return self.stdin.fileno() - - def read(self): - return self.stdin.read() - - -class PipeInput(Input): - """ - Input that is send through a pipe. - This is useful if we want to send the input programatically into the - interface, but still use the eventloop. - - Usage:: - - input = PipeInput() - input.send('inputdata') - """ - def __init__(self): - self._r, self._w = os.pipe() - - def fileno(self): - return self._r - - def read(self): - return os.read(self._r) - - def send_text(self, data): - " Send text to the input. " - os.write(self._w, data.encode('utf-8')) - - # Deprecated alias for `send_text`. - send = send_text - - def raw_mode(self): - return DummyContext() - - def cooked_mode(self): - return DummyContext() - - def close(self): - " Close pipe fds. " - os.close(self._r) - os.close(self._w) - self._r = None - self._w = None diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py deleted file mode 100644 index e1e0e56393..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py +++ /dev/null @@ -1,1190 +0,0 @@ -""" -The main `CommandLineInterface` class and logic. -""" -from __future__ import unicode_literals - -import functools -import os -import signal -import six -import sys -import textwrap -import threading -import time -import types -import weakref - -from subprocess import Popen - -from .application import Application, AbortAction -from .buffer import Buffer -from .buffer_mapping import BufferMapping -from .completion import CompleteEvent, get_common_complete_suffix -from .enums import SEARCH_BUFFER -from .eventloop.base import EventLoop -from .eventloop.callbacks import EventLoopCallbacks -from .filters import Condition -from .input import StdinInput, Input -from .key_binding.input_processor import InputProcessor -from .key_binding.input_processor import KeyPress -from .key_binding.registry import Registry -from .key_binding.vi_state import ViState -from .keys import Keys -from .output import Output -from .renderer import Renderer, print_tokens -from .search_state import SearchState -from .utils import Event - -# Following import is required for backwards compatibility. -from .buffer import AcceptAction - -__all__ = ( - 'AbortAction', - 'CommandLineInterface', -) - - -class CommandLineInterface(object): - """ - Wrapper around all the other classes, tying everything together. - - Typical usage:: - - application = Application(...) - cli = CommandLineInterface(application, eventloop) - result = cli.run() - print(result) - - :param application: :class:`~prompt_toolkit.application.Application` instance. - :param eventloop: The :class:`~prompt_toolkit.eventloop.base.EventLoop` to - be used when `run` is called. The easiest way to create - an eventloop is by calling - :meth:`~prompt_toolkit.shortcuts.create_eventloop`. - :param input: :class:`~prompt_toolkit.input.Input` instance. - :param output: :class:`~prompt_toolkit.output.Output` instance. (Probably - Vt100_Output or Win32Output.) - """ - def __init__(self, application, eventloop=None, input=None, output=None): - assert isinstance(application, Application) - assert isinstance(eventloop, EventLoop), 'Passing an eventloop is required.' - assert output is None or isinstance(output, Output) - assert input is None or isinstance(input, Input) - - from .shortcuts import create_output - - self.application = application - self.eventloop = eventloop - self._is_running = False - - # Inputs and outputs. - self.output = output or create_output() - self.input = input or StdinInput(sys.stdin) - - #: The input buffers. - assert isinstance(application.buffers, BufferMapping) - self.buffers = application.buffers - - #: EditingMode.VI or EditingMode.EMACS - self.editing_mode = application.editing_mode - - #: Quoted insert. This flag is set if we go into quoted insert mode. - self.quoted_insert = False - - #: Vi state. (For Vi key bindings.) - self.vi_state = ViState() - - #: The `Renderer` instance. - # Make sure that the same stdout is used, when a custom renderer has been passed. - self.renderer = Renderer( - self.application.style, - self.output, - use_alternate_screen=application.use_alternate_screen, - mouse_support=application.mouse_support) - - #: Render counter. This one is increased every time the UI is rendered. - #: It can be used as a key for caching certain information during one - #: rendering. - self.render_counter = 0 - - #: When there is high CPU, postpone the renderering max x seconds. - #: '0' means: don't postpone. '.5' means: try to draw at least twice a second. - self.max_render_postpone_time = 0 # E.g. .5 - - # Invalidate flag. When 'True', a repaint has been scheduled. - self._invalidated = False - - #: The `InputProcessor` instance. - self.input_processor = InputProcessor(application.key_bindings_registry, weakref.ref(self)) - - self._async_completers = {} # Map buffer name to completer function. - - # Pointer to sub CLI. (In chain of CLI instances.) - self._sub_cli = None # None or other CommandLineInterface instance. - - # Call `add_buffer` for each buffer. - for name, b in self.buffers.items(): - self.add_buffer(name, b) - - # Events. - self.on_buffer_changed = Event(self, application.on_buffer_changed) - self.on_initialize = Event(self, application.on_initialize) - self.on_input_timeout = Event(self, application.on_input_timeout) - self.on_invalidate = Event(self, application.on_invalidate) - self.on_render = Event(self, application.on_render) - self.on_reset = Event(self, application.on_reset) - self.on_start = Event(self, application.on_start) - self.on_stop = Event(self, application.on_stop) - - # Trigger initialize callback. - self.reset() - self.on_initialize += self.application.on_initialize - self.on_initialize.fire() - - @property - def layout(self): - return self.application.layout - - @property - def clipboard(self): - return self.application.clipboard - - @property - def pre_run_callables(self): - return self.application.pre_run_callables - - def add_buffer(self, name, buffer, focus=False): - """ - Insert a new buffer. - """ - assert isinstance(buffer, Buffer) - self.buffers[name] = buffer - - if focus: - self.buffers.focus(name) - - # Create asynchronous completer / auto suggestion. - auto_suggest_function = self._create_auto_suggest_function(buffer) - completer_function = self._create_async_completer(buffer) - self._async_completers[name] = completer_function - - # Complete/suggest on text insert. - def create_on_insert_handler(): - """ - Wrapper around the asynchronous completer and auto suggestion, that - ensures that it's only called while typing if the - `complete_while_typing` filter is enabled. - """ - def on_text_insert(_): - # Only complete when "complete_while_typing" is enabled. - if buffer.completer and buffer.complete_while_typing(): - completer_function() - - # Call auto_suggest. - if buffer.auto_suggest: - auto_suggest_function() - - return on_text_insert - - buffer.on_text_insert += create_on_insert_handler() - - def buffer_changed(_): - """ - When the text in a buffer changes. - (A paste event is also a change, but not an insert. So we don't - want to do autocompletions in this case, but we want to propagate - the on_buffer_changed event.) - """ - # Trigger on_buffer_changed. - self.on_buffer_changed.fire() - - buffer.on_text_changed += buffer_changed - - def start_completion(self, buffer_name=None, select_first=False, - select_last=False, insert_common_part=False, - complete_event=None): - """ - Start asynchronous autocompletion of this buffer. - (This will do nothing if a previous completion was still in progress.) - """ - buffer_name = buffer_name or self.current_buffer_name - completer = self._async_completers.get(buffer_name) - - if completer: - completer(select_first=select_first, - select_last=select_last, - insert_common_part=insert_common_part, - complete_event=CompleteEvent(completion_requested=True)) - - @property - def current_buffer_name(self): - """ - The name of the current :class:`.Buffer`. (Or `None`.) - """ - return self.buffers.current_name(self) - - @property - def current_buffer(self): - """ - The currently focussed :class:`~.Buffer`. - - (This returns a dummy :class:`.Buffer` when none of the actual buffers - has the focus. In this case, it's really not practical to check for - `None` values or catch exceptions every time.) - """ - return self.buffers.current(self) - - def focus(self, buffer_name): - """ - Focus the buffer with the given name on the focus stack. - """ - self.buffers.focus(self, buffer_name) - - def push_focus(self, buffer_name): - """ - Push to the focus stack. - """ - self.buffers.push_focus(self, buffer_name) - - def pop_focus(self): - """ - Pop from the focus stack. - """ - self.buffers.pop_focus(self) - - @property - def terminal_title(self): - """ - Return the current title to be displayed in the terminal. - When this in `None`, the terminal title remains the original. - """ - result = self.application.get_title() - - # Make sure that this function returns a unicode object, - # and not a byte string. - assert result is None or isinstance(result, six.text_type) - return result - - @property - def is_searching(self): - """ - True when we are searching. - """ - return self.current_buffer_name == SEARCH_BUFFER - - def reset(self, reset_current_buffer=False): - """ - Reset everything, for reading the next input. - - :param reset_current_buffer: XXX: not used anymore. The reason for - having this option in the past was when this CommandLineInterface - is run multiple times, that we could reset the buffer content from - the previous run. This is now handled in the AcceptAction. - """ - # Notice that we don't reset the buffers. (This happens just before - # returning, and when we have multiple buffers, we clearly want the - # content in the other buffers to remain unchanged between several - # calls of `run`. (And the same is true for the focus stack.) - - self._exit_flag = False - self._abort_flag = False - - self._return_value = None - - self.renderer.reset() - self.input_processor.reset() - self.layout.reset() - self.vi_state.reset() - - # Search new search state. (Does also remember what has to be - # highlighted.) - self.search_state = SearchState(ignore_case=Condition(lambda: self.is_ignoring_case)) - - # Trigger reset event. - self.on_reset.fire() - - @property - def in_paste_mode(self): - """ True when we are in paste mode. """ - return self.application.paste_mode(self) - - @property - def is_ignoring_case(self): - """ True when we currently ignore casing. """ - return self.application.ignore_case(self) - - def invalidate(self): - """ - Thread safe way of sending a repaint trigger to the input event loop. - """ - # Never schedule a second redraw, when a previous one has not yet been - # executed. (This should protect against other threads calling - # 'invalidate' many times, resulting in 100% CPU.) - if self._invalidated: - return - else: - self._invalidated = True - - # Trigger event. - self.on_invalidate.fire() - - if self.eventloop is not None: - def redraw(): - self._invalidated = False - self._redraw() - - # Call redraw in the eventloop (thread safe). - # Usually with the high priority, in order to make the application - # feel responsive, but this can be tuned by changing the value of - # `max_render_postpone_time`. - if self.max_render_postpone_time: - _max_postpone_until = time.time() + self.max_render_postpone_time - else: - _max_postpone_until = None - - self.eventloop.call_from_executor( - redraw, _max_postpone_until=_max_postpone_until) - - # Depracated alias for 'invalidate'. - request_redraw = invalidate - - def _redraw(self): - """ - Render the command line again. (Not thread safe!) (From other threads, - or if unsure, use :meth:`.CommandLineInterface.invalidate`.) - """ - # Only draw when no sub application was started. - if self._is_running and self._sub_cli is None: - self.render_counter += 1 - self.renderer.render(self, self.layout, is_done=self.is_done) - - # Fire render event. - self.on_render.fire() - - def _on_resize(self): - """ - When the window size changes, we erase the current output and request - again the cursor position. When the CPR answer arrives, the output is - drawn again. - """ - # Erase, request position (when cursor is at the start position) - # and redraw again. -- The order is important. - self.renderer.erase(leave_alternate_screen=False, erase_title=False) - self.renderer.request_absolute_cursor_position() - self._redraw() - - def _load_next_buffer_indexes(self): - for buff, index in self._next_buffer_indexes.items(): - if buff in self.buffers: - self.buffers[buff].working_index = index - - def _pre_run(self, pre_run=None): - " Called during `run`. " - if pre_run: - pre_run() - - # Process registered "pre_run_callables" and clear list. - for c in self.pre_run_callables: - c() - del self.pre_run_callables[:] - - def run(self, reset_current_buffer=False, pre_run=None): - """ - Read input from the command line. - This runs the eventloop until a return value has been set. - - :param reset_current_buffer: XXX: Not used anymore. - :param pre_run: Callable that is called right after the reset has taken - place. This allows custom initialisation. - """ - assert pre_run is None or callable(pre_run) - - try: - self._is_running = True - - self.on_start.fire() - self.reset() - - # Call pre_run. - self._pre_run(pre_run) - - # Run eventloop in raw mode. - with self.input.raw_mode(): - self.renderer.request_absolute_cursor_position() - self._redraw() - - self.eventloop.run(self.input, self.create_eventloop_callbacks()) - finally: - # Clean up renderer. (This will leave the alternate screen, if we use - # that.) - - # If exit/abort haven't been called set, but another exception was - # thrown instead for some reason, make sure that we redraw in exit - # mode. - if not self.is_done: - self._exit_flag = True - self._redraw() - - self.renderer.reset() - self.on_stop.fire() - self._is_running = False - - # Return result. - return self.return_value() - - try: - # The following `run_async` function is compiled at runtime - # because it contains syntax which is not supported on older Python - # versions. (A 'return' inside a generator.) - six.exec_(textwrap.dedent(''' - def run_async(self, reset_current_buffer=True, pre_run=None): - """ - Same as `run`, but this returns a coroutine. - - This is only available on Python >3.3, with asyncio. - """ - # Inline import, because it slows down startup when asyncio is not - # needed. - import asyncio - - @asyncio.coroutine - def run(): - assert pre_run is None or callable(pre_run) - - try: - self._is_running = True - - self.on_start.fire() - self.reset() - - # Call pre_run. - self._pre_run(pre_run) - - with self.input.raw_mode(): - self.renderer.request_absolute_cursor_position() - self._redraw() - - yield from self.eventloop.run_as_coroutine( - self.input, self.create_eventloop_callbacks()) - - return self.return_value() - finally: - if not self.is_done: - self._exit_flag = True - self._redraw() - - self.renderer.reset() - self.on_stop.fire() - self._is_running = False - - return run() - ''')) - except SyntaxError: - # Python2, or early versions of Python 3. - def run_async(self, reset_current_buffer=True, pre_run=None): - """ - Same as `run`, but this returns a coroutine. - - This is only available on Python >3.3, with asyncio. - """ - raise NotImplementedError - - def run_sub_application(self, application, done_callback=None, erase_when_done=False, - _from_application_generator=False): - # `erase_when_done` is deprecated, set Application.erase_when_done instead. - """ - Run a sub :class:`~prompt_toolkit.application.Application`. - - This will suspend the main application and display the sub application - until that one returns a value. The value is returned by calling - `done_callback` with the result. - - The sub application will share the same I/O of the main application. - That means, it uses the same input and output channels and it shares - the same event loop. - - .. note:: Technically, it gets another Eventloop instance, but that is - only a proxy to our main event loop. The reason is that calling - 'stop' --which returns the result of an application when it's - done-- is handled differently. - """ - assert isinstance(application, Application) - assert done_callback is None or callable(done_callback) - - if self._sub_cli is not None: - raise RuntimeError('Another sub application started already.') - - # Erase current application. - if not _from_application_generator: - self.renderer.erase() - - # Callback when the sub app is done. - def done(): - # Redraw sub app in done state. - # and reset the renderer. (This reset will also quit the alternate - # screen, if the sub application used that.) - sub_cli._redraw() - if erase_when_done or application.erase_when_done: - sub_cli.renderer.erase() - sub_cli.renderer.reset() - sub_cli._is_running = False # Don't render anymore. - - self._sub_cli = None - - # Restore main application. - if not _from_application_generator: - self.renderer.request_absolute_cursor_position() - self._redraw() - - # Deliver result. - if done_callback: - done_callback(sub_cli.return_value()) - - # Create sub CommandLineInterface. - sub_cli = CommandLineInterface( - application=application, - eventloop=_SubApplicationEventLoop(self, done), - input=self.input, - output=self.output) - sub_cli._is_running = True # Allow rendering of sub app. - - sub_cli._redraw() - self._sub_cli = sub_cli - - def exit(self): - """ - Set exit. When Control-D has been pressed. - """ - on_exit = self.application.on_exit - self._exit_flag = True - self._redraw() - - if on_exit == AbortAction.RAISE_EXCEPTION: - def eof_error(): - raise EOFError() - self._set_return_callable(eof_error) - - elif on_exit == AbortAction.RETRY: - self.reset() - self.renderer.request_absolute_cursor_position() - self.current_buffer.reset() - - elif on_exit == AbortAction.RETURN_NONE: - self.set_return_value(None) - - def abort(self): - """ - Set abort. When Control-C has been pressed. - """ - on_abort = self.application.on_abort - self._abort_flag = True - self._redraw() - - if on_abort == AbortAction.RAISE_EXCEPTION: - def keyboard_interrupt(): - raise KeyboardInterrupt() - self._set_return_callable(keyboard_interrupt) - - elif on_abort == AbortAction.RETRY: - self.reset() - self.renderer.request_absolute_cursor_position() - self.current_buffer.reset() - - elif on_abort == AbortAction.RETURN_NONE: - self.set_return_value(None) - - # Deprecated aliase for exit/abort. - set_exit = exit - set_abort = abort - - def set_return_value(self, document): - """ - Set a return value. The eventloop can retrieve the result it by calling - `return_value`. - """ - self._set_return_callable(lambda: document) - self._redraw() # Redraw in "done" state, after the return value has been set. - - def _set_return_callable(self, value): - assert callable(value) - self._return_value = value - - if self.eventloop: - self.eventloop.stop() - - def run_in_terminal(self, func, render_cli_done=False, cooked_mode=True): - """ - Run function on the terminal above the prompt. - - What this does is first hiding the prompt, then running this callable - (which can safely output to the terminal), and then again rendering the - prompt which causes the output of this function to scroll above the - prompt. - - :param func: The callable to execute. - :param render_cli_done: When True, render the interface in the - 'Done' state first, then execute the function. If False, - erase the interface first. - :param cooked_mode: When True (the default), switch the input to - cooked mode while executing the function. - - :returns: the result of `func`. - """ - # Draw interface in 'done' state, or erase. - if render_cli_done: - self._return_value = True - self._redraw() - self.renderer.reset() # Make sure to disable mouse mode, etc... - else: - self.renderer.erase() - self._return_value = None - - # Run system command. - if cooked_mode: - with self.input.cooked_mode(): - result = func() - else: - result = func() - - # Redraw interface again. - self.renderer.reset() - self.renderer.request_absolute_cursor_position() - self._redraw() - - return result - - def run_application_generator(self, coroutine, render_cli_done=False): - """ - EXPERIMENTAL - Like `run_in_terminal`, but takes a generator that can yield Application instances. - - Example: - - def f(): - yield Application1(...) - print('...') - yield Application2(...) - cli.run_in_terminal_async(f) - - The values which are yielded by the given coroutine are supposed to be - `Application` instances that run in the current CLI, all other code is - supposed to be CPU bound, so except for yielding the applications, - there should not be any user interaction or I/O in the given function. - """ - # Draw interface in 'done' state, or erase. - if render_cli_done: - self._return_value = True - self._redraw() - self.renderer.reset() # Make sure to disable mouse mode, etc... - else: - self.renderer.erase() - self._return_value = None - - # Loop through the generator. - g = coroutine() - assert isinstance(g, types.GeneratorType) - - def step_next(send_value=None): - " Execute next step of the coroutine." - try: - # Run until next yield, in cooked mode. - with self.input.cooked_mode(): - result = g.send(send_value) - except StopIteration: - done() - except: - done() - raise - else: - # Process yielded value from coroutine. - assert isinstance(result, Application) - self.run_sub_application(result, done_callback=step_next, - _from_application_generator=True) - - def done(): - # Redraw interface again. - self.renderer.reset() - self.renderer.request_absolute_cursor_position() - self._redraw() - - # Start processing coroutine. - step_next() - - def run_system_command(self, command): - """ - Run system command (While hiding the prompt. When finished, all the - output will scroll above the prompt.) - - :param command: Shell command to be executed. - """ - def wait_for_enter(): - """ - Create a sub application to wait for the enter key press. - This has two advantages over using 'input'/'raw_input': - - This will share the same input/output I/O. - - This doesn't block the event loop. - """ - from .shortcuts import create_prompt_application - - registry = Registry() - - @registry.add_binding(Keys.ControlJ) - @registry.add_binding(Keys.ControlM) - def _(event): - event.cli.set_return_value(None) - - application = create_prompt_application( - message='Press ENTER to continue...', - key_bindings_registry=registry) - self.run_sub_application(application) - - def run(): - # Try to use the same input/output file descriptors as the one, - # used to run this application. - try: - input_fd = self.input.fileno() - except AttributeError: - input_fd = sys.stdin.fileno() - try: - output_fd = self.output.fileno() - except AttributeError: - output_fd = sys.stdout.fileno() - - # Run sub process. - # XXX: This will still block the event loop. - p = Popen(command, shell=True, - stdin=input_fd, stdout=output_fd) - p.wait() - - # Wait for the user to press enter. - wait_for_enter() - - self.run_in_terminal(run) - - def suspend_to_background(self, suspend_group=True): - """ - (Not thread safe -- to be called from inside the key bindings.) - Suspend process. - - :param suspend_group: When true, suspend the whole process group. - (This is the default, and probably what you want.) - """ - # Only suspend when the opperating system supports it. - # (Not on Windows.) - if hasattr(signal, 'SIGTSTP'): - def run(): - # Send `SIGSTP` to own process. - # This will cause it to suspend. - - # Usually we want the whole process group to be suspended. This - # handles the case when input is piped from another process. - if suspend_group: - os.kill(0, signal.SIGTSTP) - else: - os.kill(os.getpid(), signal.SIGTSTP) - - self.run_in_terminal(run) - - def print_tokens(self, tokens, style=None): - """ - Print a list of (Token, text) tuples to the output. - (When the UI is running, this method has to be called through - `run_in_terminal`, otherwise it will destroy the UI.) - - :param style: Style class to use. Defaults to the active style in the CLI. - """ - print_tokens(self.output, tokens, style or self.application.style) - - @property - def is_exiting(self): - """ - ``True`` when the exit flag as been set. - """ - return self._exit_flag - - @property - def is_aborting(self): - """ - ``True`` when the abort flag as been set. - """ - return self._abort_flag - - @property - def is_returning(self): - """ - ``True`` when a return value has been set. - """ - return self._return_value is not None - - def return_value(self): - """ - Get the return value. Not that this method can throw an exception. - """ - # Note that it's a method, not a property, because it can throw - # exceptions. - if self._return_value: - return self._return_value() - - @property - def is_done(self): - return self.is_exiting or self.is_aborting or self.is_returning - - def _create_async_completer(self, buffer): - """ - Create function for asynchronous autocompletion. - (Autocomplete in other thread.) - """ - complete_thread_running = [False] # By ref. - - def completion_does_nothing(document, completion): - """ - Return `True` if applying this completion doesn't have any effect. - (When it doesn't insert any new text. - """ - text_before_cursor = document.text_before_cursor - replaced_text = text_before_cursor[ - len(text_before_cursor) + completion.start_position:] - return replaced_text == completion.text - - def async_completer(select_first=False, select_last=False, - insert_common_part=False, complete_event=None): - document = buffer.document - complete_event = complete_event or CompleteEvent(text_inserted=True) - - # Don't start two threads at the same time. - if complete_thread_running[0]: - return - - # Don't complete when we already have completions. - if buffer.complete_state or not buffer.completer: - return - - # Otherwise, get completions in other thread. - complete_thread_running[0] = True - - def run(): - completions = list(buffer.completer.get_completions(document, complete_event)) - - def callback(): - """ - Set the new complete_state in a safe way. Don't replace an - existing complete_state if we had one. (The user could have - pressed 'Tab' in the meantime. Also don't set it if the text - was changed in the meantime. - """ - complete_thread_running[0] = False - - # When there is only one completion, which has nothing to add, ignore it. - if (len(completions) == 1 and - completion_does_nothing(document, completions[0])): - del completions[:] - - # Set completions if the text was not yet changed. - if buffer.text == document.text and \ - buffer.cursor_position == document.cursor_position and \ - not buffer.complete_state: - - set_completions = True - select_first_anyway = False - - # When the common part has to be inserted, and there - # is a common part. - if insert_common_part: - common_part = get_common_complete_suffix(document, completions) - if common_part: - # Insert the common part, update completions. - buffer.insert_text(common_part) - if len(completions) > 1: - # (Don't call `async_completer` again, but - # recalculate completions. See: - # https://github.com/ipython/ipython/issues/9658) - completions[:] = [ - c.new_completion_from_position(len(common_part)) - for c in completions] - else: - set_completions = False - else: - # When we were asked to insert the "common" - # prefix, but there was no common suffix but - # still exactly one match, then select the - # first. (It could be that we have a completion - # which does * expansion, like '*.py', with - # exactly one match.) - if len(completions) == 1: - select_first_anyway = True - - if set_completions: - buffer.set_completions( - completions=completions, - go_to_first=select_first or select_first_anyway, - go_to_last=select_last) - self.invalidate() - elif not buffer.complete_state: - # Otherwise, restart thread. - async_completer() - - if self.eventloop: - self.eventloop.call_from_executor(callback) - - self.eventloop.run_in_executor(run) - return async_completer - - def _create_auto_suggest_function(self, buffer): - """ - Create function for asynchronous auto suggestion. - (AutoSuggest in other thread.) - """ - suggest_thread_running = [False] # By ref. - - def async_suggestor(): - document = buffer.document - - # Don't start two threads at the same time. - if suggest_thread_running[0]: - return - - # Don't suggest when we already have a suggestion. - if buffer.suggestion or not buffer.auto_suggest: - return - - # Otherwise, get completions in other thread. - suggest_thread_running[0] = True - - def run(): - suggestion = buffer.auto_suggest.get_suggestion(self, buffer, document) - - def callback(): - suggest_thread_running[0] = False - - # Set suggestion only if the text was not yet changed. - if buffer.text == document.text and \ - buffer.cursor_position == document.cursor_position: - - # Set suggestion and redraw interface. - buffer.suggestion = suggestion - self.invalidate() - else: - # Otherwise, restart thread. - async_suggestor() - - if self.eventloop: - self.eventloop.call_from_executor(callback) - - self.eventloop.run_in_executor(run) - return async_suggestor - - def stdout_proxy(self, raw=False): - """ - Create an :class:`_StdoutProxy` class which can be used as a patch for - `sys.stdout`. Writing to this proxy will make sure that the text - appears above the prompt, and that it doesn't destroy the output from - the renderer. - - :param raw: (`bool`) When True, vt100 terminal escape sequences are not - removed/escaped. - """ - return _StdoutProxy(self, raw=raw) - - def patch_stdout_context(self, raw=False, patch_stdout=True, patch_stderr=True): - """ - Return a context manager that will replace ``sys.stdout`` with a proxy - that makes sure that all printed text will appear above the prompt, and - that it doesn't destroy the output from the renderer. - - :param patch_stdout: Replace `sys.stdout`. - :param patch_stderr: Replace `sys.stderr`. - """ - return _PatchStdoutContext( - self.stdout_proxy(raw=raw), - patch_stdout=patch_stdout, patch_stderr=patch_stderr) - - def create_eventloop_callbacks(self): - return _InterfaceEventLoopCallbacks(self) - - -class _InterfaceEventLoopCallbacks(EventLoopCallbacks): - """ - Callbacks on the :class:`.CommandLineInterface` object, to which an - eventloop can talk. - """ - def __init__(self, cli): - assert isinstance(cli, CommandLineInterface) - self.cli = cli - - @property - def _active_cli(self): - """ - Return the active `CommandLineInterface`. - """ - cli = self.cli - - # If there is a sub CLI. That one is always active. - while cli._sub_cli: - cli = cli._sub_cli - - return cli - - def terminal_size_changed(self): - """ - Report terminal size change. This will trigger a redraw. - """ - self._active_cli._on_resize() - - def input_timeout(self): - cli = self._active_cli - cli.on_input_timeout.fire() - - def feed_key(self, key_press): - """ - Feed a key press to the CommandLineInterface. - """ - assert isinstance(key_press, KeyPress) - cli = self._active_cli - - # Feed the key and redraw. - # (When the CLI is in 'done' state, it should return to the event loop - # as soon as possible. Ignore all key presses beyond this point.) - if not cli.is_done: - cli.input_processor.feed(key_press) - cli.input_processor.process_keys() - - -class _PatchStdoutContext(object): - def __init__(self, new_stdout, patch_stdout=True, patch_stderr=True): - self.new_stdout = new_stdout - self.patch_stdout = patch_stdout - self.patch_stderr = patch_stderr - - def __enter__(self): - self.original_stdout = sys.stdout - self.original_stderr = sys.stderr - - if self.patch_stdout: - sys.stdout = self.new_stdout - if self.patch_stderr: - sys.stderr = self.new_stdout - - def __exit__(self, *a, **kw): - if self.patch_stdout: - sys.stdout = self.original_stdout - - if self.patch_stderr: - sys.stderr = self.original_stderr - - -class _StdoutProxy(object): - """ - Proxy for stdout, as returned by - :class:`CommandLineInterface.stdout_proxy`. - """ - def __init__(self, cli, raw=False): - assert isinstance(cli, CommandLineInterface) - assert isinstance(raw, bool) - - self._lock = threading.RLock() - self._cli = cli - self._raw = raw - self._buffer = [] - - self.errors = sys.__stdout__.errors - self.encoding = sys.__stdout__.encoding - - def _do(self, func): - if self._cli._is_running: - run_in_terminal = functools.partial(self._cli.run_in_terminal, func) - self._cli.eventloop.call_from_executor(run_in_terminal) - else: - func() - - def _write(self, data): - """ - Note: print()-statements cause to multiple write calls. - (write('line') and write('\n')). Of course we don't want to call - `run_in_terminal` for every individual call, because that's too - expensive, and as long as the newline hasn't been written, the - text itself is again overwritter by the rendering of the input - command line. Therefor, we have a little buffer which holds the - text until a newline is written to stdout. - """ - if '\n' in data: - # When there is a newline in the data, write everything before the - # newline, including the newline itself. - before, after = data.rsplit('\n', 1) - to_write = self._buffer + [before, '\n'] - self._buffer = [after] - - def run(): - for s in to_write: - if self._raw: - self._cli.output.write_raw(s) - else: - self._cli.output.write(s) - self._do(run) - else: - # Otherwise, cache in buffer. - self._buffer.append(data) - - def write(self, data): - with self._lock: - self._write(data) - - def _flush(self): - def run(): - for s in self._buffer: - if self._raw: - self._cli.output.write_raw(s) - else: - self._cli.output.write(s) - self._buffer = [] - self._cli.output.flush() - self._do(run) - - def flush(self): - """ - Flush buffered output. - """ - with self._lock: - self._flush() - - -class _SubApplicationEventLoop(EventLoop): - """ - Eventloop used by sub applications. - - A sub application is an `Application` that is "spawned" by a parent - application. The parent application is suspended temporarily and the sub - application is displayed instead. - - It doesn't need it's own event loop. The `EventLoopCallbacks` from the - parent application are redirected to the sub application. So if the event - loop that is run by the parent application detects input, the callbacks - will make sure that it's forwarded to the sub application. - - When the sub application has a return value set, it will terminate - by calling the `stop` method of this event loop. This is used to - transfer control back to the parent application. - """ - def __init__(self, cli, stop_callback): - assert isinstance(cli, CommandLineInterface) - assert callable(stop_callback) - - self.cli = cli - self.stop_callback = stop_callback - - def stop(self): - self.stop_callback() - - def close(self): - pass - - def run_in_executor(self, callback): - self.cli.eventloop.run_in_executor(callback) - - def call_from_executor(self, callback, _max_postpone_until=None): - self.cli.eventloop.call_from_executor( - callback, _max_postpone_until=_max_postpone_until) - - def add_reader(self, fd, callback): - self.cli.eventloop.add_reader(fd, callback) - - def remove_reader(self, fd): - self.cli.eventloop.remove_reader(fd) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/__init__.py +++ /dev/null diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py deleted file mode 100644 index 401135dec0..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py +++ /dev/null @@ -1,407 +0,0 @@ -# pylint: disable=function-redefined -from __future__ import unicode_literals - -from prompt_toolkit.enums import DEFAULT_BUFFER -from prompt_toolkit.filters import HasSelection, Condition, EmacsInsertMode, ViInsertMode -from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.screen import Point -from prompt_toolkit.mouse_events import MouseEventType, MouseEvent -from prompt_toolkit.renderer import HeightIsUnknownError -from prompt_toolkit.utils import suspend_to_background_supported, is_windows - -from .named_commands import get_by_name -from ..registry import Registry - - -__all__ = ( - 'load_basic_bindings', - 'load_abort_and_exit_bindings', - 'load_basic_system_bindings', - 'load_auto_suggestion_bindings', -) - -def if_no_repeat(event): - """ Callable that returns True when the previous event was delivered to - another handler. """ - return not event.is_repeat - - -def load_basic_bindings(): - registry = Registry() - insert_mode = ViInsertMode() | EmacsInsertMode() - handle = registry.add_binding - has_selection = HasSelection() - - @handle(Keys.ControlA) - @handle(Keys.ControlB) - @handle(Keys.ControlC) - @handle(Keys.ControlD) - @handle(Keys.ControlE) - @handle(Keys.ControlF) - @handle(Keys.ControlG) - @handle(Keys.ControlH) - @handle(Keys.ControlI) - @handle(Keys.ControlJ) - @handle(Keys.ControlK) - @handle(Keys.ControlL) - @handle(Keys.ControlM) - @handle(Keys.ControlN) - @handle(Keys.ControlO) - @handle(Keys.ControlP) - @handle(Keys.ControlQ) - @handle(Keys.ControlR) - @handle(Keys.ControlS) - @handle(Keys.ControlT) - @handle(Keys.ControlU) - @handle(Keys.ControlV) - @handle(Keys.ControlW) - @handle(Keys.ControlX) - @handle(Keys.ControlY) - @handle(Keys.ControlZ) - @handle(Keys.F1) - @handle(Keys.F2) - @handle(Keys.F3) - @handle(Keys.F4) - @handle(Keys.F5) - @handle(Keys.F6) - @handle(Keys.F7) - @handle(Keys.F8) - @handle(Keys.F9) - @handle(Keys.F10) - @handle(Keys.F11) - @handle(Keys.F12) - @handle(Keys.F13) - @handle(Keys.F14) - @handle(Keys.F15) - @handle(Keys.F16) - @handle(Keys.F17) - @handle(Keys.F18) - @handle(Keys.F19) - @handle(Keys.F20) - @handle(Keys.ControlSpace) - @handle(Keys.ControlBackslash) - @handle(Keys.ControlSquareClose) - @handle(Keys.ControlCircumflex) - @handle(Keys.ControlUnderscore) - @handle(Keys.Backspace) - @handle(Keys.Up) - @handle(Keys.Down) - @handle(Keys.Right) - @handle(Keys.Left) - @handle(Keys.ShiftUp) - @handle(Keys.ShiftDown) - @handle(Keys.ShiftRight) - @handle(Keys.ShiftLeft) - @handle(Keys.Home) - @handle(Keys.End) - @handle(Keys.Delete) - @handle(Keys.ShiftDelete) - @handle(Keys.ControlDelete) - @handle(Keys.PageUp) - @handle(Keys.PageDown) - @handle(Keys.BackTab) - @handle(Keys.Tab) - @handle(Keys.ControlLeft) - @handle(Keys.ControlRight) - @handle(Keys.ControlUp) - @handle(Keys.ControlDown) - @handle(Keys.Insert) - @handle(Keys.Ignore) - def _(event): - """ - First, for any of these keys, Don't do anything by default. Also don't - catch them in the 'Any' handler which will insert them as data. - - If people want to insert these characters as a literal, they can always - do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi - mode.) - """ - pass - - # Readline-style bindings. - handle(Keys.Home)(get_by_name('beginning-of-line')) - handle(Keys.End)(get_by_name('end-of-line')) - handle(Keys.Left)(get_by_name('backward-char')) - handle(Keys.Right)(get_by_name('forward-char')) - handle(Keys.ControlUp)(get_by_name('previous-history')) - handle(Keys.ControlDown)(get_by_name('next-history')) - handle(Keys.ControlL)(get_by_name('clear-screen')) - - handle(Keys.ControlK, filter=insert_mode)(get_by_name('kill-line')) - handle(Keys.ControlU, filter=insert_mode)(get_by_name('unix-line-discard')) - handle(Keys.ControlH, filter=insert_mode, save_before=if_no_repeat)( - get_by_name('backward-delete-char')) - handle(Keys.Backspace, filter=insert_mode, save_before=if_no_repeat)( - get_by_name('backward-delete-char')) - handle(Keys.Delete, filter=insert_mode, save_before=if_no_repeat)( - get_by_name('delete-char')) - handle(Keys.ShiftDelete, filter=insert_mode, save_before=if_no_repeat)( - get_by_name('delete-char')) - handle(Keys.Any, filter=insert_mode, save_before=if_no_repeat)( - get_by_name('self-insert')) - handle(Keys.ControlT, filter=insert_mode)(get_by_name('transpose-chars')) - handle(Keys.ControlW, filter=insert_mode)(get_by_name('unix-word-rubout')) - handle(Keys.ControlI, filter=insert_mode)(get_by_name('menu-complete')) - handle(Keys.BackTab, filter=insert_mode)(get_by_name('menu-complete-backward')) - - handle(Keys.PageUp, filter= ~has_selection)(get_by_name('previous-history')) - handle(Keys.PageDown, filter= ~has_selection)(get_by_name('next-history')) - - # CTRL keys. - - text_before_cursor = Condition(lambda cli: cli.current_buffer.text) - handle(Keys.ControlD, filter=text_before_cursor & insert_mode)(get_by_name('delete-char')) - - is_multiline = Condition(lambda cli: cli.current_buffer.is_multiline()) - is_returnable = Condition(lambda cli: cli.current_buffer.accept_action.is_returnable) - - @handle(Keys.ControlJ, filter=is_multiline & insert_mode) - def _(event): - " Newline (in case of multiline input. " - event.current_buffer.newline(copy_margin=not event.cli.in_paste_mode) - - @handle(Keys.ControlJ, filter=~is_multiline & is_returnable) - def _(event): - " Enter, accept input. " - buff = event.current_buffer - buff.accept_action.validate_and_handle(event.cli, buff) - - # Delete the word before the cursor. - - @handle(Keys.Up) - def _(event): - event.current_buffer.auto_up(count=event.arg) - - @handle(Keys.Down) - def _(event): - event.current_buffer.auto_down(count=event.arg) - - @handle(Keys.Delete, filter=has_selection) - def _(event): - data = event.current_buffer.cut_selection() - event.cli.clipboard.set_data(data) - - # Global bindings. - - @handle(Keys.ControlZ) - def _(event): - """ - By default, control-Z should literally insert Ctrl-Z. - (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File. - In a Python REPL for instance, it's possible to type - Control-Z followed by enter to quit.) - - When the system bindings are loaded and suspend-to-background is - supported, that will override this binding. - """ - event.current_buffer.insert_text(event.data) - - @handle(Keys.CPRResponse, save_before=lambda e: False) - def _(event): - """ - Handle incoming Cursor-Position-Request response. - """ - # The incoming data looks like u'\x1b[35;1R' - # Parse row/col information. - row, col = map(int, event.data[2:-1].split(';')) - - # Report absolute cursor position to the renderer. - event.cli.renderer.report_absolute_cursor_row(row) - - @handle(Keys.BracketedPaste) - def _(event): - " Pasting from clipboard. " - data = event.data - - # Be sure to use \n as line ending. - # Some terminals (Like iTerm2) seem to paste \r\n line endings in a - # bracketed paste. See: https://github.com/ipython/ipython/issues/9737 - data = data.replace('\r\n', '\n') - data = data.replace('\r', '\n') - - event.current_buffer.insert_text(data) - - @handle(Keys.Any, filter=Condition(lambda cli: cli.quoted_insert), eager=True) - def _(event): - """ - Handle quoted insert. - """ - event.current_buffer.insert_text(event.data, overwrite=False) - event.cli.quoted_insert = False - - return registry - - -def load_mouse_bindings(): - """ - Key bindings, required for mouse support. - (Mouse events enter through the key binding system.) - """ - registry = Registry() - - @registry.add_binding(Keys.Vt100MouseEvent) - def _(event): - """ - Handling of incoming mouse event. - """ - # Typical: "Esc[MaB*" - # Urxvt: "Esc[96;14;13M" - # Xterm SGR: "Esc[<64;85;12M" - - # Parse incoming packet. - if event.data[2] == 'M': - # Typical. - mouse_event, x, y = map(ord, event.data[3:]) - mouse_event = { - 32: MouseEventType.MOUSE_DOWN, - 35: MouseEventType.MOUSE_UP, - 96: MouseEventType.SCROLL_UP, - 97: MouseEventType.SCROLL_DOWN, - }.get(mouse_event) - - # Handle situations where `PosixStdinReader` used surrogateescapes. - if x >= 0xdc00: x-= 0xdc00 - if y >= 0xdc00: y-= 0xdc00 - - x -= 32 - y -= 32 - else: - # Urxvt and Xterm SGR. - # When the '<' is not present, we are not using the Xterm SGR mode, - # but Urxvt instead. - data = event.data[2:] - if data[:1] == '<': - sgr = True - data = data[1:] - else: - sgr = False - - # Extract coordinates. - mouse_event, x, y = map(int, data[:-1].split(';')) - m = data[-1] - - # Parse event type. - if sgr: - mouse_event = { - (0, 'M'): MouseEventType.MOUSE_DOWN, - (0, 'm'): MouseEventType.MOUSE_UP, - (64, 'M'): MouseEventType.SCROLL_UP, - (65, 'M'): MouseEventType.SCROLL_DOWN, - }.get((mouse_event, m)) - else: - mouse_event = { - 32: MouseEventType.MOUSE_DOWN, - 35: MouseEventType.MOUSE_UP, - 96: MouseEventType.SCROLL_UP, - 97: MouseEventType.SCROLL_DOWN, - }.get(mouse_event) - - x -= 1 - y -= 1 - - # Only handle mouse events when we know the window height. - if event.cli.renderer.height_is_known and mouse_event is not None: - # Take region above the layout into account. The reported - # coordinates are absolute to the visible part of the terminal. - try: - y -= event.cli.renderer.rows_above_layout - except HeightIsUnknownError: - return - - # Call the mouse handler from the renderer. - handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y] - handler(event.cli, MouseEvent(position=Point(x=x, y=y), - event_type=mouse_event)) - - @registry.add_binding(Keys.WindowsMouseEvent) - def _(event): - """ - Handling of mouse events for Windows. - """ - assert is_windows() # This key binding should only exist for Windows. - - # Parse data. - event_type, x, y = event.data.split(';') - x = int(x) - y = int(y) - - # Make coordinates absolute to the visible part of the terminal. - screen_buffer_info = event.cli.renderer.output.get_win32_screen_buffer_info() - rows_above_cursor = screen_buffer_info.dwCursorPosition.Y - event.cli.renderer._cursor_pos.y - y -= rows_above_cursor - - # Call the mouse event handler. - handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y] - handler(event.cli, MouseEvent(position=Point(x=x, y=y), - event_type=event_type)) - - return registry - - -def load_abort_and_exit_bindings(): - """ - Basic bindings for abort (Ctrl-C) and exit (Ctrl-D). - """ - registry = Registry() - handle = registry.add_binding - - @handle(Keys.ControlC) - def _(event): - " Abort when Control-C has been pressed. " - event.cli.abort() - - @Condition - def ctrl_d_condition(cli): - """ Ctrl-D binding is only active when the default buffer is selected - and empty. """ - return (cli.current_buffer_name == DEFAULT_BUFFER and - not cli.current_buffer.text) - - handle(Keys.ControlD, filter=ctrl_d_condition)(get_by_name('end-of-file')) - - return registry - - -def load_basic_system_bindings(): - """ - Basic system bindings (For both Emacs and Vi mode.) - """ - registry = Registry() - - suspend_supported = Condition( - lambda cli: suspend_to_background_supported()) - - @registry.add_binding(Keys.ControlZ, filter=suspend_supported) - def _(event): - """ - Suspend process to background. - """ - event.cli.suspend_to_background() - - return registry - - -def load_auto_suggestion_bindings(): - """ - Key bindings for accepting auto suggestion text. - """ - registry = Registry() - handle = registry.add_binding - - suggestion_available = Condition( - lambda cli: - cli.current_buffer.suggestion is not None and - cli.current_buffer.document.is_cursor_at_the_end) - - @handle(Keys.ControlF, filter=suggestion_available) - @handle(Keys.ControlE, filter=suggestion_available) - @handle(Keys.Right, filter=suggestion_available) - def _(event): - " Accept suggestion. " - b = event.current_buffer - suggestion = b.suggestion - - if suggestion: - b.insert_text(suggestion.text) - - return registry diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/completion.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/completion.py deleted file mode 100644 index 4903900bc6..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/completion.py +++ /dev/null @@ -1,161 +0,0 @@ -""" -Key binding handlers for displaying completions. -""" -from __future__ import unicode_literals -from prompt_toolkit.completion import CompleteEvent, get_common_complete_suffix -from prompt_toolkit.utils import get_cwidth -from prompt_toolkit.keys import Keys -from prompt_toolkit.key_binding.registry import Registry - -import math - -__all__ = ( - 'generate_completions', - 'display_completions_like_readline', -) - -def generate_completions(event): - r""" - Tab-completion: where the first tab completes the common suffix and the - second tab lists all the completions. - """ - b = event.current_buffer - - # When already navigating through completions, select the next one. - if b.complete_state: - b.complete_next() - else: - event.cli.start_completion(insert_common_part=True, select_first=False) - - -def display_completions_like_readline(event): - """ - Key binding handler for readline-style tab completion. - This is meant to be as similar as possible to the way how readline displays - completions. - - Generate the completions immediately (blocking) and display them above the - prompt in columns. - - Usage:: - - # Call this handler when 'Tab' has been pressed. - registry.add_binding(Keys.ControlI)(display_completions_like_readline) - """ - # Request completions. - b = event.current_buffer - if b.completer is None: - return - complete_event = CompleteEvent(completion_requested=True) - completions = list(b.completer.get_completions(b.document, complete_event)) - - # Calculate the common suffix. - common_suffix = get_common_complete_suffix(b.document, completions) - - # One completion: insert it. - if len(completions) == 1: - b.delete_before_cursor(-completions[0].start_position) - b.insert_text(completions[0].text) - # Multiple completions with common part. - elif common_suffix: - b.insert_text(common_suffix) - # Otherwise: display all completions. - elif completions: - _display_completions_like_readline(event.cli, completions) - - -def _display_completions_like_readline(cli, completions): - """ - Display the list of completions in columns above the prompt. - This will ask for a confirmation if there are too many completions to fit - on a single page and provide a paginator to walk through them. - """ - from prompt_toolkit.shortcuts import create_confirm_application - assert isinstance(completions, list) - - # Get terminal dimensions. - term_size = cli.output.get_size() - term_width = term_size.columns - term_height = term_size.rows - - # Calculate amount of required columns/rows for displaying the - # completions. (Keep in mind that completions are displayed - # alphabetically column-wise.) - max_compl_width = min(term_width, - max(get_cwidth(c.text) for c in completions) + 1) - column_count = max(1, term_width // max_compl_width) - completions_per_page = column_count * (term_height - 1) - page_count = int(math.ceil(len(completions) / float(completions_per_page))) - # Note: math.ceil can return float on Python2. - - def display(page): - # Display completions. - page_completions = completions[page * completions_per_page: - (page+1) * completions_per_page] - - page_row_count = int(math.ceil(len(page_completions) / float(column_count))) - page_columns = [page_completions[i * page_row_count:(i+1) * page_row_count] - for i in range(column_count)] - - result = [] - for r in range(page_row_count): - for c in range(column_count): - try: - result.append(page_columns[c][r].text.ljust(max_compl_width)) - except IndexError: - pass - result.append('\n') - cli.output.write(''.join(result)) - cli.output.flush() - - # User interaction through an application generator function. - def run(): - if len(completions) > completions_per_page: - # Ask confirmation if it doesn't fit on the screen. - message = 'Display all {} possibilities? (y on n) '.format(len(completions)) - confirm = yield create_confirm_application(message) - - if confirm: - # Display pages. - for page in range(page_count): - display(page) - - if page != page_count - 1: - # Display --MORE-- and go to the next page. - show_more = yield _create_more_application() - if not show_more: - return - else: - cli.output.write('\n'); cli.output.flush() - else: - # Display all completions. - display(0) - - cli.run_application_generator(run, render_cli_done=True) - - -def _create_more_application(): - """ - Create an `Application` instance that displays the "--MORE--". - """ - from prompt_toolkit.shortcuts import create_prompt_application - registry = Registry() - - @registry.add_binding(' ') - @registry.add_binding('y') - @registry.add_binding('Y') - @registry.add_binding(Keys.ControlJ) - @registry.add_binding(Keys.ControlI) # Tab. - def _(event): - event.cli.set_return_value(True) - - @registry.add_binding('n') - @registry.add_binding('N') - @registry.add_binding('q') - @registry.add_binding('Q') - @registry.add_binding(Keys.ControlC) - def _(event): - event.cli.set_return_value(False) - - return create_prompt_application( - '--MORE--', key_bindings_registry=registry, erase_when_done=True) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py deleted file mode 100644 index bccdb04ff3..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py +++ /dev/null @@ -1,452 +0,0 @@ -# pylint: disable=function-redefined -from __future__ import unicode_literals -from prompt_toolkit.buffer import SelectionType, indent, unindent -from prompt_toolkit.keys import Keys -from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER, SYSTEM_BUFFER -from prompt_toolkit.filters import Condition, EmacsMode, HasSelection, EmacsInsertMode, HasFocus, HasArg -from prompt_toolkit.completion import CompleteEvent - -from .scroll import scroll_page_up, scroll_page_down -from .named_commands import get_by_name -from ..registry import Registry, ConditionalRegistry - -__all__ = ( - 'load_emacs_bindings', - 'load_emacs_search_bindings', - 'load_emacs_system_bindings', - 'load_extra_emacs_page_navigation_bindings', -) - - -def load_emacs_bindings(): - """ - Some e-macs extensions. - """ - # Overview of Readline emacs commands: - # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf - registry = ConditionalRegistry(Registry(), EmacsMode()) - handle = registry.add_binding - - insert_mode = EmacsInsertMode() - has_selection = HasSelection() - - @handle(Keys.Escape) - def _(event): - """ - By default, ignore escape key. - - (If we don't put this here, and Esc is followed by a key which sequence - is not handled, we'll insert an Escape character in the input stream. - Something we don't want and happens to easily in emacs mode. - Further, people can always use ControlQ to do a quoted insert.) - """ - pass - - handle(Keys.ControlA)(get_by_name('beginning-of-line')) - handle(Keys.ControlB)(get_by_name('backward-char')) - handle(Keys.ControlDelete, filter=insert_mode)(get_by_name('kill-word')) - handle(Keys.ControlE)(get_by_name('end-of-line')) - handle(Keys.ControlF)(get_by_name('forward-char')) - handle(Keys.ControlLeft)(get_by_name('backward-word')) - handle(Keys.ControlRight)(get_by_name('forward-word')) - handle(Keys.ControlX, 'r', 'y', filter=insert_mode)(get_by_name('yank')) - handle(Keys.ControlY, filter=insert_mode)(get_by_name('yank')) - handle(Keys.Escape, 'b')(get_by_name('backward-word')) - handle(Keys.Escape, 'c', filter=insert_mode)(get_by_name('capitalize-word')) - handle(Keys.Escape, 'd', filter=insert_mode)(get_by_name('kill-word')) - handle(Keys.Escape, 'f')(get_by_name('forward-word')) - handle(Keys.Escape, 'l', filter=insert_mode)(get_by_name('downcase-word')) - handle(Keys.Escape, 'u', filter=insert_mode)(get_by_name('uppercase-word')) - handle(Keys.Escape, 'y', filter=insert_mode)(get_by_name('yank-pop')) - handle(Keys.Escape, Keys.ControlH, filter=insert_mode)(get_by_name('backward-kill-word')) - handle(Keys.Escape, Keys.Backspace, filter=insert_mode)(get_by_name('backward-kill-word')) - handle(Keys.Escape, '\\', filter=insert_mode)(get_by_name('delete-horizontal-space')) - - handle(Keys.ControlUnderscore, save_before=(lambda e: False), filter=insert_mode)( - get_by_name('undo')) - - handle(Keys.ControlX, Keys.ControlU, save_before=(lambda e: False), filter=insert_mode)( - get_by_name('undo')) - - - handle(Keys.Escape, '<', filter= ~has_selection)(get_by_name('beginning-of-history')) - handle(Keys.Escape, '>', filter= ~has_selection)(get_by_name('end-of-history')) - - handle(Keys.Escape, '.', filter=insert_mode)(get_by_name('yank-last-arg')) - handle(Keys.Escape, '_', filter=insert_mode)(get_by_name('yank-last-arg')) - handle(Keys.Escape, Keys.ControlY, filter=insert_mode)(get_by_name('yank-nth-arg')) - handle(Keys.Escape, '#', filter=insert_mode)(get_by_name('insert-comment')) - handle(Keys.ControlO)(get_by_name('operate-and-get-next')) - - # ControlQ does a quoted insert. Not that for vt100 terminals, you have to - # disable flow control by running ``stty -ixon``, otherwise Ctrl-Q and - # Ctrl-S are captured by the terminal. - handle(Keys.ControlQ, filter= ~has_selection)(get_by_name('quoted-insert')) - - handle(Keys.ControlX, '(')(get_by_name('start-kbd-macro')) - handle(Keys.ControlX, ')')(get_by_name('end-kbd-macro')) - handle(Keys.ControlX, 'e')(get_by_name('call-last-kbd-macro')) - - @handle(Keys.ControlN) - def _(event): - " Next line. " - event.current_buffer.auto_down() - - @handle(Keys.ControlP) - def _(event): - " Previous line. " - event.current_buffer.auto_up(count=event.arg) - - def handle_digit(c): - """ - Handle input of arguments. - The first number needs to be preceeded by escape. - """ - @handle(c, filter=HasArg()) - @handle(Keys.Escape, c) - def _(event): - event.append_to_arg_count(c) - - for c in '0123456789': - handle_digit(c) - - @handle(Keys.Escape, '-', filter=~HasArg()) - def _(event): - """ - """ - if event._arg is None: - event.append_to_arg_count('-') - - @handle('-', filter=Condition(lambda cli: cli.input_processor.arg == '-')) - def _(event): - """ - When '-' is typed again, after exactly '-' has been given as an - argument, ignore this. - """ - event.cli.input_processor.arg = '-' - - is_returnable = Condition( - lambda cli: cli.current_buffer.accept_action.is_returnable) - - # Meta + Newline: always accept input. - handle(Keys.Escape, Keys.ControlJ, filter=insert_mode & is_returnable)( - get_by_name('accept-line')) - - def character_search(buff, char, count): - if count < 0: - match = buff.document.find_backwards(char, in_current_line=True, count=-count) - else: - match = buff.document.find(char, in_current_line=True, count=count) - - if match is not None: - buff.cursor_position += match - - @handle(Keys.ControlSquareClose, Keys.Any) - def _(event): - " When Ctl-] + a character is pressed. go to that character. " - # Also named 'character-search' - character_search(event.current_buffer, event.data, event.arg) - - @handle(Keys.Escape, Keys.ControlSquareClose, Keys.Any) - def _(event): - " Like Ctl-], but backwards. " - # Also named 'character-search-backward' - character_search(event.current_buffer, event.data, -event.arg) - - @handle(Keys.Escape, 'a') - def _(event): - " Previous sentence. " - # TODO: - - @handle(Keys.Escape, 'e') - def _(event): - " Move to end of sentence. " - # TODO: - - @handle(Keys.Escape, 't', filter=insert_mode) - def _(event): - """ - Swap the last two words before the cursor. - """ - # TODO - - @handle(Keys.Escape, '*', filter=insert_mode) - def _(event): - """ - `meta-*`: Insert all possible completions of the preceding text. - """ - buff = event.current_buffer - - # List all completions. - complete_event = CompleteEvent(text_inserted=False, completion_requested=True) - completions = list(buff.completer.get_completions(buff.document, complete_event)) - - # Insert them. - text_to_insert = ' '.join(c.text for c in completions) - buff.insert_text(text_to_insert) - - @handle(Keys.ControlX, Keys.ControlX) - def _(event): - """ - Move cursor back and forth between the start and end of the current - line. - """ - buffer = event.current_buffer - - if buffer.document.is_cursor_at_the_end_of_line: - buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=False) - else: - buffer.cursor_position += buffer.document.get_end_of_line_position() - - @handle(Keys.ControlSpace) - def _(event): - """ - Start of the selection (if the current buffer is not empty). - """ - # Take the current cursor position as the start of this selection. - buff = event.current_buffer - if buff.text: - buff.start_selection(selection_type=SelectionType.CHARACTERS) - - @handle(Keys.ControlG, filter= ~has_selection) - def _(event): - """ - Control + G: Cancel completion menu and validation state. - """ - event.current_buffer.complete_state = None - event.current_buffer.validation_error = None - - @handle(Keys.ControlG, filter=has_selection) - def _(event): - """ - Cancel selection. - """ - event.current_buffer.exit_selection() - - @handle(Keys.ControlW, filter=has_selection) - @handle(Keys.ControlX, 'r', 'k', filter=has_selection) - def _(event): - """ - Cut selected text. - """ - data = event.current_buffer.cut_selection() - event.cli.clipboard.set_data(data) - - @handle(Keys.Escape, 'w', filter=has_selection) - def _(event): - """ - Copy selected text. - """ - data = event.current_buffer.copy_selection() - event.cli.clipboard.set_data(data) - - @handle(Keys.Escape, Keys.Left) - def _(event): - """ - Cursor to start of previous word. - """ - buffer = event.current_buffer - buffer.cursor_position += buffer.document.find_previous_word_beginning(count=event.arg) or 0 - - @handle(Keys.Escape, Keys.Right) - def _(event): - """ - Cursor to start of next word. - """ - buffer = event.current_buffer - buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \ - buffer.document.get_end_of_document_position() - - @handle(Keys.Escape, '/', filter=insert_mode) - def _(event): - """ - M-/: Complete. - """ - b = event.current_buffer - if b.complete_state: - b.complete_next() - else: - event.cli.start_completion(select_first=True) - - @handle(Keys.ControlC, '>', filter=has_selection) - def _(event): - """ - Indent selected text. - """ - buffer = event.current_buffer - - buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True) - - from_, to = buffer.document.selection_range() - from_, _ = buffer.document.translate_index_to_position(from_) - to, _ = buffer.document.translate_index_to_position(to) - - indent(buffer, from_, to + 1, count=event.arg) - - @handle(Keys.ControlC, '<', filter=has_selection) - def _(event): - """ - Unindent selected text. - """ - buffer = event.current_buffer - - from_, to = buffer.document.selection_range() - from_, _ = buffer.document.translate_index_to_position(from_) - to, _ = buffer.document.translate_index_to_position(to) - - unindent(buffer, from_, to + 1, count=event.arg) - - return registry - - -def load_emacs_open_in_editor_bindings(): - """ - Pressing C-X C-E will open the buffer in an external editor. - """ - registry = Registry() - - registry.add_binding(Keys.ControlX, Keys.ControlE, - filter=EmacsMode() & ~HasSelection())( - get_by_name('edit-and-execute-command')) - - return registry - - -def load_emacs_system_bindings(): - registry = ConditionalRegistry(Registry(), EmacsMode()) - handle = registry.add_binding - - has_focus = HasFocus(SYSTEM_BUFFER) - - @handle(Keys.Escape, '!', filter= ~has_focus) - def _(event): - """ - M-'!' opens the system prompt. - """ - event.cli.push_focus(SYSTEM_BUFFER) - - @handle(Keys.Escape, filter=has_focus) - @handle(Keys.ControlG, filter=has_focus) - @handle(Keys.ControlC, filter=has_focus) - def _(event): - """ - Cancel system prompt. - """ - event.cli.buffers[SYSTEM_BUFFER].reset() - event.cli.pop_focus() - - @handle(Keys.ControlJ, filter=has_focus) - def _(event): - """ - Run system command. - """ - system_line = event.cli.buffers[SYSTEM_BUFFER] - event.cli.run_system_command(system_line.text) - system_line.reset(append_to_history=True) - - # Focus previous buffer again. - event.cli.pop_focus() - - return registry - - -def load_emacs_search_bindings(get_search_state=None): - registry = ConditionalRegistry(Registry(), EmacsMode()) - handle = registry.add_binding - - has_focus = HasFocus(SEARCH_BUFFER) - - assert get_search_state is None or callable(get_search_state) - - if not get_search_state: - def get_search_state(cli): return cli.search_state - - @handle(Keys.ControlG, filter=has_focus) - @handle(Keys.ControlC, filter=has_focus) - # NOTE: the reason for not also binding Escape to this one, is that we want - # Alt+Enter to accept input directly in incremental search mode. - def _(event): - """ - Abort an incremental search and restore the original line. - """ - search_buffer = event.cli.buffers[SEARCH_BUFFER] - - search_buffer.reset() - event.cli.pop_focus() - - @handle(Keys.ControlJ, filter=has_focus) - @handle(Keys.Escape, filter=has_focus, eager=True) - def _(event): - """ - When enter pressed in isearch, quit isearch mode. (Multiline - isearch would be too complicated.) - """ - input_buffer = event.cli.buffers.previous(event.cli) - search_buffer = event.cli.buffers[SEARCH_BUFFER] - - # Update search state. - if search_buffer.text: - get_search_state(event.cli).text = search_buffer.text - - # Apply search. - input_buffer.apply_search(get_search_state(event.cli), include_current_position=True) - - # Add query to history of search line. - search_buffer.append_to_history() - search_buffer.reset() - - # Focus previous document again. - event.cli.pop_focus() - - @handle(Keys.ControlR, filter= ~has_focus) - def _(event): - get_search_state(event.cli).direction = IncrementalSearchDirection.BACKWARD - event.cli.push_focus(SEARCH_BUFFER) - - @handle(Keys.ControlS, filter= ~has_focus) - def _(event): - get_search_state(event.cli).direction = IncrementalSearchDirection.FORWARD - event.cli.push_focus(SEARCH_BUFFER) - - def incremental_search(cli, direction, count=1): - " Apply search, but keep search buffer focussed. " - # Update search_state. - search_state = get_search_state(cli) - direction_changed = search_state.direction != direction - - search_state.text = cli.buffers[SEARCH_BUFFER].text - search_state.direction = direction - - # Apply search to current buffer. - if not direction_changed: - input_buffer = cli.buffers.previous(cli) - input_buffer.apply_search(search_state, - include_current_position=False, count=count) - - @handle(Keys.ControlR, filter=has_focus) - @handle(Keys.Up, filter=has_focus) - def _(event): - incremental_search(event.cli, IncrementalSearchDirection.BACKWARD, count=event.arg) - - @handle(Keys.ControlS, filter=has_focus) - @handle(Keys.Down, filter=has_focus) - def _(event): - incremental_search(event.cli, IncrementalSearchDirection.FORWARD, count=event.arg) - - return registry - - -def load_extra_emacs_page_navigation_bindings(): - """ - Key bindings, for scrolling up and down through pages. - This are separate bindings, because GNU readline doesn't have them. - """ - registry = ConditionalRegistry(Registry(), EmacsMode()) - handle = registry.add_binding - - handle(Keys.ControlV)(scroll_page_down) - handle(Keys.PageDown)(scroll_page_down) - handle(Keys.Escape, 'v')(scroll_page_up) - handle(Keys.PageUp)(scroll_page_up) - - return registry diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/named_commands.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/named_commands.py deleted file mode 100644 index f80c439fc6..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/named_commands.py +++ /dev/null @@ -1,578 +0,0 @@ -""" -Key bindings which are also known by GNU readline by the given names. - -See: http://www.delorie.com/gnu/docs/readline/rlman_13.html -""" -from __future__ import unicode_literals -from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER -from prompt_toolkit.selection import PasteMode -from six.moves import range -import six - -from .completion import generate_completions, display_completions_like_readline -from prompt_toolkit.document import Document -from prompt_toolkit.enums import EditingMode -from prompt_toolkit.key_binding.input_processor import KeyPress -from prompt_toolkit.keys import Keys - -__all__ = ( - 'get_by_name', -) - - -# Registry that maps the Readline command names to their handlers. -_readline_commands = {} - -def register(name): - """ - Store handler in the `_readline_commands` dictionary. - """ - assert isinstance(name, six.text_type) - def decorator(handler): - assert callable(handler) - - _readline_commands[name] = handler - return handler - return decorator - - -def get_by_name(name): - """ - Return the handler for the (Readline) command with the given name. - """ - try: - return _readline_commands[name] - except KeyError: - raise KeyError('Unknown readline command: %r' % name) - -# -# Commands for moving -# See: http://www.delorie.com/gnu/docs/readline/rlman_14.html -# - -@register('beginning-of-line') -def beginning_of_line(event): - " Move to the start of the current line. " - buff = event.current_buffer - buff.cursor_position += buff.document.get_start_of_line_position(after_whitespace=False) - - -@register('end-of-line') -def end_of_line(event): - " Move to the end of the line. " - buff = event.current_buffer - buff.cursor_position += buff.document.get_end_of_line_position() - - -@register('forward-char') -def forward_char(event): - " Move forward a character. " - buff = event.current_buffer - buff.cursor_position += buff.document.get_cursor_right_position(count=event.arg) - - -@register('backward-char') -def backward_char(event): - " Move back a character. " - buff = event.current_buffer - buff.cursor_position += buff.document.get_cursor_left_position(count=event.arg) - - -@register('forward-word') -def forward_word(event): - """ - Move forward to the end of the next word. Words are composed of letters and - digits. - """ - buff = event.current_buffer - pos = buff.document.find_next_word_ending(count=event.arg) - - if pos: - buff.cursor_position += pos - - -@register('backward-word') -def backward_word(event): - """ - Move back to the start of the current or previous word. Words are composed - of letters and digits. - """ - buff = event.current_buffer - pos = buff.document.find_previous_word_beginning(count=event.arg) - - if pos: - buff.cursor_position += pos - - -@register('clear-screen') -def clear_screen(event): - """ - Clear the screen and redraw everything at the top of the screen. - """ - event.cli.renderer.clear() - - -@register('redraw-current-line') -def redraw_current_line(event): - """ - Refresh the current line. - (Readline defines this command, but prompt-toolkit doesn't have it.) - """ - pass - -# -# Commands for manipulating the history. -# See: http://www.delorie.com/gnu/docs/readline/rlman_15.html -# - -@register('accept-line') -def accept_line(event): - " Accept the line regardless of where the cursor is. " - b = event.current_buffer - b.accept_action.validate_and_handle(event.cli, b) - - -@register('previous-history') -def previous_history(event): - " Move `back` through the history list, fetching the previous command. " - event.current_buffer.history_backward(count=event.arg) - - -@register('next-history') -def next_history(event): - " Move `forward` through the history list, fetching the next command. " - event.current_buffer.history_forward(count=event.arg) - - -@register('beginning-of-history') -def beginning_of_history(event): - " Move to the first line in the history. " - event.current_buffer.go_to_history(0) - - -@register('end-of-history') -def end_of_history(event): - """ - Move to the end of the input history, i.e., the line currently being entered. - """ - event.current_buffer.history_forward(count=10**100) - buff = event.current_buffer - buff.go_to_history(len(buff._working_lines) - 1) - - -@register('reverse-search-history') -def reverse_search_history(event): - """ - Search backward starting at the current line and moving `up` through - the history as necessary. This is an incremental search. - """ - event.cli.current_search_state.direction = IncrementalSearchDirection.BACKWARD - event.cli.push_focus(SEARCH_BUFFER) - - -# -# Commands for changing text -# - -@register('end-of-file') -def end_of_file(event): - """ - Exit. - """ - event.cli.exit() - - -@register('delete-char') -def delete_char(event): - " Delete character before the cursor. " - deleted = event.current_buffer.delete(count=event.arg) - if not deleted: - event.cli.output.bell() - - -@register('backward-delete-char') -def backward_delete_char(event): - " Delete the character behind the cursor. " - if event.arg < 0: - # When a negative argument has been given, this should delete in front - # of the cursor. - deleted = event.current_buffer.delete(count=-event.arg) - else: - deleted = event.current_buffer.delete_before_cursor(count=event.arg) - - if not deleted: - event.cli.output.bell() - - -@register('self-insert') -def self_insert(event): - " Insert yourself. " - event.current_buffer.insert_text(event.data * event.arg) - - -@register('transpose-chars') -def transpose_chars(event): - """ - Emulate Emacs transpose-char behavior: at the beginning of the buffer, - do nothing. At the end of a line or buffer, swap the characters before - the cursor. Otherwise, move the cursor right, and then swap the - characters before the cursor. - """ - b = event.current_buffer - p = b.cursor_position - if p == 0: - return - elif p == len(b.text) or b.text[p] == '\n': - b.swap_characters_before_cursor() - else: - b.cursor_position += b.document.get_cursor_right_position() - b.swap_characters_before_cursor() - - -@register('uppercase-word') -def uppercase_word(event): - """ - Uppercase the current (or following) word. - """ - buff = event.current_buffer - - for i in range(event.arg): - pos = buff.document.find_next_word_ending() - words = buff.document.text_after_cursor[:pos] - buff.insert_text(words.upper(), overwrite=True) - - -@register('downcase-word') -def downcase_word(event): - """ - Lowercase the current (or following) word. - """ - buff = event.current_buffer - - for i in range(event.arg): # XXX: not DRY: see meta_c and meta_u!! - pos = buff.document.find_next_word_ending() - words = buff.document.text_after_cursor[:pos] - buff.insert_text(words.lower(), overwrite=True) - - -@register('capitalize-word') -def capitalize_word(event): - """ - Capitalize the current (or following) word. - """ - buff = event.current_buffer - - for i in range(event.arg): - pos = buff.document.find_next_word_ending() - words = buff.document.text_after_cursor[:pos] - buff.insert_text(words.title(), overwrite=True) - - -@register('quoted-insert') -def quoted_insert(event): - """ - Add the next character typed to the line verbatim. This is how to insert - key sequences like C-q, for example. - """ - event.cli.quoted_insert = True - - -# -# Killing and yanking. -# - -@register('kill-line') -def kill_line(event): - """ - Kill the text from the cursor to the end of the line. - - If we are at the end of the line, this should remove the newline. - (That way, it is possible to delete multiple lines by executing this - command multiple times.) - """ - buff = event.current_buffer - if event.arg < 0: - deleted = buff.delete_before_cursor(count=-buff.document.get_start_of_line_position()) - else: - if buff.document.current_char == '\n': - deleted = buff.delete(1) - else: - deleted = buff.delete(count=buff.document.get_end_of_line_position()) - event.cli.clipboard.set_text(deleted) - - -@register('kill-word') -def kill_word(event): - """ - Kill from point to the end of the current word, or if between words, to the - end of the next word. Word boundaries are the same as forward-word. - """ - buff = event.current_buffer - pos = buff.document.find_next_word_ending(count=event.arg) - - if pos: - deleted = buff.delete(count=pos) - event.cli.clipboard.set_text(deleted) - - -@register('unix-word-rubout') -def unix_word_rubout(event, WORD=True): - """ - Kill the word behind point, using whitespace as a word boundary. - Usually bound to ControlW. - """ - buff = event.current_buffer - pos = buff.document.find_start_of_previous_word(count=event.arg, WORD=WORD) - - if pos is None: - # Nothing found? delete until the start of the document. (The - # input starts with whitespace and no words were found before the - # cursor.) - pos = - buff.cursor_position - - if pos: - deleted = buff.delete_before_cursor(count=-pos) - - # If the previous key press was also Control-W, concatenate deleted - # text. - if event.is_repeat: - deleted += event.cli.clipboard.get_data().text - - event.cli.clipboard.set_text(deleted) - else: - # Nothing to delete. Bell. - event.cli.output.bell() - - -@register('backward-kill-word') -def backward_kill_word(event): - """ - Kills the word before point, using "not a letter nor a digit" as a word boundary. - Usually bound to M-Del or M-Backspace. - """ - unix_word_rubout(event, WORD=False) - - -@register('delete-horizontal-space') -def delete_horizontal_space(event): - " Delete all spaces and tabs around point. " - buff = event.current_buffer - text_before_cursor = buff.document.text_before_cursor - text_after_cursor = buff.document.text_after_cursor - - delete_before = len(text_before_cursor) - len(text_before_cursor.rstrip('\t ')) - delete_after = len(text_after_cursor) - len(text_after_cursor.lstrip('\t ')) - - buff.delete_before_cursor(count=delete_before) - buff.delete(count=delete_after) - - -@register('unix-line-discard') -def unix_line_discard(event): - """ - Kill backward from the cursor to the beginning of the current line. - """ - buff = event.current_buffer - - if buff.document.cursor_position_col == 0 and buff.document.cursor_position > 0: - buff.delete_before_cursor(count=1) - else: - deleted = buff.delete_before_cursor(count=-buff.document.get_start_of_line_position()) - event.cli.clipboard.set_text(deleted) - - -@register('yank') -def yank(event): - """ - Paste before cursor. - """ - event.current_buffer.paste_clipboard_data( - event.cli.clipboard.get_data(), count=event.arg, paste_mode=PasteMode.EMACS) - -@register('yank-nth-arg') -def yank_nth_arg(event): - """ - Insert the first argument of the previous command. With an argument, insert - the nth word from the previous command (start counting at 0). - """ - n = (event.arg if event.arg_present else None) - event.current_buffer.yank_nth_arg(n) - - -@register('yank-last-arg') -def yank_last_arg(event): - """ - Like `yank_nth_arg`, but if no argument has been given, yank the last word - of each line. - """ - n = (event.arg if event.arg_present else None) - event.current_buffer.yank_last_arg(n) - -@register('yank-pop') -def yank_pop(event): - """ - Rotate the kill ring, and yank the new top. Only works following yank or - yank-pop. - """ - buff = event.current_buffer - doc_before_paste = buff.document_before_paste - clipboard = event.cli.clipboard - - if doc_before_paste is not None: - buff.document = doc_before_paste - clipboard.rotate() - buff.paste_clipboard_data( - clipboard.get_data(), paste_mode=PasteMode.EMACS) - -# -# Completion. -# - -@register('complete') -def complete(event): - " Attempt to perform completion. " - display_completions_like_readline(event) - - -@register('menu-complete') -def menu_complete(event): - """ - Generate completions, or go to the next completion. (This is the default - way of completing input in prompt_toolkit.) - """ - generate_completions(event) - - -@register('menu-complete-backward') -def menu_complete_backward(event): - " Move backward through the list of possible completions. " - event.current_buffer.complete_previous() - -# -# Keyboard macros. -# - -@register('start-kbd-macro') -def start_kbd_macro(event): - """ - Begin saving the characters typed into the current keyboard macro. - """ - event.cli.input_processor.start_macro() - - -@register('end-kbd-macro') -def start_kbd_macro(event): - """ - Stop saving the characters typed into the current keyboard macro and save - the definition. - """ - event.cli.input_processor.end_macro() - - -@register('call-last-kbd-macro') -def start_kbd_macro(event): - """ - Re-execute the last keyboard macro defined, by making the characters in the - macro appear as if typed at the keyboard. - """ - event.cli.input_processor.call_macro() - - -@register('print-last-kbd-macro') -def print_last_kbd_macro(event): - " Print the last keboard macro. " - # TODO: Make the format suitable for the inputrc file. - def print_macro(): - for k in event.cli.input_processor.macro: - print(k) - event.cli.run_in_terminal(print_macro) - -# -# Miscellaneous Commands. -# - -@register('undo') -def undo(event): - " Incremental undo. " - event.current_buffer.undo() - - -@register('insert-comment') -def insert_comment(event): - """ - Without numeric argument, comment all lines. - With numeric argument, uncomment all lines. - In any case accept the input. - """ - buff = event.current_buffer - - # Transform all lines. - if event.arg != 1: - def change(line): - return line[1:] if line.startswith('#') else line - else: - def change(line): - return '#' + line - - buff.document = Document( - text='\n'.join(map(change, buff.text.splitlines())), - cursor_position=0) - - # Accept input. - buff.accept_action.validate_and_handle(event.cli, buff) - - -@register('vi-editing-mode') -def vi_editing_mode(event): - " Switch to Vi editing mode. " - event.cli.editing_mode = EditingMode.VI - - -@register('emacs-editing-mode') -def emacs_editing_mode(event): - " Switch to Emacs editing mode. " - event.cli.editing_mode = EditingMode.EMACS - - -@register('prefix-meta') -def prefix_meta(event): - """ - Metafy the next character typed. This is for keyboards without a meta key. - - Sometimes people also want to bind other keys to Meta, e.g. 'jj':: - - registry.add_key_binding('j', 'j', filter=ViInsertMode())(prefix_meta) - """ - event.cli.input_processor.feed(KeyPress(Keys.Escape)) - - -@register('operate-and-get-next') -def operate_and_get_next(event): - """ - Accept the current line for execution and fetch the next line relative to - the current line from the history for editing. - """ - buff = event.current_buffer - new_index = buff.working_index + 1 - - # Accept the current input. (This will also redraw the interface in the - # 'done' state.) - buff.accept_action.validate_and_handle(event.cli, buff) - - # Set the new index at the start of the next run. - def set_working_index(): - if new_index < len(buff._working_lines): - buff.working_index = new_index - - event.cli.pre_run_callables.append(set_working_index) - - -@register('edit-and-execute-command') -def edit_and_execute(event): - """ - Invoke an editor on the current command line, and accept the result. - """ - buff = event.current_buffer - - buff.open_in_editor(event.cli) - buff.accept_action.validate_and_handle(event.cli, buff) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py deleted file mode 100644 index 2cc58129ff..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py +++ /dev/null @@ -1,185 +0,0 @@ -""" -Key bindings, for scrolling up and down through pages. - -This are separate bindings, because GNU readline doesn't have them, but -they are very useful for navigating through long multiline buffers, like in -Vi, Emacs, etc... -""" -from __future__ import unicode_literals - -from prompt_toolkit.layout.utils import find_window_for_buffer_name -from six.moves import range - -__all__ = ( - 'scroll_forward', - 'scroll_backward', - 'scroll_half_page_up', - 'scroll_half_page_down', - 'scroll_one_line_up', - 'scroll_one_line_down', -) - - -def _current_window_for_event(event): - """ - Return the `Window` for the currently focussed Buffer. - """ - return find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - - -def scroll_forward(event, half=False): - """ - Scroll window down. - """ - w = _current_window_for_event(event) - b = event.cli.current_buffer - - if w and w.render_info: - info = w.render_info - ui_content = info.ui_content - - # Height to scroll. - scroll_height = info.window_height - if half: - scroll_height //= 2 - - # Calculate how many lines is equivalent to that vertical space. - y = b.document.cursor_position_row + 1 - height = 0 - while y < ui_content.line_count: - line_height = info.get_height_for_line(y) - - if height + line_height < scroll_height: - height += line_height - y += 1 - else: - break - - b.cursor_position = b.document.translate_row_col_to_index(y, 0) - - -def scroll_backward(event, half=False): - """ - Scroll window up. - """ - w = _current_window_for_event(event) - b = event.cli.current_buffer - - if w and w.render_info: - info = w.render_info - - # Height to scroll. - scroll_height = info.window_height - if half: - scroll_height //= 2 - - # Calculate how many lines is equivalent to that vertical space. - y = max(0, b.document.cursor_position_row - 1) - height = 0 - while y > 0: - line_height = info.get_height_for_line(y) - - if height + line_height < scroll_height: - height += line_height - y -= 1 - else: - break - - b.cursor_position = b.document.translate_row_col_to_index(y, 0) - - -def scroll_half_page_down(event): - """ - Same as ControlF, but only scroll half a page. - """ - scroll_forward(event, half=True) - - -def scroll_half_page_up(event): - """ - Same as ControlB, but only scroll half a page. - """ - scroll_backward(event, half=True) - - -def scroll_one_line_down(event): - """ - scroll_offset += 1 - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - b = event.cli.current_buffer - - if w: - # When the cursor is at the top, move to the next line. (Otherwise, only scroll.) - if w.render_info: - info = w.render_info - - if w.vertical_scroll < info.content_height - info.window_height: - if info.cursor_position.y <= info.configured_scroll_offsets.top: - b.cursor_position += b.document.get_cursor_down_position() - - w.vertical_scroll += 1 - - -def scroll_one_line_up(event): - """ - scroll_offset -= 1 - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - b = event.cli.current_buffer - - if w: - # When the cursor is at the bottom, move to the previous line. (Otherwise, only scroll.) - if w.render_info: - info = w.render_info - - if w.vertical_scroll > 0: - first_line_height = info.get_height_for_line(info.first_visible_line()) - - cursor_up = info.cursor_position.y - (info.window_height - 1 - first_line_height - - info.configured_scroll_offsets.bottom) - - # Move cursor up, as many steps as the height of the first line. - # TODO: not entirely correct yet, in case of line wrapping and many long lines. - for _ in range(max(0, cursor_up)): - b.cursor_position += b.document.get_cursor_up_position() - - # Scroll window - w.vertical_scroll -= 1 - - -def scroll_page_down(event): - """ - Scroll page down. (Prefer the cursor at the top of the page, after scrolling.) - """ - w = _current_window_for_event(event) - b = event.cli.current_buffer - - if w and w.render_info: - # Scroll down one page. - line_index = max(w.render_info.last_visible_line(), w.vertical_scroll + 1) - w.vertical_scroll = line_index - - b.cursor_position = b.document.translate_row_col_to_index(line_index, 0) - b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True) - - -def scroll_page_up(event): - """ - Scroll page up. (Prefer the cursor at the bottom of the page, after scrolling.) - """ - w = _current_window_for_event(event) - b = event.cli.current_buffer - - if w and w.render_info: - # Put cursor at the first visible line. (But make sure that the cursor - # moves at least one line up.) - line_index = max(0, min(w.render_info.first_visible_line(), - b.document.cursor_position_row - 1)) - - b.cursor_position = b.document.translate_row_col_to_index(line_index, 0) - b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True) - - # Set the scroll offset. We can safely set it to zero; the Window will - # make sure that it scrolls at least until the cursor becomes visible. - w.vertical_scroll = 0 diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py deleted file mode 100644 index caf08c5c1b..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import unicode_literals -from prompt_toolkit.filters import CLIFilter, Always - -__all__ = ( - 'create_handle_decorator', -) - -def create_handle_decorator(registry, filter=Always()): - """ - Create a key handle decorator, which is compatible with `Registry.handle`, - but will chain the given filter to every key binding. - - :param filter: `CLIFilter` - """ - assert isinstance(filter, CLIFilter) - - def handle(*keys, **kw): - # Chain the given filter to the filter of this specific binding. - if 'filter' in kw: - kw['filter'] = kw['filter'] & filter - else: - kw['filter'] = filter - - return registry.add_binding(*keys, **kw) - return handle diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py deleted file mode 100644 index 72568ee273..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py +++ /dev/null @@ -1,1903 +0,0 @@ -# pylint: disable=function-redefined -from __future__ import unicode_literals -from prompt_toolkit.buffer import ClipboardData, indent, unindent, reshape_text -from prompt_toolkit.document import Document -from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER, SYSTEM_BUFFER -from prompt_toolkit.filters import Filter, Condition, HasArg, Always, IsReadOnly -from prompt_toolkit.filters.cli import ViNavigationMode, ViInsertMode, ViInsertMultipleMode, ViReplaceMode, ViSelectionMode, ViWaitingForTextObjectMode, ViDigraphMode, ViMode -from prompt_toolkit.key_binding.digraphs import DIGRAPHS -from prompt_toolkit.key_binding.vi_state import CharacterFind, InputMode -from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.utils import find_window_for_buffer_name -from prompt_toolkit.selection import SelectionType, SelectionState, PasteMode - -from .scroll import scroll_forward, scroll_backward, scroll_half_page_up, scroll_half_page_down, scroll_one_line_up, scroll_one_line_down, scroll_page_up, scroll_page_down -from .named_commands import get_by_name -from ..registry import Registry, ConditionalRegistry, BaseRegistry - -import prompt_toolkit.filters as filters -from six.moves import range -import codecs -import six -import string - -try: - from itertools import accumulate -except ImportError: # < Python 3.2 - def accumulate(iterable): - " Super simpel 'accumulate' implementation. " - total = 0 - for item in iterable: - total += item - yield total - -__all__ = ( - 'load_vi_bindings', - 'load_vi_search_bindings', - 'load_vi_system_bindings', - 'load_extra_vi_page_navigation_bindings', -) - -if six.PY2: - ascii_lowercase = string.ascii_lowercase.decode('ascii') -else: - ascii_lowercase = string.ascii_lowercase - -vi_register_names = ascii_lowercase + '0123456789' - - -class TextObjectType(object): - EXCLUSIVE = 'EXCLUSIVE' - INCLUSIVE = 'INCLUSIVE' - LINEWISE = 'LINEWISE' - BLOCK = 'BLOCK' - - -class TextObject(object): - """ - Return struct for functions wrapped in ``text_object``. - Both `start` and `end` are relative to the current cursor position. - """ - def __init__(self, start, end=0, type=TextObjectType.EXCLUSIVE): - self.start = start - self.end = end - self.type = type - - @property - def selection_type(self): - if self.type == TextObjectType.LINEWISE: - return SelectionType.LINES - if self.type == TextObjectType.BLOCK: - return SelectionType.BLOCK - else: - return SelectionType.CHARACTERS - - def sorted(self): - """ - Return a (start, end) tuple where start <= end. - """ - if self.start < self.end: - return self.start, self.end - else: - return self.end, self.start - - def operator_range(self, document): - """ - Return a (start, end) tuple with start <= end that indicates the range - operators should operate on. - `buffer` is used to get start and end of line positions. - """ - start, end = self.sorted() - doc = document - - if (self.type == TextObjectType.EXCLUSIVE and - doc.translate_index_to_position(end + doc.cursor_position)[1] == 0): - # If the motion is exclusive and the end of motion is on the first - # column, the end position becomes end of previous line. - end -= 1 - if self.type == TextObjectType.INCLUSIVE: - end += 1 - if self.type == TextObjectType.LINEWISE: - # Select whole lines - row, col = doc.translate_index_to_position(start + doc.cursor_position) - start = doc.translate_row_col_to_index(row, 0) - doc.cursor_position - row, col = doc.translate_index_to_position(end + doc.cursor_position) - end = doc.translate_row_col_to_index(row, len(doc.lines[row])) - doc.cursor_position - return start, end - - def get_line_numbers(self, buffer): - """ - Return a (start_line, end_line) pair. - """ - # Get absolute cursor positions from the text object. - from_, to = self.operator_range(buffer.document) - from_ += buffer.cursor_position - to += buffer.cursor_position - - # Take the start of the lines. - from_, _ = buffer.document.translate_index_to_position(from_) - to, _ = buffer.document.translate_index_to_position(to) - - return from_, to - - def cut(self, buffer): - """ - Turn text object into `ClipboardData` instance. - """ - from_, to = self.operator_range(buffer.document) - - from_ += buffer.cursor_position - to += buffer.cursor_position - to -= 1 # SelectionState does not include the end position, `operator_range` does. - - document = Document(buffer.text, to, SelectionState( - original_cursor_position=from_, type=self.selection_type)) - - new_document, clipboard_data = document.cut_selection() - return new_document, clipboard_data - - -def create_text_object_decorator(registry): - """ - Create a decorator that can be used to register Vi text object implementations. - """ - assert isinstance(registry, BaseRegistry) - - operator_given = ViWaitingForTextObjectMode() - navigation_mode = ViNavigationMode() - selection_mode = ViSelectionMode() - - def text_object_decorator(*keys, **kw): - """ - Register a text object function. - - Usage:: - - @text_object('w', filter=..., no_move_handler=False) - def handler(event): - # Return a text object for this key. - return TextObject(...) - - :param no_move_handler: Disable the move handler in navigation mode. - (It's still active in selection mode.) - """ - filter = kw.pop('filter', Always()) - no_move_handler = kw.pop('no_move_handler', False) - no_selection_handler = kw.pop('no_selection_handler', False) - eager = kw.pop('eager', False) - assert not kw - - def decorator(text_object_func): - assert callable(text_object_func) - - @registry.add_binding(*keys, filter=operator_given & filter, eager=eager) - def _(event): - # Arguments are multiplied. - vi_state = event.cli.vi_state - event._arg = (vi_state.operator_arg or 1) * (event.arg or 1) - - # Call the text object handler. - text_obj = text_object_func(event) - if text_obj is not None: - assert isinstance(text_obj, TextObject) - - # Call the operator function with the text object. - vi_state.operator_func(event, text_obj) - - # Clear operator. - event.cli.vi_state.operator_func = None - event.cli.vi_state.operator_arg = None - - # Register a move operation. (Doesn't need an operator.) - if not no_move_handler: - @registry.add_binding(*keys, filter=~operator_given & filter & navigation_mode, eager=eager) - def _(event): - " Move handler for navigation mode. " - text_object = text_object_func(event) - event.current_buffer.cursor_position += text_object.start - - # Register a move selection operation. - if not no_selection_handler: - @registry.add_binding(*keys, filter=~operator_given & filter & selection_mode, eager=eager) - def _(event): - " Move handler for selection mode. " - text_object = text_object_func(event) - buff = event.current_buffer - - # When the text object has both a start and end position, like 'i(' or 'iw', - # Turn this into a selection, otherwise the cursor. - if text_object.end: - # Take selection positions from text object. - start, end = text_object.operator_range(buff.document) - start += buff.cursor_position - end += buff.cursor_position - - buff.selection_state.original_cursor_position = start - buff.cursor_position = end - - # Take selection type from text object. - if text_object.type == TextObjectType.LINEWISE: - buff.selection_state.type = SelectionType.LINES - else: - buff.selection_state.type = SelectionType.CHARACTERS - else: - event.current_buffer.cursor_position += text_object.start - - # Make it possible to chain @text_object decorators. - return text_object_func - - return decorator - return text_object_decorator - - -def create_operator_decorator(registry): - """ - Create a decorator that can be used for registering Vi operators. - """ - assert isinstance(registry, BaseRegistry) - - operator_given = ViWaitingForTextObjectMode() - navigation_mode = ViNavigationMode() - selection_mode = ViSelectionMode() - - def operator_decorator(*keys, **kw): - """ - Register a Vi operator. - - Usage:: - - @operator('d', filter=...) - def handler(cli, text_object): - # Do something with the text object here. - """ - filter = kw.pop('filter', Always()) - eager = kw.pop('eager', False) - assert not kw - - def decorator(operator_func): - @registry.add_binding(*keys, filter=~operator_given & filter & navigation_mode, eager=eager) - def _(event): - """ - Handle operator in navigation mode. - """ - # When this key binding is matched, only set the operator - # function in the ViState. We should execute it after a text - # object has been received. - event.cli.vi_state.operator_func = operator_func - event.cli.vi_state.operator_arg = event.arg - - @registry.add_binding(*keys, filter=~operator_given & filter & selection_mode, eager=eager) - def _(event): - """ - Handle operator in selection mode. - """ - buff = event.current_buffer - selection_state = buff.selection_state - - # Create text object from selection. - if selection_state.type == SelectionType.LINES: - text_obj_type = TextObjectType.LINEWISE - elif selection_state.type == SelectionType.BLOCK: - text_obj_type = TextObjectType.BLOCK - else: - text_obj_type = TextObjectType.INCLUSIVE - - text_object = TextObject( - selection_state.original_cursor_position - buff.cursor_position, - type=text_obj_type) - - # Execute operator. - operator_func(event, text_object) - - # Quit selection mode. - buff.selection_state = None - - return operator_func - return decorator - return operator_decorator - - -def load_vi_bindings(get_search_state=None): - """ - Vi extensions. - - # Overview of Readline Vi commands: - # http://www.catonmat.net/download/bash-vi-editing-mode-cheat-sheet.pdf - - :param get_search_state: None or a callable that takes a - CommandLineInterface and returns a SearchState. - """ - # Note: Some key bindings have the "~IsReadOnly()" filter added. This - # prevents the handler to be executed when the focus is on a - # read-only buffer. - # This is however only required for those that change the ViState to - # INSERT mode. The `Buffer` class itself throws the - # `EditReadOnlyBuffer` exception for any text operations which is - # handled correctly. There is no need to add "~IsReadOnly" to all key - # bindings that do text manipulation. - - registry = ConditionalRegistry(Registry(), ViMode()) - handle = registry.add_binding - - # Default get_search_state. - if get_search_state is None: - def get_search_state(cli): return cli.search_state - - # (Note: Always take the navigation bindings in read-only mode, even when - # ViState says different.) - navigation_mode = ViNavigationMode() - insert_mode = ViInsertMode() - insert_multiple_mode = ViInsertMultipleMode() - replace_mode = ViReplaceMode() - selection_mode = ViSelectionMode() - operator_given = ViWaitingForTextObjectMode() - digraph_mode = ViDigraphMode() - - vi_transform_functions = [ - # Rot 13 transformation - (('g', '?'), Always(), lambda string: codecs.encode(string, 'rot_13')), - - # To lowercase - (('g', 'u'), Always(), lambda string: string.lower()), - - # To uppercase. - (('g', 'U'), Always(), lambda string: string.upper()), - - # Swap case. - (('g', '~'), Always(), lambda string: string.swapcase()), - (('~', ), Condition(lambda cli: cli.vi_state.tilde_operator), lambda string: string.swapcase()), - ] - - # Insert a character literally (quoted insert). - handle(Keys.ControlV, filter=insert_mode)(get_by_name('quoted-insert')) - - @handle(Keys.Escape) - def _(event): - """ - Escape goes to vi navigation mode. - """ - buffer = event.current_buffer - vi_state = event.cli.vi_state - - if vi_state.input_mode in (InputMode.INSERT, InputMode.REPLACE): - buffer.cursor_position += buffer.document.get_cursor_left_position() - - vi_state.reset(InputMode.NAVIGATION) - - if bool(buffer.selection_state): - buffer.exit_selection() - - @handle('k', filter=selection_mode) - def _(event): - """ - Arrow up in selection mode. - """ - event.current_buffer.cursor_up(count=event.arg) - - @handle('j', filter=selection_mode) - def _(event): - """ - Arrow down in selection mode. - """ - event.current_buffer.cursor_down(count=event.arg) - - @handle(Keys.Up, filter=navigation_mode) - @handle(Keys.ControlP, filter=navigation_mode) - def _(event): - """ - Arrow up and ControlP in navigation mode go up. - """ - event.current_buffer.auto_up(count=event.arg) - - @handle('k', filter=navigation_mode) - def _(event): - """ - Go up, but if we enter a new history entry, move to the start of the - line. - """ - event.current_buffer.auto_up( - count=event.arg, go_to_start_of_line_if_history_changes=True) - - @handle(Keys.Down, filter=navigation_mode) - @handle(Keys.ControlN, filter=navigation_mode) - def _(event): - """ - Arrow down and Control-N in navigation mode. - """ - event.current_buffer.auto_down(count=event.arg) - - @handle('j', filter=navigation_mode) - def _(event): - """ - Go down, but if we enter a new history entry, go to the start of the line. - """ - event.current_buffer.auto_down( - count=event.arg, go_to_start_of_line_if_history_changes=True) - - @handle(Keys.ControlH, filter=navigation_mode) - @handle(Keys.Backspace, filter=navigation_mode) - def _(event): - """ - In navigation-mode, move cursor. - """ - event.current_buffer.cursor_position += \ - event.current_buffer.document.get_cursor_left_position(count=event.arg) - - @handle(Keys.ControlN, filter=insert_mode) - def _(event): - b = event.current_buffer - - if b.complete_state: - b.complete_next() - else: - event.cli.start_completion(select_first=True) - - @handle(Keys.ControlP, filter=insert_mode) - def _(event): - """ - Control-P: To previous completion. - """ - b = event.current_buffer - - if b.complete_state: - b.complete_previous() - else: - event.cli.start_completion(select_last=True) - - @handle(Keys.ControlY, filter=insert_mode) - def _(event): - """ - Accept current completion. - """ - event.current_buffer.complete_state = None - - @handle(Keys.ControlE, filter=insert_mode) - def _(event): - """ - Cancel completion. Go back to originally typed text. - """ - event.current_buffer.cancel_completion() - - @handle(Keys.ControlJ, filter=navigation_mode) # XXX: only if the selected buffer has a return handler. - def _(event): - """ - In navigation mode, pressing enter will always return the input. - """ - b = event.current_buffer - - if b.accept_action.is_returnable: - b.accept_action.validate_and_handle(event.cli, b) - - # ** In navigation mode ** - - # List of navigation commands: http://hea-www.harvard.edu/~fine/Tech/vi.html - - @handle(Keys.Insert, filter=navigation_mode) - def _(event): - " Presing the Insert key. " - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('a', filter=navigation_mode & ~IsReadOnly()) - # ~IsReadOnly, because we want to stay in navigation mode for - # read-only buffers. - def _(event): - event.current_buffer.cursor_position += event.current_buffer.document.get_cursor_right_position() - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('A', filter=navigation_mode & ~IsReadOnly()) - def _(event): - event.current_buffer.cursor_position += event.current_buffer.document.get_end_of_line_position() - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('C', filter=navigation_mode & ~IsReadOnly()) - def _(event): - """ - # Change to end of line. - # Same as 'c$' (which is implemented elsewhere.) - """ - buffer = event.current_buffer - - deleted = buffer.delete(count=buffer.document.get_end_of_line_position()) - event.cli.clipboard.set_text(deleted) - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('c', 'c', filter=navigation_mode & ~IsReadOnly()) - @handle('S', filter=navigation_mode & ~IsReadOnly()) - def _(event): # TODO: implement 'arg' - """ - Change current line - """ - buffer = event.current_buffer - - # We copy the whole line. - data = ClipboardData(buffer.document.current_line, SelectionType.LINES) - event.cli.clipboard.set_data(data) - - # But we delete after the whitespace - buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True) - buffer.delete(count=buffer.document.get_end_of_line_position()) - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('D', filter=navigation_mode) - def _(event): - buffer = event.current_buffer - deleted = buffer.delete(count=buffer.document.get_end_of_line_position()) - event.cli.clipboard.set_text(deleted) - - @handle('d', 'd', filter=navigation_mode) - def _(event): - """ - Delete line. (Or the following 'n' lines.) - """ - buffer = event.current_buffer - - # Split string in before/deleted/after text. - lines = buffer.document.lines - - before = '\n'.join(lines[:buffer.document.cursor_position_row]) - deleted = '\n'.join(lines[buffer.document.cursor_position_row: - buffer.document.cursor_position_row + event.arg]) - after = '\n'.join(lines[buffer.document.cursor_position_row + event.arg:]) - - # Set new text. - if before and after: - before = before + '\n' - - # Set text and cursor position. - buffer.document = Document( - text=before + after, - # Cursor At the start of the first 'after' line, after the leading whitespace. - cursor_position = len(before) + len(after) - len(after.lstrip(' '))) - - # Set clipboard data - event.cli.clipboard.set_data(ClipboardData(deleted, SelectionType.LINES)) - - @handle('x', filter=selection_mode) - def _(event): - """ - Cut selection. - ('x' is not an operator.) - """ - clipboard_data = event.current_buffer.cut_selection() - event.cli.clipboard.set_data(clipboard_data) - - @handle('i', filter=navigation_mode & ~IsReadOnly()) - def _(event): - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('I', filter=navigation_mode & ~IsReadOnly()) - def _(event): - event.cli.vi_state.input_mode = InputMode.INSERT - event.current_buffer.cursor_position += \ - event.current_buffer.document.get_start_of_line_position(after_whitespace=True) - - @Condition - def in_block_selection(cli): - buff = cli.current_buffer - return buff.selection_state and buff.selection_state.type == SelectionType.BLOCK - - @handle('I', filter=in_block_selection & ~IsReadOnly()) - def go_to_block_selection(event, after=False): - " Insert in block selection mode. " - buff = event.current_buffer - - # Store all cursor positions. - positions = [] - - if after: - def get_pos(from_to): - return from_to[1] + 1 - else: - def get_pos(from_to): - return from_to[0] - - for i, from_to in enumerate(buff.document.selection_ranges()): - positions.append(get_pos(from_to)) - if i == 0: - buff.cursor_position = get_pos(from_to) - - buff.multiple_cursor_positions = positions - - # Go to 'INSERT_MULTIPLE' mode. - event.cli.vi_state.input_mode = InputMode.INSERT_MULTIPLE - buff.exit_selection() - - @handle('A', filter=in_block_selection & ~IsReadOnly()) - def _(event): - go_to_block_selection(event, after=True) - - @handle('J', filter=navigation_mode & ~IsReadOnly()) - def _(event): - " Join lines. " - for i in range(event.arg): - event.current_buffer.join_next_line() - - @handle('g', 'J', filter=navigation_mode & ~IsReadOnly()) - def _(event): - " Join lines without space. " - for i in range(event.arg): - event.current_buffer.join_next_line(separator='') - - @handle('J', filter=selection_mode & ~IsReadOnly()) - def _(event): - " Join selected lines. " - event.current_buffer.join_selected_lines() - - @handle('g', 'J', filter=selection_mode & ~IsReadOnly()) - def _(event): - " Join selected lines without space. " - event.current_buffer.join_selected_lines(separator='') - - @handle('p', filter=navigation_mode) - def _(event): - """ - Paste after - """ - event.current_buffer.paste_clipboard_data( - event.cli.clipboard.get_data(), - count=event.arg, - paste_mode=PasteMode.VI_AFTER) - - @handle('P', filter=navigation_mode) - def _(event): - """ - Paste before - """ - event.current_buffer.paste_clipboard_data( - event.cli.clipboard.get_data(), - count=event.arg, - paste_mode=PasteMode.VI_BEFORE) - - @handle('"', Keys.Any, 'p', filter=navigation_mode) - def _(event): - " Paste from named register. " - c = event.key_sequence[1].data - if c in vi_register_names: - data = event.cli.vi_state.named_registers.get(c) - if data: - event.current_buffer.paste_clipboard_data( - data, count=event.arg, paste_mode=PasteMode.VI_AFTER) - - @handle('"', Keys.Any, 'P', filter=navigation_mode) - def _(event): - " Paste (before) from named register. " - c = event.key_sequence[1].data - if c in vi_register_names: - data = event.cli.vi_state.named_registers.get(c) - if data: - event.current_buffer.paste_clipboard_data( - data, count=event.arg, paste_mode=PasteMode.VI_BEFORE) - - @handle('r', Keys.Any, filter=navigation_mode) - def _(event): - """ - Replace single character under cursor - """ - event.current_buffer.insert_text(event.data * event.arg, overwrite=True) - event.current_buffer.cursor_position -= 1 - - @handle('R', filter=navigation_mode) - def _(event): - """ - Go to 'replace'-mode. - """ - event.cli.vi_state.input_mode = InputMode.REPLACE - - @handle('s', filter=navigation_mode & ~IsReadOnly()) - def _(event): - """ - Substitute with new text - (Delete character(s) and go to insert mode.) - """ - text = event.current_buffer.delete(count=event.arg) - event.cli.clipboard.set_text(text) - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('u', filter=navigation_mode, save_before=(lambda e: False)) - def _(event): - for i in range(event.arg): - event.current_buffer.undo() - - @handle('V', filter=navigation_mode) - def _(event): - """ - Start lines selection. - """ - event.current_buffer.start_selection(selection_type=SelectionType.LINES) - - @handle(Keys.ControlV, filter=navigation_mode) - def _(event): - " Enter block selection mode. " - event.current_buffer.start_selection(selection_type=SelectionType.BLOCK) - - @handle('V', filter=selection_mode) - def _(event): - """ - Exit line selection mode, or go from non line selection mode to line - selection mode. - """ - selection_state = event.current_buffer.selection_state - - if selection_state.type != SelectionType.LINES: - selection_state.type = SelectionType.LINES - else: - event.current_buffer.exit_selection() - - @handle('v', filter=navigation_mode) - def _(event): - " Enter character selection mode. " - event.current_buffer.start_selection(selection_type=SelectionType.CHARACTERS) - - @handle('v', filter=selection_mode) - def _(event): - """ - Exit character selection mode, or go from non-character-selection mode - to character selection mode. - """ - selection_state = event.current_buffer.selection_state - - if selection_state.type != SelectionType.CHARACTERS: - selection_state.type = SelectionType.CHARACTERS - else: - event.current_buffer.exit_selection() - - @handle(Keys.ControlV, filter=selection_mode) - def _(event): - """ - Exit block selection mode, or go from non block selection mode to block - selection mode. - """ - selection_state = event.current_buffer.selection_state - - if selection_state.type != SelectionType.BLOCK: - selection_state.type = SelectionType.BLOCK - else: - event.current_buffer.exit_selection() - - - @handle('a', 'w', filter=selection_mode) - @handle('a', 'W', filter=selection_mode) - def _(event): - """ - Switch from visual linewise mode to visual characterwise mode. - """ - buffer = event.current_buffer - - if buffer.selection_state and buffer.selection_state.type == SelectionType.LINES: - buffer.selection_state.type = SelectionType.CHARACTERS - - @handle('x', filter=navigation_mode) - def _(event): - """ - Delete character. - """ - text = event.current_buffer.delete(count=event.arg) - event.cli.clipboard.set_text(text) - - @handle('X', filter=navigation_mode) - def _(event): - text = event.current_buffer.delete_before_cursor() - event.cli.clipboard.set_text(text) - - @handle('y', 'y', filter=navigation_mode) - @handle('Y', filter=navigation_mode) - def _(event): - """ - Yank the whole line. - """ - text = '\n'.join(event.current_buffer.document.lines_from_current[:event.arg]) - event.cli.clipboard.set_data(ClipboardData(text, SelectionType.LINES)) - - @handle('+', filter=navigation_mode) - def _(event): - """ - Move to first non whitespace of next line - """ - buffer = event.current_buffer - buffer.cursor_position += buffer.document.get_cursor_down_position(count=event.arg) - buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True) - - @handle('-', filter=navigation_mode) - def _(event): - """ - Move to first non whitespace of previous line - """ - buffer = event.current_buffer - buffer.cursor_position += buffer.document.get_cursor_up_position(count=event.arg) - buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True) - - @handle('>', '>', filter=navigation_mode) - def _(event): - """ - Indent lines. - """ - buffer = event.current_buffer - current_row = buffer.document.cursor_position_row - indent(buffer, current_row, current_row + event.arg) - - @handle('<', '<', filter=navigation_mode) - def _(event): - """ - Unindent lines. - """ - current_row = event.current_buffer.document.cursor_position_row - unindent(event.current_buffer, current_row, current_row + event.arg) - - @handle('O', filter=navigation_mode & ~IsReadOnly()) - def _(event): - """ - Open line above and enter insertion mode - """ - event.current_buffer.insert_line_above( - copy_margin=not event.cli.in_paste_mode) - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('o', filter=navigation_mode & ~IsReadOnly()) - def _(event): - """ - Open line below and enter insertion mode - """ - event.current_buffer.insert_line_below( - copy_margin=not event.cli.in_paste_mode) - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle('~', filter=navigation_mode) - def _(event): - """ - Reverse case of current character and move cursor forward. - """ - buffer = event.current_buffer - c = buffer.document.current_char - - if c is not None and c != '\n': - buffer.insert_text(c.swapcase(), overwrite=True) - - @handle('g', 'u', 'u', filter=navigation_mode & ~IsReadOnly()) - def _(event): - " Lowercase current line. " - buff = event.current_buffer - buff.transform_current_line(lambda s: s.lower()) - - @handle('g', 'U', 'U', filter=navigation_mode & ~IsReadOnly()) - def _(event): - " Uppercase current line. " - buff = event.current_buffer - buff.transform_current_line(lambda s: s.upper()) - - @handle('g', '~', '~', filter=navigation_mode & ~IsReadOnly()) - def _(event): - " Swap case of the current line. " - buff = event.current_buffer - buff.transform_current_line(lambda s: s.swapcase()) - - @handle('#', filter=navigation_mode) - def _(event): - """ - Go to previous occurence of this word. - """ - b = event.cli.current_buffer - - search_state = get_search_state(event.cli) - search_state.text = b.document.get_word_under_cursor() - search_state.direction = IncrementalSearchDirection.BACKWARD - - b.apply_search(search_state, count=event.arg, - include_current_position=False) - - @handle('*', filter=navigation_mode) - def _(event): - """ - Go to next occurence of this word. - """ - b = event.cli.current_buffer - - search_state = get_search_state(event.cli) - search_state.text = b.document.get_word_under_cursor() - search_state.direction = IncrementalSearchDirection.FORWARD - - b.apply_search(search_state, count=event.arg, - include_current_position=False) - - @handle('(', filter=navigation_mode) - def _(event): - # TODO: go to begin of sentence. - # XXX: should become text_object. - pass - - @handle(')', filter=navigation_mode) - def _(event): - # TODO: go to end of sentence. - # XXX: should become text_object. - pass - - operator = create_operator_decorator(registry) - text_object = create_text_object_decorator(registry) - - @text_object(Keys.Any, filter=operator_given) - def _(event): - """ - Unknown key binding while waiting for a text object. - """ - event.cli.output.bell() - - # - # *** Operators *** - # - - def create_delete_and_change_operators(delete_only, with_register=False): - """ - Delete and change operators. - - :param delete_only: Create an operator that deletes, but doesn't go to insert mode. - :param with_register: Copy the deleted text to this named register instead of the clipboard. - """ - if with_register: - handler_keys = ('"', Keys.Any, 'cd'[delete_only]) - else: - handler_keys = 'cd'[delete_only] - - @operator(*handler_keys, filter=~IsReadOnly()) - def delete_or_change_operator(event, text_object): - clipboard_data = None - buff = event.current_buffer - - if text_object: - new_document, clipboard_data = text_object.cut(buff) - buff.document = new_document - - # Set deleted/changed text to clipboard or named register. - if clipboard_data and clipboard_data.text: - if with_register: - reg_name = event.key_sequence[1].data - if reg_name in vi_register_names: - event.cli.vi_state.named_registers[reg_name] = clipboard_data - else: - event.cli.clipboard.set_data(clipboard_data) - - # Only go back to insert mode in case of 'change'. - if not delete_only: - event.cli.vi_state.input_mode = InputMode.INSERT - - create_delete_and_change_operators(False, False) - create_delete_and_change_operators(False, True) - create_delete_and_change_operators(True, False) - create_delete_and_change_operators(True, True) - - def create_transform_handler(filter, transform_func, *a): - @operator(*a, filter=filter & ~IsReadOnly()) - def _(event, text_object): - """ - Apply transformation (uppercase, lowercase, rot13, swap case). - """ - buff = event.current_buffer - start, end = text_object.operator_range(buff.document) - - if start < end: - # Transform. - buff.transform_region( - buff.cursor_position + start, - buff.cursor_position + end, - transform_func) - - # Move cursor - buff.cursor_position += (text_object.end or text_object.start) - - for k, f, func in vi_transform_functions: - create_transform_handler(f, func, *k) - - @operator('y') - def yank_handler(event, text_object): - """ - Yank operator. (Copy text.) - """ - _, clipboard_data = text_object.cut(event.current_buffer) - if clipboard_data.text: - event.cli.clipboard.set_data(clipboard_data) - - @operator('"', Keys.Any, 'y') - def _(event, text_object): - " Yank selection to named register. " - c = event.key_sequence[1].data - if c in vi_register_names: - _, clipboard_data = text_object.cut(event.current_buffer) - event.cli.vi_state.named_registers[c] = clipboard_data - - @operator('>') - def _(event, text_object): - """ - Indent. - """ - buff = event.current_buffer - from_, to = text_object.get_line_numbers(buff) - indent(buff, from_, to + 1, count=event.arg) - - @operator('<') - def _(event, text_object): - """ - Unindent. - """ - buff = event.current_buffer - from_, to = text_object.get_line_numbers(buff) - unindent(buff, from_, to + 1, count=event.arg) - - @operator('g', 'q') - def _(event, text_object): - """ - Reshape text. - """ - buff = event.current_buffer - from_, to = text_object.get_line_numbers(buff) - reshape_text(buff, from_, to) - - # - # *** Text objects *** - # - - @text_object('b') - def _(event): - """ Move one word or token left. """ - return TextObject(event.current_buffer.document.find_start_of_previous_word(count=event.arg) or 0) - - @text_object('B') - def _(event): - """ Move one non-blank word left """ - return TextObject(event.current_buffer.document.find_start_of_previous_word(count=event.arg, WORD=True) or 0) - - @text_object('$') - def key_dollar(event): - """ 'c$', 'd$' and '$': Delete/change/move until end of line. """ - return TextObject(event.current_buffer.document.get_end_of_line_position()) - - @text_object('w') - def _(event): - """ 'word' forward. 'cw', 'dw', 'w': Delete/change/move one word. """ - return TextObject(event.current_buffer.document.find_next_word_beginning(count=event.arg) or - event.current_buffer.document.get_end_of_document_position()) - - @text_object('W') - def _(event): - """ 'WORD' forward. 'cW', 'dW', 'W': Delete/change/move one WORD. """ - return TextObject(event.current_buffer.document.find_next_word_beginning(count=event.arg, WORD=True) or - event.current_buffer.document.get_end_of_document_position()) - - @text_object('e') - def _(event): - """ End of 'word': 'ce', 'de', 'e' """ - end = event.current_buffer.document.find_next_word_ending(count=event.arg) - return TextObject(end - 1 if end else 0, type=TextObjectType.INCLUSIVE) - - @text_object('E') - def _(event): - """ End of 'WORD': 'cE', 'dE', 'E' """ - end = event.current_buffer.document.find_next_word_ending(count=event.arg, WORD=True) - return TextObject(end - 1 if end else 0, type=TextObjectType.INCLUSIVE) - - @text_object('i', 'w', no_move_handler=True) - def _(event): - """ Inner 'word': ciw and diw """ - start, end = event.current_buffer.document.find_boundaries_of_current_word() - return TextObject(start, end) - - @text_object('a', 'w', no_move_handler=True) - def _(event): - """ A 'word': caw and daw """ - start, end = event.current_buffer.document.find_boundaries_of_current_word(include_trailing_whitespace=True) - return TextObject(start, end) - - @text_object('i', 'W', no_move_handler=True) - def _(event): - """ Inner 'WORD': ciW and diW """ - start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True) - return TextObject(start, end) - - @text_object('a', 'W', no_move_handler=True) - def _(event): - """ A 'WORD': caw and daw """ - start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True, include_trailing_whitespace=True) - return TextObject(start, end) - - @text_object('a', 'p', no_move_handler=True) - def _(event): - """ - Auto paragraph. - """ - start = event.current_buffer.document.start_of_paragraph() - end = event.current_buffer.document.end_of_paragraph(count=event.arg) - return TextObject(start, end) - - @text_object('^') - def key_circumflex(event): - """ 'c^', 'd^' and '^': Soft start of line, after whitespace. """ - return TextObject(event.current_buffer.document.get_start_of_line_position(after_whitespace=True)) - - @text_object('0') - def key_zero(event): - """ - 'c0', 'd0': Hard start of line, before whitespace. - (The move '0' key is implemented elsewhere, because a '0' could also change the `arg`.) - """ - return TextObject(event.current_buffer.document.get_start_of_line_position(after_whitespace=False)) - - def create_ci_ca_handles(ci_start, ci_end, inner, key=None): - # TODO: 'dat', 'dit', (tags (like xml) - """ - Delete/Change string between this start and stop character. But keep these characters. - This implements all the ci", ci<, ci{, ci(, di", di<, ca", ca<, ... combinations. - """ - def handler(event): - if ci_start == ci_end: - # Quotes - start = event.current_buffer.document.find_backwards(ci_start, in_current_line=False) - end = event.current_buffer.document.find(ci_end, in_current_line=False) - else: - # Brackets - start = event.current_buffer.document.find_enclosing_bracket_left(ci_start, ci_end) - end = event.current_buffer.document.find_enclosing_bracket_right(ci_start, ci_end) - - if start is not None and end is not None: - offset = 0 if inner else 1 - return TextObject(start + 1 - offset, end + offset) - else: - # Nothing found. - return TextObject(0) - - if key is None: - text_object('ai'[inner], ci_start, no_move_handler=True)(handler) - text_object('ai'[inner], ci_end, no_move_handler=True)(handler) - else: - text_object('ai'[inner], key, no_move_handler=True)(handler) - - for inner in (False, True): - for ci_start, ci_end in [('"', '"'), ("'", "'"), ("`", "`"), - ('[', ']'), ('<', '>'), ('{', '}'), ('(', ')')]: - create_ci_ca_handles(ci_start, ci_end, inner) - - create_ci_ca_handles('(', ')', inner, 'b') # 'dab', 'dib' - create_ci_ca_handles('{', '}', inner, 'B') # 'daB', 'diB' - - @text_object('{') - def _(event): - """ - Move to previous blank-line separated section. - Implements '{', 'c{', 'd{', 'y{' - """ - index = event.current_buffer.document.start_of_paragraph( - count=event.arg, before=True) - return TextObject(index) - - @text_object('}') - def _(event): - """ - Move to next blank-line separated section. - Implements '}', 'c}', 'd}', 'y}' - """ - index = event.current_buffer.document.end_of_paragraph(count=event.arg, after=True) - return TextObject(index) - - @text_object('f', Keys.Any) - def _(event): - """ - Go to next occurance of character. Typing 'fx' will move the - cursor to the next occurance of character. 'x'. - """ - event.cli.vi_state.last_character_find = CharacterFind(event.data, False) - match = event.current_buffer.document.find( - event.data, in_current_line=True, count=event.arg) - if match: - return TextObject(match, type=TextObjectType.INCLUSIVE) - else: - return TextObject(0) - - @text_object('F', Keys.Any) - def _(event): - """ - Go to previous occurance of character. Typing 'Fx' will move the - cursor to the previous occurance of character. 'x'. - """ - event.cli.vi_state.last_character_find = CharacterFind(event.data, True) - return TextObject(event.current_buffer.document.find_backwards( - event.data, in_current_line=True, count=event.arg) or 0) - - @text_object('t', Keys.Any) - def _(event): - """ - Move right to the next occurance of c, then one char backward. - """ - event.cli.vi_state.last_character_find = CharacterFind(event.data, False) - match = event.current_buffer.document.find( - event.data, in_current_line=True, count=event.arg) - if match: - return TextObject(match - 1, type=TextObjectType.INCLUSIVE) - else: - return TextObject(0) - - @text_object('T', Keys.Any) - def _(event): - """ - Move left to the previous occurance of c, then one char forward. - """ - event.cli.vi_state.last_character_find = CharacterFind(event.data, True) - match = event.current_buffer.document.find_backwards( - event.data, in_current_line=True, count=event.arg) - return TextObject(match + 1 if match else 0) - - def repeat(reverse): - """ - Create ',' and ';' commands. - """ - @text_object(',' if reverse else ';') - def _(event): - # Repeat the last 'f'/'F'/'t'/'T' command. - pos = 0 - vi_state = event.cli.vi_state - - type = TextObjectType.EXCLUSIVE - - if vi_state.last_character_find: - char = vi_state.last_character_find.character - backwards = vi_state.last_character_find.backwards - - if reverse: - backwards = not backwards - - if backwards: - pos = event.current_buffer.document.find_backwards(char, in_current_line=True, count=event.arg) - else: - pos = event.current_buffer.document.find(char, in_current_line=True, count=event.arg) - type = TextObjectType.INCLUSIVE - if pos: - return TextObject(pos, type=type) - else: - return TextObject(0) - repeat(True) - repeat(False) - - @text_object('h') - @text_object(Keys.Left) - def _(event): - """ Implements 'ch', 'dh', 'h': Cursor left. """ - return TextObject(event.current_buffer.document.get_cursor_left_position(count=event.arg)) - - @text_object('j', no_move_handler=True, no_selection_handler=True) - # Note: We also need `no_selection_handler`, because we in - # selection mode, we prefer the other 'j' binding that keeps - # `buffer.preferred_column`. - def _(event): - """ Implements 'cj', 'dj', 'j', ... Cursor up. """ - return TextObject(event.current_buffer.document.get_cursor_down_position(count=event.arg), - type=TextObjectType.LINEWISE) - - @text_object('k', no_move_handler=True, no_selection_handler=True) - def _(event): - """ Implements 'ck', 'dk', 'k', ... Cursor up. """ - return TextObject(event.current_buffer.document.get_cursor_up_position(count=event.arg), - type=TextObjectType.LINEWISE) - - @text_object('l') - @text_object(' ') - @text_object(Keys.Right) - def _(event): - """ Implements 'cl', 'dl', 'l', 'c ', 'd ', ' '. Cursor right. """ - return TextObject(event.current_buffer.document.get_cursor_right_position(count=event.arg)) - - @text_object('H') - def _(event): - """ - Moves to the start of the visible region. (Below the scroll offset.) - Implements 'cH', 'dH', 'H'. - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - b = event.current_buffer - - if w and w.render_info: - # When we find a Window that has BufferControl showing this window, - # move to the start of the visible area. - pos = (b.document.translate_row_col_to_index( - w.render_info.first_visible_line(after_scroll_offset=True), 0) - - b.cursor_position) - - else: - # Otherwise, move to the start of the input. - pos = -len(b.document.text_before_cursor) - return TextObject(pos, type=TextObjectType.LINEWISE) - - @text_object('M') - def _(event): - """ - Moves cursor to the vertical center of the visible region. - Implements 'cM', 'dM', 'M'. - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - b = event.current_buffer - - if w and w.render_info: - # When we find a Window that has BufferControl showing this window, - # move to the center of the visible area. - pos = (b.document.translate_row_col_to_index( - w.render_info.center_visible_line(), 0) - - b.cursor_position) - - else: - # Otherwise, move to the start of the input. - pos = -len(b.document.text_before_cursor) - return TextObject(pos, type=TextObjectType.LINEWISE) - - @text_object('L') - def _(event): - """ - Moves to the end of the visible region. (Above the scroll offset.) - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - b = event.current_buffer - - if w and w.render_info: - # When we find a Window that has BufferControl showing this window, - # move to the end of the visible area. - pos = (b.document.translate_row_col_to_index( - w.render_info.last_visible_line(before_scroll_offset=True), 0) - - b.cursor_position) - - else: - # Otherwise, move to the end of the input. - pos = len(b.document.text_after_cursor) - return TextObject(pos, type=TextObjectType.LINEWISE) - - @text_object('n', no_move_handler=True) - def _(event): - " Search next. " - buff = event.current_buffer - cursor_position = buff.get_search_position( - get_search_state(event.cli), include_current_position=False, - count=event.arg) - return TextObject(cursor_position - buff.cursor_position) - - @handle('n', filter=navigation_mode) - def _(event): - " Search next in navigation mode. (This goes through the history.) " - event.current_buffer.apply_search( - get_search_state(event.cli), include_current_position=False, - count=event.arg) - - @text_object('N', no_move_handler=True) - def _(event): - " Search previous. " - buff = event.current_buffer - cursor_position = buff.get_search_position( - ~get_search_state(event.cli), include_current_position=False, - count=event.arg) - return TextObject(cursor_position - buff.cursor_position) - - @handle('N', filter=navigation_mode) - def _(event): - " Search previous in navigation mode. (This goes through the history.) " - event.current_buffer.apply_search( - ~get_search_state(event.cli), include_current_position=False, - count=event.arg) - - @handle('z', '+', filter=navigation_mode|selection_mode) - @handle('z', 't', filter=navigation_mode|selection_mode) - @handle('z', Keys.ControlJ, filter=navigation_mode|selection_mode) - def _(event): - """ - Scrolls the window to makes the current line the first line in the visible region. - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - b = event.cli.current_buffer - w.vertical_scroll = b.document.cursor_position_row - - @handle('z', '-', filter=navigation_mode|selection_mode) - @handle('z', 'b', filter=navigation_mode|selection_mode) - def _(event): - """ - Scrolls the window to makes the current line the last line in the visible region. - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - - # We can safely set the scroll offset to zero; the Window will meke - # sure that it scrolls at least enough to make the cursor visible - # again. - w.vertical_scroll = 0 - - @handle('z', 'z', filter=navigation_mode|selection_mode) - def _(event): - """ - Center Window vertically around cursor. - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - b = event.cli.current_buffer - - if w and w.render_info: - info = w.render_info - - # Calculate the offset that we need in order to position the row - # containing the cursor in the center. - scroll_height = info.window_height // 2 - - y = max(0, b.document.cursor_position_row - 1) - height = 0 - while y > 0: - line_height = info.get_height_for_line(y) - - if height + line_height < scroll_height: - height += line_height - y -= 1 - else: - break - - w.vertical_scroll = y - - @text_object('%') - def _(event): - """ - Implements 'c%', 'd%', '%, 'y%' (Move to corresponding bracket.) - If an 'arg' has been given, go this this % position in the file. - """ - buffer = event.current_buffer - - if event._arg: - # If 'arg' has been given, the meaning of % is to go to the 'x%' - # row in the file. - if 0 < event.arg <= 100: - absolute_index = buffer.document.translate_row_col_to_index( - int((event.arg * buffer.document.line_count - 1) / 100), 0) - return TextObject(absolute_index - buffer.document.cursor_position, type=TextObjectType.LINEWISE) - else: - return TextObject(0) # Do nothing. - - else: - # Move to the corresponding opening/closing bracket (()'s, []'s and {}'s). - match = buffer.document.find_matching_bracket_position() - if match: - return TextObject(match, type=TextObjectType.INCLUSIVE) - else: - return TextObject(0) - - @text_object('|') - def _(event): - # Move to the n-th column (you may specify the argument n by typing - # it on number keys, for example, 20|). - return TextObject(event.current_buffer.document.get_column_cursor_position(event.arg - 1)) - - @text_object('g', 'g') - def _(event): - """ - Implements 'gg', 'cgg', 'ygg' - """ - d = event.current_buffer.document - - if event._arg: - # Move to the given line. - return TextObject(d.translate_row_col_to_index(event.arg - 1, 0) - d.cursor_position, type=TextObjectType.LINEWISE) - else: - # Move to the top of the input. - return TextObject(d.get_start_of_document_position(), type=TextObjectType.LINEWISE) - - @text_object('g', '_') - def _(event): - """ - Go to last non-blank of line. - 'g_', 'cg_', 'yg_', etc.. - """ - return TextObject( - event.current_buffer.document.last_non_blank_of_current_line_position(), type=TextObjectType.INCLUSIVE) - - @text_object('g', 'e') - def _(event): - """ - Go to last character of previous word. - 'ge', 'cge', 'yge', etc.. - """ - prev_end = event.current_buffer.document.find_previous_word_ending(count=event.arg) - return TextObject(prev_end - 1 if prev_end is not None else 0, type=TextObjectType.INCLUSIVE) - - @text_object('g', 'E') - def _(event): - """ - Go to last character of previous WORD. - 'gE', 'cgE', 'ygE', etc.. - """ - prev_end = event.current_buffer.document.find_previous_word_ending(count=event.arg, WORD=True) - return TextObject(prev_end - 1 if prev_end is not None else 0, type=TextObjectType.INCLUSIVE) - - @text_object('g', 'm') - def _(event): - """ - Like g0, but half a screenwidth to the right. (Or as much as possible.) - """ - w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) - buff = event.current_buffer - - if w and w.render_info: - width = w.render_info.window_width - start = buff.document.get_start_of_line_position(after_whitespace=False) - start += int(min(width / 2, len(buff.document.current_line))) - - return TextObject(start, type=TextObjectType.INCLUSIVE) - return TextObject(0) - - @text_object('G') - def _(event): - """ - Go to the end of the document. (If no arg has been given.) - """ - buf = event.current_buffer - return TextObject(buf.document.translate_row_col_to_index(buf.document.line_count - 1, 0) - - buf.cursor_position, type=TextObjectType.LINEWISE) - - # - # *** Other *** - # - - @handle('G', filter=HasArg()) - def _(event): - """ - If an argument is given, move to this line in the history. (for - example, 15G) - """ - event.current_buffer.go_to_history(event.arg - 1) - - for n in '123456789': - @handle(n, filter=navigation_mode|selection_mode|operator_given) - def _(event): - """ - Always handle numberics in navigation mode as arg. - """ - event.append_to_arg_count(event.data) - - @handle('0', filter=(navigation_mode|selection_mode|operator_given) & HasArg()) - def _(event): - " Zero when an argument was already give. " - event.append_to_arg_count(event.data) - - @handle(Keys.Any, filter=replace_mode) - def _(event): - """ - Insert data at cursor position. - """ - event.current_buffer.insert_text(event.data, overwrite=True) - - @handle(Keys.Any, filter=insert_multiple_mode, - save_before=(lambda e: not e.is_repeat)) - def _(event): - """ - Insert data at multiple cursor positions at once. - (Usually a result of pressing 'I' or 'A' in block-selection mode.) - """ - buff = event.current_buffer - original_text = buff.text - - # Construct new text. - text = [] - p = 0 - - for p2 in buff.multiple_cursor_positions: - text.append(original_text[p:p2]) - text.append(event.data) - p = p2 - - text.append(original_text[p:]) - - # Shift all cursor positions. - new_cursor_positions = [ - p + i + 1 for i, p in enumerate(buff.multiple_cursor_positions)] - - # Set result. - buff.text = ''.join(text) - buff.multiple_cursor_positions = new_cursor_positions - buff.cursor_position += 1 - - @handle(Keys.Backspace, filter=insert_multiple_mode) - def _(event): - " Backspace, using multiple cursors. " - buff = event.current_buffer - original_text = buff.text - - # Construct new text. - deleted_something = False - text = [] - p = 0 - - for p2 in buff.multiple_cursor_positions: - if p2 > 0 and original_text[p2 - 1] != '\n': # Don't delete across lines. - text.append(original_text[p:p2 - 1]) - deleted_something = True - else: - text.append(original_text[p:p2]) - p = p2 - - text.append(original_text[p:]) - - if deleted_something: - # Shift all cursor positions. - lengths = [len(part) for part in text[:-1]] - new_cursor_positions = list(accumulate(lengths)) - - # Set result. - buff.text = ''.join(text) - buff.multiple_cursor_positions = new_cursor_positions - buff.cursor_position -= 1 - else: - event.cli.output.bell() - - @handle(Keys.Delete, filter=insert_multiple_mode) - def _(event): - " Delete, using multiple cursors. " - buff = event.current_buffer - original_text = buff.text - - # Construct new text. - deleted_something = False - text = [] - new_cursor_positions = [] - p = 0 - - for p2 in buff.multiple_cursor_positions: - text.append(original_text[p:p2]) - if p2 >= len(original_text) or original_text[p2] == '\n': - # Don't delete across lines. - p = p2 - else: - p = p2 + 1 - deleted_something = True - - text.append(original_text[p:]) - - if deleted_something: - # Shift all cursor positions. - lengths = [len(part) for part in text[:-1]] - new_cursor_positions = list(accumulate(lengths)) - - # Set result. - buff.text = ''.join(text) - buff.multiple_cursor_positions = new_cursor_positions - else: - event.cli.output.bell() - - - @handle(Keys.ControlX, Keys.ControlL, filter=insert_mode) - def _(event): - """ - Pressing the ControlX - ControlL sequence in Vi mode does line - completion based on the other lines in the document and the history. - """ - event.current_buffer.start_history_lines_completion() - - @handle(Keys.ControlX, Keys.ControlF, filter=insert_mode) - def _(event): - """ - Complete file names. - """ - # TODO - pass - - @handle(Keys.ControlK, filter=insert_mode|replace_mode) - def _(event): - " Go into digraph mode. " - event.cli.vi_state.waiting_for_digraph = True - - @Condition - def digraph_symbol_1_given(cli): - return cli.vi_state.digraph_symbol1 is not None - - @handle(Keys.Any, filter=digraph_mode & ~digraph_symbol_1_given) - def _(event): - event.cli.vi_state.digraph_symbol1 = event.data - - @handle(Keys.Any, filter=digraph_mode & digraph_symbol_1_given) - def _(event): - " Insert digraph. " - try: - # Lookup. - code = (event.cli.vi_state.digraph_symbol1, event.data) - if code not in DIGRAPHS: - code = code[::-1] # Try reversing. - symbol = DIGRAPHS[code] - except KeyError: - # Unkown digraph. - event.cli.output.bell() - else: - # Insert digraph. - overwrite = event.cli.vi_state.input_mode == InputMode.REPLACE - event.current_buffer.insert_text( - six.unichr(symbol), overwrite=overwrite) - event.cli.vi_state.waiting_for_digraph = False - finally: - event.cli.vi_state.waiting_for_digraph = False - event.cli.vi_state.digraph_symbol1 = None - - return registry - - -def load_vi_open_in_editor_bindings(): - """ - Pressing 'v' in navigation mode will open the buffer in an external editor. - """ - registry = Registry() - navigation_mode = ViNavigationMode() - - registry.add_binding('v', filter=navigation_mode)( - get_by_name('edit-and-execute-command')) - return registry - - -def load_vi_system_bindings(): - registry = ConditionalRegistry(Registry(), ViMode()) - handle = registry.add_binding - - has_focus = filters.HasFocus(SYSTEM_BUFFER) - navigation_mode = ViNavigationMode() - - @handle('!', filter=~has_focus & navigation_mode) - def _(event): - """ - '!' opens the system prompt. - """ - event.cli.push_focus(SYSTEM_BUFFER) - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle(Keys.Escape, filter=has_focus) - @handle(Keys.ControlC, filter=has_focus) - def _(event): - """ - Cancel system prompt. - """ - event.cli.vi_state.input_mode = InputMode.NAVIGATION - event.cli.buffers[SYSTEM_BUFFER].reset() - event.cli.pop_focus() - - @handle(Keys.ControlJ, filter=has_focus) - def _(event): - """ - Run system command. - """ - event.cli.vi_state.input_mode = InputMode.NAVIGATION - - system_buffer = event.cli.buffers[SYSTEM_BUFFER] - event.cli.run_system_command(system_buffer.text) - system_buffer.reset(append_to_history=True) - - # Focus previous buffer again. - event.cli.pop_focus() - - return registry - - -def load_vi_search_bindings(get_search_state=None, - search_buffer_name=SEARCH_BUFFER): - assert get_search_state is None or callable(get_search_state) - - if not get_search_state: - def get_search_state(cli): return cli.search_state - - registry = ConditionalRegistry(Registry(), ViMode()) - handle = registry.add_binding - - has_focus = filters.HasFocus(search_buffer_name) - navigation_mode = ViNavigationMode() - selection_mode = ViSelectionMode() - - reverse_vi_search_direction = Condition( - lambda cli: cli.application.reverse_vi_search_direction(cli)) - - @handle('/', filter=(navigation_mode|selection_mode)&~reverse_vi_search_direction) - @handle('?', filter=(navigation_mode|selection_mode)&reverse_vi_search_direction) - @handle(Keys.ControlS, filter=~has_focus) - def _(event): - """ - Vi-style forward search. - """ - # Set the ViState. - get_search_state(event.cli).direction = IncrementalSearchDirection.FORWARD - event.cli.vi_state.input_mode = InputMode.INSERT - - # Focus search buffer. - event.cli.push_focus(search_buffer_name) - - @handle('?', filter=(navigation_mode|selection_mode)&~reverse_vi_search_direction) - @handle('/', filter=(navigation_mode|selection_mode)&reverse_vi_search_direction) - @handle(Keys.ControlR, filter=~has_focus) - def _(event): - """ - Vi-style backward search. - """ - # Set the ViState. - get_search_state(event.cli).direction = IncrementalSearchDirection.BACKWARD - - # Focus search buffer. - event.cli.push_focus(search_buffer_name) - event.cli.vi_state.input_mode = InputMode.INSERT - - @handle(Keys.ControlJ, filter=has_focus) - @handle(Keys.Escape, filter=has_focus) - def _(event): - """ - Apply the search. (At the / or ? prompt.) - """ - input_buffer = event.cli.buffers.previous(event.cli) - search_buffer = event.cli.buffers[search_buffer_name] - - # Update search state. - if search_buffer.text: - get_search_state(event.cli).text = search_buffer.text - - # Apply search. - input_buffer.apply_search(get_search_state(event.cli)) - - # Add query to history of search line. - search_buffer.append_to_history() - search_buffer.reset() - - # Focus previous document again. - event.cli.vi_state.input_mode = InputMode.NAVIGATION - event.cli.pop_focus() - - def incremental_search(cli, direction, count=1): - " Apply search, but keep search buffer focussed. " - # Update search_state. - search_state = get_search_state(cli) - direction_changed = search_state.direction != direction - - search_state.text = cli.buffers[search_buffer_name].text - search_state.direction = direction - - # Apply search to current buffer. - if not direction_changed: - input_buffer = cli.buffers.previous(cli) - input_buffer.apply_search(search_state, - include_current_position=False, count=count) - - @handle(Keys.ControlR, filter=has_focus) - def _(event): - incremental_search(event.cli, IncrementalSearchDirection.BACKWARD, count=event.arg) - - @handle(Keys.ControlS, filter=has_focus) - def _(event): - incremental_search(event.cli, IncrementalSearchDirection.FORWARD, count=event.arg) - - def search_buffer_is_empty(cli): - """ Returns True when the search buffer is empty. """ - return cli.buffers[search_buffer_name].text == '' - - @handle(Keys.ControlC, filter=has_focus) - @handle(Keys.ControlH, filter=has_focus & Condition(search_buffer_is_empty)) - @handle(Keys.Backspace, filter=has_focus & Condition(search_buffer_is_empty)) - def _(event): - """ - Cancel search. - """ - event.cli.vi_state.input_mode = InputMode.NAVIGATION - - event.cli.pop_focus() - event.cli.buffers[search_buffer_name].reset() - - return registry - - -def load_extra_vi_page_navigation_bindings(): - """ - Key bindings, for scrolling up and down through pages. - This are separate bindings, because GNU readline doesn't have them. - """ - registry = ConditionalRegistry(Registry(), ViMode()) - handle = registry.add_binding - - handle(Keys.ControlF)(scroll_forward) - handle(Keys.ControlB)(scroll_backward) - handle(Keys.ControlD)(scroll_half_page_down) - handle(Keys.ControlU)(scroll_half_page_up) - handle(Keys.ControlE)(scroll_one_line_down) - handle(Keys.ControlY)(scroll_one_line_up) - handle(Keys.PageDown)(scroll_page_down) - handle(Keys.PageUp)(scroll_page_up) - - return registry - - -class ViStateFilter(Filter): - " Deprecated! " - def __init__(self, get_vi_state, mode): - self.get_vi_state = get_vi_state - self.mode = mode - - def __call__(self, cli): - return self.get_vi_state(cli).input_mode == self.mode diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/defaults.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/defaults.py deleted file mode 100644 index fb2c1070f7..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/defaults.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -Default key bindings.:: - - registry = load_key_bindings() - app = Application(key_bindings_registry=registry) -""" -from __future__ import unicode_literals -from prompt_toolkit.key_binding.registry import ConditionalRegistry, MergedRegistry -from prompt_toolkit.key_binding.bindings.basic import load_basic_bindings, load_abort_and_exit_bindings, load_basic_system_bindings, load_auto_suggestion_bindings, load_mouse_bindings -from prompt_toolkit.key_binding.bindings.emacs import load_emacs_bindings, load_emacs_system_bindings, load_emacs_search_bindings, load_emacs_open_in_editor_bindings, load_extra_emacs_page_navigation_bindings -from prompt_toolkit.key_binding.bindings.vi import load_vi_bindings, load_vi_system_bindings, load_vi_search_bindings, load_vi_open_in_editor_bindings, load_extra_vi_page_navigation_bindings -from prompt_toolkit.filters import to_cli_filter - -__all__ = ( - 'load_key_bindings', - 'load_key_bindings_for_prompt', -) - - -def load_key_bindings( - get_search_state=None, - enable_abort_and_exit_bindings=False, - enable_system_bindings=False, - enable_search=False, - enable_open_in_editor=False, - enable_extra_page_navigation=False, - enable_auto_suggest_bindings=False): - """ - Create a Registry object that contains the default key bindings. - - :param enable_abort_and_exit_bindings: Filter to enable Ctrl-C and Ctrl-D. - :param enable_system_bindings: Filter to enable the system bindings (meta-! - prompt and Control-Z suspension.) - :param enable_search: Filter to enable the search bindings. - :param enable_open_in_editor: Filter to enable open-in-editor. - :param enable_open_in_editor: Filter to enable open-in-editor. - :param enable_extra_page_navigation: Filter for enabling extra page - navigation. (Bindings for up/down scrolling through long pages, like in - Emacs or Vi.) - :param enable_auto_suggest_bindings: Filter to enable fish-style suggestions. - """ - - assert get_search_state is None or callable(get_search_state) - - # Accept both Filters and booleans as input. - enable_abort_and_exit_bindings = to_cli_filter(enable_abort_and_exit_bindings) - enable_system_bindings = to_cli_filter(enable_system_bindings) - enable_search = to_cli_filter(enable_search) - enable_open_in_editor = to_cli_filter(enable_open_in_editor) - enable_extra_page_navigation = to_cli_filter(enable_extra_page_navigation) - enable_auto_suggest_bindings = to_cli_filter(enable_auto_suggest_bindings) - - registry = MergedRegistry([ - # Load basic bindings. - load_basic_bindings(), - load_mouse_bindings(), - - ConditionalRegistry(load_abort_and_exit_bindings(), - enable_abort_and_exit_bindings), - - ConditionalRegistry(load_basic_system_bindings(), - enable_system_bindings), - - # Load emacs bindings. - load_emacs_bindings(), - - ConditionalRegistry(load_emacs_open_in_editor_bindings(), - enable_open_in_editor), - - ConditionalRegistry(load_emacs_search_bindings(get_search_state=get_search_state), - enable_search), - - ConditionalRegistry(load_emacs_system_bindings(), - enable_system_bindings), - - ConditionalRegistry(load_extra_emacs_page_navigation_bindings(), - enable_extra_page_navigation), - - # Load Vi bindings. - load_vi_bindings(get_search_state=get_search_state), - - ConditionalRegistry(load_vi_open_in_editor_bindings(), - enable_open_in_editor), - - ConditionalRegistry(load_vi_search_bindings(get_search_state=get_search_state), - enable_search), - - ConditionalRegistry(load_vi_system_bindings(), - enable_system_bindings), - - ConditionalRegistry(load_extra_vi_page_navigation_bindings(), - enable_extra_page_navigation), - - # Suggestion bindings. - # (This has to come at the end, because the Vi bindings also have an - # implementation for the "right arrow", but we really want the - # suggestion binding when a suggestion is available.) - ConditionalRegistry(load_auto_suggestion_bindings(), - enable_auto_suggest_bindings), - ]) - - return registry - - -def load_key_bindings_for_prompt(**kw): - """ - Create a ``Registry`` object with the defaults key bindings for an input - prompt. - - This activates the key bindings for abort/exit (Ctrl-C/Ctrl-D), - incremental search and auto suggestions. - - (Not for full screen applications.) - """ - kw.setdefault('enable_abort_and_exit_bindings', True) - kw.setdefault('enable_search', True) - kw.setdefault('enable_auto_suggest_bindings', True) - - return load_key_bindings(**kw) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/digraphs.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/digraphs.py deleted file mode 100644 index 36c6b15103..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/digraphs.py +++ /dev/null @@ -1,1378 +0,0 @@ -# encoding: utf-8 -from __future__ import unicode_literals -""" -Vi Digraphs. -This is a list of special characters that can be inserted in Vi insert mode by -pressing Control-K followed by to normal characters. - -Taken from Neovim and translated to Python: -https://raw.githubusercontent.com/neovim/neovim/master/src/nvim/digraph.c -""" -__all__ = ('DIGRAPHS', ) - -# digraphs for Unicode from RFC1345 -# (also work for ISO-8859-1 aka latin1) -DIGRAPHS = { - ('N', 'U'): 0x00, - ('S', 'H'): 0x01, - ('S', 'X'): 0x02, - ('E', 'X'): 0x03, - ('E', 'T'): 0x04, - ('E', 'Q'): 0x05, - ('A', 'K'): 0x06, - ('B', 'L'): 0x07, - ('B', 'S'): 0x08, - ('H', 'T'): 0x09, - ('L', 'F'): 0x0a, - ('V', 'T'): 0x0b, - ('F', 'F'): 0x0c, - ('C', 'R'): 0x0d, - ('S', 'O'): 0x0e, - ('S', 'I'): 0x0f, - ('D', 'L'): 0x10, - ('D', '1'): 0x11, - ('D', '2'): 0x12, - ('D', '3'): 0x13, - ('D', '4'): 0x14, - ('N', 'K'): 0x15, - ('S', 'Y'): 0x16, - ('E', 'B'): 0x17, - ('C', 'N'): 0x18, - ('E', 'M'): 0x19, - ('S', 'B'): 0x1a, - ('E', 'C'): 0x1b, - ('F', 'S'): 0x1c, - ('G', 'S'): 0x1d, - ('R', 'S'): 0x1e, - ('U', 'S'): 0x1f, - ('S', 'P'): 0x20, - ('N', 'b'): 0x23, - ('D', 'O'): 0x24, - ('A', 't'): 0x40, - ('<', '('): 0x5b, - ('/', '/'): 0x5c, - (')', '>'): 0x5d, - ('\'', '>'): 0x5e, - ('\'', '!'): 0x60, - ('(', '!'): 0x7b, - ('!', '!'): 0x7c, - ('!', ')'): 0x7d, - ('\'', '?'): 0x7e, - ('D', 'T'): 0x7f, - ('P', 'A'): 0x80, - ('H', 'O'): 0x81, - ('B', 'H'): 0x82, - ('N', 'H'): 0x83, - ('I', 'N'): 0x84, - ('N', 'L'): 0x85, - ('S', 'A'): 0x86, - ('E', 'S'): 0x87, - ('H', 'S'): 0x88, - ('H', 'J'): 0x89, - ('V', 'S'): 0x8a, - ('P', 'D'): 0x8b, - ('P', 'U'): 0x8c, - ('R', 'I'): 0x8d, - ('S', '2'): 0x8e, - ('S', '3'): 0x8f, - ('D', 'C'): 0x90, - ('P', '1'): 0x91, - ('P', '2'): 0x92, - ('T', 'S'): 0x93, - ('C', 'C'): 0x94, - ('M', 'W'): 0x95, - ('S', 'G'): 0x96, - ('E', 'G'): 0x97, - ('S', 'S'): 0x98, - ('G', 'C'): 0x99, - ('S', 'C'): 0x9a, - ('C', 'I'): 0x9b, - ('S', 'T'): 0x9c, - ('O', 'C'): 0x9d, - ('P', 'M'): 0x9e, - ('A', 'C'): 0x9f, - ('N', 'S'): 0xa0, - ('!', 'I'): 0xa1, - ('C', 't'): 0xa2, - ('P', 'd'): 0xa3, - ('C', 'u'): 0xa4, - ('Y', 'e'): 0xa5, - ('B', 'B'): 0xa6, - ('S', 'E'): 0xa7, - ('\'', ':'): 0xa8, - ('C', 'o'): 0xa9, - ('-', 'a'): 0xaa, - ('<', '<'): 0xab, - ('N', 'O'): 0xac, - ('-', '-'): 0xad, - ('R', 'g'): 0xae, - ('\'', 'm'): 0xaf, - ('D', 'G'): 0xb0, - ('+', '-'): 0xb1, - ('2', 'S'): 0xb2, - ('3', 'S'): 0xb3, - ('\'', '\''): 0xb4, - ('M', 'y'): 0xb5, - ('P', 'I'): 0xb6, - ('.', 'M'): 0xb7, - ('\'', ','): 0xb8, - ('1', 'S'): 0xb9, - ('-', 'o'): 0xba, - ('>', '>'): 0xbb, - ('1', '4'): 0xbc, - ('1', '2'): 0xbd, - ('3', '4'): 0xbe, - ('?', 'I'): 0xbf, - ('A', '!'): 0xc0, - ('A', '\''): 0xc1, - ('A', '>'): 0xc2, - ('A', '?'): 0xc3, - ('A', ':'): 0xc4, - ('A', 'A'): 0xc5, - ('A', 'E'): 0xc6, - ('C', ','): 0xc7, - ('E', '!'): 0xc8, - ('E', '\''): 0xc9, - ('E', '>'): 0xca, - ('E', ':'): 0xcb, - ('I', '!'): 0xcc, - ('I', '\''): 0xcd, - ('I', '>'): 0xce, - ('I', ':'): 0xcf, - ('D', '-'): 0xd0, - ('N', '?'): 0xd1, - ('O', '!'): 0xd2, - ('O', '\''): 0xd3, - ('O', '>'): 0xd4, - ('O', '?'): 0xd5, - ('O', ':'): 0xd6, - ('*', 'X'): 0xd7, - ('O', '/'): 0xd8, - ('U', '!'): 0xd9, - ('U', '\''): 0xda, - ('U', '>'): 0xdb, - ('U', ':'): 0xdc, - ('Y', '\''): 0xdd, - ('T', 'H'): 0xde, - ('s', 's'): 0xdf, - ('a', '!'): 0xe0, - ('a', '\''): 0xe1, - ('a', '>'): 0xe2, - ('a', '?'): 0xe3, - ('a', ':'): 0xe4, - ('a', 'a'): 0xe5, - ('a', 'e'): 0xe6, - ('c', ','): 0xe7, - ('e', '!'): 0xe8, - ('e', '\''): 0xe9, - ('e', '>'): 0xea, - ('e', ':'): 0xeb, - ('i', '!'): 0xec, - ('i', '\''): 0xed, - ('i', '>'): 0xee, - ('i', ':'): 0xef, - ('d', '-'): 0xf0, - ('n', '?'): 0xf1, - ('o', '!'): 0xf2, - ('o', '\''): 0xf3, - ('o', '>'): 0xf4, - ('o', '?'): 0xf5, - ('o', ':'): 0xf6, - ('-', ':'): 0xf7, - ('o', '/'): 0xf8, - ('u', '!'): 0xf9, - ('u', '\''): 0xfa, - ('u', '>'): 0xfb, - ('u', ':'): 0xfc, - ('y', '\''): 0xfd, - ('t', 'h'): 0xfe, - ('y', ':'): 0xff, - - ('A', '-'): 0x0100, - ('a', '-'): 0x0101, - ('A', '('): 0x0102, - ('a', '('): 0x0103, - ('A', ';'): 0x0104, - ('a', ';'): 0x0105, - ('C', '\''): 0x0106, - ('c', '\''): 0x0107, - ('C', '>'): 0x0108, - ('c', '>'): 0x0109, - ('C', '.'): 0x010a, - ('c', '.'): 0x010b, - ('C', '<'): 0x010c, - ('c', '<'): 0x010d, - ('D', '<'): 0x010e, - ('d', '<'): 0x010f, - ('D', '/'): 0x0110, - ('d', '/'): 0x0111, - ('E', '-'): 0x0112, - ('e', '-'): 0x0113, - ('E', '('): 0x0114, - ('e', '('): 0x0115, - ('E', '.'): 0x0116, - ('e', '.'): 0x0117, - ('E', ';'): 0x0118, - ('e', ';'): 0x0119, - ('E', '<'): 0x011a, - ('e', '<'): 0x011b, - ('G', '>'): 0x011c, - ('g', '>'): 0x011d, - ('G', '('): 0x011e, - ('g', '('): 0x011f, - ('G', '.'): 0x0120, - ('g', '.'): 0x0121, - ('G', ','): 0x0122, - ('g', ','): 0x0123, - ('H', '>'): 0x0124, - ('h', '>'): 0x0125, - ('H', '/'): 0x0126, - ('h', '/'): 0x0127, - ('I', '?'): 0x0128, - ('i', '?'): 0x0129, - ('I', '-'): 0x012a, - ('i', '-'): 0x012b, - ('I', '('): 0x012c, - ('i', '('): 0x012d, - ('I', ';'): 0x012e, - ('i', ';'): 0x012f, - ('I', '.'): 0x0130, - ('i', '.'): 0x0131, - ('I', 'J'): 0x0132, - ('i', 'j'): 0x0133, - ('J', '>'): 0x0134, - ('j', '>'): 0x0135, - ('K', ','): 0x0136, - ('k', ','): 0x0137, - ('k', 'k'): 0x0138, - ('L', '\''): 0x0139, - ('l', '\''): 0x013a, - ('L', ','): 0x013b, - ('l', ','): 0x013c, - ('L', '<'): 0x013d, - ('l', '<'): 0x013e, - ('L', '.'): 0x013f, - ('l', '.'): 0x0140, - ('L', '/'): 0x0141, - ('l', '/'): 0x0142, - ('N', '\''): 0x0143, - ('n', '\''): 0x0144, - ('N', ','): 0x0145, - ('n', ','): 0x0146, - ('N', '<'): 0x0147, - ('n', '<'): 0x0148, - ('\'', 'n'): 0x0149, - ('N', 'G'): 0x014a, - ('n', 'g'): 0x014b, - ('O', '-'): 0x014c, - ('o', '-'): 0x014d, - ('O', '('): 0x014e, - ('o', '('): 0x014f, - ('O', '"'): 0x0150, - ('o', '"'): 0x0151, - ('O', 'E'): 0x0152, - ('o', 'e'): 0x0153, - ('R', '\''): 0x0154, - ('r', '\''): 0x0155, - ('R', ','): 0x0156, - ('r', ','): 0x0157, - ('R', '<'): 0x0158, - ('r', '<'): 0x0159, - ('S', '\''): 0x015a, - ('s', '\''): 0x015b, - ('S', '>'): 0x015c, - ('s', '>'): 0x015d, - ('S', ','): 0x015e, - ('s', ','): 0x015f, - ('S', '<'): 0x0160, - ('s', '<'): 0x0161, - ('T', ','): 0x0162, - ('t', ','): 0x0163, - ('T', '<'): 0x0164, - ('t', '<'): 0x0165, - ('T', '/'): 0x0166, - ('t', '/'): 0x0167, - ('U', '?'): 0x0168, - ('u', '?'): 0x0169, - ('U', '-'): 0x016a, - ('u', '-'): 0x016b, - ('U', '('): 0x016c, - ('u', '('): 0x016d, - ('U', '0'): 0x016e, - ('u', '0'): 0x016f, - ('U', '"'): 0x0170, - ('u', '"'): 0x0171, - ('U', ';'): 0x0172, - ('u', ';'): 0x0173, - ('W', '>'): 0x0174, - ('w', '>'): 0x0175, - ('Y', '>'): 0x0176, - ('y', '>'): 0x0177, - ('Y', ':'): 0x0178, - ('Z', '\''): 0x0179, - ('z', '\''): 0x017a, - ('Z', '.'): 0x017b, - ('z', '.'): 0x017c, - ('Z', '<'): 0x017d, - ('z', '<'): 0x017e, - ('O', '9'): 0x01a0, - ('o', '9'): 0x01a1, - ('O', 'I'): 0x01a2, - ('o', 'i'): 0x01a3, - ('y', 'r'): 0x01a6, - ('U', '9'): 0x01af, - ('u', '9'): 0x01b0, - ('Z', '/'): 0x01b5, - ('z', '/'): 0x01b6, - ('E', 'D'): 0x01b7, - ('A', '<'): 0x01cd, - ('a', '<'): 0x01ce, - ('I', '<'): 0x01cf, - ('i', '<'): 0x01d0, - ('O', '<'): 0x01d1, - ('o', '<'): 0x01d2, - ('U', '<'): 0x01d3, - ('u', '<'): 0x01d4, - ('A', '1'): 0x01de, - ('a', '1'): 0x01df, - ('A', '7'): 0x01e0, - ('a', '7'): 0x01e1, - ('A', '3'): 0x01e2, - ('a', '3'): 0x01e3, - ('G', '/'): 0x01e4, - ('g', '/'): 0x01e5, - ('G', '<'): 0x01e6, - ('g', '<'): 0x01e7, - ('K', '<'): 0x01e8, - ('k', '<'): 0x01e9, - ('O', ';'): 0x01ea, - ('o', ';'): 0x01eb, - ('O', '1'): 0x01ec, - ('o', '1'): 0x01ed, - ('E', 'Z'): 0x01ee, - ('e', 'z'): 0x01ef, - ('j', '<'): 0x01f0, - ('G', '\''): 0x01f4, - ('g', '\''): 0x01f5, - (';', 'S'): 0x02bf, - ('\'', '<'): 0x02c7, - ('\'', '('): 0x02d8, - ('\'', '.'): 0x02d9, - ('\'', '0'): 0x02da, - ('\'', ';'): 0x02db, - ('\'', '"'): 0x02dd, - ('A', '%'): 0x0386, - ('E', '%'): 0x0388, - ('Y', '%'): 0x0389, - ('I', '%'): 0x038a, - ('O', '%'): 0x038c, - ('U', '%'): 0x038e, - ('W', '%'): 0x038f, - ('i', '3'): 0x0390, - ('A', '*'): 0x0391, - ('B', '*'): 0x0392, - ('G', '*'): 0x0393, - ('D', '*'): 0x0394, - ('E', '*'): 0x0395, - ('Z', '*'): 0x0396, - ('Y', '*'): 0x0397, - ('H', '*'): 0x0398, - ('I', '*'): 0x0399, - ('K', '*'): 0x039a, - ('L', '*'): 0x039b, - ('M', '*'): 0x039c, - ('N', '*'): 0x039d, - ('C', '*'): 0x039e, - ('O', '*'): 0x039f, - ('P', '*'): 0x03a0, - ('R', '*'): 0x03a1, - ('S', '*'): 0x03a3, - ('T', '*'): 0x03a4, - ('U', '*'): 0x03a5, - ('F', '*'): 0x03a6, - ('X', '*'): 0x03a7, - ('Q', '*'): 0x03a8, - ('W', '*'): 0x03a9, - ('J', '*'): 0x03aa, - ('V', '*'): 0x03ab, - ('a', '%'): 0x03ac, - ('e', '%'): 0x03ad, - ('y', '%'): 0x03ae, - ('i', '%'): 0x03af, - ('u', '3'): 0x03b0, - ('a', '*'): 0x03b1, - ('b', '*'): 0x03b2, - ('g', '*'): 0x03b3, - ('d', '*'): 0x03b4, - ('e', '*'): 0x03b5, - ('z', '*'): 0x03b6, - ('y', '*'): 0x03b7, - ('h', '*'): 0x03b8, - ('i', '*'): 0x03b9, - ('k', '*'): 0x03ba, - ('l', '*'): 0x03bb, - ('m', '*'): 0x03bc, - ('n', '*'): 0x03bd, - ('c', '*'): 0x03be, - ('o', '*'): 0x03bf, - ('p', '*'): 0x03c0, - ('r', '*'): 0x03c1, - ('*', 's'): 0x03c2, - ('s', '*'): 0x03c3, - ('t', '*'): 0x03c4, - ('u', '*'): 0x03c5, - ('f', '*'): 0x03c6, - ('x', '*'): 0x03c7, - ('q', '*'): 0x03c8, - ('w', '*'): 0x03c9, - ('j', '*'): 0x03ca, - ('v', '*'): 0x03cb, - ('o', '%'): 0x03cc, - ('u', '%'): 0x03cd, - ('w', '%'): 0x03ce, - ('\'', 'G'): 0x03d8, - (',', 'G'): 0x03d9, - ('T', '3'): 0x03da, - ('t', '3'): 0x03db, - ('M', '3'): 0x03dc, - ('m', '3'): 0x03dd, - ('K', '3'): 0x03de, - ('k', '3'): 0x03df, - ('P', '3'): 0x03e0, - ('p', '3'): 0x03e1, - ('\'', '%'): 0x03f4, - ('j', '3'): 0x03f5, - ('I', 'O'): 0x0401, - ('D', '%'): 0x0402, - ('G', '%'): 0x0403, - ('I', 'E'): 0x0404, - ('D', 'S'): 0x0405, - ('I', 'I'): 0x0406, - ('Y', 'I'): 0x0407, - ('J', '%'): 0x0408, - ('L', 'J'): 0x0409, - ('N', 'J'): 0x040a, - ('T', 's'): 0x040b, - ('K', 'J'): 0x040c, - ('V', '%'): 0x040e, - ('D', 'Z'): 0x040f, - ('A', '='): 0x0410, - ('B', '='): 0x0411, - ('V', '='): 0x0412, - ('G', '='): 0x0413, - ('D', '='): 0x0414, - ('E', '='): 0x0415, - ('Z', '%'): 0x0416, - ('Z', '='): 0x0417, - ('I', '='): 0x0418, - ('J', '='): 0x0419, - ('K', '='): 0x041a, - ('L', '='): 0x041b, - ('M', '='): 0x041c, - ('N', '='): 0x041d, - ('O', '='): 0x041e, - ('P', '='): 0x041f, - ('R', '='): 0x0420, - ('S', '='): 0x0421, - ('T', '='): 0x0422, - ('U', '='): 0x0423, - ('F', '='): 0x0424, - ('H', '='): 0x0425, - ('C', '='): 0x0426, - ('C', '%'): 0x0427, - ('S', '%'): 0x0428, - ('S', 'c'): 0x0429, - ('=', '"'): 0x042a, - ('Y', '='): 0x042b, - ('%', '"'): 0x042c, - ('J', 'E'): 0x042d, - ('J', 'U'): 0x042e, - ('J', 'A'): 0x042f, - ('a', '='): 0x0430, - ('b', '='): 0x0431, - ('v', '='): 0x0432, - ('g', '='): 0x0433, - ('d', '='): 0x0434, - ('e', '='): 0x0435, - ('z', '%'): 0x0436, - ('z', '='): 0x0437, - ('i', '='): 0x0438, - ('j', '='): 0x0439, - ('k', '='): 0x043a, - ('l', '='): 0x043b, - ('m', '='): 0x043c, - ('n', '='): 0x043d, - ('o', '='): 0x043e, - ('p', '='): 0x043f, - ('r', '='): 0x0440, - ('s', '='): 0x0441, - ('t', '='): 0x0442, - ('u', '='): 0x0443, - ('f', '='): 0x0444, - ('h', '='): 0x0445, - ('c', '='): 0x0446, - ('c', '%'): 0x0447, - ('s', '%'): 0x0448, - ('s', 'c'): 0x0449, - ('=', '\''): 0x044a, - ('y', '='): 0x044b, - ('%', '\''): 0x044c, - ('j', 'e'): 0x044d, - ('j', 'u'): 0x044e, - ('j', 'a'): 0x044f, - ('i', 'o'): 0x0451, - ('d', '%'): 0x0452, - ('g', '%'): 0x0453, - ('i', 'e'): 0x0454, - ('d', 's'): 0x0455, - ('i', 'i'): 0x0456, - ('y', 'i'): 0x0457, - ('j', '%'): 0x0458, - ('l', 'j'): 0x0459, - ('n', 'j'): 0x045a, - ('t', 's'): 0x045b, - ('k', 'j'): 0x045c, - ('v', '%'): 0x045e, - ('d', 'z'): 0x045f, - ('Y', '3'): 0x0462, - ('y', '3'): 0x0463, - ('O', '3'): 0x046a, - ('o', '3'): 0x046b, - ('F', '3'): 0x0472, - ('f', '3'): 0x0473, - ('V', '3'): 0x0474, - ('v', '3'): 0x0475, - ('C', '3'): 0x0480, - ('c', '3'): 0x0481, - ('G', '3'): 0x0490, - ('g', '3'): 0x0491, - ('A', '+'): 0x05d0, - ('B', '+'): 0x05d1, - ('G', '+'): 0x05d2, - ('D', '+'): 0x05d3, - ('H', '+'): 0x05d4, - ('W', '+'): 0x05d5, - ('Z', '+'): 0x05d6, - ('X', '+'): 0x05d7, - ('T', 'j'): 0x05d8, - ('J', '+'): 0x05d9, - ('K', '%'): 0x05da, - ('K', '+'): 0x05db, - ('L', '+'): 0x05dc, - ('M', '%'): 0x05dd, - ('M', '+'): 0x05de, - ('N', '%'): 0x05df, - ('N', '+'): 0x05e0, - ('S', '+'): 0x05e1, - ('E', '+'): 0x05e2, - ('P', '%'): 0x05e3, - ('P', '+'): 0x05e4, - ('Z', 'j'): 0x05e5, - ('Z', 'J'): 0x05e6, - ('Q', '+'): 0x05e7, - ('R', '+'): 0x05e8, - ('S', 'h'): 0x05e9, - ('T', '+'): 0x05ea, - (',', '+'): 0x060c, - (';', '+'): 0x061b, - ('?', '+'): 0x061f, - ('H', '\''): 0x0621, - ('a', 'M'): 0x0622, - ('a', 'H'): 0x0623, - ('w', 'H'): 0x0624, - ('a', 'h'): 0x0625, - ('y', 'H'): 0x0626, - ('a', '+'): 0x0627, - ('b', '+'): 0x0628, - ('t', 'm'): 0x0629, - ('t', '+'): 0x062a, - ('t', 'k'): 0x062b, - ('g', '+'): 0x062c, - ('h', 'k'): 0x062d, - ('x', '+'): 0x062e, - ('d', '+'): 0x062f, - ('d', 'k'): 0x0630, - ('r', '+'): 0x0631, - ('z', '+'): 0x0632, - ('s', '+'): 0x0633, - ('s', 'n'): 0x0634, - ('c', '+'): 0x0635, - ('d', 'd'): 0x0636, - ('t', 'j'): 0x0637, - ('z', 'H'): 0x0638, - ('e', '+'): 0x0639, - ('i', '+'): 0x063a, - ('+', '+'): 0x0640, - ('f', '+'): 0x0641, - ('q', '+'): 0x0642, - ('k', '+'): 0x0643, - ('l', '+'): 0x0644, - ('m', '+'): 0x0645, - ('n', '+'): 0x0646, - ('h', '+'): 0x0647, - ('w', '+'): 0x0648, - ('j', '+'): 0x0649, - ('y', '+'): 0x064a, - (':', '+'): 0x064b, - ('"', '+'): 0x064c, - ('=', '+'): 0x064d, - ('/', '+'): 0x064e, - ('\'', '+'): 0x064f, - ('1', '+'): 0x0650, - ('3', '+'): 0x0651, - ('0', '+'): 0x0652, - ('a', 'S'): 0x0670, - ('p', '+'): 0x067e, - ('v', '+'): 0x06a4, - ('g', 'f'): 0x06af, - ('0', 'a'): 0x06f0, - ('1', 'a'): 0x06f1, - ('2', 'a'): 0x06f2, - ('3', 'a'): 0x06f3, - ('4', 'a'): 0x06f4, - ('5', 'a'): 0x06f5, - ('6', 'a'): 0x06f6, - ('7', 'a'): 0x06f7, - ('8', 'a'): 0x06f8, - ('9', 'a'): 0x06f9, - ('B', '.'): 0x1e02, - ('b', '.'): 0x1e03, - ('B', '_'): 0x1e06, - ('b', '_'): 0x1e07, - ('D', '.'): 0x1e0a, - ('d', '.'): 0x1e0b, - ('D', '_'): 0x1e0e, - ('d', '_'): 0x1e0f, - ('D', ','): 0x1e10, - ('d', ','): 0x1e11, - ('F', '.'): 0x1e1e, - ('f', '.'): 0x1e1f, - ('G', '-'): 0x1e20, - ('g', '-'): 0x1e21, - ('H', '.'): 0x1e22, - ('h', '.'): 0x1e23, - ('H', ':'): 0x1e26, - ('h', ':'): 0x1e27, - ('H', ','): 0x1e28, - ('h', ','): 0x1e29, - ('K', '\''): 0x1e30, - ('k', '\''): 0x1e31, - ('K', '_'): 0x1e34, - ('k', '_'): 0x1e35, - ('L', '_'): 0x1e3a, - ('l', '_'): 0x1e3b, - ('M', '\''): 0x1e3e, - ('m', '\''): 0x1e3f, - ('M', '.'): 0x1e40, - ('m', '.'): 0x1e41, - ('N', '.'): 0x1e44, - ('n', '.'): 0x1e45, - ('N', '_'): 0x1e48, - ('n', '_'): 0x1e49, - ('P', '\''): 0x1e54, - ('p', '\''): 0x1e55, - ('P', '.'): 0x1e56, - ('p', '.'): 0x1e57, - ('R', '.'): 0x1e58, - ('r', '.'): 0x1e59, - ('R', '_'): 0x1e5e, - ('r', '_'): 0x1e5f, - ('S', '.'): 0x1e60, - ('s', '.'): 0x1e61, - ('T', '.'): 0x1e6a, - ('t', '.'): 0x1e6b, - ('T', '_'): 0x1e6e, - ('t', '_'): 0x1e6f, - ('V', '?'): 0x1e7c, - ('v', '?'): 0x1e7d, - ('W', '!'): 0x1e80, - ('w', '!'): 0x1e81, - ('W', '\''): 0x1e82, - ('w', '\''): 0x1e83, - ('W', ':'): 0x1e84, - ('w', ':'): 0x1e85, - ('W', '.'): 0x1e86, - ('w', '.'): 0x1e87, - ('X', '.'): 0x1e8a, - ('x', '.'): 0x1e8b, - ('X', ':'): 0x1e8c, - ('x', ':'): 0x1e8d, - ('Y', '.'): 0x1e8e, - ('y', '.'): 0x1e8f, - ('Z', '>'): 0x1e90, - ('z', '>'): 0x1e91, - ('Z', '_'): 0x1e94, - ('z', '_'): 0x1e95, - ('h', '_'): 0x1e96, - ('t', ':'): 0x1e97, - ('w', '0'): 0x1e98, - ('y', '0'): 0x1e99, - ('A', '2'): 0x1ea2, - ('a', '2'): 0x1ea3, - ('E', '2'): 0x1eba, - ('e', '2'): 0x1ebb, - ('E', '?'): 0x1ebc, - ('e', '?'): 0x1ebd, - ('I', '2'): 0x1ec8, - ('i', '2'): 0x1ec9, - ('O', '2'): 0x1ece, - ('o', '2'): 0x1ecf, - ('U', '2'): 0x1ee6, - ('u', '2'): 0x1ee7, - ('Y', '!'): 0x1ef2, - ('y', '!'): 0x1ef3, - ('Y', '2'): 0x1ef6, - ('y', '2'): 0x1ef7, - ('Y', '?'): 0x1ef8, - ('y', '?'): 0x1ef9, - (';', '\''): 0x1f00, - (',', '\''): 0x1f01, - (';', '!'): 0x1f02, - (',', '!'): 0x1f03, - ('?', ';'): 0x1f04, - ('?', ','): 0x1f05, - ('!', ':'): 0x1f06, - ('?', ':'): 0x1f07, - ('1', 'N'): 0x2002, - ('1', 'M'): 0x2003, - ('3', 'M'): 0x2004, - ('4', 'M'): 0x2005, - ('6', 'M'): 0x2006, - ('1', 'T'): 0x2009, - ('1', 'H'): 0x200a, - ('-', '1'): 0x2010, - ('-', 'N'): 0x2013, - ('-', 'M'): 0x2014, - ('-', '3'): 0x2015, - ('!', '2'): 0x2016, - ('=', '2'): 0x2017, - ('\'', '6'): 0x2018, - ('\'', '9'): 0x2019, - ('.', '9'): 0x201a, - ('9', '\''): 0x201b, - ('"', '6'): 0x201c, - ('"', '9'): 0x201d, - (':', '9'): 0x201e, - ('9', '"'): 0x201f, - ('/', '-'): 0x2020, - ('/', '='): 0x2021, - ('.', '.'): 0x2025, - ('%', '0'): 0x2030, - ('1', '\''): 0x2032, - ('2', '\''): 0x2033, - ('3', '\''): 0x2034, - ('1', '"'): 0x2035, - ('2', '"'): 0x2036, - ('3', '"'): 0x2037, - ('C', 'a'): 0x2038, - ('<', '1'): 0x2039, - ('>', '1'): 0x203a, - (':', 'X'): 0x203b, - ('\'', '-'): 0x203e, - ('/', 'f'): 0x2044, - ('0', 'S'): 0x2070, - ('4', 'S'): 0x2074, - ('5', 'S'): 0x2075, - ('6', 'S'): 0x2076, - ('7', 'S'): 0x2077, - ('8', 'S'): 0x2078, - ('9', 'S'): 0x2079, - ('+', 'S'): 0x207a, - ('-', 'S'): 0x207b, - ('=', 'S'): 0x207c, - ('(', 'S'): 0x207d, - (')', 'S'): 0x207e, - ('n', 'S'): 0x207f, - ('0', 's'): 0x2080, - ('1', 's'): 0x2081, - ('2', 's'): 0x2082, - ('3', 's'): 0x2083, - ('4', 's'): 0x2084, - ('5', 's'): 0x2085, - ('6', 's'): 0x2086, - ('7', 's'): 0x2087, - ('8', 's'): 0x2088, - ('9', 's'): 0x2089, - ('+', 's'): 0x208a, - ('-', 's'): 0x208b, - ('=', 's'): 0x208c, - ('(', 's'): 0x208d, - (')', 's'): 0x208e, - ('L', 'i'): 0x20a4, - ('P', 't'): 0x20a7, - ('W', '='): 0x20a9, - ('=', 'e'): 0x20ac, # euro - ('E', 'u'): 0x20ac, # euro - ('=', 'R'): 0x20bd, # rouble - ('=', 'P'): 0x20bd, # rouble - ('o', 'C'): 0x2103, - ('c', 'o'): 0x2105, - ('o', 'F'): 0x2109, - ('N', '0'): 0x2116, - ('P', 'O'): 0x2117, - ('R', 'x'): 0x211e, - ('S', 'M'): 0x2120, - ('T', 'M'): 0x2122, - ('O', 'm'): 0x2126, - ('A', 'O'): 0x212b, - ('1', '3'): 0x2153, - ('2', '3'): 0x2154, - ('1', '5'): 0x2155, - ('2', '5'): 0x2156, - ('3', '5'): 0x2157, - ('4', '5'): 0x2158, - ('1', '6'): 0x2159, - ('5', '6'): 0x215a, - ('1', '8'): 0x215b, - ('3', '8'): 0x215c, - ('5', '8'): 0x215d, - ('7', '8'): 0x215e, - ('1', 'R'): 0x2160, - ('2', 'R'): 0x2161, - ('3', 'R'): 0x2162, - ('4', 'R'): 0x2163, - ('5', 'R'): 0x2164, - ('6', 'R'): 0x2165, - ('7', 'R'): 0x2166, - ('8', 'R'): 0x2167, - ('9', 'R'): 0x2168, - ('a', 'R'): 0x2169, - ('b', 'R'): 0x216a, - ('c', 'R'): 0x216b, - ('1', 'r'): 0x2170, - ('2', 'r'): 0x2171, - ('3', 'r'): 0x2172, - ('4', 'r'): 0x2173, - ('5', 'r'): 0x2174, - ('6', 'r'): 0x2175, - ('7', 'r'): 0x2176, - ('8', 'r'): 0x2177, - ('9', 'r'): 0x2178, - ('a', 'r'): 0x2179, - ('b', 'r'): 0x217a, - ('c', 'r'): 0x217b, - ('<', '-'): 0x2190, - ('-', '!'): 0x2191, - ('-', '>'): 0x2192, - ('-', 'v'): 0x2193, - ('<', '>'): 0x2194, - ('U', 'D'): 0x2195, - ('<', '='): 0x21d0, - ('=', '>'): 0x21d2, - ('=', '='): 0x21d4, - ('F', 'A'): 0x2200, - ('d', 'P'): 0x2202, - ('T', 'E'): 0x2203, - ('/', '0'): 0x2205, - ('D', 'E'): 0x2206, - ('N', 'B'): 0x2207, - ('(', '-'): 0x2208, - ('-', ')'): 0x220b, - ('*', 'P'): 0x220f, - ('+', 'Z'): 0x2211, - ('-', '2'): 0x2212, - ('-', '+'): 0x2213, - ('*', '-'): 0x2217, - ('O', 'b'): 0x2218, - ('S', 'b'): 0x2219, - ('R', 'T'): 0x221a, - ('0', '('): 0x221d, - ('0', '0'): 0x221e, - ('-', 'L'): 0x221f, - ('-', 'V'): 0x2220, - ('P', 'P'): 0x2225, - ('A', 'N'): 0x2227, - ('O', 'R'): 0x2228, - ('(', 'U'): 0x2229, - (')', 'U'): 0x222a, - ('I', 'n'): 0x222b, - ('D', 'I'): 0x222c, - ('I', 'o'): 0x222e, - ('.', ':'): 0x2234, - (':', '.'): 0x2235, - (':', 'R'): 0x2236, - (':', ':'): 0x2237, - ('?', '1'): 0x223c, - ('C', 'G'): 0x223e, - ('?', '-'): 0x2243, - ('?', '='): 0x2245, - ('?', '2'): 0x2248, - ('=', '?'): 0x224c, - ('H', 'I'): 0x2253, - ('!', '='): 0x2260, - ('=', '3'): 0x2261, - ('=', '<'): 0x2264, - ('>', '='): 0x2265, - ('<', '*'): 0x226a, - ('*', '>'): 0x226b, - ('!', '<'): 0x226e, - ('!', '>'): 0x226f, - ('(', 'C'): 0x2282, - (')', 'C'): 0x2283, - ('(', '_'): 0x2286, - (')', '_'): 0x2287, - ('0', '.'): 0x2299, - ('0', '2'): 0x229a, - ('-', 'T'): 0x22a5, - ('.', 'P'): 0x22c5, - (':', '3'): 0x22ee, - ('.', '3'): 0x22ef, - ('E', 'h'): 0x2302, - ('<', '7'): 0x2308, - ('>', '7'): 0x2309, - ('7', '<'): 0x230a, - ('7', '>'): 0x230b, - ('N', 'I'): 0x2310, - ('(', 'A'): 0x2312, - ('T', 'R'): 0x2315, - ('I', 'u'): 0x2320, - ('I', 'l'): 0x2321, - ('<', '/'): 0x2329, - ('/', '>'): 0x232a, - ('V', 's'): 0x2423, - ('1', 'h'): 0x2440, - ('3', 'h'): 0x2441, - ('2', 'h'): 0x2442, - ('4', 'h'): 0x2443, - ('1', 'j'): 0x2446, - ('2', 'j'): 0x2447, - ('3', 'j'): 0x2448, - ('4', 'j'): 0x2449, - ('1', '.'): 0x2488, - ('2', '.'): 0x2489, - ('3', '.'): 0x248a, - ('4', '.'): 0x248b, - ('5', '.'): 0x248c, - ('6', '.'): 0x248d, - ('7', '.'): 0x248e, - ('8', '.'): 0x248f, - ('9', '.'): 0x2490, - ('h', 'h'): 0x2500, - ('H', 'H'): 0x2501, - ('v', 'v'): 0x2502, - ('V', 'V'): 0x2503, - ('3', '-'): 0x2504, - ('3', '_'): 0x2505, - ('3', '!'): 0x2506, - ('3', '/'): 0x2507, - ('4', '-'): 0x2508, - ('4', '_'): 0x2509, - ('4', '!'): 0x250a, - ('4', '/'): 0x250b, - ('d', 'r'): 0x250c, - ('d', 'R'): 0x250d, - ('D', 'r'): 0x250e, - ('D', 'R'): 0x250f, - ('d', 'l'): 0x2510, - ('d', 'L'): 0x2511, - ('D', 'l'): 0x2512, - ('L', 'D'): 0x2513, - ('u', 'r'): 0x2514, - ('u', 'R'): 0x2515, - ('U', 'r'): 0x2516, - ('U', 'R'): 0x2517, - ('u', 'l'): 0x2518, - ('u', 'L'): 0x2519, - ('U', 'l'): 0x251a, - ('U', 'L'): 0x251b, - ('v', 'r'): 0x251c, - ('v', 'R'): 0x251d, - ('V', 'r'): 0x2520, - ('V', 'R'): 0x2523, - ('v', 'l'): 0x2524, - ('v', 'L'): 0x2525, - ('V', 'l'): 0x2528, - ('V', 'L'): 0x252b, - ('d', 'h'): 0x252c, - ('d', 'H'): 0x252f, - ('D', 'h'): 0x2530, - ('D', 'H'): 0x2533, - ('u', 'h'): 0x2534, - ('u', 'H'): 0x2537, - ('U', 'h'): 0x2538, - ('U', 'H'): 0x253b, - ('v', 'h'): 0x253c, - ('v', 'H'): 0x253f, - ('V', 'h'): 0x2542, - ('V', 'H'): 0x254b, - ('F', 'D'): 0x2571, - ('B', 'D'): 0x2572, - ('T', 'B'): 0x2580, - ('L', 'B'): 0x2584, - ('F', 'B'): 0x2588, - ('l', 'B'): 0x258c, - ('R', 'B'): 0x2590, - ('.', 'S'): 0x2591, - (':', 'S'): 0x2592, - ('?', 'S'): 0x2593, - ('f', 'S'): 0x25a0, - ('O', 'S'): 0x25a1, - ('R', 'O'): 0x25a2, - ('R', 'r'): 0x25a3, - ('R', 'F'): 0x25a4, - ('R', 'Y'): 0x25a5, - ('R', 'H'): 0x25a6, - ('R', 'Z'): 0x25a7, - ('R', 'K'): 0x25a8, - ('R', 'X'): 0x25a9, - ('s', 'B'): 0x25aa, - ('S', 'R'): 0x25ac, - ('O', 'r'): 0x25ad, - ('U', 'T'): 0x25b2, - ('u', 'T'): 0x25b3, - ('P', 'R'): 0x25b6, - ('T', 'r'): 0x25b7, - ('D', 't'): 0x25bc, - ('d', 'T'): 0x25bd, - ('P', 'L'): 0x25c0, - ('T', 'l'): 0x25c1, - ('D', 'b'): 0x25c6, - ('D', 'w'): 0x25c7, - ('L', 'Z'): 0x25ca, - ('0', 'm'): 0x25cb, - ('0', 'o'): 0x25ce, - ('0', 'M'): 0x25cf, - ('0', 'L'): 0x25d0, - ('0', 'R'): 0x25d1, - ('S', 'n'): 0x25d8, - ('I', 'c'): 0x25d9, - ('F', 'd'): 0x25e2, - ('B', 'd'): 0x25e3, - ('*', '2'): 0x2605, - ('*', '1'): 0x2606, - ('<', 'H'): 0x261c, - ('>', 'H'): 0x261e, - ('0', 'u'): 0x263a, - ('0', 'U'): 0x263b, - ('S', 'U'): 0x263c, - ('F', 'm'): 0x2640, - ('M', 'l'): 0x2642, - ('c', 'S'): 0x2660, - ('c', 'H'): 0x2661, - ('c', 'D'): 0x2662, - ('c', 'C'): 0x2663, - ('M', 'd'): 0x2669, - ('M', '8'): 0x266a, - ('M', '2'): 0x266b, - ('M', 'b'): 0x266d, - ('M', 'x'): 0x266e, - ('M', 'X'): 0x266f, - ('O', 'K'): 0x2713, - ('X', 'X'): 0x2717, - ('-', 'X'): 0x2720, - ('I', 'S'): 0x3000, - (',', '_'): 0x3001, - ('.', '_'): 0x3002, - ('+', '"'): 0x3003, - ('+', '_'): 0x3004, - ('*', '_'): 0x3005, - (';', '_'): 0x3006, - ('0', '_'): 0x3007, - ('<', '+'): 0x300a, - ('>', '+'): 0x300b, - ('<', '\''): 0x300c, - ('>', '\''): 0x300d, - ('<', '"'): 0x300e, - ('>', '"'): 0x300f, - ('(', '"'): 0x3010, - (')', '"'): 0x3011, - ('=', 'T'): 0x3012, - ('=', '_'): 0x3013, - ('(', '\''): 0x3014, - (')', '\''): 0x3015, - ('(', 'I'): 0x3016, - (')', 'I'): 0x3017, - ('-', '?'): 0x301c, - ('A', '5'): 0x3041, - ('a', '5'): 0x3042, - ('I', '5'): 0x3043, - ('i', '5'): 0x3044, - ('U', '5'): 0x3045, - ('u', '5'): 0x3046, - ('E', '5'): 0x3047, - ('e', '5'): 0x3048, - ('O', '5'): 0x3049, - ('o', '5'): 0x304a, - ('k', 'a'): 0x304b, - ('g', 'a'): 0x304c, - ('k', 'i'): 0x304d, - ('g', 'i'): 0x304e, - ('k', 'u'): 0x304f, - ('g', 'u'): 0x3050, - ('k', 'e'): 0x3051, - ('g', 'e'): 0x3052, - ('k', 'o'): 0x3053, - ('g', 'o'): 0x3054, - ('s', 'a'): 0x3055, - ('z', 'a'): 0x3056, - ('s', 'i'): 0x3057, - ('z', 'i'): 0x3058, - ('s', 'u'): 0x3059, - ('z', 'u'): 0x305a, - ('s', 'e'): 0x305b, - ('z', 'e'): 0x305c, - ('s', 'o'): 0x305d, - ('z', 'o'): 0x305e, - ('t', 'a'): 0x305f, - ('d', 'a'): 0x3060, - ('t', 'i'): 0x3061, - ('d', 'i'): 0x3062, - ('t', 'U'): 0x3063, - ('t', 'u'): 0x3064, - ('d', 'u'): 0x3065, - ('t', 'e'): 0x3066, - ('d', 'e'): 0x3067, - ('t', 'o'): 0x3068, - ('d', 'o'): 0x3069, - ('n', 'a'): 0x306a, - ('n', 'i'): 0x306b, - ('n', 'u'): 0x306c, - ('n', 'e'): 0x306d, - ('n', 'o'): 0x306e, - ('h', 'a'): 0x306f, - ('b', 'a'): 0x3070, - ('p', 'a'): 0x3071, - ('h', 'i'): 0x3072, - ('b', 'i'): 0x3073, - ('p', 'i'): 0x3074, - ('h', 'u'): 0x3075, - ('b', 'u'): 0x3076, - ('p', 'u'): 0x3077, - ('h', 'e'): 0x3078, - ('b', 'e'): 0x3079, - ('p', 'e'): 0x307a, - ('h', 'o'): 0x307b, - ('b', 'o'): 0x307c, - ('p', 'o'): 0x307d, - ('m', 'a'): 0x307e, - ('m', 'i'): 0x307f, - ('m', 'u'): 0x3080, - ('m', 'e'): 0x3081, - ('m', 'o'): 0x3082, - ('y', 'A'): 0x3083, - ('y', 'a'): 0x3084, - ('y', 'U'): 0x3085, - ('y', 'u'): 0x3086, - ('y', 'O'): 0x3087, - ('y', 'o'): 0x3088, - ('r', 'a'): 0x3089, - ('r', 'i'): 0x308a, - ('r', 'u'): 0x308b, - ('r', 'e'): 0x308c, - ('r', 'o'): 0x308d, - ('w', 'A'): 0x308e, - ('w', 'a'): 0x308f, - ('w', 'i'): 0x3090, - ('w', 'e'): 0x3091, - ('w', 'o'): 0x3092, - ('n', '5'): 0x3093, - ('v', 'u'): 0x3094, - ('"', '5'): 0x309b, - ('0', '5'): 0x309c, - ('*', '5'): 0x309d, - ('+', '5'): 0x309e, - ('a', '6'): 0x30a1, - ('A', '6'): 0x30a2, - ('i', '6'): 0x30a3, - ('I', '6'): 0x30a4, - ('u', '6'): 0x30a5, - ('U', '6'): 0x30a6, - ('e', '6'): 0x30a7, - ('E', '6'): 0x30a8, - ('o', '6'): 0x30a9, - ('O', '6'): 0x30aa, - ('K', 'a'): 0x30ab, - ('G', 'a'): 0x30ac, - ('K', 'i'): 0x30ad, - ('G', 'i'): 0x30ae, - ('K', 'u'): 0x30af, - ('G', 'u'): 0x30b0, - ('K', 'e'): 0x30b1, - ('G', 'e'): 0x30b2, - ('K', 'o'): 0x30b3, - ('G', 'o'): 0x30b4, - ('S', 'a'): 0x30b5, - ('Z', 'a'): 0x30b6, - ('S', 'i'): 0x30b7, - ('Z', 'i'): 0x30b8, - ('S', 'u'): 0x30b9, - ('Z', 'u'): 0x30ba, - ('S', 'e'): 0x30bb, - ('Z', 'e'): 0x30bc, - ('S', 'o'): 0x30bd, - ('Z', 'o'): 0x30be, - ('T', 'a'): 0x30bf, - ('D', 'a'): 0x30c0, - ('T', 'i'): 0x30c1, - ('D', 'i'): 0x30c2, - ('T', 'U'): 0x30c3, - ('T', 'u'): 0x30c4, - ('D', 'u'): 0x30c5, - ('T', 'e'): 0x30c6, - ('D', 'e'): 0x30c7, - ('T', 'o'): 0x30c8, - ('D', 'o'): 0x30c9, - ('N', 'a'): 0x30ca, - ('N', 'i'): 0x30cb, - ('N', 'u'): 0x30cc, - ('N', 'e'): 0x30cd, - ('N', 'o'): 0x30ce, - ('H', 'a'): 0x30cf, - ('B', 'a'): 0x30d0, - ('P', 'a'): 0x30d1, - ('H', 'i'): 0x30d2, - ('B', 'i'): 0x30d3, - ('P', 'i'): 0x30d4, - ('H', 'u'): 0x30d5, - ('B', 'u'): 0x30d6, - ('P', 'u'): 0x30d7, - ('H', 'e'): 0x30d8, - ('B', 'e'): 0x30d9, - ('P', 'e'): 0x30da, - ('H', 'o'): 0x30db, - ('B', 'o'): 0x30dc, - ('P', 'o'): 0x30dd, - ('M', 'a'): 0x30de, - ('M', 'i'): 0x30df, - ('M', 'u'): 0x30e0, - ('M', 'e'): 0x30e1, - ('M', 'o'): 0x30e2, - ('Y', 'A'): 0x30e3, - ('Y', 'a'): 0x30e4, - ('Y', 'U'): 0x30e5, - ('Y', 'u'): 0x30e6, - ('Y', 'O'): 0x30e7, - ('Y', 'o'): 0x30e8, - ('R', 'a'): 0x30e9, - ('R', 'i'): 0x30ea, - ('R', 'u'): 0x30eb, - ('R', 'e'): 0x30ec, - ('R', 'o'): 0x30ed, - ('W', 'A'): 0x30ee, - ('W', 'a'): 0x30ef, - ('W', 'i'): 0x30f0, - ('W', 'e'): 0x30f1, - ('W', 'o'): 0x30f2, - ('N', '6'): 0x30f3, - ('V', 'u'): 0x30f4, - ('K', 'A'): 0x30f5, - ('K', 'E'): 0x30f6, - ('V', 'a'): 0x30f7, - ('V', 'i'): 0x30f8, - ('V', 'e'): 0x30f9, - ('V', 'o'): 0x30fa, - ('.', '6'): 0x30fb, - ('-', '6'): 0x30fc, - ('*', '6'): 0x30fd, - ('+', '6'): 0x30fe, - ('b', '4'): 0x3105, - ('p', '4'): 0x3106, - ('m', '4'): 0x3107, - ('f', '4'): 0x3108, - ('d', '4'): 0x3109, - ('t', '4'): 0x310a, - ('n', '4'): 0x310b, - ('l', '4'): 0x310c, - ('g', '4'): 0x310d, - ('k', '4'): 0x310e, - ('h', '4'): 0x310f, - ('j', '4'): 0x3110, - ('q', '4'): 0x3111, - ('x', '4'): 0x3112, - ('z', 'h'): 0x3113, - ('c', 'h'): 0x3114, - ('s', 'h'): 0x3115, - ('r', '4'): 0x3116, - ('z', '4'): 0x3117, - ('c', '4'): 0x3118, - ('s', '4'): 0x3119, - ('a', '4'): 0x311a, - ('o', '4'): 0x311b, - ('e', '4'): 0x311c, - ('a', 'i'): 0x311e, - ('e', 'i'): 0x311f, - ('a', 'u'): 0x3120, - ('o', 'u'): 0x3121, - ('a', 'n'): 0x3122, - ('e', 'n'): 0x3123, - ('a', 'N'): 0x3124, - ('e', 'N'): 0x3125, - ('e', 'r'): 0x3126, - ('i', '4'): 0x3127, - ('u', '4'): 0x3128, - ('i', 'u'): 0x3129, - ('v', '4'): 0x312a, - ('n', 'G'): 0x312b, - ('g', 'n'): 0x312c, - ('1', 'c'): 0x3220, - ('2', 'c'): 0x3221, - ('3', 'c'): 0x3222, - ('4', 'c'): 0x3223, - ('5', 'c'): 0x3224, - ('6', 'c'): 0x3225, - ('7', 'c'): 0x3226, - ('8', 'c'): 0x3227, - ('9', 'c'): 0x3228, - - # code points 0xe000 - 0xefff excluded, they have no assigned - # characters, only used in proposals. - ('f', 'f'): 0xfb00, - ('f', 'i'): 0xfb01, - ('f', 'l'): 0xfb02, - ('f', 't'): 0xfb05, - ('s', 't'): 0xfb06, - - # Vim 5.x compatible digraphs that don't conflict with the above - ('~', '!'): 161, - ('c', '|'): 162, - ('$', '$'): 163, - ('o', 'x'): 164, # currency symbol in ISO 8859-1 - ('Y', '-'): 165, - ('|', '|'): 166, - ('c', 'O'): 169, - ('-', ','): 172, - ('-', '='): 175, - ('~', 'o'): 176, - ('2', '2'): 178, - ('3', '3'): 179, - ('p', 'p'): 182, - ('~', '.'): 183, - ('1', '1'): 185, - ('~', '?'): 191, - ('A', '`'): 192, - ('A', '^'): 194, - ('A', '~'): 195, - ('A', '"'): 196, - ('A', '@'): 197, - ('E', '`'): 200, - ('E', '^'): 202, - ('E', '"'): 203, - ('I', '`'): 204, - ('I', '^'): 206, - ('I', '"'): 207, - ('N', '~'): 209, - ('O', '`'): 210, - ('O', '^'): 212, - ('O', '~'): 213, - ('/', '\\'): 215, # multiplication symbol in ISO 8859-1 - ('U', '`'): 217, - ('U', '^'): 219, - ('I', 'p'): 222, - ('a', '`'): 224, - ('a', '^'): 226, - ('a', '~'): 227, - ('a', '"'): 228, - ('a', '@'): 229, - ('e', '`'): 232, - ('e', '^'): 234, - ('e', '"'): 235, - ('i', '`'): 236, - ('i', '^'): 238, - ('n', '~'): 241, - ('o', '`'): 242, - ('o', '^'): 244, - ('o', '~'): 245, - ('u', '`'): 249, - ('u', '^'): 251, - ('y', '"'): 255, -} diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py deleted file mode 100644 index 51a3110827..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py +++ /dev/null @@ -1,372 +0,0 @@ -# *** encoding: utf-8 *** -""" -An :class:`~.InputProcessor` receives callbacks for the keystrokes parsed from -the input in the :class:`~prompt_toolkit.inputstream.InputStream` instance. - -The `InputProcessor` will according to the implemented keybindings call the -correct callbacks when new key presses are feed through `feed`. -""" -from __future__ import unicode_literals -from prompt_toolkit.buffer import EditReadOnlyBuffer -from prompt_toolkit.filters.cli import ViNavigationMode -from prompt_toolkit.keys import Keys, Key -from prompt_toolkit.utils import Event - -from .registry import BaseRegistry - -from collections import deque -from six.moves import range -import weakref -import six - -__all__ = ( - 'InputProcessor', - 'KeyPress', -) - - -class KeyPress(object): - """ - :param key: A `Keys` instance or text (one character). - :param data: The received string on stdin. (Often vt100 escape codes.) - """ - def __init__(self, key, data=None): - assert isinstance(key, (six.text_type, Key)) - assert data is None or isinstance(data, six.text_type) - - if data is None: - data = key.name if isinstance(key, Key) else key - - self.key = key - self.data = data - - def __repr__(self): - return '%s(key=%r, data=%r)' % ( - self.__class__.__name__, self.key, self.data) - - def __eq__(self, other): - return self.key == other.key and self.data == other.data - - -class InputProcessor(object): - """ - Statemachine that receives :class:`KeyPress` instances and according to the - key bindings in the given :class:`Registry`, calls the matching handlers. - - :: - - p = InputProcessor(registry) - - # Send keys into the processor. - p.feed(KeyPress(Keys.ControlX, '\x18')) - p.feed(KeyPress(Keys.ControlC, '\x03') - - # Process all the keys in the queue. - p.process_keys() - - # Now the ControlX-ControlC callback will be called if this sequence is - # registered in the registry. - - :param registry: `BaseRegistry` instance. - :param cli_ref: weakref to `CommandLineInterface`. - """ - def __init__(self, registry, cli_ref): - assert isinstance(registry, BaseRegistry) - - self._registry = registry - self._cli_ref = cli_ref - - self.beforeKeyPress = Event(self) - self.afterKeyPress = Event(self) - - # The queue of keys not yet send to our _process generator/state machine. - self.input_queue = deque() - - # The key buffer that is matched in the generator state machine. - # (This is at at most the amount of keys that make up for one key binding.) - self.key_buffer = [] - - # Simple macro recording. (Like readline does.) - self.record_macro = False - self.macro = [] - - self.reset() - - def reset(self): - self._previous_key_sequence = [] - self._previous_handler = None - - self._process_coroutine = self._process() - self._process_coroutine.send(None) - - #: Readline argument (for repetition of commands.) - #: https://www.gnu.org/software/bash/manual/html_node/Readline-Arguments.html - self.arg = None - - def start_macro(self): - " Start recording macro. " - self.record_macro = True - self.macro = [] - - def end_macro(self): - " End recording macro. " - self.record_macro = False - - def call_macro(self): - for k in self.macro: - self.feed(k) - - def _get_matches(self, key_presses): - """ - For a list of :class:`KeyPress` instances. Give the matching handlers - that would handle this. - """ - keys = tuple(k.key for k in key_presses) - cli = self._cli_ref() - - # Try match, with mode flag - return [b for b in self._registry.get_bindings_for_keys(keys) if b.filter(cli)] - - def _is_prefix_of_longer_match(self, key_presses): - """ - For a list of :class:`KeyPress` instances. Return True if there is any - handler that is bound to a suffix of this keys. - """ - keys = tuple(k.key for k in key_presses) - cli = self._cli_ref() - - # Get the filters for all the key bindings that have a longer match. - # Note that we transform it into a `set`, because we don't care about - # the actual bindings and executing it more than once doesn't make - # sense. (Many key bindings share the same filter.) - filters = set(b.filter for b in self._registry.get_bindings_starting_with_keys(keys)) - - # When any key binding is active, return True. - return any(f(cli) for f in filters) - - def _process(self): - """ - Coroutine implementing the key match algorithm. Key strokes are sent - into this generator, and it calls the appropriate handlers. - """ - buffer = self.key_buffer - retry = False - - while True: - if retry: - retry = False - else: - buffer.append((yield)) - - # If we have some key presses, check for matches. - if buffer: - is_prefix_of_longer_match = self._is_prefix_of_longer_match(buffer) - matches = self._get_matches(buffer) - - # When eager matches were found, give priority to them and also - # ignore all the longer matches. - eager_matches = [m for m in matches if m.eager(self._cli_ref())] - - if eager_matches: - matches = eager_matches - is_prefix_of_longer_match = False - - # Exact matches found, call handler. - if not is_prefix_of_longer_match and matches: - self._call_handler(matches[-1], key_sequence=buffer[:]) - del buffer[:] # Keep reference. - - # No match found. - elif not is_prefix_of_longer_match and not matches: - retry = True - found = False - - # Loop over the input, try longest match first and shift. - for i in range(len(buffer), 0, -1): - matches = self._get_matches(buffer[:i]) - if matches: - self._call_handler(matches[-1], key_sequence=buffer[:i]) - del buffer[:i] - found = True - break - - if not found: - del buffer[:1] - - def feed(self, key_press): - """ - Add a new :class:`KeyPress` to the input queue. - (Don't forget to call `process_keys` in order to process the queue.) - """ - assert isinstance(key_press, KeyPress) - self.input_queue.append(key_press) - - def process_keys(self): - """ - Process all the keys in the `input_queue`. - (To be called after `feed`.) - - Note: because of the `feed`/`process_keys` separation, it is - possible to call `feed` from inside a key binding. - This function keeps looping until the queue is empty. - """ - while self.input_queue: - key_press = self.input_queue.popleft() - - if key_press.key != Keys.CPRResponse: - self.beforeKeyPress.fire() - - self._process_coroutine.send(key_press) - - if key_press.key != Keys.CPRResponse: - self.afterKeyPress.fire() - - # Invalidate user interface. - cli = self._cli_ref() - if cli: - cli.invalidate() - - def _call_handler(self, handler, key_sequence=None): - was_recording = self.record_macro - arg = self.arg - self.arg = None - - event = KeyPressEvent( - weakref.ref(self), arg=arg, key_sequence=key_sequence, - previous_key_sequence=self._previous_key_sequence, - is_repeat=(handler == self._previous_handler)) - - # Save the state of the current buffer. - cli = event.cli # Can be `None` (In unit-tests only.) - - if handler.save_before(event) and cli: - cli.current_buffer.save_to_undo_stack() - - # Call handler. - try: - handler.call(event) - self._fix_vi_cursor_position(event) - - except EditReadOnlyBuffer: - # When a key binding does an attempt to change a buffer which is - # read-only, we can just silently ignore that. - pass - - self._previous_key_sequence = key_sequence - self._previous_handler = handler - - # Record the key sequence in our macro. (Only if we're in macro mode - # before and after executing the key.) - if self.record_macro and was_recording: - self.macro.extend(key_sequence) - - def _fix_vi_cursor_position(self, event): - """ - After every command, make sure that if we are in Vi navigation mode, we - never put the cursor after the last character of a line. (Unless it's - an empty line.) - """ - cli = self._cli_ref() - if cli: - buff = cli.current_buffer - preferred_column = buff.preferred_column - - if (ViNavigationMode()(event.cli) and - buff.document.is_cursor_at_the_end_of_line and - len(buff.document.current_line) > 0): - buff.cursor_position -= 1 - - # Set the preferred_column for arrow up/down again. - # (This was cleared after changing the cursor position.) - buff.preferred_column = preferred_column - - - -class KeyPressEvent(object): - """ - Key press event, delivered to key bindings. - - :param input_processor_ref: Weak reference to the `InputProcessor`. - :param arg: Repetition argument. - :param key_sequence: List of `KeyPress` instances. - :param previouskey_sequence: Previous list of `KeyPress` instances. - :param is_repeat: True when the previous event was delivered to the same handler. - """ - def __init__(self, input_processor_ref, arg=None, key_sequence=None, - previous_key_sequence=None, is_repeat=False): - self._input_processor_ref = input_processor_ref - self.key_sequence = key_sequence - self.previous_key_sequence = previous_key_sequence - - #: True when the previous key sequence was handled by the same handler. - self.is_repeat = is_repeat - - self._arg = arg - - def __repr__(self): - return 'KeyPressEvent(arg=%r, key_sequence=%r, is_repeat=%r)' % ( - self.arg, self.key_sequence, self.is_repeat) - - @property - def data(self): - return self.key_sequence[-1].data - - @property - def input_processor(self): - return self._input_processor_ref() - - @property - def cli(self): - """ - Command line interface. - """ - return self.input_processor._cli_ref() - - @property - def current_buffer(self): - """ - The current buffer. - """ - return self.cli.current_buffer - - @property - def arg(self): - """ - Repetition argument. - """ - if self._arg == '-': - return -1 - - result = int(self._arg or 1) - - # Don't exceed a million. - if int(result) >= 1000000: - result = 1 - - return result - - @property - def arg_present(self): - """ - True if repetition argument was explicitly provided. - """ - return self._arg is not None - - def append_to_arg_count(self, data): - """ - Add digit to the input argument. - - :param data: the typed digit as string - """ - assert data in '-0123456789' - current = self._arg - - if data == '-': - assert current is None or current == '-' - result = data - elif current is None: - result = data - else: - result = "%s%s" % (current, data) - - self.input_processor.arg = result diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py deleted file mode 100644 index 83612c2a5c..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -DEPRECATED: -Use `prompt_toolkit.key_binding.defaults.load_key_bindings` instead. - -:class:`KeyBindingManager` is a utility (or shortcut) for loading all the key -bindings in a key binding registry, with a logic set of filters to quickly to -quickly change from Vi to Emacs key bindings at runtime. - -You don't have to use this, but it's practical. - -Usage:: - - manager = KeyBindingManager() - app = Application(key_bindings_registry=manager.registry) -""" -from __future__ import unicode_literals -from .defaults import load_key_bindings -from prompt_toolkit.filters import to_cli_filter -from prompt_toolkit.key_binding.registry import Registry, ConditionalRegistry, MergedRegistry - -__all__ = ( - 'KeyBindingManager', -) - - -class KeyBindingManager(object): - """ - Utility for loading all key bindings into memory. - - :param registry: Optional `Registry` instance. - :param enable_abort_and_exit_bindings: Filter to enable Ctrl-C and Ctrl-D. - :param enable_system_bindings: Filter to enable the system bindings - (meta-! prompt and Control-Z suspension.) - :param enable_search: Filter to enable the search bindings. - :param enable_open_in_editor: Filter to enable open-in-editor. - :param enable_open_in_editor: Filter to enable open-in-editor. - :param enable_extra_page_navigation: Filter for enabling extra page navigation. - (Bindings for up/down scrolling through long pages, like in Emacs or Vi.) - :param enable_auto_suggest_bindings: Filter to enable fish-style suggestions. - - :param enable_vi_mode: Deprecated! - """ - def __init__(self, - registry=None, # XXX: not used anymore. - enable_vi_mode=None, # (`enable_vi_mode` is deprecated.) - enable_all=True, # - get_search_state=None, - enable_abort_and_exit_bindings=False, - enable_system_bindings=False, - enable_search=False, - enable_open_in_editor=False, - enable_extra_page_navigation=False, - enable_auto_suggest_bindings=False): - - assert registry is None or isinstance(registry, Registry) - assert get_search_state is None or callable(get_search_state) - enable_all = to_cli_filter(enable_all) - - defaults = load_key_bindings( - get_search_state=get_search_state, - enable_abort_and_exit_bindings=enable_abort_and_exit_bindings, - enable_system_bindings=enable_system_bindings, - enable_search=enable_search, - enable_open_in_editor=enable_open_in_editor, - enable_extra_page_navigation=enable_extra_page_navigation, - enable_auto_suggest_bindings=enable_auto_suggest_bindings) - - # Note, we wrap this whole thing again in a MergedRegistry, because we - # don't want the `enable_all` settings to apply on items that were - # added to the registry as a whole. - self.registry = MergedRegistry([ - ConditionalRegistry(defaults, enable_all) - ]) - - @classmethod - def for_prompt(cls, **kw): - """ - Create a ``KeyBindingManager`` with the defaults for an input prompt. - This activates the key bindings for abort/exit (Ctrl-C/Ctrl-D), - incremental search and auto suggestions. - - (Not for full screen applications.) - """ - kw.setdefault('enable_abort_and_exit_bindings', True) - kw.setdefault('enable_search', True) - kw.setdefault('enable_auto_suggest_bindings', True) - - return cls(**kw) - - def reset(self, cli): - # For backwards compatibility. - pass - - def get_vi_state(self, cli): - # Deprecated! - return cli.vi_state diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py deleted file mode 100644 index 24d0e729a1..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py +++ /dev/null @@ -1,350 +0,0 @@ -""" -Key bindings registry. - -A `Registry` object is a container that holds a list of key bindings. It has a -very efficient internal data structure for checking which key bindings apply -for a pressed key. - -Typical usage:: - - r = Registry() - - @r.add_binding(Keys.ControlX, Keys.ControlC, filter=INSERT) - def handler(event): - # Handle ControlX-ControlC key sequence. - pass - - -It is also possible to combine multiple registries. We do this in the default -key bindings. There are some registries that contain Emacs bindings, while -others contain the Vi bindings. They are merged together using a -`MergedRegistry`. - -We also have a `ConditionalRegistry` object that can enable/disable a group of -key bindings at once. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod - -from prompt_toolkit.cache import SimpleCache -from prompt_toolkit.filters import CLIFilter, to_cli_filter, Never -from prompt_toolkit.keys import Key, Keys - -from six import text_type, with_metaclass - -__all__ = ( - 'BaseRegistry', - 'Registry', - 'ConditionalRegistry', - 'MergedRegistry', -) - - -class _Binding(object): - """ - (Immutable binding class.) - """ - def __init__(self, keys, handler, filter=None, eager=None, save_before=None): - assert isinstance(keys, tuple) - assert callable(handler) - assert isinstance(filter, CLIFilter) - assert isinstance(eager, CLIFilter) - assert callable(save_before) - - self.keys = keys - self.handler = handler - self.filter = filter - self.eager = eager - self.save_before = save_before - - def call(self, event): - return self.handler(event) - - def __repr__(self): - return '%s(keys=%r, handler=%r)' % ( - self.__class__.__name__, self.keys, self.handler) - - -class BaseRegistry(with_metaclass(ABCMeta, object)): - """ - Interface for a Registry. - """ - _version = 0 # For cache invalidation. - - @abstractmethod - def get_bindings_for_keys(self, keys): - pass - - @abstractmethod - def get_bindings_starting_with_keys(self, keys): - pass - - # `add_binding` and `remove_binding` don't have to be part of this - # interface. - - -class Registry(BaseRegistry): - """ - Key binding registry. - """ - def __init__(self): - self.key_bindings = [] - self._get_bindings_for_keys_cache = SimpleCache(maxsize=10000) - self._get_bindings_starting_with_keys_cache = SimpleCache(maxsize=1000) - self._version = 0 # For cache invalidation. - - def _clear_cache(self): - self._version += 1 - self._get_bindings_for_keys_cache.clear() - self._get_bindings_starting_with_keys_cache.clear() - - def add_binding(self, *keys, **kwargs): - """ - Decorator for annotating key bindings. - - :param filter: :class:`~prompt_toolkit.filters.CLIFilter` to determine - when this key binding is active. - :param eager: :class:`~prompt_toolkit.filters.CLIFilter` or `bool`. - When True, ignore potential longer matches when this key binding is - hit. E.g. when there is an active eager key binding for Ctrl-X, - execute the handler immediately and ignore the key binding for - Ctrl-X Ctrl-E of which it is a prefix. - :param save_before: Callable that takes an `Event` and returns True if - we should save the current buffer, before handling the event. - (That's the default.) - """ - filter = to_cli_filter(kwargs.pop('filter', True)) - eager = to_cli_filter(kwargs.pop('eager', False)) - save_before = kwargs.pop('save_before', lambda e: True) - to_cli_filter(kwargs.pop('invalidate_ui', True)) # Deprecated! (ignored.) - - assert not kwargs - assert keys - assert all(isinstance(k, (Key, text_type)) for k in keys), \ - 'Key bindings should consist of Key and string (unicode) instances.' - assert callable(save_before) - - if isinstance(filter, Never): - # When a filter is Never, it will always stay disabled, so in that case - # don't bother putting it in the registry. It will slow down every key - # press otherwise. - def decorator(func): - return func - else: - def decorator(func): - self.key_bindings.append( - _Binding(keys, func, filter=filter, eager=eager, - save_before=save_before)) - self._clear_cache() - - return func - return decorator - - def remove_binding(self, function): - """ - Remove a key binding. - - This expects a function that was given to `add_binding` method as - parameter. Raises `ValueError` when the given function was not - registered before. - """ - assert callable(function) - - for b in self.key_bindings: - if b.handler == function: - self.key_bindings.remove(b) - self._clear_cache() - return - - # No key binding found for this function. Raise ValueError. - raise ValueError('Binding not found: %r' % (function, )) - - def get_bindings_for_keys(self, keys): - """ - Return a list of key bindings that can handle this key. - (This return also inactive bindings, so the `filter` still has to be - called, for checking it.) - - :param keys: tuple of keys. - """ - def get(): - result = [] - for b in self.key_bindings: - if len(keys) == len(b.keys): - match = True - any_count = 0 - - for i, j in zip(b.keys, keys): - if i != j and i != Keys.Any: - match = False - break - - if i == Keys.Any: - any_count += 1 - - if match: - result.append((any_count, b)) - - # Place bindings that have more 'Any' occurences in them at the end. - result = sorted(result, key=lambda item: -item[0]) - - return [item[1] for item in result] - - return self._get_bindings_for_keys_cache.get(keys, get) - - def get_bindings_starting_with_keys(self, keys): - """ - Return a list of key bindings that handle a key sequence starting with - `keys`. (It does only return bindings for which the sequences are - longer than `keys`. And like `get_bindings_for_keys`, it also includes - inactive bindings.) - - :param keys: tuple of keys. - """ - def get(): - result = [] - for b in self.key_bindings: - if len(keys) < len(b.keys): - match = True - for i, j in zip(b.keys, keys): - if i != j and i != Keys.Any: - match = False - break - if match: - result.append(b) - return result - - return self._get_bindings_starting_with_keys_cache.get(keys, get) - - -class _AddRemoveMixin(BaseRegistry): - """ - Common part for ConditionalRegistry and MergedRegistry. - """ - def __init__(self): - # `Registry` to be synchronized with all the others. - self._registry2 = Registry() - self._last_version = None - - # The 'extra' registry. Mostly for backwards compatibility. - self._extra_registry = Registry() - - def _update_cache(self): - raise NotImplementedError - - # For backwards, compatibility, we allow adding bindings to both - # ConditionalRegistry and MergedRegistry. This is however not the - # recommended way. Better is to create a new registry and merge them - # together using MergedRegistry. - - def add_binding(self, *k, **kw): - return self._extra_registry.add_binding(*k, **kw) - - def remove_binding(self, *k, **kw): - return self._extra_registry.remove_binding(*k, **kw) - - # Proxy methods to self._registry2. - - @property - def key_bindings(self): - self._update_cache() - return self._registry2.key_bindings - - @property - def _version(self): - self._update_cache() - return self._last_version - - def get_bindings_for_keys(self, *a, **kw): - self._update_cache() - return self._registry2.get_bindings_for_keys(*a, **kw) - - def get_bindings_starting_with_keys(self, *a, **kw): - self._update_cache() - return self._registry2.get_bindings_starting_with_keys(*a, **kw) - - -class ConditionalRegistry(_AddRemoveMixin): - """ - Wraps around a `Registry`. Disable/enable all the key bindings according to - the given (additional) filter.:: - - @Condition - def setting_is_true(cli): - return True # or False - - registy = ConditionalRegistry(registry, setting_is_true) - - When new key bindings are added to this object. They are also - enable/disabled according to the given `filter`. - - :param registries: List of `Registry` objects. - :param filter: `CLIFilter` object. - """ - def __init__(self, registry=None, filter=True): - registry = registry or Registry() - assert isinstance(registry, BaseRegistry) - - _AddRemoveMixin.__init__(self) - - self.registry = registry - self.filter = to_cli_filter(filter) - - def _update_cache(self): - " If the original registry was changed. Update our copy version. " - expected_version = (self.registry._version, self._extra_registry._version) - - if self._last_version != expected_version: - registry2 = Registry() - - # Copy all bindings from `self.registry`, adding our condition. - for reg in (self.registry, self._extra_registry): - for b in reg.key_bindings: - registry2.key_bindings.append( - _Binding( - keys=b.keys, - handler=b.handler, - filter=self.filter & b.filter, - eager=b.eager, - save_before=b.save_before)) - - self._registry2 = registry2 - self._last_version = expected_version - - -class MergedRegistry(_AddRemoveMixin): - """ - Merge multiple registries of key bindings into one. - - This class acts as a proxy to multiple `Registry` objects, but behaves as - if this is just one bigger `Registry`. - - :param registries: List of `Registry` objects. - """ - def __init__(self, registries): - assert all(isinstance(r, BaseRegistry) for r in registries) - - _AddRemoveMixin.__init__(self) - - self.registries = registries - - def _update_cache(self): - """ - If one of the original registries was changed. Update our merged - version. - """ - expected_version = ( - tuple(r._version for r in self.registries) + - (self._extra_registry._version, )) - - if self._last_version != expected_version: - registry2 = Registry() - - for reg in self.registries: - registry2.key_bindings.extend(reg.key_bindings) - - # Copy all bindings from `self._extra_registry`. - registry2.key_bindings.extend(self._extra_registry.key_bindings) - - self._registry2 = registry2 - self._last_version = expected_version diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py deleted file mode 100644 index 92ce3cbd29..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import unicode_literals - -__all__ = ( - 'InputMode', - 'CharacterFind', - 'ViState', -) - - -class InputMode(object): - INSERT = 'vi-insert' - INSERT_MULTIPLE = 'vi-insert-multiple' - NAVIGATION = 'vi-navigation' - REPLACE = 'vi-replace' - - -class CharacterFind(object): - def __init__(self, character, backwards=False): - self.character = character - self.backwards = backwards - - -class ViState(object): - """ - Mutable class to hold the state of the Vi navigation. - """ - def __init__(self): - #: None or CharacterFind instance. (This is used to repeat the last - #: search in Vi mode, by pressing the 'n' or 'N' in navigation mode.) - self.last_character_find = None - - # When an operator is given and we are waiting for text object, - # -- e.g. in the case of 'dw', after the 'd' --, an operator callback - # is set here. - self.operator_func = None - self.operator_arg = None - - #: Named registers. Maps register name (e.g. 'a') to - #: :class:`ClipboardData` instances. - self.named_registers = {} - - #: The Vi mode we're currently in to. - self.input_mode = InputMode.INSERT - - #: Waiting for digraph. - self.waiting_for_digraph = False - self.digraph_symbol1 = None # (None or a symbol.) - - #: When true, make ~ act as an operator. - self.tilde_operator = False - - def reset(self, mode=InputMode.INSERT): - """ - Reset state, go back to the given mode. INSERT by default. - """ - # Go back to insert mode. - self.input_mode = mode - - self.waiting_for_digraph = False - self.operator_func = None - self.operator_arg = None diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py deleted file mode 100644 index d5df9bff41..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py +++ /dev/null @@ -1,129 +0,0 @@ -from __future__ import unicode_literals - -__all__ = ( - 'Key', - 'Keys', -) - - -class Key(object): - def __init__(self, name): - - #: Descriptive way of writing keys in configuration files. e.g. <C-A> - #: for ``Control-A``. - self.name = name - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.name) - - -class Keys(object): - Escape = Key('<Escape>') - - ControlA = Key('<C-A>') - ControlB = Key('<C-B>') - ControlC = Key('<C-C>') - ControlD = Key('<C-D>') - ControlE = Key('<C-E>') - ControlF = Key('<C-F>') - ControlG = Key('<C-G>') - ControlH = Key('<C-H>') - ControlI = Key('<C-I>') # Tab - ControlJ = Key('<C-J>') # Enter - ControlK = Key('<C-K>') - ControlL = Key('<C-L>') - ControlM = Key('<C-M>') # Enter - ControlN = Key('<C-N>') - ControlO = Key('<C-O>') - ControlP = Key('<C-P>') - ControlQ = Key('<C-Q>') - ControlR = Key('<C-R>') - ControlS = Key('<C-S>') - ControlT = Key('<C-T>') - ControlU = Key('<C-U>') - ControlV = Key('<C-V>') - ControlW = Key('<C-W>') - ControlX = Key('<C-X>') - ControlY = Key('<C-Y>') - ControlZ = Key('<C-Z>') - - ControlSpace = Key('<C-Space>') - ControlBackslash = Key('<C-Backslash>') - ControlSquareClose = Key('<C-SquareClose>') - ControlCircumflex = Key('<C-Circumflex>') - ControlUnderscore = Key('<C-Underscore>') - ControlLeft = Key('<C-Left>') - ControlRight = Key('<C-Right>') - ControlUp = Key('<C-Up>') - ControlDown = Key('<C-Down>') - - Up = Key('<Up>') - Down = Key('<Down>') - Right = Key('<Right>') - Left = Key('<Left>') - - ShiftLeft = Key('<ShiftLeft>') - ShiftUp = Key('<ShiftUp>') - ShiftDown = Key('<ShiftDown>') - ShiftRight = Key('<ShiftRight>') - - Home = Key('<Home>') - End = Key('<End>') - Delete = Key('<Delete>') - ShiftDelete = Key('<ShiftDelete>') - ControlDelete = Key('<C-Delete>') - PageUp = Key('<PageUp>') - PageDown = Key('<PageDown>') - BackTab = Key('<BackTab>') # shift + tab - Insert = Key('<Insert>') - Backspace = Key('<Backspace>') - - # Aliases. - Tab = ControlI - Enter = ControlJ - # XXX: Actually Enter equals ControlM, not ControlJ, - # However, in prompt_toolkit, we made the mistake of translating - # \r into \n during the input, so everyone is now handling the - # enter key by binding ControlJ. - - # From now on, it's better to bind `Keys.Enter` everywhere, - # because that's future compatible, and will still work when we - # stop replacing \r by \n. - - F1 = Key('<F1>') - F2 = Key('<F2>') - F3 = Key('<F3>') - F4 = Key('<F4>') - F5 = Key('<F5>') - F6 = Key('<F6>') - F7 = Key('<F7>') - F8 = Key('<F8>') - F9 = Key('<F9>') - F10 = Key('<F10>') - F11 = Key('<F11>') - F12 = Key('<F12>') - F13 = Key('<F13>') - F14 = Key('<F14>') - F15 = Key('<F15>') - F16 = Key('<F16>') - F17 = Key('<F17>') - F18 = Key('<F18>') - F19 = Key('<F19>') - F20 = Key('<F20>') - F21 = Key('<F21>') - F22 = Key('<F22>') - F23 = Key('<F23>') - F24 = Key('<F24>') - - # Matches any key. - Any = Key('<Any>') - - # Special - CPRResponse = Key('<Cursor-Position-Response>') - Vt100MouseEvent = Key('<Vt100-Mouse-Event>') - WindowsMouseEvent = Key('<Windows-Mouse-Event>') - BracketedPaste = Key('<Bracketed-Paste>') - - # Key which is ignored. (The key binding for this key should not do - # anything.) - Ignore = Key('<Ignore>') diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py deleted file mode 100644 index 0dec5ecfaf..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Command line layout definitions -------------------------------- - -The layout of a command line interface is defined by a Container instance. -There are two main groups of classes here. Containers and controls: - -- A container can contain other containers or controls, it can have multiple - children and it decides about the dimensions. -- A control is responsible for rendering the actual content to a screen. - A control can propose some dimensions, but it's the container who decides - about the dimensions -- or when the control consumes more space -- which part - of the control will be visible. - - -Container classes:: - - - Container (Abstract base class) - |- HSplit (Horizontal split) - |- VSplit (Vertical split) - |- FloatContainer (Container which can also contain menus and other floats) - `- Window (Container which contains one actual control - -Control classes:: - - - UIControl (Abstract base class) - |- TokenListControl (Renders a simple list of tokens) - |- FillControl (Fills control with one token/character.) - `- BufferControl (Renders an input buffer.) - - -Usually, you end up wrapping every control inside a `Window` object, because -that's the only way to render it in a layout. - -There are some prepared toolbars which are ready to use:: - -- SystemToolbar (Shows the 'system' input buffer, for entering system commands.) -- ArgToolbar (Shows the input 'arg', for repetition of input commands.) -- SearchToolbar (Shows the 'search' input buffer, for incremental search.) -- CompletionsToolbar (Shows the completions of the current buffer.) -- ValidationToolbar (Shows validation errors of the current buffer.) - -And one prepared menu: - -- CompletionsMenu - -""" -from __future__ import unicode_literals - -from .containers import Float, FloatContainer, HSplit, VSplit, Window, ConditionalContainer -from .controls import TokenListControl, FillControl, BufferControl diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py deleted file mode 100644 index 0bdafe18e0..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py +++ /dev/null @@ -1,1665 +0,0 @@ -""" -Container for the layout. -(Containers can contain other containers or user interface controls.) -""" -from __future__ import unicode_literals - -from abc import ABCMeta, abstractmethod -from six import with_metaclass -from six.moves import range - -from .controls import UIControl, TokenListControl, UIContent -from .dimension import LayoutDimension, sum_layout_dimensions, max_layout_dimensions -from .margins import Margin -from .screen import Point, WritePosition, _CHAR_CACHE -from .utils import token_list_to_text, explode_tokens -from prompt_toolkit.cache import SimpleCache -from prompt_toolkit.filters import to_cli_filter, ViInsertMode, EmacsInsertMode -from prompt_toolkit.mouse_events import MouseEvent, MouseEventType -from prompt_toolkit.reactive import Integer -from prompt_toolkit.token import Token -from prompt_toolkit.utils import take_using_weights, get_cwidth - -__all__ = ( - 'Container', - 'HSplit', - 'VSplit', - 'FloatContainer', - 'Float', - 'Window', - 'WindowRenderInfo', - 'ConditionalContainer', - 'ScrollOffsets', - 'ColorColumn', -) - -Transparent = Token.Transparent - - -class Container(with_metaclass(ABCMeta, object)): - """ - Base class for user interface layout. - """ - @abstractmethod - def reset(self): - """ - Reset the state of this container and all the children. - (E.g. reset scroll offsets, etc...) - """ - - @abstractmethod - def preferred_width(self, cli, max_available_width): - """ - Return a :class:`~prompt_toolkit.layout.dimension.LayoutDimension` that - represents the desired width for this container. - - :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`. - """ - - @abstractmethod - def preferred_height(self, cli, width, max_available_height): - """ - Return a :class:`~prompt_toolkit.layout.dimension.LayoutDimension` that - represents the desired height for this container. - - :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`. - """ - - @abstractmethod - def write_to_screen(self, cli, screen, mouse_handlers, write_position): - """ - Write the actual content to the screen. - - :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`. - :param screen: :class:`~prompt_toolkit.layout.screen.Screen` - :param mouse_handlers: :class:`~prompt_toolkit.layout.mouse_handlers.MouseHandlers`. - """ - - @abstractmethod - def walk(self, cli): - """ - Walk through all the layout nodes (and their children) and yield them. - """ - - -def _window_too_small(): - " Create a `Window` that displays the 'Window too small' text. " - return Window(TokenListControl.static( - [(Token.WindowTooSmall, ' Window too small... ')])) - - -class HSplit(Container): - """ - Several layouts, one stacked above/under the other. - - :param children: List of child :class:`.Container` objects. - :param window_too_small: A :class:`.Container` object that is displayed if - there is not enough space for all the children. By default, this is a - "Window too small" message. - :param get_dimensions: (`None` or a callable that takes a - `CommandLineInterface` and returns a list of `LayoutDimension` - instances.) By default the dimensions are taken from the children and - divided by the available space. However, when `get_dimensions` is specified, - this is taken instead. - :param report_dimensions_callback: When rendering, this function is called - with the `CommandLineInterface` and the list of used dimensions. (As a - list of integers.) - """ - def __init__(self, children, window_too_small=None, - get_dimensions=None, report_dimensions_callback=None): - assert all(isinstance(c, Container) for c in children) - assert window_too_small is None or isinstance(window_too_small, Container) - assert get_dimensions is None or callable(get_dimensions) - assert report_dimensions_callback is None or callable(report_dimensions_callback) - - self.children = children - self.window_too_small = window_too_small or _window_too_small() - self.get_dimensions = get_dimensions - self.report_dimensions_callback = report_dimensions_callback - - def preferred_width(self, cli, max_available_width): - if self.children: - dimensions = [c.preferred_width(cli, max_available_width) for c in self.children] - return max_layout_dimensions(dimensions) - else: - return LayoutDimension(0) - - def preferred_height(self, cli, width, max_available_height): - dimensions = [c.preferred_height(cli, width, max_available_height) for c in self.children] - return sum_layout_dimensions(dimensions) - - def reset(self): - for c in self.children: - c.reset() - - def write_to_screen(self, cli, screen, mouse_handlers, write_position): - """ - Render the prompt to a `Screen` instance. - - :param screen: The :class:`~prompt_toolkit.layout.screen.Screen` class - to which the output has to be written. - """ - sizes = self._divide_heigths(cli, write_position) - - if self.report_dimensions_callback: - self.report_dimensions_callback(cli, sizes) - - if sizes is None: - self.window_too_small.write_to_screen( - cli, screen, mouse_handlers, write_position) - else: - # Draw child panes. - ypos = write_position.ypos - xpos = write_position.xpos - width = write_position.width - - for s, c in zip(sizes, self.children): - c.write_to_screen(cli, screen, mouse_handlers, WritePosition(xpos, ypos, width, s)) - ypos += s - - def _divide_heigths(self, cli, write_position): - """ - Return the heights for all rows. - Or None when there is not enough space. - """ - if not self.children: - return [] - - # Calculate heights. - given_dimensions = self.get_dimensions(cli) if self.get_dimensions else None - - def get_dimension_for_child(c, index): - if given_dimensions and given_dimensions[index] is not None: - return given_dimensions[index] - else: - return c.preferred_height(cli, write_position.width, write_position.extended_height) - - dimensions = [get_dimension_for_child(c, index) for index, c in enumerate(self.children)] - - # Sum dimensions - sum_dimensions = sum_layout_dimensions(dimensions) - - # If there is not enough space for both. - # Don't do anything. - if sum_dimensions.min > write_position.extended_height: - return - - # Find optimal sizes. (Start with minimal size, increase until we cover - # the whole height.) - sizes = [d.min for d in dimensions] - - child_generator = take_using_weights( - items=list(range(len(dimensions))), - weights=[d.weight for d in dimensions]) - - i = next(child_generator) - - while sum(sizes) < min(write_position.extended_height, sum_dimensions.preferred): - # Increase until we meet at least the 'preferred' size. - if sizes[i] < dimensions[i].preferred: - sizes[i] += 1 - i = next(child_generator) - - if not any([cli.is_returning, cli.is_exiting, cli.is_aborting]): - while sum(sizes) < min(write_position.height, sum_dimensions.max): - # Increase until we use all the available space. (or until "max") - if sizes[i] < dimensions[i].max: - sizes[i] += 1 - i = next(child_generator) - - return sizes - - def walk(self, cli): - """ Walk through children. """ - yield self - for c in self.children: - for i in c.walk(cli): - yield i - - -class VSplit(Container): - """ - Several layouts, one stacked left/right of the other. - - :param children: List of child :class:`.Container` objects. - :param window_too_small: A :class:`.Container` object that is displayed if - there is not enough space for all the children. By default, this is a - "Window too small" message. - :param get_dimensions: (`None` or a callable that takes a - `CommandLineInterface` and returns a list of `LayoutDimension` - instances.) By default the dimensions are taken from the children and - divided by the available space. However, when `get_dimensions` is specified, - this is taken instead. - :param report_dimensions_callback: When rendering, this function is called - with the `CommandLineInterface` and the list of used dimensions. (As a - list of integers.) - """ - def __init__(self, children, window_too_small=None, - get_dimensions=None, report_dimensions_callback=None): - assert all(isinstance(c, Container) for c in children) - assert window_too_small is None or isinstance(window_too_small, Container) - assert get_dimensions is None or callable(get_dimensions) - assert report_dimensions_callback is None or callable(report_dimensions_callback) - - self.children = children - self.window_too_small = window_too_small or _window_too_small() - self.get_dimensions = get_dimensions - self.report_dimensions_callback = report_dimensions_callback - - def preferred_width(self, cli, max_available_width): - dimensions = [c.preferred_width(cli, max_available_width) for c in self.children] - return sum_layout_dimensions(dimensions) - - def preferred_height(self, cli, width, max_available_height): - sizes = self._divide_widths(cli, width) - if sizes is None: - return LayoutDimension() - else: - dimensions = [c.preferred_height(cli, s, max_available_height) - for s, c in zip(sizes, self.children)] - return max_layout_dimensions(dimensions) - - def reset(self): - for c in self.children: - c.reset() - - def _divide_widths(self, cli, width): - """ - Return the widths for all columns. - Or None when there is not enough space. - """ - if not self.children: - return [] - - # Calculate widths. - given_dimensions = self.get_dimensions(cli) if self.get_dimensions else None - - def get_dimension_for_child(c, index): - if given_dimensions and given_dimensions[index] is not None: - return given_dimensions[index] - else: - return c.preferred_width(cli, width) - - dimensions = [get_dimension_for_child(c, index) for index, c in enumerate(self.children)] - - # Sum dimensions - sum_dimensions = sum_layout_dimensions(dimensions) - - # If there is not enough space for both. - # Don't do anything. - if sum_dimensions.min > width: - return - - # Find optimal sizes. (Start with minimal size, increase until we cover - # the whole height.) - sizes = [d.min for d in dimensions] - - child_generator = take_using_weights( - items=list(range(len(dimensions))), - weights=[d.weight for d in dimensions]) - - i = next(child_generator) - - while sum(sizes) < min(width, sum_dimensions.preferred): - # Increase until we meet at least the 'preferred' size. - if sizes[i] < dimensions[i].preferred: - sizes[i] += 1 - i = next(child_generator) - - while sum(sizes) < min(width, sum_dimensions.max): - # Increase until we use all the available space. - if sizes[i] < dimensions[i].max: - sizes[i] += 1 - i = next(child_generator) - - return sizes - - def write_to_screen(self, cli, screen, mouse_handlers, write_position): - """ - Render the prompt to a `Screen` instance. - - :param screen: The :class:`~prompt_toolkit.layout.screen.Screen` class - to which the output has to be written. - """ - if not self.children: - return - - sizes = self._divide_widths(cli, write_position.width) - - if self.report_dimensions_callback: - self.report_dimensions_callback(cli, sizes) - - # If there is not enough space. - if sizes is None: - self.window_too_small.write_to_screen( - cli, screen, mouse_handlers, write_position) - return - - # Calculate heights, take the largest possible, but not larger than write_position.extended_height. - heights = [child.preferred_height(cli, width, write_position.extended_height).preferred - for width, child in zip(sizes, self.children)] - height = max(write_position.height, min(write_position.extended_height, max(heights))) - - # Draw child panes. - ypos = write_position.ypos - xpos = write_position.xpos - - for s, c in zip(sizes, self.children): - c.write_to_screen(cli, screen, mouse_handlers, WritePosition(xpos, ypos, s, height)) - xpos += s - - def walk(self, cli): - """ Walk through children. """ - yield self - for c in self.children: - for i in c.walk(cli): - yield i - - -class FloatContainer(Container): - """ - Container which can contain another container for the background, as well - as a list of floating containers on top of it. - - Example Usage:: - - FloatContainer(content=Window(...), - floats=[ - Float(xcursor=True, - ycursor=True, - layout=CompletionMenu(...)) - ]) - """ - def __init__(self, content, floats): - assert isinstance(content, Container) - assert all(isinstance(f, Float) for f in floats) - - self.content = content - self.floats = floats - - def reset(self): - self.content.reset() - - for f in self.floats: - f.content.reset() - - def preferred_width(self, cli, write_position): - return self.content.preferred_width(cli, write_position) - - def preferred_height(self, cli, width, max_available_height): - """ - Return the preferred height of the float container. - (We don't care about the height of the floats, they should always fit - into the dimensions provided by the container.) - """ - return self.content.preferred_height(cli, width, max_available_height) - - def write_to_screen(self, cli, screen, mouse_handlers, write_position): - self.content.write_to_screen(cli, screen, mouse_handlers, write_position) - - for fl in self.floats: - # When a menu_position was given, use this instead of the cursor - # position. (These cursor positions are absolute, translate again - # relative to the write_position.) - # Note: This should be inside the for-loop, because one float could - # set the cursor position to be used for the next one. - cursor_position = screen.menu_position or screen.cursor_position - cursor_position = Point(x=cursor_position.x - write_position.xpos, - y=cursor_position.y - write_position.ypos) - - fl_width = fl.get_width(cli) - fl_height = fl.get_height(cli) - - # Left & width given. - if fl.left is not None and fl_width is not None: - xpos = fl.left - width = fl_width - # Left & right given -> calculate width. - elif fl.left is not None and fl.right is not None: - xpos = fl.left - width = write_position.width - fl.left - fl.right - # Width & right given -> calculate left. - elif fl_width is not None and fl.right is not None: - xpos = write_position.width - fl.right - fl_width - width = fl_width - elif fl.xcursor: - width = fl_width - if width is None: - width = fl.content.preferred_width(cli, write_position.width).preferred - width = min(write_position.width, width) - - xpos = cursor_position.x - if xpos + width > write_position.width: - xpos = max(0, write_position.width - width) - # Only width given -> center horizontally. - elif fl_width: - xpos = int((write_position.width - fl_width) / 2) - width = fl_width - # Otherwise, take preferred width from float content. - else: - width = fl.content.preferred_width(cli, write_position.width).preferred - - if fl.left is not None: - xpos = fl.left - elif fl.right is not None: - xpos = max(0, write_position.width - width - fl.right) - else: # Center horizontally. - xpos = max(0, int((write_position.width - width) / 2)) - - # Trim. - width = min(width, write_position.width - xpos) - - # Top & height given. - if fl.top is not None and fl_height is not None: - ypos = fl.top - height = fl_height - # Top & bottom given -> calculate height. - elif fl.top is not None and fl.bottom is not None: - ypos = fl.top - height = write_position.height - fl.top - fl.bottom - # Height & bottom given -> calculate top. - elif fl_height is not None and fl.bottom is not None: - ypos = write_position.height - fl_height - fl.bottom - height = fl_height - # Near cursor - elif fl.ycursor: - ypos = cursor_position.y + 1 - - height = fl_height - if height is None: - height = fl.content.preferred_height( - cli, width, write_position.extended_height).preferred - - # Reduce height if not enough space. (We can use the - # extended_height when the content requires it.) - if height > write_position.extended_height - ypos: - if write_position.extended_height - ypos + 1 >= ypos: - # When the space below the cursor is more than - # the space above, just reduce the height. - height = write_position.extended_height - ypos - else: - # Otherwise, fit the float above the cursor. - height = min(height, cursor_position.y) - ypos = cursor_position.y - height - - # Only height given -> center vertically. - elif fl_width: - ypos = int((write_position.height - fl_height) / 2) - height = fl_height - # Otherwise, take preferred height from content. - else: - height = fl.content.preferred_height( - cli, width, write_position.extended_height).preferred - - if fl.top is not None: - ypos = fl.top - elif fl.bottom is not None: - ypos = max(0, write_position.height - height - fl.bottom) - else: # Center vertically. - ypos = max(0, int((write_position.height - height) / 2)) - - # Trim. - height = min(height, write_position.height - ypos) - - # Write float. - # (xpos and ypos can be negative: a float can be partially visible.) - if height > 0 and width > 0: - wp = WritePosition(xpos=xpos + write_position.xpos, - ypos=ypos + write_position.ypos, - width=width, height=height) - - if not fl.hide_when_covering_content or self._area_is_empty(screen, wp): - fl.content.write_to_screen(cli, screen, mouse_handlers, wp) - - def _area_is_empty(self, screen, write_position): - """ - Return True when the area below the write position is still empty. - (For floats that should not hide content underneath.) - """ - wp = write_position - Transparent = Token.Transparent - - for y in range(wp.ypos, wp.ypos + wp.height): - if y in screen.data_buffer: - row = screen.data_buffer[y] - - for x in range(wp.xpos, wp.xpos + wp.width): - c = row[x] - if c.char != ' ' or c.token != Transparent: - return False - - return True - - def walk(self, cli): - """ Walk through children. """ - yield self - - for i in self.content.walk(cli): - yield i - - for f in self.floats: - for i in f.content.walk(cli): - yield i - - -class Float(object): - """ - Float for use in a :class:`.FloatContainer`. - - :param content: :class:`.Container` instance. - :param hide_when_covering_content: Hide the float when it covers content underneath. - """ - def __init__(self, top=None, right=None, bottom=None, left=None, - width=None, height=None, get_width=None, get_height=None, - xcursor=False, ycursor=False, content=None, - hide_when_covering_content=False): - assert isinstance(content, Container) - assert width is None or get_width is None - assert height is None or get_height is None - - self.left = left - self.right = right - self.top = top - self.bottom = bottom - - self._width = width - self._height = height - - self._get_width = get_width - self._get_height = get_height - - self.xcursor = xcursor - self.ycursor = ycursor - - self.content = content - self.hide_when_covering_content = hide_when_covering_content - - def get_width(self, cli): - if self._width: - return self._width - if self._get_width: - return self._get_width(cli) - - def get_height(self, cli): - if self._height: - return self._height - if self._get_height: - return self._get_height(cli) - - def __repr__(self): - return 'Float(content=%r)' % self.content - - -class WindowRenderInfo(object): - """ - Render information, for the last render time of this control. - It stores mapping information between the input buffers (in case of a - :class:`~prompt_toolkit.layout.controls.BufferControl`) and the actual - render position on the output screen. - - (Could be used for implementation of the Vi 'H' and 'L' key bindings as - well as implementing mouse support.) - - :param ui_content: The original :class:`.UIContent` instance that contains - the whole input, without clipping. (ui_content) - :param horizontal_scroll: The horizontal scroll of the :class:`.Window` instance. - :param vertical_scroll: The vertical scroll of the :class:`.Window` instance. - :param window_width: The width of the window that displays the content, - without the margins. - :param window_height: The height of the window that displays the content. - :param configured_scroll_offsets: The scroll offsets as configured for the - :class:`Window` instance. - :param visible_line_to_row_col: Mapping that maps the row numbers on the - displayed screen (starting from zero for the first visible line) to - (row, col) tuples pointing to the row and column of the :class:`.UIContent`. - :param rowcol_to_yx: Mapping that maps (row, column) tuples representing - coordinates of the :class:`UIContent` to (y, x) absolute coordinates at - the rendered screen. - """ - def __init__(self, ui_content, horizontal_scroll, vertical_scroll, - window_width, window_height, - configured_scroll_offsets, - visible_line_to_row_col, rowcol_to_yx, - x_offset, y_offset, wrap_lines): - assert isinstance(ui_content, UIContent) - assert isinstance(horizontal_scroll, int) - assert isinstance(vertical_scroll, int) - assert isinstance(window_width, int) - assert isinstance(window_height, int) - assert isinstance(configured_scroll_offsets, ScrollOffsets) - assert isinstance(visible_line_to_row_col, dict) - assert isinstance(rowcol_to_yx, dict) - assert isinstance(x_offset, int) - assert isinstance(y_offset, int) - assert isinstance(wrap_lines, bool) - - self.ui_content = ui_content - self.vertical_scroll = vertical_scroll - self.window_width = window_width # Width without margins. - self.window_height = window_height - - self.configured_scroll_offsets = configured_scroll_offsets - self.visible_line_to_row_col = visible_line_to_row_col - self.wrap_lines = wrap_lines - - self._rowcol_to_yx = rowcol_to_yx # row/col from input to absolute y/x - # screen coordinates. - self._x_offset = x_offset - self._y_offset = y_offset - - @property - def visible_line_to_input_line(self): - return dict( - (visible_line, rowcol[0]) - for visible_line, rowcol in self.visible_line_to_row_col.items()) - - @property - def cursor_position(self): - """ - Return the cursor position coordinates, relative to the left/top corner - of the rendered screen. - """ - cpos = self.ui_content.cursor_position - y, x = self._rowcol_to_yx[cpos.y, cpos.x] - return Point(x=x - self._x_offset, y=y - self._y_offset) - - @property - def applied_scroll_offsets(self): - """ - Return a :class:`.ScrollOffsets` instance that indicates the actual - offset. This can be less than or equal to what's configured. E.g, when - the cursor is completely at the top, the top offset will be zero rather - than what's configured. - """ - if self.displayed_lines[0] == 0: - top = 0 - else: - # Get row where the cursor is displayed. - y = self.input_line_to_visible_line[self.ui_content.cursor_position.y] - top = min(y, self.configured_scroll_offsets.top) - - return ScrollOffsets( - top=top, - bottom=min(self.ui_content.line_count - self.displayed_lines[-1] - 1, - self.configured_scroll_offsets.bottom), - - # For left/right, it probably doesn't make sense to return something. - # (We would have to calculate the widths of all the lines and keep - # double width characters in mind.) - left=0, right=0) - - @property - def displayed_lines(self): - """ - List of all the visible rows. (Line numbers of the input buffer.) - The last line may not be entirely visible. - """ - return sorted(row for row, col in self.visible_line_to_row_col.values()) - - @property - def input_line_to_visible_line(self): - """ - Return the dictionary mapping the line numbers of the input buffer to - the lines of the screen. When a line spans several rows at the screen, - the first row appears in the dictionary. - """ - result = {} - for k, v in self.visible_line_to_input_line.items(): - if v in result: - result[v] = min(result[v], k) - else: - result[v] = k - return result - - def first_visible_line(self, after_scroll_offset=False): - """ - Return the line number (0 based) of the input document that corresponds - with the first visible line. - """ - if after_scroll_offset: - return self.displayed_lines[self.applied_scroll_offsets.top] - else: - return self.displayed_lines[0] - - def last_visible_line(self, before_scroll_offset=False): - """ - Like `first_visible_line`, but for the last visible line. - """ - if before_scroll_offset: - return self.displayed_lines[-1 - self.applied_scroll_offsets.bottom] - else: - return self.displayed_lines[-1] - - def center_visible_line(self, before_scroll_offset=False, - after_scroll_offset=False): - """ - Like `first_visible_line`, but for the center visible line. - """ - return (self.first_visible_line(after_scroll_offset) + - (self.last_visible_line(before_scroll_offset) - - self.first_visible_line(after_scroll_offset)) // 2 - ) - - @property - def content_height(self): - """ - The full height of the user control. - """ - return self.ui_content.line_count - - @property - def full_height_visible(self): - """ - True when the full height is visible (There is no vertical scroll.) - """ - return self.vertical_scroll == 0 and self.last_visible_line() == self.content_height - - @property - def top_visible(self): - """ - True when the top of the buffer is visible. - """ - return self.vertical_scroll == 0 - - @property - def bottom_visible(self): - """ - True when the bottom of the buffer is visible. - """ - return self.last_visible_line() == self.content_height - 1 - - @property - def vertical_scroll_percentage(self): - """ - Vertical scroll as a percentage. (0 means: the top is visible, - 100 means: the bottom is visible.) - """ - if self.bottom_visible: - return 100 - else: - return (100 * self.vertical_scroll // self.content_height) - - def get_height_for_line(self, lineno): - """ - Return the height of the given line. - (The height that it would take, if this line became visible.) - """ - if self.wrap_lines: - return self.ui_content.get_height_for_line(lineno, self.window_width) - else: - return 1 - - -class ScrollOffsets(object): - """ - Scroll offsets for the :class:`.Window` class. - - Note that left/right offsets only make sense if line wrapping is disabled. - """ - def __init__(self, top=0, bottom=0, left=0, right=0): - assert isinstance(top, Integer) - assert isinstance(bottom, Integer) - assert isinstance(left, Integer) - assert isinstance(right, Integer) - - self._top = top - self._bottom = bottom - self._left = left - self._right = right - - @property - def top(self): - return int(self._top) - - @property - def bottom(self): - return int(self._bottom) - - @property - def left(self): - return int(self._left) - - @property - def right(self): - return int(self._right) - - def __repr__(self): - return 'ScrollOffsets(top=%r, bottom=%r, left=%r, right=%r)' % ( - self.top, self.bottom, self.left, self.right) - - -class ColorColumn(object): - def __init__(self, position, token=Token.ColorColumn): - self.position = position - self.token = token - - -_in_insert_mode = ViInsertMode() | EmacsInsertMode() - - -class Window(Container): - """ - Container that holds a control. - - :param content: :class:`~prompt_toolkit.layout.controls.UIControl` instance. - :param width: :class:`~prompt_toolkit.layout.dimension.LayoutDimension` instance. - :param height: :class:`~prompt_toolkit.layout.dimension.LayoutDimension` instance. - :param get_width: callable which takes a `CommandLineInterface` and returns a `LayoutDimension`. - :param get_height: callable which takes a `CommandLineInterface` and returns a `LayoutDimension`. - :param dont_extend_width: When `True`, don't take up more width then the - preferred width reported by the control. - :param dont_extend_height: When `True`, don't take up more width then the - preferred height reported by the control. - :param left_margins: A list of :class:`~prompt_toolkit.layout.margins.Margin` - instance to be displayed on the left. For instance: - :class:`~prompt_toolkit.layout.margins.NumberredMargin` can be one of - them in order to show line numbers. - :param right_margins: Like `left_margins`, but on the other side. - :param scroll_offsets: :class:`.ScrollOffsets` instance, representing the - preferred amount of lines/columns to be always visible before/after the - cursor. When both top and bottom are a very high number, the cursor - will be centered vertically most of the time. - :param allow_scroll_beyond_bottom: A `bool` or - :class:`~prompt_toolkit.filters.CLIFilter` instance. When True, allow - scrolling so far, that the top part of the content is not visible - anymore, while there is still empty space available at the bottom of - the window. In the Vi editor for instance, this is possible. You will - see tildes while the top part of the body is hidden. - :param wrap_lines: A `bool` or :class:`~prompt_toolkit.filters.CLIFilter` - instance. When True, don't scroll horizontally, but wrap lines instead. - :param get_vertical_scroll: Callable that takes this window - instance as input and returns a preferred vertical scroll. - (When this is `None`, the scroll is only determined by the last and - current cursor position.) - :param get_horizontal_scroll: Callable that takes this window - instance as input and returns a preferred vertical scroll. - :param always_hide_cursor: A `bool` or - :class:`~prompt_toolkit.filters.CLIFilter` instance. When True, never - display the cursor, even when the user control specifies a cursor - position. - :param cursorline: A `bool` or :class:`~prompt_toolkit.filters.CLIFilter` - instance. When True, display a cursorline. - :param cursorcolumn: A `bool` or :class:`~prompt_toolkit.filters.CLIFilter` - instance. When True, display a cursorcolumn. - :param get_colorcolumns: A callable that takes a `CommandLineInterface` and - returns a a list of :class:`.ColorColumn` instances that describe the - columns to be highlighted. - :param cursorline_token: The token to be used for highlighting the current line, - if `cursorline` is True. - :param cursorcolumn_token: The token to be used for highlighting the current line, - if `cursorcolumn` is True. - """ - def __init__(self, content, width=None, height=None, get_width=None, - get_height=None, dont_extend_width=False, dont_extend_height=False, - left_margins=None, right_margins=None, scroll_offsets=None, - allow_scroll_beyond_bottom=False, wrap_lines=False, - get_vertical_scroll=None, get_horizontal_scroll=None, always_hide_cursor=False, - cursorline=False, cursorcolumn=False, get_colorcolumns=None, - cursorline_token=Token.CursorLine, cursorcolumn_token=Token.CursorColumn): - assert isinstance(content, UIControl) - assert width is None or isinstance(width, LayoutDimension) - assert height is None or isinstance(height, LayoutDimension) - assert get_width is None or callable(get_width) - assert get_height is None or callable(get_height) - assert width is None or get_width is None - assert height is None or get_height is None - assert scroll_offsets is None or isinstance(scroll_offsets, ScrollOffsets) - assert left_margins is None or all(isinstance(m, Margin) for m in left_margins) - assert right_margins is None or all(isinstance(m, Margin) for m in right_margins) - assert get_vertical_scroll is None or callable(get_vertical_scroll) - assert get_horizontal_scroll is None or callable(get_horizontal_scroll) - assert get_colorcolumns is None or callable(get_colorcolumns) - - self.allow_scroll_beyond_bottom = to_cli_filter(allow_scroll_beyond_bottom) - self.always_hide_cursor = to_cli_filter(always_hide_cursor) - self.wrap_lines = to_cli_filter(wrap_lines) - self.cursorline = to_cli_filter(cursorline) - self.cursorcolumn = to_cli_filter(cursorcolumn) - - self.content = content - self.dont_extend_width = dont_extend_width - self.dont_extend_height = dont_extend_height - self.left_margins = left_margins or [] - self.right_margins = right_margins or [] - self.scroll_offsets = scroll_offsets or ScrollOffsets() - self.get_vertical_scroll = get_vertical_scroll - self.get_horizontal_scroll = get_horizontal_scroll - self._width = get_width or (lambda cli: width) - self._height = get_height or (lambda cli: height) - self.get_colorcolumns = get_colorcolumns or (lambda cli: []) - self.cursorline_token = cursorline_token - self.cursorcolumn_token = cursorcolumn_token - - # Cache for the screens generated by the margin. - self._ui_content_cache = SimpleCache(maxsize=8) - self._margin_width_cache = SimpleCache(maxsize=1) - - self.reset() - - def __repr__(self): - return 'Window(content=%r)' % self.content - - def reset(self): - self.content.reset() - - #: Scrolling position of the main content. - self.vertical_scroll = 0 - self.horizontal_scroll = 0 - - # Vertical scroll 2: this is the vertical offset that a line is - # scrolled if a single line (the one that contains the cursor) consumes - # all of the vertical space. - self.vertical_scroll_2 = 0 - - #: Keep render information (mappings between buffer input and render - #: output.) - self.render_info = None - - def _get_margin_width(self, cli, margin): - """ - Return the width for this margin. - (Calculate only once per render time.) - """ - # Margin.get_width, needs to have a UIContent instance. - def get_ui_content(): - return self._get_ui_content(cli, width=0, height=0) - - def get_width(): - return margin.get_width(cli, get_ui_content) - - key = (margin, cli.render_counter) - return self._margin_width_cache.get(key, get_width) - - def preferred_width(self, cli, max_available_width): - # Calculate the width of the margin. - total_margin_width = sum(self._get_margin_width(cli, m) for m in - self.left_margins + self.right_margins) - - # Window of the content. (Can be `None`.) - preferred_width = self.content.preferred_width( - cli, max_available_width - total_margin_width) - - if preferred_width is not None: - # Include width of the margins. - preferred_width += total_margin_width - - # Merge. - return self._merge_dimensions( - dimension=self._width(cli), - preferred=preferred_width, - dont_extend=self.dont_extend_width) - - def preferred_height(self, cli, width, max_available_height): - total_margin_width = sum(self._get_margin_width(cli, m) for m in - self.left_margins + self.right_margins) - wrap_lines = self.wrap_lines(cli) - - return self._merge_dimensions( - dimension=self._height(cli), - preferred=self.content.preferred_height( - cli, width - total_margin_width, max_available_height, wrap_lines), - dont_extend=self.dont_extend_height) - - @staticmethod - def _merge_dimensions(dimension, preferred=None, dont_extend=False): - """ - Take the LayoutDimension from this `Window` class and the received - preferred size from the `UIControl` and return a `LayoutDimension` to - report to the parent container. - """ - dimension = dimension or LayoutDimension() - - # When a preferred dimension was explicitly given to the Window, - # ignore the UIControl. - if dimension.preferred_specified: - preferred = dimension.preferred - - # When a 'preferred' dimension is given by the UIControl, make sure - # that it stays within the bounds of the Window. - if preferred is not None: - if dimension.max: - preferred = min(preferred, dimension.max) - - if dimension.min: - preferred = max(preferred, dimension.min) - - # When a `dont_extend` flag has been given, use the preferred dimension - # also as the max dimension. - if dont_extend and preferred is not None: - max_ = min(dimension.max, preferred) - else: - max_ = dimension.max - - return LayoutDimension( - min=dimension.min, max=max_, - preferred=preferred, weight=dimension.weight) - - def _get_ui_content(self, cli, width, height): - """ - Create a `UIContent` instance. - """ - def get_content(): - return self.content.create_content(cli, width=width, height=height) - - key = (cli.render_counter, width, height) - return self._ui_content_cache.get(key, get_content) - - def _get_digraph_char(self, cli): - " Return `False`, or the Digraph symbol to be used. " - if cli.quoted_insert: - return '^' - if cli.vi_state.waiting_for_digraph: - if cli.vi_state.digraph_symbol1: - return cli.vi_state.digraph_symbol1 - return '?' - return False - - def write_to_screen(self, cli, screen, mouse_handlers, write_position): - """ - Write window to screen. This renders the user control, the margins and - copies everything over to the absolute position at the given screen. - """ - # Calculate margin sizes. - left_margin_widths = [self._get_margin_width(cli, m) for m in self.left_margins] - right_margin_widths = [self._get_margin_width(cli, m) for m in self.right_margins] - total_margin_width = sum(left_margin_widths + right_margin_widths) - - # Render UserControl. - ui_content = self.content.create_content( - cli, write_position.width - total_margin_width, write_position.height) - assert isinstance(ui_content, UIContent) - - # Scroll content. - wrap_lines = self.wrap_lines(cli) - scroll_func = self._scroll_when_linewrapping if wrap_lines else self._scroll_without_linewrapping - - scroll_func( - ui_content, write_position.width - total_margin_width, write_position.height, cli) - - # Write body - visible_line_to_row_col, rowcol_to_yx = self._copy_body( - cli, ui_content, screen, write_position, - sum(left_margin_widths), write_position.width - total_margin_width, - self.vertical_scroll, self.horizontal_scroll, - has_focus=self.content.has_focus(cli), - wrap_lines=wrap_lines, highlight_lines=True, - vertical_scroll_2=self.vertical_scroll_2, - always_hide_cursor=self.always_hide_cursor(cli)) - - # Remember render info. (Set before generating the margins. They need this.) - x_offset=write_position.xpos + sum(left_margin_widths) - y_offset=write_position.ypos - - self.render_info = WindowRenderInfo( - ui_content=ui_content, - horizontal_scroll=self.horizontal_scroll, - vertical_scroll=self.vertical_scroll, - window_width=write_position.width - total_margin_width, - window_height=write_position.height, - configured_scroll_offsets=self.scroll_offsets, - visible_line_to_row_col=visible_line_to_row_col, - rowcol_to_yx=rowcol_to_yx, - x_offset=x_offset, - y_offset=y_offset, - wrap_lines=wrap_lines) - - # Set mouse handlers. - def mouse_handler(cli, mouse_event): - """ Wrapper around the mouse_handler of the `UIControl` that turns - screen coordinates into line coordinates. """ - # Find row/col position first. - yx_to_rowcol = dict((v, k) for k, v in rowcol_to_yx.items()) - y = mouse_event.position.y - x = mouse_event.position.x - - # If clicked below the content area, look for a position in the - # last line instead. - max_y = write_position.ypos + len(visible_line_to_row_col) - 1 - y = min(max_y, y) - - while x >= 0: - try: - row, col = yx_to_rowcol[y, x] - except KeyError: - # Try again. (When clicking on the right side of double - # width characters, or on the right side of the input.) - x -= 1 - else: - # Found position, call handler of UIControl. - result = self.content.mouse_handler( - cli, MouseEvent(position=Point(x=col, y=row), - event_type=mouse_event.event_type)) - break - else: - # nobreak. - # (No x/y coordinate found for the content. This happens in - # case of a FillControl, that only specifies a background, but - # doesn't have a content. Report (0,0) instead.) - result = self.content.mouse_handler( - cli, MouseEvent(position=Point(x=0, y=0), - event_type=mouse_event.event_type)) - - # If it returns NotImplemented, handle it here. - if result == NotImplemented: - return self._mouse_handler(cli, mouse_event) - - return result - - mouse_handlers.set_mouse_handler_for_range( - x_min=write_position.xpos + sum(left_margin_widths), - x_max=write_position.xpos + write_position.width - total_margin_width, - y_min=write_position.ypos, - y_max=write_position.ypos + write_position.height, - handler=mouse_handler) - - # Render and copy margins. - move_x = 0 - - def render_margin(m, width): - " Render margin. Return `Screen`. " - # Retrieve margin tokens. - tokens = m.create_margin(cli, self.render_info, width, write_position.height) - - # Turn it into a UIContent object. - # already rendered those tokens using this size.) - return TokenListControl.static(tokens).create_content( - cli, width + 1, write_position.height) - - for m, width in zip(self.left_margins, left_margin_widths): - # Create screen for margin. - margin_screen = render_margin(m, width) - - # Copy and shift X. - self._copy_margin(cli, margin_screen, screen, write_position, move_x, width) - move_x += width - - move_x = write_position.width - sum(right_margin_widths) - - for m, width in zip(self.right_margins, right_margin_widths): - # Create screen for margin. - margin_screen = render_margin(m, width) - - # Copy and shift X. - self._copy_margin(cli, margin_screen, screen, write_position, move_x, width) - move_x += width - - def _copy_body(self, cli, ui_content, new_screen, write_position, move_x, - width, vertical_scroll=0, horizontal_scroll=0, - has_focus=False, wrap_lines=False, highlight_lines=False, - vertical_scroll_2=0, always_hide_cursor=False): - """ - Copy the UIContent into the output screen. - """ - xpos = write_position.xpos + move_x - ypos = write_position.ypos - line_count = ui_content.line_count - new_buffer = new_screen.data_buffer - empty_char = _CHAR_CACHE['', Token] - ZeroWidthEscape = Token.ZeroWidthEscape - - # Map visible line number to (row, col) of input. - # 'col' will always be zero if line wrapping is off. - visible_line_to_row_col = {} - rowcol_to_yx = {} # Maps (row, col) from the input to (y, x) screen coordinates. - - # Fill background with default_char first. - default_char = ui_content.default_char - - if default_char: - for y in range(ypos, ypos + write_position.height): - new_buffer_row = new_buffer[y] - for x in range(xpos, xpos + width): - new_buffer_row[x] = default_char - - # Copy content. - def copy(): - y = - vertical_scroll_2 - lineno = vertical_scroll - - while y < write_position.height and lineno < line_count: - # Take the next line and copy it in the real screen. - line = ui_content.get_line(lineno) - - col = 0 - x = -horizontal_scroll - - visible_line_to_row_col[y] = (lineno, horizontal_scroll) - new_buffer_row = new_buffer[y + ypos] - - for token, text in line: - # Remember raw VT escape sequences. (E.g. FinalTerm's - # escape sequences.) - if token == ZeroWidthEscape: - new_screen.zero_width_escapes[y + ypos][x + xpos] += text - continue - - for c in text: - char = _CHAR_CACHE[c, token] - char_width = char.width - - # Wrap when the line width is exceeded. - if wrap_lines and x + char_width > width: - visible_line_to_row_col[y + 1] = ( - lineno, visible_line_to_row_col[y][1] + x) - y += 1 - x = -horizontal_scroll # This would be equal to zero. - # (horizontal_scroll=0 when wrap_lines.) - new_buffer_row = new_buffer[y + ypos] - - if y >= write_position.height: - return y # Break out of all for loops. - - # Set character in screen and shift 'x'. - if x >= 0 and y >= 0 and x < write_position.width: - new_buffer_row[x + xpos] = char - - # When we print a multi width character, make sure - # to erase the neighbous positions in the screen. - # (The empty string if different from everything, - # so next redraw this cell will repaint anyway.) - if char_width > 1: - for i in range(1, char_width): - new_buffer_row[x + xpos + i] = empty_char - - # If this is a zero width characters, then it's - # probably part of a decomposed unicode character. - # See: https://en.wikipedia.org/wiki/Unicode_equivalence - # Merge it in the previous cell. - elif char_width == 0 and x - 1 >= 0: - prev_char = new_buffer_row[x + xpos - 1] - char2 = _CHAR_CACHE[prev_char.char + c, prev_char.token] - new_buffer_row[x + xpos - 1] = char2 - - # Keep track of write position for each character. - rowcol_to_yx[lineno, col] = (y + ypos, x + xpos) - - col += 1 - x += char_width - - lineno += 1 - y += 1 - return y - - y = copy() - - def cursor_pos_to_screen_pos(row, col): - " Translate row/col from UIContent to real Screen coordinates. " - try: - y, x = rowcol_to_yx[row, col] - except KeyError: - # Normally this should never happen. (It is a bug, if it happens.) - # But to be sure, return (0, 0) - return Point(y=0, x=0) - - # raise ValueError( - # 'Invalid position. row=%r col=%r, vertical_scroll=%r, ' - # 'horizontal_scroll=%r, height=%r' % - # (row, col, vertical_scroll, horizontal_scroll, write_position.height)) - else: - return Point(y=y, x=x) - - # Set cursor and menu positions. - if ui_content.cursor_position: - screen_cursor_position = cursor_pos_to_screen_pos( - ui_content.cursor_position.y, ui_content.cursor_position.x) - - if has_focus: - new_screen.cursor_position = screen_cursor_position - - if always_hide_cursor: - new_screen.show_cursor = False - else: - new_screen.show_cursor = ui_content.show_cursor - - self._highlight_digraph(cli, new_screen) - - if highlight_lines: - self._highlight_cursorlines( - cli, new_screen, screen_cursor_position, xpos, ypos, width, - write_position.height) - - # Draw input characters from the input processor queue. - if has_focus and ui_content.cursor_position: - self._show_input_processor_key_buffer(cli, new_screen) - - # Set menu position. - if not new_screen.menu_position and ui_content.menu_position: - new_screen.menu_position = cursor_pos_to_screen_pos( - ui_content.menu_position.y, ui_content.menu_position.x) - - # Update output screne height. - new_screen.height = max(new_screen.height, ypos + write_position.height) - - return visible_line_to_row_col, rowcol_to_yx - - def _highlight_digraph(self, cli, new_screen): - """ - When we are in Vi digraph mode, put a question mark underneath the - cursor. - """ - digraph_char = self._get_digraph_char(cli) - if digraph_char: - cpos = new_screen.cursor_position - new_screen.data_buffer[cpos.y][cpos.x] = \ - _CHAR_CACHE[digraph_char, Token.Digraph] - - def _show_input_processor_key_buffer(self, cli, new_screen): - """ - When the user is typing a key binding that consists of several keys, - display the last pressed key if the user is in insert mode and the key - is meaningful to be displayed. - E.g. Some people want to bind 'jj' to escape in Vi insert mode. But the - first 'j' needs to be displayed in order to get some feedback. - """ - key_buffer = cli.input_processor.key_buffer - - if key_buffer and _in_insert_mode(cli) and not cli.is_done: - # The textual data for the given key. (Can be a VT100 escape - # sequence.) - data = key_buffer[-1].data - - # Display only if this is a 1 cell width character. - if get_cwidth(data) == 1: - cpos = new_screen.cursor_position - new_screen.data_buffer[cpos.y][cpos.x] = \ - _CHAR_CACHE[data, Token.PartialKeyBinding] - - def _highlight_cursorlines(self, cli, new_screen, cpos, x, y, width, height): - """ - Highlight cursor row/column. - """ - cursor_line_token = (':', ) + self.cursorline_token - cursor_column_token = (':', ) + self.cursorcolumn_token - - data_buffer = new_screen.data_buffer - - # Highlight cursor line. - if self.cursorline(cli): - row = data_buffer[cpos.y] - for x in range(x, x + width): - original_char = row[x] - row[x] = _CHAR_CACHE[ - original_char.char, original_char.token + cursor_line_token] - - # Highlight cursor column. - if self.cursorcolumn(cli): - for y2 in range(y, y + height): - row = data_buffer[y2] - original_char = row[cpos.x] - row[cpos.x] = _CHAR_CACHE[ - original_char.char, original_char.token + cursor_column_token] - - # Highlight color columns - for cc in self.get_colorcolumns(cli): - assert isinstance(cc, ColorColumn) - color_column_token = (':', ) + cc.token - column = cc.position - - for y2 in range(y, y + height): - row = data_buffer[y2] - original_char = row[column] - row[column] = _CHAR_CACHE[ - original_char.char, original_char.token + color_column_token] - - def _copy_margin(self, cli, lazy_screen, new_screen, write_position, move_x, width): - """ - Copy characters from the margin screen to the real screen. - """ - xpos = write_position.xpos + move_x - ypos = write_position.ypos - - margin_write_position = WritePosition(xpos, ypos, width, write_position.height) - self._copy_body(cli, lazy_screen, new_screen, margin_write_position, 0, width) - - def _scroll_when_linewrapping(self, ui_content, width, height, cli): - """ - Scroll to make sure the cursor position is visible and that we maintain - the requested scroll offset. - - Set `self.horizontal_scroll/vertical_scroll`. - """ - scroll_offsets_bottom = self.scroll_offsets.bottom - scroll_offsets_top = self.scroll_offsets.top - - # We don't have horizontal scrolling. - self.horizontal_scroll = 0 - - # If the current line consumes more than the whole window height, - # then we have to scroll vertically inside this line. (We don't take - # the scroll offsets into account for this.) - # Also, ignore the scroll offsets in this case. Just set the vertical - # scroll to this line. - if ui_content.get_height_for_line(ui_content.cursor_position.y, width) > height - scroll_offsets_top: - # Calculate the height of the text before the cursor, with the line - # containing the cursor included, and the character belowe the - # cursor included as well. - line = explode_tokens(ui_content.get_line(ui_content.cursor_position.y)) - text_before_cursor = token_list_to_text(line[:ui_content.cursor_position.x + 1]) - text_before_height = UIContent.get_height_for_text(text_before_cursor, width) - - # Adjust scroll offset. - self.vertical_scroll = ui_content.cursor_position.y - self.vertical_scroll_2 = min(text_before_height - 1, self.vertical_scroll_2) - self.vertical_scroll_2 = max(0, text_before_height - height, self.vertical_scroll_2) - return - else: - self.vertical_scroll_2 = 0 - - # Current line doesn't consume the whole height. Take scroll offsets into account. - def get_min_vertical_scroll(): - # Make sure that the cursor line is not below the bottom. - # (Calculate how many lines can be shown between the cursor and the .) - used_height = 0 - prev_lineno = ui_content.cursor_position.y - - for lineno in range(ui_content.cursor_position.y, -1, -1): - used_height += ui_content.get_height_for_line(lineno, width) - - if used_height > height - scroll_offsets_bottom: - return prev_lineno - else: - prev_lineno = lineno - return 0 - - def get_max_vertical_scroll(): - # Make sure that the cursor line is not above the top. - prev_lineno = ui_content.cursor_position.y - used_height = 0 - - for lineno in range(ui_content.cursor_position.y - 1, -1, -1): - used_height += ui_content.get_height_for_line(lineno, width) - - if used_height > scroll_offsets_top: - return prev_lineno - else: - prev_lineno = lineno - return prev_lineno - - def get_topmost_visible(): - """ - Calculate the upper most line that can be visible, while the bottom - is still visible. We should not allow scroll more than this if - `allow_scroll_beyond_bottom` is false. - """ - prev_lineno = ui_content.line_count - 1 - used_height = 0 - for lineno in range(ui_content.line_count - 1, -1, -1): - used_height += ui_content.get_height_for_line(lineno, width) - if used_height > height: - return prev_lineno - else: - prev_lineno = lineno - return prev_lineno - - # Scroll vertically. (Make sure that the whole line which contains the - # cursor is visible. - topmost_visible = get_topmost_visible() - - # Note: the `min(topmost_visible, ...)` is to make sure that we - # don't require scrolling up because of the bottom scroll offset, - # when we are at the end of the document. - self.vertical_scroll = max(self.vertical_scroll, min(topmost_visible, get_min_vertical_scroll())) - self.vertical_scroll = min(self.vertical_scroll, get_max_vertical_scroll()) - - # Disallow scrolling beyond bottom? - if not self.allow_scroll_beyond_bottom(cli): - self.vertical_scroll = min(self.vertical_scroll, topmost_visible) - - def _scroll_without_linewrapping(self, ui_content, width, height, cli): - """ - Scroll to make sure the cursor position is visible and that we maintain - the requested scroll offset. - - Set `self.horizontal_scroll/vertical_scroll`. - """ - cursor_position = ui_content.cursor_position or Point(0, 0) - - # Without line wrapping, we will never have to scroll vertically inside - # a single line. - self.vertical_scroll_2 = 0 - - if ui_content.line_count == 0: - self.vertical_scroll = 0 - self.horizontal_scroll = 0 - return - else: - current_line_text = token_list_to_text(ui_content.get_line(cursor_position.y)) - - def do_scroll(current_scroll, scroll_offset_start, scroll_offset_end, - cursor_pos, window_size, content_size): - " Scrolling algorithm. Used for both horizontal and vertical scrolling. " - # Calculate the scroll offset to apply. - # This can obviously never be more than have the screen size. Also, when the - # cursor appears at the top or bottom, we don't apply the offset. - scroll_offset_start = int(min(scroll_offset_start, window_size / 2, cursor_pos)) - scroll_offset_end = int(min(scroll_offset_end, window_size / 2, - content_size - 1 - cursor_pos)) - - # Prevent negative scroll offsets. - if current_scroll < 0: - current_scroll = 0 - - # Scroll back if we scrolled to much and there's still space to show more of the document. - if (not self.allow_scroll_beyond_bottom(cli) and - current_scroll > content_size - window_size): - current_scroll = max(0, content_size - window_size) - - # Scroll up if cursor is before visible part. - if current_scroll > cursor_pos - scroll_offset_start: - current_scroll = max(0, cursor_pos - scroll_offset_start) - - # Scroll down if cursor is after visible part. - if current_scroll < (cursor_pos + 1) - window_size + scroll_offset_end: - current_scroll = (cursor_pos + 1) - window_size + scroll_offset_end - - return current_scroll - - # When a preferred scroll is given, take that first into account. - if self.get_vertical_scroll: - self.vertical_scroll = self.get_vertical_scroll(self) - assert isinstance(self.vertical_scroll, int) - if self.get_horizontal_scroll: - self.horizontal_scroll = self.get_horizontal_scroll(self) - assert isinstance(self.horizontal_scroll, int) - - # Update horizontal/vertical scroll to make sure that the cursor - # remains visible. - offsets = self.scroll_offsets - - self.vertical_scroll = do_scroll( - current_scroll=self.vertical_scroll, - scroll_offset_start=offsets.top, - scroll_offset_end=offsets.bottom, - cursor_pos=ui_content.cursor_position.y, - window_size=height, - content_size=ui_content.line_count) - - self.horizontal_scroll = do_scroll( - current_scroll=self.horizontal_scroll, - scroll_offset_start=offsets.left, - scroll_offset_end=offsets.right, - cursor_pos=get_cwidth(current_line_text[:ui_content.cursor_position.x]), - window_size=width, - # We can only analyse the current line. Calculating the width off - # all the lines is too expensive. - content_size=max(get_cwidth(current_line_text), self.horizontal_scroll + width)) - - def _mouse_handler(self, cli, mouse_event): - """ - Mouse handler. Called when the UI control doesn't handle this - particular event. - """ - if mouse_event.event_type == MouseEventType.SCROLL_DOWN: - self._scroll_down(cli) - elif mouse_event.event_type == MouseEventType.SCROLL_UP: - self._scroll_up(cli) - - def _scroll_down(self, cli): - " Scroll window down. " - info = self.render_info - - if self.vertical_scroll < info.content_height - info.window_height: - if info.cursor_position.y <= info.configured_scroll_offsets.top: - self.content.move_cursor_down(cli) - - self.vertical_scroll += 1 - - def _scroll_up(self, cli): - " Scroll window up. " - info = self.render_info - - if info.vertical_scroll > 0: - # TODO: not entirely correct yet in case of line wrapping and long lines. - if info.cursor_position.y >= info.window_height - 1 - info.configured_scroll_offsets.bottom: - self.content.move_cursor_up(cli) - - self.vertical_scroll -= 1 - - def walk(self, cli): - # Only yield self. A window doesn't have children. - yield self - - -class ConditionalContainer(Container): - """ - Wrapper around any other container that can change the visibility. The - received `filter` determines whether the given container should be - displayed or not. - - :param content: :class:`.Container` instance. - :param filter: :class:`~prompt_toolkit.filters.CLIFilter` instance. - """ - def __init__(self, content, filter): - assert isinstance(content, Container) - - self.content = content - self.filter = to_cli_filter(filter) - - def __repr__(self): - return 'ConditionalContainer(%r, filter=%r)' % (self.content, self.filter) - - def reset(self): - self.content.reset() - - def preferred_width(self, cli, max_available_width): - if self.filter(cli): - return self.content.preferred_width(cli, max_available_width) - else: - return LayoutDimension.exact(0) - - def preferred_height(self, cli, width, max_available_height): - if self.filter(cli): - return self.content.preferred_height(cli, width, max_available_height) - else: - return LayoutDimension.exact(0) - - def write_to_screen(self, cli, screen, mouse_handlers, write_position): - if self.filter(cli): - return self.content.write_to_screen(cli, screen, mouse_handlers, write_position) - - def walk(self, cli): - return self.content.walk(cli) - - -# Deprecated alias for 'Container'. -Layout = Container diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py deleted file mode 100644 index ca74931dbc..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py +++ /dev/null @@ -1,730 +0,0 @@ -""" -User interface Controls for the layout. -""" -from __future__ import unicode_literals - -from abc import ABCMeta, abstractmethod -from collections import namedtuple -from six import with_metaclass -from six.moves import range - -from prompt_toolkit.cache import SimpleCache -from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER -from prompt_toolkit.filters import to_cli_filter -from prompt_toolkit.mouse_events import MouseEventType -from prompt_toolkit.search_state import SearchState -from prompt_toolkit.selection import SelectionType -from prompt_toolkit.token import Token -from prompt_toolkit.utils import get_cwidth - -from .lexers import Lexer, SimpleLexer -from .processors import Processor -from .screen import Char, Point -from .utils import token_list_width, split_lines, token_list_to_text - -import six -import time - - -__all__ = ( - 'BufferControl', - 'FillControl', - 'TokenListControl', - 'UIControl', - 'UIContent', -) - - -class UIControl(with_metaclass(ABCMeta, object)): - """ - Base class for all user interface controls. - """ - def reset(self): - # Default reset. (Doesn't have to be implemented.) - pass - - def preferred_width(self, cli, max_available_width): - return None - - def preferred_height(self, cli, width, max_available_height, wrap_lines): - return None - - def has_focus(self, cli): - """ - Return ``True`` when this user control has the focus. - - If so, the cursor will be displayed according to the cursor position - reported by :meth:`.UIControl.create_content`. If the created content - has the property ``show_cursor=False``, the cursor will be hidden from - the output. - """ - return False - - @abstractmethod - def create_content(self, cli, width, height): - """ - Generate the content for this user control. - - Returns a :class:`.UIContent` instance. - """ - - def mouse_handler(self, cli, mouse_event): - """ - Handle mouse events. - - When `NotImplemented` is returned, it means that the given event is not - handled by the `UIControl` itself. The `Window` or key bindings can - decide to handle this event as scrolling or changing focus. - - :param cli: `CommandLineInterface` instance. - :param mouse_event: `MouseEvent` instance. - """ - return NotImplemented - - def move_cursor_down(self, cli): - """ - Request to move the cursor down. - This happens when scrolling down and the cursor is completely at the - top. - """ - - def move_cursor_up(self, cli): - """ - Request to move the cursor up. - """ - - -class UIContent(object): - """ - Content generated by a user control. This content consists of a list of - lines. - - :param get_line: Callable that returns the current line. This is a list of - (Token, text) tuples. - :param line_count: The number of lines. - :param cursor_position: a :class:`.Point` for the cursor position. - :param menu_position: a :class:`.Point` for the menu position. - :param show_cursor: Make the cursor visible. - :param default_char: The default :class:`.Char` for filling the background. - """ - def __init__(self, get_line=None, line_count=0, - cursor_position=None, menu_position=None, show_cursor=True, - default_char=None): - assert callable(get_line) - assert isinstance(line_count, six.integer_types) - assert cursor_position is None or isinstance(cursor_position, Point) - assert menu_position is None or isinstance(menu_position, Point) - assert default_char is None or isinstance(default_char, Char) - - self.get_line = get_line - self.line_count = line_count - self.cursor_position = cursor_position or Point(0, 0) - self.menu_position = menu_position - self.show_cursor = show_cursor - self.default_char = default_char - - # Cache for line heights. Maps (lineno, width) -> height. - self._line_heights = {} - - def __getitem__(self, lineno): - " Make it iterable (iterate line by line). " - if lineno < self.line_count: - return self.get_line(lineno) - else: - raise IndexError - - def get_height_for_line(self, lineno, width): - """ - Return the height that a given line would need if it is rendered in a - space with the given width. - """ - try: - return self._line_heights[lineno, width] - except KeyError: - text = token_list_to_text(self.get_line(lineno)) - result = self.get_height_for_text(text, width) - - # Cache and return - self._line_heights[lineno, width] = result - return result - - @staticmethod - def get_height_for_text(text, width): - # Get text width for this line. - line_width = get_cwidth(text) - - # Calculate height. - try: - quotient, remainder = divmod(line_width, width) - except ZeroDivisionError: - # Return something very big. - # (This can happen, when the Window gets very small.) - return 10 ** 10 - else: - if remainder: - quotient += 1 # Like math.ceil. - return max(1, quotient) - - -class TokenListControl(UIControl): - """ - Control that displays a list of (Token, text) tuples. - (It's mostly optimized for rather small widgets, like toolbars, menus, etc...) - - Mouse support: - - The list of tokens can also contain tuples of three items, looking like: - (Token, text, handler). When mouse support is enabled and the user - clicks on this token, then the given handler is called. That handler - should accept two inputs: (CommandLineInterface, MouseEvent) and it - should either handle the event or return `NotImplemented` in case we - want the containing Window to handle this event. - - :param get_tokens: Callable that takes a `CommandLineInterface` instance - and returns the list of (Token, text) tuples to be displayed right now. - :param default_char: default :class:`.Char` (character and Token) to use - for the background when there is more space available than `get_tokens` - returns. - :param get_default_char: Like `default_char`, but this is a callable that - takes a :class:`prompt_toolkit.interface.CommandLineInterface` and - returns a :class:`.Char` instance. - :param has_focus: `bool` or `CLIFilter`, when this evaluates to `True`, - this UI control will take the focus. The cursor will be shown in the - upper left corner of this control, unless `get_token` returns a - ``Token.SetCursorPosition`` token somewhere in the token list, then the - cursor will be shown there. - """ - def __init__(self, get_tokens, default_char=None, get_default_char=None, - align_right=False, align_center=False, has_focus=False): - assert callable(get_tokens) - assert default_char is None or isinstance(default_char, Char) - assert get_default_char is None or callable(get_default_char) - assert not (default_char and get_default_char) - - self.align_right = to_cli_filter(align_right) - self.align_center = to_cli_filter(align_center) - self._has_focus_filter = to_cli_filter(has_focus) - - self.get_tokens = get_tokens - - # Construct `get_default_char` callable. - if default_char: - get_default_char = lambda _: default_char - elif not get_default_char: - get_default_char = lambda _: Char(' ', Token.Transparent) - - self.get_default_char = get_default_char - - #: Cache for the content. - self._content_cache = SimpleCache(maxsize=18) - self._token_cache = SimpleCache(maxsize=1) - # Only cache one token list. We don't need the previous item. - - # Render info for the mouse support. - self._tokens = None - - def reset(self): - self._tokens = None - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.get_tokens) - - def _get_tokens_cached(self, cli): - """ - Get tokens, but only retrieve tokens once during one render run. - (This function is called several times during one rendering, because - we also need those for calculating the dimensions.) - """ - return self._token_cache.get( - cli.render_counter, lambda: self.get_tokens(cli)) - - def has_focus(self, cli): - return self._has_focus_filter(cli) - - def preferred_width(self, cli, max_available_width): - """ - Return the preferred width for this control. - That is the width of the longest line. - """ - text = token_list_to_text(self._get_tokens_cached(cli)) - line_lengths = [get_cwidth(l) for l in text.split('\n')] - return max(line_lengths) - - def preferred_height(self, cli, width, max_available_height, wrap_lines): - content = self.create_content(cli, width, None) - return content.line_count - - def create_content(self, cli, width, height): - # Get tokens - tokens_with_mouse_handlers = self._get_tokens_cached(cli) - - default_char = self.get_default_char(cli) - - # Wrap/align right/center parameters. - right = self.align_right(cli) - center = self.align_center(cli) - - def process_line(line): - " Center or right align a single line. " - used_width = token_list_width(line) - padding = width - used_width - if center: - padding = int(padding / 2) - return [(default_char.token, default_char.char * padding)] + line - - if right or center: - token_lines_with_mouse_handlers = [] - - for line in split_lines(tokens_with_mouse_handlers): - token_lines_with_mouse_handlers.append(process_line(line)) - else: - token_lines_with_mouse_handlers = list(split_lines(tokens_with_mouse_handlers)) - - # Strip mouse handlers from tokens. - token_lines = [ - [tuple(item[:2]) for item in line] - for line in token_lines_with_mouse_handlers - ] - - # Keep track of the tokens with mouse handler, for later use in - # `mouse_handler`. - self._tokens = tokens_with_mouse_handlers - - # If there is a `Token.SetCursorPosition` in the token list, set the - # cursor position here. - def get_cursor_position(): - SetCursorPosition = Token.SetCursorPosition - - for y, line in enumerate(token_lines): - x = 0 - for token, text in line: - if token == SetCursorPosition: - return Point(x=x, y=y) - x += len(text) - return None - - # Create content, or take it from the cache. - key = (default_char.char, default_char.token, - tuple(tokens_with_mouse_handlers), width, right, center) - - def get_content(): - return UIContent(get_line=lambda i: token_lines[i], - line_count=len(token_lines), - default_char=default_char, - cursor_position=get_cursor_position()) - - return self._content_cache.get(key, get_content) - - @classmethod - def static(cls, tokens): - def get_static_tokens(cli): - return tokens - return cls(get_static_tokens) - - def mouse_handler(self, cli, mouse_event): - """ - Handle mouse events. - - (When the token list contained mouse handlers and the user clicked on - on any of these, the matching handler is called. This handler can still - return `NotImplemented` in case we want the `Window` to handle this - particular event.) - """ - if self._tokens: - # Read the generator. - tokens_for_line = list(split_lines(self._tokens)) - - try: - tokens = tokens_for_line[mouse_event.position.y] - except IndexError: - return NotImplemented - else: - # Find position in the token list. - xpos = mouse_event.position.x - - # Find mouse handler for this character. - count = 0 - for item in tokens: - count += len(item[1]) - if count >= xpos: - if len(item) >= 3: - # Handler found. Call it. - # (Handler can return NotImplemented, so return - # that result.) - handler = item[2] - return handler(cli, mouse_event) - else: - break - - # Otherwise, don't handle here. - return NotImplemented - - -class FillControl(UIControl): - """ - Fill whole control with characters with this token. - (Also helpful for debugging.) - - :param char: :class:`.Char` instance to use for filling. - :param get_char: A callable that takes a CommandLineInterface and returns a - :class:`.Char` object. - """ - def __init__(self, character=None, token=Token, char=None, get_char=None): # 'character' and 'token' parameters are deprecated. - assert char is None or isinstance(char, Char) - assert get_char is None or callable(get_char) - assert not (char and get_char) - - self.char = char - - if character: - # Passing (character=' ', token=token) is deprecated. - self.character = character - self.token = token - - self.get_char = lambda cli: Char(character, token) - elif get_char: - # When 'get_char' is given. - self.get_char = get_char - else: - # When 'char' is given. - self.char = self.char or Char() - self.get_char = lambda cli: self.char - self.char = char - - def __repr__(self): - if self.char: - return '%s(char=%r)' % (self.__class__.__name__, self.char) - else: - return '%s(get_char=%r)' % (self.__class__.__name__, self.get_char) - - def reset(self): - pass - - def has_focus(self, cli): - return False - - def create_content(self, cli, width, height): - def get_line(i): - return [] - - return UIContent( - get_line=get_line, - line_count=100 ** 100, # Something very big. - default_char=self.get_char(cli)) - - -_ProcessedLine = namedtuple('_ProcessedLine', 'tokens source_to_display display_to_source') - - -class BufferControl(UIControl): - """ - Control for visualising the content of a `Buffer`. - - :param input_processors: list of :class:`~prompt_toolkit.layout.processors.Processor`. - :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` instance for syntax highlighting. - :param preview_search: `bool` or `CLIFilter`: Show search while typing. - :param get_search_state: Callable that takes a CommandLineInterface and - returns the SearchState to be used. (If not CommandLineInterface.search_state.) - :param buffer_name: String representing the name of the buffer to display. - :param default_char: :class:`.Char` instance to use to fill the background. This is - transparent by default. - :param focus_on_click: Focus this buffer when it's click, but not yet focussed. - """ - def __init__(self, - buffer_name=DEFAULT_BUFFER, - input_processors=None, - lexer=None, - preview_search=False, - search_buffer_name=SEARCH_BUFFER, - get_search_state=None, - menu_position=None, - default_char=None, - focus_on_click=False): - assert input_processors is None or all(isinstance(i, Processor) for i in input_processors) - assert menu_position is None or callable(menu_position) - assert lexer is None or isinstance(lexer, Lexer) - assert get_search_state is None or callable(get_search_state) - assert default_char is None or isinstance(default_char, Char) - - self.preview_search = to_cli_filter(preview_search) - self.get_search_state = get_search_state - self.focus_on_click = to_cli_filter(focus_on_click) - - self.input_processors = input_processors or [] - self.buffer_name = buffer_name - self.menu_position = menu_position - self.lexer = lexer or SimpleLexer() - self.default_char = default_char or Char(token=Token.Transparent) - self.search_buffer_name = search_buffer_name - - #: Cache for the lexer. - #: Often, due to cursor movement, undo/redo and window resizing - #: operations, it happens that a short time, the same document has to be - #: lexed. This is a faily easy way to cache such an expensive operation. - self._token_cache = SimpleCache(maxsize=8) - - self._xy_to_cursor_position = None - self._last_click_timestamp = None - self._last_get_processed_line = None - - def _buffer(self, cli): - """ - The buffer object that contains the 'main' content. - """ - return cli.buffers[self.buffer_name] - - def has_focus(self, cli): - # This control gets the focussed if the actual `Buffer` instance has the - # focus or when any of the `InputProcessor` classes tells us that it - # wants the focus. (E.g. in case of a reverse-search, where the actual - # search buffer may not be displayed, but the "reverse-i-search" text - # should get the focus.) - return cli.current_buffer_name == self.buffer_name or \ - any(i.has_focus(cli) for i in self.input_processors) - - def preferred_width(self, cli, max_available_width): - """ - This should return the preferred width. - - Note: We don't specify a preferred width according to the content, - because it would be too expensive. Calculating the preferred - width can be done by calculating the longest line, but this would - require applying all the processors to each line. This is - unfeasible for a larger document, and doing it for small - documents only would result in inconsistent behaviour. - """ - return None - - def preferred_height(self, cli, width, max_available_height, wrap_lines): - # Calculate the content height, if it was drawn on a screen with the - # given width. - height = 0 - content = self.create_content(cli, width, None) - - # When line wrapping is off, the height should be equal to the amount - # of lines. - if not wrap_lines: - return content.line_count - - # When the number of lines exceeds the max_available_height, just - # return max_available_height. No need to calculate anything. - if content.line_count >= max_available_height: - return max_available_height - - for i in range(content.line_count): - height += content.get_height_for_line(i, width) - - if height >= max_available_height: - return max_available_height - - return height - - def _get_tokens_for_line_func(self, cli, document): - """ - Create a function that returns the tokens for a given line. - """ - # Cache using `document.text`. - def get_tokens_for_line(): - return self.lexer.lex_document(cli, document) - - return self._token_cache.get(document.text, get_tokens_for_line) - - def _create_get_processed_line_func(self, cli, document): - """ - Create a function that takes a line number of the current document and - returns a _ProcessedLine(processed_tokens, source_to_display, display_to_source) - tuple. - """ - def transform(lineno, tokens): - " Transform the tokens for a given line number. " - source_to_display_functions = [] - display_to_source_functions = [] - - # Get cursor position at this line. - if document.cursor_position_row == lineno: - cursor_column = document.cursor_position_col - else: - cursor_column = None - - def source_to_display(i): - """ Translate x position from the buffer to the x position in the - processed token list. """ - for f in source_to_display_functions: - i = f(i) - return i - - # Apply each processor. - for p in self.input_processors: - transformation = p.apply_transformation( - cli, document, lineno, source_to_display, tokens) - tokens = transformation.tokens - - if cursor_column: - cursor_column = transformation.source_to_display(cursor_column) - - display_to_source_functions.append(transformation.display_to_source) - source_to_display_functions.append(transformation.source_to_display) - - def display_to_source(i): - for f in reversed(display_to_source_functions): - i = f(i) - return i - - return _ProcessedLine(tokens, source_to_display, display_to_source) - - def create_func(): - get_line = self._get_tokens_for_line_func(cli, document) - cache = {} - - def get_processed_line(i): - try: - return cache[i] - except KeyError: - processed_line = transform(i, get_line(i)) - cache[i] = processed_line - return processed_line - return get_processed_line - - return create_func() - - def create_content(self, cli, width, height): - """ - Create a UIContent. - """ - buffer = self._buffer(cli) - - # Get the document to be shown. If we are currently searching (the - # search buffer has focus, and the preview_search filter is enabled), - # then use the search document, which has possibly a different - # text/cursor position.) - def preview_now(): - """ True when we should preview a search. """ - return bool(self.preview_search(cli) and - cli.buffers[self.search_buffer_name].text) - - if preview_now(): - if self.get_search_state: - ss = self.get_search_state(cli) - else: - ss = cli.search_state - - document = buffer.document_for_search(SearchState( - text=cli.current_buffer.text, - direction=ss.direction, - ignore_case=ss.ignore_case)) - else: - document = buffer.document - - get_processed_line = self._create_get_processed_line_func(cli, document) - self._last_get_processed_line = get_processed_line - - def translate_rowcol(row, col): - " Return the content column for this coordinate. " - return Point(y=row, x=get_processed_line(row).source_to_display(col)) - - def get_line(i): - " Return the tokens for a given line number. " - tokens = get_processed_line(i).tokens - - # Add a space at the end, because that is a possible cursor - # position. (When inserting after the input.) We should do this on - # all the lines, not just the line containing the cursor. (Because - # otherwise, line wrapping/scrolling could change when moving the - # cursor around.) - tokens = tokens + [(self.default_char.token, ' ')] - return tokens - - content = UIContent( - get_line=get_line, - line_count=document.line_count, - cursor_position=translate_rowcol(document.cursor_position_row, - document.cursor_position_col), - default_char=self.default_char) - - # If there is an auto completion going on, use that start point for a - # pop-up menu position. (But only when this buffer has the focus -- - # there is only one place for a menu, determined by the focussed buffer.) - if cli.current_buffer_name == self.buffer_name: - menu_position = self.menu_position(cli) if self.menu_position else None - if menu_position is not None: - assert isinstance(menu_position, int) - menu_row, menu_col = buffer.document.translate_index_to_position(menu_position) - content.menu_position = translate_rowcol(menu_row, menu_col) - elif buffer.complete_state: - # Position for completion menu. - # Note: We use 'min', because the original cursor position could be - # behind the input string when the actual completion is for - # some reason shorter than the text we had before. (A completion - # can change and shorten the input.) - menu_row, menu_col = buffer.document.translate_index_to_position( - min(buffer.cursor_position, - buffer.complete_state.original_document.cursor_position)) - content.menu_position = translate_rowcol(menu_row, menu_col) - else: - content.menu_position = None - - return content - - def mouse_handler(self, cli, mouse_event): - """ - Mouse handler for this control. - """ - buffer = self._buffer(cli) - position = mouse_event.position - - # Focus buffer when clicked. - if self.has_focus(cli): - if self._last_get_processed_line: - processed_line = self._last_get_processed_line(position.y) - - # Translate coordinates back to the cursor position of the - # original input. - xpos = processed_line.display_to_source(position.x) - index = buffer.document.translate_row_col_to_index(position.y, xpos) - - # Set the cursor position. - if mouse_event.event_type == MouseEventType.MOUSE_DOWN: - buffer.exit_selection() - buffer.cursor_position = index - - elif mouse_event.event_type == MouseEventType.MOUSE_UP: - # When the cursor was moved to another place, select the text. - # (The >1 is actually a small but acceptable workaround for - # selecting text in Vi navigation mode. In navigation mode, - # the cursor can never be after the text, so the cursor - # will be repositioned automatically.) - if abs(buffer.cursor_position - index) > 1: - buffer.start_selection(selection_type=SelectionType.CHARACTERS) - buffer.cursor_position = index - - # Select word around cursor on double click. - # Two MOUSE_UP events in a short timespan are considered a double click. - double_click = self._last_click_timestamp and time.time() - self._last_click_timestamp < .3 - self._last_click_timestamp = time.time() - - if double_click: - start, end = buffer.document.find_boundaries_of_current_word() - buffer.cursor_position += start - buffer.start_selection(selection_type=SelectionType.CHARACTERS) - buffer.cursor_position += end - start - else: - # Don't handle scroll events here. - return NotImplemented - - # Not focussed, but focussing on click events. - else: - if self.focus_on_click(cli) and mouse_event.event_type == MouseEventType.MOUSE_UP: - # Focus happens on mouseup. (If we did this on mousedown, the - # up event will be received at the point where this widget is - # focussed and be handled anyway.) - cli.focus(self.buffer_name) - else: - return NotImplemented - - def move_cursor_down(self, cli): - b = self._buffer(cli) - b.cursor_position += b.document.get_cursor_down_position() - - def move_cursor_up(self, cli): - b = self._buffer(cli) - b.cursor_position += b.document.get_cursor_up_position() diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py deleted file mode 100644 index 717ad7a81f..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Layout dimensions are used to give the minimum, maximum and preferred -dimensions for containers and controls. -""" -from __future__ import unicode_literals - -__all__ = ( - 'LayoutDimension', - 'sum_layout_dimensions', - 'max_layout_dimensions', -) - - -class LayoutDimension(object): - """ - Specified dimension (width/height) of a user control or window. - - The layout engine tries to honor the preferred size. If that is not - possible, because the terminal is larger or smaller, it tries to keep in - between min and max. - - :param min: Minimum size. - :param max: Maximum size. - :param weight: For a VSplit/HSplit, the actual size will be determined - by taking the proportion of weights from all the children. - E.g. When there are two children, one width a weight of 1, - and the other with a weight of 2. The second will always be - twice as big as the first, if the min/max values allow it. - :param preferred: Preferred size. - """ - def __init__(self, min=None, max=None, weight=1, preferred=None): - assert isinstance(weight, int) and weight > 0 # Cannot be a float. - - self.min_specified = min is not None - self.max_specified = max is not None - self.preferred_specified = preferred is not None - - if min is None: - min = 0 # Smallest possible value. - if max is None: # 0-values are allowed, so use "is None" - max = 1000 ** 10 # Something huge. - if preferred is None: - preferred = min - - self.min = min - self.max = max - self.preferred = preferred - self.weight = weight - - # Make sure that the 'preferred' size is always in the min..max range. - if self.preferred < self.min: - self.preferred = self.min - - if self.preferred > self.max: - self.preferred = self.max - - @classmethod - def exact(cls, amount): - """ - Return a :class:`.LayoutDimension` with an exact size. (min, max and - preferred set to ``amount``). - """ - return cls(min=amount, max=amount, preferred=amount) - - def __repr__(self): - return 'LayoutDimension(min=%r, max=%r, preferred=%r, weight=%r)' % ( - self.min, self.max, self.preferred, self.weight) - - def __add__(self, other): - return sum_layout_dimensions([self, other]) - - -def sum_layout_dimensions(dimensions): - """ - Sum a list of :class:`.LayoutDimension` instances. - """ - min = sum([d.min for d in dimensions if d.min is not None]) - max = sum([d.max for d in dimensions if d.max is not None]) - preferred = sum([d.preferred for d in dimensions]) - - return LayoutDimension(min=min, max=max, preferred=preferred) - - -def max_layout_dimensions(dimensions): - """ - Take the maximum of a list of :class:`.LayoutDimension` instances. - """ - min_ = max([d.min for d in dimensions if d.min is not None]) - max_ = max([d.max for d in dimensions if d.max is not None]) - preferred = max([d.preferred for d in dimensions]) - - return LayoutDimension(min=min_, max=max_, preferred=preferred) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py deleted file mode 100644 index a928fd8226..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py +++ /dev/null @@ -1,320 +0,0 @@ -""" -Lexer interface and implementation. -Used for syntax highlighting. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass -from six.moves import range - -from prompt_toolkit.token import Token -from prompt_toolkit.filters import to_cli_filter -from .utils import split_lines - -import re -import six - -__all__ = ( - 'Lexer', - 'SimpleLexer', - 'PygmentsLexer', - 'SyntaxSync', - 'SyncFromStart', - 'RegexSync', -) - - -class Lexer(with_metaclass(ABCMeta, object)): - """ - Base class for all lexers. - """ - @abstractmethod - def lex_document(self, cli, document): - """ - Takes a :class:`~prompt_toolkit.document.Document` and returns a - callable that takes a line number and returns the tokens for that line. - """ - - -class SimpleLexer(Lexer): - """ - Lexer that doesn't do any tokenizing and returns the whole input as one token. - - :param token: The `Token` for this lexer. - """ - # `default_token` parameter is deprecated! - def __init__(self, token=Token, default_token=None): - self.token = token - - if default_token is not None: - self.token = default_token - - def lex_document(self, cli, document): - lines = document.lines - - def get_line(lineno): - " Return the tokens for the given line. " - try: - return [(self.token, lines[lineno])] - except IndexError: - return [] - return get_line - - -class SyntaxSync(with_metaclass(ABCMeta, object)): - """ - Syntax synchroniser. This is a tool that finds a start position for the - lexer. This is especially important when editing big documents; we don't - want to start the highlighting by running the lexer from the beginning of - the file. That is very slow when editing. - """ - @abstractmethod - def get_sync_start_position(self, document, lineno): - """ - Return the position from where we can start lexing as a (row, column) - tuple. - - :param document: `Document` instance that contains all the lines. - :param lineno: The line that we want to highlight. (We need to return - this line, or an earlier position.) - """ - -class SyncFromStart(SyntaxSync): - """ - Always start the syntax highlighting from the beginning. - """ - def get_sync_start_position(self, document, lineno): - return 0, 0 - - -class RegexSync(SyntaxSync): - """ - Synchronize by starting at a line that matches the given regex pattern. - """ - # Never go more than this amount of lines backwards for synchronisation. - # That would be too CPU intensive. - MAX_BACKWARDS = 500 - - # Start lexing at the start, if we are in the first 'n' lines and no - # synchronisation position was found. - FROM_START_IF_NO_SYNC_POS_FOUND = 100 - - def __init__(self, pattern): - assert isinstance(pattern, six.text_type) - self._compiled_pattern = re.compile(pattern) - - def get_sync_start_position(self, document, lineno): - " Scan backwards, and find a possible position to start. " - pattern = self._compiled_pattern - lines = document.lines - - # Scan upwards, until we find a point where we can start the syntax - # synchronisation. - for i in range(lineno, max(-1, lineno - self.MAX_BACKWARDS), -1): - match = pattern.match(lines[i]) - if match: - return i, match.start() - - # No synchronisation point found. If we aren't that far from the - # beginning, start at the very beginning, otherwise, just try to start - # at the current line. - if lineno < self.FROM_START_IF_NO_SYNC_POS_FOUND: - return 0, 0 - else: - return lineno, 0 - - @classmethod - def from_pygments_lexer_cls(cls, lexer_cls): - """ - Create a :class:`.RegexSync` instance for this Pygments lexer class. - """ - patterns = { - # For Python, start highlighting at any class/def block. - 'Python': r'^\s*(class|def)\s+', - 'Python 3': r'^\s*(class|def)\s+', - - # For HTML, start at any open/close tag definition. - 'HTML': r'<[/a-zA-Z]', - - # For javascript, start at a function. - 'JavaScript': r'\bfunction\b' - - # TODO: Add definitions for other languages. - # By default, we start at every possible line. - } - p = patterns.get(lexer_cls.name, '^') - return cls(p) - - -class PygmentsLexer(Lexer): - """ - Lexer that calls a pygments lexer. - - Example:: - - from pygments.lexers import HtmlLexer - lexer = PygmentsLexer(HtmlLexer) - - Note: Don't forget to also load a Pygments compatible style. E.g.:: - - from prompt_toolkit.styles.from_pygments import style_from_pygments - from pygments.styles import get_style_by_name - style = style_from_pygments(get_style_by_name('monokai')) - - :param pygments_lexer_cls: A `Lexer` from Pygments. - :param sync_from_start: Start lexing at the start of the document. This - will always give the best results, but it will be slow for bigger - documents. (When the last part of the document is display, then the - whole document will be lexed by Pygments on every key stroke.) It is - recommended to disable this for inputs that are expected to be more - than 1,000 lines. - :param syntax_sync: `SyntaxSync` object. - """ - # Minimum amount of lines to go backwards when starting the parser. - # This is important when the lines are retrieved in reverse order, or when - # scrolling upwards. (Due to the complexity of calculating the vertical - # scroll offset in the `Window` class, lines are not always retrieved in - # order.) - MIN_LINES_BACKWARDS = 50 - - # When a parser was started this amount of lines back, read the parser - # until we get the current line. Otherwise, start a new parser. - # (This should probably be bigger than MIN_LINES_BACKWARDS.) - REUSE_GENERATOR_MAX_DISTANCE = 100 - - def __init__(self, pygments_lexer_cls, sync_from_start=True, syntax_sync=None): - assert syntax_sync is None or isinstance(syntax_sync, SyntaxSync) - - self.pygments_lexer_cls = pygments_lexer_cls - self.sync_from_start = to_cli_filter(sync_from_start) - - # Instantiate the Pygments lexer. - self.pygments_lexer = pygments_lexer_cls( - stripnl=False, - stripall=False, - ensurenl=False) - - # Create syntax sync instance. - self.syntax_sync = syntax_sync or RegexSync.from_pygments_lexer_cls(pygments_lexer_cls) - - @classmethod - def from_filename(cls, filename, sync_from_start=True): - """ - Create a `Lexer` from a filename. - """ - # Inline imports: the Pygments dependency is optional! - from pygments.util import ClassNotFound - from pygments.lexers import get_lexer_for_filename - - try: - pygments_lexer = get_lexer_for_filename(filename) - except ClassNotFound: - return SimpleLexer() - else: - return cls(pygments_lexer.__class__, sync_from_start=sync_from_start) - - def lex_document(self, cli, document): - """ - Create a lexer function that takes a line number and returns the list - of (Token, text) tuples as the Pygments lexer returns for that line. - """ - # Cache of already lexed lines. - cache = {} - - # Pygments generators that are currently lexing. - line_generators = {} # Map lexer generator to the line number. - - def get_syntax_sync(): - " The Syntax synchronisation objcet that we currently use. " - if self.sync_from_start(cli): - return SyncFromStart() - else: - return self.syntax_sync - - def find_closest_generator(i): - " Return a generator close to line 'i', or None if none was fonud. " - for generator, lineno in line_generators.items(): - if lineno < i and i - lineno < self.REUSE_GENERATOR_MAX_DISTANCE: - return generator - - def create_line_generator(start_lineno, column=0): - """ - Create a generator that yields the lexed lines. - Each iteration it yields a (line_number, [(token, text), ...]) tuple. - """ - def get_tokens(): - text = '\n'.join(document.lines[start_lineno:])[column:] - - # We call `get_tokens_unprocessed`, because `get_tokens` will - # still replace \r\n and \r by \n. (We don't want that, - # Pygments should return exactly the same amount of text, as we - # have given as input.) - for _, t, v in self.pygments_lexer.get_tokens_unprocessed(text): - yield t, v - - return enumerate(split_lines(get_tokens()), start_lineno) - - def get_generator(i): - """ - Find an already started generator that is close, or create a new one. - """ - # Find closest line generator. - generator = find_closest_generator(i) - if generator: - return generator - - # No generator found. Determine starting point for the syntax - # synchronisation first. - - # Go at least x lines back. (Make scrolling upwards more - # efficient.) - i = max(0, i - self.MIN_LINES_BACKWARDS) - - if i == 0: - row = 0 - column = 0 - else: - row, column = get_syntax_sync().get_sync_start_position(document, i) - - # Find generator close to this point, or otherwise create a new one. - generator = find_closest_generator(i) - if generator: - return generator - else: - generator = create_line_generator(row, column) - - # If the column is not 0, ignore the first line. (Which is - # incomplete. This happens when the synchronisation algorithm tells - # us to start parsing in the middle of a line.) - if column: - next(generator) - row += 1 - - line_generators[generator] = row - return generator - - def get_line(i): - " Return the tokens for a given line number. " - try: - return cache[i] - except KeyError: - generator = get_generator(i) - - # Exhaust the generator, until we find the requested line. - for num, line in generator: - cache[num] = line - if num == i: - line_generators[generator] = i - - # Remove the next item from the cache. - # (It could happen that it's already there, because of - # another generator that started filling these lines, - # but we want to synchronise these lines with the - # current lexer's state.) - if num + 1 in cache: - del cache[num + 1] - - return cache[num] - return [] - - return get_line diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py deleted file mode 100644 index 2934dfc9a7..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py +++ /dev/null @@ -1,253 +0,0 @@ -""" -Margin implementations for a :class:`~prompt_toolkit.layout.containers.Window`. -""" -from __future__ import unicode_literals - -from abc import ABCMeta, abstractmethod -from six import with_metaclass -from six.moves import range - -from prompt_toolkit.filters import to_cli_filter -from prompt_toolkit.token import Token -from prompt_toolkit.utils import get_cwidth -from .utils import token_list_to_text - -__all__ = ( - 'Margin', - 'NumberredMargin', - 'ScrollbarMargin', - 'ConditionalMargin', - 'PromptMargin', -) - - -class Margin(with_metaclass(ABCMeta, object)): - """ - Base interface for a margin. - """ - @abstractmethod - def get_width(self, cli, get_ui_content): - """ - Return the width that this margin is going to consume. - - :param cli: :class:`.CommandLineInterface` instance. - :param get_ui_content: Callable that asks the user control to create - a :class:`.UIContent` instance. This can be used for instance to - obtain the number of lines. - """ - return 0 - - @abstractmethod - def create_margin(self, cli, window_render_info, width, height): - """ - Creates a margin. - This should return a list of (Token, text) tuples. - - :param cli: :class:`.CommandLineInterface` instance. - :param window_render_info: - :class:`~prompt_toolkit.layout.containers.WindowRenderInfo` - instance, generated after rendering and copying the visible part of - the :class:`~prompt_toolkit.layout.controls.UIControl` into the - :class:`~prompt_toolkit.layout.containers.Window`. - :param width: The width that's available for this margin. (As reported - by :meth:`.get_width`.) - :param height: The height that's available for this margin. (The height - of the :class:`~prompt_toolkit.layout.containers.Window`.) - """ - return [] - - -class NumberredMargin(Margin): - """ - Margin that displays the line numbers. - - :param relative: Number relative to the cursor position. Similar to the Vi - 'relativenumber' option. - :param display_tildes: Display tildes after the end of the document, just - like Vi does. - """ - def __init__(self, relative=False, display_tildes=False): - self.relative = to_cli_filter(relative) - self.display_tildes = to_cli_filter(display_tildes) - - def get_width(self, cli, get_ui_content): - line_count = get_ui_content().line_count - return max(3, len('%s' % line_count) + 1) - - def create_margin(self, cli, window_render_info, width, height): - relative = self.relative(cli) - - token = Token.LineNumber - token_current = Token.LineNumber.Current - - # Get current line number. - current_lineno = window_render_info.ui_content.cursor_position.y - - # Construct margin. - result = [] - last_lineno = None - - for y, lineno in enumerate(window_render_info.displayed_lines): - # Only display line number if this line is not a continuation of the previous line. - if lineno != last_lineno: - if lineno is None: - pass - elif lineno == current_lineno: - # Current line. - if relative: - # Left align current number in relative mode. - result.append((token_current, '%i' % (lineno + 1))) - else: - result.append((token_current, ('%i ' % (lineno + 1)).rjust(width))) - else: - # Other lines. - if relative: - lineno = abs(lineno - current_lineno) - 1 - - result.append((token, ('%i ' % (lineno + 1)).rjust(width))) - - last_lineno = lineno - result.append((Token, '\n')) - - # Fill with tildes. - if self.display_tildes(cli): - while y < window_render_info.window_height: - result.append((Token.Tilde, '~\n')) - y += 1 - - return result - - -class ConditionalMargin(Margin): - """ - Wrapper around other :class:`.Margin` classes to show/hide them. - """ - def __init__(self, margin, filter): - assert isinstance(margin, Margin) - - self.margin = margin - self.filter = to_cli_filter(filter) - - def get_width(self, cli, ui_content): - if self.filter(cli): - return self.margin.get_width(cli, ui_content) - else: - return 0 - - def create_margin(self, cli, window_render_info, width, height): - if width and self.filter(cli): - return self.margin.create_margin(cli, window_render_info, width, height) - else: - return [] - - -class ScrollbarMargin(Margin): - """ - Margin displaying a scrollbar. - - :param display_arrows: Display scroll up/down arrows. - """ - def __init__(self, display_arrows=False): - self.display_arrows = to_cli_filter(display_arrows) - - def get_width(self, cli, ui_content): - return 1 - - def create_margin(self, cli, window_render_info, width, height): - total_height = window_render_info.content_height - display_arrows = self.display_arrows(cli) - - window_height = window_render_info.window_height - if display_arrows: - window_height -= 2 - - try: - items_per_row = float(total_height) / min(total_height, window_height) - except ZeroDivisionError: - return [] - else: - def is_scroll_button(row): - " True if we should display a button on this row. " - current_row_middle = int((row + .5) * items_per_row) - return current_row_middle in window_render_info.displayed_lines - - # Up arrow. - result = [] - if display_arrows: - result.extend([ - (Token.Scrollbar.Arrow, '^'), - (Token.Scrollbar, '\n') - ]) - - # Scrollbar body. - for i in range(window_height): - if is_scroll_button(i): - result.append((Token.Scrollbar.Button, ' ')) - else: - result.append((Token.Scrollbar, ' ')) - result.append((Token, '\n')) - - # Down arrow - if display_arrows: - result.append((Token.Scrollbar.Arrow, 'v')) - - return result - - -class PromptMargin(Margin): - """ - Create margin that displays a prompt. - This can display one prompt at the first line, and a continuation prompt - (e.g, just dots) on all the following lines. - - :param get_prompt_tokens: Callable that takes a CommandLineInterface as - input and returns a list of (Token, type) tuples to be shown as the - prompt at the first line. - :param get_continuation_tokens: Callable that takes a CommandLineInterface - and a width as input and returns a list of (Token, type) tuples for the - next lines of the input. - :param show_numbers: (bool or :class:`~prompt_toolkit.filters.CLIFilter`) - Display line numbers instead of the continuation prompt. - """ - def __init__(self, get_prompt_tokens, get_continuation_tokens=None, - show_numbers=False): - assert callable(get_prompt_tokens) - assert get_continuation_tokens is None or callable(get_continuation_tokens) - show_numbers = to_cli_filter(show_numbers) - - self.get_prompt_tokens = get_prompt_tokens - self.get_continuation_tokens = get_continuation_tokens - self.show_numbers = show_numbers - - def get_width(self, cli, ui_content): - " Width to report to the `Window`. " - # Take the width from the first line. - text = token_list_to_text(self.get_prompt_tokens(cli)) - return get_cwidth(text) - - def create_margin(self, cli, window_render_info, width, height): - # First line. - tokens = self.get_prompt_tokens(cli)[:] - - # Next lines. (Show line numbering when numbering is enabled.) - if self.get_continuation_tokens: - # Note: we turn this into a list, to make sure that we fail early - # in case `get_continuation_tokens` returns something else, - # like `None`. - tokens2 = list(self.get_continuation_tokens(cli, width)) - else: - tokens2 = [] - - show_numbers = self.show_numbers(cli) - last_y = None - - for y in window_render_info.displayed_lines[1:]: - tokens.append((Token, '\n')) - if show_numbers: - if y != last_y: - tokens.append((Token.LineNumber, ('%i ' % (y + 1)).rjust(width))) - else: - tokens.extend(tokens2) - last_y = y - - return tokens diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py deleted file mode 100644 index a916846e45..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py +++ /dev/null @@ -1,496 +0,0 @@ -from __future__ import unicode_literals - -from six.moves import zip_longest, range -from prompt_toolkit.filters import HasCompletions, IsDone, Condition, to_cli_filter -from prompt_toolkit.mouse_events import MouseEventType -from prompt_toolkit.token import Token -from prompt_toolkit.utils import get_cwidth - -from .containers import Window, HSplit, ConditionalContainer, ScrollOffsets -from .controls import UIControl, UIContent -from .dimension import LayoutDimension -from .margins import ScrollbarMargin -from .screen import Point, Char - -import math - -__all__ = ( - 'CompletionsMenu', - 'MultiColumnCompletionsMenu', -) - - -class CompletionsMenuControl(UIControl): - """ - Helper for drawing the complete menu to the screen. - - :param scroll_offset: Number (integer) representing the preferred amount of - completions to be displayed before and after the current one. When this - is a very high number, the current completion will be shown in the - middle most of the time. - """ - # Preferred minimum size of the menu control. - # The CompletionsMenu class defines a width of 8, and there is a scrollbar - # of 1.) - MIN_WIDTH = 7 - - def __init__(self): - self.token = Token.Menu.Completions - - def has_focus(self, cli): - return False - - def preferred_width(self, cli, max_available_width): - complete_state = cli.current_buffer.complete_state - if complete_state: - menu_width = self._get_menu_width(500, complete_state) - menu_meta_width = self._get_menu_meta_width(500, complete_state) - - return menu_width + menu_meta_width - else: - return 0 - - def preferred_height(self, cli, width, max_available_height, wrap_lines): - complete_state = cli.current_buffer.complete_state - if complete_state: - return len(complete_state.current_completions) - else: - return 0 - - def create_content(self, cli, width, height): - """ - Create a UIContent object for this control. - """ - complete_state = cli.current_buffer.complete_state - if complete_state: - completions = complete_state.current_completions - index = complete_state.complete_index # Can be None! - - # Calculate width of completions menu. - menu_width = self._get_menu_width(width, complete_state) - menu_meta_width = self._get_menu_meta_width(width - menu_width, complete_state) - show_meta = self._show_meta(complete_state) - - def get_line(i): - c = completions[i] - is_current_completion = (i == index) - result = self._get_menu_item_tokens(c, is_current_completion, menu_width) - - if show_meta: - result += self._get_menu_item_meta_tokens(c, is_current_completion, menu_meta_width) - return result - - return UIContent(get_line=get_line, - cursor_position=Point(x=0, y=index or 0), - line_count=len(completions), - default_char=Char(' ', self.token)) - - return UIContent() - - def _show_meta(self, complete_state): - """ - Return ``True`` if we need to show a column with meta information. - """ - return any(c.display_meta for c in complete_state.current_completions) - - def _get_menu_width(self, max_width, complete_state): - """ - Return the width of the main column. - """ - return min(max_width, max(self.MIN_WIDTH, max(get_cwidth(c.display) - for c in complete_state.current_completions) + 2)) - - def _get_menu_meta_width(self, max_width, complete_state): - """ - Return the width of the meta column. - """ - if self._show_meta(complete_state): - return min(max_width, max(get_cwidth(c.display_meta) - for c in complete_state.current_completions) + 2) - else: - return 0 - - def _get_menu_item_tokens(self, completion, is_current_completion, width): - if is_current_completion: - token = self.token.Completion.Current - else: - token = self.token.Completion - - text, tw = _trim_text(completion.display, width - 2) - padding = ' ' * (width - 2 - tw) - return [(token, ' %s%s ' % (text, padding))] - - def _get_menu_item_meta_tokens(self, completion, is_current_completion, width): - if is_current_completion: - token = self.token.Meta.Current - else: - token = self.token.Meta - - text, tw = _trim_text(completion.display_meta, width - 2) - padding = ' ' * (width - 2 - tw) - return [(token, ' %s%s ' % (text, padding))] - - def mouse_handler(self, cli, mouse_event): - """ - Handle mouse events: clicking and scrolling. - """ - b = cli.current_buffer - - if mouse_event.event_type == MouseEventType.MOUSE_UP: - # Select completion. - b.go_to_completion(mouse_event.position.y) - b.complete_state = None - - elif mouse_event.event_type == MouseEventType.SCROLL_DOWN: - # Scroll up. - b.complete_next(count=3, disable_wrap_around=True) - - elif mouse_event.event_type == MouseEventType.SCROLL_UP: - # Scroll down. - b.complete_previous(count=3, disable_wrap_around=True) - - -def _trim_text(text, max_width): - """ - Trim the text to `max_width`, append dots when the text is too long. - Returns (text, width) tuple. - """ - width = get_cwidth(text) - - # When the text is too wide, trim it. - if width > max_width: - # When there are no double width characters, just use slice operation. - if len(text) == width: - trimmed_text = (text[:max(1, max_width-3)] + '...')[:max_width] - return trimmed_text, len(trimmed_text) - - # Otherwise, loop until we have the desired width. (Rather - # inefficient, but ok for now.) - else: - trimmed_text = '' - for c in text: - if get_cwidth(trimmed_text + c) <= max_width - 3: - trimmed_text += c - trimmed_text += '...' - - return (trimmed_text, get_cwidth(trimmed_text)) - else: - return text, width - - -class CompletionsMenu(ConditionalContainer): - def __init__(self, max_height=None, scroll_offset=0, extra_filter=True, display_arrows=False): - extra_filter = to_cli_filter(extra_filter) - display_arrows = to_cli_filter(display_arrows) - - super(CompletionsMenu, self).__init__( - content=Window( - content=CompletionsMenuControl(), - width=LayoutDimension(min=8), - height=LayoutDimension(min=1, max=max_height), - scroll_offsets=ScrollOffsets(top=scroll_offset, bottom=scroll_offset), - right_margins=[ScrollbarMargin(display_arrows=display_arrows)], - dont_extend_width=True, - ), - # Show when there are completions but not at the point we are - # returning the input. - filter=HasCompletions() & ~IsDone() & extra_filter) - - -class MultiColumnCompletionMenuControl(UIControl): - """ - Completion menu that displays all the completions in several columns. - When there are more completions than space for them to be displayed, an - arrow is shown on the left or right side. - - `min_rows` indicates how many rows will be available in any possible case. - When this is langer than one, in will try to use less columns and more - rows until this value is reached. - Be careful passing in a too big value, if less than the given amount of - rows are available, more columns would have been required, but - `preferred_width` doesn't know about that and reports a too small value. - This results in less completions displayed and additional scrolling. - (It's a limitation of how the layout engine currently works: first the - widths are calculated, then the heights.) - - :param suggested_max_column_width: The suggested max width of a column. - The column can still be bigger than this, but if there is place for two - columns of this width, we will display two columns. This to avoid that - if there is one very wide completion, that it doesn't significantly - reduce the amount of columns. - """ - _required_margin = 3 # One extra padding on the right + space for arrows. - - def __init__(self, min_rows=3, suggested_max_column_width=30): - assert isinstance(min_rows, int) and min_rows >= 1 - - self.min_rows = min_rows - self.suggested_max_column_width = suggested_max_column_width - self.token = Token.Menu.Completions - self.scroll = 0 - - # Info of last rendering. - self._rendered_rows = 0 - self._rendered_columns = 0 - self._total_columns = 0 - self._render_pos_to_completion = {} - self._render_left_arrow = False - self._render_right_arrow = False - self._render_width = 0 - - def reset(self): - self.scroll = 0 - - def has_focus(self, cli): - return False - - def preferred_width(self, cli, max_available_width): - """ - Preferred width: prefer to use at least min_rows, but otherwise as much - as possible horizontally. - """ - complete_state = cli.current_buffer.complete_state - column_width = self._get_column_width(complete_state) - result = int(column_width * math.ceil(len(complete_state.current_completions) / float(self.min_rows))) - - # When the desired width is still more than the maximum available, - # reduce by removing columns until we are less than the available - # width. - while result > column_width and result > max_available_width - self._required_margin: - result -= column_width - return result + self._required_margin - - def preferred_height(self, cli, width, max_available_height, wrap_lines): - """ - Preferred height: as much as needed in order to display all the completions. - """ - complete_state = cli.current_buffer.complete_state - column_width = self._get_column_width(complete_state) - column_count = max(1, (width - self._required_margin) // column_width) - - return int(math.ceil(len(complete_state.current_completions) / float(column_count))) - - def create_content(self, cli, width, height): - """ - Create a UIContent object for this menu. - """ - complete_state = cli.current_buffer.complete_state - column_width = self._get_column_width(complete_state) - self._render_pos_to_completion = {} - - def grouper(n, iterable, fillvalue=None): - " grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx " - args = [iter(iterable)] * n - return zip_longest(fillvalue=fillvalue, *args) - - def is_current_completion(completion): - " Returns True when this completion is the currently selected one. " - return complete_state.complete_index is not None and c == complete_state.current_completion - - # Space required outside of the regular columns, for displaying the - # left and right arrow. - HORIZONTAL_MARGIN_REQUIRED = 3 - - if complete_state: - # There should be at least one column, but it cannot be wider than - # the available width. - column_width = min(width - HORIZONTAL_MARGIN_REQUIRED, column_width) - - # However, when the columns tend to be very wide, because there are - # some very wide entries, shrink it anyway. - if column_width > self.suggested_max_column_width: - # `column_width` can still be bigger that `suggested_max_column_width`, - # but if there is place for two columns, we divide by two. - column_width //= (column_width // self.suggested_max_column_width) - - visible_columns = max(1, (width - self._required_margin) // column_width) - - columns_ = list(grouper(height, complete_state.current_completions)) - rows_ = list(zip(*columns_)) - - # Make sure the current completion is always visible: update scroll offset. - selected_column = (complete_state.complete_index or 0) // height - self.scroll = min(selected_column, max(self.scroll, selected_column - visible_columns + 1)) - - render_left_arrow = self.scroll > 0 - render_right_arrow = self.scroll < len(rows_[0]) - visible_columns - - # Write completions to screen. - tokens_for_line = [] - - for row_index, row in enumerate(rows_): - tokens = [] - middle_row = row_index == len(rows_) // 2 - - # Draw left arrow if we have hidden completions on the left. - if render_left_arrow: - tokens += [(Token.Scrollbar, '<' if middle_row else ' ')] - - # Draw row content. - for column_index, c in enumerate(row[self.scroll:][:visible_columns]): - if c is not None: - tokens += self._get_menu_item_tokens(c, is_current_completion(c), column_width) - - # Remember render position for mouse click handler. - for x in range(column_width): - self._render_pos_to_completion[(column_index * column_width + x, row_index)] = c - else: - tokens += [(self.token.Completion, ' ' * column_width)] - - # Draw trailing padding. (_get_menu_item_tokens only returns padding on the left.) - tokens += [(self.token.Completion, ' ')] - - # Draw right arrow if we have hidden completions on the right. - if render_right_arrow: - tokens += [(Token.Scrollbar, '>' if middle_row else ' ')] - - # Newline. - tokens_for_line.append(tokens) - - else: - tokens = [] - - self._rendered_rows = height - self._rendered_columns = visible_columns - self._total_columns = len(columns_) - self._render_left_arrow = render_left_arrow - self._render_right_arrow = render_right_arrow - self._render_width = column_width * visible_columns + render_left_arrow + render_right_arrow + 1 - - def get_line(i): - return tokens_for_line[i] - - return UIContent(get_line=get_line, line_count=len(rows_)) - - def _get_column_width(self, complete_state): - """ - Return the width of each column. - """ - return max(get_cwidth(c.display) for c in complete_state.current_completions) + 1 - - def _get_menu_item_tokens(self, completion, is_current_completion, width): - if is_current_completion: - token = self.token.Completion.Current - else: - token = self.token.Completion - - text, tw = _trim_text(completion.display, width) - padding = ' ' * (width - tw - 1) - - return [(token, ' %s%s' % (text, padding))] - - def mouse_handler(self, cli, mouse_event): - """ - Handle scoll and click events. - """ - b = cli.current_buffer - - def scroll_left(): - b.complete_previous(count=self._rendered_rows, disable_wrap_around=True) - self.scroll = max(0, self.scroll - 1) - - def scroll_right(): - b.complete_next(count=self._rendered_rows, disable_wrap_around=True) - self.scroll = min(self._total_columns - self._rendered_columns, self.scroll + 1) - - if mouse_event.event_type == MouseEventType.SCROLL_DOWN: - scroll_right() - - elif mouse_event.event_type == MouseEventType.SCROLL_UP: - scroll_left() - - elif mouse_event.event_type == MouseEventType.MOUSE_UP: - x = mouse_event.position.x - y = mouse_event.position.y - - # Mouse click on left arrow. - if x == 0: - if self._render_left_arrow: - scroll_left() - - # Mouse click on right arrow. - elif x == self._render_width - 1: - if self._render_right_arrow: - scroll_right() - - # Mouse click on completion. - else: - completion = self._render_pos_to_completion.get((x, y)) - if completion: - b.apply_completion(completion) - - -class MultiColumnCompletionsMenu(HSplit): - """ - Container that displays the completions in several columns. - When `show_meta` (a :class:`~prompt_toolkit.filters.CLIFilter`) evaluates - to True, it shows the meta information at the bottom. - """ - def __init__(self, min_rows=3, suggested_max_column_width=30, show_meta=True, extra_filter=True): - show_meta = to_cli_filter(show_meta) - extra_filter = to_cli_filter(extra_filter) - - # Display filter: show when there are completions but not at the point - # we are returning the input. - full_filter = HasCompletions() & ~IsDone() & extra_filter - - any_completion_has_meta = Condition(lambda cli: - any(c.display_meta for c in cli.current_buffer.complete_state.current_completions)) - - # Create child windows. - completions_window = ConditionalContainer( - content=Window( - content=MultiColumnCompletionMenuControl( - min_rows=min_rows, suggested_max_column_width=suggested_max_column_width), - width=LayoutDimension(min=8), - height=LayoutDimension(min=1)), - filter=full_filter) - - meta_window = ConditionalContainer( - content=Window(content=_SelectedCompletionMetaControl()), - filter=show_meta & full_filter & any_completion_has_meta) - - # Initialise split. - super(MultiColumnCompletionsMenu, self).__init__([ - completions_window, - meta_window - ]) - - -class _SelectedCompletionMetaControl(UIControl): - """ - Control that shows the meta information of the selected token. - """ - def preferred_width(self, cli, max_available_width): - """ - Report the width of the longest meta text as the preferred width of this control. - - It could be that we use less width, but this way, we're sure that the - layout doesn't change when we select another completion (E.g. that - completions are suddenly shown in more or fewer columns.) - """ - if cli.current_buffer.complete_state: - state = cli.current_buffer.complete_state - return 2 + max(get_cwidth(c.display_meta) for c in state.current_completions) - else: - return 0 - - def preferred_height(self, cli, width, max_available_height, wrap_lines): - return 1 - - def create_content(self, cli, width, height): - tokens = self._get_tokens(cli) - - def get_line(i): - return tokens - - return UIContent(get_line=get_line, line_count=1 if tokens else 0) - - def _get_tokens(self, cli): - token = Token.Menu.Completions.MultiColumnMeta - state = cli.current_buffer.complete_state - - if state and state.current_completion and state.current_completion.display_meta: - return [(token, ' %s ' % state.current_completion.display_meta)] - - return [] diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py deleted file mode 100644 index d443bf8315..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import unicode_literals - -from itertools import product -from collections import defaultdict - -__all__ = ( - 'MouseHandlers', -) - - -class MouseHandlers(object): - """ - Two dimentional raster of callbacks for mouse events. - """ - def __init__(self): - def dummy_callback(cli, mouse_event): - """ - :param mouse_event: `MouseEvent` instance. - """ - - # Map (x,y) tuples to handlers. - self.mouse_handlers = defaultdict(lambda: dummy_callback) - - def set_mouse_handler_for_range(self, x_min, x_max, y_min, y_max, handler=None): - """ - Set mouse handler for a region. - """ - for x, y in product(range(x_min, x_max), range(y_min, y_max)): - self.mouse_handlers[x,y] = handler diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py deleted file mode 100644 index 0b8bc9c223..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py +++ /dev/null @@ -1,605 +0,0 @@ -""" -Processors are little transformation blocks that transform the token list from -a buffer before the BufferControl will render it to the screen. - -They can insert tokens before or after, or highlight fragments by replacing the -token types. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass -from six.moves import range - -from prompt_toolkit.cache import SimpleCache -from prompt_toolkit.document import Document -from prompt_toolkit.enums import SEARCH_BUFFER -from prompt_toolkit.filters import to_cli_filter, ViInsertMultipleMode -from prompt_toolkit.layout.utils import token_list_to_text -from prompt_toolkit.reactive import Integer -from prompt_toolkit.token import Token - -from .utils import token_list_len, explode_tokens - -import re - -__all__ = ( - 'Processor', - 'Transformation', - - 'HighlightSearchProcessor', - 'HighlightSelectionProcessor', - 'PasswordProcessor', - 'HighlightMatchingBracketProcessor', - 'DisplayMultipleCursors', - 'BeforeInput', - 'AfterInput', - 'AppendAutoSuggestion', - 'ConditionalProcessor', - 'ShowLeadingWhiteSpaceProcessor', - 'ShowTrailingWhiteSpaceProcessor', - 'TabsProcessor', -) - - -class Processor(with_metaclass(ABCMeta, object)): - """ - Manipulate the tokens for a given line in a - :class:`~prompt_toolkit.layout.controls.BufferControl`. - """ - @abstractmethod - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - """ - Apply transformation. Returns a :class:`.Transformation` instance. - - :param cli: :class:`.CommandLineInterface` instance. - :param lineno: The number of the line to which we apply the processor. - :param source_to_display: A function that returns the position in the - `tokens` for any position in the source string. (This takes - previous processors into account.) - :param tokens: List of tokens that we can transform. (Received from the - previous processor.) - """ - return Transformation(tokens) - - def has_focus(self, cli): - """ - Processors can override the focus. - (Used for the reverse-i-search prefix in DefaultPrompt.) - """ - return False - - -class Transformation(object): - """ - Transformation result, as returned by :meth:`.Processor.apply_transformation`. - - Important: Always make sure that the length of `document.text` is equal to - the length of all the text in `tokens`! - - :param tokens: The transformed tokens. To be displayed, or to pass to the - next processor. - :param source_to_display: Cursor position transformation from original string to - transformed string. - :param display_to_source: Cursor position transformed from source string to - original string. - """ - def __init__(self, tokens, source_to_display=None, display_to_source=None): - self.tokens = tokens - self.source_to_display = source_to_display or (lambda i: i) - self.display_to_source = display_to_source or (lambda i: i) - - -class HighlightSearchProcessor(Processor): - """ - Processor that highlights search matches in the document. - Note that this doesn't support multiline search matches yet. - - :param preview_search: A Filter; when active it indicates that we take - the search text in real time while the user is typing, instead of the - last active search state. - """ - def __init__(self, preview_search=False, search_buffer_name=SEARCH_BUFFER, - get_search_state=None): - self.preview_search = to_cli_filter(preview_search) - self.search_buffer_name = search_buffer_name - self.get_search_state = get_search_state or (lambda cli: cli.search_state) - - def _get_search_text(self, cli): - """ - The text we are searching for. - """ - # When the search buffer has focus, take that text. - if self.preview_search(cli) and cli.buffers[self.search_buffer_name].text: - return cli.buffers[self.search_buffer_name].text - # Otherwise, take the text of the last active search. - else: - return self.get_search_state(cli).text - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - search_text = self._get_search_text(cli) - searchmatch_current_token = (':', ) + Token.SearchMatch.Current - searchmatch_token = (':', ) + Token.SearchMatch - - if search_text and not cli.is_returning: - # For each search match, replace the Token. - line_text = token_list_to_text(tokens) - tokens = explode_tokens(tokens) - - flags = re.IGNORECASE if cli.is_ignoring_case else 0 - - # Get cursor column. - if document.cursor_position_row == lineno: - cursor_column = source_to_display(document.cursor_position_col) - else: - cursor_column = None - - for match in re.finditer(re.escape(search_text), line_text, flags=flags): - if cursor_column is not None: - on_cursor = match.start() <= cursor_column < match.end() - else: - on_cursor = False - - for i in range(match.start(), match.end()): - old_token, text = tokens[i] - if on_cursor: - tokens[i] = (old_token + searchmatch_current_token, tokens[i][1]) - else: - tokens[i] = (old_token + searchmatch_token, tokens[i][1]) - - return Transformation(tokens) - - -class HighlightSelectionProcessor(Processor): - """ - Processor that highlights the selection in the document. - """ - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - selected_token = (':', ) + Token.SelectedText - - # In case of selection, highlight all matches. - selection_at_line = document.selection_range_at_line(lineno) - - if selection_at_line: - from_, to = selection_at_line - from_ = source_to_display(from_) - to = source_to_display(to) - - tokens = explode_tokens(tokens) - - if from_ == 0 and to == 0 and len(tokens) == 0: - # When this is an empty line, insert a space in order to - # visualiase the selection. - return Transformation([(Token.SelectedText, ' ')]) - else: - for i in range(from_, to + 1): - if i < len(tokens): - old_token, old_text = tokens[i] - tokens[i] = (old_token + selected_token, old_text) - - return Transformation(tokens) - - -class PasswordProcessor(Processor): - """ - Processor that turns masks the input. (For passwords.) - - :param char: (string) Character to be used. "*" by default. - """ - def __init__(self, char='*'): - self.char = char - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - tokens = [(token, self.char * len(text)) for token, text in tokens] - return Transformation(tokens) - - -class HighlightMatchingBracketProcessor(Processor): - """ - When the cursor is on or right after a bracket, it highlights the matching - bracket. - - :param max_cursor_distance: Only highlight matching brackets when the - cursor is within this distance. (From inside a `Processor`, we can't - know which lines will be visible on the screen. But we also don't want - to scan the whole document for matching brackets on each key press, so - we limit to this value.) - """ - _closing_braces = '])}>' - - def __init__(self, chars='[](){}<>', max_cursor_distance=1000): - self.chars = chars - self.max_cursor_distance = max_cursor_distance - - self._positions_cache = SimpleCache(maxsize=8) - - def _get_positions_to_highlight(self, document): - """ - Return a list of (row, col) tuples that need to be highlighted. - """ - # Try for the character under the cursor. - if document.current_char and document.current_char in self.chars: - pos = document.find_matching_bracket_position( - start_pos=document.cursor_position - self.max_cursor_distance, - end_pos=document.cursor_position + self.max_cursor_distance) - - # Try for the character before the cursor. - elif (document.char_before_cursor and document.char_before_cursor in - self._closing_braces and document.char_before_cursor in self.chars): - document = Document(document.text, document.cursor_position - 1) - - pos = document.find_matching_bracket_position( - start_pos=document.cursor_position - self.max_cursor_distance, - end_pos=document.cursor_position + self.max_cursor_distance) - else: - pos = None - - # Return a list of (row, col) tuples that need to be highlighted. - if pos: - pos += document.cursor_position # pos is relative. - row, col = document.translate_index_to_position(pos) - return [(row, col), (document.cursor_position_row, document.cursor_position_col)] - else: - return [] - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - # Get the highlight positions. - key = (cli.render_counter, document.text, document.cursor_position) - positions = self._positions_cache.get( - key, lambda: self._get_positions_to_highlight(document)) - - # Apply if positions were found at this line. - if positions: - for row, col in positions: - if row == lineno: - col = source_to_display(col) - tokens = explode_tokens(tokens) - token, text = tokens[col] - - if col == document.cursor_position_col: - token += (':', ) + Token.MatchingBracket.Cursor - else: - token += (':', ) + Token.MatchingBracket.Other - - tokens[col] = (token, text) - - return Transformation(tokens) - - -class DisplayMultipleCursors(Processor): - """ - When we're in Vi block insert mode, display all the cursors. - """ - _insert_multiple = ViInsertMultipleMode() - - def __init__(self, buffer_name): - self.buffer_name = buffer_name - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - buff = cli.buffers[self.buffer_name] - - if self._insert_multiple(cli): - positions = buff.multiple_cursor_positions - tokens = explode_tokens(tokens) - - # If any cursor appears on the current line, highlight that. - start_pos = document.translate_row_col_to_index(lineno, 0) - end_pos = start_pos + len(document.lines[lineno]) - - token_suffix = (':', ) + Token.MultipleCursors.Cursor - - for p in positions: - if start_pos <= p < end_pos: - column = source_to_display(p - start_pos) - - # Replace token. - token, text = tokens[column] - token += token_suffix - tokens[column] = (token, text) - elif p == end_pos: - tokens.append((token_suffix, ' ')) - - return Transformation(tokens) - else: - return Transformation(tokens) - - -class BeforeInput(Processor): - """ - Insert tokens before the input. - - :param get_tokens: Callable that takes a - :class:`~prompt_toolkit.interface.CommandLineInterface` and returns the - list of tokens to be inserted. - """ - def __init__(self, get_tokens): - assert callable(get_tokens) - self.get_tokens = get_tokens - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - if lineno == 0: - tokens_before = self.get_tokens(cli) - tokens = tokens_before + tokens - - shift_position = token_list_len(tokens_before) - source_to_display = lambda i: i + shift_position - display_to_source = lambda i: i - shift_position - else: - source_to_display = None - display_to_source = None - - return Transformation(tokens, source_to_display=source_to_display, - display_to_source=display_to_source) - - @classmethod - def static(cls, text, token=Token): - """ - Create a :class:`.BeforeInput` instance that always inserts the same - text. - """ - def get_static_tokens(cli): - return [(token, text)] - return cls(get_static_tokens) - - def __repr__(self): - return '%s(get_tokens=%r)' % ( - self.__class__.__name__, self.get_tokens) - - -class AfterInput(Processor): - """ - Insert tokens after the input. - - :param get_tokens: Callable that takes a - :class:`~prompt_toolkit.interface.CommandLineInterface` and returns the - list of tokens to be appended. - """ - def __init__(self, get_tokens): - assert callable(get_tokens) - self.get_tokens = get_tokens - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - # Insert tokens after the last line. - if lineno == document.line_count - 1: - return Transformation(tokens=tokens + self.get_tokens(cli)) - else: - return Transformation(tokens=tokens) - - @classmethod - def static(cls, text, token=Token): - """ - Create a :class:`.AfterInput` instance that always inserts the same - text. - """ - def get_static_tokens(cli): - return [(token, text)] - return cls(get_static_tokens) - - def __repr__(self): - return '%s(get_tokens=%r)' % ( - self.__class__.__name__, self.get_tokens) - - -class AppendAutoSuggestion(Processor): - """ - Append the auto suggestion to the input. - (The user can then press the right arrow the insert the suggestion.) - - :param buffer_name: The name of the buffer from where we should take the - auto suggestion. If not given, we take the current buffer. - """ - def __init__(self, buffer_name=None, token=Token.AutoSuggestion): - self.buffer_name = buffer_name - self.token = token - - def _get_buffer(self, cli): - if self.buffer_name: - return cli.buffers[self.buffer_name] - else: - return cli.current_buffer - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - # Insert tokens after the last line. - if lineno == document.line_count - 1: - buffer = self._get_buffer(cli) - - if buffer.suggestion and buffer.document.is_cursor_at_the_end: - suggestion = buffer.suggestion.text - else: - suggestion = '' - - return Transformation(tokens=tokens + [(self.token, suggestion)]) - else: - return Transformation(tokens=tokens) - - -class ShowLeadingWhiteSpaceProcessor(Processor): - """ - Make leading whitespace visible. - - :param get_char: Callable that takes a :class:`CommandLineInterface` - instance and returns one character. - :param token: Token to be used. - """ - def __init__(self, get_char=None, token=Token.LeadingWhiteSpace): - assert get_char is None or callable(get_char) - - if get_char is None: - def get_char(cli): - if '\xb7'.encode(cli.output.encoding(), 'replace') == b'?': - return '.' - else: - return '\xb7' - - self.token = token - self.get_char = get_char - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - # Walk through all te tokens. - if tokens and token_list_to_text(tokens).startswith(' '): - t = (self.token, self.get_char(cli)) - tokens = explode_tokens(tokens) - - for i in range(len(tokens)): - if tokens[i][1] == ' ': - tokens[i] = t - else: - break - - return Transformation(tokens) - - -class ShowTrailingWhiteSpaceProcessor(Processor): - """ - Make trailing whitespace visible. - - :param get_char: Callable that takes a :class:`CommandLineInterface` - instance and returns one character. - :param token: Token to be used. - """ - def __init__(self, get_char=None, token=Token.TrailingWhiteSpace): - assert get_char is None or callable(get_char) - - if get_char is None: - def get_char(cli): - if '\xb7'.encode(cli.output.encoding(), 'replace') == b'?': - return '.' - else: - return '\xb7' - - self.token = token - self.get_char = get_char - - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - if tokens and tokens[-1][1].endswith(' '): - t = (self.token, self.get_char(cli)) - tokens = explode_tokens(tokens) - - # Walk backwards through all te tokens and replace whitespace. - for i in range(len(tokens) - 1, -1, -1): - char = tokens[i][1] - if char == ' ': - tokens[i] = t - else: - break - - return Transformation(tokens) - - -class TabsProcessor(Processor): - """ - Render tabs as spaces (instead of ^I) or make them visible (for instance, - by replacing them with dots.) - - :param tabstop: (Integer) Horizontal space taken by a tab. - :param get_char1: Callable that takes a `CommandLineInterface` and return a - character (text of length one). This one is used for the first space - taken by the tab. - :param get_char2: Like `get_char1`, but for the rest of the space. - """ - def __init__(self, tabstop=4, get_char1=None, get_char2=None, token=Token.Tab): - assert isinstance(tabstop, Integer) - assert get_char1 is None or callable(get_char1) - assert get_char2 is None or callable(get_char2) - - self.get_char1 = get_char1 or get_char2 or (lambda cli: '|') - self.get_char2 = get_char2 or get_char1 or (lambda cli: '\u2508') - self.tabstop = tabstop - self.token = token - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - tabstop = int(self.tabstop) - token = self.token - - # Create separator for tabs. - separator1 = self.get_char1(cli) - separator2 = self.get_char2(cli) - - # Transform tokens. - tokens = explode_tokens(tokens) - - position_mappings = {} - result_tokens = [] - pos = 0 - - for i, token_and_text in enumerate(tokens): - position_mappings[i] = pos - - if token_and_text[1] == '\t': - # Calculate how many characters we have to insert. - count = tabstop - (pos % tabstop) - if count == 0: - count = tabstop - - # Insert tab. - result_tokens.append((token, separator1)) - result_tokens.append((token, separator2 * (count - 1))) - pos += count - else: - result_tokens.append(token_and_text) - pos += 1 - - position_mappings[len(tokens)] = pos - - def source_to_display(from_position): - " Maps original cursor position to the new one. " - return position_mappings[from_position] - - def display_to_source(display_pos): - " Maps display cursor position to the original one. " - position_mappings_reversed = dict((v, k) for k, v in position_mappings.items()) - - while display_pos >= 0: - try: - return position_mappings_reversed[display_pos] - except KeyError: - display_pos -= 1 - return 0 - - return Transformation( - result_tokens, - source_to_display=source_to_display, - display_to_source=display_to_source) - - -class ConditionalProcessor(Processor): - """ - Processor that applies another processor, according to a certain condition. - Example:: - - # Create a function that returns whether or not the processor should - # currently be applied. - def highlight_enabled(cli): - return true_or_false - - # Wrapt it in a `ConditionalProcessor` for usage in a `BufferControl`. - BufferControl(input_processors=[ - ConditionalProcessor(HighlightSearchProcessor(), - Condition(highlight_enabled))]) - - :param processor: :class:`.Processor` instance. - :param filter: :class:`~prompt_toolkit.filters.CLIFilter` instance. - """ - def __init__(self, processor, filter): - assert isinstance(processor, Processor) - - self.processor = processor - self.filter = to_cli_filter(filter) - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - # Run processor when enabled. - if self.filter(cli): - return self.processor.apply_transformation( - cli, document, lineno, source_to_display, tokens) - else: - return Transformation(tokens) - - def has_focus(self, cli): - if self.filter(cli): - return self.processor.has_focus(cli) - else: - return False - - def __repr__(self): - return '%s(processor=%r, filter=%r)' % ( - self.__class__.__name__, self.processor, self.filter) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py deleted file mode 100644 index 7d00ec513e..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import unicode_literals - -from six import text_type - -from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER -from prompt_toolkit.token import Token - -from .utils import token_list_len -from .processors import Processor, Transformation - -__all__ = ( - 'DefaultPrompt', -) - - -class DefaultPrompt(Processor): - """ - Default prompt. This one shows the 'arg' and reverse search like - Bash/readline normally do. - - There are two ways to instantiate a ``DefaultPrompt``. For a prompt - with a static message, do for instance:: - - prompt = DefaultPrompt.from_message('prompt> ') - - For a dynamic prompt, generated from a token list function:: - - def get_tokens(cli): - return [(Token.A, 'text'), (Token.B, 'text2')] - - prompt = DefaultPrompt(get_tokens) - """ - def __init__(self, get_tokens): - assert callable(get_tokens) - self.get_tokens = get_tokens - - @classmethod - def from_message(cls, message='> '): - """ - Create a default prompt with a static message text. - """ - assert isinstance(message, text_type) - - def get_message_tokens(cli): - return [(Token.Prompt, message)] - return cls(get_message_tokens) - - def apply_transformation(self, cli, document, lineno, source_to_display, tokens): - # Get text before cursor. - if cli.is_searching: - before = _get_isearch_tokens(cli) - - elif cli.input_processor.arg is not None: - before = _get_arg_tokens(cli) - - else: - before = self.get_tokens(cli) - - # Insert before buffer text. - shift_position = token_list_len(before) - - # Only show the prompt before the first line. For the following lines, - # only indent using spaces. - if lineno != 0: - before = [(Token.Prompt, ' ' * shift_position)] - - return Transformation( - tokens=before + tokens, - source_to_display=lambda i: i + shift_position, - display_to_source=lambda i: i - shift_position) - - def has_focus(self, cli): - # Obtain focus when the CLI is searching. - - # Usually, when using this `DefaultPrompt`, we don't have a - # `BufferControl` instance that displays the content of the search - # buffer. Instead the search text is displayed before the current text. - # So, we can still show the cursor here, while it's actually not this - # buffer that's focussed. - return cli.is_searching - - -def _get_isearch_tokens(cli): - def before(): - if cli.search_state.direction == IncrementalSearchDirection.BACKWARD: - text = 'reverse-i-search' - else: - text = 'i-search' - - return [(Token.Prompt.Search, '(%s)`' % text)] - - def text(): - return [(Token.Prompt.Search.Text, cli.buffers[SEARCH_BUFFER].text)] - - def after(): - return [(Token.Prompt.Search, '`: ')] - - return before() + text() + after() - - -def _get_arg_tokens(cli): - """ - Tokens for the arg-prompt. - """ - arg = cli.input_processor.arg - - return [ - (Token.Prompt.Arg, '(arg: '), - (Token.Prompt.Arg.Text, str(arg)), - (Token.Prompt.Arg, ') '), - ] diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py deleted file mode 100644 index 95561f5de7..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py +++ /dev/null @@ -1,151 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.cache import FastDictCache -from prompt_toolkit.token import Token -from prompt_toolkit.utils import get_cwidth - -from collections import defaultdict, namedtuple - -__all__ = ( - 'Point', - 'Size', - 'Screen', - 'Char', -) - - -Point = namedtuple('Point', 'y x') -Size = namedtuple('Size', 'rows columns') - - -class Char(object): - """ - Represent a single character in a :class:`.Screen`. - - This should be considered immutable. - """ - __slots__ = ('char', 'token', 'width') - - # If we end up having one of these special control sequences in the input string, - # we should display them as follows: - # Usually this happens after a "quoted insert". - display_mappings = { - '\x00': '^@', # Control space - '\x01': '^A', - '\x02': '^B', - '\x03': '^C', - '\x04': '^D', - '\x05': '^E', - '\x06': '^F', - '\x07': '^G', - '\x08': '^H', - '\x09': '^I', - '\x0a': '^J', - '\x0b': '^K', - '\x0c': '^L', - '\x0d': '^M', - '\x0e': '^N', - '\x0f': '^O', - '\x10': '^P', - '\x11': '^Q', - '\x12': '^R', - '\x13': '^S', - '\x14': '^T', - '\x15': '^U', - '\x16': '^V', - '\x17': '^W', - '\x18': '^X', - '\x19': '^Y', - '\x1a': '^Z', - '\x1b': '^[', # Escape - '\x1c': '^\\', - '\x1d': '^]', - '\x1f': '^_', - '\x7f': '^?', # Backspace - } - - def __init__(self, char=' ', token=Token): - # If this character has to be displayed otherwise, take that one. - char = self.display_mappings.get(char, char) - - self.char = char - self.token = token - - # Calculate width. (We always need this, so better to store it directly - # as a member for performance.) - self.width = get_cwidth(char) - - def __eq__(self, other): - return self.char == other.char and self.token == other.token - - def __ne__(self, other): - # Not equal: We don't do `not char.__eq__` here, because of the - # performance of calling yet another function. - return self.char != other.char or self.token != other.token - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self.char, self.token) - - -_CHAR_CACHE = FastDictCache(Char, size=1000 * 1000) -Transparent = Token.Transparent - - -class Screen(object): - """ - Two dimentional buffer of :class:`.Char` instances. - """ - def __init__(self, default_char=None, initial_width=0, initial_height=0): - if default_char is None: - default_char = _CHAR_CACHE[' ', Transparent] - - self.data_buffer = defaultdict(lambda: defaultdict(lambda: default_char)) - - #: Escape sequences to be injected. - self.zero_width_escapes = defaultdict(lambda: defaultdict(lambda: '')) - - #: Position of the cursor. - self.cursor_position = Point(y=0, x=0) - - #: Visibility of the cursor. - self.show_cursor = True - - #: (Optional) Where to position the menu. E.g. at the start of a completion. - #: (We can't use the cursor position, because we don't want the - #: completion menu to change its position when we browse through all the - #: completions.) - self.menu_position = None - - #: Currently used width/height of the screen. This will increase when - #: data is written to the screen. - self.width = initial_width or 0 - self.height = initial_height or 0 - - def replace_all_tokens(self, token): - """ - For all the characters in the screen. Set the token to the given `token`. - """ - b = self.data_buffer - - for y, row in b.items(): - for x, char in row.items(): - b[y][x] = _CHAR_CACHE[char.char, token] - - -class WritePosition(object): - def __init__(self, xpos, ypos, width, height, extended_height=None): - assert height >= 0 - assert extended_height is None or extended_height >= 0 - assert width >= 0 - # xpos and ypos can be negative. (A float can be partially visible.) - - self.xpos = xpos - self.ypos = ypos - self.width = width - self.height = height - self.extended_height = extended_height or height - - def __repr__(self): - return '%s(%r, %r, %r, %r, %r)' % ( - self.__class__.__name__, - self.xpos, self.ypos, self.width, self.height, self.extended_height) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py deleted file mode 100644 index 2e77c2fa16..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py +++ /dev/null @@ -1,209 +0,0 @@ -from __future__ import unicode_literals - -from ..enums import IncrementalSearchDirection - -from .processors import BeforeInput - -from .lexers import SimpleLexer -from .dimension import LayoutDimension -from .controls import BufferControl, TokenListControl, UIControl, UIContent -from .containers import Window, ConditionalContainer -from .screen import Char -from .utils import token_list_len -from prompt_toolkit.enums import SEARCH_BUFFER, SYSTEM_BUFFER -from prompt_toolkit.filters import HasFocus, HasArg, HasCompletions, HasValidationError, HasSearch, Always, IsDone -from prompt_toolkit.token import Token - -__all__ = ( - 'TokenListToolbar', - 'ArgToolbar', - 'CompletionsToolbar', - 'SearchToolbar', - 'SystemToolbar', - 'ValidationToolbar', -) - - -class TokenListToolbar(ConditionalContainer): - def __init__(self, get_tokens, filter=Always(), **kw): - super(TokenListToolbar, self).__init__( - content=Window( - TokenListControl(get_tokens, **kw), - height=LayoutDimension.exact(1)), - filter=filter) - - -class SystemToolbarControl(BufferControl): - def __init__(self): - token = Token.Toolbar.System - - super(SystemToolbarControl, self).__init__( - buffer_name=SYSTEM_BUFFER, - default_char=Char(token=token), - lexer=SimpleLexer(token=token.Text), - input_processors=[BeforeInput.static('Shell command: ', token)],) - - -class SystemToolbar(ConditionalContainer): - def __init__(self): - super(SystemToolbar, self).__init__( - content=Window( - SystemToolbarControl(), - height=LayoutDimension.exact(1)), - filter=HasFocus(SYSTEM_BUFFER) & ~IsDone()) - - -class ArgToolbarControl(TokenListControl): - def __init__(self): - def get_tokens(cli): - arg = cli.input_processor.arg - if arg == '-': - arg = '-1' - - return [ - (Token.Toolbar.Arg, 'Repeat: '), - (Token.Toolbar.Arg.Text, arg), - ] - - super(ArgToolbarControl, self).__init__(get_tokens) - - -class ArgToolbar(ConditionalContainer): - def __init__(self): - super(ArgToolbar, self).__init__( - content=Window( - ArgToolbarControl(), - height=LayoutDimension.exact(1)), - filter=HasArg()) - - -class SearchToolbarControl(BufferControl): - """ - :param vi_mode: Display '/' and '?' instead of I-search. - """ - def __init__(self, vi_mode=False): - token = Token.Toolbar.Search - - def get_before_input(cli): - if not cli.is_searching: - text = '' - elif cli.search_state.direction == IncrementalSearchDirection.BACKWARD: - text = ('?' if vi_mode else 'I-search backward: ') - else: - text = ('/' if vi_mode else 'I-search: ') - - return [(token, text)] - - super(SearchToolbarControl, self).__init__( - buffer_name=SEARCH_BUFFER, - input_processors=[BeforeInput(get_before_input)], - default_char=Char(token=token), - lexer=SimpleLexer(token=token.Text)) - - -class SearchToolbar(ConditionalContainer): - def __init__(self, vi_mode=False): - super(SearchToolbar, self).__init__( - content=Window( - SearchToolbarControl(vi_mode=vi_mode), - height=LayoutDimension.exact(1)), - filter=HasSearch() & ~IsDone()) - - -class CompletionsToolbarControl(UIControl): - token = Token.Toolbar.Completions - - def create_content(self, cli, width, height): - complete_state = cli.current_buffer.complete_state - if complete_state: - completions = complete_state.current_completions - index = complete_state.complete_index # Can be None! - - # Width of the completions without the left/right arrows in the margins. - content_width = width - 6 - - # Booleans indicating whether we stripped from the left/right - cut_left = False - cut_right = False - - # Create Menu content. - tokens = [] - - for i, c in enumerate(completions): - # When there is no more place for the next completion - if token_list_len(tokens) + len(c.display) >= content_width: - # If the current one was not yet displayed, page to the next sequence. - if i <= (index or 0): - tokens = [] - cut_left = True - # If the current one is visible, stop here. - else: - cut_right = True - break - - tokens.append((self.token.Completion.Current if i == index else self.token.Completion, c.display)) - tokens.append((self.token, ' ')) - - # Extend/strip until the content width. - tokens.append((self.token, ' ' * (content_width - token_list_len(tokens)))) - tokens = tokens[:content_width] - - # Return tokens - all_tokens = [ - (self.token, ' '), - (self.token.Arrow, '<' if cut_left else ' '), - (self.token, ' '), - ] + tokens + [ - (self.token, ' '), - (self.token.Arrow, '>' if cut_right else ' '), - (self.token, ' '), - ] - else: - all_tokens = [] - - def get_line(i): - return all_tokens - - return UIContent(get_line=get_line, line_count=1) - - -class CompletionsToolbar(ConditionalContainer): - def __init__(self, extra_filter=Always()): - super(CompletionsToolbar, self).__init__( - content=Window( - CompletionsToolbarControl(), - height=LayoutDimension.exact(1)), - filter=HasCompletions() & ~IsDone() & extra_filter) - - -class ValidationToolbarControl(TokenListControl): - def __init__(self, show_position=False): - token = Token.Toolbar.Validation - - def get_tokens(cli): - buffer = cli.current_buffer - - if buffer.validation_error: - row, column = buffer.document.translate_index_to_position( - buffer.validation_error.cursor_position) - - if show_position: - text = '%s (line=%s column=%s)' % ( - buffer.validation_error.message, row + 1, column + 1) - else: - text = buffer.validation_error.message - - return [(token, text)] - else: - return [] - - super(ValidationToolbarControl, self).__init__(get_tokens) - - -class ValidationToolbar(ConditionalContainer): - def __init__(self, show_position=False): - super(ValidationToolbar, self).__init__( - content=Window( - ValidationToolbarControl(show_position=show_position), - height=LayoutDimension.exact(1)), - filter=HasValidationError() & ~IsDone()) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py deleted file mode 100644 index a4fb7ed0f5..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py +++ /dev/null @@ -1,181 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.utils import get_cwidth -from prompt_toolkit.token import Token - -__all__ = ( - 'token_list_len', - 'token_list_width', - 'token_list_to_text', - 'explode_tokens', - 'split_lines', - 'find_window_for_buffer_name', -) - - -def token_list_len(tokenlist): - """ - Return the amount of characters in this token list. - - :param tokenlist: List of (token, text) or (token, text, mouse_handler) - tuples. - """ - ZeroWidthEscape = Token.ZeroWidthEscape - return sum(len(item[1]) for item in tokenlist if item[0] != ZeroWidthEscape) - - -def token_list_width(tokenlist): - """ - Return the character width of this token list. - (Take double width characters into account.) - - :param tokenlist: List of (token, text) or (token, text, mouse_handler) - tuples. - """ - ZeroWidthEscape = Token.ZeroWidthEscape - return sum(get_cwidth(c) for item in tokenlist for c in item[1] if item[0] != ZeroWidthEscape) - - -def token_list_to_text(tokenlist): - """ - Concatenate all the text parts again. - """ - ZeroWidthEscape = Token.ZeroWidthEscape - return ''.join(item[1] for item in tokenlist if item[0] != ZeroWidthEscape) - - -def iter_token_lines(tokenlist): - """ - Iterator that yields tokenlists for each line. - """ - line = [] - for token, c in explode_tokens(tokenlist): - line.append((token, c)) - - if c == '\n': - yield line - line = [] - - yield line - - -def split_lines(tokenlist): - """ - Take a single list of (Token, text) tuples and yield one such list for each - line. Just like str.split, this will yield at least one item. - - :param tokenlist: List of (token, text) or (token, text, mouse_handler) - tuples. - """ - line = [] - - for item in tokenlist: - # For (token, text) tuples. - if len(item) == 2: - token, string = item - parts = string.split('\n') - - for part in parts[:-1]: - if part: - line.append((token, part)) - yield line - line = [] - - line.append((token, parts[-1])) - # Note that parts[-1] can be empty, and that's fine. It happens - # in the case of [(Token.SetCursorPosition, '')]. - - # For (token, text, mouse_handler) tuples. - # I know, partly copy/paste, but understandable and more efficient - # than many tests. - else: - token, string, mouse_handler = item - parts = string.split('\n') - - for part in parts[:-1]: - if part: - line.append((token, part, mouse_handler)) - yield line - line = [] - - line.append((token, parts[-1], mouse_handler)) - - # Always yield the last line, even when this is an empty line. This ensures - # that when `tokenlist` ends with a newline character, an additional empty - # line is yielded. (Otherwise, there's no way to differentiate between the - # cases where `tokenlist` does and doesn't end with a newline.) - yield line - - -class _ExplodedList(list): - """ - Wrapper around a list, that marks it as 'exploded'. - - As soon as items are added or the list is extended, the new items are - automatically exploded as well. - """ - def __init__(self, *a, **kw): - super(_ExplodedList, self).__init__(*a, **kw) - self.exploded = True - - def append(self, item): - self.extend([item]) - - def extend(self, lst): - super(_ExplodedList, self).extend(explode_tokens(lst)) - - def insert(self, index, item): - raise NotImplementedError # TODO - - # TODO: When creating a copy() or [:], return also an _ExplodedList. - - def __setitem__(self, index, value): - """ - Ensure that when `(Token, 'long string')` is set, the string will be - exploded. - """ - if not isinstance(index, slice): - index = slice(index, index + 1) - value = explode_tokens([value]) - super(_ExplodedList, self).__setitem__(index, value) - - -def explode_tokens(tokenlist): - """ - Turn a list of (token, text) tuples into another list where each string is - exactly one character. - - It should be fine to call this function several times. Calling this on a - list that is already exploded, is a null operation. - - :param tokenlist: List of (token, text) tuples. - """ - # When the tokenlist is already exploded, don't explode again. - if getattr(tokenlist, 'exploded', False): - return tokenlist - - result = [] - - for token, string in tokenlist: - for c in string: - result.append((token, c)) - - return _ExplodedList(result) - - -def find_window_for_buffer_name(cli, buffer_name): - """ - Look for a :class:`~prompt_toolkit.layout.containers.Window` in the Layout - that contains the :class:`~prompt_toolkit.layout.controls.BufferControl` - for the given buffer and return it. If no such Window is found, return None. - """ - from prompt_toolkit.interface import CommandLineInterface - assert isinstance(cli, CommandLineInterface) - - from .containers import Window - from .controls import BufferControl - - for l in cli.layout.walk(cli): - if isinstance(l, Window) and isinstance(l.content, BufferControl): - if l.content.buffer_name == buffer_name: - return l diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py deleted file mode 100644 index f42276ce9f..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Mouse events. - - -How it works ------------- - -The renderer has a 2 dimensional grid of mouse event handlers. -(`prompt_toolkit.layout.MouseHandlers`.) When the layout is rendered, the -`Window` class will make sure that this grid will also be filled with -callbacks. For vt100 terminals, mouse events are received through stdin, just -like any other key press. There is a handler among the key bindings that -catches these events and forwards them to such a mouse event handler. It passes -through the `Window` class where the coordinates are translated from absolute -coordinates to coordinates relative to the user control, and there -`UIControl.mouse_handler` is called. -""" -from __future__ import unicode_literals - -__all__ = ( - 'MouseEventType', - 'MouseEvent' -) - - -class MouseEventType: - MOUSE_UP = 'MOUSE_UP' - MOUSE_DOWN = 'MOUSE_DOWN' - SCROLL_UP = 'SCROLL_UP' - SCROLL_DOWN = 'SCROLL_DOWN' - - -MouseEventTypes = MouseEventType # Deprecated: plural for backwards compatibility. - - -class MouseEvent(object): - """ - Mouse event, sent to `UIControl.mouse_handler`. - - :param position: `Point` instance. - :param event_type: `MouseEventType`. - """ - def __init__(self, position, event_type): - self.position = position - self.event_type = event_type - - def __repr__(self): - return 'MouseEvent(%r, %r)' % (self.position, self.event_type) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py deleted file mode 100644 index 072fb0677f..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Interface for an output. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass -from prompt_toolkit.layout.screen import Size - -__all__ = ( - 'Output', -) - - -class Output(with_metaclass(ABCMeta, object)): - """ - Base class defining the output interface for a - :class:`~prompt_toolkit.renderer.Renderer`. - - Actual implementations are - :class:`~prompt_toolkit.terminal.vt100_output.Vt100_Output` and - :class:`~prompt_toolkit.terminal.win32_output.Win32Output`. - """ - @abstractmethod - def fileno(self): - " Return the file descriptor to which we can write for the output. " - - @abstractmethod - def encoding(self): - """ - Return the encoding for this output, e.g. 'utf-8'. - (This is used mainly to know which characters are supported by the - output the data, so that the UI can provide alternatives, when - required.) - """ - - @abstractmethod - def write(self, data): - " Write text (Terminal escape sequences will be removed/escaped.) " - - @abstractmethod - def write_raw(self, data): - " Write text. " - - @abstractmethod - def set_title(self, title): - " Set terminal title. " - - @abstractmethod - def clear_title(self): - " Clear title again. (or restore previous title.) " - - @abstractmethod - def flush(self): - " Write to output stream and flush. " - - @abstractmethod - def erase_screen(self): - """ - Erases the screen with the background colour and moves the cursor to - home. - """ - - @abstractmethod - def enter_alternate_screen(self): - " Go to the alternate screen buffer. (For full screen applications). " - - @abstractmethod - def quit_alternate_screen(self): - " Leave the alternate screen buffer. " - - @abstractmethod - def enable_mouse_support(self): - " Enable mouse. " - - @abstractmethod - def disable_mouse_support(self): - " Disable mouse. " - - @abstractmethod - def erase_end_of_line(self): - """ - Erases from the current cursor position to the end of the current line. - """ - - @abstractmethod - def erase_down(self): - """ - Erases the screen from the current line down to the bottom of the - screen. - """ - - @abstractmethod - def reset_attributes(self): - " Reset color and styling attributes. " - - @abstractmethod - def set_attributes(self, attrs): - " Set new color and styling attributes. " - - @abstractmethod - def disable_autowrap(self): - " Disable auto line wrapping. " - - @abstractmethod - def enable_autowrap(self): - " Enable auto line wrapping. " - - @abstractmethod - def cursor_goto(self, row=0, column=0): - " Move cursor position. " - - @abstractmethod - def cursor_up(self, amount): - " Move cursor `amount` place up. " - - @abstractmethod - def cursor_down(self, amount): - " Move cursor `amount` place down. " - - @abstractmethod - def cursor_forward(self, amount): - " Move cursor `amount` place forward. " - - @abstractmethod - def cursor_backward(self, amount): - " Move cursor `amount` place backward. " - - @abstractmethod - def hide_cursor(self): - " Hide cursor. " - - @abstractmethod - def show_cursor(self): - " Show cursor. " - - def ask_for_cpr(self): - """ - Asks for a cursor position report (CPR). - (VT100 only.) - """ - - def bell(self): - " Sound bell. " - - def enable_bracketed_paste(self): - " For vt100 only. " - - def disable_bracketed_paste(self): - " For vt100 only. " - - -class DummyOutput(Output): - """ - For testing. An output class that doesn't render anything. - """ - def fileno(self): - " There is no sensible default for fileno(). " - raise NotImplementedError - - def encoding(self): - return 'utf-8' - - def write(self, data): pass - def write_raw(self, data): pass - def set_title(self, title): pass - def clear_title(self): pass - def flush(self): pass - def erase_screen(self): pass - def enter_alternate_screen(self): pass - def quit_alternate_screen(self): pass - def enable_mouse_support(self): pass - def disable_mouse_support(self): pass - def erase_end_of_line(self): pass - def erase_down(self): pass - def reset_attributes(self): pass - def set_attributes(self, attrs): pass - def disable_autowrap(self): pass - def enable_autowrap(self): pass - def cursor_goto(self, row=0, column=0): pass - def cursor_up(self, amount): pass - def cursor_down(self, amount): pass - def cursor_forward(self, amount): pass - def cursor_backward(self, amount): pass - def hide_cursor(self): pass - def show_cursor(self): pass - def ask_for_cpr(self): pass - def bell(self): pass - def enable_bracketed_paste(self): pass - def disable_bracketed_paste(self): pass - - def get_size(self): - return Size(rows=40, columns=80) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py deleted file mode 100644 index ec3aa06712..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Prompt_toolkit is designed a way that the amount of changing state is reduced -to a minimum. Where possible, code is written in a pure functional way. In -general, this results in code where the flow is very easy to follow: the value -of a variable can be deducted from its first assignment. - -However, often, practicality and performance beat purity and some classes still -have a changing state. In order to not having to care too much about -transferring states between several components we use some reactive -programming. Actually some kind of data binding. - -We introduce two types: - -- Filter: for binding a boolean state. They can be chained using & and | - operators. Have a look in the ``filters`` module. Resolving the actual value - of a filter happens by calling it. - -- Integer: for binding integer values. Reactive operations (like addition and - substraction) are not suppported. Resolving the actual value happens by - casting it to int, like ``int(integer)``. This way, it is possible to use - normal integers as well for static values. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from six import with_metaclass - - -class Integer(with_metaclass(ABCMeta, object)): - """ - Reactive integer -- anything that can be resolved to an ``int``. - """ - @abstractmethod - def __int__(self): - return 0 - - @classmethod - def from_callable(cls, func): - """ - Create an Integer-like object that calls the given function when it is - resolved to an int. - """ - return _IntegerFromCallable(func) - - -Integer.register(int) - - -class _IntegerFromCallable(Integer): - def __init__(self, func=0): - self.func = func - - def __repr__(self): - return 'Integer.from_callable(%r)' % self.func - - def __int__(self): - return int(self.func()) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py deleted file mode 100644 index 7a8fde55b3..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py +++ /dev/null @@ -1,535 +0,0 @@ -""" -Renders the command line on the console. -(Redraws parts of the input line that were changed.) -""" -from __future__ import unicode_literals - -from prompt_toolkit.filters import to_cli_filter -from prompt_toolkit.layout.mouse_handlers import MouseHandlers -from prompt_toolkit.layout.screen import Point, Screen, WritePosition -from prompt_toolkit.output import Output -from prompt_toolkit.styles import Style -from prompt_toolkit.token import Token -from prompt_toolkit.utils import is_windows - -from six.moves import range - -__all__ = ( - 'Renderer', - 'print_tokens', -) - - -def _output_screen_diff(output, screen, current_pos, previous_screen=None, last_token=None, - is_done=False, use_alternate_screen=False, attrs_for_token=None, size=None, - previous_width=0): # XXX: drop is_done - """ - Render the diff between this screen and the previous screen. - - This takes two `Screen` instances. The one that represents the output like - it was during the last rendering and one that represents the current - output raster. Looking at these two `Screen` instances, this function will - render the difference by calling the appropriate methods of the `Output` - object that only paint the changes to the terminal. - - This is some performance-critical code which is heavily optimized. - Don't change things without profiling first. - - :param current_pos: Current cursor position. - :param last_token: `Token` instance that represents the output attributes of - the last drawn character. (Color/attributes.) - :param attrs_for_token: :class:`._TokenToAttrsCache` instance. - :param width: The width of the terminal. - :param prevous_width: The width of the terminal during the last rendering. - """ - width, height = size.columns, size.rows - - #: Remember the last printed character. - last_token = [last_token] # nonlocal - - #: Variable for capturing the output. - write = output.write - write_raw = output.write_raw - - # Create locals for the most used output methods. - # (Save expensive attribute lookups.) - _output_set_attributes = output.set_attributes - _output_reset_attributes = output.reset_attributes - _output_cursor_forward = output.cursor_forward - _output_cursor_up = output.cursor_up - _output_cursor_backward = output.cursor_backward - - # Hide cursor before rendering. (Avoid flickering.) - output.hide_cursor() - - def reset_attributes(): - " Wrapper around Output.reset_attributes. " - _output_reset_attributes() - last_token[0] = None # Forget last char after resetting attributes. - - def move_cursor(new): - " Move cursor to this `new` point. Returns the given Point. " - current_x, current_y = current_pos.x, current_pos.y - - if new.y > current_y: - # Use newlines instead of CURSOR_DOWN, because this meight add new lines. - # CURSOR_DOWN will never create new lines at the bottom. - # Also reset attributes, otherwise the newline could draw a - # background color. - reset_attributes() - write('\r\n' * (new.y - current_y)) - current_x = 0 - _output_cursor_forward(new.x) - return new - elif new.y < current_y: - _output_cursor_up(current_y - new.y) - - if current_x >= width - 1: - write('\r') - _output_cursor_forward(new.x) - elif new.x < current_x or current_x >= width - 1: - _output_cursor_backward(current_x - new.x) - elif new.x > current_x: - _output_cursor_forward(new.x - current_x) - - return new - - def output_char(char): - """ - Write the output of this character. - """ - # If the last printed character has the same token, it also has the - # same style, so we don't output it. - the_last_token = last_token[0] - - if the_last_token and the_last_token == char.token: - write(char.char) - else: - _output_set_attributes(attrs_for_token[char.token]) - write(char.char) - last_token[0] = char.token - - # Render for the first time: reset styling. - if not previous_screen: - reset_attributes() - - # Disable autowrap. (When entering a the alternate screen, or anytime when - # we have a prompt. - In the case of a REPL, like IPython, people can have - # background threads, and it's hard for debugging if their output is not - # wrapped.) - if not previous_screen or not use_alternate_screen: - output.disable_autowrap() - - # When the previous screen has a different size, redraw everything anyway. - # Also when we are done. (We meight take up less rows, so clearing is important.) - if is_done or not previous_screen or previous_width != width: # XXX: also consider height?? - current_pos = move_cursor(Point(0, 0)) - reset_attributes() - output.erase_down() - - previous_screen = Screen() - - # Get height of the screen. - # (height changes as we loop over data_buffer, so remember the current value.) - # (Also make sure to clip the height to the size of the output.) - current_height = min(screen.height, height) - - # Loop over the rows. - row_count = min(max(screen.height, previous_screen.height), height) - c = 0 # Column counter. - - for y in range(row_count): - new_row = screen.data_buffer[y] - previous_row = previous_screen.data_buffer[y] - zero_width_escapes_row = screen.zero_width_escapes[y] - - new_max_line_len = min(width - 1, max(new_row.keys()) if new_row else 0) - previous_max_line_len = min(width - 1, max(previous_row.keys()) if previous_row else 0) - - # Loop over the columns. - c = 0 - while c < new_max_line_len + 1: - new_char = new_row[c] - old_char = previous_row[c] - char_width = (new_char.width or 1) - - # When the old and new character at this position are different, - # draw the output. (Because of the performance, we don't call - # `Char.__ne__`, but inline the same expression.) - if new_char.char != old_char.char or new_char.token != old_char.token: - current_pos = move_cursor(Point(y=y, x=c)) - - # Send injected escape sequences to output. - if c in zero_width_escapes_row: - write_raw(zero_width_escapes_row[c]) - - output_char(new_char) - current_pos = current_pos._replace(x=current_pos.x + char_width) - - c += char_width - - # If the new line is shorter, trim it. - if previous_screen and new_max_line_len < previous_max_line_len: - current_pos = move_cursor(Point(y=y, x=new_max_line_len+1)) - reset_attributes() - output.erase_end_of_line() - - # Correctly reserve vertical space as required by the layout. - # When this is a new screen (drawn for the first time), or for some reason - # higher than the previous one. Move the cursor once to the bottom of the - # output. That way, we're sure that the terminal scrolls up, even when the - # lower lines of the canvas just contain whitespace. - - # The most obvious reason that we actually want this behaviour is the avoid - # the artifact of the input scrolling when the completion menu is shown. - # (If the scrolling is actually wanted, the layout can still be build in a - # way to behave that way by setting a dynamic height.) - if current_height > previous_screen.height: - current_pos = move_cursor(Point(y=current_height - 1, x=0)) - - # Move cursor: - if is_done: - current_pos = move_cursor(Point(y=current_height, x=0)) - output.erase_down() - else: - current_pos = move_cursor(screen.cursor_position) - - if is_done or not use_alternate_screen: - output.enable_autowrap() - - # Always reset the color attributes. This is important because a background - # thread could print data to stdout and we want that to be displayed in the - # default colors. (Also, if a background color has been set, many terminals - # give weird artifacs on resize events.) - reset_attributes() - - if screen.show_cursor or is_done: - output.show_cursor() - - return current_pos, last_token[0] - - -class HeightIsUnknownError(Exception): - " Information unavailable. Did not yet receive the CPR response. " - - -class _TokenToAttrsCache(dict): - """ - A cache structure that maps Pygments Tokens to :class:`.Attr`. - (This is an important speed up.) - """ - def __init__(self, get_style_for_token): - self.get_style_for_token = get_style_for_token - - def __missing__(self, token): - try: - result = self.get_style_for_token(token) - except KeyError: - result = None - - self[token] = result - return result - - -class Renderer(object): - """ - Typical usage: - - :: - - output = Vt100_Output.from_pty(sys.stdout) - r = Renderer(style, output) - r.render(cli, layout=...) - """ - def __init__(self, style, output, use_alternate_screen=False, mouse_support=False): - assert isinstance(style, Style) - assert isinstance(output, Output) - - self.style = style - self.output = output - self.use_alternate_screen = use_alternate_screen - self.mouse_support = to_cli_filter(mouse_support) - - self._in_alternate_screen = False - self._mouse_support_enabled = False - self._bracketed_paste_enabled = False - - # Waiting for CPR flag. True when we send the request, but didn't got a - # response. - self.waiting_for_cpr = False - - self.reset(_scroll=True) - - def reset(self, _scroll=False, leave_alternate_screen=True): - # Reset position - self._cursor_pos = Point(x=0, y=0) - - # Remember the last screen instance between renderers. This way, - # we can create a `diff` between two screens and only output the - # difference. It's also to remember the last height. (To show for - # instance a toolbar at the bottom position.) - self._last_screen = None - self._last_size = None - self._last_token = None - - # When the style hash changes, we have to do a full redraw as well as - # clear the `_attrs_for_token` dictionary. - self._last_style_hash = None - self._attrs_for_token = None - - # Default MouseHandlers. (Just empty.) - self.mouse_handlers = MouseHandlers() - - # Remember the last title. Only set the title when it changes. - self._last_title = None - - #: Space from the top of the layout, until the bottom of the terminal. - #: We don't know this until a `report_absolute_cursor_row` call. - self._min_available_height = 0 - - # In case of Windown, also make sure to scroll to the current cursor - # position. (Only when rendering the first time.) - if is_windows() and _scroll: - self.output.scroll_buffer_to_prompt() - - # Quit alternate screen. - if self._in_alternate_screen and leave_alternate_screen: - self.output.quit_alternate_screen() - self._in_alternate_screen = False - - # Disable mouse support. - if self._mouse_support_enabled: - self.output.disable_mouse_support() - self._mouse_support_enabled = False - - # Disable bracketed paste. - if self._bracketed_paste_enabled: - self.output.disable_bracketed_paste() - self._bracketed_paste_enabled = False - - # Flush output. `disable_mouse_support` needs to write to stdout. - self.output.flush() - - @property - def height_is_known(self): - """ - True when the height from the cursor until the bottom of the terminal - is known. (It's often nicer to draw bottom toolbars only if the height - is known, in order to avoid flickering when the CPR response arrives.) - """ - return self.use_alternate_screen or self._min_available_height > 0 or \ - is_windows() # On Windows, we don't have to wait for a CPR. - - @property - def rows_above_layout(self): - """ - Return the number of rows visible in the terminal above the layout. - """ - if self._in_alternate_screen: - return 0 - elif self._min_available_height > 0: - total_rows = self.output.get_size().rows - last_screen_height = self._last_screen.height if self._last_screen else 0 - return total_rows - max(self._min_available_height, last_screen_height) - else: - raise HeightIsUnknownError('Rows above layout is unknown.') - - def request_absolute_cursor_position(self): - """ - Get current cursor position. - For vt100: Do CPR request. (answer will arrive later.) - For win32: Do API call. (Answer comes immediately.) - """ - # Only do this request when the cursor is at the top row. (after a - # clear or reset). We will rely on that in `report_absolute_cursor_row`. - assert self._cursor_pos.y == 0 - - # For Win32, we have an API call to get the number of rows below the - # cursor. - if is_windows(): - self._min_available_height = self.output.get_rows_below_cursor_position() - else: - if self.use_alternate_screen: - self._min_available_height = self.output.get_size().rows - else: - # Asks for a cursor position report (CPR). - self.waiting_for_cpr = True - self.output.ask_for_cpr() - - def report_absolute_cursor_row(self, row): - """ - To be called when we know the absolute cursor position. - (As an answer of a "Cursor Position Request" response.) - """ - # Calculate the amount of rows from the cursor position until the - # bottom of the terminal. - total_rows = self.output.get_size().rows - rows_below_cursor = total_rows - row + 1 - - # Set the - self._min_available_height = rows_below_cursor - - self.waiting_for_cpr = False - - def render(self, cli, layout, is_done=False): - """ - Render the current interface to the output. - - :param is_done: When True, put the cursor at the end of the interface. We - won't print any changes to this part. - """ - output = self.output - - # Enter alternate screen. - if self.use_alternate_screen and not self._in_alternate_screen: - self._in_alternate_screen = True - output.enter_alternate_screen() - - # Enable bracketed paste. - if not self._bracketed_paste_enabled: - self.output.enable_bracketed_paste() - self._bracketed_paste_enabled = True - - # Enable/disable mouse support. - needs_mouse_support = self.mouse_support(cli) - - if needs_mouse_support and not self._mouse_support_enabled: - output.enable_mouse_support() - self._mouse_support_enabled = True - - elif not needs_mouse_support and self._mouse_support_enabled: - output.disable_mouse_support() - self._mouse_support_enabled = False - - # Create screen and write layout to it. - size = output.get_size() - screen = Screen() - screen.show_cursor = False # Hide cursor by default, unless one of the - # containers decides to display it. - mouse_handlers = MouseHandlers() - - if is_done: - height = 0 # When we are done, we don't necessary want to fill up until the bottom. - else: - height = self._last_screen.height if self._last_screen else 0 - height = max(self._min_available_height, height) - - # When te size changes, don't consider the previous screen. - if self._last_size != size: - self._last_screen = None - - # When we render using another style, do a full repaint. (Forget about - # the previous rendered screen.) - # (But note that we still use _last_screen to calculate the height.) - if self.style.invalidation_hash() != self._last_style_hash: - self._last_screen = None - self._attrs_for_token = None - if self._attrs_for_token is None: - self._attrs_for_token = _TokenToAttrsCache(self.style.get_attrs_for_token) - self._last_style_hash = self.style.invalidation_hash() - - layout.write_to_screen(cli, screen, mouse_handlers, WritePosition( - xpos=0, - ypos=0, - width=size.columns, - height=(size.rows if self.use_alternate_screen else height), - extended_height=size.rows, - )) - - # When grayed. Replace all tokens in the new screen. - if cli.is_aborting or cli.is_exiting: - screen.replace_all_tokens(Token.Aborted) - - # Process diff and write to output. - self._cursor_pos, self._last_token = _output_screen_diff( - output, screen, self._cursor_pos, - self._last_screen, self._last_token, is_done, - use_alternate_screen=self.use_alternate_screen, - attrs_for_token=self._attrs_for_token, - size=size, - previous_width=(self._last_size.columns if self._last_size else 0)) - self._last_screen = screen - self._last_size = size - self.mouse_handlers = mouse_handlers - - # Write title if it changed. - new_title = cli.terminal_title - - if new_title != self._last_title: - if new_title is None: - self.output.clear_title() - else: - self.output.set_title(new_title) - self._last_title = new_title - - output.flush() - - def erase(self, leave_alternate_screen=True, erase_title=True): - """ - Hide all output and put the cursor back at the first line. This is for - instance used for running a system command (while hiding the CLI) and - later resuming the same CLI.) - - :param leave_alternate_screen: When True, and when inside an alternate - screen buffer, quit the alternate screen. - :param erase_title: When True, clear the title from the title bar. - """ - output = self.output - - output.cursor_backward(self._cursor_pos.x) - output.cursor_up(self._cursor_pos.y) - output.erase_down() - output.reset_attributes() - output.enable_autowrap() - output.flush() - - # Erase title. - if self._last_title and erase_title: - output.clear_title() - - self.reset(leave_alternate_screen=leave_alternate_screen) - - def clear(self): - """ - Clear screen and go to 0,0 - """ - # Erase current output first. - self.erase() - - # Send "Erase Screen" command and go to (0, 0). - output = self.output - - output.erase_screen() - output.cursor_goto(0, 0) - output.flush() - - self.request_absolute_cursor_position() - - -def print_tokens(output, tokens, style): - """ - Print a list of (Token, text) tuples in the given style to the output. - """ - assert isinstance(output, Output) - assert isinstance(style, Style) - - # Reset first. - output.reset_attributes() - output.enable_autowrap() - - # Print all (token, text) tuples. - attrs_for_token = _TokenToAttrsCache(style.get_attrs_for_token) - - for token, text in tokens: - attrs = attrs_for_token[token] - - if attrs: - output.set_attributes(attrs) - else: - output.reset_attributes() - - output.write(text) - - # Reset again. - output.reset_attributes() - output.flush() diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py deleted file mode 100644 index 3c494ea1a9..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py +++ /dev/null @@ -1,36 +0,0 @@ -from .enums import IncrementalSearchDirection -from .filters import to_simple_filter - -__all__ = ( - 'SearchState', -) - - -class SearchState(object): - """ - A search 'query'. - """ - __slots__ = ('text', 'direction', 'ignore_case') - - def __init__(self, text='', direction=IncrementalSearchDirection.FORWARD, ignore_case=False): - ignore_case = to_simple_filter(ignore_case) - - self.text = text - self.direction = direction - self.ignore_case = ignore_case - - def __repr__(self): - return '%s(%r, direction=%r, ignore_case=%r)' % ( - self.__class__.__name__, self.text, self.direction, self.ignore_case) - - def __invert__(self): - """ - Create a new SearchState where backwards becomes forwards and the other - way around. - """ - if self.direction == IncrementalSearchDirection.BACKWARD: - direction = IncrementalSearchDirection.FORWARD - else: - direction = IncrementalSearchDirection.BACKWARD - - return SearchState(text=self.text, direction=direction, ignore_case=self.ignore_case) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py deleted file mode 100644 index 6582921222..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Data structures for the selection. -""" -from __future__ import unicode_literals - -__all__ = ( - 'SelectionType', - 'PasteMode', - 'SelectionState', -) - - -class SelectionType(object): - """ - Type of selection. - """ - #: Characters. (Visual in Vi.) - CHARACTERS = 'CHARACTERS' - - #: Whole lines. (Visual-Line in Vi.) - LINES = 'LINES' - - #: A block selection. (Visual-Block in Vi.) - BLOCK = 'BLOCK' - - -class PasteMode(object): - EMACS = 'EMACS' # Yank like emacs. - VI_AFTER = 'VI_AFTER' # When pressing 'p' in Vi. - VI_BEFORE = 'VI_BEFORE' # When pressing 'P' in Vi. - - -class SelectionState(object): - """ - State of the current selection. - - :param original_cursor_position: int - :param type: :class:`~.SelectionType` - """ - def __init__(self, original_cursor_position=0, type=SelectionType.CHARACTERS): - self.original_cursor_position = original_cursor_position - self.type = type - - def __repr__(self): - return '%s(original_cursor_position=%r, type=%r)' % ( - self.__class__.__name__, - self.original_cursor_position, self.type) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py deleted file mode 100644 index 9893624c6e..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py +++ /dev/null @@ -1,717 +0,0 @@ -""" -Shortcuts for retrieving input from the user. - -If you are using this library for retrieving some input from the user (as a -pure Python replacement for GNU readline), probably for 90% of the use cases, -the :func:`.prompt` function is all you need. It's the easiest shortcut which -does a lot of the underlying work like creating a -:class:`~prompt_toolkit.interface.CommandLineInterface` instance for you. - -When is this not sufficient: - - When you want to have more complicated layouts (maybe with sidebars or - multiple toolbars. Or visibility of certain user interface controls - according to some conditions.) - - When you wish to have multiple input buffers. (If you would create an - editor like a Vi clone.) - - Something else that requires more customization than what is possible - with the parameters of `prompt`. - -In that case, study the code in this file and build your own -`CommandLineInterface` instance. It's not too complicated. -""" -from __future__ import unicode_literals - -from .buffer import Buffer, AcceptAction -from .document import Document -from .enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode -from .filters import IsDone, HasFocus, RendererHeightIsKnown, to_simple_filter, to_cli_filter, Condition -from .history import InMemoryHistory -from .interface import CommandLineInterface, Application, AbortAction -from .key_binding.defaults import load_key_bindings_for_prompt -from .key_binding.registry import Registry -from .keys import Keys -from .layout import Window, HSplit, FloatContainer, Float -from .layout.containers import ConditionalContainer -from .layout.controls import BufferControl, TokenListControl -from .layout.dimension import LayoutDimension -from .layout.lexers import PygmentsLexer -from .layout.margins import PromptMargin, ConditionalMargin -from .layout.menus import CompletionsMenu, MultiColumnCompletionsMenu -from .layout.processors import PasswordProcessor, ConditionalProcessor, AppendAutoSuggestion, HighlightSearchProcessor, HighlightSelectionProcessor, DisplayMultipleCursors -from .layout.prompt import DefaultPrompt -from .layout.screen import Char -from .layout.toolbars import ValidationToolbar, SystemToolbar, ArgToolbar, SearchToolbar -from .layout.utils import explode_tokens -from .renderer import print_tokens as renderer_print_tokens -from .styles import DEFAULT_STYLE, Style, style_from_dict -from .token import Token -from .utils import is_conemu_ansi, is_windows, DummyContext - -from six import text_type, exec_, PY2 - -import os -import sys -import textwrap -import threading -import time - -try: - from pygments.lexer import Lexer as pygments_Lexer - from pygments.style import Style as pygments_Style -except ImportError: - pygments_Lexer = None - pygments_Style = None - -if is_windows(): - from .terminal.win32_output import Win32Output - from .terminal.conemu_output import ConEmuOutput -else: - from .terminal.vt100_output import Vt100_Output - - -__all__ = ( - 'create_eventloop', - 'create_output', - 'create_prompt_layout', - 'create_prompt_application', - 'prompt', - 'prompt_async', - 'create_confirm_application', - 'run_application', - 'confirm', - 'print_tokens', - 'clear', -) - - -def create_eventloop(inputhook=None, recognize_win32_paste=True): - """ - Create and return an - :class:`~prompt_toolkit.eventloop.base.EventLoop` instance for a - :class:`~prompt_toolkit.interface.CommandLineInterface`. - """ - if is_windows(): - from prompt_toolkit.eventloop.win32 import Win32EventLoop as Loop - return Loop(inputhook=inputhook, recognize_paste=recognize_win32_paste) - else: - from prompt_toolkit.eventloop.posix import PosixEventLoop as Loop - return Loop(inputhook=inputhook) - - -def create_output(stdout=None, true_color=False, ansi_colors_only=None): - """ - Return an :class:`~prompt_toolkit.output.Output` instance for the command - line. - - :param true_color: When True, use 24bit colors instead of 256 colors. - (`bool` or :class:`~prompt_toolkit.filters.SimpleFilter`.) - :param ansi_colors_only: When True, restrict to 16 ANSI colors only. - (`bool` or :class:`~prompt_toolkit.filters.SimpleFilter`.) - """ - stdout = stdout or sys.__stdout__ - true_color = to_simple_filter(true_color) - - if is_windows(): - if is_conemu_ansi(): - return ConEmuOutput(stdout) - else: - return Win32Output(stdout) - else: - term = os.environ.get('TERM', '') - if PY2: - term = term.decode('utf-8') - - return Vt100_Output.from_pty( - stdout, true_color=true_color, - ansi_colors_only=ansi_colors_only, term=term) - - -def create_asyncio_eventloop(loop=None): - """ - Returns an asyncio :class:`~prompt_toolkit.eventloop.EventLoop` instance - for usage in a :class:`~prompt_toolkit.interface.CommandLineInterface`. It - is a wrapper around an asyncio loop. - - :param loop: The asyncio eventloop (or `None` if the default asyncioloop - should be used.) - """ - # Inline import, to make sure the rest doesn't break on Python 2. (Where - # asyncio is not available.) - if is_windows(): - from prompt_toolkit.eventloop.asyncio_win32 import Win32AsyncioEventLoop as AsyncioEventLoop - else: - from prompt_toolkit.eventloop.asyncio_posix import PosixAsyncioEventLoop as AsyncioEventLoop - - return AsyncioEventLoop(loop) - - -def _split_multiline_prompt(get_prompt_tokens): - """ - Take a `get_prompt_tokens` function and return three new functions instead. - One that tells whether this prompt consists of multiple lines; one that - returns the tokens to be shown on the lines above the input; and another - one with the tokens to be shown at the first line of the input. - """ - def has_before_tokens(cli): - for token, char in get_prompt_tokens(cli): - if '\n' in char: - return True - return False - - def before(cli): - result = [] - found_nl = False - for token, char in reversed(explode_tokens(get_prompt_tokens(cli))): - if found_nl: - result.insert(0, (token, char)) - elif char == '\n': - found_nl = True - return result - - def first_input_line(cli): - result = [] - for token, char in reversed(explode_tokens(get_prompt_tokens(cli))): - if char == '\n': - break - else: - result.insert(0, (token, char)) - return result - - return has_before_tokens, before, first_input_line - - -class _RPrompt(Window): - " The prompt that is displayed on the right side of the Window. " - def __init__(self, get_tokens=None): - get_tokens = get_tokens or (lambda cli: []) - - super(_RPrompt, self).__init__( - TokenListControl(get_tokens, align_right=True)) - - -def create_prompt_layout(message='', lexer=None, is_password=False, - reserve_space_for_menu=8, - get_prompt_tokens=None, get_continuation_tokens=None, - get_rprompt_tokens=None, - get_bottom_toolbar_tokens=None, - display_completions_in_columns=False, - extra_input_processors=None, multiline=False, - wrap_lines=True): - """ - Create a :class:`.Container` instance for a prompt. - - :param message: Text to be used as prompt. - :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for - the highlighting. - :param is_password: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. - When True, display input as '*'. - :param reserve_space_for_menu: Space to be reserved for the menu. When >0, - make sure that a minimal height is allocated in the terminal, in order - to display the completion menu. - :param get_prompt_tokens: An optional callable that returns the tokens to be - shown in the menu. (To be used instead of a `message`.) - :param get_continuation_tokens: An optional callable that takes a - CommandLineInterface and width as input and returns a list of (Token, - text) tuples to be used for the continuation. - :param get_bottom_toolbar_tokens: An optional callable that returns the - tokens for a toolbar at the bottom. - :param display_completions_in_columns: `bool` or - :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in - multiple columns. - :param multiline: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. - When True, prefer a layout that is more adapted for multiline input. - Text after newlines is automatically indented, and search/arg input is - shown below the input, instead of replacing the prompt. - :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. - When True (the default), automatically wrap long lines instead of - scrolling horizontally. - """ - assert isinstance(message, text_type), 'Please provide a unicode string.' - assert get_bottom_toolbar_tokens is None or callable(get_bottom_toolbar_tokens) - assert get_prompt_tokens is None or callable(get_prompt_tokens) - assert get_rprompt_tokens is None or callable(get_rprompt_tokens) - assert not (message and get_prompt_tokens) - - display_completions_in_columns = to_cli_filter(display_completions_in_columns) - multiline = to_cli_filter(multiline) - - if get_prompt_tokens is None: - get_prompt_tokens = lambda _: [(Token.Prompt, message)] - - has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = \ - _split_multiline_prompt(get_prompt_tokens) - - # `lexer` is supposed to be a `Lexer` instance. But if a Pygments lexer - # class is given, turn it into a PygmentsLexer. (Important for - # backwards-compatibility.) - try: - if pygments_Lexer and issubclass(lexer, pygments_Lexer): - lexer = PygmentsLexer(lexer, sync_from_start=True) - except TypeError: # Happens when lexer is `None` or an instance of something else. - pass - - # Create processors list. - input_processors = [ - ConditionalProcessor( - # By default, only highlight search when the search - # input has the focus. (Note that this doesn't mean - # there is no search: the Vi 'n' binding for instance - # still allows to jump to the next match in - # navigation mode.) - HighlightSearchProcessor(preview_search=True), - HasFocus(SEARCH_BUFFER)), - HighlightSelectionProcessor(), - ConditionalProcessor(AppendAutoSuggestion(), HasFocus(DEFAULT_BUFFER) & ~IsDone()), - ConditionalProcessor(PasswordProcessor(), is_password), - DisplayMultipleCursors(DEFAULT_BUFFER), - ] - - if extra_input_processors: - input_processors.extend(extra_input_processors) - - # Show the prompt before the input (using the DefaultPrompt processor. - # This also replaces it with reverse-i-search and 'arg' when required. - # (Only for single line mode.) - # (DefaultPrompt should always be at the end of the processors.) - input_processors.append(ConditionalProcessor( - DefaultPrompt(get_prompt_tokens_2), ~multiline)) - - # Create bottom toolbar. - if get_bottom_toolbar_tokens: - toolbars = [ConditionalContainer( - Window(TokenListControl(get_bottom_toolbar_tokens, - default_char=Char(' ', Token.Toolbar)), - height=LayoutDimension.exact(1)), - filter=~IsDone() & RendererHeightIsKnown())] - else: - toolbars = [] - - def get_height(cli): - # If there is an autocompletion menu to be shown, make sure that our - # layout has at least a minimal height in order to display it. - if reserve_space_for_menu and not cli.is_done: - buff = cli.current_buffer - - # Reserve the space, either when there are completions, or when - # `complete_while_typing` is true and we expect completions very - # soon. - if buff.complete_while_typing() or buff.complete_state is not None: - return LayoutDimension(min=reserve_space_for_menu) - - return LayoutDimension() - - # Create and return Container instance. - return HSplit([ - # The main input, with completion menus floating on top of it. - FloatContainer( - HSplit([ - ConditionalContainer( - Window( - TokenListControl(get_prompt_tokens_1), - dont_extend_height=True), - Condition(has_before_tokens) - ), - Window( - BufferControl( - input_processors=input_processors, - lexer=lexer, - # Enable preview_search, we want to have immediate feedback - # in reverse-i-search mode. - preview_search=True), - get_height=get_height, - left_margins=[ - # In multiline mode, use the window margin to display - # the prompt and continuation tokens. - ConditionalMargin( - PromptMargin(get_prompt_tokens_2, get_continuation_tokens), - filter=multiline - ) - ], - wrap_lines=wrap_lines, - ), - ]), - [ - # Completion menus. - Float(xcursor=True, - ycursor=True, - content=CompletionsMenu( - max_height=16, - scroll_offset=1, - extra_filter=HasFocus(DEFAULT_BUFFER) & - ~display_completions_in_columns)), - Float(xcursor=True, - ycursor=True, - content=MultiColumnCompletionsMenu( - extra_filter=HasFocus(DEFAULT_BUFFER) & - display_completions_in_columns, - show_meta=True)), - - # The right prompt. - Float(right=0, top=0, hide_when_covering_content=True, - content=_RPrompt(get_rprompt_tokens)), - ] - ), - ValidationToolbar(), - SystemToolbar(), - - # In multiline mode, we use two toolbars for 'arg' and 'search'. - ConditionalContainer(ArgToolbar(), multiline), - ConditionalContainer(SearchToolbar(), multiline), - ] + toolbars) - - -def create_prompt_application( - message='', - multiline=False, - wrap_lines=True, - is_password=False, - vi_mode=False, - editing_mode=EditingMode.EMACS, - complete_while_typing=True, - enable_history_search=False, - lexer=None, - enable_system_bindings=False, - enable_open_in_editor=False, - validator=None, - completer=None, - reserve_space_for_menu=8, - auto_suggest=None, - style=None, - history=None, - clipboard=None, - get_prompt_tokens=None, - get_continuation_tokens=None, - get_rprompt_tokens=None, - get_bottom_toolbar_tokens=None, - display_completions_in_columns=False, - get_title=None, - mouse_support=False, - extra_input_processors=None, - key_bindings_registry=None, - on_abort=AbortAction.RAISE_EXCEPTION, - on_exit=AbortAction.RAISE_EXCEPTION, - accept_action=AcceptAction.RETURN_DOCUMENT, - erase_when_done=False, - default=''): - """ - Create an :class:`~Application` instance for a prompt. - - (It is meant to cover 90% of the prompt use cases, where no extreme - customization is required. For more complex input, it is required to create - a custom :class:`~Application` instance.) - - :param message: Text to be shown before the prompt. - :param mulitiline: Allow multiline input. Pressing enter will insert a - newline. (This requires Meta+Enter to accept the input.) - :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. - When True (the default), automatically wrap long lines instead of - scrolling horizontally. - :param is_password: Show asterisks instead of the actual typed characters. - :param editing_mode: ``EditingMode.VI`` or ``EditingMode.EMACS``. - :param vi_mode: `bool`, if True, Identical to ``editing_mode=EditingMode.VI``. - :param complete_while_typing: `bool` or - :class:`~prompt_toolkit.filters.SimpleFilter`. Enable autocompletion - while typing. - :param enable_history_search: `bool` or - :class:`~prompt_toolkit.filters.SimpleFilter`. Enable up-arrow parting - string matching. - :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for - the syntax highlighting. - :param validator: :class:`~prompt_toolkit.validation.Validator` instance - for input validation. - :param completer: :class:`~prompt_toolkit.completion.Completer` instance - for input completion. - :param reserve_space_for_menu: Space to be reserved for displaying the menu. - (0 means that no space needs to be reserved.) - :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest` - instance for input suggestions. - :param style: :class:`.Style` instance for the color scheme. - :param enable_system_bindings: `bool` or - :class:`~prompt_toolkit.filters.CLIFilter`. Pressing Meta+'!' will show - a system prompt. - :param enable_open_in_editor: `bool` or - :class:`~prompt_toolkit.filters.CLIFilter`. Pressing 'v' in Vi mode or - C-X C-E in emacs mode will open an external editor. - :param history: :class:`~prompt_toolkit.history.History` instance. - :param clipboard: :class:`~prompt_toolkit.clipboard.base.Clipboard` instance. - (e.g. :class:`~prompt_toolkit.clipboard.in_memory.InMemoryClipboard`) - :param get_bottom_toolbar_tokens: Optional callable which takes a - :class:`~prompt_toolkit.interface.CommandLineInterface` and returns a - list of tokens for the bottom toolbar. - :param display_completions_in_columns: `bool` or - :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in - multiple columns. - :param get_title: Callable that returns the title to be displayed in the - terminal. - :param mouse_support: `bool` or :class:`~prompt_toolkit.filters.CLIFilter` - to enable mouse support. - :param default: The default text to be shown in the input buffer. (This can - be edited by the user.) - """ - if key_bindings_registry is None: - key_bindings_registry = load_key_bindings_for_prompt( - enable_system_bindings=enable_system_bindings, - enable_open_in_editor=enable_open_in_editor) - - # Ensure backwards-compatibility, when `vi_mode` is passed. - if vi_mode: - editing_mode = EditingMode.VI - - # Make sure that complete_while_typing is disabled when enable_history_search - # is enabled. (First convert to SimpleFilter, to avoid doing bitwise operations - # on bool objects.) - complete_while_typing = to_simple_filter(complete_while_typing) - enable_history_search = to_simple_filter(enable_history_search) - multiline = to_simple_filter(multiline) - - complete_while_typing = complete_while_typing & ~enable_history_search - - # Accept Pygments styles as well for backwards compatibility. - try: - if pygments_Style and issubclass(style, pygments_Style): - style = style_from_dict(style.styles) - except TypeError: # Happens when style is `None` or an instance of something else. - pass - - # Create application - return Application( - layout=create_prompt_layout( - message=message, - lexer=lexer, - is_password=is_password, - reserve_space_for_menu=(reserve_space_for_menu if completer is not None else 0), - multiline=Condition(lambda cli: multiline()), - get_prompt_tokens=get_prompt_tokens, - get_continuation_tokens=get_continuation_tokens, - get_rprompt_tokens=get_rprompt_tokens, - get_bottom_toolbar_tokens=get_bottom_toolbar_tokens, - display_completions_in_columns=display_completions_in_columns, - extra_input_processors=extra_input_processors, - wrap_lines=wrap_lines), - buffer=Buffer( - enable_history_search=enable_history_search, - complete_while_typing=complete_while_typing, - is_multiline=multiline, - history=(history or InMemoryHistory()), - validator=validator, - completer=completer, - auto_suggest=auto_suggest, - accept_action=accept_action, - initial_document=Document(default), - ), - style=style or DEFAULT_STYLE, - clipboard=clipboard, - key_bindings_registry=key_bindings_registry, - get_title=get_title, - mouse_support=mouse_support, - editing_mode=editing_mode, - erase_when_done=erase_when_done, - reverse_vi_search_direction=True, - on_abort=on_abort, - on_exit=on_exit) - - -def prompt(message='', **kwargs): - """ - Get input from the user and return it. - - This is a wrapper around a lot of ``prompt_toolkit`` functionality and can - be a replacement for `raw_input`. (or GNU readline.) - - If you want to keep your history across several calls, create one - :class:`~prompt_toolkit.history.History` instance and pass it every time. - - This function accepts many keyword arguments. Except for the following, - they are a proxy to the arguments of :func:`.create_prompt_application`. - - :param patch_stdout: Replace ``sys.stdout`` by a proxy that ensures that - print statements from other threads won't destroy the prompt. (They - will be printed above the prompt instead.) - :param return_asyncio_coroutine: When True, return a asyncio coroutine. (Python >3.3) - :param true_color: When True, use 24bit colors instead of 256 colors. - :param refresh_interval: (number; in seconds) When given, refresh the UI - every so many seconds. - """ - patch_stdout = kwargs.pop('patch_stdout', False) - return_asyncio_coroutine = kwargs.pop('return_asyncio_coroutine', False) - true_color = kwargs.pop('true_color', False) - refresh_interval = kwargs.pop('refresh_interval', 0) - eventloop = kwargs.pop('eventloop', None) - - application = create_prompt_application(message, **kwargs) - - return run_application(application, - patch_stdout=patch_stdout, - return_asyncio_coroutine=return_asyncio_coroutine, - true_color=true_color, - refresh_interval=refresh_interval, - eventloop=eventloop) - - -def run_application( - application, patch_stdout=False, return_asyncio_coroutine=False, - true_color=False, refresh_interval=0, eventloop=None): - """ - Run a prompt toolkit application. - - :param patch_stdout: Replace ``sys.stdout`` by a proxy that ensures that - print statements from other threads won't destroy the prompt. (They - will be printed above the prompt instead.) - :param return_asyncio_coroutine: When True, return a asyncio coroutine. (Python >3.3) - :param true_color: When True, use 24bit colors instead of 256 colors. - :param refresh_interval: (number; in seconds) When given, refresh the UI - every so many seconds. - """ - assert isinstance(application, Application) - - if return_asyncio_coroutine: - eventloop = create_asyncio_eventloop() - else: - eventloop = eventloop or create_eventloop() - - # Create CommandLineInterface. - cli = CommandLineInterface( - application=application, - eventloop=eventloop, - output=create_output(true_color=true_color)) - - # Set up refresh interval. - if refresh_interval: - done = [False] - def start_refresh_loop(cli): - def run(): - while not done[0]: - time.sleep(refresh_interval) - cli.request_redraw() - t = threading.Thread(target=run) - t.daemon = True - t.start() - - def stop_refresh_loop(cli): - done[0] = True - - cli.on_start += start_refresh_loop - cli.on_stop += stop_refresh_loop - - # Replace stdout. - patch_context = cli.patch_stdout_context(raw=True) if patch_stdout else DummyContext() - - # Read input and return it. - if return_asyncio_coroutine: - # Create an asyncio coroutine and call it. - exec_context = {'patch_context': patch_context, 'cli': cli, - 'Document': Document} - exec_(textwrap.dedent(''' - def prompt_coro(): - # Inline import, because it slows down startup when asyncio is not - # needed. - import asyncio - - @asyncio.coroutine - def run(): - with patch_context: - result = yield from cli.run_async() - - if isinstance(result, Document): # Backwards-compatibility. - return result.text - return result - return run() - '''), exec_context) - - return exec_context['prompt_coro']() - else: - try: - with patch_context: - result = cli.run() - - if isinstance(result, Document): # Backwards-compatibility. - return result.text - return result - finally: - eventloop.close() - - -def prompt_async(message='', **kwargs): - """ - Similar to :func:`.prompt`, but return an asyncio coroutine instead. - """ - kwargs['return_asyncio_coroutine'] = True - return prompt(message, **kwargs) - - -def create_confirm_application(message): - """ - Create a confirmation `Application` that returns True/False. - """ - registry = Registry() - - @registry.add_binding('y') - @registry.add_binding('Y') - def _(event): - event.cli.buffers[DEFAULT_BUFFER].text = 'y' - event.cli.set_return_value(True) - - @registry.add_binding('n') - @registry.add_binding('N') - @registry.add_binding(Keys.ControlC) - def _(event): - event.cli.buffers[DEFAULT_BUFFER].text = 'n' - event.cli.set_return_value(False) - - return create_prompt_application(message, key_bindings_registry=registry) - - -def confirm(message='Confirm (y or n) '): - """ - Display a confirmation prompt. - """ - assert isinstance(message, text_type) - - app = create_confirm_application(message) - return run_application(app) - - -def print_tokens(tokens, style=None, true_color=False, file=None): - """ - Print a list of (Token, text) tuples in the given style to the output. - E.g.:: - - style = style_from_dict({ - Token.Hello: '#ff0066', - Token.World: '#884444 italic', - }) - tokens = [ - (Token.Hello, 'Hello'), - (Token.World, 'World'), - ] - print_tokens(tokens, style=style) - - :param tokens: List of ``(Token, text)`` tuples. - :param style: :class:`.Style` instance for the color scheme. - :param true_color: When True, use 24bit colors instead of 256 colors. - :param file: The output file. This can be `sys.stdout` or `sys.stderr`. - """ - if style is None: - style = DEFAULT_STYLE - assert isinstance(style, Style) - - output = create_output(true_color=true_color, stdout=file) - renderer_print_tokens(output, tokens, style) - - -def clear(): - """ - Clear the screen. - """ - out = create_output() - out.erase_screen() - out.cursor_goto(0, 0) - out.flush() - - -# Deprecated alias for `prompt`. -get_input = prompt -# Deprecated alias for create_prompt_layout -create_default_layout = create_prompt_layout -# Deprecated alias for create_prompt_application -create_default_application = create_prompt_application diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/__init__.py deleted file mode 100644 index 9d641f0447..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Styling for prompt_toolkit applications. -""" -from __future__ import unicode_literals - -from .base import * -from .defaults import * -from .from_dict import * -from .from_pygments import * -from .utils import * - - -#: The default built-in style. -#: (For backwards compatibility, when Pygments is installed, this includes the -#: default Pygments style.) -try: - import pygments -except ImportError: - DEFAULT_STYLE = style_from_dict(DEFAULT_STYLE_EXTENSIONS) -else: - DEFAULT_STYLE = style_from_pygments() diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/base.py deleted file mode 100644 index e9ddaa524d..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/base.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -The base classes for the styling. -""" -from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod -from collections import namedtuple -from six import with_metaclass - -__all__ = ( - 'Attrs', - 'DEFAULT_ATTRS', - 'ANSI_COLOR_NAMES', - 'Style', - 'DynamicStyle', -) - - -#: Style attributes. -Attrs = namedtuple('Attrs', 'color bgcolor bold underline italic blink reverse') -""" -:param color: Hexadecimal string. E.g. '000000' or Ansi color name: e.g. 'ansiblue' -:param bgcolor: Hexadecimal string. E.g. 'ffffff' or Ansi color name: e.g. 'ansired' -:param bold: Boolean -:param underline: Boolean -:param italic: Boolean -:param blink: Boolean -:param reverse: Boolean -""" - -#: The default `Attrs`. -DEFAULT_ATTRS = Attrs(color=None, bgcolor=None, bold=False, underline=False, - italic=False, blink=False, reverse=False) - - -#: ``Attrs.bgcolor/fgcolor`` can be in either 'ffffff' format, or can be any of -#: the following in case we want to take colors from the 8/16 color palette. -#: Usually, in that case, the terminal application allows to configure the RGB -#: values for these names. -ANSI_COLOR_NAMES = [ - 'ansiblack', 'ansiwhite', 'ansidefault', - - # Low intensity. - 'ansired', 'ansigreen', 'ansiyellow', 'ansiblue', 'ansifuchsia', 'ansiturquoise', 'ansilightgray', - - # High intensity. (Not supported everywhere.) - 'ansidarkgray', 'ansidarkred', 'ansidarkgreen', 'ansibrown', 'ansidarkblue', - 'ansipurple', 'ansiteal', -] - - -class Style(with_metaclass(ABCMeta, object)): - """ - Abstract base class for prompt_toolkit styles. - """ - @abstractmethod - def get_attrs_for_token(self, token): - """ - Return :class:`.Attrs` for the given token. - """ - - @abstractmethod - def invalidation_hash(self): - """ - Invalidation hash for the style. When this changes over time, the - renderer knows that something in the style changed, and that everything - has to be redrawn. - """ - - -class DynamicStyle(Style): - """ - Style class that can dynamically returns an other Style. - - :param get_style: Callable that returns a :class:`.Style` instance. - """ - def __init__(self, get_style): - self.get_style = get_style - - def get_attrs_for_token(self, token): - style = self.get_style() - assert isinstance(style, Style) - - return style.get_attrs_for_token(token) - - def invalidation_hash(self): - return self.get_style().invalidation_hash() diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/defaults.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/defaults.py deleted file mode 100644 index 5357eaa111..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/defaults.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -The default styling. -""" -from __future__ import unicode_literals - -from prompt_toolkit.token import Token - -__all__ = ( - 'DEFAULT_STYLE_EXTENSIONS', - 'default_style_extensions', -) - - -#: Styling of prompt-toolkit specific tokens, that are not know by the default -#: Pygments style. -DEFAULT_STYLE_EXTENSIONS = { - # Highlighting of search matches in document. - Token.SearchMatch: 'noinherit reverse', - Token.SearchMatch.Current: 'noinherit #ffffff bg:#448844 underline', - - # Highlighting of select text in document. - Token.SelectedText: 'reverse', - - Token.CursorColumn: 'bg:#dddddd', - Token.CursorLine: 'underline', - Token.ColorColumn: 'bg:#ccaacc', - - # Highlighting of matching brackets. - Token.MatchingBracket: '', - Token.MatchingBracket.Other: '#000000 bg:#aacccc', - Token.MatchingBracket.Cursor: '#ff8888 bg:#880000', - - Token.MultipleCursors.Cursor: '#000000 bg:#ccccaa', - - # Line numbers. - Token.LineNumber: '#888888', - Token.LineNumber.Current: 'bold', - Token.Tilde: '#8888ff', - - # Default prompt. - Token.Prompt: '', - Token.Prompt.Arg: 'noinherit', - Token.Prompt.Search: 'noinherit', - Token.Prompt.Search.Text: '', - - # Search toolbar. - Token.Toolbar.Search: 'bold', - Token.Toolbar.Search.Text: 'nobold', - - # System toolbar - Token.Toolbar.System: 'bold', - Token.Toolbar.System.Text: 'nobold', - - # "arg" toolbar. - Token.Toolbar.Arg: 'bold', - Token.Toolbar.Arg.Text: 'nobold', - - # Validation toolbar. - Token.Toolbar.Validation: 'bg:#550000 #ffffff', - Token.WindowTooSmall: 'bg:#550000 #ffffff', - - # Completions toolbar. - Token.Toolbar.Completions: 'bg:#bbbbbb #000000', - Token.Toolbar.Completions.Arrow: 'bg:#bbbbbb #000000 bold', - Token.Toolbar.Completions.Completion: 'bg:#bbbbbb #000000', - Token.Toolbar.Completions.Completion.Current: 'bg:#444444 #ffffff', - - # Completions menu. - Token.Menu.Completions: 'bg:#bbbbbb #000000', - Token.Menu.Completions.Completion: '', - Token.Menu.Completions.Completion.Current: 'bg:#888888 #ffffff', - Token.Menu.Completions.Meta: 'bg:#999999 #000000', - Token.Menu.Completions.Meta.Current: 'bg:#aaaaaa #000000', - Token.Menu.Completions.MultiColumnMeta: 'bg:#aaaaaa #000000', - - # Scrollbars. - Token.Scrollbar: 'bg:#888888', - Token.Scrollbar.Button: 'bg:#444444', - Token.Scrollbar.Arrow: 'bg:#222222 #888888 bold', - - # Auto suggestion text. - Token.AutoSuggestion: '#666666', - - # Trailing whitespace and tabs. - Token.TrailingWhiteSpace: '#999999', - Token.Tab: '#999999', - - # When Control-C has been pressed. Grayed. - Token.Aborted: '#888888', - - # Entering a Vi digraph. - Token.Digraph: '#4444ff', -} - -default_style_extensions = DEFAULT_STYLE_EXTENSIONS # Old name. diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/from_dict.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/from_dict.py deleted file mode 100644 index b50325710f..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/from_dict.py +++ /dev/null @@ -1,151 +0,0 @@ -""" -Tool for creating styles from a dictionary. - -This is very similar to the Pygments style dictionary, with some additions: -- Support for reverse and blink. -- Support for ANSI color names. (These will map directly to the 16 terminal - colors.) -""" -try: - from collections.abc import Mapping -except ImportError: - from collections import Mapping - -from .base import Style, DEFAULT_ATTRS, ANSI_COLOR_NAMES -from .defaults import DEFAULT_STYLE_EXTENSIONS -from .utils import merge_attrs, split_token_in_parts -from six.moves import range - -__all__ = ( - 'style_from_dict', -) - - -def _colorformat(text): - """ - Parse/validate color format. - - Like in Pygments, but also support the ANSI color names. - (These will map to the colors of the 16 color palette.) - """ - if text[0:1] == '#': - col = text[1:] - if col in ANSI_COLOR_NAMES: - return col - elif len(col) == 6: - return col - elif len(col) == 3: - return col[0]*2 + col[1]*2 + col[2]*2 - elif text == '': - return text - - raise ValueError('Wrong color format %r' % text) - - -def style_from_dict(style_dict, include_defaults=True): - """ - Create a ``Style`` instance from a dictionary or other mapping. - - The dictionary is equivalent to the ``Style.styles`` dictionary from - pygments, with a few additions: it supports 'reverse' and 'blink'. - - Usage:: - - style_from_dict({ - Token: '#ff0000 bold underline', - Token.Title: 'blink', - Token.SomethingElse: 'reverse', - }) - - :param include_defaults: Include the defaults (built-in) styling for - selected text, etc...) - """ - assert isinstance(style_dict, Mapping) - - if include_defaults: - s2 = {} - s2.update(DEFAULT_STYLE_EXTENSIONS) - s2.update(style_dict) - style_dict = s2 - - # Expand token inheritance and turn style description into Attrs. - token_to_attrs = {} - - # (Loop through the tokens in order. Sorting makes sure that - # we process the parent first.) - for ttype, styledef in sorted(style_dict.items()): - # Start from parent Attrs or default Attrs. - attrs = DEFAULT_ATTRS - - if 'noinherit' not in styledef: - for i in range(1, len(ttype) + 1): - try: - attrs = token_to_attrs[ttype[:-i]] - except KeyError: - pass - else: - break - - # Now update with the given attributes. - for part in styledef.split(): - if part == 'noinherit': - pass - elif part == 'bold': - attrs = attrs._replace(bold=True) - elif part == 'nobold': - attrs = attrs._replace(bold=False) - elif part == 'italic': - attrs = attrs._replace(italic=True) - elif part == 'noitalic': - attrs = attrs._replace(italic=False) - elif part == 'underline': - attrs = attrs._replace(underline=True) - elif part == 'nounderline': - attrs = attrs._replace(underline=False) - - # prompt_toolkit extensions. Not in Pygments. - elif part == 'blink': - attrs = attrs._replace(blink=True) - elif part == 'noblink': - attrs = attrs._replace(blink=False) - elif part == 'reverse': - attrs = attrs._replace(reverse=True) - elif part == 'noreverse': - attrs = attrs._replace(reverse=False) - - # Pygments properties that we ignore. - elif part in ('roman', 'sans', 'mono'): - pass - elif part.startswith('border:'): - pass - - # Colors. - - elif part.startswith('bg:'): - attrs = attrs._replace(bgcolor=_colorformat(part[3:])) - else: - attrs = attrs._replace(color=_colorformat(part)) - - token_to_attrs[ttype] = attrs - - return _StyleFromDict(token_to_attrs) - - -class _StyleFromDict(Style): - """ - Turn a dictionary that maps `Token` to `Attrs` into a style class. - - :param token_to_attrs: Dictionary that maps `Token` to `Attrs`. - """ - def __init__(self, token_to_attrs): - self.token_to_attrs = token_to_attrs - - def get_attrs_for_token(self, token): - # Split Token. - list_of_attrs = [] - for token in split_token_in_parts(token): - list_of_attrs.append(self.token_to_attrs.get(token, DEFAULT_ATTRS)) - return merge_attrs(list_of_attrs) - - def invalidation_hash(self): - return id(self.token_to_attrs) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/from_pygments.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/from_pygments.py deleted file mode 100644 index 0af8c53cf2..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/from_pygments.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -Adaptor for building prompt_toolkit styles, starting from a Pygments style. - -Usage:: - - from pygments.styles.tango import TangoStyle - style = style_from_pygments(pygments_style_cls=TangoStyle) -""" -from __future__ import unicode_literals - -from .base import Style -from .from_dict import style_from_dict - -__all__ = ( - 'PygmentsStyle', - 'style_from_pygments', -) - - -# Following imports are only needed when a ``PygmentsStyle`` class is used. -try: - from pygments.style import Style as pygments_Style - from pygments.styles.default import DefaultStyle as pygments_DefaultStyle -except ImportError: - pygments_Style = None - pygments_DefaultStyle = None - - -def style_from_pygments(style_cls=pygments_DefaultStyle, - style_dict=None, - include_defaults=True): - """ - Shortcut to create a :class:`.Style` instance from a Pygments style class - and a style dictionary. - - Example:: - - from prompt_toolkit.styles.from_pygments import style_from_pygments - from pygments.styles import get_style_by_name - style = style_from_pygments(get_style_by_name('monokai')) - - :param style_cls: Pygments style class to start from. - :param style_dict: Dictionary for this style. `{Token: style}`. - :param include_defaults: (`bool`) Include prompt_toolkit extensions. - """ - assert style_dict is None or isinstance(style_dict, dict) - assert style_cls is None or issubclass(style_cls, pygments_Style) - - styles_dict = {} - - if style_cls is not None: - styles_dict.update(style_cls.styles) - - if style_dict is not None: - styles_dict.update(style_dict) - - return style_from_dict(styles_dict, include_defaults=include_defaults) - - -class PygmentsStyle(Style): - " Deprecated. " - def __new__(cls, pygments_style_cls): - assert issubclass(pygments_style_cls, pygments_Style) - return style_from_dict(pygments_style_cls.styles) - - def invalidation_hash(self): - pass - - @classmethod - def from_defaults(cls, style_dict=None, - pygments_style_cls=pygments_DefaultStyle, - include_extensions=True): - " Deprecated. " - return style_from_pygments( - style_cls=pygments_style_cls, - style_dict=style_dict, - include_defaults=include_extensions) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/utils.py deleted file mode 100644 index 6087e76abe..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/styles/utils.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import unicode_literals -from .base import DEFAULT_ATTRS, Attrs - -__all__ = ( - 'split_token_in_parts', - 'merge_attrs', -) - - -def split_token_in_parts(token): - """ - Take a Token, and turn it in a list of tokens, by splitting - it on ':' (taking that as a separator.) - """ - result = [] - current = [] - for part in token + (':', ): - if part == ':': - if current: - result.append(tuple(current)) - current = [] - else: - current.append(part) - - return result - - -def merge_attrs(list_of_attrs): - """ - Take a list of :class:`.Attrs` instances and merge them into one. - Every `Attr` in the list can override the styling of the previous one. - """ - result = DEFAULT_ATTRS - - for attr in list_of_attrs: - result = Attrs( - color=attr.color or result.color, - bgcolor=attr.bgcolor or result.bgcolor, - bold=attr.bold or result.bold, - underline=attr.underline or result.underline, - italic=attr.italic or result.italic, - blink=attr.blink or result.blink, - reverse=attr.reverse or result.reverse) - - return result diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/__init__.py +++ /dev/null diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py deleted file mode 100644 index 16b7bde8f3..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py +++ /dev/null @@ -1,42 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.renderer import Output - -from .win32_output import Win32Output -from .vt100_output import Vt100_Output - -__all__ = ( - 'ConEmuOutput', -) - - -class ConEmuOutput(object): - """ - ConEmu (Windows) output abstraction. - - ConEmu is a Windows console application, but it also supports ANSI escape - sequences. This output class is actually a proxy to both `Win32Output` and - `Vt100_Output`. It uses `Win32Output` for console sizing and scrolling, but - all cursor movements and scrolling happens through the `Vt100_Output`. - - This way, we can have 256 colors in ConEmu and Cmder. Rendering will be - even a little faster as well. - - http://conemu.github.io/ - http://gooseberrycreative.com/cmder/ - """ - def __init__(self, stdout): - self.win32_output = Win32Output(stdout) - self.vt100_output = Vt100_Output(stdout, lambda: None) - - def __getattr__(self, name): - if name in ('get_size', 'get_rows_below_cursor_position', - 'enable_mouse_support', 'disable_mouse_support', - 'scroll_buffer_to_prompt', 'get_win32_screen_buffer_info', - 'enable_bracketed_paste', 'disable_bracketed_paste'): - return getattr(self.win32_output, name) - else: - return getattr(self.vt100_output, name) - - -Output.register(ConEmuOutput) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py deleted file mode 100644 index 74841312fa..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py +++ /dev/null @@ -1,520 +0,0 @@ -""" -Parser for VT100 input stream. -""" -from __future__ import unicode_literals - -import os -import re -import six -import termios -import tty - -from six.moves import range - -from ..keys import Keys -from ..key_binding.input_processor import KeyPress - -__all__ = ( - 'InputStream', - 'raw_mode', - 'cooked_mode', -) - -_DEBUG_RENDERER_INPUT = False -_DEBUG_RENDERER_INPUT_FILENAME = 'prompt-toolkit-render-input.log' - - -# Regex matching any CPR response -# (Note that we use '\Z' instead of '$', because '$' could include a trailing -# newline.) -_cpr_response_re = re.compile('^' + re.escape('\x1b[') + r'\d+;\d+R\Z') - -# Mouse events: -# Typical: "Esc[MaB*" Urxvt: "Esc[96;14;13M" and for Xterm SGR: "Esc[<64;85;12M" -_mouse_event_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]+[mM]|M...)\Z') - -# Regex matching any valid prefix of a CPR response. -# (Note that it doesn't contain the last character, the 'R'. The prefix has to -# be shorter.) -_cpr_response_prefix_re = re.compile('^' + re.escape('\x1b[') + r'[\d;]*\Z') - -_mouse_event_prefix_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]*|M.{0,2})\Z') - - -class _Flush(object): - """ Helper object to indicate flush operation to the parser. """ - pass - - -# Mapping of vt100 escape codes to Keys. -ANSI_SEQUENCES = { - '\x1b': Keys.Escape, - - '\x00': Keys.ControlSpace, # Control-Space (Also for Ctrl-@) - '\x01': Keys.ControlA, # Control-A (home) - '\x02': Keys.ControlB, # Control-B (emacs cursor left) - '\x03': Keys.ControlC, # Control-C (interrupt) - '\x04': Keys.ControlD, # Control-D (exit) - '\x05': Keys.ControlE, # Contrel-E (end) - '\x06': Keys.ControlF, # Control-F (cursor forward) - '\x07': Keys.ControlG, # Control-G - '\x08': Keys.ControlH, # Control-H (8) (Identical to '\b') - '\x09': Keys.ControlI, # Control-I (9) (Identical to '\t') - '\x0a': Keys.ControlJ, # Control-J (10) (Identical to '\n') - '\x0b': Keys.ControlK, # Control-K (delete until end of line; vertical tab) - '\x0c': Keys.ControlL, # Control-L (clear; form feed) - '\x0d': Keys.ControlM, # Control-M (13) (Identical to '\r') - '\x0e': Keys.ControlN, # Control-N (14) (history forward) - '\x0f': Keys.ControlO, # Control-O (15) - '\x10': Keys.ControlP, # Control-P (16) (history back) - '\x11': Keys.ControlQ, # Control-Q - '\x12': Keys.ControlR, # Control-R (18) (reverse search) - '\x13': Keys.ControlS, # Control-S (19) (forward search) - '\x14': Keys.ControlT, # Control-T - '\x15': Keys.ControlU, # Control-U - '\x16': Keys.ControlV, # Control-V - '\x17': Keys.ControlW, # Control-W - '\x18': Keys.ControlX, # Control-X - '\x19': Keys.ControlY, # Control-Y (25) - '\x1a': Keys.ControlZ, # Control-Z - - '\x1c': Keys.ControlBackslash, # Both Control-\ and Ctrl-| - '\x1d': Keys.ControlSquareClose, # Control-] - '\x1e': Keys.ControlCircumflex, # Control-^ - '\x1f': Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.) - '\x7f': Keys.Backspace, # (127) Backspace - '\x1b[A': Keys.Up, - '\x1b[B': Keys.Down, - '\x1b[C': Keys.Right, - '\x1b[D': Keys.Left, - '\x1b[H': Keys.Home, - '\x1bOH': Keys.Home, - '\x1b[F': Keys.End, - '\x1bOF': Keys.End, - '\x1b[3~': Keys.Delete, - '\x1b[3;2~': Keys.ShiftDelete, # xterm, gnome-terminal. - '\x1b[3;5~': Keys.ControlDelete, # xterm, gnome-terminal. - '\x1b[1~': Keys.Home, # tmux - '\x1b[4~': Keys.End, # tmux - '\x1b[5~': Keys.PageUp, - '\x1b[6~': Keys.PageDown, - '\x1b[7~': Keys.Home, # xrvt - '\x1b[8~': Keys.End, # xrvt - '\x1b[Z': Keys.BackTab, # shift + tab - '\x1b[2~': Keys.Insert, - - '\x1bOP': Keys.F1, - '\x1bOQ': Keys.F2, - '\x1bOR': Keys.F3, - '\x1bOS': Keys.F4, - '\x1b[[A': Keys.F1, # Linux console. - '\x1b[[B': Keys.F2, # Linux console. - '\x1b[[C': Keys.F3, # Linux console. - '\x1b[[D': Keys.F4, # Linux console. - '\x1b[[E': Keys.F5, # Linux console. - '\x1b[11~': Keys.F1, # rxvt-unicode - '\x1b[12~': Keys.F2, # rxvt-unicode - '\x1b[13~': Keys.F3, # rxvt-unicode - '\x1b[14~': Keys.F4, # rxvt-unicode - '\x1b[15~': Keys.F5, - '\x1b[17~': Keys.F6, - '\x1b[18~': Keys.F7, - '\x1b[19~': Keys.F8, - '\x1b[20~': Keys.F9, - '\x1b[21~': Keys.F10, - '\x1b[23~': Keys.F11, - '\x1b[24~': Keys.F12, - '\x1b[25~': Keys.F13, - '\x1b[26~': Keys.F14, - '\x1b[28~': Keys.F15, - '\x1b[29~': Keys.F16, - '\x1b[31~': Keys.F17, - '\x1b[32~': Keys.F18, - '\x1b[33~': Keys.F19, - '\x1b[34~': Keys.F20, - - # Xterm - '\x1b[1;2P': Keys.F13, - '\x1b[1;2Q': Keys.F14, - # '\x1b[1;2R': Keys.F15, # Conflicts with CPR response. - '\x1b[1;2S': Keys.F16, - '\x1b[15;2~': Keys.F17, - '\x1b[17;2~': Keys.F18, - '\x1b[18;2~': Keys.F19, - '\x1b[19;2~': Keys.F20, - '\x1b[20;2~': Keys.F21, - '\x1b[21;2~': Keys.F22, - '\x1b[23;2~': Keys.F23, - '\x1b[24;2~': Keys.F24, - - '\x1b[1;5A': Keys.ControlUp, # Cursor Mode - '\x1b[1;5B': Keys.ControlDown, # Cursor Mode - '\x1b[1;5C': Keys.ControlRight, # Cursor Mode - '\x1b[1;5D': Keys.ControlLeft, # Cursor Mode - - '\x1b[1;2A': Keys.ShiftUp, - '\x1b[1;2B': Keys.ShiftDown, - '\x1b[1;2C': Keys.ShiftRight, - '\x1b[1;2D': Keys.ShiftLeft, - - # Tmux sends following keystrokes when control+arrow is pressed, but for - # Emacs ansi-term sends the same sequences for normal arrow keys. Consider - # it a normal arrow press, because that's more important. - '\x1bOA': Keys.Up, - '\x1bOB': Keys.Down, - '\x1bOC': Keys.Right, - '\x1bOD': Keys.Left, - - '\x1b[5A': Keys.ControlUp, - '\x1b[5B': Keys.ControlDown, - '\x1b[5C': Keys.ControlRight, - '\x1b[5D': Keys.ControlLeft, - - '\x1bOc': Keys.ControlRight, # rxvt - '\x1bOd': Keys.ControlLeft, # rxvt - - '\x1b[200~': Keys.BracketedPaste, # Start of bracketed paste. - - # Meta + arrow keys. Several terminals handle this differently. - # The following sequences are for xterm and gnome-terminal. - # (Iterm sends ESC followed by the normal arrow_up/down/left/right - # sequences, and the OSX Terminal sends ESCb and ESCf for "alt - # arrow_left" and "alt arrow_right." We don't handle these - # explicitely, in here, because would could not distinguesh between - # pressing ESC (to go to Vi navigation mode), followed by just the - # 'b' or 'f' key. These combinations are handled in - # the input processor.) - '\x1b[1;3D': (Keys.Escape, Keys.Left), - '\x1b[1;3C': (Keys.Escape, Keys.Right), - '\x1b[1;3A': (Keys.Escape, Keys.Up), - '\x1b[1;3B': (Keys.Escape, Keys.Down), - - # Sequences generated by numpad 5. Not sure what it means. (It doesn't - # appear in 'infocmp'. Just ignore. - '\x1b[E': Keys.Ignore, # Xterm. - '\x1b[G': Keys.Ignore, # Linux console. -} - - -class _IsPrefixOfLongerMatchCache(dict): - """ - Dictiory that maps input sequences to a boolean indicating whether there is - any key that start with this characters. - """ - def __missing__(self, prefix): - # (hard coded) If this could be a prefix of a CPR response, return - # True. - if (_cpr_response_prefix_re.match(prefix) or _mouse_event_prefix_re.match(prefix)): - result = True - else: - # If this could be a prefix of anything else, also return True. - result = any(v for k, v in ANSI_SEQUENCES.items() if k.startswith(prefix) and k != prefix) - - self[prefix] = result - return result - - -_IS_PREFIX_OF_LONGER_MATCH_CACHE = _IsPrefixOfLongerMatchCache() - - -class InputStream(object): - """ - Parser for VT100 input stream. - - Feed the data through the `feed` method and the correct callbacks of the - `input_processor` will be called. - - :: - - def callback(key): - pass - i = InputStream(callback) - i.feed('data\x01...') - - :attr input_processor: :class:`~prompt_toolkit.key_binding.InputProcessor` instance. - """ - # Lookup table of ANSI escape sequences for a VT100 terminal - # Hint: in order to know what sequences your terminal writes to stdin, run - # "od -c" and start typing. - def __init__(self, feed_key_callback): - assert callable(feed_key_callback) - - self.feed_key_callback = feed_key_callback - self.reset() - - if _DEBUG_RENDERER_INPUT: - self.LOG = open(_DEBUG_RENDERER_INPUT_FILENAME, 'ab') - - def reset(self, request=False): - self._in_bracketed_paste = False - self._start_parser() - - def _start_parser(self): - """ - Start the parser coroutine. - """ - self._input_parser = self._input_parser_generator() - self._input_parser.send(None) - - def _get_match(self, prefix): - """ - Return the key that maps to this prefix. - """ - # (hard coded) If we match a CPR response, return Keys.CPRResponse. - # (This one doesn't fit in the ANSI_SEQUENCES, because it contains - # integer variables.) - if _cpr_response_re.match(prefix): - return Keys.CPRResponse - - elif _mouse_event_re.match(prefix): - return Keys.Vt100MouseEvent - - # Otherwise, use the mappings. - try: - return ANSI_SEQUENCES[prefix] - except KeyError: - return None - - def _input_parser_generator(self): - """ - Coroutine (state machine) for the input parser. - """ - prefix = '' - retry = False - flush = False - - while True: - flush = False - - if retry: - retry = False - else: - # Get next character. - c = yield - - if c == _Flush: - flush = True - else: - prefix += c - - # If we have some data, check for matches. - if prefix: - is_prefix_of_longer_match = _IS_PREFIX_OF_LONGER_MATCH_CACHE[prefix] - match = self._get_match(prefix) - - # Exact matches found, call handlers.. - if (flush or not is_prefix_of_longer_match) and match: - self._call_handler(match, prefix) - prefix = '' - - # No exact match found. - elif (flush or not is_prefix_of_longer_match) and not match: - found = False - retry = True - - # Loop over the input, try the longest match first and - # shift. - for i in range(len(prefix), 0, -1): - match= self._get_match(prefix[:i]) - if match: - self._call_handler(match, prefix[:i]) - prefix = prefix[i:] - found = True - - if not found: - self._call_handler(prefix[0], prefix[0]) - prefix = prefix[1:] - - def _call_handler(self, key, insert_text): - """ - Callback to handler. - """ - if isinstance(key, tuple): - for k in key: - self._call_handler(k, insert_text) - else: - if key == Keys.BracketedPaste: - self._in_bracketed_paste = True - self._paste_buffer = '' - else: - self.feed_key_callback(KeyPress(key, insert_text)) - - def feed(self, data): - """ - Feed the input stream. - - :param data: Input string (unicode). - """ - assert isinstance(data, six.text_type) - - if _DEBUG_RENDERER_INPUT: - self.LOG.write(repr(data).encode('utf-8') + b'\n') - self.LOG.flush() - - # Handle bracketed paste. (We bypass the parser that matches all other - # key presses and keep reading input until we see the end mark.) - # This is much faster then parsing character by character. - if self._in_bracketed_paste: - self._paste_buffer += data - end_mark = '\x1b[201~' - - if end_mark in self._paste_buffer: - end_index = self._paste_buffer.index(end_mark) - - # Feed content to key bindings. - paste_content = self._paste_buffer[:end_index] - self.feed_key_callback(KeyPress(Keys.BracketedPaste, paste_content)) - - # Quit bracketed paste mode and handle remaining input. - self._in_bracketed_paste = False - remaining = self._paste_buffer[end_index + len(end_mark):] - self._paste_buffer = '' - - self.feed(remaining) - - # Handle normal input character by character. - else: - for i, c in enumerate(data): - if self._in_bracketed_paste: - # Quit loop and process from this position when the parser - # entered bracketed paste. - self.feed(data[i:]) - break - else: - # Replace \r by \n. (Some clients send \r instead of \n - # when enter is pressed. E.g. telnet and some other - # terminals.) - - # XXX: We should remove this in a future version. It *is* - # now possible to recognise the difference. - # (We remove ICRNL/INLCR/IGNCR below.) - # However, this breaks IPython and maybe other applications, - # because they bind ControlJ (\n) for handling the Enter key. - - # When this is removed, replace Enter=ControlJ by - # Enter=ControlM in keys.py. - if c == '\r': - c = '\n' - self._input_parser.send(c) - - def flush(self): - """ - Flush the buffer of the input stream. - - This will allow us to handle the escape key (or maybe meta) sooner. - The input received by the escape key is actually the same as the first - characters of e.g. Arrow-Up, so without knowing what follows the escape - sequence, we don't know whether escape has been pressed, or whether - it's something else. This flush function should be called after a - timeout, and processes everything that's still in the buffer as-is, so - without assuming any characters will folow. - """ - self._input_parser.send(_Flush) - - def feed_and_flush(self, data): - """ - Wrapper around ``feed`` and ``flush``. - """ - self.feed(data) - self.flush() - - -class raw_mode(object): - """ - :: - - with raw_mode(stdin): - ''' the pseudo-terminal stdin is now used in raw mode ''' - - We ignore errors when executing `tcgetattr` fails. - """ - # There are several reasons for ignoring errors: - # 1. To avoid the "Inappropriate ioctl for device" crash if somebody would - # execute this code (In a Python REPL, for instance): - # - # import os; f = open(os.devnull); os.dup2(f.fileno(), 0) - # - # The result is that the eventloop will stop correctly, because it has - # to logic to quit when stdin is closed. However, we should not fail at - # this point. See: - # https://github.com/jonathanslenders/python-prompt-toolkit/pull/393 - # https://github.com/jonathanslenders/python-prompt-toolkit/issues/392 - - # 2. Related, when stdin is an SSH pipe, and no full terminal was allocated. - # See: https://github.com/jonathanslenders/python-prompt-toolkit/pull/165 - def __init__(self, fileno): - self.fileno = fileno - try: - self.attrs_before = termios.tcgetattr(fileno) - except termios.error: - # Ignore attribute errors. - self.attrs_before = None - - def __enter__(self): - # NOTE: On os X systems, using pty.setraw() fails. Therefor we are using this: - try: - newattr = termios.tcgetattr(self.fileno) - except termios.error: - pass - else: - newattr[tty.LFLAG] = self._patch_lflag(newattr[tty.LFLAG]) - newattr[tty.IFLAG] = self._patch_iflag(newattr[tty.IFLAG]) - - # VMIN defines the number of characters read at a time in - # non-canonical mode. It seems to default to 1 on Linux, but on - # Solaris and derived operating systems it defaults to 4. (This is - # because the VMIN slot is the same as the VEOF slot, which - # defaults to ASCII EOT = Ctrl-D = 4.) - newattr[tty.CC][termios.VMIN] = 1 - - termios.tcsetattr(self.fileno, termios.TCSANOW, newattr) - - # Put the terminal in cursor mode. (Instead of application mode.) - os.write(self.fileno, b'\x1b[?1l') - - @classmethod - def _patch_lflag(cls, attrs): - return attrs & ~(termios.ECHO | termios.ICANON | termios.IEXTEN | termios.ISIG) - - @classmethod - def _patch_iflag(cls, attrs): - return attrs & ~( - # Disable XON/XOFF flow control on output and input. - # (Don't capture Ctrl-S and Ctrl-Q.) - # Like executing: "stty -ixon." - termios.IXON | termios.IXOFF | - - # Don't translate carriage return into newline on input. - termios.ICRNL | termios.INLCR | termios.IGNCR - ) - - def __exit__(self, *a, **kw): - if self.attrs_before is not None: - try: - termios.tcsetattr(self.fileno, termios.TCSANOW, self.attrs_before) - except termios.error: - pass - - # # Put the terminal in application mode. - # self._stdout.write('\x1b[?1h') - - -class cooked_mode(raw_mode): - """ - The opposide of ``raw_mode``, used when we need cooked mode inside a - `raw_mode` block. Used in `CommandLineInterface.run_in_terminal`.:: - - with cooked_mode(stdin): - ''' the pseudo-terminal stdin is now used in cooked mode. ''' - """ - @classmethod - def _patch_lflag(cls, attrs): - return attrs | (termios.ECHO | termios.ICANON | termios.IEXTEN | termios.ISIG) - - @classmethod - def _patch_iflag(cls, attrs): - # Turn the ICRNL flag back on. (Without this, calling `input()` in - # run_in_terminal doesn't work and displays ^M instead. Ptpython - # evaluates commands using `run_in_terminal`, so it's important that - # they translate ^M back into ^J.) - return attrs | termios.ICRNL diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py deleted file mode 100644 index b800aaacec..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py +++ /dev/null @@ -1,632 +0,0 @@ -""" -Output for vt100 terminals. - -A lot of thanks, regarding outputting of colors, goes to the Pygments project: -(We don't rely on Pygments anymore, because many things are very custom, and -everything has been highly optimized.) -http://pygments.org/ -""" -from __future__ import unicode_literals - -from prompt_toolkit.filters import to_simple_filter, Condition -from prompt_toolkit.layout.screen import Size -from prompt_toolkit.renderer import Output -from prompt_toolkit.styles import ANSI_COLOR_NAMES - -from six.moves import range -import array -import errno -import os -import six - -__all__ = ( - 'Vt100_Output', -) - - -FG_ANSI_COLORS = { - 'ansidefault': 39, - - # Low intensity. - 'ansiblack': 30, - 'ansidarkred': 31, - 'ansidarkgreen': 32, - 'ansibrown': 33, - 'ansidarkblue': 34, - 'ansipurple': 35, - 'ansiteal': 36, - 'ansilightgray': 37, - - # High intensity. - 'ansidarkgray': 90, - 'ansired': 91, - 'ansigreen': 92, - 'ansiyellow': 93, - 'ansiblue': 94, - 'ansifuchsia': 95, - 'ansiturquoise': 96, - 'ansiwhite': 97, -} - -BG_ANSI_COLORS = { - 'ansidefault': 49, - - # Low intensity. - 'ansiblack': 40, - 'ansidarkred': 41, - 'ansidarkgreen': 42, - 'ansibrown': 43, - 'ansidarkblue': 44, - 'ansipurple': 45, - 'ansiteal': 46, - 'ansilightgray': 47, - - # High intensity. - 'ansidarkgray': 100, - 'ansired': 101, - 'ansigreen': 102, - 'ansiyellow': 103, - 'ansiblue': 104, - 'ansifuchsia': 105, - 'ansiturquoise': 106, - 'ansiwhite': 107, -} - - -ANSI_COLORS_TO_RGB = { - 'ansidefault': (0x00, 0x00, 0x00), # Don't use, 'default' doesn't really have a value. - 'ansiblack': (0x00, 0x00, 0x00), - 'ansidarkgray': (0x7f, 0x7f, 0x7f), - 'ansiwhite': (0xff, 0xff, 0xff), - 'ansilightgray': (0xe5, 0xe5, 0xe5), - - # Low intensity. - 'ansidarkred': (0xcd, 0x00, 0x00), - 'ansidarkgreen': (0x00, 0xcd, 0x00), - 'ansibrown': (0xcd, 0xcd, 0x00), - 'ansidarkblue': (0x00, 0x00, 0xcd), - 'ansipurple': (0xcd, 0x00, 0xcd), - 'ansiteal': (0x00, 0xcd, 0xcd), - - # High intensity. - 'ansired': (0xff, 0x00, 0x00), - 'ansigreen': (0x00, 0xff, 0x00), - 'ansiyellow': (0xff, 0xff, 0x00), - 'ansiblue': (0x00, 0x00, 0xff), - 'ansifuchsia': (0xff, 0x00, 0xff), - 'ansiturquoise': (0x00, 0xff, 0xff), -} - - -assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES) -assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES) -assert set(ANSI_COLORS_TO_RGB) == set(ANSI_COLOR_NAMES) - - -def _get_closest_ansi_color(r, g, b, exclude=()): - """ - Find closest ANSI color. Return it by name. - - :param r: Red (Between 0 and 255.) - :param g: Green (Between 0 and 255.) - :param b: Blue (Between 0 and 255.) - :param exclude: A tuple of color names to exclude. (E.g. ``('ansired', )``.) - """ - assert isinstance(exclude, tuple) - - # When we have a bit of saturation, avoid the gray-like colors, otherwise, - # too often the distance to the gray color is less. - saturation = abs(r - g) + abs(g - b) + abs(b - r) # Between 0..510 - - if saturation > 30: - exclude += ('ansilightgray', 'ansidarkgray', 'ansiwhite', 'ansiblack') - - # Take the closest color. - # (Thanks to Pygments for this part.) - distance = 257*257*3 # "infinity" (>distance from #000000 to #ffffff) - match = 'ansidefault' - - for name, (r2, g2, b2) in ANSI_COLORS_TO_RGB.items(): - if name != 'ansidefault' and name not in exclude: - d = (r - r2) ** 2 + (g - g2) ** 2 + (b - b2) ** 2 - - if d < distance: - match = name - distance = d - - return match - - -class _16ColorCache(dict): - """ - Cache which maps (r, g, b) tuples to 16 ansi colors. - - :param bg: Cache for background colors, instead of foreground. - """ - def __init__(self, bg=False): - assert isinstance(bg, bool) - self.bg = bg - - def get_code(self, value, exclude=()): - """ - Return a (ansi_code, ansi_name) tuple. (E.g. ``(44, 'ansiblue')``.) for - a given (r,g,b) value. - """ - key = (value, exclude) - if key not in self: - self[key] = self._get(value, exclude) - return self[key] - - def _get(self, value, exclude=()): - r, g, b = value - match = _get_closest_ansi_color(r, g, b, exclude=exclude) - - # Turn color name into code. - if self.bg: - code = BG_ANSI_COLORS[match] - else: - code = FG_ANSI_COLORS[match] - - self[value] = code - return code, match - - -class _256ColorCache(dict): - """ - Cach which maps (r, g, b) tuples to 256 colors. - """ - def __init__(self): - # Build color table. - colors = [] - - # colors 0..15: 16 basic colors - colors.append((0x00, 0x00, 0x00)) # 0 - colors.append((0xcd, 0x00, 0x00)) # 1 - colors.append((0x00, 0xcd, 0x00)) # 2 - colors.append((0xcd, 0xcd, 0x00)) # 3 - colors.append((0x00, 0x00, 0xee)) # 4 - colors.append((0xcd, 0x00, 0xcd)) # 5 - colors.append((0x00, 0xcd, 0xcd)) # 6 - colors.append((0xe5, 0xe5, 0xe5)) # 7 - colors.append((0x7f, 0x7f, 0x7f)) # 8 - colors.append((0xff, 0x00, 0x00)) # 9 - colors.append((0x00, 0xff, 0x00)) # 10 - colors.append((0xff, 0xff, 0x00)) # 11 - colors.append((0x5c, 0x5c, 0xff)) # 12 - colors.append((0xff, 0x00, 0xff)) # 13 - colors.append((0x00, 0xff, 0xff)) # 14 - colors.append((0xff, 0xff, 0xff)) # 15 - - # colors 16..232: the 6x6x6 color cube - valuerange = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) - - for i in range(217): - r = valuerange[(i // 36) % 6] - g = valuerange[(i // 6) % 6] - b = valuerange[i % 6] - colors.append((r, g, b)) - - # colors 233..253: grayscale - for i in range(1, 22): - v = 8 + i * 10 - colors.append((v, v, v)) - - self.colors = colors - - def __missing__(self, value): - r, g, b = value - - # Find closest color. - # (Thanks to Pygments for this!) - distance = 257*257*3 # "infinity" (>distance from #000000 to #ffffff) - match = 0 - - for i, (r2, g2, b2) in enumerate(self.colors): - d = (r - r2) ** 2 + (g - g2) ** 2 + (b - b2) ** 2 - - if d < distance: - match = i - distance = d - - # Turn color name into code. - self[value] = match - return match - - -_16_fg_colors = _16ColorCache(bg=False) -_16_bg_colors = _16ColorCache(bg=True) -_256_colors = _256ColorCache() - - -class _EscapeCodeCache(dict): - """ - Cache for VT100 escape codes. It maps - (fgcolor, bgcolor, bold, underline, reverse) tuples to VT100 escape sequences. - - :param true_color: When True, use 24bit colors instead of 256 colors. - """ - def __init__(self, true_color=False, ansi_colors_only=False): - assert isinstance(true_color, bool) - self.true_color = true_color - self.ansi_colors_only = to_simple_filter(ansi_colors_only) - - def __missing__(self, attrs): - fgcolor, bgcolor, bold, underline, italic, blink, reverse = attrs - parts = [] - - parts.extend(self._colors_to_code(fgcolor, bgcolor)) - - if bold: - parts.append('1') - if italic: - parts.append('3') - if blink: - parts.append('5') - if underline: - parts.append('4') - if reverse: - parts.append('7') - - if parts: - result = '\x1b[0;' + ';'.join(parts) + 'm' - else: - result = '\x1b[0m' - - self[attrs] = result - return result - - def _color_name_to_rgb(self, color): - " Turn 'ffffff', into (0xff, 0xff, 0xff). " - try: - rgb = int(color, 16) - except ValueError: - raise - else: - r = (rgb >> 16) & 0xff - g = (rgb >> 8) & 0xff - b = rgb & 0xff - return r, g, b - - def _colors_to_code(self, fg_color, bg_color): - " Return a tuple with the vt100 values that represent this color. " - # When requesting ANSI colors only, and both fg/bg color were converted - # to ANSI, ensure that the foreground and background color are not the - # same. (Unless they were explicitely defined to be the same color.) - fg_ansi = [()] - - def get(color, bg): - table = BG_ANSI_COLORS if bg else FG_ANSI_COLORS - - if color is None: - return () - - # 16 ANSI colors. (Given by name.) - elif color in table: - return (table[color], ) - - # RGB colors. (Defined as 'ffffff'.) - else: - try: - rgb = self._color_name_to_rgb(color) - except ValueError: - return () - - # When only 16 colors are supported, use that. - if self.ansi_colors_only(): - if bg: # Background. - if fg_color != bg_color: - exclude = (fg_ansi[0], ) - else: - exclude = () - code, name = _16_bg_colors.get_code(rgb, exclude=exclude) - return (code, ) - else: # Foreground. - code, name = _16_fg_colors.get_code(rgb) - fg_ansi[0] = name - return (code, ) - - # True colors. (Only when this feature is enabled.) - elif self.true_color: - r, g, b = rgb - return (48 if bg else 38, 2, r, g, b) - - # 256 RGB colors. - else: - return (48 if bg else 38, 5, _256_colors[rgb]) - - result = [] - result.extend(get(fg_color, False)) - result.extend(get(bg_color, True)) - - return map(six.text_type, result) - - -def _get_size(fileno): - # Thanks to fabric (fabfile.org), and - # http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/ - """ - Get the size of this pseudo terminal. - - :param fileno: stdout.fileno() - :returns: A (rows, cols) tuple. - """ - # Inline imports, because these modules are not available on Windows. - # (This file is used by ConEmuOutput, which is used on Windows.) - import fcntl - import termios - - # Buffer for the C call - buf = array.array(b'h' if six.PY2 else u'h', [0, 0, 0, 0]) - - # Do TIOCGWINSZ (Get) - # Note: We should not pass 'True' as a fourth parameter to 'ioctl'. (True - # is the default.) This causes segmentation faults on some systems. - # See: https://github.com/jonathanslenders/python-prompt-toolkit/pull/364 - fcntl.ioctl(fileno, termios.TIOCGWINSZ, buf) - - # Return rows, cols - return buf[0], buf[1] - - -class Vt100_Output(Output): - """ - :param get_size: A callable which returns the `Size` of the output terminal. - :param stdout: Any object with has a `write` and `flush` method + an 'encoding' property. - :param true_color: Use 24bit color instead of 256 colors. (Can be a :class:`SimpleFilter`.) - When `ansi_colors_only` is set, only 16 colors are used. - :param ansi_colors_only: Restrict to 16 ANSI colors only. - :param term: The terminal environment variable. (xterm, xterm-256color, linux, ...) - :param write_binary: Encode the output before writing it. If `True` (the - default), the `stdout` object is supposed to expose an `encoding` attribute. - """ - def __init__(self, stdout, get_size, true_color=False, - ansi_colors_only=None, term=None, write_binary=True): - assert callable(get_size) - assert term is None or isinstance(term, six.text_type) - assert all(hasattr(stdout, a) for a in ('write', 'flush')) - - if write_binary: - assert hasattr(stdout, 'encoding') - - self._buffer = [] - self.stdout = stdout - self.write_binary = write_binary - self.get_size = get_size - self.true_color = to_simple_filter(true_color) - self.term = term or 'xterm' - - # ANSI colors only? - if ansi_colors_only is None: - # When not given, use the following default. - ANSI_COLORS_ONLY = bool(os.environ.get( - 'PROMPT_TOOLKIT_ANSI_COLORS_ONLY', False)) - - @Condition - def ansi_colors_only(): - return ANSI_COLORS_ONLY or term in ('linux', 'eterm-color') - else: - ansi_colors_only = to_simple_filter(ansi_colors_only) - - self.ansi_colors_only = ansi_colors_only - - # Cache for escape codes. - self._escape_code_cache = _EscapeCodeCache(ansi_colors_only=ansi_colors_only) - self._escape_code_cache_true_color = _EscapeCodeCache( - true_color=True, ansi_colors_only=ansi_colors_only) - - @classmethod - def from_pty(cls, stdout, true_color=False, ansi_colors_only=None, term=None): - """ - Create an Output class from a pseudo terminal. - (This will take the dimensions by reading the pseudo - terminal attributes.) - """ - assert stdout.isatty() - def get_size(): - rows, columns = _get_size(stdout.fileno()) - # If terminal (incorrectly) reports its size as 0, pick a reasonable default. - # See https://github.com/ipython/ipython/issues/10071 - return Size(rows=(rows or 24), columns=(columns or 80)) - - return cls(stdout, get_size, true_color=true_color, - ansi_colors_only=ansi_colors_only, term=term) - - def fileno(self): - " Return file descriptor. " - return self.stdout.fileno() - - def encoding(self): - " Return encoding used for stdout. " - return self.stdout.encoding - - def write_raw(self, data): - """ - Write raw data to output. - """ - self._buffer.append(data) - - def write(self, data): - """ - Write text to output. - (Removes vt100 escape codes. -- used for safely writing text.) - """ - self._buffer.append(data.replace('\x1b', '?')) - - def set_title(self, title): - """ - Set terminal title. - """ - if self.term not in ('linux', 'eterm-color'): # Not supported by the Linux console. - self.write_raw('\x1b]2;%s\x07' % title.replace('\x1b', '').replace('\x07', '')) - - def clear_title(self): - self.set_title('') - - def erase_screen(self): - """ - Erases the screen with the background colour and moves the cursor to - home. - """ - self.write_raw('\x1b[2J') - - def enter_alternate_screen(self): - self.write_raw('\x1b[?1049h\x1b[H') - - def quit_alternate_screen(self): - self.write_raw('\x1b[?1049l') - - def enable_mouse_support(self): - self.write_raw('\x1b[?1000h') - - # Enable urxvt Mouse mode. (For terminals that understand this.) - self.write_raw('\x1b[?1015h') - - # Also enable Xterm SGR mouse mode. (For terminals that understand this.) - self.write_raw('\x1b[?1006h') - - # Note: E.g. lxterminal understands 1000h, but not the urxvt or sgr - # extensions. - - def disable_mouse_support(self): - self.write_raw('\x1b[?1000l') - self.write_raw('\x1b[?1015l') - self.write_raw('\x1b[?1006l') - - def erase_end_of_line(self): - """ - Erases from the current cursor position to the end of the current line. - """ - self.write_raw('\x1b[K') - - def erase_down(self): - """ - Erases the screen from the current line down to the bottom of the - screen. - """ - self.write_raw('\x1b[J') - - def reset_attributes(self): - self.write_raw('\x1b[0m') - - def set_attributes(self, attrs): - """ - Create new style and output. - - :param attrs: `Attrs` instance. - """ - if self.true_color() and not self.ansi_colors_only(): - self.write_raw(self._escape_code_cache_true_color[attrs]) - else: - self.write_raw(self._escape_code_cache[attrs]) - - def disable_autowrap(self): - self.write_raw('\x1b[?7l') - - def enable_autowrap(self): - self.write_raw('\x1b[?7h') - - def enable_bracketed_paste(self): - self.write_raw('\x1b[?2004h') - - def disable_bracketed_paste(self): - self.write_raw('\x1b[?2004l') - - def cursor_goto(self, row=0, column=0): - """ Move cursor position. """ - self.write_raw('\x1b[%i;%iH' % (row, column)) - - def cursor_up(self, amount): - if amount == 0: - pass - elif amount == 1: - self.write_raw('\x1b[A') - else: - self.write_raw('\x1b[%iA' % amount) - - def cursor_down(self, amount): - if amount == 0: - pass - elif amount == 1: - # Note: Not the same as '\n', '\n' can cause the window content to - # scroll. - self.write_raw('\x1b[B') - else: - self.write_raw('\x1b[%iB' % amount) - - def cursor_forward(self, amount): - if amount == 0: - pass - elif amount == 1: - self.write_raw('\x1b[C') - else: - self.write_raw('\x1b[%iC' % amount) - - def cursor_backward(self, amount): - if amount == 0: - pass - elif amount == 1: - self.write_raw('\b') # '\x1b[D' - else: - self.write_raw('\x1b[%iD' % amount) - - def hide_cursor(self): - self.write_raw('\x1b[?25l') - - def show_cursor(self): - self.write_raw('\x1b[?12l\x1b[?25h') # Stop blinking cursor and show. - - def flush(self): - """ - Write to output stream and flush. - """ - if not self._buffer: - return - - data = ''.join(self._buffer) - - try: - # (We try to encode ourself, because that way we can replace - # characters that don't exist in the character set, avoiding - # UnicodeEncodeError crashes. E.g. u'\xb7' does not appear in 'ascii'.) - # My Arch Linux installation of july 2015 reported 'ANSI_X3.4-1968' - # for sys.stdout.encoding in xterm. - if self.write_binary: - if hasattr(self.stdout, 'buffer'): - out = self.stdout.buffer # Py3. - else: - out = self.stdout - out.write(data.encode(self.stdout.encoding or 'utf-8', 'replace')) - else: - self.stdout.write(data) - - self.stdout.flush() - except IOError as e: - if e.args and e.args[0] == errno.EINTR: - # Interrupted system call. Can happpen in case of a window - # resize signal. (Just ignore. The resize handler will render - # again anyway.) - pass - elif e.args and e.args[0] == 0: - # This can happen when there is a lot of output and the user - # sends a KeyboardInterrupt by pressing Control-C. E.g. in - # a Python REPL when we execute "while True: print('test')". - # (The `ptpython` REPL uses this `Output` class instead of - # `stdout` directly -- in order to be network transparent.) - # So, just ignore. - pass - else: - raise - - self._buffer = [] - - def ask_for_cpr(self): - """ - Asks for a cursor position report (CPR). - """ - self.write_raw('\x1b[6n') - self.flush() - - def bell(self): - " Sound bell. " - self.write_raw('\a') - self.flush() diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py deleted file mode 100644 index 410e5fa517..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py +++ /dev/null @@ -1,364 +0,0 @@ -from __future__ import unicode_literals -from ctypes import windll, pointer -from ctypes.wintypes import DWORD, HANDLE -from six.moves import range - -from prompt_toolkit.key_binding.input_processor import KeyPress -from prompt_toolkit.keys import Keys -from prompt_toolkit.mouse_events import MouseEventType -from prompt_toolkit.win32_types import EventTypes, KEY_EVENT_RECORD, MOUSE_EVENT_RECORD, INPUT_RECORD, STD_INPUT_HANDLE - -import msvcrt -import os -import sys -import six - -__all__ = ( - 'ConsoleInputReader', - 'raw_mode', - 'cooked_mode' -) - - -class ConsoleInputReader(object): - """ - :param recognize_paste: When True, try to discover paste actions and turn - the event into a BracketedPaste. - """ - # Keys with character data. - mappings = { - b'\x1b': Keys.Escape, - - b'\x00': Keys.ControlSpace, # Control-Space (Also for Ctrl-@) - b'\x01': Keys.ControlA, # Control-A (home) - b'\x02': Keys.ControlB, # Control-B (emacs cursor left) - b'\x03': Keys.ControlC, # Control-C (interrupt) - b'\x04': Keys.ControlD, # Control-D (exit) - b'\x05': Keys.ControlE, # Contrel-E (end) - b'\x06': Keys.ControlF, # Control-F (cursor forward) - b'\x07': Keys.ControlG, # Control-G - b'\x08': Keys.ControlH, # Control-H (8) (Identical to '\b') - b'\x09': Keys.ControlI, # Control-I (9) (Identical to '\t') - b'\x0a': Keys.ControlJ, # Control-J (10) (Identical to '\n') - b'\x0b': Keys.ControlK, # Control-K (delete until end of line; vertical tab) - b'\x0c': Keys.ControlL, # Control-L (clear; form feed) - b'\x0d': Keys.ControlJ, # Control-J NOTE: Windows sends \r instead of - # \n when pressing enter. We turn it into \n - # to be compatible with other platforms. - b'\x0e': Keys.ControlN, # Control-N (14) (history forward) - b'\x0f': Keys.ControlO, # Control-O (15) - b'\x10': Keys.ControlP, # Control-P (16) (history back) - b'\x11': Keys.ControlQ, # Control-Q - b'\x12': Keys.ControlR, # Control-R (18) (reverse search) - b'\x13': Keys.ControlS, # Control-S (19) (forward search) - b'\x14': Keys.ControlT, # Control-T - b'\x15': Keys.ControlU, # Control-U - b'\x16': Keys.ControlV, # Control-V - b'\x17': Keys.ControlW, # Control-W - b'\x18': Keys.ControlX, # Control-X - b'\x19': Keys.ControlY, # Control-Y (25) - b'\x1a': Keys.ControlZ, # Control-Z - - b'\x1c': Keys.ControlBackslash, # Both Control-\ and Ctrl-| - b'\x1d': Keys.ControlSquareClose, # Control-] - b'\x1e': Keys.ControlCircumflex, # Control-^ - b'\x1f': Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.) - b'\x7f': Keys.Backspace, # (127) Backspace - } - - # Keys that don't carry character data. - keycodes = { - # Home/End - 33: Keys.PageUp, - 34: Keys.PageDown, - 35: Keys.End, - 36: Keys.Home, - - # Arrows - 37: Keys.Left, - 38: Keys.Up, - 39: Keys.Right, - 40: Keys.Down, - - 45: Keys.Insert, - 46: Keys.Delete, - - # F-keys. - 112: Keys.F1, - 113: Keys.F2, - 114: Keys.F3, - 115: Keys.F4, - 116: Keys.F5, - 117: Keys.F6, - 118: Keys.F7, - 119: Keys.F8, - 120: Keys.F9, - 121: Keys.F10, - 122: Keys.F11, - 123: Keys.F12, - } - - LEFT_ALT_PRESSED = 0x0002 - RIGHT_ALT_PRESSED = 0x0001 - SHIFT_PRESSED = 0x0010 - LEFT_CTRL_PRESSED = 0x0008 - RIGHT_CTRL_PRESSED = 0x0004 - - def __init__(self, recognize_paste=True): - self._fdcon = None - self.recognize_paste = recognize_paste - - # When stdin is a tty, use that handle, otherwise, create a handle from - # CONIN$. - if sys.stdin.isatty(): - self.handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)) - else: - self._fdcon = os.open('CONIN$', os.O_RDWR | os.O_BINARY) - self.handle = HANDLE(msvcrt.get_osfhandle(self._fdcon)) - - def close(self): - " Close fdcon. " - if self._fdcon is not None: - os.close(self._fdcon) - - def read(self): - """ - Return a list of `KeyPress` instances. It won't return anything when - there was nothing to read. (This function doesn't block.) - - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx - """ - max_count = 2048 # Max events to read at the same time. - - read = DWORD(0) - arrtype = INPUT_RECORD * max_count - input_records = arrtype() - - # Get next batch of input event. - windll.kernel32.ReadConsoleInputW( - self.handle, pointer(input_records), max_count, pointer(read)) - - # First, get all the keys from the input buffer, in order to determine - # whether we should consider this a paste event or not. - all_keys = list(self._get_keys(read, input_records)) - - if self.recognize_paste and self._is_paste(all_keys): - gen = iter(all_keys) - for k in gen: - # Pasting: if the current key consists of text or \n, turn it - # into a BracketedPaste. - data = [] - while k and (isinstance(k.key, six.text_type) or - k.key == Keys.ControlJ): - data.append(k.data) - try: - k = next(gen) - except StopIteration: - k = None - - if data: - yield KeyPress(Keys.BracketedPaste, ''.join(data)) - if k is not None: - yield k - else: - for k in all_keys: - yield k - - def _get_keys(self, read, input_records): - """ - Generator that yields `KeyPress` objects from the input records. - """ - for i in range(read.value): - ir = input_records[i] - - # Get the right EventType from the EVENT_RECORD. - # (For some reason the Windows console application 'cmder' - # [http://gooseberrycreative.com/cmder/] can return '0' for - # ir.EventType. -- Just ignore that.) - if ir.EventType in EventTypes: - ev = getattr(ir.Event, EventTypes[ir.EventType]) - - # Process if this is a key event. (We also have mouse, menu and - # focus events.) - if type(ev) == KEY_EVENT_RECORD and ev.KeyDown: - for key_press in self._event_to_key_presses(ev): - yield key_press - - elif type(ev) == MOUSE_EVENT_RECORD: - for key_press in self._handle_mouse(ev): - yield key_press - - @staticmethod - def _is_paste(keys): - """ - Return `True` when we should consider this list of keys as a paste - event. Pasted text on windows will be turned into a - `Keys.BracketedPaste` event. (It's not 100% correct, but it is probably - the best possible way to detect pasting of text and handle that - correctly.) - """ - # Consider paste when it contains at least one newline and at least one - # other character. - text_count = 0 - newline_count = 0 - - for k in keys: - if isinstance(k.key, six.text_type): - text_count += 1 - if k.key == Keys.ControlJ: - newline_count += 1 - - return newline_count >= 1 and text_count > 1 - - def _event_to_key_presses(self, ev): - """ - For this `KEY_EVENT_RECORD`, return a list of `KeyPress` instances. - """ - assert type(ev) == KEY_EVENT_RECORD and ev.KeyDown - - result = None - - u_char = ev.uChar.UnicodeChar - ascii_char = u_char.encode('utf-8') - - # NOTE: We don't use `ev.uChar.AsciiChar`. That appears to be latin-1 - # encoded. See also: - # https://github.com/ipython/ipython/issues/10004 - # https://github.com/jonathanslenders/python-prompt-toolkit/issues/389 - - if u_char == '\x00': - if ev.VirtualKeyCode in self.keycodes: - result = KeyPress(self.keycodes[ev.VirtualKeyCode], '') - else: - if ascii_char in self.mappings: - if self.mappings[ascii_char] == Keys.ControlJ: - u_char = '\n' # Windows sends \n, turn into \r for unix compatibility. - result = KeyPress(self.mappings[ascii_char], u_char) - else: - result = KeyPress(u_char, u_char) - - # Correctly handle Control-Arrow keys. - if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or - ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result: - if result.key == Keys.Left: - result.key = Keys.ControlLeft - - if result.key == Keys.Right: - result.key = Keys.ControlRight - - if result.key == Keys.Up: - result.key = Keys.ControlUp - - if result.key == Keys.Down: - result.key = Keys.ControlDown - - # Turn 'Tab' into 'BackTab' when shift was pressed. - if ev.ControlKeyState & self.SHIFT_PRESSED and result: - if result.key == Keys.Tab: - result.key = Keys.BackTab - - # Turn 'Space' into 'ControlSpace' when control was pressed. - if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or - ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and result.data == ' ': - result = KeyPress(Keys.ControlSpace, ' ') - - # Turn Control-Enter into META-Enter. (On a vt100 terminal, we cannot - # detect this combination. But it's really practical on Windows.) - if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or - ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and \ - result.key == Keys.ControlJ: - return [KeyPress(Keys.Escape, ''), result] - - # Return result. If alt was pressed, prefix the result with an - # 'Escape' key, just like unix VT100 terminals do. - - # NOTE: Only replace the left alt with escape. The right alt key often - # acts as altgr and is used in many non US keyboard layouts for - # typing some special characters, like a backslash. We don't want - # all backslashes to be prefixed with escape. (Esc-\ has a - # meaning in E-macs, for instance.) - if result: - meta_pressed = ev.ControlKeyState & self.LEFT_ALT_PRESSED - - if meta_pressed: - return [KeyPress(Keys.Escape, ''), result] - else: - return [result] - - else: - return [] - - def _handle_mouse(self, ev): - """ - Handle mouse events. Return a list of KeyPress instances. - """ - FROM_LEFT_1ST_BUTTON_PRESSED = 0x1 - - result = [] - - # Check event type. - if ev.ButtonState == FROM_LEFT_1ST_BUTTON_PRESSED: - # On a key press, generate both the mouse down and up event. - for event_type in [MouseEventType.MOUSE_DOWN, MouseEventType.MOUSE_UP]: - data = ';'.join([ - event_type, - str(ev.MousePosition.X), - str(ev.MousePosition.Y) - ]) - result.append(KeyPress(Keys.WindowsMouseEvent, data)) - - return result - - -class raw_mode(object): - """ - :: - - with raw_mode(stdin): - ''' the windows terminal is now in 'raw' mode. ''' - - The ``fileno`` attribute is ignored. This is to be compatble with the - `raw_input` method of `.vt100_input`. - """ - def __init__(self, fileno=None): - self.handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)) - - def __enter__(self): - # Remember original mode. - original_mode = DWORD() - windll.kernel32.GetConsoleMode(self.handle, pointer(original_mode)) - self.original_mode = original_mode - - self._patch() - - def _patch(self): - # Set raw - ENABLE_ECHO_INPUT = 0x0004 - ENABLE_LINE_INPUT = 0x0002 - ENABLE_PROCESSED_INPUT = 0x0001 - - windll.kernel32.SetConsoleMode( - self.handle, self.original_mode.value & - ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)) - - def __exit__(self, *a, **kw): - # Restore original mode - windll.kernel32.SetConsoleMode(self.handle, self.original_mode) - - -class cooked_mode(raw_mode): - """ - :: - - with cooked_mode(stdin): - ''' the pseudo-terminal stdin is now used in raw mode ''' - """ - def _patch(self): - # Set cooked. - ENABLE_ECHO_INPUT = 0x0004 - ENABLE_LINE_INPUT = 0x0002 - ENABLE_PROCESSED_INPUT = 0x0001 - - windll.kernel32.SetConsoleMode( - self.handle, self.original_mode.value | - (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py deleted file mode 100644 index d4dddbab42..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py +++ /dev/null @@ -1,556 +0,0 @@ -from __future__ import unicode_literals - -from ctypes import windll, byref, ArgumentError, c_char, c_long, c_ulong, c_uint, pointer -from ctypes.wintypes import DWORD, HANDLE - -from prompt_toolkit.renderer import Output -from prompt_toolkit.styles import ANSI_COLOR_NAMES -from prompt_toolkit.win32_types import CONSOLE_SCREEN_BUFFER_INFO, STD_OUTPUT_HANDLE, STD_INPUT_HANDLE, COORD, SMALL_RECT - -import os -import six - -__all__ = ( - 'Win32Output', -) - - -def _coord_byval(coord): - """ - Turns a COORD object into a c_long. - This will cause it to be passed by value instead of by reference. (That is what I think at least.) - - When runing ``ptipython`` is run (only with IPython), we often got the following error:: - - Error in 'SetConsoleCursorPosition'. - ArgumentError("argument 2: <class 'TypeError'>: wrong type",) - argument 2: <class 'TypeError'>: wrong type - - It was solved by turning ``COORD`` parameters into a ``c_long`` like this. - - More info: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx - """ - return c_long(coord.Y * 0x10000 | coord.X & 0xFFFF) - - -#: If True: write the output of the renderer also to the following file. This -#: is very useful for debugging. (e.g.: to see that we don't write more bytes -#: than required.) -_DEBUG_RENDER_OUTPUT = False -_DEBUG_RENDER_OUTPUT_FILENAME = r'prompt-toolkit-windows-output.log' - - -class NoConsoleScreenBufferError(Exception): - """ - Raised when the application is not running inside a Windows Console, but - the user tries to instantiate Win32Output. - """ - def __init__(self): - # Are we running in 'xterm' on Windows, like git-bash for instance? - xterm = 'xterm' in os.environ.get('TERM', '') - - if xterm: - message = ('Found %s, while expecting a Windows console. ' - 'Maybe try to run this program using "winpty" ' - 'or run it in cmd.exe instead. Or otherwise, ' - 'in case of Cygwin, use the Python executable ' - 'that is compiled for Cygwin.' % os.environ['TERM']) - else: - message = 'No Windows console found. Are you running cmd.exe?' - super(NoConsoleScreenBufferError, self).__init__(message) - - -class Win32Output(Output): - """ - I/O abstraction for rendering to Windows consoles. - (cmd.exe and similar.) - """ - def __init__(self, stdout, use_complete_width=False): - self.use_complete_width = use_complete_width - - self._buffer = [] - self.stdout = stdout - self.hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)) - - self._in_alternate_screen = False - - self.color_lookup_table = ColorLookupTable() - - # Remember the default console colors. - info = self.get_win32_screen_buffer_info() - self.default_attrs = info.wAttributes if info else 15 - - if _DEBUG_RENDER_OUTPUT: - self.LOG = open(_DEBUG_RENDER_OUTPUT_FILENAME, 'ab') - - def fileno(self): - " Return file descriptor. " - return self.stdout.fileno() - - def encoding(self): - " Return encoding used for stdout. " - return self.stdout.encoding - - def write(self, data): - self._buffer.append(data) - - def write_raw(self, data): - " For win32, there is no difference between write and write_raw. " - self.write(data) - - def get_size(self): - from prompt_toolkit.layout.screen import Size - info = self.get_win32_screen_buffer_info() - - # We take the width of the *visible* region as the size. Not the width - # of the complete screen buffer. (Unless use_complete_width has been - # set.) - if self.use_complete_width: - width = info.dwSize.X - else: - width = info.srWindow.Right - info.srWindow.Left - - height = info.srWindow.Bottom - info.srWindow.Top + 1 - - # We avoid the right margin, windows will wrap otherwise. - maxwidth = info.dwSize.X - 1 - width = min(maxwidth, width) - - # Create `Size` object. - return Size(rows=height, columns=width) - - def _winapi(self, func, *a, **kw): - """ - Flush and call win API function. - """ - self.flush() - - if _DEBUG_RENDER_OUTPUT: - self.LOG.write(('%r' % func.__name__).encode('utf-8') + b'\n') - self.LOG.write(b' ' + ', '.join(['%r' % i for i in a]).encode('utf-8') + b'\n') - self.LOG.write(b' ' + ', '.join(['%r' % type(i) for i in a]).encode('utf-8') + b'\n') - self.LOG.flush() - - try: - return func(*a, **kw) - except ArgumentError as e: - if _DEBUG_RENDER_OUTPUT: - self.LOG.write((' Error in %r %r %s\n' % (func.__name__, e, e)).encode('utf-8')) - - def get_win32_screen_buffer_info(self): - """ - Return Screen buffer info. - """ - # NOTE: We don't call the `GetConsoleScreenBufferInfo` API through - # `self._winapi`. Doing so causes Python to crash on certain 64bit - # Python versions. (Reproduced with 64bit Python 2.7.6, on Windows - # 10). It is not clear why. Possibly, it has to do with passing - # these objects as an argument, or through *args. - - # The Python documentation contains the following - possibly related - warning: - # ctypes does not support passing unions or structures with - # bit-fields to functions by value. While this may work on 32-bit - # x86, it's not guaranteed by the library to work in the general - # case. Unions and structures with bit-fields should always be - # passed to functions by pointer. - - # Also see: - # - https://github.com/ipython/ipython/issues/10070 - # - https://github.com/jonathanslenders/python-prompt-toolkit/issues/406 - # - https://github.com/jonathanslenders/python-prompt-toolkit/issues/86 - - self.flush() - sbinfo = CONSOLE_SCREEN_BUFFER_INFO() - success = windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo)) - - # success = self._winapi(windll.kernel32.GetConsoleScreenBufferInfo, - # self.hconsole, byref(sbinfo)) - - if success: - return sbinfo - else: - raise NoConsoleScreenBufferError - - def set_title(self, title): - """ - Set terminal title. - """ - assert isinstance(title, six.text_type) - self._winapi(windll.kernel32.SetConsoleTitleW, title) - - def clear_title(self): - self._winapi(windll.kernel32.SetConsoleTitleW, '') - - def erase_screen(self): - start = COORD(0, 0) - sbinfo = self.get_win32_screen_buffer_info() - length = sbinfo.dwSize.X * sbinfo.dwSize.Y - - self.cursor_goto(row=0, column=0) - self._erase(start, length) - - def erase_down(self): - sbinfo = self.get_win32_screen_buffer_info() - size = sbinfo.dwSize - - start = sbinfo.dwCursorPosition - length = ((size.X - size.X) + size.X * (size.Y - sbinfo.dwCursorPosition.Y)) - - self._erase(start, length) - - def erase_end_of_line(self): - """ - """ - sbinfo = self.get_win32_screen_buffer_info() - start = sbinfo.dwCursorPosition - length = sbinfo.dwSize.X - sbinfo.dwCursorPosition.X - - self._erase(start, length) - - def _erase(self, start, length): - chars_written = c_ulong() - - self._winapi(windll.kernel32.FillConsoleOutputCharacterA, - self.hconsole, c_char(b' '), DWORD(length), _coord_byval(start), - byref(chars_written)) - - # Reset attributes. - sbinfo = self.get_win32_screen_buffer_info() - self._winapi(windll.kernel32.FillConsoleOutputAttribute, - self.hconsole, sbinfo.wAttributes, length, _coord_byval(start), - byref(chars_written)) - - def reset_attributes(self): - " Reset the console foreground/background color. " - self._winapi(windll.kernel32.SetConsoleTextAttribute, self.hconsole, - self.default_attrs) - - def set_attributes(self, attrs): - fgcolor, bgcolor, bold, underline, italic, blink, reverse = attrs - - # Start from the default attributes. - attrs = self.default_attrs - - # Override the last four bits: foreground color. - if fgcolor is not None: - attrs = attrs & ~0xf - attrs |= self.color_lookup_table.lookup_fg_color(fgcolor) - - # Override the next four bits: background color. - if bgcolor is not None: - attrs = attrs & ~0xf0 - attrs |= self.color_lookup_table.lookup_bg_color(bgcolor) - - # Reverse: swap these four bits groups. - if reverse: - attrs = (attrs & ~0xff) | ((attrs & 0xf) << 4) | ((attrs & 0xf0) >> 4) - - self._winapi(windll.kernel32.SetConsoleTextAttribute, self.hconsole, attrs) - - def disable_autowrap(self): - # Not supported by Windows. - pass - - def enable_autowrap(self): - # Not supported by Windows. - pass - - def cursor_goto(self, row=0, column=0): - pos = COORD(x=column, y=row) - self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)) - - def cursor_up(self, amount): - sr = self.get_win32_screen_buffer_info().dwCursorPosition - pos = COORD(sr.X, sr.Y - amount) - self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)) - - def cursor_down(self, amount): - self.cursor_up(-amount) - - def cursor_forward(self, amount): - sr = self.get_win32_screen_buffer_info().dwCursorPosition -# assert sr.X + amount >= 0, 'Negative cursor position: x=%r amount=%r' % (sr.X, amount) - - pos = COORD(max(0, sr.X + amount), sr.Y) - self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)) - - def cursor_backward(self, amount): - self.cursor_forward(-amount) - - def flush(self): - """ - Write to output stream and flush. - """ - if not self._buffer: - # Only flush stdout buffer. (It could be that Python still has - # something in its buffer. -- We want to be sure to print that in - # the correct color.) - self.stdout.flush() - return - - data = ''.join(self._buffer) - - if _DEBUG_RENDER_OUTPUT: - self.LOG.write(('%r' % data).encode('utf-8') + b'\n') - self.LOG.flush() - - # Print characters one by one. This appears to be the best soluton - # in oder to avoid traces of vertical lines when the completion - # menu disappears. - for b in data: - written = DWORD() - - retval = windll.kernel32.WriteConsoleW(self.hconsole, b, 1, byref(written), None) - assert retval != 0 - - self._buffer = [] - - def get_rows_below_cursor_position(self): - info = self.get_win32_screen_buffer_info() - return info.srWindow.Bottom - info.dwCursorPosition.Y + 1 - - def scroll_buffer_to_prompt(self): - """ - To be called before drawing the prompt. This should scroll the console - to left, with the cursor at the bottom (if possible). - """ - # Get current window size - info = self.get_win32_screen_buffer_info() - sr = info.srWindow - cursor_pos = info.dwCursorPosition - - result = SMALL_RECT() - - # Scroll to the left. - result.Left = 0 - result.Right = sr.Right - sr.Left - - # Scroll vertical - win_height = sr.Bottom - sr.Top - if 0 < sr.Bottom - cursor_pos.Y < win_height - 1: - # no vertical scroll if cursor already on the screen - result.Bottom = sr.Bottom - else: - result.Bottom = max(win_height, cursor_pos.Y) - result.Top = result.Bottom - win_height - - # Scroll API - self._winapi(windll.kernel32.SetConsoleWindowInfo, self.hconsole, True, byref(result)) - - def enter_alternate_screen(self): - """ - Go to alternate screen buffer. - """ - if not self._in_alternate_screen: - GENERIC_READ = 0x80000000 - GENERIC_WRITE = 0x40000000 - - # Create a new console buffer and activate that one. - handle = HANDLE(self._winapi(windll.kernel32.CreateConsoleScreenBuffer, GENERIC_READ|GENERIC_WRITE, - DWORD(0), None, DWORD(1), None)) - - self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, handle) - self.hconsole = handle - self._in_alternate_screen = True - - def quit_alternate_screen(self): - """ - Make stdout again the active buffer. - """ - if self._in_alternate_screen: - stdout = HANDLE(self._winapi(windll.kernel32.GetStdHandle, STD_OUTPUT_HANDLE)) - self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, stdout) - self._winapi(windll.kernel32.CloseHandle, self.hconsole) - self.hconsole = stdout - self._in_alternate_screen = False - - def enable_mouse_support(self): - ENABLE_MOUSE_INPUT = 0x10 - handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)) - - original_mode = DWORD() - self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode)) - self._winapi(windll.kernel32.SetConsoleMode, handle, original_mode.value | ENABLE_MOUSE_INPUT) - - def disable_mouse_support(self): - ENABLE_MOUSE_INPUT = 0x10 - handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)) - - original_mode = DWORD() - self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode)) - self._winapi(windll.kernel32.SetConsoleMode, handle, original_mode.value & ~ ENABLE_MOUSE_INPUT) - - def hide_cursor(self): - pass - - def show_cursor(self): - pass - - @classmethod - def win32_refresh_window(cls): - """ - Call win32 API to refresh the whole Window. - - This is sometimes necessary when the application paints background - for completion menus. When the menu disappears, it leaves traces due - to a bug in the Windows Console. Sending a repaint request solves it. - """ - # Get console handle - handle = HANDLE(windll.kernel32.GetConsoleWindow()) - - RDW_INVALIDATE = 0x0001 - windll.user32.RedrawWindow(handle, None, None, c_uint(RDW_INVALIDATE)) - - -class FOREGROUND_COLOR: - BLACK = 0x0000 - BLUE = 0x0001 - GREEN = 0x0002 - CYAN = 0x0003 - RED = 0x0004 - MAGENTA = 0x0005 - YELLOW = 0x0006 - GRAY = 0x0007 - INTENSITY = 0x0008 # Foreground color is intensified. - - -class BACKROUND_COLOR: - BLACK = 0x0000 - BLUE = 0x0010 - GREEN = 0x0020 - CYAN = 0x0030 - RED = 0x0040 - MAGENTA = 0x0050 - YELLOW = 0x0060 - GRAY = 0x0070 - INTENSITY = 0x0080 # Background color is intensified. - - -def _create_ansi_color_dict(color_cls): - " Create a table that maps the 16 named ansi colors to their Windows code. " - return { - 'ansidefault': color_cls.BLACK, - 'ansiblack': color_cls.BLACK, - 'ansidarkgray': color_cls.BLACK | color_cls.INTENSITY, - 'ansilightgray': color_cls.GRAY, - 'ansiwhite': color_cls.GRAY | color_cls.INTENSITY, - - # Low intensity. - 'ansidarkred': color_cls.RED, - 'ansidarkgreen': color_cls.GREEN, - 'ansibrown': color_cls.YELLOW, - 'ansidarkblue': color_cls.BLUE, - 'ansipurple': color_cls.MAGENTA, - 'ansiteal': color_cls.CYAN, - - # High intensity. - 'ansired': color_cls.RED | color_cls.INTENSITY, - 'ansigreen': color_cls.GREEN | color_cls.INTENSITY, - 'ansiyellow': color_cls.YELLOW | color_cls.INTENSITY, - 'ansiblue': color_cls.BLUE | color_cls.INTENSITY, - 'ansifuchsia': color_cls.MAGENTA | color_cls.INTENSITY, - 'ansiturquoise': color_cls.CYAN | color_cls.INTENSITY, - } - -FG_ANSI_COLORS = _create_ansi_color_dict(FOREGROUND_COLOR) -BG_ANSI_COLORS = _create_ansi_color_dict(BACKROUND_COLOR) - -assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES) -assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES) - - -class ColorLookupTable(object): - """ - Inspired by pygments/formatters/terminal256.py - """ - def __init__(self): - self._win32_colors = self._build_color_table() - self.best_match = {} # Cache - - @staticmethod - def _build_color_table(): - """ - Build an RGB-to-256 color conversion table - """ - FG = FOREGROUND_COLOR - BG = BACKROUND_COLOR - - return [ - (0x00, 0x00, 0x00, FG.BLACK, BG.BLACK), - (0x00, 0x00, 0xaa, FG.BLUE, BG.BLUE), - (0x00, 0xaa, 0x00, FG.GREEN, BG.GREEN), - (0x00, 0xaa, 0xaa, FG.CYAN, BG.CYAN), - (0xaa, 0x00, 0x00, FG.RED, BG.RED), - (0xaa, 0x00, 0xaa, FG.MAGENTA, BG.MAGENTA), - (0xaa, 0xaa, 0x00, FG.YELLOW, BG.YELLOW), - (0x88, 0x88, 0x88, FG.GRAY, BG.GRAY), - - (0x44, 0x44, 0xff, FG.BLUE | FG.INTENSITY, BG.BLUE | BG.INTENSITY), - (0x44, 0xff, 0x44, FG.GREEN | FG.INTENSITY, BG.GREEN | BG.INTENSITY), - (0x44, 0xff, 0xff, FG.CYAN | FG.INTENSITY, BG.CYAN | BG.INTENSITY), - (0xff, 0x44, 0x44, FG.RED | FG.INTENSITY, BG.RED | BG.INTENSITY), - (0xff, 0x44, 0xff, FG.MAGENTA | FG.INTENSITY, BG.MAGENTA | BG.INTENSITY), - (0xff, 0xff, 0x44, FG.YELLOW | FG.INTENSITY, BG.YELLOW | BG.INTENSITY), - - (0x44, 0x44, 0x44, FG.BLACK | FG.INTENSITY, BG.BLACK | BG.INTENSITY), - (0xff, 0xff, 0xff, FG.GRAY | FG.INTENSITY, BG.GRAY | BG.INTENSITY), - ] - - def _closest_color(self, r, g, b): - distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff) - fg_match = 0 - bg_match = 0 - - for r_, g_, b_, fg_, bg_ in self._win32_colors: - rd = r - r_ - gd = g - g_ - bd = b - b_ - - d = rd * rd + gd * gd + bd * bd - - if d < distance: - fg_match = fg_ - bg_match = bg_ - distance = d - return fg_match, bg_match - - def _color_indexes(self, color): - indexes = self.best_match.get(color, None) - if indexes is None: - try: - rgb = int(str(color), 16) - except ValueError: - rgb = 0 - - r = (rgb >> 16) & 0xff - g = (rgb >> 8) & 0xff - b = rgb & 0xff - indexes = self._closest_color(r, g, b) - self.best_match[color] = indexes - return indexes - - def lookup_fg_color(self, fg_color): - """ - Return the color for use in the - `windll.kernel32.SetConsoleTextAttribute` API call. - - :param fg_color: Foreground as text. E.g. 'ffffff' or 'red' - """ - # Foreground. - if fg_color in FG_ANSI_COLORS: - return FG_ANSI_COLORS[fg_color] - else: - return self._color_indexes(fg_color)[0] - - def lookup_bg_color(self, bg_color): - """ - Return the color for use in the - `windll.kernel32.SetConsoleTextAttribute` API call. - - :param bg_color: Background as text. E.g. 'ffffff' or 'red' - """ - # Background. - if bg_color in BG_ANSI_COLORS: - return BG_ANSI_COLORS[bg_color] - else: - return self._color_indexes(bg_color)[1] diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/token.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/token.py deleted file mode 100644 index 5170daf38a..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/token.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -The Token class, interchangeable with ``pygments.token``. - -A `Token` has some semantics for a piece of text that is given a style through -a :class:`~prompt_toolkit.styles.Style` class. A pygments lexer for instance, -returns a list of (Token, text) tuples. Each fragment of text has a token -assigned, which when combined with a style sheet, will determine the fine -style. -""" - -# If we don't need any lexers or style classes from Pygments, we don't want -# Pygments to be installed for only the following 10 lines of code. So, there -# is some duplication, but this should stay compatible with Pygments. - -__all__ = ( - 'Token', - 'ZeroWidthEscape', -) - - -class _TokenType(tuple): - def __getattr__(self, val): - if not val or not val[0].isupper(): - return tuple.__getattribute__(self, val) - - new = _TokenType(self + (val,)) - setattr(self, val, new) - return new - - def __repr__(self): - return 'Token' + (self and '.' or '') + '.'.join(self) - - -# Prefer the Token class from Pygments. If Pygments is not installed, use our -# minimalistic Token class. -try: - from pygments.token import Token -except ImportError: - Token = _TokenType() - - -# Built-in tokens: - -#: `ZeroWidthEscape` can be used for raw VT escape sequences that don't -#: cause the cursor position to move. (E.g. FinalTerm's escape sequences -#: for shell integration.) -ZeroWidthEscape = Token.ZeroWidthEscape diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py deleted file mode 100644 index 3cd931883c..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py +++ /dev/null @@ -1,240 +0,0 @@ -from __future__ import unicode_literals -import inspect -import os -import signal -import sys -import threading -import weakref - -from wcwidth import wcwidth -from six.moves import range - - -__all__ = ( - 'Event', - 'DummyContext', - 'get_cwidth', - 'suspend_to_background_supported', - 'is_conemu_ansi', - 'is_windows', - 'in_main_thread', - 'take_using_weights', - 'test_callable_args', -) - - -class Event(object): - """ - Simple event to which event handlers can be attached. For instance:: - - class Cls: - def __init__(self): - # Define event. The first parameter is the sender. - self.event = Event(self) - - obj = Cls() - - def handler(sender): - pass - - # Add event handler by using the += operator. - obj.event += handler - - # Fire event. - obj.event() - """ - def __init__(self, sender, handler=None): - self.sender = sender - self._handlers = [] - - if handler is not None: - self += handler - - def __call__(self): - " Fire event. " - for handler in self._handlers: - handler(self.sender) - - def fire(self): - " Alias for just calling the event. " - self() - - def __iadd__(self, handler): - """ - Add another handler to this callback. - (Handler should be a callable that takes exactly one parameter: the - sender object.) - """ - # Test handler. - assert callable(handler) - if not test_callable_args(handler, [None]): - raise TypeError("%r doesn't take exactly one argument." % handler) - - # Add to list of event handlers. - self._handlers.append(handler) - return self - - def __isub__(self, handler): - """ - Remove a handler from this callback. - """ - self._handlers.remove(handler) - return self - - -# Cache of signatures. Improves the performance of `test_callable_args`. -_signatures_cache = weakref.WeakKeyDictionary() - - -def test_callable_args(func, args): - """ - Return True when this function can be called with the given arguments. - """ - assert isinstance(args, (list, tuple)) - signature = getattr(inspect, 'signature', None) - - if signature is not None: - # For Python 3, use inspect.signature. - try: - sig = _signatures_cache[func] - except KeyError: - sig = signature(func) - _signatures_cache[func] = sig - - try: - sig.bind(*args) - except TypeError: - return False - else: - return True - else: - # For older Python versions, fall back to using getargspec. - spec = inspect.getargspec(func) - - # Drop the 'self' - def drop_self(spec): - args, varargs, varkw, defaults = spec - if args[0:1] == ['self']: - args = args[1:] - return inspect.ArgSpec(args, varargs, varkw, defaults) - - spec = drop_self(spec) - - # When taking *args, always return True. - if spec.varargs is not None: - return True - - # Test whether the given amount of args is between the min and max - # accepted argument counts. - return len(spec.args) - len(spec.defaults or []) <= len(args) <= len(spec.args) - - -class DummyContext(object): - """ - (contextlib.nested is not available on Py3) - """ - def __enter__(self): - pass - - def __exit__(self, *a): - pass - - -class _CharSizesCache(dict): - """ - Cache for wcwidth sizes. - """ - def __missing__(self, string): - # Note: We use the `max(0, ...` because some non printable control - # characters, like e.g. Ctrl-underscore get a -1 wcwidth value. - # It can be possible that these characters end up in the input - # text. - if len(string) == 1: - result = max(0, wcwidth(string)) - else: - result = sum(max(0, wcwidth(c)) for c in string) - - # Cache for short strings. - # (It's hard to tell what we can consider short...) - if len(string) < 256: - self[string] = result - - return result - - -_CHAR_SIZES_CACHE = _CharSizesCache() - - -def get_cwidth(string): - """ - Return width of a string. Wrapper around ``wcwidth``. - """ - return _CHAR_SIZES_CACHE[string] - - -def suspend_to_background_supported(): - """ - Returns `True` when the Python implementation supports - suspend-to-background. This is typically `False' on Windows systems. - """ - return hasattr(signal, 'SIGTSTP') - - -def is_windows(): - """ - True when we are using Windows. - """ - return sys.platform.startswith('win') # E.g. 'win32', not 'darwin' or 'linux2' - - -def is_conemu_ansi(): - """ - True when the ConEmu Windows console is used. - """ - return is_windows() and os.environ.get('ConEmuANSI', 'OFF') == 'ON' - - -def in_main_thread(): - """ - True when the current thread is the main thread. - """ - return threading.current_thread().__class__.__name__ == '_MainThread' - - -def take_using_weights(items, weights): - """ - Generator that keeps yielding items from the items list, in proportion to - their weight. For instance:: - - # Getting the first 70 items from this generator should have yielded 10 - # times A, 20 times B and 40 times C, all distributed equally.. - take_using_weights(['A', 'B', 'C'], [5, 10, 20]) - - :param items: List of items to take from. - :param weights: Integers representing the weight. (Numbers have to be - integers, not floats.) - """ - assert isinstance(items, list) - assert isinstance(weights, list) - assert all(isinstance(i, int) for i in weights) - assert len(items) == len(weights) - assert len(items) > 0 - - already_taken = [0 for i in items] - item_count = len(items) - max_weight = max(weights) - - i = 0 - while True: - # Each iteration of this loop, we fill up until by (total_weight/max_weight). - adding = True - while adding: - adding = False - - for item_i, item, weight in zip(range(item_count), items, weights): - if already_taken[item_i] < i * weight / float(max_weight): - yield item - already_taken[item_i] += 1 - adding = True - - i += 1 diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py deleted file mode 100644 index 0027873f88..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Input validation for a `Buffer`. -(Validators will be called before accepting input.) -""" -from __future__ import unicode_literals -from .filters import to_simple_filter - -from abc import ABCMeta, abstractmethod -from six import with_metaclass - -__all__ = ( - 'ConditionalValidator', - 'ValidationError', - 'Validator', -) - - -class ValidationError(Exception): - """ - Error raised by :meth:`.Validator.validate`. - - :param cursor_position: The cursor position where the error occured. - :param message: Text. - """ - def __init__(self, cursor_position=0, message=''): - super(ValidationError, self).__init__(message) - self.cursor_position = cursor_position - self.message = message - - def __repr__(self): - return '%s(cursor_position=%r, message=%r)' % ( - self.__class__.__name__, self.cursor_position, self.message) - - -class Validator(with_metaclass(ABCMeta, object)): - """ - Abstract base class for an input validator. - """ - @abstractmethod - def validate(self, document): - """ - Validate the input. - If invalid, this should raise a :class:`.ValidationError`. - - :param document: :class:`~prompt_toolkit.document.Document` instance. - """ - pass - - -class ConditionalValidator(Validator): - """ - Validator that can be switched on/off according to - a filter. (This wraps around another validator.) - """ - def __init__(self, validator, filter): - assert isinstance(validator, Validator) - - self.validator = validator - self.filter = to_simple_filter(filter) - - def validate(self, document): - # Call the validator only if the filter is active. - if self.filter(): - self.validator.validate(document) diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py deleted file mode 100644 index ba2d90df8e..0000000000 --- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py +++ /dev/null @@ -1,155 +0,0 @@ -from ctypes import Union, Structure, c_char, c_short, c_long, c_ulong -from ctypes.wintypes import DWORD, BOOL, LPVOID, WORD, WCHAR - - -# Input/Output standard device numbers. Note that these are not handle objects. -# It's the `windll.kernel32.GetStdHandle` system call that turns them into a -# real handle object. -STD_INPUT_HANDLE = c_ulong(-10) -STD_OUTPUT_HANDLE = c_ulong(-11) -STD_ERROR_HANDLE = c_ulong(-12) - - -class COORD(Structure): - """ - Struct in wincon.h - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx - """ - _fields_ = [ - ('X', c_short), # Short - ('Y', c_short), # Short - ] - - def __repr__(self): - return '%s(X=%r, Y=%r, type_x=%r, type_y=%r)' % ( - self.__class__.__name__, self.X, self.Y, type(self.X), type(self.Y)) - - -class UNICODE_OR_ASCII(Union): - _fields_ = [ - ('AsciiChar', c_char), - ('UnicodeChar', WCHAR), - ] - - -class KEY_EVENT_RECORD(Structure): - """ - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684166(v=vs.85).aspx - """ - _fields_ = [ - ('KeyDown', c_long), # bool - ('RepeatCount', c_short), # word - ('VirtualKeyCode', c_short), # word - ('VirtualScanCode', c_short), # word - ('uChar', UNICODE_OR_ASCII), # Unicode or ASCII. - ('ControlKeyState', c_long) # double word - ] - - -class MOUSE_EVENT_RECORD(Structure): - """ - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684239(v=vs.85).aspx - """ - _fields_ = [ - ('MousePosition', COORD), - ('ButtonState', c_long), # dword - ('ControlKeyState', c_long), # dword - ('EventFlags', c_long) # dword - ] - - -class WINDOW_BUFFER_SIZE_RECORD(Structure): - """ - http://msdn.microsoft.com/en-us/library/windows/desktop/ms687093(v=vs.85).aspx - """ - _fields_ = [ - ('Size', COORD) - ] - - -class MENU_EVENT_RECORD(Structure): - """ - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684213(v=vs.85).aspx - """ - _fields_ = [ - ('CommandId', c_long) # uint - ] - - -class FOCUS_EVENT_RECORD(Structure): - """ - http://msdn.microsoft.com/en-us/library/windows/desktop/ms683149(v=vs.85).aspx - """ - _fields_ = [ - ('SetFocus', c_long) # bool - ] - - -class EVENT_RECORD(Union): - _fields_ = [ - ('KeyEvent', KEY_EVENT_RECORD), - ('MouseEvent', MOUSE_EVENT_RECORD), - ('WindowBufferSizeEvent', WINDOW_BUFFER_SIZE_RECORD), - ('MenuEvent', MENU_EVENT_RECORD), - ('FocusEvent', FOCUS_EVENT_RECORD) - ] - - -class INPUT_RECORD(Structure): - """ - http://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx - """ - _fields_ = [ - ('EventType', c_short), # word - ('Event', EVENT_RECORD) # Union. - ] - - -EventTypes = { - 1: 'KeyEvent', - 2: 'MouseEvent', - 4: 'WindowBufferSizeEvent', - 8: 'MenuEvent', - 16: 'FocusEvent' -} - - -class SMALL_RECT(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("Left", c_short), - ("Top", c_short), - ("Right", c_short), - ("Bottom", c_short), - ] - - -class CONSOLE_SCREEN_BUFFER_INFO(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("dwSize", COORD), - ("dwCursorPosition", COORD), - ("wAttributes", WORD), - ("srWindow", SMALL_RECT), - ("dwMaximumWindowSize", COORD), - ] - - def __str__(self): - return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( - self.dwSize.Y, self.dwSize.X, - self.dwCursorPosition.Y, self.dwCursorPosition.X, - self.wAttributes, - self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right, - self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X, - ) - - -class SECURITY_ATTRIBUTES(Structure): - """ - http://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx - """ - _fields_ = [ - ('nLength', DWORD), - ('lpSecurityDescriptor', LPVOID), - ('bInheritHandle', BOOL), - ] diff --git a/contrib/python/prompt-toolkit/py2/tests/test_buffer.py b/contrib/python/prompt-toolkit/py2/tests/test_buffer.py deleted file mode 100644 index a9cff19024..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_buffer.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.buffer import Buffer - -import pytest - - -@pytest.fixture -def _buffer(): - return Buffer() - - -def test_initial(_buffer): - assert _buffer.text == '' - assert _buffer.cursor_position == 0 - - -def test_insert_text(_buffer): - _buffer.insert_text('some_text') - assert _buffer.text == 'some_text' - assert _buffer.cursor_position == len('some_text') - - -def test_cursor_movement(_buffer): - _buffer.insert_text('some_text') - _buffer.cursor_left() - _buffer.cursor_left() - _buffer.cursor_left() - _buffer.cursor_right() - _buffer.insert_text('A') - - assert _buffer.text == 'some_teAxt' - assert _buffer.cursor_position == len('some_teA') - - -def test_backspace(_buffer): - _buffer.insert_text('some_text') - _buffer.cursor_left() - _buffer.cursor_left() - _buffer.delete_before_cursor() - - assert _buffer.text == 'some_txt' - assert _buffer.cursor_position == len('some_t') - - -def test_cursor_up(_buffer): - # Cursor up to a line thats longer. - _buffer.insert_text('long line1\nline2') - _buffer.cursor_up() - - assert _buffer.document.cursor_position == 5 - - # Going up when already at the top. - _buffer.cursor_up() - assert _buffer.document.cursor_position == 5 - - # Going up to a line that's shorter. - _buffer.reset() - _buffer.insert_text('line1\nlong line2') - - _buffer.cursor_up() - assert _buffer.document.cursor_position == 5 - - -def test_cursor_down(_buffer): - _buffer.insert_text('line1\nline2') - _buffer.cursor_position = 3 - - # Normally going down - _buffer.cursor_down() - assert _buffer.document.cursor_position == len('line1\nlin') - - # Going down to a line that's storter. - _buffer.reset() - _buffer.insert_text('long line1\na\nb') - _buffer.cursor_position = 3 - - _buffer.cursor_down() - assert _buffer.document.cursor_position == len('long line1\na') - - -def test_join_next_line(_buffer): - _buffer.insert_text('line1\nline2\nline3') - _buffer.cursor_up() - _buffer.join_next_line() - - assert _buffer.text == 'line1\nline2 line3' - - # Test when there is no '\n' in the text - _buffer.reset() - _buffer.insert_text('line1') - _buffer.cursor_position = 0 - _buffer.join_next_line() - - assert _buffer.text == 'line1' - - -def test_newline(_buffer): - _buffer.insert_text('hello world') - _buffer.newline() - - assert _buffer.text == 'hello world\n' - - -def test_swap_characters_before_cursor(_buffer): - _buffer.insert_text('hello world') - _buffer.cursor_left() - _buffer.cursor_left() - _buffer.swap_characters_before_cursor() - - assert _buffer.text == 'hello wrold' diff --git a/contrib/python/prompt-toolkit/py2/tests/test_cli.py b/contrib/python/prompt-toolkit/py2/tests/test_cli.py deleted file mode 100644 index 68ca3d03f0..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_cli.py +++ /dev/null @@ -1,629 +0,0 @@ -# encoding: utf-8 -""" -These are almost end-to-end tests. They create a CommandLineInterface -instance, feed it with some input and check the result. -""" -from __future__ import unicode_literals -from prompt_toolkit.application import Application -from prompt_toolkit.buffer import Buffer, AcceptAction -from prompt_toolkit.clipboard import InMemoryClipboard, ClipboardData -from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode -from prompt_toolkit.eventloop.posix import PosixEventLoop -from prompt_toolkit.history import InMemoryHistory -from prompt_toolkit.input import PipeInput -from prompt_toolkit.interface import CommandLineInterface -from prompt_toolkit.key_binding.manager import KeyBindingManager -from prompt_toolkit.output import DummyOutput -from prompt_toolkit.terminal.vt100_input import ANSI_SEQUENCES -from functools import partial -import pytest - - -def _history(): - h = InMemoryHistory() - h.append('line1 first input') - h.append('line2 second input') - h.append('line3 third input') - return h - - -def _feed_cli_with_input(text, editing_mode=EditingMode.EMACS, clipboard=None, - history=None, multiline=False, check_line_ending=True, - pre_run_callback=None): - """ - Create a CommandLineInterface, feed it with the given user input and return - the CLI object. - - This returns a (result, CLI) tuple. - """ - # If the given text doesn't end with a newline, the interface won't finish. - if check_line_ending: - assert text.endswith('\n') - - loop = PosixEventLoop() - try: - inp = PipeInput() - inp.send_text(text) - cli = CommandLineInterface( - application=Application( - buffer=Buffer(accept_action=AcceptAction.RETURN_DOCUMENT, - history=history, is_multiline=multiline), - editing_mode=editing_mode, - clipboard=clipboard or InMemoryClipboard(), - key_bindings_registry=KeyBindingManager.for_prompt().registry, - ), - eventloop=loop, - input=inp, - output=DummyOutput()) - - if pre_run_callback: - pre_run_callback(cli) - - result = cli.run() - return result, cli - finally: - loop.close() - inp.close() - - -def test_simple_text_input(): - # Simple text input, followed by enter. - result, cli = _feed_cli_with_input('hello\n') - assert result.text == 'hello' - assert cli.buffers[DEFAULT_BUFFER].text == 'hello' - - -def test_emacs_cursor_movements(): - """ - Test cursor movements with Emacs key bindings. - """ - # ControlA (beginning-of-line) - result, cli = _feed_cli_with_input('hello\x01X\n') - assert result.text == 'Xhello' - - # ControlE (end-of-line) - result, cli = _feed_cli_with_input('hello\x01X\x05Y\n') - assert result.text == 'XhelloY' - - # ControlH or \b - result, cli = _feed_cli_with_input('hello\x08X\n') - assert result.text == 'hellX' - - # Delete. (Left, left, delete) - result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x1b[3~\n') - assert result.text == 'helo' - - # Left. - result, cli = _feed_cli_with_input('hello\x1b[DX\n') - assert result.text == 'hellXo' - - # ControlA, right - result, cli = _feed_cli_with_input('hello\x01\x1b[CX\n') - assert result.text == 'hXello' - - # ControlA, right - result, cli = _feed_cli_with_input('hello\x01\x1b[CX\n') - assert result.text == 'hXello' - - # ControlB (backward-char) - result, cli = _feed_cli_with_input('hello\x02X\n') - assert result.text == 'hellXo' - - # ControlF (forward-char) - result, cli = _feed_cli_with_input('hello\x01\x06X\n') - assert result.text == 'hXello' - - # ControlC: raise KeyboardInterrupt. - with pytest.raises(KeyboardInterrupt): - result, cli = _feed_cli_with_input('hello\x03\n') - assert result.text == 'hello' - - # ControlD without any input: raises EOFError. - with pytest.raises(EOFError): - result, cli = _feed_cli_with_input('\x04\n') - assert result.text == 'hello' - - # ControlD: delete after cursor. - result, cli = _feed_cli_with_input('hello\x01\x04\n') - assert result.text == 'ello' - - # ControlD at the end of the input ssshould not do anything. - result, cli = _feed_cli_with_input('hello\x04\n') - assert result.text == 'hello' - - # Left, Left, ControlK (kill-line) - result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x0b\n') - assert result.text == 'hel' - - # Left, Left Esc- ControlK (kill-line, but negative) - result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x1b-\x0b\n') - assert result.text == 'lo' - - # ControlL: should not influence the result. - result, cli = _feed_cli_with_input('hello\x0c\n') - assert result.text == 'hello' - - # ControlRight (forward-word) - result, cli = _feed_cli_with_input('hello world\x01X\x1b[1;5CY\n') - assert result.text == 'XhelloY world' - - # ContrlolLeft (backward-word) - result, cli = _feed_cli_with_input('hello world\x1b[1;5DY\n') - assert result.text == 'hello Yworld' - - # <esc>-f with argument. (forward-word) - result, cli = _feed_cli_with_input('hello world abc def\x01\x1b3\x1bfX\n') - assert result.text == 'hello world abcX def' - - # <esc>-f with negative argument. (forward-word) - result, cli = _feed_cli_with_input('hello world abc def\x1b-\x1b3\x1bfX\n') - assert result.text == 'hello Xworld abc def' - - # <esc>-b with argument. (backward-word) - result, cli = _feed_cli_with_input('hello world abc def\x1b3\x1bbX\n') - assert result.text == 'hello Xworld abc def' - - # <esc>-b with negative argument. (backward-word) - result, cli = _feed_cli_with_input('hello world abc def\x01\x1b-\x1b3\x1bbX\n') - assert result.text == 'hello world abc Xdef' - - # ControlW (kill-word / unix-word-rubout) - result, cli = _feed_cli_with_input('hello world\x17\n') - assert result.text == 'hello ' - assert cli.clipboard.get_data().text == 'world' - - result, cli = _feed_cli_with_input('test hello world\x1b2\x17\n') - assert result.text == 'test ' - - # Escape Backspace (unix-word-rubout) - result, cli = _feed_cli_with_input('hello world\x1b\x7f\n') - assert result.text == 'hello ' - assert cli.clipboard.get_data().text == 'world' - - result, cli = _feed_cli_with_input('hello world\x1b\x08\n') - assert result.text == 'hello ' - assert cli.clipboard.get_data().text == 'world' - - # Backspace (backward-delete-char) - result, cli = _feed_cli_with_input('hello world\x7f\n') - assert result.text == 'hello worl' - assert result.cursor_position == len('hello worl') - - result, cli = _feed_cli_with_input('hello world\x08\n') - assert result.text == 'hello worl' - assert result.cursor_position == len('hello worl') - - # Delete (delete-char) - result, cli = _feed_cli_with_input('hello world\x01\x1b[3~\n') - assert result.text == 'ello world' - assert result.cursor_position == 0 - - # Escape-\\ (delete-horizontal-space) - result, cli = _feed_cli_with_input('hello world\x1b8\x02\x1b\\\n') - assert result.text == 'helloworld' - assert result.cursor_position == len('hello') - - -def test_emacs_yank(): - # ControlY (yank) - c = InMemoryClipboard(ClipboardData('XYZ')) - result, cli = _feed_cli_with_input('hello\x02\x19\n', clipboard=c) - assert result.text == 'hellXYZo' - assert result.cursor_position == len('hellXYZ') - - -def test_quoted_insert(): - # ControlQ - ControlB (quoted-insert) - result, cli = _feed_cli_with_input('hello\x11\x02\n') - assert result.text == 'hello\x02' - - -def test_transformations(): - # Meta-c (capitalize-word) - result, cli = _feed_cli_with_input('hello world\01\x1bc\n') - assert result.text == 'Hello world' - assert result.cursor_position == len('Hello') - - # Meta-u (uppercase-word) - result, cli = _feed_cli_with_input('hello world\01\x1bu\n') - assert result.text == 'HELLO world' - assert result.cursor_position == len('Hello') - - # Meta-u (downcase-word) - result, cli = _feed_cli_with_input('HELLO WORLD\01\x1bl\n') - assert result.text == 'hello WORLD' - assert result.cursor_position == len('Hello') - - # ControlT (transpose-chars) - result, cli = _feed_cli_with_input('hello\x14\n') - assert result.text == 'helol' - assert result.cursor_position == len('hello') - - # Left, Left, Control-T (transpose-chars) - result, cli = _feed_cli_with_input('abcde\x1b[D\x1b[D\x14\n') - assert result.text == 'abdce' - assert result.cursor_position == len('abcd') - - -def test_emacs_other_bindings(): - # Transpose characters. - result, cli = _feed_cli_with_input('abcde\x14X\n') # Ctrl-T - assert result.text == 'abcedX' - - # Left, Left, Transpose. (This is slightly different.) - result, cli = _feed_cli_with_input('abcde\x1b[D\x1b[D\x14X\n') - assert result.text == 'abdcXe' - - # Clear before cursor. - result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x15X\n') - assert result.text == 'Xlo' - - # unix-word-rubout: delete word before the cursor. - # (ControlW). - result, cli = _feed_cli_with_input('hello world test\x17X\n') - assert result.text == 'hello world X' - - result, cli = _feed_cli_with_input('hello world /some/very/long/path\x17X\n') - assert result.text == 'hello world X' - - # (with argument.) - result, cli = _feed_cli_with_input('hello world test\x1b2\x17X\n') - assert result.text == 'hello X' - - result, cli = _feed_cli_with_input('hello world /some/very/long/path\x1b2\x17X\n') - assert result.text == 'hello X' - - # backward-kill-word: delete word before the cursor. - # (Esc-ControlH). - result, cli = _feed_cli_with_input('hello world /some/very/long/path\x1b\x08X\n') - assert result.text == 'hello world /some/very/long/X' - - # (with arguments.) - result, cli = _feed_cli_with_input('hello world /some/very/long/path\x1b3\x1b\x08X\n') - assert result.text == 'hello world /some/very/X' - - -def test_controlx_controlx(): - # At the end: go to the start of the line. - result, cli = _feed_cli_with_input('hello world\x18\x18X\n') - assert result.text == 'Xhello world' - assert result.cursor_position == 1 - - # At the start: go to the end of the line. - result, cli = _feed_cli_with_input('hello world\x01\x18\x18X\n') - assert result.text == 'hello worldX' - - # Left, Left Control-X Control-X: go to the end of the line. - result, cli = _feed_cli_with_input('hello world\x1b[D\x1b[D\x18\x18X\n') - assert result.text == 'hello worldX' - - -def test_emacs_history_bindings(): - # Adding a new item to the history. - history = _history() - result, cli = _feed_cli_with_input('new input\n', history=history) - assert result.text == 'new input' - history.strings[-1] == 'new input' - - # Go up in history, and accept the last item. - result, cli = _feed_cli_with_input('hello\x1b[A\n', history=history) - assert result.text == 'new input' - - # Esc< (beginning-of-history) - result, cli = _feed_cli_with_input('hello\x1b<\n', history=history) - assert result.text == 'line1 first input' - - # Esc> (end-of-history) - result, cli = _feed_cli_with_input('another item\x1b[A\x1b[a\x1b>\n', history=history) - assert result.text == 'another item' - - # ControlUp (previous-history) - result, cli = _feed_cli_with_input('\x1b[1;5A\n', history=history) - assert result.text == 'another item' - - # Esc< ControlDown (beginning-of-history, next-history) - result, cli = _feed_cli_with_input('\x1b<\x1b[1;5B\n', history=history) - assert result.text == 'line2 second input' - - -def test_emacs_reverse_search(): - history = _history() - - # ControlR (reverse-search-history) - result, cli = _feed_cli_with_input('\x12input\n\n', history=history) - assert result.text == 'line3 third input' - - # Hitting ControlR twice. - result, cli = _feed_cli_with_input('\x12input\x12\n\n', history=history) - assert result.text == 'line2 second input' - - -def test_emacs_arguments(): - """ - Test various combinations of arguments in Emacs mode. - """ - # esc 4 - result, cli = _feed_cli_with_input('\x1b4x\n') - assert result.text == 'xxxx' - - # esc 4 4 - result, cli = _feed_cli_with_input('\x1b44x\n') - assert result.text == 'x' * 44 - - # esc 4 esc 4 - result, cli = _feed_cli_with_input('\x1b4\x1b4x\n') - assert result.text == 'x' * 44 - - # esc - right (-1 position to the right, equals 1 to the left.) - result, cli = _feed_cli_with_input('aaaa\x1b-\x1b[Cbbbb\n') - assert result.text == 'aaabbbba' - - # esc - 3 right - result, cli = _feed_cli_with_input('aaaa\x1b-3\x1b[Cbbbb\n') - assert result.text == 'abbbbaaa' - - # esc - - - 3 right - result, cli = _feed_cli_with_input('aaaa\x1b---3\x1b[Cbbbb\n') - assert result.text == 'abbbbaaa' - - -def test_emacs_arguments_for_all_commands(): - """ - Test all Emacs commands with Meta-[0-9] arguments (both positive and - negative). No one should crash. - """ - for key in ANSI_SEQUENCES: - # Ignore BracketedPaste. This would hang forever, because it waits for - # the end sequence. - if key != '\x1b[200~': - try: - # Note: we add an 'X' after the key, because Ctrl-Q (quoted-insert) - # expects something to follow. We add an additional \n, because - # Ctrl-R and Ctrl-S (reverse-search) expect that. - result, cli = _feed_cli_with_input( - 'hello\x1b4' + key + 'X\n\n') - - result, cli = _feed_cli_with_input( - 'hello\x1b-' + key + 'X\n\n') - except KeyboardInterrupt: - # This exception should only be raised for Ctrl-C - assert key == '\x03' - - -def test_emacs_kill_ring(): - operations = ( - # abc ControlA ControlK - 'abc\x01\x0b' - - # def ControlA ControlK - 'def\x01\x0b' - - # ghi ControlA ControlK - 'ghi\x01\x0b' - - # ControlY (yank) - '\x19' - ) - - result, cli = _feed_cli_with_input(operations + '\n') - assert result.text == 'ghi' - - result, cli = _feed_cli_with_input(operations + '\x1by\n') - assert result.text == 'def' - - result, cli = _feed_cli_with_input(operations + '\x1by\x1by\n') - assert result.text == 'abc' - - result, cli = _feed_cli_with_input(operations + '\x1by\x1by\x1by\n') - assert result.text == 'ghi' - - -def test_emacs_insert_comment(): - # Test insert-comment (M-#) binding. - result, cli = _feed_cli_with_input('hello\x1b#', check_line_ending=False) - assert result.text == '#hello' - - result, cli = _feed_cli_with_input( - 'hello\nworld\x1b#', check_line_ending=False, multiline=True) - assert result.text == '#hello\n#world' - - -def test_emacs_record_macro(): - operations = ( - ' ' - '\x18(' # Start recording macro. C-X( - 'hello' - '\x18)' # Stop recording macro. - ' ' - '\x18e' # Execute macro. - '\x18e' # Execute macro. - '\n' - ) - - result, cli = _feed_cli_with_input(operations) - assert result.text == ' hello hellohello' - - -def test_prefix_meta(): - # Test the prefix-meta command. - def setup_keybindings(cli): - from prompt_toolkit.key_binding.bindings.named_commands import prefix_meta - from prompt_toolkit.filters import ViInsertMode - cli.application.key_bindings_registry.add_binding('j', 'j', filter=ViInsertMode())(prefix_meta) - - result, cli = _feed_cli_with_input( - 'hellojjIX\n', pre_run_callback=setup_keybindings, editing_mode=EditingMode.VI) - assert result.text == 'Xhello' - - -def test_bracketed_paste(): - result, cli = _feed_cli_with_input('\x1b[200~hello world\x1b[201~\n') - assert result.text == 'hello world' - - result, cli = _feed_cli_with_input('\x1b[200~hello\nworld\x1b[201~\x1b\n') - assert result.text == 'hello\nworld' - - # With \r\n endings. - result, cli = _feed_cli_with_input('\x1b[200~hello\r\nworld\x1b[201~\x1b\n') - assert result.text == 'hello\nworld' - - # With \r endings. - result, cli = _feed_cli_with_input('\x1b[200~hello\rworld\x1b[201~\x1b\n') - assert result.text == 'hello\nworld' - - -def test_vi_cursor_movements(): - """ - Test cursor movements with Vi key bindings. - """ - feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI) - - result, cli = feed('\x1b\n') - assert result.text == '' - assert cli.editing_mode == EditingMode.VI - - # Esc h a X - result, cli = feed('hello\x1bhaX\n') - assert result.text == 'hellXo' - - # Esc I X - result, cli = feed('hello\x1bIX\n') - assert result.text == 'Xhello' - - # Esc I X - result, cli = feed('hello\x1bIX\n') - assert result.text == 'Xhello' - - # Esc 2hiX - result, cli = feed('hello\x1b2hiX\n') - assert result.text == 'heXllo' - - # Esc 2h2liX - result, cli = feed('hello\x1b2h2liX\n') - assert result.text == 'hellXo' - - # Esc \b\b - result, cli = feed('hello\b\b\n') - assert result.text == 'hel' - - # Esc \b\b - result, cli = feed('hello\b\b\n') - assert result.text == 'hel' - - # Esc 2h D - result, cli = feed('hello\x1b2hD\n') - assert result.text == 'he' - - # Esc 2h rX \n - result, cli = feed('hello\x1b2hrX\n') - assert result.text == 'heXlo' - - -def test_vi_operators(): - feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI) - - # Esc g~0 - result, cli = feed('hello\x1bg~0\n') - assert result.text == 'HELLo' - - # Esc gU0 - result, cli = feed('hello\x1bgU0\n') - assert result.text == 'HELLo' - - # Esc d0 - result, cli = feed('hello\x1bd0\n') - assert result.text == 'o' - - -def test_vi_text_objects(): - feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI) - - # Esc gUgg - result, cli = feed('hello\x1bgUgg\n') - assert result.text == 'HELLO' - - # Esc gUU - result, cli = feed('hello\x1bgUU\n') - assert result.text == 'HELLO' - - # Esc di( - result, cli = feed('before(inside)after\x1b8hdi(\n') - assert result.text == 'before()after' - - # Esc di[ - result, cli = feed('before[inside]after\x1b8hdi[\n') - assert result.text == 'before[]after' - - # Esc da( - result, cli = feed('before(inside)after\x1b8hda(\n') - assert result.text == 'beforeafter' - - -def test_vi_digraphs(): - feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI) - - # C-K o/ - result, cli = feed('hello\x0bo/\n') - assert result.text == 'helloø' - - # C-K /o (reversed input.) - result, cli = feed('hello\x0b/o\n') - assert result.text == 'helloø' - - # C-K e: - result, cli = feed('hello\x0be:\n') - assert result.text == 'helloë' - - # C-K xxy (Unknown digraph.) - result, cli = feed('hello\x0bxxy\n') - assert result.text == 'helloy' - - -def test_vi_block_editing(): - " Test Vi Control-V style block insertion. " - feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI, - multiline=True) - - operations = ( - # Three lines of text. - '-line1\n-line2\n-line3\n-line4\n-line5\n-line6' - # Go to the second character of the second line. - '\x1bkkkkkkkj0l' - # Enter Visual block mode. - '\x16' - # Go down two more lines. - 'jj' - # Go 3 characters to the right. - 'lll' - # Go to insert mode. - 'insert' # (Will be replaced.) - # Insert stars. - '***' - # Escape again. - '\x1b\n') - - # Control-I - result, cli = feed(operations.replace('insert', 'I')) - - assert (result.text == - '-line1\n-***line2\n-***line3\n-***line4\n-line5\n-line6') - - # Control-A - result, cli = feed(operations.replace('insert', 'A')) - - assert (result.text == - '-line1\n-line***2\n-line***3\n-line***4\n-line5\n-line6') - - -def test_vi_character_paste(): - feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI) - - # Test 'p' character paste. - result, cli = feed('abcde\x1bhhxp\n') - assert result.text == 'abdce' - assert result.cursor_position == 3 - - # Test 'P' character paste. - result, cli = feed('abcde\x1bhhxP\n') - assert result.text == 'abcde' - assert result.cursor_position == 2 diff --git a/contrib/python/prompt-toolkit/py2/tests/test_contrib.py b/contrib/python/prompt-toolkit/py2/tests/test_contrib.py deleted file mode 100644 index 64765d3f1a..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_contrib.py +++ /dev/null @@ -1,254 +0,0 @@ -from __future__ import unicode_literals, absolute_import, print_function - -import os -import shutil -import tempfile - -from contextlib import contextmanager - -from six import text_type - -from prompt_toolkit.completion import CompleteEvent -from prompt_toolkit.document import Document -from prompt_toolkit.contrib.completers.filesystem import PathCompleter - - -@contextmanager -def chdir(directory): - """Context manager for current working directory temporary change.""" - orig_dir = os.getcwd() - os.chdir(directory) - - try: - yield - finally: - os.chdir(orig_dir) - - -def write_test_files(test_dir, names=None): - """Write test files in test_dir using the names list.""" - names = names or range(10) - for i in names: - with open(os.path.join(test_dir, str(i)), 'wb') as out: - out.write(''.encode('UTF-8')) - - -def test_pathcompleter_completes_in_current_directory(): - completer = PathCompleter() - doc_text = '' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - assert len(completions) > 0 - - -def test_pathcompleter_completes_files_in_current_directory(): - # setup: create a test dir with 10 files - test_dir = tempfile.mkdtemp() - write_test_files(test_dir) - - expected = sorted([str(i) for i in range(10)]) - - if not test_dir.endswith(os.path.sep): - test_dir += os.path.sep - - with chdir(test_dir): - completer = PathCompleter() - # this should complete on the cwd - doc_text = '' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = sorted(c.text for c in completions) - assert expected == result - - # cleanup - shutil.rmtree(test_dir) - - -def test_pathcompleter_completes_files_in_absolute_directory(): - # setup: create a test dir with 10 files - test_dir = tempfile.mkdtemp() - write_test_files(test_dir) - - expected = sorted([str(i) for i in range(10)]) - - test_dir = os.path.abspath(test_dir) - if not test_dir.endswith(os.path.sep): - test_dir += os.path.sep - - completer = PathCompleter() - # force unicode - doc_text = text_type(test_dir) - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = sorted([c.text for c in completions]) - assert expected == result - - # cleanup - shutil.rmtree(test_dir) - - -def test_pathcompleter_completes_directories_with_only_directories(): - # setup: create a test dir with 10 files - test_dir = tempfile.mkdtemp() - write_test_files(test_dir) - - # create a sub directory there - os.mkdir(os.path.join(test_dir, 'subdir')) - - if not test_dir.endswith(os.path.sep): - test_dir += os.path.sep - - with chdir(test_dir): - completer = PathCompleter(only_directories=True) - doc_text = '' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = [c.text for c in completions] - assert ['subdir'] == result - - # check that there is no completion when passing a file - with chdir(test_dir): - completer = PathCompleter(only_directories=True) - doc_text = '1' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - assert [] == completions - - # cleanup - shutil.rmtree(test_dir) - - -def test_pathcompleter_respects_completions_under_min_input_len(): - # setup: create a test dir with 10 files - test_dir = tempfile.mkdtemp() - write_test_files(test_dir) - - # min len:1 and no text - with chdir(test_dir): - completer = PathCompleter(min_input_len=1) - doc_text = '' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - assert [] == completions - - # min len:1 and text of len 1 - with chdir(test_dir): - completer = PathCompleter(min_input_len=1) - doc_text = '1' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = [c.text for c in completions] - assert [''] == result - - # min len:0 and text of len 2 - with chdir(test_dir): - completer = PathCompleter(min_input_len=0) - doc_text = '1' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = [c.text for c in completions] - assert [''] == result - - # create 10 files with a 2 char long name - for i in range(10): - with open(os.path.join(test_dir, str(i) * 2), 'wb') as out: - out.write(b'') - - # min len:1 and text of len 1 - with chdir(test_dir): - completer = PathCompleter(min_input_len=1) - doc_text = '2' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = sorted(c.text for c in completions) - assert ['', '2'] == result - - # min len:2 and text of len 1 - with chdir(test_dir): - completer = PathCompleter(min_input_len=2) - doc_text = '2' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - assert [] == completions - - # cleanup - shutil.rmtree(test_dir) - - -def test_pathcompleter_does_not_expanduser_by_default(): - completer = PathCompleter() - doc_text = '~' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - assert [] == completions - - -def test_pathcompleter_can_expanduser(monkeypatch): - monkeypatch.setenv('HOME', '/tmp') - completer = PathCompleter(expanduser=True) - doc_text = '~' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - assert len(completions) > 0 - - -def test_pathcompleter_can_apply_file_filter(): - # setup: create a test dir with 10 files - test_dir = tempfile.mkdtemp() - write_test_files(test_dir) - - # add a .csv file - with open(os.path.join(test_dir, 'my.csv'), 'wb') as out: - out.write(b'') - - file_filter = lambda f: f and f.endswith('.csv') - - with chdir(test_dir): - completer = PathCompleter(file_filter=file_filter) - doc_text = '' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = [c.text for c in completions] - assert ['my.csv'] == result - - # cleanup - shutil.rmtree(test_dir) - - -def test_pathcompleter_get_paths_constrains_path(): - # setup: create a test dir with 10 files - test_dir = tempfile.mkdtemp() - write_test_files(test_dir) - - # add a subdir with 10 other files with different names - subdir = os.path.join(test_dir, 'subdir') - os.mkdir(subdir) - write_test_files(subdir, 'abcdefghij') - - get_paths = lambda: ['subdir'] - - with chdir(test_dir): - completer = PathCompleter(get_paths=get_paths) - doc_text = '' - doc = Document(doc_text, len(doc_text)) - event = CompleteEvent() - completions = list(completer.get_completions(doc, event)) - result = [c.text for c in completions] - expected = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] - assert expected == result - - # cleanup - shutil.rmtree(test_dir) diff --git a/contrib/python/prompt-toolkit/py2/tests/test_document.py b/contrib/python/prompt-toolkit/py2/tests/test_document.py deleted file mode 100644 index 8c0cf5704c..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_document.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import unicode_literals - -import pytest - -from prompt_toolkit.document import Document - - -@pytest.fixture -def document(): - return Document( - 'line 1\n' + - 'line 2\n' + - 'line 3\n' + - 'line 4\n', - len('line 1\n' + 'lin') - ) - - -def test_current_char(document): - assert document.current_char == 'e' - - -def test_text_before_cursor(document): - assert document.text_before_cursor == 'line 1\nlin' - - -def test_text_after_cursor(document): - assert document.text_after_cursor == 'e 2\n' + \ - 'line 3\n' + \ - 'line 4\n' - - -def test_lines(document): - assert document.lines == [ - 'line 1', - 'line 2', - 'line 3', - 'line 4', ''] - - -def test_line_count(document): - assert document.line_count == 5 - - -def test_current_line_before_cursor(document): - assert document.current_line_before_cursor == 'lin' - - -def test_current_line_after_cursor(document): - assert document.current_line_after_cursor == 'e 2' - - -def test_current_line(document): - assert document.current_line == 'line 2' - - -def test_cursor_position(document): - assert document.cursor_position_row == 1 - assert document.cursor_position_col == 3 - - d = Document('', 0) - assert d.cursor_position_row == 0 - assert d.cursor_position_col == 0 - - -def test_translate_index_to_position(document): - pos = document.translate_index_to_position( - len('line 1\nline 2\nlin')) - - assert pos[0] == 2 - assert pos[1] == 3 - - pos = document.translate_index_to_position(0) - assert pos == (0, 0) diff --git a/contrib/python/prompt-toolkit/py2/tests/test_filter.py b/contrib/python/prompt-toolkit/py2/tests/test_filter.py deleted file mode 100644 index 5aee62a9a9..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_filter.py +++ /dev/null @@ -1,168 +0,0 @@ -from __future__ import unicode_literals -from prompt_toolkit.filters import Condition, Never, Always, Filter -from prompt_toolkit.filters.types import CLIFilter, SimpleFilter -from prompt_toolkit.filters.utils import to_cli_filter, to_simple_filter -from prompt_toolkit.filters.cli import HasArg, HasFocus, HasSelection - -import pytest - - -def test_condition_filter_args(): - c = Condition(lambda a, b, c: True) - assert c.test_args('a', 'b', 'c') - assert not c.test_args() - assert not c.test_args('a') - assert not c.test_args('a', 'b') - assert not c.test_args('a', 'b', 'c', 'd') - - c2 = Condition(lambda a, b=1: True) - assert c2.test_args('a') - assert c2.test_args('a', 'b') - assert not c2.test_args('a', 'b', 'c') - assert not c2.test_args() - - c3 = Condition(lambda *a: True) - assert c3.test_args() - assert c3.test_args('a') - assert c3.test_args('a', 'b') - - -def test_and_arg(): - c1 = Condition(lambda a: True) - c2 = Condition(lambda a: True) - c3 = c1 & c2 - - assert c3.test_args('a') - assert not c3.test_args() - assert not c3.test_args('a', 'b') - - -def test_or_arg(): - c1 = Condition(lambda a: True) - c2 = Condition(lambda a: True) - c3 = c1 | c2 - - assert c3.test_args('a') - assert not c3.test_args() - assert not c3.test_args('a', 'b') - - -def test_condition(): - c = Condition(lambda a: a % 2 == 0) - assert c(4) - assert c(6) - assert not c(5) - assert not c(3) - - -def test_never(): - assert not Never()() - - -def test_always(): - assert Always()() - - -def test_invert(): - assert not (~Always())() - assert (~Never()()) - - c = ~Condition(lambda: False) - assert c() - - -def test_or(): - for a in (True, False): - for b in (True, False): - c1 = Condition(lambda: a) - c2 = Condition(lambda: b) - c3 = c1 | c2 - - assert isinstance(c3, Filter) - assert c3() == a or b - - -def test_and(): - for a in (True, False): - for b in (True, False): - c1 = Condition(lambda: a) - c2 = Condition(lambda: b) - c3 = c1 & c2 - - assert isinstance(c3, Filter) - assert c3() == (a and b) - - -def test_cli_filter(): - c1 = Condition(lambda cli: True) - assert isinstance(c1, CLIFilter) - assert not isinstance(c1, SimpleFilter) - - c2 = Condition(lambda: True) - assert not isinstance(c2, CLIFilter) - assert isinstance(c2, SimpleFilter) - - c3 = c1 | c2 - assert not isinstance(c3, CLIFilter) - assert not isinstance(c3, SimpleFilter) - - c4 = Condition(lambda cli: True) - c5 = Condition(lambda cli: True) - c6 = c4 & c5 - c7 = c4 | c5 - assert isinstance(c6, CLIFilter) - assert isinstance(c7, CLIFilter) - assert not isinstance(c6, SimpleFilter) - assert not isinstance(c7, SimpleFilter) - - c8 = Condition(lambda *args: True) - assert isinstance(c8, CLIFilter) - assert isinstance(c8, SimpleFilter) - - -def test_to_cli_filter(): - f1 = to_cli_filter(True) - f2 = to_cli_filter(False) - f3 = to_cli_filter(Condition(lambda cli: True)) - f4 = to_cli_filter(Condition(lambda cli: False)) - - assert isinstance(f1, CLIFilter) - assert isinstance(f2, CLIFilter) - assert isinstance(f3, CLIFilter) - assert isinstance(f4, CLIFilter) - assert f1(None) - assert not f2(None) - assert f3(None) - assert not f4(None) - - with pytest.raises(TypeError): - to_cli_filter(4) - with pytest.raises(TypeError): - to_cli_filter(Condition(lambda: True)) - - -def test_to_simple_filter(): - f1 = to_simple_filter(True) - f2 = to_simple_filter(False) - f3 = to_simple_filter(Condition(lambda: True)) - f4 = to_simple_filter(Condition(lambda: False)) - - assert isinstance(f1, SimpleFilter) - assert isinstance(f2, SimpleFilter) - assert isinstance(f3, SimpleFilter) - assert isinstance(f4, SimpleFilter) - assert f1() - assert not f2() - assert f3() - assert not f4() - - with pytest.raises(TypeError): - to_simple_filter(4) - with pytest.raises(TypeError): - to_simple_filter(Condition(lambda cli: True)) - - -def test_cli_filters(): - assert isinstance(HasArg(), CLIFilter) - assert isinstance(HasFocus('BUFFER_NAME'), CLIFilter) - assert isinstance(HasSelection(), CLIFilter) diff --git a/contrib/python/prompt-toolkit/py2/tests/test_inputstream.py b/contrib/python/prompt-toolkit/py2/tests/test_inputstream.py deleted file mode 100644 index de10c0f9a9..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_inputstream.py +++ /dev/null @@ -1,142 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.terminal.vt100_input import InputStream -from prompt_toolkit.keys import Keys - -import pytest - - -class _ProcessorMock(object): - - def __init__(self): - self.keys = [] - - def feed_key(self, key_press): - self.keys.append(key_press) - - -@pytest.fixture -def processor(): - return _ProcessorMock() - - -@pytest.fixture -def stream(processor): - return InputStream(processor.feed_key) - - -def test_control_keys(processor, stream): - stream.feed('\x01\x02\x10') - - assert len(processor.keys) == 3 - assert processor.keys[0].key == Keys.ControlA - assert processor.keys[1].key == Keys.ControlB - assert processor.keys[2].key == Keys.ControlP - assert processor.keys[0].data == '\x01' - assert processor.keys[1].data == '\x02' - assert processor.keys[2].data == '\x10' - - -def test_arrows(processor, stream): - stream.feed('\x1b[A\x1b[B\x1b[C\x1b[D') - - assert len(processor.keys) == 4 - assert processor.keys[0].key == Keys.Up - assert processor.keys[1].key == Keys.Down - assert processor.keys[2].key == Keys.Right - assert processor.keys[3].key == Keys.Left - assert processor.keys[0].data == '\x1b[A' - assert processor.keys[1].data == '\x1b[B' - assert processor.keys[2].data == '\x1b[C' - assert processor.keys[3].data == '\x1b[D' - - -def test_escape(processor, stream): - stream.feed('\x1bhello') - - assert len(processor.keys) == 1 + len('hello') - assert processor.keys[0].key == Keys.Escape - assert processor.keys[1].key == 'h' - assert processor.keys[0].data == '\x1b' - assert processor.keys[1].data == 'h' - - -def test_special_double_keys(processor, stream): - stream.feed('\x1b[1;3D') # Should both send escape and left. - - assert len(processor.keys) == 2 - assert processor.keys[0].key == Keys.Escape - assert processor.keys[1].key == Keys.Left - assert processor.keys[0].data == '\x1b[1;3D' - assert processor.keys[1].data == '\x1b[1;3D' - - -def test_flush_1(processor, stream): - # Send left key in two parts without flush. - stream.feed('\x1b') - stream.feed('[D') - - assert len(processor.keys) == 1 - assert processor.keys[0].key == Keys.Left - assert processor.keys[0].data == '\x1b[D' - - -def test_flush_2(processor, stream): - # Send left key with a 'Flush' in between. - # The flush should make sure that we process evenything before as-is, - # with makes the first part just an escape character instead. - stream.feed('\x1b') - stream.flush() - stream.feed('[D') - - assert len(processor.keys) == 3 - assert processor.keys[0].key == Keys.Escape - assert processor.keys[1].key == '[' - assert processor.keys[2].key == 'D' - - assert processor.keys[0].data == '\x1b' - assert processor.keys[1].data == '[' - assert processor.keys[2].data == 'D' - - -def test_meta_arrows(processor, stream): - stream.feed('\x1b\x1b[D') - - assert len(processor.keys) == 2 - assert processor.keys[0].key == Keys.Escape - assert processor.keys[1].key == Keys.Left - - -def test_control_square_close(processor, stream): - stream.feed('\x1dC') - - assert len(processor.keys) == 2 - assert processor.keys[0].key == Keys.ControlSquareClose - assert processor.keys[1].key == 'C' - - -def test_invalid(processor, stream): - # Invalid sequence that has at two characters in common with other - # sequences. - stream.feed('\x1b[*') - - assert len(processor.keys) == 3 - assert processor.keys[0].key == Keys.Escape - assert processor.keys[1].key == '[' - assert processor.keys[2].key == '*' - - -def test_cpr_response(processor, stream): - stream.feed('a\x1b[40;10Rb') - assert len(processor.keys) == 3 - assert processor.keys[0].key == 'a' - assert processor.keys[1].key == Keys.CPRResponse - assert processor.keys[2].key == 'b' - - -def test_cpr_response_2(processor, stream): - # Make sure that the newline is not included in the CPR response. - stream.feed('\x1b[40;1R\n') - assert len(processor.keys) == 2 - assert processor.keys[0].key == Keys.CPRResponse - assert processor.keys[1].key == Keys.ControlJ diff --git a/contrib/python/prompt-toolkit/py2/tests/test_key_binding.py b/contrib/python/prompt-toolkit/py2/tests/test_key_binding.py deleted file mode 100644 index d706c4443b..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_key_binding.py +++ /dev/null @@ -1,140 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.key_binding.input_processor import InputProcessor, KeyPress -from prompt_toolkit.key_binding.registry import Registry -from prompt_toolkit.keys import Keys - -import pytest - - -class Handlers(object): - - def __init__(self): - self.called = [] - - def __getattr__(self, name): - def func(event): - self.called.append(name) - return func - - -@pytest.fixture -def handlers(): - return Handlers() - - -@pytest.fixture -def registry(handlers): - registry = Registry() - registry.add_binding( - Keys.ControlX, Keys.ControlC)(handlers.controlx_controlc) - registry.add_binding(Keys.ControlX)(handlers.control_x) - registry.add_binding(Keys.ControlD)(handlers.control_d) - registry.add_binding( - Keys.ControlSquareClose, Keys.Any)(handlers.control_square_close_any) - - return registry - - -@pytest.fixture -def processor(registry): - return InputProcessor(registry, lambda: None) - - -def test_feed_simple(processor, handlers): - processor.feed(KeyPress(Keys.ControlX, '\x18')) - processor.feed(KeyPress(Keys.ControlC, '\x03')) - processor.process_keys() - - assert handlers.called == ['controlx_controlc'] - - -def test_feed_several(processor, handlers): - # First an unknown key first. - processor.feed(KeyPress(Keys.ControlQ, '')) - processor.process_keys() - - assert handlers.called == [] - - # Followed by a know key sequence. - processor.feed(KeyPress(Keys.ControlX, '')) - processor.feed(KeyPress(Keys.ControlC, '')) - processor.process_keys() - - assert handlers.called == ['controlx_controlc'] - - # Followed by another unknown sequence. - processor.feed(KeyPress(Keys.ControlR, '')) - processor.feed(KeyPress(Keys.ControlS, '')) - - # Followed again by a know key sequence. - processor.feed(KeyPress(Keys.ControlD, '')) - processor.process_keys() - - assert handlers.called == ['controlx_controlc', 'control_d'] - - -def test_control_square_closed_any(processor, handlers): - processor.feed(KeyPress(Keys.ControlSquareClose, '')) - processor.feed(KeyPress('C', 'C')) - processor.process_keys() - - assert handlers.called == ['control_square_close_any'] - - -def test_common_prefix(processor, handlers): - # Sending Control_X should not yet do anything, because there is - # another sequence starting with that as well. - processor.feed(KeyPress(Keys.ControlX, '')) - processor.process_keys() - - assert handlers.called == [] - - # When another key is pressed, we know that we did not meant the longer - # "ControlX ControlC" sequence and the callbacks are called. - processor.feed(KeyPress(Keys.ControlD, '')) - processor.process_keys() - - assert handlers.called == ['control_x', 'control_d'] - - -def test_previous_key_sequence(processor, handlers): - """ - test whether we receive the correct previous_key_sequence. - """ - events = [] - def handler(event): - events.append(event) - - # Build registry. - registry = Registry() - registry.add_binding('a', 'a')(handler) - registry.add_binding('b', 'b')(handler) - processor = InputProcessor(registry, lambda: None) - - # Create processor and feed keys. - processor.feed(KeyPress('a', 'a')) - processor.feed(KeyPress('a', 'a')) - processor.feed(KeyPress('b', 'b')) - processor.feed(KeyPress('b', 'b')) - processor.process_keys() - - # Test. - assert len(events) == 2 - assert len(events[0].key_sequence) == 2 - assert events[0].key_sequence[0].key == 'a' - assert events[0].key_sequence[0].data == 'a' - assert events[0].key_sequence[1].key == 'a' - assert events[0].key_sequence[1].data == 'a' - assert events[0].previous_key_sequence == [] - - assert len(events[1].key_sequence) == 2 - assert events[1].key_sequence[0].key == 'b' - assert events[1].key_sequence[0].data == 'b' - assert events[1].key_sequence[1].key == 'b' - assert events[1].key_sequence[1].data == 'b' - assert len(events[1].previous_key_sequence) == 2 - assert events[1].previous_key_sequence[0].key == 'a' - assert events[1].previous_key_sequence[0].data == 'a' - assert events[1].previous_key_sequence[1].key == 'a' - assert events[1].previous_key_sequence[1].data == 'a' diff --git a/contrib/python/prompt-toolkit/py2/tests/test_layout.py b/contrib/python/prompt-toolkit/py2/tests/test_layout.py deleted file mode 100644 index 6c9e67b4de..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_layout.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.layout.utils import split_lines -from prompt_toolkit.token import Token - - -def test_split_lines(): - lines = list(split_lines([(Token.A, 'line1\nline2\nline3')])) - - assert lines == [ - [(Token.A, 'line1')], - [(Token.A, 'line2')], - [(Token.A, 'line3')], - ] - - -def test_split_lines_2(): - lines = list(split_lines([ - (Token.A, 'line1'), - (Token.B, 'line2\nline3\nline4') - ])) - - assert lines == [ - [(Token.A, 'line1'), (Token.B, 'line2')], - [(Token.B, 'line3')], - [(Token.B, 'line4')], - ] - - -def test_split_lines_3(): - " Edge cases: inputs ending with newlines. " - # -1- - lines = list(split_lines([ - (Token.A, 'line1\nline2\n') - ])) - - assert lines == [ - [(Token.A, 'line1')], - [(Token.A, 'line2')], - [(Token.A, '')], - ] - - # -2- - lines = list(split_lines([ - (Token.A, '\n'), - ])) - - assert lines == [ - [], - [(Token.A, '')], - ] - - # -3- - lines = list(split_lines([ - (Token.A, ''), - ])) - - assert lines == [ - [(Token.A, '')], - ] diff --git a/contrib/python/prompt-toolkit/py2/tests/test_print_tokens.py b/contrib/python/prompt-toolkit/py2/tests/test_print_tokens.py deleted file mode 100644 index c3b5826b36..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_print_tokens.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Test `shortcuts.print_tokens`. -""" -from __future__ import unicode_literals -from prompt_toolkit.shortcuts import print_tokens -from prompt_toolkit.token import Token -from prompt_toolkit.styles import style_from_dict - - -class _Capture: - " Emulate an stdout object. " - encoding = 'utf-8' - - def __init__(self): - self._data = [] - - def write(self, data): - self._data.append(data) - - @property - def data(self): - return b''.join(self._data) - - def flush(self): - pass - - def isatty(self): - return True - - -def test_print_tokens(): - f = _Capture() - print_tokens([(Token, 'hello'), (Token, 'world')], file=f) - assert b'hello' in f.data - assert b'world' in f.data - - -def test_with_style(): - f = _Capture() - style = style_from_dict({ - Token.Hello: '#ff0066', - Token.World: '#44ff44 italic', - }) - tokens = [ - (Token.Hello, 'Hello '), - (Token.World, 'world'), - ] - print_tokens(tokens, style=style, file=f) - assert b'\x1b[0;38;5;197mHello' in f.data - assert b'\x1b[0;38;5;83;3mworld' in f.data diff --git a/contrib/python/prompt-toolkit/py2/tests/test_regular_languages.py b/contrib/python/prompt-toolkit/py2/tests/test_regular_languages.py deleted file mode 100644 index 6ece5cdeb5..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_regular_languages.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.completion import CompleteEvent, Completer, Completion -from prompt_toolkit.contrib.regular_languages import compile -from prompt_toolkit.contrib.regular_languages.compiler import Match, Variables -from prompt_toolkit.contrib.regular_languages.completion import \ - GrammarCompleter -from prompt_toolkit.document import Document - - -def test_simple_match(): - g = compile('hello|world') - - m = g.match('hello') - assert isinstance(m, Match) - - m = g.match('world') - assert isinstance(m, Match) - - m = g.match('somethingelse') - assert m is None - - -def test_variable_varname(): - """ - Test `Variable` with varname. - """ - g = compile('((?P<varname>hello|world)|test)') - - m = g.match('hello') - variables = m.variables() - assert isinstance(variables, Variables) - assert variables.get('varname') == 'hello' - assert variables['varname'] == 'hello' - - m = g.match('world') - variables = m.variables() - assert isinstance(variables, Variables) - assert variables.get('varname') == 'world' - assert variables['varname'] == 'world' - - m = g.match('test') - variables = m.variables() - assert isinstance(variables, Variables) - assert variables.get('varname') is None - assert variables['varname'] is None - - -def test_prefix(): - """ - Test `match_prefix`. - """ - g = compile(r'(hello\ world|something\ else)') - - m = g.match_prefix('hello world') - assert isinstance(m, Match) - - m = g.match_prefix('he') - assert isinstance(m, Match) - - m = g.match_prefix('') - assert isinstance(m, Match) - - m = g.match_prefix('som') - assert isinstance(m, Match) - - m = g.match_prefix('hello wor') - assert isinstance(m, Match) - - m = g.match_prefix('no-match') - assert m.trailing_input().start == 0 - assert m.trailing_input().stop == len('no-match') - - m = g.match_prefix('hellotest') - assert m.trailing_input().start == len('hello') - assert m.trailing_input().stop == len('hellotest') - - -def test_completer(): - class completer1(Completer): - - def get_completions(self, document, complete_event): - yield Completion( - 'before-%s-after' % document.text, -len(document.text)) - yield Completion( - 'before-%s-after-B' % document.text, -len(document.text)) - - class completer2(Completer): - - def get_completions(self, document, complete_event): - yield Completion( - 'before2-%s-after2' % document.text, -len(document.text)) - yield Completion( - 'before2-%s-after2-B' % document.text, -len(document.text)) - - # Create grammar. "var1" + "whitespace" + "var2" - g = compile(r'(?P<var1>[a-z]*) \s+ (?P<var2>[a-z]*)') - - # Test 'get_completions()' - completer = GrammarCompleter( - g, {'var1': completer1(), 'var2': completer2()}) - completions = list(completer.get_completions( - Document('abc def', len('abc def')), - CompleteEvent())) - - assert len(completions) == 2 - assert completions[0].text == 'before2-def-after2' - assert completions[0].start_position == -3 - assert completions[1].text == 'before2-def-after2-B' - assert completions[1].start_position == -3 diff --git a/contrib/python/prompt-toolkit/py2/tests/test_shortcuts.py b/contrib/python/prompt-toolkit/py2/tests/test_shortcuts.py deleted file mode 100644 index 8c13510ea8..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_shortcuts.py +++ /dev/null @@ -1,50 +0,0 @@ -from prompt_toolkit.shortcuts import _split_multiline_prompt -from prompt_toolkit.token import Token - - -def test_split_multiline_prompt(): - # Test 1: no newlines: - tokens = [(Token, 'ab')] - has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens) - assert has_before_tokens(None) is False - assert before(None) == [] - assert first_input_line(None) == [ - (Token, 'a'), - (Token, 'b'), - ] - - # Test 1: multiple lines. - tokens = [(Token, 'ab\ncd\nef')] - has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens) - assert has_before_tokens(None) is True - assert before(None) == [ - (Token, 'a'), - (Token, 'b'), - (Token, '\n'), - (Token, 'c'), - (Token, 'd'), - ] - assert first_input_line(None) == [ - (Token, 'e'), - (Token, 'f'), - ] - - # Edge case 1: starting with a newline. - tokens = [(Token, '\nab')] - has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens) - assert has_before_tokens(None) is True - assert before(None) == [] - assert first_input_line(None) == [ - (Token, 'a'), - (Token, 'b') - ] - - # Edge case 2: starting with two newlines. - tokens = [(Token, '\n\nab')] - has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens) - assert has_before_tokens(None) is True - assert before(None) == [(Token, '\n')] - assert first_input_line(None) == [ - (Token, 'a'), - (Token, 'b') - ] diff --git a/contrib/python/prompt-toolkit/py2/tests/test_style.py b/contrib/python/prompt-toolkit/py2/tests/test_style.py deleted file mode 100644 index fc839ec95f..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_style.py +++ /dev/null @@ -1,40 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.styles import Attrs, style_from_dict -from prompt_toolkit.token import Token - - -def test_style_from_dict(): - style = style_from_dict({ - Token.A: '#ff0000 bold underline italic', - Token.B: 'bg:#00ff00 blink reverse', - }) - - expected = Attrs(color='ff0000', bgcolor=None, bold=True, - underline=True, italic=True, blink=False, reverse=False) - assert style.get_attrs_for_token(Token.A) == expected - - expected = Attrs(color=None, bgcolor='00ff00', bold=False, - underline=False, italic=False, blink=True, reverse=True) - assert style.get_attrs_for_token(Token.B) == expected - - -def test_style_inheritance(): - style = style_from_dict({ - Token: '#ff0000', - Token.A.B.C: 'bold', - Token.A.B.C.D: '#ansired', - Token.A.B.C.D.E: 'noinherit blink' - }) - - expected = Attrs(color='ff0000', bgcolor=None, bold=True, - underline=False, italic=False, blink=False, reverse=False) - assert style.get_attrs_for_token(Token.A.B.C) == expected - - expected = Attrs(color='ansired', bgcolor=None, bold=True, - underline=False, italic=False, blink=False, reverse=False) - assert style.get_attrs_for_token(Token.A.B.C.D) == expected - - expected = Attrs(color=None, bgcolor=None, bold=False, - underline=False, italic=False, blink=True, reverse=False) - assert style.get_attrs_for_token(Token.A.B.C.D.E) == expected diff --git a/contrib/python/prompt-toolkit/py2/tests/test_utils.py b/contrib/python/prompt-toolkit/py2/tests/test_utils.py deleted file mode 100644 index 1e3d92cda6..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_utils.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import unicode_literals - -from prompt_toolkit.utils import take_using_weights - -import itertools - - -def test_using_weights(): - def take(generator, count): - return list(itertools.islice(generator, 0, count)) - - # Check distribution. - data = take(take_using_weights(['A', 'B', 'C'], [5, 10, 20]), 35) - assert data.count('A') == 5 - assert data.count('B') == 10 - assert data.count('C') == 20 - - assert data == [ - 'A', 'B', 'C', 'C', 'B', 'C', 'C', 'A', 'B', 'C', 'C', 'B', 'C', - 'C', 'A', 'B', 'C', 'C', 'B', 'C', 'C', 'A', 'B', 'C', 'C', - 'B', 'C', 'C', 'A', 'B', 'C', 'C', 'B', 'C', 'C'] - - # Another order. - data = take(take_using_weights(['A', 'B', 'C'], [20, 10, 5]), 35) - assert data.count('A') == 20 - assert data.count('B') == 10 - assert data.count('C') == 5 - - # Bigger numbers. - data = take(take_using_weights(['A', 'B', 'C'], [20, 10, 5]), 70) - assert data.count('A') == 40 - assert data.count('B') == 20 - assert data.count('C') == 10 - - # Negative numbers. - data = take(take_using_weights(['A', 'B', 'C'], [-20, 10, 0]), 70) - assert data.count('A') == 0 - assert data.count('B') == 70 - assert data.count('C') == 0 diff --git a/contrib/python/prompt-toolkit/py2/tests/test_yank_nth_arg.py b/contrib/python/prompt-toolkit/py2/tests/test_yank_nth_arg.py deleted file mode 100644 index 1ccec7bf7b..0000000000 --- a/contrib/python/prompt-toolkit/py2/tests/test_yank_nth_arg.py +++ /dev/null @@ -1,85 +0,0 @@ -from __future__ import unicode_literals -from prompt_toolkit.buffer import Buffer -from prompt_toolkit.history import InMemoryHistory - -import pytest - - -@pytest.fixture -def _history(): - " Prefilled history. " - history = InMemoryHistory() - history.append('alpha beta gamma delta') - history.append('one two three four') - return history - - -# Test yank_last_arg. - - -def test_empty_history(): - buf = Buffer() - buf.yank_last_arg() - assert buf.document.current_line == '' - - -def test_simple_search(_history): - buff = Buffer(history=_history) - buff.yank_last_arg() - assert buff.document.current_line == 'four' - - -def test_simple_search_with_quotes(_history): - _history.append("""one two "three 'x' four"\n""") - buff = Buffer(history=_history) - buff.yank_last_arg() - assert buff.document.current_line == '''"three 'x' four"''' - - -def test_simple_search_with_arg(_history): - buff = Buffer(history=_history) - buff.yank_last_arg(n=2) - assert buff.document.current_line == 'three' - - -def test_simple_search_with_arg_out_of_bounds(_history): - buff = Buffer(history=_history) - buff.yank_last_arg(n=8) - assert buff.document.current_line == '' - - -def test_repeated_search(_history): - buff = Buffer(history=_history) - buff.yank_last_arg() - buff.yank_last_arg() - assert buff.document.current_line == 'delta' - - -def test_repeated_search_with_wraparound(_history): - buff = Buffer(history=_history) - buff.yank_last_arg() - buff.yank_last_arg() - buff.yank_last_arg() - assert buff.document.current_line == 'four' - - -# Test yank_last_arg. - - -def test_yank_nth_arg(_history): - buff = Buffer(history=_history) - buff.yank_nth_arg() - assert buff.document.current_line == 'two' - - -def test_repeated_yank_nth_arg(_history): - buff = Buffer(history=_history) - buff.yank_nth_arg() - buff.yank_nth_arg() - assert buff.document.current_line == 'beta' - - -def test_yank_nth_arg_with_arg(_history): - buff = Buffer(history=_history) - buff.yank_nth_arg(n=2) - assert buff.document.current_line == 'three' |