Skip to content

inline

This module lets you run widgets as an inline terminal prompt.

inline(widget, *, exit_on=None, width=None)

Runs a widget as an inline terminal prompt.

This can be useful for adding GUI-like functionality within CLI scripts, as it gives you access to the widget system for building prompts, built in keyboard & mouse handling and everything else that makes PyTermGUI's WindowManager work, without the commitment to a full-screen app.

Parameters:

Name Type Description Default
widget T

Some widget that will be run.

required
width int | None

The width to set for the widget. If nothing is given, the widget's width is unchanged.

None

Returns:

Type Description
T

The same widget. This allows defining and running a prompt in the same line:

prompt = inline(_build_prompt())
Source code in pytermgui/widgets/inline.py
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def inline(
    widget: T, *, exit_on: list[str] | None = None, width: int | None = None
) -> T:
    """Runs a widget as an inline terminal prompt.

    This can be useful for adding GUI-like functionality within CLI scripts, as it
    gives you access to the widget system for building prompts, built in keyboard &
    mouse handling and everything else that makes PyTermGUI's WindowManager work,
    without the commitment to a full-screen app.

    Args:
        widget: Some widget that will be run.
        width: The width to set for the widget. If nothing is given, the widget's
            width is unchanged.

    Returns:
        The same widget. This allows defining and running a prompt in the same line:

            ```python
            prompt = inline(_build_prompt())
            ```
    """

    # Make sure we use the global terminal
    terminal = get_terminal()

    unset_echo()
    hide_cursor()

    if width is not None:
        widget.width = width

    if exit_on is None:
        exit_on = [keys.CTRL_C, keys.ENTER]

    widget.pos = report_cursor()

    def _print_widget() -> None:
        save_cursor()

        for line in widget.get_lines():
            print(line)

        for pos, line in widget.positioned_line_buffer:
            print_to(pos, line)
        widget.positioned_line_buffer = []

        restore_cursor()

    def _clear_widget() -> None:
        save_cursor()

        for _ in range(widget.height):
            clear("line")
            terminal.write("\n")

        restore_cursor()
        terminal.flush()

    _print_widget()

    with mouse_handler(["press_hold", "hover"], "decimal_xterm") as translate:
        while True:
            key = getch(interrupts=False)

            if key in exit_on:
                break

            if not widget.handle_key(key):
                events = translate(key)
                # Don't try iterating when there are no events
                if events is None:
                    continue

                for event in events:
                    if event is None:
                        continue
                    widget.handle_mouse(event)

            _clear_widget()
            _print_widget()

    _clear_widget()

    set_echo()
    show_cursor()

    return widget