Beispiel #1
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(enable_vi_mode=self.vi_mode)
        insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT)
        # 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)
        def _(event):
            event.current_buffer.reset()

        @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 _(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)

        style_overrides = {
            Token.Prompt: '#009900',
            Token.PromptNum: '#00ff00 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)

        app = create_prompt_application(
            multiline=True,
            lexer=PygmentsLexer(Python3Lexer if PY3 else PythonLexer),
            get_prompt_tokens=self.get_prompt_tokens,
            get_continuation_tokens=self.get_continuation_tokens,
            key_bindings_registry=kbmanager.registry,
            history=history,
            completer=IPythonPTCompleter(self.Completer),
            enable_history_search=True,
            style=style,
            mouse_support=self.mouse_support,
        )

        self.pt_cli = CommandLineInterface(app,
                                           eventloop=create_eventloop(
                                               self.inputhook))
Beispiel #2
0
def create_key_bindings(editor):
    """
    Create custom key bindings.

    This starts with the key bindings, defined by `prompt-toolkit`, but adds
    the ones which are specific for the editor.
    """
    # Create new Key binding manager.
    manager = KeyBindingManager(enable_vi_mode=Always(),
                                enable_search=True,
                                enable_extra_page_navigation=Always(),
                                enable_system_bindings=Always())

    # Filters.
    vi_buffer_focussed = Condition(
        lambda cli: cli.current_buffer_name.startswith('buffer-'))

    in_insert_mode = (ViStateFilter(manager.get_vi_state, InputMode.INSERT)
                      & vi_buffer_focussed)
    in_navigation_mode = (ViStateFilter(
        manager.get_vi_state, InputMode.NAVIGATION) & vi_buffer_focussed)

    # Decorator.
    handle = create_handle_decorator(manager.registry)

    @handle(Keys.ControlT)
    def _(event):
        """
        Override default behaviour of prompt-toolkit.
        (Control-T will swap the last two characters before the cursor, because
        that's what readline does.)
        """
        pass

    @handle(Keys.ControlT, filter=in_insert_mode)
    def indent_line(event):
        """
        Indent current line.
        """
        b = event.cli.current_buffer

        # Move to start of line.
        pos = b.document.get_start_of_line_position(after_whitespace=True)
        b.cursor_position += pos

        # Insert tab.
        if editor.expand_tab:
            b.insert_text('    ')
        else:
            b.insert_text('\t')

        # Restore cursor.
        b.cursor_position -= pos

    @handle(Keys.ControlR,
            filter=in_navigation_mode,
            save_before=(lambda e: False))
    def redo(event):
        """
        Redo.
        """
        event.cli.current_buffer.redo()

    @handle(':', filter=in_navigation_mode)
    def enter_command_mode(event):
        """
        Entering command mode.
        """
        editor.enter_command_mode()

    @handle(Keys.Tab,
            filter=ViStateFilter(manager.get_vi_state, InputMode.INSERT)
            & ~HasFocus(COMMAND_BUFFER) & WhitespaceBeforeCursorOnLine())
    def autocomplete_or_indent(event):
        """
        When the 'tab' key is pressed with only whitespace character before the
        cursor, do autocompletion. Otherwise, insert indentation.
        """
        b = event.cli.current_buffer
        if editor.expand_tab:
            b.insert_text('    ')
        else:
            b.insert_text('\t')

    @handle(Keys.Escape, filter=HasFocus(COMMAND_BUFFER))
    @handle(Keys.ControlC, filter=HasFocus(COMMAND_BUFFER))
    @handle(Keys.Backspace,
            filter=HasFocus(COMMAND_BUFFER)
            & Condition(lambda cli: cli.buffers[COMMAND_BUFFER].text == ''))
    def leave_command_mode(event):
        """
        Leaving command mode.
        """
        editor.leave_command_mode()

    @handle(Keys.ControlW, Keys.ControlW, filter=in_navigation_mode)
    def focus_next_window(event):
        editor.window_arrangement.cycle_focus()
        editor.sync_with_prompt_toolkit()

    @handle(Keys.ControlW, 'n', filter=in_navigation_mode)
    def horizontal_split(event):
        """
        Split horizontally.
        """
        editor.window_arrangement.hsplit(None)
        editor.sync_with_prompt_toolkit()

    @handle(Keys.ControlW, 'v', filter=in_navigation_mode)
    def vertical_split(event):
        """
        Split vertically.
        """
        editor.window_arrangement.vsplit(None)
        editor.sync_with_prompt_toolkit()

    @handle('g', 't', filter=in_navigation_mode)
    def focus_next_tab(event):
        editor.window_arrangement.go_to_next_tab()
        editor.sync_with_prompt_toolkit()

    @handle('g', 'T', filter=in_navigation_mode)
    def focus_previous_tab(event):
        editor.window_arrangement.go_to_previous_tab()
        editor.sync_with_prompt_toolkit()

    @handle(Keys.ControlJ, filter=in_navigation_mode)
    def goto_line_beginning(event):
        """ Enter in navigation mode should move to the start of the next line. """
        b = event.current_buffer
        b.cursor_down(count=event.arg)
        b.cursor_position += b.document.get_start_of_line_position(
            after_whitespace=True)

    @handle(Keys.F1)
    def show_help(event):
        editor.show_help()

    return manager
Beispiel #3
0
def load_python_bindings(key_bindings_manager, settings, add_buffer,
                         close_current_buffer):
    """
    Custom key bindings.
    """
    handle = key_bindings_manager.registry.add_binding
    has_selection = HasSelection()

    vi_navigation_mode = ViStateFilter(key_bindings_manager.vi_state, InputMode.NAVIGATION) & \
        ~ HasSelection()

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

    @handle(Keys.F3)
    def _(event):
        """
        Shange completion style.
        """
        # Toggle between combinations.
        settings.show_completions_toolbar, settings.show_completions_menu = {
            (False, False): (False, True),
            (False, True): (True, False),
            (True, False): (False, False),
        }[settings.show_completions_toolbar, settings.show_completions_menu]

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

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

    @handle(Keys.F7)
    def _(event):
        """
        Enable/Disable multiline mode.
        """
        settings.currently_multiline = not settings.currently_multiline

    @handle(Keys.F8)
    def _(event):
        """
        Show/hide signature.
        """
        settings.show_signature = not settings.show_signature

    @handle(Keys.F9)
    def _(event):
        """
        Show/hide docstring window.
        """
        settings.show_docstring = not settings.show_docstring

    @handle(Keys.F10)
    def _(event):
        """
        Show/hide line numbers
        """
        settings.show_line_numbers = not settings.show_line_numbers

    @handle(Keys.F5)
    def _(event):
        """
        Show all buffers
        """
        settings.show_all_buffers = not settings.show_all_buffers

    @handle('g', 't', filter=vi_navigation_mode)
    @handle(Keys.ControlRight)
    def _(event):
        """
        Focus next tab.
        """
        focus_next_buffer(event.cli)

    @handle('g', 'T', filter=vi_navigation_mode)
    @handle(Keys.ControlLeft)
    def _(event):
        """
        Focus previous tab.
        """
        focus_previous_buffer(event.cli)


#    @handle(Keys.F5, filter=filters.HasFocus('default') & ~has_selection)  # XXX: use current tab
#    def _(event):
#        """
#        Merge the previous entry from the history on top.
#        """
#        buffer = event.cli.buffers['default']
#
#        buffer.text = buffer._working_lines[buffer.working_index - 1] + '\n' + buffer.text
#        buffer._working_lines = buffer._working_lines[:buffer.working_index - 1] + buffer._working_lines[buffer.working_index:]
#        buffer.working_index -= 1

    @handle(Keys.ControlT, filter=IsPythonBufferFocussed() & ~has_selection)
    def _(event):
        """
        Create a new Python buffer.
        """
        add_buffer()

    @handle(Keys.ControlD, filter=IsPythonBufferFocussed())
    def _(event):
        """
        Close Python buffer.
        """
        close_current_buffer()

    @handle(Keys.Tab, filter=~has_selection)
    def _(event):
        """
        When the 'tab' key is pressed with only whitespace character before the
        cursor, do autocompletion. Otherwise, insert indentation.
        """
        buffer = event.cli.current_buffer
        current_char = buffer.document.current_line_before_cursor

        if not current_char or current_char.isspace():
            buffer.insert_text('    ')
        else:
            buffer.complete_next()

    @handle(Keys.ControlJ,
            filter=~has_selection
            & ~(ViModeEnabled(key_bindings_manager) & ViStateFilter(
                key_bindings_manager.vi_state, InputMode.NAVIGATION))
            & IsPythonBufferFocussed() & IsMultiline())
    def _(event):
        """
        Auto indent after newline/Enter.
        (When not in Vi navigaton mode, and when multiline is enabled.)
        """
        buffer = event.current_buffer

        if settings.paste_mode:
            buffer.insert_text('\n')
        else:
            auto_newline(buffer)
Beispiel #4
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.key_bindings_manager.get_vi_state(
            event.cli).input_mode = InputMode.NAVIGATION

        def done(result):
            if result is not None:
                event.cli.buffers[DEFAULT_BUFFER].document = result

            python_input.key_bindings_manager.get_vi_state(
                event.cli).input_mode = InputMode.INSERT

        event.cli.run_sub_application(
            create_history_application(
                python_input, event.cli.buffers[DEFAULT_BUFFER].document),
            done)

    @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
            & ~(vi_mode_enabled & ViStateFilter(
                key_bindings_manager.get_vi_state, InputMode.NAVIGATION))
            & 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
Beispiel #5
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(enable_vi_mode=self.vi_mode)
        insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT)
        # 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 _(event):
            event.current_buffer.reset()

        @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
        def _(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 _(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 _(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)

        self._app = create_prompt_application(
                            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.pt_cli = CommandLineInterface(self._app,
                           eventloop=create_eventloop(self.inputhook))
Beispiel #6
0
def create_key_bindings(editor):
    """
    Create custom key bindings.

    This starts with the key bindings, defined by `prompt-toolkit`, but adds
    the ones which are specific for the editor.
    """
    # Create new Key binding manager.
    manager = KeyBindingManager(enable_vi_mode=True, enable_system_prompt=True)
    manager.vi_state.input_mode = InputMode.NAVIGATION

    # Filters.
    vi_buffer_focussed = Condition(
        lambda cli: cli.current_buffer_name.startswith('buffer-'))

    in_insert_mode = (ViStateFilter(manager.vi_state, InputMode.INSERT)
                      & vi_buffer_focussed)
    in_navigation_mode = (ViStateFilter(manager.vi_state, InputMode.NAVIGATION)
                          & vi_buffer_focussed)

    # Decorator.
    handle = create_handle_decorator(manager.registry)

    @handle(Keys.ControlF)
    def _(event):
        """
        Scroll window down.
        """
        w = find_window_for_buffer_name(event.cli.layout,
                                        event.cli.current_buffer_name)
        b = event.cli.current_buffer

        if w and w.render_info:
            new_document_line = min(
                b.document.line_count - 1, b.document.cursor_position_row +
                int(w.render_info.rendered_height / 2))
            b.cursor_position = b.document.translate_row_col_to_index(
                new_document_line, 0)
            w.vertical_scroll = w.render_info.input_line_to_screen_line(
                new_document_line)

    @handle(Keys.ControlT, filter=in_insert_mode)
    def _(event):
        """
        Indent current line.
        """
        b = event.cli.current_buffer

        # Move to start of line.
        pos = b.document.get_start_of_line_position(after_whitespace=True)
        b.cursor_position += pos

        # Insert tab.
        if editor.expand_tab:
            b.insert_text('    ')
        else:
            b.insert_text('\t')

        # Restore cursor.
        b.cursor_position -= pos

    @handle(Keys.ControlU)
    def _(event):
        """
        Scroll window up.
        """
        w = find_window_for_buffer_name(event.cli.layout,
                                        event.cli.current_buffer_name)
        b = event.cli.current_buffer

        if w and w.render_info:
            new_document_line = max(
                0, b.document.cursor_position_row -
                int(w.render_info.rendered_height / 2))
            b.cursor_position = b.document.translate_row_col_to_index(
                new_document_line, 0)
            w.vertical_scroll = w.render_info.input_line_to_screen_line(
                new_document_line)

    @handle(Keys.ControlR, filter=in_navigation_mode, save_before=False)
    def _(event):
        """
        Redo.
        """
        event.cli.current_buffer.redo()

    @handle(':', filter=in_navigation_mode)
    def enter_command_mode(event):
        """
        Entering command mode.
        """
        editor.enter_command_mode()

    @handle(Keys.Tab,
            filter=ViStateFilter(manager.vi_state, InputMode.INSERT)
            & ~HasFocus(COMMAND_BUFFER) & WhitespaceBeforeCursorOnLine())
    def _(event):
        """
        When the 'tab' key is pressed with only whitespace character before the
        cursor, do autocompletion. Otherwise, insert indentation.
        """
        b = event.cli.current_buffer
        if editor.expand_tab:
            b.insert_text('    ')
        else:
            b.insert_text('\t')

    @handle(Keys.Escape, filter=HasFocus(COMMAND_BUFFER))
    @handle(Keys.ControlC, filter=HasFocus(COMMAND_BUFFER))
    @handle(Keys.Backspace,
            filter=HasFocus(COMMAND_BUFFER)
            & Condition(lambda cli: cli.buffers[COMMAND_BUFFER].text == ''))
    def leave_command_mode(event):
        """
        Leaving command mode.
        """
        editor.leave_command_mode()

    @handle(Keys.ControlW, Keys.ControlW, filter=in_navigation_mode)
    def focus_next_window(event):
        editor.window_arrangement.cycle_focus()
        editor.sync_with_prompt_toolkit()

    @handle('g', 't', filter=in_navigation_mode)
    def focus_next_tab(event):
        editor.window_arrangement.go_to_next_tab()
        editor.sync_with_prompt_toolkit()

    @handle('g', 'T', filter=in_navigation_mode)
    def focus_previous_tab(event):
        editor.window_arrangement.go_to_previous_tab()
        editor.sync_with_prompt_toolkit()

    @handle(Keys.ControlJ, filter=in_navigation_mode)
    def _(event):
        """ Enter in navigation mode should move to the start of the next line. """
        b = event.current_buffer
        b.cursor_down(count=event.arg)
        b.cursor_position += b.document.get_start_of_line_position(
            after_whitespace=True)

    @handle(Keys.F1)
    def show_help(event):
        editor.show_help()

    return manager
Beispiel #7
0
def load_python_bindings(key_bindings_manager, settings):
    """
    Custom key bindings.
    """
    handle = key_bindings_manager.registry.add_binding
    has_selection = HasSelection()

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

    @handle(Keys.F3)
    def _(event):
        """
        Shange completion style.
        """
        # Toggle between combinations.
        settings.show_completions_toolbar, settings.show_completions_menu = {
            (False, False): (False, True),
            (False, True): (True, False),
            (True, False): (False, False),
        }[settings.show_completions_toolbar, settings.show_completions_menu]

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

    @handle(Keys.F5)
    def _(event):
        """
        Enable/Disable complete while typing.
        """
        settings.complete_while_typing = not settings.complete_while_typing

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

    @handle(Keys.F8)
    def _(event):
        """
        Show/hide signature.
        """
        settings.show_signature = not settings.show_signature

    @handle(Keys.F9)
    def _(event):
        """
        Show/hide docstring window.
        """
        settings.show_docstring = not settings.show_docstring

    @handle(Keys.F10)
    def _(event):
        """
        Show/hide line numbers
        """
        settings.show_line_numbers = not settings.show_line_numbers

    @handle(Keys.Tab,
            filter=~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=~has_selection
            & ~(ViModeEnabled(key_bindings_manager) & ViStateFilter(
                key_bindings_manager.vi_state, InputMode.NAVIGATION))
            & HasFocus('default') & 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

        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 settings.paste_mode:
            # In paste mode, always insert text.
            b.insert_text('\n')

        elif at_the_end(b) and b.document.text.replace(' ', '').endswith('\n'):
            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.append_to_history()
                event.cli.set_return_value(b.document)
        else:
            auto_newline(b)
Beispiel #8
0
def edit_file(filename):
    manager = KeyBindingManager(enable_vi_mode=True, enable_system_prompt=True)
    manager.vi_state.input_mode = InputMode.NAVIGATION

    layout = HSplit([
        Header(),
        Window(content=BufferControl(show_line_numbers=AlwaysOn(),
                                     lexer=get_lexer_for_filename(
                                         filename).__class__)),
        VimToolbar(filename, manager),
        VimInputBar(),
        SystemToolbar(),
        SearchToolbar(),
    ])

    with codecs.open(filename, 'r', 'utf-8') as f:
        text = f.read()

    @manager.registry.add_binding(':',
                                  filter=ViStateFilter(manager.vi_state,
                                                       InputMode.NAVIGATION))
    def enter_command_mode(event):
        """
        Entering command mode.
        """
        event.cli.focus_stack.push('vim-input')
        manager.vi_state.input_mode = InputMode.INSERT

    @manager.registry.add_binding(Keys.Escape, filter=HasFocus('vim-input'))
    @manager.registry.add_binding(Keys.ControlC, filter=HasFocus('vim-input'))
    @manager.registry.add_binding(
        Keys.Backspace,
        filter=HasFocus('vim-input')
        & Condition(lambda cli: cli.buffers['vim-input'].text == ''))
    def leave_command_mode(event):
        """
        Leaving command mode.
        """
        event.cli.focus_stack.pop()
        manager.vi_state.input_mode = InputMode.NAVIGATION
        event.cli.buffers['vim-input'].document = Document()

    @manager.registry.add_binding(Keys.ControlJ, filter=HasFocus('vim-input'))
    def process_command(event):
        """
        Handling of commands.
        """
        text = event.current_buffer.text

        def save():
            with codecs.open(filename, 'w', 'utf-8') as f:
                f.write(event.cli.buffers['default'].text)

        def leave_command_mode():
            event.cli.focus_stack.pop()
            manager.vi_state.input_mode = InputMode.NAVIGATION
            event.cli.buffers['vim-input'].document = Document()

        if text == 'w':
            save()
            leave_command_mode()
        elif text in ('wq', 'wqa'):
            save()
            event.cli.set_return_value('')

        elif text in ('q', 'qa', 'q!', 'qa!'):
            event.cli.set_return_value('')

        else:
            leave_command_mode()

        # TODO: validation of other commands.

    cli = CommandLineInterface(
        layout=layout,
        renderer=Renderer(use_alternate_screen=True),
        key_bindings_registry=manager.registry,
        buffers={
            'default':
            Buffer(returnable=AlwaysOff(),
                   is_multiline=True,
                   initial_document=Document(text, 0)),
            'vim-input':
            Buffer(returnable=AlwaysOff()),
        },
        style=VimStyle,
    )

    # Run interface.
    cli.read_input()