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