shore

Types

Send events to shore with the send function

pub type Event(msg) =
  @internal Event(msg)

Represents UI

pub type Node(msg) =
  @internal Node(msg)

Values

pub fn default_keybinds() -> @internal Keybinds

A typical set of keybindings

  • exit: ctrl+x
  • submit: enter
  • focus_clear: escape
  • focus_next: tab
  • focus_prv: shift+tab
pub fn exit() -> @internal Event(msg)

Manually trigger the exit for your TUI. Normally this would be handled through the exit keybind.

pub fn keybinds(
  exit exit: key.Key,
  submit submit: key.Key,
  focus_clear focus_clear: key.Key,
  focus_next focus_next: key.Key,
  focus_prev focus_prev: key.Key,
) -> @internal Keybinds

Set keybinds for various shore level functions, such as moving between focusable elements such as input boxes and buttons, as well as exiting and triggering button events.

pub fn on_timer(ms ms: Int) -> @internal Redraw

Redraw every x milliseconds

pub fn on_update() -> @internal Redraw

Redraw in response to events. Suitable for infrequently changing state.

pub fn send(msg: msg) -> @internal Event(msg)

Allows sending a message to your TUI from another actor. This can be used, for example, to push an event to your TUI, rather than have it poll.

pub fn spec(
  init init: fn() -> #(model, List(fn() -> msg)),
  view view: fn(model) -> @internal Node(msg),
  update update: fn(model, msg) -> #(model, List(fn() -> msg)),
  exit exit: process.Subject(Nil),
  keybinds keybinds: @internal Keybinds,
  redraw redraw: @internal Redraw,
) -> @internal Spec(model, msg)

A shore application is made up of these base parts. Following The Elm Architecture, you must define an init, view and update function which shore will handle calling.

Additionally, a simple subject to pass the exit call to is required. keybinding for the framework level events such as exiting and ui focusing. And finally redraw for defining when the applicaiton should be redrawn, either on update messages or on a timer.

init and update functions second argument List(fn() -> Msg) is an “effects handler”. You can pass effectful/blocking code here such as requests to databases, file system io, network requests and they will be automatically passed to a separate erlang process which will call update for you on their return. See the reader example for practical usage examples.

Example

import gleam/erlang/process
import shore

pub fn main() {
  let exit = process.new_subject()
  let assert Ok(_actor) =
    shore.spec(
      init:,
      update:,
      view:,
      exit:,
      keybinds: shore.default_keybinds(),
      redraw: shore.on_timer(16),
    )
    |> shore.start
  exit |> process.receive_forever
}

pub fn start(
  spec: @internal Spec(model, msg),
) -> Result(
  process.Subject(@internal Event(msg)),
  actor.StartError,
)

Starts the application actor and returns its subject

Search Document