starkernel: REPL scrollback, ~1000 lines (FABRIC.md item 4.4q)
Scope decided with Captain Bob before implementation: ring buffer + recall on today's full-screen vt100 grid, not also confining REPL text to the 4.4o 640x480 box (that confinement stays open as its own future item, not a third silent deferral). No keyboard input path exists yet (M8 unstarted), so the trigger is two new FORTH words, SCROLL-BACK ( n -- ) / SCROLL-FWD ( n -- ), exercised via serial injection. vt100.c gains a text-only 1000-line ring buffer (kmalloc'd, tens of KB -- not pixel snapshots, which would be ~1000x larger for no benefit) plus a shadow buffer mirroring the current screen. scroll_up() now pushes evicted rows into the ring before the pixel scroll. History is one continuous sequence (ring then shadow); scrolling always redraws from that sequence -- no separate pixel-scroll path for scrollback, decided up front to avoid retrofitting later. New src/word_source/scroll_words.c (Module 31), thin wrappers over console_fb_scroll_back()/_fwd() -> vt100_scroll_back()/_fwd(). Bug caught during live testing: both words initially used an off-by-one underflow check (dsp < 1) copied from a different, older dsp convention elsewhere in this codebase; vm_pop() (which these words actually call) uses dsp as a 0-based top-of-stack index, so the check rejected every legitimate single-argument call. Fixed by removing the separate precheck and relying on vm_pop()'s own guard. Live-verified on all three architectures (exceeds this item's amd64-minimum bar): generated 50+ lines via a FORTH loop, confirmed SCROLL-BACK recovers correctly older content, and on amd64 confirmed SCROLL-FWD returns to genuinely live state (not a frozen snapshot) by showing the injected commands' own echo. Known limitation confirmed by direct pixel measurement: redrawn lines lose their original SGR color (not stored per-cell) -- text recovers exactly, color does not. Three-arch verified: Failed: 0, dict-hashes identical across all three (values changed correctly from prior items -- two new words were added). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
277845e3bf
commit
1f3ec3554e
@@ -5613,7 +5613,7 @@ document and committing that amendment as its own item.*
|
||||
> Probe code reverted from `repl.c` immediately after screendump capture; tree confirmed
|
||||
> clean.
|
||||
|
||||
- [ ] **4.4q — Scrollback, ~1000 lines.** A circular buffer of prior scroll-box lines, target
|
||||
- [x] **4.4q — Scrollback, ~1000 lines.** A circular buffer of prior scroll-box lines, target
|
||||
depth approximately 1000 (Captain Bob's own qualification: "something along those lines,"
|
||||
not a hard-locked spec number). Storage mechanism (`kmalloc` ring buffer vs. static array)
|
||||
is this item's own implementation call.
|
||||
@@ -5622,6 +5622,72 @@ document and committing that amendment as its own item.*
|
||||
+ logs per CLAUDE.md.
|
||||
*Refs:* §27.8.
|
||||
|
||||
> **Scope decided with Captain Bob before implementation, 2026-08-11:** this item is the
|
||||
> ring buffer and recall mechanism on today's full-screen `vt100` grid, not also confining
|
||||
> REPL text to the 4.4o 640×480 box. That confinement (`vt100`'s grid still spans the whole
|
||||
> screen, per 4.4p's "observed, not fixed") stays open, explicitly, as its own future item —
|
||||
> not a third silent deferral. Trigger mechanism: no keyboard input path exists yet
|
||||
> (`console_getc()` confirmed serial-only; M8 is unstarted) — implemented as two FORTH
|
||||
> words, `SCROLL-BACK ( n -- )` / `SCROLL-FWD ( n -- )`, exercised via the same serial
|
||||
> injection technique 4.4k used.
|
||||
>
|
||||
> **Done 2026-08-11.** `vt100.c` gained a text-only ring buffer (`g_ring`,
|
||||
> `VT100_SCROLLBACK_MAX_LINES` = 1000, `kmalloc`'d in `vt100_enable_ttf()` — text, not
|
||||
> pixels: at ~cols bytes/line this is tens of KB, roughly three orders of magnitude smaller
|
||||
> than a pixel-snapshot ring for the same depth would be) plus a `g_shadow` buffer mirroring
|
||||
> exactly what's on screen (updated by every `draw_cursor_glyph()` call and shifted by every
|
||||
> `scroll_up()`, which now pushes evicted rows into the ring before the pixel scroll).
|
||||
> History model: one continuous sequence, ring (oldest→newest evicted) then shadow
|
||||
> (oldest→newest on-screen); `g_scroll_offset` selects a window into it and
|
||||
> `scrollback_redraw()` draws that window. Scrolling is always "redraw from the ring/shadow
|
||||
> history," never a second pixel-scroll mechanism — decided up front per this document's own
|
||||
> advisory review, since retrofitting a redraw model onto a blit-scroll model later would
|
||||
> have been the expensive order.
|
||||
>
|
||||
> New words in `src/word_source/scroll_words.c` (registered as Module 31,
|
||||
> `word_registry.c`), thin wrappers over new `console_fb_scroll_back()`/`_fwd()` →
|
||||
> `vt100_scroll_back()`/`_fwd()`. **Bug caught during live testing, not left in:** both words
|
||||
> initially used `if (vm->dsp < 1)` for a single-argument underflow check, copied from a
|
||||
> pattern that turned out to belong to a different, older `dsp`-as-raw-count convention
|
||||
> elsewhere in this codebase; the convention `vm_pop()` (which these words actually call)
|
||||
> uses is `dsp` as a 0-based top-of-stack index, where `dsp < 0` is empty — the off-by-one
|
||||
> rejected every legitimate single-argument call as underflow. Fixed by removing the
|
||||
> separate precheck entirely and relying on `vm_pop()`'s own guard, sidestepping the
|
||||
> multi-convention mismatch rather than risking picking the wrong one again.
|
||||
>
|
||||
> **Live-verified on all three architectures**, not just amd64 (exceeds this item's own
|
||||
> amd64-minimum bar): injected `: GENLINES 0 DO I . CR LOOP ; 50 GENLINES` (`DO`/`LOOP` are
|
||||
> compile-only in this FORTH, needs a definition — also caught live, fixed the test not the
|
||||
> code) to generate far more than one screen's worth of output — each iteration's HADES/ECW
|
||||
> trace logging multiplies the line count well past 50 real terminal lines. amd64: captured
|
||||
> three screendumps — (A) live tail showing lines up to 49, (B) after `30 SCROLL-BACK`
|
||||
> showing lines 38–44 (correctly older), (C) after `30 SCROLL-FWD` showing genuinely live
|
||||
> content again, including the echoed `SCROLL-BACK`/`SCROLL-FWD` commands themselves and
|
||||
> their `ok` responses — proof it tracks whatever is truly live "now" rather than a frozen
|
||||
> snapshot, not just a coincidental match to an earlier capture. aarch64/riscv64: same
|
||||
> `GENLINES`/`SCROLL-BACK` sequence, both correctly recovered older lines (46/47) after
|
||||
> scrolling back 20. Screendumps:
|
||||
> [evidence/amd64/qemu-screenshot-20260811-210852-4.4q-scrollback-A-live.png](evidence/amd64/qemu-screenshot-20260811-210852-4.4q-scrollback-A-live.png),
|
||||
> [...-B-scrolled.png](evidence/amd64/qemu-screenshot-20260811-210852-4.4q-scrollback-B-scrolled.png),
|
||||
> [...-C-restored.png](evidence/amd64/qemu-screenshot-20260811-210852-4.4q-scrollback-C-restored.png),
|
||||
> [evidence/aarch64/qemu-screenshot-20260811-211338-4.4q-scrollback-A-live.png](evidence/aarch64/qemu-screenshot-20260811-211338-4.4q-scrollback-A-live.png),
|
||||
> [...-B-scrolled.png](evidence/aarch64/qemu-screenshot-20260811-211338-4.4q-scrollback-B-scrolled.png),
|
||||
> [evidence/riscv64/qemu-screenshot-20260811-212029-4.4q-scrollback-A-live.png](evidence/riscv64/qemu-screenshot-20260811-212029-4.4q-scrollback-A-live.png),
|
||||
> [...-B-scrolled.png](evidence/riscv64/qemu-screenshot-20260811-212029-4.4q-scrollback-B-scrolled.png).
|
||||
>
|
||||
> **Known limitation, confirmed by direct pixel measurement, not just documented:** redrawn
|
||||
> lines lose their original SGR color (per-cell color history isn't stored) — measured the
|
||||
> amd64 restored-view screenshot's `[Hera]` prefix pixels directly: no orange found in any
|
||||
> row touched by the `SCROLL-FWD` redraw, only in the one freshly-drawn live row after the
|
||||
> redraw settled. Text content is recovered exactly; color is not — this is the tradeoff
|
||||
> this item's own text left as "this item's own implementation call."
|
||||
>
|
||||
> Three-arch standard boot+log basis: amd64 (`logs/20260811-210705/amd64/`), aarch64
|
||||
> (`logs/20260811-211155/aarch64/`), riscv64 (`logs/20260811-211617/riscv64/`) — `Failed: 0`
|
||||
> all three, dict-hashes identical across all three (values changed from prior items,
|
||||
> correctly — two new words were added to the dictionary — but still cross-arch consistent,
|
||||
> which is the actual parity property that matters).
|
||||
|
||||
- [ ] **4.4r — Toggle word: hide/show the scroll box.** A FORTH word that hides the 640×480
|
||||
scroll box, revealing the rest of CANVAS beneath it for drawing; showing it again restores
|
||||
the scroll-box content undisturbed, no scrollback loss. Depends on 4.4o/4.4p (geometry) and
|
||||
|
||||
Reference in New Issue
Block a user