| | """ |
| | Line editing functionality. |
| | --------------------------- |
| | |
| | This provides a UI for a line input, similar to GNU Readline, libedit and |
| | linenoise. |
| | |
| | Either call the `prompt` function for every line input. Or create an instance |
| | of the :class:`.PromptSession` class and call the `prompt` method from that |
| | class. In the second case, we'll have a 'session' that keeps all the state like |
| | the history in between several calls. |
| | |
| | There is a lot of overlap between the arguments taken by the `prompt` function |
| | and the `PromptSession` (like `completer`, `style`, etcetera). There we have |
| | the freedom to decide which settings we want for the whole 'session', and which |
| | we want for an individual `prompt`. |
| | |
| | Example:: |
| | |
| | # Simple `prompt` call. |
| | result = prompt('Say something: ') |
| | |
| | # Using a 'session'. |
| | s = PromptSession() |
| | result = s.prompt('Say something: ') |
| | """ |
| |
|
| | from __future__ import annotations |
| |
|
| | from asyncio import get_running_loop |
| | from contextlib import contextmanager |
| | from enum import Enum |
| | from functools import partial |
| | from typing import TYPE_CHECKING, Callable, Generic, Iterator, TypeVar, Union, cast |
| |
|
| | from prompt_toolkit.application import Application |
| | from prompt_toolkit.application.current import get_app |
| | from prompt_toolkit.auto_suggest import AutoSuggest, DynamicAutoSuggest |
| | from prompt_toolkit.buffer import Buffer |
| | from prompt_toolkit.clipboard import Clipboard, DynamicClipboard, InMemoryClipboard |
| | from prompt_toolkit.completion import Completer, DynamicCompleter, ThreadedCompleter |
| | from prompt_toolkit.cursor_shapes import ( |
| | AnyCursorShapeConfig, |
| | CursorShapeConfig, |
| | DynamicCursorShapeConfig, |
| | ) |
| | from prompt_toolkit.document import Document |
| | from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode |
| | from prompt_toolkit.eventloop import InputHook |
| | from prompt_toolkit.filters import ( |
| | Condition, |
| | FilterOrBool, |
| | has_arg, |
| | has_focus, |
| | is_done, |
| | is_true, |
| | renderer_height_is_known, |
| | to_filter, |
| | ) |
| | from prompt_toolkit.formatted_text import ( |
| | AnyFormattedText, |
| | StyleAndTextTuples, |
| | fragment_list_to_text, |
| | merge_formatted_text, |
| | to_formatted_text, |
| | ) |
| | from prompt_toolkit.history import History, InMemoryHistory |
| | from prompt_toolkit.input.base import Input |
| | from prompt_toolkit.key_binding.bindings.auto_suggest import load_auto_suggest_bindings |
| | from prompt_toolkit.key_binding.bindings.completion import ( |
| | display_completions_like_readline, |
| | ) |
| | from prompt_toolkit.key_binding.bindings.open_in_editor import ( |
| | load_open_in_editor_bindings, |
| | ) |
| | from prompt_toolkit.key_binding.key_bindings import ( |
| | ConditionalKeyBindings, |
| | DynamicKeyBindings, |
| | KeyBindings, |
| | KeyBindingsBase, |
| | merge_key_bindings, |
| | ) |
| | from prompt_toolkit.key_binding.key_processor import KeyPressEvent |
| | from prompt_toolkit.keys import Keys |
| | from prompt_toolkit.layout import Float, FloatContainer, HSplit, Window |
| | from prompt_toolkit.layout.containers import ConditionalContainer, WindowAlign |
| | from prompt_toolkit.layout.controls import ( |
| | BufferControl, |
| | FormattedTextControl, |
| | SearchBufferControl, |
| | ) |
| | from prompt_toolkit.layout.dimension import Dimension |
| | from prompt_toolkit.layout.layout import Layout |
| | from prompt_toolkit.layout.menus import CompletionsMenu, MultiColumnCompletionsMenu |
| | from prompt_toolkit.layout.processors import ( |
| | AfterInput, |
| | AppendAutoSuggestion, |
| | ConditionalProcessor, |
| | DisplayMultipleCursors, |
| | DynamicProcessor, |
| | HighlightIncrementalSearchProcessor, |
| | HighlightSelectionProcessor, |
| | PasswordProcessor, |
| | Processor, |
| | ReverseSearchProcessor, |
| | merge_processors, |
| | ) |
| | from prompt_toolkit.layout.utils import explode_text_fragments |
| | from prompt_toolkit.lexers import DynamicLexer, Lexer |
| | from prompt_toolkit.output import ColorDepth, DummyOutput, Output |
| | from prompt_toolkit.styles import ( |
| | BaseStyle, |
| | ConditionalStyleTransformation, |
| | DynamicStyle, |
| | DynamicStyleTransformation, |
| | StyleTransformation, |
| | SwapLightAndDarkStyleTransformation, |
| | merge_style_transformations, |
| | ) |
| | from prompt_toolkit.utils import ( |
| | get_cwidth, |
| | is_dumb_terminal, |
| | suspend_to_background_supported, |
| | to_str, |
| | ) |
| | from prompt_toolkit.validation import DynamicValidator, Validator |
| | from prompt_toolkit.widgets.toolbars import ( |
| | SearchToolbar, |
| | SystemToolbar, |
| | ValidationToolbar, |
| | ) |
| |
|
| | if TYPE_CHECKING: |
| | from prompt_toolkit.formatted_text.base import MagicFormattedText |
| |
|
| | __all__ = [ |
| | "PromptSession", |
| | "prompt", |
| | "confirm", |
| | "create_confirm_session", |
| | "CompleteStyle", |
| | ] |
| |
|
| | _StyleAndTextTuplesCallable = Callable[[], StyleAndTextTuples] |
| | E = KeyPressEvent |
| |
|
| |
|
| | def _split_multiline_prompt( |
| | get_prompt_text: _StyleAndTextTuplesCallable, |
| | ) -> tuple[ |
| | Callable[[], bool], _StyleAndTextTuplesCallable, _StyleAndTextTuplesCallable |
| | ]: |
| | """ |
| | Take a `get_prompt_text` function and return three new functions instead. |
| | One that tells whether this prompt consists of multiple lines; one that |
| | returns the fragments to be shown on the lines above the input; and another |
| | one with the fragments to be shown at the first line of the input. |
| | """ |
| |
|
| | def has_before_fragments() -> bool: |
| | for fragment, char, *_ in get_prompt_text(): |
| | if "\n" in char: |
| | return True |
| | return False |
| |
|
| | def before() -> StyleAndTextTuples: |
| | result: StyleAndTextTuples = [] |
| | found_nl = False |
| | for fragment, char, *_ in reversed(explode_text_fragments(get_prompt_text())): |
| | if found_nl: |
| | result.insert(0, (fragment, char)) |
| | elif char == "\n": |
| | found_nl = True |
| | return result |
| |
|
| | def first_input_line() -> StyleAndTextTuples: |
| | result: StyleAndTextTuples = [] |
| | for fragment, char, *_ in reversed(explode_text_fragments(get_prompt_text())): |
| | if char == "\n": |
| | break |
| | else: |
| | result.insert(0, (fragment, char)) |
| | return result |
| |
|
| | return has_before_fragments, before, first_input_line |
| |
|
| |
|
| | class _RPrompt(Window): |
| | """ |
| | The prompt that is displayed on the right side of the Window. |
| | """ |
| |
|
| | def __init__(self, text: AnyFormattedText) -> None: |
| | super().__init__( |
| | FormattedTextControl(text=text), |
| | align=WindowAlign.RIGHT, |
| | style="class:rprompt", |
| | ) |
| |
|
| |
|
| | class CompleteStyle(str, Enum): |
| | """ |
| | How to display autocompletions for the prompt. |
| | """ |
| |
|
| | value: str |
| |
|
| | COLUMN = "COLUMN" |
| | MULTI_COLUMN = "MULTI_COLUMN" |
| | READLINE_LIKE = "READLINE_LIKE" |
| |
|
| |
|
| | |
| | |
| | PromptContinuationText = Union[ |
| | str, |
| | "MagicFormattedText", |
| | StyleAndTextTuples, |
| | |
| | Callable[[int, int, int], AnyFormattedText], |
| | ] |
| |
|
| | _T = TypeVar("_T") |
| |
|
| |
|
| | class PromptSession(Generic[_T]): |
| | """ |
| | PromptSession for a prompt application, which can be used as a GNU Readline |
| | replacement. |
| | |
| | This is a wrapper around a lot of ``prompt_toolkit`` functionality and can |
| | be a replacement for `raw_input`. |
| | |
| | All parameters that expect "formatted text" can take either just plain text |
| | (a unicode object), a list of ``(style_str, text)`` tuples or an HTML object. |
| | |
| | Example usage:: |
| | |
| | s = PromptSession(message='>') |
| | text = s.prompt() |
| | |
| | :param message: Plain text or formatted text to be shown before the prompt. |
| | This can also be a callable that returns formatted text. |
| | :param multiline: `bool` or :class:`~prompt_toolkit.filters.Filter`. |
| | When True, prefer a layout that is more adapted for multiline input. |
| | Text after newlines is automatically indented, and search/arg input is |
| | shown below the input, instead of replacing the prompt. |
| | :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.Filter`. |
| | When True (the default), automatically wrap long lines instead of |
| | scrolling horizontally. |
| | :param is_password: Show asterisks instead of the actual typed characters. |
| | :param editing_mode: ``EditingMode.VI`` or ``EditingMode.EMACS``. |
| | :param vi_mode: `bool`, if True, Identical to ``editing_mode=EditingMode.VI``. |
| | :param complete_while_typing: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. Enable autocompletion while |
| | typing. |
| | :param validate_while_typing: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. Enable input validation while |
| | typing. |
| | :param enable_history_search: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. Enable up-arrow parting |
| | string matching. |
| | :param search_ignore_case: |
| | :class:`~prompt_toolkit.filters.Filter`. Search case insensitive. |
| | :param lexer: :class:`~prompt_toolkit.lexers.Lexer` to be used for the |
| | syntax highlighting. |
| | :param validator: :class:`~prompt_toolkit.validation.Validator` instance |
| | for input validation. |
| | :param completer: :class:`~prompt_toolkit.completion.Completer` instance |
| | for input completion. |
| | :param complete_in_thread: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. Run the completer code in a |
| | background thread in order to avoid blocking the user interface. |
| | For ``CompleteStyle.READLINE_LIKE``, this setting has no effect. There |
| | we always run the completions in the main thread. |
| | :param reserve_space_for_menu: Space to be reserved for displaying the menu. |
| | (0 means that no space needs to be reserved.) |
| | :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest` |
| | instance for input suggestions. |
| | :param style: :class:`.Style` instance for the color scheme. |
| | :param include_default_pygments_style: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. Tell whether the default |
| | styling for Pygments lexers has to be included. By default, this is |
| | true, but it is recommended to be disabled if another Pygments style is |
| | passed as the `style` argument, otherwise, two Pygments styles will be |
| | merged. |
| | :param style_transformation: |
| | :class:`~prompt_toolkit.style.StyleTransformation` instance. |
| | :param swap_light_and_dark_colors: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. When enabled, apply |
| | :class:`~prompt_toolkit.style.SwapLightAndDarkStyleTransformation`. |
| | This is useful for switching between dark and light terminal |
| | backgrounds. |
| | :param enable_system_prompt: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. Pressing Meta+'!' will show |
| | a system prompt. |
| | :param enable_suspend: `bool` or :class:`~prompt_toolkit.filters.Filter`. |
| | Enable Control-Z style suspension. |
| | :param enable_open_in_editor: `bool` or |
| | :class:`~prompt_toolkit.filters.Filter`. Pressing 'v' in Vi mode or |
| | C-X C-E in emacs mode will open an external editor. |
| | :param history: :class:`~prompt_toolkit.history.History` instance. |
| | :param clipboard: :class:`~prompt_toolkit.clipboard.Clipboard` instance. |
| | (e.g. :class:`~prompt_toolkit.clipboard.InMemoryClipboard`) |
| | :param rprompt: Text or formatted text to be displayed on the right side. |
| | This can also be a callable that returns (formatted) text. |
| | :param bottom_toolbar: Formatted text or callable which is supposed to |
| | return formatted text. |
| | :param prompt_continuation: Text that needs to be displayed for a multiline |
| | prompt continuation. This can either be formatted text or a callable |
| | that takes a `prompt_width`, `line_number` and `wrap_count` as input |
| | and returns formatted text. When this is `None` (the default), then |
| | `prompt_width` spaces will be used. |
| | :param complete_style: ``CompleteStyle.COLUMN``, |
| | ``CompleteStyle.MULTI_COLUMN`` or ``CompleteStyle.READLINE_LIKE``. |
| | :param mouse_support: `bool` or :class:`~prompt_toolkit.filters.Filter` |
| | to enable mouse support. |
| | :param placeholder: Text to be displayed when no input has been given |
| | yet. Unlike the `default` parameter, this won't be returned as part of |
| | the output ever. This can be formatted text or a callable that returns |
| | formatted text. |
| | :param refresh_interval: (number; in seconds) When given, refresh the UI |
| | every so many seconds. |
| | :param input: `Input` object. (Note that the preferred way to change the |
| | input/output is by creating an `AppSession`.) |
| | :param output: `Output` object. |
| | :param interrupt_exception: The exception type that will be raised when |
| | there is a keyboard interrupt (control-c keypress). |
| | :param eof_exception: The exception type that will be raised when there is |
| | an end-of-file/exit event (control-d keypress). |
| | """ |
| |
|
| | _fields = ( |
| | "message", |
| | "lexer", |
| | "completer", |
| | "complete_in_thread", |
| | "is_password", |
| | "editing_mode", |
| | "key_bindings", |
| | "is_password", |
| | "bottom_toolbar", |
| | "style", |
| | "style_transformation", |
| | "swap_light_and_dark_colors", |
| | "color_depth", |
| | "cursor", |
| | "include_default_pygments_style", |
| | "rprompt", |
| | "multiline", |
| | "prompt_continuation", |
| | "wrap_lines", |
| | "enable_history_search", |
| | "search_ignore_case", |
| | "complete_while_typing", |
| | "validate_while_typing", |
| | "complete_style", |
| | "mouse_support", |
| | "auto_suggest", |
| | "clipboard", |
| | "validator", |
| | "refresh_interval", |
| | "input_processors", |
| | "placeholder", |
| | "enable_system_prompt", |
| | "enable_suspend", |
| | "enable_open_in_editor", |
| | "reserve_space_for_menu", |
| | "tempfile_suffix", |
| | "tempfile", |
| | ) |
| |
|
| | def __init__( |
| | self, |
| | message: AnyFormattedText = "", |
| | *, |
| | multiline: FilterOrBool = False, |
| | wrap_lines: FilterOrBool = True, |
| | is_password: FilterOrBool = False, |
| | vi_mode: bool = False, |
| | editing_mode: EditingMode = EditingMode.EMACS, |
| | complete_while_typing: FilterOrBool = True, |
| | validate_while_typing: FilterOrBool = True, |
| | enable_history_search: FilterOrBool = False, |
| | search_ignore_case: FilterOrBool = False, |
| | lexer: Lexer | None = None, |
| | enable_system_prompt: FilterOrBool = False, |
| | enable_suspend: FilterOrBool = False, |
| | enable_open_in_editor: FilterOrBool = False, |
| | validator: Validator | None = None, |
| | completer: Completer | None = None, |
| | complete_in_thread: bool = False, |
| | reserve_space_for_menu: int = 8, |
| | complete_style: CompleteStyle = CompleteStyle.COLUMN, |
| | auto_suggest: AutoSuggest | None = None, |
| | style: BaseStyle | None = None, |
| | style_transformation: StyleTransformation | None = None, |
| | swap_light_and_dark_colors: FilterOrBool = False, |
| | color_depth: ColorDepth | None = None, |
| | cursor: AnyCursorShapeConfig = None, |
| | include_default_pygments_style: FilterOrBool = True, |
| | history: History | None = None, |
| | clipboard: Clipboard | None = None, |
| | prompt_continuation: PromptContinuationText | None = None, |
| | rprompt: AnyFormattedText = None, |
| | bottom_toolbar: AnyFormattedText = None, |
| | mouse_support: FilterOrBool = False, |
| | input_processors: list[Processor] | None = None, |
| | placeholder: AnyFormattedText | None = None, |
| | key_bindings: KeyBindingsBase | None = None, |
| | erase_when_done: bool = False, |
| | tempfile_suffix: str | Callable[[], str] | None = ".txt", |
| | tempfile: str | Callable[[], str] | None = None, |
| | refresh_interval: float = 0, |
| | input: Input | None = None, |
| | output: Output | None = None, |
| | interrupt_exception: type[BaseException] = KeyboardInterrupt, |
| | eof_exception: type[BaseException] = EOFError, |
| | ) -> None: |
| | history = history or InMemoryHistory() |
| | clipboard = clipboard or InMemoryClipboard() |
| |
|
| | |
| | if vi_mode: |
| | editing_mode = EditingMode.VI |
| |
|
| | |
| | self._input = input |
| | self._output = output |
| |
|
| | |
| | |
| | self.message = message |
| | self.lexer = lexer |
| | self.completer = completer |
| | self.complete_in_thread = complete_in_thread |
| | self.is_password = is_password |
| | self.key_bindings = key_bindings |
| | self.bottom_toolbar = bottom_toolbar |
| | self.style = style |
| | self.style_transformation = style_transformation |
| | self.swap_light_and_dark_colors = swap_light_and_dark_colors |
| | self.color_depth = color_depth |
| | self.cursor = cursor |
| | self.include_default_pygments_style = include_default_pygments_style |
| | self.rprompt = rprompt |
| | self.multiline = multiline |
| | self.prompt_continuation = prompt_continuation |
| | self.wrap_lines = wrap_lines |
| | self.enable_history_search = enable_history_search |
| | self.search_ignore_case = search_ignore_case |
| | self.complete_while_typing = complete_while_typing |
| | self.validate_while_typing = validate_while_typing |
| | self.complete_style = complete_style |
| | self.mouse_support = mouse_support |
| | self.auto_suggest = auto_suggest |
| | self.clipboard = clipboard |
| | self.validator = validator |
| | self.refresh_interval = refresh_interval |
| | self.input_processors = input_processors |
| | self.placeholder = placeholder |
| | self.enable_system_prompt = enable_system_prompt |
| | self.enable_suspend = enable_suspend |
| | self.enable_open_in_editor = enable_open_in_editor |
| | self.reserve_space_for_menu = reserve_space_for_menu |
| | self.tempfile_suffix = tempfile_suffix |
| | self.tempfile = tempfile |
| | self.interrupt_exception = interrupt_exception |
| | self.eof_exception = eof_exception |
| |
|
| | |
| | self.history = history |
| | self.default_buffer = self._create_default_buffer() |
| | self.search_buffer = self._create_search_buffer() |
| | self.layout = self._create_layout() |
| | self.app = self._create_application(editing_mode, erase_when_done) |
| |
|
| | def _dyncond(self, attr_name: str) -> Condition: |
| | """ |
| | Dynamically take this setting from this 'PromptSession' class. |
| | `attr_name` represents an attribute name of this class. Its value |
| | can either be a boolean or a `Filter`. |
| | |
| | This returns something that can be used as either a `Filter` |
| | or `Filter`. |
| | """ |
| |
|
| | @Condition |
| | def dynamic() -> bool: |
| | value = cast(FilterOrBool, getattr(self, attr_name)) |
| | return to_filter(value)() |
| |
|
| | return dynamic |
| |
|
| | def _create_default_buffer(self) -> Buffer: |
| | """ |
| | Create and return the default input buffer. |
| | """ |
| | dyncond = self._dyncond |
| |
|
| | |
| | def accept(buff: Buffer) -> bool: |
| | """Accept the content of the default buffer. This is called when |
| | the validation succeeds.""" |
| | cast(Application[str], get_app()).exit(result=buff.document.text) |
| | return True |
| |
|
| | return Buffer( |
| | name=DEFAULT_BUFFER, |
| | |
| | |
| | |
| | complete_while_typing=Condition( |
| | lambda: is_true(self.complete_while_typing) |
| | and not is_true(self.enable_history_search) |
| | and not self.complete_style == CompleteStyle.READLINE_LIKE |
| | ), |
| | validate_while_typing=dyncond("validate_while_typing"), |
| | enable_history_search=dyncond("enable_history_search"), |
| | validator=DynamicValidator(lambda: self.validator), |
| | completer=DynamicCompleter( |
| | lambda: ThreadedCompleter(self.completer) |
| | if self.complete_in_thread and self.completer |
| | else self.completer |
| | ), |
| | history=self.history, |
| | auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest), |
| | accept_handler=accept, |
| | tempfile_suffix=lambda: to_str(self.tempfile_suffix or ""), |
| | tempfile=lambda: to_str(self.tempfile or ""), |
| | ) |
| |
|
| | def _create_search_buffer(self) -> Buffer: |
| | return Buffer(name=SEARCH_BUFFER) |
| |
|
| | def _create_layout(self) -> Layout: |
| | """ |
| | Create `Layout` for this prompt. |
| | """ |
| | dyncond = self._dyncond |
| |
|
| | |
| | |
| | ( |
| | has_before_fragments, |
| | get_prompt_text_1, |
| | get_prompt_text_2, |
| | ) = _split_multiline_prompt(self._get_prompt) |
| |
|
| | default_buffer = self.default_buffer |
| | search_buffer = self.search_buffer |
| |
|
| | |
| | @Condition |
| | def display_placeholder() -> bool: |
| | return self.placeholder is not None and self.default_buffer.text == "" |
| |
|
| | all_input_processors = [ |
| | HighlightIncrementalSearchProcessor(), |
| | HighlightSelectionProcessor(), |
| | ConditionalProcessor( |
| | AppendAutoSuggestion(), has_focus(default_buffer) & ~is_done |
| | ), |
| | ConditionalProcessor(PasswordProcessor(), dyncond("is_password")), |
| | DisplayMultipleCursors(), |
| | |
| | DynamicProcessor(lambda: merge_processors(self.input_processors or [])), |
| | ConditionalProcessor( |
| | AfterInput(lambda: self.placeholder), |
| | filter=display_placeholder, |
| | ), |
| | ] |
| |
|
| | |
| | bottom_toolbar = ConditionalContainer( |
| | Window( |
| | FormattedTextControl( |
| | lambda: self.bottom_toolbar, style="class:bottom-toolbar.text" |
| | ), |
| | style="class:bottom-toolbar", |
| | dont_extend_height=True, |
| | height=Dimension(min=1), |
| | ), |
| | filter=Condition(lambda: self.bottom_toolbar is not None) |
| | & ~is_done |
| | & renderer_height_is_known, |
| | ) |
| |
|
| | search_toolbar = SearchToolbar( |
| | search_buffer, ignore_case=dyncond("search_ignore_case") |
| | ) |
| |
|
| | search_buffer_control = SearchBufferControl( |
| | buffer=search_buffer, |
| | input_processors=[ReverseSearchProcessor()], |
| | ignore_case=dyncond("search_ignore_case"), |
| | ) |
| |
|
| | system_toolbar = SystemToolbar( |
| | enable_global_bindings=dyncond("enable_system_prompt") |
| | ) |
| |
|
| | def get_search_buffer_control() -> SearchBufferControl: |
| | "Return the UIControl to be focused when searching start." |
| | if is_true(self.multiline): |
| | return search_toolbar.control |
| | else: |
| | return search_buffer_control |
| |
|
| | default_buffer_control = BufferControl( |
| | buffer=default_buffer, |
| | search_buffer_control=get_search_buffer_control, |
| | input_processors=all_input_processors, |
| | include_default_input_processors=False, |
| | lexer=DynamicLexer(lambda: self.lexer), |
| | preview_search=True, |
| | ) |
| |
|
| | default_buffer_window = Window( |
| | default_buffer_control, |
| | height=self._get_default_buffer_control_height, |
| | get_line_prefix=partial( |
| | self._get_line_prefix, get_prompt_text_2=get_prompt_text_2 |
| | ), |
| | wrap_lines=dyncond("wrap_lines"), |
| | ) |
| |
|
| | @Condition |
| | def multi_column_complete_style() -> bool: |
| | return self.complete_style == CompleteStyle.MULTI_COLUMN |
| |
|
| | |
| | layout = HSplit( |
| | [ |
| | |
| | FloatContainer( |
| | HSplit( |
| | [ |
| | ConditionalContainer( |
| | Window( |
| | FormattedTextControl(get_prompt_text_1), |
| | dont_extend_height=True, |
| | ), |
| | Condition(has_before_fragments), |
| | ), |
| | ConditionalContainer( |
| | default_buffer_window, |
| | Condition( |
| | lambda: get_app().layout.current_control |
| | != search_buffer_control |
| | ), |
| | ), |
| | ConditionalContainer( |
| | Window(search_buffer_control), |
| | Condition( |
| | lambda: get_app().layout.current_control |
| | == search_buffer_control |
| | ), |
| | ), |
| | ] |
| | ), |
| | [ |
| | |
| | |
| | |
| | |
| | Float( |
| | xcursor=True, |
| | ycursor=True, |
| | transparent=True, |
| | content=CompletionsMenu( |
| | max_height=16, |
| | scroll_offset=1, |
| | extra_filter=has_focus(default_buffer) |
| | & ~multi_column_complete_style, |
| | ), |
| | ), |
| | Float( |
| | xcursor=True, |
| | ycursor=True, |
| | transparent=True, |
| | content=MultiColumnCompletionsMenu( |
| | show_meta=True, |
| | extra_filter=has_focus(default_buffer) |
| | & multi_column_complete_style, |
| | ), |
| | ), |
| | |
| | Float( |
| | right=0, |
| | top=0, |
| | hide_when_covering_content=True, |
| | content=_RPrompt(lambda: self.rprompt), |
| | ), |
| | ], |
| | ), |
| | ConditionalContainer(ValidationToolbar(), filter=~is_done), |
| | ConditionalContainer( |
| | system_toolbar, dyncond("enable_system_prompt") & ~is_done |
| | ), |
| | |
| | ConditionalContainer( |
| | Window(FormattedTextControl(self._get_arg_text), height=1), |
| | dyncond("multiline") & has_arg, |
| | ), |
| | ConditionalContainer(search_toolbar, dyncond("multiline") & ~is_done), |
| | bottom_toolbar, |
| | ] |
| | ) |
| |
|
| | return Layout(layout, default_buffer_window) |
| |
|
| | def _create_application( |
| | self, editing_mode: EditingMode, erase_when_done: bool |
| | ) -> Application[_T]: |
| | """ |
| | Create the `Application` object. |
| | """ |
| | dyncond = self._dyncond |
| |
|
| | |
| | auto_suggest_bindings = load_auto_suggest_bindings() |
| | open_in_editor_bindings = load_open_in_editor_bindings() |
| | prompt_bindings = self._create_prompt_bindings() |
| |
|
| | |
| | application: Application[_T] = Application( |
| | layout=self.layout, |
| | style=DynamicStyle(lambda: self.style), |
| | style_transformation=merge_style_transformations( |
| | [ |
| | DynamicStyleTransformation(lambda: self.style_transformation), |
| | ConditionalStyleTransformation( |
| | SwapLightAndDarkStyleTransformation(), |
| | dyncond("swap_light_and_dark_colors"), |
| | ), |
| | ] |
| | ), |
| | include_default_pygments_style=dyncond("include_default_pygments_style"), |
| | clipboard=DynamicClipboard(lambda: self.clipboard), |
| | key_bindings=merge_key_bindings( |
| | [ |
| | merge_key_bindings( |
| | [ |
| | auto_suggest_bindings, |
| | ConditionalKeyBindings( |
| | open_in_editor_bindings, |
| | dyncond("enable_open_in_editor") |
| | & has_focus(DEFAULT_BUFFER), |
| | ), |
| | prompt_bindings, |
| | ] |
| | ), |
| | DynamicKeyBindings(lambda: self.key_bindings), |
| | ] |
| | ), |
| | mouse_support=dyncond("mouse_support"), |
| | editing_mode=editing_mode, |
| | erase_when_done=erase_when_done, |
| | reverse_vi_search_direction=True, |
| | color_depth=lambda: self.color_depth, |
| | cursor=DynamicCursorShapeConfig(lambda: self.cursor), |
| | refresh_interval=self.refresh_interval, |
| | input=self._input, |
| | output=self._output, |
| | ) |
| |
|
| | |
| | |
| | |
| | """ |
| | def on_render(app): |
| | multiline = is_true(self.multiline) |
| | current_control = app.layout.current_control |
| | |
| | if multiline: |
| | if current_control == search_buffer_control: |
| | app.layout.current_control = search_toolbar.control |
| | app.invalidate() |
| | else: |
| | if current_control == search_toolbar.control: |
| | app.layout.current_control = search_buffer_control |
| | app.invalidate() |
| | |
| | app.on_render += on_render |
| | """ |
| |
|
| | return application |
| |
|
| | def _create_prompt_bindings(self) -> KeyBindings: |
| | """ |
| | Create the KeyBindings for a prompt application. |
| | """ |
| | kb = KeyBindings() |
| | handle = kb.add |
| | default_focused = has_focus(DEFAULT_BUFFER) |
| |
|
| | @Condition |
| | def do_accept() -> bool: |
| | return not is_true(self.multiline) and self.app.layout.has_focus( |
| | DEFAULT_BUFFER |
| | ) |
| |
|
| | @handle("enter", filter=do_accept & default_focused) |
| | def _accept_input(event: E) -> None: |
| | "Accept input when enter has been pressed." |
| | self.default_buffer.validate_and_handle() |
| |
|
| | @Condition |
| | def readline_complete_style() -> bool: |
| | return self.complete_style == CompleteStyle.READLINE_LIKE |
| |
|
| | @handle("tab", filter=readline_complete_style & default_focused) |
| | def _complete_like_readline(event: E) -> None: |
| | "Display completions (like Readline)." |
| | display_completions_like_readline(event) |
| |
|
| | @handle("c-c", filter=default_focused) |
| | @handle("<sigint>") |
| | def _keyboard_interrupt(event: E) -> None: |
| | "Abort when Control-C has been pressed." |
| | event.app.exit(exception=self.interrupt_exception(), style="class:aborting") |
| |
|
| | @Condition |
| | def ctrl_d_condition() -> bool: |
| | """Ctrl-D binding is only active when the default buffer is selected |
| | and empty.""" |
| | app = get_app() |
| | return ( |
| | app.current_buffer.name == DEFAULT_BUFFER |
| | and not app.current_buffer.text |
| | ) |
| |
|
| | @handle("c-d", filter=ctrl_d_condition & default_focused) |
| | def _eof(event: E) -> None: |
| | "Exit when Control-D has been pressed." |
| | event.app.exit(exception=self.eof_exception(), style="class:exiting") |
| |
|
| | suspend_supported = Condition(suspend_to_background_supported) |
| |
|
| | @Condition |
| | def enable_suspend() -> bool: |
| | return to_filter(self.enable_suspend)() |
| |
|
| | @handle("c-z", filter=suspend_supported & enable_suspend) |
| | def _suspend(event: E) -> None: |
| | """ |
| | Suspend process to background. |
| | """ |
| | event.app.suspend_to_background() |
| |
|
| | return kb |
| |
|
| | def prompt( |
| | self, |
| | |
| | |
| | message: AnyFormattedText | None = None, |
| | |
| | |
| | *, |
| | editing_mode: EditingMode | None = None, |
| | refresh_interval: float | None = None, |
| | vi_mode: bool | None = None, |
| | lexer: Lexer | None = None, |
| | completer: Completer | None = None, |
| | complete_in_thread: bool | None = None, |
| | is_password: bool | None = None, |
| | key_bindings: KeyBindingsBase | None = None, |
| | bottom_toolbar: AnyFormattedText | None = None, |
| | style: BaseStyle | None = None, |
| | color_depth: ColorDepth | None = None, |
| | cursor: AnyCursorShapeConfig | None = None, |
| | include_default_pygments_style: FilterOrBool | None = None, |
| | style_transformation: StyleTransformation | None = None, |
| | swap_light_and_dark_colors: FilterOrBool | None = None, |
| | rprompt: AnyFormattedText | None = None, |
| | multiline: FilterOrBool | None = None, |
| | prompt_continuation: PromptContinuationText | None = None, |
| | wrap_lines: FilterOrBool | None = None, |
| | enable_history_search: FilterOrBool | None = None, |
| | search_ignore_case: FilterOrBool | None = None, |
| | complete_while_typing: FilterOrBool | None = None, |
| | validate_while_typing: FilterOrBool | None = None, |
| | complete_style: CompleteStyle | None = None, |
| | auto_suggest: AutoSuggest | None = None, |
| | validator: Validator | None = None, |
| | clipboard: Clipboard | None = None, |
| | mouse_support: FilterOrBool | None = None, |
| | input_processors: list[Processor] | None = None, |
| | placeholder: AnyFormattedText | None = None, |
| | reserve_space_for_menu: int | None = None, |
| | enable_system_prompt: FilterOrBool | None = None, |
| | enable_suspend: FilterOrBool | None = None, |
| | enable_open_in_editor: FilterOrBool | None = None, |
| | tempfile_suffix: str | Callable[[], str] | None = None, |
| | tempfile: str | Callable[[], str] | None = None, |
| | |
| | default: str | Document = "", |
| | accept_default: bool = False, |
| | pre_run: Callable[[], None] | None = None, |
| | set_exception_handler: bool = True, |
| | handle_sigint: bool = True, |
| | in_thread: bool = False, |
| | inputhook: InputHook | None = None, |
| | ) -> _T: |
| | """ |
| | Display the prompt. |
| | |
| | The first set of arguments is a subset of the :class:`~.PromptSession` |
| | class itself. For these, passing in ``None`` will keep the current |
| | values that are active in the session. Passing in a value will set the |
| | attribute for the session, which means that it applies to the current, |
| | but also to the next prompts. |
| | |
| | Note that in order to erase a ``Completer``, ``Validator`` or |
| | ``AutoSuggest``, you can't use ``None``. Instead pass in a |
| | ``DummyCompleter``, ``DummyValidator`` or ``DummyAutoSuggest`` instance |
| | respectively. For a ``Lexer`` you can pass in an empty ``SimpleLexer``. |
| | |
| | Additional arguments, specific for this prompt: |
| | |
| | :param default: The default input text to be shown. (This can be edited |
| | by the user). |
| | :param accept_default: When `True`, automatically accept the default |
| | value without allowing the user to edit the input. |
| | :param pre_run: Callable, called at the start of `Application.run`. |
| | :param in_thread: Run the prompt in a background thread; block the |
| | current thread. This avoids interference with an event loop in the |
| | current thread. Like `Application.run(in_thread=True)`. |
| | |
| | This method will raise ``KeyboardInterrupt`` when control-c has been |
| | pressed (for abort) and ``EOFError`` when control-d has been pressed |
| | (for exit). |
| | """ |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if message is not None: |
| | self.message = message |
| | if editing_mode is not None: |
| | self.editing_mode = editing_mode |
| | if refresh_interval is not None: |
| | self.refresh_interval = refresh_interval |
| | if vi_mode: |
| | self.editing_mode = EditingMode.VI |
| | if lexer is not None: |
| | self.lexer = lexer |
| | if completer is not None: |
| | self.completer = completer |
| | if complete_in_thread is not None: |
| | self.complete_in_thread = complete_in_thread |
| | if is_password is not None: |
| | self.is_password = is_password |
| | if key_bindings is not None: |
| | self.key_bindings = key_bindings |
| | if bottom_toolbar is not None: |
| | self.bottom_toolbar = bottom_toolbar |
| | if style is not None: |
| | self.style = style |
| | if color_depth is not None: |
| | self.color_depth = color_depth |
| | if cursor is not None: |
| | self.cursor = cursor |
| | if include_default_pygments_style is not None: |
| | self.include_default_pygments_style = include_default_pygments_style |
| | if style_transformation is not None: |
| | self.style_transformation = style_transformation |
| | if swap_light_and_dark_colors is not None: |
| | self.swap_light_and_dark_colors = swap_light_and_dark_colors |
| | if rprompt is not None: |
| | self.rprompt = rprompt |
| | if multiline is not None: |
| | self.multiline = multiline |
| | if prompt_continuation is not None: |
| | self.prompt_continuation = prompt_continuation |
| | if wrap_lines is not None: |
| | self.wrap_lines = wrap_lines |
| | if enable_history_search is not None: |
| | self.enable_history_search = enable_history_search |
| | if search_ignore_case is not None: |
| | self.search_ignore_case = search_ignore_case |
| | if complete_while_typing is not None: |
| | self.complete_while_typing = complete_while_typing |
| | if validate_while_typing is not None: |
| | self.validate_while_typing = validate_while_typing |
| | if complete_style is not None: |
| | self.complete_style = complete_style |
| | if auto_suggest is not None: |
| | self.auto_suggest = auto_suggest |
| | if validator is not None: |
| | self.validator = validator |
| | if clipboard is not None: |
| | self.clipboard = clipboard |
| | if mouse_support is not None: |
| | self.mouse_support = mouse_support |
| | if input_processors is not None: |
| | self.input_processors = input_processors |
| | if placeholder is not None: |
| | self.placeholder = placeholder |
| | if reserve_space_for_menu is not None: |
| | self.reserve_space_for_menu = reserve_space_for_menu |
| | if enable_system_prompt is not None: |
| | self.enable_system_prompt = enable_system_prompt |
| | if enable_suspend is not None: |
| | self.enable_suspend = enable_suspend |
| | if enable_open_in_editor is not None: |
| | self.enable_open_in_editor = enable_open_in_editor |
| | if tempfile_suffix is not None: |
| | self.tempfile_suffix = tempfile_suffix |
| | if tempfile is not None: |
| | self.tempfile = tempfile |
| |
|
| | self._add_pre_run_callables(pre_run, accept_default) |
| | self.default_buffer.reset( |
| | default if isinstance(default, Document) else Document(default) |
| | ) |
| | self.app.refresh_interval = self.refresh_interval |
| |
|
| | |
| | |
| | if self._output is None and is_dumb_terminal(): |
| | with self._dumb_prompt(self.message) as dump_app: |
| | return dump_app.run(in_thread=in_thread, handle_sigint=handle_sigint) |
| |
|
| | return self.app.run( |
| | set_exception_handler=set_exception_handler, |
| | in_thread=in_thread, |
| | handle_sigint=handle_sigint, |
| | inputhook=inputhook, |
| | ) |
| |
|
| | @contextmanager |
| | def _dumb_prompt(self, message: AnyFormattedText = "") -> Iterator[Application[_T]]: |
| | """ |
| | Create prompt `Application` for prompt function for dumb terminals. |
| | |
| | Dumb terminals have minimum rendering capabilities. We can only print |
| | text to the screen. We can't use colors, and we can't do cursor |
| | movements. The Emacs inferior shell is an example of a dumb terminal. |
| | |
| | We will show the prompt, and wait for the input. We still handle arrow |
| | keys, and all custom key bindings, but we don't really render the |
| | cursor movements. Instead we only print the typed character that's |
| | right before the cursor. |
| | """ |
| | |
| | self.output.write(fragment_list_to_text(to_formatted_text(self.message))) |
| | self.output.flush() |
| |
|
| | |
| | key_bindings: KeyBindingsBase = self._create_prompt_bindings() |
| | if self.key_bindings: |
| | key_bindings = merge_key_bindings([self.key_bindings, key_bindings]) |
| |
|
| | |
| | application = cast( |
| | Application[_T], |
| | Application( |
| | input=self.input, |
| | output=DummyOutput(), |
| | layout=self.layout, |
| | key_bindings=key_bindings, |
| | ), |
| | ) |
| |
|
| | def on_text_changed(_: object) -> None: |
| | self.output.write(self.default_buffer.document.text_before_cursor[-1:]) |
| | self.output.flush() |
| |
|
| | self.default_buffer.on_text_changed += on_text_changed |
| |
|
| | try: |
| | yield application |
| | finally: |
| | |
| | self.output.write("\r\n") |
| | self.output.flush() |
| |
|
| | self.default_buffer.on_text_changed -= on_text_changed |
| |
|
| | async def prompt_async( |
| | self, |
| | |
| | |
| | message: AnyFormattedText | None = None, |
| | |
| | |
| | *, |
| | editing_mode: EditingMode | None = None, |
| | refresh_interval: float | None = None, |
| | vi_mode: bool | None = None, |
| | lexer: Lexer | None = None, |
| | completer: Completer | None = None, |
| | complete_in_thread: bool | None = None, |
| | is_password: bool | None = None, |
| | key_bindings: KeyBindingsBase | None = None, |
| | bottom_toolbar: AnyFormattedText | None = None, |
| | style: BaseStyle | None = None, |
| | color_depth: ColorDepth | None = None, |
| | cursor: CursorShapeConfig | None = None, |
| | include_default_pygments_style: FilterOrBool | None = None, |
| | style_transformation: StyleTransformation | None = None, |
| | swap_light_and_dark_colors: FilterOrBool | None = None, |
| | rprompt: AnyFormattedText | None = None, |
| | multiline: FilterOrBool | None = None, |
| | prompt_continuation: PromptContinuationText | None = None, |
| | wrap_lines: FilterOrBool | None = None, |
| | enable_history_search: FilterOrBool | None = None, |
| | search_ignore_case: FilterOrBool | None = None, |
| | complete_while_typing: FilterOrBool | None = None, |
| | validate_while_typing: FilterOrBool | None = None, |
| | complete_style: CompleteStyle | None = None, |
| | auto_suggest: AutoSuggest | None = None, |
| | validator: Validator | None = None, |
| | clipboard: Clipboard | None = None, |
| | mouse_support: FilterOrBool | None = None, |
| | input_processors: list[Processor] | None = None, |
| | placeholder: AnyFormattedText | None = None, |
| | reserve_space_for_menu: int | None = None, |
| | enable_system_prompt: FilterOrBool | None = None, |
| | enable_suspend: FilterOrBool | None = None, |
| | enable_open_in_editor: FilterOrBool | None = None, |
| | tempfile_suffix: str | Callable[[], str] | None = None, |
| | tempfile: str | Callable[[], str] | None = None, |
| | |
| | default: str | Document = "", |
| | accept_default: bool = False, |
| | pre_run: Callable[[], None] | None = None, |
| | set_exception_handler: bool = True, |
| | handle_sigint: bool = True, |
| | ) -> _T: |
| | if message is not None: |
| | self.message = message |
| | if editing_mode is not None: |
| | self.editing_mode = editing_mode |
| | if refresh_interval is not None: |
| | self.refresh_interval = refresh_interval |
| | if vi_mode: |
| | self.editing_mode = EditingMode.VI |
| | if lexer is not None: |
| | self.lexer = lexer |
| | if completer is not None: |
| | self.completer = completer |
| | if complete_in_thread is not None: |
| | self.complete_in_thread = complete_in_thread |
| | if is_password is not None: |
| | self.is_password = is_password |
| | if key_bindings is not None: |
| | self.key_bindings = key_bindings |
| | if bottom_toolbar is not None: |
| | self.bottom_toolbar = bottom_toolbar |
| | if style is not None: |
| | self.style = style |
| | if color_depth is not None: |
| | self.color_depth = color_depth |
| | if cursor is not None: |
| | self.cursor = cursor |
| | if include_default_pygments_style is not None: |
| | self.include_default_pygments_style = include_default_pygments_style |
| | if style_transformation is not None: |
| | self.style_transformation = style_transformation |
| | if swap_light_and_dark_colors is not None: |
| | self.swap_light_and_dark_colors = swap_light_and_dark_colors |
| | if rprompt is not None: |
| | self.rprompt = rprompt |
| | if multiline is not None: |
| | self.multiline = multiline |
| | if prompt_continuation is not None: |
| | self.prompt_continuation = prompt_continuation |
| | if wrap_lines is not None: |
| | self.wrap_lines = wrap_lines |
| | if enable_history_search is not None: |
| | self.enable_history_search = enable_history_search |
| | if search_ignore_case is not None: |
| | self.search_ignore_case = search_ignore_case |
| | if complete_while_typing is not None: |
| | self.complete_while_typing = complete_while_typing |
| | if validate_while_typing is not None: |
| | self.validate_while_typing = validate_while_typing |
| | if complete_style is not None: |
| | self.complete_style = complete_style |
| | if auto_suggest is not None: |
| | self.auto_suggest = auto_suggest |
| | if validator is not None: |
| | self.validator = validator |
| | if clipboard is not None: |
| | self.clipboard = clipboard |
| | if mouse_support is not None: |
| | self.mouse_support = mouse_support |
| | if input_processors is not None: |
| | self.input_processors = input_processors |
| | if placeholder is not None: |
| | self.placeholder = placeholder |
| | if reserve_space_for_menu is not None: |
| | self.reserve_space_for_menu = reserve_space_for_menu |
| | if enable_system_prompt is not None: |
| | self.enable_system_prompt = enable_system_prompt |
| | if enable_suspend is not None: |
| | self.enable_suspend = enable_suspend |
| | if enable_open_in_editor is not None: |
| | self.enable_open_in_editor = enable_open_in_editor |
| | if tempfile_suffix is not None: |
| | self.tempfile_suffix = tempfile_suffix |
| | if tempfile is not None: |
| | self.tempfile = tempfile |
| |
|
| | self._add_pre_run_callables(pre_run, accept_default) |
| | self.default_buffer.reset( |
| | default if isinstance(default, Document) else Document(default) |
| | ) |
| | self.app.refresh_interval = self.refresh_interval |
| |
|
| | |
| | |
| | if self._output is None and is_dumb_terminal(): |
| | with self._dumb_prompt(self.message) as dump_app: |
| | return await dump_app.run_async(handle_sigint=handle_sigint) |
| |
|
| | return await self.app.run_async( |
| | set_exception_handler=set_exception_handler, handle_sigint=handle_sigint |
| | ) |
| |
|
| | def _add_pre_run_callables( |
| | self, pre_run: Callable[[], None] | None, accept_default: bool |
| | ) -> None: |
| | def pre_run2() -> None: |
| | if pre_run: |
| | pre_run() |
| |
|
| | if accept_default: |
| | |
| | |
| | |
| | |
| | get_running_loop().call_soon(self.default_buffer.validate_and_handle) |
| |
|
| | self.app.pre_run_callables.append(pre_run2) |
| |
|
| | @property |
| | def editing_mode(self) -> EditingMode: |
| | return self.app.editing_mode |
| |
|
| | @editing_mode.setter |
| | def editing_mode(self, value: EditingMode) -> None: |
| | self.app.editing_mode = value |
| |
|
| | def _get_default_buffer_control_height(self) -> Dimension: |
| | |
| | |
| | if ( |
| | self.completer is not None |
| | and self.complete_style != CompleteStyle.READLINE_LIKE |
| | ): |
| | space = self.reserve_space_for_menu |
| | else: |
| | space = 0 |
| |
|
| | if space and not get_app().is_done: |
| | buff = self.default_buffer |
| |
|
| | |
| | |
| | |
| | if buff.complete_while_typing() or buff.complete_state is not None: |
| | return Dimension(min=space) |
| |
|
| | return Dimension() |
| |
|
| | def _get_prompt(self) -> StyleAndTextTuples: |
| | return to_formatted_text(self.message, style="class:prompt") |
| |
|
| | def _get_continuation( |
| | self, width: int, line_number: int, wrap_count: int |
| | ) -> StyleAndTextTuples: |
| | """ |
| | Insert the prompt continuation. |
| | |
| | :param width: The width that was used for the prompt. (more or less can |
| | be used.) |
| | :param line_number: |
| | :param wrap_count: Amount of times that the line has been wrapped. |
| | """ |
| | prompt_continuation = self.prompt_continuation |
| |
|
| | if callable(prompt_continuation): |
| | continuation: AnyFormattedText = prompt_continuation( |
| | width, line_number, wrap_count |
| | ) |
| | else: |
| | continuation = prompt_continuation |
| |
|
| | |
| | |
| | if continuation is None and is_true(self.multiline): |
| | continuation = " " * width |
| |
|
| | return to_formatted_text(continuation, style="class:prompt-continuation") |
| |
|
| | def _get_line_prefix( |
| | self, |
| | line_number: int, |
| | wrap_count: int, |
| | get_prompt_text_2: _StyleAndTextTuplesCallable, |
| | ) -> StyleAndTextTuples: |
| | """ |
| | Return whatever needs to be inserted before every line. |
| | (the prompt, or a line continuation.) |
| | """ |
| | |
| | if line_number == 0 and wrap_count == 0: |
| | if not is_true(self.multiline) and get_app().key_processor.arg is not None: |
| | return self._inline_arg() |
| | else: |
| | return get_prompt_text_2() |
| |
|
| | |
| | prompt_width = get_cwidth(fragment_list_to_text(get_prompt_text_2())) |
| | return self._get_continuation(prompt_width, line_number, wrap_count) |
| |
|
| | def _get_arg_text(self) -> StyleAndTextTuples: |
| | "'arg' toolbar, for in multiline mode." |
| | arg = self.app.key_processor.arg |
| | if arg is None: |
| | |
| | return [] |
| |
|
| | if arg == "-": |
| | arg = "-1" |
| |
|
| | return [("class:arg-toolbar", "Repeat: "), ("class:arg-toolbar.text", arg)] |
| |
|
| | def _inline_arg(self) -> StyleAndTextTuples: |
| | "'arg' prefix, for in single line mode." |
| | app = get_app() |
| | if app.key_processor.arg is None: |
| | return [] |
| | else: |
| | arg = app.key_processor.arg |
| |
|
| | return [ |
| | ("class:prompt.arg", "(arg: "), |
| | ("class:prompt.arg.text", str(arg)), |
| | ("class:prompt.arg", ") "), |
| | ] |
| |
|
| | |
| | |
| |
|
| | @property |
| | def input(self) -> Input: |
| | return self.app.input |
| |
|
| | @property |
| | def output(self) -> Output: |
| | return self.app.output |
| |
|
| |
|
| | def prompt( |
| | message: AnyFormattedText | None = None, |
| | *, |
| | history: History | None = None, |
| | editing_mode: EditingMode | None = None, |
| | refresh_interval: float | None = None, |
| | vi_mode: bool | None = None, |
| | lexer: Lexer | None = None, |
| | completer: Completer | None = None, |
| | complete_in_thread: bool | None = None, |
| | is_password: bool | None = None, |
| | key_bindings: KeyBindingsBase | None = None, |
| | bottom_toolbar: AnyFormattedText | None = None, |
| | style: BaseStyle | None = None, |
| | color_depth: ColorDepth | None = None, |
| | cursor: AnyCursorShapeConfig = None, |
| | include_default_pygments_style: FilterOrBool | None = None, |
| | style_transformation: StyleTransformation | None = None, |
| | swap_light_and_dark_colors: FilterOrBool | None = None, |
| | rprompt: AnyFormattedText | None = None, |
| | multiline: FilterOrBool | None = None, |
| | prompt_continuation: PromptContinuationText | None = None, |
| | wrap_lines: FilterOrBool | None = None, |
| | enable_history_search: FilterOrBool | None = None, |
| | search_ignore_case: FilterOrBool | None = None, |
| | complete_while_typing: FilterOrBool | None = None, |
| | validate_while_typing: FilterOrBool | None = None, |
| | complete_style: CompleteStyle | None = None, |
| | auto_suggest: AutoSuggest | None = None, |
| | validator: Validator | None = None, |
| | clipboard: Clipboard | None = None, |
| | mouse_support: FilterOrBool | None = None, |
| | input_processors: list[Processor] | None = None, |
| | placeholder: AnyFormattedText | None = None, |
| | reserve_space_for_menu: int | None = None, |
| | enable_system_prompt: FilterOrBool | None = None, |
| | enable_suspend: FilterOrBool | None = None, |
| | enable_open_in_editor: FilterOrBool | None = None, |
| | tempfile_suffix: str | Callable[[], str] | None = None, |
| | tempfile: str | Callable[[], str] | None = None, |
| | |
| | default: str = "", |
| | accept_default: bool = False, |
| | pre_run: Callable[[], None] | None = None, |
| | set_exception_handler: bool = True, |
| | handle_sigint: bool = True, |
| | in_thread: bool = False, |
| | inputhook: InputHook | None = None, |
| | ) -> str: |
| | """ |
| | The global `prompt` function. This will create a new `PromptSession` |
| | instance for every call. |
| | """ |
| | |
| | |
| | session: PromptSession[str] = PromptSession(history=history) |
| |
|
| | return session.prompt( |
| | message, |
| | editing_mode=editing_mode, |
| | refresh_interval=refresh_interval, |
| | vi_mode=vi_mode, |
| | lexer=lexer, |
| | completer=completer, |
| | complete_in_thread=complete_in_thread, |
| | is_password=is_password, |
| | key_bindings=key_bindings, |
| | bottom_toolbar=bottom_toolbar, |
| | style=style, |
| | color_depth=color_depth, |
| | cursor=cursor, |
| | include_default_pygments_style=include_default_pygments_style, |
| | style_transformation=style_transformation, |
| | swap_light_and_dark_colors=swap_light_and_dark_colors, |
| | rprompt=rprompt, |
| | multiline=multiline, |
| | prompt_continuation=prompt_continuation, |
| | wrap_lines=wrap_lines, |
| | enable_history_search=enable_history_search, |
| | search_ignore_case=search_ignore_case, |
| | complete_while_typing=complete_while_typing, |
| | validate_while_typing=validate_while_typing, |
| | complete_style=complete_style, |
| | auto_suggest=auto_suggest, |
| | validator=validator, |
| | clipboard=clipboard, |
| | mouse_support=mouse_support, |
| | input_processors=input_processors, |
| | placeholder=placeholder, |
| | reserve_space_for_menu=reserve_space_for_menu, |
| | enable_system_prompt=enable_system_prompt, |
| | enable_suspend=enable_suspend, |
| | enable_open_in_editor=enable_open_in_editor, |
| | tempfile_suffix=tempfile_suffix, |
| | tempfile=tempfile, |
| | default=default, |
| | accept_default=accept_default, |
| | pre_run=pre_run, |
| | set_exception_handler=set_exception_handler, |
| | handle_sigint=handle_sigint, |
| | in_thread=in_thread, |
| | inputhook=inputhook, |
| | ) |
| |
|
| |
|
| | prompt.__doc__ = PromptSession.prompt.__doc__ |
| |
|
| |
|
| | def create_confirm_session( |
| | message: str, suffix: str = " (y/n) " |
| | ) -> PromptSession[bool]: |
| | """ |
| | Create a `PromptSession` object for the 'confirm' function. |
| | """ |
| | bindings = KeyBindings() |
| |
|
| | @bindings.add("y") |
| | @bindings.add("Y") |
| | def yes(event: E) -> None: |
| | session.default_buffer.text = "y" |
| | event.app.exit(result=True) |
| |
|
| | @bindings.add("n") |
| | @bindings.add("N") |
| | def no(event: E) -> None: |
| | session.default_buffer.text = "n" |
| | event.app.exit(result=False) |
| |
|
| | @bindings.add(Keys.Any) |
| | def _(event: E) -> None: |
| | "Disallow inserting other text." |
| | pass |
| |
|
| | complete_message = merge_formatted_text([message, suffix]) |
| | session: PromptSession[bool] = PromptSession( |
| | complete_message, key_bindings=bindings |
| | ) |
| | return session |
| |
|
| |
|
| | def confirm(message: str = "Confirm?", suffix: str = " (y/n) ") -> bool: |
| | """ |
| | Display a confirmation prompt that returns True/False. |
| | """ |
| | session = create_confirm_session(message, suffix) |
| | return session.prompt() |
| |
|