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

470 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 06:07 +0000

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""" 

27from __future__ import annotations 

28 

29from asyncio import get_running_loop 

30from contextlib import contextmanager 

31from enum import Enum 

32from functools import partial 

33from typing import ( 

34 TYPE_CHECKING, 

35 Callable, 

36 Generic, 

37 Iterator, 

38 List, 

39 Optional, 

40 Tuple, 

41 TypeVar, 

42 Union, 

43 cast, 

44) 

45 

46from prompt_toolkit.application import Application 

47from prompt_toolkit.application.current import get_app 

48from prompt_toolkit.auto_suggest import AutoSuggest, DynamicAutoSuggest 

49from prompt_toolkit.buffer import Buffer 

50from prompt_toolkit.clipboard import Clipboard, DynamicClipboard, InMemoryClipboard 

51from prompt_toolkit.completion import Completer, DynamicCompleter, ThreadedCompleter 

52from prompt_toolkit.cursor_shapes import ( 

53 AnyCursorShapeConfig, 

54 CursorShapeConfig, 

55 DynamicCursorShapeConfig, 

56) 

57from prompt_toolkit.document import Document 

58from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode 

59from prompt_toolkit.filters import ( 

60 Condition, 

61 FilterOrBool, 

62 has_arg, 

63 has_focus, 

64 is_done, 

65 is_true, 

66 renderer_height_is_known, 

67 to_filter, 

68) 

69from prompt_toolkit.formatted_text import ( 

70 AnyFormattedText, 

71 StyleAndTextTuples, 

72 fragment_list_to_text, 

73 merge_formatted_text, 

74 to_formatted_text, 

75) 

76from prompt_toolkit.history import History, InMemoryHistory 

77from prompt_toolkit.input.base import Input 

78from prompt_toolkit.key_binding.bindings.auto_suggest import load_auto_suggest_bindings 

79from prompt_toolkit.key_binding.bindings.completion import ( 

80 display_completions_like_readline, 

81) 

82from prompt_toolkit.key_binding.bindings.open_in_editor import ( 

83 load_open_in_editor_bindings, 

84) 

85from prompt_toolkit.key_binding.key_bindings import ( 

86 ConditionalKeyBindings, 

87 DynamicKeyBindings, 

88 KeyBindings, 

89 KeyBindingsBase, 

90 merge_key_bindings, 

91) 

92from prompt_toolkit.key_binding.key_processor import KeyPressEvent 

93from prompt_toolkit.keys import Keys 

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

95from prompt_toolkit.layout.containers import ConditionalContainer, WindowAlign 

96from prompt_toolkit.layout.controls import ( 

97 BufferControl, 

98 FormattedTextControl, 

99 SearchBufferControl, 

100) 

101from prompt_toolkit.layout.dimension import Dimension 

102from prompt_toolkit.layout.layout import Layout 

103from prompt_toolkit.layout.menus import CompletionsMenu, MultiColumnCompletionsMenu 

104from prompt_toolkit.layout.processors import ( 

105 AfterInput, 

106 AppendAutoSuggestion, 

107 ConditionalProcessor, 

108 DisplayMultipleCursors, 

109 DynamicProcessor, 

110 HighlightIncrementalSearchProcessor, 

111 HighlightSelectionProcessor, 

112 PasswordProcessor, 

113 Processor, 

114 ReverseSearchProcessor, 

115 merge_processors, 

116) 

117from prompt_toolkit.layout.utils import explode_text_fragments 

118from prompt_toolkit.lexers import DynamicLexer, Lexer 

119from prompt_toolkit.output import ColorDepth, DummyOutput, Output 

120from prompt_toolkit.styles import ( 

121 BaseStyle, 

122 ConditionalStyleTransformation, 

123 DynamicStyle, 

124 DynamicStyleTransformation, 

125 StyleTransformation, 

126 SwapLightAndDarkStyleTransformation, 

127 merge_style_transformations, 

128) 

129from prompt_toolkit.utils import ( 

130 get_cwidth, 

131 is_dumb_terminal, 

132 suspend_to_background_supported, 

133 to_str, 

134) 

135from prompt_toolkit.validation import DynamicValidator, Validator 

136from prompt_toolkit.widgets.toolbars import ( 

137 SearchToolbar, 

138 SystemToolbar, 

139 ValidationToolbar, 

140) 

141 

142if TYPE_CHECKING: 

143 from prompt_toolkit.formatted_text.base import MagicFormattedText 

144 

145__all__ = [ 

146 "PromptSession", 

147 "prompt", 

148 "confirm", 

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

150 "CompleteStyle", 

151] 

152 

153_StyleAndTextTuplesCallable = Callable[[], StyleAndTextTuples] 

154E = KeyPressEvent 

155 

156 

157def _split_multiline_prompt( 

158 get_prompt_text: _StyleAndTextTuplesCallable, 

159) -> tuple[ 

160 Callable[[], bool], _StyleAndTextTuplesCallable, _StyleAndTextTuplesCallable 

161]: 

162 """ 

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

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

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

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

167 """ 

168 

169 def has_before_fragments() -> bool: 

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

171 if "\n" in char: 

172 return True 

173 return False 

174 

175 def before() -> StyleAndTextTuples: 

176 result: StyleAndTextTuples = [] 

177 found_nl = False 

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

179 if found_nl: 

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

181 elif char == "\n": 

182 found_nl = True 

183 return result 

184 

185 def first_input_line() -> StyleAndTextTuples: 

186 result: StyleAndTextTuples = [] 

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

188 if char == "\n": 

189 break 

190 else: 

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

192 return result 

193 

194 return has_before_fragments, before, first_input_line 

195 

196 

197class _RPrompt(Window): 

198 """ 

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

200 """ 

201 

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

203 super().__init__( 

204 FormattedTextControl(text=text), 

205 align=WindowAlign.RIGHT, 

206 style="class:rprompt", 

207 ) 

208 

209 

210class CompleteStyle(str, Enum): 

211 """ 

212 How to display autocompletions for the prompt. 

213 """ 

214 

215 value: str 

216 

217 COLUMN = "COLUMN" 

218 MULTI_COLUMN = "MULTI_COLUMN" 

219 READLINE_LIKE = "READLINE_LIKE" 

220 

221 

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

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

224PromptContinuationText = Union[ 

225 str, 

226 "MagicFormattedText", 

227 StyleAndTextTuples, 

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

229 Callable[[int, int, int], AnyFormattedText], 

230] 

231 

232_T = TypeVar("_T") 

233 

234 

235class PromptSession(Generic[_T]): 

236 """ 

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

238 replacement. 

239 

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

241 be a replacement for `raw_input`. 

242 

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

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

245 

246 Example usage:: 

247 

248 s = PromptSession(message='>') 

249 text = s.prompt() 

250 

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

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

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

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

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

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

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

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

259 scrolling horizontally. 

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

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

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

263 :param complete_while_typing: `bool` or 

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

265 typing. 

266 :param validate_while_typing: `bool` or 

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

268 typing. 

269 :param enable_history_search: `bool` or 

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

271 string matching. 

272 :param search_ignore_case: 

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

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

275 syntax highlighting. 

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

277 for input validation. 

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

279 for input completion. 

280 :param complete_in_thread: `bool` or 

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

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

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

284 we always run the completions in the main thread. 

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

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

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

288 instance for input suggestions. 

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

290 :param include_default_pygments_style: `bool` or 

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

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

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

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

295 merged. 

296 :param style_transformation: 

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

298 :param swap_light_and_dark_colors: `bool` or 

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

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

301 This is useful for switching between dark and light terminal 

302 backgrounds. 

303 :param enable_system_prompt: `bool` or 

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

305 a system prompt. 

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

307 Enable Control-Z style suspension. 

308 :param enable_open_in_editor: `bool` or 

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

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

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

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

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

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

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

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

317 return formatted text. 

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

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

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

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

322 `prompt_width` spaces will be used. 

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

324 ``CompleteStyle.MULTI_COLUMN`` or ``CompleteStyle.READLINE_LIKE``. 

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

326 to enable mouse support. 

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

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

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

330 formatted text. 

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

332 every so many seconds. 

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

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

335 :param output: `Output` object. 

336 """ 

337 

338 _fields = ( 

339 "message", 

340 "lexer", 

341 "completer", 

342 "complete_in_thread", 

343 "is_password", 

344 "editing_mode", 

345 "key_bindings", 

346 "is_password", 

347 "bottom_toolbar", 

348 "style", 

349 "style_transformation", 

350 "swap_light_and_dark_colors", 

351 "color_depth", 

352 "cursor", 

353 "include_default_pygments_style", 

354 "rprompt", 

355 "multiline", 

356 "prompt_continuation", 

357 "wrap_lines", 

358 "enable_history_search", 

359 "search_ignore_case", 

360 "complete_while_typing", 

361 "validate_while_typing", 

362 "complete_style", 

363 "mouse_support", 

364 "auto_suggest", 

365 "clipboard", 

366 "validator", 

367 "refresh_interval", 

368 "input_processors", 

369 "placeholder", 

370 "enable_system_prompt", 

371 "enable_suspend", 

372 "enable_open_in_editor", 

373 "reserve_space_for_menu", 

374 "tempfile_suffix", 

375 "tempfile", 

376 ) 

377 

378 def __init__( 

379 self, 

380 message: AnyFormattedText = "", 

381 *, 

382 multiline: FilterOrBool = False, 

383 wrap_lines: FilterOrBool = True, 

384 is_password: FilterOrBool = False, 

385 vi_mode: bool = False, 

386 editing_mode: EditingMode = EditingMode.EMACS, 

387 complete_while_typing: FilterOrBool = True, 

388 validate_while_typing: FilterOrBool = True, 

389 enable_history_search: FilterOrBool = False, 

390 search_ignore_case: FilterOrBool = False, 

391 lexer: Lexer | None = None, 

392 enable_system_prompt: FilterOrBool = False, 

393 enable_suspend: FilterOrBool = False, 

394 enable_open_in_editor: FilterOrBool = False, 

395 validator: Validator | None = None, 

396 completer: Completer | None = None, 

397 complete_in_thread: bool = False, 

398 reserve_space_for_menu: int = 8, 

399 complete_style: CompleteStyle = CompleteStyle.COLUMN, 

400 auto_suggest: AutoSuggest | None = None, 

401 style: BaseStyle | None = None, 

402 style_transformation: StyleTransformation | None = None, 

403 swap_light_and_dark_colors: FilterOrBool = False, 

404 color_depth: ColorDepth | None = None, 

405 cursor: AnyCursorShapeConfig = None, 

406 include_default_pygments_style: FilterOrBool = True, 

407 history: History | None = None, 

408 clipboard: Clipboard | None = None, 

409 prompt_continuation: PromptContinuationText | None = None, 

410 rprompt: AnyFormattedText = None, 

411 bottom_toolbar: AnyFormattedText = None, 

412 mouse_support: FilterOrBool = False, 

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

414 placeholder: AnyFormattedText | None = None, 

415 key_bindings: KeyBindingsBase | None = None, 

416 erase_when_done: bool = False, 

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

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

419 refresh_interval: float = 0, 

420 input: Input | None = None, 

421 output: Output | None = None, 

422 ) -> None: 

423 history = history or InMemoryHistory() 

424 clipboard = clipboard or InMemoryClipboard() 

425 

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

427 if vi_mode: 

428 editing_mode = EditingMode.VI 

429 

430 # Store all settings in this class. 

431 self._input = input 

432 self._output = output 

433 

434 # Store attributes. 

435 # (All except 'editing_mode'.) 

436 self.message = message 

437 self.lexer = lexer 

438 self.completer = completer 

439 self.complete_in_thread = complete_in_thread 

440 self.is_password = is_password 

441 self.key_bindings = key_bindings 

442 self.bottom_toolbar = bottom_toolbar 

443 self.style = style 

444 self.style_transformation = style_transformation 

445 self.swap_light_and_dark_colors = swap_light_and_dark_colors 

446 self.color_depth = color_depth 

447 self.cursor = cursor 

448 self.include_default_pygments_style = include_default_pygments_style 

449 self.rprompt = rprompt 

450 self.multiline = multiline 

451 self.prompt_continuation = prompt_continuation 

452 self.wrap_lines = wrap_lines 

453 self.enable_history_search = enable_history_search 

454 self.search_ignore_case = search_ignore_case 

455 self.complete_while_typing = complete_while_typing 

456 self.validate_while_typing = validate_while_typing 

457 self.complete_style = complete_style 

458 self.mouse_support = mouse_support 

459 self.auto_suggest = auto_suggest 

460 self.clipboard = clipboard 

461 self.validator = validator 

462 self.refresh_interval = refresh_interval 

463 self.input_processors = input_processors 

464 self.placeholder = placeholder 

465 self.enable_system_prompt = enable_system_prompt 

466 self.enable_suspend = enable_suspend 

467 self.enable_open_in_editor = enable_open_in_editor 

468 self.reserve_space_for_menu = reserve_space_for_menu 

469 self.tempfile_suffix = tempfile_suffix 

470 self.tempfile = tempfile 

471 

472 # Create buffers, layout and Application. 

473 self.history = history 

474 self.default_buffer = self._create_default_buffer() 

475 self.search_buffer = self._create_search_buffer() 

476 self.layout = self._create_layout() 

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

478 

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

480 """ 

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

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

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

484 

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

486 or `Filter`. 

487 """ 

488 

489 @Condition 

490 def dynamic() -> bool: 

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

492 return to_filter(value)() 

493 

494 return dynamic 

495 

496 def _create_default_buffer(self) -> Buffer: 

497 """ 

498 Create and return the default input buffer. 

499 """ 

500 dyncond = self._dyncond 

501 

502 # Create buffers list. 

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

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

505 the validation succeeds.""" 

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

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

508 

509 return Buffer( 

510 name=DEFAULT_BUFFER, 

511 # Make sure that complete_while_typing is disabled when 

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

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

514 complete_while_typing=Condition( 

515 lambda: is_true(self.complete_while_typing) 

516 and not is_true(self.enable_history_search) 

517 and not self.complete_style == CompleteStyle.READLINE_LIKE 

518 ), 

519 validate_while_typing=dyncond("validate_while_typing"), 

520 enable_history_search=dyncond("enable_history_search"), 

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

522 completer=DynamicCompleter( 

523 lambda: ThreadedCompleter(self.completer) 

524 if self.complete_in_thread and self.completer 

525 else self.completer 

526 ), 

527 history=self.history, 

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

529 accept_handler=accept, 

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

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

532 ) 

533 

534 def _create_search_buffer(self) -> Buffer: 

535 return Buffer(name=SEARCH_BUFFER) 

536 

537 def _create_layout(self) -> Layout: 

538 """ 

539 Create `Layout` for this prompt. 

540 """ 

541 dyncond = self._dyncond 

542 

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

544 # a multiline prompt.) 

545 ( 

546 has_before_fragments, 

547 get_prompt_text_1, 

548 get_prompt_text_2, 

549 ) = _split_multiline_prompt(self._get_prompt) 

550 

551 default_buffer = self.default_buffer 

552 search_buffer = self.search_buffer 

553 

554 # Create processors list. 

555 @Condition 

556 def display_placeholder() -> bool: 

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

558 

559 all_input_processors = [ 

560 HighlightIncrementalSearchProcessor(), 

561 HighlightSelectionProcessor(), 

562 ConditionalProcessor( 

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

564 ), 

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

566 DisplayMultipleCursors(), 

567 # Users can insert processors here. 

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

569 ConditionalProcessor( 

570 AfterInput(lambda: self.placeholder), 

571 filter=display_placeholder, 

572 ), 

573 ] 

574 

575 # Create bottom toolbars. 

576 bottom_toolbar = ConditionalContainer( 

577 Window( 

578 FormattedTextControl( 

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

580 ), 

581 style="class:bottom-toolbar", 

582 dont_extend_height=True, 

583 height=Dimension(min=1), 

584 ), 

585 filter=~is_done 

586 & renderer_height_is_known 

587 & Condition(lambda: self.bottom_toolbar is not None), 

588 ) 

589 

590 search_toolbar = SearchToolbar( 

591 search_buffer, ignore_case=dyncond("search_ignore_case") 

592 ) 

593 

594 search_buffer_control = SearchBufferControl( 

595 buffer=search_buffer, 

596 input_processors=[ReverseSearchProcessor()], 

597 ignore_case=dyncond("search_ignore_case"), 

598 ) 

599 

600 system_toolbar = SystemToolbar( 

601 enable_global_bindings=dyncond("enable_system_prompt") 

602 ) 

603 

604 def get_search_buffer_control() -> SearchBufferControl: 

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

606 if is_true(self.multiline): 

607 return search_toolbar.control 

608 else: 

609 return search_buffer_control 

610 

611 default_buffer_control = BufferControl( 

612 buffer=default_buffer, 

613 search_buffer_control=get_search_buffer_control, 

614 input_processors=all_input_processors, 

615 include_default_input_processors=False, 

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

617 preview_search=True, 

618 ) 

619 

620 default_buffer_window = Window( 

621 default_buffer_control, 

622 height=self._get_default_buffer_control_height, 

623 get_line_prefix=partial( 

624 self._get_line_prefix, get_prompt_text_2=get_prompt_text_2 

625 ), 

626 wrap_lines=dyncond("wrap_lines"), 

627 ) 

628 

629 @Condition 

630 def multi_column_complete_style() -> bool: 

631 return self.complete_style == CompleteStyle.MULTI_COLUMN 

632 

633 # Build the layout. 

634 layout = HSplit( 

635 [ 

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

637 FloatContainer( 

638 HSplit( 

639 [ 

640 ConditionalContainer( 

641 Window( 

642 FormattedTextControl(get_prompt_text_1), 

643 dont_extend_height=True, 

644 ), 

645 Condition(has_before_fragments), 

646 ), 

647 ConditionalContainer( 

648 default_buffer_window, 

649 Condition( 

650 lambda: get_app().layout.current_control 

651 != search_buffer_control 

652 ), 

653 ), 

654 ConditionalContainer( 

655 Window(search_buffer_control), 

656 Condition( 

657 lambda: get_app().layout.current_control 

658 == search_buffer_control 

659 ), 

660 ), 

661 ] 

662 ), 

663 [ 

664 # Completion menus. 

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

666 # transparent, because the shape is not always 

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

668 Float( 

669 xcursor=True, 

670 ycursor=True, 

671 transparent=True, 

672 content=CompletionsMenu( 

673 max_height=16, 

674 scroll_offset=1, 

675 extra_filter=has_focus(default_buffer) 

676 & ~multi_column_complete_style, 

677 ), 

678 ), 

679 Float( 

680 xcursor=True, 

681 ycursor=True, 

682 transparent=True, 

683 content=MultiColumnCompletionsMenu( 

684 show_meta=True, 

685 extra_filter=has_focus(default_buffer) 

686 & multi_column_complete_style, 

687 ), 

688 ), 

689 # The right prompt. 

690 Float( 

691 right=0, 

692 top=0, 

693 hide_when_covering_content=True, 

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

695 ), 

696 ], 

697 ), 

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

699 ConditionalContainer( 

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

701 ), 

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

703 ConditionalContainer( 

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

705 dyncond("multiline") & has_arg, 

706 ), 

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

708 bottom_toolbar, 

709 ] 

710 ) 

711 

712 return Layout(layout, default_buffer_window) 

713 

714 def _create_application( 

715 self, editing_mode: EditingMode, erase_when_done: bool 

716 ) -> Application[_T]: 

717 """ 

718 Create the `Application` object. 

719 """ 

720 dyncond = self._dyncond 

721 

722 # Default key bindings. 

723 auto_suggest_bindings = load_auto_suggest_bindings() 

724 open_in_editor_bindings = load_open_in_editor_bindings() 

725 prompt_bindings = self._create_prompt_bindings() 

726 

727 # Create application 

728 application: Application[_T] = Application( 

729 layout=self.layout, 

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

731 style_transformation=merge_style_transformations( 

732 [ 

733 DynamicStyleTransformation(lambda: self.style_transformation), 

734 ConditionalStyleTransformation( 

735 SwapLightAndDarkStyleTransformation(), 

736 dyncond("swap_light_and_dark_colors"), 

737 ), 

738 ] 

739 ), 

740 include_default_pygments_style=dyncond("include_default_pygments_style"), 

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

742 key_bindings=merge_key_bindings( 

743 [ 

744 merge_key_bindings( 

745 [ 

746 auto_suggest_bindings, 

747 ConditionalKeyBindings( 

748 open_in_editor_bindings, 

749 dyncond("enable_open_in_editor") 

750 & has_focus(DEFAULT_BUFFER), 

751 ), 

752 prompt_bindings, 

753 ] 

754 ), 

755 DynamicKeyBindings(lambda: self.key_bindings), 

756 ] 

757 ), 

758 mouse_support=dyncond("mouse_support"), 

759 editing_mode=editing_mode, 

760 erase_when_done=erase_when_done, 

761 reverse_vi_search_direction=True, 

762 color_depth=lambda: self.color_depth, 

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

764 refresh_interval=self.refresh_interval, 

765 input=self._input, 

766 output=self._output, 

767 ) 

768 

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

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

771 # 'multiline' property dynamic. 

772 """ 

773 def on_render(app): 

774 multiline = is_true(self.multiline) 

775 current_control = app.layout.current_control 

776 

777 if multiline: 

778 if current_control == search_buffer_control: 

779 app.layout.current_control = search_toolbar.control 

780 app.invalidate() 

781 else: 

782 if current_control == search_toolbar.control: 

783 app.layout.current_control = search_buffer_control 

784 app.invalidate() 

785 

786 app.on_render += on_render 

787 """ 

788 

789 return application 

790 

791 def _create_prompt_bindings(self) -> KeyBindings: 

792 """ 

793 Create the KeyBindings for a prompt application. 

794 """ 

795 kb = KeyBindings() 

796 handle = kb.add 

797 default_focused = has_focus(DEFAULT_BUFFER) 

798 

799 @Condition 

800 def do_accept() -> bool: 

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

802 DEFAULT_BUFFER 

803 ) 

804 

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

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

807 "Accept input when enter has been pressed." 

808 self.default_buffer.validate_and_handle() 

809 

810 @Condition 

811 def readline_complete_style() -> bool: 

812 return self.complete_style == CompleteStyle.READLINE_LIKE 

813 

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

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

816 "Display completions (like Readline)." 

817 display_completions_like_readline(event) 

818 

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

820 @handle("<sigint>") 

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

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

823 event.app.exit(exception=KeyboardInterrupt, style="class:aborting") 

824 

825 @Condition 

826 def ctrl_d_condition() -> bool: 

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

828 and empty.""" 

829 app = get_app() 

830 return ( 

831 app.current_buffer.name == DEFAULT_BUFFER 

832 and not app.current_buffer.text 

833 ) 

834 

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

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

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

838 event.app.exit(exception=EOFError, style="class:exiting") 

839 

840 suspend_supported = Condition(suspend_to_background_supported) 

841 

842 @Condition 

843 def enable_suspend() -> bool: 

844 return to_filter(self.enable_suspend)() 

845 

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

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

848 """ 

849 Suspend process to background. 

850 """ 

851 event.app.suspend_to_background() 

852 

853 return kb 

854 

855 def prompt( 

856 self, 

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

858 # in this PromptSession. 

859 message: AnyFormattedText | None = None, 

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

861 # positional argument. 

862 *, 

863 editing_mode: EditingMode | None = None, 

864 refresh_interval: float | None = None, 

865 vi_mode: bool | None = None, 

866 lexer: Lexer | None = None, 

867 completer: Completer | None = None, 

868 complete_in_thread: bool | None = None, 

869 is_password: bool | None = None, 

870 key_bindings: KeyBindingsBase | None = None, 

871 bottom_toolbar: AnyFormattedText | None = None, 

872 style: BaseStyle | None = None, 

873 color_depth: ColorDepth | None = None, 

874 cursor: AnyCursorShapeConfig | None = None, 

875 include_default_pygments_style: FilterOrBool | None = None, 

876 style_transformation: StyleTransformation | None = None, 

877 swap_light_and_dark_colors: FilterOrBool | None = None, 

878 rprompt: AnyFormattedText | None = None, 

879 multiline: FilterOrBool | None = None, 

880 prompt_continuation: PromptContinuationText | None = None, 

881 wrap_lines: FilterOrBool | None = None, 

882 enable_history_search: FilterOrBool | None = None, 

883 search_ignore_case: FilterOrBool | None = None, 

884 complete_while_typing: FilterOrBool | None = None, 

885 validate_while_typing: FilterOrBool | None = None, 

886 complete_style: CompleteStyle | None = None, 

887 auto_suggest: AutoSuggest | None = None, 

888 validator: Validator | None = None, 

889 clipboard: Clipboard | None = None, 

890 mouse_support: FilterOrBool | None = None, 

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

892 placeholder: AnyFormattedText | None = None, 

893 reserve_space_for_menu: int | None = None, 

894 enable_system_prompt: FilterOrBool | None = None, 

895 enable_suspend: FilterOrBool | None = None, 

896 enable_open_in_editor: FilterOrBool | None = None, 

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

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

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

900 default: str | Document = "", 

901 accept_default: bool = False, 

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

903 set_exception_handler: bool = True, 

904 handle_sigint: bool = True, 

905 in_thread: bool = False, 

906 ) -> _T: 

907 """ 

908 Display the prompt. 

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 ) 

1040 

1041 @contextmanager 

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

1043 """ 

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

1045 

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

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

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

1049 

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

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

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

1053 right before the cursor. 

1054 """ 

1055 # Send prompt to output. 

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

1057 self.output.flush() 

1058 

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

1060 key_bindings: KeyBindingsBase = self._create_prompt_bindings() 

1061 if self.key_bindings: 

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

1063 

1064 # Create and run application. 

1065 application = cast( 

1066 Application[_T], 

1067 Application( 

1068 input=self.input, 

1069 output=DummyOutput(), 

1070 layout=self.layout, 

1071 key_bindings=key_bindings, 

1072 ), 

1073 ) 

1074 

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

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

1077 self.output.flush() 

1078 

1079 self.default_buffer.on_text_changed += on_text_changed 

1080 

1081 try: 

1082 yield application 

1083 finally: 

1084 # Render line ending. 

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

1086 self.output.flush() 

1087 

1088 self.default_buffer.on_text_changed -= on_text_changed 

1089 

1090 async def prompt_async( 

1091 self, 

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

1093 # in this PromptSession. 

1094 message: AnyFormattedText | None = None, 

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

1096 # positional argument. 

1097 *, 

1098 editing_mode: EditingMode | None = None, 

1099 refresh_interval: float | None = None, 

1100 vi_mode: bool | None = None, 

1101 lexer: Lexer | None = None, 

1102 completer: Completer | None = None, 

1103 complete_in_thread: bool | None = None, 

1104 is_password: bool | None = None, 

1105 key_bindings: KeyBindingsBase | None = None, 

1106 bottom_toolbar: AnyFormattedText | None = None, 

1107 style: BaseStyle | None = None, 

1108 color_depth: ColorDepth | None = None, 

1109 cursor: CursorShapeConfig | None = None, 

1110 include_default_pygments_style: FilterOrBool | None = None, 

1111 style_transformation: StyleTransformation | None = None, 

1112 swap_light_and_dark_colors: FilterOrBool | None = None, 

1113 rprompt: AnyFormattedText | None = None, 

1114 multiline: FilterOrBool | None = None, 

1115 prompt_continuation: PromptContinuationText | None = None, 

1116 wrap_lines: FilterOrBool | None = None, 

1117 enable_history_search: FilterOrBool | None = None, 

1118 search_ignore_case: FilterOrBool | None = None, 

1119 complete_while_typing: FilterOrBool | None = None, 

1120 validate_while_typing: FilterOrBool | None = None, 

1121 complete_style: CompleteStyle | None = None, 

1122 auto_suggest: AutoSuggest | None = None, 

1123 validator: Validator | None = None, 

1124 clipboard: Clipboard | None = None, 

1125 mouse_support: FilterOrBool | None = None, 

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

1127 placeholder: AnyFormattedText | None = None, 

1128 reserve_space_for_menu: int | None = None, 

1129 enable_system_prompt: FilterOrBool | None = None, 

1130 enable_suspend: FilterOrBool | None = None, 

1131 enable_open_in_editor: FilterOrBool | None = None, 

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

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

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

1135 default: str | Document = "", 

1136 accept_default: bool = False, 

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

1138 set_exception_handler: bool = True, 

1139 handle_sigint: bool = True, 

1140 ) -> _T: 

1141 if message is not None: 

1142 self.message = message 

1143 if editing_mode is not None: 

1144 self.editing_mode = editing_mode 

1145 if refresh_interval is not None: 

1146 self.refresh_interval = refresh_interval 

1147 if vi_mode: 

1148 self.editing_mode = EditingMode.VI 

1149 if lexer is not None: 

1150 self.lexer = lexer 

1151 if completer is not None: 

1152 self.completer = completer 

1153 if complete_in_thread is not None: 

1154 self.complete_in_thread = complete_in_thread 

1155 if is_password is not None: 

1156 self.is_password = is_password 

1157 if key_bindings is not None: 

1158 self.key_bindings = key_bindings 

1159 if bottom_toolbar is not None: 

1160 self.bottom_toolbar = bottom_toolbar 

1161 if style is not None: 

1162 self.style = style 

1163 if color_depth is not None: 

1164 self.color_depth = color_depth 

1165 if cursor is not None: 

1166 self.cursor = cursor 

1167 if include_default_pygments_style is not None: 

1168 self.include_default_pygments_style = include_default_pygments_style 

1169 if style_transformation is not None: 

1170 self.style_transformation = style_transformation 

1171 if swap_light_and_dark_colors is not None: 

1172 self.swap_light_and_dark_colors = swap_light_and_dark_colors 

1173 if rprompt is not None: 

1174 self.rprompt = rprompt 

1175 if multiline is not None: 

1176 self.multiline = multiline 

1177 if prompt_continuation is not None: 

1178 self.prompt_continuation = prompt_continuation 

1179 if wrap_lines is not None: 

1180 self.wrap_lines = wrap_lines 

1181 if enable_history_search is not None: 

1182 self.enable_history_search = enable_history_search 

1183 if search_ignore_case is not None: 

1184 self.search_ignore_case = search_ignore_case 

1185 if complete_while_typing is not None: 

1186 self.complete_while_typing = complete_while_typing 

1187 if validate_while_typing is not None: 

1188 self.validate_while_typing = validate_while_typing 

1189 if complete_style is not None: 

1190 self.complete_style = complete_style 

1191 if auto_suggest is not None: 

1192 self.auto_suggest = auto_suggest 

1193 if validator is not None: 

1194 self.validator = validator 

1195 if clipboard is not None: 

1196 self.clipboard = clipboard 

1197 if mouse_support is not None: 

1198 self.mouse_support = mouse_support 

1199 if input_processors is not None: 

1200 self.input_processors = input_processors 

1201 if placeholder is not None: 

1202 self.placeholder = placeholder 

1203 if reserve_space_for_menu is not None: 

1204 self.reserve_space_for_menu = reserve_space_for_menu 

1205 if enable_system_prompt is not None: 

1206 self.enable_system_prompt = enable_system_prompt 

1207 if enable_suspend is not None: 

1208 self.enable_suspend = enable_suspend 

1209 if enable_open_in_editor is not None: 

1210 self.enable_open_in_editor = enable_open_in_editor 

1211 if tempfile_suffix is not None: 

1212 self.tempfile_suffix = tempfile_suffix 

1213 if tempfile is not None: 

1214 self.tempfile = tempfile 

1215 

1216 self._add_pre_run_callables(pre_run, accept_default) 

1217 self.default_buffer.reset( 

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

1219 ) 

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

1221 

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

1223 # dumb prompt. 

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

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

1226 return await dump_app.run_async(handle_sigint=handle_sigint) 

1227 

1228 return await self.app.run_async( 

1229 set_exception_handler=set_exception_handler, handle_sigint=handle_sigint 

1230 ) 

1231 

1232 def _add_pre_run_callables( 

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

1234 ) -> None: 

1235 def pre_run2() -> None: 

1236 if pre_run: 

1237 pre_run() 

1238 

1239 if accept_default: 

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

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

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

1243 # display the default value. 

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

1245 

1246 self.app.pre_run_callables.append(pre_run2) 

1247 

1248 @property 

1249 def editing_mode(self) -> EditingMode: 

1250 return self.app.editing_mode 

1251 

1252 @editing_mode.setter 

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

1254 self.app.editing_mode = value 

1255 

1256 def _get_default_buffer_control_height(self) -> Dimension: 

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

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

1259 if ( 

1260 self.completer is not None 

1261 and self.complete_style != CompleteStyle.READLINE_LIKE 

1262 ): 

1263 space = self.reserve_space_for_menu 

1264 else: 

1265 space = 0 

1266 

1267 if space and not get_app().is_done: 

1268 buff = self.default_buffer 

1269 

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

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

1272 # soon. 

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

1274 return Dimension(min=space) 

1275 

1276 return Dimension() 

1277 

1278 def _get_prompt(self) -> StyleAndTextTuples: 

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

1280 

1281 def _get_continuation( 

1282 self, width: int, line_number: int, wrap_count: int 

1283 ) -> StyleAndTextTuples: 

1284 """ 

1285 Insert the prompt continuation. 

1286 

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

1288 be used.) 

1289 :param line_number: 

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

1291 """ 

1292 prompt_continuation = self.prompt_continuation 

1293 

1294 if callable(prompt_continuation): 

1295 continuation: AnyFormattedText = prompt_continuation( 

1296 width, line_number, wrap_count 

1297 ) 

1298 else: 

1299 continuation = prompt_continuation 

1300 

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

1302 # the actual prompt. 

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

1304 continuation = " " * width 

1305 

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

1307 

1308 def _get_line_prefix( 

1309 self, 

1310 line_number: int, 

1311 wrap_count: int, 

1312 get_prompt_text_2: _StyleAndTextTuplesCallable, 

1313 ) -> StyleAndTextTuples: 

1314 """ 

1315 Return whatever needs to be inserted before every line. 

1316 (the prompt, or a line continuation.) 

1317 """ 

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

1319 if line_number == 0 and wrap_count == 0: 

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

1321 return self._inline_arg() 

1322 else: 

1323 return get_prompt_text_2() 

1324 

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

1326 prompt_width = get_cwidth(fragment_list_to_text(get_prompt_text_2())) 

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

1328 

1329 def _get_arg_text(self) -> StyleAndTextTuples: 

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

1331 arg = self.app.key_processor.arg 

1332 if arg is None: 

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

1334 return [] 

1335 

1336 if arg == "-": 

1337 arg = "-1" 

1338 

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

1340 

1341 def _inline_arg(self) -> StyleAndTextTuples: 

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

1343 app = get_app() 

1344 if app.key_processor.arg is None: 

1345 return [] 

1346 else: 

1347 arg = app.key_processor.arg 

1348 

1349 return [ 

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

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

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

1353 ] 

1354 

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

1356 # backward-compatibility. 

1357 

1358 @property 

1359 def input(self) -> Input: 

1360 return self.app.input 

1361 

1362 @property 

1363 def output(self) -> Output: 

1364 return self.app.output 

1365 

1366 

1367def prompt( 

1368 message: AnyFormattedText | None = None, 

1369 *, 

1370 history: History | None = None, 

1371 editing_mode: EditingMode | None = None, 

1372 refresh_interval: float | None = None, 

1373 vi_mode: bool | None = None, 

1374 lexer: Lexer | None = None, 

1375 completer: Completer | None = None, 

1376 complete_in_thread: bool | None = None, 

1377 is_password: bool | None = None, 

1378 key_bindings: KeyBindingsBase | None = None, 

1379 bottom_toolbar: AnyFormattedText | None = None, 

1380 style: BaseStyle | None = None, 

1381 color_depth: ColorDepth | None = None, 

1382 cursor: AnyCursorShapeConfig = None, 

1383 include_default_pygments_style: FilterOrBool | None = None, 

1384 style_transformation: StyleTransformation | None = None, 

1385 swap_light_and_dark_colors: FilterOrBool | None = None, 

1386 rprompt: AnyFormattedText | None = None, 

1387 multiline: FilterOrBool | None = None, 

1388 prompt_continuation: PromptContinuationText | None = None, 

1389 wrap_lines: FilterOrBool | None = None, 

1390 enable_history_search: FilterOrBool | None = None, 

1391 search_ignore_case: FilterOrBool | None = None, 

1392 complete_while_typing: FilterOrBool | None = None, 

1393 validate_while_typing: FilterOrBool | None = None, 

1394 complete_style: CompleteStyle | None = None, 

1395 auto_suggest: AutoSuggest | None = None, 

1396 validator: Validator | None = None, 

1397 clipboard: Clipboard | None = None, 

1398 mouse_support: FilterOrBool | None = None, 

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

1400 placeholder: AnyFormattedText | None = None, 

1401 reserve_space_for_menu: int | None = None, 

1402 enable_system_prompt: FilterOrBool | None = None, 

1403 enable_suspend: FilterOrBool | None = None, 

1404 enable_open_in_editor: FilterOrBool | None = None, 

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

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

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

1408 default: str = "", 

1409 accept_default: bool = False, 

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

1411) -> str: 

1412 """ 

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

1414 instance for every call. 

1415 """ 

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

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

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

1419 

1420 return session.prompt( 

1421 message, 

1422 editing_mode=editing_mode, 

1423 refresh_interval=refresh_interval, 

1424 vi_mode=vi_mode, 

1425 lexer=lexer, 

1426 completer=completer, 

1427 complete_in_thread=complete_in_thread, 

1428 is_password=is_password, 

1429 key_bindings=key_bindings, 

1430 bottom_toolbar=bottom_toolbar, 

1431 style=style, 

1432 color_depth=color_depth, 

1433 cursor=cursor, 

1434 include_default_pygments_style=include_default_pygments_style, 

1435 style_transformation=style_transformation, 

1436 swap_light_and_dark_colors=swap_light_and_dark_colors, 

1437 rprompt=rprompt, 

1438 multiline=multiline, 

1439 prompt_continuation=prompt_continuation, 

1440 wrap_lines=wrap_lines, 

1441 enable_history_search=enable_history_search, 

1442 search_ignore_case=search_ignore_case, 

1443 complete_while_typing=complete_while_typing, 

1444 validate_while_typing=validate_while_typing, 

1445 complete_style=complete_style, 

1446 auto_suggest=auto_suggest, 

1447 validator=validator, 

1448 clipboard=clipboard, 

1449 mouse_support=mouse_support, 

1450 input_processors=input_processors, 

1451 placeholder=placeholder, 

1452 reserve_space_for_menu=reserve_space_for_menu, 

1453 enable_system_prompt=enable_system_prompt, 

1454 enable_suspend=enable_suspend, 

1455 enable_open_in_editor=enable_open_in_editor, 

1456 tempfile_suffix=tempfile_suffix, 

1457 tempfile=tempfile, 

1458 default=default, 

1459 accept_default=accept_default, 

1460 pre_run=pre_run, 

1461 ) 

1462 

1463 

1464prompt.__doc__ = PromptSession.prompt.__doc__ 

1465 

1466 

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() 

1474 

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) 

1480 

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) 

1486 

1487 @bindings.add(Keys.Any) 

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

1489 "Disallow inserting other text." 

1490 pass 

1491 

1492 complete_message = merge_formatted_text([message, suffix]) 

1493 session: PromptSession[bool] = PromptSession( 

1494 complete_message, key_bindings=bindings 

1495 ) 

1496 return session 

1497 

1498 

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()