diff --git a/pkg/cli/prompt.go b/pkg/cli/prompt.go index 7ff4c8c..7e7ebe4 100644 --- a/pkg/cli/prompt.go +++ b/pkg/cli/prompt.go @@ -32,6 +32,8 @@ func newReader() *bufio.Reader { // Prompt asks for text input with a default value. func Prompt(label, defaultVal string) (string, error) { + label = compileGlyphs(label) + defaultVal = compileGlyphs(defaultVal) if defaultVal != "" { fmt.Printf("%s [%s]: ", label, defaultVal) } else { @@ -40,7 +42,7 @@ func Prompt(label, defaultVal string) (string, error) { r := newReader() input, err := r.ReadString('\n') - if err != nil { + if err != nil && !errors.Is(err, io.EOF) { return "", err } @@ -53,15 +55,15 @@ func Prompt(label, defaultVal string) (string, error) { // Select presents numbered options and returns the selected value. func Select(label string, options []string) (string, error) { - fmt.Println(label) + fmt.Println(compileGlyphs(label)) for i, opt := range options { - fmt.Printf(" %d. %s\n", i+1, opt) + fmt.Printf(" %d. %s\n", i+1, compileGlyphs(opt)) } fmt.Printf("Choose [1-%d]: ", len(options)) r := newReader() input, err := r.ReadString('\n') - if err != nil { + if err != nil && strings.TrimSpace(input) == "" { return "", err } @@ -74,9 +76,9 @@ func Select(label string, options []string) (string, error) { // MultiSelect presents checkboxes (space-separated numbers). func MultiSelect(label string, options []string) ([]string, error) { - fmt.Println(label) + fmt.Println(compileGlyphs(label)) for i, opt := range options { - fmt.Printf(" %d. %s\n", i+1, opt) + fmt.Printf(" %d. %s\n", i+1, compileGlyphs(opt)) } fmt.Printf("Choose (space-separated) [1-%d]: ", len(options)) diff --git a/pkg/cli/prompt_test.go b/pkg/cli/prompt_test.go index a3ea2b6..926d969 100644 --- a/pkg/cli/prompt_test.go +++ b/pkg/cli/prompt_test.go @@ -1,6 +1,7 @@ package cli import ( + "io" "os" "strings" "testing" @@ -26,6 +27,15 @@ func TestPrompt_Good_Default(t *testing.T) { assert.Equal(t, "world", val) } +func TestPrompt_Bad_EOFUsesDefault(t *testing.T) { + SetStdin(strings.NewReader("")) + defer SetStdin(nil) + + val, err := Prompt("Name", "world") + assert.NoError(t, err) + assert.Equal(t, "world", val) +} + func TestSelect_Good(t *testing.T) { SetStdin(strings.NewReader("2\n")) defer SetStdin(nil) @@ -43,6 +53,14 @@ func TestSelect_Bad_Invalid(t *testing.T) { assert.Error(t, err) } +func TestSelect_Bad_EOF(t *testing.T) { + SetStdin(strings.NewReader("")) + defer SetStdin(nil) + + _, err := Select("Pick", []string{"a", "b"}) + assert.ErrorIs(t, err, io.EOF) +} + func TestMultiSelect_Good(t *testing.T) { SetStdin(strings.NewReader("1 3\n")) defer SetStdin(nil) diff --git a/pkg/cli/utils.go b/pkg/cli/utils.go index 2a20db1..1b47afd 100644 --- a/pkg/cli/utils.go +++ b/pkg/cli/utils.go @@ -81,6 +81,8 @@ func Confirm(prompt string, opts ...ConfirmOption) bool { opt(cfg) } + prompt = compileGlyphs(prompt) + // Build the prompt suffix var suffix string if cfg.required { @@ -218,12 +220,14 @@ func Question(prompt string, opts ...QuestionOption) string { opt(cfg) } + prompt = compileGlyphs(prompt) + reader := newReader() for { // Build prompt with default if cfg.defaultValue != "" { - fmt.Printf("%s [%s] ", prompt, cfg.defaultValue) + fmt.Printf("%s [%s] ", prompt, compileGlyphs(cfg.defaultValue)) } else { fmt.Printf("%s ", prompt) } @@ -328,6 +332,8 @@ func Choose[T any](prompt string, items []T, opts ...ChooseOption[T]) T { opt(cfg) } + prompt = compileGlyphs(prompt) + reader := newReader() visible := make([]int, len(items)) for i := range items { @@ -404,6 +410,8 @@ func ChooseMulti[T any](prompt string, items []T, opts ...ChooseOption[T]) []T { opt(cfg) } + prompt = compileGlyphs(prompt) + reader := newReader() visible := make([]int, len(items)) for i := range items { @@ -458,7 +466,7 @@ func renderChoices[T any](prompt string, items []T, visible []int, displayFn fun if defaultN >= 0 && idx == defaultN { marker = "*" } - fmt.Printf(" %s%d. %s\n", marker, i+1, displayFn(items[idx])) + fmt.Printf(" %s%d. %s\n", marker, i+1, compileGlyphs(displayFn(items[idx]))) } if filter { fmt.Println(" (type to filter the list)")