diff options
| author | monster <[email protected]> | 2022-07-07 14:41:37 +0300 |
|---|---|---|
| committer | monster <[email protected]> | 2022-07-07 14:41:37 +0300 |
| commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
| tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets | |
| parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
fix ya.make
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets')
5 files changed, 0 insertions, 1896 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 deleted file mode 100644 index 552d3559488..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/__init__.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -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 deleted file mode 100644 index bd2d3322094..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/base.py +++ /dev/null @@ -1,982 +0,0 @@ -""" -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, - # There is no cursor navigation in a label, so it makes sense to always - # wrap lines by default. - wrap_lines: FilterOrBool = True, - ) -> 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, - wrap_lines=wrap_lines, - ) - - 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 = (f"{{:^{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]], - default_values: Optional[Sequence[_T]] = None, - ) -> None: - assert len(values) > 0 - default_values = default_values or [] - - self.values = values - # current_values will be used in multiple_selection, - # current_value will be used otherwise. - keys: List[_T] = [value for (value, _) in values] - self.current_values: List[_T] = [ - value for value in default_values if value in keys - ] - self.current_value: _T = ( - default_values[0] - if len(default_values) and default_values[0] in keys - else values[0][0] - ) - - # Cursor index: take first selected item or first item otherwise. - if len(self.current_values) > 0: - self._selected_index = keys.index(self.current_values[0]) - else: - 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 - - def __init__( - self, - values: Sequence[Tuple[_T, AnyFormattedText]], - default: Optional[_T] = None, - ) -> None: - if default is None: - default_values = None - else: - default_values = [default] - - super().__init__(values, default_values=default_values) - - -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)] - super().__init__(values=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: - """ - 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 = f"{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 deleted file mode 100644 index 920582b4e68..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/dialogs.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -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 deleted file mode 100644 index 6827ebecc7c..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/menus.py +++ /dev/null @@ -1,374 +0,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", - f"{Border.HORIZONTAL * (menu.width + 3)}", - mouse_handler, - ) - else: - yield ( - style, - f" {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 deleted file mode 100644 index 402ecaa9824..00000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/widgets/toolbars.py +++ /dev/null @@ -1,374 +0,0 @@ -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 - 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() - - # 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 = "{} (line={} column={})".format( - 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 |
