Skip to content

Add @clayterm/virtualizer v1#11

Open
taras wants to merge 9 commits intodocs/add-clayterm-specfrom
feat/virtualizer-v1
Open

Add @clayterm/virtualizer v1#11
taras wants to merge 9 commits intodocs/add-clayterm-specfrom
feat/virtualizer-v1

Conversation

@taras
Copy link
Copy Markdown
Member

@taras taras commented Apr 11, 2026

Demo

2026-04-11 07 24 30

Summary

  • Add createDisplayWidth() async WASM factory to @clayterm/clayterm — returns a synchronous per-codepoint wcwidth string-width function
  • Add @clayterm/virtualizer package — viewport virtualization over large terminal text output with ring buffer storage, ANSI-aware line wrapping, scroll position tracking, and viewport resolution
  • Add current-state specification document for the Clayterm rendering contract

Virtualizer API

class Virtualizer {
  constructor(options: { measureWidth, columns, rows, maxLines? })
  appendLine(text: string): number
  resize(columns: number, rows: number): void
  scrollBy(deltaVisualRows: number): void
  scrollToFraction(fraction: number): void
  resolveViewport(): ResolvedViewport
}

Key design decisions:

  • ANSI handling is internal — the virtualizer owns CSI/OSC skipping; the injected measureWidth only sees visible codepoints
  • Exact wrapping for visible lines, approximate estimation for scrollbarresolveViewport() computes exact wrap points for viewport entries while totalEstimatedVisualRows uses ceil(displayWidth/columns) for O(1) append
  • Stable monotonic line identitylineIndex values are never reused, even after FIFO eviction
  • Anchor-based scroll position — scroll state is (anchorLineIndex, anchorSubRow) with bottom-follow behavior

Test coverage

125 test steps across 18 suites:

  • Core invariants, ANSI handling, wrapping golden fixtures
  • Scroll, resize, eviction conformance tests
  • Exactness vs approximation structural tests
  • Property-based tests with deterministic PRNG
  • 7 validation-gate benchmarks (informational)

Test plan

  • deno test in virtualizer/ — 125 steps pass
  • deno test in root — renderer width tests pass
  • Verify CI passes

taras added 4 commits April 11, 2026 06:30
Adds the v0.1 draft specification covering the architectural model,
core invariants, public rendering API, descriptor model, and boundary
responsibilities. Non-normative sections document settling surfaces
(transfer encoding, input parsing, pointer events) separately from
the stable rendering core.
Implement the virtualizer package for viewport virtualization over
large terminal text output. This covers PRs 1–3 of the implementation
plan:

- PR 1: Export createDisplayWidth from renderer (WASM per-codepoint
  wcwidth, R.WIDTH.* tests)
- PR 2: Virtualizer core — appendLine, resolveViewport, ring buffer,
  ANSI scanner, wrap walker, getLineDisplayWidth (~66 tests)
- PR 3: scrollBy + scrollToFraction with all deferred scroll-dependent
  tests (~92 tests total)

resize() still throws "not implemented" — deferred to PR 4.
Implement Virtualizer.resize(): clear wrap cache on column change,
recompute estimated visual rows, clamp anchor sub-row. Row-only
changes update rows without invalidation.

Add 17 new tests: C.RESIZE.* (8), G.RESIZE.* (2), deferred
C.APPEND.caches-displayWidth (1), exactness structural tests (6).
109 virtualizer tests total, 249 repo-wide.
Property tests cover identity monotonicity, eviction stability,
estimation constraints, and viewport invariants under random ops.
Benchmarks report informational gate results for all 7 perf gates.
@taras taras force-pushed the feat/virtualizer-v1 branch from 16d6370 to fbc05cd Compare April 11, 2026 10:30
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 11, 2026

Open in StackBlitz

npm i https://pkg.pr.new/clayterm@11

commit: 80324f4

@taras taras changed the base branch from main to docs/add-clayterm-spec April 11, 2026 10:31
taras added 2 commits April 11, 2026 06:41
1. resize() now clamps anchorSubRow using exact wrap count instead of
   ceil(displayWidth/columns) estimate, which undercounts when boundary
   waste from wide characters increases actual sub-row count.

2. _recomputeCurrentEstimate() clamps currentEstimatedVisualRow to
   [0, totalEstimatedVisualRows-1] so the scrollbar invariant holds
   even when exact wrap counts exceed the estimate.

3. computeWrapPoints() no longer emits wrap point at index 0 when the
   first visible character is wider than columns — the character
   overflows its row instead of creating an empty first sub-row.

Adds 4 regression tests covering all three fixes.
@taras taras force-pushed the docs/add-clayterm-spec branch from e31bd93 to 30b0eef Compare April 11, 2026 10:49
taras added 3 commits April 11, 2026 07:04
…dition

Fix two blocking issues before merge:

1. When maxLines=1 and isAtBottom=false, evicting the anchor line left
   the anchor pointing at a gone lineIndex. resolveViewport() returned
   no entries from a non-empty buffer. Removed the `lineCount > 1` guard
   so the anchor always clamps to `evictedLineIndex + 1`. Added
   regression test R.EVICT.maxLines1-not-at-bottom.

2. Resolved the contradiction between O-9 ("every slice fits within
   columns") and the columns=1 + width-2 CJK glyph behavior. Documented
   columns ≥ max glyph width as a precondition on VirtualizerOptions,
   updated O-9 test name, wrap-golden test labels, and the spec.
Full-screen less-like pager that renders virtualizer viewport entries
through Clay ops with line numbers, scrollbar, and status bar.
Supports file args or generated content fallback.
Extract thumb geometry into reusable helper so event handling can
hit-test the scrollbar. Left-click the thumb to drag, click the
track to jump (top-aligned). Drag cancels on resize or mouseup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant