Exemplo n.º 1
0
def register_ipython_shortcuts(registry, shell):
    """Set up the prompt_toolkit keyboard shortcuts for IPython"""
    insert_mode = ViInsertMode() | EmacsInsertMode()

    # Ctrl+J == Enter, seemingly
    registry.add_binding(Keys.ControlJ,
                         filter=(HasFocus(DEFAULT_BUFFER)
                                 & ~HasSelection()
                                 & insert_mode))(
                                     newline_or_execute_outer(shell))

    registry.add_binding(Keys.ControlBackslash)(force_exit)

    registry.add_binding(Keys.ControlP,
                         filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
                                 ))(previous_history_or_previous_completion)

    registry.add_binding(
        Keys.ControlN,
        filter=(ViInsertMode()
                & HasFocus(DEFAULT_BUFFER)))(next_history_or_next_completion)

    registry.add_binding(Keys.ControlG,
                         filter=(HasFocus(DEFAULT_BUFFER)
                                 & HasCompletions()))(dismiss_completion)

    registry.add_binding(Keys.ControlC,
                         filter=HasFocus(DEFAULT_BUFFER))(reset_buffer)

    registry.add_binding(Keys.ControlC,
                         filter=HasFocus(SEARCH_BUFFER))(reset_search_buffer)

    supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
    registry.add_binding(Keys.ControlZ, filter=supports_suspend)(suspend_to_bg)

    # Ctrl+I == Tab
    registry.add_binding(Keys.ControlI,
                         filter=(HasFocus(DEFAULT_BUFFER)
                                 & ~HasSelection()
                                 & insert_mode
                                 & cursor_in_leading_ws))(indent_buffer)

    registry.add_binding(
        Keys.ControlO, filter=(HasFocus(DEFAULT_BUFFER)
                               & EmacsInsertMode()))(newline_with_copy_margin)

    if shell.display_completions == 'readlinelike':
        registry.add_binding(
            Keys.ControlI,
            filter=(
                HasFocus(DEFAULT_BUFFER)
                & ~HasSelection()
                & insert_mode
                & ~cursor_in_leading_ws))(display_completions_like_readline)

    if sys.platform == 'win32':
        registry.add_binding(Keys.ControlV,
                             filter=(HasFocus(DEFAULT_BUFFER)
                                     & ~ViMode()))(win_paste)
Exemplo n.º 2
0
def custom_keybindings(bindings, **kw):

    from xonsh2.ptk_shell.key_bindings import carriage_return
    from prompt_toolkit.filters import EmacsInsertMode, ViInsertMode

    handler = bindings.add
    insert_mode = ViInsertMode() | EmacsInsertMode()

    @handler(" ", filter=IsMultiline() & insert_mode)
    def handle_space(event):
        buffer = event.app.current_buffer
        if not revert_abbrev(buffer):
            expand_abbrev(buffer)
        if last_expanded is None or not set_cursor_position(buffer):
            buffer.insert_text(" ")

    @handler(Keys.ControlJ,
             filter=IsMultiline() & insert_mode & ~completion_is_selected)
    @handler(Keys.ControlM,
             filter=IsMultiline() & insert_mode & ~completion_is_selected)
    def multiline_carriage_return(event):
        buffer = event.app.current_buffer
        current_char = buffer.document.current_char
        if not current_char or current_char.isspace():
            expand_abbrev(buffer)
        carriage_return(buffer, event.cli)
Exemplo n.º 3
0
def custom_keybindings(bindings, **kw):

    from prompt_toolkit.filters import EmacsInsertMode, ViInsertMode

    from xonsh.ptk_shell.key_bindings import carriage_return

    handler = bindings.add
    insert_mode = ViInsertMode() | EmacsInsertMode()
    abbrev = Abbreviation()

    @handler(" ", filter=IsMultiline() & insert_mode)
    def handle_space(event):
        buffer = event.app.current_buffer

        add_space = True
        if not abbrev.revert(buffer):
            position_changed = abbrev.expand(buffer)
            if position_changed:
                add_space = False
        if add_space:
            buffer.insert_text(" ")

    @handler(Keys.ControlJ,
             filter=IsMultiline() & insert_mode & ~completion_is_selected)
    @handler(Keys.ControlM,
             filter=IsMultiline() & insert_mode & ~completion_is_selected)
    def multiline_carriage_return(event):
        buffer = event.app.current_buffer
        current_char = buffer.document.current_char
        if not current_char or current_char.isspace():
            abbrev.expand(buffer)
        carriage_return(buffer, event.cli)
Exemplo n.º 4
0
def custom_keybindings(bindings, **kw):

    if ptk_shell_type() == "prompt_toolkit2":
        from xonsh.ptk2.key_bindings import carriage_return
        from prompt_toolkit.filters import EmacsInsertMode, ViInsertMode

        handler = bindings.add
        insert_mode = ViInsertMode() | EmacsInsertMode()
    else:
        from xonsh.ptk.key_bindings import carriage_return
        from prompt_toolkit.filters import to_filter

        handler = bindings.registry.add_binding
        insert_mode = to_filter(True)

    @handler(" ", filter=IsMultiline() & insert_mode)
    def handle_space(event):
        buffer = event.app.current_buffer
        expand_abbrev(buffer)
        buffer.insert_text(" ")

    @handler(
        Keys.ControlJ, filter=IsMultiline() & insert_mode & ~completion_is_selected
    )
    @handler(
        Keys.ControlM, filter=IsMultiline() & insert_mode & ~completion_is_selected
    )
    def multiline_carriage_return(event):
        buffer = event.app.current_buffer
        current_char = buffer.document.current_char
        if not current_char or current_char.isspace():
            expand_abbrev(buffer)
        carriage_return(buffer, event.cli)
Exemplo n.º 5
0
def custom_keybindings(bindings, **kw):
    handler = bindings.registry.add_binding
    insert_mode = ViInsertMode() | EmacsInsertMode()

    @Condition
    def last_command_exists(cli):
        return len(__xonsh_history__) > 0

    @handler(Keys.Escape, '.', filter=last_command_exists & insert_mode)
    def recall_last_arg(event):
        arg = __xonsh_history__[-1].cmd.split()[-1]
        event.current_buffer.insert_text(arg)
Exemplo n.º 6
0
    def load_bindings(key_bindings_manager):
        handle = key_bindings_manager.registry.add_binding
        has_selection = HasSelection()

        @key_bindings_manager.registry.add_binding(Keys.ControlL)#, eager=True)
        def clear_(event):
            clear()
            print(env.welcome)
            PROMPT = env.prompt
            PROMPT = PROMPT.replace(r"\u", env.user).replace(r"\w", env.directory)
            print(unicode_(PROMPT), end="")

        @key_bindings_manager.registry.add_binding(Keys.ControlB)
        def list_(event):
            print("\n".join(ls(env, [], {})))
            PROMPT = env.prompt
            PROMPT = PROMPT.replace(r"\u", env.user).replace(r"\w", env.directory)
            print(env.default_color, end="")
            print(unicode_(PROMPT), end="")
            
        @handle(Keys.ControlJ, filter= ~has_selection &
            (ViInsertMode() | EmacsInsertMode()) &
            HasFocus(DEFAULT_BUFFER) & IsMultiline())
        def _(event):
            """
            Behaviour of the Enter key.
            
            Auto indent after newline/Enter.
            (When not in Vi navigaton mode, and when multiline is enabled.)
            """
            b = event.current_buffer
            empty_lines_required = 2

            def at_the_end(b):
                """ we consider the cursor at the end when there is no text after
                the cursor, or only whitespace. """
                text = b.document.text_after_cursor
                return text == '' or (text.isspace() and not '\n' in text)

            if at_the_end(b) and (b.document.text.replace(' ', '').endswith('\n' * (empty_lines_required - 1)) or (b.document.text.replace("\n", "").endswith(";"))):
                # When the cursor is at the end, and we have an empty line:
                # drop the empty lines, but return the value.
                b.document = Document(
                    text=b.text.rstrip(),
                    cursor_position=len(b.text.rstrip()))

                b.accept_action.validate_and_handle(event.cli, b)
            else:
                _auto_newline(b)
Exemplo n.º 7
0
def custom_keybindings(bindings, **kw):
    if ptk_shell_type() == "prompt_toolkit2":
        handler = bindings.add
    else:
        handler = bindings.registry.add_binding

    insert_mode = ViInsertMode() | EmacsInsertMode()

    @Condition
    def last_command_exists():
        return len(__xonsh__.history) > 0

    @handler(Keys.Escape, ".", filter=last_command_exists & insert_mode)
    def recall_last_arg(event):
        arg = __xonsh__.history[-1].cmd.split()[-1]
        event.current_buffer.insert_text(arg)
Exemplo n.º 8
0
def load_ipython_extension(ip):

    insert_mode = ViInsertMode() | EmacsInsertMode()


    def insert_unexpected(event):
        #  buf = event.current_buffer
        #  buf.insert_text("view(_)")
        #  get_by_name('accept-line').handler(event)
        view(ip.user_ns['_'])


    # Register the shortcut if IPython is using prompt_toolkit
    if getattr(ip, "pt_app", None):
        registry = ip.pt_app.key_bindings
        registry.add_binding(
            Keys.ControlT, filter=(HasFocus(DEFAULT_BUFFER) & ~HasSelection() & insert_mode)
        )(insert_unexpected)
Exemplo n.º 9
0
    def pt_init(self):
        def get_prompt_tokens(cli):
            return [(Token.Prompt, self.prompt)]

        def patch_stdout(**kwargs):
            return self.pt_cli.patch_stdout_context(**kwargs)

        if self._ptcomp is None:
            compl = IPCompleter(
                shell=self.shell,
                namespace={},
                global_namespace={},
                use_readline=False,
                parent=self.shell,
            )
            self._ptcomp = IPythonPTCompleter(compl, patch_stdout=patch_stdout)

        kbmanager = KeyBindingManager.for_prompt()
        supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
        kbmanager.registry.add_binding(Keys.ControlZ,
                                       filter=supports_suspend)(suspend_to_bg)

        if self.shell.display_completions == 'readlinelike':
            kbmanager.registry.add_binding(
                Keys.ControlI,
                filter=(HasFocus(DEFAULT_BUFFER)
                        & ~HasSelection()
                        & ViInsertMode() | EmacsInsertMode()
                        & ~cursor_in_leading_ws
                        ))(display_completions_like_readline)
        multicolumn = (self.shell.display_completions == 'multicolumn')

        self._pt_app = create_prompt_application(
            editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
            key_bindings_registry=kbmanager.registry,
            history=self.shell.debugger_history,
            completer=self._ptcomp,
            enable_history_search=True,
            mouse_support=self.shell.mouse_support,
            get_prompt_tokens=get_prompt_tokens,
            display_completions_in_columns=multicolumn,
        )
        self.pt_cli = CommandLineInterface(self._pt_app,
                                           eventloop=self.shell._eventloop)
Exemplo n.º 10
0
    def init_prompt_toolkit_cli(self):
        if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty():
            # Fall back to plain non-interactive output for tests.
            # This is very limited, and only accepts a single line.
            def prompt():
                return cast_unicode_py2(
                    input('In [%d]: ' % self.execution_count))

            self.prompt_for_code = prompt
            return

        kbmanager = KeyBindingManager.for_prompt()
        insert_mode = ViInsertMode() | EmacsInsertMode()
        # Ctrl+J == Enter, seemingly
        @kbmanager.registry.add_binding(Keys.ControlJ,
                                        filter=(HasFocus(DEFAULT_BUFFER)
                                                & ~HasSelection()
                                                & insert_mode))
        def _(event):
            b = event.current_buffer
            d = b.document
            if not (d.on_last_line or d.cursor_position_row >=
                    d.line_count - d.empty_line_count_at_the_end()):
                b.newline()
                return

            status, indent = self.input_splitter.check_complete(d.text)

            if (status != 'incomplete') and b.accept_action.is_returnable:
                b.accept_action.validate_and_handle(event.cli, b)
            else:
                b.insert_text('\n' + (' ' * (indent or 0)))

        @kbmanager.registry.add_binding(Keys.ControlC,
                                        filter=HasFocus(DEFAULT_BUFFER))
        def _reset_buffer(event):
            event.current_buffer.reset()

        @kbmanager.registry.add_binding(Keys.ControlC,
                                        filter=HasFocus(SEARCH_BUFFER))
        def _reset_search_buffer(event):
            if event.current_buffer.document.text:
                event.current_buffer.reset()
            else:
                event.cli.push_focus(DEFAULT_BUFFER)

        supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))

        @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
        def _suspend_to_bg(event):
            event.cli.suspend_to_background()

        @Condition
        def cursor_in_leading_ws(cli):
            before = cli.application.buffer.document.current_line_before_cursor
            return (not before) or before.isspace()

        # Ctrl+I == Tab
        @kbmanager.registry.add_binding(Keys.ControlI,
                                        filter=(HasFocus(DEFAULT_BUFFER)
                                                & ~HasSelection()
                                                & insert_mode
                                                & cursor_in_leading_ws))
        def _indent_buffer(event):
            event.current_buffer.insert_text(' ' * 4)

        # Pre-populate history from IPython's history database
        history = InMemoryHistory()
        last_cell = u""
        for __, ___, cell in self.history_manager.get_tail(
                self.history_load_length, include_latest=True):
            # Ignore blank lines and consecutive duplicates
            cell = cell.rstrip()
            if cell and (cell != last_cell):
                history.append(cell)

        self._style = self._make_style_from_name(self.highlighting_style)
        style = DynamicStyle(lambda: self._style)

        editing_mode = getattr(EditingMode, self.editing_mode.upper())

        self._app = create_prompt_application(
            editing_mode=editing_mode,
            key_bindings_registry=kbmanager.registry,
            history=history,
            completer=IPythonPTCompleter(self.Completer),
            enable_history_search=True,
            style=style,
            mouse_support=self.mouse_support,
            **self._layout_options())
        self._eventloop = create_eventloop(self.inputhook)
        self.pt_cli = CommandLineInterface(self._app,
                                           eventloop=self._eventloop)
Exemplo n.º 11
0
def __rc():
    import sys
    from pathlib import Path

    from IPython import get_ipython
    from IPython.core.magic import (
        needs_local_scope,
        register_cell_magic,
        register_line_magic,
    )
    from IPython.display import HTML, display
    from IPython.terminal.prompts import Prompts, Token
    from prompt_toolkit.enums import DEFAULT_BUFFER
    from prompt_toolkit.filters import EmacsInsertMode, HasFocus, HasSelection

    sys.path.append(str(Path(__file__).parents[3]))

    ip = get_ipython()
    insert_mode = EmacsInsertMode()

    # Register the shortcut if IPython is using prompt_toolkit
    if getattr(ip, "pt_app", None):
        registry = ip.pt_app.key_bindings

        @registry.add_binding(
            "escape",
            "m",
            filter=(HasFocus(DEFAULT_BUFFER) & ~HasSelection() & insert_mode),
        )
        def _(event):
            event.current_buffer.validate_and_handle()

    class MyPrompt(Prompts):
        def in_prompt_tokens(self, cli=None):
            return [(Token.Prompt, "❱ ")]

        def continuation_prompt_tokens(self, width=None):
            if width is None:
                width = self._width()
            return [
                (Token.Prompt, (" " * (width - 2)) + "| "),
            ]

        def out_prompt_tokens(self):
            return [
                (Token.OutPrompt, "❰ "),
            ]

    @register_line_magic
    @needs_local_scope
    def var(line, local_ns):
        import sympy

        result = sympy.symbols(line)
        try:
            for x in result:
                local_ns[x.name] = x
            return sympy.Matrix([result])
        except TypeError:
            local_ns[x.name] = x
            return x

    def sympy_parse(line, local_ns, *args, **kwargs):
        import sympy

        try:
            return sympy.S(line, *args, **kwargs)
        except ValueError as err:
            if ":=" in line:
                name, expr = line.split(":=")
                result = sympy_parse(expr, local_ns, *args, **kwargs)
                local_ns[name.strip()] = result
                return result
            elif "=" in line:
                return sympy.S("Eq(" + ",".join(line.split("=")) + ")", *args,
                               **kwargs)
            else:
                raise err

    @register_line_magic
    @needs_local_scope
    def s(line, local_ns):
        return sympy_parse(line, local_ns)

    @register_line_magic
    @needs_local_scope
    def sp(line, local_ns):
        return sympy_parse(line, local_ns, locals=local_ns)

    @register_cell_magic
    @needs_local_scope
    def interact(line, cell, local_ns):
        import ipywidgets

        decorator = eval(
            "ipywidgets.interact(" + line + ")",
            globals(),
            {
                **local_ns, "ipywidgets": ipywidgets
            },
        )
        lines = cell.strip().split("\n")
        last = "_result = " + lines[-1]

        local_ns["__interact_decorator"] = decorator
        src = ("\n@__interact_decorator"
               "\ndef __interact_f(" + ", ".join(decorator.kwargs) + "):" +
               "\n    " + "\n    ".join([*lines, last]) +
               "\n    return _result")

        ip.run_cell(src, store_history=False)

    def pre_run_cell(info):
        display(
            HTML(f"""
            <script
                id="output-{id(info)}"
            >pre_run_cell && pre_run_cell('{id(info)}')</script>
        """))

    def post_run_cell(result):
        display(
            HTML(f"""
            <script>post_run_cell && post_run_cell('{id(result.info)}', '{result.success}')</script>
        """))

    def clear():
        display(
            HTML(f"""
            <script>shell_initialized(); console.log('called')</script>
        """))

    ip = get_ipython()
    ip.prompts = MyPrompt(ip)
    ip.events.register("pre_run_cell", pre_run_cell)
    ip.events.register("post_run_cell", post_run_cell)

    # matplotlib doesn't get my custom rc file if I don't run this
    # https://github.com/jupyter/notebook/issues/3385
    ip.run_line_magic("matplotlib", "notebook")
Exemplo n.º 12
0
def load_basic_bindings():
    registry = Registry()
    insert_mode = ViInsertMode() | EmacsInsertMode()
    handle = registry.add_binding
    has_selection = HasSelection()

    @handle(Keys.ControlA)
    @handle(Keys.ControlB)
    @handle(Keys.ControlC)
    @handle(Keys.ControlD)
    @handle(Keys.ControlE)
    @handle(Keys.ControlF)
    @handle(Keys.ControlG)
    @handle(Keys.ControlH)
    @handle(Keys.ControlI)
    @handle(Keys.ControlJ)
    @handle(Keys.ControlK)
    @handle(Keys.ControlL)
    @handle(Keys.ControlM)
    @handle(Keys.ControlN)
    @handle(Keys.ControlO)
    @handle(Keys.ControlP)
    @handle(Keys.ControlQ)
    @handle(Keys.ControlR)
    @handle(Keys.ControlS)
    @handle(Keys.ControlT)
    @handle(Keys.ControlU)
    @handle(Keys.ControlV)
    @handle(Keys.ControlW)
    @handle(Keys.ControlX)
    @handle(Keys.ControlY)
    @handle(Keys.ControlZ)
    @handle(Keys.F1)
    @handle(Keys.F2)
    @handle(Keys.F3)
    @handle(Keys.F4)
    @handle(Keys.F5)
    @handle(Keys.F6)
    @handle(Keys.F7)
    @handle(Keys.F8)
    @handle(Keys.F9)
    @handle(Keys.F10)
    @handle(Keys.F11)
    @handle(Keys.F12)
    @handle(Keys.F13)
    @handle(Keys.F14)
    @handle(Keys.F15)
    @handle(Keys.F16)
    @handle(Keys.F17)
    @handle(Keys.F18)
    @handle(Keys.F19)
    @handle(Keys.F20)
    @handle(Keys.ControlSpace)
    @handle(Keys.ControlBackslash)
    @handle(Keys.ControlSquareClose)
    @handle(Keys.ControlCircumflex)
    @handle(Keys.ControlUnderscore)
    @handle(Keys.Backspace)
    @handle(Keys.Up)
    @handle(Keys.Down)
    @handle(Keys.Right)
    @handle(Keys.Left)
    @handle(Keys.ShiftUp)
    @handle(Keys.ShiftDown)
    @handle(Keys.ShiftRight)
    @handle(Keys.ShiftLeft)
    @handle(Keys.Home)
    @handle(Keys.End)
    @handle(Keys.Delete)
    @handle(Keys.ShiftDelete)
    @handle(Keys.ControlDelete)
    @handle(Keys.PageUp)
    @handle(Keys.PageDown)
    @handle(Keys.BackTab)
    @handle(Keys.Tab)
    @handle(Keys.ControlLeft)
    @handle(Keys.ControlRight)
    @handle(Keys.ControlUp)
    @handle(Keys.ControlDown)
    @handle(Keys.Insert)
    @handle(Keys.Ignore)
    def _(event):
        """
        First, for any of these keys, Don't do anything by default. Also don't
        catch them in the 'Any' handler which will insert them as data.

        If people want to insert these characters as a literal, they can always
        do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi
        mode.)
        """
        pass

    # Readline-style bindings.
    handle(Keys.Home)(get_by_name('beginning-of-line'))
    handle(Keys.End)(get_by_name('end-of-line'))
    handle(Keys.Left)(get_by_name('backward-char'))
    handle(Keys.Right)(get_by_name('forward-char'))
    handle(Keys.ControlUp)(get_by_name('previous-history'))
    handle(Keys.ControlDown)(get_by_name('next-history'))
    handle(Keys.ControlL)(get_by_name('clear-screen'))

    handle(Keys.ControlK, filter=insert_mode)(get_by_name('kill-line'))
    handle(Keys.ControlU, filter=insert_mode)(get_by_name('unix-line-discard'))
    handle(Keys.ControlH, filter=insert_mode, save_before=if_no_repeat)(
        get_by_name('backward-delete-char'))
    handle(Keys.Backspace, filter=insert_mode, save_before=if_no_repeat)(
        get_by_name('backward-delete-char'))
    handle(Keys.Delete, filter=insert_mode, save_before=if_no_repeat)(
        get_by_name('delete-char'))
    handle(Keys.ShiftDelete, filter=insert_mode, save_before=if_no_repeat)(
        get_by_name('delete-char'))
    handle(Keys.Any, filter=insert_mode, save_before=if_no_repeat)(
        get_by_name('self-insert'))
    handle(Keys.ControlT, filter=insert_mode)(get_by_name('transpose-chars'))
    handle(Keys.ControlW, filter=insert_mode)(get_by_name('unix-word-rubout'))
    handle(Keys.ControlI, filter=insert_mode)(get_by_name('menu-complete'))
    handle(Keys.BackTab, filter=insert_mode)(get_by_name('menu-complete-backward'))

    handle(Keys.PageUp, filter= ~has_selection)(get_by_name('previous-history'))
    handle(Keys.PageDown, filter= ~has_selection)(get_by_name('next-history'))

    # CTRL keys.

    text_before_cursor = Condition(lambda cli: cli.current_buffer.text)
    handle(Keys.ControlD, filter=text_before_cursor & insert_mode)(get_by_name('delete-char'))

    is_multiline = Condition(lambda cli: cli.current_buffer.is_multiline())
    is_returnable = Condition(lambda cli: cli.current_buffer.accept_action.is_returnable)

    @handle(Keys.ControlJ, filter=is_multiline & insert_mode)
    def _(event):
        " Newline (in case of multiline input. "
        event.current_buffer.newline(copy_margin=not event.cli.in_paste_mode)

    @handle(Keys.ControlJ, filter=~is_multiline & is_returnable)
    def _(event):
        " Enter, accept input. "
        buff = event.current_buffer
        buff.accept_action.validate_and_handle(event.cli, buff)

    # Delete the word before the cursor.

    @handle(Keys.Up)
    def _(event):
        event.current_buffer.auto_up(count=event.arg)

    @handle(Keys.Down)
    def _(event):
        event.current_buffer.auto_down(count=event.arg)

    @handle(Keys.Delete, filter=has_selection)
    def _(event):
        data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(data)

    # Global bindings.

    @handle(Keys.ControlZ)
    def _(event):
        """
        By default, control-Z should literally insert Ctrl-Z.
        (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File.
        In a Python REPL for instance, it's possible to type
        Control-Z followed by enter to quit.)

        When the system bindings are loaded and suspend-to-background is
        supported, that will override this binding.
        """
        event.current_buffer.insert_text(event.data)

    @handle(Keys.CPRResponse, save_before=lambda e: False)
    def _(event):
        """
        Handle incoming Cursor-Position-Request response.
        """
        # The incoming data looks like u'\x1b[35;1R'
        # Parse row/col information.
        row, col = map(int, event.data[2:-1].split(';'))

        # Report absolute cursor position to the renderer.
        event.cli.renderer.report_absolute_cursor_row(row)

    @handle(Keys.BracketedPaste)
    def _(event):
        " Pasting from clipboard. "
        data = event.data

        # Be sure to use \n as line ending.
        # Some terminals (Like iTerm2) seem to paste \r\n line endings in a
        # bracketed paste. See: https://github.com/ipython/ipython/issues/9737
        data = data.replace('\r\n', '\n')
        data = data.replace('\r', '\n')

        event.current_buffer.insert_text(data)

    @handle(Keys.Any, filter=Condition(lambda cli: cli.quoted_insert), eager=True)
    def _(event):
        """
        Handle quoted insert.
        """
        event.current_buffer.insert_text(event.data, overwrite=False)
        event.cli.quoted_insert = False

    return registry
Exemplo n.º 13
0
def load_emacs_bindings(registry, filter=Always()):
    """
    Some e-macs extensions.
    """
    # Overview of Readline emacs commands:
    # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf
    filter = to_cli_filter(filter)

    handle = create_handle_decorator(registry, filter & EmacsMode())
    insert_mode = EmacsInsertMode()
    has_selection = HasSelection()

    @handle(Keys.Escape)
    def _(event):
        """
        By default, ignore escape key.

        (If we don't put this here, and Esc is followed by a key which sequence
        is not handled, we'll insert an Escape character in the input stream.
        Something we don't want and happens to easily in emacs mode.
        Further, people can always use ControlQ to do a quoted insert.)
        """
        pass

    handle(Keys.ControlA)(get_by_name('beginning-of-line'))
    handle(Keys.ControlB)(get_by_name('backward-char'))
    handle(Keys.ControlDelete, filter=insert_mode)(get_by_name('kill-word'))
    handle(Keys.ControlE)(get_by_name('end-of-line'))
    handle(Keys.ControlF)(get_by_name('forward-char'))
    handle(Keys.ControlLeft)(get_by_name('backward-word'))
    handle(Keys.ControlRight)(get_by_name('forward-word'))
    handle(Keys.ControlX, 'r', 'y', filter=insert_mode)(get_by_name('yank'))
    handle(Keys.ControlY, filter=insert_mode)(get_by_name('yank'))
    handle(Keys.Escape, 'b')(get_by_name('backward-word'))
    handle(Keys.Escape, 'c',
           filter=insert_mode)(get_by_name('capitalize-word'))
    handle(Keys.Escape, 'd', filter=insert_mode)(get_by_name('kill-word'))
    handle(Keys.Escape, 'f')(get_by_name('forward-word'))
    handle(Keys.Escape, 'l', filter=insert_mode)(get_by_name('downcase-word'))
    handle(Keys.Escape, 'u', filter=insert_mode)(get_by_name('uppercase-word'))
    handle(Keys.Escape, Keys.ControlH,
           filter=insert_mode)(get_by_name('unix-word-rubout'))
    handle(Keys.Escape, Keys.Backspace,
           filter=insert_mode)(get_by_name('unix-word-rubout'))
    handle(Keys.Escape, '\\',
           filter=insert_mode)(get_by_name('delete-horizontal-space'))

    handle(Keys.ControlUnderscore,
           save_before=(lambda e: False),
           filter=insert_mode)(get_by_name('undo'))

    handle(Keys.ControlX,
           Keys.ControlU,
           save_before=(lambda e: False),
           filter=insert_mode)(get_by_name('undo'))

    handle(Keys.Escape, '<',
           filter=~has_selection)(get_by_name('beginning-of-history'))
    handle(Keys.Escape, '>',
           filter=~has_selection)(get_by_name('end-of-history'))

    @handle(Keys.ControlN)
    def _(event):
        " Next line. "
        event.current_buffer.auto_down()

    @handle(Keys.ControlO, filter=insert_mode)
    def _(event):
        " Insert newline, but don't move the cursor. "
        event.current_buffer.insert_text('\n', move_cursor=False)

    @handle(Keys.ControlP)
    def _(event):
        " Previous line. "
        event.current_buffer.auto_up(count=event.arg)

    @handle(Keys.ControlQ, Keys.Any, filter=~has_selection)
    def _(event):
        """
        Quoted insert.

        For vt100 terminals, you have to disable flow control by running
        ``stty -ixon``, otherwise Ctrl-Q and Ctrl-S are captured by the
        terminal.
        """
        event.current_buffer.insert_text(event.data, overwrite=False)

    def handle_digit(c):
        """
        Handle input of arguments.
        The first number needs to be preceeded by escape.
        """
        @handle(c, filter=HasArg())
        @handle(Keys.Escape, c)
        def _(event):
            event.append_to_arg_count(c)

    for c in '0123456789':
        handle_digit(c)

    @handle(Keys.Escape, '-', filter=~HasArg())
    def _(event):
        """
        """
        if event._arg is None:
            event.append_to_arg_count('-')

    @handle('-', filter=Condition(lambda cli: cli.input_processor.arg == '-'))
    def _(event):
        """
        When '-' is typed again, after exactly '-' has been given as an
        argument, ignore this.
        """
        event.cli.input_processor.arg = '-'

    is_returnable = Condition(
        lambda cli: cli.current_buffer.accept_action.is_returnable)

    # Meta + Newline: always accept input.
    handle(Keys.Escape, Keys.ControlJ,
           filter=insert_mode & is_returnable)(get_by_name('accept-line'))

    def character_search(buff, char, count):
        if count < 0:
            match = buff.document.find_backwards(char,
                                                 in_current_line=True,
                                                 count=-count)
        else:
            match = buff.document.find(char, in_current_line=True, count=count)

        if match is not None:
            buff.cursor_position += match

    @handle(Keys.ControlSquareClose, Keys.Any)
    def _(event):
        " When Ctl-] + a character is pressed. go to that character. "
        character_search(event.current_buffer, event.data, event.arg)

    @handle(Keys.Escape, Keys.ControlSquareClose, Keys.Any)
    def _(event):
        " Like Ctl-], but backwards. "
        character_search(event.current_buffer, event.data, -event.arg)

    @handle(Keys.Escape, 'a')
    def _(event):
        " Previous sentence. "
        # TODO:

    @handle(Keys.Escape, 'e')
    def _(event):
        " Move to end of sentence. "
        # TODO:

    @handle(Keys.Escape, 't', filter=insert_mode)
    def _(event):
        """
        Swap the last two words before the cursor.
        """
        # TODO

    @handle(Keys.Escape, '.', filter=insert_mode)
    def _(event):
        """
        Rotate through the last word (white-space delimited) of the previous lines in history.
        """
        # TODO

    @handle(Keys.Escape, '*', filter=insert_mode)
    def _(event):
        """
        `meta-*`: Insert all possible completions of the preceding text.
        """
        buff = event.current_buffer

        # List all completions.
        complete_event = CompleteEvent(text_inserted=False,
                                       completion_requested=True)
        completions = list(
            buff.completer.get_completions(buff.document, complete_event))

        # Insert them.
        text_to_insert = ' '.join(c.text for c in completions)
        buff.insert_text(text_to_insert)

    @handle(Keys.ControlX, Keys.ControlX)
    def _(event):
        """
        Move cursor back and forth between the start and end of the current
        line.
        """
        buffer = event.current_buffer

        if buffer.document.is_cursor_at_the_end_of_line:
            buffer.cursor_position += buffer.document.get_start_of_line_position(
                after_whitespace=False)
        else:
            buffer.cursor_position += buffer.document.get_end_of_line_position(
            )

    @handle(Keys.ControlSpace)
    def _(event):
        """
        Start of the selection (if the current buffer is not empty).
        """
        # Take the current cursor position as the start of this selection.
        buff = event.current_buffer
        if buff.text:
            buff.start_selection(selection_type=SelectionType.CHARACTERS)

    @handle(Keys.ControlG, filter=~has_selection)
    def _(event):
        """
        Control + G: Cancel completion menu and validation state.
        """
        event.current_buffer.complete_state = None
        event.current_buffer.validation_error = None

    @handle(Keys.ControlG, filter=has_selection)
    def _(event):
        """
        Cancel selection.
        """
        event.current_buffer.exit_selection()

    @handle(Keys.ControlW, filter=has_selection)
    @handle(Keys.ControlX, 'r', 'k', filter=has_selection)
    def _(event):
        """
        Cut selected text.
        """
        data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Escape, 'w', filter=has_selection)
    def _(event):
        """
        Copy selected text.
        """
        data = event.current_buffer.copy_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Escape, Keys.Left)
    def _(event):
        """
        Cursor to start of previous word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_previous_word_beginning(
            count=event.arg) or 0

    @handle(Keys.Escape, Keys.Right)
    def _(event):
        """
        Cursor to start of next word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \
            buffer.document.get_end_of_document_position()

    @handle(Keys.Escape, '/', filter=insert_mode)
    def _(event):
        """
        M-/: Complete.
        """
        b = event.current_buffer
        if b.complete_state:
            b.complete_next()
        else:
            event.cli.start_completion(select_first=True)

    @handle(Keys.ControlC, '>', filter=has_selection)
    def _(event):
        """
        Indent selected text.
        """
        buffer = event.current_buffer

        buffer.cursor_position += buffer.document.get_start_of_line_position(
            after_whitespace=True)

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        indent(buffer, from_, to + 1, count=event.arg)

    @handle(Keys.ControlC, '<', filter=has_selection)
    def _(event):
        """
        Unindent selected text.
        """
        buffer = event.current_buffer

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        unindent(buffer, from_, to + 1, count=event.arg)
Exemplo n.º 14
0
    def init_prompt_toolkit_cli(self):
        self._app = None
        if self.simple_prompt:
            # Fall back to plain non-interactive output for tests.
            # This is very limited, and only accepts a single line.
            def prompt():
                return cast_unicode_py2(
                    input('In [%d]: ' % self.execution_count))

            self.prompt_for_code = prompt
            return

        kbmanager = KeyBindingManager.for_prompt()
        insert_mode = ViInsertMode() | EmacsInsertMode()
        # Ctrl+J == Enter, seemingly
        @kbmanager.registry.add_binding(Keys.ControlJ,
                                        filter=(HasFocus(DEFAULT_BUFFER)
                                                & ~HasSelection()
                                                & insert_mode))
        def _(event):
            b = event.current_buffer
            d = b.document

            if b.complete_state:
                cc = b.complete_state.current_completion
                if cc:
                    b.apply_completion(cc)
                else:
                    b.cancel_completion()
                return

            if not (d.on_last_line or d.cursor_position_row >=
                    d.line_count - d.empty_line_count_at_the_end()):
                b.newline()
                return

            status, indent = self.input_splitter.check_complete(d.text + '\n')

            if (status != 'incomplete') and b.accept_action.is_returnable:
                b.accept_action.validate_and_handle(event.cli, b)
            else:
                b.insert_text('\n' + (' ' * (indent or 0)))

        @kbmanager.registry.add_binding(Keys.ControlP,
                                        filter=(ViInsertMode()
                                                & HasFocus(DEFAULT_BUFFER)))
        def _previous_history_or_previous_completion(event):
            """
            Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.

            If completer is open this still select previous completion.
            """
            event.current_buffer.auto_up()

        @kbmanager.registry.add_binding(Keys.ControlN,
                                        filter=(ViInsertMode()
                                                & HasFocus(DEFAULT_BUFFER)))
        def _next_history_or_next_completion(event):
            """
            Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.

            If completer is open this still select next completion.
            """
            event.current_buffer.auto_down()

        @kbmanager.registry.add_binding(Keys.ControlG,
                                        filter=(HasFocus(DEFAULT_BUFFER)
                                                & HasCompletions()))
        def _dismiss_completion(event):
            b = event.current_buffer
            if b.complete_state:
                b.cancel_completion()

        @kbmanager.registry.add_binding(Keys.ControlC,
                                        filter=HasFocus(DEFAULT_BUFFER))
        def _reset_buffer(event):
            b = event.current_buffer
            if b.complete_state:
                b.cancel_completion()
            else:
                b.reset()

        @kbmanager.registry.add_binding(Keys.ControlC,
                                        filter=HasFocus(SEARCH_BUFFER))
        def _reset_search_buffer(event):
            if event.current_buffer.document.text:
                event.current_buffer.reset()
            else:
                event.cli.push_focus(DEFAULT_BUFFER)

        supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))

        @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
        def _suspend_to_bg(event):
            event.cli.suspend_to_background()

        @Condition
        def cursor_in_leading_ws(cli):
            before = cli.application.buffer.document.current_line_before_cursor
            return (not before) or before.isspace()

        # Ctrl+I == Tab
        @kbmanager.registry.add_binding(Keys.ControlI,
                                        filter=(HasFocus(DEFAULT_BUFFER)
                                                & ~HasSelection()
                                                & insert_mode
                                                & cursor_in_leading_ws))
        def _indent_buffer(event):
            event.current_buffer.insert_text(' ' * 4)

        if self.display_completions == 'readlinelike':

            @kbmanager.registry.add_binding(Keys.ControlI,
                                            filter=(HasFocus(DEFAULT_BUFFER)
                                                    & ~HasSelection()
                                                    & insert_mode
                                                    & ~cursor_in_leading_ws))
            def _disaply_compl(ev):
                display_completions_like_readline(ev)

        if sys.platform == 'win32':
            from IPython.lib.clipboard import (ClipboardEmpty,
                                               win32_clipboard_get,
                                               tkinter_clipboard_get)

            @kbmanager.registry.add_binding(Keys.ControlV,
                                            filter=(HasFocus(DEFAULT_BUFFER)
                                                    & ~ViMode()))
            def _paste(event):
                try:
                    text = win32_clipboard_get()
                except TryNext:
                    try:
                        text = tkinter_clipboard_get()
                    except (TryNext, ClipboardEmpty):
                        return
                except ClipboardEmpty:
                    return
                event.current_buffer.insert_text(text.replace('\t', ' ' * 4))

        # Pre-populate history from IPython's history database
        history = InMemoryHistory()
        last_cell = u""
        for __, ___, cell in self.history_manager.get_tail(
                self.history_load_length, include_latest=True):
            # Ignore blank lines and consecutive duplicates
            cell = cell.rstrip()
            if cell and (cell != last_cell):
                history.append(cell)

        self._style = self._make_style_from_name(self.highlighting_style)
        style = DynamicStyle(lambda: self._style)

        editing_mode = getattr(EditingMode, self.editing_mode.upper())

        self._app = create_prompt_application(
            editing_mode=editing_mode,
            key_bindings_registry=kbmanager.registry,
            history=history,
            completer=IPythonPTCompleter(self.Completer),
            enable_history_search=True,
            style=style,
            mouse_support=self.mouse_support,
            **self._layout_options())
        self._eventloop = create_eventloop(self.inputhook)
        self.pt_cli = CommandLineInterface(self._app,
                                           eventloop=self._eventloop)
Exemplo n.º 15
0
def load_xonsh_bindings() -> KeyBindingsBase:
    """
    Load custom key bindings.
    """
    key_bindings = KeyBindings()
    handle = key_bindings.add
    has_selection = HasSelection()
    insert_mode = ViInsertMode() | EmacsInsertMode()

    @handle(Keys.Tab, filter=tab_insert_indent)
    def insert_indent(event):
        """
        If there are only whitespaces before current cursor position insert
        indent instead of autocompleting.
        """
        env = builtins.__xonsh__.env
        event.cli.current_buffer.insert_text(env.get("INDENT"))

    @handle(Keys.Tab, filter=~tab_insert_indent & tab_menu_complete)
    def menu_complete_select(event):
        """Start completion in menu-complete mode, or tab to next completion"""
        b = event.current_buffer
        if b.complete_state:
            b.complete_next()
        else:
            b.start_completion(select_first=True)

    @handle(Keys.ControlX, Keys.ControlE, filter=~has_selection)
    def open_editor(event):
        """Open current buffer in editor"""
        event.current_buffer.open_in_editor(event.cli)

    @handle(Keys.BackTab, filter=insert_mode)
    def insert_literal_tab(event):
        """Insert literal tab on Shift+Tab instead of autocompleting"""
        b = event.current_buffer
        if b.complete_state:
            b.complete_previous()
        else:
            env = builtins.__xonsh__.env
            event.cli.current_buffer.insert_text(env.get("INDENT"))

    def generate_parens_handlers(left, right):
        @handle(left, filter=autopair_condition)
        def insert_left_paren(event):
            buffer = event.cli.current_buffer

            if has_selection():
                wrap_selection(buffer, left, right)
            elif whitespace_or_bracket_after():
                buffer.insert_text(left)
                buffer.insert_text(right, move_cursor=False)
            else:
                buffer.insert_text(left)

        @handle(right, filter=autopair_condition)
        def overwrite_right_paren(event):
            buffer = event.cli.current_buffer

            if buffer.document.current_char == right:
                buffer.cursor_position += 1
            else:
                buffer.insert_text(right)

    generate_parens_handlers("(", ")")
    generate_parens_handlers("[", "]")
    generate_parens_handlers("{", "}")

    def generate_quote_handler(quote):
        @handle(quote, filter=autopair_condition)
        def insert_quote(event):
            buffer = event.cli.current_buffer

            if has_selection():
                wrap_selection(buffer, quote, quote)
            elif buffer.document.current_char == quote:
                buffer.cursor_position += 1
            elif whitespace_or_bracket_before() and whitespace_or_bracket_after():
                buffer.insert_text(quote)
                buffer.insert_text(quote, move_cursor=False)
            else:
                buffer.insert_text(quote)

    generate_quote_handler("'")
    generate_quote_handler('"')

    @handle(Keys.Backspace, filter=autopair_condition)
    def delete_brackets_or_quotes(event):
        """Delete empty pair of brackets or quotes"""
        buffer = event.cli.current_buffer
        before = buffer.document.char_before_cursor
        after = buffer.document.current_char

        if any(
            [before == b and after == a for (b, a) in ["()", "[]", "{}", "''", '""']]
        ):
            buffer.delete(1)

        buffer.delete_before_cursor(1)

    @handle(Keys.ControlD, filter=ctrl_d_condition)
    def call_exit_alias(event):
        """Use xonsh exit function"""
        b = event.cli.current_buffer
        b.validate_and_handle()
        xonsh_exit([])

    @handle(Keys.ControlJ, filter=IsMultiline() & insert_mode)
    @handle(Keys.ControlM, filter=IsMultiline() & insert_mode)
    def multiline_carriage_return(event):
        """Wrapper around carriage_return multiline parser"""
        b = event.cli.current_buffer
        carriage_return(b, event.cli)

    @handle(Keys.ControlJ, filter=should_confirm_completion)
    @handle(Keys.ControlM, filter=should_confirm_completion)
    def enter_confirm_completion(event):
        """Ignore <enter> (confirm completion)"""
        event.current_buffer.complete_state = None

    @handle(Keys.Escape, filter=should_confirm_completion)
    def esc_cancel_completion(event):
        """Use <ESC> to cancel completion"""
        event.cli.current_buffer.cancel_completion()

    @handle(Keys.Escape, Keys.ControlJ)
    def execute_block_now(event):
        """Execute a block of text irrespective of cursor position"""
        b = event.cli.current_buffer
        b.validate_and_handle()

    @handle(Keys.Left, filter=beginning_of_line)
    def wrap_cursor_back(event):
        """Move cursor to end of previous line unless at beginning of
        document
        """
        b = event.cli.current_buffer
        b.cursor_up(count=1)
        relative_end_index = b.document.get_end_of_line_position()
        b.cursor_right(count=relative_end_index)

    @handle(Keys.Right, filter=end_of_line)
    def wrap_cursor_forward(event):
        """Move cursor to beginning of next line unless at end of document"""
        b = event.cli.current_buffer
        relative_begin_index = b.document.get_start_of_line_position()
        b.cursor_left(count=abs(relative_begin_index))
        b.cursor_down(count=1)

    @handle(Keys.ControlM, filter=IsSearching())
    @handle(Keys.ControlJ, filter=IsSearching())
    def accept_search(event):
        search.accept_search()

    @handle(Keys.ControlZ)
    def skip_control_z(event):
        """Prevents the writing of ^Z to the prompt, if Ctrl+Z was pressed
        during the previous command.
        """
        pass

    @handle(Keys.ControlX, Keys.ControlX, filter=has_selection)
    def _cut(event):
        """Cut selected text."""
        data = event.current_buffer.cut_selection()
        event.app.clipboard.set_data(data)

    @handle(Keys.ControlX, Keys.ControlC, filter=has_selection)
    def _copy(event):
        """Copy selected text."""
        data = event.current_buffer.copy_selection()
        event.app.clipboard.set_data(data)

    @handle(Keys.ControlV, filter=insert_mode | has_selection)
    def _yank(event):
        """Paste selected text."""
        buff = event.current_buffer
        if buff.selection_state:
            buff.cut_selection()
        get_by_name("yank").call(event)

    return key_bindings
Exemplo n.º 16
0
def load_xonsh_bindings(key_bindings_manager):
    """
    Load custom key bindings.
    """
    handle = key_bindings_manager.registry.add_binding
    has_selection = HasSelection()
    insert_mode = ViInsertMode() | EmacsInsertMode()

    @handle(Keys.Tab, filter=TabShouldInsertIndentFilter())
    def _(event):
        """
        If there are only whitespaces before current cursor position insert
        indent instead of autocompleting.
        """
        event.cli.current_buffer.insert_text(env.get('INDENT'))

    @handle(Keys.ControlX, Keys.ControlE, filter=~has_selection)
    def open_editor(event):
        """ Open current buffer in editor """
        event.current_buffer.open_in_editor(event.cli)

    @handle(Keys.BackTab)
    def insert_literal_tab(event):
        """ Insert literal tab on Shift+Tab instead of autocompleting """
        event.cli.current_buffer.insert_text(env.get('INDENT'))

    @handle(Keys.ControlD, filter=ctrl_d_condition)
    def call_exit_alias(event):
        """Use xonsh exit function"""
        b = event.cli.current_buffer
        b.accept_action.validate_and_handle(event.cli, b)
        xonsh_exit([])

    @handle(Keys.ControlJ, filter=IsMultiline())
    def multiline_carriage_return(event):
        """ Wrapper around carriage_return multiline parser """
        b = event.cli.current_buffer
        carriage_return(b, event.cli)

    @handle(Keys.Left, filter=BeginningOfLine())
    def wrap_cursor_back(event):
        """Move cursor to end of previous line unless at beginning of document"""
        b = event.cli.current_buffer
        b.cursor_up(count=1)
        relative_end_index = b.document.get_end_of_line_position()
        b.cursor_right(count=relative_end_index)

    @handle(Keys.Right, filter=EndOfLine())
    def wrap_cursor_forward(event):
        """Move cursor to beginning of next line unless at end of document"""
        b = event.cli.current_buffer
        relative_begin_index = b.document.get_start_of_line_position()
        b.cursor_left(count=abs(relative_begin_index))
        b.cursor_down(count=1)

    @handle(Keys.ControlI, filter=insert_mode)
    def generate_completions(event):
        """
        Tab-completion: where the first tab completes the common suffix and the
        second tab lists all the completions.

        Notes
        -----
        This method was forked from the mainline prompt-toolkit repo.
        Copyright (c) 2014, Jonathan Slenders, All rights reserved.
        """
        b = event.current_buffer

        def second_tab():
            if b.complete_state:
                b.complete_next()
            else:
                event.cli.start_completion(select_first=False)

        # On the second tab-press, or when already navigating through
        # completions.
        if event.is_repeat or b.complete_state:
            second_tab()
        else:
            event.cli.start_completion(insert_common_part=True,
                                       select_first=False)
Exemplo n.º 17
0
def load_xonsh_bindings(ptk_bindings: KeyBindingsBase) -> KeyBindingsBase:
    """
    Load custom key bindings.

    Parameters
    ----------
    ptk_bindings :
        The default prompt toolkit bindings. We need these to add aliases to them.
    """
    key_bindings = KeyBindings()
    handle = key_bindings.add
    has_selection = HasSelection()
    insert_mode = ViInsertMode() | EmacsInsertMode()

    if XSH.env["XONSH_CTRL_BKSP_DELETION"]:
        # Not all terminal emulators emit the same keys for backspace, therefore
        # ptk always maps backspace ("\x7f") to ^H ("\x08"), and all the backspace bindings are registered for ^H.
        # This means we can't re-map backspace and instead we register a new "real-ctrl-bksp" key.
        # See https://github.com/xonsh/xonsh/issues/4407

        if ON_WINDOWS:
            # On windows BKSP is "\x08" and CTRL-BKSP is "\x7f"
            REAL_CTRL_BKSP = "\x7f"

            # PTK uses a second mapping
            from prompt_toolkit.input import win32 as ptk_win32

            ptk_win32.ConsoleInputReader.mappings[b"\x7f"] = REAL_CTRL_BKSP  # type: ignore
        else:
            REAL_CTRL_BKSP = "\x08"

        # Prompt-toolkit allows using single-character keys that aren't in the `Keys` enum.
        ansi_escape_sequences.ANSI_SEQUENCES[REAL_CTRL_BKSP] = REAL_CTRL_BKSP  # type: ignore
        ansi_escape_sequences.REVERSE_ANSI_SEQUENCES[REAL_CTRL_BKSP] = REAL_CTRL_BKSP  # type: ignore

        @handle(REAL_CTRL_BKSP, filter=insert_mode)
        def delete_word(event):
            """Delete a single word (like ALT-backspace)"""
            get_by_name("backward-kill-word").call(event)

    @handle(Keys.Tab, filter=tab_insert_indent)
    def insert_indent(event):
        """
        If there are only whitespaces before current cursor position insert
        indent instead of autocompleting.
        """
        env = XSH.env
        event.cli.current_buffer.insert_text(env.get("INDENT"))

    @handle(Keys.Tab, filter=~tab_insert_indent & tab_menu_complete)
    def menu_complete_select(event):
        """Start completion in menu-complete mode, or tab to next completion"""
        b = event.current_buffer
        if b.complete_state:
            b.complete_next()
        else:
            b.start_completion(select_first=True)

    @handle(Keys.ControlX, Keys.ControlE, filter=~has_selection)
    def open_editor(event):
        """Open current buffer in editor"""
        event.current_buffer.open_in_editor(event.cli)

    @handle(Keys.BackTab, filter=insert_mode)
    def insert_literal_tab(event):
        """Insert literal tab on Shift+Tab instead of autocompleting"""
        b = event.current_buffer
        if b.complete_state:
            b.complete_previous()
        else:
            env = XSH.env
            event.cli.current_buffer.insert_text(env.get("INDENT"))

    def generate_parens_handlers(left, right):
        @handle(left, filter=autopair_condition)
        def insert_left_paren(event):
            buffer = event.cli.current_buffer

            if has_selection():
                wrap_selection(buffer, left, right)
            elif whitespace_or_bracket_after():
                buffer.insert_text(left)
                buffer.insert_text(right, move_cursor=False)
            else:
                buffer.insert_text(left)

        @handle(right, filter=autopair_condition)
        def overwrite_right_paren(event):
            buffer = event.cli.current_buffer

            if buffer.document.current_char == right:
                buffer.cursor_position += 1
            else:
                buffer.insert_text(right)

    generate_parens_handlers("(", ")")
    generate_parens_handlers("[", "]")
    generate_parens_handlers("{", "}")

    def generate_quote_handler(quote):
        @handle(quote, filter=autopair_condition)
        def insert_quote(event):
            buffer = event.cli.current_buffer

            if has_selection():
                wrap_selection(buffer, quote, quote)
            elif buffer.document.current_char == quote:
                buffer.cursor_position += 1
            elif whitespace_or_bracket_before() and whitespace_or_bracket_after():
                buffer.insert_text(quote)
                buffer.insert_text(quote, move_cursor=False)
            else:
                buffer.insert_text(quote)

    generate_quote_handler("'")
    generate_quote_handler('"')

    @handle(Keys.Backspace, filter=autopair_condition)
    def delete_brackets_or_quotes(event):
        """Delete empty pair of brackets or quotes"""
        buffer = event.cli.current_buffer
        before = buffer.document.char_before_cursor
        after = buffer.document.current_char

        if any(
            [before == b and after == a for (b, a) in ["()", "[]", "{}", "''", '""']]
        ):
            buffer.delete(1)

        buffer.delete_before_cursor(1)

    @handle(Keys.ControlD, filter=ctrl_d_condition)
    def call_exit_alias(event):
        """Use xonsh exit function"""
        b = event.cli.current_buffer
        b.validate_and_handle()
        xonsh_exit([])

    @handle(Keys.ControlJ, filter=IsMultiline() & insert_mode)
    @handle(Keys.ControlM, filter=IsMultiline() & insert_mode)
    def multiline_carriage_return(event):
        """Wrapper around carriage_return multiline parser"""
        b = event.cli.current_buffer
        carriage_return(b, event.cli)

    @handle(Keys.ControlJ, filter=should_confirm_completion)
    @handle(Keys.ControlM, filter=should_confirm_completion)
    def enter_confirm_completion(event):
        """Ignore <enter> (confirm completion)"""
        event.current_buffer.complete_state = None

    @handle(Keys.Escape, filter=should_confirm_completion)
    def esc_cancel_completion(event):
        """Use <ESC> to cancel completion"""
        event.cli.current_buffer.cancel_completion()

    @handle(Keys.Escape, Keys.ControlJ)
    def execute_block_now(event):
        """Execute a block of text irrespective of cursor position"""
        b = event.cli.current_buffer
        b.validate_and_handle()

    @handle(Keys.Left, filter=beginning_of_line)
    def wrap_cursor_back(event):
        """Move cursor to end of previous line unless at beginning of
        document
        """
        b = event.cli.current_buffer
        b.cursor_up(count=1)
        relative_end_index = b.document.get_end_of_line_position()
        b.cursor_right(count=relative_end_index)

    @handle(Keys.Right, filter=end_of_line)
    def wrap_cursor_forward(event):
        """Move cursor to beginning of next line unless at end of document"""
        b = event.cli.current_buffer
        relative_begin_index = b.document.get_start_of_line_position()
        b.cursor_left(count=abs(relative_begin_index))
        b.cursor_down(count=1)

    @handle(Keys.ControlM, filter=IsSearching())
    @handle(Keys.ControlJ, filter=IsSearching())
    def accept_search(event):
        search.accept_search()

    @handle(Keys.ControlZ)
    def skip_control_z(event):
        """Prevents the writing of ^Z to the prompt, if Ctrl+Z was pressed
        during the previous command.
        """
        pass

    @handle(Keys.ControlX, Keys.ControlX, filter=has_selection)
    def _cut(event):
        """Cut selected text."""
        data = event.current_buffer.cut_selection()
        event.app.clipboard.set_data(data)

    @handle(Keys.ControlX, Keys.ControlC, filter=has_selection)
    def _copy(event):
        """Copy selected text."""
        data = event.current_buffer.copy_selection()
        event.app.clipboard.set_data(data)

    @handle(Keys.ControlV, filter=insert_mode | has_selection)
    def _yank(event):
        """Paste selected text."""
        buff = event.current_buffer
        if buff.selection_state:
            buff.cut_selection()
        get_by_name("yank").call(event)

    def create_alias(new_keys, original_keys):
        bindings = ptk_bindings.get_bindings_for_keys(tuple(original_keys))
        for original_binding in bindings:
            handle(*new_keys, filter=original_binding.filter)(original_binding.handler)

    # Complete a single auto-suggestion word
    create_alias([Keys.ControlRight], ["escape", "f"])

    return key_bindings
Exemplo n.º 18
0
def load_basic_bindings(registry, filter=Always()):
    assert isinstance(filter, CLIFilter)

    insert_mode = ViInsertMode() | EmacsInsertMode()
    handle = create_handle_decorator(registry, filter)
    has_selection = HasSelection()

    @handle(Keys.ControlA)
    @handle(Keys.ControlB)
    @handle(Keys.ControlC)
    @handle(Keys.ControlD)
    @handle(Keys.ControlE)
    @handle(Keys.ControlF)
    @handle(Keys.ControlG)
    @handle(Keys.ControlH)
    @handle(Keys.ControlI)
    @handle(Keys.ControlJ)
    @handle(Keys.ControlK)
    @handle(Keys.ControlL)
    @handle(Keys.ControlM)
    @handle(Keys.ControlN)
    @handle(Keys.ControlO)
    @handle(Keys.ControlP)
    @handle(Keys.ControlQ)
    @handle(Keys.ControlR)
    @handle(Keys.ControlS)
    @handle(Keys.ControlT)
    @handle(Keys.ControlU)
    @handle(Keys.ControlV)
    @handle(Keys.ControlW)
    @handle(Keys.ControlX)
    @handle(Keys.ControlY)
    @handle(Keys.ControlZ)
    @handle(Keys.F1)
    @handle(Keys.F2)
    @handle(Keys.F3)
    @handle(Keys.F4)
    @handle(Keys.F5)
    @handle(Keys.F6)
    @handle(Keys.F7)
    @handle(Keys.F8)
    @handle(Keys.F9)
    @handle(Keys.F10)
    @handle(Keys.F11)
    @handle(Keys.F12)
    @handle(Keys.F13)
    @handle(Keys.F14)
    @handle(Keys.F15)
    @handle(Keys.F16)
    @handle(Keys.F17)
    @handle(Keys.F18)
    @handle(Keys.F19)
    @handle(Keys.F20)
    @handle(Keys.ControlSpace)
    @handle(Keys.ControlBackslash)
    @handle(Keys.ControlSquareClose)
    @handle(Keys.ControlCircumflex)
    @handle(Keys.ControlUnderscore)
    @handle(Keys.Backspace)
    @handle(Keys.Up)
    @handle(Keys.Down)
    @handle(Keys.Right)
    @handle(Keys.Left)
    @handle(Keys.Home)
    @handle(Keys.End)
    @handle(Keys.Delete)
    @handle(Keys.ShiftDelete)
    @handle(Keys.ControlDelete)
    @handle(Keys.PageUp)
    @handle(Keys.PageDown)
    @handle(Keys.BackTab)
    @handle(Keys.Tab)
    @handle(Keys.ControlLeft)
    @handle(Keys.ControlRight)
    @handle(Keys.ControlUp)
    @handle(Keys.ControlDown)
    @handle(Keys.Insert)
    @handle(Keys.Ignore)
    def _(event):
        """
        First, for any of these keys, Don't do anything by default. Also don't
        catch them in the 'Any' handler which will insert them as data.

        If people want to insert these characters as a literal, they can always
        do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi
        mode.)
        """
        pass

    @handle(Keys.Home)
    def _(event):
        b = event.current_buffer
        b.cursor_position += b.document.get_start_of_line_position()

    @handle(Keys.End)
    def _(event):
        b = event.current_buffer
        b.cursor_position += b.document.get_end_of_line_position()

    # CTRL keys.

    text_before_cursor = Condition(lambda cli: cli.current_buffer.text)

    @handle(Keys.ControlD, filter=text_before_cursor & insert_mode)
    def _(event):
        " Delete text before cursor. "
        event.current_buffer.delete(event.arg)

    # Tab completion. (ControlI == Tab)
    handle(Keys.ControlI, filter=insert_mode)(generate_completions)

    @handle(Keys.BackTab, filter=insert_mode)
    def _(event):
        """
        Shift+Tab: go to previous completion.
        """
        event.current_buffer.complete_previous()

    is_multiline = Condition(lambda cli: cli.current_buffer.is_multiline())
    is_returnable = Condition(lambda cli: cli.current_buffer.accept_action.is_returnable)

    @handle(Keys.ControlJ, filter=is_multiline)
    def _(event):
        " Newline (in case of multiline input. "
        event.current_buffer.newline(copy_margin=not event.cli.in_paste_mode)

    @handle(Keys.ControlJ, filter=~is_multiline & is_returnable)
    def _(event):
        " Enter, accept input. "
        buff = event.current_buffer
        buff.accept_action.validate_and_handle(event.cli, buff)

    @handle(Keys.ControlK, filter=insert_mode)
    def _(event):
        buffer = event.current_buffer
        deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
        event.cli.clipboard.set_text(deleted)

    @handle(Keys.ControlT, filter=insert_mode)
    def _(event):
        """
        Emulate Emacs transpose-char behavior: at the beginning of the buffer,
        do nothing.  At the end of a line or buffer, swap the characters before
        the cursor.  Otherwise, move the cursor right, and then swap the
        characters before the cursor.
        """
        b = event.current_buffer
        p = b.cursor_position
        if p == 0:
            return
        elif p == len(b.text) or b.text[p] == '\n':
            b.swap_characters_before_cursor()
        else:
            b.cursor_position += b.document.get_cursor_right_position()
            b.swap_characters_before_cursor()

    @handle(Keys.ControlU, filter=insert_mode)
    def _(event):
        """
        Clears the line before the cursor position. If you are at the end of
        the line, clears the entire line.
        """
        buffer = event.current_buffer
        deleted = buffer.delete_before_cursor(count=-buffer.document.get_start_of_line_position())
        event.cli.clipboard.set_text(deleted)

    @handle(Keys.ControlW, filter=insert_mode)
    def _(event):
        """
        Delete the word before the cursor.
        """
        buffer = event.current_buffer
        pos = buffer.document.find_start_of_previous_word(count=event.arg)

        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 = - buffer.cursor_position

        if pos:
            deleted = buffer.delete_before_cursor(count=-pos)

            # If the previous key press was also Control-W, concatenate deleted
            # text.
            if event.is_repeat:
                deleted += event.cli.clipboard.get_data().text

            event.cli.clipboard.set_text(deleted)
        else:
            # Nothing to delete. Bell.
            event.cli.output.bell()

    @handle(Keys.PageUp, filter= ~has_selection)
    @handle(Keys.ControlUp)
    def _(event):
        event.current_buffer.history_backward()

    @handle(Keys.PageDown, filter= ~has_selection)
    @handle(Keys.ControlDown)
    def _(event):
        event.current_buffer.history_forward()

    @handle(Keys.Left)
    def _(event):
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_left_position(count=event.arg)

    @handle(Keys.Right)
    def _(event):
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_right_position(count=event.arg)

    @handle(Keys.Up, filter= ~has_selection)
    def _(event):
        event.current_buffer.auto_up(count=event.arg)

    @handle(Keys.Up, filter=has_selection)
    def _(event):
        event.current_buffer.cursor_up(count=event.arg)

    @handle(Keys.Down, filter= ~has_selection)
    def _(event):
        event.current_buffer.auto_down(count=event.arg)

    @handle(Keys.Down, filter=has_selection)
    def _(event):
        event.current_buffer.cursor_down(count=event.arg)

    @handle(Keys.ControlH, filter=insert_mode, save_before=if_no_repeat)
    def _(event):
        " Backspace: delete before cursor. "
        deleted = event.current_buffer.delete_before_cursor(count=event.arg)
        if not deleted:
            event.cli.output.bell()

    @handle(Keys.Delete, filter=insert_mode, save_before=if_no_repeat)
    @handle(Keys.ShiftDelete, filter=insert_mode, save_before=if_no_repeat)
    def _(event):
        deleted = event.current_buffer.delete(count=event.arg)

        if not deleted:
            event.cli.output.bell()

    @handle(Keys.Delete, filter=has_selection)
    def _(event):
        data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Any, filter=insert_mode, save_before=if_no_repeat)
    def _(event):
        """
        Insert data at cursor position.
        """
        event.current_buffer.insert_text(event.data * event.arg)

    # Global bindings. These are never disabled and don't include the default filter.

    @handle(Keys.ControlL)
    def _(event):
        " Clear whole screen and redraw. "
        event.cli.renderer.clear()

    @handle(Keys.ControlZ)
    def _(event):
        """
        By default, control-Z should literally insert Ctrl-Z.
        (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File.
        In a Python REPL for instance, it's possible to type
        Control-Z followed by enter to quit.)

        When the system bindings are loaded and suspend-to-background is
        supported, that will override this binding.
        """
        event.current_buffer.insert_text(event.data)

    @registry.add_binding(Keys.CPRResponse)
    def _(event):
        """
        Handle incoming Cursor-Position-Request response.
        """
        # The incoming data looks like u'\x1b[35;1R'
        # Parse row/col information.
        row, col = map(int, event.data[2:-1].split(';'))

        # Report absolute cursor position to the renderer.
        event.cli.renderer.report_absolute_cursor_row(row)

    @registry.add_binding(Keys.BracketedPaste)
    def _(event):
        " Pasting from clipboard. "
        event.current_buffer.insert_text(event.data)
    def load_bindings(key_bindings_manager):
        """
        Load keybindings into prompt_toolkit.
        """

        handle = key_bindings_manager.registry.add_binding
        has_selection = HasSelection()

        # for some reason Pylint doesn't think this function is "used"
        @key_bindings_manager.registry.add_binding(Keys.ControlL)
        def clear_(event):  # pylint: disable=unused-variable
            """
            Clear the screen.
            """

            clear()
            print(env.welcome)
            print(env.get_prompt(), end="")

        @handle(Keys.Tab, filter=TabShouldInsertWhitespaceFilter())
        def _(event):
            """
            When tab should insert whitespace, do that instead of completion.
            """
            event.cli.current_buffer.insert_text('   ')

        # prompt_toolkit _wants_ these two methods (they have different filter
        # attributes)
        @handle(Keys.ControlJ,
                filter=~has_selection & (ViInsertMode() | EmacsInsertMode())
                & HasFocus(DEFAULT_BUFFER) & IsMultiline())
        def _(event):  # pylint: disable=function-redefined
            """
            Behaviour of the Enter key.

            Auto indent after newline/Enter.
            (When not in Vi navigaton mode, and when multiline is enabled.)
            """
            current_buffer = event.current_buffer
            empty_lines_required = 2

            def at_the_end(ptk_buffer):
                """ we consider the cursor at the end when there is no text after
                the cursor, or only whitespace. """
                text = ptk_buffer.document.text_after_cursor
                return text == '' or (text.isspace() and not '\n' in text)

            def all_blocks_closed(ptk_buffer):
                """Return True when all Ergonomica code blocks are closed."""
                return tokenize(ptk_buffer.text).count("(") == tokenize(
                    ptk_buffer.text).count(")")

            if at_the_end(current_buffer)\
               and (current_buffer.document.text.replace(' ', '')
                    .endswith('\n' * (empty_lines_required - 1)
                             ) or all_blocks_closed(current_buffer)):
                current_buffer.document = Document(
                    text=current_buffer.text.rstrip(),
                    cursor_position=len(current_buffer.text.rstrip()))

                current_buffer.accept_action.validate_and_handle(
                    event.cli, current_buffer)
            else:
                _auto_newline(current_buffer)
Exemplo n.º 20
0
def custom_keybindings(bindings, **kw):
    insert_mode = ViInsertMode() | EmacsInsertMode()

    # Key bindings for jumping over whole words (everything that's not
    # white space) using Ctrl+Left and Ctrl+Right;
    # Alt+Left and Alt+Right still jump over smaller word segments.
    # See https://github.com/xonsh/xonsh/issues/2403

    @bindings.add(Keys.ControlLeft)
    def ctrl_left(event):
        buff = event.current_buffer
        pos = buff.document.find_previous_word_beginning(count=event.arg,
                                                         WORD=True)
        if pos:
            buff.cursor_position += pos

    @bindings.add(Keys.ControlRight)
    def ctrl_right(event):
        buff = event.current_buffer
        pos = buff.document.find_next_word_ending(count=event.arg, WORD=True)
        if pos:
            buff.cursor_position += pos

    @bindings.add(Keys.ShiftDelete, filter=insert_mode)
    def delete_surrounding_big_word(event):
        buff = event.current_buffer
        startpos, endpos = buff.document.find_boundaries_of_current_word(
            WORD=True)
        startpos = buff.cursor_position + startpos - 1
        startpos = 0 if startpos < 0 else startpos
        endpos = buff.cursor_position + endpos
        endpos = endpos + 1 if startpos == 0 else endpos
        buff.text = buff.text[:startpos] + buff.text[endpos:]
        buff.cursor_position = startpos

    @bindings.add(Keys.ControlDelete, filter=insert_mode)
    def delete_big_word(event):
        buff = event.current_buffer
        pos = buff.document.find_next_word_ending(count=event.arg, WORD=True)
        if pos:
            buff.delete(count=pos)

    @bindings.add(Keys.Escape, Keys.Delete, filter=insert_mode)
    def delete_small_word(event):
        get_by_name("kill-word").call(event)

    # PTK sets both "\x7f" (^?) and "\x08" (^H) to the same behavior. Refs:
    # https://github.com/prompt-toolkit/python-prompt-toolkit/blob/65c3d0607c69c19d80abb052a18569a2546280e5/src/prompt_toolkit/input/ansi_escape_sequences.py#L65
    # https://github.com/prompt-toolkit/python-prompt-toolkit/issues/257#issuecomment-190328366
    # We patch the ANSI sequences used by PTK.  This requires a terminal
    # that sends different codes for <backspace> and <control-h>.
    # PTK sets Keys.Backspace = Keys.ControlH, so we hardcode the code.
    # Windows has the codes reversed, see https://github.com/xonsh/xonsh/commit/406d20f78f18af39d9bbaf9580b0a763df78a0db
    if XSH.env.get("XONSH_WHOLE_WORD_CTRL_BKSP", True):
        CONTROL_BKSP = "\x08"
        if ON_WINDOWS:
            # On windows BKSP is "\x08" and CTRL-BKSP is "\x7f"
            CONTROL_BKSP = "\x7f"
            ptk_win32.ConsoleInputReader.mappings[b"\x7f"] = CONTROL_BKSP
        ansiseq.ANSI_SEQUENCES[CONTROL_BKSP] = CONTROL_BKSP
        ansiseq.REVERSE_ANSI_SEQUENCES[CONTROL_BKSP] = CONTROL_BKSP

        @bindings.add(CONTROL_BKSP, filter=insert_mode)
        def backward_delete_big_word(event):
            get_by_name("unix-word-rubout").call(event)
Exemplo n.º 21
0
def load_emacs_bindings(registry, filter=Always()):
    """
    Some e-macs extensions.
    """
    # Overview of Readline emacs commands:
    # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf
    filter = to_cli_filter(filter)

    handle = create_handle_decorator(registry, filter & EmacsMode())
    insert_mode = EmacsInsertMode()
    has_selection = HasSelection()

    @handle(Keys.Escape)
    def _(event):
        """
        By default, ignore escape key.

        (If we don't put this here, and Esc is followed by a key which sequence
        is not handled, we'll insert an Escape character in the input stream.
        Something we don't want and happens to easily in emacs mode.
        Further, people can always use ControlQ to do a quoted insert.)
        """
        pass

    @handle(Keys.ControlA)
    def _(event):
        """
        Start of line.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_start_of_line_position(
            after_whitespace=False)

    @handle(Keys.ControlB)
    def _(event):
        """
        Character back.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_left_position(
            count=event.arg)

    @handle(Keys.ControlE)
    def _(event):
        """
        End of line.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_end_of_line_position()

    @handle(Keys.ControlF)
    def _(event):
        """
        Character forward.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_right_position(
            count=event.arg)

    @handle(Keys.ControlN, filter=~has_selection)
    def _(event):
        """
        Next line.
        """
        event.current_buffer.auto_down()

    @handle(Keys.ControlN, filter=has_selection)
    def _(event):
        """
        Next line.
        """
        event.current_buffer.cursor_down()

    @handle(Keys.ControlO, filter=insert_mode)
    def _(event):
        """
        Insert newline, but don't move the cursor.
        """
        event.current_buffer.insert_text('\n', move_cursor=False)

    @handle(Keys.ControlP, filter=~has_selection)
    def _(event):
        """
        Previous line.
        """
        event.current_buffer.auto_up(count=event.arg)

    @handle(Keys.ControlP, filter=has_selection)
    def _(event):
        """
        Previous line.
        """
        event.current_buffer.cursor_up(count=event.arg)

    @handle(Keys.ControlQ, Keys.Any, filter=~has_selection)
    def _(event):
        """
        Quoted insert.

        For vt100 terminals, you have to disable flow control by running
        ``stty -ixon``, otherwise Ctrl-Q and Ctrl-S are captured by the
        terminal.
        """
        event.current_buffer.insert_text(event.data, overwrite=False)

    @handle(Keys.ControlY, filter=insert_mode)
    @handle(Keys.ControlX, 'r', 'y', filter=insert_mode)
    def _(event):
        """
        Paste before cursor.
        """
        event.current_buffer.paste_clipboard_data(
            event.cli.clipboard.get_data(), count=event.arg, before=True)

    @handle(Keys.ControlUnderscore,
            save_before=(lambda e: False),
            filter=insert_mode)
    def _(event):
        """
        Undo.
        """
        event.current_buffer.undo()

    def handle_digit(c):
        """
        Handle Alt + digit in the `meta_digit` method.
        """
        @handle(Keys.Escape, c)
        def _(event):
            event.append_to_arg_count(c)

    for c in '0123456789':
        handle_digit(c)

    @handle(Keys.Escape, '-')
    def _(event):
        """
        """
        if event._arg is None:
            event.append_to_arg_count('-')

    is_returnable = Condition(
        lambda cli: cli.current_buffer.accept_action.is_returnable)

    @handle(Keys.Escape, Keys.ControlJ, filter=insert_mode & is_returnable)
    def _(event):
        """
        Meta + Newline: always accept input.
        """
        b = event.current_buffer
        b.accept_action.validate_and_handle(event.cli, b)

    @handle(Keys.ControlSquareClose, Keys.Any)
    def _(event):
        """
        When Ctl-] + a character is pressed. go to that character.
        """
        match = event.current_buffer.document.find(event.data,
                                                   in_current_line=True,
                                                   count=(event.arg))
        if match is not None:
            event.current_buffer.cursor_position += match

    @handle(Keys.Escape, Keys.Backspace, filter=insert_mode)
    def _(event):
        """
        Delete word backwards.
        """
        buffer = event.current_buffer
        pos = buffer.document.find_start_of_previous_word(count=event.arg)

        if pos is None:
            # Nothing found. Only whitespace before the cursor?
            pos = -buffer.cursor_position

        if pos:
            deleted = buffer.delete_before_cursor(count=-pos)
            event.cli.clipboard.set_text(deleted)

    @handle(Keys.ControlDelete, filter=insert_mode)
    def _(event):
        """
        Delete word after cursor.
        """
        buff = event.current_buffer
        pos = buff.document.find_next_word_ending(count=event.arg)

        if pos:
            deleted = buff.delete(count=pos)
            event.cli.clipboard.set_text(deleted)

    @handle(Keys.Escape, 'a')
    def _(event):
        """
        Previous sentence.
        """
        # TODO:
        pass

    @handle(Keys.Escape, 'c', filter=insert_mode)
    def _(event):
        """
        Capitalize the current (or following) word.
        """
        buffer = event.current_buffer

        for i in range(event.arg):
            pos = buffer.document.find_next_word_ending()
            words = buffer.document.text_after_cursor[:pos]
            buffer.insert_text(words.title(), overwrite=True)

    @handle(Keys.Escape, 'd', filter=insert_mode)
    def _(event):
        """
        Delete word forwards.
        """
        buffer = event.current_buffer
        pos = buffer.document.find_next_word_ending(count=event.arg)

        if pos:
            deleted = buffer.delete(count=pos)
            event.cli.clipboard.set_text(deleted)

    @handle(Keys.Escape, 'e')
    def _(event):
        """ Move to end of sentence. """
        # TODO:
        pass

    @handle(Keys.Escape, 'f')
    @handle(Keys.ControlRight)
    def _(event):
        """
        Cursor to end of next word.
        """
        buffer = event.current_buffer
        pos = buffer.document.find_next_word_ending(count=event.arg)

        if pos:
            buffer.cursor_position += pos

    @handle(Keys.Escape, 'b')
    @handle(Keys.ControlLeft)
    def _(event):
        """
        Cursor to start of previous word.
        """
        buffer = event.current_buffer
        pos = buffer.document.find_previous_word_beginning(count=event.arg)
        if pos:
            buffer.cursor_position += pos

    @handle(Keys.Escape, 'l', filter=insert_mode)
    def _(event):
        """
        Lowercase the current (or following) word.
        """
        buffer = event.current_buffer

        for i in range(event.arg):  # XXX: not DRY: see meta_c and meta_u!!
            pos = buffer.document.find_next_word_ending()
            words = buffer.document.text_after_cursor[:pos]
            buffer.insert_text(words.lower(), overwrite=True)

    @handle(Keys.Escape, 't', filter=insert_mode)
    def _(event):
        """
        Swap the last two words before the cursor.
        """
        # TODO

    @handle(Keys.Escape, 'u', filter=insert_mode)
    def _(event):
        """
        Uppercase the current (or following) word.
        """
        buffer = event.current_buffer

        for i in range(event.arg):
            pos = buffer.document.find_next_word_ending()
            words = buffer.document.text_after_cursor[:pos]
            buffer.insert_text(words.upper(), overwrite=True)

    @handle(Keys.Escape, '.', filter=insert_mode)
    def _(event):
        """
        Rotate through the last word (white-space delimited) of the previous lines in history.
        """
        # TODO

    @handle(Keys.Escape, '\\', filter=insert_mode)
    def _(event):
        """
        Delete all spaces and tabs around point.
        (delete-horizontal-space)
        """
        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)

    @handle(Keys.Escape, '*', filter=insert_mode)
    def _(event):
        """
        `meta-*`: Insert all possible completions of the preceding text.
        """
        buff = event.current_buffer

        # List all completions.
        complete_event = CompleteEvent(text_inserted=False,
                                       completion_requested=True)
        completions = list(
            buff.completer.get_completions(buff.document, complete_event))

        # Insert them.
        text_to_insert = ' '.join(c.text for c in completions)
        buff.insert_text(text_to_insert)

    @handle(Keys.ControlX,
            Keys.ControlU,
            save_before=(lambda e: False),
            filter=insert_mode)
    def _(event):
        event.current_buffer.undo()

    @handle(Keys.ControlX, Keys.ControlX)
    def _(event):
        """
        Move cursor back and forth between the start and end of the current
        line.
        """
        buffer = event.current_buffer

        if buffer.document.current_char == '\n':
            buffer.cursor_position += buffer.document.get_start_of_line_position(
                after_whitespace=False)
        else:
            buffer.cursor_position += buffer.document.get_end_of_line_position(
            )

    @handle(Keys.ControlSpace)
    def _(event):
        """
        Start of the selection (if the current buffer is not empty).
        """
        # Take the current cursor position as the start of this selection.
        buff = event.current_buffer
        if buff.text:
            buff.start_selection(selection_type=SelectionType.CHARACTERS)

    @handle(Keys.ControlG, filter=~has_selection)
    def _(event):
        """
        Control + G: Cancel completion menu and validation state.
        """
        event.current_buffer.complete_state = None
        event.current_buffer.validation_error = None

    @handle(Keys.ControlG, filter=has_selection)
    def _(event):
        """
        Cancel selection.
        """
        event.current_buffer.exit_selection()

    @handle(Keys.ControlW, filter=has_selection)
    @handle(Keys.ControlX, 'r', 'k', filter=has_selection)
    def _(event):
        """
        Cut selected text.
        """
        data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Escape, 'w', filter=has_selection)
    def _(event):
        """
        Copy selected text.
        """
        data = event.current_buffer.copy_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Escape, '<', filter=~has_selection)
    def _(event):
        """
        Move to the first line in the history.
        """
        event.current_buffer.go_to_history(0)

    @handle(Keys.Escape, '>', filter=~has_selection)
    def _(event):
        """
        Move to the end of the input history.
        This is the line we are editing.
        """
        buffer = event.current_buffer
        buffer.go_to_history(len(buffer._working_lines) - 1)

    @handle(Keys.Escape, Keys.Left)
    def _(event):
        """
        Cursor to start of previous word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_previous_word_beginning(
            count=event.arg) or 0

    @handle(Keys.Escape, Keys.Right)
    def _(event):
        """
        Cursor to start of next word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \
            buffer.document.get_end_of_document_position()

    @handle(Keys.Escape, '/', filter=insert_mode)
    def _(event):
        """
        M-/: Complete.
        """
        b = event.current_buffer
        if b.complete_state:
            b.complete_next()
        else:
            event.cli.start_completion(select_first=True)

    @handle(Keys.ControlC, '>', filter=has_selection)
    def _(event):
        """
        Indent selected text.
        """
        buffer = event.current_buffer

        buffer.cursor_position += buffer.document.get_start_of_line_position(
            after_whitespace=True)

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        indent(buffer, from_, to + 1, count=event.arg)

    @handle(Keys.ControlC, '<', filter=has_selection)
    def _(event):
        """
        Unindent selected text.
        """
        buffer = event.current_buffer

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        unindent(buffer, from_, to + 1, count=event.arg)
Exemplo n.º 22
0
def load_python_bindings(key_bindings_manager, python_input):
    """
    Custom key bindings.
    """
    sidebar_visible = Condition(lambda cli: python_input.show_sidebar)
    handle = key_bindings_manager.registry.add_binding
    has_selection = HasSelection()
    vi_mode_enabled = Condition(lambda cli: python_input.vi_mode)

    @handle(Keys.ControlL)
    def _(event):
        """
        Clear whole screen and render again -- also when the sidebar is visible.
        """
        event.cli.renderer.clear()

    @handle(Keys.F2)
    def _(event):
        """
        Show/hide sidebar.
        """
        python_input.show_sidebar = not python_input.show_sidebar

    @handle(Keys.F3)
    def _(event):
        """
        Select from the history.
        """
        python_input.enter_history(event.cli)

    @handle(Keys.F4)
    def _(event):
        """
        Toggle between Vi and Emacs mode.
        """
        python_input.vi_mode = not python_input.vi_mode

    @handle(Keys.F6)
    def _(event):
        """
        Enable/Disable paste mode.
        """
        python_input.paste_mode = not python_input.paste_mode

    @handle(Keys.Tab, filter= ~sidebar_visible & ~has_selection & TabShouldInsertWhitespaceFilter())
    def _(event):
        """
        When tab should insert whitespace, do that instead of completion.
        """
        event.cli.current_buffer.insert_text('    ')

    @handle(Keys.ControlJ, filter= ~sidebar_visible & ~has_selection &
            (ViInsertMode() | EmacsInsertMode()) &
            HasFocus(DEFAULT_BUFFER) & IsMultiline())
    def _(event):
        """
        Behaviour of the Enter key.

        Auto indent after newline/Enter.
        (When not in Vi navigaton mode, and when multiline is enabled.)
        """
        b = event.current_buffer
        empty_lines_required = python_input.accept_input_on_enter or 10000

        def at_the_end(b):
            """ we consider the cursor at the end when there is no text after
            the cursor, or only whitespace. """
            text = b.document.text_after_cursor
            return text == '' or (text.isspace() and not '\n' in text)

        if python_input.paste_mode:
            # In paste mode, always insert text.
            b.insert_text('\n')

        elif at_the_end(b) and b.document.text.replace(' ', '').endswith(
                    '\n' * (empty_lines_required - 1)):
            if b.validate():
                # When the cursor is at the end, and we have an empty line:
                # drop the empty lines, but return the value.
                b.document = Document(
                    text=b.text.rstrip(),
                    cursor_position=len(b.text.rstrip()))

                b.accept_action.validate_and_handle(event.cli, b)
        else:
            auto_newline(b)

    @handle(Keys.ControlD, filter=~sidebar_visible & Condition(lambda cli:
            # Only when the `confirm_exit` flag is set.
            python_input.confirm_exit and
            # And the current buffer is empty.
            cli.current_buffer_name == DEFAULT_BUFFER and
            not cli.current_buffer.text))
    def _(event):
        """
        Override Control-D exit, to ask for confirmation.
        """
        python_input.show_exit_confirmation = True
Exemplo n.º 23
0
def load_xonsh_bindings(key_bindings_manager):
    """
    Load custom key bindings.
    """
    handle = key_bindings_manager.registry.add_binding
    has_selection = HasSelection()
    insert_mode = ViInsertMode() | EmacsInsertMode()

    @handle(Keys.Tab, filter=tab_insert_indent)
    def insert_indent(event):
        """
        If there are only whitespaces before current cursor position insert
        indent instead of autocompleting.
        """
        event.cli.current_buffer.insert_text(env.get('INDENT'))

    @handle(Keys.ControlX, Keys.ControlE, filter=~has_selection)
    def open_editor(event):
        """ Open current buffer in editor """
        event.current_buffer.open_in_editor(event.cli)

    @handle(Keys.BackTab, filter=insert_mode)
    def insert_literal_tab(event):
        """ Insert literal tab on Shift+Tab instead of autocompleting """
        b = event.current_buffer
        if b.complete_state:
            b.complete_previous()
        else:
            event.cli.current_buffer.insert_text(env.get('INDENT'))

    @handle('(', filter=autopair_condition)
    def insert_right_parens(event):
        event.cli.current_buffer.insert_text('(')
        event.cli.current_buffer.insert_text(')', move_cursor=False)

    @handle(')', filter=autopair_condition)
    def overwrite_right_parens(event):
        buffer = event.cli.current_buffer
        if buffer.document.current_char == ')':
            buffer.cursor_position += 1
        else:
            buffer.insert_text(')')

    @handle('[', filter=autopair_condition)
    def insert_right_bracket(event):
        event.cli.current_buffer.insert_text('[')
        event.cli.current_buffer.insert_text(']', move_cursor=False)

    @handle(']', filter=autopair_condition)
    def overwrite_right_bracket(event):
        buffer = event.cli.current_buffer

        if buffer.document.current_char == ']':
            buffer.cursor_position += 1
        else:
            buffer.insert_text(']')

    @handle('\'', filter=autopair_condition)
    def insert_right_quote(event):
        buffer = event.cli.current_buffer

        if buffer.document.current_char == '\'':
            buffer.cursor_position += 1
        else:
            buffer.insert_text('\'')
            buffer.insert_text('\'', move_cursor=False)

    @handle('"', filter=autopair_condition)
    def insert_right_double_quote(event):
        buffer = event.cli.current_buffer

        if buffer.document.current_char == '"':
            buffer.cursor_position += 1
        else:
            buffer.insert_text('"')
            buffer.insert_text('"', move_cursor=False)

    @handle(Keys.ControlD, filter=ctrl_d_condition)
    def call_exit_alias(event):
        """Use xonsh exit function"""
        b = event.cli.current_buffer
        b.accept_action.validate_and_handle(event.cli, b)
        xonsh_exit([])

    @handle(Keys.ControlJ, filter=IsMultiline())
    def multiline_carriage_return(event):
        """ Wrapper around carriage_return multiline parser """
        b = event.cli.current_buffer
        carriage_return(b, event.cli)

    @handle(Keys.ControlJ, filter=should_confirm_completion)
    def enter_confirm_completion(event):
        """Ignore <enter> (confirm completion)"""
        event.current_buffer.complete_state = None

    @handle(Keys.Escape, filter=should_confirm_completion)
    def esc_cancel_completion(event):
        """Use <ESC> to cancel completion"""
        event.cli.current_buffer.cancel_completion()

    @handle(Keys.Escape, Keys.ControlJ)
    def execute_block_now(event):
        """Execute a block of text irrespective of cursor position"""
        b = event.cli.current_buffer
        b.accept_action.validate_and_handle(event.cli, b)

    @handle(Keys.Left, filter=beginning_of_line)
    def wrap_cursor_back(event):
        """Move cursor to end of previous line unless at beginning of
        document
        """
        b = event.cli.current_buffer
        b.cursor_up(count=1)
        relative_end_index = b.document.get_end_of_line_position()
        b.cursor_right(count=relative_end_index)

    @handle(Keys.Right, filter=end_of_line)
    def wrap_cursor_forward(event):
        """Move cursor to beginning of next line unless at end of document"""
        b = event.cli.current_buffer
        relative_begin_index = b.document.get_start_of_line_position()
        b.cursor_left(count=abs(relative_begin_index))
        b.cursor_down(count=1)

    @handle(Keys.ControlI, filter=insert_mode)
    def generate_completions(event):
        """
        Tab-completion: where the first tab completes the common suffix and the
        second tab lists all the completions.

        Notes
        -----
        This method was forked from the mainline prompt-toolkit repo.
        Copyright (c) 2014, Jonathan Slenders, All rights reserved.
        """
        b = event.current_buffer

        def second_tab():
            if b.complete_state:
                b.complete_next()
            else:
                event.cli.start_completion(select_first=False)

        # On the second tab-press, or when already navigating through
        # completions.
        if event.is_repeat or b.complete_state:
            second_tab()
        else:
            event.cli.start_completion(insert_common_part=True,
                                       select_first=False)
Exemplo n.º 24
0
# -*- coding: utf-8 -*-
from IPython import get_ipython
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.keys import Keys
from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode
from prompt_toolkit.key_binding.bindings.named_commands import get_by_name


ip = get_ipython()
insert_mode = ViInsertMode() | EmacsInsertMode()

cursor_left = lambda ev: ev.current_buffer.cursor_left()
cursor_right = lambda ev: ev.current_buffer.cursor_right()

default_filters = HasFocus(DEFAULT_BUFFER) & ~HasSelection() & insert_mode

# Register the shortcut if IPython is using prompt_toolkit
if getattr(ip, 'pt_cli'):
    registry = ip.pt_cli.application.key_bindings_registry
    registry.add_binding(Keys.ControlH, filter=default_filters)(cursor_left)
    registry.add_binding(Keys.ControlL, filter=default_filters)(cursor_right)
    registry.add_binding(Keys.ControlB,
            filter=default_filters)(get_by_name('backward-word'))

Exemplo n.º 25
0
    def init_prompt_toolkit_cli(self):
        if self.simple_prompt or ('JUPYTER_CONSOLE_TEST' in os.environ):
            # Simple restricted interface for tests so we can find prompts with
            # pexpect. Multi-line input not supported.
            def prompt():
                return cast_unicode_py2(
                    input('In [%d]: ' % self.execution_count))

            self.prompt_for_code = prompt
            self.print_out_prompt = \
                lambda: print('Out[%d]: ' % self.execution_count, end='')
            return

        kbmanager = KeyBindingManager.for_prompt()
        insert_mode = ViInsertMode() | EmacsInsertMode()
        # Ctrl+J == Enter, seemingly
        @kbmanager.registry.add_binding(Keys.ControlJ,
                                        filter=(HasFocus(DEFAULT_BUFFER)
                                                & ~HasSelection()
                                                & insert_mode))
        def _(event):
            b = event.current_buffer
            d = b.document
            if not (d.on_last_line or d.cursor_position_row >=
                    d.line_count - d.empty_line_count_at_the_end()):
                b.newline()
                return

            # Pressing enter flushes any pending display. This also ensures
            # the displayed execution_count is correct.
            self.handle_iopub()

            more, indent = self.check_complete(d.text)

            if (not more) and b.accept_action.is_returnable:
                b.accept_action.validate_and_handle(event.cli, b)
            else:
                b.insert_text('\n' + indent)

        @kbmanager.registry.add_binding(Keys.ControlC,
                                        filter=HasFocus(DEFAULT_BUFFER))
        def _(event):
            event.current_buffer.reset()

        @kbmanager.registry.add_binding(Keys.ControlBackslash,
                                        filter=HasFocus(DEFAULT_BUFFER))
        def _(event):
            raise EOFError

        # Pre-populate history from IPython's history database
        history = InMemoryHistory()
        last_cell = u""
        for _, _, cell in self.history_manager.get_tail(
                self.history_load_length, include_latest=True):
            # Ignore blank lines and consecutive duplicates
            cell = cast_unicode_py2(cell.rstrip())
            if cell and (cell != last_cell):
                history.append(cell)

        style_overrides = {
            Token.Prompt: '#009900',
            Token.PromptNum: '#00ff00 bold',
            Token.OutPrompt: '#ff2200',
            Token.OutPromptNum: '#ff0000 bold',
        }
        if self.highlighting_style:
            style_cls = get_style_by_name(self.highlighting_style)
        else:
            style_cls = get_style_by_name('default')
            # The default theme needs to be visible on both a dark background
            # and a light background, because we can't tell what the terminal
            # looks like. These tweaks to the default theme help with that.
            style_overrides.update({
                Token.Number: '#007700',
                Token.Operator: 'noinherit',
                Token.String: '#BB6622',
                Token.Name.Function: '#2080D0',
                Token.Name.Class: 'bold #2080D0',
                Token.Name.Namespace: 'bold #2080D0',
            })
        style_overrides.update(self.highlighting_style_overrides)
        style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
                                            style_dict=style_overrides)

        editing_mode = getattr(EditingMode, self.editing_mode.upper())
        langinfo = self.kernel_info.get('language_info', {})
        lexer = langinfo.get('pygments_lexer', langinfo.get('name', 'text'))
        app = create_prompt_application(
            multiline=True,
            editing_mode=editing_mode,
            lexer=PygmentsLexer(get_pygments_lexer(lexer)),
            get_prompt_tokens=self.get_prompt_tokens,
            get_continuation_tokens=self.get_continuation_tokens,
            key_bindings_registry=kbmanager.registry,
            history=history,
            completer=JupyterPTCompleter(self.Completer),
            enable_history_search=True,
            style=style,
        )

        self._eventloop = create_eventloop()
        self.pt_cli = CommandLineInterface(
            app,
            eventloop=self._eventloop,
            output=create_output(true_color=self.true_color),
        )
Exemplo n.º 26
0
def load_xonsh_bindings(key_bindings):
    """
    Load custom key bindings.
    """
    handle = key_bindings.add
    has_selection = HasSelection()
    insert_mode = ViInsertMode() | EmacsInsertMode()

    @handle(Keys.Tab, filter=tab_insert_indent)
    def insert_indent(event):
        """
        If there are only whitespaces before current cursor position insert
        indent instead of autocompleting.
        """
        env = builtins.__xonsh__.env
        event.cli.current_buffer.insert_text(env.get("INDENT"))

    @handle(Keys.ControlX, Keys.ControlE, filter=~has_selection)
    def open_editor(event):
        """ Open current buffer in editor """
        event.current_buffer.open_in_editor(event.cli)

    @handle(Keys.BackTab, filter=insert_mode)
    def insert_literal_tab(event):
        """ Insert literal tab on Shift+Tab instead of autocompleting """
        b = event.current_buffer
        if b.complete_state:
            b.complete_previous()
        else:
            env = builtins.__xonsh__.env
            event.cli.current_buffer.insert_text(env.get("INDENT"))

    @handle("(", filter=autopair_condition & whitespace_or_bracket_after)
    def insert_right_parens(event):
        event.cli.current_buffer.insert_text("(")
        event.cli.current_buffer.insert_text(")", move_cursor=False)

    @handle(")", filter=autopair_condition)
    def overwrite_right_parens(event):
        buffer = event.cli.current_buffer
        if buffer.document.current_char == ")":
            buffer.cursor_position += 1
        else:
            buffer.insert_text(")")

    @handle("[", filter=autopair_condition & whitespace_or_bracket_after)
    def insert_right_bracket(event):
        event.cli.current_buffer.insert_text("[")
        event.cli.current_buffer.insert_text("]", move_cursor=False)

    @handle("]", filter=autopair_condition)
    def overwrite_right_bracket(event):
        buffer = event.cli.current_buffer

        if buffer.document.current_char == "]":
            buffer.cursor_position += 1
        else:
            buffer.insert_text("]")

    @handle("{", filter=autopair_condition & whitespace_or_bracket_after)
    def insert_right_brace(event):
        event.cli.current_buffer.insert_text("{")
        event.cli.current_buffer.insert_text("}", move_cursor=False)

    @handle("}", filter=autopair_condition)
    def overwrite_right_brace(event):
        buffer = event.cli.current_buffer

        if buffer.document.current_char == "}":
            buffer.cursor_position += 1
        else:
            buffer.insert_text("}")

    @handle("'", filter=autopair_condition)
    def insert_right_quote(event):
        buffer = event.cli.current_buffer

        if buffer.document.current_char == "'":
            buffer.cursor_position += 1
        elif whitespace_or_bracket_before() and whitespace_or_bracket_after():
            buffer.insert_text("'")
            buffer.insert_text("'", move_cursor=False)
        else:
            buffer.insert_text("'")

    @handle('"', filter=autopair_condition)
    def insert_right_double_quote(event):
        buffer = event.cli.current_buffer

        if buffer.document.current_char == '"':
            buffer.cursor_position += 1
        elif whitespace_or_bracket_before() and whitespace_or_bracket_after():
            buffer.insert_text('"')
            buffer.insert_text('"', move_cursor=False)
        else:
            buffer.insert_text('"')

    @handle(Keys.Backspace, filter=autopair_condition)
    def delete_brackets_or_quotes(event):
        """Delete empty pair of brackets or quotes"""
        buffer = event.cli.current_buffer
        before = buffer.document.char_before_cursor
        after = buffer.document.current_char

        if any(
            [before == b and after == a for (b, a) in ["()", "[]", "{}", "''", '""']]
        ):
            buffer.delete(1)

        buffer.delete_before_cursor(1)

    @handle(Keys.ControlD, filter=ctrl_d_condition)
    def call_exit_alias(event):
        """Use xonsh exit function"""
        b = event.cli.current_buffer
        b.validate_and_handle()
        xonsh_exit([])

    @handle(Keys.ControlJ, filter=IsMultiline())
    @handle(Keys.ControlM, filter=IsMultiline())
    def multiline_carriage_return(event):
        """ Wrapper around carriage_return multiline parser """
        b = event.cli.current_buffer
        carriage_return(b, event.cli)

    @handle(Keys.ControlJ, filter=should_confirm_completion)
    @handle(Keys.ControlM, filter=should_confirm_completion)
    def enter_confirm_completion(event):
        """Ignore <enter> (confirm completion)"""
        event.current_buffer.complete_state = None

    @handle(Keys.Escape, filter=should_confirm_completion)
    def esc_cancel_completion(event):
        """Use <ESC> to cancel completion"""
        event.cli.current_buffer.cancel_completion()

    @handle(Keys.Escape, Keys.ControlJ)
    def execute_block_now(event):
        """Execute a block of text irrespective of cursor position"""
        b = event.cli.current_buffer
        b.validate_and_handle()

    @handle(Keys.Left, filter=beginning_of_line)
    def wrap_cursor_back(event):
        """Move cursor to end of previous line unless at beginning of
        document
        """
        b = event.cli.current_buffer
        b.cursor_up(count=1)
        relative_end_index = b.document.get_end_of_line_position()
        b.cursor_right(count=relative_end_index)

    @handle(Keys.Right, filter=end_of_line)
    def wrap_cursor_forward(event):
        """Move cursor to beginning of next line unless at end of document"""
        b = event.cli.current_buffer
        relative_begin_index = b.document.get_start_of_line_position()
        b.cursor_left(count=abs(relative_begin_index))
        b.cursor_down(count=1)

    @handle(Keys.ControlM, filter=IsSearching())
    @handle(Keys.ControlJ, filter=IsSearching())
    def accept_search(event):
        search.accept_search()