claudewheel v0.20.1 /claudewheel.ui
Edit
On this page

Reusable raw-mode selection form: a vertical list navigated with arrow keys.

#claudewheel.ui

#claudewheel.ui

Themed widget layer: form fields, a form runner, and fullscreen pages.

#_erase_inline

python
def _erase_inline(term: Terminal, line_count: int) -> None

Erase the inline form so subsequent output flows cleanly.

#run_selection

python
def run_selection(title: str, options: list[tuple[str, str]], theme: ThemeColors, terminal, use_alt_screen: bool=True, initial_key: str | None=None) -> str | None

Run a vertical selection list and return the chosen option's key.

options is a list of (key, label) pairs. Returns the focused option's key on Enter, or None on Esc/Ctrl-C. initial_key pre-focuses the matching option (falls back to the first option if absent).

Built on run_form: theme and terminal are required, and the terminal semantics (borrowed when already raw, owned raw cycle otherwise) apply.

#FormField

One widget in a form: text input, radio group, checkbox, button, readonly line, or selection list.

options holds plain strings for radio groups and (key, label) pairs for selection lists (whose value is the focused option's key). visible (if set) is called with the full field list and hides the field when it returns False. on_change (if set) is called with the full field list after every text edit, so dependent fields can update.

#get_field

python
def get_field(fields: list[FormField], key: str) -> FormField

Look up a form field by its key.

#_visible_indices

python
def _visible_indices(fields: list[FormField]) -> set[int]

Indices of fields whose visible predicate allows rendering.

#_focusable_indices

python
def _focusable_indices(fields: list[FormField]) -> list[int]

Indices of fields that are visible and interactive.

#_move_focus

python
def _move_focus(fields: list[FormField], focus: int, step: int) -> int

Move focus by step through focusable fields, wrapping at both ends.

#_cycle_radio

python
def _cycle_radio(f: FormField, step: int) -> None

Cycle a radio field's value by step, wrapping.

#_cycle_select

python
def _cycle_select(f: FormField, step: int) -> None

Cycle a select field's focused option key by step, wrapping.

#_hints_for_field

python
def _hints_for_field(f: FormField) -> str

Return keyboard hint text for the focused field.

#_field_lines

python
def _field_lines(f: FormField, focused: bool, th: ThemeColors) -> list[str]

Styled display lines for one field (selects span multiple lines).

Focused widgets render as a forms_focus_bg + forms_focus_fg span then RESET (the segment-bar focus idiom), never bold-foreground.

#_render_form_alt

python
def _render_form_alt(term, th: ThemeColors, title: str, fields: list[FormField], focus: int, error: str) -> None

Render the form centered on a full screen (absolute positioning).

#_render_form_inline

python
def _render_form_inline(term, th: ThemeColors, title: str, fields: list[FormField], focus: int, error: str, prev_lines: int) -> int

Render the form in place at the cursor position (no alt screen).

On redraw the cursor sits just below the form: move up prev_lines and reprint. Returns the new line count (visibility changes can alter it).

#_form_session

python
def _form_session(terminal, use_alt_screen: bool, render)

Signal swap and raw-mode ownership around a form or page.

Borrowed mode (terminal already raw): render only -- never enter or exit raw mode, and never close. Owned mode (cooked terminal): enter_raw at start, exit_raw at end -- but never close a terminal we didn't create. The resize handler is installed before entering raw mode so the previous owner's handler can't draw over the form.

SIGTERM and SIGHUP are caught so the terminal can be restored on abrupt termination. In owned mode the handler calls exit_raw before raising SystemExit; in borrowed mode it raises SystemExit directly (the outer owner is responsible for terminal cleanup).

#run_form

python
def run_form(title: str, fields: list[FormField], theme: ThemeColors, terminal, *, use_alt_screen: bool=True, validate: Callable[[list[FormField]], str | None] | None=None) -> dict[str, object] | None

Run a form's key loop and return {key: value} or None on cancel.

The runner owns focus traversal (TAB/SHIFT_TAB/UP/DOWN), radio cycling (LEFT/RIGHT/SPACE), checkbox toggling (SPACE), text editing, conditional field visibility, ENTER submit (from text, button, or select fields), and ESC/CTRL_C cancel. validate runs on submit; a returned error string blocks the submit and is shown in forms_error_fg.

If terminal is already raw, the form renders borrowed (fullscreen pages in the existing screen, regardless of use_alt_screen). Otherwise the runner enters raw mode itself -- with an alt screen when use_alt_screen is True, or inline (in-place, line-based) when False.

#show_page

python
def show_page(title: str, lines: list[str], theme: ThemeColors, terminal, *, hint: str='press any key to continue') -> str

Render a fullscreen page of text and wait for a single keypress.

Uses the same terminal semantics as run_form: borrowed when the terminal is already raw, otherwise an owned alt-screen raw cycle (never closed).

Returns the key string that was pressed (empty string on interrupt).