Merge pull request '[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/cli/RFC.md fully. Find features des...' (#55) from agent/read---spec-code-core-go-cli-rfc-md-full into dev
Some checks are pending
Security Scan / security (push) Waiting to run

This commit is contained in:
Virgil 2026-04-02 06:08:31 +00:00
commit dd7439d1c2
3 changed files with 36 additions and 8 deletions

View file

@ -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))

View file

@ -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)

View file

@ -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)")