arizona_terminal_session (arizona v0.4.0)
View SourceTransport-agnostic orchestrator for ?terminal live views.
Mounts a ?terminal view (the calling process is its transport), then delegates
the terminal policy -- key mapping, paint model, screen setup/teardown -- to an
arizona_terminal_driver module. It holds no UX opinion of its own, so it serves
the local TTY driver (arizona_terminal_tty) and the SSH transport (arizona_terminal_ssh)
unchanged, with whatever terminal style the driver implements. Each callback
dispatches to the given driver if it exports it, otherwise to
arizona_terminal_default_driver's default -- so a driver overrides only what it
changes.
It is parameterized by a driver module and an output function out/0
(fun((iodata()) -> ok)). The owning process becomes the live view's transport: it
must forward each {arizona_push, _, _, Effects, _} it receives to handle_push/2, key
reads to handle_key/2, terminal resizes to resize/3, and {arizona_reloader, reload}
to handle_reload/1,2.
In dev mode (arizona_reloader:enabled/0) the owning process joins the reloader topic,
and handle_reload/1,2 remounts the view on fresh code in place: a fun held in the view's
state points into code a second reload purges, and a terminal client has no reconnect to
fall back on.
Summary
Functions
Handles a raw key read (a character list from a local TTY, or a byte binary from a
network transport). The driver maps it to commands: a stop command tears down and
returns quit; event commands are dispatched to the view and the result is
repainted. A read that maps to nothing returns {cont, Session} without repainting.
Handles a live-process push (the Effects from an {arizona_push, _, _, Effects, _} the
owning process received): repaints via the driver, returning quit if the driver
stops.
Handles a dev reload ({arizona_reloader, reload}): remounts the view with the bindings
it was mounted with. See handle_reload/2.
Handles a dev reload ({arizona_reloader, reload}): stops the live view and mounts a
fresh one from Bindings (a transport passes its current connection context, e.g. the
latest term_rows/term_cols), then repaints it. The view's state resets, as a browser
page's does on reload. Further reloads already queued are folded into this one, and so
are pushes the old view queued, which describe a view that no longer exists. Returns
quit if the driver stops on the repaint. A session that did not join the reloader
topic (the reloader was not enabled when it started) ignores it.
The live view process backing the session.
Notifies the view of a terminal resize. Sends {term_resize, Rows, Cols} to the
view's handle_info/2 (which updates bindings and re-renders); the resulting push
repaints. Sent straight to the live pid (not arizona_live:send/2, which targets
the live process's own mailbox).
Mounts Handler (request-free mount/1) as a live view whose transport is the
calling process, creates the Driver state from DriverArg, and paints the
initial frame via Out (after the driver's setup). Bindings carries any
connection context (e.g. term_rows/term_cols).
Stops the live process backing the session. A transport calls this when its connection ends, so the view doesn't outlive the transport (and unsubscribes from any pubsub channels). Teardown output is emitted on the quit path, not here -- on a disconnect the client is gone, so there's nothing to write to.
Emits the driver's teardown output (e.g. restoring the cursor) via the session's
output function, without touching the live process. A transport calls this to
restore the client's terminal when the live view has died asynchronously -- the
quit path already tears down before returning quit, but an out-of-band live-view
crash never reaches that path.
Types
-type out() :: fun((iodata()) -> ok).
-opaque session()
Functions
Handles a raw key read (a character list from a local TTY, or a byte binary from a
network transport). The driver maps it to commands: a stop command tears down and
returns quit; event commands are dispatched to the view and the result is
repainted. A read that maps to nothing returns {cont, Session} without repainting.
-spec handle_push(session(), [arizona_effect:cmd()]) -> {cont, session()} | quit.
Handles a live-process push (the Effects from an {arizona_push, _, _, Effects, _} the
owning process received): repaints via the driver, returning quit if the driver
stops.
Handles a dev reload ({arizona_reloader, reload}): remounts the view with the bindings
it was mounted with. See handle_reload/2.
-spec handle_reload(session(), arizona_template:bindings()) -> {cont, session()} | quit.
Handles a dev reload ({arizona_reloader, reload}): stops the live view and mounts a
fresh one from Bindings (a transport passes its current connection context, e.g. the
latest term_rows/term_cols), then repaints it. The view's state resets, as a browser
page's does on reload. Further reloads already queued are folded into this one, and so
are pushes the old view queued, which describe a view that no longer exists. Returns
quit if the driver stops on the repaint. A session that did not join the reloader
topic (the reloader was not enabled when it started) ignores it.
The live view process backing the session.
-spec resize(session(), pos_integer(), pos_integer()) -> ok.
Notifies the view of a terminal resize. Sends {term_resize, Rows, Cols} to the
view's handle_info/2 (which updates bindings and re-renders); the resulting push
repaints. Sent straight to the live pid (not arizona_live:send/2, which targets
the live process's own mailbox).
-spec start(Handler, Bindings, Driver, DriverArg, Out) -> {ok, session()} | quit when Handler :: module(), Bindings :: arizona_template:bindings(), Driver :: module(), DriverArg :: term(), Out :: out().
Mounts Handler (request-free mount/1) as a live view whose transport is the
calling process, creates the Driver state from DriverArg, and paints the
initial frame via Out (after the driver's setup). Bindings carries any
connection context (e.g. term_rows/term_cols).
The initial paint decides continue/stop like every other paint: a driver that
stops on the very first frame gets quit instead of a session, having already
emitted its teardown. Since the caller never receives a session it could stop,
start/5 also stops the live process itself on that path.
-spec stop(session()) -> ok.
Stops the live process backing the session. A transport calls this when its connection ends, so the view doesn't outlive the transport (and unsubscribes from any pubsub channels). Teardown output is emitted on the quit path, not here -- on a disconnect the client is gone, so there's nothing to write to.
-spec teardown(session()) -> ok.
Emits the driver's teardown output (e.g. restoring the cursor) via the session's
output function, without touching the live process. A transport calls this to
restore the client's terminal when the live view has died asynchronously -- the
quit path already tears down before returning quit, but an out-of-band live-view
crash never reaches that path.