diff options
| author | shadchin <[email protected]> | 2022-02-10 16:44:30 +0300 | 
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:44:30 +0300 | 
| commit | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch) | |
| tree | 012bb94d777798f1f56ac1cec429509766d05181 /contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets | |
| parent | 6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff) | |
Restoring authorship annotation for <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets')
5 files changed, 1861 insertions, 1861 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/__init__.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/__init__.py index 552d3559488..a7559ebd0fd 100644 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/__init__.py +++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/__init__.py @@ -1,60 +1,60 @@ -""" -Collection of reusable components for building full screen applications. -These are higher level abstractions on top of the `prompt_toolkit.layout` -module. - -Most of these widgets implement the ``__pt_container__`` method, which makes it -possible to embed these in the layout like any other container. -""" -from .base import ( -    Box, -    Button, -    Checkbox, -    CheckboxList, -    Frame, -    HorizontalLine, -    Label, -    ProgressBar, -    RadioList, -    Shadow, -    TextArea, -    VerticalLine, -) -from .dialogs import Dialog -from .menus import MenuContainer, MenuItem -from .toolbars import ( -    ArgToolbar, -    CompletionsToolbar, -    FormattedTextToolbar, -    SearchToolbar, -    SystemToolbar, -    ValidationToolbar, -) - -__all__ = [ -    # Base. -    "TextArea", -    "Label", -    "Button", -    "Frame", -    "Shadow", -    "Box", -    "VerticalLine", -    "HorizontalLine", -    "CheckboxList", -    "RadioList", -    "Checkbox", -    "ProgressBar", -    # Toolbars. -    "ArgToolbar", -    "CompletionsToolbar", -    "FormattedTextToolbar", -    "SearchToolbar", -    "SystemToolbar", -    "ValidationToolbar", -    # Dialogs. -    "Dialog", -    # Menus. -    "MenuContainer", -    "MenuItem", -] +"""  +Collection of reusable components for building full screen applications.  +These are higher level abstractions on top of the `prompt_toolkit.layout`  +module.  +  +Most of these widgets implement the ``__pt_container__`` method, which makes it  +possible to embed these in the layout like any other container.  +"""  +from .base import (  +    Box,  +    Button,  +    Checkbox,  +    CheckboxList,  +    Frame,  +    HorizontalLine,  +    Label,  +    ProgressBar,  +    RadioList,  +    Shadow,  +    TextArea,  +    VerticalLine,  +)  +from .dialogs import Dialog  +from .menus import MenuContainer, MenuItem  +from .toolbars import (  +    ArgToolbar,  +    CompletionsToolbar,  +    FormattedTextToolbar,  +    SearchToolbar,  +    SystemToolbar,  +    ValidationToolbar,  +)  +  +__all__ = [  +    # Base.  +    "TextArea",  +    "Label",  +    "Button",  +    "Frame",  +    "Shadow",  +    "Box",  +    "VerticalLine",  +    "HorizontalLine",  +    "CheckboxList",  +    "RadioList",  +    "Checkbox",  +    "ProgressBar",  +    # Toolbars.  +    "ArgToolbar",  +    "CompletionsToolbar",  +    "FormattedTextToolbar",  +    "SearchToolbar",  +    "SystemToolbar",  +    "ValidationToolbar",  +    # Dialogs.  +    "Dialog",  +    # Menus.  +    "MenuContainer",  +    "MenuItem",  +]  diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/base.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/base.py index 728190b54c2..c059872793d 100644 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/base.py +++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/base.py @@ -1,949 +1,949 @@ -""" -Collection of reusable components for building full screen applications. - -All of these widgets implement the ``__pt_container__`` method, which makes -them usable in any situation where we are expecting a `prompt_toolkit` -container object. - -.. warning:: - -    At this point, the API for these widgets is considered unstable, and can -    potentially change between minor releases (we try not too, but no -    guarantees are made yet). The public API in -    `prompt_toolkit.shortcuts.dialogs` on the other hand is considered stable. -""" -from functools import partial -from typing import Callable, Generic, List, Optional, Sequence, Tuple, TypeVar, Union - -from prompt_toolkit.application.current import get_app -from prompt_toolkit.auto_suggest import AutoSuggest, DynamicAutoSuggest -from prompt_toolkit.buffer import Buffer, BufferAcceptHandler -from prompt_toolkit.completion import Completer, DynamicCompleter -from prompt_toolkit.document import Document -from prompt_toolkit.filters import ( -    Condition, -    FilterOrBool, -    has_focus, -    is_done, -    is_true, -    to_filter, -) -from prompt_toolkit.formatted_text import ( -    AnyFormattedText, -    StyleAndTextTuples, -    Template, -    to_formatted_text, -) -from prompt_toolkit.formatted_text.utils import fragment_list_to_text -from prompt_toolkit.history import History -from prompt_toolkit.key_binding.key_bindings import KeyBindings -from prompt_toolkit.key_binding.key_processor import KeyPressEvent -from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.containers import ( -    AnyContainer, -    ConditionalContainer, -    Container, -    DynamicContainer, -    Float, -    FloatContainer, -    HSplit, -    VSplit, -    Window, -    WindowAlign, -) -from prompt_toolkit.layout.controls import ( -    BufferControl, -    FormattedTextControl, -    GetLinePrefixCallable, -) -from prompt_toolkit.layout.dimension import AnyDimension -from prompt_toolkit.layout.dimension import Dimension as D -from prompt_toolkit.layout.dimension import to_dimension -from prompt_toolkit.layout.margins import ( -    ConditionalMargin, -    NumberedMargin, -    ScrollbarMargin, -) -from prompt_toolkit.layout.processors import ( -    AppendAutoSuggestion, -    BeforeInput, -    ConditionalProcessor, -    PasswordProcessor, -    Processor, -) -from prompt_toolkit.lexers import DynamicLexer, Lexer -from prompt_toolkit.mouse_events import MouseEvent, MouseEventType -from prompt_toolkit.utils import get_cwidth -from prompt_toolkit.validation import DynamicValidator, Validator - -from .toolbars import SearchToolbar - -__all__ = [ -    "TextArea", -    "Label", -    "Button", -    "Frame", -    "Shadow", -    "Box", -    "VerticalLine", -    "HorizontalLine", -    "RadioList", -    "CheckboxList", -    "Checkbox",  # backward compatibility -    "ProgressBar", -] - -E = KeyPressEvent - - -class Border: -    "Box drawing characters. (Thin)" -    HORIZONTAL = "\u2500" -    VERTICAL = "\u2502" -    TOP_LEFT = "\u250c" -    TOP_RIGHT = "\u2510" -    BOTTOM_LEFT = "\u2514" -    BOTTOM_RIGHT = "\u2518" - - -class TextArea: -    """ -    A simple input field. - -    This is a higher level abstraction on top of several other classes with -    sane defaults. - -    This widget does have the most common options, but it does not intend to -    cover every single use case. For more configurations options, you can -    always build a text area manually, using a -    :class:`~prompt_toolkit.buffer.Buffer`, -    :class:`~prompt_toolkit.layout.BufferControl` and -    :class:`~prompt_toolkit.layout.Window`. - -    Buffer attributes: - -    :param text: The initial text. -    :param multiline: If True, allow multiline input. -    :param completer: :class:`~prompt_toolkit.completion.Completer` instance -        for auto completion. -    :param complete_while_typing: Boolean. -    :param accept_handler: Called when `Enter` is pressed (This should be a -        callable that takes a buffer as input). -    :param history: :class:`~prompt_toolkit.history.History` instance. -    :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest` -        instance for input suggestions. - -    BufferControl attributes: - -    :param password: When `True`, display using asterisks. -    :param focusable: When `True`, allow this widget to receive the focus. -    :param focus_on_click: When `True`, focus after mouse click. -    :param input_processors: `None` or a list of -        :class:`~prompt_toolkit.layout.Processor` objects. -    :param validator: `None` or a :class:`~prompt_toolkit.validation.Validator` -        object. - -    Window attributes: - -    :param lexer: :class:`~prompt_toolkit.lexers.Lexer` instance for syntax -        highlighting. -    :param wrap_lines: When `True`, don't scroll horizontally, but wrap lines. -    :param width: Window width. (:class:`~prompt_toolkit.layout.Dimension` object.) -    :param height: Window height. (:class:`~prompt_toolkit.layout.Dimension` object.) -    :param scrollbar: When `True`, display a scroll bar. -    :param style: A style string. -    :param dont_extend_width: When `True`, don't take up more width then the -                              preferred width reported by the control. -    :param dont_extend_height: When `True`, don't take up more width then the -                               preferred height reported by the control. -    :param get_line_prefix: None or a callable that returns formatted text to -        be inserted before a line. It takes a line number (int) and a -        wrap_count and returns formatted text. This can be used for -        implementation of line continuations, things like Vim "breakindent" and -        so on. - -    Other attributes: - -    :param search_field: An optional `SearchToolbar` object. -    """ - -    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, -        validator: Optional[Validator] = None, -        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.validator = validator - -        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) -            ), -            validator=DynamicValidator(lambda: self.validator), -            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 - -        # If no height was given, guarantee height of at least 1. -        if height is None: -            height = D(min=1) - -        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, -        ) - -    @property -    def text(self) -> str: -        """ -        The `Buffer` text. -        """ -        return self.buffer.text - -    @text.setter -    def text(self, value: str) -> None: -        self.document = Document(value, 0) - -    @property -    def document(self) -> Document: -        """ -        The `Buffer` document (text + cursor position). -        """ -        return self.buffer.document - -    @document.setter -    def document(self, value: Document) -> None: -        self.buffer.set_document(value, bypass_readonly=True) - -    @property -    def accept_handler(self) -> Optional[BufferAcceptHandler]: -        """ -        The accept handler. Called when the user accepts the input. -        """ -        return self.buffer.accept_handler - -    @accept_handler.setter -    def accept_handler(self, value: BufferAcceptHandler) -> None: -        self.buffer.accept_handler = value - -    def __pt_container__(self) -> Container: -        return self.window - - -class Label: -    """ -    Widget that displays the given text. It is not editable or focusable. - -    :param text: Text to display. Can be multiline. All value types accepted by -        :class:`prompt_toolkit.layout.FormattedTextControl` are allowed, -        including a callable. -    :param style: A style string. -    :param width: When given, use this width, rather than calculating it from -        the text size. -    :param dont_extend_width: When `True`, don't take up more width than -                              preferred, i.e. the length of the longest line of -                              the text, or value of `width` parameter, if -                              given. `True` by default -    :param dont_extend_height: When `True`, don't take up more width than the -                               preferred height, i.e. the number of lines of -                               the text. `False` by default. -    """ - -    def __init__( -        self, -        text: AnyFormattedText, -        style: str = "", -        width: AnyDimension = None, -        dont_extend_height: bool = True, -        dont_extend_width: bool = False, +"""  +Collection of reusable components for building full screen applications.  +  +All of these widgets implement the ``__pt_container__`` method, which makes  +them usable in any situation where we are expecting a `prompt_toolkit`  +container object.  +  +.. warning::  +  +    At this point, the API for these widgets is considered unstable, and can  +    potentially change between minor releases (we try not too, but no  +    guarantees are made yet). The public API in  +    `prompt_toolkit.shortcuts.dialogs` on the other hand is considered stable.  +"""  +from functools import partial  +from typing import Callable, Generic, List, Optional, Sequence, Tuple, TypeVar, Union  +  +from prompt_toolkit.application.current import get_app  +from prompt_toolkit.auto_suggest import AutoSuggest, DynamicAutoSuggest  +from prompt_toolkit.buffer import Buffer, BufferAcceptHandler  +from prompt_toolkit.completion import Completer, DynamicCompleter  +from prompt_toolkit.document import Document  +from prompt_toolkit.filters import (  +    Condition,  +    FilterOrBool,  +    has_focus,  +    is_done,  +    is_true,  +    to_filter,  +)  +from prompt_toolkit.formatted_text import (  +    AnyFormattedText,  +    StyleAndTextTuples,  +    Template,  +    to_formatted_text,  +)  +from prompt_toolkit.formatted_text.utils import fragment_list_to_text  +from prompt_toolkit.history import History  +from prompt_toolkit.key_binding.key_bindings import KeyBindings  +from prompt_toolkit.key_binding.key_processor import KeyPressEvent  +from prompt_toolkit.keys import Keys  +from prompt_toolkit.layout.containers import (  +    AnyContainer,  +    ConditionalContainer,  +    Container,  +    DynamicContainer,  +    Float,  +    FloatContainer,  +    HSplit,  +    VSplit,  +    Window,  +    WindowAlign,  +)  +from prompt_toolkit.layout.controls import (  +    BufferControl,  +    FormattedTextControl,  +    GetLinePrefixCallable,  +)  +from prompt_toolkit.layout.dimension import AnyDimension  +from prompt_toolkit.layout.dimension import Dimension as D  +from prompt_toolkit.layout.dimension import to_dimension  +from prompt_toolkit.layout.margins import (  +    ConditionalMargin,  +    NumberedMargin,  +    ScrollbarMargin,  +)  +from prompt_toolkit.layout.processors import (  +    AppendAutoSuggestion,  +    BeforeInput,  +    ConditionalProcessor,  +    PasswordProcessor,  +    Processor,  +)  +from prompt_toolkit.lexers import DynamicLexer, Lexer  +from prompt_toolkit.mouse_events import MouseEvent, MouseEventType  +from prompt_toolkit.utils import get_cwidth  +from prompt_toolkit.validation import DynamicValidator, Validator  +  +from .toolbars import SearchToolbar  +  +__all__ = [  +    "TextArea",  +    "Label",  +    "Button",  +    "Frame",  +    "Shadow",  +    "Box",  +    "VerticalLine",  +    "HorizontalLine",  +    "RadioList",  +    "CheckboxList",  +    "Checkbox",  # backward compatibility  +    "ProgressBar",  +]  +  +E = KeyPressEvent  +  +  +class Border:  +    "Box drawing characters. (Thin)"  +    HORIZONTAL = "\u2500"  +    VERTICAL = "\u2502"  +    TOP_LEFT = "\u250c"  +    TOP_RIGHT = "\u2510"  +    BOTTOM_LEFT = "\u2514"  +    BOTTOM_RIGHT = "\u2518"  +  +  +class TextArea:  +    """  +    A simple input field.  +  +    This is a higher level abstraction on top of several other classes with  +    sane defaults.  +  +    This widget does have the most common options, but it does not intend to  +    cover every single use case. For more configurations options, you can  +    always build a text area manually, using a  +    :class:`~prompt_toolkit.buffer.Buffer`,  +    :class:`~prompt_toolkit.layout.BufferControl` and  +    :class:`~prompt_toolkit.layout.Window`.  +  +    Buffer attributes:  +  +    :param text: The initial text.  +    :param multiline: If True, allow multiline input.  +    :param completer: :class:`~prompt_toolkit.completion.Completer` instance  +        for auto completion.  +    :param complete_while_typing: Boolean.  +    :param accept_handler: Called when `Enter` is pressed (This should be a  +        callable that takes a buffer as input).  +    :param history: :class:`~prompt_toolkit.history.History` instance.  +    :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest`  +        instance for input suggestions.  +  +    BufferControl attributes:  +  +    :param password: When `True`, display using asterisks.  +    :param focusable: When `True`, allow this widget to receive the focus.  +    :param focus_on_click: When `True`, focus after mouse click.  +    :param input_processors: `None` or a list of  +        :class:`~prompt_toolkit.layout.Processor` objects.  +    :param validator: `None` or a :class:`~prompt_toolkit.validation.Validator`  +        object.  +  +    Window attributes:  +  +    :param lexer: :class:`~prompt_toolkit.lexers.Lexer` instance for syntax  +        highlighting.  +    :param wrap_lines: When `True`, don't scroll horizontally, but wrap lines.  +    :param width: Window width. (:class:`~prompt_toolkit.layout.Dimension` object.)  +    :param height: Window height. (:class:`~prompt_toolkit.layout.Dimension` object.)  +    :param scrollbar: When `True`, display a scroll bar.  +    :param style: A style string.  +    :param dont_extend_width: When `True`, don't take up more width then the  +                              preferred width reported by the control.  +    :param dont_extend_height: When `True`, don't take up more width then the  +                               preferred height reported by the control.  +    :param get_line_prefix: None or a callable that returns formatted text to  +        be inserted before a line. It takes a line number (int) and a  +        wrap_count and returns formatted text. This can be used for  +        implementation of line continuations, things like Vim "breakindent" and  +        so on.  +  +    Other attributes:  +  +    :param search_field: An optional `SearchToolbar` object.  +    """  +  +    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,  +        validator: Optional[Validator] = None,  +        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.validator = validator  +  +        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)  +            ),  +            validator=DynamicValidator(lambda: self.validator),  +            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  +  +        # If no height was given, guarantee height of at least 1.  +        if height is None:  +            height = D(min=1)  +  +        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,  +        )  +  +    @property  +    def text(self) -> str:  +        """  +        The `Buffer` text.  +        """  +        return self.buffer.text  +  +    @text.setter  +    def text(self, value: str) -> None:  +        self.document = Document(value, 0)  +  +    @property  +    def document(self) -> Document:  +        """  +        The `Buffer` document (text + cursor position).  +        """  +        return self.buffer.document  +  +    @document.setter  +    def document(self, value: Document) -> None:  +        self.buffer.set_document(value, bypass_readonly=True)  +  +    @property  +    def accept_handler(self) -> Optional[BufferAcceptHandler]:  +        """  +        The accept handler. Called when the user accepts the input.  +        """  +        return self.buffer.accept_handler  +  +    @accept_handler.setter  +    def accept_handler(self, value: BufferAcceptHandler) -> None:  +        self.buffer.accept_handler = value  +  +    def __pt_container__(self) -> Container:  +        return self.window  +  +  +class Label:  +    """  +    Widget that displays the given text. It is not editable or focusable.  +  +    :param text: Text to display. Can be multiline. All value types accepted by  +        :class:`prompt_toolkit.layout.FormattedTextControl` are allowed,  +        including a callable.  +    :param style: A style string.  +    :param width: When given, use this width, rather than calculating it from  +        the text size.  +    :param dont_extend_width: When `True`, don't take up more width than  +                              preferred, i.e. the length of the longest line of  +                              the text, or value of `width` parameter, if  +                              given. `True` by default  +    :param dont_extend_height: When `True`, don't take up more width than the  +                               preferred height, i.e. the number of lines of  +                               the text. `False` by default.  +    """  +  +    def __init__(  +        self,  +        text: AnyFormattedText,  +        style: str = "",  +        width: AnyDimension = None,  +        dont_extend_height: bool = True,  +        dont_extend_width: bool = False,           align: Union[WindowAlign, Callable[[], WindowAlign]] = WindowAlign.LEFT, -    ) -> None: - -        self.text = text - -        def get_width() -> AnyDimension: -            if width is None: -                text_fragments = to_formatted_text(self.text) -                text = fragment_list_to_text(text_fragments) -                if text: -                    longest_line = max(get_cwidth(line) for line in text.splitlines()) -                else: -                    return D(preferred=0) -                return D(preferred=longest_line) -            else: -                return width - -        self.formatted_text_control = FormattedTextControl(text=lambda: self.text) - -        self.window = Window( -            content=self.formatted_text_control, -            width=get_width, -            height=D(min=1), -            style="class:label " + style, -            dont_extend_height=dont_extend_height, -            dont_extend_width=dont_extend_width, +    ) -> None:  +  +        self.text = text  +  +        def get_width() -> AnyDimension:  +            if width is None:  +                text_fragments = to_formatted_text(self.text)  +                text = fragment_list_to_text(text_fragments)  +                if text:  +                    longest_line = max(get_cwidth(line) for line in text.splitlines())  +                else:  +                    return D(preferred=0)  +                return D(preferred=longest_line)  +            else:  +                return width  +  +        self.formatted_text_control = FormattedTextControl(text=lambda: self.text)  +  +        self.window = Window(  +            content=self.formatted_text_control,  +            width=get_width,  +            height=D(min=1),  +            style="class:label " + style,  +            dont_extend_height=dont_extend_height,  +            dont_extend_width=dont_extend_width,               align=align, -        ) - -    def __pt_container__(self) -> Container: -        return self.window - - -class Button: -    """ -    Clickable button. - -    :param text: The caption for the button. -    :param handler: `None` or callable. Called when the button is clicked. No -        parameters are passed to this callable. Use for instance Python's -        `functools.partial` to pass parameters to this callable if needed. -    :param width: Width of the button. -    """ - -    def __init__( -        self, -        text: str, -        handler: Optional[Callable[[], None]] = None, -        width: int = 12, -        left_symbol: str = "<", -        right_symbol: str = ">", -    ) -> None: - -        self.text = text -        self.left_symbol = left_symbol -        self.right_symbol = right_symbol -        self.handler = handler -        self.width = width -        self.control = FormattedTextControl( -            self._get_text_fragments, -            key_bindings=self._get_key_bindings(), -            focusable=True, -        ) - -        def get_style() -> str: -            if get_app().layout.has_focus(self): -                return "class:button.focused" -            else: -                return "class:button" - -        # Note: `dont_extend_width` is False, because we want to allow buttons -        #       to take more space if the parent container provides more space. -        #       Otherwise, we will also truncate the text. -        #       Probably we need a better way here to adjust to width of the -        #       button to the text. - -        self.window = Window( -            self.control, -            align=WindowAlign.CENTER, -            height=1, -            width=width, -            style=get_style, -            dont_extend_width=False, -            dont_extend_height=True, -        ) - -    def _get_text_fragments(self) -> StyleAndTextTuples: -        width = self.width - ( -            get_cwidth(self.left_symbol) + get_cwidth(self.right_symbol) -        ) -        text = ("{{:^{}}}".format(width)).format(self.text) - -        def handler(mouse_event: MouseEvent) -> None: -            if ( -                self.handler is not None -                and mouse_event.event_type == MouseEventType.MOUSE_UP -            ): -                self.handler() - -        return [ -            ("class:button.arrow", self.left_symbol, handler), -            ("[SetCursorPosition]", ""), -            ("class:button.text", text, handler), -            ("class:button.arrow", self.right_symbol, handler), -        ] - -    def _get_key_bindings(self) -> KeyBindings: -        "Key bindings for the Button." -        kb = KeyBindings() - -        @kb.add(" ") -        @kb.add("enter") -        def _(event: E) -> None: -            if self.handler is not None: -                self.handler() - -        return kb - -    def __pt_container__(self) -> Container: -        return self.window - - -class Frame: -    """ -    Draw a border around any container, optionally with a title text. - -    Changing the title and body of the frame is possible at runtime by -    assigning to the `body` and `title` attributes of this class. - -    :param body: Another container object. -    :param title: Text to be displayed in the top of the frame (can be formatted text). -    :param style: Style string to be applied to this widget. -    """ - -    def __init__( -        self, -        body: AnyContainer, -        title: AnyFormattedText = "", -        style: str = "", -        width: AnyDimension = None, -        height: AnyDimension = None, -        key_bindings: Optional[KeyBindings] = None, -        modal: bool = False, -    ) -> None: - -        self.title = title -        self.body = body - -        fill = partial(Window, style="class:frame.border") -        style = "class:frame " + style - -        top_row_with_title = VSplit( -            [ -                fill(width=1, height=1, char=Border.TOP_LEFT), -                fill(char=Border.HORIZONTAL), -                fill(width=1, height=1, char="|"), -                # Notice: we use `Template` here, because `self.title` can be an -                # `HTML` object for instance. -                Label( -                    lambda: Template(" {} ").format(self.title), -                    style="class:frame.label", -                    dont_extend_width=True, -                ), -                fill(width=1, height=1, char="|"), -                fill(char=Border.HORIZONTAL), -                fill(width=1, height=1, char=Border.TOP_RIGHT), -            ], -            height=1, -        ) - -        top_row_without_title = VSplit( -            [ -                fill(width=1, height=1, char=Border.TOP_LEFT), -                fill(char=Border.HORIZONTAL), -                fill(width=1, height=1, char=Border.TOP_RIGHT), -            ], -            height=1, -        ) - -        @Condition -        def has_title() -> bool: -            return bool(self.title) - -        self.container = HSplit( -            [ -                ConditionalContainer(content=top_row_with_title, filter=has_title), -                ConditionalContainer(content=top_row_without_title, filter=~has_title), -                VSplit( -                    [ -                        fill(width=1, char=Border.VERTICAL), -                        DynamicContainer(lambda: self.body), -                        fill(width=1, char=Border.VERTICAL), -                        # Padding is required to make sure that if the content is -                        # too small, the right frame border is still aligned. -                    ], -                    padding=0, -                ), -                VSplit( -                    [ -                        fill(width=1, height=1, char=Border.BOTTOM_LEFT), -                        fill(char=Border.HORIZONTAL), -                        fill(width=1, height=1, char=Border.BOTTOM_RIGHT), -                    ], -                    # specifying height here will increase the rendering speed. -                    height=1, -                ), -            ], -            width=width, -            height=height, -            style=style, -            key_bindings=key_bindings, -            modal=modal, -        ) - -    def __pt_container__(self) -> Container: -        return self.container - - -class Shadow: -    """ -    Draw a shadow underneath/behind this container. -    (This applies `class:shadow` the the cells under the shadow. The Style -    should define the colors for the shadow.) - -    :param body: Another container object. -    """ - -    def __init__(self, body: AnyContainer) -> None: -        self.container = FloatContainer( -            content=body, -            floats=[ -                Float( -                    bottom=-1, -                    height=1, -                    left=1, -                    right=-1, -                    transparent=True, -                    content=Window(style="class:shadow"), -                ), -                Float( -                    bottom=-1, -                    top=1, -                    width=1, -                    right=-1, -                    transparent=True, -                    content=Window(style="class:shadow"), -                ), -            ], -        ) - -    def __pt_container__(self) -> Container: -        return self.container - - -class Box: -    """ -    Add padding around a container. - -    This also makes sure that the parent can provide more space than required by -    the child. This is very useful when wrapping a small element with a fixed -    size into a ``VSplit`` or ``HSplit`` object. The ``HSplit`` and ``VSplit`` -    try to make sure to adapt respectively the width and height, possibly -    shrinking other elements. Wrapping something in a ``Box`` makes it flexible. - -    :param body: Another container object. -    :param padding: The margin to be used around the body. This can be -        overridden by `padding_left`, padding_right`, `padding_top` and -        `padding_bottom`. -    :param style: A style string. -    :param char: Character to be used for filling the space around the body. -        (This is supposed to be a character with a terminal width of 1.) -    """ - -    def __init__( -        self, -        body: AnyContainer, -        padding: AnyDimension = None, -        padding_left: AnyDimension = None, -        padding_right: AnyDimension = None, -        padding_top: AnyDimension = None, -        padding_bottom: AnyDimension = None, -        width: AnyDimension = None, -        height: AnyDimension = None, -        style: str = "", -        char: Union[None, str, Callable[[], str]] = None, -        modal: bool = False, -        key_bindings: Optional[KeyBindings] = None, -    ) -> None: - -        if padding is None: -            padding = D(preferred=0) - -        def get(value: AnyDimension) -> D: -            if value is None: -                value = padding -            return to_dimension(value) - -        self.padding_left = get(padding_left) -        self.padding_right = get(padding_right) -        self.padding_top = get(padding_top) -        self.padding_bottom = get(padding_bottom) -        self.body = body - -        self.container = HSplit( -            [ -                Window(height=self.padding_top, char=char), -                VSplit( -                    [ -                        Window(width=self.padding_left, char=char), -                        body, -                        Window(width=self.padding_right, char=char), -                    ] -                ), -                Window(height=self.padding_bottom, char=char), -            ], -            width=width, -            height=height, -            style=style, -            modal=modal, -            key_bindings=None, -        ) - -    def __pt_container__(self) -> Container: -        return self.container - - -_T = TypeVar("_T") - - -class _DialogList(Generic[_T]): -    """ -    Common code for `RadioList` and `CheckboxList`. -    """ - -    open_character: str = "" -    close_character: str = "" -    container_style: str = "" -    default_style: str = "" -    selected_style: str = "" -    checked_style: str = "" -    multiple_selection: bool = False -    show_scrollbar: bool = True - -    def __init__(self, values: Sequence[Tuple[_T, AnyFormattedText]]) -> None: -        assert len(values) > 0 - -        self.values = values -        # current_values will be used in multiple_selection, -        # current_value will be used otherwise. -        self.current_values: List[_T] = [] -        self.current_value: _T = values[0][0] -        self._selected_index = 0 - -        # Key bindings. -        kb = KeyBindings() - -        @kb.add("up") -        def _up(event: E) -> None: -            self._selected_index = max(0, self._selected_index - 1) - -        @kb.add("down") -        def _down(event: E) -> None: -            self._selected_index = min(len(self.values) - 1, self._selected_index + 1) - -        @kb.add("pageup") -        def _pageup(event: E) -> None: -            w = event.app.layout.current_window -            if w.render_info: -                self._selected_index = max( -                    0, self._selected_index - len(w.render_info.displayed_lines) -                ) - -        @kb.add("pagedown") -        def _pagedown(event: E) -> None: -            w = event.app.layout.current_window -            if w.render_info: -                self._selected_index = min( -                    len(self.values) - 1, -                    self._selected_index + len(w.render_info.displayed_lines), -                ) - -        @kb.add("enter") -        @kb.add(" ") -        def _click(event: E) -> None: -            self._handle_enter() - -        @kb.add(Keys.Any) -        def _find(event: E) -> None: -            # We first check values after the selected value, then all values. -            values = list(self.values) -            for value in values[self._selected_index + 1 :] + values: -                text = fragment_list_to_text(to_formatted_text(value[1])).lower() - -                if text.startswith(event.data.lower()): -                    self._selected_index = self.values.index(value) -                    return - -        # Control and window. -        self.control = FormattedTextControl( -            self._get_text_fragments, key_bindings=kb, focusable=True -        ) - -        self.window = Window( -            content=self.control, -            style=self.container_style, -            right_margins=[ -                ConditionalMargin( -                    margin=ScrollbarMargin(display_arrows=True), -                    filter=Condition(lambda: self.show_scrollbar), -                ), -            ], -            dont_extend_height=True, -        ) - -    def _handle_enter(self) -> None: -        if self.multiple_selection: -            val = self.values[self._selected_index][0] -            if val in self.current_values: -                self.current_values.remove(val) -            else: -                self.current_values.append(val) -        else: -            self.current_value = self.values[self._selected_index][0] - -    def _get_text_fragments(self) -> StyleAndTextTuples: -        def mouse_handler(mouse_event: MouseEvent) -> None: -            """ -            Set `_selected_index` and `current_value` according to the y -            position of the mouse click event. -            """ -            if mouse_event.event_type == MouseEventType.MOUSE_UP: -                self._selected_index = mouse_event.position.y -                self._handle_enter() - -        result: StyleAndTextTuples = [] -        for i, value in enumerate(self.values): -            if self.multiple_selection: -                checked = value[0] in self.current_values -            else: -                checked = value[0] == self.current_value -            selected = i == self._selected_index - -            style = "" -            if checked: -                style += " " + self.checked_style -            if selected: -                style += " " + self.selected_style - -            result.append((style, self.open_character)) - -            if selected: -                result.append(("[SetCursorPosition]", "")) - -            if checked: -                result.append((style, "*")) -            else: -                result.append((style, " ")) - -            result.append((style, self.close_character)) -            result.append((self.default_style, " ")) -            result.extend(to_formatted_text(value[1], style=self.default_style)) -            result.append(("", "\n")) - -        # Add mouse handler to all fragments. -        for i in range(len(result)): -            result[i] = (result[i][0], result[i][1], mouse_handler) - -        result.pop()  # Remove last newline. -        return result - -    def __pt_container__(self) -> Container: -        return self.window - - -class RadioList(_DialogList[_T]): -    """ -    List of radio buttons. Only one can be checked at the same time. - -    :param values: List of (value, label) tuples. -    """ - -    open_character = "(" -    close_character = ")" -    container_style = "class:radio-list" -    default_style = "class:radio" -    selected_style = "class:radio-selected" -    checked_style = "class:radio-checked" -    multiple_selection = False - - -class CheckboxList(_DialogList[_T]): -    """ -    List of checkbox buttons. Several can be checked at the same time. - -    :param values: List of (value, label) tuples. -    """ - -    open_character = "[" -    close_character = "]" -    container_style = "class:checkbox-list" -    default_style = "class:checkbox" -    selected_style = "class:checkbox-selected" -    checked_style = "class:checkbox-checked" -    multiple_selection = True - - -class Checkbox(CheckboxList[str]): -    """Backward compatibility util: creates a 1-sized CheckboxList - -    :param text: the text -    """ - -    show_scrollbar = False - -    def __init__(self, text: AnyFormattedText = "", checked: bool = False) -> None: -        values = [("value", text)] -        CheckboxList.__init__(self, values) -        self.checked = checked - -    @property -    def checked(self) -> bool: -        return "value" in self.current_values - -    @checked.setter -    def checked(self, value: bool) -> None: -        if value: -            self.current_values = ["value"] -        else: -            self.current_values = [] - - -class VerticalLine(object): -    """ -    A simple vertical line with a width of 1. -    """ - -    def __init__(self) -> None: -        self.window = Window( -            char=Border.VERTICAL, style="class:line,vertical-line", width=1 -        ) - -    def __pt_container__(self) -> Container: -        return self.window - - -class HorizontalLine: -    """ -    A simple horizontal line with a height of 1. -    """ - -    def __init__(self) -> None: -        self.window = Window( -            char=Border.HORIZONTAL, style="class:line,horizontal-line", height=1 -        ) - -    def __pt_container__(self) -> Container: -        return self.window - - -class ProgressBar: -    def __init__(self) -> None: -        self._percentage = 60 - -        self.label = Label("60%") -        self.container = FloatContainer( -            content=Window(height=1), -            floats=[ -                # We first draw the label, then the actual progress bar.  Right -                # now, this is the only way to have the colors of the progress -                # bar appear on top of the label. The problem is that our label -                # can't be part of any `Window` below. -                Float(content=self.label, top=0, bottom=0), -                Float( -                    left=0, -                    top=0, -                    right=0, -                    bottom=0, -                    content=VSplit( -                        [ -                            Window( -                                style="class:progress-bar.used", -                                width=lambda: D(weight=int(self._percentage)), -                            ), -                            Window( -                                style="class:progress-bar", -                                width=lambda: D(weight=int(100 - self._percentage)), -                            ), -                        ] -                    ), -                ), -            ], -        ) - -    @property -    def percentage(self) -> int: -        return self._percentage - -    @percentage.setter -    def percentage(self, value: int) -> None: -        self._percentage = value -        self.label.text = "{0}%".format(value) - -    def __pt_container__(self) -> Container: -        return self.container +        )  +  +    def __pt_container__(self) -> Container:  +        return self.window  +  +  +class Button:  +    """  +    Clickable button.  +  +    :param text: The caption for the button.  +    :param handler: `None` or callable. Called when the button is clicked. No  +        parameters are passed to this callable. Use for instance Python's  +        `functools.partial` to pass parameters to this callable if needed.  +    :param width: Width of the button.  +    """  +  +    def __init__(  +        self,  +        text: str,  +        handler: Optional[Callable[[], None]] = None,  +        width: int = 12,  +        left_symbol: str = "<",  +        right_symbol: str = ">",  +    ) -> None:  +  +        self.text = text  +        self.left_symbol = left_symbol  +        self.right_symbol = right_symbol  +        self.handler = handler  +        self.width = width  +        self.control = FormattedTextControl(  +            self._get_text_fragments,  +            key_bindings=self._get_key_bindings(),  +            focusable=True,  +        )  +  +        def get_style() -> str:  +            if get_app().layout.has_focus(self):  +                return "class:button.focused"  +            else:  +                return "class:button"  +  +        # Note: `dont_extend_width` is False, because we want to allow buttons  +        #       to take more space if the parent container provides more space.  +        #       Otherwise, we will also truncate the text.  +        #       Probably we need a better way here to adjust to width of the  +        #       button to the text.  +  +        self.window = Window(  +            self.control,  +            align=WindowAlign.CENTER,  +            height=1,  +            width=width,  +            style=get_style,  +            dont_extend_width=False,  +            dont_extend_height=True,  +        )  +  +    def _get_text_fragments(self) -> StyleAndTextTuples:  +        width = self.width - (  +            get_cwidth(self.left_symbol) + get_cwidth(self.right_symbol)  +        )  +        text = ("{{:^{}}}".format(width)).format(self.text)  +  +        def handler(mouse_event: MouseEvent) -> None:  +            if (  +                self.handler is not None  +                and mouse_event.event_type == MouseEventType.MOUSE_UP  +            ):  +                self.handler()  +  +        return [  +            ("class:button.arrow", self.left_symbol, handler),  +            ("[SetCursorPosition]", ""),  +            ("class:button.text", text, handler),  +            ("class:button.arrow", self.right_symbol, handler),  +        ]  +  +    def _get_key_bindings(self) -> KeyBindings:  +        "Key bindings for the Button."  +        kb = KeyBindings()  +  +        @kb.add(" ")  +        @kb.add("enter")  +        def _(event: E) -> None:  +            if self.handler is not None:  +                self.handler()  +  +        return kb  +  +    def __pt_container__(self) -> Container:  +        return self.window  +  +  +class Frame:  +    """  +    Draw a border around any container, optionally with a title text.  +  +    Changing the title and body of the frame is possible at runtime by  +    assigning to the `body` and `title` attributes of this class.  +  +    :param body: Another container object.  +    :param title: Text to be displayed in the top of the frame (can be formatted text).  +    :param style: Style string to be applied to this widget.  +    """  +  +    def __init__(  +        self,  +        body: AnyContainer,  +        title: AnyFormattedText = "",  +        style: str = "",  +        width: AnyDimension = None,  +        height: AnyDimension = None,  +        key_bindings: Optional[KeyBindings] = None,  +        modal: bool = False,  +    ) -> None:  +  +        self.title = title  +        self.body = body  +  +        fill = partial(Window, style="class:frame.border")  +        style = "class:frame " + style  +  +        top_row_with_title = VSplit(  +            [  +                fill(width=1, height=1, char=Border.TOP_LEFT),  +                fill(char=Border.HORIZONTAL),  +                fill(width=1, height=1, char="|"),  +                # Notice: we use `Template` here, because `self.title` can be an  +                # `HTML` object for instance.  +                Label(  +                    lambda: Template(" {} ").format(self.title),  +                    style="class:frame.label",  +                    dont_extend_width=True,  +                ),  +                fill(width=1, height=1, char="|"),  +                fill(char=Border.HORIZONTAL),  +                fill(width=1, height=1, char=Border.TOP_RIGHT),  +            ],  +            height=1,  +        )  +  +        top_row_without_title = VSplit(  +            [  +                fill(width=1, height=1, char=Border.TOP_LEFT),  +                fill(char=Border.HORIZONTAL),  +                fill(width=1, height=1, char=Border.TOP_RIGHT),  +            ],  +            height=1,  +        )  +  +        @Condition  +        def has_title() -> bool:  +            return bool(self.title)  +  +        self.container = HSplit(  +            [  +                ConditionalContainer(content=top_row_with_title, filter=has_title),  +                ConditionalContainer(content=top_row_without_title, filter=~has_title),  +                VSplit(  +                    [  +                        fill(width=1, char=Border.VERTICAL),  +                        DynamicContainer(lambda: self.body),  +                        fill(width=1, char=Border.VERTICAL),  +                        # Padding is required to make sure that if the content is  +                        # too small, the right frame border is still aligned.  +                    ],  +                    padding=0,  +                ),  +                VSplit(  +                    [  +                        fill(width=1, height=1, char=Border.BOTTOM_LEFT),  +                        fill(char=Border.HORIZONTAL),  +                        fill(width=1, height=1, char=Border.BOTTOM_RIGHT),  +                    ],  +                    # specifying height here will increase the rendering speed.  +                    height=1,  +                ),  +            ],  +            width=width,  +            height=height,  +            style=style,  +            key_bindings=key_bindings,  +            modal=modal,  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +class Shadow:  +    """  +    Draw a shadow underneath/behind this container.  +    (This applies `class:shadow` the the cells under the shadow. The Style  +    should define the colors for the shadow.)  +  +    :param body: Another container object.  +    """  +  +    def __init__(self, body: AnyContainer) -> None:  +        self.container = FloatContainer(  +            content=body,  +            floats=[  +                Float(  +                    bottom=-1,  +                    height=1,  +                    left=1,  +                    right=-1,  +                    transparent=True,  +                    content=Window(style="class:shadow"),  +                ),  +                Float(  +                    bottom=-1,  +                    top=1,  +                    width=1,  +                    right=-1,  +                    transparent=True,  +                    content=Window(style="class:shadow"),  +                ),  +            ],  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +class Box:  +    """  +    Add padding around a container.  +  +    This also makes sure that the parent can provide more space than required by  +    the child. This is very useful when wrapping a small element with a fixed  +    size into a ``VSplit`` or ``HSplit`` object. The ``HSplit`` and ``VSplit``  +    try to make sure to adapt respectively the width and height, possibly  +    shrinking other elements. Wrapping something in a ``Box`` makes it flexible.  +  +    :param body: Another container object.  +    :param padding: The margin to be used around the body. This can be  +        overridden by `padding_left`, padding_right`, `padding_top` and  +        `padding_bottom`.  +    :param style: A style string.  +    :param char: Character to be used for filling the space around the body.  +        (This is supposed to be a character with a terminal width of 1.)  +    """  +  +    def __init__(  +        self,  +        body: AnyContainer,  +        padding: AnyDimension = None,  +        padding_left: AnyDimension = None,  +        padding_right: AnyDimension = None,  +        padding_top: AnyDimension = None,  +        padding_bottom: AnyDimension = None,  +        width: AnyDimension = None,  +        height: AnyDimension = None,  +        style: str = "",  +        char: Union[None, str, Callable[[], str]] = None,  +        modal: bool = False,  +        key_bindings: Optional[KeyBindings] = None,  +    ) -> None:  +  +        if padding is None:  +            padding = D(preferred=0)  +  +        def get(value: AnyDimension) -> D:  +            if value is None:  +                value = padding  +            return to_dimension(value)  +  +        self.padding_left = get(padding_left)  +        self.padding_right = get(padding_right)  +        self.padding_top = get(padding_top)  +        self.padding_bottom = get(padding_bottom)  +        self.body = body  +  +        self.container = HSplit(  +            [  +                Window(height=self.padding_top, char=char),  +                VSplit(  +                    [  +                        Window(width=self.padding_left, char=char),  +                        body,  +                        Window(width=self.padding_right, char=char),  +                    ]  +                ),  +                Window(height=self.padding_bottom, char=char),  +            ],  +            width=width,  +            height=height,  +            style=style,  +            modal=modal,  +            key_bindings=None,  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +_T = TypeVar("_T")  +  +  +class _DialogList(Generic[_T]):  +    """  +    Common code for `RadioList` and `CheckboxList`.  +    """  +  +    open_character: str = ""  +    close_character: str = ""  +    container_style: str = ""  +    default_style: str = ""  +    selected_style: str = ""  +    checked_style: str = ""  +    multiple_selection: bool = False  +    show_scrollbar: bool = True  +  +    def __init__(self, values: Sequence[Tuple[_T, AnyFormattedText]]) -> None:  +        assert len(values) > 0  +  +        self.values = values  +        # current_values will be used in multiple_selection,  +        # current_value will be used otherwise.  +        self.current_values: List[_T] = []  +        self.current_value: _T = values[0][0]  +        self._selected_index = 0  +  +        # Key bindings.  +        kb = KeyBindings()  +  +        @kb.add("up")  +        def _up(event: E) -> None:  +            self._selected_index = max(0, self._selected_index - 1)  +  +        @kb.add("down")  +        def _down(event: E) -> None:  +            self._selected_index = min(len(self.values) - 1, self._selected_index + 1)  +  +        @kb.add("pageup")  +        def _pageup(event: E) -> None:  +            w = event.app.layout.current_window  +            if w.render_info:  +                self._selected_index = max(  +                    0, self._selected_index - len(w.render_info.displayed_lines)  +                )  +  +        @kb.add("pagedown")  +        def _pagedown(event: E) -> None:  +            w = event.app.layout.current_window  +            if w.render_info:  +                self._selected_index = min(  +                    len(self.values) - 1,  +                    self._selected_index + len(w.render_info.displayed_lines),  +                )  +  +        @kb.add("enter")  +        @kb.add(" ")  +        def _click(event: E) -> None:  +            self._handle_enter()  +  +        @kb.add(Keys.Any)  +        def _find(event: E) -> None:  +            # We first check values after the selected value, then all values.  +            values = list(self.values)  +            for value in values[self._selected_index + 1 :] + values:  +                text = fragment_list_to_text(to_formatted_text(value[1])).lower()  +  +                if text.startswith(event.data.lower()):  +                    self._selected_index = self.values.index(value)  +                    return  +  +        # Control and window.  +        self.control = FormattedTextControl(  +            self._get_text_fragments, key_bindings=kb, focusable=True  +        )  +  +        self.window = Window(  +            content=self.control,  +            style=self.container_style,  +            right_margins=[  +                ConditionalMargin(  +                    margin=ScrollbarMargin(display_arrows=True),  +                    filter=Condition(lambda: self.show_scrollbar),  +                ),  +            ],  +            dont_extend_height=True,  +        )  +  +    def _handle_enter(self) -> None:  +        if self.multiple_selection:  +            val = self.values[self._selected_index][0]  +            if val in self.current_values:  +                self.current_values.remove(val)  +            else:  +                self.current_values.append(val)  +        else:  +            self.current_value = self.values[self._selected_index][0]  +  +    def _get_text_fragments(self) -> StyleAndTextTuples:  +        def mouse_handler(mouse_event: MouseEvent) -> None:  +            """  +            Set `_selected_index` and `current_value` according to the y  +            position of the mouse click event.  +            """  +            if mouse_event.event_type == MouseEventType.MOUSE_UP:  +                self._selected_index = mouse_event.position.y  +                self._handle_enter()  +  +        result: StyleAndTextTuples = []  +        for i, value in enumerate(self.values):  +            if self.multiple_selection:  +                checked = value[0] in self.current_values  +            else:  +                checked = value[0] == self.current_value  +            selected = i == self._selected_index  +  +            style = ""  +            if checked:  +                style += " " + self.checked_style  +            if selected:  +                style += " " + self.selected_style  +  +            result.append((style, self.open_character))  +  +            if selected:  +                result.append(("[SetCursorPosition]", ""))  +  +            if checked:  +                result.append((style, "*"))  +            else:  +                result.append((style, " "))  +  +            result.append((style, self.close_character))  +            result.append((self.default_style, " "))  +            result.extend(to_formatted_text(value[1], style=self.default_style))  +            result.append(("", "\n"))  +  +        # Add mouse handler to all fragments.  +        for i in range(len(result)):  +            result[i] = (result[i][0], result[i][1], mouse_handler)  +  +        result.pop()  # Remove last newline.  +        return result  +  +    def __pt_container__(self) -> Container:  +        return self.window  +  +  +class RadioList(_DialogList[_T]):  +    """  +    List of radio buttons. Only one can be checked at the same time.  +  +    :param values: List of (value, label) tuples.  +    """  +  +    open_character = "("  +    close_character = ")"  +    container_style = "class:radio-list"  +    default_style = "class:radio"  +    selected_style = "class:radio-selected"  +    checked_style = "class:radio-checked"  +    multiple_selection = False  +  +  +class CheckboxList(_DialogList[_T]):  +    """  +    List of checkbox buttons. Several can be checked at the same time.  +  +    :param values: List of (value, label) tuples.  +    """  +  +    open_character = "["  +    close_character = "]"  +    container_style = "class:checkbox-list"  +    default_style = "class:checkbox"  +    selected_style = "class:checkbox-selected"  +    checked_style = "class:checkbox-checked"  +    multiple_selection = True  +  +  +class Checkbox(CheckboxList[str]):  +    """Backward compatibility util: creates a 1-sized CheckboxList  +  +    :param text: the text  +    """  +  +    show_scrollbar = False  +  +    def __init__(self, text: AnyFormattedText = "", checked: bool = False) -> None:  +        values = [("value", text)]  +        CheckboxList.__init__(self, values)  +        self.checked = checked  +  +    @property  +    def checked(self) -> bool:  +        return "value" in self.current_values  +  +    @checked.setter  +    def checked(self, value: bool) -> None:  +        if value:  +            self.current_values = ["value"]  +        else:  +            self.current_values = []  +  +  +class VerticalLine(object):  +    """  +    A simple vertical line with a width of 1.  +    """  +  +    def __init__(self) -> None:  +        self.window = Window(  +            char=Border.VERTICAL, style="class:line,vertical-line", width=1  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.window  +  +  +class HorizontalLine:  +    """  +    A simple horizontal line with a height of 1.  +    """  +  +    def __init__(self) -> None:  +        self.window = Window(  +            char=Border.HORIZONTAL, style="class:line,horizontal-line", height=1  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.window  +  +  +class ProgressBar:  +    def __init__(self) -> None:  +        self._percentage = 60  +  +        self.label = Label("60%")  +        self.container = FloatContainer(  +            content=Window(height=1),  +            floats=[  +                # We first draw the label, then the actual progress bar.  Right  +                # now, this is the only way to have the colors of the progress  +                # bar appear on top of the label. The problem is that our label  +                # can't be part of any `Window` below.  +                Float(content=self.label, top=0, bottom=0),  +                Float(  +                    left=0,  +                    top=0,  +                    right=0,  +                    bottom=0,  +                    content=VSplit(  +                        [  +                            Window(  +                                style="class:progress-bar.used",  +                                width=lambda: D(weight=int(self._percentage)),  +                            ),  +                            Window(  +                                style="class:progress-bar",  +                                width=lambda: D(weight=int(100 - self._percentage)),  +                            ),  +                        ]  +                    ),  +                ),  +            ],  +        )  +  +    @property  +    def percentage(self) -> int:  +        return self._percentage  +  +    @percentage.setter  +    def percentage(self, value: int) -> None:  +        self._percentage = value  +        self.label.text = "{0}%".format(value)  +  +    def __pt_container__(self) -> Container:  +        return self.container  diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/dialogs.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/dialogs.py index 920582b4e68..d814d275eac 100644 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/dialogs.py +++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/dialogs.py @@ -1,106 +1,106 @@ -""" -Collection of reusable components for building full screen applications. -""" -from typing import Optional, Sequence, Union - -from prompt_toolkit.filters import has_completions, has_focus -from prompt_toolkit.formatted_text import AnyFormattedText -from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous -from prompt_toolkit.key_binding.key_bindings import KeyBindings -from prompt_toolkit.layout.containers import ( -    AnyContainer, -    DynamicContainer, -    HSplit, -    VSplit, -) -from prompt_toolkit.layout.dimension import AnyDimension -from prompt_toolkit.layout.dimension import Dimension as D - -from .base import Box, Button, Frame, Shadow - -__all__ = [ -    "Dialog", -] - - -class Dialog: -    """ -    Simple dialog window. This is the base for input dialogs, message dialogs -    and confirmation dialogs. - -    Changing the title and body of the dialog is possible at runtime by -    assigning to the `body` and `title` attributes of this class. - -    :param body: Child container object. -    :param title: Text to be displayed in the heading of the dialog. -    :param buttons: A list of `Button` widgets, displayed at the bottom. -    """ - -    def __init__( -        self, -        body: AnyContainer, -        title: AnyFormattedText = "", -        buttons: Optional[Sequence[Button]] = None, -        modal: bool = True, -        width: AnyDimension = None, -        with_background: bool = False, -    ) -> None: - -        self.body = body -        self.title = title - -        buttons = buttons or [] - -        # When a button is selected, handle left/right key bindings. -        buttons_kb = KeyBindings() -        if len(buttons) > 1: -            first_selected = has_focus(buttons[0]) -            last_selected = has_focus(buttons[-1]) - -            buttons_kb.add("left", filter=~first_selected)(focus_previous) -            buttons_kb.add("right", filter=~last_selected)(focus_next) - -        frame_body: AnyContainer -        if buttons: -            frame_body = HSplit( -                [ -                    # Add optional padding around the body. -                    Box( -                        body=DynamicContainer(lambda: self.body), -                        padding=D(preferred=1, max=1), -                        padding_bottom=0, -                    ), -                    # The buttons. -                    Box( -                        body=VSplit(buttons, padding=1, key_bindings=buttons_kb), -                        height=D(min=1, max=3, preferred=3), -                    ), -                ] -            ) -        else: -            frame_body = body - -        # Key bindings for whole dialog. -        kb = KeyBindings() -        kb.add("tab", filter=~has_completions)(focus_next) -        kb.add("s-tab", filter=~has_completions)(focus_previous) - -        frame = Shadow( -            body=Frame( -                title=lambda: self.title, -                body=frame_body, -                style="class:dialog.body", -                width=(None if with_background is None else width), -                key_bindings=kb, -                modal=modal, -            ) -        ) - -        self.container: Union[Box, Shadow] -        if with_background: -            self.container = Box(body=frame, style="class:dialog", width=width) -        else: -            self.container = frame - -    def __pt_container__(self) -> AnyContainer: -        return self.container +"""  +Collection of reusable components for building full screen applications.  +"""  +from typing import Optional, Sequence, Union  +  +from prompt_toolkit.filters import has_completions, has_focus  +from prompt_toolkit.formatted_text import AnyFormattedText  +from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous  +from prompt_toolkit.key_binding.key_bindings import KeyBindings  +from prompt_toolkit.layout.containers import (  +    AnyContainer,  +    DynamicContainer,  +    HSplit,  +    VSplit,  +)  +from prompt_toolkit.layout.dimension import AnyDimension  +from prompt_toolkit.layout.dimension import Dimension as D  +  +from .base import Box, Button, Frame, Shadow  +  +__all__ = [  +    "Dialog",  +]  +  +  +class Dialog:  +    """  +    Simple dialog window. This is the base for input dialogs, message dialogs  +    and confirmation dialogs.  +  +    Changing the title and body of the dialog is possible at runtime by  +    assigning to the `body` and `title` attributes of this class.  +  +    :param body: Child container object.  +    :param title: Text to be displayed in the heading of the dialog.  +    :param buttons: A list of `Button` widgets, displayed at the bottom.  +    """  +  +    def __init__(  +        self,  +        body: AnyContainer,  +        title: AnyFormattedText = "",  +        buttons: Optional[Sequence[Button]] = None,  +        modal: bool = True,  +        width: AnyDimension = None,  +        with_background: bool = False,  +    ) -> None:  +  +        self.body = body  +        self.title = title  +  +        buttons = buttons or []  +  +        # When a button is selected, handle left/right key bindings.  +        buttons_kb = KeyBindings()  +        if len(buttons) > 1:  +            first_selected = has_focus(buttons[0])  +            last_selected = has_focus(buttons[-1])  +  +            buttons_kb.add("left", filter=~first_selected)(focus_previous)  +            buttons_kb.add("right", filter=~last_selected)(focus_next)  +  +        frame_body: AnyContainer  +        if buttons:  +            frame_body = HSplit(  +                [  +                    # Add optional padding around the body.  +                    Box(  +                        body=DynamicContainer(lambda: self.body),  +                        padding=D(preferred=1, max=1),  +                        padding_bottom=0,  +                    ),  +                    # The buttons.  +                    Box(  +                        body=VSplit(buttons, padding=1, key_bindings=buttons_kb),  +                        height=D(min=1, max=3, preferred=3),  +                    ),  +                ]  +            )  +        else:  +            frame_body = body  +  +        # Key bindings for whole dialog.  +        kb = KeyBindings()  +        kb.add("tab", filter=~has_completions)(focus_next)  +        kb.add("s-tab", filter=~has_completions)(focus_previous)  +  +        frame = Shadow(  +            body=Frame(  +                title=lambda: self.title,  +                body=frame_body,  +                style="class:dialog.body",  +                width=(None if with_background is None else width),  +                key_bindings=kb,  +                modal=modal,  +            )  +        )  +  +        self.container: Union[Box, Shadow]  +        if with_background:  +            self.container = Box(body=frame, style="class:dialog", width=width)  +        else:  +            self.container = frame  +  +    def __pt_container__(self) -> AnyContainer:  +        return self.container  diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/menus.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/menus.py index 7203aae1181..f4d91067c96 100644 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/menus.py +++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/menus.py @@ -1,374 +1,374 @@ -from typing import Callable, Iterable, List, Optional, Sequence, Union - -from prompt_toolkit.application.current import get_app -from prompt_toolkit.filters import Condition -from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple, StyleAndTextTuples -from prompt_toolkit.key_binding.key_bindings import KeyBindings, KeyBindingsBase -from prompt_toolkit.key_binding.key_processor import KeyPressEvent -from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.containers import ( -    AnyContainer, -    ConditionalContainer, -    Container, -    Float, -    FloatContainer, -    HSplit, -    Window, -) -from prompt_toolkit.layout.controls import FormattedTextControl -from prompt_toolkit.mouse_events import MouseEvent, MouseEventType -from prompt_toolkit.utils import get_cwidth -from prompt_toolkit.widgets import Shadow - -from .base import Border - -__all__ = [ -    "MenuContainer", -    "MenuItem", -] - -E = KeyPressEvent - - -class MenuContainer: -    """ -    :param floats: List of extra Float objects to display. -    :param menu_items: List of `MenuItem` objects. -    """ - -    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 _left(event: E) -> None: -            self.selected_menu[0] = max(0, self.selected_menu[0] - 1) - -        @kb.add("right", filter=in_main_menu) -        def _right(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 _down(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 _cancel(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 _back(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 _submenu(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 _up_in_submenu(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 _down_in_submenu(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 _click(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, -        ) - -    def _get_menu(self, level: int) -> "MenuItem": -        menu = self.menu_items[self.selected_menu[0]] - -        for i, index in enumerate(self.selected_menu[1:]): -            if i < level: -                try: -                    menu = menu.children[index] -                except IndexError: -                    return MenuItem("debug") - -        return menu - -    def _get_menu_fragments(self) -> StyleAndTextTuples: -        focused = get_app().layout.has_focus(self.window) - -        # This is called during the rendering. When we discover that this -        # widget doesn't have the focus anymore. Reset menu state. -        if not focused: -            self.selected_menu = [0] - -        # Generate text fragments for the main menu. -        def one_item(i: int, item: MenuItem) -> Iterable[OneStyleAndTextTuple]: -            def mouse_handler(mouse_event: MouseEvent) -> None: -                hover = mouse_event.event_type == MouseEventType.MOUSE_MOVE -                if ( -                    mouse_event.event_type == MouseEventType.MOUSE_DOWN -                    or hover -                    and focused -                ): -                    # Toggle focus. -                    app = get_app() -                    if not hover: -                        if app.layout.has_focus(self.window): -                            if self.selected_menu == [i]: -                                app.layout.focus_last() -                        else: -                            app.layout.focus(self.window) -                    self.selected_menu = [i] - -            yield ("class:menu-bar", " ", mouse_handler) -            if i == self.selected_menu[0] and focused: -                yield ("[SetMenuPosition]", "", mouse_handler) -                style = "class:menu-bar.selected-item" -            else: -                style = "class:menu-bar" -            yield style, item.text, mouse_handler - -        result: StyleAndTextTuples = [] -        for i, item in enumerate(self.menu_items): -            result.extend(one_item(i, item)) - -        return result - -    def _submenu(self, level: int = 0) -> Window: -        def get_text_fragments() -> StyleAndTextTuples: -            result: StyleAndTextTuples = [] -            if level < len(self.selected_menu): -                menu = self._get_menu(level) -                if menu.children: -                    result.append(("class:menu", Border.TOP_LEFT)) -                    result.append(("class:menu", Border.HORIZONTAL * (menu.width + 4))) -                    result.append(("class:menu", Border.TOP_RIGHT)) -                    result.append(("", "\n")) -                    try: -                        selected_item = self.selected_menu[level + 1] -                    except IndexError: -                        selected_item = -1 - -                    def one_item( -                        i: int, item: MenuItem -                    ) -> Iterable[OneStyleAndTextTuple]: -                        def mouse_handler(mouse_event: MouseEvent) -> None: -                            if item.disabled: -                                # The arrow keys can't interact with menu items that are disabled. -                                # The mouse shouldn't be able to either. -                                return -                            hover = mouse_event.event_type == MouseEventType.MOUSE_MOVE -                            if ( -                                mouse_event.event_type == MouseEventType.MOUSE_UP -                                or hover -                            ): -                                app = get_app() -                                if not hover and item.handler: -                                    app.layout.focus_last() -                                    item.handler() -                                else: -                                    self.selected_menu = self.selected_menu[ -                                        : level + 1 -                                    ] + [i] - -                        if i == selected_item: -                            yield ("[SetCursorPosition]", "") -                            style = "class:menu-bar.selected-item" -                        else: -                            style = "" - -                        yield ("class:menu", Border.VERTICAL) -                        if item.text == "-": -                            yield ( -                                style + "class:menu-border", -                                "{}".format(Border.HORIZONTAL * (menu.width + 3)), -                                mouse_handler, -                            ) -                        else: -                            yield ( -                                style, -                                " {}".format(item.text).ljust(menu.width + 3), -                                mouse_handler, -                            ) - -                        if item.children: -                            yield (style, ">", mouse_handler) -                        else: -                            yield (style, " ", mouse_handler) - -                        if i == selected_item: -                            yield ("[SetMenuPosition]", "") -                        yield ("class:menu", Border.VERTICAL) - -                        yield ("", "\n") - -                    for i, item in enumerate(menu.children): -                        result.extend(one_item(i, item)) - -                    result.append(("class:menu", Border.BOTTOM_LEFT)) -                    result.append(("class:menu", Border.HORIZONTAL * (menu.width + 4))) -                    result.append(("class:menu", Border.BOTTOM_RIGHT)) -            return result - -        return Window(FormattedTextControl(get_text_fragments), style="class:menu") - -    @property -    def floats(self) -> Optional[List[Float]]: -        return self.container.floats - -    def __pt_container__(self) -> Container: -        return self.container - - -class MenuItem: -    def __init__( -        self, -        text: str = "", -        handler: Optional[Callable[[], None]] = None, -        children: Optional[List["MenuItem"]] = None, -        shortcut: Optional[Sequence[Union[Keys, str]]] = None, -        disabled: bool = False, -    ) -> None: - -        self.text = text -        self.handler = handler -        self.children = children or [] -        self.shortcut = shortcut -        self.disabled = disabled -        self.selected_item = 0 - -    @property -    def width(self) -> int: -        if self.children: -            return max(get_cwidth(c.text) for c in self.children) -        else: -            return 0 +from typing import Callable, Iterable, List, Optional, Sequence, Union  +  +from prompt_toolkit.application.current import get_app  +from prompt_toolkit.filters import Condition  +from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple, StyleAndTextTuples  +from prompt_toolkit.key_binding.key_bindings import KeyBindings, KeyBindingsBase  +from prompt_toolkit.key_binding.key_processor import KeyPressEvent  +from prompt_toolkit.keys import Keys  +from prompt_toolkit.layout.containers import (  +    AnyContainer,  +    ConditionalContainer,  +    Container,  +    Float,  +    FloatContainer,  +    HSplit,  +    Window,  +)  +from prompt_toolkit.layout.controls import FormattedTextControl  +from prompt_toolkit.mouse_events import MouseEvent, MouseEventType  +from prompt_toolkit.utils import get_cwidth  +from prompt_toolkit.widgets import Shadow  +  +from .base import Border  +  +__all__ = [  +    "MenuContainer",  +    "MenuItem",  +]  +  +E = KeyPressEvent  +  +  +class MenuContainer:  +    """  +    :param floats: List of extra Float objects to display.  +    :param menu_items: List of `MenuItem` objects.  +    """  +  +    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 _left(event: E) -> None:  +            self.selected_menu[0] = max(0, self.selected_menu[0] - 1)  +  +        @kb.add("right", filter=in_main_menu)  +        def _right(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 _down(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 _cancel(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 _back(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 _submenu(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 _up_in_submenu(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 _down_in_submenu(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 _click(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,  +        )  +  +    def _get_menu(self, level: int) -> "MenuItem":  +        menu = self.menu_items[self.selected_menu[0]]  +  +        for i, index in enumerate(self.selected_menu[1:]):  +            if i < level:  +                try:  +                    menu = menu.children[index]  +                except IndexError:  +                    return MenuItem("debug")  +  +        return menu  +  +    def _get_menu_fragments(self) -> StyleAndTextTuples:  +        focused = get_app().layout.has_focus(self.window)  +  +        # This is called during the rendering. When we discover that this  +        # widget doesn't have the focus anymore. Reset menu state.  +        if not focused:  +            self.selected_menu = [0]  +  +        # Generate text fragments for the main menu.  +        def one_item(i: int, item: MenuItem) -> Iterable[OneStyleAndTextTuple]:  +            def mouse_handler(mouse_event: MouseEvent) -> None:  +                hover = mouse_event.event_type == MouseEventType.MOUSE_MOVE  +                if (  +                    mouse_event.event_type == MouseEventType.MOUSE_DOWN  +                    or hover  +                    and focused  +                ):  +                    # Toggle focus.  +                    app = get_app()  +                    if not hover:  +                        if app.layout.has_focus(self.window):  +                            if self.selected_menu == [i]:  +                                app.layout.focus_last()  +                        else:  +                            app.layout.focus(self.window)  +                    self.selected_menu = [i]  +  +            yield ("class:menu-bar", " ", mouse_handler)  +            if i == self.selected_menu[0] and focused:  +                yield ("[SetMenuPosition]", "", mouse_handler)  +                style = "class:menu-bar.selected-item"  +            else:  +                style = "class:menu-bar"  +            yield style, item.text, mouse_handler  +  +        result: StyleAndTextTuples = []  +        for i, item in enumerate(self.menu_items):  +            result.extend(one_item(i, item))  +  +        return result  +  +    def _submenu(self, level: int = 0) -> Window:  +        def get_text_fragments() -> StyleAndTextTuples:  +            result: StyleAndTextTuples = []  +            if level < len(self.selected_menu):  +                menu = self._get_menu(level)  +                if menu.children:  +                    result.append(("class:menu", Border.TOP_LEFT))  +                    result.append(("class:menu", Border.HORIZONTAL * (menu.width + 4)))  +                    result.append(("class:menu", Border.TOP_RIGHT))  +                    result.append(("", "\n"))  +                    try:  +                        selected_item = self.selected_menu[level + 1]  +                    except IndexError:  +                        selected_item = -1  +  +                    def one_item(  +                        i: int, item: MenuItem  +                    ) -> Iterable[OneStyleAndTextTuple]:  +                        def mouse_handler(mouse_event: MouseEvent) -> None:  +                            if item.disabled:  +                                # The arrow keys can't interact with menu items that are disabled.  +                                # The mouse shouldn't be able to either.  +                                return  +                            hover = mouse_event.event_type == MouseEventType.MOUSE_MOVE  +                            if (  +                                mouse_event.event_type == MouseEventType.MOUSE_UP  +                                or hover  +                            ):  +                                app = get_app()  +                                if not hover and item.handler:  +                                    app.layout.focus_last()  +                                    item.handler()  +                                else:  +                                    self.selected_menu = self.selected_menu[  +                                        : level + 1  +                                    ] + [i]  +  +                        if i == selected_item:  +                            yield ("[SetCursorPosition]", "")  +                            style = "class:menu-bar.selected-item"  +                        else:  +                            style = ""  +  +                        yield ("class:menu", Border.VERTICAL)  +                        if item.text == "-":  +                            yield (  +                                style + "class:menu-border",  +                                "{}".format(Border.HORIZONTAL * (menu.width + 3)),  +                                mouse_handler,  +                            )  +                        else:  +                            yield (  +                                style,  +                                " {}".format(item.text).ljust(menu.width + 3),  +                                mouse_handler,  +                            )  +  +                        if item.children:  +                            yield (style, ">", mouse_handler)  +                        else:  +                            yield (style, " ", mouse_handler)  +  +                        if i == selected_item:  +                            yield ("[SetMenuPosition]", "")  +                        yield ("class:menu", Border.VERTICAL)  +  +                        yield ("", "\n")  +  +                    for i, item in enumerate(menu.children):  +                        result.extend(one_item(i, item))  +  +                    result.append(("class:menu", Border.BOTTOM_LEFT))  +                    result.append(("class:menu", Border.HORIZONTAL * (menu.width + 4)))  +                    result.append(("class:menu", Border.BOTTOM_RIGHT))  +            return result  +  +        return Window(FormattedTextControl(get_text_fragments), style="class:menu")  +  +    @property  +    def floats(self) -> Optional[List[Float]]:  +        return self.container.floats  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +class MenuItem:  +    def __init__(  +        self,  +        text: str = "",  +        handler: Optional[Callable[[], None]] = None,  +        children: Optional[List["MenuItem"]] = None,  +        shortcut: Optional[Sequence[Union[Keys, str]]] = None,  +        disabled: bool = False,  +    ) -> None:  +  +        self.text = text  +        self.handler = handler  +        self.children = children or []  +        self.shortcut = shortcut  +        self.disabled = disabled  +        self.selected_item = 0  +  +    @property  +    def width(self) -> int:  +        if self.children:  +            return max(get_cwidth(c.text) for c in self.children)  +        else:  +            return 0  diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/toolbars.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/toolbars.py index c3559c2b83c..eaf29b5b18f 100644 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/toolbars.py +++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/toolbars.py @@ -1,374 +1,374 @@ -from typing import Any, Optional - -from prompt_toolkit.application.current import get_app -from prompt_toolkit.buffer import Buffer -from prompt_toolkit.enums import SYSTEM_BUFFER -from prompt_toolkit.filters import ( -    Condition, -    FilterOrBool, -    emacs_mode, -    has_arg, -    has_completions, -    has_focus, -    has_validation_error, -    to_filter, -    vi_mode, -    vi_navigation_mode, -) -from prompt_toolkit.formatted_text import ( -    AnyFormattedText, -    StyleAndTextTuples, -    fragment_list_len, -    to_formatted_text, -) -from prompt_toolkit.key_binding.key_bindings import ( -    ConditionalKeyBindings, -    KeyBindings, -    KeyBindingsBase, -    merge_key_bindings, -) -from prompt_toolkit.key_binding.key_processor import KeyPressEvent -from prompt_toolkit.key_binding.vi_state import InputMode -from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.containers import ConditionalContainer, Container, Window -from prompt_toolkit.layout.controls import ( -    BufferControl, -    FormattedTextControl, -    SearchBufferControl, -    UIContent, -    UIControl, -) -from prompt_toolkit.layout.dimension import Dimension -from prompt_toolkit.layout.processors import BeforeInput -from prompt_toolkit.lexers import SimpleLexer -from prompt_toolkit.search import SearchDirection - -__all__ = [ -    "ArgToolbar", -    "CompletionsToolbar", -    "FormattedTextToolbar", -    "SearchToolbar", -    "SystemToolbar", -    "ValidationToolbar", -] - -E = KeyPressEvent - - -class FormattedTextToolbar(Window): -    def __init__(self, text: AnyFormattedText, style: str = "", **kw: Any) -> None: -        # Note: The style needs to be applied to the toolbar as a whole, not -        #       just the `FormattedTextControl`. -        super().__init__( -            FormattedTextControl(text, **kw), -            style=style, -            dont_extend_height=True, -            height=Dimension(min=1), -        ) - - -class SystemToolbar: -    """ -    Toolbar for a system prompt. - -    :param prompt: Prompt to be displayed to the user. -    """ - -    def __init__( -        self, -        prompt: AnyFormattedText = "Shell command: ", -        enable_global_bindings: FilterOrBool = True, -    ) -> None: - -        self.prompt = prompt -        self.enable_global_bindings = to_filter(enable_global_bindings) - -        self.system_buffer = Buffer(name=SYSTEM_BUFFER) - -        self._bindings = self._build_key_bindings() - -        self.buffer_control = BufferControl( -            buffer=self.system_buffer, -            lexer=SimpleLexer(style="class:system-toolbar.text"), -            input_processors=[ -                BeforeInput(lambda: self.prompt, style="class:system-toolbar") -            ], -            key_bindings=self._bindings, -        ) - -        self.window = Window( -            self.buffer_control, height=1, style="class:system-toolbar" -        ) - -        self.container = ConditionalContainer( -            content=self.window, filter=has_focus(self.system_buffer) -        ) - -    def _get_display_before_text(self) -> StyleAndTextTuples: -        return [ -            ("class:system-toolbar", "Shell command: "), -            ("class:system-toolbar.text", self.system_buffer.text), -            ("", "\n"), -        ] - -    def _build_key_bindings(self) -> KeyBindingsBase: -        focused = has_focus(self.system_buffer) - -        # Emacs -        emacs_bindings = KeyBindings() -        handle = emacs_bindings.add - -        @handle("escape", filter=focused) -        @handle("c-g", filter=focused) -        @handle("c-c", filter=focused) -        def _cancel(event: E) -> None: -            "Hide system prompt." -            self.system_buffer.reset() -            event.app.layout.focus_last() - -        @handle("enter", filter=focused) -        async def _accept(event: E) -> None: -            "Run system command." -            await event.app.run_system_command( -                self.system_buffer.text, -                display_before_text=self._get_display_before_text(), -            ) -            self.system_buffer.reset(append_to_history=True) -            event.app.layout.focus_last() - -        # Vi. -        vi_bindings = KeyBindings() -        handle = vi_bindings.add - -        @handle("escape", filter=focused) -        @handle("c-c", filter=focused) -        def _cancel_vi(event: E) -> None: -            "Hide system prompt." -            event.app.vi_state.input_mode = InputMode.NAVIGATION -            self.system_buffer.reset() -            event.app.layout.focus_last() - -        @handle("enter", filter=focused) -        async def _accept_vi(event: E) -> None: -            "Run system command." -            event.app.vi_state.input_mode = InputMode.NAVIGATION -            event.app.run_system_command( -                self.system_buffer.text, -                display_before_text=self._get_display_before_text(), -            ) -            self.system_buffer.reset(append_to_history=True) -            event.app.layout.focus_last() - -        # Global bindings. (Listen to these bindings, even when this widget is -        # not focussed.) -        global_bindings = KeyBindings() -        handle = global_bindings.add - -        @handle(Keys.Escape, "!", filter=~focused & emacs_mode, is_global=True) -        def _focus_me(event: E) -> None: -            "M-'!' will focus this user control." -            event.app.layout.focus(self.window) - -        @handle("!", filter=~focused & vi_mode & vi_navigation_mode, is_global=True) -        def _focus_me_vi(event: E) -> None: -            "Focus." -            event.app.vi_state.input_mode = InputMode.INSERT -            event.app.layout.focus(self.window) - -        return merge_key_bindings( -            [ -                ConditionalKeyBindings(emacs_bindings, emacs_mode), -                ConditionalKeyBindings(vi_bindings, vi_mode), -                ConditionalKeyBindings(global_bindings, self.enable_global_bindings), -            ] -        ) - -    def __pt_container__(self) -> Container: -        return self.container - - -class ArgToolbar: -    def __init__(self) -> None: -        def get_formatted_text() -> StyleAndTextTuples: -            arg = get_app().key_processor.arg or "" -            if arg == "-": -                arg = "-1" - -            return [ -                ("class:arg-toolbar", "Repeat: "), -                ("class:arg-toolbar.text", arg), -            ] - -        self.window = Window(FormattedTextControl(get_formatted_text), height=1) - -        self.container = ConditionalContainer(content=self.window, filter=has_arg) - -    def __pt_container__(self) -> Container: -        return self.container - - -class SearchToolbar: -    """ -    :param vi_mode: Display '/' and '?' instead of I-search. -    :param ignore_case: Search case insensitive. -    """ - -    def __init__( -        self, -        search_buffer: Optional[Buffer] = None, -        vi_mode: bool = False, -        text_if_not_searching: AnyFormattedText = "", -        forward_search_prompt: AnyFormattedText = "I-search: ", -        backward_search_prompt: AnyFormattedText = "I-search backward: ", -        ignore_case: FilterOrBool = False, -    ) -> None: - -        if search_buffer is None: -            search_buffer = Buffer() - -        @Condition -        def is_searching() -> bool: -            return self.control in get_app().layout.search_links - -        def get_before_input() -> AnyFormattedText: -            if not is_searching(): -                return text_if_not_searching -            elif ( -                self.control.searcher_search_state.direction == SearchDirection.BACKWARD -            ): -                return "?" if vi_mode else backward_search_prompt -            else: -                return "/" if vi_mode else forward_search_prompt - -        self.search_buffer = search_buffer - -        self.control = SearchBufferControl( -            buffer=search_buffer, -            input_processors=[ -                BeforeInput(get_before_input, style="class:search-toolbar.prompt") -            ], -            lexer=SimpleLexer(style="class:search-toolbar.text"), -            ignore_case=ignore_case, -        ) - -        self.container = ConditionalContainer( -            content=Window(self.control, height=1, style="class:search-toolbar"), -            filter=is_searching, -        ) - -    def __pt_container__(self) -> Container: -        return self.container - - -class _CompletionsToolbarControl(UIControl): -    def create_content(self, width: int, height: int) -> UIContent: -        all_fragments: StyleAndTextTuples = [] - -        complete_state = get_app().current_buffer.complete_state -        if complete_state: -            completions = complete_state.completions -            index = complete_state.complete_index  # Can be None! - -            # Width of the completions without the left/right arrows in the margins. -            content_width = width - 6 - -            # Booleans indicating whether we stripped from the left/right -            cut_left = False -            cut_right = False - -            # Create Menu content. -            fragments: StyleAndTextTuples = [] - -            for i, c in enumerate(completions): -                # When there is no more place for the next completion -                if fragment_list_len(fragments) + len(c.display_text) >= content_width: -                    # If the current one was not yet displayed, page to the next sequence. -                    if i <= (index or 0): -                        fragments = [] -                        cut_left = True -                    # If the current one is visible, stop here. -                    else: -                        cut_right = True -                        break - -                fragments.extend( -                    to_formatted_text( -                        c.display_text, -                        style=( -                            "class:completion-toolbar.completion.current" -                            if i == index -                            else "class:completion-toolbar.completion" -                        ), -                    ) -                ) -                fragments.append(("", " ")) - -            # Extend/strip until the content width. -            fragments.append(("", " " * (content_width - fragment_list_len(fragments)))) -            fragments = fragments[:content_width] - -            # Return fragments -            all_fragments.append(("", " ")) -            all_fragments.append( -                ("class:completion-toolbar.arrow", "<" if cut_left else " ") -            ) -            all_fragments.append(("", " ")) - -            all_fragments.extend(fragments) - -            all_fragments.append(("", " ")) -            all_fragments.append( -                ("class:completion-toolbar.arrow", ">" if cut_right else " ") -            ) -            all_fragments.append(("", " ")) - -        def get_line(i: int) -> StyleAndTextTuples: -            return all_fragments - -        return UIContent(get_line=get_line, line_count=1) - - -class CompletionsToolbar: -    def __init__(self) -> None: -        self.container = ConditionalContainer( -            content=Window( -                _CompletionsToolbarControl(), height=1, style="class:completion-toolbar" -            ), -            filter=has_completions, -        ) - -    def __pt_container__(self) -> Container: -        return self.container - - -class ValidationToolbar: -    def __init__(self, show_position: bool = False) -> None: -        def get_formatted_text() -> StyleAndTextTuples: -            buff = get_app().current_buffer - -            if buff.validation_error: -                row, column = buff.document.translate_index_to_position( -                    buff.validation_error.cursor_position -                ) - -                if show_position: -                    text = "%s (line=%s column=%s)" % ( -                        buff.validation_error.message, -                        row + 1, -                        column + 1, -                    ) -                else: -                    text = buff.validation_error.message - -                return [("class:validation-toolbar", text)] -            else: -                return [] - -        self.control = FormattedTextControl(get_formatted_text) - -        self.container = ConditionalContainer( -            content=Window(self.control, height=1), filter=has_validation_error -        ) - -    def __pt_container__(self) -> Container: -        return self.container +from typing import Any, Optional  +  +from prompt_toolkit.application.current import get_app  +from prompt_toolkit.buffer import Buffer  +from prompt_toolkit.enums import SYSTEM_BUFFER  +from prompt_toolkit.filters import (  +    Condition,  +    FilterOrBool,  +    emacs_mode,  +    has_arg,  +    has_completions,  +    has_focus,  +    has_validation_error,  +    to_filter,  +    vi_mode,  +    vi_navigation_mode,  +)  +from prompt_toolkit.formatted_text import (  +    AnyFormattedText,  +    StyleAndTextTuples,  +    fragment_list_len,  +    to_formatted_text,  +)  +from prompt_toolkit.key_binding.key_bindings import (  +    ConditionalKeyBindings,  +    KeyBindings,  +    KeyBindingsBase,  +    merge_key_bindings,  +)  +from prompt_toolkit.key_binding.key_processor import KeyPressEvent  +from prompt_toolkit.key_binding.vi_state import InputMode  +from prompt_toolkit.keys import Keys  +from prompt_toolkit.layout.containers import ConditionalContainer, Container, Window  +from prompt_toolkit.layout.controls import (  +    BufferControl,  +    FormattedTextControl,  +    SearchBufferControl,  +    UIContent,  +    UIControl,  +)  +from prompt_toolkit.layout.dimension import Dimension  +from prompt_toolkit.layout.processors import BeforeInput  +from prompt_toolkit.lexers import SimpleLexer  +from prompt_toolkit.search import SearchDirection  +  +__all__ = [  +    "ArgToolbar",  +    "CompletionsToolbar",  +    "FormattedTextToolbar",  +    "SearchToolbar",  +    "SystemToolbar",  +    "ValidationToolbar",  +]  +  +E = KeyPressEvent  +  +  +class FormattedTextToolbar(Window):  +    def __init__(self, text: AnyFormattedText, style: str = "", **kw: Any) -> None:  +        # Note: The style needs to be applied to the toolbar as a whole, not  +        #       just the `FormattedTextControl`.  +        super().__init__(  +            FormattedTextControl(text, **kw),  +            style=style,  +            dont_extend_height=True,  +            height=Dimension(min=1),  +        )  +  +  +class SystemToolbar:  +    """  +    Toolbar for a system prompt.  +  +    :param prompt: Prompt to be displayed to the user.  +    """  +  +    def __init__(  +        self,  +        prompt: AnyFormattedText = "Shell command: ",  +        enable_global_bindings: FilterOrBool = True,  +    ) -> None:  +  +        self.prompt = prompt  +        self.enable_global_bindings = to_filter(enable_global_bindings)  +  +        self.system_buffer = Buffer(name=SYSTEM_BUFFER)  +  +        self._bindings = self._build_key_bindings()  +  +        self.buffer_control = BufferControl(  +            buffer=self.system_buffer,  +            lexer=SimpleLexer(style="class:system-toolbar.text"),  +            input_processors=[  +                BeforeInput(lambda: self.prompt, style="class:system-toolbar")  +            ],  +            key_bindings=self._bindings,  +        )  +  +        self.window = Window(  +            self.buffer_control, height=1, style="class:system-toolbar"  +        )  +  +        self.container = ConditionalContainer(  +            content=self.window, filter=has_focus(self.system_buffer)  +        )  +  +    def _get_display_before_text(self) -> StyleAndTextTuples:  +        return [  +            ("class:system-toolbar", "Shell command: "),  +            ("class:system-toolbar.text", self.system_buffer.text),  +            ("", "\n"),  +        ]  +  +    def _build_key_bindings(self) -> KeyBindingsBase:  +        focused = has_focus(self.system_buffer)  +  +        # Emacs  +        emacs_bindings = KeyBindings()  +        handle = emacs_bindings.add  +  +        @handle("escape", filter=focused)  +        @handle("c-g", filter=focused)  +        @handle("c-c", filter=focused)  +        def _cancel(event: E) -> None:  +            "Hide system prompt."  +            self.system_buffer.reset()  +            event.app.layout.focus_last()  +  +        @handle("enter", filter=focused)  +        async def _accept(event: E) -> None:  +            "Run system command."  +            await event.app.run_system_command(  +                self.system_buffer.text,  +                display_before_text=self._get_display_before_text(),  +            )  +            self.system_buffer.reset(append_to_history=True)  +            event.app.layout.focus_last()  +  +        # Vi.  +        vi_bindings = KeyBindings()  +        handle = vi_bindings.add  +  +        @handle("escape", filter=focused)  +        @handle("c-c", filter=focused)  +        def _cancel_vi(event: E) -> None:  +            "Hide system prompt."  +            event.app.vi_state.input_mode = InputMode.NAVIGATION  +            self.system_buffer.reset()  +            event.app.layout.focus_last()  +  +        @handle("enter", filter=focused)  +        async def _accept_vi(event: E) -> None:  +            "Run system command."  +            event.app.vi_state.input_mode = InputMode.NAVIGATION  +            event.app.run_system_command(  +                self.system_buffer.text,  +                display_before_text=self._get_display_before_text(),  +            )  +            self.system_buffer.reset(append_to_history=True)  +            event.app.layout.focus_last()  +  +        # Global bindings. (Listen to these bindings, even when this widget is  +        # not focussed.)  +        global_bindings = KeyBindings()  +        handle = global_bindings.add  +  +        @handle(Keys.Escape, "!", filter=~focused & emacs_mode, is_global=True)  +        def _focus_me(event: E) -> None:  +            "M-'!' will focus this user control."  +            event.app.layout.focus(self.window)  +  +        @handle("!", filter=~focused & vi_mode & vi_navigation_mode, is_global=True)  +        def _focus_me_vi(event: E) -> None:  +            "Focus."  +            event.app.vi_state.input_mode = InputMode.INSERT  +            event.app.layout.focus(self.window)  +  +        return merge_key_bindings(  +            [  +                ConditionalKeyBindings(emacs_bindings, emacs_mode),  +                ConditionalKeyBindings(vi_bindings, vi_mode),  +                ConditionalKeyBindings(global_bindings, self.enable_global_bindings),  +            ]  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +class ArgToolbar:  +    def __init__(self) -> None:  +        def get_formatted_text() -> StyleAndTextTuples:  +            arg = get_app().key_processor.arg or ""  +            if arg == "-":  +                arg = "-1"  +  +            return [  +                ("class:arg-toolbar", "Repeat: "),  +                ("class:arg-toolbar.text", arg),  +            ]  +  +        self.window = Window(FormattedTextControl(get_formatted_text), height=1)  +  +        self.container = ConditionalContainer(content=self.window, filter=has_arg)  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +class SearchToolbar:  +    """  +    :param vi_mode: Display '/' and '?' instead of I-search.  +    :param ignore_case: Search case insensitive.  +    """  +  +    def __init__(  +        self,  +        search_buffer: Optional[Buffer] = None,  +        vi_mode: bool = False,  +        text_if_not_searching: AnyFormattedText = "",  +        forward_search_prompt: AnyFormattedText = "I-search: ",  +        backward_search_prompt: AnyFormattedText = "I-search backward: ",  +        ignore_case: FilterOrBool = False,  +    ) -> None:  +  +        if search_buffer is None:  +            search_buffer = Buffer()  +  +        @Condition  +        def is_searching() -> bool:  +            return self.control in get_app().layout.search_links  +  +        def get_before_input() -> AnyFormattedText:  +            if not is_searching():  +                return text_if_not_searching  +            elif (  +                self.control.searcher_search_state.direction == SearchDirection.BACKWARD  +            ):  +                return "?" if vi_mode else backward_search_prompt  +            else:  +                return "/" if vi_mode else forward_search_prompt  +  +        self.search_buffer = search_buffer  +  +        self.control = SearchBufferControl(  +            buffer=search_buffer,  +            input_processors=[  +                BeforeInput(get_before_input, style="class:search-toolbar.prompt")  +            ],  +            lexer=SimpleLexer(style="class:search-toolbar.text"),  +            ignore_case=ignore_case,  +        )  +  +        self.container = ConditionalContainer(  +            content=Window(self.control, height=1, style="class:search-toolbar"),  +            filter=is_searching,  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +class _CompletionsToolbarControl(UIControl):  +    def create_content(self, width: int, height: int) -> UIContent:  +        all_fragments: StyleAndTextTuples = []  +  +        complete_state = get_app().current_buffer.complete_state  +        if complete_state:  +            completions = complete_state.completions  +            index = complete_state.complete_index  # Can be None!  +  +            # Width of the completions without the left/right arrows in the margins.  +            content_width = width - 6  +  +            # Booleans indicating whether we stripped from the left/right  +            cut_left = False  +            cut_right = False  +  +            # Create Menu content.  +            fragments: StyleAndTextTuples = []  +  +            for i, c in enumerate(completions):  +                # When there is no more place for the next completion  +                if fragment_list_len(fragments) + len(c.display_text) >= content_width:  +                    # If the current one was not yet displayed, page to the next sequence.  +                    if i <= (index or 0):  +                        fragments = []  +                        cut_left = True  +                    # If the current one is visible, stop here.  +                    else:  +                        cut_right = True  +                        break  +  +                fragments.extend(  +                    to_formatted_text(  +                        c.display_text,  +                        style=(  +                            "class:completion-toolbar.completion.current"  +                            if i == index  +                            else "class:completion-toolbar.completion"  +                        ),  +                    )  +                )  +                fragments.append(("", " "))  +  +            # Extend/strip until the content width.  +            fragments.append(("", " " * (content_width - fragment_list_len(fragments))))  +            fragments = fragments[:content_width]  +  +            # Return fragments  +            all_fragments.append(("", " "))  +            all_fragments.append(  +                ("class:completion-toolbar.arrow", "<" if cut_left else " ")  +            )  +            all_fragments.append(("", " "))  +  +            all_fragments.extend(fragments)  +  +            all_fragments.append(("", " "))  +            all_fragments.append(  +                ("class:completion-toolbar.arrow", ">" if cut_right else " ")  +            )  +            all_fragments.append(("", " "))  +  +        def get_line(i: int) -> StyleAndTextTuples:  +            return all_fragments  +  +        return UIContent(get_line=get_line, line_count=1)  +  +  +class CompletionsToolbar:  +    def __init__(self) -> None:  +        self.container = ConditionalContainer(  +            content=Window(  +                _CompletionsToolbarControl(), height=1, style="class:completion-toolbar"  +            ),  +            filter=has_completions,  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.container  +  +  +class ValidationToolbar:  +    def __init__(self, show_position: bool = False) -> None:  +        def get_formatted_text() -> StyleAndTextTuples:  +            buff = get_app().current_buffer  +  +            if buff.validation_error:  +                row, column = buff.document.translate_index_to_position(  +                    buff.validation_error.cursor_position  +                )  +  +                if show_position:  +                    text = "%s (line=%s column=%s)" % (  +                        buff.validation_error.message,  +                        row + 1,  +                        column + 1,  +                    )  +                else:  +                    text = buff.validation_error.message  +  +                return [("class:validation-toolbar", text)]  +            else:  +                return []  +  +        self.control = FormattedTextControl(get_formatted_text)  +  +        self.container = ConditionalContainer(  +            content=Window(self.control, height=1), filter=has_validation_error  +        )  +  +    def __pt_container__(self) -> Container:  +        return self.container   | 
