ElixirOpentui.Runtime (ElixirOpentui v0.2.0)

Copy Markdown View Source

The MVU runtime GenServer. Owns all application and component state.

Runs the main loop:

  1. Receive events (from DemoRunner or test harness)
  2. Route through EventManager
  3. Update component states
  4. Re-render the element tree
  5. Diff and output to terminal

Can run in two modes:

  • :live - driven by a real terminal
  • :headless — for testing (no terminal, captures frames)

Summary

Functions

Returns a specification to start this module under a supervisor.

Dispatch an agent action. Synchronous — by the time this returns, the UI has re-rendered and is ready for a follow-up snapshot/1.

Drop live mode by ref. Decrements live counter.

Find a single widget in the current snapshot by id. Returns the semantic node or nil.

Get a component's current state.

Get the current focus state.

Get the current rendered frame as list of strings (headless mode).

Get the current element tree.

Set the root app module and initialize it.

Force a re-render.

Request live mode. Returns a ref that must be passed to drop_live/2.

Resize the runtime.

Resume the runtime — restores terminal and restarts tick loop. Must match each suspend.

Send a message to the app module's update/3 directly.

Send an event to the runtime for processing.

Send a message to a specific component.

Return a semantic snapshot of the UI for agent consumption.

Start continuous tick loop (explicit mode).

Start the runtime.

Stop continuous tick loop.

Suspend the runtime — pauses tick loop and suspends terminal. Supports nesting.

Types

component_state()

@type component_state() :: %{module: module(), state: term(), props: map()}

model()

@type model() :: %{
  app_module: module() | nil,
  app_state: term(),
  component_states: %{optional(term()) => component_state()},
  renderer: ElixirOpentui.Renderer.t(),
  event_manager: ElixirOpentui.EventManager.state(),
  tree: ElixirOpentui.Element.t() | nil,
  mode: :live | :headless,
  on_event: (term() -> :ok) | nil,
  control_state: :idle | :running | :stopping,
  target_frame_time: pos_integer(),
  last_tick_time: non_neg_integer(),
  live_refs: MapSet.t(reference()),
  explicit_start: boolean(),
  suspend_count: non_neg_integer(),
  tick_timer_ref: reference() | nil
}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

dispatch(server, action)

Dispatch an agent action. Synchronous — by the time this returns, the UI has re-rendered and is ready for a follow-up snapshot/1.

See ElixirOpentui.Accessibility.action/0 for the action vocabulary.

drop_live(server, ref)

@spec drop_live(GenServer.server(), reference()) :: :ok

Drop live mode by ref. Decrements live counter.

find_widget(server, id)

Find a single widget in the current snapshot by id. Returns the semantic node or nil.

get_component_state(server, id)

@spec get_component_state(GenServer.server(), term()) :: term() | nil

Get a component's current state.

get_focus(server)

@spec get_focus(GenServer.server()) :: ElixirOpentui.Focus.t()

Get the current focus state.

get_frame(server)

@spec get_frame(GenServer.server()) :: [String.t()]

Get the current rendered frame as list of strings (headless mode).

get_tree(server)

@spec get_tree(GenServer.server()) :: ElixirOpentui.Element.t() | nil

Get the current element tree.

mount(server, app_module, props \\ %{})

@spec mount(GenServer.server(), module(), map()) :: :ok

Set the root app module and initialize it.

render(server)

@spec render(GenServer.server()) :: :ok

Force a re-render.

request_live(server)

@spec request_live(GenServer.server()) :: reference()

Request live mode. Returns a ref that must be passed to drop_live/2.

resize(server, cols, rows)

@spec resize(GenServer.server(), non_neg_integer(), non_neg_integer()) :: :ok

Resize the runtime.

resume(server)

@spec resume(GenServer.server()) :: :ok

Resume the runtime — restores terminal and restarts tick loop. Must match each suspend.

send_app_msg(server, msg)

@spec send_app_msg(GenServer.server(), term()) :: :ok

Send a message to the app module's update/3 directly.

send_event(server, event)

@spec send_event(GenServer.server(), term()) :: :ok

Send an event to the runtime for processing.

send_msg(server, component_id, msg)

@spec send_msg(GenServer.server(), term(), term()) :: :ok

Send a message to a specific component.

snapshot(server)

Return a semantic snapshot of the UI for agent consumption.

See ElixirOpentui.Accessibility for the snapshot shape.

start(server)

@spec start(GenServer.server()) :: :ok

Start continuous tick loop (explicit mode).

start_link(opts \\ [])

Start the runtime.

stop(server)

@spec stop(GenServer.server()) :: :ok

Stop continuous tick loop.

suspend(server)

@spec suspend(GenServer.server()) :: :ok

Suspend the runtime — pauses tick loop and suspends terminal. Supports nesting.