ba7ac06c16
ctrl+↑/↓ jumps between your sent (user) messages in the transcript: ctrl+↑ from the bottom selects the most recent, steps to older ones (clamping); ctrl+↓ steps back and drops to tail-follow past the last. The selected message is highlighted and scrolled into view (routerRows tracks per-message row offsets and windows to the selection). `y` yanks the selected message — or the latest turn when none is selected — to the system clipboard over OSC52 (go-osc52, tmux-wrapped under $TMUX), which is SSH/Termius- safe unlike a mouse drag. A brief "✓ copied" footer note animates out (and self-stops the tick). esc drops the selection; switching sessions clears it. Tests cover the user-message jump/clamp/tail and the copy-text selection. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
68 lines
2.1 KiB
Go
68 lines
2.1 KiB
Go
package app
|
|
|
|
import "testing"
|
|
|
|
func transcriptModel(roles ...string) Model {
|
|
m := NewModel(nil)
|
|
m.selectedID = "s1"
|
|
msgs := make([]RouterEntry, len(roles))
|
|
for i, r := range roles {
|
|
msgs[i] = RouterEntry{Role: r, Content: r + itoa(i)}
|
|
}
|
|
m.routerMessages["s1"] = msgs
|
|
return m
|
|
}
|
|
|
|
// ctrl+↑/↓ jumps between USER messages: from no selection ↑ grabs the most recent user
|
|
// message, keeps stepping to older ones (clamping), and ↓ steps back down, dropping to
|
|
// tail-follow (-1) once past the last user message.
|
|
func TestTranscriptNavUser(t *testing.T) {
|
|
// indices: 0 1 2 3 4
|
|
m := transcriptModel("user", "router", "user", "router", "user")
|
|
|
|
if m.transcriptSel != -1 {
|
|
t.Fatalf("initial sel = %d, want -1", m.transcriptSel)
|
|
}
|
|
m.transcriptNavUser(-1) // up from bottom → newest user (idx 4)
|
|
if m.transcriptSel != 4 {
|
|
t.Fatalf("up#1 = %d, want 4", m.transcriptSel)
|
|
}
|
|
m.transcriptNavUser(-1) // → user idx 2
|
|
if m.transcriptSel != 2 {
|
|
t.Fatalf("up#2 = %d, want 2", m.transcriptSel)
|
|
}
|
|
m.transcriptNavUser(-1) // → user idx 0
|
|
if m.transcriptSel != 0 {
|
|
t.Fatalf("up#3 = %d, want 0", m.transcriptSel)
|
|
}
|
|
m.transcriptNavUser(-1) // clamp at oldest
|
|
if m.transcriptSel != 0 {
|
|
t.Fatalf("up#4 (clamp) = %d, want 0", m.transcriptSel)
|
|
}
|
|
m.transcriptNavUser(1) // → user idx 2
|
|
if m.transcriptSel != 2 {
|
|
t.Fatalf("down#1 = %d, want 2", m.transcriptSel)
|
|
}
|
|
m.transcriptNavUser(1) // → user idx 4
|
|
m.transcriptNavUser(1) // past last user → tail-follow
|
|
if m.transcriptSel != -1 {
|
|
t.Fatalf("down past last = %d, want -1 (tail-follow)", m.transcriptSel)
|
|
}
|
|
}
|
|
|
|
// `y` copies the selected message, or the latest user/router turn when nothing is selected.
|
|
func TestCopyText(t *testing.T) {
|
|
m := transcriptModel("user", "router", "tool")
|
|
|
|
// no selection → most recent user/router turn (the "router" at idx 1, since "tool"
|
|
// is skipped).
|
|
if got := m.copyText(); got != "router1" {
|
|
t.Fatalf("copyText (no sel) = %q, want %q", got, "router1")
|
|
}
|
|
|
|
m.transcriptSel = 0
|
|
if got := m.copyText(); got != "user0" {
|
|
t.Fatalf("copyText (sel idx 0) = %q, want %q", got, "user0")
|
|
}
|
|
}
|