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