WIP: restore lost C behaviors (schtick message, forced redraw, greeting)

Incomplete checkpoint, preserved after the implementing session hit a
capacity limit partway through mutation verification. NOT reviewed and NOT
gate-clean: make fmt has not been run, so fmt-check currently fails on
ARCHITECTURE.md and TODO.md.

Work still outstanding before this is fit for review:
  - run make fmt and fold the result in
  - finish mutation-proving each of the three behaviors
  - verify every message string byte-for-byte against the C sources
  - confirm TestSeedCompatItemTables passes with its golden untouched

Refs #13.
This commit is contained in:
2026-08-09 09:55:38 +00:00
parent 727dfb2642
commit 3f0a14c5e6
15 changed files with 401 additions and 9 deletions

View File

@@ -1488,6 +1488,8 @@ type Terminal interface {
ReadChar() (byte, bool) // event loop → C char codes (arrows→hjkl, ^C→quit);
// ok is false when Interrupt woke the read
Interrupt() // wake a blocked ReadChar (signal goroutine only)
Repaint() // forced full redraw for CTRL-R
// (curses clearok(curscr,TRUE)+wrefresh(curscr))
Fini() // restore the device (curses endwin) on exit
}
@@ -1507,13 +1509,22 @@ func (w *Window) Printwf(format string, a ...any); func (w *Window) Inch(y, x in
func (w *Window) Clear(); func (w *Window) Clrtoeol(); func (w *Window) Standout(on bool)
func (s *Screen) Refresh() // blit stdscr to the device
func (s *Screen) RefreshWin(w *Window) // blit any window
func (s *Screen) Repaint() // force a full redraw of the device
func (s *Screen) Fini() // tear the device down
```
Ported drawing code keeps its structure: `mvaddch(y, x, ch)`
`g.scr.Std.MvAddCh(y, x, ch)`. Curses `mvinch` reads come from the Window
buffer, preserving the "screen is a data structure" idiom without touching the
real terminal. `md_readchar`'s escape decoding is deleted; tcell's `EventKey`
real terminal. `Repaint` is the one drawing call that is not a blit: it is the
`CTRL('R')` command's `clearok(curscr, TRUE)` plus `wrefresh(curscr)`,
implemented as tcell's `Screen.Sync`, and it exists because `Render` cannot do
its job. Both diff a new frame against the device's record of the old one and
send nothing where they agree, which is the wrong answer precisely when the
screen has been corrupted by something else's output — the only reason a player
types `CTRL('R')`. Like C's, it repaints what was last drawn rather than
re-blitting `stdscr`, so it takes no window. `md_readchar`'s escape decoding is
deleted; tcell's `EventKey`
provides decoded keys and we translate to the byte codes `command()` already
handles (KeyUp → 'k', etc.). Resize is handled by tcell, which registers only
SIGWINCH — SIGTSTP is not among the signals it takes, and is dropped (§9).