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/bindings | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) |
fix ya.make
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/key_binding/bindings')
14 files changed, 0 insertions, 4794 deletions
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) |