From 37310c7cbd06c399e7517ae30c4cb2d1f6450f8e Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 06:01:35 +0000 Subject: [PATCH] fix(cli): avoid hanging prompts on EOF Co-Authored-By: Virgil --- pkg/cli/prompt_test.go | 16 ++++++++++++++++ pkg/cli/utils.go | 16 +++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/pkg/cli/prompt_test.go b/pkg/cli/prompt_test.go index 363a55e..a3ea2b6 100644 --- a/pkg/cli/prompt_test.go +++ b/pkg/cli/prompt_test.go @@ -68,6 +68,14 @@ func TestConfirm_Good(t *testing.T) { assert.True(t, Confirm("Proceed?")) } +func TestConfirm_Bad_EOFUsesDefault(t *testing.T) { + SetStdin(strings.NewReader("")) + defer SetStdin(nil) + + assert.False(t, Confirm("Proceed?", Required())) + assert.True(t, Confirm("Proceed?", DefaultYes(), Required())) +} + func TestQuestion_Good(t *testing.T) { SetStdin(strings.NewReader("alice\n")) defer SetStdin(nil) @@ -76,6 +84,14 @@ func TestQuestion_Good(t *testing.T) { assert.Equal(t, "alice", val) } +func TestQuestion_Bad_EOFReturnsDefault(t *testing.T) { + SetStdin(strings.NewReader("")) + defer SetStdin(nil) + + assert.Equal(t, "anonymous", Question("Name:", WithDefault("anonymous"))) + assert.Equal(t, "", Question("Name:", RequiredInput())) +} + func TestChoose_Good_DefaultIndex(t *testing.T) { SetStdin(strings.NewReader("\n")) defer SetStdin(nil) diff --git a/pkg/cli/utils.go b/pkg/cli/utils.go index c0fea5c..2a20db1 100644 --- a/pkg/cli/utils.go +++ b/pkg/cli/utils.go @@ -119,14 +119,18 @@ func Confirm(prompt string, opts ...ConfirmOption) bool { return cfg.defaultYes } } else { - response, _ = reader.ReadString('\n') + line, err := reader.ReadString('\n') + if err != nil && line == "" { + return cfg.defaultYes + } + response = line response = strings.ToLower(strings.TrimSpace(response)) } // Handle empty response if response == "" { if cfg.required { - continue // Ask again + return cfg.defaultYes } return cfg.defaultYes } @@ -224,14 +228,16 @@ func Question(prompt string, opts ...QuestionOption) string { fmt.Printf("%s ", prompt) } - response, _ := reader.ReadString('\n') + response, err := reader.ReadString('\n') response = strings.TrimSpace(response) + if err != nil && response == "" { + return cfg.defaultValue + } // Handle empty response if response == "" { if cfg.required { - fmt.Println("Response required") - continue + return cfg.defaultValue } response = cfg.defaultValue } -- 2.45.3