Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: interactive confirm with confirmation #648

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion _examples/interactive_confirm/demo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

func main() {
// Show an interactive confirmation dialog and get the result.
result, _ := pterm.DefaultInteractiveConfirm.Show()
result, _ := pterm.DefaultInteractiveConfirm.WithConfirmation(true).Show()

// Print a blank line for better readability.
pterm.Println()
Expand Down
35 changes: 28 additions & 7 deletions interactive_confirm_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type InteractiveConfirmPrinter struct {
RejectStyle *Style
SuffixStyle *Style
OnInterruptFunc func()
Confirmation bool
}

// WithDefaultText sets the default text.
Expand All @@ -58,13 +59,13 @@ func (p InteractiveConfirmPrinter) WithTextStyle(style *Style) *InteractiveConfi
return &p
}

// WithConfirmText sets the confirm text.
// WithConfirmText sets the confirmation text.
func (p InteractiveConfirmPrinter) WithConfirmText(text string) *InteractiveConfirmPrinter {
p.ConfirmText = text
return &p
}

// WithConfirmStyle sets the confirm style.
// WithConfirmStyle sets the confirmation style.
func (p InteractiveConfirmPrinter) WithConfirmStyle(style *Style) *InteractiveConfirmPrinter {
p.ConfirmStyle = style
return &p
Expand All @@ -88,7 +89,7 @@ func (p InteractiveConfirmPrinter) WithSuffixStyle(style *Style) *InteractiveCon
return &p
}

// OnInterrupt sets the function to execute on exit of the input reader
// WithOnInterruptFunc sets the function to execute on exit of the input reader
func (p InteractiveConfirmPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveConfirmPrinter {
p.OnInterruptFunc = exitFunc
return &p
Expand All @@ -100,7 +101,12 @@ func (p InteractiveConfirmPrinter) WithDelimiter(delimiter string) *InteractiveC
return &p
}

// Show shows the confirm prompt.
func (p InteractiveConfirmPrinter) WithConfirmation(value bool) *InteractiveConfirmPrinter {
p.Confirmation = value
return &p
}

// Show shows the confirmation prompt.
//
// Example:
//
Expand All @@ -113,6 +119,7 @@ func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {
defer exit()

var result bool
var resultFlag bool

if len(text) == 0 || text[0] == "" {
text = []string{p.DefaultText}
Expand All @@ -131,19 +138,33 @@ func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {

switch key {
case keys.RuneKey:
if p.Confirmation && resultFlag {
return false, nil
}
switch char {
case y:
p.ConfirmStyle.Print(p.ConfirmText)
Println()
result = true
Println()
if p.Confirmation {
resultFlag = true
return false, nil
}
return true, nil
case n:
p.RejectStyle.Print(p.RejectText)
Println()
result = false
Println()
if p.Confirmation {
resultFlag = true
return false, nil
}
return true, nil
}
case keys.Enter:
if p.Confirmation && resultFlag {
return true, nil
}
if p.DefaultValue {
p.ConfirmStyle.Print(p.ConfirmText)
} else {
Expand All @@ -165,7 +186,7 @@ func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {
return result, err
}

// getShortHandles returns the short hand answers for the confirmation prompt
// getShortHandles returns the shorthand answers for the confirmation prompt
func (p InteractiveConfirmPrinter) getShortHandles() (string, string) {
y := strings.ToLower(string([]rune(p.ConfirmText)[0]))
n := strings.ToLower(string([]rune(p.RejectText)[0]))
Expand Down
42 changes: 42 additions & 0 deletions interactive_confirm_printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pterm_test
import (
"reflect"
"testing"
"time"

"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
Expand Down Expand Up @@ -82,6 +83,47 @@ func TestInteractiveConfirmPrinter_WithRejectText(t *testing.T) {
testza.AssertEqual(t, p.RejectText, "reject")
}

func TestInteractiveConfirmPrinter_WithConfirmation(t *testing.T) {
p := pterm.DefaultInteractiveConfirm.WithConfirmation(true)
testza.AssertEqual(t, p.Confirmation, true)
}

func TestInteractiveConfirmPrinter_WithConfirmation_true(t *testing.T) {
p := pterm.DefaultInteractiveConfirm.WithConfirmation(true)
tests := []struct {
name string
key string
expected bool
}{
{
name: "Confirm",
key: "y",
expected: true,
},
{
name: "Reject",
key: "n",
expected: false,
},
{
name: "Default_Value",
key: keys.Enter.String(),
expected: p.DefaultValue,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
go func() {
keyboard.SimulateKeyPress(tc.key)
time.Sleep(100 * time.Millisecond)
keyboard.SimulateKeyPress(keys.Enter)
}()
result, _ := p.Show()
testza.AssertEqual(t, result, tc.expected)
})
}
}

func TestInteractiveConfirmPrinter_CustomAnswers(t *testing.T) {
p := pterm.DefaultInteractiveConfirm.WithRejectText("reject").WithConfirmText("accept")
tests := []struct {
Expand Down