summaryrefslogtreecommitdiff
path: root/internal/tmuxedit/cursor_agent.go
blob: 1346d051c7b54aefe31ce3a08952bffefe2008d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package tmuxedit

import (
	"regexp"
)

// cursorAgent handles Cursor's distinctive box-drawing │ → prompt │ UI.
// Cursor uses a text field (not vim), so clearing is done with End + bulk
// backspace. Multi-line prompts are entered with Shift-Enter within the box.
type cursorAgent struct{ baseAgent }

// newCursorAgent returns a cursorAgent with the default configuration.
// Detect by the box structure or "/ commands" footer. Checked first because
// cursor panes often show model names like "Claude 4.5 Sonnet".
func newCursorAgent() *cursorAgent {
	return &cursorAgent{baseAgent{
		name:          "cursor",
		displayName:   "Cursor",
		detectPattern: `(│\s*→|/ commands · @ files)`,
		promptPat:     `(?m)│\s*→?\s*(.+?)\s*│\s*$`,
		stripPatterns: []string{"INSERT", "Add a follow-up", "ctrl+c to stop"},
		clearFirst:    true,
		clearKeys:     "End BSpace*200",
		newlineKeys:   "S-Enter",
		submitKeys:    "Enter",
	}}
}

// ExtractPrompt extracts the prompt text from the last contiguous │...│ block
// in the pane. This avoids picking up earlier command-review or dialog boxes
// that also use box-drawing characters.
func (c *cursorAgent) ExtractPrompt(paneContent string) string {
	if c.promptPat == "" {
		return ""
	}
	re, err := regexp.Compile(c.promptPat)
	if err != nil {
		return ""
	}
	allMatches := matchPromptLines(re, paneContent)
	if len(allMatches) == 0 {
		return ""
	}
	return joinLastContiguousBlock(allMatches, c.stripPatterns)
}

// ClearInput sends End + 200 backspaces to clear Cursor's text field.
// Cursor's input is a standard text field, not vim.
func (c *cursorAgent) ClearInput(paneID string) error {
	if !c.clearFirst || c.clearKeys == "" {
		return nil
	}
	if err := sendClearSequence(paneID, c.clearKeys); err != nil {
		return err
	}
	sleepAfterClear()
	return nil
}