gleamtea

gleamtea — a delightful terminal UI framework for the BEAM, Gleam edition.

These are typed Gleam bindings to the Erlang beamtea library: Bubble Tea / The Elm Architecture on prim_tty.

A program is three functions:

Wire them together with program and run with start.

The neat part: Gleam’s custom types compile to exactly the Erlang terms beamtea already speaks. Quit becomes the atom quit, Tick(1000, msg) becomes {tick, 1000, Msg}, and an incoming keypress {key, up} matches the Key(Up) pattern — so the binding is (almost) all types and no glue.

Types

A command: a side-effect for the runtime to run after an update.

Each variant compiles directly to the Erlang term beamtea’s runtime interprets, so there is no marshalling cost.

pub type Cmd(msg) {
  None
  Quit
  Msg(msg)
  Tick(Int, msg)
  Every(Int, msg)
  Task(fn() -> msg)
  Batch(List(Cmd(msg)))
  Seq(List(Cmd(msg)))
}

Constructors

  • None

    Do nothing.

  • Quit

    Quit the program after this update.

  • Msg(msg)

    Deliver msg back to update as soon as possible.

  • Tick(Int, msg)

    Deliver msg once, after the given number of milliseconds.

  • Every(Int, msg)

    Deliver msg repeatedly, every N milliseconds, until the program quits.

  • Task(fn() -> msg)

    Run a function asynchronously; its return value is delivered to update.

  • Batch(List(Cmd(msg)))

    Run several commands.

  • Seq(List(Cmd(msg)))

    Run several commands in sequence.

A message delivered to your update. Wrap your own messages in User; the runtime delivers keyboard and resize events as Key and Resize.

pub type Event(user) {
  Key(key.Key)
  Resize(#(Int, Int))
  User(user)
}

Constructors

  • Key(key.Key)

    A keypress. See gleamtea/key.

  • Resize(#(Int, Int))

    The terminal was resized to #(columns, rows).

  • User(user)

    One of your own messages, produced by a command such as tick, every or task.

Where the runtime positions your whole view within the terminal. Center and TopCenter re-flow automatically on resize, so a small view can fill or centre the screen without any manual sizing. For finer control, compose with gleamtea/layout inside your view instead.

pub type Layout {
  TopLeft
  Center
  TopCenter
  Fill
}

Constructors

  • TopLeft

    Draw the view at the top-left corner (the default).

  • Center

    Centre the view horizontally and vertically.

  • TopCenter

    Centre the view horizontally, pinned to the top.

  • Fill

    Wrap the view in a bordered panel that fills the whole terminal.

Runtime options.

pub type Options {
  Options(alt_screen: Bool, catch_ctrl_c: Bool, layout: Layout)
}

Constructors

  • Options(alt_screen: Bool, catch_ctrl_c: Bool, layout: Layout)

    Arguments

    alt_screen

    Use the alternate screen buffer (like vim/less). Default True.

    catch_ctrl_c

    Quit on Ctrl-C instead of passing it to update. Default True.

    layout

    How to position the whole view within the terminal. Default TopLeft.

A normalized program: the three functions of The Elm Architecture.

pub type Program(model, msg) {
  Program(
    init: fn() -> #(model, Cmd(msg)),
    update: fn(msg, model) -> #(model, Cmd(msg)),
    view: fn(model) -> String,
  )
}

Constructors

  • Program(
      init: fn() -> #(model, Cmd(msg)),
      update: fn(msg, model) -> #(model, Cmd(msg)),
      view: fn(model) -> String,
    )

Values

pub fn default_options() -> Options

The default options: alternate screen on, Ctrl-C quits, top-left layout.

pub fn program(
  init init: fn() -> #(model, Cmd(msg)),
  update update: fn(msg, model) -> #(model, Cmd(msg)),
  view view: fn(model) -> String,
) -> Program(model, msg)

Assemble a program from its three functions.

pub fn start(
  program: Program(model, msg),
) -> Result(model, dynamic.Dynamic)

Start a program and block until it quits.

Returns Ok(final_model) on a clean exit, or Error(reason) if the program could not start (e.g. stdout is not a terminal) or crashed.

Run gleamtea programs so they own the terminal — use bin/gleamtea-run, which launches the VM with -noshell -noinput and puts the tty in raw mode. Starting from an interactive gleam run/shell will fight the shell for control of the terminal.

pub fn start_with(
  program: Program(model, msg),
  options: Options,
) -> Result(model, dynamic.Dynamic)

Start a program with explicit Options.

pub fn window_size() -> #(Int, Int)

The current terminal size as #(columns, rows).

Callable from init and view (they run in the runtime process), so a view can size its content to the terminal without threading the size through the model. The size also arrives in update as Resize(#(cols, rows)) if you prefer to store it. Returns #(80, 24) outside a running program.

Search Document