feat(tui-go): make the ? overlay list every keybind
Audited handleNormalKey / handleApprovalKey / the OverlayDiff handler against the help cheat-sheet and found gaps: enter, ↑↓/jk, /, s, c, a, w, q and ? itself were bound but undocumented. Reorganise helpBody into navigate / session / overlays / approval band / diff-viewer groups covering all of them. help_complete_test.go asserts a row exists for every binding so the help can't silently drift from the handlers. The longer sheet scrolls fine via the modal-scroll support. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Every key the TUI binds (normal mode, approval band, and the diff/preview viewer) must
|
||||||
|
// have a row in the ? overlay. Keyed by a distinctive description phrase so deleting a row
|
||||||
|
// fails loudly here — keep this list in step with handleNormalKey / handleApprovalKey and
|
||||||
|
// the OverlayDiff handler whenever a binding is added or changed.
|
||||||
|
func TestHelpCoversEveryKeybind(t *testing.T) {
|
||||||
|
m := inSessionModel(120, 80)
|
||||||
|
help := strings.Join(m.helpBody(), "\n")
|
||||||
|
|
||||||
|
want := []string{
|
||||||
|
// navigate
|
||||||
|
"move the session / list selection", // ↑↓ / j k
|
||||||
|
"open the selected session", // enter
|
||||||
|
"filter the session list", // /
|
||||||
|
"jump to your previous / next message", // ^↑ / ^↓
|
||||||
|
"scroll output", // PgUp / PgDn (+ ^u / ^d)
|
||||||
|
"drop selection", // esc
|
||||||
|
"back to the session list", // l
|
||||||
|
// session
|
||||||
|
"compose a message", // i
|
||||||
|
"toggle chat / steering mode", // s
|
||||||
|
"show workflows", // w
|
||||||
|
"copy the selected message", // y
|
||||||
|
"open the latest diff / preview", // ^x
|
||||||
|
"cancel the running session", // c
|
||||||
|
"re-open a dismissed approval gate", // a
|
||||||
|
"quit", // q
|
||||||
|
// overlays
|
||||||
|
"command palette", // p
|
||||||
|
"this keybindings help", // ?
|
||||||
|
"event inspector", // e
|
||||||
|
"tools / artifacts", // t / v
|
||||||
|
"resume past sessions", // S / R
|
||||||
|
"swap model / edit config", // m / g
|
||||||
|
"grants / idea board", // G / I
|
||||||
|
// approval band
|
||||||
|
"approve once", // y / a / enter
|
||||||
|
"reject", // n / r
|
||||||
|
"steer (add a note)", // e / s
|
||||||
|
"approve-always", // A
|
||||||
|
"walk the pending queue", // ↑ / ↓
|
||||||
|
"fullscreen the diff / command preview", // ^x
|
||||||
|
"dismiss for now", // esc
|
||||||
|
// diff / preview viewer
|
||||||
|
"scroll a line", // ↑ / ↓
|
||||||
|
"scroll a page", // PgUp / PgDn
|
||||||
|
"jump to top / end", // g / G
|
||||||
|
}
|
||||||
|
for _, w := range want {
|
||||||
|
if !strings.Contains(help, w) {
|
||||||
|
t.Errorf("? help is missing a row for %q", w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -818,20 +818,31 @@ func (m Model) helpBody() []string {
|
|||||||
}
|
}
|
||||||
out = append(out, "")
|
out = append(out, "")
|
||||||
}
|
}
|
||||||
section("session", []kb{
|
section("navigate", []kb{
|
||||||
{"i", "compose a message"},
|
{"↑↓ / j k", "move the session / list selection"},
|
||||||
|
{"enter", "open the selected session"},
|
||||||
|
{"/", "filter the session list"},
|
||||||
{"^↑ / ^↓", "jump to your previous / next message"},
|
{"^↑ / ^↓", "jump to your previous / next message"},
|
||||||
{"y", "copy the selected message (OSC52)"},
|
|
||||||
{"PgUp / PgDn", "scroll output (^u / ^d half-page)"},
|
{"PgUp / PgDn", "scroll output (^u / ^d half-page)"},
|
||||||
{"esc", "drop selection / scroll → follow newest"},
|
{"esc", "drop selection / scroll → follow newest"},
|
||||||
{"^x", "open the latest diff"},
|
|
||||||
{"l", "back to the session list"},
|
{"l", "back to the session list"},
|
||||||
})
|
})
|
||||||
|
section("session", []kb{
|
||||||
|
{"i", "compose a message"},
|
||||||
|
{"s", "toggle chat / steering mode"},
|
||||||
|
{"w", "show workflows (idle screen)"},
|
||||||
|
{"y", "copy the selected message (OSC52)"},
|
||||||
|
{"^x", "open the latest diff / preview"},
|
||||||
|
{"c", "cancel the running session"},
|
||||||
|
{"a", "re-open a dismissed approval gate"},
|
||||||
|
{"q", "quit"},
|
||||||
|
})
|
||||||
section("overlays", []kb{
|
section("overlays", []kb{
|
||||||
{"p", "command palette (shows all shortcuts)"},
|
{"p", "command palette (all shortcuts)"},
|
||||||
|
{"?", "this keybindings help"},
|
||||||
{"e", "event inspector (/ to filter)"},
|
{"e", "event inspector (/ to filter)"},
|
||||||
{"t / v", "tools / artifacts"},
|
{"t / v", "tools / artifacts"},
|
||||||
{"S / R", "session stats / resume sessions"},
|
{"S / R", "session stats / resume past sessions"},
|
||||||
{"m / g", "swap model / edit config"},
|
{"m / g", "swap model / edit config"},
|
||||||
{"G / I", "grants / idea board"},
|
{"G / I", "grants / idea board"},
|
||||||
})
|
})
|
||||||
@@ -842,6 +853,7 @@ func (m Model) helpBody() []string {
|
|||||||
{"A", "approve-always — choose scope"},
|
{"A", "approve-always — choose scope"},
|
||||||
{"↑ / ↓", "walk the pending queue"},
|
{"↑ / ↓", "walk the pending queue"},
|
||||||
{"^x", "fullscreen the diff / command preview"},
|
{"^x", "fullscreen the diff / command preview"},
|
||||||
|
{"esc", "dismiss for now (a re-opens)"},
|
||||||
})
|
})
|
||||||
section("diff / preview viewer (^x)", []kb{
|
section("diff / preview viewer (^x)", []kb{
|
||||||
{"↑ / ↓", "scroll a line"},
|
{"↑ / ↓", "scroll a line"},
|
||||||
|
|||||||
Reference in New Issue
Block a user