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.

  • rect returns the element’s absolute screen rectangle, or Error(Nil) when no element has that id.
  • scroll_extents returns a scroll container’s fresh scroll geometry, or Error(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 within by cells triggers the shortfall scroll away from that edge. This is the behavior of vim’s scrolloff, CSS scroll-margin, and OpenTUI’s own editor scrollMargin, 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)
Search Document