github.com/sleungcy-sap/cli@v7.1.0+incompatible/util/ui/prompt.go (about) 1 package ui 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "strconv" 8 9 "github.com/vito/go-interact/interact" 10 "github.com/vito/go-interact/interact/terminal" 11 ) 12 13 const sigIntExitCode = 130 14 15 var ErrInvalidIndex = errors.New("invalid list index") 16 17 type InvalidChoiceError struct { 18 Choice string 19 } 20 21 func (InvalidChoiceError) Error() string { 22 return "Some error" 23 } 24 25 //go:generate counterfeiter . Resolver 26 27 type Resolver interface { 28 Resolve(dst interface{}) error 29 SetIn(io.Reader) 30 SetOut(io.Writer) 31 } 32 33 // DisplayBoolPrompt outputs the prompt and waits for user input. It only 34 // allows for a boolean response. A default boolean response can be set with 35 // defaultResponse. 36 func (ui *UI) DisplayBoolPrompt(defaultResponse bool, template string, templateValues ...map[string]interface{}) (bool, error) { 37 ui.terminalLock.Lock() 38 defer ui.terminalLock.Unlock() 39 40 response := defaultResponse 41 interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...)) 42 interactivePrompt.SetIn(ui.In) 43 interactivePrompt.SetOut(ui.OutForInteration) 44 err := interactivePrompt.Resolve(&response) 45 if isInterrupt(err) { 46 ui.Exiter.Exit(sigIntExitCode) 47 } 48 return response, err 49 } 50 51 // DisplayOptionalTextPrompt outputs the prompt and waits for user input. 52 func (ui *UI) DisplayOptionalTextPrompt(defaultValue string, template string, templateValues ...map[string]interface{}) (string, error) { 53 interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...)) 54 var value = defaultValue 55 interactivePrompt.SetIn(ui.In) 56 interactivePrompt.SetOut(ui.OutForInteration) 57 err := interactivePrompt.Resolve(&value) 58 if isInterrupt(err) { 59 ui.Exiter.Exit(sigIntExitCode) 60 } 61 return value, err 62 } 63 64 // DisplayPasswordPrompt outputs the prompt and waits for user input. Hides 65 // user's response from the screen. 66 func (ui *UI) DisplayPasswordPrompt(template string, templateValues ...map[string]interface{}) (string, error) { 67 ui.terminalLock.Lock() 68 defer ui.terminalLock.Unlock() 69 70 var password interact.Password 71 interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...)) 72 interactivePrompt.SetIn(ui.In) 73 interactivePrompt.SetOut(ui.OutForInteration) 74 err := interactivePrompt.Resolve(interact.Required(&password)) 75 if isInterrupt(err) { 76 ui.Exiter.Exit(sigIntExitCode) 77 } 78 return string(password), err 79 } 80 81 // DisplayTextMenu lets the user choose from a list of options, either by name 82 // or by number. 83 func (ui *UI) DisplayTextMenu(choices []string, promptTemplate string, templateValues ...map[string]interface{}) (string, error) { 84 for i, c := range choices { 85 t := fmt.Sprintf("%d. %s", i+1, c) 86 ui.DisplayText(t) 87 } 88 ui.DisplayNewline() 89 90 translatedPrompt := ui.TranslateText(promptTemplate, templateValues...) 91 92 interactivePrompt := ui.Interactor.NewInteraction(translatedPrompt) 93 94 interactivePrompt.SetIn(ui.In) 95 interactivePrompt.SetOut(ui.OutForInteration) 96 97 var value string = "enter to skip" 98 err := interactivePrompt.Resolve(&value) 99 100 if isInterrupt(err) { 101 ui.Exiter.Exit(sigIntExitCode) 102 } 103 104 if err != nil { 105 return "", err 106 } 107 108 if value == "enter to skip" { 109 return "", nil 110 } 111 112 i, err := strconv.Atoi(value) 113 if err != nil { 114 if contains(choices, value) { 115 return value, nil 116 } 117 return "", InvalidChoiceError{Choice: value} 118 } 119 120 if i > len(choices) || i <= 0 { 121 return "", ErrInvalidIndex 122 } 123 return choices[i-1], nil 124 } 125 126 // DisplayTextPrompt outputs the prompt and waits for user input. 127 func (ui *UI) DisplayTextPrompt(template string, templateValues ...map[string]interface{}) (string, error) { 128 interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...)) 129 var value string 130 interactivePrompt.SetIn(ui.In) 131 interactivePrompt.SetOut(ui.OutForInteration) 132 err := interactivePrompt.Resolve(interact.Required(&value)) 133 if isInterrupt(err) { 134 ui.Exiter.Exit(sigIntExitCode) 135 } 136 return value, err 137 } 138 139 func contains(s []string, v string) bool { 140 for _, x := range s { 141 if x == v { 142 return true 143 } 144 } 145 return false 146 } 147 148 func isInterrupt(err error) bool { 149 return err == interact.ErrKeyboardInterrupt || err == terminal.ErrKeyboardInterrupt 150 }