Gboard capitalizes the first character of a fresh input session and
derives its word context from the text it holds locally; it never
queries the app for context while typing. The editor was resetting that
session on essentially every event, so Gboard re-anchored to a fresh
session mid-word and caps went random:
- The pushed snippet WAS the render window. Any viewport change (keyboard
show/hide animation, tap re-centering, scroll) changed the snippet, and
gioui turns every snippet change into imm.restartInput — a full IME
session reset. The snippet is now a hysteresis window around the caret
(32 KB, re-anchor only when the caret is within 4 KB of an edge),
decoupled from the render window: typing, taps within range, keyboard
animation and flings never re-push it.
- gioui's EditEvent callback applies the commit to its own window state
directly, so the op queue lags it by one commit; any frame event in
the gap regressed the state and sent a restartInput with pre-commit
text per keystroke. The drained commit is now applied to the pushed
model immediately (Renderer.ApplyIMECommitToModel), and a short hold
keeps stale pre-commit frames out of FlushIME until the logic's
post-commit frame arrives.
- The layout feedback loop re-emitted on exact float equality of the
derived last-line Y, spinning a re-emit -> shape -> re-emit loop
(float-sum noise) that re-drew the editor and re-pushed IME state;
gate it with a 0.5 dp epsilon.
- The render window bottom mapped through the WrapIndex whose
in-viewport counts land while this very window is being shaped: the
bottom oscillated frame to frame, resizing the window (and the old
snippet) every frame. Use a fixed line span from the stable top
instead (each logical line yields >= 1 visual line, so the viewport is
always covered).
Result: zero snippet re-pushes during typing or flings (one re-anchor at
a far tap/file switch); emulator typing tests show all-lowercase
mid-word commits ('thaaaaaaaae', 'vapoaaaaaaaar') and the stress suite
(7 scenarios) passes clean with contiguous insertions only.