1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
package pterm
import (
"fmt"
"strings"
"atomicgo.dev/cursor"
"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/pterm/pterm/internal"
)
// DefaultInteractiveContinue is the default InteractiveContinue printer.
// Pressing "y" will return yes, "n" will return no, "a" returns all and "s" returns stop.
// Pressing enter without typing any letter will return the configured default value (by default set to "yes", the fisrt option).
var DefaultInteractiveContinue = InteractiveContinuePrinter{
DefaultValueIndex: 0,
DefaultText: "Do you want to continue",
TextStyle: &ThemeDefault.PrimaryStyle,
Options: []string{"yes", "no", "all", "cancel"},
OptionsStyle: &ThemeDefault.SuccessMessageStyle,
SuffixStyle: &ThemeDefault.SecondaryStyle,
Delimiter: ": ",
}
// InteractiveContinuePrinter is a printer for interactive continue prompts.
type InteractiveContinuePrinter struct {
DefaultValueIndex int
DefaultText string
Delimiter string
TextStyle *Style
Options []string
OptionsStyle *Style
Handles []string
ShowShortHandles bool
SuffixStyle *Style
}
// WithDefaultText sets the default text.
func (p InteractiveContinuePrinter) WithDefaultText(text string) *InteractiveContinuePrinter {
p.DefaultText = text
return &p
}
// WithDefaultValueIndex sets the default value, which will be returned when the user presses enter without typing any letter.
func (p InteractiveContinuePrinter) WithDefaultValueIndex(value int) *InteractiveContinuePrinter {
if value >= len(p.Options) {
panic("Index out of range")
}
p.DefaultValueIndex = value
return &p
}
// WithDefaultValue sets the default value, which will be returned when the user presses enter without typing any letter.
func (p InteractiveContinuePrinter) WithDefaultValue(value string) *InteractiveContinuePrinter {
for i, o := range p.Options {
if o == value {
p.DefaultValueIndex = i
break
}
}
return &p
}
// WithTextStyle sets the text style.
func (p InteractiveContinuePrinter) WithTextStyle(style *Style) *InteractiveContinuePrinter {
p.TextStyle = style
return &p
}
// WithOptions sets the options.
func (p InteractiveContinuePrinter) WithOptions(options []string) *InteractiveContinuePrinter {
p.Options = options
return &p
}
// WithHandles allows you to customize the short handles for the answers.
func (p InteractiveContinuePrinter) WithHandles(handles []string) *InteractiveContinuePrinter {
if len(handles) != len(p.Options) {
Warning.Printf("%v is not a valid set of handles", handles)
p.setDefaultHandles()
return &p
}
p.Handles = handles
return &p
}
// WithShowShortHandles will set ShowShortHandles to true
// this makes the printer display the shorthand options instead their shorthand version.
func (p InteractiveContinuePrinter) WithShowShortHandles(b ...bool) *InteractiveContinuePrinter {
p.ShowShortHandles = internal.WithBoolean(b)
return &p
}
// WithOptionsStyle sets the continue style.
func (p InteractiveContinuePrinter) WithOptionsStyle(style *Style) *InteractiveContinuePrinter {
p.OptionsStyle = style
return &p
}
// WithSuffixStyle sets the suffix style.
func (p InteractiveContinuePrinter) WithSuffixStyle(style *Style) *InteractiveContinuePrinter {
p.SuffixStyle = style
return &p
}
// WithDelimiter sets the delimiter between the message and the input.
func (p InteractiveContinuePrinter) WithDelimiter(delimiter string) *InteractiveContinuePrinter {
p.Delimiter = delimiter
return &p
}
// Show shows the continue prompt.
//
// Example:
//
// result, _ := pterm.DefaultInteractiveContinue.Show("Do you want to apply the changes?")
// pterm.Println(result)
func (p InteractiveContinuePrinter) Show(text ...string) (string, error) {
var result string
if len(text) == 0 || text[0] == "" {
text = []string{p.DefaultText}
}
p.TextStyle.Print(text[0] + " " + p.getSuffix() + p.Delimiter)
err := keyboard.Listen(func(keyInfo keys.Key) (stop bool, err error) {
if err != nil {
return false, fmt.Errorf("failed to get key: %w", err)
}
key := keyInfo.Code
char := keyInfo.String()
switch key {
case keys.RuneKey:
for i, c := range p.Handles {
if !p.ShowShortHandles {
c = string([]rune(c)[0])
}
if char == c || (i == p.DefaultValueIndex && strings.EqualFold(c, char)) {
p.OptionsStyle.Print(p.Options[i])
Println()
result = p.Options[i]
return true, nil
}
}
case keys.Enter:
p.OptionsStyle.Print(p.Options[p.DefaultValueIndex])
Println()
result = p.Options[p.DefaultValueIndex]
return true, nil
case keys.CtrlC:
internal.Exit(1)
return true, nil
}
return false, nil
})
cursor.StartOfLine()
return result, err
}
// getShortHandles returns the short hand answers for the continueation prompt
func (p InteractiveContinuePrinter) getShortHandles() []string {
var handles []string
for _, option := range p.Options {
handles = append(handles, strings.ToLower(string([]rune(option)[0])))
}
handles[p.DefaultValueIndex] = strings.ToUpper(handles[p.DefaultValueIndex])
return handles
}
// setDefaultHandles initialises the handles
func (p *InteractiveContinuePrinter) setDefaultHandles() {
if p.ShowShortHandles {
p.Handles = p.getShortHandles()
}
if p.Handles == nil || len(p.Handles) == 0 {
p.Handles = make([]string, len(p.Options))
copy(p.Handles, p.Options)
p.Handles[p.DefaultValueIndex] = cases.Title(language.Und, cases.Compact).String(p.Handles[p.DefaultValueIndex])
}
}
// getSuffix returns the continuation prompt suffix
func (p *InteractiveContinuePrinter) getSuffix() string {
if p.Handles == nil || len(p.Handles) != len(p.Options) {
p.setDefaultHandles()
}
return p.SuffixStyle.Sprintf("[%s]", strings.Join(p.Handles, "/"))
}
|