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