Init
im going to bed -=-
This commit is contained in:
311
lib/prompt_toolkit/shortcuts/choice_input.py
Normal file
311
lib/prompt_toolkit/shortcuts/choice_input.py
Normal file
@@ -0,0 +1,311 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Generic, Sequence, TypeVar
|
||||
|
||||
from prompt_toolkit.application import Application
|
||||
from prompt_toolkit.filters import (
|
||||
Condition,
|
||||
FilterOrBool,
|
||||
is_done,
|
||||
renderer_height_is_known,
|
||||
to_filter,
|
||||
)
|
||||
from prompt_toolkit.formatted_text import AnyFormattedText
|
||||
from prompt_toolkit.key_binding.key_bindings import (
|
||||
DynamicKeyBindings,
|
||||
KeyBindings,
|
||||
KeyBindingsBase,
|
||||
merge_key_bindings,
|
||||
)
|
||||
from prompt_toolkit.key_binding.key_processor import KeyPressEvent
|
||||
from prompt_toolkit.layout import (
|
||||
AnyContainer,
|
||||
ConditionalContainer,
|
||||
HSplit,
|
||||
Layout,
|
||||
Window,
|
||||
)
|
||||
from prompt_toolkit.layout.controls import FormattedTextControl
|
||||
from prompt_toolkit.layout.dimension import Dimension
|
||||
from prompt_toolkit.styles import BaseStyle, Style
|
||||
from prompt_toolkit.utils import suspend_to_background_supported
|
||||
from prompt_toolkit.widgets import Box, Frame, Label, RadioList
|
||||
|
||||
__all__ = [
|
||||
"ChoiceInput",
|
||||
"choice",
|
||||
]
|
||||
|
||||
_T = TypeVar("_T")
|
||||
E = KeyPressEvent
|
||||
|
||||
|
||||
def create_default_choice_input_style() -> BaseStyle:
|
||||
return Style.from_dict(
|
||||
{
|
||||
"frame.border": "#884444",
|
||||
"selected-option": "bold",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class ChoiceInput(Generic[_T]):
|
||||
"""
|
||||
Input selection prompt. Ask the user to choose among a set of options.
|
||||
|
||||
Example usage::
|
||||
|
||||
input_selection = ChoiceInput(
|
||||
message="Please select a dish:",
|
||||
options=[
|
||||
("pizza", "Pizza with mushrooms"),
|
||||
("salad", "Salad with tomatoes"),
|
||||
("sushi", "Sushi"),
|
||||
],
|
||||
default="pizza",
|
||||
)
|
||||
result = input_selection.prompt()
|
||||
|
||||
:param message: Plain text or formatted text to be shown before the options.
|
||||
:param options: Sequence of ``(value, label)`` tuples. The labels can be
|
||||
formatted text.
|
||||
:param default: Default value. If none is given, the first option is
|
||||
considered the default.
|
||||
:param mouse_support: Enable mouse support.
|
||||
:param style: :class:`.Style` instance for the color scheme.
|
||||
:param symbol: Symbol to be displayed in front of the selected choice.
|
||||
:param bottom_toolbar: Formatted text or callable that returns formatted
|
||||
text to be displayed at the bottom of the screen.
|
||||
:param show_frame: `bool` or
|
||||
:class:`~prompt_toolkit.filters.Filter`. When True, surround the input
|
||||
with a frame.
|
||||
:param enable_interrupt: `bool` or
|
||||
:class:`~prompt_toolkit.filters.Filter`. When True, raise
|
||||
the ``interrupt_exception`` (``KeyboardInterrupt`` by default) when
|
||||
control-c has been pressed.
|
||||
:param interrupt_exception: The exception type that will be raised when
|
||||
there is a keyboard interrupt (control-c keypress).
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
message: AnyFormattedText,
|
||||
options: Sequence[tuple[_T, AnyFormattedText]],
|
||||
default: _T | None = None,
|
||||
mouse_support: bool = False,
|
||||
style: BaseStyle | None = None,
|
||||
symbol: str = ">",
|
||||
bottom_toolbar: AnyFormattedText = None,
|
||||
show_frame: FilterOrBool = False,
|
||||
enable_suspend: FilterOrBool = False,
|
||||
enable_interrupt: FilterOrBool = True,
|
||||
interrupt_exception: type[BaseException] = KeyboardInterrupt,
|
||||
key_bindings: KeyBindingsBase | None = None,
|
||||
) -> None:
|
||||
if style is None:
|
||||
style = create_default_choice_input_style()
|
||||
|
||||
self.message = message
|
||||
self.default = default
|
||||
self.options = options
|
||||
self.mouse_support = mouse_support
|
||||
self.style = style
|
||||
self.symbol = symbol
|
||||
self.show_frame = show_frame
|
||||
self.enable_suspend = enable_suspend
|
||||
self.interrupt_exception = interrupt_exception
|
||||
self.enable_interrupt = enable_interrupt
|
||||
self.bottom_toolbar = bottom_toolbar
|
||||
self.key_bindings = key_bindings
|
||||
|
||||
def _create_application(self) -> Application[_T]:
|
||||
radio_list = RadioList(
|
||||
values=self.options,
|
||||
default=self.default,
|
||||
select_on_focus=True,
|
||||
open_character="",
|
||||
select_character=self.symbol,
|
||||
close_character="",
|
||||
show_cursor=False,
|
||||
show_numbers=True,
|
||||
container_style="class:input-selection",
|
||||
default_style="class:option",
|
||||
selected_style="",
|
||||
checked_style="class:selected-option",
|
||||
number_style="class:number",
|
||||
show_scrollbar=False,
|
||||
)
|
||||
container: AnyContainer = HSplit(
|
||||
[
|
||||
Box(
|
||||
Label(text=self.message, dont_extend_height=True),
|
||||
padding_top=0,
|
||||
padding_left=1,
|
||||
padding_right=1,
|
||||
padding_bottom=0,
|
||||
),
|
||||
Box(
|
||||
radio_list,
|
||||
padding_top=0,
|
||||
padding_left=3,
|
||||
padding_right=1,
|
||||
padding_bottom=0,
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@Condition
|
||||
def show_frame_filter() -> bool:
|
||||
return to_filter(self.show_frame)()
|
||||
|
||||
show_bottom_toolbar = (
|
||||
Condition(lambda: self.bottom_toolbar is not None)
|
||||
& ~is_done
|
||||
& renderer_height_is_known
|
||||
)
|
||||
|
||||
container = ConditionalContainer(
|
||||
Frame(container),
|
||||
alternative_content=container,
|
||||
filter=show_frame_filter,
|
||||
)
|
||||
|
||||
bottom_toolbar = ConditionalContainer(
|
||||
Window(
|
||||
FormattedTextControl(
|
||||
lambda: self.bottom_toolbar, style="class:bottom-toolbar.text"
|
||||
),
|
||||
style="class:bottom-toolbar",
|
||||
dont_extend_height=True,
|
||||
height=Dimension(min=1),
|
||||
),
|
||||
filter=show_bottom_toolbar,
|
||||
)
|
||||
|
||||
layout = Layout(
|
||||
HSplit(
|
||||
[
|
||||
container,
|
||||
# Add an empty window between the selection input and the
|
||||
# bottom toolbar, if the bottom toolbar is visible, in
|
||||
# order to allow the bottom toolbar to be displayed at the
|
||||
# bottom of the screen.
|
||||
ConditionalContainer(Window(), filter=show_bottom_toolbar),
|
||||
bottom_toolbar,
|
||||
]
|
||||
),
|
||||
focused_element=radio_list,
|
||||
)
|
||||
|
||||
kb = KeyBindings()
|
||||
|
||||
@kb.add("enter", eager=True)
|
||||
def _accept_input(event: E) -> None:
|
||||
"Accept input when enter has been pressed."
|
||||
event.app.exit(result=radio_list.current_value, style="class:accepted")
|
||||
|
||||
@Condition
|
||||
def enable_interrupt() -> bool:
|
||||
return to_filter(self.enable_interrupt)()
|
||||
|
||||
@kb.add("c-c", filter=enable_interrupt)
|
||||
@kb.add("<sigint>", filter=enable_interrupt)
|
||||
def _keyboard_interrupt(event: E) -> None:
|
||||
"Abort when Control-C has been pressed."
|
||||
event.app.exit(exception=self.interrupt_exception(), style="class:aborting")
|
||||
|
||||
suspend_supported = Condition(suspend_to_background_supported)
|
||||
|
||||
@Condition
|
||||
def enable_suspend() -> bool:
|
||||
return to_filter(self.enable_suspend)()
|
||||
|
||||
@kb.add("c-z", filter=suspend_supported & enable_suspend)
|
||||
def _suspend(event: E) -> None:
|
||||
"""
|
||||
Suspend process to background.
|
||||
"""
|
||||
event.app.suspend_to_background()
|
||||
|
||||
return Application(
|
||||
layout=layout,
|
||||
full_screen=False,
|
||||
mouse_support=self.mouse_support,
|
||||
key_bindings=merge_key_bindings(
|
||||
[kb, DynamicKeyBindings(lambda: self.key_bindings)]
|
||||
),
|
||||
style=self.style,
|
||||
)
|
||||
|
||||
def prompt(self) -> _T:
|
||||
return self._create_application().run()
|
||||
|
||||
async def prompt_async(self) -> _T:
|
||||
return await self._create_application().run_async()
|
||||
|
||||
|
||||
def choice(
|
||||
message: AnyFormattedText,
|
||||
*,
|
||||
options: Sequence[tuple[_T, AnyFormattedText]],
|
||||
default: _T | None = None,
|
||||
mouse_support: bool = False,
|
||||
style: BaseStyle | None = None,
|
||||
symbol: str = ">",
|
||||
bottom_toolbar: AnyFormattedText = None,
|
||||
show_frame: bool = False,
|
||||
enable_suspend: FilterOrBool = False,
|
||||
enable_interrupt: FilterOrBool = True,
|
||||
interrupt_exception: type[BaseException] = KeyboardInterrupt,
|
||||
key_bindings: KeyBindingsBase | None = None,
|
||||
) -> _T:
|
||||
"""
|
||||
Choice selection prompt. Ask the user to choose among a set of options.
|
||||
|
||||
Example usage::
|
||||
|
||||
result = choice(
|
||||
message="Please select a dish:",
|
||||
options=[
|
||||
("pizza", "Pizza with mushrooms"),
|
||||
("salad", "Salad with tomatoes"),
|
||||
("sushi", "Sushi"),
|
||||
],
|
||||
default="pizza",
|
||||
)
|
||||
|
||||
:param message: Plain text or formatted text to be shown before the options.
|
||||
:param options: Sequence of ``(value, label)`` tuples. The labels can be
|
||||
formatted text.
|
||||
:param default: Default value. If none is given, the first option is
|
||||
considered the default.
|
||||
:param mouse_support: Enable mouse support.
|
||||
:param style: :class:`.Style` instance for the color scheme.
|
||||
:param symbol: Symbol to be displayed in front of the selected choice.
|
||||
:param bottom_toolbar: Formatted text or callable that returns formatted
|
||||
text to be displayed at the bottom of the screen.
|
||||
:param show_frame: `bool` or
|
||||
:class:`~prompt_toolkit.filters.Filter`. When True, surround the input
|
||||
with a frame.
|
||||
:param enable_interrupt: `bool` or
|
||||
:class:`~prompt_toolkit.filters.Filter`. When True, raise
|
||||
the ``interrupt_exception`` (``KeyboardInterrupt`` by default) when
|
||||
control-c has been pressed.
|
||||
:param interrupt_exception: The exception type that will be raised when
|
||||
there is a keyboard interrupt (control-c keypress).
|
||||
"""
|
||||
return ChoiceInput[_T](
|
||||
message=message,
|
||||
options=options,
|
||||
default=default,
|
||||
mouse_support=mouse_support,
|
||||
style=style,
|
||||
symbol=symbol,
|
||||
bottom_toolbar=bottom_toolbar,
|
||||
show_frame=show_frame,
|
||||
enable_suspend=enable_suspend,
|
||||
enable_interrupt=enable_interrupt,
|
||||
interrupt_exception=interrupt_exception,
|
||||
key_bindings=key_bindings,
|
||||
).prompt()
|
||||
Reference in New Issue
Block a user