Skip to content

Commit

Permalink
Merge pull request #507 from lammel/feature/interactive-text-input-on…
Browse files Browse the repository at this point in the history
…exit
  • Loading branch information
MarvinJWendt committed Jul 1, 2023
2 parents 8f48d99 + fbe253b commit 9867c5a
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 42 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ linters:
- gosec
- govet
- ineffassign
- interfacer
- unconvert
- gosimple
- godox
Expand Down
25 changes: 16 additions & 9 deletions interactive_confirm_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ var (

// InteractiveConfirmPrinter is a printer for interactive confirm prompts.
type InteractiveConfirmPrinter struct {
DefaultValue bool
DefaultText string
TextStyle *Style
ConfirmText string
ConfirmStyle *Style
RejectText string
RejectStyle *Style
SuffixStyle *Style
DefaultValue bool
DefaultText string
TextStyle *Style
ConfirmText string
ConfirmStyle *Style
RejectText string
RejectStyle *Style
SuffixStyle *Style
OnInterruptFunc func()
}

// WithDefaultText sets the default text.
Expand Down Expand Up @@ -86,6 +87,12 @@ func (p InteractiveConfirmPrinter) WithSuffixStyle(style *Style) *InteractiveCon
return &p
}

// OnInterrupt sets the function to execute on exit of the input reader
func (p InteractiveConfirmPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveConfirmPrinter {
p.OnInterruptFunc = exitFunc
return &p
}

// Show shows the confirm prompt.
//
// Example:
Expand All @@ -95,7 +102,7 @@ func (p InteractiveConfirmPrinter) WithSuffixStyle(style *Style) *InteractiveCon
func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
cancel, exit := internal.NewCancelationSignal()
cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()

var result bool
Expand Down
12 changes: 12 additions & 0 deletions interactive_confirm_printer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pterm_test

import (
"reflect"
"testing"

"atomicgo.dev/keyboard"
Expand Down Expand Up @@ -126,3 +127,14 @@ func TestInteractiveConfirmPrinter_WithTextStyle(t *testing.T) {
p := pterm.DefaultInteractiveConfirm.WithTextStyle(style)
testza.AssertEqual(t, p.TextStyle, style)
}

func TestInteractiveConfirmPrinter_WithOnInterruptFunc(t *testing.T) {
// OnInterrupt function defaults to nil
pd := pterm.InteractiveConfirmPrinter{}
testza.AssertNil(t, pd.OnInterruptFunc)

// Verify OnInterrupt is set
exitfunc := func() {}
p := pterm.DefaultInteractiveConfirm.WithOnInterruptFunc(exitfunc)
testza.AssertEqual(t, reflect.ValueOf(p.OnInterruptFunc).Pointer(), reflect.ValueOf(exitfunc).Pointer())
}
29 changes: 18 additions & 11 deletions interactive_multiselect_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ var (

// InteractiveMultiselectPrinter is a printer for interactive multiselect menus.
type InteractiveMultiselectPrinter struct {
DefaultText string
TextStyle *Style
Options []string
OptionStyle *Style
DefaultOptions []string
MaxHeight int
Selector string
SelectorStyle *Style
Filter bool
Checkmark *Checkmark
DefaultText string
TextStyle *Style
Options []string
OptionStyle *Style
DefaultOptions []string
MaxHeight int
Selector string
SelectorStyle *Style
Filter bool
Checkmark *Checkmark
OnInterruptFunc func()

selectedOption int
selectedOptions []int
Expand Down Expand Up @@ -109,11 +110,17 @@ func (p InteractiveMultiselectPrinter) WithCheckmark(checkmark *Checkmark) *Inte
return &p
}

// OnInterrupt sets the function to execute on exit of the input reader
func (p InteractiveMultiselectPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveMultiselectPrinter {
p.OnInterruptFunc = exitFunc
return &p
}

// Show shows the interactive multiselect menu and returns the selected entry.
func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
cancel, exit := internal.NewCancelationSignal()
cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()

if len(text) == 0 || Sprint(text[0]) == "" {
Expand Down
12 changes: 12 additions & 0 deletions interactive_multiselect_printer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pterm_test

import (
"reflect"
"testing"

"atomicgo.dev/keyboard"
Expand Down Expand Up @@ -66,3 +67,14 @@ func TestInteractiveMultiselectPrinter_WithCheckmark(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithCheckmark(&pterm.Checkmark{Checked: "+", Unchecked: "-"}).WithOptions([]string{"a", "b", "c"})
testza.AssertEqual(t, p.Checkmark, &pterm.Checkmark{Checked: "+", Unchecked: "-"})
}

func TestInteractiveMultiselectPrinter_WithOnInterruptFunc(t *testing.T) {
// OnInterrupt function defaults to nil
pd := pterm.InteractiveMultiselectPrinter{}
testza.AssertNil(t, pd.OnInterruptFunc)

// Verify OnInterrupt is set
exitfunc := func() {}
p := pterm.DefaultInteractiveMultiselect.WithOnInterruptFunc(exitfunc)
testza.AssertEqual(t, reflect.ValueOf(p.OnInterruptFunc).Pointer(), reflect.ValueOf(exitfunc).Pointer())
}
25 changes: 16 additions & 9 deletions interactive_select_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ var (

// InteractiveSelectPrinter is a printer for interactive select menus.
type InteractiveSelectPrinter struct {
TextStyle *Style
DefaultText string
Options []string
OptionStyle *Style
DefaultOption string
MaxHeight int
Selector string
SelectorStyle *Style
TextStyle *Style
DefaultText string
Options []string
OptionStyle *Style
DefaultOption string
MaxHeight int
Selector string
SelectorStyle *Style
OnInterruptFunc func()

selectedOption int
result string
Expand Down Expand Up @@ -71,11 +72,17 @@ func (p InteractiveSelectPrinter) WithMaxHeight(maxHeight int) *InteractiveSelec
return &p
}

// OnInterrupt sets the function to execute on exit of the input reader
func (p InteractiveSelectPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveSelectPrinter {
p.OnInterruptFunc = exitFunc
return &p
}

// Show shows the interactive select menu and returns the selected entry.
func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
cancel, exit := internal.NewCancelationSignal()
cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()

if len(text) == 0 || Sprint(text[0]) == "" {
Expand Down
12 changes: 12 additions & 0 deletions interactive_select_printer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pterm_test

import (
"reflect"
"testing"

"atomicgo.dev/keyboard"
Expand Down Expand Up @@ -49,3 +50,14 @@ func TestInteractiveSelectPrinter_WithMaxHeight(t *testing.T) {
p := pterm.DefaultInteractiveSelect.WithMaxHeight(1337)
testza.AssertEqual(t, p.MaxHeight, 1337)
}

func TestInteractiveSelectPrinter_WithOnInterruptFunc(t *testing.T) {
// OnInterrupt function defaults to nil
pd := pterm.InteractiveSelectPrinter{}
testza.AssertNil(t, pd.OnInterruptFunc)

// Verify OnInterrupt is set
exitfunc := func() {}
p := pterm.DefaultInteractiveSelect.WithOnInterruptFunc(exitfunc)
testza.AssertEqual(t, reflect.ValueOf(p.OnInterruptFunc).Pointer(), reflect.ValueOf(exitfunc).Pointer())
}
17 changes: 12 additions & 5 deletions interactive_textinput_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ var (

// InteractiveTextInputPrinter is a printer for interactive select menus.
type InteractiveTextInputPrinter struct {
TextStyle *Style
DefaultText string
MultiLine bool
Mask string
TextStyle *Style
DefaultText string
MultiLine bool
Mask string
OnInterruptFunc func()

input []string
cursorXPos int
Expand Down Expand Up @@ -56,11 +57,17 @@ func (p InteractiveTextInputPrinter) WithMask(mask string) *InteractiveTextInput
return &p
}

// OnInterrupt sets the function to execute on exit of the input reader
func (p InteractiveTextInputPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveTextInputPrinter {
p.OnInterruptFunc = exitFunc
return &p
}

// Show shows the interactive select menu and returns the selected entry.
func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
cancel, exit := internal.NewCancelationSignal()
cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()

var areaText string
Expand Down
12 changes: 12 additions & 0 deletions interactive_textinput_printer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pterm_test

import (
"reflect"
"testing"

"atomicgo.dev/keyboard"
Expand Down Expand Up @@ -41,3 +42,14 @@ func TestInteractiveTextInputPrinter_WithMask(t *testing.T) {
result, _ := pterm.DefaultInteractiveTextInput.WithMask("*").Show()
testza.AssertEqual(t, result, "abc")
}

func TestInteractiveTextInputPrinter_WithOnInterruptFunc(t *testing.T) {
// OnInterrupt function defaults to nil
pd := pterm.InteractiveTextInputPrinter{}
testza.AssertNil(t, pd.OnInterruptFunc)

// Verify OnInterrupt is set
exitfunc := func() {}
p := pterm.DefaultInteractiveTextInput.WithOnInterruptFunc(exitfunc)
testza.AssertEqual(t, reflect.ValueOf(p.OnInterruptFunc).Pointer(), reflect.ValueOf(exitfunc).Pointer())
}
11 changes: 4 additions & 7 deletions internal/cancelation_signal.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package internal

import (
"os"
)

// NewCancelationSignal for keeping track of a cancelation
func NewCancelationSignal() (func(), func()) {
func NewCancelationSignal(interruptFunc func()) (func(), func()) {
canceled := false

cancel := func() {
canceled = true
}

exit := func() {
if canceled {
os.Exit(1)
if canceled && interruptFunc != nil {
interruptFunc()
}
}

Expand Down

0 comments on commit 9867c5a

Please sign in to comment.