Ejemplo n.º 1
0
    def _build_key_bindings(self):
        focussed = has_focus(self.system_buffer)

        # Emacs
        emacs_bindings = KeyBindings()
        handle = emacs_bindings.add

        @handle('escape', filter=focussed)
        @handle('c-g', filter=focussed)
        @handle('c-c', filter=focussed)
        def _(event):
            " Hide system prompt. "
            self.system_buffer.reset()
            event.app.layout.focus_previous()

        @handle('enter', filter=focussed)
        def _(event):
            " Run system command. "
            event.app.run_system_command(
                self.system_buffer.text,
                display_before_text=self._get_display_before_text())
            self.system_buffer.reset(append_to_history=True)
            event.app.layout.focus_previous()

        # Vi.
        vi_bindings = KeyBindings()
        handle = vi_bindings.add

        @handle('escape', filter=focussed)
        @handle('c-c', filter=focussed)
        def _(event):
            " Hide system prompt. "
            event.app.vi_state.input_mode = InputMode.NAVIGATION
            self.system_buffer.reset()
            event.app.layout.focus_previous()

        @handle('enter', filter=focussed)
        def _(event):
            " Run system command. "
            event.app.vi_state.input_mode = InputMode.NAVIGATION
            event.app.run_system_command(
                self.system_buffer.text,
                display_before_text=self._get_display_before_text())
            self.system_buffer.reset(append_to_history=True)
            event.app.layout.focus_previous()

        return merge_key_bindings([
            ConditionalKeyBindings(emacs_bindings, emacs_mode),
            ConditionalKeyBindings(vi_bindings, vi_mode),
        ])
Ejemplo n.º 2
0
def load_key_bindings():
    """
    Create a KeyBindings object that contains the default key bindings.
    """
    all_bindings = merge_key_bindings([
        # Load basic bindings.
        load_basic_bindings(),

        # Load emacs bindings.
        load_emacs_bindings(),
        load_emacs_search_bindings(),

        # Load Vi bindings.
        load_vi_bindings(),
        load_vi_search_bindings(),
    ])

    return merge_key_bindings([
        # Make sure that the above key bindings are only active if the
        # currently focussed control is a `BufferControl`. For other controls, we
        # don't want these key bindings to intervene. (This would break "ptterm"
        # for instance, which handles 'Keys.Any' in the user control itself.)
        ConditionalKeyBindings(all_bindings, buffer_has_focus),

        # Active, even when no buffer has been focussed.
        load_mouse_bindings(),
        load_cpr_bindings(),
    ])
Ejemplo n.º 3
0
    def create_application(self):

        # Default key bindings.
        open_in_editor_bindings = load_open_in_editor_bindings()
        prompt_bindings = create_prompt_bindings()

        self.app = Application(
            layout=self.create_layout(),
            style=merge_styles([
                default_style(),
                DynamicStyle(lambda: self.style),
            ]),
            key_bindings=merge_key_bindings([
                merge_key_bindings([
                    ConditionalKeyBindings(
                        open_in_editor_bindings,
                        to_filter(self.enable_open_in_editor)
                        & has_focus(DEFAULT_BUFFER)), prompt_bindings
                ]),
                DynamicKeyBindings(lambda: self.extra_key_bindings),
            ]),
            editing_mode=self.editing_mode,
            reverse_vi_search_direction=True,
            on_render=self.on_render,
            input=self.input,
            output=self.output)

        self.app.mp = self
Ejemplo n.º 4
0
    def _create_key_bindings(self, current_window, other_controls):
        """
        Create a `KeyBindings` object that merges the `KeyBindings` from the
        `UIControl` with all the parent controls and the global key bindings.
        """
        key_bindings = []

        # Collect key bindings from currently focused control and all parent
        # controls. Don't include key bindings of container parent controls.
        container = current_window
        while container is not None:
            kb = container.get_key_bindings()
            if kb is not None:
                key_bindings.append(kb)

            if container.is_modal():
                break
            container = self.app.layout.get_parent(container)

        # Add App key bindings
        if self.app.key_bindings:
            key_bindings.append(self.app.key_bindings)

        # Add mouse bindings.
        key_bindings.append(
            ConditionalKeyBindings(self.app._page_navigation_bindings,
                                   self.app.enable_page_navigation_bindings))
        key_bindings.append(self.app._default_bindings)

        # Reverse this list. The current control's key bindings should come
        # last. They need priority.
        key_bindings = key_bindings[::-1]

        return merge_key_bindings(key_bindings)
Ejemplo n.º 5
0
    def _create_application(self, editing_mode, erase_when_done):
        """
        Create the `Application` object.
        """
        dyncond = self._dyncond

        # Default key bindings.
        auto_suggest_bindings = load_auto_suggest_bindings()
        open_in_editor_bindings = load_open_in_editor_bindings()
        prompt_bindings = self._create_prompt_bindings()

        # Create application
        application = Application(
            layout=self.layout,
            style=DynamicStyle(lambda: self.style),
            include_default_pygments_style=dyncond(
                'include_default_pygments_style'),
            clipboard=DynamicClipboard(lambda: self.clipboard),
            key_bindings=merge_key_bindings([
                merge_key_bindings([
                    auto_suggest_bindings,
                    ConditionalKeyBindings(
                        open_in_editor_bindings,
                        dyncond('enable_open_in_editor')
                        & has_focus(DEFAULT_BUFFER)), prompt_bindings
                ]),
                DynamicKeyBindings(lambda: self.key_bindings),
            ]),
            mouse_support=dyncond('mouse_support'),
            editing_mode=editing_mode,
            erase_when_done=erase_when_done,
            reverse_vi_search_direction=True,
            color_depth=lambda: self.color_depth,

            # I/O.
            input=self.input,
            output=self.output)

        # During render time, make sure that we focus the right search control
        # (if we are searching). - This could be useful if people make the
        # 'multiline' property dynamic.
        '''
        def on_render(app):
            multiline = _true(self.multiline)
            current_control = app.layout.current_control

            if multiline:
                if current_control == search_buffer_control:
                    app.layout.current_control = search_toolbar.control
                    app.invalidate()
            else:
                if current_control == search_toolbar.control:
                    app.layout.current_control = search_buffer_control
                    app.invalidate()

        app.on_render += on_render
        '''

        return application
    def _create_key_bindings(
        self, current_window: Window, other_controls: List[UIControl]
    ) -> KeyBindingsBase:
        """
        Create a `KeyBindings` object that merges the `KeyBindings` from the
        `UIControl` with all the parent controls and the global key bindings.
        """
        key_bindings = []
        collected_containers = set()

        # Collect key bindings from currently focused control and all parent
        # controls. Don't include key bindings of container parent controls.
        container: Container = current_window
        while True:
            collected_containers.add(container)
            kb = container.get_key_bindings()
            if kb is not None:
                key_bindings.append(kb)

            if container.is_modal():
                break

            parent = self.app.layout.get_parent(container)
            if parent is None:
                break
            else:
                container = parent

        # Include global bindings (starting at the top-model container).
        for c in walk(container):
            if c not in collected_containers:
                kb = c.get_key_bindings()
                if kb is not None:
                    key_bindings.append(GlobalOnlyKeyBindings(kb))

        # Add App key bindings
        if self.app.key_bindings:
            key_bindings.append(self.app.key_bindings)

        # Add mouse bindings.
        key_bindings.append(
            ConditionalKeyBindings(
                self.app._page_navigation_bindings,
                self.app.enable_page_navigation_bindings,
            )
        )
        key_bindings.append(self.app._default_bindings)

        # Reverse this list. The current control's key bindings should come
        # last. They need priority.
        key_bindings = key_bindings[::-1]

        return merge_key_bindings(key_bindings)
def load_page_navigation_bindings() -> KeyBindingsBase:
    """
    Load both the Vi and Emacs bindings for page navigation.
    """
    # Only enable when a `Buffer` is focused, otherwise, we would catch keys
    # when another widget is focused (like for instance `c-d` in a
    # ptterm.Terminal).
    return ConditionalKeyBindings(
        merge_key_bindings([
            load_emacs_page_navigation_bindings(),
            load_vi_page_navigation_bindings(),
        ]), buffer_has_focus)
def load_emacs_page_navigation_bindings() -> KeyBindingsBase:
    """
    Key bindings, for scrolling up and down through pages.
    This are separate bindings, because GNU readline doesn't have them.
    """
    key_bindings = KeyBindings()
    handle = key_bindings.add

    handle('c-v')(scroll_page_down)
    handle('pagedown')(scroll_page_down)
    handle('escape', 'v')(scroll_page_up)
    handle('pageup')(scroll_page_up)

    return ConditionalKeyBindings(key_bindings, emacs_mode)
def load_vi_page_navigation_bindings() -> KeyBindingsBase:
    """
    Key bindings, for scrolling up and down through pages.
    This are separate bindings, because GNU readline doesn't have them.
    """
    key_bindings = KeyBindings()
    handle = key_bindings.add

    handle('c-f')(scroll_forward)
    handle('c-b')(scroll_backward)
    handle('c-d')(scroll_half_page_down)
    handle('c-u')(scroll_half_page_up)
    handle('c-e')(scroll_one_line_down)
    handle('c-y')(scroll_one_line_up)
    handle('pagedown')(scroll_page_down)
    handle('pageup')(scroll_page_up)

    return ConditionalKeyBindings(key_bindings, vi_mode)
    def _build_key_bindings(self):
        focused = has_focus(self.system_buffer)

        # Emacs
        emacs_bindings = KeyBindings()
        handle = emacs_bindings.add

        @handle('escape', filter=focused)
        @handle('c-g', filter=focused)
        @handle('c-c', filter=focused)
        def _(event):
            " Hide system prompt. "
            self.system_buffer.reset()
            event.app.layout.focus_last()

        @handle('enter', filter=focused)
        def _(event):
            " Run system command. "
            event.app.run_system_command(
                self.system_buffer.text,
                display_before_text=self._get_display_before_text())
            self.system_buffer.reset(append_to_history=True)
            event.app.layout.focus_last()

        # Vi.
        vi_bindings = KeyBindings()
        handle = vi_bindings.add

        @handle('escape', filter=focused)
        @handle('c-c', filter=focused)
        def _(event):
            " Hide system prompt. "
            event.app.vi_state.input_mode = InputMode.NAVIGATION
            self.system_buffer.reset()
            event.app.layout.focus_last()

        @handle('enter', filter=focused)
        def _(event):
            " Run system command. "
            event.app.vi_state.input_mode = InputMode.NAVIGATION
            event.app.run_system_command(
                self.system_buffer.text,
                display_before_text=self._get_display_before_text())
            self.system_buffer.reset(append_to_history=True)
            event.app.layout.focus_last()

        # Global bindings. (Listen to these bindings, even when this widget is
        # not focussed.)
        global_bindings = KeyBindings()
        handle = global_bindings.add

        @handle(Keys.Escape, '!', filter=~focused & emacs_mode, is_global=True)
        def _(event):
            " M-'!' will focus this user control. "
            event.app.layout.focus(self.window)

        @handle('!',
                filter=~focused & vi_mode & vi_navigation_mode,
                is_global=True)
        def _(event):
            " Focus. "
            event.app.vi_state.input_mode = InputMode.INSERT
            event.app.layout.focus(self.window)

        return merge_key_bindings([
            ConditionalKeyBindings(emacs_bindings, emacs_mode),
            ConditionalKeyBindings(vi_bindings, vi_mode),
            ConditionalKeyBindings(global_bindings,
                                   self.enable_global_bindings),
        ])
Ejemplo n.º 11
0
    def _create_application(self, editing_mode, erase_when_done):
        def dyncond(attr_name):
            """
            Dynamically take this setting from this 'Prompt' class.
            `attr_name` represents an attribute name of this class. Its value
            can either be a boolean or a `Filter`.

            This returns something that can be used as either a `Filter`
            or `Filter`.
            """
            @Condition
            def dynamic():
                value = getattr(self, attr_name)
                return to_filter(value)()

            return dynamic

        # Create functions that will dynamically split the prompt. (If we have
        # a multiline prompt.)
        has_before_fragments, get_prompt_text_1, get_prompt_text_2 = \
            _split_multiline_prompt(self._get_prompt)

        # Create buffers list.
        def accept(buff):
            """ Accept the content of the default buffer. This is called when
            the validation succeeds. """
            self.app.set_result(buff.document.text)

            # Reset content before running again.
            self.app.pre_run_callables.append(buff.reset)

        default_buffer = Buffer(
            name=DEFAULT_BUFFER,
            # Make sure that complete_while_typing is disabled when
            # enable_history_search is enabled. (First convert to Filter,
            # to avoid doing bitwise operations on bool objects.)
            complete_while_typing=Condition(
                lambda: _true(self.complete_while_typing) and not _true(
                    self.enable_history_search) and not self.complete_style ==
                CompleteStyle.READLINE_LIKE),
            validate_while_typing=dyncond('validate_while_typing'),
            enable_history_search=dyncond('enable_history_search'),
            validator=DynamicValidator(lambda: self.validator),
            completer=ThreadedCompleter(
                completer=DynamicCompleter(lambda: self.completer),
                in_thread=dyncond('complete_in_thread'),
            ),
            history=DynamicHistory(lambda: self.history),
            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
            accept_handler=accept,
            get_tempfile_suffix=lambda: self.tempfile_suffix)

        search_buffer = Buffer(name=SEARCH_BUFFER)

        # Create processors list.
        input_processor = merge_processors([
            ConditionalProcessor(
                # By default, only highlight search when the search
                # input has the focus. (Note that this doesn't mean
                # there is no search: the Vi 'n' binding for instance
                # still allows to jump to the next match in
                # navigation mode.)
                HighlightSearchProcessor(preview_search=True),
                has_focus(search_buffer)),
            HighlightSelectionProcessor(),
            ConditionalProcessor(AppendAutoSuggestion(),
                                 has_focus(default_buffer) & ~is_done),
            ConditionalProcessor(PasswordProcessor(), dyncond('is_password')),
            DisplayMultipleCursors(),

            # Users can insert processors here.
            DynamicProcessor(lambda: self.extra_input_processor),

            # For single line mode, show the prompt before the input.
            ConditionalProcessor(
                merge_processors([
                    BeforeInput(get_prompt_text_2),
                    ShowArg(),
                ]), ~dyncond('multiline'))
        ])

        # Create bottom toolbars.
        bottom_toolbar = ConditionalContainer(
            Window(FormattedTextControl(lambda: self.bottom_toolbar,
                                        style='class:bottom-toolbar.text'),
                   style='class:bottom-toolbar',
                   dont_extend_height=True,
                   height=Dimension(min=1)),
            filter=~is_done & renderer_height_is_known
            & Condition(lambda: self.bottom_toolbar is not None))

        search_toolbar = SearchToolbar(
            search_buffer,
            get_search_state=lambda: default_buffer_control.get_search_state())
        search_buffer_control = BufferControl(buffer=search_buffer,
                                              input_processor=merge_processors(
                                                  [
                                                      ReverseSearchProcessor(),
                                                      ShowArg(),
                                                  ]))

        system_toolbar = SystemToolbar()

        def get_search_buffer_control():
            " Return the UIControl to be focused when searching start. "
            if _true(self.multiline):
                return search_toolbar.control
            else:
                return search_buffer_control

        default_buffer_control = BufferControl(
            buffer=default_buffer,
            get_search_buffer_control=get_search_buffer_control,
            input_processor=input_processor,
            lexer=DynamicLexer(lambda: self.lexer),
            preview_search=True)

        default_buffer_window = Window(
            default_buffer_control,
            height=self._get_default_buffer_control_height,
            left_margins=[
                # In multiline mode, use the window margin to display
                # the prompt and continuation fragments.
                ConditionalMargin(
                    PromptMargin(get_prompt_text_2, self._get_continuation),
                    filter=dyncond('multiline'),
                )
            ],
            wrap_lines=dyncond('wrap_lines'))

        @Condition
        def multi_column_complete_style():
            return self.complete_style == CompleteStyle.MULTI_COLUMN

        # Build the layout.
        layout = HSplit([
            # The main input, with completion menus floating on top of it.
            FloatContainer(
                HSplit([
                    ConditionalContainer(
                        Window(FormattedTextControl(get_prompt_text_1),
                               dont_extend_height=True),
                        Condition(has_before_fragments)),
                    ConditionalContainer(
                        default_buffer_window,
                        Condition(lambda: get_app().layout.current_control !=
                                  search_buffer_control),
                    ),
                    ConditionalContainer(
                        Window(search_buffer_control),
                        Condition(lambda: get_app().layout.current_control ==
                                  search_buffer_control),
                    ),
                ]),
                [
                    # Completion menus.
                    Float(xcursor=True,
                          ycursor=True,
                          content=CompletionsMenu(
                              max_height=16,
                              scroll_offset=1,
                              extra_filter=has_focus(default_buffer)
                              & ~multi_column_complete_style)),
                    Float(xcursor=True,
                          ycursor=True,
                          content=MultiColumnCompletionsMenu(
                              show_meta=True,
                              extra_filter=has_focus(default_buffer)
                              & multi_column_complete_style)),
                    # The right prompt.
                    Float(right=0,
                          top=0,
                          hide_when_covering_content=True,
                          content=_RPrompt(lambda: self.rprompt)),
                ]),
            ConditionalContainer(ValidationToolbar(), filter=~is_done),
            ConditionalContainer(system_toolbar,
                                 dyncond('enable_system_prompt') & ~is_done),

            # In multiline mode, we use two toolbars for 'arg' and 'search'.
            ConditionalContainer(
                Window(FormattedTextControl(self._get_arg_text), height=1),
                dyncond('multiline') & has_arg),
            ConditionalContainer(search_toolbar,
                                 dyncond('multiline') & ~is_done),
            bottom_toolbar,
        ])

        # Default key bindings.
        auto_suggest_bindings = load_auto_suggest_bindings()
        open_in_editor_bindings = load_open_in_editor_bindings()
        prompt_bindings = self._create_prompt_bindings()

        # Create application
        application = Application(
            layout=Layout(layout, default_buffer_window),
            style=DynamicStyle(lambda: self.style),
            include_default_pygments_style=dyncond(
                'include_default_pygments_style'),
            clipboard=DynamicClipboard(lambda: self.clipboard),
            key_bindings=merge_key_bindings([
                merge_key_bindings([
                    auto_suggest_bindings,
                    ConditionalKeyBindings(
                        open_in_editor_bindings,
                        dyncond('enable_open_in_editor')
                        & has_focus(DEFAULT_BUFFER)), prompt_bindings
                ]),
                ConditionalKeyBindings(
                    system_toolbar.get_global_key_bindings(),
                    dyncond('enable_system_prompt')),
                DynamicKeyBindings(lambda: self.extra_key_bindings),
            ]),
            mouse_support=dyncond('mouse_support'),
            editing_mode=editing_mode,
            erase_when_done=erase_when_done,
            reverse_vi_search_direction=True,

            # I/O.
            input=self.input,
            output=self.output)

        # During render time, make sure that we focus the right search control
        # (if we are searching). - This could be useful if people make the
        # 'multiline' property dynamic.
        '''
        def on_render(app):
            multiline = _true(self.multiline)
            current_control = app.layout.current_control

            if multiline:
                if current_control == search_buffer_control:
                    app.layout.current_control = search_toolbar.control
                    app.invalidate()
            else:
                if current_control == search_toolbar.control:
                    app.layout.current_control = search_buffer_control
                    app.invalidate()

        app.on_render += on_render
        '''

        return application, default_buffer, default_buffer_control