[Python-modules-commits] [prompt-toolkit] 01/06: Import prompt-toolkit_1.0.0.orig.tar.gz

Scott Kitterman kitterman at moszumanska.debian.org
Mon May 23 20:59:44 UTC 2016


This is an automated email from the git hooks/post-receive script.

kitterman pushed a commit to branch master
in repository prompt-toolkit.

commit 0db2578045eda5318a12fbb910c74d05cec02991
Author: Scott Kitterman <scott at kitterman.com>
Date:   Mon May 23 16:34:41 2016 -0400

    Import prompt-toolkit_1.0.0.orig.tar.gz
---
 CHANGELOG                                          |   93 +-
 PKG-INFO                                           |    8 +-
 README.rst                                         |    6 +-
 examples/clock-input.py                            |    7 +-
 examples/full-screen-layout.py                     |    8 +-
 examples/switch-between-vi-emacs.py                |   15 +-
 prompt_toolkit.egg-info/PKG-INFO                   |    8 +-
 prompt_toolkit.egg-info/SOURCES.txt                |    3 +
 prompt_toolkit/__init__.py                         |    2 +-
 prompt_toolkit/application.py                      |   60 +-
 prompt_toolkit/buffer.py                           |   96 +-
 .../contrib/regular_languages/compiler.py          |    1 +
 prompt_toolkit/document.py                         |  218 +++-
 prompt_toolkit/enums.py                            |    6 +
 prompt_toolkit/eventloop/asyncio_posix.py          |    4 +
 prompt_toolkit/eventloop/posix.py                  |    4 +
 prompt_toolkit/eventloop/posix_utils.py            |   44 +-
 prompt_toolkit/filters/cli.py                      |  118 ++
 prompt_toolkit/filters/types.py                    |   39 +-
 prompt_toolkit/input.py                            |   13 +-
 prompt_toolkit/interface.py                        |   53 +-
 prompt_toolkit/key_binding/bindings/basic.py       |   85 +-
 prompt_toolkit/key_binding/bindings/emacs.py       |  105 +-
 prompt_toolkit/key_binding/bindings/scroll.py      |    1 +
 prompt_toolkit/key_binding/bindings/vi.py          |  986 ++++++++------
 prompt_toolkit/key_binding/digraphs.py             | 1378 ++++++++++++++++++++
 prompt_toolkit/key_binding/input_processor.py      |   48 +-
 prompt_toolkit/key_binding/manager.py              |   59 +-
 prompt_toolkit/key_binding/registry.py             |    3 -
 prompt_toolkit/key_binding/vi_state.py             |   28 +-
 prompt_toolkit/keys.py                             |    1 +
 prompt_toolkit/layout/containers.py                |  159 ++-
 prompt_toolkit/layout/controls.py                  |    9 +-
 prompt_toolkit/layout/lexers.py                    |   12 +-
 prompt_toolkit/layout/margins.py                   |    3 +-
 prompt_toolkit/layout/menus.py                     |   27 +-
 prompt_toolkit/layout/processors.py                |   23 +-
 prompt_toolkit/layout/toolbars.py                  |   10 +-
 prompt_toolkit/mouse_events.py                     |    7 +-
 prompt_toolkit/output.py                           |   41 +
 prompt_toolkit/renderer.py                         |    2 +
 prompt_toolkit/selection.py                        |    6 +-
 prompt_toolkit/shortcuts.py                        |   25 +-
 prompt_toolkit/styles/__init__.py                  |    1 +
 prompt_toolkit/styles/defaults.py                  |   10 +-
 prompt_toolkit/styles/from_dict.py                 |    7 +-
 prompt_toolkit/styles/utils.py                     |   45 +
 prompt_toolkit/terminal/vt100_input.py             |    3 +
 prompt_toolkit/terminal/vt100_output.py            |    2 +-
 prompt_toolkit/terminal/win32_input.py             |    5 +-
 prompt_toolkit/terminal/win32_output.py            |    1 +
 prompt_toolkit/utils.py                            |  105 +-
 setup.cfg                                          |    4 +-
 tests/cli_tests.py                                 |  183 +++
 tests/run_tests.py                                 |    1 +
 55 files changed, 3400 insertions(+), 791 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index ac06351..dcde93e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,13 +1,92 @@
 CHANGELOG
 =========
 
-About the version numbering:
-    As long as the version number starts with a zero, we allow backwards
-    incompatible changes between each release. This is required order to move
-    forward. However, we do our best to keep it to a minimum and ensure
-    backwards-compatibility in the most used public APIs.
-    When the library stabilizes, which is hopefully very soon, we will switch
-    to a <breaking>.<feature>.<fix> style of numbering.
+1.0.0: 2016-05-05
+-----------------
+
+Fixes:
+- Adjust minimum completion menu width to match UIControl and Window class.
+- Bugfix regarding weakref in InputProcessor.
+- Fix for pypy3: bug in WeakValueDictionary.
+- Correctly handle '0' key binding in Vi mode.
+- Also load Vi bindings by default in Application if no registry has been given.
+- Only go into selection mode if the current buffer is not empty.
+- Close PipeInput after usage.
+- Only use 16 colors in (Emacs) eterm-color.
+- Bugfix in "xP Vi key binding.
+- Bugfix in Vi { and } key binding.
+- Fix: use correct token for Scrollbar in MultiColumnCompletionMenuControl.
+- Handle negative values in translate_row_col_to_index.
+- Handle decomposed unicode characters.
+- Fixed Window.always_hide_cursor. (Parameter was ignored.)
+- Fix in zz Vi key binding. (When render info is not available.)
+- Fix in Document.get_cursor_up_position. (When an argument is given.)
+
+New features:
+- Separated `load_mouse_bindings`.
+- Refactoring/simplification of the key bindings: better use of filters and
+  CLI.editing_mode.
+- Added DummyOutput class and a few unit tests that test the whole CLI.
+- Use the bisect module in Document._line_start_indexes instead of a custom
+  binary search. This should improve the performance.
+- Stay in the same column when doing multiple up/down movements.
+- Visual improvements:
+  * Implemented cursorcolumn, cursorline and colorcolumn.
+  * Only reserve menu space when `complete_while_typing=True` or when there are
+    completions to be displayed.
+  * Support for chaining tokens for combined styles. SelectedText will now
+    reverse the colors from the highlighting by default. Style
+    `Token.SelectedText` to set a fixed foreground/background.
+    Also for SearchMatch, we now use combined tokens.
+  * Support for dark gray on Windows.
+  * Default token for SystemToolbar and SearchToolbar.
+  * Display selection also on empty lines.
+- Emacs key bindings improved:
+  * Recognize + handle ControlDelete key.
+  * Implemented meta-* and control-backslash key bindings.
+- Vi key bindings improved:
+  * Handle inclusive and linewise motions properly.
+  * Fix g_ motion off by one character, and don't work when cursor is in
+    the trailing whitespace part of line.
+  * Make a(/a)/i(/i)/... motions. Find enclosing brackets instead of the next
+    bracket.
+  * Update N% motion according to vim behaviors.
+  * Fix | motion off by one character.
+  * ge/gE motions go to end of previous word, not start.
+  * Added Vi 'gm' key binding.
+  * Implemented 'gq' key binding in Vi mode. (Reshape text.)
+  * Vi operator/text object separation for key bindings.
+  * Added 'ap' (auto-paragraph) text object.
+  * Implemented Vi digraphs. ControlK will now insert a digraph.
+  * Implemented vi tilde_operator.
+  * Support named registers.
+  * Vi < and > key bindings became operators.
+  * Text objects and motions are now separate bindings.
+  * Improved copy/paste in Vi mode.
+
+Backwards-incompatible changes:
+- Don't reset the current buffer anymore by default in
+  CommandLineInterface.run(). Passing `reset_current_buffer=True` is now
+  required.
+- Renamed MouseEventTypes to MouseEventType for consistency. The old name is
+  still valid, but deprecated.
+- Refactoring of Callbacks. All events should now receive one argument, which
+  is the sender. (Furter, Callback was renamed to Event.) This is mostly used
+  internally.
+- Moved on_invalidate callback from CommandLineInterface to Application
+- Renamed `PipeInput.send` to `PipeInput.send_text`. (Old deprecated name is
+  still kept as a valid alias.)
+- Renamed SimpleLexer.default_token to SimpleLexer.token. (+
+  backwards-compatibility.)
+- Refactoring of the filters: `ViStateFilter` has been deprecated. (Should not
+  be used anymore.) Use the filters, as defined in prompt_toolkit.filters.
+- `editing_mode` is now a property of `CommandLineInterface`. This is replacing
+  the `vi_mode` parameter in `KeyBindingManager`.
+- The default accept_action for the default Buffer in Application now becomes
+  IGNORE. This is a much more sensible default. Pass RETURN_DOCUMENT to get
+  the previous behaviour,
+- Always expect an EventLoop instance in CommandLineInterface. Creating it in
+  __init__ caused a memory leak.
 
 
 0.60: 2016-03-14
diff --git a/PKG-INFO b/PKG-INFO
index 128f1a9..5bd2723 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: prompt_toolkit
-Version: 0.60
+Version: 1.0.0
 Summary: Library for building powerful interactive command lines in Python
 Home-page: https://github.com/jonathanslenders/python-prompt-toolkit
 Author: Jonathan Slenders
@@ -42,7 +42,7 @@ Description: Python Prompt Toolkit
         - Advanced code completion.
         - Both Emacs and Vi key bindings. (Similar to readline.)
         - Reverse and forward incremental search.
-        - Runs on all Python versions from 2.6 up to 3.4.
+        - 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>`_.
@@ -122,7 +122,7 @@ Description: Python Prompt Toolkit
         - `pgcli <http://pgcli.com/>`_: Postgres client.
         - `mycli <http://mycli.net>`_: MySql client.
         - `wharfee <http://wharfee.com/>`_: A Docker command line.
-        - `xonsh <http://xonsh.org/>`_: A Python-ish, BASHwards-compatible shell.
+        - `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.
@@ -130,6 +130,8 @@ Description: Python Prompt Toolkit
         - `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.
         
         Full screen applications:
         
diff --git a/README.rst b/README.rst
index ce28b6a..d6a797b 100644
--- a/README.rst
+++ b/README.rst
@@ -34,7 +34,7 @@ Some features:
 - Advanced code completion.
 - Both Emacs and Vi key bindings. (Similar to readline.)
 - Reverse and forward incremental search.
-- Runs on all Python versions from 2.6 up to 3.4.
+- 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>`_.
@@ -114,7 +114,7 @@ Shells:
 - `pgcli <http://pgcli.com/>`_: Postgres client.
 - `mycli <http://mycli.net>`_: MySql client.
 - `wharfee <http://wharfee.com/>`_: A Docker command line.
-- `xonsh <http://xonsh.org/>`_: A Python-ish, BASHwards-compatible shell.
+- `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.
@@ -122,6 +122,8 @@ Shells:
 - `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.
 
 Full screen applications:
 
diff --git a/examples/clock-input.py b/examples/clock-input.py
index 8d2ff24..33e826b 100755
--- a/examples/clock-input.py
+++ b/examples/clock-input.py
@@ -10,7 +10,6 @@ from prompt_toolkit.layout.controls import BufferControl
 from prompt_toolkit.layout.processors import BeforeInput
 from prompt_toolkit.shortcuts import create_eventloop
 from prompt_toolkit.token import Token
-from prompt_toolkit.utils import Callback
 
 import datetime
 import time
@@ -45,13 +44,13 @@ def main():
 
         cli.eventloop.run_in_executor(run)
 
-    def on_read_end(cli):
+    def on_read_stop(cli):
         done[0] = True
 
     app = Application(
         layout=Window(BufferControl(input_processors=[BeforeInput(_clock_tokens)])),
-        on_start=Callback(on_read_start),
-        on_stop=Callback(on_read_end))
+        on_start=on_read_start,
+        on_stop=on_read_stop)
 
     cli = CommandLineInterface(application=app, eventloop=eventloop)
 
diff --git a/examples/full-screen-layout.py b/examples/full-screen-layout.py
index 696079e..6883d28 100755
--- a/examples/full-screen-layout.py
+++ b/examples/full-screen-layout.py
@@ -113,13 +113,17 @@ manager = KeyBindingManager()  # Start with the `KeyBindingManager`.
 # `eager=True` to all key bindings, but do it when it conflicts with another
 # existing key binding, and you definitely want to override that behaviour.
 
+ at manager.registry.add_binding(Keys.ControlC, eager=True)
 @manager.registry.add_binding(Keys.ControlQ, eager=True)
 def _(event):
     """
-    Pressing Ctrl-Q will exit the user interface.
+    Pressing Ctrl-Q or Ctrl-C will exit the user interface.
 
     Setting a return value means: quit the event loop that drives the user
     interface and return this value from the `CommandLineInterface.run()` call.
+
+    Note that Ctrl-Q does not work on all terminals. Sometimes it requires
+    executing `stty -ixon`.
     """
     event.cli.set_return_value(None)
 
@@ -137,7 +141,7 @@ buffers={
 # Now we add an event handler that captures change events to the buffer on the
 # left. If the text changes over there, we'll update the buffer on the right.
 
-def default_buffer_changed():
+def default_buffer_changed(cli):
     """
     When the buffer on the left (DEFAULT_BUFFER) changes, update the buffer on
     the right. We just reverse the text.
diff --git a/examples/switch-between-vi-emacs.py b/examples/switch-between-vi-emacs.py
index 4791f73..8ba11ac 100755
--- a/examples/switch-between-vi-emacs.py
+++ b/examples/switch-between-vi-emacs.py
@@ -4,26 +4,25 @@ Example that displays how to switch between Emacs and Vi input mode.
 
 """
 from prompt_toolkit import prompt
-from prompt_toolkit.filters import Condition
+from prompt_toolkit.enums import EditingMode
 from prompt_toolkit.key_binding.manager import KeyBindingManager
 from prompt_toolkit.keys import Keys
 from prompt_toolkit.styles import style_from_dict
 from prompt_toolkit.token import Token
 
 def run():
-    vi_mode_enabled = False
-
     # Create a set of key bindings that have Vi mode enabled if the
     # ``vi_mode_enabled`` is True..
-    manager = KeyBindingManager.for_prompt(
-        enable_vi_mode=Condition(lambda cli: vi_mode_enabled))
+    manager = KeyBindingManager.for_prompt()
 
     # Add an additional key binding for toggling this flag.
     @manager.registry.add_binding(Keys.F4)
     def _(event):
         " Toggle between Emacs and Vi mode. "
-        nonlocal vi_mode_enabled
-        vi_mode_enabled = not vi_mode_enabled
+        if event.cli.editing_mode == EditingMode.VI:
+            event.cli.editing_mode = EditingMode.EMACS
+        else:
+            event.cli.editing_mode = EditingMode.VI
 
     # Add a bottom toolbar to display the status.
     style = style_from_dict({
@@ -32,7 +31,7 @@ def run():
 
     def get_bottom_toolbar_tokens(cli):
         " Display the current input mode. "
-        text = 'Vi' if vi_mode_enabled else 'Emacs'
+        text = 'Vi' if cli.editing_mode == EditingMode.VI else 'Emacs'
         return [
             (Token.Toolbar, ' [F4] %s ' % text)
         ]
diff --git a/prompt_toolkit.egg-info/PKG-INFO b/prompt_toolkit.egg-info/PKG-INFO
index ba464f9..bd517f6 100644
--- a/prompt_toolkit.egg-info/PKG-INFO
+++ b/prompt_toolkit.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: prompt-toolkit
-Version: 0.60
+Version: 1.0.0
 Summary: Library for building powerful interactive command lines in Python
 Home-page: https://github.com/jonathanslenders/python-prompt-toolkit
 Author: Jonathan Slenders
@@ -42,7 +42,7 @@ Description: Python Prompt Toolkit
         - Advanced code completion.
         - Both Emacs and Vi key bindings. (Similar to readline.)
         - Reverse and forward incremental search.
-        - Runs on all Python versions from 2.6 up to 3.4.
+        - 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>`_.
@@ -122,7 +122,7 @@ Description: Python Prompt Toolkit
         - `pgcli <http://pgcli.com/>`_: Postgres client.
         - `mycli <http://mycli.net>`_: MySql client.
         - `wharfee <http://wharfee.com/>`_: A Docker command line.
-        - `xonsh <http://xonsh.org/>`_: A Python-ish, BASHwards-compatible shell.
+        - `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.
@@ -130,6 +130,8 @@ Description: Python Prompt Toolkit
         - `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.
         
         Full screen applications:
         
diff --git a/prompt_toolkit.egg-info/SOURCES.txt b/prompt_toolkit.egg-info/SOURCES.txt
index c8a5061..0c45d30 100644
--- a/prompt_toolkit.egg-info/SOURCES.txt
+++ b/prompt_toolkit.egg-info/SOURCES.txt
@@ -112,6 +112,7 @@ prompt_toolkit/filters/cli.py
 prompt_toolkit/filters/types.py
 prompt_toolkit/filters/utils.py
 prompt_toolkit/key_binding/__init__.py
+prompt_toolkit/key_binding/digraphs.py
 prompt_toolkit/key_binding/input_processor.py
 prompt_toolkit/key_binding/manager.py
 prompt_toolkit/key_binding/registry.py
@@ -140,12 +141,14 @@ prompt_toolkit/styles/base.py
 prompt_toolkit/styles/defaults.py
 prompt_toolkit/styles/from_dict.py
 prompt_toolkit/styles/from_pygments.py
+prompt_toolkit/styles/utils.py
 prompt_toolkit/terminal/__init__.py
 prompt_toolkit/terminal/conemu_output.py
 prompt_toolkit/terminal/vt100_input.py
 prompt_toolkit/terminal/vt100_output.py
 prompt_toolkit/terminal/win32_input.py
 prompt_toolkit/terminal/win32_output.py
+tests/cli_tests.py
 tests/contrib_tests.py
 tests/filter_tests.py
 tests/run_tests.py
diff --git a/prompt_toolkit/__init__.py b/prompt_toolkit/__init__.py
index d4d23b5..04c1450 100644
--- a/prompt_toolkit/__init__.py
+++ b/prompt_toolkit/__init__.py
@@ -19,4 +19,4 @@ from .shortcuts import prompt
 
 
 # Don't forget to update in `docs/conf.py`!
-__version__ = '0.60'
+__version__ = '1.0.0'
diff --git a/prompt_toolkit/application.py b/prompt_toolkit/application.py
index c23fa1f..f47a033 100644
--- a/prompt_toolkit/application.py
+++ b/prompt_toolkit/application.py
@@ -3,16 +3,17 @@ 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
+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 Registry
 from .layout import Window
 from .layout.containers import Container
 from .layout.controls import BufferControl
 from .styles import DEFAULT_STYLE, Style
-from .utils import Callback
+import six
 
 __all__ = (
     'AbortAction',
@@ -62,8 +63,10 @@ class Application(object):
         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:
+    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.)
@@ -74,6 +77,7 @@ class Application(object):
     :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,
@@ -83,10 +87,11 @@ class Application(object):
                  use_alternate_screen=False, mouse_support=False,
                  get_title=None,
 
-                 paste_mode=False, ignore_case=False,
+                 paste_mode=False, ignore_case=False, editing_mode=EditingMode.EMACS,
 
                  on_input_timeout=None, on_start=None, on_stop=None,
-                 on_reset=None, on_initialize=None, on_buffer_changed=None, on_render=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)
@@ -103,18 +108,27 @@ class Application(object):
         assert get_title is None or callable(get_title)
         assert isinstance(paste_mode, CLIFilter)
         assert isinstance(ignore_case, CLIFilter)
-        assert on_start is None or isinstance(on_start, Callback)
-        assert on_stop is None or isinstance(on_stop, Callback)
-        assert on_reset is None or isinstance(on_reset, Callback)
-        assert on_buffer_changed is None or isinstance(on_buffer_changed, Callback)
-        assert on_initialize is None or isinstance(on_initialize, Callback)
-        assert on_render is None or isinstance(on_render, Callback)
+        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 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.
-        self.buffer = buffer or Buffer(accept_action=AcceptAction.RETURN_DOCUMENT)
+        # 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:
@@ -131,6 +145,7 @@ class Application(object):
             key_bindings_registry = Registry()
             load_basic_bindings(key_bindings_registry)
             load_emacs_bindings(key_bindings_registry)
+            load_vi_bindings(key_bindings_registry)
 
         if get_title is None:
             get_title = lambda: None
@@ -145,11 +160,16 @@ class Application(object):
 
         self.paste_mode = paste_mode
         self.ignore_case = ignore_case
-
-        self.on_input_timeout = on_input_timeout or Callback()
-        self.on_start = on_start or Callback()
-        self.on_stop = on_stop or Callback()
-        self.on_reset = on_reset or Callback()
-        self.on_initialize = on_initialize or Callback()
-        self.on_buffer_changed = on_buffer_changed or Callback()
-        self.on_render = on_render or Callback()
+        self.editing_mode = editing_mode
+
+        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
diff --git a/prompt_toolkit/buffer.py b/prompt_toolkit/buffer.py
index 0dc26c6..29dac07 100644
--- a/prompt_toolkit/buffer.py
+++ b/prompt_toolkit/buffer.py
@@ -13,13 +13,14 @@ from .filters import to_simple_filter
 from .history import History, InMemoryHistory
 from .search_state import SearchState
 from .selection import SelectionType, SelectionState
-from .utils import Callback
+from .utils import Event
 from .cache import FastDictCache
 from .validation import ValidationError
 
 from six.moves import range
 
 import os
+import re
 import six
 import subprocess
 import tempfile
@@ -30,6 +31,7 @@ __all__ = (
     'Buffer',
     'indent',
     'unindent',
+    'reshape_text',
 )
 
 
@@ -161,9 +163,9 @@ class Buffer(object):
 
     Events:
 
-    :param on_text_changed: Callback instance or None.
-    :param on_text_insert: Callback instance or None.
-    :param on_cursor_position_changed: Callback instance or None.
+    :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:
 
@@ -199,9 +201,9 @@ class Buffer(object):
         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 isinstance(on_text_changed, Callback)
-        assert on_text_insert is None or isinstance(on_text_insert, Callback)
-        assert on_cursor_position_changed is None or isinstance(on_cursor_position_changed, Callback)
+        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
@@ -215,6 +217,9 @@ class Buffer(object):
         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.
@@ -223,9 +228,9 @@ class Buffer(object):
         self.__cursor_position = 0
 
         # Events
-        self.on_text_changed = on_text_changed or Callback()
-        self.on_text_insert = on_text_insert or Callback()
-        self.on_cursor_position_changed = on_cursor_position_changed or Callback()
+        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)
@@ -251,6 +256,9 @@ class Buffer(object):
         # State of the selection.
         self.selection_state = None
 
+        # 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.
 
@@ -362,6 +370,7 @@ class Buffer(object):
         self.complete_state = None
         self.selection_state = None
         self.suggestion = None
+        self.preferred_column = None
 
         # fire 'on_text_changed' event.
         self.on_text_changed.fire()
@@ -371,6 +380,10 @@ class Buffer(object):
         self.validation_error = None
         self.complete_state = 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.
 
@@ -494,11 +507,21 @@ class Buffer(object):
 
     def cursor_up(self, count=1):
         """ (for multiline edit). Move cursor to the previous line.  """
-        self.cursor_position += self.document.get_cursor_up_position(count=count)
+        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.  """
-        self.cursor_position += self.document.get_cursor_down_position(count=count)
+        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):
         """
@@ -508,7 +531,7 @@ class Buffer(object):
         if self.complete_state:
             self.complete_previous(count=count)
         elif self.document.cursor_position_row > 0:
-            self.cursor_position += self.document.get_cursor_up_position(count=count)
+            self.cursor_up(count=count)
         elif not self.selection_state:
             self.history_backward(count=count)
 
@@ -520,7 +543,7 @@ class Buffer(object):
         if self.complete_state:
             self.complete_next(count=count)
         elif self.document.cursor_position_row < self.document.line_count - 1:
-            self.cursor_position += self.document.get_cursor_down_position(count=count)
+            self.cursor_down(count=count)
         elif not self.selection_state:
             self.history_forward(count=count)
 
@@ -1171,3 +1194,48 @@ def unindent(buffer, from_row, to_row, count=1):
 
     # 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/prompt_toolkit/contrib/regular_languages/compiler.py b/prompt_toolkit/contrib/regular_languages/compiler.py
index 1e50fcf..01476bf 100644
--- a/prompt_toolkit/contrib/regular_languages/compiler.py
+++ b/prompt_toolkit/contrib/regular_languages/compiler.py
@@ -41,6 +41,7 @@ Partial matches are possible::
 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
 
diff --git a/prompt_toolkit/document.py b/prompt_toolkit/document.py
index 60b9e51..ed9b056 100644
--- a/prompt_toolkit/document.py
+++ b/prompt_toolkit/document.py
@@ -3,11 +3,12 @@ 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
+from six.moves import range, map
 
 from .selection import SelectionType, SelectionState
 from .clipboard import ClipboardData
@@ -99,7 +100,17 @@ class Document(object):
 
         # Cache for lines/indexes. (Shared with other Document instances that
         # contain the same text.
-        self._cache = _text_to_document_cache.setdefault(self.text, _DocumentCache())
+        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)
@@ -125,12 +136,14 @@ class Document(object):
     @property
     def current_line_before_cursor(self):
         """ Text from the start of the line until the cursor. """
-        return self.text_before_cursor.rsplit('\n', 1)[-1]
+        _, _, 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. """
-        return self.text_after_cursor.split('\n', 1)[0]
+        text, _, _ = self.text_after_cursor.partition('\n')
+        return text
 
     @property
     def lines(self):
@@ -248,24 +261,8 @@ class Document(object):
         """
         indexes = self._line_start_indexes
 
-        # Special case: 'index' appears after the last line.
-        if index >= indexes[-1]:
-            return len(indexes) - 1, indexes[-1]
-
-        # Binary search for the closest index.
-        a, b = 0, len(indexes) - 1
-
-        while a != b:
-            mid = (a + b) // 2
-
-            if indexes[mid] <= index and indexes[mid + 1] > index:
-                return mid, indexes[mid]
-            elif indexes[mid] <= index:
-                a = mid
-            else:
-                b = mid
-
-        return a, indexes[a]
+        pos = bisect.bisect_right(indexes, index) - 1
+        return pos, indexes[pos]
 
     def translate_index_to_position(self, index):
         """
@@ -283,15 +280,21 @@ class Document(object):
         """
         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:
-            result = self._line_start_indexes[-1]
-            line = self.lines[-1]
+            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 += min(col, len(line))
+        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.)
@@ -502,7 +505,7 @@ class Document(object):
     def find_previous_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.
+        of the previous word. Return `None` if nothing was found.
         """
         regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
         iterator = regex.finditer(self.text_before_cursor[::-1])
@@ -514,6 +517,27 @@ class Document(object):
         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.
+        """
+        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.
@@ -560,73 +584,105 @@ class Document(object):
         """
         return min(count, len(self.current_line_after_cursor))
 
-    def get_cursor_up_position(self, count=1):
+    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
-        if self.cursor_position_row > 0:
-            return self.translate_row_col_to_index(
-                self.cursor_position_row - count, self.cursor_position_col) - self.cursor_position
-        else:
-            return 0
+        column = self.cursor_position_col if preferred_column is None else preferred_column
 
-    def get_cursor_down_position(self, count=1):
+        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, self.cursor_position_col) - self.cursor_position
+            self.cursor_position_row + count, column) - self.cursor_position
 
-    def find_matching_bracket_position(self, start_pos=None, end_pos=None):
+    def find_enclosing_bracket_right(self, left_ch, right_ch, end_pos=None):
         """
-        Return relative cursor position of matching [, (, { or < bracket.
+        Find the right bracket enclosing current position. Return the relative
+        position to the cursor position.
 
-        When `start_pos` or `end_pos` are given. Don't look past the positions.
+        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
 
-        # Start/end limit.
+        # 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)
 
-        if end_pos is None:
-            end_pos = len(self.text)
-        else:
-            end_pos = min(len(self.text), end_pos)
+        stack = 1
 
-        # Look for a match.
-        for A, B in '()', '[]', '{}', '<>':
-            # Look forward.
-            if self.current_char == A:
-                for i in range(self.cursor_position + 1, end_pos):
-                    c = self.text[i]
+        # Look backward.
+        for i in range(self.cursor_position - 1, start_pos - 1, -1):
... 5736 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/prompt-toolkit.git



More information about the Python-modules-commits mailing list