Exemple #1
0
def _create_more_session(message='--MORE--'):
    """
    Create a `PromptSession` object for displaying the "--MORE--".
    """
    from polymorph.deps.prompt_toolkit.shortcuts import PromptSession
    bindings = KeyBindings()

    @bindings.add(' ')
    @bindings.add('y')
    @bindings.add('Y')
    @bindings.add(Keys.ControlJ)
    @bindings.add(Keys.ControlM)
    @bindings.add(Keys.ControlI)  # Tab.
    def _(event):
        event.app.exit(result=True)

    @bindings.add('n')
    @bindings.add('N')
    @bindings.add('q')
    @bindings.add('Q')
    @bindings.add(Keys.ControlC)
    def _(event):
        event.app.exit(result=False)

    @bindings.add(Keys.Any)
    def _(event):
        " Disable inserting of text. "

    session = PromptSession(message,
                            key_bindings=bindings,
                            erase_when_done=True)
    return session
Exemple #2
0
def create_confirm_session(message):
    """
    Create a `PromptSession` object for the 'confirm' function.
    """
    assert isinstance(message, text_type)
    bindings = KeyBindings()

    @bindings.add('y')
    @bindings.add('Y')
    def yes(event):
        session.default_buffer.text = 'y'
        event.app.exit(result=True)

    @bindings.add('n')
    @bindings.add('N')
    @bindings.add('c-c')
    def no(event):
        session.default_buffer.text = 'n'
        event.app.exit(result=False)

    @bindings.add(Keys.Any)
    def _(event):
        " Disallow inserting other text. "
        pass

    session = PromptSession(message, key_bindings=bindings)
    return session
Exemple #3
0
    def _create_prompt_bindings(self):
        """
        Create the KeyBindings for a prompt application.
        """
        kb = KeyBindings()
        handle = kb.add
        default_focused = has_focus(DEFAULT_BUFFER)

        @Condition
        def do_accept():
            return (not _true(self.multiline)
                    and self.app.layout.has_focus(DEFAULT_BUFFER))

        @handle('enter', filter=do_accept & default_focused)
        def _(event):
            " Accept input when enter has been pressed. "
            self.default_buffer.validate_and_handle()

        @Condition
        def readline_complete_style():
            return self.complete_style == CompleteStyle.READLINE_LIKE

        @handle('tab', filter=readline_complete_style & default_focused)
        def _(event):
            " Display completions (like Readline). "
            display_completions_like_readline(event)

        @handle('c-c', filter=default_focused)
        def _(event):
            " Abort when Control-C has been pressed. "
            event.app.exit(exception=KeyboardInterrupt, style='class:aborting')

        @Condition
        def ctrl_d_condition():
            """ Ctrl-D binding is only active when the default buffer is selected
            and empty. """
            app = get_app()
            return (app.current_buffer.name == DEFAULT_BUFFER
                    and not app.current_buffer.text)

        @handle('c-d', filter=ctrl_d_condition & default_focused)
        def _(event):
            " Exit when Control-D has been pressed. "
            event.app.exit(exception=EOFError, style='class:exiting')

        suspend_supported = Condition(suspend_to_background_supported)

        @Condition
        def enable_suspend():
            return to_filter(self.enable_suspend)()

        @handle('c-z', filter=suspend_supported & enable_suspend)
        def _(event):
            """
            Suspend process to background.
            """
            event.app.suspend_to_background()

        return kb
Exemple #4
0
    def _get_key_bindings(self):
        " Key bindings for the Button. "
        kb = KeyBindings()

        @kb.add(' ')
        @kb.add('enter')
        def _(event):
            if self.handler is not None:
                self.handler()

        return kb
Exemple #5
0
    def get_key_bindings(self):
        """
        Expose key bindings that handle the left/right arrow keys when the menu
        is displayed.
        """
        from polymorph.deps.prompt_toolkit.key_binding.key_bindings import KeyBindings
        kb = KeyBindings()

        @Condition
        def filter():
            " Only handle key bindings if this menu is visible. "
            app = get_app()
            complete_state = app.current_buffer.complete_state

            # There need to be completions, and one needs to be selected.
            if complete_state is None or complete_state.complete_index is None:
                return False

            # This menu needs to be visible.
            return any(window.content == self
                       for window in app.layout.visible_windows)

        def move(right=False):
            buff = get_app().current_buffer
            complete_state = buff.complete_state

            if complete_state is not None and \
                    buff.complete_state.complete_index is not None:
                # Calculate new complete index.
                new_index = buff.complete_state.complete_index
                if right:
                    new_index += self._rendered_rows
                else:
                    new_index -= self._rendered_rows

                if 0 <= new_index < len(complete_state.completions):
                    buff.go_to_completion(new_index)

        # NOTE: the is_global is required because the completion menu will
        #       never be focussed.

        @kb.add('left', is_global=True, filter=filter)
        def _(event):
            move()

        @kb.add('right', is_global=True, filter=filter)
        def _(event):
            move(True)

        return kb
Exemple #6
0
def load_emacs_page_navigation_bindings():
    """
    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)
Exemple #7
0
def load_vi_page_navigation_bindings():
    """
    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)
Exemple #8
0
def load_auto_suggest_bindings():
    """
    Key bindings for accepting auto suggestion text.

    (This has to come after the Vi bindings, because they also have an
    implementation for the "right arrow", but we really want the suggestion
    binding when a suggestion is available.)
    """
    key_bindings = KeyBindings()
    handle = key_bindings.add

    @Condition
    def suggestion_available():
        app = get_app()
        return (app.current_buffer.suggestion is not None
                and app.current_buffer.document.is_cursor_at_the_end)

    @handle('c-f', filter=suggestion_available)
    @handle('c-e', filter=suggestion_available)
    @handle('right', filter=suggestion_available)
    def _(event):
        " Accept suggestion. "
        b = event.current_buffer
        suggestion = b.suggestion

        if suggestion:
            b.insert_text(suggestion.text)

    @handle('escape', 'f', filter=suggestion_available & emacs_mode)
    def _(event):
        " Fill partial suggestion. "
        b = event.current_buffer
        suggestion = b.suggestion

        if suggestion:
            t = re.split(r'(\S+\s+)', suggestion.text)
            b.insert_text(next(x for x in t if x))

    return key_bindings
Exemple #9
0
def _do_wait_for_enter(wait_text):
    """
    Create a sub application to wait for the enter key press.
    This has two advantages over using 'input'/'raw_input':
    - This will share the same input/output I/O.
    - This doesn't block the event loop.
    """
    from polymorph.deps.prompt_toolkit.shortcuts import PromptSession

    key_bindings = KeyBindings()

    @key_bindings.add('enter')
    def _(event):
        event.app.exit()

    @key_bindings.add(Keys.Any)
    def _(event):
        " Disallow typing. "
        pass

    session = PromptSession(message=wait_text, key_bindings=key_bindings)
    yield From(session.app.run_async())
Exemple #10
0
    def __init__(self, text=''):
        assert is_formatted_text(text)

        self.checked = True

        kb = KeyBindings()

        @kb.add(' ')
        @kb.add('enter')
        def _(event):
            self.checked = not self.checked

        self.control = FormattedTextControl(self._get_text_fragments,
                                            key_bindings=kb,
                                            focusable=True)

        self.window = Window(width=3, content=self.control, height=1)

        self.container = VSplit(
            [self.window,
             Label(text=Template(' {}').format(text))],
            style='class:checkbox')
Exemple #11
0
    def __init__(self, values):
        assert isinstance(values, list)
        assert len(values) > 0
        assert all(isinstance(i, tuple) and len(i) == 2 for i in values)

        self.values = values
        self.current_value = values[0][0]
        self._selected_index = 0

        # Key bindings.
        kb = KeyBindings()

        @kb.add('up')
        def _(event):
            self._selected_index = max(0, self._selected_index - 1)

        @kb.add('down')
        def _(event):
            self._selected_index = min(
                len(self.values) - 1, self._selected_index + 1)

        @kb.add('enter')
        @kb.add(' ')
        def _(event):
            self.current_value = self.values[self._selected_index][0]

        # Control and window.
        self.control = FormattedTextControl(self._get_text_fragments,
                                            key_bindings=kb,
                                            focusable=True)

        self.window = Window(content=self.control,
                             style='class:radio-list',
                             right_margins=[
                                 ScrollbarMargin(display_arrows=True),
                             ],
                             dont_extend_height=True)
Exemple #12
0
    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),
        ])
Exemple #13
0
    def __init__(self,
                 body,
                 title='',
                 buttons=None,
                 modal=True,
                 width=None,
                 with_background=False):
        assert is_formatted_text(title)
        assert buttons is None or isinstance(buttons, list)

        buttons = buttons or []

        # When a button is selected, handle left/right key bindings.
        buttons_kb = KeyBindings()
        if len(buttons) > 1:
            first_selected = has_focus(buttons[0])
            last_selected = has_focus(buttons[-1])

            buttons_kb.add('left', filter=~first_selected)(focus_previous)
            buttons_kb.add('right', filter=~last_selected)(focus_next)

        if buttons:
            frame_body = HSplit([
                # Add optional padding around the body.
                Box(body=body, padding=D(preferred=1, max=1),
                    padding_bottom=0),
                # The buttons.
                Box(body=VSplit(buttons, padding=1, key_bindings=buttons_kb),
                    height=D(min=1, max=3, preferred=3))
            ])
        else:
            frame_body = body

        # Key bindings for whole dialog.
        kb = KeyBindings()
        kb.add('tab', filter=~has_completions)(focus_next)
        kb.add('s-tab', filter=~has_completions)(focus_previous)

        frame = Shadow(body=Frame(
            title=title,
            body=frame_body,
            style='class:dialog.body',
            width=(None if with_background is None else width),
            key_bindings=kb,
            modal=modal,
        ))

        if with_background:
            self.container = Box(body=frame, style='class:dialog', width=width)
        else:
            self.container = frame
Exemple #14
0
    def __init__(self, body, menu_items=None, floats=None, key_bindings=None):
        assert isinstance(menu_items, list) and \
            all(isinstance(i, MenuItem) for i in menu_items)
        assert floats is None or all(isinstance(f, Float) for f in floats)

        self.body = body
        self.menu_items = menu_items
        self.selected_menu = [0]

        # Key bindings.
        kb = KeyBindings()

        @Condition
        def in_main_menu():
            return len(self.selected_menu) == 1

        @Condition
        def in_sub_menu():
            return len(self.selected_menu) > 1

        # Navigation through the main menu.

        @kb.add('left', filter=in_main_menu)
        def _(event):
            self.selected_menu[0] = max(0, self.selected_menu[0] - 1)

        @kb.add('right', filter=in_main_menu)
        def _(event):
            self.selected_menu[0] = min(
                len(self.menu_items) - 1, self.selected_menu[0] + 1)

        @kb.add('down', filter=in_main_menu)
        def _(event):
            self.selected_menu.append(0)

        @kb.add('c-c', filter=in_main_menu)
        @kb.add('c-g', filter=in_main_menu)
        def _(event):
            " Leave menu. "
            event.app.layout.focus_last()

        # Sub menu navigation.

        @kb.add('left', filter=in_sub_menu)
        @kb.add('c-g', filter=in_sub_menu)
        @kb.add('c-c', filter=in_sub_menu)
        def _(event):
            " Go back to parent menu. "
            if len(self.selected_menu) > 1:
                self.selected_menu.pop()

        @kb.add('right', filter=in_sub_menu)
        def _(event):
            " go into sub menu. "
            if self._get_menu(len(self.selected_menu) - 1).children:
                self.selected_menu.append(0)

            # If This item does not have a sub menu. Go up in the parent menu.
            elif len(self.selected_menu) == 2 and self.selected_menu[0] < len(
                    self.menu_items) - 1:
                self.selected_menu = [
                    min(len(self.menu_items) - 1, self.selected_menu[0] + 1)
                ]
                if self.menu_items[self.selected_menu[0]].children:
                    self.selected_menu.append(0)

        @kb.add('up', filter=in_sub_menu)
        def _(event):
            " Select previous (enabled) menu item or return to main menu. "
            # Look for previous enabled items in this sub menu.
            menu = self._get_menu(len(self.selected_menu) - 2)
            index = self.selected_menu[-1]

            previous_indexes = [
                i for i, item in enumerate(menu.children)
                if i < index and not item.disabled
            ]

            if previous_indexes:
                self.selected_menu[-1] = previous_indexes[-1]
            elif len(self.selected_menu) == 2:
                # Return to main menu.
                self.selected_menu.pop()

        @kb.add('down', filter=in_sub_menu)
        def _(event):
            " Select next (enabled) menu item. "
            menu = self._get_menu(len(self.selected_menu) - 2)
            index = self.selected_menu[-1]

            next_indexes = [
                i for i, item in enumerate(menu.children)
                if i > index and not item.disabled
            ]

            if next_indexes:
                self.selected_menu[-1] = next_indexes[0]

        @kb.add('enter')
        def _(event):
            " Click the selected menu item. "
            item = self._get_menu(len(self.selected_menu) - 1)
            if item.handler:
                event.app.layout.focus_last()
                item.handler()

        # Controls.
        self.control = FormattedTextControl(self._get_menu_fragments,
                                            key_bindings=kb,
                                            focusable=True,
                                            show_cursor=False)

        self.window = Window(height=1,
                             content=self.control,
                             style='class:menu-bar')

        submenu = self._submenu(0)
        submenu2 = self._submenu(1)
        submenu3 = self._submenu(2)

        @Condition
        def has_focus():
            return get_app().layout.current_window == self.window

        self.container = FloatContainer(
            content=HSplit([
                # The titlebar.
                self.window,

                # The 'body', like defined above.
                body,
            ]),
            floats=[
                Float(xcursor=self.window,
                      ycursor=self.window,
                      content=ConditionalContainer(
                          content=Shadow(body=submenu), filter=has_focus)),
                Float(attach_to_window=submenu,
                      xcursor=True,
                      ycursor=True,
                      allow_cover_cursor=True,
                      content=ConditionalContainer(
                          content=Shadow(body=submenu2),
                          filter=has_focus
                          & Condition(lambda: len(self.selected_menu) >= 1))),
                Float(attach_to_window=submenu2,
                      xcursor=True,
                      ycursor=True,
                      allow_cover_cursor=True,
                      content=ConditionalContainer(
                          content=Shadow(body=submenu3),
                          filter=has_focus
                          & Condition(lambda: len(self.selected_menu) >= 2))),

                # --
            ] + (floats or []),
            key_bindings=key_bindings,
        )