TermUI.Runtime (TermUI v0.2.0)

View Source

The central runtime orchestrator for TermUI applications.

The runtime implements The Elm Architecture dispatch loop:

  1. Receive event from terminal
  2. Route to appropriate component
  3. Call component's event_to_msg
  4. Call component's update with message
  5. Collect commands from update
  6. Mark component dirty
  7. On render timer, call view and render

Usage

# Start with a root component
{:ok, runtime} = Runtime.start_link(root: MyApp.Root)

# Send events (usually from terminal input)
Runtime.send_event(runtime, Event.key(:enter))

# Shutdown gracefully
Runtime.shutdown(runtime)

Summary

Functions

Returns a specification to start this module under a supervisor.

Delivers a command result back to the runtime.

Forces an immediate render (bypassing framerate limiter).

Gets the current runtime state (for testing/debugging).

Starts the runtime and blocks until it shuts down.

Sends an event to the runtime for processing.

Sends a message directly to a component.

Initiates graceful shutdown of the runtime.

Starts the runtime with the given options.

Synchronously waits for all pending events and messages to be processed.

Types

option()

@type option() ::
  {:root, module()}
  | {:name, GenServer.name()}
  | {:render_interval, pos_integer()}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

command_result(runtime, component_id, command_id, result)

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

Delivers a command result back to the runtime.

force_render(runtime)

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

Forces an immediate render (bypassing framerate limiter).

get_state(runtime)

@spec get_state(GenServer.server()) :: TermUI.Runtime.State.t()

Gets the current runtime state (for testing/debugging).

run(opts)

@spec run([option()]) :: :ok | {:error, term()}

Starts the runtime and blocks until it shuts down.

This is the main entry point for running a TUI application. It starts the runtime, takes over the terminal, and blocks the calling process until the application exits (e.g., user presses quit key).

Options

Same as start_link/1.

Example

# In your application entry point:
TermUI.Runtime.run(root: MyApp.Root)
# This blocks until the app exits

send_event(runtime, event)

@spec send_event(GenServer.server(), TermUI.Event.t()) :: :ok

Sends an event to the runtime for processing.

send_message(runtime, component_id, message)

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

Sends a message directly to a component.

shutdown(runtime)

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

Initiates graceful shutdown of the runtime.

start_link(opts)

@spec start_link([option()]) :: GenServer.on_start()

Starts the runtime with the given options.

Options

  • :root - The root component module (required)
  • :name - GenServer name (optional)
  • :render_interval - Milliseconds between renders (default: 16)

sync(runtime, timeout \\ 5000)

@spec sync(GenServer.server(), timeout()) :: :ok

Synchronously waits for all pending events and messages to be processed.

This is primarily useful for testing to avoid race conditions from Process.sleep. It processes all queued messages and returns when complete.

Example

Runtime.send_event(runtime, Event.key(:up))
Runtime.send_event(runtime, Event.key(:up))
Runtime.sync(runtime)  # Wait for both events to be processed
state = Runtime.get_state(runtime)
assert state.root_state.count == 2