Liking cljdoc? Tell your friends :D

com.fulcrologic.fulcro.tui.engine

The pure TUI engine: the layout, paint, diff, focus, input, and overlay-compositing pipeline that turns a tree of terminal-native nodes into a character cell buffer (and ANSI), plus the component-render walker. This namespace also owns the node-structure vocabulary (the ::tag/ ::attrs/::children keys and related specs) and the focus/scroll/caret state keys.

Build the node tree with the element generators in com.fulcrologic.fulcro.tui.elements; drive it to a terminal with com.fulcrologic.fulcro.tui.application; paint to a concrete terminal via com.fulcrologic.fulcro.tui.terminal.

A node is a plain map of the form:

{:com.fulcrologic.fulcro.tui.engine/tag      :vbox        ; one of `tags`
 :com.fulcrologic.fulcro.tui.engine/attrs    {...}        ; layout/style/event attributes
 :com.fulcrologic.fulcro.tui.engine/children [...]}       ; child nodes, strings, and numbers

This is JVM/babashka only (plain .clj).

The pure TUI engine: the layout, paint, diff, focus, input, and overlay-compositing pipeline that
turns a tree of terminal-native *nodes* into a character cell buffer (and ANSI), plus the
component-render walker. This namespace also owns the node-structure vocabulary (the `::tag`/
`::attrs`/`::children` keys and related specs) and the focus/scroll/caret state keys.

Build the node tree with the element generators in `com.fulcrologic.fulcro.tui.elements`; drive it
to a terminal with `com.fulcrologic.fulcro.tui.application`; paint to a concrete terminal via
`com.fulcrologic.fulcro.tui.terminal`.

A node is a plain map of the form:

```
{:com.fulcrologic.fulcro.tui.engine/tag      :vbox        ; one of `tags`
 :com.fulcrologic.fulcro.tui.engine/attrs    {...}        ; layout/style/event attributes
 :com.fulcrologic.fulcro.tui.engine/children [...]}       ; child nodes, strings, and numbers
```

This is JVM/babashka only (plain `.clj`).
raw docstring

*current-focus*clj

The :id of the currently focused node, bound by the walker/driver during a render so that render code can call focused?. Defaults to nil.

The `:id` of the currently focused node, bound by the walker/driver during a
render so that render code can call `focused?`. Defaults to `nil`.
sourceraw docstring

activate!clj

(activate! node)

Invokes the :on-activate handler attribute of TUI node (if present) with no arguments and returns its result. Returns nil when there is no handler. Used to simulate activating a button/control.

Invokes the `:on-activate` handler attribute of TUI `node` (if present) with no
arguments and returns its result. Returns `nil` when there is no handler. Used to
simulate activating a button/control.
sourceraw docstring

active-treeclj

(active-tree node-tree)

Returns the subtree that should receive focus and keyboard input. When an overlay is open it is the topmost (last in document order) OPEN :modal node — trapping focus to the overlay; otherwise it is node-tree itself. In either case any other (closed or nested) :modal nodes are stripped, so a closed modal's contents are never focusable and only the active layer's controls take keys.

Returns the subtree that should receive focus and keyboard input. When an overlay is open it is
the topmost (last in document order) OPEN `:modal` node — trapping focus to the overlay; otherwise it
is `node-tree` itself. In either case any other (closed or nested) `:modal` nodes are stripped, so a
closed modal's contents are never focusable and only the active layer's controls take keys.
sourceraw docstring

align-offsetclj

(align-offset align extent size)

Returns the offset of a child of size within a track of extent for the given align keyword. :center/:middle center it, :end/:right/:bottom push it to the far edge, anything else (default) keeps it at the near edge.

Returns the offset of a child of `size` within a track of `extent` for the given `align` keyword.
`:center`/`:middle` center it, `:end`/`:right`/`:bottom` push it to the far edge, anything else
(default) keeps it at the near edge.
sourceraw docstring

all-scrollclj

(all-scroll app-or-state)

Returns the whole viewport-scroll map {viewport-id {:x :y}} from app-or-state (the state-map key ::scroll), or {} when none is recorded. Accepts a Fulcro app (reads its state-atom) or a raw state-map.

Returns the whole viewport-scroll map `{viewport-id {:x :y}}` from `app-or-state` (the state-map
key `::scroll`), or `{}` when none is recorded. Accepts a Fulcro app (reads its state-atom) or a
raw state-map.
sourceraw docstring

apply-editclj

(apply-edit value caret key-event)

Returns {:value :caret} after applying the editing key-event to controlled input text value with the cursor at caret (a 0-based index, clamped into [0, (count value)]). Handles:

  • a printable key (:char is a 1-char string) — insert at the caret, caret += 1
  • :backspace — delete the char left of the caret, caret -= 1
  • :delete — delete the char right of the caret, caret unchanged
  • :left/:right — move the caret one cell (clamped)
  • :home/:end — move the caret to the start/end

Any other key leaves value and (clamped) caret unchanged. Pure.

Returns `{:value :caret}` after applying the editing `key-event` to controlled
input text `value` with the cursor at `caret` (a 0-based index, clamped into
`[0, (count value)]`). Handles:

* a printable key (`:char` is a 1-char string) — insert at the caret, caret += 1
* `:backspace` — delete the char left of the caret, caret -= 1
* `:delete`    — delete the char right of the caret, caret unchanged
* `:left`/`:right` — move the caret one cell (clamped)
* `:home`/`:end`   — move the caret to the start/end

Any other key leaves `value` and (clamped) `caret` unchanged. Pure.
sourceraw docstring

apply-edit-multilineclj

(apply-edit-multiline value caret width key-event)

Returns {:value :caret} after applying editing key-event to multiline input text value (a string that may contain \n) with the cursor at caret, given the input's display width (the wrap width, used for visual-line navigation). caret is clamped into [0, (count value)]. Differs from apply-edit for a single-line input in three ways:

  • :enter inserts a newline (\n) at the caret and advances it (it does NOT submit).
  • :up/:down move the caret one VISUAL line (per the wrapped layout at width), preserving the current visual column as the target column (clamped to the destination row's length).
  • :home/:end move to the start/end of the current VISUAL line (not the whole value).

Printable insertion, :backspace, :delete, and :left/:right behave as in apply-edit; because \n is an ordinary character of value, left/right and backspace/delete cross line boundaries naturally. Any other key leaves value and (clamped) caret unchanged. Pure.

Returns `{:value :caret}` after applying editing `key-event` to multiline input text `value` (a
string that may contain `\n`) with the cursor at `caret`, given the input's display `width` (the
wrap width, used for visual-line navigation). `caret` is clamped into `[0, (count value)]`. Differs
from `apply-edit` for a single-line input in three ways:

* `:enter` inserts a newline (`\n`) at the caret and advances it (it does NOT submit).
* `:up`/`:down` move the caret one VISUAL line (per the wrapped layout at `width`), preserving the
  current visual column as the target column (clamped to the destination row's length).
* `:home`/`:end` move to the start/end of the current VISUAL line (not the whole value).

Printable insertion, `:backspace`, `:delete`, and `:left`/`:right` behave as in `apply-edit`;
because `\n` is an ordinary character of `value`, left/right and backspace/delete cross line
boundaries naturally. Any other key leaves `value` and (clamped) `caret` unchanged. Pure.
sourceraw docstring

apply-focus-change!clj

(apply-focus-change! app node-tree old-id new-id)

Fires focus-transition handlers when focus moves from old-id to new-id within node-tree. When the ids differ, the node with old-id has its :on-lost-focus handler invoked with old-id, and the node with new-id has its :on-focus handler invoked with new-id (both found via find-by-id, matching the interaction-util handler-arg convention). Returns app. A no-op when the ids are equal.

Fires focus-transition handlers when focus moves from `old-id` to `new-id` within
`node-tree`. When the ids differ, the node with `old-id` has its `:on-lost-focus`
handler invoked with `old-id`, and the node with `new-id` has its `:on-focus`
handler invoked with `new-id` (both found via `find-by-id`, matching the
interaction-util handler-arg convention). Returns `app`. A no-op when the ids are
equal.
sourceraw docstring

as-nodeclj

(as-node c)

Returns c unchanged if it is a node, otherwise wraps it as a :text node. Lets containers hold bare strings/numbers, which become text lines.

Returns `c` unchanged if it is a node, otherwise wraps it as a `:text` node. Lets containers hold
bare strings/numbers, which become text lines.
sourceraw docstring

blitclj

(blit dest src src-x src-y w h dest-x dest-y clip)

Returns dest buffer with the [src-x src-y w h] window of the src buffer copied so that the window's top-left lands at dest-x,dest-y in dest. Each copied cell is written via put-cell, so writes are clipped to dest's bounds; in addition, copies are clipped to clip (a dest-space rect). Cells read from outside src's bounds are skipped. Pure.

Returns `dest` buffer with the `[src-x src-y w h]` window of the `src` buffer copied so that the
window's top-left lands at `dest-x`,`dest-y` in `dest`. Each copied cell is written via `put-cell`,
so writes are clipped to `dest`'s bounds; in addition, copies are clipped to `clip` (a dest-space
rect). Cells read from outside `src`'s bounds are skipped. Pure.
sourceraw docstring

caret->rowcolclj

(caret->rowcol value width caret)

Returns the visual [row col] of caret index caret within the layout of value wrapped to width columns. The caret is clamped into [0, (count value)]. At a soft-wrap boundary the caret resolves to the END of the earlier row (see the wrap-boundary convention above). Pure.

Returns the visual `[row col]` of caret index `caret` within the layout of `value` wrapped to
`width` columns. The caret is clamped into `[0, (count value)]`. At a soft-wrap boundary the caret
resolves to the END of the earlier row (see the wrap-boundary convention above). Pure.
sourceraw docstring

child-sizeclj

(child-size c)

Returns the intrinsic {:w :h} of a child c, which may be a node, string, or number.

Returns the intrinsic `{:w :h}` of a child `c`, which may be a node, string, or number.
sourceraw docstring

clamp-scrollclj

(clamp-scroll scroll virtual-size view-size)

Returns the scroll offset {:x :y} clamped so the visible window stays within the virtual content. Given the virtual-size {:w :h} of the laid-out child and the view-size {:w :h} of the viewport's content area, each axis is clamped to 0..(max 0 (- virtual view)). When the virtual content is no larger than the view, that axis clamps to 0. Pure.

Returns the `scroll` offset `{:x :y}` clamped so the visible window stays within the virtual
content. Given the `virtual-size` `{:w :h}` of the laid-out child and the `view-size` `{:w :h}`
of the viewport's content area, each axis is clamped to `0..(max 0 (- virtual view))`. When the
virtual content is no larger than the view, that axis clamps to 0. Pure.
sourceraw docstring

clear-caret!clj

(clear-caret! app id)

Removes any stored caret for input id from app's runtime caret store (::carets). Returns app.

Removes any stored caret for input `id` from `app`'s runtime caret store
(`::carets`). Returns `app`.
sourceraw docstring

code-point-widthclj

(code-point-width cp)

Returns the terminal column width (0, 1, or 2) of Unicode code point cp, using a compact approximation of POSIX wcwidth: 0 for NUL, control characters, and combining/zero-width marks; 2 for East Asian wide/fullwidth characters and common emoji; 1 otherwise.

Returns the terminal column width (0, 1, or 2) of Unicode code point `cp`, using a compact
approximation of POSIX `wcwidth`: 0 for NUL, control characters, and combining/zero-width marks;
2 for East Asian wide/fullwidth characters and common emoji; 1 otherwise.
sourceraw docstring

collect-overlaysclj

(collect-overlays node-tree)

Returns a vector of the OPEN :modal nodes in node-tree (those whose :open? attr is truthy), in document (pre-order, depth-first) order. Closed modals are omitted. The last element is the topmost overlay (a later sibling/descendant draws over earlier ones).

Returns a vector of the OPEN `:modal` nodes in `node-tree` (those whose `:open?` attr is truthy), in
document (pre-order, depth-first) order. Closed modals are omitted. The last element is the topmost
overlay (a later sibling/descendant draws over earlier ones).
sourceraw docstring

content-rectclj

(content-rect node)

Returns the inner content rectangle of placed node: its ::rect shrunk by the edge insets implied by its attrs (:border?/:padding).

Returns the inner content rectangle of placed `node`: its `::rect` shrunk by the edge insets implied
by its attrs (`:border?`/`:padding`).
sourceraw docstring

content-sizecljmultimethod

Returns the content-driven intrinsic {:w :h} of node for its ::tag, BEFORE the node's own :width/:height/:min-* overrides (which intrinsic-size applies). Extension seam for custom RENDERED tags: register the natural size of your tag with (defmethod content-size :my/tag [node] {:w .. :h ..}) (include any :padding/:border? insets yourself — see edge-insets). Built-in tags are handled by :default; an unregistered custom tag falls back to insets-only.

Returns the content-driven intrinsic `{:w :h}` of `node` for its `::tag`, BEFORE the node's own
`:width`/`:height`/`:min-*` overrides (which `intrinsic-size` applies). Extension seam for custom
RENDERED tags: register the natural size of your tag with `(defmethod content-size :my/tag [node]
{:w .. :h ..})` (include any `:padding`/`:border?` insets yourself — see `edge-insets`). Built-in
tags are handled by `:default`; an unregistered custom tag falls back to insets-only.
sourceraw docstring

content-view-sizeclj

(content-view-size node)

Returns the content-area size {:w :h} of a placed node: its ::rect size shrunk by the edge insets implied by its attrs (:border?/:padding). This is the visible window size of a viewport.

Returns the content-area size `{:w :h}` of a placed `node`: its `::rect` size shrunk by the edge
insets implied by its attrs (`:border?`/`:padding`). This is the visible window size of a viewport.
sourceraw docstring

continuation-cell?clj

(continuation-cell? prev cell)

Returns true if cell is a wide-char continuation marker: a space whose preceding cell prev holds a 2-column character.

Returns true if `cell` is a wide-char continuation marker: a space whose preceding cell `prev` holds
a 2-column character.
sourceraw docstring

current-focusclj

(current-focus app-or-state)

Returns the currently focused node :id from app-or-state. Accepts either a Fulcro app (reads its state-atom) or a raw state-map. Returns nil when nothing is focused.

Returns the currently focused node `:id` from `app-or-state`. Accepts either a
Fulcro app (reads its state-atom) or a raw state-map. Returns `nil` when nothing
is focused.
sourceraw docstring

current-node-treeclj

(current-node-tree app)

Returns the current pure TUI node tree for app, computed from its state. The root class is read from the runtime atom (:com.fulcrologic.fulcro.application/root-class); its props are obtained via fdn/db->tree of the root query over the state-map. *current-focus* is bound to the current ::focus while rendering so render code can call focused?.

Returns the current pure TUI node tree for `app`, computed from its state. The root
class is read from the runtime atom
(`:com.fulcrologic.fulcro.application/root-class`); its props are obtained via
`fdn/db->tree` of the root query over the state-map. `*current-focus*` is bound to
the current `::focus` while rendering so render code can call `focused?`.
sourceraw docstring

diffclj

(diff prev next)

Returns a vector of run ops describing how to turn buffer prev into buffer next. Each op is {:row r :col c :sgr <codes-vector> :text "..."}; horizontally adjacent changed cells sharing a style are coalesced into a single op and unchanged cells produce no ops. When prev is nil or has different dimensions than next, a full repaint is emitted (every non-default cell, still coalesced per row).

Returns a vector of run ops describing how to turn buffer `prev` into buffer `next`. Each op is
`{:row r :col c :sgr <codes-vector> :text "..."}`; horizontally adjacent changed cells sharing a
style are coalesced into a single op and unchanged cells produce no ops. When `prev` is `nil` or has
different dimensions than `next`, a full repaint is emitted (every non-default cell, still
coalesced per row).
sourceraw docstring

distribute-mainclj

(distribute-main extent cross-extent children main-attr)

Returns a vector of resolved main-axis sizes (one per child) that partition extent. Children with a :grow weight share the space left over after fixed/fraction/content-sized children; leftover is split by weight with any rounding remainder given to the last grow child. cross-extent is the cross-axis track size each child will fill, used to resolve height-for-width wrapping text.

Returns a vector of resolved main-axis sizes (one per child) that partition `extent`. Children
with a `:grow` weight share the space left over after fixed/fraction/content-sized children;
leftover is split by weight with any rounding remainder given to the last grow child. `cross-extent`
is the cross-axis track size each child will fill, used to resolve height-for-width wrapping text.
sourceraw docstring

draw-borderclj

(draw-border buffer rect style clip)

Returns buffer with a single-cell box-drawing border (┌┐└┘ corners, top/bottom, sides) drawn around the outer rect, clipped to clip. Boxes smaller than 2x2 are not drawn.

Returns `buffer` with a single-cell box-drawing border (`┌┐└┘` corners, `─` top/bottom, `│` sides)
drawn around the outer `rect`, clipped to `clip`. Boxes smaller than 2x2 are not drawn.
sourceraw docstring

edge-insetsclj

(edge-insets attrs)

Returns {:l :r :t :b} per-edge insets implied by attrs. :border? adds 1 to every edge and :padding (a non-negative integer) adds its value to every edge.

Returns `{:l :r :t :b}` per-edge insets implied by `attrs`. `:border?` adds 1 to every edge and
`:padding` (a non-negative integer) adds its value to every edge.
sourceraw docstring

fill-rectclj

(fill-rect buffer rect style clip)

Returns buffer with every cell of rect set to a space in style, clipped to clip.

Returns `buffer` with every cell of `rect` set to a space in `style`, clipped to `clip`.
sourceraw docstring

find-by-idclj

(find-by-id node id)

Returns the first node (depth-first, pre-order) within node whose :id attribute equals id, or nil if none is found. Strings/numbers and non-node children are skipped. node may itself be the match.

Returns the first node (depth-first, pre-order) within `node` whose `:id` attribute
equals `id`, or `nil` if none is found. Strings/numbers and non-node children are
skipped. `node` may itself be the match.
sourceraw docstring

focus!clj

(focus! app id)

Sets the focused node :id to id in the app's state-map at ::focus (the single source of truth) via a direct swap!. If the app declares a renderer (:com.fulcrologic.fulcro.application/render-root!/schedule-render!) it triggers a render so the change is reflected on screen, but it remains usable without a terminal. Returns the app.

Sets the focused node `:id` to `id` in the app's state-map at `::focus` (the
single source of truth) via a direct `swap!`. If the app declares a renderer
(`:com.fulcrologic.fulcro.application/render-root!`/`schedule-render!`) it triggers
a render so the change is reflected on screen, but it remains usable without a
terminal. Returns the app.
sourceraw docstring

focus-orderclj

(focus-order focusables)

Returns focusables sorted into focus-traversal order: by :priority descending, then by :dfs (document order) ascending.

Returns `focusables` sorted into focus-traversal order: by `:priority`
descending, then by `:dfs` (document order) ascending.
sourceraw docstring

focus-viewport-contextclj

(focus-viewport-context placed-tree focus-id)

Returns {:viewport <placed-viewport-node> :virtual-rect <rect>} describing the innermost placed :viewport in placed-tree whose virtual content subtree (::viewport-content) contains the node with :id focus-id, along with that focused node's VIRTUAL ::rect (0-based within the viewport). Returns nil when focus-id is not inside any viewport. When viewports are nested, the innermost enclosing viewport is returned.

Returns `{:viewport <placed-viewport-node> :virtual-rect <rect>}` describing the innermost placed
`:viewport` in `placed-tree` whose virtual content subtree (`::viewport-content`) contains the node
with `:id` `focus-id`, along with that focused node's VIRTUAL `::rect` (0-based within the viewport).
Returns `nil` when `focus-id` is not inside any viewport. When viewports are nested, the innermost
enclosing viewport is returned.
sourceraw docstring

focusable-node?clj

(focusable-node? node)

Returns true if node can receive focus. A node is focusable when it has an :id attribute AND either: its attrs set :focusable? true, its tag is :input or :button, or it carries any of the focus-relevant handler attributes (:on-key, :on-activate, :on-change, :on-focus, :on-lost-focus).

Returns true if `node` can receive focus. A node is focusable when it has an
`:id` attribute AND either: its attrs set `:focusable? true`, its tag is `:input`
or `:button`, or it carries any of the focus-relevant handler attributes
(`:on-key`, `:on-activate`, `:on-change`, `:on-focus`, `:on-lost-focus`).
sourceraw docstring

focusablesclj

(focusables node-tree)

Returns an ordered vector of focusable descriptors for every focusable node in node-tree, in document (pre-order, depth-first) order. Each descriptor is a map {:id :priority :dfs :node} where :priority is the node's :priority attr (default 0) and :dfs is the node's pre-order index among all visited nodes.

Returns an ordered vector of focusable descriptors for every focusable node in
`node-tree`, in document (pre-order, depth-first) order. Each descriptor is a map
`{:id :priority :dfs :node}` where `:priority` is the node's `:priority` attr
(default 0) and `:dfs` is the node's pre-order index among all visited nodes.
sourceraw docstring

frame->ansiclj

(frame->ansi prev next opts)

Returns the ANSI string to render the transition from buffer prev to buffer next, by diffing them and serializing the ops. When :sync? in opts is true the whole sequence is wrapped in DEC private mode 2026 ("\u001b[?2026h""\u001b[?2026l") so the terminal applies it as a single atomic frame; otherwise no wrapper is added. When :clear? in opts is true a clear-screen plus cursor-home is prepended to the body — used on a resize repaint, where a plain full repaint only writes non-blank cells and would otherwise leave stale content from the previous size on screen.

Returns the ANSI string to render the transition from buffer `prev` to buffer `next`, by diffing
them and serializing the ops. When `:sync?` in `opts` is true the whole sequence is wrapped in DEC
private mode 2026 (`"\u001b[?2026h"` … `"\u001b[?2026l"`) so the terminal applies it as a
single atomic frame; otherwise no wrapper is added. When `:clear?` in `opts` is true a clear-screen
plus cursor-home is prepended to the body — used on a resize repaint, where a plain full repaint only
writes non-blank cells and would otherwise leave stale content from the previous size on screen.
sourceraw docstring

get-caretclj

(get-caret app id default)

Returns the caret index stored for input id in app's runtime caret store (::carets), or default (the end of the value) when none is stored.

Returns the caret index stored for input `id` in `app`'s runtime caret store
(`::carets`), or `default` (the end of the value) when none is stored.
sourceraw docstring

handle-input-key!clj

(handle-input-key! app input-node key-event)

Applies key key-event to focused input-node (an :input node) in app, mutating value and caret per the controlled-input model. Reads the node's current :value attr and caret (from the runtime store, or — when the node opts in with a :caret attr — from that attr), computes the edit, then calls the node's :on-change handler with the new value and caret (interaction-util convention). The new caret is written to the runtime store UNLESS the node opted into caret-in-state (has a :caret attr), in which case the store is left for the node to manage.

Single-line vs multiline (:multiline? true):

  • Single-line: an :enter key invokes the node's :on-submit handler with the current value (it does not edit); other keys use apply-edit.
  • Multiline: editing uses apply-edit-multiline with the input's effective wrap width (from the runtime ::input-widths store, falling back to the node's :width attr, then a large default so a not-yet-painted input wraps only on hard newlines). :enter inserts a \n (it does NOT submit), and :up/:down move the caret by one visual line.

Returns app.

Applies key `key-event` to focused `input-node` (an `:input` node) in `app`,
mutating value and caret per the controlled-input model. Reads the node's current
`:value` attr and caret (from the runtime store, or — when the node opts in with a
`:caret` attr — from that attr), computes the edit, then calls the node's `:on-change`
handler with the new value and caret (interaction-util convention). The new caret is
written to the runtime store UNLESS the node opted into caret-in-state (has a `:caret`
attr), in which case the store is left for the node to manage.

Single-line vs multiline (`:multiline? true`):
* Single-line: an `:enter` key invokes the node's `:on-submit` handler with the current value
  (it does not edit); other keys use `apply-edit`.
* Multiline: editing uses `apply-edit-multiline` with the input's effective wrap width (from the
  runtime `::input-widths` store, falling back to the node's `:width` attr, then a large default
  so a not-yet-painted input wraps only on hard newlines). `:enter` inserts a `\n` (it does NOT
  submit), and `:up`/`:down` move the caret by one visual line.

Returns `app`.
sourceraw docstring

hard-breakclj

(hard-break s width)

Returns a vector of pieces of string s, each at most width display columns wide, splitting s greedily at code-point boundaries (measured with code-point-width). Used to break an over-long word that cannot fit on a single wrapped line. A piece never exceeds width columns, so a wide (2-column) character is never split. Returns [] for the empty string.

Returns a vector of pieces of string `s`, each at most `width` display columns wide, splitting `s`
greedily at code-point boundaries (measured with `code-point-width`). Used to break an over-long
word that cannot fit on a single wrapped line. A piece never exceeds `width` columns, so a wide
(2-column) character is never split. Returns `[]` for the empty string.
sourceraw docstring

in-bounds?clj

(in-bounds? buffer x y)

Returns true if the 0-based column x and row y lie inside the rowsxcols buffer.

Returns true if the 0-based column `x` and row `y` lie inside the `rows`x`cols` `buffer`.
sourceraw docstring

in-clip?clj

(in-clip? clip x y)

Returns true if column x, row y is inside the clip rect {:x :y :w :h}.

Returns true if column `x`, row `y` is inside the `clip` rect `{:x :y :w :h}`.
sourceraw docstring

input-widthclj

(input-width app id default)

Returns the effective content width (in columns) recorded for multiline input id in app's runtime (::input-widths, populated by the driver during render), or default when none is recorded. The width is used by handle-input-key!/the driver to wrap the value and run visual caret navigation.

Returns the effective content width (in columns) recorded for multiline input `id` in `app`'s
runtime (`::input-widths`, populated by the driver during render), or `default` when none is
recorded. The width is used by `handle-input-key!`/the driver to wrap the value and run visual
caret navigation.
sourceraw docstring

internal-content-sizeclj

(internal-content-size node)

Returns the content-driven intrinsic {:w :h} of a BUILT-IN node for its tag, before the node's own fixed :width/:height or :min-* overrides are applied. Container sizes include edge insets. The case default is a terminal fallback (insets only) used for an unregistered custom tag — a custom tag that declares :width/:height still sizes via the overrides applied in intrinsic-size-impl.

Returns the content-driven intrinsic `{:w :h}` of a BUILT-IN `node` for its tag, before the node's
own fixed `:width`/`:height` or `:min-*` overrides are applied. Container sizes include edge insets.
The `case` default is a terminal fallback (insets only) used for an unregistered custom tag — a custom
tag that declares `:width`/`:height` still sizes via the overrides applied in `intrinsic-size-impl`.
sourceraw docstring

internal-paintclj

(internal-paint buffer node clip)

Returns buffer after painting a BUILT-IN placed node and its descendants (the paint :default), clipping every write to clip (the intersection of ancestor rects). Containers draw their border/background then recurse (via paint, so custom children dispatch); leaves write their text/value/rule into their content rect. The case default is a terminal fallback (paint nothing) for an unregistered custom tag — it must NOT re-enter paint.

Returns `buffer` after painting a BUILT-IN placed `node` and its descendants (the `paint`
`:default`), clipping every write to `clip` (the intersection of ancestor rects). Containers draw
their border/background then recurse (via `paint`, so custom children dispatch); leaves write their
text/value/rule into their content rect. The `case` default is a terminal fallback (paint nothing)
for an unregistered custom tag — it must NOT re-enter `paint`.
sourceraw docstring

internal-placeclj

(internal-place node rect)

Lays out a BUILT-IN node within the outer rect (the place :default). :vbox/:hbox partition their content area among children (honoring fixed/:half/:fraction/:grow/content sizing and :align); :box fills its content area with each child; leaves keep their string/number children for the paint pass. :border?/:padding inset the content area.

A :viewport is special: it has a bounded outer ::rect (sized like any box), but its single child is laid out at the child's NATURAL height (and the viewport's content width) into a VIRTUAL rect {:x 0 :y 0 :w content-w :h (max content-h natural-h)} — i.e. in 0-based virtual coordinates rather than absolute screen coordinates. The placed virtual child subtree is stored under ::viewport-content, the virtual content size under ::virtual-size {:w :h}, and a default ::scroll {:x 0 :y 0} is attached (the driver later injects the real scroll). The viewport's ::children are also placed (in virtual coords) so generic walkers still see them.

The case default is the terminal leaf placement (annotate ::rect, keep children), used by the built-in leaves AND by an unregistered custom tag — so it must NOT re-enter place.

Lays out a BUILT-IN `node` within the outer `rect` (the `place` `:default`). `:vbox`/`:hbox`
partition their content area among children (honoring fixed/`:half`/`:fraction`/`:grow`/content
sizing and `:align`); `:box` fills its content area with each child; leaves keep their string/number
children for the paint pass. `:border?`/`:padding` inset the content area.

A `:viewport` is special: it has a bounded outer `::rect` (sized like any box), but its single
child is laid out at the child's NATURAL height (and the viewport's content width) into a VIRTUAL
rect `{:x 0 :y 0 :w content-w :h (max content-h natural-h)}` — i.e. in 0-based virtual coordinates
rather than absolute screen coordinates. The placed virtual child subtree is stored under
`::viewport-content`, the virtual content size under `::virtual-size {:w :h}`, and a default
`::scroll {:x 0 :y 0}` is attached (the driver later injects the real scroll). The viewport's
`::children` are also placed (in virtual coords) so generic walkers still see them.

The `case` default is the terminal leaf placement (annotate `::rect`, keep children), used by the
built-in leaves AND by an unregistered custom tag — so it must NOT re-enter `place`.
sourceraw docstring

intrinsic-sizeclj

(intrinsic-size node)

Returns the intrinsic {:w :h} of node in terminal cells. The content size (text length, stacked/abutted children, plus any :border?/:padding insets) is overridden by the node's own fixed :width/:height when those are integers, and then floored by :min-width/:min-height. Fraction and :grow sizing are not resolved here — they require a concrete parent rectangle and are handled by the place pass.

The result is memoized by node value (see intrinsic-size-impl); this is the public, transparent entry point and is what child-size recurses through, so every subtree level hits the cache.

Returns the intrinsic `{:w :h}` of `node` in terminal cells. The content size (text length,
stacked/abutted children, plus any `:border?`/`:padding` insets) is overridden by the node's own
fixed `:width`/`:height` when those are integers, and then floored by `:min-width`/`:min-height`.
Fraction and `:grow` sizing are not resolved here — they require a concrete parent rectangle and
are handled by the place pass.

The result is memoized by node value (see `intrinsic-size-impl`); this is the public, transparent
entry point and is what `child-size` recurses through, so every subtree level hits the cache.
sourceraw docstring

key-chordclj

(key-chord event)

Returns the normalized chord for key event event, used to look up a handler in a global keymap. With no modifiers, a special key returns its :key keyword (e.g. :tab) and a printable key returns its 1-char string (e.g. "a"). When a modifier is set, returns a vector of the active modifier keywords (in [:ctrl :alt :shift] order) followed by the base key, e.g. [:ctrl "q"].

Returns the normalized chord for key event `event`, used to look up a handler in a
global keymap. With no modifiers, a special key returns its `:key` keyword (e.g.
`:tab`) and a printable key returns its 1-char string (e.g. `"a"`). When a
modifier is set, returns a vector of the active modifier keywords (in
`[:ctrl :alt :shift]` order) followed by the base key, e.g. `[:ctrl "q"]`.
sourceraw docstring

main-content-sizeclj

(main-content-size c cross-extent main-attr)

Returns the content-driven main-axis size of child c being stacked along main-attr (:height for a vbox, :width for an hbox) given the cross-extent (the cross-axis track size the child will fill). For a wrapping :text stacked vertically this is its wrapped line count at the available content width (cross-extent minus the node's own insets); otherwise it is the child's ordinary intrinsic size on the main axis.

Returns the content-driven main-axis size of child `c` being stacked along `main-attr`
(`:height` for a vbox, `:width` for an hbox) given the `cross-extent` (the cross-axis track size
the child will fill). For a wrapping `:text` stacked vertically this is its wrapped line count at
the available content width (`cross-extent` minus the node's own insets); otherwise it is the
child's ordinary intrinsic size on the main axis.
sourceraw docstring

make-bufferclj

(make-buffer rows cols)

Returns a blank cell buffer of rows by cols. Every cell is a space with the default (empty) style. Cells are stored row-major in a flat vector of length rows*cols.

Returns a blank cell buffer of `rows` by `cols`. Every cell is a space with the default (empty)
style. Cells are stored row-major in a flat vector of length `rows`*`cols`.
sourceraw docstring

(modal-node? node)

Returns true if node is a :modal overlay node.

Returns true if `node` is a `:modal` overlay node.
sourceraw docstring

multiline-input?clj

(multiline-input? node)

Returns true if node is an :input node whose attrs request multiline editing (:multiline? true).

Returns true if `node` is an `:input` node whose attrs request multiline editing (`:multiline?
true`).
sourceraw docstring

neighbor-idclj

(neighbor-id order current-id step)

Returns the id of the focusable neighbor of current-id within ordered order, stepping by step (+1 for next, -1 for previous), wrapping around. Returns the first id (or nil) when current-id is absent/nil or order is empty.

Returns the id of the focusable neighbor of `current-id` within ordered `order`,
stepping by `step` (+1 for next, -1 for previous), wrapping around. Returns the
first id (or `nil`) when `current-id` is absent/nil or `order` is empty.
sourceraw docstring

next-focusclj

(next-focus order current-id)

Returns the id of the next focusable after current-id in order (the result of focus-order), wrapping to the first. When current-id is absent or nil, returns the first id. Returns nil when order is empty.

Returns the id of the next focusable after `current-id` in `order` (the result of
`focus-order`), wrapping to the first. When `current-id` is absent or `nil`,
returns the first id. Returns `nil` when `order` is empty.
sourceraw docstring

node-attrclj

(node-attr node k)

Returns the value of attribute k on TUI node (from its ::attrs), or nil if node is not a node or lacks the attribute.

Returns the value of attribute `k` on TUI `node` (from its `::attrs`), or `nil` if
`node` is not a node or lacks the attribute.
sourceraw docstring

node-pathclj

(node-path node-tree target-id)

Returns a vector of nodes from node-tree's root down to (and including) the node whose :id is target-id, in root→target order, or nil when not found.

Returns a vector of nodes from `node-tree`'s root down to (and including) the node
whose `:id` is `target-id`, in root→target order, or `nil` when not found.
sourceraw docstring

node-styleclj

(node-style attrs)

Returns the ::style map implied by a node's attrs. :highlight true sets :reverse?, :color <kw> sets :fg, :bg <kw> sets :bg, and :bold true sets :bold?.

Returns the `::style` map implied by a node's `attrs`. `:highlight true` sets `:reverse?`,
`:color <kw>` sets `:fg`, `:bg <kw>` sets `:bg`, and `:bold true` sets `:bold?`.
sourceraw docstring

node-textclj

(node-text node)

Returns the concatenated text of the node subtree: the string/number children of the node and, recursively, of all of its descendant nodes, joined left-to-right. Non-node, non-text children contribute nothing. A bare string/number returns its own string.

Returns the concatenated text of the `node` subtree: the string/number children of
the node and, recursively, of all of its descendant nodes, joined left-to-right.
Non-node, non-text children contribute nothing. A bare string/number returns its
own string.
sourceraw docstring

node?clj

(node? x)

Returns true if x is a TUI node: a map carrying a legal ::tag.

Returns true if `x` is a TUI node: a map carrying a legal `::tag`.
sourceraw docstring

ops->ansiclj

(ops->ansi ops)

Returns a single ANSI string that applies the run ops to a terminal. Each op emits a cursor move "\u001b[<row+1>;<col+1>H", an SGR sequence only when the pen style changes from the previous op, then the op's text. A trailing reset ("\u001b[0m") is emitted when the final pen style is non-default.

Returns a single ANSI string that applies the run `ops` to a terminal. Each op emits a cursor move
`"\u001b[<row+1>;<col+1>H"`, an SGR sequence only when the pen style changes from the previous
op, then the op's text. A trailing reset (`"\u001b[0m"`) is emitted when the final pen style is
non-default.
sourceraw docstring

ops->ansi*clj

(ops->ansi* ops)

Serializes run ops to a single ANSI string; see ops->ansi for the full contract.

Serializes run `ops` to a single ANSI string; see `ops->ansi` for the full contract.
sourceraw docstring

overlay-window-rectclj

(overlay-window-rect modal-node screen-rect)

Returns the on-screen ::rect at which open modal-node should be placed within screen-rect. The window's :width/:height (a number or [:fraction f], defaulting to the modal's intrinsic size) are resolved against the screen and clamped to it, and the window is positioned by the modal's :align (:center by default) on both axes.

Returns the on-screen `::rect` at which open `modal-node` should be placed within `screen-rect`. The
window's `:width`/`:height` (a number or `[:fraction f]`, defaulting to the modal's intrinsic size)
are resolved against the screen and clamped to it, and the window is positioned by the modal's
`:align` (`:center` by default) on both axes.
sourceraw docstring

paintcljmultimethod

Returns buffer after painting placed node (and its descendants) into it, clipping all writes to clip. Dispatches on ::tag. Uses the painter's algorithm: a node paints itself (border/background or its text) then its children, so children draw over parents.

Extension seam for custom RENDERED tags: register (defmethod paint :my/tag [buffer node clip] ...), drawing into buffer with the public painter toolkit (put-cell, put-str, fill-rect, draw-border, blit, node-style, content-rect, rect-intersection, in-clip?); to paint children, call paint recursively. Built-in tags are handled by :default; an unregistered custom tag paints nothing.

Returns `buffer` after painting placed `node` (and its descendants) into it, clipping all writes to
`clip`. Dispatches on `::tag`. Uses the painter's algorithm: a node paints itself (border/background
or its text) then its children, so children draw over parents.

Extension seam for custom RENDERED tags: register `(defmethod paint :my/tag [buffer node clip] ...)`,
drawing into `buffer` with the public painter toolkit (`put-cell`, `put-str`, `fill-rect`,
`draw-border`, `blit`, `node-style`, `content-rect`, `rect-intersection`, `in-clip?`); to paint
children, call `paint` recursively. Built-in tags are handled by `:default`; an unregistered custom
tag paints nothing.
sourceraw docstring

paletteclj

Map of palette color keywords to their foreground SGR base codes. Standard colors map to 30..37 and bright colors to 90..97. A background code is the foreground code plus 10.

Map of palette color keywords to their foreground SGR base codes. Standard colors map to 30..37 and
bright colors to 90..97. A background code is the foreground code plus 10.
sourceraw docstring

placecljmultimethod

Returns node laid out within the outer rect {:x :y :w :h}: annotates it with its ::rect and replaces ::children with placed children (each carrying its own ::rect). Dispatches on ::tag.

Extension seam for custom RENDERED tags: register a custom CONTAINER's layout with (defmethod place :my/tag [node rect] ...). To lay children out like a :vbox/:hbox, reuse place-stack; to place a single child, call place recursively; use edge-insets/as-node for the content rect and child coercion. Built-in tags are handled by :default; an unregistered custom tag is treated as a leaf (gets a ::rect, children left for its paint method).

Returns `node` laid out within the outer `rect` `{:x :y :w :h}`: annotates it with its `::rect` and
replaces `::children` with placed children (each carrying its own `::rect`). Dispatches on `::tag`.

Extension seam for custom RENDERED tags: register a custom CONTAINER's layout with `(defmethod place
:my/tag [node rect] ...)`. To lay children out like a `:vbox`/`:hbox`, reuse `place-stack`; to place a
single child, call `place` recursively; use `edge-insets`/`as-node` for the content rect and child
coercion. Built-in tags are handled by `:default`; an unregistered custom tag is treated as a leaf
(gets a `::rect`, children left for its paint method).
sourceraw docstring

place-stackclj

(place-stack axis content children)

Places children within the content rectangle along axis (:v stacks vertically, :h horizontally). Main-axis sizes are distributed by distribute-main; on the cross axis each child fills the track unless it declares a size, in which case :align positions it. Returns the vector of placed children. Public so a custom container's place method can reuse the built-in :vbox/:hbox layout.

Places `children` within the `content` rectangle along `axis` (`:v` stacks vertically, `:h`
horizontally). Main-axis sizes are distributed by `distribute-main`; on the cross axis each child
fills the track unless it declares a size, in which case `:align` positions it. Returns the vector
of placed children. Public so a custom container's `place` method can reuse the built-in
`:vbox`/`:hbox` layout.
sourceraw docstring

placed-viewportsclj

(placed-viewports tree)

Returns a vector of every placed :viewport node found (depth-first, pre-order) within the placed tree, including any nested inside another viewport's virtual content subtree (::viewport-content). Each returned node carries its ::rect, ::virtual-size, ::scroll, and ::viewport-content.

Returns a vector of every placed `:viewport` node found (depth-first, pre-order) within the placed
`tree`, including any nested inside another viewport's virtual content subtree (`::viewport-content`).
Each returned node carries its `::rect`, `::virtual-size`, `::scroll`, and `::viewport-content`.
sourceraw docstring

press!clj

(press! node k)

Invokes the :on-key handler attribute of TUI node (if present) with the key k and returns its result. Returns nil when there is no handler. Used to simulate a key press delivered to a focused node.

Invokes the `:on-key` handler attribute of TUI `node` (if present) with the key
`k` and returns its result. Returns `nil` when there is no handler. Used to
simulate a key press delivered to a focused node.
sourceraw docstring

prev-focusclj

(prev-focus order current-id)

Returns the id of the previous focusable before current-id in order (the result of focus-order), wrapping to the last. When current-id is absent or nil, returns the first id. Returns nil when order is empty.

Returns the id of the previous focusable before `current-id` in `order` (the result
of `focus-order`), wrapping to the last. When `current-id` is absent or `nil`,
returns the first id. Returns `nil` when `order` is empty.
sourceraw docstring

process-key!clj

(process-key! app key-event)
(process-key! app key-event global-keymap)

Single-step driver: applies key event key-event to app, mutating focus and/or state synchronously, and returns app.

Steps:

  1. Compute the current node tree from app state (current-node-tree).
  2. Dispatch by precedence:
    • :tab → focus the next-focus in the focus ring;
    • :backtab or Shift-:tab → focus the prev-focus;
    • :down → focus the next-focus; :up → focus the prev-focus (arrow focus navigation, mirroring :tab/:backtab in the ring); (all of the above then focus! + fire apply-focus-change!)
    • else if the focused node is an :input → controlled-input editing (handle-input-key!);
    • else → route-key (focused :on-key → bubble to ancestors → global keymap).
  3. After dispatch, re-resolve focus against the (possibly new) node tree: if the focused id vanished, advance to the next focusable (else first; else nil), firing transitions.

Arrow-key capture rule: :up/:down move focus EXCEPT when the focused node is an :input whose attrs set :multiline? true — such an input captures :up/:down, routing them to handle-input-key! (reserved for future multiline caret movement) rather than navigating focus. A single-line :input (no :multiline?) does NOT capture them, so :up/:down navigate focus while it uses only left/right/home/end for the caret.

global-keymap (optional) maps normalized chords (see key-chord) to handlers invoked as (handler app key-event). Works on a synchronous raw app with NO terminal attached.

TODO: viewport scrolling / follow-focus (keeping the focused node's placed rect visible) is intentionally NOT implemented here — it requires placed rects and the terminal size and is handled by a later task.

Single-step driver: applies key event `key-event` to `app`, mutating focus and/or
state synchronously, and returns `app`.

Steps:
1. Compute the current node tree from app state (`current-node-tree`).
2. Dispatch by precedence:
   * `:tab` → focus the `next-focus` in the focus ring;
   * `:backtab` or Shift-`:tab` → focus the `prev-focus`;
   * `:down` → focus the `next-focus`; `:up` → focus the `prev-focus`
     (arrow focus navigation, mirroring `:tab`/`:backtab` in the ring);
     (all of the above then `focus!` + fire `apply-focus-change!`)
   * else if the focused node is an `:input` → controlled-input editing
     (`handle-input-key!`);
   * else → `route-key` (focused `:on-key` → bubble to ancestors → global keymap).
3. After dispatch, re-resolve focus against the (possibly new) node tree: if the
   focused id vanished, advance to the next focusable (else first; else nil),
   firing transitions.

Arrow-key capture rule: `:up`/`:down` move focus EXCEPT when the focused node is an
`:input` whose attrs set `:multiline? true` — such an input *captures* `:up`/`:down`,
routing them to `handle-input-key!` (reserved for future multiline caret movement)
rather than navigating focus. A single-line `:input` (no `:multiline?`) does NOT
capture them, so `:up`/`:down` navigate focus while it uses only left/right/home/end
for the caret.

`global-keymap` (optional) maps normalized chords (see `key-chord`) to handlers
invoked as `(handler app key-event)`. Works on a synchronous raw app with NO
terminal attached.

TODO: viewport scrolling / follow-focus (keeping the focused node's placed rect
visible) is intentionally NOT implemented here — it requires placed rects and the
terminal size and is handled by a later task.
sourceraw docstring

put-cellclj

(put-cell buffer x y ch style)

Returns buffer with the cell at 0-based column x, row y set to character ch with style. Writes that fall outside the buffer bounds are ignored (clipped), returning the buffer unchanged.

Returns `buffer` with the cell at 0-based column `x`, row `y` set to character `ch` with `style`.
Writes that fall outside the buffer bounds are ignored (clipped), returning the buffer unchanged.
sourceraw docstring

put-strclj

(put-str buffer x y s style clip-rect)

Returns buffer with string s written starting at 0-based column x, row y, advancing by each character's display width and styling each written cell with style. Writes are clipped to both the clip-rect {:x :y :w :h} and the buffer bounds.

Wide-char cell scheme: a 2-column character is written into its starting cell and a continuation marker (a space with the same style) is written into the next cell. The screen helper drops these continuation cells so screen strings read naturally. A wide char is written only if BOTH its cells pass the clip/bounds test, so a wide char is never split across a clip boundary.

Returns `buffer` with string `s` written starting at 0-based column `x`, row `y`, advancing by each
character's display width and styling each written cell with `style`. Writes are clipped to both
the `clip-rect` `{:x :y :w :h}` and the buffer bounds.

Wide-char cell scheme: a 2-column character is written into its starting cell and a continuation
marker (a space with the same `style`) is written into the next cell. The `screen` helper drops
these continuation cells so screen strings read naturally. A wide char is written only if BOTH its
cells pass the clip/bounds test, so a wide char is never split across a clip boundary.
sourceraw docstring

put-str*clj

(put-str* buffer x y s style clip-rect)

Writes string s into buffer starting at x,y; implementation for put-str.

Writes string `s` into `buffer` starting at `x`,`y`; implementation for `put-str`.
sourceraw docstring

rect-intersectionclj

(rect-intersection a b)

Returns the rectangle that is the intersection of rects a and b. When they do not overlap the result has zero (or negative-clamped) width/height.

Returns the rectangle that is the intersection of rects `a` and `b`. When they do not overlap the
result has zero (or negative-clamped) width/height.
sourceraw docstring

render-bufferclj

(render-buffer placed-root rows cols)

Returns a fresh rowsxcols buffer with the placed tree rooted at placed-root painted into it. Painting walks the tree in order (painter's algorithm), clipping every write to the screen bounds.

Returns a fresh `rows`x`cols` buffer with the placed tree rooted at `placed-root` painted into it.
Painting walks the tree in order (painter's algorithm), clipping every write to the screen bounds.
sourceraw docstring

render-childrenclj

(render-children children)

Returns a vector of the results of render-tree over each child in children, dropping nil results and splicing vector results in as siblings.

Returns a vector of the results of `render-tree` over each child in `children`,
dropping `nil` results and splicing vector results in as siblings.
sourceraw docstring

render-instanceclj

(render-instance instance)

Returns the node (or vector of nodes/strings/numbers) produced by calling the :render of the component instance's class. Returns nil if the class has no :render.

Returns the node (or vector of nodes/strings/numbers) produced by calling the
`:render` of the component `instance`'s class. Returns `nil` if the class has no
`:render`.
sourceraw docstring

render-rootclj

(render-root class props)
(render-root class props app)

Returns the pure TUI node tree for a root component class given its props tree. Builds a root instance via (comp/factory class) and walks it with render-tree. Binds Fulcro's render-time dynamic vars (comp/*app*/comp/*parent*/comp/*shared*) around the walk — the same vars com.fulcrologic.fulcro.application/mount! binds during a React render — so the app and shared props are stamped onto the instances the factories create.

Returns the pure TUI node tree for a root component `class` given its `props` tree.
Builds a root instance via `(comp/factory class)` and walks it with `render-tree`. Binds
Fulcro's render-time dynamic vars (`comp/*app*`/`comp/*parent*`/`comp/*shared*`) around the
walk — the same vars `com.fulcrologic.fulcro.application/mount!` binds during a React render —
so the app and shared props are stamped onto the instances the factories create.
sourceraw docstring

render-treeclj

(render-tree x)

Returns a pure TUI node tree for x, recursively replacing every component instance with the node tree its render produces. The result contains no component instances and is suitable to hand to place. Each kind of x is handled as:

  • a TUI node (node?) - recurse into its ::children (rendering each child), keeping the node's tag/attrs;
  • a component instance (rc/component-instance?) - bind comp/*parent* to it, call its :render, then recurse into the returned node (or splice a returned vector of siblings);
  • a string or number - returned unchanged;
  • nil - returned as nil (callers/render-children drop it);
  • a sequential collection - rendered element-wise and returned as a vector of siblings (spliced by the caller).

When the render of a component yields several siblings, this returns a vector of nodes; otherwise it returns a single node (or scalar).

Returns a pure TUI node tree for `x`, recursively replacing every component
instance with the node tree its render produces. The result contains no component
instances and is suitable to hand to `place`. Each kind of `x` is handled as:

* a TUI node (`node?`) - recurse into its `::children` (rendering each child),
keeping the node's tag/attrs;
* a component instance (`rc/component-instance?`) - bind `comp/*parent*` to it, call its
`:render`, then recurse into the returned node (or splice a returned vector of
siblings);
* a string or number - returned unchanged;
* `nil` - returned as `nil` (callers/`render-children` drop it);
* a sequential collection - rendered element-wise and returned as a vector of
siblings (spliced by the caller).

When the render of a component yields several siblings, this returns a vector of
nodes; otherwise it returns a single node (or scalar).
sourceraw docstring

resolve-focus!clj

(resolve-focus! app node-tree)

Re-resolves focus after a dispatch may have changed app's state/tree. Recomputes focusables from the freshly rendered node-tree; if the currently focused id is no longer focusable it is moved to the next id in focus-order (else the first; else nil), firing the appropriate :on-lost-focus/:on-focus transitions. Returns app.

Re-resolves focus after a dispatch may have changed `app`'s state/tree. Recomputes
focusables from the freshly rendered `node-tree`; if the currently focused id is no
longer focusable it is moved to the next id in `focus-order` (else the first; else
`nil`), firing the appropriate `:on-lost-focus`/`:on-focus` transitions. Returns
`app`.
sourceraw docstring

resolve-sizeclj

(resolve-size spec extent intrinsic)

Resolves a child size spec against the available main-axis extent and the child's intrinsic size. A number is a fixed cell count; :half is half the extent; [:fraction f] is that fraction of the extent (rounded); nil (or anything else) falls back to the intrinsic size.

Resolves a child size `spec` against the available main-axis `extent` and the child's `intrinsic`
size. A number is a fixed cell count; `:half` is half the extent; `[:fraction f]` is that fraction
of the extent (rounded); `nil` (or anything else) falls back to the intrinsic size.
sourceraw docstring

route-keyclj

(route-key context node-tree focus-id key-event global-keymap)

Routes key event key-event through node-tree, returning a truthy value when the event was handled. Dispatch precedence:

(a) the focused node's :on-key handler (focused node = the one whose :id is focus-id), then (b) the :on-key handlers of its ancestors, from nearest to root (bubbling), stopping as soon as a handler returns a truthy value (e.g. :handled); then (c) if still unhandled, the handler in global-keymap (a map from a normalized chord — see key-chord — to a handler) for this event's chord.

:on-key handlers receive the key-event (interaction-util convention); a global keymap handler receives context and the key-event. Returns the truthy handler result, or false when nothing handled the event.

Routes key event `key-event` through `node-tree`, returning a truthy value when the
event was handled. Dispatch precedence:

(a) the focused node's `:on-key` handler (focused node = the one whose `:id` is
    `focus-id`), then
(b) the `:on-key` handlers of its ancestors, from nearest to root (bubbling),
stopping as soon as a handler returns a truthy value (e.g. `:handled`); then
(c) if still unhandled, the handler in `global-keymap` (a map from a normalized
    chord — see `key-chord` — to a handler) for this event's chord.

`:on-key` handlers receive the `key-event` (interaction-util convention); a global
keymap handler receives `context` and the `key-event`. Returns the truthy handler
result, or `false` when nothing handled the event.
sourceraw docstring

row-opsclj

(row-ops row cols next-cells prev-cells)

Returns the vector of run ops for a single row of next-buf, comparing against prev-cells (the same row of the previous buffer, or nil for a full repaint). Adjacent changed cells that share a style are coalesced into one op; on a full repaint every non-default cell is emitted (still coalesced).

Returns the vector of run ops for a single `row` of `next-buf`, comparing against `prev-cells` (the
same row of the previous buffer, or `nil` for a full repaint). Adjacent changed cells that share a
style are coalesced into one op; on a full repaint every non-default cell is emitted (still
coalesced).
sourceraw docstring

rowcol->caretclj

(rowcol->caret value width row col)

Returns the caret index into value for the visual position [row col] in the layout of value wrapped to width columns. row is clamped into the row range and col is clamped to the target row's length, so an off-the-end position lands at that row's end. The inverse of caret->rowcol (modulo the wrap-boundary convention). Pure.

Returns the caret index into `value` for the visual position `[row col]` in the layout of `value`
wrapped to `width` columns. `row` is clamped into the row range and `col` is clamped to the target
row's length, so an off-the-end position lands at that row's end. The inverse of `caret->rowcol`
(modulo the wrap-boundary convention). Pure.
sourceraw docstring

same-dims?clj

(same-dims? a b)

Returns true if buffers a and b have identical row and column counts.

Returns true if buffers `a` and `b` have identical row and column counts.
sourceraw docstring

screenclj

(screen buffer)

Returns a vector of rows strings, one per buffer row, formed by joining each row's cell characters. Wide-char continuation cells (the blank that follows a 2-column character) are dropped so the strings read naturally.

Returns a vector of `rows` strings, one per buffer row, formed by joining each row's cell
characters. Wide-char continuation cells (the blank that follows a 2-column character) are dropped
so the strings read naturally.
sourceraw docstring

screen-styledclj

(screen-styled buffer)

Returns a vector (one per buffer row) of vectors of cell maps {:ch :sgr}, exposing the full styled contents of buffer for fine-grained assertions.

Returns a vector (one per buffer row) of vectors of cell maps `{:ch :sgr}`, exposing the full styled
contents of `buffer` for fine-grained assertions.
sourceraw docstring

scroll-to-showclj

(scroll-to-show scroll virtual-rect view-size)

Returns the new scroll offset {:x :y} for a viewport so that the focused node's virtual-rect becomes visible within the view-size {:w :h} content window, given the current scroll {:x :y}. Performs the MINIMAL scroll on each axis: if the rect is above/left of the window, scroll back to its near edge; if below/right, scroll forward so its far edge is the last visible cell; otherwise leave that axis unchanged. Does not clamp to the virtual size (callers clamp via clamp-scroll). Pure.

Returns the new scroll offset `{:x :y}` for a viewport so that the focused node's `virtual-rect`
becomes visible within the `view-size` `{:w :h}` content window, given the current `scroll` `{:x :y}`.
Performs the MINIMAL scroll on each axis: if the rect is above/left of the window, scroll back to its
near edge; if below/right, scroll forward so its far edge is the last visible cell; otherwise leave
that axis unchanged. Does not clamp to the virtual size (callers clamp via `clamp-scroll`). Pure.
sourceraw docstring

set-caret!clj

(set-caret! app id caret)

Stores caret index caret for input id in app's runtime caret store (::carets) via swap! on the runtime atom. Returns app.

Stores caret index `caret` for input `id` in `app`'s runtime caret store
(`::carets`) via `swap!` on the runtime atom. Returns `app`.
sourceraw docstring

set-input-width!clj

(set-input-width! app id width)

Records the effective content width (in columns) for multiline input id in app's runtime (::input-widths) via swap! on the runtime atom, so subsequent key handling wraps and navigates at the same width the input is painted with. Returns app.

Records the effective content `width` (in columns) for multiline input `id` in `app`'s runtime
(`::input-widths`) via `swap!` on the runtime atom, so subsequent key handling wraps and navigates
at the same width the input is painted with. Returns `app`.
sourceraw docstring

set-viewport-scroll!clj

(set-viewport-scroll! app vp-id scroll)

Sets the scroll offset {:x :y} for the viewport with id vp-id in app's state-map (under ::scroll) via a direct swap!. Returns app.

Sets the scroll offset `{:x :y}` for the viewport with id `vp-id` in `app`'s state-map (under
`::scroll`) via a direct `swap!`. Returns `app`.
sourceraw docstring

sgr-stringclj

(sgr-string codes)

Returns the ANSI SGR escape string for the vector of integer codes, e.g. [1 31] becomes the CSI select-graphic-rendition sequence "\u001b[1;31m". An empty codes vector yields the reset sequence "\u001b[0m".

Returns the ANSI SGR escape string for the vector of integer `codes`, e.g. `[1 31]` becomes the CSI
select-graphic-rendition sequence `"\u001b[1;31m"`. An empty `codes` vector yields the reset
sequence `"\u001b[0m"`.
sourceraw docstring

special-keysclj

The set of recognized non-printable :key values in a key event.

The set of recognized non-printable `:key` values in a key event.
sourceraw docstring

string-widthclj

(string-width s)

Returns the total terminal column width of string s (the sum of its per-code-point widths). Control characters, including newlines, contribute 0; callers that care about multi-line text should split on newlines and measure each line.

Returns the total terminal column width of string `s` (the sum of its per-code-point widths).
Control characters, including newlines, contribute 0; callers that care about multi-line text
should split on newlines and measure each line.
sourceraw docstring

strip-overlaysclj

(strip-overlays node-tree)

Returns node-tree with every :modal node (open or closed) removed from its children, recursively. The base layout/paint walks this stripped tree so overlays never occupy space or paint inline — they are composited separately by the driver.

Returns `node-tree` with every `:modal` node (open or closed) removed from its children, recursively.
The base layout/paint walks this stripped tree so overlays never occupy space or paint inline — they
are composited separately by the driver.
sourceraw docstring

style->sgr-codesclj

(style->sgr-codes style)

Returns the ordered vector of SGR integer codes for style. Attribute codes come first (reverse=7, then bold=1), followed by the foreground color code and then the background color code (foreground base + 10). The empty/default style yields an empty vector.

Returns the ordered vector of SGR integer codes for `style`. Attribute codes come first (reverse=7,
then bold=1), followed by the foreground color code and then the background color code (foreground
base + 10). The empty/default style yields an empty vector.
sourceraw docstring

text-contentclj

(text-content node)

Returns the string formed by concatenating the string/number children of node (its text/label).

Returns the string formed by concatenating the string/number children of `node` (its text/label).
sourceraw docstring

text-scroll-topclj

(text-scroll-top value width caret height)

Returns the internal top visual-line offset for a multiline input so that the caret's visual row is visible within a height-row window, given the value wrapped to width columns and the current caret. Performs minimal scrolling: if the caret row is above the current window it would scroll to it; here, with no prior offset tracked, it returns the smallest non-negative top such that the caret row lies in [top, top+height) and the window does not run past the last row unnecessarily. Concretely it returns (max 0 (min (- caret-row (dec height)) ...)) clamped so the caret row is the last visible row when it would otherwise be below the window, and 0 when the caret row already fits from the top. Pure.

Returns the internal top visual-line offset for a multiline input so that the caret's visual row is
visible within a `height`-row window, given the `value` wrapped to `width` columns and the current
`caret`. Performs minimal scrolling: if the caret row is above the current window it would scroll
to it; here, with no prior offset tracked, it returns the smallest non-negative top such that the
caret row lies in `[top, top+height)` and the window does not run past the last row unnecessarily.
Concretely it returns `(max 0 (min (- caret-row (dec height)) ...))` clamped so the caret row is the
last visible row when it would otherwise be below the window, and 0 when the caret row already fits
from the top. Pure.
sourceraw docstring

type!clj

(type! node s)

Invokes the :on-change handler attribute of TUI node (if present) with the string s and returns its result. Returns nil when there is no handler. Used to simulate typing the proposed value s into an input.

Invokes the `:on-change` handler attribute of TUI `node` (if present) with the
string `s` and returns its result. Returns `nil` when there is no handler. Used to
simulate typing the proposed value `s` into an input.
sourceraw docstring

viewport-scrollclj

(viewport-scroll app-or-state vp-id)

Returns the scroll offset {:x :y} recorded for the viewport with id vp-id in app-or-state (under the state-map key ::scroll), defaulting to {:x 0 :y 0} when none is recorded.

Returns the scroll offset `{:x :y}` recorded for the viewport with id `vp-id` in `app-or-state`
(under the state-map key `::scroll`), defaulting to `{:x 0 :y 0}` when none is recorded.
sourceraw docstring

viewport?clj

(viewport? node)

Returns true if node is a :viewport node.

Returns true if `node` is a `:viewport` node.
sourceraw docstring

wrap-layoutclj

(wrap-layout value width)

Returns the visual-line layout of string value wrapped to width display columns: a vector of {:start :len :text} maps, one per visual row, in order. :text is the row's wrapped string, :start is the caret index (into value) of the row's first character, and :len is the number of value characters the row's text spans. Characters dropped at a soft-wrap boundary (the collapsed space between two wrapped words) and the hard \n are NOT counted in any row's :len; they live in the gap between one row's :start + :len and the next row's :start. Reuses wrap-text so the rows match what paint displays.

Returns the visual-line layout of string `value` wrapped to `width` display columns: a vector of
`{:start :len :text}` maps, one per visual row, in order. `:text` is the row's wrapped string,
`:start` is the caret index (into `value`) of the row's first character, and `:len` is the number
of `value` characters the row's text spans. Characters dropped at a soft-wrap boundary (the
collapsed space between two wrapped words) and the hard `\n` are NOT counted in any row's `:len`;
they live in the gap between one row's `:start + :len` and the next row's `:start`. Reuses
`wrap-text` so the rows match what `paint` displays.
sourceraw docstring

wrap-segmentclj

(wrap-segment segment width)

Returns a vector of visual lines for a single newline-free segment greedily word-wrapped to width display columns (words split on a single space, widths measured with string-width). Words are packed onto a line separated by single spaces while they fit; a word that does not fit starts a new line; a word wider than width is hard-broken (hard-break). When width is 0 or negative the whole segment is returned as one line. An empty/blank segment yields a single empty line.

Returns a vector of visual lines for a single newline-free `segment` greedily word-wrapped to
`width` display columns (words split on a single space, widths measured with `string-width`).
Words are packed onto a line separated by single spaces while they fit; a word that does not fit
starts a new line; a word wider than `width` is hard-broken (`hard-break`). When `width` is 0 or
negative the whole segment is returned as one line. An empty/blank segment yields a single empty
line.
sourceraw docstring

wrap-textclj

(wrap-text s width)

Returns a vector of visual-line strings produced by word-wrapping string s to width display columns. s is first split on hard newlines (\n), then each segment is greedily word-wrapped (wrap-segment): words are packed left-to-right separated by single spaces while they fit on the current line; a word that does not fit moves to the next line; a word wider than width is broken hard at width columns (so a single over-long token never overflows). All widths are measured with string-width/code-point-width, never count, so wide and zero-width characters are handled correctly.

Conventions:

  • An empty or all-spaces segment yields a single empty line (so a blank line in s is preserved as an empty visual line).
  • width <= 0 disables wrapping: each newline-separated segment becomes exactly one line.
  • Leading/trailing spaces and runs of spaces inside a line may collapse when wrapping forces a break, but spaces are otherwise preserved within a line.
Returns a vector of visual-line strings produced by word-wrapping string `s` to `width` display
columns. `s` is first split on hard newlines (`\n`), then each segment is greedily word-wrapped
(`wrap-segment`): words are packed left-to-right separated by single spaces while they fit on the
current line; a word that does not fit moves to the next line; a word wider than `width` is broken
hard at `width` columns (so a single over-long token never overflows). All widths are measured
with `string-width`/`code-point-width`, never `count`, so wide and zero-width characters are
handled correctly.

Conventions:
* An empty or all-spaces segment yields a single empty line (so a blank line in `s` is preserved
  as an empty visual line).
* `width <= 0` disables wrapping: each newline-separated segment becomes exactly one line.
* Leading/trailing spaces and runs of spaces inside a line may collapse when wrapping forces a
  break, but spaces are otherwise preserved within a line.
sourceraw docstring

wrapped-line-countclj

(wrapped-line-count node width)

Returns the number of visual lines that wrapping-text node occupies when laid out into a content width of width columns (the width inside any of the node's own insets). Always at least one line.

Returns the number of visual lines that wrapping-`text` `node` occupies when laid out into a
content width of `width` columns (the width inside any of the node's own insets). Always at least
one line.
sourceraw docstring

wrapping-text?clj

(wrapping-text? node)

Returns true if node is a :text node whose attrs request line wrapping (:wrap true). Such a text is laid out height-for-width: at place time its height is the number of visual lines its content wraps to at its assigned width.

Returns true if `node` is a `:text` node whose attrs request line wrapping (`:wrap true`). Such a
text is laid out *height-for-width*: at place time its height is the number of visual lines its
content wraps to at its assigned width.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close