Files
correx/apps/tui-go/internal/app/input_test.go
T
kami ccfa4b4740 feat(tui): composer soft-wrap, alt+backspace, bracketed paste, borderless input
- 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
2026-06-28 20:42:50 +04:00

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)
}
}
}