agnostic/platform/opentui/effect
Effects for OpenTUI keyboard input, focus management, terminal control, clipboard, selection, lifecycle, and scrolling.
OpenTUI dispatches keyboard events through the renderer’s keyInput
EventEmitter, not through individual nodes. This module provides effects
that subscribe to global keyboard input, manage focus programmatically,
control the terminal, and more — letting you wire these into your MVU loop.
The renderer is managed internally by opentui.platform() — effects
access it automatically without requiring a renderer parameter.
Types
A keyboard event from the terminal.
pub type KeyEvent {
KeyEvent(
key: String,
ctrl: Bool,
shift: Bool,
meta: Bool,
option: Bool,
)
}
Constructors
-
KeyEvent( key: String, ctrl: Bool, shift: Bool, meta: Bool, option: Bool, )
Fresh, layout-final geometry, provided to after_layout
callbacks. Both functions look an element up by its OpenTUI id and read
its geometry directly from the layout engine — the only safe source at
that timing, where the renderables’ cached accessors still hold last
frame’s values. Only valid for the duration of the callback: the next
update can invalidate everything.
rectreturns the element’s absolute screen rectangle, orError(Nil)when no element has that id.scroll_extentsreturns a scroll container’s fresh scroll geometry, orError(Nil)when the id is unresolvable or the element is not a scrollable container.
pub type Layout {
Layout(
rect: fn(String) -> Result(Rect, Nil),
scroll_extents: fn(String) -> Result(ScrollExtents, Nil),
)
}
Constructors
-
Layout( rect: fn(String) -> Result(Rect, Nil), scroll_extents: fn(String) -> Result(ScrollExtents, Nil), )
The absolute screen rectangle of a renderable, in terminal cells: x/y
are the top-left corner in absolute screen space, width/height the
renderable’s size. Returned by Layout’s rect.
pub type Rect {
Rect(x: Int, y: Int, width: Int, height: Int)
}
Constructors
-
Rect(x: Int, y: Int, width: Int, height: Int)
The scroll geometry of a scrollable container, in terminal cells: the
content’s total size, the viewport’s size, and the current scroll
position. Returned by Layout’s scroll_extents. The maximum
scroll position on an axis is the content size minus the viewport size.
pub type ScrollExtents {
ScrollExtents(
content_width: Int,
content_height: Int,
viewport_width: Int,
viewport_height: Int,
scroll_x: Int,
scroll_y: Int,
)
}
Constructors
-
ScrollExtents( content_width: Int, content_height: Int, viewport_width: Int, viewport_height: Int, scroll_x: Int, scroll_y: Int, )
A scroll padding for
scroll_into_view_with_padding: extra
clearance, in terminal cells, given between the revealed target and the
viewport edge when reconciling the target into view. The same type serves
both axes — by means rows or columns depending on which argument
carries it.
The padding is landing-edge-relative and symmetric: it applies at
whichever edge the reveal lands the target at — revealing downward leaves
by cells visible below the target, revealing upward leaves by cells
above it (left/right on the horizontal axis). Because the reveal’s scroll
can approach from either edge, signed past-the-edge semantics would be
ambiguous; the value is simply the extra given beyond the minimal reveal.
Negative values clamp to zero, and by: 0 is the minimal flush reveal.
OnScroll(by:)applies the padding only when the reveal actually scrolls on that axis. A target that is already visible is never touched — no jitter, reveals stay safe to fire liberally.Always(by:)enforces the clearance from both viewport edges even for an already-visible target: crowding either edge withinbycells triggers the shortfall scroll away from that edge. This is the behavior of vim’sscrolloff, CSSscroll-margin, and OpenTUI’s own editorscrollMargin, applied at the scrollbox level.
Paddings are capped so the target always stays fully in view (OnScroll
caps at the viewport size minus the target size; Always at half that,
so the clearances at both edges can hold simultaneously), and clamp
silently at the content extents — no context exists past the last row,
so a padding there rests at the maximum scroll position.
pub type ScrollPadding {
OnScroll(by: Int)
Always(by: Int)
}
Constructors
-
OnScroll(by: Int) -
Always(by: Int)
A renderer-level selection. Used by both subscribe_selection (for
drag-completion events) and get_selection (for the current state).
ranges contains one entry per participating EditBufferRenderable, in the
order OpenTUI’s selectedRenderables array reports them. Non-EditBuffer
selectables are dropped (they have no character-range API). focused_id
is the currently focused Renderable’s id at the time of the event, or the
empty string if nothing is focused. anchor and focus are the drag’s
starting and ending terminal cell coordinates #(column, row) in absolute
screen space.
pub type Selection {
Selection(
ranges: List(SelectionRange),
focused_id: String,
anchor: #(Int, Int),
focus: #(Int, Int),
)
}
Constructors
-
Selection( ranges: List(SelectionRange), focused_id: String, anchor: #(Int, Int), focus: #(Int, Int), )
A single EditBuffer’s contribution to a multi-paragraph selection.
id is the OpenTUI Renderable id of the participating EditBuffer. start
and end are character offsets within that EditBuffer’s local text.
pub type SelectionRange {
SelectionRange(id: String, start: Int, end: Int)
}
Constructors
-
SelectionRange(id: String, start: Int, end: Int)