ccfa4b4740
- editorLines now soft-wraps long logical lines at the box width (caret tracked across wrapped rows) instead of overflowing/truncating - alt+backspace deletes the word before the cursor (deleteWordBack) - handle tea.PasteMsg so bracketed paste (Ctrl+V / Ctrl+Shift+V / right-click) drops clipboard text into the focused composer; was silently dropped - render the composer (in-session + launcher) borderless: top rule + flush text, no side borders or trailing padding, so a terminal drag-copy yields just the typed text instead of box chrome and whitespace
74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package app
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A bracketed paste inserts at the cursor in the main composer (insert mode, no overlay).
|
|
func TestHandlePasteIntoComposer(t *testing.T) {
|
|
m := NewModel(nil)
|
|
m.editMode, m.overlay = ModeInsert, OverlayNone
|
|
m.inputBuffer, m.inputCursor = "ab", 1
|
|
m = m.handlePaste("XY").(Model)
|
|
if m.inputBuffer != "aXYb" || m.inputCursor != 3 {
|
|
t.Fatalf("composer paste = (%q,%d), want (%q,3)", m.inputBuffer, m.inputCursor, "aXYb")
|
|
}
|
|
}
|
|
|
|
// A paste while steering appends to the steer note, not the input buffer.
|
|
func TestHandlePasteWhileSteering(t *testing.T) {
|
|
m := NewModel(nil)
|
|
m.steering = true
|
|
m.steerBuffer = "go "
|
|
m = m.handlePaste("now").(Model)
|
|
if m.steerBuffer != "go now" || m.inputBuffer != "" {
|
|
t.Fatalf("steer paste = steer:%q input:%q", m.steerBuffer, m.inputBuffer)
|
|
}
|
|
}
|
|
|
|
// Alt+Backspace deletes the word (plus trailing spaces) left of the cursor.
|
|
func TestDeleteWordBack(t *testing.T) {
|
|
cases := []struct {
|
|
buf string
|
|
cur int
|
|
wantBuf string
|
|
wantCur int
|
|
}{
|
|
{"foo bar", 7, "foo ", 4},
|
|
{"foo bar ", 9, "foo ", 4},
|
|
{"foo bar baz", 7, "foo baz", 4}, // cursor mid-string
|
|
{"one", 3, "", 0},
|
|
{"", 0, "", 0},
|
|
}
|
|
for _, c := range cases {
|
|
m := NewModel(nil)
|
|
m.inputBuffer, m.inputCursor = c.buf, c.cur
|
|
m.deleteWordBack()
|
|
if m.inputBuffer != c.wantBuf || m.inputCursor != c.wantCur {
|
|
t.Errorf("deleteWordBack(%q,%d) = (%q,%d), want (%q,%d)",
|
|
c.buf, c.cur, m.inputBuffer, m.inputCursor, c.wantBuf, c.wantCur)
|
|
}
|
|
}
|
|
}
|
|
|
|
// F-006: a multi-line paste must collapse to a single display line so the fixed-height
|
|
// input box can't overflow and leave a smeared/stale region.
|
|
func TestFlattenForDisplay(t *testing.T) {
|
|
cases := map[string]string{
|
|
"plain text": "plain text",
|
|
"line one\nline two": "line one↵ line two",
|
|
"crlf\r\nhere": "crlf↵ here",
|
|
"tab\tseparated": "tab separated",
|
|
"a\nb\nc": "a↵ b↵ c",
|
|
}
|
|
for in, want := range cases {
|
|
if got := flattenForDisplay(in); got != want {
|
|
t.Errorf("flattenForDisplay(%q) = %q, want %q", in, got, want)
|
|
}
|
|
if strings.ContainsAny(flattenForDisplay(in), "\n\r\t") {
|
|
t.Errorf("flattenForDisplay(%q) still contains a control char", in)
|
|
}
|
|
}
|
|
}
|