def test_split_multiline_prompt():
    # Test 1: no newlines:
    tokens = [(Token, 'ab')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
    assert has_before_tokens(None) == False
    assert before(None) == []
    assert first_input_line(None) == [
        (Token, 'a'),
        (Token, 'b'),
    ]

    # Test 1: multiple lines.
    tokens = [(Token, 'ab\ncd\nef')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
    assert has_before_tokens(None) == True
    assert before(None) == [
        (Token, 'a'),
        (Token, 'b'),
        (Token, '\n'),
        (Token, 'c'),
        (Token, 'd'),
    ]
    assert first_input_line(None) == [
        (Token, 'e'),
        (Token, 'f'),
    ]

    # Edge case 1: starting with a newline.
    tokens = [(Token, '\nab')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
    assert has_before_tokens(None) == True
    assert before(None) == []
    assert first_input_line(None) == [
        (Token, 'a'),
        (Token, 'b')
    ]

    # Edge case 2: starting with two newlines.
    tokens = [(Token, '\n\nab')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
    assert has_before_tokens(None) == True
    assert before(None) == [(Token, '\n')]
    assert first_input_line(None) == [
        (Token, 'a'),
        (Token, 'b')
    ]
Esempio n. 2
0
def test_split_multiline_prompt():
    # Test 1: no newlines:
    tokens = [(Token, 'ab')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(
        lambda cli: tokens)
    assert has_before_tokens(None) == False
    assert before(None) == []
    assert first_input_line(None) == [
        (Token, 'a'),
        (Token, 'b'),
    ]

    # Test 1: multiple lines.
    tokens = [(Token, 'ab\ncd\nef')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(
        lambda cli: tokens)
    assert has_before_tokens(None) == True
    assert before(None) == [
        (Token, 'a'),
        (Token, 'b'),
        (Token, '\n'),
        (Token, 'c'),
        (Token, 'd'),
    ]
    assert first_input_line(None) == [
        (Token, 'e'),
        (Token, 'f'),
    ]

    # Edge case 1: starting with a newline.
    tokens = [(Token, '\nab')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(
        lambda cli: tokens)
    assert has_before_tokens(None) == True
    assert before(None) == []
    assert first_input_line(None) == [(Token, 'a'), (Token, 'b')]

    # Edge case 2: starting with two newlines.
    tokens = [(Token, '\n\nab')]
    has_before_tokens, before, first_input_line = _split_multiline_prompt(
        lambda cli: tokens)
    assert has_before_tokens(None) == True
    assert before(None) == [(Token, '\n')]
    assert first_input_line(None) == [(Token, 'a'), (Token, 'b')]
def CreatePromptLayout(config,
                       lexer=None,
                       is_password=False,
                       get_prompt_tokens=None,
                       get_continuation_tokens=None,
                       get_bottom_status_tokens=None,
                       get_bottom_toolbar_tokens=None,
                       extra_input_processors=None,
                       multiline=False,
                       show_help=True,
                       wrap_lines=True):
    """Create a container instance for the prompt."""
    assert get_bottom_status_tokens is None or callable(
        get_bottom_status_tokens)
    assert get_bottom_toolbar_tokens is None or callable(
        get_bottom_toolbar_tokens)
    assert get_prompt_tokens is None or callable(get_prompt_tokens)
    assert not (config.prompt and get_prompt_tokens)

    multi_column_completion_menu = filters.to_cli_filter(
        config.multi_column_completion_menu)
    multiline = filters.to_cli_filter(multiline)

    if get_prompt_tokens is None:
        get_prompt_tokens = lambda _: [(token.Token.Prompt, config.prompt)]

    has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = (
        shortcuts._split_multiline_prompt(get_prompt_tokens))  # pylint: disable=protected-access
    # TODO(b/35347840): reimplement _split_multiline_prompt to remove
    #                   protected-access.

    # Create processors list.
    input_processors = [
        processors.ConditionalProcessor(
            # By default, only highlight search when the search
            # input has the focus. (Note that this doesn't mean
            # there is no search: the Vi 'n' binding for instance
            # still allows to jump to the next match in
            # navigation mode.)
            processors.HighlightSearchProcessor(preview_search=True),
            filters.HasFocus(enums.SEARCH_BUFFER)),
        processors.HighlightSelectionProcessor(),
        processors.ConditionalProcessor(
            processors.AppendAutoSuggestion(),
            filters.HasFocus(enums.DEFAULT_BUFFER)
            & ~filters.IsDone()),
        processors.ConditionalProcessor(processors.PasswordProcessor(),
                                        is_password),
    ]

    if extra_input_processors:
        input_processors.extend(extra_input_processors)

    # Show the prompt before the input using the DefaultPrompt processor.
    # This also replaces it with reverse-i-search and 'arg' when required.
    # (Only for single line mode.)
    # (DefaultPrompt should always be at the end of the processors.)
    input_processors.append(
        processors.ConditionalProcessor(
            prompt.DefaultPrompt(get_prompt_tokens_2), ~multiline))

    # Create toolbars
    toolbars = []
    if config.fixed_prompt_position:
        help_height = dimension.LayoutDimension.exact(config.help_lines)
        help_filter = (show_help & ~filters.IsDone()
                       & filters.RendererHeightIsKnown())
    else:
        help_height = dimension.LayoutDimension(preferred=config.help_lines,
                                                max=config.help_lines)
        help_filter = (show_help & UserTypingFilter & ~filters.IsDone()
                       & filters.RendererHeightIsKnown())
    toolbars.append(
        containers.ConditionalContainer(layout.HSplit([
            layout.Window(
                controls.FillControl(char=screen.Char('_', token.Token.HSep)),
                height=dimension.LayoutDimension.exact(1)),
            layout.Window(help_window.HelpWindowControl(
                default_char=screen.Char(' ', token.Token.Toolbar)),
                          height=help_height),
        ]),
                                        filter=help_filter))
    if (config.bottom_status_line and get_bottom_status_tokens
            or config.bottom_bindings_line and get_bottom_toolbar_tokens):
        windows = []
        windows.append(
            layout.Window(
                controls.FillControl(char=screen.Char('_', token.Token.HSep)),
                height=dimension.LayoutDimension.exact(1)))
        if config.bottom_status_line and get_bottom_status_tokens:
            windows.append(
                layout.Window(controls.TokenListControl(
                    get_bottom_status_tokens,
                    default_char=screen.Char(' ', token.Token.Toolbar)),
                              height=dimension.LayoutDimension.exact(1)))
        if config.bottom_bindings_line and get_bottom_toolbar_tokens:
            windows.append(
                layout.Window(controls.TokenListControl(
                    get_bottom_toolbar_tokens,
                    default_char=screen.Char(' ', token.Token.Toolbar)),
                              height=dimension.LayoutDimension.exact(1)))
        toolbars.append(
            containers.ConditionalContainer(layout.HSplit(windows),
                                            filter=~filters.IsDone()
                                            & filters.RendererHeightIsKnown()))

    def GetHeight(cli):
        """Determine the height for the input buffer."""
        # If there is an autocompletion menu to be shown, make sure that our
        # layout has at least a minimal height in order to display it.
        if cli.config.completion_menu_lines and not cli.is_done:
            # Reserve the space, either when there are completions, or when
            # `complete_while_typing` is true and we expect completions very
            # soon.
            buf = cli.current_buffer
            # if UserTypingFilter(cli) or not buf.text or buf.complete_state:
            if UserTypingFilter(cli) or buf.complete_state:
                return dimension.LayoutDimension(
                    min=cli.config.completion_menu_lines + 1)
        return dimension.LayoutDimension()

    # Create and return Container instance.
    return layout.HSplit([
        # The main input, with completion menus floating on top of it.
        containers.FloatContainer(
            layout.HSplit([
                containers.ConditionalContainer(
                    layout.Window(
                        controls.TokenListControl(get_prompt_tokens_1),
                        dont_extend_height=True,
                        wrap_lines=wrap_lines,
                    ),
                    filters.Condition(has_before_tokens),
                ),
                layout.Window(
                    controls.BufferControl(
                        input_processors=input_processors,
                        lexer=lexer,
                        # Enable preview_search, we want to have immediate
                        # feedback in reverse-i-search mode.
                        preview_search=True,
                    ),
                    get_height=GetHeight,
                    left_margins=[
                        # In multiline mode, use the window margin to display
                        # the prompt and continuation tokens.
                        margins.ConditionalMargin(
                            margins.PromptMargin(get_prompt_tokens_2,
                                                 get_continuation_tokens),
                            filter=multiline,
                        ),
                    ],
                    wrap_lines=wrap_lines,
                ),
            ]),
            [
                # Completion menus.
                layout.Float(
                    xcursor=True,
                    ycursor=True,
                    content=menus.CompletionsMenu(
                        max_height=16,
                        scroll_offset=1,
                        extra_filter=(filters.HasFocus(enums.DEFAULT_BUFFER)
                                      & ~multi_column_completion_menu),
                    ),
                ),
                layout.Float(
                    ycursor=True,
                    content=menus.MultiColumnCompletionsMenu(
                        show_meta=True,
                        extra_filter=(filters.HasFocus(enums.DEFAULT_BUFFER)
                                      & multi_column_completion_menu),
                    ),
                ),
            ],
        ),
        pt_toolbars.ValidationToolbar(),
        pt_toolbars.SystemToolbar(),

        # In multiline mode, we use two toolbars for 'arg' and 'search'.
        containers.ConditionalContainer(pt_toolbars.ArgToolbar(), multiline),
        containers.ConditionalContainer(pt_toolbars.SearchToolbar(),
                                        multiline),
    ] + toolbars)
Esempio n. 4
0
    def create_prompt_layout(self,
                             message='',
                             lexer=None,
                             is_password=False,
                             reserve_space_for_menu=8,
                             get_prompt_tokens=None,
                             get_bottom_toolbar_tokens=None,
                             display_completions_in_columns=False,
                             extra_input_processors=None,
                             multiline=False,
                             wrap_lines=True):
        """Create a Container instance for a prompt.

        Parameters
        ----------
        message : Text to be used as prompt.
        lexer : ~prompt_toolkit.layout.lexers.Lexer to be used for
            the highlighting.
        is_password : bool or ~prompt_toolkit.filters.CLIFilter.
            When True, display input as '*'.
        reserve_space_for_menu : Space to be reserved for the menu. When >0,
            make sure that a minimal height is allocated in the terminal, in order
            to display the completion menu.
        get_prompt_tokens : An optional callable that returns the tokens to be
            shown in the menu. (To be used instead of a `message`.)
        get_bottom_toolbar_tokens : An optional callable that returns the
            tokens for a toolbar at the bottom.
        display_completions_in_columns : `bool` or
            :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in
            multiple columns.
        multiline : `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
            When True, prefer a layout that is more adapted for multiline input.
            Text after newlines is automatically indented, and search/arg input is
            shown below the input, instead of replacing the prompt.
        wrap_lines : `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
            When True (the default), automatically wrap long lines instead of
            scrolling horizontally.

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

        WARNING; This method is due for removal once prompt-toolkit >v0.54 
        is released.
        """
        assert isinstance(message, str)
        assert get_bottom_toolbar_tokens is None or callable(
            get_bottom_toolbar_tokens)
        assert get_prompt_tokens is None or callable(get_prompt_tokens)
        assert not (message and get_prompt_tokens)

        display_completions_in_columns = to_cli_filter(
            display_completions_in_columns)
        multiline = to_cli_filter(multiline)

        if get_prompt_tokens is None:
            get_prompt_tokens = lambda _: [(Token.Prompt, message)]

        get_prompt_tokens_1, get_prompt_tokens_2 = _split_multiline_prompt(
            get_prompt_tokens)

        # `lexer` is supposed to be a `Lexer` instance. But if a Pygments lexer
        # class is given, turn it into a PygmentsLexer. (Important for
        # backwards-compatibility.)
        try:
            if issubclass(lexer, pygments.lexer.Lexer):
                lexer = PygmentsLexer(lexer)
        except TypeError:  # Happens when lexer is `None` or an instance of something else.
            pass

        # Create highlighters and processors list.
        if ConditionalHighlighter is None:
            highlighters = None
            highlighters_kwargs = {}
        else:
            highlighters = [
                ConditionalHighlighter(
                    # By default, only highlight search when the search
                    # input has the focus. (Note that this doesn't mean
                    # there is no search: the Vi 'n' binding for instance
                    # still allows to jump to the next match in
                    # navigation mode.)
                    SearchHighlighter(preview_search=True),
                    HasFocus(SEARCH_BUFFER)),
                SelectionHighlighter()
            ]
            highlighters_kwargs = {'highlighters': highlighters}

        input_processors = [
            ConditionalProcessor(AppendAutoSuggestion(),
                                 HasFocus(DEFAULT_BUFFER) & ~IsDone()),
            ConditionalProcessor(PasswordProcessor(), is_password)
        ]

        if extra_input_processors:
            input_processors.extend(extra_input_processors)

        # Show the prompt before the input (using the DefaultPrompt processor.
        # This also replaces it with reverse-i-search and 'arg' when required.
        # (Only for single line mode.)
        # (DefaultPrompt should always be at the end of the processors.)
        input_processors.append(
            ConditionalProcessor(DefaultPrompt(get_prompt_tokens), ~multiline))

        # Create bottom toolbar.
        if get_bottom_toolbar_tokens:
            toolbars = [
                ConditionalContainer(
                    Window(TokenListControl(get_bottom_toolbar_tokens,
                                            default_char=Char(
                                                ' ', Token.Toolbar)),
                           height=LayoutDimension.exact(1)),
                    filter=~IsDone() & RendererHeightIsKnown())
            ]
        else:
            toolbars = []

        def get_height(cli):
            # If there is an autocompletion menu to be shown, make sure that our
            # layout has at least a minimal height in order to display it.
            if reserve_space_for_menu and not cli.is_done:
                return LayoutDimension(min=reserve_space_for_menu)
            else:
                return LayoutDimension()

        # Create and return Container instance.
        return HSplit([
            ConditionalContainer(
                Window(TokenListControl(get_prompt_tokens_1),
                       dont_extend_height=True),
                filter=multiline,
            ),
            VSplit([
                # In multiline mode, the prompt is displayed in a left pane.
                ConditionalContainer(
                    Window(
                        TokenListControl(get_prompt_tokens_2),
                        dont_extend_width=True,
                    ),
                    filter=multiline,
                ),
                # The main input, with completion menus floating on top of it.
                FloatContainer(
                    Window(
                        BufferControl(
                            input_processors=input_processors,
                            lexer=lexer,
                            wrap_lines=wrap_lines,
                            # Enable preview_search, we want to have immediate feedback
                            # in reverse-i-search mode.
                            preview_search=True,
                            **highlighters_kwargs),
                        get_height=get_height,
                    ),
                    [
                        Float(xcursor=True,
                              ycursor=True,
                              content=CompletionsMenu(
                                  max_height=16,
                                  scroll_offset=1,
                                  extra_filter=HasFocus(DEFAULT_BUFFER)
                                  & ~display_completions_in_columns)),
                        Float(xcursor=True,
                              ycursor=True,
                              content=MultiColumnCompletionsMenu(
                                  extra_filter=HasFocus(DEFAULT_BUFFER)
                                  & display_completions_in_columns,
                                  show_meta=True))
                    ]),
            ]),
            ValidationToolbar(),
            SystemToolbar(),

            # In multiline mode, we use two toolbars for 'arg' and 'search'.
            ConditionalContainer(ArgToolbar(), multiline),
            ConditionalContainer(SearchToolbar(), multiline),
        ] + toolbars)
Esempio n. 5
0
def create_default_layout(get_prompt_tokens,
                          get_error_tokens=None,
                          extra_input_processors=None,
                          hide_cursor=False,
                          hint=None,
                          extra_hint_filter=None,
                          reactive_window_factory=None,
                          transformer=None):
    has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = _split_multiline_prompt(
        get_prompt_tokens)

    assert get_prompt_tokens is None or callable(get_prompt_tokens)
    assert get_error_tokens is None or callable(get_error_tokens)

    reactive_windows = []
    if callable(reactive_window_factory):
        reactive_windows = reactive_window_factory()
    has_reactive = to_cli_filter(reactive_windows is not None)

    has_hint = to_cli_filter(hint is not None)

    hint_filter = has_hint
    if extra_hint_filter is not None:
        hint_filter = hint_filter & extra_hint_filter

    input_processors = []
    if extra_input_processors is not None:
        input_processors.extend(extra_input_processors)

    input_processors.extend([
        ConditionalProcessor(HintProcessor(hint), hint_filter & ~IsDone()),
        ConditionalProcessor(TransformProcessor(transformer), IsDone()),
        Prompt(get_prompt_tokens_2),
    ])

    return HSplit([
        ConditionalContainer(
            Window(
                TokenListControl(get_prompt_tokens_1),
                dont_extend_height=True,
                wrap_lines=True,
            ),
            Condition(has_before_tokens),
        ),
        Window(
            BufferControl(input_processors=input_processors, ),
            always_hide_cursor=hide_cursor,
            dont_extend_height=True,
            wrap_lines=True,
        ),
        ConditionalContainer(
            HSplit(reactive_windows),
            filter=has_reactive & ~IsDone(),
        ),
        ConditionalContainer(
            Window(
                TokenListControl(get_error_tokens
                                 or _get_default_error_tokens),
                dont_extend_height=True,
                wrap_lines=True,
            ),
            filter=HasValidationError() & ~IsDone(),
        ),
    ])
Esempio n. 6
0
    def _create_layout(self,
                       message='',
                       lexer=None,
                       is_password=False,
                       reserve_space_for_menu=8,
                       get_prompt_tokens=None,
                       get_continuation_tokens=None,
                       get_rprompt_tokens=None,
                       get_bottom_toolbar_tokens=None,
                       get_url_tokens=None,
                       display_completions_in_columns=False,
                       extra_input_processors=None,
                       multiline=False,
                       wrap_lines=True):
        """
        Create a :class:`.Container` instance for a prompt.
        :param message: Text to be used as prompt.
        :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for
            the highlighting.
        :param is_password: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
            When True, display input as '*'.
        :param reserve_space_for_menu: Space to be reserved for the menu. When >0,
            make sure that a minimal height is allocated in the terminal, in order
            to display the completion menu.
        :param get_prompt_tokens: An optional callable that returns the tokens to be
            shown in the menu. (To be used instead of a `message`.)
        :param get_continuation_tokens: An optional callable that takes a
            CommandLineInterface and width as input and returns a list of (Token,
            text) tuples to be used for the continuation.
        :param get_bottom_toolbar_tokens: An optional callable that returns the
            tokens for a toolbar at the bottom.
        :param display_completions_in_columns: `bool` or
            :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in
            multiple columns.
        :param multiline: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
            When True, prefer a layout that is more adapted for multiline input.
            Text after newlines is automatically indented, and search/arg input is
            shown below the input, instead of replacing the prompt.
        :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
            When True (the default), automatically wrap long lines instead of
            scrolling horizontally.
        """
        assert get_bottom_toolbar_tokens is None or callable(
            get_bottom_toolbar_tokens)
        assert get_prompt_tokens is None or callable(get_prompt_tokens)
        assert get_rprompt_tokens is None or callable(get_rprompt_tokens)
        assert not (message and get_prompt_tokens)

        display_completions_in_columns = to_cli_filter(
            display_completions_in_columns)
        multiline = to_cli_filter(multiline)

        if get_prompt_tokens is None:
            get_prompt_tokens = lambda _: [(Token.Prompt, message)]

        has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = \
            _split_multiline_prompt(get_prompt_tokens)

        # `lexer` is supposed to be a `Lexer` instance. But if a Pygments lexer
        # class is given, turn it into a PygmentsLexer. (Important for
        # backwards-compatibility.)
        try:
            if pygments_Lexer and issubclass(lexer, pygments_Lexer):
                lexer = PygmentsLexer(lexer, sync_from_start=True)
        except TypeError:  # Happens when lexer is `None` or an instance of something else.
            pass

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

        if extra_input_processors:
            input_processors.extend(extra_input_processors)

        # Show the prompt before the input (using the DefaultPrompt processor.
        # This also replaces it with reverse-i-search and 'arg' when required.
        # (Only for single line mode.)
        # (DefaultPrompt should always be at the end of the processors.)
        input_processors.append(
            ConditionalProcessor(DefaultPrompt(get_prompt_tokens_2),
                                 ~multiline))

        # Create bottom toolbar.
        if get_bottom_toolbar_tokens:
            toolbars = [
                ConditionalContainer(VSplit([
                    Window(TokenListControl(get_url_tokens,
                                            default_char=Char(
                                                ' ', Token.Toolbar)),
                           height=LayoutDimension.exact(1)),
                    Window(TokenListControl(get_bottom_toolbar_tokens,
                                            default_char=Char(
                                                ' ', Token.Toolbar),
                                            align_right=True),
                           height=LayoutDimension.exact(1))
                ]),
                                     filter=~IsDone()
                                     & RendererHeightIsKnown())
            ]
        else:
            toolbars = []

        def get_height(cli):
            # If there is an autocompletion menu to be shown, make sure that our
            # layout has at least a minimal height in order to display it.
            if reserve_space_for_menu and not cli.is_done:
                buff = cli.current_buffer

                # Reserve the space, either when there are completions, or when
                # `complete_while_typing` is true and we expect completions very
                # soon.
                if buff.complete_while_typing(
                ) or buff.complete_state is not None:
                    return LayoutDimension(min=reserve_space_for_menu)

            return LayoutDimension()

        # Create and return Container instance.
        return HSplit([
            # The main input, with completion menus floating on top of it.
            FloatContainer(
                HSplit([
                    ConditionalContainer(
                        Window(TokenListControl(get_prompt_tokens_1),
                               dont_extend_height=True),
                        Condition(has_before_tokens)),
                    Window(
                        BufferControl(
                            input_processors=input_processors,
                            lexer=lexer,
                            # Enable preview_search, we want to have immediate feedback
                            # in reverse-i-search mode.
                            preview_search=True),
                        get_height=get_height,
                        left_margins=[
                            # In multiline mode, use the window margin to display
                            # the prompt and continuation tokens.
                            ConditionalMargin(PromptMargin(
                                get_prompt_tokens_2, get_continuation_tokens),
                                              filter=multiline)
                        ],
                        wrap_lines=wrap_lines,
                    ),
                ]),
                [
                    # Completion menus.
                    Float(xcursor=True,
                          ycursor=True,
                          content=CompletionsMenu(
                              max_height=16,
                              scroll_offset=1,
                              extra_filter=HasFocus(DEFAULT_BUFFER)
                              & ~display_completions_in_columns)),
                    Float(xcursor=True,
                          ycursor=True,
                          content=MultiColumnCompletionsMenu(
                              extra_filter=HasFocus(DEFAULT_BUFFER)
                              & display_completions_in_columns,
                              show_meta=True)),

                    # The right prompt.
                    Float(right=0,
                          top=0,
                          hide_when_covering_content=True,
                          content=_RPrompt(get_rprompt_tokens)),
                ]),
            ValidationToolbar(),
            SystemToolbar(),

            # In multiline mode, we use two toolbars for 'arg' and 'search'.
            ConditionalContainer(ArgToolbar(), multiline),
            ConditionalContainer(SearchToolbar(), multiline),
        ] + toolbars)
Esempio n. 7
0
def CreatePromptLayout(config,
                       lexer=None,
                       is_password=False,
                       get_prompt_tokens=None,
                       get_continuation_tokens=None,
                       get_bottom_status_tokens=None,
                       get_bottom_toolbar_tokens=None,
                       extra_input_processors=None,
                       multiline=False,
                       show_help=True,
                       wrap_lines=True):
  """Create a container instance for the prompt."""
  assert get_bottom_status_tokens is None or callable(
      get_bottom_status_tokens)
  assert get_bottom_toolbar_tokens is None or callable(
      get_bottom_toolbar_tokens)
  assert get_prompt_tokens is None or callable(get_prompt_tokens)
  assert not (config.prompt and get_prompt_tokens)

  multi_column_completion_menu = filters.to_cli_filter(
      config.multi_column_completion_menu)
  multiline = filters.to_cli_filter(multiline)

  if get_prompt_tokens is None:
    get_prompt_tokens = lambda _: [(token.Token.Prompt, config.prompt)]

  has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = (
      shortcuts._split_multiline_prompt(get_prompt_tokens))  # pylint: disable=protected-access
  # TODO(b/35347840): reimplement _split_multiline_prompt to remove
  #                   protected-access.

  # Create processors list.
  input_processors = [
      processors.ConditionalProcessor(
          # By default, only highlight search when the search
          # input has the focus. (Note that this doesn't mean
          # there is no search: the Vi 'n' binding for instance
          # still allows to jump to the next match in
          # navigation mode.)
          processors.HighlightSearchProcessor(preview_search=True),
          filters.HasFocus(enums.SEARCH_BUFFER)),
      processors.HighlightSelectionProcessor(),
      processors.ConditionalProcessor(processors.AppendAutoSuggestion(),
                                      filters.HasFocus(enums.DEFAULT_BUFFER)
                                      & ~filters.IsDone()),
      processors.ConditionalProcessor(processors.PasswordProcessor(),
                                      is_password),
  ]

  if extra_input_processors:
    input_processors.extend(extra_input_processors)

  # Show the prompt before the input using the DefaultPrompt processor.
  # This also replaces it with reverse-i-search and 'arg' when required.
  # (Only for single line mode.)
  # (DefaultPrompt should always be at the end of the processors.)
  input_processors.append(
      processors.ConditionalProcessor(
          prompt.DefaultPrompt(get_prompt_tokens_2), ~multiline))

  # Create toolbars
  toolbars = []
  if config.fixed_prompt_position:
    help_height = dimension.LayoutDimension.exact(config.help_lines)
    help_filter = (show_help & ~filters.IsDone() &
                   filters.RendererHeightIsKnown())
  else:
    help_height = dimension.LayoutDimension(
        preferred=config.help_lines,
        max=config.help_lines)
    help_filter = (show_help & UserTypingFilter & ~filters.IsDone() &
                   filters.RendererHeightIsKnown())
  toolbars.append(
      containers.ConditionalContainer(
          layout.HSplit([
              layout.Window(
                  controls.FillControl(char=screen.Char('_', token.Token.HSep)),
                  height=dimension.LayoutDimension.exact(1)),
              layout.Window(
                  help_window.HelpWindowControl(
                      default_char=screen.Char(' ', token.Token.Toolbar)),
                  height=help_height),
          ]),
          filter=help_filter))
  if (config.bottom_status_line and get_bottom_status_tokens
      or config.bottom_bindings_line and get_bottom_toolbar_tokens):
    windows = []
    windows.append(layout.Window(
        controls.FillControl(char=screen.Char('_', token.Token.HSep)),
        height=dimension.LayoutDimension.exact(1)))
    if config.bottom_status_line and get_bottom_status_tokens:
      windows.append(
          layout.Window(
              controls.TokenListControl(
                  get_bottom_status_tokens,
                  default_char=screen.Char(' ', token.Token.Toolbar)),
              height=dimension.LayoutDimension.exact(1)))
    if config.bottom_bindings_line and get_bottom_toolbar_tokens:
      windows.append(
          layout.Window(
              controls.TokenListControl(
                  get_bottom_toolbar_tokens,
                  default_char=screen.Char(' ', token.Token.Toolbar)),
              height=dimension.LayoutDimension.exact(1)))
    toolbars.append(
        containers.ConditionalContainer(
            layout.HSplit(windows),
            filter=~filters.IsDone() & filters.RendererHeightIsKnown()))

  def GetHeight(cli):
    """Determine the height for the input buffer."""
    # If there is an autocompletion menu to be shown, make sure that our
    # layout has at least a minimal height in order to display it.
    if cli.config.completion_menu_lines and not cli.is_done:
      # Reserve the space, either when there are completions, or when
      # `complete_while_typing` is true and we expect completions very
      # soon.
      buf = cli.current_buffer
      # if UserTypingFilter(cli) or not buf.text or buf.complete_state:
      if UserTypingFilter(cli) or buf.complete_state:
        return dimension.LayoutDimension(
            min=cli.config.completion_menu_lines + 1)
    return dimension.LayoutDimension()

  # Create and return Container instance.
  return layout.HSplit([
      # The main input, with completion menus floating on top of it.
      containers.FloatContainer(
          layout.HSplit([
              containers.ConditionalContainer(
                  layout.Window(
                      controls.TokenListControl(get_prompt_tokens_1),
                      dont_extend_height=True,
                      wrap_lines=wrap_lines,
                  ),
                  filters.Condition(has_before_tokens),
              ),
              layout.Window(
                  controls.BufferControl(
                      input_processors=input_processors,
                      lexer=lexer,
                      # Enable preview_search, we want to have immediate
                      # feedback in reverse-i-search mode.
                      preview_search=True,
                  ),
                  get_height=GetHeight,
                  left_margins=[
                      # In multiline mode, use the window margin to display
                      # the prompt and continuation tokens.
                      margins.ConditionalMargin(
                          margins.PromptMargin(get_prompt_tokens_2,
                                               get_continuation_tokens),
                          filter=multiline,
                      ),
                  ],
                  wrap_lines=wrap_lines,
              ),
          ]),
          [
              # Completion menus.
              layout.Float(
                  xcursor=True,
                  ycursor=True,
                  content=menus.CompletionsMenu(
                      max_height=16,
                      scroll_offset=1,
                      extra_filter=(
                          filters.HasFocus(enums.DEFAULT_BUFFER) &
                          ~multi_column_completion_menu
                      ),
                  ),
              ),
              layout.Float(
                  ycursor=True,
                  content=menus.MultiColumnCompletionsMenu(
                      show_meta=True,
                      extra_filter=(
                          filters.HasFocus(enums.DEFAULT_BUFFER) &
                          multi_column_completion_menu
                      ),
                  ),
              ),
          ],
      ),
      pt_toolbars.ValidationToolbar(),
      pt_toolbars.SystemToolbar(),

      # In multiline mode, we use two toolbars for 'arg' and 'search'.
      containers.ConditionalContainer(pt_toolbars.ArgToolbar(), multiline),
      containers.ConditionalContainer(pt_toolbars.SearchToolbar(), multiline),
  ] + toolbars)
Esempio n. 8
0
    def create_prompt_layout(self, message='', lexer=None, is_password=False,
        reserve_space_for_menu=8, get_prompt_tokens=None, 
        get_bottom_toolbar_tokens=None, display_completions_in_columns=False,
        extra_input_processors=None, multiline=False, wrap_lines=True):
        """Create a Container instance for a prompt.

        Parameters
        ----------
        message : Text to be used as prompt.
        lexer : ~prompt_toolkit.layout.lexers.Lexer to be used for
            the highlighting.
        is_password : bool or ~prompt_toolkit.filters.CLIFilter.
            When True, display input as '*'.
        reserve_space_for_menu : Space to be reserved for the menu. When >0,
            make sure that a minimal height is allocated in the terminal, in order
            to display the completion menu.
        get_prompt_tokens : An optional callable that returns the tokens to be
            shown in the menu. (To be used instead of a `message`.)
        get_bottom_toolbar_tokens : An optional callable that returns the
            tokens for a toolbar at the bottom.
        display_completions_in_columns : `bool` or
            :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in
            multiple columns.
        multiline : `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
            When True, prefer a layout that is more adapted for multiline input.
            Text after newlines is automatically indented, and search/arg input is
            shown below the input, instead of replacing the prompt.
        wrap_lines : `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
            When True (the default), automatically wrap long lines instead of
            scrolling horizontally.

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

        WARNING; This method is due for removal once prompt-toolkit >v0.54 
        is released.
        """
        assert isinstance(message, str)
        assert get_bottom_toolbar_tokens is None or callable(get_bottom_toolbar_tokens)
        assert get_prompt_tokens is None or callable(get_prompt_tokens)
        assert not (message and get_prompt_tokens)

        display_completions_in_columns = to_cli_filter(display_completions_in_columns)
        multiline = to_cli_filter(multiline)

        if get_prompt_tokens is None:
            get_prompt_tokens = lambda _: [(Token.Prompt, message)]

        get_prompt_tokens_1, get_prompt_tokens_2 = _split_multiline_prompt(get_prompt_tokens)

        # `lexer` is supposed to be a `Lexer` instance. But if a Pygments lexer
        # class is given, turn it into a PygmentsLexer. (Important for
        # backwards-compatibility.)
        try:
            if issubclass(lexer, pygments.lexer.Lexer):
                lexer = PygmentsLexer(lexer)
        except TypeError: # Happens when lexer is `None` or an instance of something else.
            pass

        # Create highlighters and processors list.
        if ConditionalHighlighter is None:
            highlighters = None
            highlighters_kwargs = {}
        else:
            highlighters = [
                ConditionalHighlighter(
                    # By default, only highlight search when the search
                    # input has the focus. (Note that this doesn't mean
                    # there is no search: the Vi 'n' binding for instance
                    # still allows to jump to the next match in
                    # navigation mode.)
                    SearchHighlighter(preview_search=True),
                HasFocus(SEARCH_BUFFER)),
                SelectionHighlighter()]
            highlighters_kwargs = {'highlighters': highlighters}

        input_processors = [
            ConditionalProcessor(AppendAutoSuggestion(), HasFocus(DEFAULT_BUFFER) & ~IsDone()),
            ConditionalProcessor(PasswordProcessor(), is_password)]

        if extra_input_processors:
            input_processors.extend(extra_input_processors)

        # Show the prompt before the input (using the DefaultPrompt processor.
        # This also replaces it with reverse-i-search and 'arg' when required.
        # (Only for single line mode.)
        # (DefaultPrompt should always be at the end of the processors.)
        input_processors.append(ConditionalProcessor(
            DefaultPrompt(get_prompt_tokens), ~multiline))

        # Create bottom toolbar.
        if get_bottom_toolbar_tokens:
            toolbars = [ConditionalContainer(
                Window(TokenListControl(get_bottom_toolbar_tokens,
                                        default_char=Char(' ', Token.Toolbar)),
                                        height=LayoutDimension.exact(1)),
                filter=~IsDone() & RendererHeightIsKnown())]
        else:
            toolbars = []

        def get_height(cli):
            # If there is an autocompletion menu to be shown, make sure that our
            # layout has at least a minimal height in order to display it.
            if reserve_space_for_menu and not cli.is_done:
                return LayoutDimension(min=reserve_space_for_menu)
            else:
                return LayoutDimension()

        # Create and return Container instance.
        return HSplit([
            ConditionalContainer(
                Window(
                    TokenListControl(get_prompt_tokens_1),
                    dont_extend_height=True),
                filter=multiline,
            ),
            VSplit([
                # In multiline mode, the prompt is displayed in a left pane.
                ConditionalContainer(
                    Window(
                        TokenListControl(get_prompt_tokens_2),
                        dont_extend_width=True,
                    ),
                    filter=multiline,
                ),
                # The main input, with completion menus floating on top of it.
                FloatContainer(
                    Window(
                        BufferControl(
                            input_processors=input_processors,
                            lexer=lexer,
                            wrap_lines=wrap_lines,
                            # Enable preview_search, we want to have immediate feedback
                            # in reverse-i-search mode.
                            preview_search=True, 
                            **highlighters_kwargs),
                        get_height=get_height,
                    ),
                    [
                        Float(xcursor=True,
                              ycursor=True,
                              content=CompletionsMenu(
                                  max_height=16,
                                  scroll_offset=1,
                                  extra_filter=HasFocus(DEFAULT_BUFFER) &
                                               ~display_completions_in_columns)),
                        Float(xcursor=True,
                              ycursor=True,
                              content=MultiColumnCompletionsMenu(
                                  extra_filter=HasFocus(DEFAULT_BUFFER) &
                                               display_completions_in_columns,
                                  show_meta=True))
                    ]
                ),
            ]),
            ValidationToolbar(),
            SystemToolbar(),

            # In multiline mode, we use two toolbars for 'arg' and 'search'.
            ConditionalContainer(ArgToolbar(), multiline),
            ConditionalContainer(SearchToolbar(), multiline),
        ] + toolbars)