Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/prompt_toolkit/shortcuts/prompt.py: 18%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

475 statements  

1""" 

2Line editing functionality. 

3--------------------------- 

4 

5This provides a UI for a line input, similar to GNU Readline, libedit and 

6linenoise. 

7 

8Either call the `prompt` function for every line input. Or create an instance 

9of the :class:`.PromptSession` class and call the `prompt` method from that 

10class. In the second case, we'll have a 'session' that keeps all the state like 

11the history in between several calls. 

12 

13There is a lot of overlap between the arguments taken by the `prompt` function 

14and the `PromptSession` (like `completer`, `style`, etcetera). There we have 

15the freedom to decide which settings we want for the whole 'session', and which 

16we want for an individual `prompt`. 

17 

18Example:: 

19 

20 # Simple `prompt` call. 

21 result = prompt('Say something: ') 

22 

23 # Using a 'session'. 

24 s = PromptSession() 

25 result = s.prompt('Say something: ') 

26""" 

27 

28from __future__ import annotations 

29 

30from asyncio import get_running_loop 

31from contextlib import contextmanager 

32from enum import Enum 

33from functools import partial 

34from typing import TYPE_CHECKING, Callable, Generic, Iterator, TypeVar, Union, cast 

35 

36from prompt_toolkit.application import Application 

37from prompt_toolkit.application.current import get_app 

38from prompt_toolkit.auto_suggest import AutoSuggest, DynamicAutoSuggest 

39from prompt_toolkit.buffer import Buffer 

40from prompt_toolkit.clipboard import Clipboard, DynamicClipboard, InMemoryClipboard 

41from prompt_toolkit.completion import Completer, DynamicCompleter, ThreadedCompleter 

42from prompt_toolkit.cursor_shapes import ( 

43 AnyCursorShapeConfig, 

44 CursorShapeConfig, 

45 DynamicCursorShapeConfig, 

46) 

47from prompt_toolkit.document import Document 

48from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode 

49from prompt_toolkit.eventloop import InputHook 

50from prompt_toolkit.filters import ( 

51 Condition, 

52 FilterOrBool, 

53 has_arg, 

54 has_focus, 

55 is_done, 

56 is_true, 

57 renderer_height_is_known, 

58 to_filter, 

59) 

60from prompt_toolkit.formatted_text import ( 

61 AnyFormattedText, 

62 StyleAndTextTuples, 

63 fragment_list_to_text, 

64 merge_formatted_text, 

65 to_formatted_text, 

66) 

67from prompt_toolkit.history import History, InMemoryHistory 

68from prompt_toolkit.input.base import Input 

69from prompt_toolkit.key_binding.bindings.auto_suggest import load_auto_suggest_bindings 

70from prompt_toolkit.key_binding.bindings.completion import ( 

71 display_completions_like_readline, 

72) 

73from prompt_toolkit.key_binding.bindings.open_in_editor import ( 

74 load_open_in_editor_bindings, 

75) 

76from prompt_toolkit.key_binding.key_bindings import ( 

77 ConditionalKeyBindings, 

78 DynamicKeyBindings, 

79 KeyBindings, 

80 KeyBindingsBase, 

81 merge_key_bindings, 

82) 

83from prompt_toolkit.key_binding.key_processor import KeyPressEvent 

84from prompt_toolkit.keys import Keys 

85from prompt_toolkit.layout import Float, FloatContainer, HSplit, Window 

86from prompt_toolkit.layout.containers import ConditionalContainer, WindowAlign 

87from prompt_toolkit.layout.controls import ( 

88 BufferControl, 

89 FormattedTextControl, 

90 SearchBufferControl, 

91) 

92from prompt_toolkit.layout.dimension import Dimension 

93from prompt_toolkit.layout.layout import Layout 

94from prompt_toolkit.layout.menus import CompletionsMenu, MultiColumnCompletionsMenu 

95from prompt_toolkit.layout.processors import ( 

96 AfterInput, 

97 AppendAutoSuggestion, 

98 ConditionalProcessor, 

99 DisplayMultipleCursors, 

100 DynamicProcessor, 

101 HighlightIncrementalSearchProcessor, 

102 HighlightSelectionProcessor, 

103 PasswordProcessor, 

104 Processor, 

105 ReverseSearchProcessor, 

106 merge_processors, 

107) 

108from prompt_toolkit.layout.utils import explode_text_fragments 

109from prompt_toolkit.lexers import DynamicLexer, Lexer 

110from prompt_toolkit.output import ColorDepth, DummyOutput, Output 

111from prompt_toolkit.styles import ( 

112 BaseStyle, 

113 ConditionalStyleTransformation, 

114 DynamicStyle, 

115 DynamicStyleTransformation, 

116 StyleTransformation, 

117 SwapLightAndDarkStyleTransformation, 

118 merge_style_transformations, 

119) 

120from prompt_toolkit.utils import ( 

121 get_cwidth, 

122 is_dumb_terminal, 

123 suspend_to_background_supported, 

124 to_str, 

125) 

126from prompt_toolkit.validation import DynamicValidator, Validator 

127from prompt_toolkit.widgets.toolbars import ( 

128 SearchToolbar, 

129 SystemToolbar, 

130 ValidationToolbar, 

131) 

132 

133if TYPE_CHECKING: 

134 from prompt_toolkit.formatted_text.base import MagicFormattedText 

135 

136__all__ = [ 

137 "PromptSession", 

138 "prompt", 

139 "confirm", 

140 "create_confirm_session", # Used by '_display_completions_like_readline'. 

141 "CompleteStyle", 

142] 

143 

144_StyleAndTextTuplesCallable = Callable[[], StyleAndTextTuples] 

145E = KeyPressEvent 

146 

147 

148def _split_multiline_prompt( 

149 get_prompt_text: _StyleAndTextTuplesCallable, 

150) -> tuple[ 

151 Callable[[], bool], _StyleAndTextTuplesCallable, _StyleAndTextTuplesCallable 

152]: 

153 """ 

154 Take a `get_prompt_text` function and return three new functions instead. 

155 One that tells whether this prompt consists of multiple lines; one that 

156 returns the fragments to be shown on the lines above the input; and another 

157 one with the fragments to be shown at the first line of the input. 

158 """ 

159 

160 def has_before_fragments() -> bool: 

161 for fragment, char, *_ in get_prompt_text(): 

162 if "\n" in char: 

163 return True 

164 return False 

165 

166 def before() -> StyleAndTextTuples: 

167 result: StyleAndTextTuples = [] 

168 found_nl = False 

169 for fragment, char, *_ in reversed(explode_text_fragments(get_prompt_text())): 

170 if found_nl: 

171 result.insert(0, (fragment, char)) 

172 elif char == "\n": 

173 found_nl = True 

174 return result 

175 

176 def first_input_line() -> StyleAndTextTuples: 

177 result: StyleAndTextTuples = [] 

178 for fragment, char, *_ in reversed(explode_text_fragments(get_prompt_text())): 

179 if char == "\n": 

180 break 

181 else: 

182 result.insert(0, (fragment, char)) 

183 return result 

184 

185 return has_before_fragments, before, first_input_line 

186 

187 

188class _RPrompt(Window): 

189 """ 

190 The prompt that is displayed on the right side of the Window. 

191 """ 

192 

193 def __init__(self, text: AnyFormattedText) -> None: 

194 super().__init__( 

195 FormattedTextControl(text=text), 

196 align=WindowAlign.RIGHT, 

197 style="class:rprompt", 

198 ) 

199 

200 

201class CompleteStyle(str, Enum): 

202 """ 

203 How to display autocompletions for the prompt. 

204 """ 

205 

206 value: str 

207 

208 COLUMN = "COLUMN" 

209 MULTI_COLUMN = "MULTI_COLUMN" 

210 READLINE_LIKE = "READLINE_LIKE" 

211 

212 

213# Formatted text for the continuation prompt. It's the same like other 

214# formatted text, except that if it's a callable, it takes three arguments. 

215PromptContinuationText = Union[ 

216 str, 

217 "MagicFormattedText", 

218 StyleAndTextTuples, 

219 # (prompt_width, line_number, wrap_count) -> AnyFormattedText. 

220 Callable[[int, int, int], AnyFormattedText], 

221] 

222 

223_T = TypeVar("_T") 

224 

225 

226class PromptSession(Generic[_T]): 

227 """ 

228 PromptSession for a prompt application, which can be used as a GNU Readline 

229 replacement. 

230 

231 This is a wrapper around a lot of ``prompt_toolkit`` functionality and can 

232 be a replacement for `raw_input`. 

233 

234 All parameters that expect "formatted text" can take either just plain text 

235 (a unicode object), a list of ``(style_str, text)`` tuples or an HTML object. 

236 

237 Example usage:: 

238 

239 s = PromptSession(message='>') 

240 text = s.prompt() 

241 

242 :param message: Plain text or formatted text to be shown before the prompt. 

243 This can also be a callable that returns formatted text. 

244 :param multiline: `bool` or :class:`~prompt_toolkit.filters.Filter`. 

245 When True, prefer a layout that is more adapted for multiline input. 

246 Text after newlines is automatically indented, and search/arg input is 

247 shown below the input, instead of replacing the prompt. 

248 :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.Filter`. 

249 When True (the default), automatically wrap long lines instead of 

250 scrolling horizontally. 

251 :param is_password: Show asterisks instead of the actual typed characters. 

252 :param editing_mode: ``EditingMode.VI`` or ``EditingMode.EMACS``. 

253 :param vi_mode: `bool`, if True, Identical to ``editing_mode=EditingMode.VI``. 

254 :param complete_while_typing: `bool` or 

255 :class:`~prompt_toolkit.filters.Filter`. Enable autocompletion while 

256 typing. 

257 :param validate_while_typing: `bool` or 

258 :class:`~prompt_toolkit.filters.Filter`. Enable input validation while 

259 typing. 

260 :param enable_history_search: `bool` or 

261 :class:`~prompt_toolkit.filters.Filter`. Enable up-arrow parting 

262 string matching. 

263 :param search_ignore_case: 

264 :class:`~prompt_toolkit.filters.Filter`. Search case insensitive. 

265 :param lexer: :class:`~prompt_toolkit.lexers.Lexer` to be used for the 

266 syntax highlighting. 

267 :param validator: :class:`~prompt_toolkit.validation.Validator` instance 

268 for input validation. 

269 :param completer: :class:`~prompt_toolkit.completion.Completer` instance 

270 for input completion. 

271 :param complete_in_thread: `bool` or 

272 :class:`~prompt_toolkit.filters.Filter`. Run the completer code in a 

273 background thread in order to avoid blocking the user interface. 

274 For ``CompleteStyle.READLINE_LIKE``, this setting has no effect. There 

275 we always run the completions in the main thread. 

276 :param reserve_space_for_menu: Space to be reserved for displaying the menu. 

277 (0 means that no space needs to be reserved.) 

278 :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest` 

279 instance for input suggestions. 

280 :param style: :class:`.Style` instance for the color scheme. 

281 :param include_default_pygments_style: `bool` or 

282 :class:`~prompt_toolkit.filters.Filter`. Tell whether the default 

283 styling for Pygments lexers has to be included. By default, this is 

284 true, but it is recommended to be disabled if another Pygments style is 

285 passed as the `style` argument, otherwise, two Pygments styles will be 

286 merged. 

287 :param style_transformation: 

288 :class:`~prompt_toolkit.style.StyleTransformation` instance. 

289 :param swap_light_and_dark_colors: `bool` or 

290 :class:`~prompt_toolkit.filters.Filter`. When enabled, apply 

291 :class:`~prompt_toolkit.style.SwapLightAndDarkStyleTransformation`. 

292 This is useful for switching between dark and light terminal 

293 backgrounds. 

294 :param enable_system_prompt: `bool` or 

295 :class:`~prompt_toolkit.filters.Filter`. Pressing Meta+'!' will show 

296 a system prompt. 

297 :param enable_suspend: `bool` or :class:`~prompt_toolkit.filters.Filter`. 

298 Enable Control-Z style suspension. 

299 :param enable_open_in_editor: `bool` or 

300 :class:`~prompt_toolkit.filters.Filter`. Pressing 'v' in Vi mode or 

301 C-X C-E in emacs mode will open an external editor. 

302 :param history: :class:`~prompt_toolkit.history.History` instance. 

303 :param clipboard: :class:`~prompt_toolkit.clipboard.Clipboard` instance. 

304 (e.g. :class:`~prompt_toolkit.clipboard.InMemoryClipboard`) 

305 :param rprompt: Text or formatted text to be displayed on the right side. 

306 This can also be a callable that returns (formatted) text. 

307 :param bottom_toolbar: Formatted text or callable which is supposed to 

308 return formatted text. 

309 :param prompt_continuation: Text that needs to be displayed for a multiline 

310 prompt continuation. This can either be formatted text or a callable 

311 that takes a `prompt_width`, `line_number` and `wrap_count` as input 

312 and returns formatted text. When this is `None` (the default), then 

313 `prompt_width` spaces will be used. 

314 :param complete_style: ``CompleteStyle.COLUMN``, 

315 ``CompleteStyle.MULTI_COLUMN`` or ``CompleteStyle.READLINE_LIKE``. 

316 :param mouse_support: `bool` or :class:`~prompt_toolkit.filters.Filter` 

317 to enable mouse support. 

318 :param placeholder: Text to be displayed when no input has been given 

319 yet. Unlike the `default` parameter, this won't be returned as part of 

320 the output ever. This can be formatted text or a callable that returns 

321 formatted text. 

322 :param refresh_interval: (number; in seconds) When given, refresh the UI 

323 every so many seconds. 

324 :param input: `Input` object. (Note that the preferred way to change the 

325 input/output is by creating an `AppSession`.) 

326 :param output: `Output` object. 

327 :param interrupt_exception: The exception type that will be raised when 

328 there is a keyboard interrupt (control-c keypress). 

329 :param eof_exception: The exception type that will be raised when there is 

330 an end-of-file/exit event (control-d keypress). 

331 """ 

332 

333 _fields = ( 

334 "message", 

335 "lexer", 

336 "completer", 

337 "complete_in_thread", 

338 "is_password", 

339 "editing_mode", 

340 "key_bindings", 

341 "is_password", 

342 "bottom_toolbar", 

343 "style", 

344 "style_transformation", 

345 "swap_light_and_dark_colors", 

346 "color_depth", 

347 "cursor", 

348 "include_default_pygments_style", 

349 "rprompt", 

350 "multiline", 

351 "prompt_continuation", 

352 "wrap_lines", 

353 "enable_history_search", 

354 "search_ignore_case", 

355 "complete_while_typing", 

356 "validate_while_typing", 

357 "complete_style", 

358 "mouse_support", 

359 "auto_suggest", 

360 "clipboard", 

361 "validator", 

362 "refresh_interval", 

363 "input_processors", 

364 "placeholder", 

365 "enable_system_prompt", 

366 "enable_suspend", 

367 "enable_open_in_editor", 

368 "reserve_space_for_menu", 

369 "tempfile_suffix", 

370 "tempfile", 

371 ) 

372 

373 def __init__( 

374 self, 

375 message: AnyFormattedText = "", 

376 *, 

377 multiline: FilterOrBool = False, 

378 wrap_lines: FilterOrBool = True, 

379 is_password: FilterOrBool = False, 

380 vi_mode: bool = False, 

381 editing_mode: EditingMode = EditingMode.EMACS, 

382 complete_while_typing: FilterOrBool = True, 

383 validate_while_typing: FilterOrBool = True, 

384 enable_history_search: FilterOrBool = False, 

385 search_ignore_case: FilterOrBool = False, 

386 lexer: Lexer | None = None, 

387 enable_system_prompt: FilterOrBool = False, 

388 enable_suspend: FilterOrBool = False, 

389 enable_open_in_editor: FilterOrBool = False, 

390 validator: Validator | None = None, 

391 completer: Completer | None = None, 

392 complete_in_thread: bool = False, 

393 reserve_space_for_menu: int = 8, 

394 complete_style: CompleteStyle = CompleteStyle.COLUMN, 

395 auto_suggest: AutoSuggest | None = None, 

396 style: BaseStyle | None = None, 

397 style_transformation: StyleTransformation | None = None, 

398 swap_light_and_dark_colors: FilterOrBool = False, 

399 color_depth: ColorDepth | None = None, 

400 cursor: AnyCursorShapeConfig = None, 

401 include_default_pygments_style: FilterOrBool = True, 

402 history: History | None = None, 

403 clipboard: Clipboard | None = None, 

404 prompt_continuation: PromptContinuationText | None = None, 

405 rprompt: AnyFormattedText = None, 

406 bottom_toolbar: AnyFormattedText = None, 

407 mouse_support: FilterOrBool = False, 

408 input_processors: list[Processor] | None = None, 

409 placeholder: AnyFormattedText | None = None, 

410 key_bindings: KeyBindingsBase | None = None, 

411 erase_when_done: bool = False, 

412 tempfile_suffix: str | Callable[[], str] | None = ".txt", 

413 tempfile: str | Callable[[], str] | None = None, 

414 refresh_interval: float = 0, 

415 input: Input | None = None, 

416 output: Output | None = None, 

417 interrupt_exception: type[BaseException] = KeyboardInterrupt, 

418 eof_exception: type[BaseException] = EOFError, 

419 ) -> None: 

420 history = history or InMemoryHistory() 

421 clipboard = clipboard or InMemoryClipboard() 

422 

423 # Ensure backwards-compatibility, when `vi_mode` is passed. 

424 if vi_mode: 

425 editing_mode = EditingMode.VI 

426 

427 # Store all settings in this class. 

428 self._input = input 

429 self._output = output 

430 

431 # Store attributes. 

432 # (All except 'editing_mode'.) 

433 self.message = message 

434 self.lexer = lexer 

435 self.completer = completer 

436 self.complete_in_thread = complete_in_thread 

437 self.is_password = is_password 

438 self.key_bindings = key_bindings 

439 self.bottom_toolbar = bottom_toolbar 

440 self.style = style 

441 self.style_transformation = style_transformation 

442 self.swap_light_and_dark_colors = swap_light_and_dark_colors 

443 self.color_depth = color_depth 

444 self.cursor = cursor 

445 self.include_default_pygments_style = include_default_pygments_style 

446 self.rprompt = rprompt 

447 self.multiline = multiline 

448 self.prompt_continuation = prompt_continuation 

449 self.wrap_lines = wrap_lines 

450 self.enable_history_search = enable_history_search 

451 self.search_ignore_case = search_ignore_case 

452 self.complete_while_typing = complete_while_typing 

453 self.validate_while_typing = validate_while_typing 

454 self.complete_style = complete_style 

455 self.mouse_support = mouse_support 

456 self.auto_suggest = auto_suggest 

457 self.clipboard = clipboard 

458 self.validator = validator 

459 self.refresh_interval = refresh_interval 

460 self.input_processors = input_processors 

461 self.placeholder = placeholder 

462 self.enable_system_prompt = enable_system_prompt 

463 self.enable_suspend = enable_suspend 

464 self.enable_open_in_editor = enable_open_in_editor 

465 self.reserve_space_for_menu = reserve_space_for_menu 

466 self.tempfile_suffix = tempfile_suffix 

467 self.tempfile = tempfile 

468 self.interrupt_exception = interrupt_exception 

469 self.eof_exception = eof_exception 

470 

471 # Create buffers, layout and Application. 

472 self.history = history 

473 self.default_buffer = self._create_default_buffer() 

474 self.search_buffer = self._create_search_buffer() 

475 self.layout = self._create_layout() 

476 self.app = self._create_application(editing_mode, erase_when_done) 

477 

478 def _dyncond(self, attr_name: str) -> Condition: 

479 """ 

480 Dynamically take this setting from this 'PromptSession' class. 

481 `attr_name` represents an attribute name of this class. Its value 

482 can either be a boolean or a `Filter`. 

483 

484 This returns something that can be used as either a `Filter` 

485 or `Filter`. 

486 """ 

487 

488 @Condition 

489 def dynamic() -> bool: 

490 value = cast(FilterOrBool, getattr(self, attr_name)) 

491 return to_filter(value)() 

492 

493 return dynamic 

494 

495 def _create_default_buffer(self) -> Buffer: 

496 """ 

497 Create and return the default input buffer. 

498 """ 

499 dyncond = self._dyncond 

500 

501 # Create buffers list. 

502 def accept(buff: Buffer) -> bool: 

503 """Accept the content of the default buffer. This is called when 

504 the validation succeeds.""" 

505 cast(Application[str], get_app()).exit(result=buff.document.text) 

506 return True # Keep text, we call 'reset' later on. 

507 

508 return Buffer( 

509 name=DEFAULT_BUFFER, 

510 # Make sure that complete_while_typing is disabled when 

511 # enable_history_search is enabled. (First convert to Filter, 

512 # to avoid doing bitwise operations on bool objects.) 

513 complete_while_typing=Condition( 

514 lambda: is_true(self.complete_while_typing) 

515 and not is_true(self.enable_history_search) 

516 and not self.complete_style == CompleteStyle.READLINE_LIKE 

517 ), 

518 validate_while_typing=dyncond("validate_while_typing"), 

519 enable_history_search=dyncond("enable_history_search"), 

520 validator=DynamicValidator(lambda: self.validator), 

521 completer=DynamicCompleter( 

522 lambda: ThreadedCompleter(self.completer) 

523 if self.complete_in_thread and self.completer 

524 else self.completer 

525 ), 

526 history=self.history, 

527 auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest), 

528 accept_handler=accept, 

529 tempfile_suffix=lambda: to_str(self.tempfile_suffix or ""), 

530 tempfile=lambda: to_str(self.tempfile or ""), 

531 ) 

532 

533 def _create_search_buffer(self) -> Buffer: 

534 return Buffer(name=SEARCH_BUFFER) 

535 

536 def _create_layout(self) -> Layout: 

537 """ 

538 Create `Layout` for this prompt. 

539 """ 

540 dyncond = self._dyncond 

541 

542 # Create functions that will dynamically split the prompt. (If we have 

543 # a multiline prompt.) 

544 ( 

545 has_before_fragments, 

546 get_prompt_text_1, 

547 get_prompt_text_2, 

548 ) = _split_multiline_prompt(self._get_prompt) 

549 

550 default_buffer = self.default_buffer 

551 search_buffer = self.search_buffer 

552 

553 # Create processors list. 

554 @Condition 

555 def display_placeholder() -> bool: 

556 return self.placeholder is not None and self.default_buffer.text == "" 

557 

558 all_input_processors = [ 

559 HighlightIncrementalSearchProcessor(), 

560 HighlightSelectionProcessor(), 

561 ConditionalProcessor( 

562 AppendAutoSuggestion(), has_focus(default_buffer) & ~is_done 

563 ), 

564 ConditionalProcessor(PasswordProcessor(), dyncond("is_password")), 

565 DisplayMultipleCursors(), 

566 # Users can insert processors here. 

567 DynamicProcessor(lambda: merge_processors(self.input_processors or [])), 

568 ConditionalProcessor( 

569 AfterInput(lambda: self.placeholder), 

570 filter=display_placeholder, 

571 ), 

572 ] 

573 

574 # Create bottom toolbars. 

575 bottom_toolbar = ConditionalContainer( 

576 Window( 

577 FormattedTextControl( 

578 lambda: self.bottom_toolbar, style="class:bottom-toolbar.text" 

579 ), 

580 style="class:bottom-toolbar", 

581 dont_extend_height=True, 

582 height=Dimension(min=1), 

583 ), 

584 filter=Condition(lambda: self.bottom_toolbar is not None) 

585 & ~is_done 

586 & renderer_height_is_known, 

587 ) 

588 

589 search_toolbar = SearchToolbar( 

590 search_buffer, ignore_case=dyncond("search_ignore_case") 

591 ) 

592 

593 search_buffer_control = SearchBufferControl( 

594 buffer=search_buffer, 

595 input_processors=[ReverseSearchProcessor()], 

596 ignore_case=dyncond("search_ignore_case"), 

597 ) 

598 

599 system_toolbar = SystemToolbar( 

600 enable_global_bindings=dyncond("enable_system_prompt") 

601 ) 

602 

603 def get_search_buffer_control() -> SearchBufferControl: 

604 "Return the UIControl to be focused when searching start." 

605 if is_true(self.multiline): 

606 return search_toolbar.control 

607 else: 

608 return search_buffer_control 

609 

610 default_buffer_control = BufferControl( 

611 buffer=default_buffer, 

612 search_buffer_control=get_search_buffer_control, 

613 input_processors=all_input_processors, 

614 include_default_input_processors=False, 

615 lexer=DynamicLexer(lambda: self.lexer), 

616 preview_search=True, 

617 ) 

618 

619 default_buffer_window = Window( 

620 default_buffer_control, 

621 height=self._get_default_buffer_control_height, 

622 get_line_prefix=partial( 

623 self._get_line_prefix, get_prompt_text_2=get_prompt_text_2 

624 ), 

625 wrap_lines=dyncond("wrap_lines"), 

626 ) 

627 

628 @Condition 

629 def multi_column_complete_style() -> bool: 

630 return self.complete_style == CompleteStyle.MULTI_COLUMN 

631 

632 # Build the layout. 

633 layout = HSplit( 

634 [ 

635 # The main input, with completion menus floating on top of it. 

636 FloatContainer( 

637 HSplit( 

638 [ 

639 ConditionalContainer( 

640 Window( 

641 FormattedTextControl(get_prompt_text_1), 

642 dont_extend_height=True, 

643 ), 

644 Condition(has_before_fragments), 

645 ), 

646 ConditionalContainer( 

647 default_buffer_window, 

648 Condition( 

649 lambda: get_app().layout.current_control 

650 != search_buffer_control 

651 ), 

652 ), 

653 ConditionalContainer( 

654 Window(search_buffer_control), 

655 Condition( 

656 lambda: get_app().layout.current_control 

657 == search_buffer_control 

658 ), 

659 ), 

660 ] 

661 ), 

662 [ 

663 # Completion menus. 

664 # NOTE: Especially the multi-column menu needs to be 

665 # transparent, because the shape is not always 

666 # rectangular due to the meta-text below the menu. 

667 Float( 

668 xcursor=True, 

669 ycursor=True, 

670 transparent=True, 

671 content=CompletionsMenu( 

672 max_height=16, 

673 scroll_offset=1, 

674 extra_filter=has_focus(default_buffer) 

675 & ~multi_column_complete_style, 

676 ), 

677 ), 

678 Float( 

679 xcursor=True, 

680 ycursor=True, 

681 transparent=True, 

682 content=MultiColumnCompletionsMenu( 

683 show_meta=True, 

684 extra_filter=has_focus(default_buffer) 

685 & multi_column_complete_style, 

686 ), 

687 ), 

688 # The right prompt. 

689 Float( 

690 right=0, 

691 top=0, 

692 hide_when_covering_content=True, 

693 content=_RPrompt(lambda: self.rprompt), 

694 ), 

695 ], 

696 ), 

697 ConditionalContainer(ValidationToolbar(), filter=~is_done), 

698 ConditionalContainer( 

699 system_toolbar, dyncond("enable_system_prompt") & ~is_done 

700 ), 

701 # In multiline mode, we use two toolbars for 'arg' and 'search'. 

702 ConditionalContainer( 

703 Window(FormattedTextControl(self._get_arg_text), height=1), 

704 dyncond("multiline") & has_arg, 

705 ), 

706 ConditionalContainer(search_toolbar, dyncond("multiline") & ~is_done), 

707 bottom_toolbar, 

708 ] 

709 ) 

710 

711 return Layout(layout, default_buffer_window) 

712 

713 def _create_application( 

714 self, editing_mode: EditingMode, erase_when_done: bool 

715 ) -> Application[_T]: 

716 """ 

717 Create the `Application` object. 

718 """ 

719 dyncond = self._dyncond 

720 

721 # Default key bindings. 

722 auto_suggest_bindings = load_auto_suggest_bindings() 

723 open_in_editor_bindings = load_open_in_editor_bindings() 

724 prompt_bindings = self._create_prompt_bindings() 

725 

726 # Create application 

727 application: Application[_T] = Application( 

728 layout=self.layout, 

729 style=DynamicStyle(lambda: self.style), 

730 style_transformation=merge_style_transformations( 

731 [ 

732 DynamicStyleTransformation(lambda: self.style_transformation), 

733 ConditionalStyleTransformation( 

734 SwapLightAndDarkStyleTransformation(), 

735 dyncond("swap_light_and_dark_colors"), 

736 ), 

737 ] 

738 ), 

739 include_default_pygments_style=dyncond("include_default_pygments_style"), 

740 clipboard=DynamicClipboard(lambda: self.clipboard), 

741 key_bindings=merge_key_bindings( 

742 [ 

743 merge_key_bindings( 

744 [ 

745 auto_suggest_bindings, 

746 ConditionalKeyBindings( 

747 open_in_editor_bindings, 

748 dyncond("enable_open_in_editor") 

749 & has_focus(DEFAULT_BUFFER), 

750 ), 

751 prompt_bindings, 

752 ] 

753 ), 

754 DynamicKeyBindings(lambda: self.key_bindings), 

755 ] 

756 ), 

757 mouse_support=dyncond("mouse_support"), 

758 editing_mode=editing_mode, 

759 erase_when_done=erase_when_done, 

760 reverse_vi_search_direction=True, 

761 color_depth=lambda: self.color_depth, 

762 cursor=DynamicCursorShapeConfig(lambda: self.cursor), 

763 refresh_interval=self.refresh_interval, 

764 input=self._input, 

765 output=self._output, 

766 ) 

767 

768 # During render time, make sure that we focus the right search control 

769 # (if we are searching). - This could be useful if people make the 

770 # 'multiline' property dynamic. 

771 """ 

772 def on_render(app): 

773 multiline = is_true(self.multiline) 

774 current_control = app.layout.current_control 

775 

776 if multiline: 

777 if current_control == search_buffer_control: 

778 app.layout.current_control = search_toolbar.control 

779 app.invalidate() 

780 else: 

781 if current_control == search_toolbar.control: 

782 app.layout.current_control = search_buffer_control 

783 app.invalidate() 

784 

785 app.on_render += on_render 

786 """ 

787 

788 return application 

789 

790 def _create_prompt_bindings(self) -> KeyBindings: 

791 """ 

792 Create the KeyBindings for a prompt application. 

793 """ 

794 kb = KeyBindings() 

795 handle = kb.add 

796 default_focused = has_focus(DEFAULT_BUFFER) 

797 

798 @Condition 

799 def do_accept() -> bool: 

800 return not is_true(self.multiline) and self.app.layout.has_focus( 

801 DEFAULT_BUFFER 

802 ) 

803 

804 @handle("enter", filter=do_accept & default_focused) 

805 def _accept_input(event: E) -> None: 

806 "Accept input when enter has been pressed." 

807 self.default_buffer.validate_and_handle() 

808 

809 @Condition 

810 def readline_complete_style() -> bool: 

811 return self.complete_style == CompleteStyle.READLINE_LIKE 

812 

813 @handle("tab", filter=readline_complete_style & default_focused) 

814 def _complete_like_readline(event: E) -> None: 

815 "Display completions (like Readline)." 

816 display_completions_like_readline(event) 

817 

818 @handle("c-c", filter=default_focused) 

819 @handle("<sigint>") 

820 def _keyboard_interrupt(event: E) -> None: 

821 "Abort when Control-C has been pressed." 

822 event.app.exit(exception=self.interrupt_exception(), style="class:aborting") 

823 

824 @Condition 

825 def ctrl_d_condition() -> bool: 

826 """Ctrl-D binding is only active when the default buffer is selected 

827 and empty.""" 

828 app = get_app() 

829 return ( 

830 app.current_buffer.name == DEFAULT_BUFFER 

831 and not app.current_buffer.text 

832 ) 

833 

834 @handle("c-d", filter=ctrl_d_condition & default_focused) 

835 def _eof(event: E) -> None: 

836 "Exit when Control-D has been pressed." 

837 event.app.exit(exception=self.eof_exception(), style="class:exiting") 

838 

839 suspend_supported = Condition(suspend_to_background_supported) 

840 

841 @Condition 

842 def enable_suspend() -> bool: 

843 return to_filter(self.enable_suspend)() 

844 

845 @handle("c-z", filter=suspend_supported & enable_suspend) 

846 def _suspend(event: E) -> None: 

847 """ 

848 Suspend process to background. 

849 """ 

850 event.app.suspend_to_background() 

851 

852 return kb 

853 

854 def prompt( 

855 self, 

856 # When any of these arguments are passed, this value is overwritten 

857 # in this PromptSession. 

858 message: AnyFormattedText | None = None, 

859 # `message` should go first, because people call it as 

860 # positional argument. 

861 *, 

862 editing_mode: EditingMode | None = None, 

863 refresh_interval: float | None = None, 

864 vi_mode: bool | None = None, 

865 lexer: Lexer | None = None, 

866 completer: Completer | None = None, 

867 complete_in_thread: bool | None = None, 

868 is_password: bool | None = None, 

869 key_bindings: KeyBindingsBase | None = None, 

870 bottom_toolbar: AnyFormattedText | None = None, 

871 style: BaseStyle | None = None, 

872 color_depth: ColorDepth | None = None, 

873 cursor: AnyCursorShapeConfig | None = None, 

874 include_default_pygments_style: FilterOrBool | None = None, 

875 style_transformation: StyleTransformation | None = None, 

876 swap_light_and_dark_colors: FilterOrBool | None = None, 

877 rprompt: AnyFormattedText | None = None, 

878 multiline: FilterOrBool | None = None, 

879 prompt_continuation: PromptContinuationText | None = None, 

880 wrap_lines: FilterOrBool | None = None, 

881 enable_history_search: FilterOrBool | None = None, 

882 search_ignore_case: FilterOrBool | None = None, 

883 complete_while_typing: FilterOrBool | None = None, 

884 validate_while_typing: FilterOrBool | None = None, 

885 complete_style: CompleteStyle | None = None, 

886 auto_suggest: AutoSuggest | None = None, 

887 validator: Validator | None = None, 

888 clipboard: Clipboard | None = None, 

889 mouse_support: FilterOrBool | None = None, 

890 input_processors: list[Processor] | None = None, 

891 placeholder: AnyFormattedText | None = None, 

892 reserve_space_for_menu: int | None = None, 

893 enable_system_prompt: FilterOrBool | None = None, 

894 enable_suspend: FilterOrBool | None = None, 

895 enable_open_in_editor: FilterOrBool | None = None, 

896 tempfile_suffix: str | Callable[[], str] | None = None, 

897 tempfile: str | Callable[[], str] | None = None, 

898 # Following arguments are specific to the current `prompt()` call. 

899 default: str | Document = "", 

900 accept_default: bool = False, 

901 pre_run: Callable[[], None] | None = None, 

902 set_exception_handler: bool = True, 

903 handle_sigint: bool = True, 

904 in_thread: bool = False, 

905 inputhook: InputHook | None = None, 

906 ) -> _T: 

907 """ 

908 Display the prompt. 

909 

910 The first set of arguments is a subset of the :class:`~.PromptSession` 

911 class itself. For these, passing in ``None`` will keep the current 

912 values that are active in the session. Passing in a value will set the 

913 attribute for the session, which means that it applies to the current, 

914 but also to the next prompts. 

915 

916 Note that in order to erase a ``Completer``, ``Validator`` or 

917 ``AutoSuggest``, you can't use ``None``. Instead pass in a 

918 ``DummyCompleter``, ``DummyValidator`` or ``DummyAutoSuggest`` instance 

919 respectively. For a ``Lexer`` you can pass in an empty ``SimpleLexer``. 

920 

921 Additional arguments, specific for this prompt: 

922 

923 :param default: The default input text to be shown. (This can be edited 

924 by the user). 

925 :param accept_default: When `True`, automatically accept the default 

926 value without allowing the user to edit the input. 

927 :param pre_run: Callable, called at the start of `Application.run`. 

928 :param in_thread: Run the prompt in a background thread; block the 

929 current thread. This avoids interference with an event loop in the 

930 current thread. Like `Application.run(in_thread=True)`. 

931 

932 This method will raise ``KeyboardInterrupt`` when control-c has been 

933 pressed (for abort) and ``EOFError`` when control-d has been pressed 

934 (for exit). 

935 """ 

936 # NOTE: We used to create a backup of the PromptSession attributes and 

937 # restore them after exiting the prompt. This code has been 

938 # removed, because it was confusing and didn't really serve a use 

939 # case. (People were changing `Application.editing_mode` 

940 # dynamically and surprised that it was reset after every call.) 

941 

942 # NOTE 2: YES, this is a lot of repeation below... 

943 # However, it is a very convenient for a user to accept all 

944 # these parameters in this `prompt` method as well. We could 

945 # use `locals()` and `setattr` to avoid the repetition, but 

946 # then we loose the advantage of mypy and pyflakes to be able 

947 # to verify the code. 

948 if message is not None: 

949 self.message = message 

950 if editing_mode is not None: 

951 self.editing_mode = editing_mode 

952 if refresh_interval is not None: 

953 self.refresh_interval = refresh_interval 

954 if vi_mode: 

955 self.editing_mode = EditingMode.VI 

956 if lexer is not None: 

957 self.lexer = lexer 

958 if completer is not None: 

959 self.completer = completer 

960 if complete_in_thread is not None: 

961 self.complete_in_thread = complete_in_thread 

962 if is_password is not None: 

963 self.is_password = is_password 

964 if key_bindings is not None: 

965 self.key_bindings = key_bindings 

966 if bottom_toolbar is not None: 

967 self.bottom_toolbar = bottom_toolbar 

968 if style is not None: 

969 self.style = style 

970 if color_depth is not None: 

971 self.color_depth = color_depth 

972 if cursor is not None: 

973 self.cursor = cursor 

974 if include_default_pygments_style is not None: 

975 self.include_default_pygments_style = include_default_pygments_style 

976 if style_transformation is not None: 

977 self.style_transformation = style_transformation 

978 if swap_light_and_dark_colors is not None: 

979 self.swap_light_and_dark_colors = swap_light_and_dark_colors 

980 if rprompt is not None: 

981 self.rprompt = rprompt 

982 if multiline is not None: 

983 self.multiline = multiline 

984 if prompt_continuation is not None: 

985 self.prompt_continuation = prompt_continuation 

986 if wrap_lines is not None: 

987 self.wrap_lines = wrap_lines 

988 if enable_history_search is not None: 

989 self.enable_history_search = enable_history_search 

990 if search_ignore_case is not None: 

991 self.search_ignore_case = search_ignore_case 

992 if complete_while_typing is not None: 

993 self.complete_while_typing = complete_while_typing 

994 if validate_while_typing is not None: 

995 self.validate_while_typing = validate_while_typing 

996 if complete_style is not None: 

997 self.complete_style = complete_style 

998 if auto_suggest is not None: 

999 self.auto_suggest = auto_suggest 

1000 if validator is not None: 

1001 self.validator = validator 

1002 if clipboard is not None: 

1003 self.clipboard = clipboard 

1004 if mouse_support is not None: 

1005 self.mouse_support = mouse_support 

1006 if input_processors is not None: 

1007 self.input_processors = input_processors 

1008 if placeholder is not None: 

1009 self.placeholder = placeholder 

1010 if reserve_space_for_menu is not None: 

1011 self.reserve_space_for_menu = reserve_space_for_menu 

1012 if enable_system_prompt is not None: 

1013 self.enable_system_prompt = enable_system_prompt 

1014 if enable_suspend is not None: 

1015 self.enable_suspend = enable_suspend 

1016 if enable_open_in_editor is not None: 

1017 self.enable_open_in_editor = enable_open_in_editor 

1018 if tempfile_suffix is not None: 

1019 self.tempfile_suffix = tempfile_suffix 

1020 if tempfile is not None: 

1021 self.tempfile = tempfile 

1022 

1023 self._add_pre_run_callables(pre_run, accept_default) 

1024 self.default_buffer.reset( 

1025 default if isinstance(default, Document) else Document(default) 

1026 ) 

1027 self.app.refresh_interval = self.refresh_interval # This is not reactive. 

1028 

1029 # If we are using the default output, and have a dumb terminal. Use the 

1030 # dumb prompt. 

1031 if self._output is None and is_dumb_terminal(): 

1032 with self._dumb_prompt(self.message) as dump_app: 

1033 return dump_app.run(in_thread=in_thread, handle_sigint=handle_sigint) 

1034 

1035 return self.app.run( 

1036 set_exception_handler=set_exception_handler, 

1037 in_thread=in_thread, 

1038 handle_sigint=handle_sigint, 

1039 inputhook=inputhook, 

1040 ) 

1041 

1042 @contextmanager 

1043 def _dumb_prompt(self, message: AnyFormattedText = "") -> Iterator[Application[_T]]: 

1044 """ 

1045 Create prompt `Application` for prompt function for dumb terminals. 

1046 

1047 Dumb terminals have minimum rendering capabilities. We can only print 

1048 text to the screen. We can't use colors, and we can't do cursor 

1049 movements. The Emacs inferior shell is an example of a dumb terminal. 

1050 

1051 We will show the prompt, and wait for the input. We still handle arrow 

1052 keys, and all custom key bindings, but we don't really render the 

1053 cursor movements. Instead we only print the typed character that's 

1054 right before the cursor. 

1055 """ 

1056 # Send prompt to output. 

1057 self.output.write(fragment_list_to_text(to_formatted_text(self.message))) 

1058 self.output.flush() 

1059 

1060 # Key bindings for the dumb prompt: mostly the same as the full prompt. 

1061 key_bindings: KeyBindingsBase = self._create_prompt_bindings() 

1062 if self.key_bindings: 

1063 key_bindings = merge_key_bindings([self.key_bindings, key_bindings]) 

1064 

1065 # Create and run application. 

1066 application = cast( 

1067 Application[_T], 

1068 Application( 

1069 input=self.input, 

1070 output=DummyOutput(), 

1071 layout=self.layout, 

1072 key_bindings=key_bindings, 

1073 ), 

1074 ) 

1075 

1076 def on_text_changed(_: object) -> None: 

1077 self.output.write(self.default_buffer.document.text_before_cursor[-1:]) 

1078 self.output.flush() 

1079 

1080 self.default_buffer.on_text_changed += on_text_changed 

1081 

1082 try: 

1083 yield application 

1084 finally: 

1085 # Render line ending. 

1086 self.output.write("\r\n") 

1087 self.output.flush() 

1088 

1089 self.default_buffer.on_text_changed -= on_text_changed 

1090 

1091 async def prompt_async( 

1092 self, 

1093 # When any of these arguments are passed, this value is overwritten 

1094 # in this PromptSession. 

1095 message: AnyFormattedText | None = None, 

1096 # `message` should go first, because people call it as 

1097 # positional argument. 

1098 *, 

1099 editing_mode: EditingMode | None = None, 

1100 refresh_interval: float | None = None, 

1101 vi_mode: bool | None = None, 

1102 lexer: Lexer | None = None, 

1103 completer: Completer | None = None, 

1104 complete_in_thread: bool | None = None, 

1105 is_password: bool | None = None, 

1106 key_bindings: KeyBindingsBase | None = None, 

1107 bottom_toolbar: AnyFormattedText | None = None, 

1108 style: BaseStyle | None = None, 

1109 color_depth: ColorDepth | None = None, 

1110 cursor: CursorShapeConfig | None = None, 

1111 include_default_pygments_style: FilterOrBool | None = None, 

1112 style_transformation: StyleTransformation | None = None, 

1113 swap_light_and_dark_colors: FilterOrBool | None = None, 

1114 rprompt: AnyFormattedText | None = None, 

1115 multiline: FilterOrBool | None = None, 

1116 prompt_continuation: PromptContinuationText | None = None, 

1117 wrap_lines: FilterOrBool | None = None, 

1118 enable_history_search: FilterOrBool | None = None, 

1119 search_ignore_case: FilterOrBool | None = None, 

1120 complete_while_typing: FilterOrBool | None = None, 

1121 validate_while_typing: FilterOrBool | None = None, 

1122 complete_style: CompleteStyle | None = None, 

1123 auto_suggest: AutoSuggest | None = None, 

1124 validator: Validator | None = None, 

1125 clipboard: Clipboard | None = None, 

1126 mouse_support: FilterOrBool | None = None, 

1127 input_processors: list[Processor] | None = None, 

1128 placeholder: AnyFormattedText | None = None, 

1129 reserve_space_for_menu: int | None = None, 

1130 enable_system_prompt: FilterOrBool | None = None, 

1131 enable_suspend: FilterOrBool | None = None, 

1132 enable_open_in_editor: FilterOrBool | None = None, 

1133 tempfile_suffix: str | Callable[[], str] | None = None, 

1134 tempfile: str | Callable[[], str] | None = None, 

1135 # Following arguments are specific to the current `prompt()` call. 

1136 default: str | Document = "", 

1137 accept_default: bool = False, 

1138 pre_run: Callable[[], None] | None = None, 

1139 set_exception_handler: bool = True, 

1140 handle_sigint: bool = True, 

1141 ) -> _T: 

1142 if message is not None: 

1143 self.message = message 

1144 if editing_mode is not None: 

1145 self.editing_mode = editing_mode 

1146 if refresh_interval is not None: 

1147 self.refresh_interval = refresh_interval 

1148 if vi_mode: 

1149 self.editing_mode = EditingMode.VI 

1150 if lexer is not None: 

1151 self.lexer = lexer 

1152 if completer is not None: 

1153 self.completer = completer 

1154 if complete_in_thread is not None: 

1155 self.complete_in_thread = complete_in_thread 

1156 if is_password is not None: 

1157 self.is_password = is_password 

1158 if key_bindings is not None: 

1159 self.key_bindings = key_bindings 

1160 if bottom_toolbar is not None: 

1161 self.bottom_toolbar = bottom_toolbar 

1162 if style is not None: 

1163 self.style = style 

1164 if color_depth is not None: 

1165 self.color_depth = color_depth 

1166 if cursor is not None: 

1167 self.cursor = cursor 

1168 if include_default_pygments_style is not None: 

1169 self.include_default_pygments_style = include_default_pygments_style 

1170 if style_transformation is not None: 

1171 self.style_transformation = style_transformation 

1172 if swap_light_and_dark_colors is not None: 

1173 self.swap_light_and_dark_colors = swap_light_and_dark_colors 

1174 if rprompt is not None: 

1175 self.rprompt = rprompt 

1176 if multiline is not None: 

1177 self.multiline = multiline 

1178 if prompt_continuation is not None: 

1179 self.prompt_continuation = prompt_continuation 

1180 if wrap_lines is not None: 

1181 self.wrap_lines = wrap_lines 

1182 if enable_history_search is not None: 

1183 self.enable_history_search = enable_history_search 

1184 if search_ignore_case is not None: 

1185 self.search_ignore_case = search_ignore_case 

1186 if complete_while_typing is not None: 

1187 self.complete_while_typing = complete_while_typing 

1188 if validate_while_typing is not None: 

1189 self.validate_while_typing = validate_while_typing 

1190 if complete_style is not None: 

1191 self.complete_style = complete_style 

1192 if auto_suggest is not None: 

1193 self.auto_suggest = auto_suggest 

1194 if validator is not None: 

1195 self.validator = validator 

1196 if clipboard is not None: 

1197 self.clipboard = clipboard 

1198 if mouse_support is not None: 

1199 self.mouse_support = mouse_support 

1200 if input_processors is not None: 

1201 self.input_processors = input_processors 

1202 if placeholder is not None: 

1203 self.placeholder = placeholder 

1204 if reserve_space_for_menu is not None: 

1205 self.reserve_space_for_menu = reserve_space_for_menu 

1206 if enable_system_prompt is not None: 

1207 self.enable_system_prompt = enable_system_prompt 

1208 if enable_suspend is not None: 

1209 self.enable_suspend = enable_suspend 

1210 if enable_open_in_editor is not None: 

1211 self.enable_open_in_editor = enable_open_in_editor 

1212 if tempfile_suffix is not None: 

1213 self.tempfile_suffix = tempfile_suffix 

1214 if tempfile is not None: 

1215 self.tempfile = tempfile 

1216 

1217 self._add_pre_run_callables(pre_run, accept_default) 

1218 self.default_buffer.reset( 

1219 default if isinstance(default, Document) else Document(default) 

1220 ) 

1221 self.app.refresh_interval = self.refresh_interval # This is not reactive. 

1222 

1223 # If we are using the default output, and have a dumb terminal. Use the 

1224 # dumb prompt. 

1225 if self._output is None and is_dumb_terminal(): 

1226 with self._dumb_prompt(self.message) as dump_app: 

1227 return await dump_app.run_async(handle_sigint=handle_sigint) 

1228 

1229 return await self.app.run_async( 

1230 set_exception_handler=set_exception_handler, handle_sigint=handle_sigint 

1231 ) 

1232 

1233 def _add_pre_run_callables( 

1234 self, pre_run: Callable[[], None] | None, accept_default: bool 

1235 ) -> None: 

1236 def pre_run2() -> None: 

1237 if pre_run: 

1238 pre_run() 

1239 

1240 if accept_default: 

1241 # Validate and handle input. We use `call_from_executor` in 

1242 # order to run it "soon" (during the next iteration of the 

1243 # event loop), instead of right now. Otherwise, it won't 

1244 # display the default value. 

1245 get_running_loop().call_soon(self.default_buffer.validate_and_handle) 

1246 

1247 self.app.pre_run_callables.append(pre_run2) 

1248 

1249 @property 

1250 def editing_mode(self) -> EditingMode: 

1251 return self.app.editing_mode 

1252 

1253 @editing_mode.setter 

1254 def editing_mode(self, value: EditingMode) -> None: 

1255 self.app.editing_mode = value 

1256 

1257 def _get_default_buffer_control_height(self) -> Dimension: 

1258 # If there is an autocompletion menu to be shown, make sure that our 

1259 # layout has at least a minimal height in order to display it. 

1260 if ( 

1261 self.completer is not None 

1262 and self.complete_style != CompleteStyle.READLINE_LIKE 

1263 ): 

1264 space = self.reserve_space_for_menu 

1265 else: 

1266 space = 0 

1267 

1268 if space and not get_app().is_done: 

1269 buff = self.default_buffer 

1270 

1271 # Reserve the space, either when there are completions, or when 

1272 # `complete_while_typing` is true and we expect completions very 

1273 # soon. 

1274 if buff.complete_while_typing() or buff.complete_state is not None: 

1275 return Dimension(min=space) 

1276 

1277 return Dimension() 

1278 

1279 def _get_prompt(self) -> StyleAndTextTuples: 

1280 return to_formatted_text(self.message, style="class:prompt") 

1281 

1282 def _get_continuation( 

1283 self, width: int, line_number: int, wrap_count: int 

1284 ) -> StyleAndTextTuples: 

1285 """ 

1286 Insert the prompt continuation. 

1287 

1288 :param width: The width that was used for the prompt. (more or less can 

1289 be used.) 

1290 :param line_number: 

1291 :param wrap_count: Amount of times that the line has been wrapped. 

1292 """ 

1293 prompt_continuation = self.prompt_continuation 

1294 

1295 if callable(prompt_continuation): 

1296 continuation: AnyFormattedText = prompt_continuation( 

1297 width, line_number, wrap_count 

1298 ) 

1299 else: 

1300 continuation = prompt_continuation 

1301 

1302 # When the continuation prompt is not given, choose the same width as 

1303 # the actual prompt. 

1304 if continuation is None and is_true(self.multiline): 

1305 continuation = " " * width 

1306 

1307 return to_formatted_text(continuation, style="class:prompt-continuation") 

1308 

1309 def _get_line_prefix( 

1310 self, 

1311 line_number: int, 

1312 wrap_count: int, 

1313 get_prompt_text_2: _StyleAndTextTuplesCallable, 

1314 ) -> StyleAndTextTuples: 

1315 """ 

1316 Return whatever needs to be inserted before every line. 

1317 (the prompt, or a line continuation.) 

1318 """ 

1319 # First line: display the "arg" or the prompt. 

1320 if line_number == 0 and wrap_count == 0: 

1321 if not is_true(self.multiline) and get_app().key_processor.arg is not None: 

1322 return self._inline_arg() 

1323 else: 

1324 return get_prompt_text_2() 

1325 

1326 # For the next lines, display the appropriate continuation. 

1327 prompt_width = get_cwidth(fragment_list_to_text(get_prompt_text_2())) 

1328 return self._get_continuation(prompt_width, line_number, wrap_count) 

1329 

1330 def _get_arg_text(self) -> StyleAndTextTuples: 

1331 "'arg' toolbar, for in multiline mode." 

1332 arg = self.app.key_processor.arg 

1333 if arg is None: 

1334 # Should not happen because of the `has_arg` filter in the layout. 

1335 return [] 

1336 

1337 if arg == "-": 

1338 arg = "-1" 

1339 

1340 return [("class:arg-toolbar", "Repeat: "), ("class:arg-toolbar.text", arg)] 

1341 

1342 def _inline_arg(self) -> StyleAndTextTuples: 

1343 "'arg' prefix, for in single line mode." 

1344 app = get_app() 

1345 if app.key_processor.arg is None: 

1346 return [] 

1347 else: 

1348 arg = app.key_processor.arg 

1349 

1350 return [ 

1351 ("class:prompt.arg", "(arg: "), 

1352 ("class:prompt.arg.text", str(arg)), 

1353 ("class:prompt.arg", ") "), 

1354 ] 

1355 

1356 # Expose the Input and Output objects as attributes, mainly for 

1357 # backward-compatibility. 

1358 

1359 @property 

1360 def input(self) -> Input: 

1361 return self.app.input 

1362 

1363 @property 

1364 def output(self) -> Output: 

1365 return self.app.output 

1366 

1367 

1368def prompt( 

1369 message: AnyFormattedText | None = None, 

1370 *, 

1371 history: History | None = None, 

1372 editing_mode: EditingMode | None = None, 

1373 refresh_interval: float | None = None, 

1374 vi_mode: bool | None = None, 

1375 lexer: Lexer | None = None, 

1376 completer: Completer | None = None, 

1377 complete_in_thread: bool | None = None, 

1378 is_password: bool | None = None, 

1379 key_bindings: KeyBindingsBase | None = None, 

1380 bottom_toolbar: AnyFormattedText | None = None, 

1381 style: BaseStyle | None = None, 

1382 color_depth: ColorDepth | None = None, 

1383 cursor: AnyCursorShapeConfig = None, 

1384 include_default_pygments_style: FilterOrBool | None = None, 

1385 style_transformation: StyleTransformation | None = None, 

1386 swap_light_and_dark_colors: FilterOrBool | None = None, 

1387 rprompt: AnyFormattedText | None = None, 

1388 multiline: FilterOrBool | None = None, 

1389 prompt_continuation: PromptContinuationText | None = None, 

1390 wrap_lines: FilterOrBool | None = None, 

1391 enable_history_search: FilterOrBool | None = None, 

1392 search_ignore_case: FilterOrBool | None = None, 

1393 complete_while_typing: FilterOrBool | None = None, 

1394 validate_while_typing: FilterOrBool | None = None, 

1395 complete_style: CompleteStyle | None = None, 

1396 auto_suggest: AutoSuggest | None = None, 

1397 validator: Validator | None = None, 

1398 clipboard: Clipboard | None = None, 

1399 mouse_support: FilterOrBool | None = None, 

1400 input_processors: list[Processor] | None = None, 

1401 placeholder: AnyFormattedText | None = None, 

1402 reserve_space_for_menu: int | None = None, 

1403 enable_system_prompt: FilterOrBool | None = None, 

1404 enable_suspend: FilterOrBool | None = None, 

1405 enable_open_in_editor: FilterOrBool | None = None, 

1406 tempfile_suffix: str | Callable[[], str] | None = None, 

1407 tempfile: str | Callable[[], str] | None = None, 

1408 # Following arguments are specific to the current `prompt()` call. 

1409 default: str = "", 

1410 accept_default: bool = False, 

1411 pre_run: Callable[[], None] | None = None, 

1412 set_exception_handler: bool = True, 

1413 handle_sigint: bool = True, 

1414 in_thread: bool = False, 

1415 inputhook: InputHook | None = None, 

1416) -> str: 

1417 """ 

1418 The global `prompt` function. This will create a new `PromptSession` 

1419 instance for every call. 

1420 """ 

1421 # The history is the only attribute that has to be passed to the 

1422 # `PromptSession`, it can't be passed into the `prompt()` method. 

1423 session: PromptSession[str] = PromptSession(history=history) 

1424 

1425 return session.prompt( 

1426 message, 

1427 editing_mode=editing_mode, 

1428 refresh_interval=refresh_interval, 

1429 vi_mode=vi_mode, 

1430 lexer=lexer, 

1431 completer=completer, 

1432 complete_in_thread=complete_in_thread, 

1433 is_password=is_password, 

1434 key_bindings=key_bindings, 

1435 bottom_toolbar=bottom_toolbar, 

1436 style=style, 

1437 color_depth=color_depth, 

1438 cursor=cursor, 

1439 include_default_pygments_style=include_default_pygments_style, 

1440 style_transformation=style_transformation, 

1441 swap_light_and_dark_colors=swap_light_and_dark_colors, 

1442 rprompt=rprompt, 

1443 multiline=multiline, 

1444 prompt_continuation=prompt_continuation, 

1445 wrap_lines=wrap_lines, 

1446 enable_history_search=enable_history_search, 

1447 search_ignore_case=search_ignore_case, 

1448 complete_while_typing=complete_while_typing, 

1449 validate_while_typing=validate_while_typing, 

1450 complete_style=complete_style, 

1451 auto_suggest=auto_suggest, 

1452 validator=validator, 

1453 clipboard=clipboard, 

1454 mouse_support=mouse_support, 

1455 input_processors=input_processors, 

1456 placeholder=placeholder, 

1457 reserve_space_for_menu=reserve_space_for_menu, 

1458 enable_system_prompt=enable_system_prompt, 

1459 enable_suspend=enable_suspend, 

1460 enable_open_in_editor=enable_open_in_editor, 

1461 tempfile_suffix=tempfile_suffix, 

1462 tempfile=tempfile, 

1463 default=default, 

1464 accept_default=accept_default, 

1465 pre_run=pre_run, 

1466 set_exception_handler=set_exception_handler, 

1467 handle_sigint=handle_sigint, 

1468 in_thread=in_thread, 

1469 inputhook=inputhook, 

1470 ) 

1471 

1472 

1473prompt.__doc__ = PromptSession.prompt.__doc__ 

1474 

1475 

1476def create_confirm_session( 

1477 message: str, suffix: str = " (y/n) " 

1478) -> PromptSession[bool]: 

1479 """ 

1480 Create a `PromptSession` object for the 'confirm' function. 

1481 """ 

1482 bindings = KeyBindings() 

1483 

1484 @bindings.add("y") 

1485 @bindings.add("Y") 

1486 def yes(event: E) -> None: 

1487 session.default_buffer.text = "y" 

1488 event.app.exit(result=True) 

1489 

1490 @bindings.add("n") 

1491 @bindings.add("N") 

1492 def no(event: E) -> None: 

1493 session.default_buffer.text = "n" 

1494 event.app.exit(result=False) 

1495 

1496 @bindings.add(Keys.Any) 

1497 def _(event: E) -> None: 

1498 "Disallow inserting other text." 

1499 pass 

1500 

1501 complete_message = merge_formatted_text([message, suffix]) 

1502 session: PromptSession[bool] = PromptSession( 

1503 complete_message, key_bindings=bindings 

1504 ) 

1505 return session 

1506 

1507 

1508def confirm(message: str = "Confirm?", suffix: str = " (y/n) ") -> bool: 

1509 """ 

1510 Display a confirmation prompt that returns True/False. 

1511 """ 

1512 session = create_confirm_session(message, suffix) 

1513 return session.prompt()