Example #1
0
        def create_python_input_window():
            def menu_position():
                """
                When there is no autocompletion menu to be shown, and we have a
                signature, set the pop-up position at `bracket_start`.
                """
                b = python_input.default_buffer

                if b.complete_state is None and python_input.signatures:
                    row, col = python_input.signatures[0].bracket_start
                    index = b.document.translate_row_col_to_index(row - 1, col)
                    return index

            return Window(
                BufferControl(
                    buffer=python_input.default_buffer,
                    search_buffer_control=search_toolbar.control,
                    lexer=lexer,
                    include_default_input_processors=False,
                    input_processors=[
                        ConditionalProcessor(
                            processor=HighlightIncrementalSearchProcessor(),
                            filter=has_focus(SEARCH_BUFFER)
                            | has_focus(search_toolbar.control),
                        ),
                        HighlightSelectionProcessor(),
                        DisplayMultipleCursors(),
                        # Show matching parentheses, but only while editing.
                        ConditionalProcessor(
                            processor=HighlightMatchingBracketProcessor(chars="[](){}"),
                            filter=has_focus(DEFAULT_BUFFER)
                            & ~is_done
                            & Condition(
                                lambda: python_input.highlight_matching_parenthesis
                            ),
                        ),
                        ConditionalProcessor(
                            processor=AppendAutoSuggestion(), filter=~is_done
                        ),
                    ]
                    + extra_buffer_processors,
                    menu_position=menu_position,
                    # Make sure that we always see the result of an reverse-i-search:
                    preview_search=True,
                ),
                left_margins=[PythonPromptMargin(python_input)],
                # Scroll offsets. The 1 at the bottom is important to make sure
                # the cursor is never below the "Press [Meta+Enter]" message
                # which is a float.
                scroll_offsets=ScrollOffsets(bottom=1, left=4, right=4),
                # As long as we're editing, prefer a minimal height of 6.
                height=(
                    lambda: (
                        None
                        if get_app().is_done or python_input.show_exit_confirmation
                        else input_buffer_height
                    )
                ),
                wrap_lines=Condition(lambda: python_input.wrap_lines),
            )
Example #2
0
    def __init__(self,
                 body: AnyContainer,
                 title: AnyFormattedText = '',
                 buttons: Optional[Sequence[Button]] = None,
                 modal: bool = True,
                 width: AnyDimension = None,
                 with_background: bool = False) -> None:

        self.body = body
        self.title = title

        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)

        frame_body: AnyContainer
        if buttons:
            frame_body = HSplit([
                # Add optional padding around the body.
                Box(body=DynamicContainer(lambda: self.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=lambda: self.title,
            body=frame_body,
            style='class:dialog.body',
            width=(None if with_background is None else width),
            key_bindings=kb,
            modal=modal,
        ))

        self.container: Union[Box, Shadow]
        if with_background:
            self.container = Box(
                body=frame,
                style='class:dialog',
                width=width)
        else:
            self.container = frame
Example #3
0
def create_button_list_kbs(buttons, key_previous, key_next):
    kb = KeyBindings()

    if (len(buttons) > 1):
        is_first_selected = has_focus(buttons[0])
        is_last_selected = has_focus(buttons[-1])

        kb.add(key_previous, filter=~is_first_selected)(focus_previous)
        kb.add(key_next, filter=~is_last_selected)(focus_next)

    return kb
Example #4
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
Example #5
0
        def create_python_input_window():
            def menu_position():
                """
                When there is no autocompletion menu to be shown, and we have a
                signature, set the pop-up position at `bracket_start`.
                """
                b = python_input.default_buffer

                if b.complete_state is None and python_input.signatures:
                    row, col = python_input.signatures[0].bracket_start
                    index = b.document.translate_row_col_to_index(row - 1, col)
                    return index

            return Window(
                BufferControl(
                    buffer=python_input.default_buffer,
                    search_buffer_control=search_toolbar.control,
                    lexer=lexer,
                    include_default_input_processors=False,
                    input_processors=[
                        ConditionalProcessor(
                            processor=HighlightIncrementalSearchProcessor(),
                            filter=has_focus(SEARCH_BUFFER) | has_focus(search_toolbar.control),
                        ),
                        HighlightSelectionProcessor(),
                        DisplayMultipleCursors(),
                        # Show matching parentheses, but only while editing.
                        ConditionalProcessor(
                            processor=HighlightMatchingBracketProcessor(chars='[](){}'),
                            filter=has_focus(DEFAULT_BUFFER) & ~is_done &
                                Condition(lambda: python_input.highlight_matching_parenthesis)),
                        ConditionalProcessor(
                            processor=AppendAutoSuggestion(),
                            filter=~is_done)
                    ] + extra_buffer_processors,
                    menu_position=menu_position,

                    # Make sure that we always see the result of an reverse-i-search:
                    preview_search=True,
                ),
                left_margins=[PythonPromptMargin(python_input)],
                # Scroll offsets. The 1 at the bottom is important to make sure
                # the cursor is never below the "Press [Meta+Enter]" message
                # which is a float.
                scroll_offsets=ScrollOffsets(bottom=1, left=4, right=4),
                # As long as we're editing, prefer a minimal height of 6.
                height=(lambda: (
                    None if get_app().is_done or python_input.show_exit_confirmation
                            else input_buffer_height)),
                wrap_lines=Condition(lambda: python_input.wrap_lines),
            )
Example #6
0
    def pt_init(self):
        def get_prompt_tokens():
            return [(Token.Prompt, self.prompt)]

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

        kb = KeyBindings()
        supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
        kb.add('c-z', filter=supports_suspend)(suspend_to_bg)

        if self.shell.display_completions == 'readlinelike':
            kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
                                  & ~has_selection
                                  & vi_insert_mode | emacs_insert_mode
                                  & ~cursor_in_leading_ws
                              ))(display_completions_like_readline)

        self.pt_app = PromptSession(
                            message=(lambda: PygmentsTokens(get_prompt_tokens())),
                            editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
                            key_bindings=kb,
                            history=self.shell.debugger_history,
                            completer=self._ptcomp,
                            enable_history_search=True,
                            mouse_support=self.shell.mouse_support,
                            complete_style=self.shell.pt_complete_style,
                            style=self.shell.style,
                            inputhook=self.shell.inputhook,
        )
Example #7
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
Example #8
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.current_control
                    == self._default_buffer_control)

        @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.abort()

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

        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
Example #9
0
 def __init__(self, editor):
     super(CommandLine, self).__init__(
         Window(BufferControl(buffer=editor.command_buffer,
                              input_processors=[BeforeInput(':')],
                              lexer=create_command_lexer()),
                height=1),
         filter=has_focus(editor.command_buffer))
Example #10
0
 def __init__(self):
     self.text_control = FormattedTextControl(text=HTML(''))
     self.window = Window(content=self.text_control,
                          always_hide_cursor=True,
                          align=WindowAlign.LEFT)
     super(HelpWindow, self).__init__(content=self.window,
                                      filter=has_focus(self.window))
Example #11
0
    def __init__(
        self,
        prompt: AnyFormattedText = "Shell command: ",
        enable_global_bindings: FilterOrBool = True,
    ) -> None:

        self.prompt = prompt
        self.enable_global_bindings = to_filter(enable_global_bindings)

        self.system_buffer = Buffer(name=SYSTEM_BUFFER)

        self._bindings = self._build_key_bindings()

        self.buffer_control = BufferControl(
            buffer=self.system_buffer,
            lexer=SimpleLexer(style="class:system-toolbar.text"),
            input_processors=[
                BeforeInput(lambda: self.prompt, style="class:system-toolbar")
            ],
            key_bindings=self._bindings,
        )

        self.window = Window(
            self.buffer_control, height=1, style="class:system-toolbar"
        )

        self.container = ConditionalContainer(
            content=self.window, filter=has_focus(self.system_buffer)
        )
Example #12
0
def meta_enter_message(python_input: "PythonInput") -> Container:
    """
    Create the `Layout` for the 'Meta+Enter` message.
    """

    def get_text_fragments() -> StyleAndTextTuples:
        return [("class:accept-message", " [Meta+Enter] Execute ")]

    @Condition
    def extra_condition() -> bool:
        " Only show when... "
        b = python_input.default_buffer

        return (
            python_input.show_meta_enter_message
            and (
                not b.document.is_cursor_at_the_end
                or python_input.accept_input_on_enter is None
            )
            and "\n" in b.text
        )

    visible = ~is_done & has_focus(DEFAULT_BUFFER) & extra_condition

    return ConditionalContainer(
        content=Window(FormattedTextControl(get_text_fragments)), filter=visible
    )
Example #13
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_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 is_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
Example #15
0
    def __init__(self, editor):
        def get_formatted_text():
            eb = editor.window_arrangement.active_editor_buffer

            lineno = eb.buffer.document.cursor_position_row
            errors = eb.report_errors

            for e in errors:
                if e.lineno == lineno:
                    return e.formatted_text

            return []

        super(ReportMessageToolbar,
              self).__init__(FormattedTextToolbar(get_formatted_text),
                             filter=~has_focus(editor.command_buffer)
                             & ~is_searching & ~has_focus('system'))
Example #16
0
 def create_completion_float(self) -> Float:
     return Float(xcursor=True,
                  ycursor=True,
                  transparent=True,
                  attach_to_window=self.input_window,
                  content=CompletionsMenu(scroll_offset=1,
                                          max_height=16,
                                          extra_filter=has_focus(
                                              self.input_buffer)))
Example #17
0
    def add_custom_binding(self,
                           key_name,
                           command,
                           arguments,
                           needs_prefix=False):
        """
        Add custom binding (for the "bind-key" command.)
        Raises ValueError if the give `key_name` is an invalid name.

        :param key_name: Pymux key name, for instance "C-a" or "M-x".
        """
        assert isinstance(key_name, six.text_type)
        assert isinstance(command, six.text_type)
        assert isinstance(arguments, list)

        # Unbind previous key.
        self.remove_custom_binding(key_name, needs_prefix=needs_prefix)

        # Translate the pymux key name into a prompt_toolkit key sequence.
        # (Can raise ValueError.)
        keys_sequence = pymux_key_to_prompt_toolkit_key_sequence(key_name)

        # Create handler and add to Registry.
        if needs_prefix:
            filter = HasPrefix(self.pymux)
        else:
            filter = ~HasPrefix(self.pymux)

        filter = filter & ~(WaitsForConfirmation(self.pymux)
                            | has_focus(COMMAND) | has_focus(PROMPT))

        def key_handler(event):
            " The actual key handler. "
            call_command_handler(command, self.pymux, arguments)
            self.pymux.get_client_state().has_prefix = False

        self.custom_key_bindings.add(*keys_sequence,
                                     filter=filter)(key_handler)

        # Store key in `custom_bindings` in order to be able to call
        # "unbind-key" later on.
        k = (needs_prefix, key_name)
        self.custom_bindings[k] = CustomBinding(key_handler, command,
                                                arguments)
Example #18
0
    def __init__(self,
                 options,
                 default_index=0,
                 header_filter=lambda x: x,
                 match_filter=lambda x: x):

        self.info_window = InfoWindow()
        self.help_window = HelpWindow()
        self.message_toolbar = MessageToolbar(style="class:message_toolbar")
        self.error_toolbar = MessageToolbar(style="class:error_toolbar")
        self.status_line = MessageToolbar(style="class:status_line")
        self.status_line_format = user._tui_status_line_format

        self.options_list = OptionsList(
            options,
            default_index,
            header_filter,
            match_filter,
            custom_filter=~has_focus(self.help_window))
        self.options_list.search_buffer.on_text_changed += self.update

        cmd, cmd_key_bindings = command_key_bindings(self)
        self.command_line_prompt = CommandLinePrompt(commands=cmd)
        key_bindings = merge_key_bindings(
            [general_key_bindings(self), cmd_key_bindings])

        _root_container = HSplit([
            HSplit([
                Window(content=BufferControl(
                    input_processors=[BeforeInput('> ')],
                    buffer=self.options_list.search_buffer)),
                self.options_list,
                self.info_window,
            ]),
            self.help_window,
            self.error_toolbar,
            self.message_toolbar,
            self.status_line,
            self.command_line_prompt.window,
        ])

        self.set_help_text()
        self.layout = Layout(_root_container)

        super(Picker, self).__init__(
            input=None,
            output=None,
            editing_mode=EditingMode.EMACS
            if user._tui_edit_mode == 'emacs' else EditingMode.VI,
            layout=self.layout,
            style=Style.from_dict(user_styles.get_user_styles()),
            key_bindings=key_bindings,
            include_default_pygments_style=False,
            full_screen=True,
            enable_page_navigation_bindings=True)
        self.update()
Example #19
0
 def __init__(self, commands: List[Command] = []):
     self.commands = commands
     wc = WordCompleter(sum([c.names for c in commands], []))
     self.buf = Buffer(completer=wc, complete_while_typing=True)
     self.buf.text = ''
     self.window = Window(content=BufferControl(
         buffer=self.buf, input_processors=[BeforeInput(':')]),
                          height=1)
     super(CommandLinePrompt, self).__init__(content=self.window,
                                             filter=has_focus(self.window))
Example #20
0
    def _load_prefix_binding(self):
        """
        Load the prefix key binding.
        """
        pymux = self.pymux

        # Remove previous binding.
        if self._prefix_binding:
            self.custom_key_bindings.remove_binding(self._prefix_binding)

        # Create new Python binding.
        @self.custom_key_bindings.add(*self._prefix, filter=
            ~(HasPrefix(pymux) | has_focus(COMMAND) | has_focus(PROMPT) |
              WaitsForConfirmation(pymux)))
        def enter_prefix_handler(event):
            " Enter prefix mode. "
            pymux.get_client_state().has_prefix = True

        self._prefix_binding = enter_prefix_handler
Example #21
0
 def __init__(self, lexer_name='yaml'):
     self.buf = Buffer()
     self.buf.text = ''
     self.lexer = PygmentsLexer(find_lexer_class_by_name(lexer_name))
     self.window = HSplit([
         HorizontalLine(),
         Window(content=BufferControl(buffer=self.buf, lexer=self.lexer))
     ],
                          height=Dimension(min=5, max=20, weight=1))
     super(InfoWindow, self).__init__(content=self.window,
                                      filter=has_focus(self))
Example #22
0
    def _load_prefix_binding(self):
        """
        Load the prefix key binding.
        """
        pymux = self.pymux

        # Remove previous binding.
        if self._prefix_binding:
            self.custom_key_bindings.remove_binding(self._prefix_binding)

        # Create new Python binding.
        @self.custom_key_bindings.add(
            *self._prefix,
            filter=~(HasPrefix(pymux) | has_focus(COMMAND) | has_focus(PROMPT)
                     | WaitsForConfirmation(pymux)))
        def enter_prefix_handler(event):
            " Enter prefix mode. "
            pymux.get_client_state().has_prefix = True

        self._prefix_binding = enter_prefix_handler
Example #23
0
    def add_custom_binding(self, key_name, command, arguments, needs_prefix=False):
        """
        Add custom binding (for the "bind-key" command.)
        Raises ValueError if the give `key_name` is an invalid name.

        :param key_name: Pymux key name, for instance "C-a" or "M-x".
        """
        assert isinstance(key_name, six.text_type)
        assert isinstance(command, six.text_type)
        assert isinstance(arguments, list)

        # Unbind previous key.
        self.remove_custom_binding(key_name, needs_prefix=needs_prefix)

        # Translate the pymux key name into a prompt_toolkit key sequence.
        # (Can raise ValueError.)
        keys_sequence = pymux_key_to_prompt_toolkit_key_sequence(key_name)

        # Create handler and add to Registry.
        if needs_prefix:
            filter = HasPrefix(self.pymux)
        else:
            filter = ~HasPrefix(self.pymux)

        filter = filter & ~(WaitsForConfirmation(self.pymux) |
                            has_focus(COMMAND) | has_focus(PROMPT))

        def key_handler(event):
            " The actual key handler. "
            call_command_handler(command, self.pymux, arguments)
            self.pymux.get_client_state().has_prefix = False

        self.custom_key_bindings.add(*keys_sequence, filter=filter)(key_handler)

        # Store key in `custom_bindings` in order to be able to call
        # "unbind-key" later on.
        k = (needs_prefix, key_name)
        self.custom_bindings[k] = CustomBinding(key_handler, command, arguments)
Example #24
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),
        ])
Example #25
0
    def _create_search_mode_bindings(self):
        key_bindings = KeyBindings()
        handle = key_bindings.add
        default_focused = has_focus(DEFAULT_BUFFER)

        @handle('c-w', filter=default_focused)
        def _(event):
            buf = event.current_buffer
            self.completer.toggle_search_mode()
            buf.complete_state = None
            buf.start_completion()
            self.update_toolbar_text()

        return key_bindings
Example #26
0
def main():
    # The layout.
    output_field = TextArea(style='class:output-field', text=help_text)
    input_field = TextArea(height=1, prompt='>>> ', style='class:input-field')

    container = HSplit([
        output_field,
        Window(height=1, char='-', style='class:line'), input_field
    ])

    # The key bindings.
    kb = KeyBindings()

    @kb.add('c-c')
    @kb.add('c-q')
    def _(event):
        " Pressing Ctrl-Q or Ctrl-C will exit the user interface. "
        event.app.exit()

    @kb.add('enter', filter=has_focus(input_field))
    def _(event):
        try:
            output = '\n\nIn:  {}\nOut: {}'.format(
                input_field.text,
                eval(input_field.text))  # Don't do 'eval' in real code!
        except BaseException as e:
            output = '\n\n{}'.format(e)
        new_text = output_field.text + output

        output_field.buffer.document = Document(text=new_text,
                                                cursor_position=len(new_text))
        input_field.text = ''

    # Style.
    style = Style([
        ('output-field', 'bg:#000044 #ffffff'),
        ('input-field', 'bg:#000000 #ffffff'),
        ('line', '#004400'),
    ])

    # Run application.
    application = Application(layout=Layout(container,
                                            focused_element=input_field),
                              key_bindings=kb,
                              style=style,
                              mouse_support=True,
                              full_screen=True)

    application.run()
Example #27
0
    def _build_global_key_bindings(self):
        focussed = has_focus(self.system_buffer)

        bindings = KeyBindings()

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

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

        return bindings
Example #28
0
    def render(self):
        choices_len = len(self._choices)

        buttons = [
            Button('[%s] %s' % (i, label) if choices_len > 1 else label,
                   handler=self._create_handler(sub_component))
            for ((label, sub_component),
                 i) in zip(self._choices, range(
                     1, choices_len +
                     1))  # this is still a loop even if it is inline..
        ]

        self._first_button = buttons[0]

        global global__default_target_focus
        global__default_target_focus = self._first_button

        kb = create_vertical_button_list_kbs(buttons)

        is_first_selected = has_focus(buttons[0])
        kb.add('up', filter=is_first_selected)(lambda e: focus_first_element())

        return Box(
            HSplit(
                [
                    TextArea(
                        text=self._label.format(
                            name=self._controller.state.username) + '\n',
                        read_only=True,
                        focusable=False,
                        scrollbar=True,
                        # push buttons to bottom of screen
                        height=Dimension(preferred=100000, max=100000)),
                    HSplit([
                        VSplit(children=[button], align=HorizontalAlign.CENTER)
                        for button in buttons
                    ],
                           padding=1,
                           key_bindings=kb)
                ],
                padding=Dimension(preferred=2, max=2),
                width=Dimension(),
                align=VerticalAlign.TOP),
            padding=1)
Example #29
0
def main():
    key_bindings = KeyBindings()
    default_focused = has_focus(DEFAULT_BUFFER)

    # Autocomplete with backspace
    @key_bindings.add('backspace', filter=default_focused)
    def _(event):
        event.current_buffer.delete_before_cursor()
        event.current_buffer.insert_text('')

    session = PromptSession(
        wrap_lines=False,
        completer=HistoryCompleter(),
        key_bindings=key_bindings,
    )
    text = '%s\n' % session.prompt('> ')
    if text.strip():
        for c in text:
            fcntl.ioctl(sys.stdout, termios.TIOCSTI, c)
Example #30
0
def create_prompt_bindings():
    """
    Create the KeyBindings for a prompt application.
    """
    kb = KeyBindings()
    handle = kb.add
    default_focussed = has_focus(DEFAULT_BUFFER)

    @handle('enter', filter=default_focussed)
    def _(event):
        " Accept input when enter has been pressed. "
        event.current_buffer.validate_and_handle()

    @handle('c-c', filter=default_focussed)
    def _(event):
        " Abort when Control-C has been pressed. "
        event.app.abort()

    @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_focussed)
    def _(event):
        " Exit when Control-D has been pressed. "
        event.app.exit()

    suspend_supported = Condition(suspend_to_background_supported)

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

    return kb
Example #31
0
    def __init__(self, prompt='Shell command: '):
        self.prompt = prompt
        self.system_buffer = Buffer(name=SYSTEM_BUFFER)

        self._global_bindings = self._build_global_key_bindings()
        self._bindings = self._build_key_bindings()

        self.buffer_control = BufferControl(
            buffer=self.system_buffer,
            lexer=SimpleLexer(style='class:system-toolbar.text'),
            input_processor=BeforeInput(
                lambda: self.prompt, style='class:system-toolbar'),
            key_bindings=self._bindings)

        self.window = Window(
            self.buffer_control, height=1,
            style='class:system-toolbar')

        self.container = ConditionalContainer(
            content=self.window,
            filter=has_focus(self.system_buffer))
Example #32
0
def meta_enter_message(python_input):
    """
    Create the `Layout` for the 'Meta+Enter` message.
    """
    def get_text_fragments():
        return [('class:accept-message', ' [Meta+Enter] Execute ')]

    def extra_condition():
        " Only show when... "
        b = python_input.default_buffer

        return (python_input.show_meta_enter_message
                and (not b.document.is_cursor_at_the_end
                     or python_input.accept_input_on_enter is None)
                and '\n' in b.text)

    visible = ~is_done & has_focus(DEFAULT_BUFFER) & Condition(extra_condition)

    return ConditionalContainer(content=Window(
        FormattedTextControl(get_text_fragments)),
                                filter=visible)
Example #33
0
    def start(self):
        # layout
        self.output_field = TextArea(style='class:output-field',
                                     text=BANNER,
                                     read_only=True,
                                     scrollbar=True)

        self.input_field = TextArea(height=1,
                                    prompt='>>> ',
                                    style='class:input-field')

        self.container = HSplit([
            output_field,
            Window(height=1, char='-', style='class:line'), input_field
        ])

        # key bindings
        self.kb = KeyBindings()

        @kb.add('c-q')
        @kb.add('c-c')
        def _(event):
            event.app.exit()

        @kb.add('enter', filter=has_focus(input_field))
        def _(event):
            try:
                out = "\n\n[ In] {i}\n[Out]{o}".format(
                    i=self.input_field.text,
                    o=self.parseline(self.input_field.text))
            except Exception as e:
                out = "\n\n{e}".format(e=e)
            new_out = self.output_field.text + out
            self.output_field.buffer.document = Document(
                text=new_text, cursor_position=len(new_text))
            self.input_field.text = ''

        # style
        style = Style(self.LAYOUT_STYLE)
Example #34
0
def meta_enter_message(python_input):
    """
    Create the `Layout` for the 'Meta+Enter` message.
    """
    def get_text_fragments():
        return [('class:accept-message', ' [Meta+Enter] Execute ')]

    def extra_condition():
        " Only show when... "
        b = python_input.default_buffer

        return (
            python_input.show_meta_enter_message and
            (not b.document.is_cursor_at_the_end or
                python_input.accept_input_on_enter is None) and
            '\n' in b.text)

    visible = ~is_done & has_focus(DEFAULT_BUFFER) & Condition(extra_condition)

    return ConditionalContainer(
        content=Window(FormattedTextControl(get_text_fragments)),
        filter=visible)
    def __init__(self, prompt='Shell command: ', enable_global_bindings=True):
        self.prompt = prompt
        self.enable_global_bindings = to_filter(enable_global_bindings)

        self.system_buffer = Buffer(name=SYSTEM_BUFFER)

        self._bindings = self._build_key_bindings()

        self.buffer_control = BufferControl(
            buffer=self.system_buffer,
            lexer=SimpleLexer(style='class:system-toolbar.text'),
            input_processors=[BeforeInput(
                lambda: self.prompt, style='class:system-toolbar')],
            key_bindings=self._bindings)

        self.window = Window(
            self.buffer_control, height=1,
            style='class:system-toolbar')

        self.container = ConditionalContainer(
            content=self.window,
            filter=has_focus(self.system_buffer))
Example #36
0
    def set_kb(self):
        @self.kb.add('c-d')
        def _(event):
            " Pressing Ctrl-D will exit the user interface. "
            event.app.exit()

        @self.kb.add('c-q')
        def _(event):
            " Pressing Ctrl-Q will exit the user interface. "
            self.quit = True
            event.app.exit()

        @self.kb.add('enter', filter=has_focus(self.elements['input']))
        def _(event):
            try:
                selection = self.elements['input'].text
                if selection == 'start':
                    self.start_game()
                else:
                    self.make_moves(selection)
            except BaseException as e:
                self.set_text('board', str(e))

            self.elements['input'].text = ''
Example #37
0
def configure(repl):
    """
    Configuration method. This is called during the start-up of ptpython.
    :param repl: `PythonRepl` instance.
    """
    # Show function signature (bool).
    repl.show_signature = True

    # Show docstring (bool).
    repl.show_docstring = False

    # Accept when pressing Enter 'n' times.
    # 'None' means that meta-enter is always required.
    repl.accept_input_on_enter = 3

    # Show the "[Meta+Enter] Execute" message when pressing [Enter] only
    # inserts a newline instead of executing the code.
    repl.show_meta_enter_message = True

    # Show completions. (NONE, POP_UP, MULTI_COLUMN or TOOLBAR)
    repl.completion_visualisation = CompletionVisualisation.POP_UP

    # When CompletionVisualisation.POP_UP has been chosen, use this
    # scroll_offset in the completion menu.
    repl.completion_menu_scroll_offset = 0

    # Show line numbers (when the input contains multiple lines.)
    repl.show_line_numbers = True

    # Show status bar.
    repl.show_status_bar = True

    # When the sidebar is visible, also show the help text.
    repl.show_sidebar_help = True

    # Highlight matching parethesis.
    repl.highlight_matching_parenthesis = True

    # Line wrapping. (Instead of horizontal scrolling.)
    repl.wrap_lines = True

    # Mouse support.
    repl.enable_mouse_support = True

    # Complete while typing. (Don't require tab before the
    # completion menu is shown.)
    repl.complete_while_typing = True

    # Vi mode.
    repl.vi_mode = False

    # Paste mode. (When True, don't insert whitespace after new line.)
    repl.paste_mode = False

    # Use the classic prompt. (Display '>>>' instead of 'In [1]'.)
    repl.prompt_style = 'classic'  # 'classic' or 'ipython'

    # Don't insert a blank line after the output.
    repl.insert_blank_line_after_output = False

    # History Search.
    # When True, going back in history will filter the history on the records
    # starting with the current input. (Like readline.)
    # Note: When enable, please disable the `complete_while_typing` option.
    #       otherwise, when there is a completion available, the arrows will
    #       browse through the available completions instead of the history.
    repl.enable_history_search = False

    # Enable auto suggestions. (Pressing right arrow will complete the input,
    # based on the history.)
    repl.enable_auto_suggest = True

    # Enable open-in-editor. Pressing C-X C-E in emacs mode or 'v' in
    # Vi navigation mode will open the input in the current editor.
    repl.enable_open_in_editor = True

    # Enable system prompt. Pressing meta-! will display the system prompt.
    # Also enables Control-Z suspend.
    repl.enable_system_bindings = True

    # Ask for confirmation on exit.
    repl.confirm_exit = True

    # Enable input validation. (Don't try to execute when the input contains
    # syntax errors.)
    repl.enable_input_validation = True

    # Use this colorscheme for the code.
    repl.use_code_colorscheme('pastie')

    # Set color depth (keep in mind that not all terminals support true color).

    #repl.color_depth = 'DEPTH_1_BIT'  # Monochrome.
    #repl.color_depth = 'DEPTH_4_BIT'  # ANSI colors only.
    repl.color_depth = 'DEPTH_8_BIT'  # The default, 256 colors.
    #repl.color_depth = 'DEPTH_24_BIT'  # True color.

    # Syntax.
    repl.enable_syntax_highlighting = True

    # Install custom colorscheme named 'my-colorscheme' and use it.
    """
    repl.install_ui_colorscheme('my-colorscheme', _custom_ui_colorscheme)
    repl.use_ui_colorscheme('my-colorscheme')
    """

    Keys.CtrlEnter = "<ignore>"
    ANSI_SEQUENCES['\x1b_KrEz\x1b\\'] = Keys.CtrlEnter
    Keys.ShiftEnter = "<ignore>"
    ANSI_SEQUENCES['\x1b_KrBz\x1b\\'] = Keys.ShiftEnter

    @Condition
    def is_multiline():
        return document_is_multiline_python(repl.default_buffer.document)

    @repl.add_key_binding(Keys.CtrlEnter, filter=has_focus(DEFAULT_BUFFER))
    @repl.add_key_binding(Keys.ShiftEnter, filter=has_focus(DEFAULT_BUFFER))
    def _(event):
        "Shift-Enter accepts line"
        b = event.cli.current_buffer
        b.validate_and_handle()

    @repl.add_key_binding('c-m', filter=(
        ~has_selection & has_focus(DEFAULT_BUFFER) & ~is_multiline &
        (vi_insert_mode | emacs_insert_mode)
    ))
    def _(event):
        "Enter inserts new line from first line"
        b = event.cli.current_buffer
        b.insert_text('\n')

    # Add custom key binding for PDB.
    """
    @repl.add_key_binding(Keys.ControlB)
    def _(event):
        ' Pressing Control-B will insert "pdb.set_trace()" '
        event.cli.current_buffer.insert_text('\nimport pdb; pdb.set_trace()\n')
    """

    # Typing ControlE twice should also execute the current command.
    # (Alternative for Meta-Enter.)
    """
    @repl.add_key_binding(Keys.ControlE, Keys.ControlE)
    def _(event):
        event.current_buffer.validate_and_handle()
    """

    # Typing 'jj' in Vi Insert mode, should send escape. (Go back to navigation
    # mode.)
    """
    @repl.add_key_binding('j', 'j', filter=ViInsertMode())
    def _(event):
        " Map 'jj' to Escape. "
        event.cli.key_processor.feed(KeyPress(Keys.Escape))
    """

    # Custom key binding for some simple autocorrection while typing.
    """
    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),
            style_transformation=merge_style_transformations([
                DynamicStyleTransformation(lambda: self.style_transformation),
                ConditionalStyleTransformation(
                    SwapLightAndDarkStyleTransformation(),
                    dyncond('swap_light_and_dark_colors'),
                ),
            ]),
            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 = is_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
Example #39
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

        kb = KeyBindings()
        insert_mode = vi_insert_mode | emacs_insert_mode

        @kb.add("enter", filter=(has_focus(DEFAULT_BUFFER)
                                 & ~has_selection
                                 & 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_handler:
                b.validate_and_handle()
            else:
                b.insert_text('\n' + indent)

        @kb.add("c-c", filter=has_focus(DEFAULT_BUFFER))
        def _(event):
            event.current_buffer.reset()

        @kb.add("c-\\", filter=has_focus(DEFAULT_BUFFER))
        def _(event):
            raise EOFError

        @kb.add("c-z", filter=Condition(lambda: suspend_to_background_supported()))
        def _(event):
            event.cli.suspend_to_background()

        # 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_string(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 = merge_styles([
            style_from_pygments_cls(style_cls),
            style_from_pygments_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'))

        # If enabled in the settings, highlight matching brackets
        # when the DEFAULT_BUFFER has the focus
        input_processors = [ConditionalProcessor(
            processor=HighlightMatchingBracketProcessor(chars='[](){}'),
            filter=has_focus(DEFAULT_BUFFER) & ~is_done &
            Condition(lambda: self.highlight_matching_brackets))
        ]

        self.pt_cli = PromptSession(
            message=(lambda: PygmentsTokens(self.get_prompt_tokens())),
            multiline=True,
            editing_mode=editing_mode,
            lexer=PygmentsLexer(get_pygments_lexer(lexer)),
            prompt_continuation=(
                lambda width, lineno, is_soft_wrap:
                PygmentsTokens(self.get_continuation_tokens(width))
            ),
            key_bindings=kb,
            history=history,
            completer=JupyterPTCompleter(self.Completer),
            enable_history_search=True,
            style=style,
            input_processors=input_processors,
            color_depth=(ColorDepth.TRUE_COLOR if self.true_color else None),

        )
Example #40
0
def create_ipython_shortcuts(shell):
    """Set up the prompt_toolkit keyboard shortcuts for IPython"""

    kb = KeyBindings()
    insert_mode = vi_insert_mode | emacs_insert_mode

    if getattr(shell, 'handle_return', None):
        return_handler = shell.handle_return(shell)
    else:
        return_handler = newline_or_execute_outer(shell)

    kb.add('enter', filter=(has_focus(DEFAULT_BUFFER)
                            & ~has_selection
                            & insert_mode
                        ))(return_handler)

    kb.add('c-\\')(force_exit)

    kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
                )(previous_history_or_previous_completion)

    kb.add('c-n', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
                )(next_history_or_next_completion)

    kb.add('c-g', filter=(has_focus(DEFAULT_BUFFER) & has_completions)
                )(dismiss_completion)

    kb.add('c-c', filter=has_focus(DEFAULT_BUFFER))(reset_buffer)

    kb.add('c-c', filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)

    supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
    kb.add('c-z', filter=supports_suspend)(suspend_to_bg)

    # Ctrl+I == Tab
    kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
                          & ~has_selection
                          & insert_mode
                          & cursor_in_leading_ws
                        ))(indent_buffer)

    kb.add('c-o', filter=(has_focus(DEFAULT_BUFFER)
                  & emacs_insert_mode))(newline_autoindent_outer(shell.input_splitter))

    kb.add('f2', filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)

    if shell.display_completions == 'readlinelike':
        kb.add('c-i', filter=(has_focus(DEFAULT_BUFFER)
                              & ~has_selection
                              & insert_mode
                              & ~cursor_in_leading_ws
                        ))(display_completions_like_readline)

    if sys.platform == 'win32':
        kb.add('c-v', filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)

    return kb
Example #41
0
    def _load_builtins(self):
        """
        Fill the Registry with the hard coded key bindings.
        """
        pymux = self.pymux
        kb = KeyBindings()

        # Create filters.
        has_prefix = HasPrefix(pymux)
        waits_for_confirmation = WaitsForConfirmation(pymux)
        prompt_or_command_focus = has_focus(COMMAND) | has_focus(PROMPT)
        display_pane_numbers = Condition(lambda: pymux.display_pane_numbers)
        in_scroll_buffer_not_searching = InScrollBufferNotSearching(pymux)

        @kb.add(Keys.Any, filter=has_prefix)
        def _(event):
            " Ignore unknown Ctrl-B prefixed key sequences. "
            pymux.get_client_state().has_prefix = False

        @kb.add('c-c', filter=prompt_or_command_focus & ~has_prefix)
        @kb.add('c-g', filter=prompt_or_command_focus & ~has_prefix)
#        @kb.add('backspace', filter=has_focus(COMMAND) & ~has_prefix &
#                              Condition(lambda: cli.buffers[COMMAND].text == ''))
        def _(event):
            " Leave command mode. "
            pymux.leave_command_mode(append_to_history=False)

        @kb.add('y', filter=waits_for_confirmation)
        @kb.add('Y', filter=waits_for_confirmation)
        def _(event):
            """
            Confirm command.
            """
            client_state = pymux.get_client_state()

            command = client_state.confirm_command
            client_state.confirm_command = None
            client_state.confirm_text = None

            pymux.handle_command(command)

        @kb.add('n', filter=waits_for_confirmation)
        @kb.add('N', filter=waits_for_confirmation)
        @kb.add('c-c' , filter=waits_for_confirmation)
        def _(event):
            """
            Cancel command.
            """
            client_state = pymux.get_client_state()
            client_state.confirm_command = None
            client_state.confirm_text = None

        @kb.add('c-c', filter=in_scroll_buffer_not_searching)
        @kb.add('enter', filter=in_scroll_buffer_not_searching)
        @kb.add('q', filter=in_scroll_buffer_not_searching)
        def _(event):
            " Exit scroll buffer. "
            pane = pymux.arrangement.get_active_pane()
            pane.exit_scroll_buffer()

        @kb.add(' ', filter=in_scroll_buffer_not_searching)
        def _(event):
            " Enter selection mode when pressing space in copy mode. "
            event.current_buffer.start_selection(selection_type=SelectionType.CHARACTERS)

        @kb.add('enter', filter=in_scroll_buffer_not_searching & has_selection)
        def _(event):
            " Copy selection when pressing Enter. "
            clipboard_data = event.current_buffer.copy_selection()
            event.app.clipboard.set_data(clipboard_data)

        @kb.add('v', filter=in_scroll_buffer_not_searching & has_selection)
        def _(event):
            " Toggle between selection types. "
            types = [SelectionType.LINES, SelectionType.BLOCK, SelectionType.CHARACTERS]
            selection_state = event.current_buffer.selection_state

            try:
                index = types.index(selection_state.type)
            except ValueError:  # Not in list.
                index = 0

            selection_state.type = types[(index + 1) % len(types)]

        @Condition
        def popup_displayed():
            return self.pymux.get_client_state().display_popup

        @kb.add('q', filter=popup_displayed, eager=True)
        def _(event):
            " Quit pop-up dialog. "
            self.pymux.get_client_state().display_popup = False

        @kb.add(Keys.Any, eager=True, filter=display_pane_numbers)
        def _(event):
            " When the pane numbers are shown. Any key press should hide them. "
            pymux.display_pane_numbers = False

        @Condition
        def clock_displayed():
            " "
            pane = pymux.arrangement.get_active_pane()
            return pane.clock_mode

        @kb.add(Keys.Any, eager=True, filter=clock_displayed)
        def _(event):
            " When the clock is displayed. Any key press should hide it. "
            pane = pymux.arrangement.get_active_pane()
            pane.clock_mode = False

        return kb
Example #42
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.
    """
    kb = KeyBindings()

    # Filters.
    @Condition
    def vi_buffer_focussed():
        app = get_app()
        if app.layout.has_focus(editor.search_buffer) or app.layout.has_focus(editor.command_buffer):
            return False
        return True

    in_insert_mode = vi_insert_mode & vi_buffer_focussed
    in_navigation_mode = vi_navigation_mode & vi_buffer_focussed

    @kb.add('c-t')
    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

    @kb.add('c-t', filter=in_insert_mode)
    def indent_line(event):
        """
        Indent current line.
        """
        b = event.application.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

    @kb.add('c-r', filter=in_navigation_mode, save_before=(lambda e: False))
    def redo(event):
        """
        Redo.
        """
        event.app.current_buffer.redo()

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

    @kb.add('tab', filter=vi_insert_mode &
            ~has_focus(editor.command_buffer) & whitespace_before_cursor_on_line)
    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.app.current_buffer
        if editor.expand_tab:
            b.insert_text('    ')
        else:
            b.insert_text('\t')

    @kb.add('escape', filter=has_focus(editor.command_buffer))
    @kb.add('c-c', filter=has_focus(editor.command_buffer))
    @kb.add('backspace',
        filter=has_focus(editor.command_buffer) & Condition(lambda: editor.command_buffer.text == ''))
    def leave_command_mode(event):
        """
        Leaving command mode.
        """
        editor.leave_command_mode()

    @kb.add('c-w', 'c-w', filter=in_navigation_mode)
    def focus_next_window(event):
        editor.window_arrangement.cycle_focus()
        editor.sync_with_prompt_toolkit()

    @kb.add('c-w', 'n', filter=in_navigation_mode)
    def horizontal_split(event):
        """
        Split horizontally.
        """
        editor.window_arrangement.hsplit(None)
        editor.sync_with_prompt_toolkit()

    @kb.add('c-w', 'v', filter=in_navigation_mode)
    def vertical_split(event):
        """
        Split vertically.
        """
        editor.window_arrangement.vsplit(None)
        editor.sync_with_prompt_toolkit()

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

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

    @kb.add('f1')
    def show_help(event):
        editor.show_help()

    @Condition
    def in_file_explorer_mode():
        return bool(editor.current_editor_buffer and
            editor.current_editor_buffer.in_file_explorer_mode)

    @kb.add('enter', filter=in_file_explorer_mode)
    def open_path(event):
        """
        Open file/directory in file explorer mode.
        """
        name_under_cursor = event.current_buffer.document.current_line
        new_path = os.path.normpath(os.path.join(
            editor.current_editor_buffer.location, name_under_cursor))

        editor.window_arrangement.open_buffer(
            new_path, show_in_current_window=True)
        editor.sync_with_prompt_toolkit()

    @kb.add('-', filter=in_file_explorer_mode)
    def to_parent_directory(event):
        new_path = os.path.normpath(os.path.join(
            editor.current_editor_buffer.location, '..'))

        editor.window_arrangement.open_buffer(
            new_path, show_in_current_window=True)
        editor.sync_with_prompt_toolkit()

    return kb
def create_key_bindings(history, python_input, history_mapping):
    """
    Key bindings.
    """
    bindings = KeyBindings()
    handle = bindings.add

    @handle(' ', filter=has_focus(history.history_buffer))
    def _(event):
        """
        Space: select/deselect line from history pane.
        """
        b = event.current_buffer
        line_no = b.document.cursor_position_row

        if not history_mapping.history_lines:
            # If we've no history, then nothing to do
            return

        if line_no in history_mapping.selected_lines:
            # Remove line.
            history_mapping.selected_lines.remove(line_no)
            history_mapping.update_default_buffer()
        else:
            # Add line.
            history_mapping.selected_lines.add(line_no)
            history_mapping.update_default_buffer()

            # Update cursor position
            default_buffer = history.default_buffer
            default_lineno = sorted(history_mapping.selected_lines).index(line_no) + \
                history_mapping.result_line_offset
            default_buffer.cursor_position = \
                default_buffer.document.translate_row_col_to_index(default_lineno, 0)

        # Also move the cursor to the next line. (This way they can hold
        # space to select a region.)
        b.cursor_position = b.document.translate_row_col_to_index(line_no + 1, 0)

    @handle(' ', filter=has_focus(DEFAULT_BUFFER))
    @handle('delete', filter=has_focus(DEFAULT_BUFFER))
    @handle('c-h', filter=has_focus(DEFAULT_BUFFER))
    def _(event):
        """
        Space: remove line from default pane.
        """
        b = event.current_buffer
        line_no = b.document.cursor_position_row - history_mapping.result_line_offset

        if line_no >= 0:
            try:
                history_lineno = sorted(history_mapping.selected_lines)[line_no]
            except IndexError:
                pass  # When `selected_lines` is an empty set.
            else:
                history_mapping.selected_lines.remove(history_lineno)

            history_mapping.update_default_buffer()

    help_focussed = has_focus(history.help_buffer)
    main_buffer_focussed = has_focus(history.history_buffer) | has_focus(history.default_buffer)

    @handle('tab', filter=main_buffer_focussed)
    @handle('c-x', filter=main_buffer_focussed, eager=True)
        # Eager: ignore the Emacs [Ctrl-X Ctrl-X] binding.
    @handle('c-w', filter=main_buffer_focussed)
    def _(event):
        " Select other window. "
        _select_other_window(history)

    @handle('f4')
    def _(event):
        " Switch between Emacs/Vi mode. "
        python_input.vi_mode = not python_input.vi_mode

    @handle('f1')
    def _(event):
        " Display/hide help. "
        _toggle_help(history)

    @handle('enter', filter=help_focussed)
    @handle('c-c', filter=help_focussed)
    @handle('c-g', filter=help_focussed)
    @handle('escape', filter=help_focussed)
    def _(event):
        " Leave help. "
        event.app.layout.focus_previous()

    @handle('q', filter=main_buffer_focussed)
    @handle('f3', filter=main_buffer_focussed)
    @handle('c-c', filter=main_buffer_focussed)
    @handle('c-g', filter=main_buffer_focussed)
    def _(event):
        " Cancel and go back. "
        event.app.exit(result=None)

    @handle('enter', filter=main_buffer_focussed)
    def _(event):
        " Accept input. "
        event.app.exit(result=history.default_buffer.text)

    enable_system_bindings = Condition(lambda: python_input.enable_system_bindings)

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

    return bindings
    def __init__(self, history):
        search_toolbar = SearchToolbar()

        self.help_buffer_control = BufferControl(
            buffer=history.help_buffer,
            lexer=PygmentsLexer(RstLexer))

        help_window = _create_popup_window(
            title='History Help',
            body=Window(
                content=self.help_buffer_control,
                right_margins=[ScrollbarMargin(display_arrows=True)],
                scroll_offsets=ScrollOffsets(top=2, bottom=2)))

        self.default_buffer_control = BufferControl(
            buffer=history.default_buffer,
            input_processors=[GrayExistingText(history.history_mapping)],
            lexer=PygmentsLexer(PythonLexer))

        self.history_buffer_control = BufferControl(
            buffer=history.history_buffer,
            lexer=PygmentsLexer(PythonLexer),
            search_buffer_control=search_toolbar.control,
            preview_search=True)

        history_window = Window(
            content=self.history_buffer_control,
            wrap_lines=False,
            left_margins=[HistoryMargin(history)],
            scroll_offsets=ScrollOffsets(top=2, bottom=2))

        self.root_container = HSplit([
            #  Top title bar.
            Window(
                content=FormattedTextControl(_get_top_toolbar_fragments),
                align=WindowAlign.CENTER,
                style='class:status-toolbar'),
            FloatContainer(
                content=VSplit([
                    # Left side: history.
                    history_window,
                    # Separator.
                    Window(width=D.exact(1),
                           char=BORDER.LIGHT_VERTICAL,
                           style='class:separator'),
                    # Right side: result.
                    Window(
                        content=self.default_buffer_control,
                        wrap_lines=False,
                        left_margins=[ResultMargin(history)],
                        scroll_offsets=ScrollOffsets(top=2, bottom=2)),
                ]),
                floats=[
                    # Help text as a float.
                    Float(width=60, top=3, bottom=2,
                          content=ConditionalContainer(
                              content=help_window, filter=has_focus(history.help_buffer))),
                ]
            ),
            # Bottom toolbars.
            ArgToolbar(),
            search_toolbar,
            Window(
                content=FormattedTextControl(
                    partial(_get_bottom_toolbar_fragments, history=history)),
                style='class:status-toolbar'),
        ])

        self.layout = Layout(self.root_container, history_window)
Example #45
0
def load_python_bindings(python_input):
    """
    Custom key bindings.
    """
    bindings = KeyBindings()

    sidebar_visible = Condition(lambda: python_input.show_sidebar)
    handle = bindings.add

    @handle('c-l')
    def _(event):
        """
        Clear whole screen and render again -- also when the sidebar is visible.
        """
        event.app.renderer.clear()

    @handle('c-z')
    def _(event):
        """
        Suspend.
        """
        if python_input.enable_system_bindings:
            event.app.suspend_to_background()

    @handle('f2')
    def _(event):
        """
        Show/hide sidebar.
        """
        python_input.show_sidebar = not python_input.show_sidebar
        if python_input.show_sidebar:
            event.app.layout.focus(python_input.ptpython_layout.sidebar)
        else:
            event.app.layout.focus_last()

    @handle('f3')
    def _(event):
        """
        Select from the history.
        """
        python_input.enter_history()

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

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

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

    @Condition
    def is_multiline():
        return document_is_multiline_python(python_input.default_buffer.document)

    @handle('enter', filter= ~sidebar_visible & ~has_selection &
            (vi_insert_mode | emacs_insert_mode) &
            has_focus(DEFAULT_BUFFER) & ~is_multiline)
    @handle(Keys.Escape, Keys.Enter, filter= ~sidebar_visible & emacs_mode)
    def _(event):
        """
        Accept input (for single line input).
        """
        b = event.current_buffer

        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.validate_and_handle()

    @handle('enter', filter= ~sidebar_visible & ~has_selection &
            (vi_insert_mode | emacs_insert_mode) &
            has_focus(DEFAULT_BUFFER) & is_multiline)
    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)):
            # When the cursor is at the end, and we have an empty line:
            # drop the empty lines, but return the value.
            if b.validate():
                b.document = Document(
                    text=b.text.rstrip(),
                    cursor_position=len(b.text.rstrip()))

                b.validate_and_handle()
        else:
            auto_newline(b)

    @handle('c-d', filter=~sidebar_visible &
            has_focus(python_input.default_buffer) &
            Condition(lambda:
                # The current buffer is empty.
                not get_app().current_buffer.text))
    def _(event):
        """
        Override Control-D exit, to ask for confirmation.
        """
        if python_input.confirm_exit:
            python_input.show_exit_confirmation = True
        else:
            event.app.exit(exception=EOFError)

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

    return bindings
    def __init__(self,
                 text: str = '',
                 multiline: FilterOrBool = True,
                 password: FilterOrBool = False,
                 lexer: Optional[Lexer] = None,
                 auto_suggest: Optional[AutoSuggest] = None,
                 completer: Optional[Completer] = None,
                 complete_while_typing: FilterOrBool = True,
                 accept_handler: Optional[BufferAcceptHandler] = None,
                 history: Optional[History] = None,
                 focusable: FilterOrBool = True,
                 focus_on_click: FilterOrBool = False,
                 wrap_lines: FilterOrBool = True,
                 read_only: FilterOrBool = False,
                 width: AnyDimension = None,
                 height: AnyDimension = None,
                 dont_extend_height: FilterOrBool = False,
                 dont_extend_width: FilterOrBool = False,
                 line_numbers: bool = False,
                 get_line_prefix: Optional[GetLinePrefixCallable] = None,
                 scrollbar: bool = False,
                 style: str = '',
                 search_field: Optional[SearchToolbar] = None,
                 preview_search: FilterOrBool = True,
                 prompt: AnyFormattedText = '',
                 input_processors: Optional[List[Processor]] = None) -> None:

        if search_field is None:
            search_control = None
        elif isinstance(search_field, SearchToolbar):
            search_control = search_field.control

        if input_processors is None:
            input_processors = []

        # Writeable attributes.
        self.completer = completer
        self.complete_while_typing = complete_while_typing
        self.lexer = lexer
        self.auto_suggest = auto_suggest
        self.read_only = read_only
        self.wrap_lines = wrap_lines

        self.buffer = Buffer(
            document=Document(text, 0),
            multiline=multiline,
            read_only=Condition(lambda: is_true(self.read_only)),
            completer=DynamicCompleter(lambda: self.completer),
            complete_while_typing=Condition(
                lambda: is_true(self.complete_while_typing)),
            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
            accept_handler=accept_handler,
            history=history)

        self.control = BufferControl(
            buffer=self.buffer,
            lexer=DynamicLexer(lambda: self.lexer),
            input_processors=[
                ConditionalProcessor(
                    AppendAutoSuggestion(),
                    has_focus(self.buffer) & ~is_done),
                ConditionalProcessor(
                    processor=PasswordProcessor(),
                    filter=to_filter(password)
                ),
                BeforeInput(prompt, style='class:text-area.prompt'),
            ] + input_processors,
            search_buffer_control=search_control,
            preview_search=preview_search,
            focusable=focusable,
            focus_on_click=focus_on_click)

        if multiline:
            if scrollbar:
                right_margins = [ScrollbarMargin(display_arrows=True)]
            else:
                right_margins = []
            if line_numbers:
                left_margins = [NumberedMargin()]
            else:
                left_margins = []
        else:
            height = D.exact(1)
            left_margins = []
            right_margins = []

        style = 'class:text-area ' + style

        self.window = Window(
            height=height,
            width=width,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
            content=self.control,
            style=style,
            wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
            left_margins=left_margins,
            right_margins=right_margins,
            get_line_prefix=get_line_prefix)
Example #47
0
def _create_container_for_process(pymux, window, arrangement_pane, zoom=False):
    """
    Create a `Container` with a titlebar for a process.
    """
    @Condition
    def clock_is_visible():
        return arrangement_pane.clock_mode

    @Condition
    def pane_numbers_are_visible():
        return pymux.display_pane_numbers

    terminal_is_focused = has_focus(arrangement_pane.terminal)

    def get_terminal_style():
        if terminal_is_focused():
            result = 'class:terminal.focused'
        else:
            result = 'class:terminal'
        return result

    def get_titlebar_text_fragments():
        result = []

        if zoom:
            result.append(('class:titlebar-zoom', ' Z '))

        if arrangement_pane.process.is_terminated:
            result.append(('class:terminated', ' Terminated '))

        # Scroll buffer info.
        if arrangement_pane.display_scroll_buffer:
            result.append(('class:copymode', ' %s ' % arrangement_pane.scroll_buffer_title))

            # Cursor position.
            document = arrangement_pane.scroll_buffer.document
            result.append(('class:copymode.position', ' %i,%i ' % (
                document.cursor_position_row, document.cursor_position_col)))

        if arrangement_pane.name:
            result.append(('class:name', ' %s ' % arrangement_pane.name))
            result.append(('', ' '))

        return result + [
            ('', format_pymux_string(pymux, ' #T ', pane=arrangement_pane))  # XXX: Make configurable.
        ]

    def get_pane_index():
        try:
            w = pymux.arrangement.get_active_window()
            index = w.get_pane_index(arrangement_pane)
        except ValueError:
            index = '/'

        return '%3s ' % index

    def on_click():
        " Click handler for the clock. When clicked, select this pane. "
        arrangement_pane.clock_mode = False
        pymux.arrangement.get_active_window().active_pane = arrangement_pane
        pymux.invalidate()


    return HighlightBordersIfActive(
        window,
        arrangement_pane,
        get_terminal_style,
        FloatContainer(
            HSplit([
                # The terminal.
                TracePaneWritePosition(
                    pymux, arrangement_pane,
                    content=arrangement_pane.terminal),
            ]),

            #
            floats=[
                # The title bar.
                Float(content=
                    ConditionalContainer(
                        content=VSplit([
                                Window(
                                    height=1,
                                    content=FormattedTextControl(
                                        get_titlebar_text_fragments)),
                                Window(
                                    height=1,
                                    width=4,
                                    content=FormattedTextControl(get_pane_index),
                                    style='class:paneindex')
                            ], style='class:titlebar'),
                        filter=Condition(lambda: pymux.enable_pane_status)),
                    left=0, right=0, top=-1, height=1, z_index=Z_INDEX.WINDOW_TITLE_BAR),

                # The clock.
                Float(
                    content=ConditionalContainer(BigClock(on_click),
                      filter=clock_is_visible)),

                # Pane number.
                Float(content=ConditionalContainer(
                      content=PaneNumber(pymux, arrangement_pane),
                      filter=pane_numbers_are_visible)),
            ]
        )
    )
    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),
        ])
Example #49
0
    def __init__(self, text='', multiline=True, password=False,
                 lexer=None, auto_suggest=None, completer=None,
                 complete_while_typing=True, accept_handler=None, history=None,
                 focusable=True, focus_on_click=False, wrap_lines=True,
                 read_only=False, width=None, height=None,
                 dont_extend_height=False, dont_extend_width=False,
                 line_numbers=False, get_line_prefix=None, scrollbar=False,
                 style='', search_field=None, preview_search=True, prompt='',
                 input_processors=None):
       # assert isinstance(text, six.text_type)

        if search_field is None:
            search_control = None

        if input_processors is None:
            input_processors = []

        # Writeable attributes.
        self.completer = completer
        self.complete_while_typing = complete_while_typing
        self.lexer = lexer
        self.auto_suggest = auto_suggest
        self.read_only = read_only
        self.wrap_lines = wrap_lines

        self.buffer = Buffer(
            document=Document(text, 0),
            multiline=multiline,
            read_only=Condition(lambda: is_true(self.read_only)),
            completer=DynamicCompleter(lambda: self.completer),
            complete_while_typing=Condition(
                lambda: is_true(self.complete_while_typing)),
            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
            accept_handler=accept_handler,
            history=history)

        self.control = BufferControl(
            buffer=self.buffer,
            lexer=DynamicLexer(lambda: self.lexer),
            input_processors=[
                ConditionalProcessor(
                    AppendAutoSuggestion(),
                    has_focus(self.buffer) & is_done), #
                ConditionalProcessor(
                    processor=PasswordProcessor(),
                    filter=to_filter(password)
                ),
                BeforeInput(prompt, style='class:text-area.prompt'),
            ] + input_processors,
            search_buffer_control=search_control,
            preview_search=preview_search,
            focusable=focusable,
            focus_on_click=focus_on_click)

        if multiline:
            if scrollbar:
                right_margins = [ScrollbarMargin(display_arrows=True)]
            else:
                right_margins = []
            if line_numbers:
                left_margins = [NumberedMargin()]
            else:
                left_margins = []
        else:
            height = D.exact(1)
            left_margins = []
            right_margins = []

        style = 'class:text-area ' + style

        self.window = Window(
            height=height,
            width=width,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
            content=self.control,
            style=style,
            wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
            left_margins=left_margins,
            right_margins=right_margins,
            get_line_prefix=get_line_prefix)
    def _create_layout(self):
        """
        Create `Layout` for this prompt.
        """
        dyncond = self._dyncond

        # 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)

        default_buffer = self.default_buffer
        search_buffer = self.search_buffer

        # Create processors list.
        all_input_processors = [
            HighlightIncrementalSearchProcessor(),
            HighlightSelectionProcessor(),
            ConditionalProcessor(AppendAutoSuggestion(),
                                 has_focus(default_buffer) & ~is_done),
            ConditionalProcessor(PasswordProcessor(), dyncond('is_password')),
            DisplayMultipleCursors(),

            # Users can insert processors here.
            DynamicProcessor(lambda: merge_processors(self.input_processors or [])),
        ]

        # 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,
            ignore_case=dyncond('search_ignore_case'))

        search_buffer_control = SearchBufferControl(
            buffer=search_buffer,
            input_processors=[
                ReverseSearchProcessor(),
            ],
            ignore_case=dyncond('search_ignore_case'))

        system_toolbar = SystemToolbar(
            enable_global_bindings=dyncond('enable_system_prompt'))

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

        default_buffer_control = BufferControl(
            buffer=default_buffer,
            search_buffer_control=get_search_buffer_control,
            input_processors=all_input_processors,
            include_default_input_processors=False,
            lexer=DynamicLexer(lambda: self.lexer),
            preview_search=True)

        default_buffer_window = Window(
            default_buffer_control,
            height=self._get_default_buffer_control_height,
            get_line_prefix=partial(
                self._get_line_prefix, get_prompt_text_2=get_prompt_text_2),
            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.
                    # NOTE: Especially the multi-column menu needs to be
                    #       transparent, because the shape is not always
                    #       rectangular due to the meta-text below the menu.
                    Float(xcursor=True,
                          ycursor=True,
                          transparent=True,
                          content=CompletionsMenu(
                              max_height=16,
                              scroll_offset=1,
                              extra_filter=has_focus(default_buffer) &
                                  ~multi_column_complete_style)),
                    Float(xcursor=True,
                          ycursor=True,
                          transparent=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,
        ])

        return Layout(layout, default_buffer_window)
Example #51
0
    def __init__(self, pager):
        self.pager = pager
        self.dynamic_body = _DynamicBody(pager)

        # Build an interface.
        has_colon = HasColon(pager)

        self.examine_control = BufferControl(
            buffer=pager.examine_buffer,
            lexer=SimpleLexer(style='class:examine,examine-text'),
            input_processors=[
                BeforeInput(lambda: [('class:examine', ' Examine: ')])
            ])

        self.search_toolbar = SearchToolbar(
            vi_mode=True,
            search_buffer=pager.search_buffer)

        self.container = FloatContainer(
            content=HSplit([
                ConditionalContainer(
                    content=Titlebar(pager),
                    filter=Condition(lambda: pager.display_titlebar)),
                self.dynamic_body,
                self.search_toolbar,
                SystemToolbar(),
                ConditionalContainer(
                    content=VSplit([
                            Window(height=1,
                                   content=FormattedTextControl(self._get_statusbar_left_tokens),
                                   style='class:statusbar'),
                            Window(height=1,
                                   content=FormattedTextControl(self._get_statusbar_right_tokens),
                                   style='class:statusbar.cursorposition',
                                   align=WindowAlign.RIGHT),
                        ]),
                    filter=~HasSearch() & ~has_focus(SYSTEM_BUFFER) & ~has_colon & ~has_focus('EXAMINE')),
                ConditionalContainer(
                    content=Window(
                        FormattedTextControl(' :'),
                        height=1,
                        style='class:examine'),
                    filter=has_colon),
                ConditionalContainer(
                    content=Window(
                        self.examine_control,
                        height=1,
                        style='class:examine'),
                    filter=has_focus(pager.examine_buffer)),
            ]),
            floats=[
                Float(right=0, height=1, bottom=1,
                      content=_Arg()),
                Float(bottom=1, left=0, right=0, height=1,
                      content=ConditionalContainer(
                          content=MessageToolbarBar(pager),
                          filter=Condition(lambda: bool(pager.message)))
                ),
                Float(right=0, height=1, bottom=1,
                      content=ConditionalContainer(
                          content=FormattedTextToolbar(
                              lambda: [('class:loading', ' Loading... ')],
                          ),
                          filter=Condition(lambda: pager.current_source_info.waiting_for_input_stream))),
                Float(xcursor=True,
                      ycursor=True,
                      content=MultiColumnCompletionsMenu()),
            ]
        )
Example #52
0
    def _create_layout(self):
        """
        Generate the main prompt_toolkit layout.
        """
        waits_for_confirmation = WaitsForConfirmation(self.pymux)

        return FloatContainer(
            content=HSplit([
                # The main window.
                FloatContainer(
                    Background(),
                    floats=[
                        Float(width=lambda: self.pymux.get_window_size().columns,
                              height=lambda: self.pymux.get_window_size().rows,
                              content=DynamicBody(self.pymux))
                    ]),
                # Status bar.
                ConditionalContainer(
                    content=VSplit([
                        # Left.
                        Window(
                            height=1,
                            width=(lambda: D(max=self.pymux.status_left_length)),
                            dont_extend_width=True,
                            content=FormattedTextControl(self._get_status_left_tokens)),
                        # List of windows in the middle.
                        Window(
                            height=1,
                            char=' ',
                            align=self._get_align,
                            content=FormattedTextControl(self._get_status_tokens)),
                        # Right.
                        Window(
                            height=1,
                            width=(lambda: D(max=self.pymux.status_right_length)),
                            dont_extend_width=True,
                            align=WindowAlign.RIGHT,
                            content=FormattedTextControl(self._get_status_right_tokens))
                    ], z_index=Z_INDEX.STATUS_BAR, style='class:statusbar'),
                    filter=Condition(lambda: self.pymux.enable_status),
                )
            ]),
            floats=[
                Float(bottom=1, left=0, z_index=Z_INDEX.MESSAGE_TOOLBAR,
                      content=MessageToolbar(self.client_state)),
                Float(left=0, right=0, bottom=0, content=HSplit([
                    # Wait for confirmation toolbar.
                    ConditionalContainer(
                        content=Window(
                            height=1,
                            content=ConfirmationToolbar(self.pymux, self.client_state),
                            z_index=Z_INDEX.COMMAND_LINE,
                        ),
                        filter=waits_for_confirmation,
                    ),
                    # ':' prompt toolbar.
                    ConditionalContainer(
                        content=Window(
                            height=D(min=1),  # Can be more if the command is multiline.
                            style='class:commandline',
                            dont_extend_height=True,
                            content=BufferControl(
                                buffer=self.client_state.command_buffer,
                                preview_search=True,
                                input_processors=[
                                    AppendAutoSuggestion(),
                                    BeforeInput(':', style='class:commandline-prompt'),
                                    ShowArg(),
                                    HighlightSelectionProcessor(),
                                ]),
                            z_index=Z_INDEX.COMMAND_LINE,
                        ),
                        filter=has_focus(self.client_state.command_buffer),
                    ),
                    # Other command-prompt commands toolbar.
                    ConditionalContainer(
                        content=Window(
                            height=1,
                            style='class:commandline',
                            content=BufferControl(
                                buffer=self.client_state.prompt_buffer,
                                input_processors=[
                                    BeforeInput(self._before_prompt_command_tokens),
                                    AppendAutoSuggestion(),
                                    HighlightSelectionProcessor(),
                                ]),
                            z_index=Z_INDEX.COMMAND_LINE,
                        ),
                        filter=has_focus(self.client_state.prompt_buffer),
                    ),
                ])),
                # Keys pop-up.
                Float(
                    content=ConditionalContainer(
                        content=self.popup_dialog,
                        filter=Condition(lambda: self.client_state.display_popup),
                    ),
                    left=3, right=3, top=5, bottom=5,
                    z_index=Z_INDEX.POPUP,
                ),
                Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=12)),
            ]
        )
Example #53
0
def create_key_bindings(pager):
    kb = KeyBindings()
    handle = kb.add

    @Condition
    def has_colon():
        return pager.in_colon_mode

    @Condition
    def default_focus():
        app = get_app()
        return app.layout.current_window == pager.current_source_info.window

    @Condition
    def displaying_help():
       return pager.displaying_help

    for c in '01234556789':
        @handle(c, filter=default_focus)
        def _(event, c=c):
            event.append_to_arg_count(c)

    @handle('q', filter=default_focus)
    @handle('Q', filter=default_focus | has_colon)
    @handle('Z', 'Z', filter=default_focus)
    def _(event):
        " Quit. "
        if pager.displaying_help:
            pager.quit_help()
        else:
            event.app.exit()

    @handle(' ', filter=default_focus)
    @handle('f', filter=default_focus)
    @handle(Keys.ControlF, filter=default_focus)
    @handle(Keys.ControlV, filter=default_focus)
    def _(event):
        " Page down."
        scroll_page_down(event)

    @handle('b', filter=default_focus)
    @handle(Keys.ControlB, filter=default_focus)
    @handle(Keys.Escape, 'v', filter=default_focus)
    def _(event):
        " Page up."
        scroll_page_up(event)

    @handle('d', filter=default_focus)
    @handle(Keys.ControlD, filter=default_focus)
    def _(event):
        " Half page down."
        scroll_half_page_down(event)

    @handle('u', filter=default_focus)
    @handle(Keys.ControlU, filter=default_focus)
    def _(event):
        " Half page up."
        scroll_half_page_up(event)

    @handle('e', filter=default_focus)
    @handle('j', filter=default_focus)
    @handle(Keys.ControlE, filter=default_focus)
    @handle(Keys.ControlN, filter=default_focus)
    @handle(Keys.ControlJ, filter=default_focus)
    @handle(Keys.ControlM, filter=default_focus)
    @handle(Keys.Down, filter=default_focus)
    def _(event):
        " Scoll one line down."
        if event.arg > 1:
            # When an argument is given, go this amount of lines down.
            event.current_buffer.auto_down(count=event.arg)
        else:
            scroll_one_line_down(event)

    @handle('y', filter=default_focus)
    @handle('k', filter=default_focus)
    @handle(Keys.ControlY, filter=default_focus)
    @handle(Keys.ControlK, filter=default_focus)
    @handle(Keys.ControlP, filter=default_focus)
    @handle(Keys.Up, filter=default_focus)
    def _(event):
        " Scoll one line up."
        if event.arg > 1:
            event.current_buffer.auto_up(count=event.arg)
        else:
            scroll_one_line_up(event)

    @handle(Keys.Escape, 'u')
    def _(event):
        " Toggle search highlighting. "
        pager.highlight_search = not pager.highlight_search

    @handle('=', filter=default_focus)
    @handle(Keys.ControlG, filter=default_focus)
    @handle('f', filter=has_colon)
    def _(event):
        " Print the current file name. "
        pager.message = ' {} '.format(pager.current_source.get_name())

    @handle('h', filter=default_focus & ~displaying_help)
    @handle('H', filter=default_focus & ~displaying_help)
    def _(event):
        " Display Help. "
        pager.display_help()

    @handle('g', filter=default_focus)
    @handle('<', filter=default_focus)
    @handle(Keys.Escape, '<', filter=default_focus)
    def _(event):
        " Go to the first line of the file. "
        event.current_buffer.cursor_position = 0

    @handle('G', filter=default_focus)
    @handle('>', filter=default_focus)
    @handle(Keys.Escape, '>', filter=default_focus)
    def _(event):
        " Go to the last line of the file. "
        b = event.current_buffer
        b.cursor_position = len(b.text)

    @handle('m', Keys.Any, filter=default_focus)
    def _(event):
        " Mark current position. "
        source_info = pager.current_source_info

        source_info.marks[event.data] = (
            event.current_buffer.cursor_position,
            source_info.window.vertical_scroll)

    @handle("'", Keys.Any, filter=default_focus)
    def _(event):
        " Go to a previously marked position. "
        go_to_mark(event, event.data)

    @handle(Keys.ControlX, Keys.ControlX, filter=default_focus)
    def _(event):
        " Same as '. "
        go_to_mark(event, '.')

    def go_to_mark(event, mark):
        b = event.current_buffer
        source_info = pager.current_source_info
        try:
            if mark == '^':  # Start of file.
                cursor_pos, vertical_scroll = 0, 0
            elif mark == '$':  # End of file - mark.
                cursor_pos, vertical_scroll = len(b.text), 0
            else:  # Custom mark.
                cursor_pos, vertical_scroll = source_info.marks[mark]
        except KeyError:
            pass  # TODO: show warning.
        else:
            b.cursor_position = cursor_pos
            source_info.window.vertical_scroll = vertical_scroll

    @handle('F', filter=default_focus)
    def _(event):
        " Forward forever, like 'tail -f'. "
        pager.forward_forever = True

    @handle('r', filter=default_focus)
    @handle('R', filter=default_focus)
    def _(event):
        event.app.renderer.clear()

    def search_buffer_is_empty():
        " Returns True when the search buffer is empty. "
        return pager.search_buffer.text == ''

    @handle('backspace', filter=has_focus(pager.search_buffer) & Condition(search_buffer_is_empty))
    def _(event):
        " Cancel search when backspace is pressed. "
        stop_search()

    @handle(Keys.Left, filter=default_focus)
    @handle(Keys.Escape, '(', filter=default_focus)
    def _(event):
        " Scroll half page to the left. "
        w = event.app.layout.current_window
        b = event.app.current_buffer

        if w and w.render_info:
            info = w.render_info
            amount = info.window_width // 2

            # Move cursor horizontally.
            value = b.cursor_position - min(amount, len(b.document.current_line_before_cursor))
            b.cursor_position = value

            # Scroll.
            w.horizontal_scroll = max(0, w.horizontal_scroll - amount)

    @handle(Keys.Right, filter=default_focus)
    @handle(Keys.Escape, ')', filter=default_focus)
    def _(event):
        " Scroll half page to the right. "
        w = event.app.layout.current_window
        b = event.app.current_buffer

        if w and w.render_info:
            info = w.render_info
            amount = info.window_width // 2

            # Move the cursor first to a visible line that is long enough to
            # have the cursor visible after scrolling. (Otherwise, the Window
            # will scroll back.)
            xpos = w.horizontal_scroll + amount

            for line in info.displayed_lines:
                if len(b.document.lines[line]) >= xpos:
                    b.cursor_position = b.document.translate_row_col_to_index(line, xpos)
                    break

            # Scroll.
            w.horizontal_scroll = max(0, w.horizontal_scroll + amount)

    @handle(':', filter=default_focus & ~displaying_help)
    def _(event):
        pager.in_colon_mode = True

    @handle('n', filter=has_colon)
    def _(event):
        " Go to next file. "
        pager.focus_next_source()

    @handle('p', filter=has_colon)
    def _(event):
        " Go to previous file. "
        pager.focus_previous_source()

    @handle('e', filter=has_colon)
    @handle(Keys.ControlX, Keys.ControlV, filter=default_focus)
    def _(event):
        event.app.layout.focus(pager.layout.examine_control)
        pager.in_colon_mode = False

    @handle('d', filter=has_colon)
    def _(event):
        pager.remove_current_source()

    @handle('backspace', filter=has_colon)
    @handle('q', filter=has_colon)
    def _(event):
        pager.in_colon_mode = False

    @handle(Keys.Any, filter=has_colon)
    def _(event):
        pager.in_colon_mode = False
        pager.message = 'No command.'

    @handle(Keys.ControlC, filter=has_focus('EXAMINE'))
    @handle(Keys.ControlG, filter=has_focus('EXAMINE'))
    def _(event):
        " Cancel 'Examine' input. "
        event.app.layout.focus(pager.current_source_info.window)

    @handle(Keys.ControlZ, filter=Condition(lambda: suspend_to_background_supported()))
    def _(event):
        " Suspend to bakground. "
        event.app.suspend_to_background()

    return kb