1""" 
    2Line editing functionality. 
    3--------------------------- 
    4 
    5This provides a UI for a line input, similar to GNU Readline, libedit and 
    6linenoise. 
    7 
    8Either call the `prompt` function for every line input. Or create an instance 
    9of the :class:`.PromptSession` class and call the `prompt` method from that 
    10class. In the second case, we'll have a 'session' that keeps all the state like 
    11the history in between several calls. 
    12 
    13There is a lot of overlap between the arguments taken by the `prompt` function 
    14and the `PromptSession` (like `completer`, `style`, etcetera). There we have 
    15the freedom to decide which settings we want for the whole 'session', and which 
    16we want for an individual `prompt`. 
    17 
    18Example:: 
    19 
    20        # Simple `prompt` call. 
    21        result = prompt('Say something: ') 
    22 
    23        # Using a 'session'. 
    24        s = PromptSession() 
    25        result = s.prompt('Say something: ') 
    26""" 
    27 
    28from __future__ import annotations 
    29 
    30from asyncio import get_running_loop 
    31from contextlib import contextmanager 
    32from enum import Enum 
    33from functools import partial 
    34from typing import TYPE_CHECKING, Callable, Generic, Iterator, TypeVar, Union, cast 
    35 
    36from prompt_toolkit.application import Application 
    37from prompt_toolkit.application.current import get_app 
    38from prompt_toolkit.auto_suggest import AutoSuggest, DynamicAutoSuggest 
    39from prompt_toolkit.buffer import Buffer 
    40from prompt_toolkit.clipboard import Clipboard, DynamicClipboard, InMemoryClipboard 
    41from prompt_toolkit.completion import Completer, DynamicCompleter, ThreadedCompleter 
    42from prompt_toolkit.cursor_shapes import ( 
    43    AnyCursorShapeConfig, 
    44    CursorShapeConfig, 
    45    DynamicCursorShapeConfig, 
    46) 
    47from prompt_toolkit.document import Document 
    48from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode 
    49from prompt_toolkit.eventloop import InputHook 
    50from prompt_toolkit.filters import ( 
    51    Condition, 
    52    FilterOrBool, 
    53    has_arg, 
    54    has_focus, 
    55    is_done, 
    56    is_true, 
    57    renderer_height_is_known, 
    58    to_filter, 
    59) 
    60from prompt_toolkit.formatted_text import ( 
    61    AnyFormattedText, 
    62    StyleAndTextTuples, 
    63    fragment_list_to_text, 
    64    merge_formatted_text, 
    65    to_formatted_text, 
    66) 
    67from prompt_toolkit.history import History, InMemoryHistory 
    68from prompt_toolkit.input.base import Input 
    69from prompt_toolkit.key_binding.bindings.auto_suggest import load_auto_suggest_bindings 
    70from prompt_toolkit.key_binding.bindings.completion import ( 
    71    display_completions_like_readline, 
    72) 
    73from prompt_toolkit.key_binding.bindings.open_in_editor import ( 
    74    load_open_in_editor_bindings, 
    75) 
    76from prompt_toolkit.key_binding.key_bindings import ( 
    77    ConditionalKeyBindings, 
    78    DynamicKeyBindings, 
    79    KeyBindings, 
    80    KeyBindingsBase, 
    81    merge_key_bindings, 
    82) 
    83from prompt_toolkit.key_binding.key_processor import KeyPressEvent 
    84from prompt_toolkit.keys import Keys 
    85from prompt_toolkit.layout import Float, FloatContainer, HSplit, Window 
    86from prompt_toolkit.layout.containers import ConditionalContainer, WindowAlign 
    87from prompt_toolkit.layout.controls import ( 
    88    BufferControl, 
    89    FormattedTextControl, 
    90    SearchBufferControl, 
    91) 
    92from prompt_toolkit.layout.dimension import Dimension 
    93from prompt_toolkit.layout.layout import Layout 
    94from prompt_toolkit.layout.menus import CompletionsMenu, MultiColumnCompletionsMenu 
    95from prompt_toolkit.layout.processors import ( 
    96    AfterInput, 
    97    AppendAutoSuggestion, 
    98    ConditionalProcessor, 
    99    DisplayMultipleCursors, 
    100    DynamicProcessor, 
    101    HighlightIncrementalSearchProcessor, 
    102    HighlightSelectionProcessor, 
    103    PasswordProcessor, 
    104    Processor, 
    105    ReverseSearchProcessor, 
    106    merge_processors, 
    107) 
    108from prompt_toolkit.layout.utils import explode_text_fragments 
    109from prompt_toolkit.lexers import DynamicLexer, Lexer 
    110from prompt_toolkit.output import ColorDepth, DummyOutput, Output 
    111from prompt_toolkit.styles import ( 
    112    BaseStyle, 
    113    ConditionalStyleTransformation, 
    114    DynamicStyle, 
    115    DynamicStyleTransformation, 
    116    StyleTransformation, 
    117    SwapLightAndDarkStyleTransformation, 
    118    merge_style_transformations, 
    119) 
    120from prompt_toolkit.utils import ( 
    121    get_cwidth, 
    122    is_dumb_terminal, 
    123    suspend_to_background_supported, 
    124    to_str, 
    125) 
    126from prompt_toolkit.validation import DynamicValidator, Validator 
    127from prompt_toolkit.widgets import Frame 
    128from prompt_toolkit.widgets.toolbars import ( 
    129    SearchToolbar, 
    130    SystemToolbar, 
    131    ValidationToolbar, 
    132) 
    133 
    134if TYPE_CHECKING: 
    135    from prompt_toolkit.formatted_text.base import MagicFormattedText 
    136 
    137__all__ = [ 
    138    "PromptSession", 
    139    "prompt", 
    140    "confirm", 
    141    "create_confirm_session",  # Used by '_display_completions_like_readline'. 
    142    "CompleteStyle", 
    143] 
    144 
    145_StyleAndTextTuplesCallable = Callable[[], StyleAndTextTuples] 
    146E = KeyPressEvent 
    147 
    148 
    149def _split_multiline_prompt( 
    150    get_prompt_text: _StyleAndTextTuplesCallable, 
    151) -> tuple[ 
    152    Callable[[], bool], _StyleAndTextTuplesCallable, _StyleAndTextTuplesCallable 
    153]: 
    154    """ 
    155    Take a `get_prompt_text` function and return three new functions instead. 
    156    One that tells whether this prompt consists of multiple lines; one that 
    157    returns the fragments to be shown on the lines above the input; and another 
    158    one with the fragments to be shown at the first line of the input. 
    159    """ 
    160 
    161    def has_before_fragments() -> bool: 
    162        for fragment, char, *_ in get_prompt_text(): 
    163            if "\n" in char: 
    164                return True 
    165        return False 
    166 
    167    def before() -> StyleAndTextTuples: 
    168        result: StyleAndTextTuples = [] 
    169        found_nl = False 
    170        for fragment, char, *_ in reversed(explode_text_fragments(get_prompt_text())): 
    171            if found_nl: 
    172                result.insert(0, (fragment, char)) 
    173            elif char == "\n": 
    174                found_nl = True 
    175        return result 
    176 
    177    def first_input_line() -> StyleAndTextTuples: 
    178        result: StyleAndTextTuples = [] 
    179        for fragment, char, *_ in reversed(explode_text_fragments(get_prompt_text())): 
    180            if char == "\n": 
    181                break 
    182            else: 
    183                result.insert(0, (fragment, char)) 
    184        return result 
    185 
    186    return has_before_fragments, before, first_input_line 
    187 
    188 
    189class _RPrompt(Window): 
    190    """ 
    191    The prompt that is displayed on the right side of the Window. 
    192    """ 
    193 
    194    def __init__(self, text: AnyFormattedText) -> None: 
    195        super().__init__( 
    196            FormattedTextControl(text=text), 
    197            align=WindowAlign.RIGHT, 
    198            style="class:rprompt", 
    199        ) 
    200 
    201 
    202class CompleteStyle(str, Enum): 
    203    """ 
    204    How to display autocompletions for the prompt. 
    205    """ 
    206 
    207    value: str 
    208 
    209    COLUMN = "COLUMN" 
    210    MULTI_COLUMN = "MULTI_COLUMN" 
    211    READLINE_LIKE = "READLINE_LIKE" 
    212 
    213 
    214# Formatted text for the continuation prompt. It's the same like other 
    215# formatted text, except that if it's a callable, it takes three arguments. 
    216PromptContinuationText = Union[ 
    217    str, 
    218    "MagicFormattedText", 
    219    StyleAndTextTuples, 
    220    # (prompt_width, line_number, wrap_count) -> AnyFormattedText. 
    221    Callable[[int, int, int], AnyFormattedText], 
    222] 
    223 
    224_T = TypeVar("_T") 
    225 
    226 
    227class PromptSession(Generic[_T]): 
    228    """ 
    229    PromptSession for a prompt application, which can be used as a GNU Readline 
    230    replacement. 
    231 
    232    This is a wrapper around a lot of ``prompt_toolkit`` functionality and can 
    233    be a replacement for `raw_input`. 
    234 
    235    All parameters that expect "formatted text" can take either just plain text 
    236    (a unicode object), a list of ``(style_str, text)`` tuples or an HTML object. 
    237 
    238    Example usage:: 
    239 
    240        s = PromptSession(message='>') 
    241        text = s.prompt() 
    242 
    243    :param message: Plain text or formatted text to be shown before the prompt. 
    244        This can also be a callable that returns formatted text. 
    245    :param multiline: `bool` or :class:`~prompt_toolkit.filters.Filter`. 
    246        When True, prefer a layout that is more adapted for multiline input. 
    247        Text after newlines is automatically indented, and search/arg input is 
    248        shown below the input, instead of replacing the prompt. 
    249    :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.Filter`. 
    250        When True (the default), automatically wrap long lines instead of 
    251        scrolling horizontally. 
    252    :param is_password: Show asterisks instead of the actual typed characters. 
    253    :param editing_mode: ``EditingMode.VI`` or ``EditingMode.EMACS``. 
    254    :param vi_mode: `bool`, if True, Identical to ``editing_mode=EditingMode.VI``. 
    255    :param complete_while_typing: `bool` or 
    256        :class:`~prompt_toolkit.filters.Filter`. Enable autocompletion while 
    257        typing. 
    258    :param validate_while_typing: `bool` or 
    259        :class:`~prompt_toolkit.filters.Filter`. Enable input validation while 
    260        typing. 
    261    :param enable_history_search: `bool` or 
    262        :class:`~prompt_toolkit.filters.Filter`. Enable up-arrow parting 
    263        string matching. 
    264    :param search_ignore_case: 
    265        :class:`~prompt_toolkit.filters.Filter`. Search case insensitive. 
    266    :param lexer: :class:`~prompt_toolkit.lexers.Lexer` to be used for the 
    267        syntax highlighting. 
    268    :param validator: :class:`~prompt_toolkit.validation.Validator` instance 
    269        for input validation. 
    270    :param completer: :class:`~prompt_toolkit.completion.Completer` instance 
    271        for input completion. 
    272    :param complete_in_thread: `bool` or 
    273        :class:`~prompt_toolkit.filters.Filter`. Run the completer code in a 
    274        background thread in order to avoid blocking the user interface. 
    275        For ``CompleteStyle.READLINE_LIKE``, this setting has no effect. There 
    276        we always run the completions in the main thread. 
    277    :param reserve_space_for_menu: Space to be reserved for displaying the menu. 
    278        (0 means that no space needs to be reserved.) 
    279    :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest` 
    280        instance for input suggestions. 
    281    :param style: :class:`.Style` instance for the color scheme. 
    282    :param include_default_pygments_style: `bool` or 
    283        :class:`~prompt_toolkit.filters.Filter`. Tell whether the default 
    284        styling for Pygments lexers has to be included. By default, this is 
    285        true, but it is recommended to be disabled if another Pygments style is 
    286        passed as the `style` argument, otherwise, two Pygments styles will be 
    287        merged. 
    288    :param style_transformation: 
    289        :class:`~prompt_toolkit.style.StyleTransformation` instance. 
    290    :param swap_light_and_dark_colors: `bool` or 
    291        :class:`~prompt_toolkit.filters.Filter`. When enabled, apply 
    292        :class:`~prompt_toolkit.style.SwapLightAndDarkStyleTransformation`. 
    293        This is useful for switching between dark and light terminal 
    294        backgrounds. 
    295    :param enable_system_prompt: `bool` or 
    296        :class:`~prompt_toolkit.filters.Filter`. Pressing Meta+'!' will show 
    297        a system prompt. 
    298    :param enable_suspend: `bool` or :class:`~prompt_toolkit.filters.Filter`. 
    299        Enable Control-Z style suspension. 
    300    :param enable_open_in_editor: `bool` or 
    301        :class:`~prompt_toolkit.filters.Filter`. Pressing 'v' in Vi mode or 
    302        C-X C-E in emacs mode will open an external editor. 
    303    :param history: :class:`~prompt_toolkit.history.History` instance. 
    304    :param clipboard: :class:`~prompt_toolkit.clipboard.Clipboard` instance. 
    305        (e.g. :class:`~prompt_toolkit.clipboard.InMemoryClipboard`) 
    306    :param rprompt: Text or formatted text to be displayed on the right side. 
    307        This can also be a callable that returns (formatted) text. 
    308    :param bottom_toolbar: Formatted text or callable that returns formatted 
    309        text to be displayed at the bottom of the screen. 
    310    :param prompt_continuation: Text that needs to be displayed for a multiline 
    311        prompt continuation. This can either be formatted text or a callable 
    312        that takes a `prompt_width`, `line_number` and `wrap_count` as input 
    313        and returns formatted text. When this is `None` (the default), then 
    314        `prompt_width` spaces will be used. 
    315    :param complete_style: ``CompleteStyle.COLUMN``, 
    316        ``CompleteStyle.MULTI_COLUMN`` or ``CompleteStyle.READLINE_LIKE``. 
    317    :param mouse_support: `bool` or :class:`~prompt_toolkit.filters.Filter` 
    318        to enable mouse support. 
    319    :param placeholder: Text to be displayed when no input has been given 
    320        yet. Unlike the `default` parameter, this won't be returned as part of 
    321        the output ever. This can be formatted text or a callable that returns 
    322        formatted text. 
    323    :param show_frame: `bool` or 
    324        :class:`~prompt_toolkit.filters.Filter`. When True, surround the input 
    325        with a frame. 
    326    :param refresh_interval: (number; in seconds) When given, refresh the UI 
    327        every so many seconds. 
    328    :param input: `Input` object. (Note that the preferred way to change the 
    329        input/output is by creating an `AppSession`.) 
    330    :param output: `Output` object. 
    331    :param interrupt_exception: The exception type that will be raised when 
    332        there is a keyboard interrupt (control-c keypress). 
    333    :param eof_exception: The exception type that will be raised when there is 
    334        an end-of-file/exit event (control-d keypress). 
    335    """ 
    336 
    337    _fields = ( 
    338        "message", 
    339        "lexer", 
    340        "completer", 
    341        "complete_in_thread", 
    342        "is_password", 
    343        "editing_mode", 
    344        "key_bindings", 
    345        "is_password", 
    346        "bottom_toolbar", 
    347        "style", 
    348        "style_transformation", 
    349        "swap_light_and_dark_colors", 
    350        "color_depth", 
    351        "cursor", 
    352        "include_default_pygments_style", 
    353        "rprompt", 
    354        "multiline", 
    355        "prompt_continuation", 
    356        "wrap_lines", 
    357        "enable_history_search", 
    358        "search_ignore_case", 
    359        "complete_while_typing", 
    360        "validate_while_typing", 
    361        "complete_style", 
    362        "mouse_support", 
    363        "auto_suggest", 
    364        "clipboard", 
    365        "validator", 
    366        "refresh_interval", 
    367        "input_processors", 
    368        "placeholder", 
    369        "enable_system_prompt", 
    370        "enable_suspend", 
    371        "enable_open_in_editor", 
    372        "reserve_space_for_menu", 
    373        "tempfile_suffix", 
    374        "tempfile", 
    375        "show_frame", 
    376    ) 
    377 
    378    def __init__( 
    379        self, 
    380        message: AnyFormattedText = "", 
    381        *, 
    382        multiline: FilterOrBool = False, 
    383        wrap_lines: FilterOrBool = True, 
    384        is_password: FilterOrBool = False, 
    385        vi_mode: bool = False, 
    386        editing_mode: EditingMode = EditingMode.EMACS, 
    387        complete_while_typing: FilterOrBool = True, 
    388        validate_while_typing: FilterOrBool = True, 
    389        enable_history_search: FilterOrBool = False, 
    390        search_ignore_case: FilterOrBool = False, 
    391        lexer: Lexer | None = None, 
    392        enable_system_prompt: FilterOrBool = False, 
    393        enable_suspend: FilterOrBool = False, 
    394        enable_open_in_editor: FilterOrBool = False, 
    395        validator: Validator | None = None, 
    396        completer: Completer | None = None, 
    397        complete_in_thread: bool = False, 
    398        reserve_space_for_menu: int = 8, 
    399        complete_style: CompleteStyle = CompleteStyle.COLUMN, 
    400        auto_suggest: AutoSuggest | None = None, 
    401        style: BaseStyle | None = None, 
    402        style_transformation: StyleTransformation | None = None, 
    403        swap_light_and_dark_colors: FilterOrBool = False, 
    404        color_depth: ColorDepth | None = None, 
    405        cursor: AnyCursorShapeConfig = None, 
    406        include_default_pygments_style: FilterOrBool = True, 
    407        history: History | None = None, 
    408        clipboard: Clipboard | None = None, 
    409        prompt_continuation: PromptContinuationText | None = None, 
    410        rprompt: AnyFormattedText = None, 
    411        bottom_toolbar: AnyFormattedText = None, 
    412        mouse_support: FilterOrBool = False, 
    413        input_processors: list[Processor] | None = None, 
    414        placeholder: AnyFormattedText | None = None, 
    415        key_bindings: KeyBindingsBase | None = None, 
    416        erase_when_done: bool = False, 
    417        tempfile_suffix: str | Callable[[], str] | None = ".txt", 
    418        tempfile: str | Callable[[], str] | None = None, 
    419        refresh_interval: float = 0, 
    420        show_frame: FilterOrBool = False, 
    421        input: Input | None = None, 
    422        output: Output | None = None, 
    423        interrupt_exception: type[BaseException] = KeyboardInterrupt, 
    424        eof_exception: type[BaseException] = EOFError, 
    425    ) -> None: 
    426        history = history or InMemoryHistory() 
    427        clipboard = clipboard or InMemoryClipboard() 
    428 
    429        # Ensure backwards-compatibility, when `vi_mode` is passed. 
    430        if vi_mode: 
    431            editing_mode = EditingMode.VI 
    432 
    433        # Store all settings in this class. 
    434        self._input = input 
    435        self._output = output 
    436 
    437        # Store attributes. 
    438        # (All except 'editing_mode'.) 
    439        self.message = message 
    440        self.lexer = lexer 
    441        self.completer = completer 
    442        self.complete_in_thread = complete_in_thread 
    443        self.is_password = is_password 
    444        self.key_bindings = key_bindings 
    445        self.bottom_toolbar = bottom_toolbar 
    446        self.style = style 
    447        self.style_transformation = style_transformation 
    448        self.swap_light_and_dark_colors = swap_light_and_dark_colors 
    449        self.color_depth = color_depth 
    450        self.cursor = cursor 
    451        self.include_default_pygments_style = include_default_pygments_style 
    452        self.rprompt = rprompt 
    453        self.multiline = multiline 
    454        self.prompt_continuation = prompt_continuation 
    455        self.wrap_lines = wrap_lines 
    456        self.enable_history_search = enable_history_search 
    457        self.search_ignore_case = search_ignore_case 
    458        self.complete_while_typing = complete_while_typing 
    459        self.validate_while_typing = validate_while_typing 
    460        self.complete_style = complete_style 
    461        self.mouse_support = mouse_support 
    462        self.auto_suggest = auto_suggest 
    463        self.clipboard = clipboard 
    464        self.validator = validator 
    465        self.refresh_interval = refresh_interval 
    466        self.input_processors = input_processors 
    467        self.placeholder = placeholder 
    468        self.enable_system_prompt = enable_system_prompt 
    469        self.enable_suspend = enable_suspend 
    470        self.enable_open_in_editor = enable_open_in_editor 
    471        self.reserve_space_for_menu = reserve_space_for_menu 
    472        self.tempfile_suffix = tempfile_suffix 
    473        self.tempfile = tempfile 
    474        self.show_frame = show_frame 
    475        self.interrupt_exception = interrupt_exception 
    476        self.eof_exception = eof_exception 
    477 
    478        # Create buffers, layout and Application. 
    479        self.history = history 
    480        self.default_buffer = self._create_default_buffer() 
    481        self.search_buffer = self._create_search_buffer() 
    482        self.layout = self._create_layout() 
    483        self.app = self._create_application(editing_mode, erase_when_done) 
    484 
    485    def _dyncond(self, attr_name: str) -> Condition: 
    486        """ 
    487        Dynamically take this setting from this 'PromptSession' class. 
    488        `attr_name` represents an attribute name of this class. Its value 
    489        can either be a boolean or a `Filter`. 
    490 
    491        This returns something that can be used as either a `Filter` 
    492        or `Filter`. 
    493        """ 
    494 
    495        @Condition 
    496        def dynamic() -> bool: 
    497            value = cast(FilterOrBool, getattr(self, attr_name)) 
    498            return to_filter(value)() 
    499 
    500        return dynamic 
    501 
    502    def _create_default_buffer(self) -> Buffer: 
    503        """ 
    504        Create and return the default input buffer. 
    505        """ 
    506        dyncond = self._dyncond 
    507 
    508        # Create buffers list. 
    509        def accept(buff: Buffer) -> bool: 
    510            """Accept the content of the default buffer. This is called when 
    511            the validation succeeds.""" 
    512            cast(Application[str], get_app()).exit( 
    513                result=buff.document.text, style="class:accepted" 
    514            ) 
    515            return True  # Keep text, we call 'reset' later on. 
    516 
    517        return Buffer( 
    518            name=DEFAULT_BUFFER, 
    519            # Make sure that complete_while_typing is disabled when 
    520            # enable_history_search is enabled. (First convert to Filter, 
    521            # to avoid doing bitwise operations on bool objects.) 
    522            complete_while_typing=Condition( 
    523                lambda: is_true(self.complete_while_typing) 
    524                and not is_true(self.enable_history_search) 
    525                and not self.complete_style == CompleteStyle.READLINE_LIKE 
    526            ), 
    527            validate_while_typing=dyncond("validate_while_typing"), 
    528            enable_history_search=dyncond("enable_history_search"), 
    529            validator=DynamicValidator(lambda: self.validator), 
    530            completer=DynamicCompleter( 
    531                lambda: ThreadedCompleter(self.completer) 
    532                if self.complete_in_thread and self.completer 
    533                else self.completer 
    534            ), 
    535            history=self.history, 
    536            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest), 
    537            accept_handler=accept, 
    538            tempfile_suffix=lambda: to_str(self.tempfile_suffix or ""), 
    539            tempfile=lambda: to_str(self.tempfile or ""), 
    540        ) 
    541 
    542    def _create_search_buffer(self) -> Buffer: 
    543        return Buffer(name=SEARCH_BUFFER) 
    544 
    545    def _create_layout(self) -> Layout: 
    546        """ 
    547        Create `Layout` for this prompt. 
    548        """ 
    549        dyncond = self._dyncond 
    550 
    551        # Create functions that will dynamically split the prompt. (If we have 
    552        # a multiline prompt.) 
    553        ( 
    554            has_before_fragments, 
    555            get_prompt_text_1, 
    556            get_prompt_text_2, 
    557        ) = _split_multiline_prompt(self._get_prompt) 
    558 
    559        default_buffer = self.default_buffer 
    560        search_buffer = self.search_buffer 
    561 
    562        # Create processors list. 
    563        @Condition 
    564        def display_placeholder() -> bool: 
    565            return self.placeholder is not None and self.default_buffer.text == "" 
    566 
    567        all_input_processors = [ 
    568            HighlightIncrementalSearchProcessor(), 
    569            HighlightSelectionProcessor(), 
    570            ConditionalProcessor( 
    571                AppendAutoSuggestion(), has_focus(default_buffer) & ~is_done 
    572            ), 
    573            ConditionalProcessor(PasswordProcessor(), dyncond("is_password")), 
    574            DisplayMultipleCursors(), 
    575            # Users can insert processors here. 
    576            DynamicProcessor(lambda: merge_processors(self.input_processors or [])), 
    577            ConditionalProcessor( 
    578                AfterInput(lambda: self.placeholder), 
    579                filter=display_placeholder, 
    580            ), 
    581        ] 
    582 
    583        # Create bottom toolbars. 
    584        bottom_toolbar = ConditionalContainer( 
    585            Window( 
    586                FormattedTextControl( 
    587                    lambda: self.bottom_toolbar, style="class:bottom-toolbar.text" 
    588                ), 
    589                style="class:bottom-toolbar", 
    590                dont_extend_height=True, 
    591                height=Dimension(min=1), 
    592            ), 
    593            filter=Condition(lambda: self.bottom_toolbar is not None) 
    594            & ~is_done 
    595            & renderer_height_is_known, 
    596        ) 
    597 
    598        search_toolbar = SearchToolbar( 
    599            search_buffer, ignore_case=dyncond("search_ignore_case") 
    600        ) 
    601 
    602        search_buffer_control = SearchBufferControl( 
    603            buffer=search_buffer, 
    604            input_processors=[ReverseSearchProcessor()], 
    605            ignore_case=dyncond("search_ignore_case"), 
    606        ) 
    607 
    608        system_toolbar = SystemToolbar( 
    609            enable_global_bindings=dyncond("enable_system_prompt") 
    610        ) 
    611 
    612        def get_search_buffer_control() -> SearchBufferControl: 
    613            "Return the UIControl to be focused when searching start." 
    614            if is_true(self.multiline): 
    615                return search_toolbar.control 
    616            else: 
    617                return search_buffer_control 
    618 
    619        default_buffer_control = BufferControl( 
    620            buffer=default_buffer, 
    621            search_buffer_control=get_search_buffer_control, 
    622            input_processors=all_input_processors, 
    623            include_default_input_processors=False, 
    624            lexer=DynamicLexer(lambda: self.lexer), 
    625            preview_search=True, 
    626        ) 
    627 
    628        default_buffer_window = Window( 
    629            default_buffer_control, 
    630            height=self._get_default_buffer_control_height, 
    631            get_line_prefix=partial( 
    632                self._get_line_prefix, get_prompt_text_2=get_prompt_text_2 
    633            ), 
    634            wrap_lines=dyncond("wrap_lines"), 
    635        ) 
    636 
    637        @Condition 
    638        def multi_column_complete_style() -> bool: 
    639            return self.complete_style == CompleteStyle.MULTI_COLUMN 
    640 
    641        # Build the layout. 
    642 
    643        # The main input, with completion menus floating on top of it. 
    644        main_input_container = FloatContainer( 
    645            HSplit( 
    646                [ 
    647                    ConditionalContainer( 
    648                        Window( 
    649                            FormattedTextControl(get_prompt_text_1), 
    650                            dont_extend_height=True, 
    651                        ), 
    652                        Condition(has_before_fragments), 
    653                    ), 
    654                    ConditionalContainer( 
    655                        default_buffer_window, 
    656                        Condition( 
    657                            lambda: get_app().layout.current_control 
    658                            != search_buffer_control 
    659                        ), 
    660                    ), 
    661                    ConditionalContainer( 
    662                        Window(search_buffer_control), 
    663                        Condition( 
    664                            lambda: get_app().layout.current_control 
    665                            == search_buffer_control 
    666                        ), 
    667                    ), 
    668                ] 
    669            ), 
    670            [ 
    671                # Completion menus. 
    672                # NOTE: Especially the multi-column menu needs to be 
    673                #       transparent, because the shape is not always 
    674                #       rectangular due to the meta-text below the menu. 
    675                Float( 
    676                    xcursor=True, 
    677                    ycursor=True, 
    678                    transparent=True, 
    679                    content=CompletionsMenu( 
    680                        max_height=16, 
    681                        scroll_offset=1, 
    682                        extra_filter=has_focus(default_buffer) 
    683                        & ~multi_column_complete_style, 
    684                    ), 
    685                ), 
    686                Float( 
    687                    xcursor=True, 
    688                    ycursor=True, 
    689                    transparent=True, 
    690                    content=MultiColumnCompletionsMenu( 
    691                        show_meta=True, 
    692                        extra_filter=has_focus(default_buffer) 
    693                        & multi_column_complete_style, 
    694                    ), 
    695                ), 
    696                # The right prompt. 
    697                Float( 
    698                    right=0, 
    699                    top=0, 
    700                    hide_when_covering_content=True, 
    701                    content=_RPrompt(lambda: self.rprompt), 
    702                ), 
    703            ], 
    704        ) 
    705 
    706        layout = HSplit( 
    707            [ 
    708                # Wrap the main input in a frame, if requested. 
    709                ConditionalContainer( 
    710                    Frame(main_input_container), 
    711                    filter=dyncond("show_frame"), 
    712                    alternative_content=main_input_container, 
    713                ), 
    714                ConditionalContainer(ValidationToolbar(), filter=~is_done), 
    715                ConditionalContainer( 
    716                    system_toolbar, dyncond("enable_system_prompt") & ~is_done 
    717                ), 
    718                # In multiline mode, we use two toolbars for 'arg' and 'search'. 
    719                ConditionalContainer( 
    720                    Window(FormattedTextControl(self._get_arg_text), height=1), 
    721                    dyncond("multiline") & has_arg, 
    722                ), 
    723                ConditionalContainer(search_toolbar, dyncond("multiline") & ~is_done), 
    724                bottom_toolbar, 
    725            ] 
    726        ) 
    727 
    728        return Layout(layout, default_buffer_window) 
    729 
    730    def _create_application( 
    731        self, editing_mode: EditingMode, erase_when_done: bool 
    732    ) -> Application[_T]: 
    733        """ 
    734        Create the `Application` object. 
    735        """ 
    736        dyncond = self._dyncond 
    737 
    738        # Default key bindings. 
    739        auto_suggest_bindings = load_auto_suggest_bindings() 
    740        open_in_editor_bindings = load_open_in_editor_bindings() 
    741        prompt_bindings = self._create_prompt_bindings() 
    742 
    743        # Create application 
    744        application: Application[_T] = Application( 
    745            layout=self.layout, 
    746            style=DynamicStyle(lambda: self.style), 
    747            style_transformation=merge_style_transformations( 
    748                [ 
    749                    DynamicStyleTransformation(lambda: self.style_transformation), 
    750                    ConditionalStyleTransformation( 
    751                        SwapLightAndDarkStyleTransformation(), 
    752                        dyncond("swap_light_and_dark_colors"), 
    753                    ), 
    754                ] 
    755            ), 
    756            include_default_pygments_style=dyncond("include_default_pygments_style"), 
    757            clipboard=DynamicClipboard(lambda: self.clipboard), 
    758            key_bindings=merge_key_bindings( 
    759                [ 
    760                    merge_key_bindings( 
    761                        [ 
    762                            auto_suggest_bindings, 
    763                            ConditionalKeyBindings( 
    764                                open_in_editor_bindings, 
    765                                dyncond("enable_open_in_editor") 
    766                                & has_focus(DEFAULT_BUFFER), 
    767                            ), 
    768                            prompt_bindings, 
    769                        ] 
    770                    ), 
    771                    DynamicKeyBindings(lambda: self.key_bindings), 
    772                ] 
    773            ), 
    774            mouse_support=dyncond("mouse_support"), 
    775            editing_mode=editing_mode, 
    776            erase_when_done=erase_when_done, 
    777            reverse_vi_search_direction=True, 
    778            color_depth=lambda: self.color_depth, 
    779            cursor=DynamicCursorShapeConfig(lambda: self.cursor), 
    780            refresh_interval=self.refresh_interval, 
    781            input=self._input, 
    782            output=self._output, 
    783        ) 
    784 
    785        # During render time, make sure that we focus the right search control 
    786        # (if we are searching). - This could be useful if people make the 
    787        # 'multiline' property dynamic. 
    788        """ 
    789        def on_render(app): 
    790            multiline = is_true(self.multiline) 
    791            current_control = app.layout.current_control 
    792 
    793            if multiline: 
    794                if current_control == search_buffer_control: 
    795                    app.layout.current_control = search_toolbar.control 
    796                    app.invalidate() 
    797            else: 
    798                if current_control == search_toolbar.control: 
    799                    app.layout.current_control = search_buffer_control 
    800                    app.invalidate() 
    801 
    802        app.on_render += on_render 
    803        """ 
    804 
    805        return application 
    806 
    807    def _create_prompt_bindings(self) -> KeyBindings: 
    808        """ 
    809        Create the KeyBindings for a prompt application. 
    810        """ 
    811        kb = KeyBindings() 
    812        handle = kb.add 
    813        default_focused = has_focus(DEFAULT_BUFFER) 
    814 
    815        @Condition 
    816        def do_accept() -> bool: 
    817            return not is_true(self.multiline) and self.app.layout.has_focus( 
    818                DEFAULT_BUFFER 
    819            ) 
    820 
    821        @handle("enter", filter=do_accept & default_focused) 
    822        def _accept_input(event: E) -> None: 
    823            "Accept input when enter has been pressed." 
    824            self.default_buffer.validate_and_handle() 
    825 
    826        @Condition 
    827        def readline_complete_style() -> bool: 
    828            return self.complete_style == CompleteStyle.READLINE_LIKE 
    829 
    830        @handle("tab", filter=readline_complete_style & default_focused) 
    831        def _complete_like_readline(event: E) -> None: 
    832            "Display completions (like Readline)." 
    833            display_completions_like_readline(event) 
    834 
    835        @handle("c-c", filter=default_focused) 
    836        @handle("<sigint>") 
    837        def _keyboard_interrupt(event: E) -> None: 
    838            "Abort when Control-C has been pressed." 
    839            event.app.exit(exception=self.interrupt_exception(), style="class:aborting") 
    840 
    841        @Condition 
    842        def ctrl_d_condition() -> bool: 
    843            """Ctrl-D binding is only active when the default buffer is selected 
    844            and empty.""" 
    845            app = get_app() 
    846            return ( 
    847                app.current_buffer.name == DEFAULT_BUFFER 
    848                and not app.current_buffer.text 
    849            ) 
    850 
    851        @handle("c-d", filter=ctrl_d_condition & default_focused) 
    852        def _eof(event: E) -> None: 
    853            "Exit when Control-D has been pressed." 
    854            event.app.exit(exception=self.eof_exception(), style="class:exiting") 
    855 
    856        suspend_supported = Condition(suspend_to_background_supported) 
    857 
    858        @Condition 
    859        def enable_suspend() -> bool: 
    860            return to_filter(self.enable_suspend)() 
    861 
    862        @handle("c-z", filter=suspend_supported & enable_suspend) 
    863        def _suspend(event: E) -> None: 
    864            """ 
    865            Suspend process to background. 
    866            """ 
    867            event.app.suspend_to_background() 
    868 
    869        return kb 
    870 
    871    def prompt( 
    872        self, 
    873        # When any of these arguments are passed, this value is overwritten 
    874        # in this PromptSession. 
    875        message: AnyFormattedText | None = None, 
    876        # `message` should go first, because people call it as 
    877        # positional argument. 
    878        *, 
    879        editing_mode: EditingMode | None = None, 
    880        refresh_interval: float | None = None, 
    881        vi_mode: bool | None = None, 
    882        lexer: Lexer | None = None, 
    883        completer: Completer | None = None, 
    884        complete_in_thread: bool | None = None, 
    885        is_password: bool | None = None, 
    886        key_bindings: KeyBindingsBase | None = None, 
    887        bottom_toolbar: AnyFormattedText | None = None, 
    888        style: BaseStyle | None = None, 
    889        color_depth: ColorDepth | None = None, 
    890        cursor: AnyCursorShapeConfig | None = None, 
    891        include_default_pygments_style: FilterOrBool | None = None, 
    892        style_transformation: StyleTransformation | None = None, 
    893        swap_light_and_dark_colors: FilterOrBool | None = None, 
    894        rprompt: AnyFormattedText | None = None, 
    895        multiline: FilterOrBool | None = None, 
    896        prompt_continuation: PromptContinuationText | None = None, 
    897        wrap_lines: FilterOrBool | None = None, 
    898        enable_history_search: FilterOrBool | None = None, 
    899        search_ignore_case: FilterOrBool | None = None, 
    900        complete_while_typing: FilterOrBool | None = None, 
    901        validate_while_typing: FilterOrBool | None = None, 
    902        complete_style: CompleteStyle | None = None, 
    903        auto_suggest: AutoSuggest | None = None, 
    904        validator: Validator | None = None, 
    905        clipboard: Clipboard | None = None, 
    906        mouse_support: FilterOrBool | None = None, 
    907        input_processors: list[Processor] | None = None, 
    908        placeholder: AnyFormattedText | None = None, 
    909        reserve_space_for_menu: int | None = None, 
    910        enable_system_prompt: FilterOrBool | None = None, 
    911        enable_suspend: FilterOrBool | None = None, 
    912        enable_open_in_editor: FilterOrBool | None = None, 
    913        tempfile_suffix: str | Callable[[], str] | None = None, 
    914        tempfile: str | Callable[[], str] | None = None, 
    915        show_frame: FilterOrBool | None = None, 
    916        # Following arguments are specific to the current `prompt()` call. 
    917        default: str | Document = "", 
    918        accept_default: bool = False, 
    919        pre_run: Callable[[], None] | None = None, 
    920        set_exception_handler: bool = True, 
    921        handle_sigint: bool = True, 
    922        in_thread: bool = False, 
    923        inputhook: InputHook | None = None, 
    924    ) -> _T: 
    925        """ 
    926        Display the prompt. 
    927 
    928        The first set of arguments is a subset of the :class:`~.PromptSession` 
    929        class itself. For these, passing in ``None`` will keep the current 
    930        values that are active in the session. Passing in a value will set the 
    931        attribute for the session, which means that it applies to the current, 
    932        but also to the next prompts. 
    933 
    934        Note that in order to erase a ``Completer``, ``Validator`` or 
    935        ``AutoSuggest``, you can't use ``None``. Instead pass in a 
    936        ``DummyCompleter``, ``DummyValidator`` or ``DummyAutoSuggest`` instance 
    937        respectively. For a ``Lexer`` you can pass in an empty ``SimpleLexer``. 
    938 
    939        Additional arguments, specific for this prompt: 
    940 
    941        :param default: The default input text to be shown. (This can be edited 
    942            by the user). 
    943        :param accept_default: When `True`, automatically accept the default 
    944            value without allowing the user to edit the input. 
    945        :param pre_run: Callable, called at the start of `Application.run`. 
    946        :param in_thread: Run the prompt in a background thread; block the 
    947            current thread. This avoids interference with an event loop in the 
    948            current thread. Like `Application.run(in_thread=True)`. 
    949 
    950        This method will raise ``KeyboardInterrupt`` when control-c has been 
    951        pressed (for abort) and ``EOFError`` when control-d has been pressed 
    952        (for exit). 
    953        """ 
    954        # NOTE: We used to create a backup of the PromptSession attributes and 
    955        #       restore them after exiting the prompt. This code has been 
    956        #       removed, because it was confusing and didn't really serve a use 
    957        #       case. (People were changing `Application.editing_mode` 
    958        #       dynamically and surprised that it was reset after every call.) 
    959 
    960        # NOTE 2: YES, this is a lot of repeation below... 
    961        #         However, it is a very convenient for a user to accept all 
    962        #         these parameters in this `prompt` method as well. We could 
    963        #         use `locals()` and `setattr` to avoid the repetition, but 
    964        #         then we loose the advantage of mypy and pyflakes to be able 
    965        #         to verify the code. 
    966        if message is not None: 
    967            self.message = message 
    968        if editing_mode is not None: 
    969            self.editing_mode = editing_mode 
    970        if refresh_interval is not None: 
    971            self.refresh_interval = refresh_interval 
    972        if vi_mode: 
    973            self.editing_mode = EditingMode.VI 
    974        if lexer is not None: 
    975            self.lexer = lexer 
    976        if completer is not None: 
    977            self.completer = completer 
    978        if complete_in_thread is not None: 
    979            self.complete_in_thread = complete_in_thread 
    980        if is_password is not None: 
    981            self.is_password = is_password 
    982        if key_bindings is not None: 
    983            self.key_bindings = key_bindings 
    984        if bottom_toolbar is not None: 
    985            self.bottom_toolbar = bottom_toolbar 
    986        if style is not None: 
    987            self.style = style 
    988        if color_depth is not None: 
    989            self.color_depth = color_depth 
    990        if cursor is not None: 
    991            self.cursor = cursor 
    992        if include_default_pygments_style is not None: 
    993            self.include_default_pygments_style = include_default_pygments_style 
    994        if style_transformation is not None: 
    995            self.style_transformation = style_transformation 
    996        if swap_light_and_dark_colors is not None: 
    997            self.swap_light_and_dark_colors = swap_light_and_dark_colors 
    998        if rprompt is not None: 
    999            self.rprompt = rprompt 
    1000        if multiline is not None: 
    1001            self.multiline = multiline 
    1002        if prompt_continuation is not None: 
    1003            self.prompt_continuation = prompt_continuation 
    1004        if wrap_lines is not None: 
    1005            self.wrap_lines = wrap_lines 
    1006        if enable_history_search is not None: 
    1007            self.enable_history_search = enable_history_search 
    1008        if search_ignore_case is not None: 
    1009            self.search_ignore_case = search_ignore_case 
    1010        if complete_while_typing is not None: 
    1011            self.complete_while_typing = complete_while_typing 
    1012        if validate_while_typing is not None: 
    1013            self.validate_while_typing = validate_while_typing 
    1014        if complete_style is not None: 
    1015            self.complete_style = complete_style 
    1016        if auto_suggest is not None: 
    1017            self.auto_suggest = auto_suggest 
    1018        if validator is not None: 
    1019            self.validator = validator 
    1020        if clipboard is not None: 
    1021            self.clipboard = clipboard 
    1022        if mouse_support is not None: 
    1023            self.mouse_support = mouse_support 
    1024        if input_processors is not None: 
    1025            self.input_processors = input_processors 
    1026        if placeholder is not None: 
    1027            self.placeholder = placeholder 
    1028        if reserve_space_for_menu is not None: 
    1029            self.reserve_space_for_menu = reserve_space_for_menu 
    1030        if enable_system_prompt is not None: 
    1031            self.enable_system_prompt = enable_system_prompt 
    1032        if enable_suspend is not None: 
    1033            self.enable_suspend = enable_suspend 
    1034        if enable_open_in_editor is not None: 
    1035            self.enable_open_in_editor = enable_open_in_editor 
    1036        if tempfile_suffix is not None: 
    1037            self.tempfile_suffix = tempfile_suffix 
    1038        if tempfile is not None: 
    1039            self.tempfile = tempfile 
    1040        if show_frame is not None: 
    1041            self.show_frame = show_frame 
    1042 
    1043        self._add_pre_run_callables(pre_run, accept_default) 
    1044        self.default_buffer.reset( 
    1045            default if isinstance(default, Document) else Document(default) 
    1046        ) 
    1047        self.app.refresh_interval = self.refresh_interval  # This is not reactive. 
    1048 
    1049        # If we are using the default output, and have a dumb terminal. Use the 
    1050        # dumb prompt. 
    1051        if self._output is None and is_dumb_terminal(): 
    1052            with self._dumb_prompt(self.message) as dump_app: 
    1053                return dump_app.run(in_thread=in_thread, handle_sigint=handle_sigint) 
    1054 
    1055        return self.app.run( 
    1056            set_exception_handler=set_exception_handler, 
    1057            in_thread=in_thread, 
    1058            handle_sigint=handle_sigint, 
    1059            inputhook=inputhook, 
    1060        ) 
    1061 
    1062    @contextmanager 
    1063    def _dumb_prompt(self, message: AnyFormattedText = "") -> Iterator[Application[_T]]: 
    1064        """ 
    1065        Create prompt `Application` for prompt function for dumb terminals. 
    1066 
    1067        Dumb terminals have minimum rendering capabilities. We can only print 
    1068        text to the screen. We can't use colors, and we can't do cursor 
    1069        movements. The Emacs inferior shell is an example of a dumb terminal. 
    1070 
    1071        We will show the prompt, and wait for the input. We still handle arrow 
    1072        keys, and all custom key bindings, but we don't really render the 
    1073        cursor movements. Instead we only print the typed character that's 
    1074        right before the cursor. 
    1075        """ 
    1076        # Send prompt to output. 
    1077        self.output.write(fragment_list_to_text(to_formatted_text(self.message))) 
    1078        self.output.flush() 
    1079 
    1080        # Key bindings for the dumb prompt: mostly the same as the full prompt. 
    1081        key_bindings: KeyBindingsBase = self._create_prompt_bindings() 
    1082        if self.key_bindings: 
    1083            key_bindings = merge_key_bindings([self.key_bindings, key_bindings]) 
    1084 
    1085        # Create and run application. 
    1086        application = cast( 
    1087            Application[_T], 
    1088            Application( 
    1089                input=self.input, 
    1090                output=DummyOutput(), 
    1091                layout=self.layout, 
    1092                key_bindings=key_bindings, 
    1093            ), 
    1094        ) 
    1095 
    1096        def on_text_changed(_: object) -> None: 
    1097            self.output.write(self.default_buffer.document.text_before_cursor[-1:]) 
    1098            self.output.flush() 
    1099 
    1100        self.default_buffer.on_text_changed += on_text_changed 
    1101 
    1102        try: 
    1103            yield application 
    1104        finally: 
    1105            # Render line ending. 
    1106            self.output.write("\r\n") 
    1107            self.output.flush() 
    1108 
    1109            self.default_buffer.on_text_changed -= on_text_changed 
    1110 
    1111    async def prompt_async( 
    1112        self, 
    1113        # When any of these arguments are passed, this value is overwritten 
    1114        # in this PromptSession. 
    1115        message: AnyFormattedText | None = None, 
    1116        # `message` should go first, because people call it as 
    1117        # positional argument. 
    1118        *, 
    1119        editing_mode: EditingMode | None = None, 
    1120        refresh_interval: float | None = None, 
    1121        vi_mode: bool | None = None, 
    1122        lexer: Lexer | None = None, 
    1123        completer: Completer | None = None, 
    1124        complete_in_thread: bool | None = None, 
    1125        is_password: bool | None = None, 
    1126        key_bindings: KeyBindingsBase | None = None, 
    1127        bottom_toolbar: AnyFormattedText | None = None, 
    1128        style: BaseStyle | None = None, 
    1129        color_depth: ColorDepth | None = None, 
    1130        cursor: CursorShapeConfig | None = None, 
    1131        include_default_pygments_style: FilterOrBool | None = None, 
    1132        style_transformation: StyleTransformation | None = None, 
    1133        swap_light_and_dark_colors: FilterOrBool | None = None, 
    1134        rprompt: AnyFormattedText | None = None, 
    1135        multiline: FilterOrBool | None = None, 
    1136        prompt_continuation: PromptContinuationText | None = None, 
    1137        wrap_lines: FilterOrBool | None = None, 
    1138        enable_history_search: FilterOrBool | None = None, 
    1139        search_ignore_case: FilterOrBool | None = None, 
    1140        complete_while_typing: FilterOrBool | None = None, 
    1141        validate_while_typing: FilterOrBool | None = None, 
    1142        complete_style: CompleteStyle | None = None, 
    1143        auto_suggest: AutoSuggest | None = None, 
    1144        validator: Validator | None = None, 
    1145        clipboard: Clipboard | None = None, 
    1146        mouse_support: FilterOrBool | None = None, 
    1147        input_processors: list[Processor] | None = None, 
    1148        placeholder: AnyFormattedText | None = None, 
    1149        reserve_space_for_menu: int | None = None, 
    1150        enable_system_prompt: FilterOrBool | None = None, 
    1151        enable_suspend: FilterOrBool | None = None, 
    1152        enable_open_in_editor: FilterOrBool | None = None, 
    1153        tempfile_suffix: str | Callable[[], str] | None = None, 
    1154        tempfile: str | Callable[[], str] | None = None, 
    1155        show_frame: FilterOrBool = False, 
    1156        # Following arguments are specific to the current `prompt()` call. 
    1157        default: str | Document = "", 
    1158        accept_default: bool = False, 
    1159        pre_run: Callable[[], None] | None = None, 
    1160        set_exception_handler: bool = True, 
    1161        handle_sigint: bool = True, 
    1162    ) -> _T: 
    1163        if message is not None: 
    1164            self.message = message 
    1165        if editing_mode is not None: 
    1166            self.editing_mode = editing_mode 
    1167        if refresh_interval is not None: 
    1168            self.refresh_interval = refresh_interval 
    1169        if vi_mode: 
    1170            self.editing_mode = EditingMode.VI 
    1171        if lexer is not None: 
    1172            self.lexer = lexer 
    1173        if completer is not None: 
    1174            self.completer = completer 
    1175        if complete_in_thread is not None: 
    1176            self.complete_in_thread = complete_in_thread 
    1177        if is_password is not None: 
    1178            self.is_password = is_password 
    1179        if key_bindings is not None: 
    1180            self.key_bindings = key_bindings 
    1181        if bottom_toolbar is not None: 
    1182            self.bottom_toolbar = bottom_toolbar 
    1183        if style is not None: 
    1184            self.style = style 
    1185        if color_depth is not None: 
    1186            self.color_depth = color_depth 
    1187        if cursor is not None: 
    1188            self.cursor = cursor 
    1189        if include_default_pygments_style is not None: 
    1190            self.include_default_pygments_style = include_default_pygments_style 
    1191        if style_transformation is not None: 
    1192            self.style_transformation = style_transformation 
    1193        if swap_light_and_dark_colors is not None: 
    1194            self.swap_light_and_dark_colors = swap_light_and_dark_colors 
    1195        if rprompt is not None: 
    1196            self.rprompt = rprompt 
    1197        if multiline is not None: 
    1198            self.multiline = multiline 
    1199        if prompt_continuation is not None: 
    1200            self.prompt_continuation = prompt_continuation 
    1201        if wrap_lines is not None: 
    1202            self.wrap_lines = wrap_lines 
    1203        if enable_history_search is not None: 
    1204            self.enable_history_search = enable_history_search 
    1205        if search_ignore_case is not None: 
    1206            self.search_ignore_case = search_ignore_case 
    1207        if complete_while_typing is not None: 
    1208            self.complete_while_typing = complete_while_typing 
    1209        if validate_while_typing is not None: 
    1210            self.validate_while_typing = validate_while_typing 
    1211        if complete_style is not None: 
    1212            self.complete_style = complete_style 
    1213        if auto_suggest is not None: 
    1214            self.auto_suggest = auto_suggest 
    1215        if validator is not None: 
    1216            self.validator = validator 
    1217        if clipboard is not None: 
    1218            self.clipboard = clipboard 
    1219        if mouse_support is not None: 
    1220            self.mouse_support = mouse_support 
    1221        if input_processors is not None: 
    1222            self.input_processors = input_processors 
    1223        if placeholder is not None: 
    1224            self.placeholder = placeholder 
    1225        if reserve_space_for_menu is not None: 
    1226            self.reserve_space_for_menu = reserve_space_for_menu 
    1227        if enable_system_prompt is not None: 
    1228            self.enable_system_prompt = enable_system_prompt 
    1229        if enable_suspend is not None: 
    1230            self.enable_suspend = enable_suspend 
    1231        if enable_open_in_editor is not None: 
    1232            self.enable_open_in_editor = enable_open_in_editor 
    1233        if tempfile_suffix is not None: 
    1234            self.tempfile_suffix = tempfile_suffix 
    1235        if tempfile is not None: 
    1236            self.tempfile = tempfile 
    1237        if show_frame is not None: 
    1238            self.show_frame = show_frame 
    1239 
    1240        self._add_pre_run_callables(pre_run, accept_default) 
    1241        self.default_buffer.reset( 
    1242            default if isinstance(default, Document) else Document(default) 
    1243        ) 
    1244        self.app.refresh_interval = self.refresh_interval  # This is not reactive. 
    1245 
    1246        # If we are using the default output, and have a dumb terminal. Use the 
    1247        # dumb prompt. 
    1248        if self._output is None and is_dumb_terminal(): 
    1249            with self._dumb_prompt(self.message) as dump_app: 
    1250                return await dump_app.run_async(handle_sigint=handle_sigint) 
    1251 
    1252        return await self.app.run_async( 
    1253            set_exception_handler=set_exception_handler, handle_sigint=handle_sigint 
    1254        ) 
    1255 
    1256    def _add_pre_run_callables( 
    1257        self, pre_run: Callable[[], None] | None, accept_default: bool 
    1258    ) -> None: 
    1259        def pre_run2() -> None: 
    1260            if pre_run: 
    1261                pre_run() 
    1262 
    1263            if accept_default: 
    1264                # Validate and handle input. We use `call_from_executor` in 
    1265                # order to run it "soon" (during the next iteration of the 
    1266                # event loop), instead of right now. Otherwise, it won't 
    1267                # display the default value. 
    1268                get_running_loop().call_soon(self.default_buffer.validate_and_handle) 
    1269 
    1270        self.app.pre_run_callables.append(pre_run2) 
    1271 
    1272    @property 
    1273    def editing_mode(self) -> EditingMode: 
    1274        return self.app.editing_mode 
    1275 
    1276    @editing_mode.setter 
    1277    def editing_mode(self, value: EditingMode) -> None: 
    1278        self.app.editing_mode = value 
    1279 
    1280    def _get_default_buffer_control_height(self) -> Dimension: 
    1281        # If there is an autocompletion menu to be shown, make sure that our 
    1282        # layout has at least a minimal height in order to display it. 
    1283        if ( 
    1284            self.completer is not None 
    1285            and self.complete_style != CompleteStyle.READLINE_LIKE 
    1286        ): 
    1287            space = self.reserve_space_for_menu 
    1288        else: 
    1289            space = 0 
    1290 
    1291        if space and not get_app().is_done: 
    1292            buff = self.default_buffer 
    1293 
    1294            # Reserve the space, either when there are completions, or when 
    1295            # `complete_while_typing` is true and we expect completions very 
    1296            # soon. 
    1297            if buff.complete_while_typing() or buff.complete_state is not None: 
    1298                return Dimension(min=space) 
    1299 
    1300        return Dimension() 
    1301 
    1302    def _get_prompt(self) -> StyleAndTextTuples: 
    1303        return to_formatted_text(self.message, style="class:prompt") 
    1304 
    1305    def _get_continuation( 
    1306        self, width: int, line_number: int, wrap_count: int 
    1307    ) -> StyleAndTextTuples: 
    1308        """ 
    1309        Insert the prompt continuation. 
    1310 
    1311        :param width: The width that was used for the prompt. (more or less can 
    1312            be used.) 
    1313        :param line_number: 
    1314        :param wrap_count: Amount of times that the line has been wrapped. 
    1315        """ 
    1316        prompt_continuation = self.prompt_continuation 
    1317 
    1318        if callable(prompt_continuation): 
    1319            continuation: AnyFormattedText = prompt_continuation( 
    1320                width, line_number, wrap_count 
    1321            ) 
    1322        else: 
    1323            continuation = prompt_continuation 
    1324 
    1325        # When the continuation prompt is not given, choose the same width as 
    1326        # the actual prompt. 
    1327        if continuation is None and is_true(self.multiline): 
    1328            continuation = " " * width 
    1329 
    1330        return to_formatted_text(continuation, style="class:prompt-continuation") 
    1331 
    1332    def _get_line_prefix( 
    1333        self, 
    1334        line_number: int, 
    1335        wrap_count: int, 
    1336        get_prompt_text_2: _StyleAndTextTuplesCallable, 
    1337    ) -> StyleAndTextTuples: 
    1338        """ 
    1339        Return whatever needs to be inserted before every line. 
    1340        (the prompt, or a line continuation.) 
    1341        """ 
    1342        # First line: display the "arg" or the prompt. 
    1343        if line_number == 0 and wrap_count == 0: 
    1344            if not is_true(self.multiline) and get_app().key_processor.arg is not None: 
    1345                return self._inline_arg() 
    1346            else: 
    1347                return get_prompt_text_2() 
    1348 
    1349        # For the next lines, display the appropriate continuation. 
    1350        prompt_width = get_cwidth(fragment_list_to_text(get_prompt_text_2())) 
    1351        return self._get_continuation(prompt_width, line_number, wrap_count) 
    1352 
    1353    def _get_arg_text(self) -> StyleAndTextTuples: 
    1354        "'arg' toolbar, for in multiline mode." 
    1355        arg = self.app.key_processor.arg 
    1356        if arg is None: 
    1357            # Should not happen because of the `has_arg` filter in the layout. 
    1358            return [] 
    1359 
    1360        if arg == "-": 
    1361            arg = "-1" 
    1362 
    1363        return [("class:arg-toolbar", "Repeat: "), ("class:arg-toolbar.text", arg)] 
    1364 
    1365    def _inline_arg(self) -> StyleAndTextTuples: 
    1366        "'arg' prefix, for in single line mode." 
    1367        app = get_app() 
    1368        if app.key_processor.arg is None: 
    1369            return [] 
    1370        else: 
    1371            arg = app.key_processor.arg 
    1372 
    1373            return [ 
    1374                ("class:prompt.arg", "(arg: "), 
    1375                ("class:prompt.arg.text", str(arg)), 
    1376                ("class:prompt.arg", ") "), 
    1377            ] 
    1378 
    1379    # Expose the Input and Output objects as attributes, mainly for 
    1380    # backward-compatibility. 
    1381 
    1382    @property 
    1383    def input(self) -> Input: 
    1384        return self.app.input 
    1385 
    1386    @property 
    1387    def output(self) -> Output: 
    1388        return self.app.output 
    1389 
    1390 
    1391def prompt( 
    1392    message: AnyFormattedText | None = None, 
    1393    *, 
    1394    history: History | None = None, 
    1395    editing_mode: EditingMode | None = None, 
    1396    refresh_interval: float | None = None, 
    1397    vi_mode: bool | None = None, 
    1398    lexer: Lexer | None = None, 
    1399    completer: Completer | None = None, 
    1400    complete_in_thread: bool | None = None, 
    1401    is_password: bool | None = None, 
    1402    key_bindings: KeyBindingsBase | None = None, 
    1403    bottom_toolbar: AnyFormattedText | None = None, 
    1404    style: BaseStyle | None = None, 
    1405    color_depth: ColorDepth | None = None, 
    1406    cursor: AnyCursorShapeConfig = None, 
    1407    include_default_pygments_style: FilterOrBool | None = None, 
    1408    style_transformation: StyleTransformation | None = None, 
    1409    swap_light_and_dark_colors: FilterOrBool | None = None, 
    1410    rprompt: AnyFormattedText | None = None, 
    1411    multiline: FilterOrBool | None = None, 
    1412    prompt_continuation: PromptContinuationText | None = None, 
    1413    wrap_lines: FilterOrBool | None = None, 
    1414    enable_history_search: FilterOrBool | None = None, 
    1415    search_ignore_case: FilterOrBool | None = None, 
    1416    complete_while_typing: FilterOrBool | None = None, 
    1417    validate_while_typing: FilterOrBool | None = None, 
    1418    complete_style: CompleteStyle | None = None, 
    1419    auto_suggest: AutoSuggest | None = None, 
    1420    validator: Validator | None = None, 
    1421    clipboard: Clipboard | None = None, 
    1422    mouse_support: FilterOrBool | None = None, 
    1423    input_processors: list[Processor] | None = None, 
    1424    placeholder: AnyFormattedText | None = None, 
    1425    reserve_space_for_menu: int | None = None, 
    1426    enable_system_prompt: FilterOrBool | None = None, 
    1427    enable_suspend: FilterOrBool | None = None, 
    1428    enable_open_in_editor: FilterOrBool | None = None, 
    1429    tempfile_suffix: str | Callable[[], str] | None = None, 
    1430    tempfile: str | Callable[[], str] | None = None, 
    1431    show_frame: FilterOrBool | None = None, 
    1432    # Following arguments are specific to the current `prompt()` call. 
    1433    default: str = "", 
    1434    accept_default: bool = False, 
    1435    pre_run: Callable[[], None] | None = None, 
    1436    set_exception_handler: bool = True, 
    1437    handle_sigint: bool = True, 
    1438    in_thread: bool = False, 
    1439    inputhook: InputHook | None = None, 
    1440) -> str: 
    1441    """ 
    1442    The global `prompt` function. This will create a new `PromptSession` 
    1443    instance for every call. 
    1444    """ 
    1445    # The history is the only attribute that has to be passed to the 
    1446    # `PromptSession`, it can't be passed into the `prompt()` method. 
    1447    session: PromptSession[str] = PromptSession(history=history) 
    1448 
    1449    return session.prompt( 
    1450        message, 
    1451        editing_mode=editing_mode, 
    1452        refresh_interval=refresh_interval, 
    1453        vi_mode=vi_mode, 
    1454        lexer=lexer, 
    1455        completer=completer, 
    1456        complete_in_thread=complete_in_thread, 
    1457        is_password=is_password, 
    1458        key_bindings=key_bindings, 
    1459        bottom_toolbar=bottom_toolbar, 
    1460        style=style, 
    1461        color_depth=color_depth, 
    1462        cursor=cursor, 
    1463        include_default_pygments_style=include_default_pygments_style, 
    1464        style_transformation=style_transformation, 
    1465        swap_light_and_dark_colors=swap_light_and_dark_colors, 
    1466        rprompt=rprompt, 
    1467        multiline=multiline, 
    1468        prompt_continuation=prompt_continuation, 
    1469        wrap_lines=wrap_lines, 
    1470        enable_history_search=enable_history_search, 
    1471        search_ignore_case=search_ignore_case, 
    1472        complete_while_typing=complete_while_typing, 
    1473        validate_while_typing=validate_while_typing, 
    1474        complete_style=complete_style, 
    1475        auto_suggest=auto_suggest, 
    1476        validator=validator, 
    1477        clipboard=clipboard, 
    1478        mouse_support=mouse_support, 
    1479        input_processors=input_processors, 
    1480        placeholder=placeholder, 
    1481        reserve_space_for_menu=reserve_space_for_menu, 
    1482        enable_system_prompt=enable_system_prompt, 
    1483        enable_suspend=enable_suspend, 
    1484        enable_open_in_editor=enable_open_in_editor, 
    1485        tempfile_suffix=tempfile_suffix, 
    1486        tempfile=tempfile, 
    1487        show_frame=show_frame, 
    1488        default=default, 
    1489        accept_default=accept_default, 
    1490        pre_run=pre_run, 
    1491        set_exception_handler=set_exception_handler, 
    1492        handle_sigint=handle_sigint, 
    1493        in_thread=in_thread, 
    1494        inputhook=inputhook, 
    1495    ) 
    1496 
    1497 
    1498prompt.__doc__ = PromptSession.prompt.__doc__ 
    1499 
    1500 
    1501def create_confirm_session( 
    1502    message: AnyFormattedText, suffix: str = " (y/n) " 
    1503) -> PromptSession[bool]: 
    1504    """ 
    1505    Create a `PromptSession` object for the 'confirm' function. 
    1506    """ 
    1507    bindings = KeyBindings() 
    1508 
    1509    @bindings.add("y") 
    1510    @bindings.add("Y") 
    1511    def yes(event: E) -> None: 
    1512        session.default_buffer.text = "y" 
    1513        event.app.exit(result=True) 
    1514 
    1515    @bindings.add("n") 
    1516    @bindings.add("N") 
    1517    def no(event: E) -> None: 
    1518        session.default_buffer.text = "n" 
    1519        event.app.exit(result=False) 
    1520 
    1521    @bindings.add(Keys.Any) 
    1522    def _(event: E) -> None: 
    1523        "Disallow inserting other text." 
    1524        pass 
    1525 
    1526    complete_message = merge_formatted_text([message, suffix]) 
    1527    session: PromptSession[bool] = PromptSession( 
    1528        complete_message, key_bindings=bindings 
    1529    ) 
    1530    return session 
    1531 
    1532 
    1533def confirm(message: AnyFormattedText = "Confirm?", suffix: str = " (y/n) ") -> bool: 
    1534    """ 
    1535    Display a confirmation prompt that returns True/False. 
    1536    """ 
    1537    session = create_confirm_session(message, suffix) 
    1538    return session.prompt()