Drafter.CellSession (drafter v0.3.1)

Copy Markdown View Source

Drives a Drafter app to an in-memory cell grid instead of a terminal.

A CellSession runs the ordinary app loop against a terminal driver that discards its output, and exposes the composited screen as rows of cells — Drafter.Draw.Strip structs, one per screen row — together with row-level diffs. A host renders those rows however it likes and feeds input back in with feed_input/2.

session = Drafter.CellSession.start(MyApp, size: {80, 24})
rows = Drafter.CellSession.take_cells(session)            # full grid
Drafter.CellSession.feed_input(session, {:key, :enter})   # drive input
{changed, session} = Drafter.CellSession.take_cells_diff(session)  # only changed rows
Drafter.CellSession.resize(session, 100, 30)
Drafter.CellSession.close(session)

Each session owns its own unnamed services, so many sessions run concurrently in one BEAM node without colliding.

Summary

Functions

Shut down the session and all of its services.

Inject an input event (e.g. {:key, :enter}, {:mouse, %{...}}) into the session.

Resize the virtual surface; the app re-renders to the new dimensions.

Start a cell-backed session for app_module.

Return the full current cell grid: one Strip per row.

Return the rows that changed since the previous diff (or first call) as {row_index, strip} tuples, and an updated session tracking the new snapshot.

Return the current screen as plain text, one string per row.

Return the current screen as one string, rows joined by newlines.

Types

cell_row()

@type cell_row() :: {non_neg_integer(), Drafter.Draw.Strip.t()}

t()

@type t() :: %Drafter.CellSession{
  app_pid: term(),
  compositor: term(),
  driver: term(),
  event_manager: term(),
  services: term(),
  snapshot: term()
}

Functions

close(cell_session)

@spec close(t()) :: :ok

Shut down the session and all of its services.

feed_input(cell_session, event)

@spec feed_input(t(), term()) :: :ok

Inject an input event (e.g. {:key, :enter}, {:mouse, %{...}}) into the session.

resize(cell_session, width, height)

@spec resize(t(), pos_integer(), pos_integer()) :: :ok

Resize the virtual surface; the app re-renders to the new dimensions.

start(app_module, opts \\ [])

@spec start(
  module(),
  keyword()
) :: t()

Start a cell-backed session for app_module.

Options:

  • :size{columns, rows} of the virtual surface, default {80, 24}
  • :shared — a shared-state server pid to join an existing multi-user session; omit for a session with private state

Every other option is passed to the app's mount/1 as a mount prop.

Returns the session struct, which the other functions in this module take. The caller must call close/1 to release the processes the session owns.

take_cells(cell_session)

@spec take_cells(t()) :: [Drafter.Draw.Strip.t()]

Return the full current cell grid: one Strip per row.

take_cells_diff(session)

@spec take_cells_diff(t()) :: {[cell_row()], t()}

Return the rows that changed since the previous diff (or first call) as {row_index, strip} tuples, and an updated session tracking the new snapshot.

take_lines(session)

@spec take_lines(t()) :: [String.t()]

Return the current screen as plain text, one string per row.

Styling is dropped and trailing blanks are trimmed, so a row is its content and an empty row is "". The list is always as long as the surface is tall.

["hello world", "second line", "", "", "", ""]

This is the same view Drafter.Test.screen_lines/1 gives of a headless app, for asserting on what is displayed rather than rendering it.

take_text(session)

@spec take_text(t()) :: String.t()

Return the current screen as one string, rows joined by newlines.

As take_lines/1, which documents the per-row form.