diff --git a/cmd/cmd.go b/cmd/cmd.go index 96a918157..d18e7f66a 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -1887,10 +1887,7 @@ func runInteractiveTUI(cmd *cobra.Command) { // Selector adapters for tui singleSelector := func(title string, items []config.ModelItem) (string, error) { - tuiItems := make([]tui.SelectItem, len(items)) - for i, item := range items { - tuiItems[i] = tui.SelectItem{Name: item.Name, Description: item.Description, Recommended: item.Recommended} - } + tuiItems := tui.ReorderItems(tui.ConvertItems(items)) result, err := tui.SelectSingle(title, tuiItems) if errors.Is(err, tui.ErrCancelled) { return "", config.ErrCancelled @@ -1899,10 +1896,7 @@ func runInteractiveTUI(cmd *cobra.Command) { } multiSelector := func(title string, items []config.ModelItem, preChecked []string) ([]string, error) { - tuiItems := make([]tui.SelectItem, len(items)) - for i, item := range items { - tuiItems[i] = tui.SelectItem{Name: item.Name, Description: item.Description, Recommended: item.Recommended} - } + tuiItems := tui.ReorderItems(tui.ConvertItems(items)) result, err := tui.SelectMultiple(title, tuiItems, preChecked) if errors.Is(err, tui.ErrCancelled) { return nil, config.ErrCancelled diff --git a/cmd/tui/selector.go b/cmd/tui/selector.go index 6791f44eb..6650f1a76 100644 --- a/cmd/tui/selector.go +++ b/cmd/tui/selector.go @@ -576,9 +576,15 @@ func (m multiSelectorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case tea.KeyRunes: - m.filter += string(msg.Runes) - m.cursor = 0 - m.scrollOffset = 0 + // On some terminals (e.g. Windows PowerShell), space arrives as + // KeyRunes instead of KeySpace. Intercept it so toggle still works. + if len(msg.Runes) == 1 && msg.Runes[0] == ' ' { + m.toggleItem() + } else { + m.filter += string(msg.Runes) + m.cursor = 0 + m.scrollOffset = 0 + } } } diff --git a/cmd/tui/selector_test.go b/cmd/tui/selector_test.go index 095fd2866..96ec0a90f 100644 --- a/cmd/tui/selector_test.go +++ b/cmd/tui/selector_test.go @@ -545,6 +545,43 @@ func TestMultiView_OverflowIndicator(t *testing.T) { } } +// --- Multi-select space toggle (including KeyRunes fallback for Windows PowerShell) --- + +func TestMultiUpdate_SpaceTogglesItem(t *testing.T) { + m := newMultiSelectorModel("Pick:", items("a", "b", "c"), nil) + m.cursor = 1 + + // Simulate space delivered as tea.KeySpace + updated, _ := m.Update(tea.KeyMsg{Type: tea.KeySpace}) + m = updated.(multiSelectorModel) + + if !m.checked[1] { + t.Error("space (KeySpace) should toggle the item at cursor") + } + if m.filter != "" { + t.Error("space should not modify filter") + } +} + +func TestMultiUpdate_SpaceRuneTogglesItem(t *testing.T) { + m := newMultiSelectorModel("Pick:", items("a", "b", "c"), nil) + m.cursor = 1 + + // Simulate space delivered as tea.KeyRunes (Windows PowerShell behavior) + updated, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{' '}}) + m = updated.(multiSelectorModel) + + if !m.checked[1] { + t.Error("space (KeyRunes) should toggle the item at cursor") + } + if m.filter != "" { + t.Error("space rune should not be added to filter") + } + if m.cursor != 1 { + t.Errorf("cursor should stay at 1, got %d", m.cursor) + } +} + // Key message helpers for testing type keyType = int