MingaEditor.Renderer.RenderWindow (Minga v0.1.0)

Copy Markdown View Source

Renderer-owned working window materialized from WindowIntent plus a WindowCache.

The editor owns live window construction, content switching, popup, fold, textobject, and viewport gesture mutations. This carrier keeps only the per-frame fields and cache-facing operations the render pipeline needs.

Render cache and dirty-line tracking

Windows carry per-frame render state that enables incremental rendering. The semantic RenderModel.Window.Builder reuses retained composed rows for lines whose inputs are unchanged and only recomposes lines marked as dirty.

The dirty set uses two representations:

  • :all means every line needs re-rendering (used for scroll, resize, theme change, highlight update, and other wholesale invalidation)
  • A map of specific buffer line numbers (%{line => true}) that need re-rendering (used for edits that touch a few lines)

Tracking fields (last_viewport_top, last_viewport_cache_key, last_gutter_w, last_line_count, last_cursor_line, last_buf_version) store the values from the previous frame. The Scroll stage compares current values against these to detect full-invalidation triggers automatically.

Summary

Types

Unique identifier for a window.

t()

Functions

Returns the applied buffer change sequence for durable line identity.

Returns a cached wrapped visual row total when the key matches.

Returns the atomic bounded snapshot for pending resident deltas.

Returns the window's durable content epoch.

Compares the current render context fingerprint against the last frame's.

Checks current frame parameters against last-frame tracking fields and returns the window with dirty_lines: :all if anything that requires a full redraw has changed.

Returns true if the given buffer line needs re-rendering.

Returns the renderer-consumed version pinned for bounded line fetches.

Returns the explicit reason for the next resident hydration.

Marks all lines dirty (full redraw needed).

Returns the window's durable logical-line identity sequence.

Marks specific buffer lines as needing re-render.

Marks the next retained GUI frame as a frontend-state reset without discarding TUI draw caches.

Returns renderer-consumed edit deltas pending resident composition.

Prepares the retained GUI content epoch for the current frame.

Overlays renderer-owned committed lineage onto a window snapshot.

Stores the current frame's residence build state for incremental reuse next frame (#2658).

Stores the current frame's retained composed rows for upstream reuse next frame (#2287).

Stores the current frame's retained wrapped logical lines for upstream reuse next frame (#2287).

Stores the producer-owned stable row-slot allocator.

Stores the wrapped visual row total for the current cache key.

Explicitly rebuilds durable content identity in a fresh epoch.

Returns whether residence was armed by the previous eligible frame (#2679).

Returns whether this window was a full-document resident window as of the last rendered frame.

Returns the persistent full-document residence build state (#2658).

Returns the retained composed rows from the previous semantic content build (#2287).

Returns the retained wrapped logical lines from the previous semantic content build (#2287).

Returns the producer-owned stable row-slot allocator.

Returns the renderer-owned monotonic scroll-authority sequence.

Stores the renderer-local cursor for this window.

Arms or disarms residence promotion for the next frame (#2679 first-paint-then-promote).

Records whether this window is a full-document resident window (#2653/#2658).

Stores the computed viewport for this window.

Settles the per-frame scroll_seq decision against the render cache baseline.

Reconciles durable logical-line identities from an atomic buffer snapshot.

Types

id()

@type id() :: pos_integer()

Unique identifier for a window.

t()

@type t() :: %MingaEditor.Renderer.RenderWindow{
  authoritative_scroll_seq: non_neg_integer(),
  content: MingaEditor.Window.Content.t(),
  cursor: Minga.Buffer.position(),
  fold_map: MingaEditor.FoldMap.t(),
  fold_ranges: [Minga.Editing.Fold.Range.t()],
  id: id(),
  popup_meta: MingaEditor.UI.Popup.Active.t() | nil,
  render_cache: MingaEditor.Renderer.WindowCache.t(),
  scroll_detach_cursor: Minga.Buffer.position() | nil,
  scroll_echo_top: integer() | nil,
  scroll_velocity: MingaEditor.Window.ScrollVelocity.t(),
  viewport: MingaEditor.Viewport.t()
}

Functions

applied_change_sequence(render_window)

@spec applied_change_sequence(t()) :: non_neg_integer()

Returns the applied buffer change sequence for durable line identity.

cached_total_visual_rows(render_window, key)

@spec cached_total_visual_rows(t(), term()) :: non_neg_integer() | nil

Returns a cached wrapped visual row total when the key matches.

changed_snapshot(render_window)

@spec changed_snapshot(t()) :: Minga.Buffer.RenderSnapshot.t() | nil

Returns the atomic bounded snapshot for pending resident deltas.

content_epoch(render_window)

@spec content_epoch(t()) :: non_neg_integer()

Returns the window's durable content epoch.

detect_context_change(window, fingerprint)

@spec detect_context_change(
  t(),
  MingaEditor.Renderer.WindowCache.context_fingerprint()
) :: t()

Compares the current render context fingerprint against the last frame's.

If the fingerprint changed, marks all lines dirty. This catches changes to visual selection, search matches, syntax highlights, diagnostic signs, git signs, horizontal scroll, active/inactive status, and theme colors, all of which affect every visible line's draw output.

detect_invalidation(window, viewport_top, gutter_w, line_count, buf_version)

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

Checks current frame parameters against last-frame tracking fields and returns the window with dirty_lines: :all if anything that requires a full redraw has changed.

Structural triggers (checked here): viewport scroll, gutter width, line count, buffer version, first frame (sentinel values).

Context triggers (checked separately via detect_context_change/2): visual selection, search matches, syntax highlights, diagnostic signs, git signs, viewport horizontal scroll, active status, theme colors.

detect_invalidation(window, viewport_top, gutter_w, line_count, buf_version, cursor_line)

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

detect_invalidation(window, viewport_top, viewport_cache_key, gutter_w, line_count, buf_version, cursor_line)

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

dirty?(render_window, line)

@spec dirty?(t(), non_neg_integer()) :: boolean()

Returns true if the given buffer line needs re-rendering.

Always true when dirty_lines is :all.

expected_buffer_version(render_window)

@spec expected_buffer_version(t()) :: non_neg_integer() | nil

Returns the renderer-consumed version pinned for bounded line fetches.

hydration_reason(render_window)

@spec hydration_reason(t()) :: atom() | nil

Returns the explicit reason for the next resident hydration.

invalidate(window)

@spec invalidate(t()) :: t()

Marks all lines dirty (full redraw needed).

Clears all caches and resets tracking fields to sentinels so the next render pass starts from scratch. Use this when the window's buffer changes, on resize, or any other event that makes all cached draws invalid.

line_identity(render_window)

@spec line_identity(t()) :: Minga.RenderModel.Window.LineIdentity.t() | nil

Returns the window's durable logical-line identity sequence.

mark_dirty(window, lines)

@spec mark_dirty(t(), [non_neg_integer()] | :all) :: t()

Marks specific buffer lines as needing re-render.

Pass :all to force a complete redraw (scroll, resize, theme change, etc.). Pass a list of buffer line numbers for targeted invalidation (edits). If the window is already fully dirty, adding specific lines is a no-op.

mark_frontend_reset_pending(window)

@spec mark_frontend_reset_pending(t()) :: t()

Marks the next retained GUI frame as a frontend-state reset without discarding TUI draw caches.

materialize(id, carrier, cache)

pending_edit_deltas(render_window)

@spec pending_edit_deltas(t()) :: [Minga.Buffer.EditDelta.t()]

Returns renderer-consumed edit deltas pending resident composition.

prepare_render_epoch(window, reset_fingerprint)

@spec prepare_render_epoch(t(), term()) :: {t(), non_neg_integer(), boolean()}

Prepares the retained GUI content epoch for the current frame.

put_lineage(window, identity, sequence)

@spec put_lineage(
  t(),
  Minga.RenderModel.Window.LineIdentity.t(),
  non_neg_integer()
) :: t()

Overlays renderer-owned committed lineage onto a window snapshot.

put_resident_build(window, state)

@spec put_resident_build(t(), MingaEditor.RenderModel.Window.ResidentBuild.t() | nil) ::
  t()

Stores the current frame's residence build state for incremental reuse next frame (#2658).

put_retained_rows(window, rows)

@spec put_retained_rows(t(), %{
  optional(non_neg_integer()) => MingaEditor.Renderer.WindowCache.retained_row()
}) :: t()

Stores the current frame's retained composed rows for upstream reuse next frame (#2287).

put_retained_wrap_lines(window, lines)

@spec put_retained_wrap_lines(
  t(),
  %{
    optional(non_neg_integer()) =>
      MingaEditor.Renderer.WindowCache.retained_wrap_line()
  }
) :: t()

Stores the current frame's retained wrapped logical lines for upstream reuse next frame (#2287).

put_row_slot_allocator(window, allocator)

@spec put_row_slot_allocator(t(), Minga.RenderModel.Window.RowSlotAllocator.t()) ::
  t()

Stores the producer-owned stable row-slot allocator.

put_total_visual_rows(window, key, total)

@spec put_total_visual_rows(t(), term(), non_neg_integer()) :: t()

Stores the wrapped visual row total for the current cache key.

reset_content_identity(window, snapshot)

@spec reset_content_identity(t(), Minga.Buffer.RenderSnapshot.t()) :: t()

Explicitly rebuilds durable content identity in a fresh epoch.

residence_armed?(render_window)

@spec residence_armed?(t()) :: boolean()

Returns whether residence was armed by the previous eligible frame (#2679).

resident?(render_window)

@spec resident?(t()) :: boolean()

Returns whether this window was a full-document resident window as of the last rendered frame.

resident_build(render_window)

@spec resident_build(t()) :: MingaEditor.RenderModel.Window.ResidentBuild.t() | nil

Returns the persistent full-document residence build state (#2658).

retained_rows(render_window)

@spec retained_rows(t()) :: %{
  optional(non_neg_integer()) => MingaEditor.Renderer.WindowCache.retained_row()
}

Returns the retained composed rows from the previous semantic content build (#2287).

retained_wrap_lines(render_window)

@spec retained_wrap_lines(t()) :: %{
  optional(non_neg_integer()) =>
    MingaEditor.Renderer.WindowCache.retained_wrap_line()
}

Returns the retained wrapped logical lines from the previous semantic content build (#2287).

row_slot_allocator(render_window)

@spec row_slot_allocator(t()) :: Minga.RenderModel.Window.RowSlotAllocator.t()

Returns the producer-owned stable row-slot allocator.

scroll_follow_cursor?(window, cursor_pos, now_ms)

@spec scroll_follow_cursor?(t(), Minga.Buffer.position(), integer()) ::
  {t(), boolean()}

scroll_seq(render_window)

@spec scroll_seq(t()) :: non_neg_integer()

Returns the renderer-owned monotonic scroll-authority sequence.

set_cursor(window, cursor)

@spec set_cursor(t(), Minga.Buffer.position()) :: t()

Stores the renderer-local cursor for this window.

set_residence_armed(window, armed?)

@spec set_residence_armed(t(), boolean()) :: t()

Arms or disarms residence promotion for the next frame (#2679 first-paint-then-promote).

set_resident(window, resident?)

@spec set_resident(t(), boolean()) :: t()

Records whether this window is a full-document resident window (#2653/#2658).

Stored in the render cache because residence is a renderer-computed value and the render cache is the only per-window struct copied back from the async render pipeline (see MingaEditor.State.merge_renderer_window/2). The input layer (mouse wheel/trackpad handling) reads it via resident?/1 so it can branch on residence without recomputing it. Stale by at most one frame, which is harmless: residence is a document-size property that doesn't flip mid-gesture.

set_viewport(window, viewport)

@spec set_viewport(t(), MingaEditor.Viewport.t()) :: t()

Stores the computed viewport for this window.

settle_scroll_seq(window)

@spec settle_scroll_seq(t()) :: t()

Settles the per-frame scroll_seq decision against the render cache baseline.

Delegates to MingaEditor.Window.RenderCache.settle_scroll_seq/4 with this frame's committed viewport top, the sticky scroll_echo_top recorded by the input path, and the authoritative_scroll_seq request counter set by command handlers. scroll_seq advances when EITHER an authoritative jump was marked since the last settle OR the top moved to a value that is neither the previous committed top nor a frontend-reported free-scroll top (a genuine BEAM-initiated anchor move). Wheel/trackpad free-scroll frames share the reported top, so they are echoes and do not advance the sequence. A jump that also moves the top bumps once, not twice (a single OR decision per settle). The counter, its baseline, and the authoritative-request baseline all live in the render cache, so the sequence is monotonic across the serially threaded, written-back render cache.

snapshot_after_render(window, viewport_top, gutter_w, line_count, cursor_line, buf_version, ctx_fingerprint)

Snapshots tracking fields after a successful render pass.

Clears the dirty set and records the current frame's parameters so the next frame can detect what changed. The context fingerprint captures all per-frame render context inputs (visual selection, search matches, syntax highlights, signs, etc.) so context changes trigger full redraws.

snapshot_after_render(window, viewport_top, viewport_cache_key, gutter_w, line_count, cursor_line, buf_version, ctx_fingerprint)

sync_line_identity(window, snapshot)

@spec sync_line_identity(t(), Minga.Buffer.RenderSnapshot.t()) :: t()

Reconciles durable logical-line identities from an atomic buffer snapshot.