Drafter.Runtime.Renderer (drafter v0.4.0)

Copy Markdown View Source

Rendering pipeline for Drafter applications.

Converts a widget hierarchy into terminal output via the compositor. Stateless — no process state, no message passing.

Summary

Types

A rectangle in terminal cells, as carried through the render pipeline.

Functions

One compositor layer per visible widget in hierarchy.

Rebuild the widget hierarchy for app_module's current state without painting.

Render one frame for app_module and return the hierarchy to reuse next frame.

Composite an already-built hierarchy and push the result to the compositor.

Composite the app, every screen on the screen stack, and any toasts, in that order.

Refresh each widget's cached state from its server and recompute preferred sizes.

Types

rect()

@type rect() :: %{
  x: integer(),
  y: integer(),
  width: non_neg_integer(),
  height: non_neg_integer()
}

A rectangle in terminal cells, as carried through the render pipeline.

Functions

create_widget_layers_from_hierarchy(hierarchy, rect, z_base \\ 0)

@spec create_widget_layers_from_hierarchy(map(), rect(), non_neg_integer()) :: [map()]

One compositor layer per visible widget in hierarchy.

Widgets listed in the hierarchy's :hidden_widgets set are skipped. z_base is added to each layer's z-index, so a screen's layers can be lifted above the app's. Default: 0. The rect argument is accepted for call-site symmetry and ignored; each layer is bounded by its own widget rect.

rebuild_hierarchy(app_module, app_state, screen_rect, existing_hierarchy)

@spec rebuild_hierarchy(module(), term(), rect(), map() | nil) :: map() | nil

Rebuild the widget hierarchy for app_module's current state without painting.

Mounts, updates and hides widgets exactly as render_app/4 would, so events that arrive before the next painted frame are routed against the tree the state describes. Returns the hierarchy to reuse, or existing_hierarchy while screens are pushed on the screen manager or the app's render/1 returned something other than a component tree.

render_app(app_module, app_state, screen_rect, existing_hierarchy \\ nil)

@spec render_app(module(), term(), rect(), map() | nil) ::
  {:ok, map() | nil} | {:error, nil}

Render one frame for app_module and return the hierarchy to reuse next frame.

With screens pushed on the screen manager, the screens are rendered and existing_hierarchy is returned untouched. With toasts but no screens, the app's hierarchy is rebuilt first so the toast composites over it. Otherwise the app is rendered directly, reusing existing_hierarchy when the app state hash and layout are both unchanged.

Returns {:ok, hierarchy}, {:ok, nil} when the app's render/1 returned strips rather than a component tree, or {:error, nil} when it returned {:error, reason}.

render_hierarchy(hierarchy, screen_rect)

@spec render_hierarchy(map(), rect()) :: :ok

Composite an already-built hierarchy and push the result to the compositor.

Used on the fast path, when the app state and layout are unchanged and no widget tree needs rebuilding. Any pushed screens and toasts are composited on top.

render_screens_from_manager(screen_rect, app_module, app_state, existing_hierarchy)

@spec render_screens_from_manager(rect(), module(), term(), map() | nil) :: :ok

Composite the app, every screen on the screen stack, and any toasts, in that order.

existing_hierarchy supplies the app's base layers when it is not nil; otherwise the app is re-rendered to produce them. Note the argument order: screen_rect comes first here, unlike render_app/4.

update_hierarchy_preferred_sizes(hierarchy)

@spec update_hierarchy_preferred_sizes(map()) :: map()

Refresh each widget's cached state from its server and recompute preferred sizes.

Widgets whose entry carries no live pid are left alone, as is a widget whose server fails to answer — its previously cached state is kept.