Skip to content

Commit 8c2489b

Browse files
Frames for prompt inputs.
1 parent 4db2b5f commit 8c2489b

File tree

2 files changed

+87
-63
lines changed

2 files changed

+87
-63
lines changed

src/prompt_toolkit/shortcuts/prompt.py

Lines changed: 82 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@
8383
from prompt_toolkit.key_binding.key_processor import KeyPressEvent
8484
from prompt_toolkit.keys import Keys
8585
from prompt_toolkit.layout import Float, FloatContainer, HSplit, Window
86-
from prompt_toolkit.layout.containers import ConditionalContainer, WindowAlign
86+
from prompt_toolkit.layout.containers import (
87+
AnyContainer,
88+
ConditionalContainer,
89+
WindowAlign,
90+
)
8791
from prompt_toolkit.layout.controls import (
8892
BufferControl,
8993
FormattedTextControl,
@@ -124,6 +128,7 @@
124128
to_str,
125129
)
126130
from prompt_toolkit.validation import DynamicValidator, Validator
131+
from prompt_toolkit.widgets import Frame
127132
from prompt_toolkit.widgets.toolbars import (
128133
SearchToolbar,
129134
SystemToolbar,
@@ -368,6 +373,7 @@ class PromptSession(Generic[_T]):
368373
"reserve_space_for_menu",
369374
"tempfile_suffix",
370375
"tempfile",
376+
"show_frame",
371377
)
372378

373379
def __init__(
@@ -412,6 +418,7 @@ def __init__(
412418
tempfile_suffix: str | Callable[[], str] | None = ".txt",
413419
tempfile: str | Callable[[], str] | None = None,
414420
refresh_interval: float = 0,
421+
show_frame: FilterOrBool = False,
415422
input: Input | None = None,
416423
output: Output | None = None,
417424
interrupt_exception: type[BaseException] = KeyboardInterrupt,
@@ -465,6 +472,7 @@ def __init__(
465472
self.reserve_space_for_menu = reserve_space_for_menu
466473
self.tempfile_suffix = tempfile_suffix
467474
self.tempfile = tempfile
475+
self.show_frame = show_frame
468476
self.interrupt_exception = interrupt_exception
469477
self.eof_exception = eof_exception
470478

@@ -632,69 +640,77 @@ def multi_column_complete_style() -> bool:
632640
return self.complete_style == CompleteStyle.MULTI_COLUMN
633641

634642
# Build the layout.
635-
layout = HSplit(
636-
[
637-
# The main input, with completion menus floating on top of it.
638-
FloatContainer(
639-
HSplit(
640-
[
641-
ConditionalContainer(
642-
Window(
643-
FormattedTextControl(get_prompt_text_1),
644-
dont_extend_height=True,
645-
),
646-
Condition(has_before_fragments),
647-
),
648-
ConditionalContainer(
649-
default_buffer_window,
650-
Condition(
651-
lambda: get_app().layout.current_control
652-
!= search_buffer_control
653-
),
654-
),
655-
ConditionalContainer(
656-
Window(search_buffer_control),
657-
Condition(
658-
lambda: get_app().layout.current_control
659-
== search_buffer_control
660-
),
661-
),
662-
]
643+
644+
# The main input, with completion menus floating on top of it.
645+
main_input_container = FloatContainer(
646+
HSplit(
647+
[
648+
ConditionalContainer(
649+
Window(
650+
FormattedTextControl(get_prompt_text_1),
651+
dont_extend_height=True,
652+
),
653+
Condition(has_before_fragments),
663654
),
664-
[
665-
# Completion menus.
666-
# NOTE: Especially the multi-column menu needs to be
667-
# transparent, because the shape is not always
668-
# rectangular due to the meta-text below the menu.
669-
Float(
670-
xcursor=True,
671-
ycursor=True,
672-
transparent=True,
673-
content=CompletionsMenu(
674-
max_height=16,
675-
scroll_offset=1,
676-
extra_filter=has_focus(default_buffer)
677-
& ~multi_column_complete_style,
678-
),
655+
ConditionalContainer(
656+
default_buffer_window,
657+
Condition(
658+
lambda: get_app().layout.current_control
659+
!= search_buffer_control
679660
),
680-
Float(
681-
xcursor=True,
682-
ycursor=True,
683-
transparent=True,
684-
content=MultiColumnCompletionsMenu(
685-
show_meta=True,
686-
extra_filter=has_focus(default_buffer)
687-
& multi_column_complete_style,
688-
),
689-
),
690-
# The right prompt.
691-
Float(
692-
right=0,
693-
top=0,
694-
hide_when_covering_content=True,
695-
content=_RPrompt(lambda: self.rprompt),
661+
),
662+
ConditionalContainer(
663+
Window(search_buffer_control),
664+
Condition(
665+
lambda: get_app().layout.current_control
666+
== search_buffer_control
696667
),
697-
],
668+
),
669+
]
670+
),
671+
[
672+
# Completion menus.
673+
# NOTE: Especially the multi-column menu needs to be
674+
# transparent, because the shape is not always
675+
# rectangular due to the meta-text below the menu.
676+
Float(
677+
xcursor=True,
678+
ycursor=True,
679+
transparent=True,
680+
content=CompletionsMenu(
681+
max_height=16,
682+
scroll_offset=1,
683+
extra_filter=has_focus(default_buffer)
684+
& ~multi_column_complete_style,
685+
),
686+
),
687+
Float(
688+
xcursor=True,
689+
ycursor=True,
690+
transparent=True,
691+
content=MultiColumnCompletionsMenu(
692+
show_meta=True,
693+
extra_filter=has_focus(default_buffer)
694+
& multi_column_complete_style,
695+
),
696+
),
697+
# The right prompt.
698+
Float(
699+
right=0,
700+
top=0,
701+
hide_when_covering_content=True,
702+
content=_RPrompt(lambda: self.rprompt),
703+
),
704+
],
705+
)
706+
707+
layout = HSplit(
708+
[
709+
# Wrap the main input in a frame, if requested.
710+
ConditionalContainer(
711+
Frame(main_input_container),
712+
filter=dyncond("show_frame"),
713+
alternative_content=main_input_container,
698714
),
699715
ConditionalContainer(ValidationToolbar(), filter=~is_done),
700716
ConditionalContainer(
@@ -897,6 +913,7 @@ def prompt(
897913
enable_open_in_editor: FilterOrBool | None = None,
898914
tempfile_suffix: str | Callable[[], str] | None = None,
899915
tempfile: str | Callable[[], str] | None = None,
916+
show_frame: FilterOrBool | None = None,
900917
# Following arguments are specific to the current `prompt()` call.
901918
default: str | Document = "",
902919
accept_default: bool = False,
@@ -1021,6 +1038,8 @@ class itself. For these, passing in ``None`` will keep the current
10211038
self.tempfile_suffix = tempfile_suffix
10221039
if tempfile is not None:
10231040
self.tempfile = tempfile
1041+
if show_frame is not None:
1042+
self.show_frame = show_frame
10241043

10251044
self._add_pre_run_callables(pre_run, accept_default)
10261045
self.default_buffer.reset(
@@ -1407,6 +1426,7 @@ def prompt(
14071426
enable_open_in_editor: FilterOrBool | None = None,
14081427
tempfile_suffix: str | Callable[[], str] | None = None,
14091428
tempfile: str | Callable[[], str] | None = None,
1429+
show_frame: FilterOrBool | None = None,
14101430
# Following arguments are specific to the current `prompt()` call.
14111431
default: str = "",
14121432
accept_default: bool = False,
@@ -1462,6 +1482,7 @@ def prompt(
14621482
enable_open_in_editor=enable_open_in_editor,
14631483
tempfile_suffix=tempfile_suffix,
14641484
tempfile=tempfile,
1485+
show_frame=show_frame,
14651486
default=default,
14661487
accept_default=accept_default,
14671488
pre_run=pre_run,

src/prompt_toolkit/widgets/base.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,11 @@ def has_title() -> bool:
535535

536536
self.container = HSplit(
537537
[
538-
ConditionalContainer(content=top_row_with_title, filter=has_title),
539-
ConditionalContainer(content=top_row_without_title, filter=~has_title),
538+
ConditionalContainer(
539+
content=top_row_with_title,
540+
filter=has_title,
541+
alternative_content=top_row_without_title,
542+
),
540543
VSplit(
541544
[
542545
fill(width=1, char=Border.VERTICAL),

0 commit comments

Comments
 (0)