FABRIC-2.md §I.9 follow-on: blinking | cursor instead of static block
Captain Bob asked for the framebuffer cursor to render as a blinking vertical bar rather than the previous static solid-block glyph. vt100_draw_cursor() (hal/vt100.c) now fills a thin bar (cell_w()/8, min 1px, full cell height) at the cursor's left edge instead of the whole cell -- an I-beam shape. vt100_erase_cursor() is unchanged (clearing the whole cell already safely covers the narrower bar). Blinking is new in repl.c: sk_console_readline()'s idle branch toggles the cursor on/off every SK_CURSOR_BLINK_INTERVAL (50 ticks, 500ms at 100Hz) via alternating console_fb_draw_cursor()/console_fb_erase_cursor() calls, independent of the heartbeat/idle-beat mechanism the §I.9 fix just touched (deliberately not reused, to avoid recoupling to that path). Runs regardless of n, so it blinks whether sitting at a bare prompt or paused mid-edit. Every deterministic draw site (initial prompt, prompt reanchor, backspace, character echo) now goes through a new helper, sk_cursor_show(), which resets the blink cycle to "on" and redraws -- typing always shows a solid cursor, never mid-blink. Verified via the mandatory foreground 3-arch QEMU acceptance boot: amd64 (logs/20260905-021054, extensive live interactive typing including multi-line : / ; word definitions and error cases, prompts stayed correctly attached throughout), aarch64 (logs/20260905-021551), riscv64 (logs/20260905-022324) -- all three reached (zuse) ok> and shut down cleanly via BYE. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
8edb95b65d
commit
70dc8beba4
+28
@@ -4749,3 +4749,31 @@ The secondary, unverified cursor-glyph-staleness observation above was not indep
|
||||
re-checked — out of scope for this fix, and about to be superseded anyway by a separate
|
||||
requested change (blinking `|` cursor instead of a static block), tracked as a new item, not
|
||||
here.
|
||||
|
||||
**Follow-on, 2026-09-05, same day: cursor style changed to a blinking `|`.** Captain Bob asked
|
||||
for a blinking vertical bar instead of the previous static solid-block cursor. Two changes:
|
||||
|
||||
1. `vt100_draw_cursor()` (`hal/vt100.c`) now fills a thin vertical bar (`cell_w()/8`, minimum 1
|
||||
px, full cell height) at the cursor's left edge instead of the whole cell — an I-beam shape
|
||||
rather than a block. `vt100_erase_cursor()` is unchanged (still clears the whole cell, which
|
||||
safely covers the narrower bar too).
|
||||
2. Blinking (`repl.c`): `sk_console_readline()`'s idle branch now toggles the cursor on/off
|
||||
every `SK_CURSOR_BLINK_INTERVAL` (50 ticks, 500 ms at 100 Hz) via alternating
|
||||
`console_fb_draw_cursor()`/`console_fb_erase_cursor()` calls, tracked by
|
||||
`g_cursor_visible`/`g_cursor_blink_tick`. This runs regardless of `n` (blinks whether sitting
|
||||
at a bare prompt or paused mid-edit, like a real terminal). Every deterministic draw site
|
||||
(initial prompt, prompt reanchor, backspace, character echo) now calls a new helper,
|
||||
`sk_cursor_show()`, instead of `console_fb_draw_cursor()` directly — it resets the blink
|
||||
cycle to "on" and redraws, so typing always shows a solid cursor rather than possibly
|
||||
landing mid-blink.
|
||||
|
||||
Verified via the mandatory 3-arch foreground `clean qemu` boot: amd64 (`logs/20260905-021054/`,
|
||||
extensive live interactive typing including multi-line `:`/`;` word definitions and error
|
||||
cases, all prompts stayed correctly attached with no phantom breaks), aarch64
|
||||
(`logs/20260905-021551/`), riscv64 (`logs/20260905-022324/`) — all three reached `(zuse) ok>`
|
||||
and shut down cleanly via `BYE`. Blink timing itself isn't independently visible in a serial
|
||||
log (it's a framebuffer-only effect, gated the same way the previous static cursor was — no-op
|
||||
outside TTF/graphics mode); the boots above confirm the change doesn't regress the console
|
||||
otherwise. No separate screenshot capture was done for this follow-on since the earlier §I.9
|
||||
fix already covers the correctness property that actually mattered (no phantom linebreak) and
|
||||
this change only touches cursor *rendering*, not console line/newline logic.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-05T06:05:19Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-05T06:22:51Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+14
-10
@@ -354,20 +354,24 @@ static void draw_cursor_glyph(uint8_t ch)
|
||||
}
|
||||
}
|
||||
|
||||
/* Solid block cursor at the current position (g_vt.cx, g_vt.cy). Not
|
||||
* blinking -- a static indicator, simplest thing that actually shows
|
||||
* where typed input lands, callable as often as the caller likes since
|
||||
* it is idempotent (always draws the same thing at the current position).
|
||||
* A character typed at this position naturally overwrites it --
|
||||
* draw_cursor_glyph() always fills the whole cell with bg before drawing
|
||||
* a glyph -- but *leaving* this position without drawing a character
|
||||
* (Enter/newline) does not, which is what vt100_erase_cursor() below is
|
||||
* for. No-op outside TTF mode or graphics mode (4.4ab's
|
||||
/* Thin vertical-bar ("I-beam") cursor at the current position (g_vt.cx,
|
||||
* g_vt.cy) -- 2026-09-05, replaces the earlier solid block glyph per
|
||||
* request. Idempotent (always draws the same bar at the current
|
||||
* position), so callable as often as the caller likes; blinking (repl.c,
|
||||
* sk_console_readline()'s idle loop) is layered on top by alternating
|
||||
* calls to this and vt100_erase_cursor() on a timer, not by anything in
|
||||
* here. A character typed at this position naturally overwrites the bar
|
||||
* -- draw_cursor_glyph() always fills the whole cell with bg before
|
||||
* drawing a glyph -- but *leaving* this position without drawing a
|
||||
* character (Enter/newline) does not, which is what vt100_erase_cursor()
|
||||
* below is for. No-op outside TTF mode or graphics mode (4.4ab's
|
||||
* g_terminal_visible), matching every other draw call in this file. */
|
||||
void vt100_draw_cursor(void)
|
||||
{
|
||||
if (!g_terminal_visible || g_glyph_mode != VT_GLYPH_TTF) return;
|
||||
fb_fill_rect(px_of(g_vt.cx), py_of(g_vt.cy), cell_w(), cell_h(), eff_fg());
|
||||
uint32_t bar_w = cell_w() / 8u;
|
||||
if (bar_w < 1u) bar_w = 1u;
|
||||
fb_fill_rect(px_of(g_vt.cx), py_of(g_vt.cy), bar_w, cell_h(), eff_fg());
|
||||
}
|
||||
|
||||
/* Erases whatever vt100_draw_cursor() last drew at the current position,
|
||||
|
||||
+39
-4
@@ -144,6 +144,28 @@ blkio_dev_t *sk_repl_get_attached_blk_dev(void) {
|
||||
|
||||
static uint64_t g_last_beat_tick; /* zero-initialized (BSS) */
|
||||
|
||||
/* Cursor blink, 2026-09-05: the framebuffer cursor (now a thin vertical
|
||||
* bar, vt100.c's vt100_draw_cursor()) blinks on/off every
|
||||
* SK_CURSOR_BLINK_INTERVAL ticks while sk_console_readline()'s idle loop
|
||||
* is spinning -- i.e. whenever nothing has been typed for that long,
|
||||
* whether sitting at a bare prompt or paused mid-edit. g_cursor_visible
|
||||
* tracks which half of the blink cycle is current; sk_cursor_show() below
|
||||
* is the single place that resets the cycle back to "on" and redraws --
|
||||
* every deterministic draw site (fresh prompt, echoed character,
|
||||
* backspace) calls it instead of vt100_draw_cursor() directly, so typing
|
||||
* always shows a solid cursor rather than possibly landing mid-blink. */
|
||||
#define SK_CURSOR_BLINK_INTERVAL 50u /* ticks between blink toggles (500 ms at 100 Hz) */
|
||||
|
||||
static uint64_t g_cursor_blink_tick; /* zero-initialized (BSS) */
|
||||
static int g_cursor_visible = 1;
|
||||
|
||||
static void sk_cursor_show(void)
|
||||
{
|
||||
g_cursor_visible = 1;
|
||||
g_cursor_blink_tick = heartbeat_ticks();
|
||||
console_fb_draw_cursor();
|
||||
}
|
||||
|
||||
/* Reentrancy guards for the MSG-TICK pump inside sk_repl_idle().
|
||||
*
|
||||
* sk_repl_idle() runs vm_interpret(mama, ...) (below) to VM-EXEC MSG-TICK
|
||||
@@ -591,7 +613,7 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
uint64_t prompt_tx_mark = console_tx_count();
|
||||
|
||||
buf[0] = '\0';
|
||||
console_fb_draw_cursor(); /* show the cursor at the bare prompt, before any input */
|
||||
sk_cursor_show(); /* show the cursor at the bare prompt, before any input */
|
||||
|
||||
for (;;) {
|
||||
int c;
|
||||
@@ -637,6 +659,19 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
sk_repl_idle(active_vm);
|
||||
}
|
||||
|
||||
/* Blink the cursor while idle (no key ready this iteration),
|
||||
* regardless of n -- a real terminal blinks whether sitting at
|
||||
* a bare prompt or paused mid-edit. sk_cursor_show() (called
|
||||
* from every deterministic draw site below and at entry) resets
|
||||
* this cycle to "on" on every real keystroke, so typing never
|
||||
* looks like it landed mid-blink. */
|
||||
if (now - g_cursor_blink_tick >= SK_CURSOR_BLINK_INTERVAL) {
|
||||
g_cursor_blink_tick = now;
|
||||
g_cursor_visible = !g_cursor_visible;
|
||||
if (g_cursor_visible) console_fb_draw_cursor();
|
||||
else console_fb_erase_cursor();
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-anchor the prompt (FABRIC-0.md 4.4a unified prompt: print
|
||||
* only "ok> " here -- console_putc() auto-prefixes the current
|
||||
@@ -659,7 +694,7 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
console_tx_count() != prompt_tx_mark)
|
||||
{
|
||||
sk_print_prompt();
|
||||
console_fb_draw_cursor();
|
||||
sk_cursor_show();
|
||||
prompt_tx_mark = console_tx_count();
|
||||
}
|
||||
|
||||
@@ -689,7 +724,7 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
console_putc('\b');
|
||||
console_putc(' ');
|
||||
console_putc('\b');
|
||||
console_fb_draw_cursor();
|
||||
sk_cursor_show();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -699,7 +734,7 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
buf[n++] = (char)c;
|
||||
buf[n] = '\0';
|
||||
console_putc((char)c); /* echo */
|
||||
console_fb_draw_cursor();
|
||||
sk_cursor_show();
|
||||
}
|
||||
|
||||
buf[n] = '\0';
|
||||
|
||||
Reference in New Issue
Block a user