summaryrefslogtreecommitdiff
path: root/internal/tmuxedit/run_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-08 15:19:36 +0200
committerPaul Buetow <paul@buetow.org>2026-02-08 15:19:36 +0200
commit887d7bc186db90c3903851b0f1db2d24df5d7a7b (patch)
tree1cfb8055ddbb907bae9461b924dda1d2b3f15b46 /internal/tmuxedit/run_test.go
parent6da37034708dc7d4dcb7c71e890478a68e6ae4a1 (diff)
fix hexai-tmux-edit agent detection, multi-line extraction, and clearing
- Reorder agents: cursor first to avoid false positive from "Claude 4.5 Sonnet" model name appearing in cursor panes - Change cursor detect pattern to box-drawing UI elements instead of name-based matching - Change claude detect pattern to ❯ prompt instead of generic "claude" - Support multi-line prompt extraction using last-contiguous-block algorithm to ignore command-review and dialog boxes - Fix deduplicateText to always return full edited text (clear + resend) instead of stripping original prefix which caused double-removal - Replace vim-style clear (Escape gg dG i) with universal End+BSpace*200 since cursor's prompt is not actually vim - Add Key*N repeat syntax in ClearKeys (parsed by parseKeyRepeat, sent via tmux send-keys -N) - Add 300ms sleep after clear to let TUI drain queued backspaces before new text arrives - Add debug logging to /tmp/hexai-tmux-edit.log - Add strip pattern for "ctrl+c to stop" noise in cursor prompt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/tmuxedit/run_test.go')
-rw-r--r--internal/tmuxedit/run_test.go70
1 files changed, 36 insertions, 34 deletions
diff --git a/internal/tmuxedit/run_test.go b/internal/tmuxedit/run_test.go
index 88c94a2..2766f6b 100644
--- a/internal/tmuxedit/run_test.go
+++ b/internal/tmuxedit/run_test.go
@@ -29,9 +29,9 @@ func TestRunWithConfig_HappyPath(t *testing.T) {
return nil, nil
}
- // Mock: capture pane content with Claude agent detected
+ // Mock: capture pane content with Claude Code agent detected
capturePane = func(paneID string) (string, error) {
- return "Claude Code v1.0\n> fix the bug", nil
+ return "claude code v1.0\n────\n❯ fix the bug\n────", nil
}
// Mock: editor popup returns modified text
@@ -58,14 +58,16 @@ func TestRunWithConfig_HappyPath(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
- // Should have sent: clear (C-u), "also refactor the module"
- // (since "fix the bug" was pre-filled and kept, only the appended text is sent)
- if len(sent) < 1 {
- t.Fatalf("no send calls recorded")
+ // Should have sent: clear (C-u), then the full edited text (both lines)
+ // since deduplicateText returns the complete text whenever anything changed.
+ if len(sent) < 2 {
+ t.Fatalf("expected at least 2 send calls (clear + text), got %d: %v", len(sent), sent)
}
- // Check that the deduplication worked - only new text should be sent
allSent := strings.Join(sent, "|")
+ if !strings.Contains(allSent, "fix the bug") {
+ t.Errorf("expected 'fix the bug' in sent calls: %v", sent)
+ }
if !strings.Contains(allSent, "also refactor the module") {
t.Errorf("expected 'also refactor the module' in sent calls: %v", sent)
}
@@ -121,7 +123,7 @@ func TestRunWithConfig_EditorEmpty(t *testing.T) {
return []byte("%1"), nil
}
capturePane = func(string) (string, error) {
- return "Claude\n> ", nil
+ return "claude code\n❯ ", nil
}
openEditorPopup = func(string, string, string) (string, error) {
return "", nil // user saved empty file
@@ -206,51 +208,51 @@ func TestShellQuote(t *testing.T) {
}
func TestLaunchPopup_CommandArgs(t *testing.T) {
- oldRunCmd := runCommand
- defer func() { runCommand = oldRunCmd }()
+ oldLaunch := launchPopup
+ defer func() { launchPopup = oldLaunch }()
- var captured []string
- runCommand = func(name string, args ...string) ([]byte, error) {
- captured = append(captured, name)
- captured = append(captured, args...)
- return nil, nil
+ var capturedArgs struct {
+ ed, path, w, h string
+ }
+ launchPopup = func(ed, path, w, h string) error {
+ capturedArgs.ed = ed
+ capturedArgs.path = path
+ capturedArgs.w = w
+ capturedArgs.h = h
+ return nil
}
err := launchPopup("vim", "/tmp/test.md", "90%", "85%")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
- // Verify command structure: tmux display-popup -E -w 90% -h 85% "vim '/tmp/test.md'"
- if captured[0] != "tmux" {
- t.Errorf("command = %q, want tmux", captured[0])
- }
- if captured[1] != "display-popup" {
- t.Errorf("args[0] = %q, want display-popup", captured[1])
+ if capturedArgs.ed != "vim" {
+ t.Errorf("ed = %q, want vim", capturedArgs.ed)
}
- if captured[2] != "-E" {
- t.Errorf("args[1] = %q, want -E", captured[2])
+ if capturedArgs.w != "90%" || capturedArgs.h != "85%" {
+ t.Errorf("dimensions = %sx%s, want 90%%x85%%", capturedArgs.w, capturedArgs.h)
}
}
func TestLaunchPopup_NoDimensions(t *testing.T) {
- oldRunCmd := runCommand
- defer func() { runCommand = oldRunCmd }()
+ oldLaunch := launchPopup
+ defer func() { launchPopup = oldLaunch }()
- var captured []string
- runCommand = func(name string, args ...string) ([]byte, error) {
- captured = args
- return nil, nil
+ var capturedArgs struct {
+ w, h string
+ }
+ launchPopup = func(ed, path, w, h string) error {
+ capturedArgs.w = w
+ capturedArgs.h = h
+ return nil
}
err := launchPopup("nano", "/tmp/f.md", "", "")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
- // Should not include -w or -h flags
- for _, a := range captured {
- if a == "-w" || a == "-h" {
- t.Errorf("unexpected dimension flag in args: %v", captured)
- }
+ if capturedArgs.w != "" || capturedArgs.h != "" {
+ t.Errorf("expected empty dimensions, got %qx%q", capturedArgs.w, capturedArgs.h)
}
}