| 1 | package cli |
| 2 | |
| 3 | import ( |
| 4 | "testing" |
| 5 | |
| 6 | "reasonix/internal/command" |
| 7 | "reasonix/internal/control" |
| 8 | "reasonix/internal/event" |
| 9 | "reasonix/internal/skill" |
| 10 | ) |
| 11 | |
| 12 | func TestSlashArgSnapshotSurvivesNoMatchWithinEditingSession(t *testing.T) { |
| 13 | isolateUserConfig(t) |
| 14 | ctrl := newOwnedTestController(t, control.Options{}) |
| 15 | m := newChatTUI(ctrl, "", make(chan event.Event, 1), 80) |
| 16 | m.skills = []skill.Skill{{Name: "warm"}} |
| 17 | |
| 18 | m.input.SetValue("/skills show w") |
| 19 | m.updateCompletion() |
| 20 | if !m.completion.active || len(m.completion.items) != 1 || m.completion.items[0].label != "warm" { |
| 21 | t.Fatalf("initial skill completion = %+v, want warm", m.completion) |
| 22 | } |
| 23 | |
| 24 | // No-match filtering hides the menu, but it does not end the argument |
| 25 | // editing session. Dynamic completion data must stay frozen until an |
| 26 | // explicit dismissal, input reset, invalidation, or command change. |
| 27 | m.skills = []skill.Skill{{Name: "changed"}} |
| 28 | m.input.SetValue("/skills show z") |
| 29 | m.updateCompletion() |
| 30 | if m.completion.active { |
| 31 | t.Fatalf("no-match completion should be hidden: %+v", m.completion) |
| 32 | } |
| 33 | m.input.SetValue("/skills show zz") |
| 34 | m.updateCompletion() |
| 35 | m.input.SetValue("/skills show w") |
| 36 | m.updateCompletion() |
| 37 | if !m.completion.active || len(m.completion.items) != 1 || m.completion.items[0].label != "warm" { |
| 38 | t.Fatalf("no-match keystrokes rebuilt argument data: %+v", m.completion) |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | func TestFreeFormSlashSkipsArgDataSnapshot(t *testing.T) { |
| 43 | isolateUserConfig(t) |
| 44 | ctrl := newOwnedTestController(t, control.Options{}) |
| 45 | m := newChatTUI(ctrl, "", make(chan event.Event, 1), 80) |
| 46 | m.commands = []command.Command{{Name: "custom", Description: "free-form prompt"}} |
| 47 | |
| 48 | for _, input := range []string{"/custom free text", "/mcp__server__prompt argument"} { |
| 49 | m.input.SetValue(input) |
| 50 | m.updateCompletion() |
| 51 | if m.slashCache != nil && m.slashCache.argBuilt { |
| 52 | t.Fatalf("free-form slash input %q built dynamic argument data", input) |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 |