Minga.Editing.Scroll (Minga v0.1.0)

Copy Markdown View Source

Generic scroll state for any content region that can be scrolled.

Encapsulates a three-part model:

  • offset — concrete line count from the top of the content. Always a real number, never a sentinel.
  • pinned — boolean flag meaning "follow the bottom." When true, the renderer ignores offset and computes the bottom position from the actual content dimensions.
  • metrics — cached {total_lines, visible_height} from the most recent render pass. Updated by the render pipeline after every frame so that scroll_up/2 and scroll_down/2 can resolve a pinned position into a concrete offset without the caller passing dimensions.

Usage

Embed a %Scroll{} in any struct that needs scrollable content:

defstruct scroll: Scroll.new()

The render pipeline must call update_metrics/3 after computing content dimensions. Scroll functions are then self-sufficient: every caller just calls scroll_up/2 or scroll_down/2 without passing content dimensions or calling a materialization step.

Summary

Types

Cached metrics from the most recent render pass.

t()

Scroll state for a content region.

Functions

Creates a new scroll state, pinned to bottom.

Creates a new scroll state starting at a specific offset, unpinned.

Pins to the bottom. The renderer resolves this to a concrete line number at render time using the actual content dimensions.

Resolves the effective scroll offset for rendering.

Scrolls down by the given number of lines. Unpins from bottom.

Scrolls to the top. Unpins from bottom.

Scrolls up by the given number of lines. Unpins from bottom.

Sets the offset to an absolute value. Unpins from bottom.

Updates the cached metrics from the most recent render pass.

Types

metrics()

@type metrics() :: %{total_lines: non_neg_integer(), visible_height: pos_integer()}

Cached metrics from the most recent render pass.

Updated by the render pipeline after each frame. Between frames no scroll commands execute, so the cache is always fresh when it matters.

t()

@type t() :: %Minga.Editing.Scroll{
  metrics: metrics(),
  offset: non_neg_integer(),
  pinned: boolean()
}

Scroll state for a content region.

Functions

new()

@spec new() :: t()

Creates a new scroll state, pinned to bottom.

new(offset)

@spec new(non_neg_integer()) :: t()

Creates a new scroll state starting at a specific offset, unpinned.

pin_to_bottom(scroll)

@spec pin_to_bottom(t()) :: t()

Pins to the bottom. The renderer resolves this to a concrete line number at render time using the actual content dimensions.

resolve(scroll, total_lines, visible_height)

@spec resolve(t(), non_neg_integer(), pos_integer()) :: non_neg_integer()

Resolves the effective scroll offset for rendering.

When pinned, computes max(total_lines - visible_height, 0). When unpinned, clamps offset to the valid range.

Renderers call this instead of reading offset directly.

scroll_down(scroll, amount)

@spec scroll_down(t(), non_neg_integer()) :: t()

Scrolls down by the given number of lines. Unpins from bottom.

When transitioning from pinned, uses cached metrics to compute the concrete bottom offset before adding. The renderer clamps overshoot, so unbounded addition is safe.

scroll_to_top(scroll)

@spec scroll_to_top(t()) :: t()

Scrolls to the top. Unpins from bottom.

scroll_up(scroll, amount)

@spec scroll_up(t(), non_neg_integer()) :: t()

Scrolls up by the given number of lines. Unpins from bottom.

When transitioning from pinned, uses cached metrics to compute the concrete bottom offset before subtracting.

set_offset(scroll, offset)

@spec set_offset(t(), non_neg_integer()) :: t()

Sets the offset to an absolute value. Unpins from bottom.

Used by search navigation, code block jumping, and other features that need to position the viewport at a specific line.

update_metrics(scroll, total_lines, visible_height)

@spec update_metrics(t(), non_neg_integer(), pos_integer()) :: t()

Updates the cached metrics from the most recent render pass.

Called by the render pipeline after computing content dimensions. Must be called every frame so that scroll_up/scroll_down have accurate dimensions when transitioning from pinned to manual.