示例#1
0
    def __enter__(self) -> "ProgressBar":
        # Create UI Application.
        title_toolbar = ConditionalContainer(
            Window(
                FormattedTextControl(lambda: self.title),
                height=1,
                style="class:progressbar,title",
            ),
            filter=Condition(lambda: self.title is not None),
        )

        bottom_toolbar = ConditionalContainer(
            Window(
                FormattedTextControl(
                    lambda: self.bottom_toolbar, style="class:bottom-toolbar.text"
                ),
                style="class:bottom-toolbar",
                height=1,
            ),
            filter=~is_done
            & renderer_height_is_known
            & Condition(lambda: self.bottom_toolbar is not None),
        )

        def width_for_formatter(formatter: Formatter) -> AnyDimension:
            # Needs to be passed as callable (partial) to the 'width'
            # parameter, because we want to call it on every resize.
            return formatter.get_width(progress_bar=self)

        progress_controls = [
            Window(
                content=_ProgressControl(self, f),
                width=functools.partial(width_for_formatter, f),
            )
            for f in self.formatters
        ]

        self.app: Application[None] = Application(
            min_redraw_interval=0.05,
            layout=Layout(
                HSplit(
                    [
                        title_toolbar,
                        VSplit(
                            progress_controls,
                            height=lambda: D(
                                preferred=len(self.counters), max=len(self.counters)
                            ),
                        ),
                        Window(),
                        bottom_toolbar,
                    ]
                )
            ),
            style=self.style,
            key_bindings=self.key_bindings,
            refresh_interval=0.3,
            color_depth=self.color_depth,
            output=self.output,
            input=self.input,
        )

        # Run application in different thread.
        def run() -> None:
            set_event_loop(self._app_loop)
            try:
                self.app.run()
            except BaseException as e:
                traceback.print_exc()
                print(e)

        ctx: contextvars.Context = contextvars.copy_context()

        self._thread = threading.Thread(target=ctx.run, args=(run,))
        self._thread.start()

        # Attach WINCH signal handler in main thread.
        # (Interrupt that we receive during resize events.)
        self._has_sigwinch = hasattr(signal, "SIGWINCH") and in_main_thread()
        if self._has_sigwinch:
            self._previous_winch_handler = signal.getsignal(signal.SIGWINCH)
            self._loop.add_signal_handler(signal.SIGWINCH, self.invalidate)

        return self
示例#2
0
def create_default_layout(app,
                          message='',
                          lexer=None,
                          is_password=False,
                          reserve_space_for_menu=False,
                          get_prompt_tokens=None,
                          get_bottom_toolbar_tokens=None,
                          display_completions_in_columns=False,
                          extra_input_processors=None,
                          multiline=False):
    """
    Generate default layout.

    Returns a ``Layout`` instance.

    :param message: Text to be used as prompt.
    :param lexer: Lexer to be used for the highlighting.
    :param is_password: `bool` or `CLIFilter`. When True, display input as '*'.
    :param reserve_space_for_menu: When True, 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_bottom_toolbar_tokens: An optional callable that returns the
        tokens for a toolbar at the bottom.
    :param display_completions_in_columns: `bool` or `CLIFilter`. Display the
        completions in multiple columns.
    :param multiline: `bool` or `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.
    """
    assert isinstance(message, text_type)
    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, Lexer):
            lexer = PygmentsLexer(lexer)
    except TypeError:
        # Happens when lexer is `None` or an instance of something else.
        pass

    # Create processors list.
    # (DefaultPrompt should always be at the end.)
    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=Always()),
            HasFocus(SEARCH_BUFFER)),
        HighlightSelectionProcessor(),
        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.)
    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=8)
        else:
            return LayoutDimension()

    def separator():
        return ConditionalContainer(content=Window(
            height=LayoutDimension.exact(1),
            content=FillControl(u'\u2500', token=Token.Separator)),
                                    filter=HasDocumentation(app) & ~IsDone())

    # Create and return Layout 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,
                        # Enable preview_search, we want to have immediate
                        # feedback in reverse-i-search mode.
                        preview_search=Always()),
                    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=Always()))
                ]),
        ]),
        separator(),
        ConditionalContainer(
            content=Window(BufferControl(buffer_name='clidocs', ),
                           height=LayoutDimension(max=15)),
            filter=HasDocumentation(app) & ~IsDone(),
        ),
        separator(),
        ValidationToolbar(),
        SystemToolbar(),

        # In multiline mode, we use two toolbars for 'arg' and 'search'.
        ConditionalContainer(ArgToolbar(), multiline),
        ConditionalContainer(SearchToolbar(), multiline),
    ] + toolbars)
示例#3
0
    def __init__(self, editor, manager, window_arrangement):
        self.editor = editor  # Back reference to editor.
        self.manager = manager
        self.window_arrangement = window_arrangement

        # Mapping from (`window_arrangement.Window`, `EditorBuffer`) to a frame
        # (Layout instance).
        # We keep this as a cache in order to easily reuse the same frames when
        # the layout is updated. (We don't want to create new frames on every
        # update call, because that way, we would loose some state, like the
        # vertical scroll offset.)
        self._frames = {}

        self._fc = FloatContainer(
            content=VSplit([
                Window(BufferControl())  # Dummy window
            ]),
            floats=[
                Float(xcursor=True,
                      ycursor=True,
                      content=CompletionsMenu(
                          max_height=12,
                          scroll_offset=2,
                          extra_filter=~HasFocus(COMMAND_BUFFER))),
                Float(content=BufferListOverlay(editor), bottom=1, left=0),
                Float(bottom=1,
                      left=0,
                      right=0,
                      height=1,
                      content=CompletionsToolbar(
                          extra_filter=HasFocus(COMMAND_BUFFER)
                          & ~bufferlist_overlay_visible_filter
                          & Condition(lambda cli: editor.show_wildmenu))),
                Float(bottom=1,
                      left=0,
                      right=0,
                      height=1,
                      content=ValidationToolbar()),
                Float(bottom=1,
                      left=0,
                      right=0,
                      height=1,
                      content=MessageToolbarBar(editor)),
                Float(content=WelcomeMessageWindow(editor),
                      height=WELCOME_MESSAGE_HEIGHT,
                      width=WELCOME_MESSAGE_WIDTH),
            ])

        self.layout = FloatContainer(content=HSplit([
            TabsToolbar(editor),
            self._fc,
            CommandLine(),
            ReportMessageToolbar(editor),
            SystemToolbar(),
            SearchToolbar(vi_mode=True),
        ]),
                                     floats=[
                                         Float(right=0,
                                               height=1,
                                               bottom=0,
                                               width=5,
                                               content=SimpleArgToolbar()),
                                     ])
示例#4
0
def create_layout(buffer,
                  lexer=None,
                  reserve_space_for_menu=8,
                  get_prompt_tokens=None,
                  get_bottom_toolbar_tokens=None,
                  extra_input_processors=None,
                  multiline=False,
                  wrap_lines=True):
    """
    Creates a custom `Layout` for the Crash input REPL

    This layout includes:
        * a bottom left-aligned session toolbar container
        * a bottom right-aligned side-bar container

    +-------------------------------------------+
    | cr> select 1;                             |
    |                                           |
    |                                           |
    +-------------------------------------------+
    | bottom_toolbar_tokens      sidebar_tokens |
    +-------------------------------------------+
    """

    input_processors = [
        ConditionalProcessor(
            # Highlight the reverse-i-search buffer
            HighlightSearchProcessor(),
            has_focus(SEARCH_BUFFER)),
    ] + (extra_input_processors or [])
    lexer = PygmentsLexer(lexer, sync_from_start=True)
    sidebar_token = [
        ('class:status-toolbar', "[ctrl+d]"),
        ('class:status-toolbar.text', " Exit")
    ]

    def _get_buffer_control_height(buf):
        # 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 get_app().is_done:
            buff = 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 Dimension(min=reserve_space_for_menu)

        return Dimension()

    search_toolbar = SearchToolbar()
    buf_ctrl_window = Window(
        BufferControl(
            buffer=buffer,
            search_buffer_control=search_toolbar.control,
            input_processors=input_processors,
            lexer=lexer,
            preview_search=True
        ),
        height=lambda: _get_buffer_control_height(buffer),
        wrap_lines=wrap_lines,
        left_margins=[
            ConditionalMargin(
                PromptMargin(get_prompt_tokens),
                filter=multiline
            )
        ]
    )
    in_out_area = VSplit([
        HSplit([
            FloatContainer(
                HSplit([buf_ctrl_window]),
                [
                    Float(
                        xcursor=True,
                        ycursor=True,
                        content=CompletionsMenu(
                            max_height=16,
                            scroll_offset=1,
                            extra_filter=has_focus(DEFAULT_BUFFER)
                        )
                    ),
                ]
            ),
            # reverse-i-search toolbar (ctrl+r)
            search_toolbar,
        ])
    ])
    bottom_toolbar = VSplit([
        ConditionalContainer(
            Window(
                FormattedTextControl(get_bottom_toolbar_tokens),
                height=Dimension.exact(1)
            ),
            filter=~is_done & renderer_height_is_known
        ),
        ConditionalContainer(
            Window(
                FormattedTextControl(lambda: sidebar_token),
                height=Dimension.exact(1),
                align=WindowAlign.RIGHT
            ),
            filter=~is_done & renderer_height_is_known
        )
    ])
    return Layout(HSplit([in_out_area, bottom_toolbar]))
示例#5
0
    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.
                    Float(xcursor=True,
                          ycursor=True,
                          content=CompletionsMenu(
                              max_height=16,
                              scroll_offset=1,
                              extra_filter=has_focus(default_buffer) &
                                  ~multi_column_complete_style)),
                    Float(xcursor=True,
                          ycursor=True,
                          content=MultiColumnCompletionsMenu(
                              show_meta=True,
                              extra_filter=has_focus(default_buffer) &
                                  multi_column_complete_style)),
                    # The right prompt.
                    Float(right=0, top=0, hide_when_covering_content=True,
                          content=_RPrompt(lambda: self.rprompt)),
                ]
            ),
            ConditionalContainer(
                ValidationToolbar(),
                filter=~is_done),
            ConditionalContainer(
                system_toolbar,
                dyncond('enable_system_prompt') & ~is_done),

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

        return Layout(layout, default_buffer_window)
    def __init__(self, exchange, get_paths_in_directory):
        super().__init__()
        self.use_default_bindings = False
        self._exchange = exchange

        self._input = TextArea(text="/project/", multiline=False)
        self._buffer = self._input.buffer
        self._buffer.cursor_position = len(self._buffer.text)
        self._completions_component = Completions()
        self._completer = AsyncCompleter(exchange, get_paths_in_directory)
        self._completer_status_component = AsyncCompleterStatus()
        self._bottom_toolbar = Window(
            FormattedTextControl(
                "[tab] Enter selected directory  "
                "[return] Choose selected directory  "
                "[arrows] Navigation  "
                "[C-c] Quit"
            ),
            height=1,
            style="reverse",
        )
        self._container = HSplit(
            [
                Window(height=1),
                Window(
                    FormattedTextControl(
                        "Choose directory to synchronize to on Faculty Platform: "
                    ),
                    height=1,
                ),
                self._input,
                Window(height=1),
                self._completions_component.container,
                self._completer_status_component.container,
            ]
        )
        self.main_container = HSplit(
            [VSplit([Window(width=2), self._container]), self._bottom_toolbar]
        )
        self._buffer.on_text_changed += self._handle_text_changed

        self.bindings = KeyBindings()

        @self.bindings.add("down")
        def _(event):
            self._completions_component.move_selection_down()

        @self.bindings.add("up")
        def _(event):
            self._completions_component.move_selection_up()

        @self.bindings.add("tab")
        def _(event):
            current_selection = self._completions_component.current_selection()
            if current_selection is not None:
                self._buffer.cursor_position = 0
                self._buffer.text = current_selection + "/"
                self._buffer.cursor_position = len(self._buffer.text)

        @self.bindings.add("enter")
        def _(event):
            current_selection = self._completions_component.current_selection()
            self._exchange.publish(
                Messages.VERIFY_REMOTE_DIRECTORY, current_selection
            )

        @self.bindings.add("c-c")
        def _(event):
            self._exchange.publish(Messages.STOP_CALLED)

        self._exchange.subscribe(
            RemoteDirMessages.NEW_SUBDIRECTORIES_WALKED,
            lambda _: self._handle_text_changed(),
        )
        self._exchange.subscribe(
            RemoteDirMessages.SUBDIRECTORY_WALKER_STATUS_CHANGE,
            lambda path: self._handle_walker_status_change(path),
        )
message1 = HTML("<ansibrightred>Hello</ansibrightred>")
message2 = HTML("<ansibrightyellow>world!</ansibrightyellow>")
message3 = HTML("<ansibrightyellow>(Esc to quit)</ansibrightyellow>")

# widgety
widget1 = Label(message1)
widget2 = Label(message2)
widget3 = Label(message3)

# styl rámce
style = "bg:#ansiblue #ansiwhite"

# správce rozvržení
vsplit = HSplit([
    VSplit([Frame(widget1, style=style),
            Frame(widget2, style=style)]),
    Frame(TextArea(), title="Editor"),
    Frame(widget3, style=style)
])

layout = Layout(vsplit)

# napojení na klávesové zkratky
key_bindings = KeyBindings()


@key_bindings.add('escape')
def on_escape_press(event):
    """Callback funkce volaná při stisku klávesy Esc."""
    print("\n\n[escape]\n\n")
    event.app.exit()
示例#8
0

def button3_clicked():
    text_area.text += "Button 3 clicked\n"


def exit_clicked():
    get_app().exit()


button1 = Button("Button 1", handler=button1_clicked)
button2 = Button("Button 2", handler=button2_clicked)
button3 = Button("Button 3", handler=button3_clicked)
button4 = Button("Exit", handler=exit_clicked)

buttons = HSplit([button1, button2, button3, button4])

text_area = TextArea(focusable=False)

# správce rozvržení
root = VSplit([
    Box(Frame(buttons, style="class:button_panel"), padding=2),
    Box(Frame(text_area, title="Events", style="class:edit_panel"), padding=2),
])

layout = Layout(root)

# napojení na klávesové zkratky
key_bindings = KeyBindings()
key_bindings.add("up")(focus_previous)
key_bindings.add("down")(focus_next)
示例#9
0
btn_pause = Button("Pause", handler=tomato.pause)
btn_reset = Button("Reset", handler=tomato.reset)
btn_reset_all = Button("Reset All", handler=tomato.reset_all)
btn_exit = Button("Exit", handler=exit_clicked)

text_area = FormattedTextControl(focusable=False, show_cursor=False)
text_window = Window(
    content=text_area, dont_extend_height=True, height=11, style="bg:#000000 #ffffff"
)

root_container = Box(
            HSplit(
                [
                    VSplit(
                        [btn_start, btn_pause, btn_reset, btn_reset_all, btn_exit],
                        padding=1,
                        style="bg:#cccccc",
                    ),
                    text_window,
                ]
            ),
)

layout = Layout(container=root_container, focused_element=btn_start)

# Key bindings. These values are set in pydoro_core/config.py.
kb = KeyBindings()

# WHY: string to action map to allow for easy configuration
actions = {
    "focus_next": focus_next,
    "focus_previous": focus_previous,
示例#10
0
radiolist = RadioList([
    ("python_val", "Python"),
    ("java_val", "Java"),
    ("clojure_val", "Clojure"),
    ("perl_val", "Perl"),
])

checkbox1 = Checkbox("Checkbox 1")
checkbox2 = Checkbox("Checkbox 2")
checkbox3 = Checkbox("Checkbox 3")
hl = HorizontalLine()
button1 = Button("Show status", handler=show_status)
button2 = Button("Exit", handler=exit_clicked)

buttons = HSplit(
    [radiolist, hl, checkbox1, checkbox2, checkbox3, hl, button1, hl, button2])

text_area = TextArea(focusable=False)

# správce rozvržení
root = VSplit([
    Box(Frame(buttons, style="bg:#ansiblue #ansiwhite"), padding=2),
    Box(Frame(text_area, title="Events"), padding=2),
])

layout = Layout(root)

# napojení na klávesové zkratky
key_bindings = KeyBindings()
key_bindings.add("s-tab")(focus_previous)
key_bindings.add("tab")(focus_next)
示例#11
0
btn_pause = Button("Pause", handler=tomato.pause)
btn_reset = Button("Reset", handler=tomato.reset)
btn_reset_all = Button("Reset All", handler=tomato.reset_all)
btn_exit = Button("Exit", handler=exit_clicked)
text_area = TextArea(read_only=True, height=11, focusable=False)

# Combine all the widgets in a UI.
# The `Box` object ensures that padding will be inserted around the containing
# widget. It adapts automatically, unless an explicit `padding` amount is given.
root_container = Box(
    HSplit([
        Label(text="Press `Tab` to move the focus."),
        HSplit([
            VSplit(
                [btn_start, btn_pause, btn_reset, btn_reset_all, btn_exit],
                padding=1,
                style="bg:#cccccc",
            ),
            text_area,
        ]),
    ]))

layout = Layout(container=root_container, focused_element=btn_start)

# Key bindings.
kb = KeyBindings()
kb.add("tab")(focus_next)
kb.add("s-tab")(focus_previous)
kb.add("right")(focus_next)
kb.add("left")(focus_previous)
kb.add("q")(exit_clicked)
示例#12
0
def edit_file(filename):
    manager = KeyBindingManager(enable_vi_mode=True, enable_system_prompt=True)
    manager.vi_state.input_mode = InputMode.NAVIGATION

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

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

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

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

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

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

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

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

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

        else:
            leave_command_mode()

        # TODO: validation of other commands.

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

    # Run interface.
    cli.read_input()
示例#13
0
def main():
    manager = KeyBindingManager(enable_system_prompt=True)

    D = LayoutDimension
    layout = HSplit([
        VSplit([
            Window(width=D(min=15, max=30, preferred=30),
                   content=FillControl('a', token=Token.A)),
            Window(width=D.exact(1),
                   content=FillControl('|', token=Token.Line)),
            Window(content=TokenListControl.static([(Token.HelloWorld,
                                                     lipsum)])),
            Window(width=D.exact(1),
                   content=FillControl('|', token=Token.Line)),
            Window(content=BufferControl(lexer=PythonLexer,
                                         show_line_numbers=Always(),
                                         input_processors=[
                                             DefaultPrompt('python> '),
                                             AfterInput.static(
                                                 ' <python',
                                                 token=Token.AfterInput),
                                         ]), ),
            Window(width=D.exact(1),
                   content=FillControl('|', token=Token.Line)),
            HSplit([
                Window(width=D(max=40),
                       height=D.exact(4),
                       content=FillControl('b', token=Token.B)),
                Window(width=D(max=40),
                       content=FillControl('f', token=Token.F)),
                Window(width=D.exact(30),
                       height=D.exact(2),
                       content=FillControl('c', token=Token.C)),
            ]),
            #CompletionsMenu(),
        ]),
        Window(height=D.exact(1), content=FillControl('-', token=Token.Line)),
        Window(height=D.exact(3), content=FillControl('d', token=Token.D)),
        SystemToolbar(),
        ArgToolbar(),
        CompletionsToolbar(),
        SearchToolbar(),
    ])

    layout = FloatContainer(content=layout,
                            floats=[
                                Float(xcursor=True,
                                      ycursor=True,
                                      content=VSplit([
                                          Window(width=D.exact(5),
                                                 content=FillControl(
                                                     'f', token=Token.F)),
                                          CompletionsMenu(),
                                      ])),
                            ])

    eventloop = create_eventloop()
    cli = CommandLineInterface(eventloop=eventloop,
                               layout=layout,
                               style=TestStyle,
                               key_bindings_registry=manager.registry,
                               buffer=Buffer(is_multiline=Always(),
                                             completer=TestCompleter()))
    cli.read_input()
    eventloop.close()
示例#14
0
def create_layout(message='',
                  lexer=None,
                  reserve_space_for_menu=8,
                  get_prompt_tokens=None,
                  get_bottom_toolbar_tokens=None,
                  extra_input_processors=None,
                  multiline=False,
                  wrap_lines=True):

    # Create processors list.
    input_processors = [
        ConditionalProcessor(
            # Highlight the reverse-i-search buffer
            HighlightSearchProcessor(preview_search=True),
            HasFocus(SEARCH_BUFFER)),
    ]

    if extra_input_processors:
        input_processors.extend(extra_input_processors)

    lexer = PygmentsLexer(lexer, sync_from_start=True)
    multiline = to_cli_filter(multiline)

    sidebar_token = [(Token.Toolbar.Status.Key, "[ctrl+d]"),
                     (Token.Toolbar.Status, " Exit")]
    sidebar_width = token_list_width(sidebar_token)

    get_prompt_tokens = lambda _: [(Token.Prompt, message)]
    get_sidebar_tokens = lambda _: sidebar_token

    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([
        VSplit([
            HSplit([
                # The main input, with completion menus floating on top of it.
                FloatContainer(
                    HSplit([
                        Window(
                            BufferControl(
                                input_processors=input_processors,
                                lexer=lexer,
                                # enable preview search for reverse-i-search
                                preview_search=True),
                            get_height=get_height,
                            wrap_lines=wrap_lines,
                            left_margins=[
                                # In multiline mode, use the window margin to display
                                # the prompt and continuation tokens.
                                ConditionalMargin(PromptMargin(
                                    get_prompt_tokens),
                                                  filter=multiline)
                            ],
                        ),
                    ]),
                    [
                        # Completion menu
                        Float(xcursor=True,
                              ycursor=True,
                              content=CompletionsMenu(max_height=16,
                                                      scroll_offset=1,
                                                      extra_filter=HasFocus(
                                                          DEFAULT_BUFFER))),
                    ]),

                # reverse-i-search toolbar (ctrl+r)
                ConditionalContainer(SearchToolbar(), multiline),
            ])
        ]),
    ] + [
        VSplit([
            # Left-Aligned Session Toolbar
            ConditionalContainer(Window(TokenListControl(
                get_bottom_toolbar_tokens),
                                        height=LayoutDimension.exact(1)),
                                 filter=~IsDone() & RendererHeightIsKnown()),

            # Right-Aligned Container
            ConditionalContainer(Window(TokenListControl(get_sidebar_tokens),
                                        height=LayoutDimension.exact(1),
                                        width=LayoutDimension.exact(
                                            sidebar_width)),
                                 filter=~IsDone() & RendererHeightIsKnown())
        ])
    ])
示例#15
0
文件: app.py 项目: eruvanos/retro-cli
def start_app(store: RetroStore, connection_string: str = ''):
    kb = KeyBindings()

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

    @kb.add('c-r')
    def refresh_(event):
        refresh()

    def refresh():
        items = store.list()

        texts = {
            Category.GOOD: StringIO(),
            Category.NEUTRAL: StringIO(),
            Category.BAD: StringIO(),
        }
        for item in items:
            texts[item.category].write(f'{item.key}. {item.text}\n')

        good_buffer.text = texts[Category.GOOD].getvalue()
        neutral_buffer.text = texts[Category.NEUTRAL].getvalue()
        bad_buffer.text = texts[Category.BAD].getvalue()

    @kb.add('c-m')
    def enter_(event):
        text = input_buffer.text

        if text.startswith('+'):
            input_buffer.reset()
            store.add_item(text[1:].strip(), Category.GOOD)
        elif text.startswith('.'):
            input_buffer.reset()
            store.add_item(text[1:].strip(), Category.NEUTRAL)
        elif text.startswith('-'):
            input_buffer.reset()
            store.add_item(text[1:].strip(), Category.BAD)

        elif text.startswith('mv '):
            cmd, key, column = text.split()

            categories = {
                '+': Category.GOOD,
                '.': Category.NEUTRAL,
                '-': Category.BAD,
            }

            input_buffer.reset()
            store.move_item(int(key), categories[column])

        elif text.startswith('rm '):
            cmd, key = text.split()

            input_buffer.reset()
            store.remove(int(key))

        refresh()

    @kb.add('c-p')
    def ping_(event):
        start = time()
        store.list(Category.GOOD)
        app.print_text(f'latency: {time() - start:.3f}')

    good_buffer = Buffer()
    neutral_buffer = Buffer()
    bad_buffer = Buffer()

    input_buffer = Buffer()
    input = Window(content=BufferControl(buffer=input_buffer), height=1)

    root_container = HSplit([
        VSplit([
            HSplit([
                Window(content=FormattedTextControl(text=':)'),
                       height=1,
                       align=WindowAlign.CENTER),
                Window(height=1, char='-'),
                Window(content=BufferControl(buffer=good_buffer)),
            ],
                   style="fg:white bold bg:ansigreen"),
            Window(width=2, char='|'),
            HSplit([
                Window(content=FormattedTextControl(text=':|'),
                       height=1,
                       align=WindowAlign.CENTER),
                Window(height=1, char='-'),
                Window(content=BufferControl(buffer=neutral_buffer)),
            ],
                   style="fg:white bold bg:ansiyellow"),
            Window(width=2, char='|'),
            HSplit([
                Window(content=FormattedTextControl(text=':('),
                       height=1,
                       align=WindowAlign.CENTER),
                Window(height=1, char='-'),
                Window(content=BufferControl(buffer=bad_buffer)),
            ],
                   style="fg:white bold bg:ansired"),
        ]),
        Window(
            content=FormattedTextControl(text=f'Invite: {connection_string}'),
            height=1,
            align=WindowAlign.CENTER), input
    ],
                            style='bg:grey')

    layout = Layout(root_container)
    layout.focus(input)

    app = Application(layout=layout, key_bindings=kb, full_screen=True)

    async def active_refresh():
        while True:
            refresh()
            await asyncio.sleep(2)

    app.create_background_task(active_refresh())

    app.run()
示例#16
0
    def __init__(
        self,
        title=None,
        elements=None,
        width=None,
        height=None,
        align=WindowAlign.LEFT,
        get_bullet=None,
        allow_select=True,
        scrollbar=True,
    ):
        self.index = 0
        self.get_bullet = get_bullet
        self.selected = -1
        self.elements = elements or []
        self.title = title
        self.allow_select = allow_select
        self.cursor = Point(0, 0)
        self.scrollbar = scrollbar
        self.control = FormattedTextControl(
            text=self._get_text,
            focusable=True,
            get_cursor_position=lambda: self.cursor,
            key_bindings=self.get_key_bindings(),
        )

        # TODO: figure out how to the make it look nicer
        right_margins = [
            ConditionalMargin(
                ScrollbarMargin(display_arrows=True),
                filter=Condition(lambda: self.scrollbar),
            ),
        ]
        self.title_window = FormattedTextArea(
            text=self.title,
            height=Dimension(min=1),
            width=Dimension(min=1),
        )
        self.list_window = Window(
            content=self.control,
            width=width,
            height=height,
            always_hide_cursor=False,
            style="class:list",
            wrap_lines=True,
            dont_extend_height=True,
            dont_extend_width=False,
            cursorline=False,
            right_margins=right_margins,
            allow_scroll_beyond_bottom=True,
            get_line_prefix=self._get_line_prefix,
        )
        self.window = HSplit(
            children=[
                Box(
                    self.title_window,
                    padding=Dimension.exact(1),
                ),
                Box(
                    self.list_window,
                    padding=Dimension.exact(1),
                    padding_top=Dimension.exact(0),
                ),
            ],
            height=Dimension(min=1),
            width=Dimension(min=1),
        )
# All the widgets for the UI.
button1 = Button('Button 1', handler=button1_clicked)
button2 = Button('Button 2', handler=button2_clicked)
button3 = Button('Button 3', handler=button3_clicked)
button4 = Button('Exit', handler=exit_clicked)
text_area = TextArea(focusable=True)

# Combine all the widgets in a UI.
# The `Box` object ensures that padding will be inserted around the containing
# widget. It adapts automatically, unless an explicit `padding` amount is given.
root_container = Box(
    HSplit([
        Label(text='Press `Tab` to move the focus.'),
        VSplit([
            Box(body=HSplit([button1, button2, button3, button4], padding=1),
                padding=1,
                style='class:left-pane'),
            Box(body=Frame(text_area), padding=1, style='class:right-pane'),
        ]),
    ]), )

layout = Layout(container=root_container, focused_element=button1)

# Key bindings.
kb = KeyBindings()
kb.add('tab')(focus_next)
kb.add('s-tab')(focus_previous)

# Styling.
style = Style([
    ('left-pane', 'bg:#888800 #000000'),
示例#18
0
    def __enter__(self):
        # Create UI Application.
        title_toolbar = ConditionalContainer(
            Window(FormattedTextControl(lambda: self.title),
                   height=1,
                   style='class:progressbar,title'),
            filter=Condition(lambda: self.title is not None))

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

        def width_for_formatter(formatter):
            # Needs to be passed as callable (partial) to the 'width'
            # parameter, because we want to call it on every resize.
            return formatter.get_width(progress_bar=self)

        progress_controls = [
            Window(content=_ProgressControl(self, f),
                   width=functools.partial(width_for_formatter, f))
            for f in self.formatters
        ]

        self.app = Application(
            min_redraw_interval=.05,
            layout=Layout(
                HSplit([
                    title_toolbar,
                    VSplit(progress_controls,
                           height=lambda: D(preferred=len(self.counters),
                                            max=len(self.counters))),
                    Window(),
                    bottom_toolbar,
                ])),
            style=self.style,
            key_bindings=self.key_bindings,
            output=self.output,
            input=self.input)

        # Run application in different thread.
        def run():
            with _auto_refresh_context(self.app, .3):
                try:
                    self.app.run()
                except Exception as e:
                    traceback.print_exc()
                    print(e)

        self._thread = threading.Thread(target=run)
        self._thread.start()

        # Attach WINCH signal handler in main thread.
        # (Interrupt that we receive during resize events.)
        self._has_sigwinch = hasattr(signal, 'SIGWINCH') and in_main_thread()
        if self._has_sigwinch:
            self._previous_winch_handler = self._loop.add_signal_handler(
                signal.SIGWINCH, self.app.invalidate)

        return self
示例#19
0
    def _create_application(self, editing_mode, erase_when_done):
        def dyncond(attr_name):
            """
            Dynamically take this setting from this 'Prompt' class.
            `attr_name` represents an attribute name of this class. Its value
            can either be a boolean or a `Filter`.

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

            return dynamic

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

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

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

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

        search_buffer = Buffer(name=SEARCH_BUFFER)

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

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

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

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

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

        system_toolbar = SystemToolbar()

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

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

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

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

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

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

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

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

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

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

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

        app.on_render += on_render
        '''

        return application, default_buffer, default_buffer_control
示例#20
0
def create_default_layout(message='',
                          lexer=None,
                          is_password=False,
                          reserve_space_for_menu=False,
                          get_prompt_tokens=None,
                          get_bottom_toolbar_tokens=None,
                          extra_input_processors=None):
    """
    Generate default layout.
    Returns a ``Layout`` instance.

    :param message: Text to be used as prompt.
    :param lexer: Pygments lexer to be used for the highlighting.
    :param is_password: When True, display input as '*'.
    :param reserve_space_for_menu: When True, 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_bottom_toolbar_tokens: An optional callable that returns the
        tokens for a toolbar at the bottom.
    """
    assert isinstance(message, text_type)
    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)

    # Create processors list.
    # (DefaultPrompt should always be at the end.)
    input_processors = [
        HighlightSearchProcessor(preview_search=Always()),
        HighlightSelectionProcessor()
    ]

    if is_password:
        input_processors.append(PasswordProcessor())

    if extra_input_processors:
        input_processors.extend(extra_input_processors)

    if message:
        input_processors.append(DefaultPrompt.from_message(message))
    else:
        input_processors.append(DefaultPrompt(get_prompt_tokens))

    # Create bottom toolbar.
    if get_bottom_toolbar_tokens:
        toolbars = [
            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=8)
        else:
            return LayoutDimension()

    # Create and return Layout instance.
    return HSplit([
        FloatContainer(
            Window(
                BufferControl(
                    input_processors=input_processors,
                    lexer=lexer,
                    # Enable preview_search, we want to have immediate feedback
                    # in reverse-i-search mode.
                    preview_search=Always()),
                get_height=get_height,
            ),
            [
                Float(xcursor=True,
                      ycursor=True,
                      content=CompletionsMenu(max_height=16,
                                              extra_filter=HasFocus(
                                                  DEFAULT_BUFFER)))
            ]),
        ValidationToolbar(),
        SystemToolbar(),
    ] + toolbars)
示例#21
0
from xradios.tui.widget.display import Display
from xradios.tui.widget.popup import PopupWindow
from xradios.tui.widget.listview import ListView
from xradios.tui.widget.prompt import Prompt
from xradios.tui.widget.topbar import TopBar

from xradios.tui.buffers.display import buffer as display_buffer
from xradios.tui.buffers.popup import buffer as popup_buffer
from xradios.tui.buffers.prompt import buffer as prompt_buffer
from xradios.tui.buffers.listview import buffer as listview_buffer

layout = Layout(
    FloatContainer(
        content=HSplit([
            TopBar(message="Need help! Press `F1`."),
            Display(display_buffer),
            ListView(listview_buffer),
            Prompt(prompt_buffer),
        ]),
        modal=True,
        floats=[
            # Help text as a float.
            Float(
                top=3,
                bottom=2,
                left=2,
                right=2,
                content=ConditionalContainer(
                    content=PopupWindow(popup_buffer, title="Help"),
                    filter=has_focus(popup_buffer),
                ),
            )