AlecAivazis / survey

A golang library for building interactive and accessible prompts with full support for windows and posix terminals.
MIT License
4.07k stars 349 forks source link

Add option to remove filters from select-type prompts #463

Open zimeg opened 1 year ago

zimeg commented 1 year ago

Summary

This PR provides an option to remove the filter from the Select and MultiSelect prompts. This is given as an option to restrict selection movement to the arrow keys to prevent options from being hidden by accidental keystrokes. 👻

Preview

Select

color := ""
prompt := &survey.Select{
    Message:    "Select a color:",
    Options:    []string{"red", "blue", "green"},
    HideFilter: true,
}

survey.AskOne(prompt, &color)
The select prompt without an option to filter

MultiSelect

days := []string{}
prompt := &survey.MultiSelect{
    Message:    "What days do you prefer:",
    Options:    []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},
    HideFilter: true,
}
survey.AskOne(prompt, &days)
The multiselect prompt without an option to filter

Notes

samcofer commented 1 year ago

Just wanted to ping this PR, as this would be really helpful in a CLI I'm developing where the list of options can be extremely long, but generally filtering is disruptive to a users workflow.

zimeg commented 9 months ago

@samcofer This same effect can be achieved with a permissive Filter and some adjustments to the selection template. The following snippet can be used to match the first preview:

package main

import (
    "github.com/AlecAivazis/survey/v2"
)

func main() {
    survey.SelectQuestionTemplate = `
{{- define "option"}}
    {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}}  {{end}}
    {{- .CurrentOpt.Value}}{{ if ne ($.GetDescription .CurrentOpt) "" }} - {{color "cyan"}}{{ $.GetDescription .CurrentOpt }}{{end}}
    {{- color "reset"}}
{{end}}
{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
{{- color "default+hb"}}{{ .Message }}{{color "reset"}}
{{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}}
{{- else}}
  {{- "  "}}{{- color "cyan"}}[Use arrows to move{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
  {{- "\n"}}
  {{- range $ix, $option := .PageEntries}}
    {{- template "option" $.IterateOption $ix $option}}
  {{- end}}
{{- end}}`

    color := ""
    prompt := &survey.Select{
        Message: "Select a color:",
        Options: []string{"red", "blue", "green"},
        Filter: func(filterValue string, optValue string, optIndex int) bool {
            return true
        },
    }
    survey.AskOne(prompt, &color)
}

The Filter that always returns true means every option will match the filtering value, so typing won't change the results shown. The updates to the template hide any input provided to the filter. Both of these together remove filtering effects!

This dropdown shows the differences between the default template and this one. ```diff {{- define "option"}} {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}} {{- .CurrentOpt.Value}}{{ if ne ($.GetDescription .CurrentOpt) "" }} - {{color "cyan"}}{{ $.GetDescription .CurrentOpt }}{{end}} {{- color "reset"}} {{end}} {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} -{{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} +{{- color "default+hb"}}{{ .Message }}{{color "reset"}} {{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}} {{- else}} - {{- " "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} + {{- " "}}{{- color "cyan"}}[Use arrows to move{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} {{- "\n"}} {{- range $ix, $option := .PageEntries}} {{- template "option" $.IterateOption $ix $option}} {{- end}} {{- end}} ```