def test_and():
    for a in (True, False):
        for b in (True, False):
            c1 = Condition(lambda: a)
            c2 = Condition(lambda: b)
            c3 = c1 & c2

            assert isinstance(c3, Filter)
            assert c3() == (a and b)
def main():
    swapped = [False]  # Nonlocal
    bindings = KeyBindings()

    @bindings.add('c-t')
    def _(event):
        ' When ControlT has been pressed, toggle light/dark colors. '
        swapped[0] = not swapped[0]

    def bottom_toolbar():
        if swapped[0]:
            on = 'on=true'
        else:
            on = 'on=false'

        return HTML('Press <style bg="#222222" fg="#ff8888">[control-t]</style> '
                    'to swap between dark/light colors. '
                    '<style bg="ansiblack" fg="ansiwhite">[%s]</style>') % on

    text = prompt(HTML('<style fg="#aaaaaa">Give some animals</style>: '),
                  completer=html_completer,
                  complete_while_typing=True,
                  bottom_toolbar=bottom_toolbar,
                  key_bindings=bindings,
                  lexer=PygmentsLexer(HtmlLexer),
                  swap_light_and_dark_colors=Condition(lambda: swapped[0]))
    print('You said: %s' % text)
def test_to_filter():
    f1 = to_filter(True)
    f2 = to_filter(False)
    f3 = to_filter(Condition(lambda: True))
    f4 = to_filter(Condition(lambda: False))

    assert isinstance(f1, Filter)
    assert isinstance(f2, Filter)
    assert isinstance(f3, Filter)
    assert isinstance(f4, Filter)
    assert f1()
    assert not f2()
    assert f3()
    assert not f4()

    with pytest.raises(TypeError):
        to_filter(4)
def main():
    hidden = [True]  # Nonlocal
    bindings = KeyBindings()

    @bindings.add('c-t')
    def _(event):
        ' When ControlT has been pressed, toggle visibility. '
        hidden[0] = not hidden[0]

    print('Type Control-T to toggle password visible.')
    password = prompt('Password: '******'You said: %s' % password)
Exemplo n.º 5
0
    def __init__(self,
                 text: str = '',
                 multiline: FilterOrBool = True,
                 password: FilterOrBool = False,
                 lexer: Optional[Lexer] = None,
                 auto_suggest: Optional[AutoSuggest] = None,
                 completer: Optional[Completer] = None,
                 complete_while_typing: FilterOrBool = True,
                 accept_handler: Optional[BufferAcceptHandler] = None,
                 history: Optional[History] = None,
                 focusable: FilterOrBool = True,
                 focus_on_click: FilterOrBool = False,
                 wrap_lines: FilterOrBool = True,
                 read_only: FilterOrBool = False,
                 width: AnyDimension = None,
                 height: AnyDimension = None,
                 dont_extend_height: FilterOrBool = False,
                 dont_extend_width: FilterOrBool = False,
                 line_numbers: bool = False,
                 get_line_prefix: Optional[GetLinePrefixCallable] = None,
                 scrollbar: bool = False,
                 style: str = '',
                 search_field: Optional[SearchToolbar] = None,
                 preview_search: FilterOrBool = True,
                 prompt: AnyFormattedText = '',
                 input_processors: Optional[List[Processor]] = None) -> None:

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

        if input_processors is None:
            input_processors = []

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

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

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

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

        style = 'class:text-area ' + style

        self.window = Window(
            height=height,
            width=width,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
            content=self.control,
            style=style,
            wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
            left_margins=left_margins,
            right_margins=right_margins,
            get_line_prefix=get_line_prefix)
Exemplo n.º 6
0
def load_emacs_bindings() -> KeyBindingsBase:
    """
    Some e-macs extensions.
    """
    # Overview of Readline emacs commands:
    # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf
    key_bindings = KeyBindings()
    handle = key_bindings.add

    insert_mode = emacs_insert_mode

    @handle('escape')
    def _(event: E) -> None:
        """
        By default, ignore escape key.

        (If we don't put this here, and Esc is followed by a key which sequence
        is not handled, we'll insert an Escape character in the input stream.
        Something we don't want and happens to easily in emacs mode.
        Further, people can always use ControlQ to do a quoted insert.)
        """
        pass

    handle('c-a')(get_by_name('beginning-of-line'))
    handle('c-b')(get_by_name('backward-char'))
    handle('c-delete', filter=insert_mode)(get_by_name('kill-word'))
    handle('c-e')(get_by_name('end-of-line'))
    handle('c-f')(get_by_name('forward-char'))
    handle('c-left')(get_by_name('backward-word'))
    handle('c-right')(get_by_name('forward-word'))
    handle('c-x', 'r', 'y', filter=insert_mode)(get_by_name('yank'))
    handle('c-y', filter=insert_mode)(get_by_name('yank'))
    handle('escape', 'b')(get_by_name('backward-word'))
    handle('escape', 'c', filter=insert_mode)(get_by_name('capitalize-word'))
    handle('escape', 'd', filter=insert_mode)(get_by_name('kill-word'))
    handle('escape', 'f')(get_by_name('forward-word'))
    handle('escape', 'l', filter=insert_mode)(get_by_name('downcase-word'))
    handle('escape', 'u', filter=insert_mode)(get_by_name('uppercase-word'))
    handle('escape', 'y', filter=insert_mode)(get_by_name('yank-pop'))
    handle('escape', 'backspace',
           filter=insert_mode)(get_by_name('backward-kill-word'))
    handle('escape', '\\',
           filter=insert_mode)(get_by_name('delete-horizontal-space'))

    handle('c-_', save_before=(lambda e: False),
           filter=insert_mode)(get_by_name('undo'))

    handle('c-x', 'c-u', save_before=(lambda e: False),
           filter=insert_mode)(get_by_name('undo'))

    handle('escape', '<',
           filter=~has_selection)(get_by_name('beginning-of-history'))
    handle('escape', '>', filter=~has_selection)(get_by_name('end-of-history'))

    handle('escape', '.', filter=insert_mode)(get_by_name('yank-last-arg'))
    handle('escape', '_', filter=insert_mode)(get_by_name('yank-last-arg'))
    handle('escape', 'c-y', filter=insert_mode)(get_by_name('yank-nth-arg'))
    handle('escape', '#', filter=insert_mode)(get_by_name('insert-comment'))
    handle('c-o')(get_by_name('operate-and-get-next'))

    # ControlQ does a quoted insert. Not that for vt100 terminals, you have to
    # disable flow control by running ``stty -ixon``, otherwise Ctrl-Q and
    # Ctrl-S are captured by the terminal.
    handle('c-q', filter=~has_selection)(get_by_name('quoted-insert'))

    handle('c-x', '(')(get_by_name('start-kbd-macro'))
    handle('c-x', ')')(get_by_name('end-kbd-macro'))
    handle('c-x', 'e')(get_by_name('call-last-kbd-macro'))

    @handle('c-n')
    def _(event: E) -> None:
        " Next line. "
        event.current_buffer.auto_down()

    @handle('c-p')
    def _(event: E) -> None:
        " Previous line. "
        event.current_buffer.auto_up(count=event.arg)

    def handle_digit(c: str) -> None:
        """
        Handle input of arguments.
        The first number needs to be preceded by escape.
        """
        @handle(c, filter=has_arg)
        @handle('escape', c)
        def _(event: E) -> None:
            event.append_to_arg_count(c)

    for c in '0123456789':
        handle_digit(c)

    @handle('escape', '-', filter=~has_arg)
    def _(event: E) -> None:
        """
        """
        if event._arg is None:
            event.append_to_arg_count('-')

    @handle('-', filter=Condition(lambda: get_app().key_processor.arg == '-'))
    def _(event: E) -> None:
        """
        When '-' is typed again, after exactly '-' has been given as an
        argument, ignore this.
        """
        event.app.key_processor.arg = '-'

    @Condition
    def is_returnable() -> bool:
        return get_app().current_buffer.is_returnable

    # Meta + Enter: always accept input.
    handle('escape', 'enter',
           filter=insert_mode & is_returnable)(get_by_name('accept-line'))

    # Enter: accept input in single line mode.
    handle('enter', filter=insert_mode & is_returnable & ~is_multiline)(
        get_by_name('accept-line'))

    def character_search(buff: Buffer, char: str, count: int) -> None:
        if count < 0:
            match = buff.document.find_backwards(char,
                                                 in_current_line=True,
                                                 count=-count)
        else:
            match = buff.document.find(char, in_current_line=True, count=count)

        if match is not None:
            buff.cursor_position += match

    @handle('c-]', Keys.Any)
    def _(event: E) -> None:
        " When Ctl-] + a character is pressed. go to that character. "
        # Also named 'character-search'
        character_search(event.current_buffer, event.data, event.arg)

    @handle('escape', 'c-]', Keys.Any)
    def _(event: E) -> None:
        " Like Ctl-], but backwards. "
        # Also named 'character-search-backward'
        character_search(event.current_buffer, event.data, -event.arg)

    @handle('escape', 'a')
    def _(event: E) -> None:
        " Previous sentence. "
        # TODO:

    @handle('escape', 'e')
    def _(event: E) -> None:
        " Move to end of sentence. "
        # TODO:

    @handle('escape', 't', filter=insert_mode)
    def _(event: E) -> None:
        """
        Swap the last two words before the cursor.
        """
        # TODO

    @handle('escape', '*', filter=insert_mode)
    def _(event: E) -> None:
        """
        `meta-*`: Insert all possible completions of the preceding text.
        """
        buff = event.current_buffer

        # List all completions.
        complete_event = CompleteEvent(text_inserted=False,
                                       completion_requested=True)
        completions = list(
            buff.completer.get_completions(buff.document, complete_event))

        # Insert them.
        text_to_insert = ' '.join(c.text for c in completions)
        buff.insert_text(text_to_insert)

    @handle('c-x', 'c-x')
    def _(event: E) -> None:
        """
        Move cursor back and forth between the start and end of the current
        line.
        """
        buffer = event.current_buffer

        if buffer.document.is_cursor_at_the_end_of_line:
            buffer.cursor_position += buffer.document.get_start_of_line_position(
                after_whitespace=False)
        else:
            buffer.cursor_position += buffer.document.get_end_of_line_position(
            )

    @handle('c-@')  # Control-space or Control-@
    def _(event: E) -> None:
        """
        Start of the selection (if the current buffer is not empty).
        """
        # Take the current cursor position as the start of this selection.
        buff = event.current_buffer
        if buff.text:
            buff.start_selection(selection_type=SelectionType.CHARACTERS)

    @handle('c-g', filter=~has_selection)
    def _(event: E) -> None:
        """
        Control + G: Cancel completion menu and validation state.
        """
        event.current_buffer.complete_state = None
        event.current_buffer.validation_error = None

    @handle('c-g', filter=has_selection)
    def _(event: E) -> None:
        """
        Cancel selection.
        """
        event.current_buffer.exit_selection()

    @handle('c-w', filter=has_selection)
    @handle('c-x', 'r', 'k', filter=has_selection)
    def _(event: E) -> None:
        """
        Cut selected text.
        """
        data = event.current_buffer.cut_selection()
        event.app.clipboard.set_data(data)

    @handle('escape', 'w', filter=has_selection)
    def _(event: E) -> None:
        """
        Copy selected text.
        """
        data = event.current_buffer.copy_selection()
        event.app.clipboard.set_data(data)

    @handle('escape', 'left')
    def _(event: E) -> None:
        """
        Cursor to start of previous word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_previous_word_beginning(
            count=event.arg) or 0

    @handle('escape', 'right')
    def _(event: E) -> None:
        """
        Cursor to start of next word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \
            buffer.document.get_end_of_document_position()

    @handle('escape', '/', filter=insert_mode)
    def _(event: E) -> None:
        """
        M-/: Complete.
        """
        b = event.current_buffer
        if b.complete_state:
            b.complete_next()
        else:
            b.start_completion(select_first=True)

    @handle('c-c', '>', filter=has_selection)
    def _(event: E) -> None:
        """
        Indent selected text.
        """
        buffer = event.current_buffer

        buffer.cursor_position += buffer.document.get_start_of_line_position(
            after_whitespace=True)

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        indent(buffer, from_, to + 1, count=event.arg)

    @handle('c-c', '<', filter=has_selection)
    def _(event: E) -> None:
        """
        Unindent selected text.
        """
        buffer = event.current_buffer

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        unindent(buffer, from_, to + 1, count=event.arg)

    return ConditionalKeyBindings(key_bindings, emacs_mode)
Exemplo n.º 7
0
# Global wrap lines flag.
wrap_lines = True

# The layout
buff = Buffer(complete_while_typing=True)
buff.text = LIPSUM

body = FloatContainer(content=HSplit([
    Window(FormattedTextControl(
        'Press "q" to quit. Press "w" to enable/disable wrapping.'),
           height=1,
           style='reverse'),
    Window(BufferControl(buffer=buff),
           get_line_prefix=get_line_prefix,
           wrap_lines=Condition(lambda: wrap_lines)),
]),
                      floats=[
                          Float(xcursor=True,
                                ycursor=True,
                                content=CompletionsMenu(max_height=16,
                                                        scroll_offset=1))
                      ])

# Key bindings
kb = KeyBindings()


@kb.add('q')
@kb.add('c-c')
def _(event):
Exemplo n.º 8
0
    def __init__(self, body: AnyContainer, menu_items: List['MenuItem'],
                 floats: Optional[List[Float]] = None,
                 key_bindings: Optional[KeyBindingsBase] = None) -> None:

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

        # Key bindings.
        kb = KeyBindings()

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

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

        # Navigation through the main menu.

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

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

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

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

        # Sub menu navigation.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                # --
            ] + (floats or []),
            key_bindings=key_bindings,
        )
Exemplo n.º 9
0
    def __init__(
            self,
            layout: Optional[Layout] = None,
            style: Optional[BaseStyle] = None,
            include_default_pygments_style: FilterOrBool = True,
            style_transformation: Optional[StyleTransformation] = None,
            key_bindings: Optional[KeyBindingsBase] = None,
            clipboard: Optional[Clipboard] = None,
            full_screen: bool = False,
            color_depth: Union[ColorDepth, Callable[[], Union[ColorDepth,
                                                              None]],
                               None] = None,
            mouse_support: FilterOrBool = False,
            enable_page_navigation_bindings: Optional[
                FilterOrBool] = None,  # Can be None, True or False.
            paste_mode: FilterOrBool = False,
            editing_mode: EditingMode = EditingMode.EMACS,
            erase_when_done: bool = False,
            reverse_vi_search_direction: FilterOrBool = False,
            min_redraw_interval: Union[float, int, None] = None,
            max_render_postpone_time: Union[float, int, None] = .01,
            refresh_interval: Optional[float] = None,
            on_reset: Optional[ApplicationEventHandler] = None,
            on_invalidate: Optional[ApplicationEventHandler] = None,
            before_render: Optional[ApplicationEventHandler] = None,
            after_render: Optional[ApplicationEventHandler] = None,

            # I/O.
            input: Optional[Input] = None,
            output: Optional[Output] = None):

        # If `enable_page_navigation_bindings` is not specified, enable it in
        # case of full screen applications only. This can be overridden by the user.
        if enable_page_navigation_bindings is None:
            enable_page_navigation_bindings = Condition(
                lambda: self.full_screen)

        paste_mode = to_filter(paste_mode)
        mouse_support = to_filter(mouse_support)
        reverse_vi_search_direction = to_filter(reverse_vi_search_direction)
        enable_page_navigation_bindings = to_filter(
            enable_page_navigation_bindings)
        include_default_pygments_style = to_filter(
            include_default_pygments_style)

        if layout is None:
            layout = create_dummy_layout()

        if style_transformation is None:
            style_transformation = DummyStyleTransformation()

        self.style = style
        self.style_transformation = style_transformation

        # Key bindings.
        self.key_bindings = key_bindings
        self._default_bindings = load_key_bindings()
        self._page_navigation_bindings = load_page_navigation_bindings()

        self.layout = layout
        self.clipboard = clipboard or InMemoryClipboard()
        self.full_screen: bool = full_screen
        self._color_depth = color_depth
        self.mouse_support = mouse_support

        self.paste_mode = paste_mode
        self.editing_mode = editing_mode
        self.erase_when_done = erase_when_done
        self.reverse_vi_search_direction = reverse_vi_search_direction
        self.enable_page_navigation_bindings = enable_page_navigation_bindings
        self.min_redraw_interval = min_redraw_interval
        self.max_render_postpone_time = max_render_postpone_time
        self.refresh_interval = refresh_interval

        # Events.
        self.on_invalidate = Event(self, on_invalidate)
        self.on_reset = Event(self, on_reset)
        self.before_render = Event(self, before_render)
        self.after_render = Event(self, after_render)

        # I/O.
        session = get_app_session()
        self.output = output or session.output
        self.input = input or session.input

        # List of 'extra' functions to execute before a Application.run.
        self.pre_run_callables: List[Callable[[], None]] = []

        self._is_running = False
        self.future: Optional[Future[_AppResult]] = None
        self.loop: Optional[AbstractEventLoop] = None
        self.context: Optional[contextvars.Context] = None

        #: Quoted insert. This flag is set if we go into quoted insert mode.
        self.quoted_insert = False

        #: Vi state. (For Vi key bindings.)
        self.vi_state = ViState()
        self.emacs_state = EmacsState()

        #: When to flush the input (For flushing escape keys.) This is important
        #: on terminals that use vt100 input. We can't distinguish the escape
        #: key from for instance the left-arrow key, if we don't know what follows
        #: after "\x1b". This little timer will consider "\x1b" to be escape if
        #: nothing did follow in this time span.
        #: This seems to work like the `ttimeoutlen` option in Vim.
        self.ttimeoutlen = .5  # Seconds.

        #: Like Vim's `timeoutlen` option. This can be `None` or a float.  For
        #: instance, suppose that we have a key binding AB and a second key
        #: binding A. If the uses presses A and then waits, we don't handle
        #: this binding yet (unless it was marked 'eager'), because we don't
        #: know what will follow. This timeout is the maximum amount of time
        #: that we wait until we call the handlers anyway. Pass `None` to
        #: disable this timeout.
        self.timeoutlen = 1.0

        #: The `Renderer` instance.
        # Make sure that the same stdout is used, when a custom renderer has been passed.
        self._merged_style = self._create_merged_style(
            include_default_pygments_style)

        self.renderer = Renderer(
            self._merged_style,
            self.output,
            self.input,
            full_screen=full_screen,
            mouse_support=mouse_support,
            cpr_not_supported_callback=self.cpr_not_supported_callback)

        #: Render counter. This one is increased every time the UI is rendered.
        #: It can be used as a key for caching certain information during one
        #: rendering.
        self.render_counter = 0

        # Invalidate flag. When 'True', a repaint has been scheduled.
        self._invalidated = False
        self._invalidate_events: List[Event[object]] = [
        ]  # Collection of 'invalidate' Event objects.
        self._last_redraw_time = 0.0  # Unix timestamp of last redraw. Used when
        # `min_redraw_interval` is given.

        #: The `InputProcessor` instance.
        self.key_processor = KeyProcessor(_CombinedRegistry(self))

        # If `run_in_terminal` was called. This will point to a `Future` what will be
        # set at the point when the previous run finishes.
        self._running_in_terminal = False
        self._running_in_terminal_f: Optional[Future[None]] = None

        # Trigger initialize callback.
        self.reset()
Exemplo n.º 10
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=.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=.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
Exemplo n.º 11
0
def test_invert():
    assert not (~Always())()
    assert (~Never()())

    c = ~Condition(lambda: False)
    assert c()
Exemplo n.º 12
0

body = HSplit([
    text_field,
    search_toolbar,
    ConditionalContainer(
        content=VSplit([
            Window(FormattedTextControl(get_statusbar_text),
                   style='class:status'),
            Window(FormattedTextControl(get_statusbar_right_text),
                   style='class:status.right',
                   width=9,
                   align=WindowAlign.RIGHT),
        ],
                       height=1),
        filter=Condition(lambda: ApplicationState.show_status_bar)),
])

# Global key bindings.
bindings = KeyBindings()


@bindings.add('c-c')
def _(event):
    " Focus menu. "
    event.app.layout.focus(root_container.window)


#
# Handlers for menu items.
#