Skip to content

Commit b5092a6

Browse files
chore: add filtering for multiselect, improve filtering algo
1 parent 7cf35d1 commit b5092a6

File tree

1 file changed

+49
-23
lines changed

1 file changed

+49
-23
lines changed

cli/cliui/select.go

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,10 @@ func (m selectModel) viewableOptions() ([]string, int) {
227227
func (m selectModel) filteredOptions() []string {
228228
options := []string{}
229229
for _, o := range m.options {
230-
prefix := strings.ToLower(m.search.Value())
230+
filter := strings.ToLower(m.search.Value())
231231
option := strings.ToLower(o)
232232

233-
if strings.HasPrefix(option, prefix) {
233+
if strings.Contains(option, filter) {
234234
options = append(options, o)
235235
}
236236
}
@@ -249,15 +249,20 @@ func MultiSelect(inv *serpent.Invocation, opts MultiSelectOptions) ([]string, er
249249
return opts.Defaults, nil
250250
}
251251

252-
options := make([]multiSelectOption, len(opts.Options))
252+
options := make([]*multiSelectOption, len(opts.Options))
253253
for i, option := range opts.Options {
254-
options[i].option = option
255-
254+
chosen := false
256255
for _, d := range opts.Defaults {
257256
if option == d {
258-
options[i].chosen = true
257+
chosen = true
259258
}
260259
}
260+
261+
options[i] = &multiSelectOption{
262+
option: option,
263+
chosen: chosen,
264+
}
265+
261266
}
262267

263268
initialModel := multiSelectModel{
@@ -293,7 +298,7 @@ type multiSelectOption struct {
293298

294299
type multiSelectModel struct {
295300
search textinput.Model
296-
options []multiSelectOption
301+
options []*multiSelectOption
297302
cursor int
298303
message string
299304
canceled bool
@@ -321,8 +326,9 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
321326
}
322327

323328
case tea.KeySpace:
324-
if len(m.options) != 0 {
325-
m.options[m.cursor].chosen = !m.options[m.cursor].chosen
329+
options := m.filteredOptions()
330+
if len(options) != 0 {
331+
options[m.cursor].chosen = !options[m.cursor].chosen
326332
}
327333

328334
case tea.KeyUp:
@@ -336,13 +342,15 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
336342
}
337343

338344
case tea.KeyRight:
339-
for i := range m.options {
340-
m.options[i].chosen = true
345+
options := m.filteredOptions()
346+
for _, option := range options {
347+
option.chosen = false
341348
}
342349

343350
case tea.KeyLeft:
344-
for i := range m.options {
345-
m.options[i].chosen = false
351+
options := m.filteredOptions()
352+
for _, option := range options {
353+
option.chosen = false
346354
}
347355

348356
default:
@@ -352,8 +360,9 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
352360
// If the search query has changed then we need to ensure
353361
// the cursor is still pointing at a valid option.
354362
if m.search.Value() != oldSearch {
355-
if m.cursor > len(m.options)-1 {
356-
m.cursor = max(0, len(m.options)-1)
363+
options := m.filteredOptions()
364+
if m.cursor > len(options)-1 {
365+
m.cursor = max(0, len(options)-1)
357366
}
358367
}
359368
}
@@ -370,23 +379,27 @@ func (m multiSelectModel) View() string {
370379
if !m.selected {
371380
s += fmt.Sprintf("%s %s[Use arrows to move, space to select, <right> to all, <left> to none, type to filter]\n", msg, m.search.View())
372381

373-
for i, option := range m.options {
382+
for i, option := range m.filteredOptions() {
374383
cursor := " "
384+
chosen := "[ ]"
385+
o := option.option
386+
375387
if m.cursor == i {
376388
cursor = pretty.Sprint(pretty.FgColor(Green), "> ")
389+
chosen = pretty.Sprint(pretty.FgColor(Green), "[ ]")
390+
o = pretty.Sprint(pretty.FgColor(Green), o)
377391
}
378392

379-
chosen := "[ ]"
380393
if option.chosen {
381394
chosen = pretty.Sprint(pretty.FgColor(Green), "[x]")
382395
}
383396

384-
o := option.option
385-
if m.cursor == i {
386-
o = pretty.Sprint(pretty.FgColor(Green), o)
387-
}
388-
389-
s += fmt.Sprintf("%s%s %s\n", cursor, chosen, o)
397+
s += fmt.Sprintf(
398+
"%s%s %s\n",
399+
cursor,
400+
chosen,
401+
o,
402+
)
390403
}
391404
} else {
392405
selected := pretty.Sprint(DefaultStyles.Keyword, strings.Join(m.selectedOptions(), ", "))
@@ -397,6 +410,19 @@ func (m multiSelectModel) View() string {
397410
return s
398411
}
399412

413+
func (m multiSelectModel) filteredOptions() []*multiSelectOption {
414+
options := []*multiSelectOption{}
415+
for _, o := range m.options {
416+
filter := strings.ToLower(m.search.Value())
417+
option := strings.ToLower(o.option)
418+
419+
if strings.Contains(option, filter) {
420+
options = append(options, o)
421+
}
422+
}
423+
return options
424+
}
425+
400426
func (m multiSelectModel) selectedOptions() []string {
401427
selected := []string{}
402428
for _, o := range m.options {

0 commit comments

Comments
 (0)