Raxol.Core.Runtime.Application behaviour (Raxol v0.5.0)

View Source

Defines the behaviour for Raxol applications following The Elm Architecture (TEA).

This module provides the core structure for building terminal applications using a pure functional approach with unidirectional data flow. The architecture is composed of three main parts:

  1. Model - The complete state of your application
  2. Update - A way to update your state
  3. View - A way to view your state as UI elements

Example

defmodule MyApp do
  use Raxol.Core.Runtime.Application

  def init(_context) do
    %{count: 0}
  end

  def update(msg, model) do
    case msg do
      :increment ->
        {%{model | count: model.count + 1}, []}
      :decrement ->
        {%{model | count: model.count - 1}, []}
      _ ->
        {model, []}
    end
  end

  def view(model) do
    view do
      panel title: "Counter" do
        row do
          button(label: "-", on_click: :decrement)
          text(content: "Count: #{model.count}")
          button(label: "+", on_click: :increment)
        end
      end
    end
  end

  def subscribe(_model) do
    # Optional subscriptions to time-based or external events
    []
  end
end

Lifecycle

  1. The application starts with init/1, which sets up the initial state
  2. Events or messages trigger update/2, which computes the new state
  3. State changes cause view/1 to re-render the UI
  4. subscribe/1 can set up recurring updates or external event subscriptions

Commands and Effects

The update function returns a tuple of {new_state, commands}, where commands are used to handle side effects like:

  • API calls
  • File operations
  • Timer operations
  • Inter-process communication

Commands are executed by the runtime system, keeping the update function pure.

Subscriptions

Subscriptions allow your application to receive messages over time, such as:

  • Timer-based updates
  • System events
  • External data streams

Define subscriptions in the subscribe/1 callback, which is called after initialization and after each state update.

Summary

Callbacks

Initializes the application state.

Sets up subscriptions based on the current state.

Updates the application state in response to messages.

Renders the current state as UI elements.

Functions

Delegates initialization to the provided application module.

Gets environment configuration for the application.

Initializes the application state.

Handles incoming events or messages and updates the application state.

Types

command()

@type command() :: term()

context()

@type context() :: map()

element()

@type element() :: Raxol.Core.Renderer.Element.t()

message()

@type message() :: term()

model()

@type model() :: any()

state()

@type state() :: term()

subscription()

@type subscription() :: term()

Callbacks

handle_event(t)

@callback handle_event(Raxol.Core.Events.Event.t()) :: message() | :halt | nil

handle_message(message, model)

@callback handle_message(message :: any(), model :: model()) :: {model(), [command()]}

handle_tick(model)

@callback handle_tick(model :: model()) :: {model(), [command()]}

init(context)

@callback init(context()) :: state() | {state(), [command()]}
@callback init(context :: context()) ::
  {model(), [command()]} | {model(), command()} | model() | {:error, term()}

Initializes the application state.

Called once when the application starts. The context map contains runtime information such as terminal dimensions, environment variables, and startup arguments.

Returns either:

  • Initial state: state()
  • State and commands: {state(), [command()]}

subscribe(state)

(optional)
@callback subscribe(state()) :: [subscription()]

Sets up subscriptions based on the current state.

Called after initialization and after each state update. Use this to set up recurring updates or subscribe to external events.

Returns a list of subscription specifications.

subscriptions(model)

@callback subscriptions(model :: model()) ::
  [Raxol.Core.Runtime.Subscription.t()]
  | Raxol.Core.Runtime.Subscription.t()
  | []

terminate(reason, model)

@callback terminate(reason :: any(), model :: model()) :: any()

update(message, state)

@callback update(message(), state()) :: {state(), [command()]}
@callback update(message :: message(), model :: model()) ::
  {model(), [command()]} | {model(), command()} | model()

Updates the application state in response to messages.

Called whenever a message is received, either from events, commands, or subscriptions. Should be a pure function that computes the new state based on the current state and message.

Returns a tuple of the new state and any commands to be executed: {state(), [command()]}

view(state)

@callback view(state()) :: element()
@callback view(model :: model()) :: Raxol.UI.Layout.element() | nil

Renders the current state as UI elements.

Called after every state update to generate the new view. Should be a pure function that converts the state into UI elements.

Returns an element tree that will be rendered to the terminal.

Functions

delegate_init(app_module, context)

@spec delegate_init(module(), context()) ::
  {model(), [Command.t()]} | {:error, term()}

Delegates initialization to the provided application module.

Attempts to call the init/1 callback on the given module, handles the result, and returns a standardized tuple of {model, commands} or an error.

Parameters

  • app_module: The module that implements the Application behavior
  • context: The initialization context containing runtime information

Returns

  • {model, commands} tuple when successful
  • {:error, reason} tuple when initialization fails

delegate_update(app_module, message, current_model)

@spec delegate_update(module(), message(), model()) ::
  {model(), [Command.t()]} | {:error, term()}

get_env(app, key, default \\ nil)

@spec get_env(atom(), atom(), any()) :: any()

Gets environment configuration for the application.

init(app_module, context)

Initializes the application state.

Called once when the application starts. The context map contains runtime information such as terminal dimensions, environment variables, and startup arguments.

A simpler version of delegate_init that provides fallbacks for different return types from application modules.

Returns

  • {model, commands} tuple when successful
  • {:error, reason} tuple when initialization fails

update(app_module, message, model)

Handles incoming events or messages and updates the application state.

Returns the updated model and optional commands to execute.