diff options
author | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/python/prompt-toolkit/py3/prompt_toolkit/shortcuts/prompt.py | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
download | ydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz |
fix ya.make
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/shortcuts/prompt.py')
-rw-r--r-- | contrib/python/prompt-toolkit/py3/prompt_toolkit/shortcuts/prompt.py | 1504 |
1 files changed, 0 insertions, 1504 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/shortcuts/prompt.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/shortcuts/prompt.py deleted file mode 100644 index 4dc1b18d1c..0000000000 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/shortcuts/prompt.py +++ /dev/null @@ -1,1504 +0,0 @@ -""" -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 contextlib import contextmanager -from enum import Enum -from functools import partial -from typing import ( - TYPE_CHECKING, - Callable, - Generic, - Iterator, - List, - Optional, - Tuple, - 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 get_event_loop -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", # Used by '_display_completions_like_readline'. - "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" - - -# Formatted text for the continuation prompt. It's the same like other -# formatted text, except that if it's a callable, it takes three arguments. -PromptContinuationText = Union[ - str, - "MagicFormattedText", - StyleAndTextTuples, - # (prompt_width, line_number, wrap_count) -> AnyFormattedText. - 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. - """ - - _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: Optional[Lexer] = None, - enable_system_prompt: FilterOrBool = False, - enable_suspend: FilterOrBool = False, - enable_open_in_editor: FilterOrBool = False, - validator: Optional[Validator] = None, - completer: Optional[Completer] = None, - complete_in_thread: bool = False, - reserve_space_for_menu: int = 8, - complete_style: CompleteStyle = CompleteStyle.COLUMN, - auto_suggest: Optional[AutoSuggest] = None, - style: Optional[BaseStyle] = None, - style_transformation: Optional[StyleTransformation] = None, - swap_light_and_dark_colors: FilterOrBool = False, - color_depth: Optional[ColorDepth] = None, - cursor: AnyCursorShapeConfig = None, - include_default_pygments_style: FilterOrBool = True, - history: Optional[History] = None, - clipboard: Optional[Clipboard] = None, - prompt_continuation: Optional[PromptContinuationText] = None, - rprompt: AnyFormattedText = None, - bottom_toolbar: AnyFormattedText = None, - mouse_support: FilterOrBool = False, - input_processors: Optional[List[Processor]] = None, - placeholder: Optional[AnyFormattedText] = None, - key_bindings: Optional[KeyBindingsBase] = None, - erase_when_done: bool = False, - tempfile_suffix: Optional[Union[str, Callable[[], str]]] = ".txt", - tempfile: Optional[Union[str, Callable[[], str]]] = None, - refresh_interval: float = 0, - input: Optional[Input] = None, - output: Optional[Output] = None, - ) -> None: - - history = history or InMemoryHistory() - clipboard = clipboard or InMemoryClipboard() - - # Ensure backwards-compatibility, when `vi_mode` is passed. - if vi_mode: - editing_mode = EditingMode.VI - - # Store all settings in this class. - self._input = input - self._output = output - - # Store attributes. - # (All except 'editing_mode'.) - 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 - - # Create buffers, layout and Application. - 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 - - # Create buffers list. - 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 # Keep text, we call 'reset' later on. - - return Buffer( - name=DEFAULT_BUFFER, - # Make sure that complete_while_typing is disabled when - # enable_history_search is enabled. (First convert to Filter, - # to avoid doing bitwise operations on bool objects.) - complete_while_typing=Condition( - lambda: 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 - - # Create functions that will dynamically split the prompt. (If we have - # a multiline prompt.) - ( - has_before_fragments, - get_prompt_text_1, - get_prompt_text_2, - ) = _split_multiline_prompt(self._get_prompt) - - default_buffer = self.default_buffer - search_buffer = self.search_buffer - - # Create processors list. - @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(), - # Users can insert processors here. - DynamicProcessor(lambda: merge_processors(self.input_processors or [])), - ConditionalProcessor( - AfterInput(lambda: self.placeholder), - filter=display_placeholder, - ), - ] - - # Create bottom toolbars. - bottom_toolbar = ConditionalContainer( - Window( - FormattedTextControl( - lambda: self.bottom_toolbar, style="class:bottom-toolbar.text" - ), - style="class:bottom-toolbar", - dont_extend_height=True, - height=Dimension(min=1), - ), - filter=~is_done - & renderer_height_is_known - & Condition(lambda: self.bottom_toolbar is not None), - ) - - search_toolbar = SearchToolbar( - search_buffer, ignore_case=dyncond("search_ignore_case") - ) - - search_buffer_control = SearchBufferControl( - buffer=search_buffer, - input_processors=[ReverseSearchProcessor()], - ignore_case=dyncond("search_ignore_case"), - ) - - system_toolbar = SystemToolbar( - enable_global_bindings=dyncond("enable_system_prompt") - ) - - def get_search_buffer_control() -> 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 - - # Build the layout. - layout = HSplit( - [ - # The main input, with completion menus floating on top of it. - FloatContainer( - HSplit( - [ - ConditionalContainer( - Window( - FormattedTextControl(get_prompt_text_1), - dont_extend_height=True, - ), - Condition(has_before_fragments), - ), - ConditionalContainer( - default_buffer_window, - Condition( - lambda: get_app().layout.current_control - != search_buffer_control - ), - ), - ConditionalContainer( - Window(search_buffer_control), - Condition( - lambda: get_app().layout.current_control - == search_buffer_control - ), - ), - ] - ), - [ - # Completion menus. - # NOTE: Especially the multi-column menu needs to be - # transparent, because the shape is not always - # rectangular due to the meta-text below the menu. - 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, - ), - ), - # The right prompt. - Float( - right=0, - bottom=0, - hide_when_covering_content=True, - content=_RPrompt(lambda: self.rprompt), - ), - ], - ), - ConditionalContainer(ValidationToolbar(), filter=~is_done), - ConditionalContainer( - system_toolbar, dyncond("enable_system_prompt") & ~is_done - ), - # In multiline mode, we use two toolbars for 'arg' and 'search'. - ConditionalContainer( - Window(FormattedTextControl(self._get_arg_text), height=1), - dyncond("multiline") & has_arg, - ), - ConditionalContainer(search_toolbar, dyncond("multiline") & ~is_done), - bottom_toolbar, - ] - ) - - return Layout(layout, default_buffer_window) - - def _create_application( - self, editing_mode: EditingMode, erase_when_done: bool - ) -> Application[_T]: - """ - Create the `Application` object. - """ - dyncond = self._dyncond - - # Default key bindings. - auto_suggest_bindings = load_auto_suggest_bindings() - open_in_editor_bindings = load_open_in_editor_bindings() - prompt_bindings = self._create_prompt_bindings() - - # Create application - application: Application[_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, - ) - - # During render time, make sure that we focus the right search control - # (if we are searching). - This could be useful if people make the - # 'multiline' property dynamic. - """ - def on_render(app): - multiline = 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=KeyboardInterrupt, 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=EOFError, 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, - # When any of these arguments are passed, this value is overwritten - # in this PromptSession. - message: Optional[AnyFormattedText] = None, - # `message` should go first, because people call it as - # positional argument. - *, - editing_mode: Optional[EditingMode] = None, - refresh_interval: Optional[float] = None, - vi_mode: Optional[bool] = None, - lexer: Optional[Lexer] = None, - completer: Optional[Completer] = None, - complete_in_thread: Optional[bool] = None, - is_password: Optional[bool] = None, - key_bindings: Optional[KeyBindingsBase] = None, - bottom_toolbar: Optional[AnyFormattedText] = None, - style: Optional[BaseStyle] = None, - color_depth: Optional[ColorDepth] = None, - cursor: Optional[AnyCursorShapeConfig] = None, - include_default_pygments_style: Optional[FilterOrBool] = None, - style_transformation: Optional[StyleTransformation] = None, - swap_light_and_dark_colors: Optional[FilterOrBool] = None, - rprompt: Optional[AnyFormattedText] = None, - multiline: Optional[FilterOrBool] = None, - prompt_continuation: Optional[PromptContinuationText] = None, - wrap_lines: Optional[FilterOrBool] = None, - enable_history_search: Optional[FilterOrBool] = None, - search_ignore_case: Optional[FilterOrBool] = None, - complete_while_typing: Optional[FilterOrBool] = None, - validate_while_typing: Optional[FilterOrBool] = None, - complete_style: Optional[CompleteStyle] = None, - auto_suggest: Optional[AutoSuggest] = None, - validator: Optional[Validator] = None, - clipboard: Optional[Clipboard] = None, - mouse_support: Optional[FilterOrBool] = None, - input_processors: Optional[List[Processor]] = None, - placeholder: Optional[AnyFormattedText] = None, - reserve_space_for_menu: Optional[int] = None, - enable_system_prompt: Optional[FilterOrBool] = None, - enable_suspend: Optional[FilterOrBool] = None, - enable_open_in_editor: Optional[FilterOrBool] = None, - tempfile_suffix: Optional[Union[str, Callable[[], str]]] = None, - tempfile: Optional[Union[str, Callable[[], str]]] = None, - # Following arguments are specific to the current `prompt()` call. - default: Union[str, Document] = "", - accept_default: bool = False, - pre_run: Optional[Callable[[], None]] = None, - set_exception_handler: bool = True, - handle_sigint: bool = True, - in_thread: bool = False, - ) -> _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). - """ - # NOTE: We used to create a backup of the PromptSession attributes and - # restore them after exiting the prompt. This code has been - # removed, because it was confusing and didn't really serve a use - # case. (People were changing `Application.editing_mode` - # dynamically and surprised that it was reset after every call.) - - # NOTE 2: YES, this is a lot of repeation below... - # However, it is a very convenient for a user to accept all - # these parameters in this `prompt` method as well. We could - # use `locals()` and `setattr` to avoid the repetition, but - # then we loose the advantage of mypy and pyflakes to be able - # to verify the code. - 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 # This is not reactive. - - # If we are using the default output, and have a dumb terminal. Use the - # dumb prompt. - 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, - ) - - @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. - """ - # Send prompt to output. - self.output.write(fragment_list_to_text(to_formatted_text(self.message))) - self.output.flush() - - # Key bindings for the dumb prompt: mostly the same as the full prompt. - key_bindings: KeyBindingsBase = self._create_prompt_bindings() - if self.key_bindings: - key_bindings = merge_key_bindings([self.key_bindings, key_bindings]) - - # Create and run application. - 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: - # Render line ending. - self.output.write("\r\n") - self.output.flush() - - self.default_buffer.on_text_changed -= on_text_changed - - async def prompt_async( - self, - # When any of these arguments are passed, this value is overwritten - # in this PromptSession. - message: Optional[AnyFormattedText] = None, - # `message` should go first, because people call it as - # positional argument. - *, - editing_mode: Optional[EditingMode] = None, - refresh_interval: Optional[float] = None, - vi_mode: Optional[bool] = None, - lexer: Optional[Lexer] = None, - completer: Optional[Completer] = None, - complete_in_thread: Optional[bool] = None, - is_password: Optional[bool] = None, - key_bindings: Optional[KeyBindingsBase] = None, - bottom_toolbar: Optional[AnyFormattedText] = None, - style: Optional[BaseStyle] = None, - color_depth: Optional[ColorDepth] = None, - cursor: Optional[CursorShapeConfig] = None, - include_default_pygments_style: Optional[FilterOrBool] = None, - style_transformation: Optional[StyleTransformation] = None, - swap_light_and_dark_colors: Optional[FilterOrBool] = None, - rprompt: Optional[AnyFormattedText] = None, - multiline: Optional[FilterOrBool] = None, - prompt_continuation: Optional[PromptContinuationText] = None, - wrap_lines: Optional[FilterOrBool] = None, - enable_history_search: Optional[FilterOrBool] = None, - search_ignore_case: Optional[FilterOrBool] = None, - complete_while_typing: Optional[FilterOrBool] = None, - validate_while_typing: Optional[FilterOrBool] = None, - complete_style: Optional[CompleteStyle] = None, - auto_suggest: Optional[AutoSuggest] = None, - validator: Optional[Validator] = None, - clipboard: Optional[Clipboard] = None, - mouse_support: Optional[FilterOrBool] = None, - input_processors: Optional[List[Processor]] = None, - placeholder: Optional[AnyFormattedText] = None, - reserve_space_for_menu: Optional[int] = None, - enable_system_prompt: Optional[FilterOrBool] = None, - enable_suspend: Optional[FilterOrBool] = None, - enable_open_in_editor: Optional[FilterOrBool] = None, - tempfile_suffix: Optional[Union[str, Callable[[], str]]] = None, - tempfile: Optional[Union[str, Callable[[], str]]] = None, - # Following arguments are specific to the current `prompt()` call. - default: Union[str, Document] = "", - accept_default: bool = False, - pre_run: Optional[Callable[[], 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 # This is not reactive. - - # If we are using the default output, and have a dumb terminal. Use the - # dumb prompt. - 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: Optional[Callable[[], None]], accept_default: bool - ) -> None: - def pre_run2() -> None: - if pre_run: - pre_run() - - if accept_default: - # Validate and handle input. We use `call_from_executor` in - # order to run it "soon" (during the next iteration of the - # event loop), instead of right now. Otherwise, it won't - # display the default value. - get_event_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 there is an autocompletion menu to be shown, make sure that our - # layout has at least a minimal height in order to display it. - if ( - 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 - - # Reserve the space, either when there are completions, or when - # `complete_while_typing` is true and we expect completions very - # soon. - if buff.complete_while_typing() or buff.complete_state is not None: - return Dimension(min=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 - - # When the continuation prompt is not given, choose the same width as - # the actual prompt. - 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.) - """ - # First line: display the "arg" or the prompt. - 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() - - # For the next lines, display the appropriate continuation. - 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: - # Should not happen because of the `has_arg` filter in the layout. - 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", ") "), - ] - - # Expose the Input and Output objects as attributes, mainly for - # backward-compatibility. - - @property - def input(self) -> Input: - return self.app.input - - @property - def output(self) -> Output: - return self.app.output - - -def prompt( - message: Optional[AnyFormattedText] = None, - *, - history: Optional[History] = None, - editing_mode: Optional[EditingMode] = None, - refresh_interval: Optional[float] = None, - vi_mode: Optional[bool] = None, - lexer: Optional[Lexer] = None, - completer: Optional[Completer] = None, - complete_in_thread: Optional[bool] = None, - is_password: Optional[bool] = None, - key_bindings: Optional[KeyBindingsBase] = None, - bottom_toolbar: Optional[AnyFormattedText] = None, - style: Optional[BaseStyle] = None, - color_depth: Optional[ColorDepth] = None, - cursor: AnyCursorShapeConfig = None, - include_default_pygments_style: Optional[FilterOrBool] = None, - style_transformation: Optional[StyleTransformation] = None, - swap_light_and_dark_colors: Optional[FilterOrBool] = None, - rprompt: Optional[AnyFormattedText] = None, - multiline: Optional[FilterOrBool] = None, - prompt_continuation: Optional[PromptContinuationText] = None, - wrap_lines: Optional[FilterOrBool] = None, - enable_history_search: Optional[FilterOrBool] = None, - search_ignore_case: Optional[FilterOrBool] = None, - complete_while_typing: Optional[FilterOrBool] = None, - validate_while_typing: Optional[FilterOrBool] = None, - complete_style: Optional[CompleteStyle] = None, - auto_suggest: Optional[AutoSuggest] = None, - validator: Optional[Validator] = None, - clipboard: Optional[Clipboard] = None, - mouse_support: Optional[FilterOrBool] = None, - input_processors: Optional[List[Processor]] = None, - placeholder: Optional[AnyFormattedText] = None, - reserve_space_for_menu: Optional[int] = None, - enable_system_prompt: Optional[FilterOrBool] = None, - enable_suspend: Optional[FilterOrBool] = None, - enable_open_in_editor: Optional[FilterOrBool] = None, - tempfile_suffix: Optional[Union[str, Callable[[], str]]] = None, - tempfile: Optional[Union[str, Callable[[], str]]] = None, - # Following arguments are specific to the current `prompt()` call. - default: str = "", - accept_default: bool = False, - pre_run: Optional[Callable[[], None]] = None, -) -> str: - """ - The global `prompt` function. This will create a new `PromptSession` - instance for every call. - """ - # The history is the only attribute that has to be passed to the - # `PromptSession`, it can't be passed into the `prompt()` method. - 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, - ) - - -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() |