diff options
author | monster <[email protected]> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <[email protected]> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) |
fix ya.make
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding')
21 files changed, 0 insertions, 7594 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/__init__.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/__init__.py deleted file mode 100644 index be105369152..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from .key_bindings import ( - ConditionalKeyBindings, - DynamicKeyBindings, - KeyBindings, - KeyBindingsBase, - merge_key_bindings, -) -from .key_processor import KeyPress, KeyPressEvent - -__all__ = [ - # key_bindings. - "ConditionalKeyBindings", - "DynamicKeyBindings", - "KeyBindings", - "KeyBindingsBase", - "merge_key_bindings", - # key_processor - "KeyPress", - "KeyPressEvent", -] diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/__init__.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/__init__.py +++ /dev/null diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/auto_suggest.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/auto_suggest.py deleted file mode 100644 index c016c0688fe..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/auto_suggest.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -Key bindings for auto suggestion (for fish-style auto suggestion). -""" -import re - -from prompt_toolkit.application.current import get_app -from prompt_toolkit.filters import Condition, emacs_mode -from prompt_toolkit.key_binding.key_bindings import KeyBindings -from prompt_toolkit.key_binding.key_processor import KeyPressEvent - -__all__ = [ - "load_auto_suggest_bindings", -] - -E = KeyPressEvent - - -def load_auto_suggest_bindings() -> KeyBindings: - """ - Key bindings for accepting auto suggestion text. - - (This has to come after the Vi bindings, because they also have an - implementation for the "right arrow", but we really want the suggestion - binding when a suggestion is available.) - """ - key_bindings = KeyBindings() - handle = key_bindings.add - - @Condition - def suggestion_available() -> bool: - app = get_app() - return ( - app.current_buffer.suggestion is not None - and len(app.current_buffer.suggestion.text) > 0 - and app.current_buffer.document.is_cursor_at_the_end - ) - - @handle("c-f", filter=suggestion_available) - @handle("c-e", filter=suggestion_available) - @handle("right", filter=suggestion_available) - def _accept(event: E) -> None: - """ - Accept suggestion. - """ - b = event.current_buffer - suggestion = b.suggestion - - if suggestion: - b.insert_text(suggestion.text) - - @handle("escape", "f", filter=suggestion_available & emacs_mode) - def _fill(event: E) -> None: - """ - Fill partial suggestion. - """ - b = event.current_buffer - suggestion = b.suggestion - - if suggestion: - t = re.split(r"(\S+\s+)", suggestion.text) - b.insert_text(next(x for x in t if x)) - - return key_bindings diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/basic.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/basic.py deleted file mode 100644 index fc8f9643596..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/basic.py +++ /dev/null @@ -1,253 +0,0 @@ -# pylint: disable=function-redefined -from prompt_toolkit.application.current import get_app -from prompt_toolkit.filters import ( - Condition, - emacs_insert_mode, - has_selection, - in_paste_mode, - is_multiline, - vi_insert_mode, -) -from prompt_toolkit.key_binding.key_processor import KeyPress, KeyPressEvent -from prompt_toolkit.keys import Keys - -from ..key_bindings import KeyBindings -from .named_commands import get_by_name - -__all__ = [ - "load_basic_bindings", -] - -E = KeyPressEvent - - -def if_no_repeat(event: E) -> bool: - """Callable that returns True when the previous event was delivered to - another handler.""" - return not event.is_repeat - - -def load_basic_bindings() -> KeyBindings: - key_bindings = KeyBindings() - insert_mode = vi_insert_mode | emacs_insert_mode - handle = key_bindings.add - - @handle("c-a") - @handle("c-b") - @handle("c-c") - @handle("c-d") - @handle("c-e") - @handle("c-f") - @handle("c-g") - @handle("c-h") - @handle("c-i") - @handle("c-j") - @handle("c-k") - @handle("c-l") - @handle("c-m") - @handle("c-n") - @handle("c-o") - @handle("c-p") - @handle("c-q") - @handle("c-r") - @handle("c-s") - @handle("c-t") - @handle("c-u") - @handle("c-v") - @handle("c-w") - @handle("c-x") - @handle("c-y") - @handle("c-z") - @handle("f1") - @handle("f2") - @handle("f3") - @handle("f4") - @handle("f5") - @handle("f6") - @handle("f7") - @handle("f8") - @handle("f9") - @handle("f10") - @handle("f11") - @handle("f12") - @handle("f13") - @handle("f14") - @handle("f15") - @handle("f16") - @handle("f17") - @handle("f18") - @handle("f19") - @handle("f20") - @handle("f21") - @handle("f22") - @handle("f23") - @handle("f24") - @handle("c-@") # Also c-space. - @handle("c-\\") - @handle("c-]") - @handle("c-^") - @handle("c-_") - @handle("backspace") - @handle("up") - @handle("down") - @handle("right") - @handle("left") - @handle("s-up") - @handle("s-down") - @handle("s-right") - @handle("s-left") - @handle("home") - @handle("end") - @handle("s-home") - @handle("s-end") - @handle("delete") - @handle("s-delete") - @handle("c-delete") - @handle("pageup") - @handle("pagedown") - @handle("s-tab") - @handle("tab") - @handle("c-s-left") - @handle("c-s-right") - @handle("c-s-home") - @handle("c-s-end") - @handle("c-left") - @handle("c-right") - @handle("c-up") - @handle("c-down") - @handle("c-home") - @handle("c-end") - @handle("insert") - @handle("s-insert") - @handle("c-insert") - @handle("<sigint>") - @handle(Keys.Ignore) - def _ignore(event: E) -> None: - """ - 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("home")(get_by_name("beginning-of-line")) - handle("end")(get_by_name("end-of-line")) - handle("left")(get_by_name("backward-char")) - handle("right")(get_by_name("forward-char")) - handle("c-up")(get_by_name("previous-history")) - handle("c-down")(get_by_name("next-history")) - handle("c-l")(get_by_name("clear-screen")) - - handle("c-k", filter=insert_mode)(get_by_name("kill-line")) - handle("c-u", filter=insert_mode)(get_by_name("unix-line-discard")) - handle("backspace", filter=insert_mode, save_before=if_no_repeat)( - get_by_name("backward-delete-char") - ) - handle("delete", filter=insert_mode, save_before=if_no_repeat)( - get_by_name("delete-char") - ) - handle("c-delete", 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("c-t", filter=insert_mode)(get_by_name("transpose-chars")) - handle("c-i", filter=insert_mode)(get_by_name("menu-complete")) - handle("s-tab", filter=insert_mode)(get_by_name("menu-complete-backward")) - - # Control-W should delete, using whitespace as separator, while M-Del - # should delete using [^a-zA-Z0-9] as a boundary. - handle("c-w", filter=insert_mode)(get_by_name("unix-word-rubout")) - - handle("pageup", filter=~has_selection)(get_by_name("previous-history")) - handle("pagedown", filter=~has_selection)(get_by_name("next-history")) - - # CTRL keys. - - @Condition - def has_text_before_cursor() -> bool: - return bool(get_app().current_buffer.text) - - handle("c-d", filter=has_text_before_cursor & insert_mode)( - get_by_name("delete-char") - ) - - @handle("enter", filter=insert_mode & is_multiline) - def _newline(event: E) -> None: - """ - Newline (in case of multiline input. - """ - event.current_buffer.newline(copy_margin=not in_paste_mode()) - - @handle("c-j") - def _newline2(event: E) -> None: - r""" - By default, handle \n as if it were a \r (enter). - (It appears that some terminals send \n instead of \r when pressing - enter. - at least the Linux subsystem for Windows.) - """ - event.key_processor.feed(KeyPress(Keys.ControlM, "\r"), first=True) - - # Delete the word before the cursor. - - @handle("up") - def _go_up(event: E) -> None: - event.current_buffer.auto_up(count=event.arg) - - @handle("down") - def _go_down(event: E) -> None: - event.current_buffer.auto_down(count=event.arg) - - @handle("delete", filter=has_selection) - def _cut(event: E) -> None: - data = event.current_buffer.cut_selection() - event.app.clipboard.set_data(data) - - # Global bindings. - - @handle("c-z") - def _insert_ctrl_z(event: E) -> None: - """ - 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.BracketedPaste) - def _paste(event: E) -> None: - """ - 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) - - @Condition - def in_quoted_insert() -> bool: - return get_app().quoted_insert - - @handle(Keys.Any, filter=in_quoted_insert, eager=True) - def _insert_text(event: E) -> None: - """ - Handle quoted insert. - """ - event.current_buffer.insert_text(event.data, overwrite=False) - event.app.quoted_insert = False - - return key_bindings diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/completion.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/completion.py deleted file mode 100644 index a30b54e632d..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/completion.py +++ /dev/null @@ -1,203 +0,0 @@ -""" -Key binding handlers for displaying completions. -""" -import asyncio -import math -from typing import TYPE_CHECKING, List - -from prompt_toolkit.application.run_in_terminal import in_terminal -from prompt_toolkit.completion import ( - CompleteEvent, - Completion, - get_common_complete_suffix, -) -from prompt_toolkit.formatted_text import StyleAndTextTuples -from prompt_toolkit.key_binding.key_bindings import KeyBindings -from prompt_toolkit.key_binding.key_processor import KeyPressEvent -from prompt_toolkit.keys import Keys -from prompt_toolkit.utils import get_cwidth - -if TYPE_CHECKING: - from prompt_toolkit.application import Application - from prompt_toolkit.shortcuts import PromptSession - -__all__ = [ - "generate_completions", - "display_completions_like_readline", -] - -E = KeyPressEvent - - -def generate_completions(event: E) -> None: - 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: - b.start_completion(insert_common_part=True) - - -def display_completions_like_readline(event: E) -> None: - """ - 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. - key_bindings.add(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.app, completions) - - -def _display_completions_like_readline( - app: "Application[object]", completions: List[Completion] -) -> "asyncio.Task[None]": - """ - 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.formatted_text import to_formatted_text - from prompt_toolkit.shortcuts.prompt import create_confirm_session - - # Get terminal dimensions. - term_size = app.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.display_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: int) -> None: - # 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: StyleAndTextTuples = [] - - for r in range(page_row_count): - for c in range(column_count): - try: - completion = page_columns[c][r] - style = "class:readline-like-completions.completion " + ( - completion.style or "" - ) - - result.extend(to_formatted_text(completion.display, style=style)) - - # Add padding. - padding = max_compl_width - get_cwidth(completion.display_text) - result.append((completion.style, " " * padding)) - except IndexError: - pass - result.append(("", "\n")) - - app.print_text(to_formatted_text(result, "class:readline-like-completions")) - - # User interaction through an application generator function. - async def run_compl() -> None: - "Coroutine." - async with in_terminal(render_cli_done=True): - if len(completions) > completions_per_page: - # Ask confirmation if it doesn't fit on the screen. - confirm = await create_confirm_session( - f"Display all {len(completions)} possibilities?", - ).prompt_async() - - 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 = await _create_more_session( - "--MORE--" - ).prompt_async() - - if not show_more: - return - else: - app.output.flush() - else: - # Display all completions. - display(0) - - return app.create_background_task(run_compl()) - - -def _create_more_session(message: str = "--MORE--") -> "PromptSession[bool]": - """ - Create a `PromptSession` object for displaying the "--MORE--". - """ - from prompt_toolkit.shortcuts import PromptSession - - bindings = KeyBindings() - - @bindings.add(" ") - @bindings.add("y") - @bindings.add("Y") - @bindings.add(Keys.ControlJ) - @bindings.add(Keys.ControlM) - @bindings.add(Keys.ControlI) # Tab. - def _yes(event: E) -> None: - event.app.exit(result=True) - - @bindings.add("n") - @bindings.add("N") - @bindings.add("q") - @bindings.add("Q") - @bindings.add(Keys.ControlC) - def _no(event: E) -> None: - event.app.exit(result=False) - - @bindings.add(Keys.Any) - def _ignore(event: E) -> None: - "Disable inserting of text." - - return PromptSession(message, key_bindings=bindings, erase_when_done=True) diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/cpr.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/cpr.py deleted file mode 100644 index 07b0fa75273..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/cpr.py +++ /dev/null @@ -1,28 +0,0 @@ -from prompt_toolkit.key_binding.key_processor import KeyPressEvent -from prompt_toolkit.keys import Keys - -from ..key_bindings import KeyBindings - -__all__ = [ - "load_cpr_bindings", -] - -E = KeyPressEvent - - -def load_cpr_bindings() -> KeyBindings: - key_bindings = KeyBindings() - - @key_bindings.add(Keys.CPRResponse, save_before=lambda e: False) - def _(event: E) -> None: - """ - 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.app.renderer.report_absolute_cursor_row(row) - - return key_bindings diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/emacs.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/emacs.py deleted file mode 100644 index a4a5e348f83..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/emacs.py +++ /dev/null @@ -1,557 +0,0 @@ -# pylint: disable=function-redefined -from typing import Dict, Union - -from prompt_toolkit.application.current import get_app -from prompt_toolkit.buffer import Buffer, indent, unindent -from prompt_toolkit.completion import CompleteEvent -from prompt_toolkit.filters import ( - Condition, - emacs_insert_mode, - emacs_mode, - has_arg, - has_selection, - in_paste_mode, - is_multiline, - is_read_only, - shift_selection_mode, - vi_search_direction_reversed, -) -from prompt_toolkit.key_binding.key_bindings import Binding -from prompt_toolkit.key_binding.key_processor import KeyPressEvent -from prompt_toolkit.keys import Keys -from prompt_toolkit.selection import SelectionType - -from ..key_bindings import ConditionalKeyBindings, KeyBindings, KeyBindingsBase -from .named_commands import get_by_name - -__all__ = [ - "load_emacs_bindings", - "load_emacs_search_bindings", - "load_emacs_shift_selection_bindings", -] - -E = KeyPressEvent - - -def load_emacs_bindings() -> KeyBindingsBase: - """ - Some e-macs extensions. - """ - # Overview of Readline emacs commands: - # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf - key_bindings = KeyBindings() - handle = key_bindings.add - - insert_mode = emacs_insert_mode - - @handle("escape") - def _esc(event: E) -> None: - """ - 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("c-a")(get_by_name("beginning-of-line")) - handle("c-b")(get_by_name("backward-char")) - handle("c-delete", filter=insert_mode)(get_by_name("kill-word")) - handle("c-e")(get_by_name("end-of-line")) - handle("c-f")(get_by_name("forward-char")) - handle("c-left")(get_by_name("backward-word")) - handle("c-right")(get_by_name("forward-word")) - handle("c-x", "r", "y", filter=insert_mode)(get_by_name("yank")) - handle("c-y", filter=insert_mode)(get_by_name("yank")) - handle("escape", "b")(get_by_name("backward-word")) - handle("escape", "c", filter=insert_mode)(get_by_name("capitalize-word")) - handle("escape", "d", filter=insert_mode)(get_by_name("kill-word")) - handle("escape", "f")(get_by_name("forward-word")) - handle("escape", "l", filter=insert_mode)(get_by_name("downcase-word")) - handle("escape", "u", filter=insert_mode)(get_by_name("uppercase-word")) - handle("escape", "y", filter=insert_mode)(get_by_name("yank-pop")) - handle("escape", "backspace", filter=insert_mode)(get_by_name("backward-kill-word")) - handle("escape", "\\", filter=insert_mode)(get_by_name("delete-horizontal-space")) - - handle("c-home")(get_by_name("beginning-of-buffer")) - handle("c-end")(get_by_name("end-of-buffer")) - - handle("c-_", save_before=(lambda e: False), filter=insert_mode)( - get_by_name("undo") - ) - - handle("c-x", "c-u", save_before=(lambda e: False), filter=insert_mode)( - get_by_name("undo") - ) - - handle("escape", "<", filter=~has_selection)(get_by_name("beginning-of-history")) - handle("escape", ">", filter=~has_selection)(get_by_name("end-of-history")) - - handle("escape", ".", filter=insert_mode)(get_by_name("yank-last-arg")) - handle("escape", "_", filter=insert_mode)(get_by_name("yank-last-arg")) - handle("escape", "c-y", filter=insert_mode)(get_by_name("yank-nth-arg")) - handle("escape", "#", filter=insert_mode)(get_by_name("insert-comment")) - handle("c-o")(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("c-q", filter=~has_selection)(get_by_name("quoted-insert")) - - handle("c-x", "(")(get_by_name("start-kbd-macro")) - handle("c-x", ")")(get_by_name("end-kbd-macro")) - handle("c-x", "e")(get_by_name("call-last-kbd-macro")) - - @handle("c-n") - def _next(event: E) -> None: - "Next line." - event.current_buffer.auto_down() - - @handle("c-p") - def _prev(event: E) -> None: - "Previous line." - event.current_buffer.auto_up(count=event.arg) - - def handle_digit(c: str) -> None: - """ - Handle input of arguments. - The first number needs to be preceded by escape. - """ - - @handle(c, filter=has_arg) - @handle("escape", c) - def _(event: E) -> None: - event.append_to_arg_count(c) - - for c in "0123456789": - handle_digit(c) - - @handle("escape", "-", filter=~has_arg) - def _meta_dash(event: E) -> None: - """""" - if event._arg is None: - event.append_to_arg_count("-") - - @handle("-", filter=Condition(lambda: get_app().key_processor.arg == "-")) - def _dash(event: E) -> None: - """ - When '-' is typed again, after exactly '-' has been given as an - argument, ignore this. - """ - event.app.key_processor.arg = "-" - - @Condition - def is_returnable() -> bool: - return get_app().current_buffer.is_returnable - - # Meta + Enter: always accept input. - handle("escape", "enter", filter=insert_mode & is_returnable)( - get_by_name("accept-line") - ) - - # Enter: accept input in single line mode. - handle("enter", filter=insert_mode & is_returnable & ~is_multiline)( - get_by_name("accept-line") - ) - - def character_search(buff: Buffer, char: str, count: int) -> None: - 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("c-]", Keys.Any) - def _goto_char(event: E) -> None: - "When Ctl-] + a character is pressed. go to that character." - # Also named 'character-search' - character_search(event.current_buffer, event.data, event.arg) - - @handle("escape", "c-]", Keys.Any) - def _goto_char_backwards(event: E) -> None: - "Like Ctl-], but backwards." - # Also named 'character-search-backward' - character_search(event.current_buffer, event.data, -event.arg) - - @handle("escape", "a") - def _prev_sentence(event: E) -> None: - "Previous sentence." - # TODO: - - @handle("escape", "e") - def _end_of_sentence(event: E) -> None: - "Move to end of sentence." - # TODO: - - @handle("escape", "t", filter=insert_mode) - def _swap_characters(event: E) -> None: - """ - Swap the last two words before the cursor. - """ - # TODO - - @handle("escape", "*", filter=insert_mode) - def _insert_all_completions(event: E) -> None: - """ - `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("c-x", "c-x") - def _toggle_start_end(event: E) -> None: - """ - 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("c-@") # Control-space or Control-@ - def _start_selection(event: E) -> None: - """ - 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("c-g", filter=~has_selection) - def _cancel(event: E) -> None: - """ - Control + G: Cancel completion menu and validation state. - """ - event.current_buffer.complete_state = None - event.current_buffer.validation_error = None - - @handle("c-g", filter=has_selection) - def _cancel_selection(event: E) -> None: - """ - Cancel selection. - """ - event.current_buffer.exit_selection() - - @handle("c-w", filter=has_selection) - @handle("c-x", "r", "k", filter=has_selection) - def _cut(event: E) -> None: - """ - Cut selected text. - """ - data = event.current_buffer.cut_selection() - event.app.clipboard.set_data(data) - - @handle("escape", "w", filter=has_selection) - def _copy(event: E) -> None: - """ - Copy selected text. - """ - data = event.current_buffer.copy_selection() - event.app.clipboard.set_data(data) - - @handle("escape", "left") - def _start_of_word(event: E) -> None: - """ - 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("escape", "right") - def _start_next_word(event: E) -> None: - """ - 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("escape", "/", filter=insert_mode) - def _complete(event: E) -> None: - """ - M-/: Complete. - """ - b = event.current_buffer - if b.complete_state: - b.complete_next() - else: - b.start_completion(select_first=True) - - @handle("c-c", ">", filter=has_selection) - def _indent(event: E) -> None: - """ - 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("c-c", "<", filter=has_selection) - def _unindent(event: E) -> None: - """ - 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 ConditionalKeyBindings(key_bindings, emacs_mode) - - -def load_emacs_search_bindings() -> KeyBindingsBase: - key_bindings = KeyBindings() - handle = key_bindings.add - from . import search - - # NOTE: We don't bind 'Escape' to 'abort_search'. The reason is that we - # want Alt+Enter to accept input directly in incremental search mode. - # Instead, we have double escape. - - handle("c-r")(search.start_reverse_incremental_search) - handle("c-s")(search.start_forward_incremental_search) - - handle("c-c")(search.abort_search) - handle("c-g")(search.abort_search) - handle("c-r")(search.reverse_incremental_search) - handle("c-s")(search.forward_incremental_search) - handle("up")(search.reverse_incremental_search) - handle("down")(search.forward_incremental_search) - handle("enter")(search.accept_search) - - # Handling of escape. - handle("escape", eager=True)(search.accept_search) - - # Like Readline, it's more natural to accept the search when escape has - # been pressed, however instead the following two bindings could be used - # instead. - # #handle('escape', 'escape', eager=True)(search.abort_search) - # #handle('escape', 'enter', eager=True)(search.accept_search_and_accept_input) - - # If Read-only: also include the following key bindings: - - # '/' and '?' key bindings for searching, just like Vi mode. - handle("?", filter=is_read_only & ~vi_search_direction_reversed)( - search.start_reverse_incremental_search - ) - handle("/", filter=is_read_only & ~vi_search_direction_reversed)( - search.start_forward_incremental_search - ) - handle("?", filter=is_read_only & vi_search_direction_reversed)( - search.start_forward_incremental_search - ) - handle("/", filter=is_read_only & vi_search_direction_reversed)( - search.start_reverse_incremental_search - ) - - @handle("n", filter=is_read_only) - def _jump_next(event: E) -> None: - "Jump to next match." - event.current_buffer.apply_search( - event.app.current_search_state, - include_current_position=False, - count=event.arg, - ) - - @handle("N", filter=is_read_only) - def _jump_prev(event: E) -> None: - "Jump to previous match." - event.current_buffer.apply_search( - ~event.app.current_search_state, - include_current_position=False, - count=event.arg, - ) - - return ConditionalKeyBindings(key_bindings, emacs_mode) - - -def load_emacs_shift_selection_bindings() -> KeyBindingsBase: - """ - Bindings to select text with shift + cursor movements - """ - - key_bindings = KeyBindings() - handle = key_bindings.add - - def unshift_move(event: E) -> None: - """ - Used for the shift selection mode. When called with - a shift + movement key press event, moves the cursor - as if shift is not pressed. - """ - key = event.key_sequence[0].key - - if key == Keys.ShiftUp: - event.current_buffer.auto_up(count=event.arg) - return - if key == Keys.ShiftDown: - event.current_buffer.auto_down(count=event.arg) - return - - # the other keys are handled through their readline command - key_to_command: Dict[Union[Keys, str], str] = { - Keys.ShiftLeft: "backward-char", - Keys.ShiftRight: "forward-char", - Keys.ShiftHome: "beginning-of-line", - Keys.ShiftEnd: "end-of-line", - Keys.ControlShiftLeft: "backward-word", - Keys.ControlShiftRight: "forward-word", - Keys.ControlShiftHome: "beginning-of-buffer", - Keys.ControlShiftEnd: "end-of-buffer", - } - - try: - # Both the dict lookup and `get_by_name` can raise KeyError. - binding = get_by_name(key_to_command[key]) - except KeyError: - pass - else: # (`else` is not really needed here.) - if isinstance(binding, Binding): - # (It should always be a binding here) - binding.call(event) - - @handle("s-left", filter=~has_selection) - @handle("s-right", filter=~has_selection) - @handle("s-up", filter=~has_selection) - @handle("s-down", filter=~has_selection) - @handle("s-home", filter=~has_selection) - @handle("s-end", filter=~has_selection) - @handle("c-s-left", filter=~has_selection) - @handle("c-s-right", filter=~has_selection) - @handle("c-s-home", filter=~has_selection) - @handle("c-s-end", filter=~has_selection) - def _start_selection(event: E) -> None: - """ - Start selection with shift + movement. - """ - # 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) - - if buff.selection_state is not None: - # (`selection_state` should never be `None`, it is created by - # `start_selection`.) - buff.selection_state.enter_shift_mode() - - # Then move the cursor - original_position = buff.cursor_position - unshift_move(event) - if buff.cursor_position == original_position: - # Cursor didn't actually move - so cancel selection - # to avoid having an empty selection - buff.exit_selection() - - @handle("s-left", filter=shift_selection_mode) - @handle("s-right", filter=shift_selection_mode) - @handle("s-up", filter=shift_selection_mode) - @handle("s-down", filter=shift_selection_mode) - @handle("s-home", filter=shift_selection_mode) - @handle("s-end", filter=shift_selection_mode) - @handle("c-s-left", filter=shift_selection_mode) - @handle("c-s-right", filter=shift_selection_mode) - @handle("c-s-home", filter=shift_selection_mode) - @handle("c-s-end", filter=shift_selection_mode) - def _extend_selection(event: E) -> None: - """ - Extend the selection - """ - # Just move the cursor, like shift was not pressed - unshift_move(event) - buff = event.current_buffer - - if buff.selection_state is not None: - if buff.cursor_position == buff.selection_state.original_cursor_position: - # selection is now empty, so cancel selection - buff.exit_selection() - - @handle(Keys.Any, filter=shift_selection_mode) - def _replace_selection(event: E) -> None: - """ - Replace selection by what is typed - """ - event.current_buffer.cut_selection() - get_by_name("self-insert").call(event) - - @handle("enter", filter=shift_selection_mode & is_multiline) - def _newline(event: E) -> None: - """ - A newline replaces the selection - """ - event.current_buffer.cut_selection() - event.current_buffer.newline(copy_margin=not in_paste_mode()) - - @handle("backspace", filter=shift_selection_mode) - def _delete(event: E) -> None: - """ - Delete selection. - """ - event.current_buffer.cut_selection() - - @handle("c-y", filter=shift_selection_mode) - def _yank(event: E) -> None: - """ - In shift selection mode, yanking (pasting) replace the selection. - """ - buff = event.current_buffer - if buff.selection_state: - buff.cut_selection() - get_by_name("yank").call(event) - - # moving the cursor in shift selection mode cancels the selection - @handle("left", filter=shift_selection_mode) - @handle("right", filter=shift_selection_mode) - @handle("up", filter=shift_selection_mode) - @handle("down", filter=shift_selection_mode) - @handle("home", filter=shift_selection_mode) - @handle("end", filter=shift_selection_mode) - @handle("c-left", filter=shift_selection_mode) - @handle("c-right", filter=shift_selection_mode) - @handle("c-home", filter=shift_selection_mode) - @handle("c-end", filter=shift_selection_mode) - def _cancel(event: E) -> None: - """ - Cancel selection. - """ - event.current_buffer.exit_selection() - # we then process the cursor movement - key_press = event.key_sequence[0] - event.key_processor.feed(key_press, first=True) - - return ConditionalKeyBindings(key_bindings, emacs_mode) diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/focus.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/focus.py deleted file mode 100644 index 40844db641c..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/focus.py +++ /dev/null @@ -1,24 +0,0 @@ -from prompt_toolkit.key_binding.key_processor import KeyPressEvent - -__all__ = [ - "focus_next", - "focus_previous", -] - -E = KeyPressEvent - - -def focus_next(event: E) -> None: - """ - Focus the next visible Window. - (Often bound to the `Tab` key.) - """ - event.app.layout.focus_next() - - -def focus_previous(event: E) -> None: - """ - Focus the previous visible Window. - (Often bound to the `BackTab` key.) - """ - event.app.layout.focus_previous() diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/mouse.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/mouse.py deleted file mode 100644 index 916cd41132f..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/mouse.py +++ /dev/null @@ -1,347 +0,0 @@ -import sys -from typing import TYPE_CHECKING, FrozenSet - -from prompt_toolkit.data_structures import Point -from prompt_toolkit.key_binding.key_processor import KeyPress, KeyPressEvent -from prompt_toolkit.keys import Keys -from prompt_toolkit.mouse_events import ( - MouseButton, - MouseEvent, - MouseEventType, - MouseModifier, -) - -from ..key_bindings import KeyBindings - -if TYPE_CHECKING: - from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone - -__all__ = [ - "load_mouse_bindings", -] - -E = KeyPressEvent - -# fmt: off -# flake8: noqa E201 -SCROLL_UP = MouseEventType.SCROLL_UP -SCROLL_DOWN = MouseEventType.SCROLL_DOWN -MOUSE_DOWN = MouseEventType.MOUSE_DOWN -MOUSE_MOVE = MouseEventType.MOUSE_MOVE -MOUSE_UP = MouseEventType.MOUSE_UP - -NO_MODIFIER : FrozenSet[MouseModifier] = frozenset() -SHIFT : FrozenSet[MouseModifier] = frozenset({MouseModifier.SHIFT}) -ALT : FrozenSet[MouseModifier] = frozenset({MouseModifier.ALT}) -SHIFT_ALT : FrozenSet[MouseModifier] = frozenset({MouseModifier.SHIFT, MouseModifier.ALT}) -CONTROL : FrozenSet[MouseModifier] = frozenset({MouseModifier.CONTROL}) -SHIFT_CONTROL : FrozenSet[MouseModifier] = frozenset({MouseModifier.SHIFT, MouseModifier.CONTROL}) -ALT_CONTROL : FrozenSet[MouseModifier] = frozenset({MouseModifier.ALT, MouseModifier.CONTROL}) -SHIFT_ALT_CONTROL: FrozenSet[MouseModifier] = frozenset({MouseModifier.SHIFT, MouseModifier.ALT, MouseModifier.CONTROL}) -UNKNOWN_MODIFIER : FrozenSet[MouseModifier] = frozenset() - -LEFT = MouseButton.LEFT -MIDDLE = MouseButton.MIDDLE -RIGHT = MouseButton.RIGHT -NO_BUTTON = MouseButton.NONE -UNKNOWN_BUTTON = MouseButton.UNKNOWN - -xterm_sgr_mouse_events = { - ( 0, 'm') : (LEFT, MOUSE_UP, NO_MODIFIER), # left_up 0+ + + =0 - ( 4, 'm') : (LEFT, MOUSE_UP, SHIFT), # left_up Shift 0+4+ + =4 - ( 8, 'm') : (LEFT, MOUSE_UP, ALT), # left_up Alt 0+ +8+ =8 - (12, 'm') : (LEFT, MOUSE_UP, SHIFT_ALT), # left_up Shift Alt 0+4+8+ =12 - (16, 'm') : (LEFT, MOUSE_UP, CONTROL), # left_up Control 0+ + +16=16 - (20, 'm') : (LEFT, MOUSE_UP, SHIFT_CONTROL), # left_up Shift Control 0+4+ +16=20 - (24, 'm') : (LEFT, MOUSE_UP, ALT_CONTROL), # left_up Alt Control 0+ +8+16=24 - (28, 'm') : (LEFT, MOUSE_UP, SHIFT_ALT_CONTROL), # left_up Shift Alt Control 0+4+8+16=28 - - ( 1, 'm') : (MIDDLE, MOUSE_UP, NO_MODIFIER), # middle_up 1+ + + =1 - ( 5, 'm') : (MIDDLE, MOUSE_UP, SHIFT), # middle_up Shift 1+4+ + =5 - ( 9, 'm') : (MIDDLE, MOUSE_UP, ALT), # middle_up Alt 1+ +8+ =9 - (13, 'm') : (MIDDLE, MOUSE_UP, SHIFT_ALT), # middle_up Shift Alt 1+4+8+ =13 - (17, 'm') : (MIDDLE, MOUSE_UP, CONTROL), # middle_up Control 1+ + +16=17 - (21, 'm') : (MIDDLE, MOUSE_UP, SHIFT_CONTROL), # middle_up Shift Control 1+4+ +16=21 - (25, 'm') : (MIDDLE, MOUSE_UP, ALT_CONTROL), # middle_up Alt Control 1+ +8+16=25 - (29, 'm') : (MIDDLE, MOUSE_UP, SHIFT_ALT_CONTROL), # middle_up Shift Alt Control 1+4+8+16=29 - - ( 2, 'm') : (RIGHT, MOUSE_UP, NO_MODIFIER), # right_up 2+ + + =2 - ( 6, 'm') : (RIGHT, MOUSE_UP, SHIFT), # right_up Shift 2+4+ + =6 - (10, 'm') : (RIGHT, MOUSE_UP, ALT), # right_up Alt 2+ +8+ =10 - (14, 'm') : (RIGHT, MOUSE_UP, SHIFT_ALT), # right_up Shift Alt 2+4+8+ =14 - (18, 'm') : (RIGHT, MOUSE_UP, CONTROL), # right_up Control 2+ + +16=18 - (22, 'm') : (RIGHT, MOUSE_UP, SHIFT_CONTROL), # right_up Shift Control 2+4+ +16=22 - (26, 'm') : (RIGHT, MOUSE_UP, ALT_CONTROL), # right_up Alt Control 2+ +8+16=26 - (30, 'm') : (RIGHT, MOUSE_UP, SHIFT_ALT_CONTROL), # right_up Shift Alt Control 2+4+8+16=30 - - ( 0, 'M') : (LEFT, MOUSE_DOWN, NO_MODIFIER), # left_down 0+ + + =0 - ( 4, 'M') : (LEFT, MOUSE_DOWN, SHIFT), # left_down Shift 0+4+ + =4 - ( 8, 'M') : (LEFT, MOUSE_DOWN, ALT), # left_down Alt 0+ +8+ =8 - (12, 'M') : (LEFT, MOUSE_DOWN, SHIFT_ALT), # left_down Shift Alt 0+4+8+ =12 - (16, 'M') : (LEFT, MOUSE_DOWN, CONTROL), # left_down Control 0+ + +16=16 - (20, 'M') : (LEFT, MOUSE_DOWN, SHIFT_CONTROL), # left_down Shift Control 0+4+ +16=20 - (24, 'M') : (LEFT, MOUSE_DOWN, ALT_CONTROL), # left_down Alt Control 0+ +8+16=24 - (28, 'M') : (LEFT, MOUSE_DOWN, SHIFT_ALT_CONTROL), # left_down Shift Alt Control 0+4+8+16=28 - - ( 1, 'M') : (MIDDLE, MOUSE_DOWN, NO_MODIFIER), # middle_down 1+ + + =1 - ( 5, 'M') : (MIDDLE, MOUSE_DOWN, SHIFT), # middle_down Shift 1+4+ + =5 - ( 9, 'M') : (MIDDLE, MOUSE_DOWN, ALT), # middle_down Alt 1+ +8+ =9 - (13, 'M') : (MIDDLE, MOUSE_DOWN, SHIFT_ALT), # middle_down Shift Alt 1+4+8+ =13 - (17, 'M') : (MIDDLE, MOUSE_DOWN, CONTROL), # middle_down Control 1+ + +16=17 - (21, 'M') : (MIDDLE, MOUSE_DOWN, SHIFT_CONTROL), # middle_down Shift Control 1+4+ +16=21 - (25, 'M') : (MIDDLE, MOUSE_DOWN, ALT_CONTROL), # middle_down Alt Control 1+ +8+16=25 - (29, 'M') : (MIDDLE, MOUSE_DOWN, SHIFT_ALT_CONTROL), # middle_down Shift Alt Control 1+4+8+16=29 - - ( 2, 'M') : (RIGHT, MOUSE_DOWN, NO_MODIFIER), # right_down 2+ + + =2 - ( 6, 'M') : (RIGHT, MOUSE_DOWN, SHIFT), # right_down Shift 2+4+ + =6 - (10, 'M') : (RIGHT, MOUSE_DOWN, ALT), # right_down Alt 2+ +8+ =10 - (14, 'M') : (RIGHT, MOUSE_DOWN, SHIFT_ALT), # right_down Shift Alt 2+4+8+ =14 - (18, 'M') : (RIGHT, MOUSE_DOWN, CONTROL), # right_down Control 2+ + +16=18 - (22, 'M') : (RIGHT, MOUSE_DOWN, SHIFT_CONTROL), # right_down Shift Control 2+4+ +16=22 - (26, 'M') : (RIGHT, MOUSE_DOWN, ALT_CONTROL), # right_down Alt Control 2+ +8+16=26 - (30, 'M') : (RIGHT, MOUSE_DOWN, SHIFT_ALT_CONTROL), # right_down Shift Alt Control 2+4+8+16=30 - - (32, 'M') : (LEFT, MOUSE_MOVE, NO_MODIFIER), # left_drag 32+ + + =32 - (36, 'M') : (LEFT, MOUSE_MOVE, SHIFT), # left_drag Shift 32+4+ + =36 - (40, 'M') : (LEFT, MOUSE_MOVE, ALT), # left_drag Alt 32+ +8+ =40 - (44, 'M') : (LEFT, MOUSE_MOVE, SHIFT_ALT), # left_drag Shift Alt 32+4+8+ =44 - (48, 'M') : (LEFT, MOUSE_MOVE, CONTROL), # left_drag Control 32+ + +16=48 - (52, 'M') : (LEFT, MOUSE_MOVE, SHIFT_CONTROL), # left_drag Shift Control 32+4+ +16=52 - (56, 'M') : (LEFT, MOUSE_MOVE, ALT_CONTROL), # left_drag Alt Control 32+ +8+16=56 - (60, 'M') : (LEFT, MOUSE_MOVE, SHIFT_ALT_CONTROL), # left_drag Shift Alt Control 32+4+8+16=60 - - (33, 'M') : (MIDDLE, MOUSE_MOVE, NO_MODIFIER), # middle_drag 33+ + + =33 - (37, 'M') : (MIDDLE, MOUSE_MOVE, SHIFT), # middle_drag Shift 33+4+ + =37 - (41, 'M') : (MIDDLE, MOUSE_MOVE, ALT), # middle_drag Alt 33+ +8+ =41 - (45, 'M') : (MIDDLE, MOUSE_MOVE, SHIFT_ALT), # middle_drag Shift Alt 33+4+8+ =45 - (49, 'M') : (MIDDLE, MOUSE_MOVE, CONTROL), # middle_drag Control 33+ + +16=49 - (53, 'M') : (MIDDLE, MOUSE_MOVE, SHIFT_CONTROL), # middle_drag Shift Control 33+4+ +16=53 - (57, 'M') : (MIDDLE, MOUSE_MOVE, ALT_CONTROL), # middle_drag Alt Control 33+ +8+16=57 - (61, 'M') : (MIDDLE, MOUSE_MOVE, SHIFT_ALT_CONTROL), # middle_drag Shift Alt Control 33+4+8+16=61 - - (34, 'M') : (RIGHT, MOUSE_MOVE, NO_MODIFIER), # right_drag 34+ + + =34 - (38, 'M') : (RIGHT, MOUSE_MOVE, SHIFT), # right_drag Shift 34+4+ + =38 - (42, 'M') : (RIGHT, MOUSE_MOVE, ALT), # right_drag Alt 34+ +8+ =42 - (46, 'M') : (RIGHT, MOUSE_MOVE, SHIFT_ALT), # right_drag Shift Alt 34+4+8+ =46 - (50, 'M') : (RIGHT, MOUSE_MOVE, CONTROL), # right_drag Control 34+ + +16=50 - (54, 'M') : (RIGHT, MOUSE_MOVE, SHIFT_CONTROL), # right_drag Shift Control 34+4+ +16=54 - (58, 'M') : (RIGHT, MOUSE_MOVE, ALT_CONTROL), # right_drag Alt Control 34+ +8+16=58 - (62, 'M') : (RIGHT, MOUSE_MOVE, SHIFT_ALT_CONTROL), # right_drag Shift Alt Control 34+4+8+16=62 - - (35, 'M') : (NO_BUTTON, MOUSE_MOVE, NO_MODIFIER), # none_drag 35+ + + =35 - (39, 'M') : (NO_BUTTON, MOUSE_MOVE, SHIFT), # none_drag Shift 35+4+ + =39 - (43, 'M') : (NO_BUTTON, MOUSE_MOVE, ALT), # none_drag Alt 35+ +8+ =43 - (47, 'M') : (NO_BUTTON, MOUSE_MOVE, SHIFT_ALT), # none_drag Shift Alt 35+4+8+ =47 - (51, 'M') : (NO_BUTTON, MOUSE_MOVE, CONTROL), # none_drag Control 35+ + +16=51 - (55, 'M') : (NO_BUTTON, MOUSE_MOVE, SHIFT_CONTROL), # none_drag Shift Control 35+4+ +16=55 - (59, 'M') : (NO_BUTTON, MOUSE_MOVE, ALT_CONTROL), # none_drag Alt Control 35+ +8+16=59 - (63, 'M') : (NO_BUTTON, MOUSE_MOVE, SHIFT_ALT_CONTROL), # none_drag Shift Alt Control 35+4+8+16=63 - - (64, 'M') : (NO_BUTTON, SCROLL_UP, NO_MODIFIER), # scroll_up 64+ + + =64 - (68, 'M') : (NO_BUTTON, SCROLL_UP, SHIFT), # scroll_up Shift 64+4+ + =68 - (72, 'M') : (NO_BUTTON, SCROLL_UP, ALT), # scroll_up Alt 64+ +8+ =72 - (76, 'M') : (NO_BUTTON, SCROLL_UP, SHIFT_ALT), # scroll_up Shift Alt 64+4+8+ =76 - (80, 'M') : (NO_BUTTON, SCROLL_UP, CONTROL), # scroll_up Control 64+ + +16=80 - (84, 'M') : (NO_BUTTON, SCROLL_UP, SHIFT_CONTROL), # scroll_up Shift Control 64+4+ +16=84 - (88, 'M') : (NO_BUTTON, SCROLL_UP, ALT_CONTROL), # scroll_up Alt Control 64+ +8+16=88 - (92, 'M') : (NO_BUTTON, SCROLL_UP, SHIFT_ALT_CONTROL), # scroll_up Shift Alt Control 64+4+8+16=92 - - (65, 'M') : (NO_BUTTON, SCROLL_DOWN, NO_MODIFIER), # scroll_down 64+ + + =65 - (69, 'M') : (NO_BUTTON, SCROLL_DOWN, SHIFT), # scroll_down Shift 64+4+ + =69 - (73, 'M') : (NO_BUTTON, SCROLL_DOWN, ALT), # scroll_down Alt 64+ +8+ =73 - (77, 'M') : (NO_BUTTON, SCROLL_DOWN, SHIFT_ALT), # scroll_down Shift Alt 64+4+8+ =77 - (81, 'M') : (NO_BUTTON, SCROLL_DOWN, CONTROL), # scroll_down Control 64+ + +16=81 - (85, 'M') : (NO_BUTTON, SCROLL_DOWN, SHIFT_CONTROL), # scroll_down Shift Control 64+4+ +16=85 - (89, 'M') : (NO_BUTTON, SCROLL_DOWN, ALT_CONTROL), # scroll_down Alt Control 64+ +8+16=89 - (93, 'M') : (NO_BUTTON, SCROLL_DOWN, SHIFT_ALT_CONTROL), # scroll_down Shift Alt Control 64+4+8+16=93 -} - -typical_mouse_events = { - 32: (LEFT , MOUSE_DOWN , UNKNOWN_MODIFIER), - 33: (MIDDLE , MOUSE_DOWN , UNKNOWN_MODIFIER), - 34: (RIGHT , MOUSE_DOWN , UNKNOWN_MODIFIER), - 35: (UNKNOWN_BUTTON , MOUSE_UP , UNKNOWN_MODIFIER), - - 64: (LEFT , MOUSE_MOVE , UNKNOWN_MODIFIER), - 65: (MIDDLE , MOUSE_MOVE , UNKNOWN_MODIFIER), - 66: (RIGHT , MOUSE_MOVE , UNKNOWN_MODIFIER), - 67: (NO_BUTTON , MOUSE_MOVE , UNKNOWN_MODIFIER), - - 96: (NO_BUTTON , SCROLL_UP , UNKNOWN_MODIFIER), - 97: (NO_BUTTON , SCROLL_DOWN, UNKNOWN_MODIFIER), -} - -urxvt_mouse_events={ - 32: (UNKNOWN_BUTTON, MOUSE_DOWN , UNKNOWN_MODIFIER), - 35: (UNKNOWN_BUTTON, MOUSE_UP , UNKNOWN_MODIFIER), - 96: (NO_BUTTON , SCROLL_UP , UNKNOWN_MODIFIER), - 97: (NO_BUTTON , SCROLL_DOWN, UNKNOWN_MODIFIER), -} -# fmt:on - - -def load_mouse_bindings() -> KeyBindings: - """ - Key bindings, required for mouse support. - (Mouse events enter through the key binding system.) - """ - key_bindings = KeyBindings() - - @key_bindings.add(Keys.Vt100MouseEvent) - def _(event: E) -> "NotImplementedOrNone": - """ - 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:]) - - # TODO: Is it possible to add modifiers here? - mouse_button, mouse_event_type, mouse_modifiers = typical_mouse_events[ - 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: - try: - ( - mouse_button, - mouse_event_type, - mouse_modifiers, - ) = xterm_sgr_mouse_events[mouse_event, m] - except KeyError: - return NotImplemented - - else: - # Some other terminals, like urxvt, Hyper terminal, ... - ( - mouse_button, - mouse_event_type, - mouse_modifiers, - ) = urxvt_mouse_events.get( - mouse_event, (UNKNOWN_BUTTON, MOUSE_MOVE, UNKNOWN_MODIFIER) - ) - - x -= 1 - y -= 1 - - # Only handle mouse events when we know the window height. - if event.app.renderer.height_is_known and mouse_event_type is not None: - # Take region above the layout into account. The reported - # coordinates are absolute to the visible part of the terminal. - from prompt_toolkit.renderer import HeightIsUnknownError - - try: - y -= event.app.renderer.rows_above_layout - except HeightIsUnknownError: - return NotImplemented - - # Call the mouse handler from the renderer. - - # Note: This can return `NotImplemented` if no mouse handler was - # found for this position, or if no repainting needs to - # happen. this way, we avoid excessive repaints during mouse - # movements. - handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x] - return handler( - MouseEvent( - position=Point(x=x, y=y), - event_type=mouse_event_type, - button=mouse_button, - modifiers=mouse_modifiers, - ) - ) - - return NotImplemented - - @key_bindings.add(Keys.ScrollUp) - def _scroll_up(event: E) -> None: - """ - Scroll up event without cursor position. - """ - # We don't receive a cursor position, so we don't know which window to - # scroll. Just send an 'up' key press instead. - event.key_processor.feed(KeyPress(Keys.Up), first=True) - - @key_bindings.add(Keys.ScrollDown) - def _scroll_down(event: E) -> None: - """ - Scroll down event without cursor position. - """ - event.key_processor.feed(KeyPress(Keys.Down), first=True) - - @key_bindings.add(Keys.WindowsMouseEvent) - def _mouse(event: E) -> "NotImplementedOrNone": - """ - Handling of mouse events for Windows. - """ - # This key binding should only exist for Windows. - if sys.platform == "win32": - # Parse data. - pieces = event.data.split(";") - - button = MouseButton(pieces[0]) - event_type = MouseEventType(pieces[1]) - x = int(pieces[2]) - y = int(pieces[3]) - - # Make coordinates absolute to the visible part of the terminal. - output = event.app.renderer.output - - from prompt_toolkit.output.win32 import Win32Output - from prompt_toolkit.output.windows10 import Windows10_Output - - if isinstance(output, (Win32Output, Windows10_Output)): - screen_buffer_info = output.get_win32_screen_buffer_info() - rows_above_cursor = ( - screen_buffer_info.dwCursorPosition.Y - - event.app.renderer._cursor_pos.y - ) - y -= rows_above_cursor - - # Call the mouse event handler. - # (Can return `NotImplemented`.) - handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x] - - return handler( - MouseEvent( - position=Point(x=x, y=y), - event_type=event_type, - button=button, - modifiers=UNKNOWN_MODIFIER, - ) - ) - - # No mouse handler found. Return `NotImplemented` so that we don't - # invalidate the UI. - return NotImplemented - - return key_bindings diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/named_commands.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/named_commands.py deleted file mode 100644 index e0796ef0b8e..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/named_commands.py +++ /dev/null @@ -1,687 +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 typing import Callable, Dict, TypeVar, Union, cast - -from prompt_toolkit.document import Document -from prompt_toolkit.enums import EditingMode -from prompt_toolkit.key_binding.key_bindings import Binding, key_binding -from prompt_toolkit.key_binding.key_processor import KeyPress, KeyPressEvent -from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.controls import BufferControl -from prompt_toolkit.search import SearchDirection -from prompt_toolkit.selection import PasteMode - -from .completion import display_completions_like_readline, generate_completions - -__all__ = [ - "get_by_name", -] - - -# Typing. -_Handler = Callable[[KeyPressEvent], None] -_HandlerOrBinding = Union[_Handler, Binding] -_T = TypeVar("_T", bound=_HandlerOrBinding) -E = KeyPressEvent - - -# Registry that maps the Readline command names to their handlers. -_readline_commands: Dict[str, Binding] = {} - - -def register(name: str) -> Callable[[_T], _T]: - """ - Store handler in the `_readline_commands` dictionary. - """ - - def decorator(handler: _T) -> _T: - "`handler` is a callable or Binding." - if isinstance(handler, Binding): - _readline_commands[name] = handler - else: - _readline_commands[name] = key_binding()(cast(_Handler, handler)) - - return handler - - return decorator - - -def get_by_name(name: str) -> Binding: - """ - Return the handler for the (Readline) command with the given name. - """ - try: - return _readline_commands[name] - except KeyError as e: - raise KeyError("Unknown Readline command: %r" % name) from e - - -# -# Commands for moving -# See: http://www.delorie.com/gnu/docs/readline/rlman_14.html -# - - -@register("beginning-of-buffer") -def beginning_of_buffer(event: E) -> None: - """ - Move to the start of the buffer. - """ - buff = event.current_buffer - buff.cursor_position = 0 - - -@register("end-of-buffer") -def end_of_buffer(event: E) -> None: - """ - Move to the end of the buffer. - """ - buff = event.current_buffer - buff.cursor_position = len(buff.text) - - -@register("beginning-of-line") -def beginning_of_line(event: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - "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: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - Clear the screen and redraw everything at the top of the screen. - """ - event.app.renderer.clear() - - -@register("redraw-current-line") -def redraw_current_line(event: E) -> None: - """ - 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: E) -> None: - """ - Accept the line regardless of where the cursor is. - """ - event.current_buffer.validate_and_handle() - - -@register("previous-history") -def previous_history(event: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - Move to the first line in the history. - """ - event.current_buffer.go_to_history(0) - - -@register("end-of-history") -def end_of_history(event: E) -> None: - """ - 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: E) -> None: - """ - Search backward starting at the current line and moving `up` through - the history as necessary. This is an incremental search. - """ - control = event.app.layout.current_control - - if isinstance(control, BufferControl) and control.search_buffer_control: - event.app.current_search_state.direction = SearchDirection.BACKWARD - event.app.layout.current_control = control.search_buffer_control - - -# -# Commands for changing text -# - - -@register("end-of-file") -def end_of_file(event: E) -> None: - """ - Exit. - """ - event.app.exit() - - -@register("delete-char") -def delete_char(event: E) -> None: - """ - Delete character before the cursor. - """ - deleted = event.current_buffer.delete(count=event.arg) - if not deleted: - event.app.output.bell() - - -@register("backward-delete-char") -def backward_delete_char(event: E) -> None: - """ - 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.app.output.bell() - - -@register("self-insert") -def self_insert(event: E) -> None: - """ - Insert yourself. - """ - event.current_buffer.insert_text(event.data * event.arg) - - -@register("transpose-chars") -def transpose_chars(event: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - Add the next character typed to the line verbatim. This is how to insert - key sequences like C-q, for example. - """ - event.app.quoted_insert = True - - -# -# Killing and yanking. -# - - -@register("kill-line") -def kill_line(event: E) -> None: - """ - 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.app.clipboard.set_text(deleted) - - -@register("kill-word") -def kill_word(event: E) -> None: - """ - 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) - - if event.is_repeat: - deleted = event.app.clipboard.get_data().text + deleted - - event.app.clipboard.set_text(deleted) - - -@register("unix-word-rubout") -def unix_word_rubout(event: E, WORD: bool = True) -> None: - """ - 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.app.clipboard.get_data().text - - event.app.clipboard.set_text(deleted) - else: - # Nothing to delete. Bell. - event.app.output.bell() - - -@register("backward-kill-word") -def backward_kill_word(event: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - 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.app.clipboard.set_text(deleted) - - -@register("yank") -def yank(event: E) -> None: - """ - Paste before cursor. - """ - event.current_buffer.paste_clipboard_data( - event.app.clipboard.get_data(), count=event.arg, paste_mode=PasteMode.EMACS - ) - - -@register("yank-nth-arg") -def yank_nth_arg(event: E) -> None: - """ - 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: E) -> None: - """ - 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: E) -> None: - """ - 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.app.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: E) -> None: - """ - Attempt to perform completion. - """ - display_completions_like_readline(event) - - -@register("menu-complete") -def menu_complete(event: E) -> None: - """ - 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: E) -> None: - """ - Move backward through the list of possible completions. - """ - event.current_buffer.complete_previous() - - -# -# Keyboard macros. -# - - -@register("start-kbd-macro") -def start_kbd_macro(event: E) -> None: - """ - Begin saving the characters typed into the current keyboard macro. - """ - event.app.emacs_state.start_macro() - - -@register("end-kbd-macro") -def end_kbd_macro(event: E) -> None: - """ - Stop saving the characters typed into the current keyboard macro and save - the definition. - """ - event.app.emacs_state.end_macro() - - -@register("call-last-kbd-macro") -@key_binding(record_in_macro=False) -def call_last_kbd_macro(event: E) -> None: - """ - Re-execute the last keyboard macro defined, by making the characters in the - macro appear as if typed at the keyboard. - - Notice that we pass `record_in_macro=False`. This ensures that the 'c-x e' - key sequence doesn't appear in the recording itself. This function inserts - the body of the called macro back into the KeyProcessor, so these keys will - be added later on to the macro of their handlers have `record_in_macro=True`. - """ - # Insert the macro. - macro = event.app.emacs_state.macro - - if macro: - event.app.key_processor.feed_multiple(macro, first=True) - - -@register("print-last-kbd-macro") -def print_last_kbd_macro(event: E) -> None: - """ - Print the last keyboard macro. - """ - # TODO: Make the format suitable for the inputrc file. - def print_macro() -> None: - macro = event.app.emacs_state.macro - if macro: - for k in macro: - print(k) - - from prompt_toolkit.application.run_in_terminal import run_in_terminal - - run_in_terminal(print_macro) - - -# -# Miscellaneous Commands. -# - - -@register("undo") -def undo(event: E) -> None: - """ - Incremental undo. - """ - event.current_buffer.undo() - - -@register("insert-comment") -def insert_comment(event: E) -> None: - """ - 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: str) -> str: - return line[1:] if line.startswith("#") else line - - else: - - def change(line: str) -> str: - return "#" + line - - buff.document = Document( - text="\n".join(map(change, buff.text.splitlines())), cursor_position=0 - ) - - # Accept input. - buff.validate_and_handle() - - -@register("vi-editing-mode") -def vi_editing_mode(event: E) -> None: - """ - Switch to Vi editing mode. - """ - event.app.editing_mode = EditingMode.VI - - -@register("emacs-editing-mode") -def emacs_editing_mode(event: E) -> None: - """ - Switch to Emacs editing mode. - """ - event.app.editing_mode = EditingMode.EMACS - - -@register("prefix-meta") -def prefix_meta(event: E) -> None: - """ - 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':: - - key_bindings.add_key_binding('j', 'j', filter=ViInsertMode())(prefix_meta) - """ - # ('first' should be true, because we want to insert it at the current - # position in the queue.) - event.app.key_processor.feed(KeyPress(Keys.Escape), first=True) - - -@register("operate-and-get-next") -def operate_and_get_next(event: E) -> None: - """ - 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.validate_and_handle() - - # Set the new index at the start of the next run. - def set_working_index() -> None: - if new_index < len(buff._working_lines): - buff.working_index = new_index - - event.app.pre_run_callables.append(set_working_index) - - -@register("edit-and-execute-command") -def edit_and_execute(event: E) -> None: - """ - Invoke an editor on the current command line, and accept the result. - """ - buff = event.current_buffer - buff.open_in_editor(validate_and_handle=True) diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/open_in_editor.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/open_in_editor.py deleted file mode 100644 index f8699f4a45b..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/open_in_editor.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Open in editor key bindings. -""" -from prompt_toolkit.filters import emacs_mode, has_selection, vi_navigation_mode - -from ..key_bindings import KeyBindings, KeyBindingsBase, merge_key_bindings -from .named_commands import get_by_name - -__all__ = [ - "load_open_in_editor_bindings", - "load_emacs_open_in_editor_bindings", - "load_vi_open_in_editor_bindings", -] - - -def load_open_in_editor_bindings() -> KeyBindingsBase: - """ - Load both the Vi and emacs key bindings for handling edit-and-execute-command. - """ - return merge_key_bindings( - [ - load_emacs_open_in_editor_bindings(), - load_vi_open_in_editor_bindings(), - ] - ) - - -def load_emacs_open_in_editor_bindings() -> KeyBindings: - """ - Pressing C-X C-E will open the buffer in an external editor. - """ - key_bindings = KeyBindings() - - key_bindings.add("c-x", "c-e", filter=emacs_mode & ~has_selection)( - get_by_name("edit-and-execute-command") - ) - - return key_bindings - - -def load_vi_open_in_editor_bindings() -> KeyBindings: - """ - Pressing 'v' in navigation mode will open the buffer in an external editor. - """ - key_bindings = KeyBindings() - key_bindings.add("v", filter=vi_navigation_mode)( - get_by_name("edit-and-execute-command") - ) - return key_bindings diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/page_navigation.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/page_navigation.py deleted file mode 100644 index 4d531c04377..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/page_navigation.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Key bindings for extra page navigation: bindings for up/down scrolling through -long pages, like in Emacs or Vi. -""" -from prompt_toolkit.filters import buffer_has_focus, emacs_mode, vi_mode -from prompt_toolkit.key_binding.key_bindings import ( - ConditionalKeyBindings, - KeyBindings, - KeyBindingsBase, - merge_key_bindings, -) - -from .scroll import ( - scroll_backward, - scroll_forward, - scroll_half_page_down, - scroll_half_page_up, - scroll_one_line_down, - scroll_one_line_up, - scroll_page_down, - scroll_page_up, -) - -__all__ = [ - "load_page_navigation_bindings", - "load_emacs_page_navigation_bindings", - "load_vi_page_navigation_bindings", -] - - -def load_page_navigation_bindings() -> KeyBindingsBase: - """ - Load both the Vi and Emacs bindings for page navigation. - """ - # Only enable when a `Buffer` is focused, otherwise, we would catch keys - # when another widget is focused (like for instance `c-d` in a - # ptterm.Terminal). - return ConditionalKeyBindings( - merge_key_bindings( - [ - load_emacs_page_navigation_bindings(), - load_vi_page_navigation_bindings(), - ] - ), - buffer_has_focus, - ) - - -def load_emacs_page_navigation_bindings() -> KeyBindingsBase: - """ - Key bindings, for scrolling up and down through pages. - This are separate bindings, because GNU readline doesn't have them. - """ - key_bindings = KeyBindings() - handle = key_bindings.add - - handle("c-v")(scroll_page_down) - handle("pagedown")(scroll_page_down) - handle("escape", "v")(scroll_page_up) - handle("pageup")(scroll_page_up) - - return ConditionalKeyBindings(key_bindings, emacs_mode) - - -def load_vi_page_navigation_bindings() -> KeyBindingsBase: - """ - Key bindings, for scrolling up and down through pages. - This are separate bindings, because GNU readline doesn't have them. - """ - key_bindings = KeyBindings() - handle = key_bindings.add - - handle("c-f")(scroll_forward) - handle("c-b")(scroll_backward) - handle("c-d")(scroll_half_page_down) - handle("c-u")(scroll_half_page_up) - handle("c-e")(scroll_one_line_down) - handle("c-y")(scroll_one_line_up) - handle("pagedown")(scroll_page_down) - handle("pageup")(scroll_page_up) - - return ConditionalKeyBindings(key_bindings, vi_mode) diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/scroll.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/scroll.py deleted file mode 100644 index 4a43ff585ac..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/scroll.py +++ /dev/null @@ -1,187 +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 prompt_toolkit.key_binding.key_processor import KeyPressEvent - -__all__ = [ - "scroll_forward", - "scroll_backward", - "scroll_half_page_up", - "scroll_half_page_down", - "scroll_one_line_up", - "scroll_one_line_down", -] - -E = KeyPressEvent - - -def scroll_forward(event: E, half: bool = False) -> None: - """ - Scroll window down. - """ - w = event.app.layout.current_window - b = event.app.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: E, half: bool = False) -> None: - """ - Scroll window up. - """ - w = event.app.layout.current_window - b = event.app.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: E) -> None: - """ - Same as ControlF, but only scroll half a page. - """ - scroll_forward(event, half=True) - - -def scroll_half_page_up(event: E) -> None: - """ - Same as ControlB, but only scroll half a page. - """ - scroll_backward(event, half=True) - - -def scroll_one_line_down(event: E) -> None: - """ - scroll_offset += 1 - """ - w = event.app.layout.current_window - b = event.app.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: E) -> None: - """ - scroll_offset -= 1 - """ - w = event.app.layout.current_window - b = event.app.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: E) -> None: - """ - Scroll page down. (Prefer the cursor at the top of the page, after scrolling.) - """ - w = event.app.layout.current_window - b = event.app.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: E) -> None: - """ - Scroll page up. (Prefer the cursor at the bottom of the page, after scrolling.) - """ - w = event.app.layout.current_window - b = event.app.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/py3/prompt_toolkit/key_binding/bindings/search.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/search.py deleted file mode 100644 index 06a047e4cd1..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/search.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -Search related key bindings. -""" -from prompt_toolkit import search -from prompt_toolkit.application.current import get_app -from prompt_toolkit.filters import Condition, control_is_searchable, is_searching -from prompt_toolkit.key_binding.key_processor import KeyPressEvent - -from ..key_bindings import key_binding - -__all__ = [ - "abort_search", - "accept_search", - "start_reverse_incremental_search", - "start_forward_incremental_search", - "reverse_incremental_search", - "forward_incremental_search", - "accept_search_and_accept_input", -] - -E = KeyPressEvent - - -@key_binding(filter=is_searching) -def abort_search(event: E) -> None: - """ - Abort an incremental search and restore the original - line. - (Usually bound to ControlG/ControlC.) - """ - search.stop_search() - - -@key_binding(filter=is_searching) -def accept_search(event: E) -> None: - """ - When enter pressed in isearch, quit isearch mode. (Multiline - isearch would be too complicated.) - (Usually bound to Enter.) - """ - search.accept_search() - - -@key_binding(filter=control_is_searchable) -def start_reverse_incremental_search(event: E) -> None: - """ - Enter reverse incremental search. - (Usually ControlR.) - """ - search.start_search(direction=search.SearchDirection.BACKWARD) - - -@key_binding(filter=control_is_searchable) -def start_forward_incremental_search(event: E) -> None: - """ - Enter forward incremental search. - (Usually ControlS.) - """ - search.start_search(direction=search.SearchDirection.FORWARD) - - -@key_binding(filter=is_searching) -def reverse_incremental_search(event: E) -> None: - """ - Apply reverse incremental search, but keep search buffer focused. - """ - search.do_incremental_search(search.SearchDirection.BACKWARD, count=event.arg) - - -@key_binding(filter=is_searching) -def forward_incremental_search(event: E) -> None: - """ - Apply forward incremental search, but keep search buffer focused. - """ - search.do_incremental_search(search.SearchDirection.FORWARD, count=event.arg) - - -@Condition -def _previous_buffer_is_returnable() -> bool: - """ - True if the previously focused buffer has a return handler. - """ - prev_control = get_app().layout.search_target_buffer_control - return bool(prev_control and prev_control.buffer.is_returnable) - - -@key_binding(filter=is_searching & _previous_buffer_is_returnable) -def accept_search_and_accept_input(event: E) -> None: - """ - Accept the search operation first, then accept the input. - """ - search.accept_search() - event.current_buffer.validate_and_handle() diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/vi.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/vi.py deleted file mode 100644 index efbb107de04..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings/vi.py +++ /dev/null @@ -1,2221 +0,0 @@ -# pylint: disable=function-redefined -import codecs -import string -from enum import Enum -from itertools import accumulate -from typing import Callable, Iterable, List, Optional, Tuple, TypeVar, Union - -from prompt_toolkit.application.current import get_app -from prompt_toolkit.buffer import Buffer, indent, reshape_text, unindent -from prompt_toolkit.clipboard import ClipboardData -from prompt_toolkit.document import Document -from prompt_toolkit.filters import ( - Always, - Condition, - Filter, - has_arg, - is_read_only, - is_searching, -) -from prompt_toolkit.filters.app import ( - in_paste_mode, - is_multiline, - vi_digraph_mode, - vi_insert_mode, - vi_insert_multiple_mode, - vi_mode, - vi_navigation_mode, - vi_recording_macro, - vi_replace_mode, - vi_replace_single_mode, - vi_search_direction_reversed, - vi_selection_mode, - vi_waiting_for_text_object_mode, -) -from prompt_toolkit.input.vt100_parser import Vt100Parser -from prompt_toolkit.key_binding.digraphs import DIGRAPHS -from prompt_toolkit.key_binding.key_processor import KeyPress, KeyPressEvent -from prompt_toolkit.key_binding.vi_state import CharacterFind, InputMode -from prompt_toolkit.keys import Keys -from prompt_toolkit.search import SearchDirection -from prompt_toolkit.selection import PasteMode, SelectionState, SelectionType - -from ..key_bindings import ConditionalKeyBindings, KeyBindings, KeyBindingsBase -from .named_commands import get_by_name - -__all__ = [ - "load_vi_bindings", - "load_vi_search_bindings", -] - -E = KeyPressEvent - -ascii_lowercase = string.ascii_lowercase - -vi_register_names = ascii_lowercase + "0123456789" - - -class TextObjectType(Enum): - EXCLUSIVE = "EXCLUSIVE" - INCLUSIVE = "INCLUSIVE" - LINEWISE = "LINEWISE" - BLOCK = "BLOCK" - - -class TextObject: - """ - Return struct for functions wrapped in ``text_object``. - Both `start` and `end` are relative to the current cursor position. - """ - - def __init__( - self, start: int, end: int = 0, type: TextObjectType = TextObjectType.EXCLUSIVE - ): - - self.start = start - self.end = end - self.type = type - - @property - def selection_type(self) -> SelectionType: - if self.type == TextObjectType.LINEWISE: - return SelectionType.LINES - if self.type == TextObjectType.BLOCK: - return SelectionType.BLOCK - else: - return SelectionType.CHARACTERS - - def sorted(self) -> Tuple[int, int]: - """ - 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: Document) -> Tuple[int, int]: - """ - 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. - - This should return something that can be used in a slice, so the `end` - position is *not* included. - """ - 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: Buffer) -> Tuple[int, int]: - """ - 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: Buffer) -> Tuple[Document, ClipboardData]: - """ - Turn text object into `ClipboardData` instance. - """ - from_, to = self.operator_range(buffer.document) - - from_ += buffer.cursor_position - to += buffer.cursor_position - - # For Vi mode, the SelectionState does include the upper position, - # while `self.operator_range` does not. So, go one to the left, unless - # we're in the line mode, then we don't want to risk going to the - # previous line, and missing one line in the selection. - if self.type != TextObjectType.LINEWISE: - to -= 1 - - 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 - - -# Typevar for any text object function: -TextObjectFunction = Callable[[E], TextObject] -_TOF = TypeVar("_TOF", bound=TextObjectFunction) - - -def create_text_object_decorator( - key_bindings: KeyBindings, -) -> Callable[..., Callable[[_TOF], _TOF]]: - """ - Create a decorator that can be used to register Vi text object implementations. - """ - - def text_object_decorator( - *keys: Union[Keys, str], - filter: Filter = Always(), - no_move_handler: bool = False, - no_selection_handler: bool = False, - eager: bool = False, - ) -> Callable[[_TOF], _TOF]: - """ - 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.) - """ - - def decorator(text_object_func: _TOF) -> _TOF: - @key_bindings.add( - *keys, filter=vi_waiting_for_text_object_mode & filter, eager=eager - ) - def _apply_operator_to_text_object(event: E) -> None: - # Arguments are multiplied. - vi_state = event.app.vi_state - event._arg = str((vi_state.operator_arg or 1) * (event.arg or 1)) - - # Call the text object handler. - text_obj = text_object_func(event) - - # Get the operator function. - # (Should never be None here, given the - # `vi_waiting_for_text_object_mode` filter state.) - operator_func = vi_state.operator_func - - if text_obj is not None and operator_func is not None: - # Call the operator function with the text object. - operator_func(event, text_obj) - - # Clear operator. - event.app.vi_state.operator_func = None - event.app.vi_state.operator_arg = None - - # Register a move operation. (Doesn't need an operator.) - if not no_move_handler: - - @key_bindings.add( - *keys, - filter=~vi_waiting_for_text_object_mode - & filter - & vi_navigation_mode, - eager=eager, - ) - def _move_in_navigation_mode(event: E) -> None: - """ - 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: - - @key_bindings.add( - *keys, - filter=~vi_waiting_for_text_object_mode - & filter - & vi_selection_mode, - eager=eager, - ) - def _move_in_selection_mode(event: E) -> None: - """ - Move handler for selection mode. - """ - text_object = text_object_func(event) - buff = event.current_buffer - selection_state = buff.selection_state - - if selection_state is None: - return # Should not happen, because of the `vi_selection_mode` filter. - - # 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 - - selection_state.original_cursor_position = start - buff.cursor_position = end - - # Take selection type from text object. - if text_object.type == TextObjectType.LINEWISE: - selection_state.type = SelectionType.LINES - else: - 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 - - -# Typevar for any operator function: -OperatorFunction = Callable[[E, TextObject], None] -_OF = TypeVar("_OF", bound=OperatorFunction) - - -def create_operator_decorator( - key_bindings: KeyBindings, -) -> Callable[..., Callable[[_OF], _OF]]: - """ - Create a decorator that can be used for registering Vi operators. - """ - - def operator_decorator( - *keys: Union[Keys, str], filter: Filter = Always(), eager: bool = False - ) -> Callable[[_OF], _OF]: - """ - Register a Vi operator. - - Usage:: - - @operator('d', filter=...) - def handler(event, text_object): - # Do something with the text object here. - """ - - def decorator(operator_func: _OF) -> _OF: - @key_bindings.add( - *keys, - filter=~vi_waiting_for_text_object_mode & filter & vi_navigation_mode, - eager=eager, - ) - def _operator_in_navigation(event: E) -> None: - """ - 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.app.vi_state.operator_func = operator_func - event.app.vi_state.operator_arg = event.arg - - @key_bindings.add( - *keys, - filter=~vi_waiting_for_text_object_mode & filter & vi_selection_mode, - eager=eager, - ) - def _operator_in_selection(event: E) -> None: - """ - Handle operator in selection mode. - """ - buff = event.current_buffer - selection_state = buff.selection_state - - if selection_state is not None: - # 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() -> KeyBindingsBase: - """ - Vi extensions. - - # Overview of Readline Vi commands: - # http://www.catonmat.net/download/bash-vi-editing-mode-cheat-sheet.pdf - """ - # 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. - - key_bindings = KeyBindings() - handle = key_bindings.add - - # (Note: Always take the navigation bindings in read-only mode, even when - # ViState says different.) - - TransformFunction = Tuple[Tuple[str, ...], Filter, Callable[[str], str]] - - vi_transform_functions: List[TransformFunction] = [ - # 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: get_app().vi_state.tilde_operator), - lambda string: string.swapcase(), - ), - ] - - # Insert a character literally (quoted insert). - handle("c-v", filter=vi_insert_mode)(get_by_name("quoted-insert")) - - @handle("escape") - def _back_to_navigation(event: E) -> None: - """ - Escape goes to vi navigation mode. - """ - buffer = event.current_buffer - vi_state = event.app.vi_state - - if vi_state.input_mode in (InputMode.INSERT, InputMode.REPLACE): - buffer.cursor_position += buffer.document.get_cursor_left_position() - - vi_state.input_mode = InputMode.NAVIGATION - - if bool(buffer.selection_state): - buffer.exit_selection() - - @handle("k", filter=vi_selection_mode) - def _up_in_selection(event: E) -> None: - """ - Arrow up in selection mode. - """ - event.current_buffer.cursor_up(count=event.arg) - - @handle("j", filter=vi_selection_mode) - def _down_in_selection(event: E) -> None: - """ - Arrow down in selection mode. - """ - event.current_buffer.cursor_down(count=event.arg) - - @handle("up", filter=vi_navigation_mode) - @handle("c-p", filter=vi_navigation_mode) - def _up_in_navigation(event: E) -> None: - """ - Arrow up and ControlP in navigation mode go up. - """ - event.current_buffer.auto_up(count=event.arg) - - @handle("k", filter=vi_navigation_mode) - def _go_up(event: E) -> None: - """ - 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("down", filter=vi_navigation_mode) - @handle("c-n", filter=vi_navigation_mode) - def _go_down(event: E) -> None: - """ - Arrow down and Control-N in navigation mode. - """ - event.current_buffer.auto_down(count=event.arg) - - @handle("j", filter=vi_navigation_mode) - def _go_down2(event: E) -> None: - """ - 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("backspace", filter=vi_navigation_mode) - def _go_left(event: E) -> None: - """ - In navigation-mode, move cursor. - """ - event.current_buffer.cursor_position += ( - event.current_buffer.document.get_cursor_left_position(count=event.arg) - ) - - @handle("c-n", filter=vi_insert_mode) - def _complete_next(event: E) -> None: - b = event.current_buffer - - if b.complete_state: - b.complete_next() - else: - b.start_completion(select_first=True) - - @handle("c-p", filter=vi_insert_mode) - def _complete_prev(event: E) -> None: - """ - Control-P: To previous completion. - """ - b = event.current_buffer - - if b.complete_state: - b.complete_previous() - else: - b.start_completion(select_last=True) - - @handle("c-g", filter=vi_insert_mode) - @handle("c-y", filter=vi_insert_mode) - def _accept_completion(event: E) -> None: - """ - Accept current completion. - """ - event.current_buffer.complete_state = None - - @handle("c-e", filter=vi_insert_mode) - def _cancel_completion(event: E) -> None: - """ - Cancel completion. Go back to originally typed text. - """ - event.current_buffer.cancel_completion() - - @Condition - def is_returnable() -> bool: - return get_app().current_buffer.is_returnable - - # In navigation mode, pressing enter will always return the input. - handle("enter", filter=vi_navigation_mode & is_returnable)( - get_by_name("accept-line") - ) - - # In insert mode, also accept input when enter is pressed, and the buffer - # has been marked as single line. - handle("enter", filter=is_returnable & ~is_multiline)(get_by_name("accept-line")) - - @handle("enter", filter=~is_returnable & vi_navigation_mode) - def _start_of_next_line(event: E) -> None: - """ - Go to the beginning of next line. - """ - b = event.current_buffer - b.cursor_down(count=event.arg) - b.cursor_position += b.document.get_start_of_line_position( - after_whitespace=True - ) - - # ** In navigation mode ** - - # List of navigation commands: http://hea-www.harvard.edu/~fine/Tech/vi.html - - @handle("insert", filter=vi_navigation_mode) - def _insert_mode(event: E) -> None: - """ - Pressing the Insert key. - """ - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("insert", filter=vi_insert_mode) - def _navigation_mode(event: E) -> None: - """ - Pressing the Insert key. - """ - event.app.vi_state.input_mode = InputMode.NAVIGATION - - @handle("a", filter=vi_navigation_mode & ~is_read_only) - # ~IsReadOnly, because we want to stay in navigation mode for - # read-only buffers. - def _a(event: E) -> None: - event.current_buffer.cursor_position += ( - event.current_buffer.document.get_cursor_right_position() - ) - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("A", filter=vi_navigation_mode & ~is_read_only) - def _A(event: E) -> None: - event.current_buffer.cursor_position += ( - event.current_buffer.document.get_end_of_line_position() - ) - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("C", filter=vi_navigation_mode & ~is_read_only) - def _change_until_end_of_line(event: E) -> None: - """ - 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.app.clipboard.set_text(deleted) - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("c", "c", filter=vi_navigation_mode & ~is_read_only) - @handle("S", filter=vi_navigation_mode & ~is_read_only) - def _change_current_line(event: E) -> None: # TODO: implement 'arg' - """ - Change current line - """ - buffer = event.current_buffer - - # We copy the whole line. - data = ClipboardData(buffer.document.current_line, SelectionType.LINES) - event.app.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.app.vi_state.input_mode = InputMode.INSERT - - @handle("D", filter=vi_navigation_mode) - def _delete_until_end_of_line(event: E) -> None: - """ - Delete from cursor position until the end of the line. - """ - buffer = event.current_buffer - deleted = buffer.delete(count=buffer.document.get_end_of_line_position()) - event.app.clipboard.set_text(deleted) - - @handle("d", "d", filter=vi_navigation_mode) - def _delete_line(event: E) -> None: - """ - 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.app.clipboard.set_data(ClipboardData(deleted, SelectionType.LINES)) - - @handle("x", filter=vi_selection_mode) - def _cut(event: E) -> None: - """ - Cut selection. - ('x' is not an operator.) - """ - clipboard_data = event.current_buffer.cut_selection() - event.app.clipboard.set_data(clipboard_data) - - @handle("i", filter=vi_navigation_mode & ~is_read_only) - def _i(event: E) -> None: - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("I", filter=vi_navigation_mode & ~is_read_only) - def _I(event: E) -> None: - event.app.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() -> bool: - buff = get_app().current_buffer - return bool( - buff.selection_state and buff.selection_state.type == SelectionType.BLOCK - ) - - @handle("I", filter=in_block_selection & ~is_read_only) - def insert_in_block_selection(event: E, after: bool = False) -> None: - """ - Insert in block selection mode. - """ - buff = event.current_buffer - - # Store all cursor positions. - positions = [] - - if after: - - def get_pos(from_to: Tuple[int, int]) -> int: - return from_to[1] - - else: - - def get_pos(from_to: Tuple[int, int]) -> int: - 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.app.vi_state.input_mode = InputMode.INSERT_MULTIPLE - buff.exit_selection() - - @handle("A", filter=in_block_selection & ~is_read_only) - def _append_after_block(event: E) -> None: - insert_in_block_selection(event, after=True) - - @handle("J", filter=vi_navigation_mode & ~is_read_only) - def _join(event: E) -> None: - """ - Join lines. - """ - for i in range(event.arg): - event.current_buffer.join_next_line() - - @handle("g", "J", filter=vi_navigation_mode & ~is_read_only) - def _join_nospace(event: E) -> None: - """ - Join lines without space. - """ - for i in range(event.arg): - event.current_buffer.join_next_line(separator="") - - @handle("J", filter=vi_selection_mode & ~is_read_only) - def _join_selection(event: E) -> None: - """ - Join selected lines. - """ - event.current_buffer.join_selected_lines() - - @handle("g", "J", filter=vi_selection_mode & ~is_read_only) - def _join_selection_nospace(event: E) -> None: - """ - Join selected lines without space. - """ - event.current_buffer.join_selected_lines(separator="") - - @handle("p", filter=vi_navigation_mode) - def _paste(event: E) -> None: - """ - Paste after - """ - event.current_buffer.paste_clipboard_data( - event.app.clipboard.get_data(), - count=event.arg, - paste_mode=PasteMode.VI_AFTER, - ) - - @handle("P", filter=vi_navigation_mode) - def _paste_before(event: E) -> None: - """ - Paste before - """ - event.current_buffer.paste_clipboard_data( - event.app.clipboard.get_data(), - count=event.arg, - paste_mode=PasteMode.VI_BEFORE, - ) - - @handle('"', Keys.Any, "p", filter=vi_navigation_mode) - def _paste_register(event: E) -> None: - """ - Paste from named register. - """ - c = event.key_sequence[1].data - if c in vi_register_names: - data = event.app.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=vi_navigation_mode) - def _paste_register_before(event: E) -> None: - """ - Paste (before) from named register. - """ - c = event.key_sequence[1].data - if c in vi_register_names: - data = event.app.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", filter=vi_navigation_mode) - def _replace(event: E) -> None: - """ - Go to 'replace-single'-mode. - """ - event.app.vi_state.input_mode = InputMode.REPLACE_SINGLE - - @handle("R", filter=vi_navigation_mode) - def _replace_mode(event: E) -> None: - """ - Go to 'replace'-mode. - """ - event.app.vi_state.input_mode = InputMode.REPLACE - - @handle("s", filter=vi_navigation_mode & ~is_read_only) - def _substitute(event: E) -> None: - """ - Substitute with new text - (Delete character(s) and go to insert mode.) - """ - text = event.current_buffer.delete(count=event.arg) - event.app.clipboard.set_text(text) - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("u", filter=vi_navigation_mode, save_before=(lambda e: False)) - def _undo(event: E) -> None: - for i in range(event.arg): - event.current_buffer.undo() - - @handle("V", filter=vi_navigation_mode) - def _visual_line(event: E) -> None: - """ - Start lines selection. - """ - event.current_buffer.start_selection(selection_type=SelectionType.LINES) - - @handle("c-v", filter=vi_navigation_mode) - def _visual_block(event: E) -> None: - """ - Enter block selection mode. - """ - event.current_buffer.start_selection(selection_type=SelectionType.BLOCK) - - @handle("V", filter=vi_selection_mode) - def _visual_line2(event: E) -> None: - """ - 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 is not None: - if selection_state.type != SelectionType.LINES: - selection_state.type = SelectionType.LINES - else: - event.current_buffer.exit_selection() - - @handle("v", filter=vi_navigation_mode) - def _visual(event: E) -> None: - """ - Enter character selection mode. - """ - event.current_buffer.start_selection(selection_type=SelectionType.CHARACTERS) - - @handle("v", filter=vi_selection_mode) - def _visual2(event: E) -> None: - """ - 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 is not None: - if selection_state.type != SelectionType.CHARACTERS: - selection_state.type = SelectionType.CHARACTERS - else: - event.current_buffer.exit_selection() - - @handle("c-v", filter=vi_selection_mode) - def _visual_block2(event: E) -> None: - """ - 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 is not None: - if selection_state.type != SelectionType.BLOCK: - selection_state.type = SelectionType.BLOCK - else: - event.current_buffer.exit_selection() - - @handle("a", "w", filter=vi_selection_mode) - @handle("a", "W", filter=vi_selection_mode) - def _visual_auto_word(event: E) -> None: - """ - 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=vi_navigation_mode) - def _delete(event: E) -> None: - """ - Delete character. - """ - buff = event.current_buffer - count = min(event.arg, len(buff.document.current_line_after_cursor)) - if count: - text = event.current_buffer.delete(count=count) - event.app.clipboard.set_text(text) - - @handle("X", filter=vi_navigation_mode) - def _delete_before_cursor(event: E) -> None: - buff = event.current_buffer - count = min(event.arg, len(buff.document.current_line_before_cursor)) - if count: - text = event.current_buffer.delete_before_cursor(count=count) - event.app.clipboard.set_text(text) - - @handle("y", "y", filter=vi_navigation_mode) - @handle("Y", filter=vi_navigation_mode) - def _yank_line(event: E) -> None: - """ - Yank the whole line. - """ - text = "\n".join(event.current_buffer.document.lines_from_current[: event.arg]) - event.app.clipboard.set_data(ClipboardData(text, SelectionType.LINES)) - - @handle("+", filter=vi_navigation_mode) - def _next_line(event: E) -> None: - """ - 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=vi_navigation_mode) - def _prev_line(event: E) -> None: - """ - 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=vi_navigation_mode) - def _indent(event: E) -> None: - """ - Indent lines. - """ - buffer = event.current_buffer - current_row = buffer.document.cursor_position_row - indent(buffer, current_row, current_row + event.arg) - - @handle("<", "<", filter=vi_navigation_mode) - def _unindent(event: E) -> None: - """ - Unindent lines. - """ - current_row = event.current_buffer.document.cursor_position_row - unindent(event.current_buffer, current_row, current_row + event.arg) - - @handle("O", filter=vi_navigation_mode & ~is_read_only) - def _open_above(event: E) -> None: - """ - Open line above and enter insertion mode - """ - event.current_buffer.insert_line_above(copy_margin=not in_paste_mode()) - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("o", filter=vi_navigation_mode & ~is_read_only) - def _open_below(event: E) -> None: - """ - Open line below and enter insertion mode - """ - event.current_buffer.insert_line_below(copy_margin=not in_paste_mode()) - event.app.vi_state.input_mode = InputMode.INSERT - - @handle("~", filter=vi_navigation_mode) - def _reverse_case(event: E) -> None: - """ - 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=vi_navigation_mode & ~is_read_only) - def _lowercase_line(event: E) -> None: - """ - Lowercase current line. - """ - buff = event.current_buffer - buff.transform_current_line(lambda s: s.lower()) - - @handle("g", "U", "U", filter=vi_navigation_mode & ~is_read_only) - def _uppercase_line(event: E) -> None: - """ - Uppercase current line. - """ - buff = event.current_buffer - buff.transform_current_line(lambda s: s.upper()) - - @handle("g", "~", "~", filter=vi_navigation_mode & ~is_read_only) - def _swapcase_line(event: E) -> None: - """ - Swap case of the current line. - """ - buff = event.current_buffer - buff.transform_current_line(lambda s: s.swapcase()) - - @handle("#", filter=vi_navigation_mode) - def _prev_occurence(event: E) -> None: - """ - Go to previous occurrence of this word. - """ - b = event.current_buffer - search_state = event.app.current_search_state - - search_state.text = b.document.get_word_under_cursor() - search_state.direction = SearchDirection.BACKWARD - - b.apply_search(search_state, count=event.arg, include_current_position=False) - - @handle("*", filter=vi_navigation_mode) - def _next_occurance(event: E) -> None: - """ - Go to next occurrence of this word. - """ - b = event.current_buffer - search_state = event.app.current_search_state - - search_state.text = b.document.get_word_under_cursor() - search_state.direction = SearchDirection.FORWARD - - b.apply_search(search_state, count=event.arg, include_current_position=False) - - @handle("(", filter=vi_navigation_mode) - def _begin_of_sentence(event: E) -> None: - # TODO: go to begin of sentence. - # XXX: should become text_object. - pass - - @handle(")", filter=vi_navigation_mode) - def _end_of_sentence(event: E) -> None: - # TODO: go to end of sentence. - # XXX: should become text_object. - pass - - operator = create_operator_decorator(key_bindings) - text_object = create_text_object_decorator(key_bindings) - - @handle(Keys.Any, filter=vi_waiting_for_text_object_mode) - def _unknown_text_object(event: E) -> None: - """ - Unknown key binding while waiting for a text object. - """ - event.app.output.bell() - - # - # *** Operators *** - # - - def create_delete_and_change_operators( - delete_only: bool, with_register: bool = False - ) -> None: - """ - 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. - """ - handler_keys: Iterable[str] - if with_register: - handler_keys = ('"', Keys.Any, "cd"[delete_only]) - else: - handler_keys = "cd"[delete_only] - - @operator(*handler_keys, filter=~is_read_only) - def delete_or_change_operator(event: E, text_object: TextObject) -> None: - 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.app.vi_state.named_registers[reg_name] = clipboard_data - else: - event.app.clipboard.set_data(clipboard_data) - - # Only go back to insert mode in case of 'change'. - if not delete_only: - event.app.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: Filter, transform_func: Callable[[str], str], *a: str - ) -> None: - @operator(*a, filter=filter & ~is_read_only) - def _(event: E, text_object: TextObject) -> None: - """ - 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(event: E, text_object: TextObject) -> None: - """ - Yank operator. (Copy text.) - """ - _, clipboard_data = text_object.cut(event.current_buffer) - if clipboard_data.text: - event.app.clipboard.set_data(clipboard_data) - - @operator('"', Keys.Any, "y") - def _yank_to_register(event: E, text_object: TextObject) -> None: - """ - 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.app.vi_state.named_registers[c] = clipboard_data - - @operator(">") - def _indent_text_object(event: E, text_object: TextObject) -> None: - """ - Indent. - """ - buff = event.current_buffer - from_, to = text_object.get_line_numbers(buff) - indent(buff, from_, to + 1, count=event.arg) - - @operator("<") - def _unindent_text_object(event: E, text_object: TextObject) -> None: - """ - 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 _reshape(event: E, text_object: TextObject) -> None: - """ - 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 _b(event: E) -> TextObject: - """ - 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 _B(event: E) -> TextObject: - """ - 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 _dollar(event: E) -> TextObject: - """ - '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 _word_forward(event: E) -> TextObject: - """ - '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 _WORD_forward(event: E) -> TextObject: - """ - '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 _end_of_word(event: E) -> TextObject: - """ - 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 _end_of_WORD(event: E) -> TextObject: - """ - 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 _inner_word(event: E) -> TextObject: - """ - 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 _a_word(event: E) -> TextObject: - """ - 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 _inner_WORD(event: E) -> TextObject: - """ - 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 _a_WORD(event: E) -> TextObject: - """ - 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 _paragraph(event: E) -> TextObject: - """ - 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 _start_of_line(event: E) -> TextObject: - """'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 _hard_start_of_line(event: E) -> TextObject: - """ - '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: str, ci_end: str, inner: bool, key: Optional[str] = None - ) -> 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: E) -> TextObject: - 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 _previous_section(event: E) -> TextObject: - """ - 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 _next_section(event: E) -> TextObject: - """ - 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 _next_occurence(event: E) -> TextObject: - """ - Go to next occurrence of character. Typing 'fx' will move the - cursor to the next occurrence of character. 'x'. - """ - event.app.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 _previous_occurance(event: E) -> TextObject: - """ - Go to previous occurrence of character. Typing 'Fx' will move the - cursor to the previous occurrence of character. 'x'. - """ - event.app.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 _t(event: E) -> TextObject: - """ - Move right to the next occurrence of c, then one char backward. - """ - event.app.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 _T(event: E) -> TextObject: - """ - Move left to the previous occurrence of c, then one char forward. - """ - event.app.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: bool) -> None: - """ - Create ',' and ';' commands. - """ - - @text_object("," if reverse else ";") - def _(event: E) -> TextObject: - """ - Repeat the last 'f'/'F'/'t'/'T' command. - """ - pos: Optional[int] = 0 - vi_state = event.app.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("left") - def _left(event: E) -> TextObject: - """ - 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 _down(event: E) -> TextObject: - """ - 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 _up(event: E) -> TextObject: - """ - 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("right") - def _right(event: E) -> TextObject: - """ - 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 _top_of_screen(event: E) -> TextObject: - """ - Moves to the start of the visible region. (Below the scroll offset.) - Implements 'cH', 'dH', 'H'. - """ - w = event.app.layout.current_window - 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 _middle_of_screen(event: E) -> TextObject: - """ - Moves cursor to the vertical center of the visible region. - Implements 'cM', 'dM', 'M'. - """ - w = event.app.layout.current_window - 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 _end_of_screen(event: E) -> TextObject: - """ - Moves to the end of the visible region. (Above the scroll offset.) - """ - w = event.app.layout.current_window - 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 _search_next(event: E) -> TextObject: - """ - Search next. - """ - buff = event.current_buffer - search_state = event.app.current_search_state - - cursor_position = buff.get_search_position( - search_state, include_current_position=False, count=event.arg - ) - return TextObject(cursor_position - buff.cursor_position) - - @handle("n", filter=vi_navigation_mode) - def _search_next2(event: E) -> None: - """ - Search next in navigation mode. (This goes through the history.) - """ - search_state = event.app.current_search_state - - event.current_buffer.apply_search( - search_state, include_current_position=False, count=event.arg - ) - - @text_object("N", no_move_handler=True) - def _search_previous(event: E) -> TextObject: - """ - Search previous. - """ - buff = event.current_buffer - search_state = event.app.current_search_state - - cursor_position = buff.get_search_position( - ~search_state, include_current_position=False, count=event.arg - ) - return TextObject(cursor_position - buff.cursor_position) - - @handle("N", filter=vi_navigation_mode) - def _search_previous2(event: E) -> None: - """ - Search previous in navigation mode. (This goes through the history.) - """ - search_state = event.app.current_search_state - - event.current_buffer.apply_search( - ~search_state, include_current_position=False, count=event.arg - ) - - @handle("z", "+", filter=vi_navigation_mode | vi_selection_mode) - @handle("z", "t", filter=vi_navigation_mode | vi_selection_mode) - @handle("z", "enter", filter=vi_navigation_mode | vi_selection_mode) - def _scroll_top(event: E) -> None: - """ - Scrolls the window to makes the current line the first line in the visible region. - """ - b = event.current_buffer - event.app.layout.current_window.vertical_scroll = b.document.cursor_position_row - - @handle("z", "-", filter=vi_navigation_mode | vi_selection_mode) - @handle("z", "b", filter=vi_navigation_mode | vi_selection_mode) - def _scroll_bottom(event: E) -> None: - """ - Scrolls the window to makes the current line the last line in the visible region. - """ - # We can safely set the scroll offset to zero; the Window will make - # sure that it scrolls at least enough to make the cursor visible - # again. - event.app.layout.current_window.vertical_scroll = 0 - - @handle("z", "z", filter=vi_navigation_mode | vi_selection_mode) - def _scroll_center(event: E) -> None: - """ - Center Window vertically around cursor. - """ - w = event.app.layout.current_window - b = event.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 _goto_corresponding_bracket(event: E) -> TextObject: - """ - 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 _to_column(event: E) -> TextObject: - """ - 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 _goto_first_line(event: E) -> TextObject: - """ - Go to the start of the very first line. - 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 _goto_last_line(event: E) -> TextObject: - """ - 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 _ge(event: E) -> TextObject: - """ - 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 _gE(event: E) -> TextObject: - """ - 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 _gm(event: E) -> TextObject: - """ - Like g0, but half a screenwidth to the right. (Or as much as possible.) - """ - w = event.app.layout.current_window - 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 _last_line(event: E) -> TextObject: - """ - 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=has_arg) - def _to_nth_history_line(event: E) -> None: - """ - 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=vi_navigation_mode - | vi_selection_mode - | vi_waiting_for_text_object_mode, - ) - def _arg(event: E) -> None: - """ - Always handle numberics in navigation mode as arg. - """ - event.append_to_arg_count(event.data) - - @handle( - "0", - filter=( - vi_navigation_mode | vi_selection_mode | vi_waiting_for_text_object_mode - ) - & has_arg, - ) - def _0_arg(event: E) -> None: - """ - Zero when an argument was already give. - """ - event.append_to_arg_count(event.data) - - @handle(Keys.Any, filter=vi_replace_mode) - def _insert_text(event: E) -> None: - """ - Insert data at cursor position. - """ - event.current_buffer.insert_text(event.data, overwrite=True) - - @handle(Keys.Any, filter=vi_replace_single_mode) - def _replace_single(event: E) -> None: - """ - Replace single character at cursor position. - """ - event.current_buffer.insert_text(event.data, overwrite=True) - event.current_buffer.cursor_position -= 1 - event.app.vi_state.input_mode = InputMode.NAVIGATION - - @handle( - Keys.Any, - filter=vi_insert_multiple_mode, - save_before=(lambda e: not e.is_repeat), - ) - def _insert_text_multiple_cursors(event: E) -> None: - """ - 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 = [ - pos + i + 1 for i, pos in enumerate(buff.multiple_cursor_positions) - ] - - # Set result. - buff.text = "".join(text) - buff.multiple_cursor_positions = new_cursor_positions - buff.cursor_position += 1 - - @handle("backspace", filter=vi_insert_multiple_mode) - def _delete_before_multiple_cursors(event: E) -> None: - """ - 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.app.output.bell() - - @handle("delete", filter=vi_insert_multiple_mode) - def _delete_after_multiple_cursors(event: E) -> None: - """ - 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.app.output.bell() - - @handle("left", filter=vi_insert_multiple_mode) - def _left_multiple(event: E) -> None: - """ - Move all cursors to the left. - (But keep all cursors on the same line.) - """ - buff = event.current_buffer - new_positions = [] - - for p in buff.multiple_cursor_positions: - if buff.document.translate_index_to_position(p)[1] > 0: - p -= 1 - new_positions.append(p) - - buff.multiple_cursor_positions = new_positions - - if buff.document.cursor_position_col > 0: - buff.cursor_position -= 1 - - @handle("right", filter=vi_insert_multiple_mode) - def _right_multiple(event: E) -> None: - """ - Move all cursors to the right. - (But keep all cursors on the same line.) - """ - buff = event.current_buffer - new_positions = [] - - for p in buff.multiple_cursor_positions: - row, column = buff.document.translate_index_to_position(p) - if column < len(buff.document.lines[row]): - p += 1 - new_positions.append(p) - - buff.multiple_cursor_positions = new_positions - - if not buff.document.is_cursor_at_the_end_of_line: - buff.cursor_position += 1 - - @handle("up", filter=vi_insert_multiple_mode) - @handle("down", filter=vi_insert_multiple_mode) - def _updown_multiple(event: E) -> None: - """ - Ignore all up/down key presses when in multiple cursor mode. - """ - - @handle("c-x", "c-l", filter=vi_insert_mode) - def _complete_line(event: E) -> None: - """ - 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("c-x", "c-f", filter=vi_insert_mode) - def _complete_filename(event: E) -> None: - """ - Complete file names. - """ - # TODO - pass - - @handle("c-k", filter=vi_insert_mode | vi_replace_mode) - def _digraph(event: E) -> None: - """ - Go into digraph mode. - """ - event.app.vi_state.waiting_for_digraph = True - - @Condition - def digraph_symbol_1_given() -> bool: - return get_app().vi_state.digraph_symbol1 is not None - - @handle(Keys.Any, filter=vi_digraph_mode & ~digraph_symbol_1_given) - def _digraph1(event: E) -> None: - """ - First digraph symbol. - """ - event.app.vi_state.digraph_symbol1 = event.data - - @handle(Keys.Any, filter=vi_digraph_mode & digraph_symbol_1_given) - def _create_digraph(event: E) -> None: - """ - Insert digraph. - """ - try: - # Lookup. - code: Tuple[str, str] = ( - event.app.vi_state.digraph_symbol1 or "", - event.data, - ) - if code not in DIGRAPHS: - code = code[::-1] # Try reversing. - symbol = DIGRAPHS[code] - except KeyError: - # Unknown digraph. - event.app.output.bell() - else: - # Insert digraph. - overwrite = event.app.vi_state.input_mode == InputMode.REPLACE - event.current_buffer.insert_text(chr(symbol), overwrite=overwrite) - event.app.vi_state.waiting_for_digraph = False - finally: - event.app.vi_state.waiting_for_digraph = False - event.app.vi_state.digraph_symbol1 = None - - @handle("c-o", filter=vi_insert_mode | vi_replace_mode) - def _quick_normal_mode(event: E) -> None: - """ - Go into normal mode for one single action. - """ - event.app.vi_state.temporary_navigation_mode = True - - @handle("q", Keys.Any, filter=vi_navigation_mode & ~vi_recording_macro) - def _start_macro(event: E) -> None: - """ - Start recording macro. - """ - c = event.key_sequence[1].data - if c in vi_register_names: - vi_state = event.app.vi_state - - vi_state.recording_register = c - vi_state.current_recording = "" - - @handle("q", filter=vi_navigation_mode & vi_recording_macro) - def _stop_macro(event: E) -> None: - """ - Stop recording macro. - """ - vi_state = event.app.vi_state - - # Store and stop recording. - if vi_state.recording_register: - vi_state.named_registers[vi_state.recording_register] = ClipboardData( - vi_state.current_recording - ) - vi_state.recording_register = None - vi_state.current_recording = "" - - @handle("@", Keys.Any, filter=vi_navigation_mode, record_in_macro=False) - def _execute_macro(event: E) -> None: - """ - Execute macro. - - Notice that we pass `record_in_macro=False`. This ensures that the `@x` - keys don't appear in the recording itself. This function inserts the - body of the called macro back into the KeyProcessor, so these keys will - be added later on to the macro of their handlers have - `record_in_macro=True`. - """ - # Retrieve macro. - c = event.key_sequence[1].data - try: - macro = event.app.vi_state.named_registers[c] - except KeyError: - return - - # Expand macro (which is a string in the register), in individual keys. - # Use vt100 parser for this. - keys: List[KeyPress] = [] - - parser = Vt100Parser(keys.append) - parser.feed(macro.text) - parser.flush() - - # Now feed keys back to the input processor. - for _ in range(event.arg): - event.app.key_processor.feed_multiple(keys, first=True) - - return ConditionalKeyBindings(key_bindings, vi_mode) - - -def load_vi_search_bindings() -> KeyBindingsBase: - key_bindings = KeyBindings() - handle = key_bindings.add - from . import search - - @Condition - def search_buffer_is_empty() -> bool: - "Returns True when the search buffer is empty." - return get_app().current_buffer.text == "" - - # Vi-style forward search. - handle( - "/", - filter=(vi_navigation_mode | vi_selection_mode) & ~vi_search_direction_reversed, - )(search.start_forward_incremental_search) - handle( - "?", - filter=(vi_navigation_mode | vi_selection_mode) & vi_search_direction_reversed, - )(search.start_forward_incremental_search) - handle("c-s")(search.start_forward_incremental_search) - - # Vi-style backward search. - handle( - "?", - filter=(vi_navigation_mode | vi_selection_mode) & ~vi_search_direction_reversed, - )(search.start_reverse_incremental_search) - handle( - "/", - filter=(vi_navigation_mode | vi_selection_mode) & vi_search_direction_reversed, - )(search.start_reverse_incremental_search) - handle("c-r")(search.start_reverse_incremental_search) - - # Apply the search. (At the / or ? prompt.) - handle("enter", filter=is_searching)(search.accept_search) - - handle("c-r", filter=is_searching)(search.reverse_incremental_search) - handle("c-s", filter=is_searching)(search.forward_incremental_search) - - handle("c-c")(search.abort_search) - handle("c-g")(search.abort_search) - handle("backspace", filter=search_buffer_is_empty)(search.abort_search) - - # Handle escape. This should accept the search, just like readline. - # `abort_search` would be a meaningful alternative. - handle("escape")(search.accept_search) - - return ConditionalKeyBindings(key_bindings, vi_mode) diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/defaults.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/defaults.py deleted file mode 100644 index baa5974333b..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/defaults.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Default key bindings.:: - - key_bindings = load_key_bindings() - app = Application(key_bindings=key_bindings) -""" -from prompt_toolkit.filters import buffer_has_focus -from prompt_toolkit.key_binding.bindings.basic import load_basic_bindings -from prompt_toolkit.key_binding.bindings.cpr import load_cpr_bindings -from prompt_toolkit.key_binding.bindings.emacs import ( - load_emacs_bindings, - load_emacs_search_bindings, - load_emacs_shift_selection_bindings, -) -from prompt_toolkit.key_binding.bindings.mouse import load_mouse_bindings -from prompt_toolkit.key_binding.bindings.vi import ( - load_vi_bindings, - load_vi_search_bindings, -) -from prompt_toolkit.key_binding.key_bindings import ( - ConditionalKeyBindings, - KeyBindingsBase, - merge_key_bindings, -) - -__all__ = [ - "load_key_bindings", -] - - -def load_key_bindings() -> KeyBindingsBase: - """ - Create a KeyBindings object that contains the default key bindings. - """ - all_bindings = merge_key_bindings( - [ - # Load basic bindings. - load_basic_bindings(), - # Load emacs bindings. - load_emacs_bindings(), - load_emacs_search_bindings(), - load_emacs_shift_selection_bindings(), - # Load Vi bindings. - load_vi_bindings(), - load_vi_search_bindings(), - ] - ) - - return merge_key_bindings( - [ - # Make sure that the above key bindings are only active if the - # currently focused control is a `BufferControl`. For other controls, we - # don't want these key bindings to intervene. (This would break "ptterm" - # for instance, which handles 'Keys.Any' in the user control itself.) - ConditionalKeyBindings(all_bindings, buffer_has_focus), - # Active, even when no buffer has been focused. - load_mouse_bindings(), - load_cpr_bindings(), - ] - ) diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/digraphs.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/digraphs.py deleted file mode 100644 index ad3d288a8a3..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/digraphs.py +++ /dev/null @@ -1,1377 +0,0 @@ -""" -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 -""" -from typing import Dict, Tuple - -__all__ = [ - "DIGRAPHS", -] - -# digraphs for Unicode from RFC1345 -# (also work for ISO-8859-1 aka latin1) -DIGRAPHS: Dict[Tuple[str, str], int] = { - ("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/py3/prompt_toolkit/key_binding/emacs_state.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/emacs_state.py deleted file mode 100644 index 4c996224a07..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/emacs_state.py +++ /dev/null @@ -1,36 +0,0 @@ -from typing import List, Optional - -from .key_processor import KeyPress - -__all__ = [ - "EmacsState", -] - - -class EmacsState: - """ - Mutable class to hold Emacs specific state. - """ - - def __init__(self) -> None: - # Simple macro recording. (Like Readline does.) - # (For Emacs mode.) - self.macro: Optional[List[KeyPress]] = [] - self.current_recording: Optional[List[KeyPress]] = None - - def reset(self) -> None: - self.current_recording = None - - @property - def is_recording(self) -> bool: - "Tell whether we are recording a macro." - return self.current_recording is not None - - def start_macro(self) -> None: - "Start recording macro." - self.current_recording = [] - - def end_macro(self) -> None: - "End recording macro." - self.macro = self.current_recording - self.current_recording = None diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/key_bindings.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/key_bindings.py deleted file mode 100644 index 03bc79ef01d..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/key_bindings.py +++ /dev/null @@ -1,672 +0,0 @@ -""" -Key bindings registry. - -A `KeyBindings` 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:: - - kb = KeyBindings() - - @kb.add(Keys.ControlX, Keys.ControlC, filter=INSERT) - def handler(event): - # Handle ControlX-ControlC key sequence. - pass - -It is also possible to combine multiple KeyBindings objects. We do this in the -default key bindings. There are some KeyBindings objects that contain the Emacs -bindings, while others contain the Vi bindings. They are merged together using -`merge_key_bindings`. - -We also have a `ConditionalKeyBindings` object that can enable/disable a group of -key bindings at once. - - -It is also possible to add a filter to a function, before a key binding has -been assigned, through the `key_binding` decorator.:: - - # First define a key handler with the `filter`. - @key_binding(filter=condition) - def my_key_binding(event): - ... - - # Later, add it to the key bindings. - kb.add(Keys.A, my_key_binding) -""" -from abc import ABCMeta, abstractmethod, abstractproperty -from inspect import isawaitable -from typing import ( - TYPE_CHECKING, - Awaitable, - Callable, - Hashable, - List, - Optional, - Sequence, - Tuple, - TypeVar, - Union, - cast, -) - -from prompt_toolkit.cache import SimpleCache -from prompt_toolkit.filters import FilterOrBool, Never, to_filter -from prompt_toolkit.keys import KEY_ALIASES, Keys - -if TYPE_CHECKING: - # Avoid circular imports. - from .key_processor import KeyPressEvent - - # The only two return values for a mouse hander (and key bindings) are - # `None` and `NotImplemented`. For the type checker it's best to annotate - # this as `object`. (The consumer never expects a more specific instance: - # checking for NotImplemented can be done using `is NotImplemented`.) - NotImplementedOrNone = object - # Other non-working options are: - # * Optional[Literal[NotImplemented]] - # --> Doesn't work, Literal can't take an Any. - # * None - # --> Doesn't work. We can't assign the result of a function that - # returns `None` to a variable. - # * Any - # --> Works, but too broad. - - -__all__ = [ - "NotImplementedOrNone", - "Binding", - "KeyBindingsBase", - "KeyBindings", - "ConditionalKeyBindings", - "merge_key_bindings", - "DynamicKeyBindings", - "GlobalOnlyKeyBindings", -] - -# Key bindings can be regular functions or coroutines. -# In both cases, if they return `NotImplemented`, the UI won't be invalidated. -# This is mainly used in case of mouse move events, to prevent excessive -# repainting during mouse move events. -KeyHandlerCallable = Callable[ - ["KeyPressEvent"], Union["NotImplementedOrNone", Awaitable["NotImplementedOrNone"]] -] - - -class Binding: - """ - Key binding: (key sequence + handler + filter). - (Immutable binding class.) - - :param record_in_macro: When True, don't record this key binding when a - macro is recorded. - """ - - def __init__( - self, - keys: Tuple[Union[Keys, str], ...], - handler: KeyHandlerCallable, - filter: FilterOrBool = True, - eager: FilterOrBool = False, - is_global: FilterOrBool = False, - save_before: Callable[["KeyPressEvent"], bool] = (lambda e: True), - record_in_macro: FilterOrBool = True, - ) -> None: - self.keys = keys - self.handler = handler - self.filter = to_filter(filter) - self.eager = to_filter(eager) - self.is_global = to_filter(is_global) - self.save_before = save_before - self.record_in_macro = to_filter(record_in_macro) - - def call(self, event: "KeyPressEvent") -> None: - result = self.handler(event) - - # If the handler is a coroutine, create an asyncio task. - if isawaitable(result): - awaitable = cast(Awaitable["NotImplementedOrNone"], result) - - async def bg_task() -> None: - result = await awaitable - if result != NotImplemented: - event.app.invalidate() - - event.app.create_background_task(bg_task()) - - elif result != NotImplemented: - event.app.invalidate() - - def __repr__(self) -> str: - return "{}(keys={!r}, handler={!r})".format( - self.__class__.__name__, - self.keys, - self.handler, - ) - - -# Sequence of keys presses. -KeysTuple = Tuple[Union[Keys, str], ...] - - -class KeyBindingsBase(metaclass=ABCMeta): - """ - Interface for a KeyBindings. - """ - - @abstractproperty - def _version(self) -> Hashable: - """ - For cache invalidation. - This should increase every time that - something changes. - """ - return 0 - - @abstractmethod - def get_bindings_for_keys(self, keys: KeysTuple) -> List[Binding]: - """ - Return a list of key bindings that can handle these keys. - (This return also inactive bindings, so the `filter` still has to be - called, for checking it.) - - :param keys: tuple of keys. - """ - return [] - - @abstractmethod - def get_bindings_starting_with_keys(self, keys: KeysTuple) -> List[Binding]: - """ - 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. - """ - return [] - - @abstractproperty - def bindings(self) -> List[Binding]: - """ - List of `Binding` objects. - (These need to be exposed, so that `KeyBindings` objects can be merged - together.) - """ - return [] - - # `add` and `remove` don't have to be part of this interface. - - -T = TypeVar("T", bound=Union[KeyHandlerCallable, Binding]) - - -class KeyBindings(KeyBindingsBase): - """ - A container for a set of key bindings. - - Example usage:: - - kb = KeyBindings() - - @kb.add('c-t') - def _(event): - print('Control-T pressed') - - @kb.add('c-a', 'c-b') - def _(event): - print('Control-A pressed, followed by Control-B') - - @kb.add('c-x', filter=is_searching) - def _(event): - print('Control-X pressed') # Works only if we are searching. - - """ - - def __init__(self) -> None: - self._bindings: List[Binding] = [] - self._get_bindings_for_keys_cache: SimpleCache[ - KeysTuple, List[Binding] - ] = SimpleCache(maxsize=10000) - self._get_bindings_starting_with_keys_cache: SimpleCache[ - KeysTuple, List[Binding] - ] = SimpleCache(maxsize=1000) - self.__version = 0 # For cache invalidation. - - def _clear_cache(self) -> None: - self.__version += 1 - self._get_bindings_for_keys_cache.clear() - self._get_bindings_starting_with_keys_cache.clear() - - @property - def bindings(self) -> List[Binding]: - return self._bindings - - @property - def _version(self) -> Hashable: - return self.__version - - def add( - self, - *keys: Union[Keys, str], - filter: FilterOrBool = True, - eager: FilterOrBool = False, - is_global: FilterOrBool = False, - save_before: Callable[["KeyPressEvent"], bool] = (lambda e: True), - record_in_macro: FilterOrBool = True, - ) -> Callable[[T], T]: - """ - Decorator for adding a key bindings. - - :param filter: :class:`~prompt_toolkit.filters.Filter` to determine - when this key binding is active. - :param eager: :class:`~prompt_toolkit.filters.Filter` 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 is_global: When this key bindings is added to a `Container` or - `Control`, make it a global (always active) binding. - :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.) - :param record_in_macro: Record these key bindings when a macro is - being recorded. (True by default.) - """ - assert keys - - keys = tuple(_parse_key(k) for k in keys) - - 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 key bindings. It will slow - # down every key press otherwise. - def decorator(func: T) -> T: - return func - - else: - - def decorator(func: T) -> T: - if isinstance(func, Binding): - # We're adding an existing Binding object. - self.bindings.append( - Binding( - keys, - func.handler, - filter=func.filter & to_filter(filter), - eager=to_filter(eager) | func.eager, - is_global=to_filter(is_global) | func.is_global, - save_before=func.save_before, - record_in_macro=func.record_in_macro, - ) - ) - else: - self.bindings.append( - Binding( - keys, - cast(KeyHandlerCallable, func), - filter=filter, - eager=eager, - is_global=is_global, - save_before=save_before, - record_in_macro=record_in_macro, - ) - ) - self._clear_cache() - - return func - - return decorator - - def remove(self, *args: Union[Keys, str, KeyHandlerCallable]) -> None: - """ - Remove a key binding. - - This expects either a function that was given to `add` method as - parameter or a sequence of key bindings. - - Raises `ValueError` when no bindings was found. - - Usage:: - - remove(handler) # Pass handler. - remove('c-x', 'c-a') # Or pass the key bindings. - """ - found = False - - if callable(args[0]): - assert len(args) == 1 - function = args[0] - - # Remove the given function. - for b in self.bindings: - if b.handler == function: - self.bindings.remove(b) - found = True - - else: - assert len(args) > 0 - args = cast(Tuple[Union[Keys, str]], args) - - # Remove this sequence of key bindings. - keys = tuple(_parse_key(k) for k in args) - - for b in self.bindings: - if b.keys == keys: - self.bindings.remove(b) - found = True - - if found: - self._clear_cache() - else: - # No key binding found for this function. Raise ValueError. - raise ValueError(f"Binding not found: {function!r}") - - # For backwards-compatibility. - add_binding = add - remove_binding = remove - - def get_bindings_for_keys(self, keys: KeysTuple) -> List[Binding]: - """ - 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() -> List[Binding]: - result: List[Tuple[int, Binding]] = [] - - for b in self.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' occurrences 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: KeysTuple) -> List[Binding]: - """ - 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() -> List[Binding]: - result = [] - for b in self.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) - - -def _parse_key(key: Union[Keys, str]) -> Union[str, Keys]: - """ - Replace key by alias and verify whether it's a valid one. - """ - # Already a parse key? -> Return it. - if isinstance(key, Keys): - return key - - # Lookup aliases. - key = KEY_ALIASES.get(key, key) - - # Replace 'space' by ' ' - if key == "space": - key = " " - - # Return as `Key` object when it's a special key. - try: - return Keys(key) - except ValueError: - pass - - # Final validation. - if len(key) != 1: - raise ValueError(f"Invalid key: {key}") - - return key - - -def key_binding( - filter: FilterOrBool = True, - eager: FilterOrBool = False, - is_global: FilterOrBool = False, - save_before: Callable[["KeyPressEvent"], bool] = (lambda event: True), - record_in_macro: FilterOrBool = True, -) -> Callable[[KeyHandlerCallable], Binding]: - """ - Decorator that turn a function into a `Binding` object. This can be added - to a `KeyBindings` object when a key binding is assigned. - """ - assert save_before is None or callable(save_before) - - filter = to_filter(filter) - eager = to_filter(eager) - is_global = to_filter(is_global) - save_before = save_before - record_in_macro = to_filter(record_in_macro) - keys = () - - def decorator(function: KeyHandlerCallable) -> Binding: - return Binding( - keys, - function, - filter=filter, - eager=eager, - is_global=is_global, - save_before=save_before, - record_in_macro=record_in_macro, - ) - - return decorator - - -class _Proxy(KeyBindingsBase): - """ - Common part for ConditionalKeyBindings and _MergedKeyBindings. - """ - - def __init__(self) -> None: - # `KeyBindings` to be synchronized with all the others. - self._bindings2: KeyBindingsBase = KeyBindings() - self._last_version: Hashable = () - - def _update_cache(self) -> None: - """ - If `self._last_version` is outdated, then this should update - the version and `self._bindings2`. - """ - raise NotImplementedError - - # Proxy methods to self._bindings2. - - @property - def bindings(self) -> List[Binding]: - self._update_cache() - return self._bindings2.bindings - - @property - def _version(self) -> Hashable: - self._update_cache() - return self._last_version - - def get_bindings_for_keys(self, keys: KeysTuple) -> List[Binding]: - self._update_cache() - return self._bindings2.get_bindings_for_keys(keys) - - def get_bindings_starting_with_keys(self, keys: KeysTuple) -> List[Binding]: - self._update_cache() - return self._bindings2.get_bindings_starting_with_keys(keys) - - -class ConditionalKeyBindings(_Proxy): - """ - Wraps around a `KeyBindings`. Disable/enable all the key bindings according to - the given (additional) filter.:: - - @Condition - def setting_is_true(): - return True # or False - - registry = ConditionalKeyBindings(key_bindings, 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 :class:`.KeyBindings` objects. - :param filter: :class:`~prompt_toolkit.filters.Filter` object. - """ - - def __init__( - self, key_bindings: KeyBindingsBase, filter: FilterOrBool = True - ) -> None: - - _Proxy.__init__(self) - - self.key_bindings = key_bindings - self.filter = to_filter(filter) - - def _update_cache(self) -> None: - "If the original key bindings was changed. Update our copy version." - expected_version = self.key_bindings._version - - if self._last_version != expected_version: - bindings2 = KeyBindings() - - # Copy all bindings from `self.key_bindings`, adding our condition. - for b in self.key_bindings.bindings: - bindings2.bindings.append( - Binding( - keys=b.keys, - handler=b.handler, - filter=self.filter & b.filter, - eager=b.eager, - is_global=b.is_global, - save_before=b.save_before, - record_in_macro=b.record_in_macro, - ) - ) - - self._bindings2 = bindings2 - self._last_version = expected_version - - -class _MergedKeyBindings(_Proxy): - """ - Merge multiple registries of key bindings into one. - - This class acts as a proxy to multiple :class:`.KeyBindings` objects, but - behaves as if this is just one bigger :class:`.KeyBindings`. - - :param registries: List of :class:`.KeyBindings` objects. - """ - - def __init__(self, registries: Sequence[KeyBindingsBase]) -> None: - _Proxy.__init__(self) - self.registries = registries - - def _update_cache(self) -> None: - """ - If one of the original registries was changed. Update our merged - version. - """ - expected_version = tuple(r._version for r in self.registries) - - if self._last_version != expected_version: - bindings2 = KeyBindings() - - for reg in self.registries: - bindings2.bindings.extend(reg.bindings) - - self._bindings2 = bindings2 - self._last_version = expected_version - - -def merge_key_bindings(bindings: Sequence[KeyBindingsBase]) -> _MergedKeyBindings: - """ - Merge multiple :class:`.Keybinding` objects together. - - Usage:: - - bindings = merge_key_bindings([bindings1, bindings2, ...]) - """ - return _MergedKeyBindings(bindings) - - -class DynamicKeyBindings(_Proxy): - """ - KeyBindings class that can dynamically returns any KeyBindings. - - :param get_key_bindings: Callable that returns a :class:`.KeyBindings` instance. - """ - - def __init__( - self, get_key_bindings: Callable[[], Optional[KeyBindingsBase]] - ) -> None: - self.get_key_bindings = get_key_bindings - self.__version = 0 - self._last_child_version = None - self._dummy = KeyBindings() # Empty key bindings. - - def _update_cache(self) -> None: - key_bindings = self.get_key_bindings() or self._dummy - assert isinstance(key_bindings, KeyBindingsBase) - version = id(key_bindings), key_bindings._version - - self._bindings2 = key_bindings - self._last_version = version - - -class GlobalOnlyKeyBindings(_Proxy): - """ - Wrapper around a :class:`.KeyBindings` object that only exposes the global - key bindings. - """ - - def __init__(self, key_bindings: KeyBindingsBase) -> None: - _Proxy.__init__(self) - self.key_bindings = key_bindings - - def _update_cache(self) -> None: - """ - If one of the original registries was changed. Update our merged - version. - """ - expected_version = self.key_bindings._version - - if self._last_version != expected_version: - bindings2 = KeyBindings() - - for b in self.key_bindings.bindings: - if b.is_global(): - bindings2.bindings.append(b) - - self._bindings2 = bindings2 - self._last_version = expected_version diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/key_processor.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/key_processor.py deleted file mode 100644 index 6fdd5191791..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/key_processor.py +++ /dev/null @@ -1,528 +0,0 @@ -""" -An :class:`~.KeyProcessor` receives callbacks for the keystrokes parsed from -the input in the :class:`~prompt_toolkit.inputstream.InputStream` instance. - -The `KeyProcessor` will according to the implemented keybindings call the -correct callbacks when new key presses are feed through `feed`. -""" -import weakref -from asyncio import Task, sleep -from collections import deque -from typing import TYPE_CHECKING, Any, Deque, Generator, List, Optional, Union - -from prompt_toolkit.application.current import get_app -from prompt_toolkit.enums import EditingMode -from prompt_toolkit.filters.app import vi_navigation_mode -from prompt_toolkit.keys import Keys -from prompt_toolkit.utils import Event - -from .key_bindings import Binding, KeyBindingsBase - -if TYPE_CHECKING: - from prompt_toolkit.application import Application - from prompt_toolkit.buffer import Buffer - - -__all__ = [ - "KeyProcessor", - "KeyPress", - "KeyPressEvent", -] - - -class KeyPress: - """ - :param key: A `Keys` instance or text (one character). - :param data: The received string on stdin. (Often vt100 escape codes.) - """ - - def __init__(self, key: Union[Keys, str], data: Optional[str] = None) -> None: - assert isinstance(key, Keys) or len(key) == 1 - - if data is None: - if isinstance(key, Keys): - data = key.value - else: - data = key # 'key' is a one character string. - - self.key = key - self.data = data - - def __repr__(self) -> str: - return f"{self.__class__.__name__}(key={self.key!r}, data={self.data!r})" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, KeyPress): - return False - return self.key == other.key and self.data == other.data - - -""" -Helper object to indicate flush operation in the KeyProcessor. -NOTE: the implementation is very similar to the VT100 parser. -""" -_Flush = KeyPress("?", data="_Flush") - - -class KeyProcessor: - """ - Statemachine that receives :class:`KeyPress` instances and according to the - key bindings in the given :class:`KeyBindings`, calls the matching handlers. - - :: - - p = KeyProcessor(key_bindings) - - # 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 key bindings. - - :param key_bindings: `KeyBindingsBase` instance. - """ - - def __init__(self, key_bindings: KeyBindingsBase) -> None: - self._bindings = key_bindings - - self.before_key_press = Event(self) - self.after_key_press = Event(self) - - self._flush_wait_task: Optional[Task[None]] = None - - self.reset() - - def reset(self) -> None: - self._previous_key_sequence: List[KeyPress] = [] - self._previous_handler: Optional[Binding] = None - - # The queue of keys not yet send to our _process generator/state machine. - self.input_queue: Deque[KeyPress] = 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: List[KeyPress] = [] - - #: Readline argument (for repetition of commands.) - #: https://www.gnu.org/software/bash/manual/html_node/Readline-Arguments.html - self.arg: Optional[str] = None - - # Start the processor coroutine. - self._process_coroutine = self._process() - self._process_coroutine.send(None) # type: ignore - - def _get_matches(self, key_presses: List[KeyPress]) -> List[Binding]: - """ - For a list of :class:`KeyPress` instances. Give the matching handlers - that would handle this. - """ - keys = tuple(k.key for k in key_presses) - - # Try match, with mode flag - return [b for b in self._bindings.get_bindings_for_keys(keys) if b.filter()] - - def _is_prefix_of_longer_match(self, key_presses: List[KeyPress]) -> bool: - """ - 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) - - # 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 = { - b.filter for b in self._bindings.get_bindings_starting_with_keys(keys) - } - - # When any key binding is active, return True. - return any(f() for f in filters) - - def _process(self) -> Generator[None, KeyPress, None]: - """ - 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: - flush = False - - if retry: - retry = False - else: - key = yield - if key is _Flush: - flush = True - else: - buffer.append(key) - - # If we have some key presses, check for matches. - if buffer: - matches = self._get_matches(buffer) - - if flush: - is_prefix_of_longer_match = False - else: - is_prefix_of_longer_match = self._is_prefix_of_longer_match(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()] - - 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: KeyPress, first: bool = False) -> None: - """ - Add a new :class:`KeyPress` to the input queue. - (Don't forget to call `process_keys` in order to process the queue.) - - :param first: If true, insert before everything else. - """ - if first: - self.input_queue.appendleft(key_press) - else: - self.input_queue.append(key_press) - - def feed_multiple(self, key_presses: List[KeyPress], first: bool = False) -> None: - """ - :param first: If true, insert before everything else. - """ - if first: - self.input_queue.extendleft(reversed(key_presses)) - else: - self.input_queue.extend(key_presses) - - def process_keys(self) -> None: - """ - 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. - """ - app = get_app() - - def not_empty() -> bool: - # When the application result is set, stop processing keys. (E.g. - # if ENTER was received, followed by a few additional key strokes, - # leave the other keys in the queue.) - if app.is_done: - # But if there are still CPRResponse keys in the queue, these - # need to be processed. - return any(k for k in self.input_queue if k.key == Keys.CPRResponse) - else: - return bool(self.input_queue) - - def get_next() -> KeyPress: - if app.is_done: - # Only process CPR responses. Everything else is typeahead. - cpr = [k for k in self.input_queue if k.key == Keys.CPRResponse][0] - self.input_queue.remove(cpr) - return cpr - else: - return self.input_queue.popleft() - - is_flush = False - - while not_empty(): - # Process next key. - key_press = get_next() - - is_flush = key_press is _Flush - is_cpr = key_press.key == Keys.CPRResponse - - if not is_flush and not is_cpr: - self.before_key_press.fire() - - try: - self._process_coroutine.send(key_press) - except Exception: - # If for some reason something goes wrong in the parser, (maybe - # an exception was raised) restart the processor for next time. - self.reset() - self.empty_queue() - raise - - if not is_flush and not is_cpr: - self.after_key_press.fire() - - # Skip timeout if the last key was flush. - if not is_flush: - self._start_timeout() - - def empty_queue(self) -> List[KeyPress]: - """ - Empty the input queue. Return the unprocessed input. - """ - key_presses = list(self.input_queue) - self.input_queue.clear() - - # Filter out CPRs. We don't want to return these. - key_presses = [k for k in key_presses if k.key != Keys.CPRResponse] - return key_presses - - def _call_handler(self, handler: Binding, key_sequence: List[KeyPress]) -> None: - app = get_app() - was_recording_emacs = app.emacs_state.is_recording - was_recording_vi = bool(app.vi_state.recording_register) - was_temporary_navigation_mode = app.vi_state.temporary_navigation_mode - 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. - if handler.save_before(event): - event.app.current_buffer.save_to_undo_stack() - - # Call handler. - from prompt_toolkit.buffer import EditReadOnlyBuffer - - 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 ignore that. We sound a bell and go on. - app.output.bell() - - if was_temporary_navigation_mode: - self._leave_vi_temp_navigation_mode(event) - - 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 handler.record_in_macro(): - if app.emacs_state.is_recording and was_recording_emacs: - recording = app.emacs_state.current_recording - if recording is not None: # Should always be true, given that - # `was_recording_emacs` is set. - recording.extend(key_sequence) - - if app.vi_state.recording_register and was_recording_vi: - for k in key_sequence: - app.vi_state.current_recording += k.data - - def _fix_vi_cursor_position(self, event: "KeyPressEvent") -> None: - """ - 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.) - """ - app = event.app - buff = app.current_buffer - preferred_column = buff.preferred_column - - if ( - vi_navigation_mode() - 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 - - def _leave_vi_temp_navigation_mode(self, event: "KeyPressEvent") -> None: - """ - If we're in Vi temporary navigation (normal) mode, return to - insert/replace mode after executing one action. - """ - app = event.app - - if app.editing_mode == EditingMode.VI: - # Not waiting for a text object and no argument has been given. - if app.vi_state.operator_func is None and self.arg is None: - app.vi_state.temporary_navigation_mode = False - - def _start_timeout(self) -> None: - """ - Start auto flush timeout. Similar to Vim's `timeoutlen` option. - - Start a background coroutine with a timer. When this timeout expires - and no key was pressed in the meantime, we flush all data in the queue - and call the appropriate key binding handlers. - """ - app = get_app() - timeout = app.timeoutlen - - if timeout is None: - return - - async def wait() -> None: - "Wait for timeout." - # This sleep can be cancelled. In that case we don't flush. - await sleep(timeout) - - if len(self.key_buffer) > 0: - # (No keys pressed in the meantime.) - flush_keys() - - def flush_keys() -> None: - "Flush keys." - self.feed(_Flush) - self.process_keys() - - # Automatically flush keys. - if self._flush_wait_task: - self._flush_wait_task.cancel() - self._flush_wait_task = app.create_background_task(wait()) - - def send_sigint(self) -> None: - """ - Send SIGINT. Immediately call the SIGINT key handler. - """ - self.feed(KeyPress(key=Keys.SIGINT), first=True) - self.process_keys() - - -class KeyPressEvent: - """ - Key press event, delivered to key bindings. - - :param key_processor_ref: Weak reference to the `KeyProcessor`. - :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, - key_processor_ref: "weakref.ReferenceType[KeyProcessor]", - arg: Optional[str], - key_sequence: List[KeyPress], - previous_key_sequence: List[KeyPress], - is_repeat: bool, - ) -> None: - - self._key_processor_ref = key_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 - self._app = get_app() - - def __repr__(self) -> str: - return "KeyPressEvent(arg={!r}, key_sequence={!r}, is_repeat={!r})".format( - self.arg, - self.key_sequence, - self.is_repeat, - ) - - @property - def data(self) -> str: - return self.key_sequence[-1].data - - @property - def key_processor(self) -> KeyProcessor: - processor = self._key_processor_ref() - if processor is None: - raise Exception("KeyProcessor was lost. This should not happen.") - return processor - - @property - def app(self) -> "Application[Any]": - """ - The current `Application` object. - """ - return self._app - - @property - def current_buffer(self) -> "Buffer": - """ - The current buffer. - """ - return self.app.current_buffer - - @property - def arg(self) -> int: - """ - 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) -> bool: - """ - True if repetition argument was explicitly provided. - """ - return self._arg is not None - - def append_to_arg_count(self, data: str) -> None: - """ - 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 = f"{current}{data}" - - self.key_processor.arg = result - - @property - def cli(self) -> "Application[Any]": - "For backward-compatibility." - return self.app diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/vi_state.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/vi_state.py deleted file mode 100644 index 10593a82e62..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/vi_state.py +++ /dev/null @@ -1,107 +0,0 @@ -from enum import Enum -from typing import TYPE_CHECKING, Callable, Dict, Optional - -from prompt_toolkit.clipboard import ClipboardData - -if TYPE_CHECKING: - from .key_bindings.vi import TextObject - from .key_processor import KeyPressEvent - -__all__ = [ - "InputMode", - "CharacterFind", - "ViState", -] - - -class InputMode(str, Enum): - value: str - - INSERT = "vi-insert" - INSERT_MULTIPLE = "vi-insert-multiple" - NAVIGATION = "vi-navigation" # Normal mode. - REPLACE = "vi-replace" - REPLACE_SINGLE = "vi-replace-single" - - -class CharacterFind: - def __init__(self, character: str, backwards: bool = False) -> None: - self.character = character - self.backwards = backwards - - -class ViState: - """ - Mutable class to hold the state of the Vi navigation. - """ - - def __init__(self) -> None: - #: 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: Optional[CharacterFind] = 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: Optional[ - Callable[["KeyPressEvent", "TextObject"], None] - ] = None - self.operator_arg: Optional[int] = None - - #: Named registers. Maps register name (e.g. 'a') to - #: :class:`ClipboardData` instances. - self.named_registers: Dict[str, ClipboardData] = {} - - #: The Vi mode we're currently in to. - self.__input_mode = InputMode.INSERT - - #: Waiting for digraph. - self.waiting_for_digraph = False - self.digraph_symbol1: Optional[str] = None # (None or a symbol.) - - #: When true, make ~ act as an operator. - self.tilde_operator = False - - #: Register in which we are recording a macro. - #: `None` when not recording anything. - # Note that the recording is only stored in the register after the - # recording is stopped. So we record in a separate `current_recording` - # variable. - self.recording_register: Optional[str] = None - self.current_recording: str = "" - - # Temporary navigation (normal) mode. - # This happens when control-o has been pressed in insert or replace - # mode. The user can now do one navigation action and we'll return back - # to insert/replace. - self.temporary_navigation_mode = False - - @property - def input_mode(self) -> InputMode: - "Get `InputMode`." - return self.__input_mode - - @input_mode.setter - def input_mode(self, value: InputMode) -> None: - "Set `InputMode`." - if value == InputMode.NAVIGATION: - self.waiting_for_digraph = False - self.operator_func = None - self.operator_arg = None - - self.__input_mode = value - - def reset(self) -> None: - """ - Reset state, go back to the given mode. INSERT by default. - """ - # Go back to insert mode. - self.input_mode = InputMode.INSERT - - self.waiting_for_digraph = False - self.operator_func = None - self.operator_arg = None - - # Reset recording state. - self.recording_register = None - self.current_recording = "" |