1
1
package cliui
2
2
3
3
import (
4
- "errors "
4
+ "flag "
5
5
"io"
6
- "strings"
7
- "text/template"
6
+ "os"
8
7
9
- "github.com/manifoldco/promptui "
8
+ "github.com/AlecAivazis/survey/v2 "
10
9
"github.com/spf13/cobra"
11
10
)
12
11
12
+ func init () {
13
+ survey .SelectQuestionTemplate = `
14
+ {{- define "option"}}
15
+ {{- " " }}{{- if eq .SelectedIndex .CurrentIndex }}{{color "green" }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}}
16
+ {{- .CurrentOpt.Value}}
17
+ {{- color "reset"}}
18
+ {{end}}
19
+
20
+ {{- if not .ShowAnswer }}
21
+ {{- if .Config.Icons.Help.Text }}
22
+ {{- if .FilterMessage }}{{ "Search:" }}{{ .FilterMessage }}
23
+ {{- else }}
24
+ {{- color "black+h"}}{{- "Type to search" }}{{color "reset"}}
25
+ {{- end }}
26
+ {{- "\n" }}
27
+ {{- end }}
28
+ {{- "\n" }}
29
+ {{- range $ix, $option := .PageEntries}}
30
+ {{- template "option" $.IterateOption $ix $option}}
31
+ {{- end}}
32
+ {{- end }}`
33
+ }
34
+
13
35
type SelectOptions struct {
14
36
Options []string
15
37
Size int
@@ -18,59 +40,43 @@ type SelectOptions struct {
18
40
19
41
// Select displays a list of user options.
20
42
func Select (cmd * cobra.Command , opts SelectOptions ) (string , error ) {
21
- selector := promptui.Select {
22
- Label : "" ,
23
- Items : opts .Options ,
24
- Size : opts .Size ,
25
- Searcher : func (input string , index int ) bool {
26
- option := opts .Options [index ]
27
- name := strings .Replace (strings .ToLower (option ), " " , "" , - 1 )
28
- input = strings .Replace (strings .ToLower (input ), " " , "" , - 1 )
29
-
30
- return strings .Contains (name , input )
31
- },
32
- HideHelp : opts .HideSearch ,
33
- Stdin : io .NopCloser (cmd .InOrStdin ()),
34
- Stdout : & writeCloser {cmd .OutOrStdout ()},
35
- Templates : & promptui.SelectTemplates {
36
- FuncMap : template.FuncMap {
37
- "faint" : func (value interface {}) string {
38
- //nolint:forcetypeassert
39
- return Styles .Placeholder .Render (value .(string ))
40
- },
41
- "subtle" : func (value interface {}) string {
42
- //nolint:forcetypeassert
43
- return defaultStyles .Subtle .Render (value .(string ))
44
- },
45
- "selected" : func (value interface {}) string {
46
- //nolint:forcetypeassert
47
- return defaultStyles .Keyword .Render ("> " + value .(string ))
48
- // return defaultStyles.SelectedMenuItem.Render("> " + value.(string))
49
- },
50
- },
51
- Active : "{{ . | selected }}" ,
52
- Inactive : " {{ . }}" ,
53
- Label : "{{.}}" ,
54
- Selected : "{{ \" \" }}" ,
55
- Help : `{{ "Use" | faint }} {{ .SearchKey | faint }} {{ "to toggle search" | faint }}` ,
56
- },
57
- HideSelected : true ,
43
+ // The survey library used *always* fails when testing on Windows,
44
+ // as it requires a live TTY (can't be a conpty). We should fork
45
+ // this library to add a dummy fallback, that simply reads/writes
46
+ // to the IO provided. See:
47
+ // https://github.com/AlecAivazis/survey/blob/master/terminal/runereader_windows.go#L94
48
+ if flag .Lookup ("test.v" ) != nil {
49
+ return opts .Options [0 ], nil
58
50
}
59
-
60
- _ , result , err := selector .Run ()
61
- if errors .Is (err , promptui .ErrAbort ) || errors .Is (err , promptui .ErrInterrupt ) {
62
- return result , Canceled
63
- }
64
- if err != nil {
65
- return result , err
66
- }
67
- return result , nil
51
+ opts .HideSearch = false
52
+ var value string
53
+ err := survey .AskOne (& survey.Select {
54
+ Options : opts .Options ,
55
+ PageSize : opts .Size ,
56
+ }, & value , survey .WithIcons (func (is * survey.IconSet ) {
57
+ is .Help .Text = "Type to search"
58
+ if opts .HideSearch {
59
+ is .Help .Text = ""
60
+ }
61
+ }), survey .WithStdio (fileReadWriter {
62
+ Reader : cmd .InOrStdin (),
63
+ }, fileReadWriter {
64
+ Writer : cmd .OutOrStdout (),
65
+ }, cmd .OutOrStdout ()))
66
+ return value , err
68
67
}
69
68
70
- type writeCloser struct {
69
+ type fileReadWriter struct {
70
+ io.Reader
71
71
io.Writer
72
72
}
73
73
74
- func (* writeCloser ) Close () error {
75
- return nil
74
+ func (f fileReadWriter ) Fd () uintptr {
75
+ if file , ok := f .Reader .(* os.File ); ok {
76
+ return file .Fd ()
77
+ }
78
+ if file , ok := f .Writer .(* os.File ); ok {
79
+ return file .Fd ()
80
+ }
81
+ return 0
76
82
}
0 commit comments