IsConfirm generates error if response is not "y"
when I perform a confirmation prompt, I am getting an empty error when entering any value other than y is this expected behavior?
to reproduce
package main
import (
"fmt"
"github.com/manifoldco/promptui"
)
func main() {
prompt := promptui.Prompt{
Label: "does this work?",
IsConfirm: true,
Default: "n",
}
answer, err := prompt.Run()
fmt.Printf("error <%v>, answer <%s> \n", err, answer)
}
// type "y" => error <<nil>>, answer <y> // err == nil (true)
// type "n" => error <>, answer <n> // err == nil (false)
// type "" => error <>, answer <> // err == nil (false)
// type "foo" => error <>, answer <foo> // err == nil (false)
I also ran into this multiple times. Just accepted that err is the result.
imo there just should be a separate ConfirmPrompt that returns bool, error
Also ran into the same issue and took the same path as @fiws... err != nil -> No / Empty
It looks like this is expected behavior. Reading the godocs states:
var ErrAbort = errors.New("")
ErrAbort is the error returned when confirm prompts are supplied "n"
Yeah this is frustrating behavior. No shouldn't be an error. If you want to split the logic tree based on the confirm result you can't do that, since it's an error. Also an acceptable answer should be "y, yes, YES, Y, 1", etc.
for anyone coming across this issue, I've gotten around this issue by mocking a normal prompt to look and act like a confirm prompt. I run the results through regex to get a true/false statement.
func confirm(label string) (bool, error) {
val := func(input string) error {
//if input == "" {
// return errors.New("input required")
//}
if len(input) > 3 {
return errors.New("Please give a yes or no answer")
}
return nil
}
faintText := promptui.Styler(promptui.FGFaint)
boldText := promptui.Styler(promptui.FGBold)
greenText := promptui.Styler(promptui.FGGreen)
redText := promptui.Styler(promptui.FGRed)
defaultLabel := fmt.Sprintf("%s %s ", boldText(label), faintText("[y/N]"))
template := promptui.PromptTemplates{
Prompt: defaultLabel,
Valid: defaultLabel,
Invalid: fmt.Sprintf("%s %s ", redText(label), faintText("[y/N]")),
Success: greenText(label) + " ",
}
prompt := promptui.Prompt{
Validate: val,
Templates: &template,
}
result, err := prompt.Run()
if err != nil {
return false, err
}
return isConfirm(result), nil
}
// acceptable answers: y,yes,Y,YES,1
var confirmExp = regexp.MustCompile("(?i)y(?:es)?|1")
func isConfirm(confirm string) bool {
return confirmExp.MatchString(confirm)
}
Repeated with latest version both in Windows and Linux
oh, man...this threw me for a loop. The confirm within _examples doesn't make this clear either. I agree with @randallmlough that "No" shouldn't be an error since it's a valid user response.
If in your want to use boolean expression of the prompt then following would do the the job.
package main
import (
"errors"
"fmt"
"strings"
"github.com/manifoldco/promptui"
)
func main() {
prompt := promptui.Prompt{
Label: "does this work?",
IsConfirm: true,
Default: "y",
}
validate := func(s string) error {
if len(s) == 1 && strings.Contains("YyNn", s) || prompt.Default != "" && len(s) == 0 {
return nil
}
return errors.New("invalid input")
}
prompt.Validate = validate
answer, err := prompt.Run()
confirmed := !errors.Is(err, promptui.ErrAbort)
if err != nil && confirmed {
fmt.Println("ERROR: ", err)
return
}
fmt.Printf("error <%v>, answer <%s> confirmed <%t>\n", err, answer, confirmed)
}
| type | output |
|---|---|
y |
error <<nil>>, answer <y> confirmed <true> |
Y |
error <<nil>>, answer <Y> confirmed <true> |
n |
error <>, answer <n> confirmed <false> |
N |
error <>, answer <n> confirmed <false> |
| `` | error <<nil>>, answer <> confirmed <true> |
foo |
shows <invalid input> and keeps prompt open |
Since implementation is emphasizing Y/N
https://github.com/manifoldco/promptui/blob/981a3cab68f6f3481bf42c6a98521af7fbd14fae/prompt.go#L43-L45
My Two Cents to this topic is that perhaps there should be new error added to the package and return ErrInvalidInput when input string is invalid option instead returning promptui.ErrAbort any input which is not y or Default.
Just test for ErrAbort like
if err != nil {
if err == promptui.ErrAbort {
// deal with abort
}
// deal with error
}
OR use the errors package to test if the returned error is/will be wrapped:
if errors.Is(err, promptui.ErrAbort) {
...
}