summaryrefslogtreecommitdiff
path: root/vendor/github.com/manifoldco/promptui/prompt.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/manifoldco/promptui/prompt.go')
-rw-r--r--vendor/github.com/manifoldco/promptui/prompt.go341
1 files changed, 341 insertions, 0 deletions
diff --git a/vendor/github.com/manifoldco/promptui/prompt.go b/vendor/github.com/manifoldco/promptui/prompt.go
new file mode 100644
index 000000000..8e35123b0
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/prompt.go
@@ -0,0 +1,341 @@
+package promptui
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "text/template"
+
+ "github.com/chzyer/readline"
+ "github.com/manifoldco/promptui/screenbuf"
+)
+
+// Prompt represents a single line text field input with options for validation and input masks.
+type Prompt struct {
+ // Label is the value displayed on the command line prompt.
+ //
+ // The value for Label can be a simple string or a struct that will need to be accessed by dot notation
+ // inside the templates. For example, `{{ .Name }}` will display the name property of a struct.
+ Label interface{}
+
+ // Default is the initial value for the prompt. This value will be displayed next to the prompt's label
+ // and the user will be able to view or change it depending on the options.
+ Default string
+
+ // AllowEdit lets the user edit the default value. If false, any key press
+ // other than <Enter> automatically clears the default value.
+ AllowEdit bool
+
+ // Validate is an optional function that fill be used against the entered value in the prompt to validate it.
+ Validate ValidateFunc
+
+ // Mask is an optional rune that sets which character to display instead of the entered characters. This
+ // allows hiding private information like passwords.
+ Mask rune
+
+ // HideEntered sets whether to hide the text after the user has pressed enter.
+ HideEntered bool
+
+ // Templates can be used to customize the prompt output. If nil is passed, the
+ // default templates are used. See the PromptTemplates docs for more info.
+ Templates *PromptTemplates
+
+ // IsConfirm makes the prompt ask for a yes or no ([Y/N]) question rather than request an input. When set,
+ // most properties related to input will be ignored.
+ IsConfirm bool
+
+ // IsVimMode enables vi-like movements (hjkl) and editing.
+ IsVimMode bool
+
+ // the Pointer defines how to render the cursor.
+ Pointer Pointer
+
+ Stdin io.ReadCloser
+ Stdout io.WriteCloser
+}
+
+// PromptTemplates allow a prompt to be customized following stdlib
+// text/template syntax. Custom state, colors and background color are available for use inside
+// the templates and are documented inside the Variable section of the docs.
+//
+// Examples
+//
+// text/templates use a special notation to display programmable content. Using the double bracket notation,
+// the value can be printed with specific helper functions. For example
+//
+// This displays the value given to the template as pure, unstylized text.
+// '{{ . }}'
+//
+// This displays the value colored in cyan
+// '{{ . | cyan }}'
+//
+// This displays the value colored in red with a cyan background-color
+// '{{ . | red | cyan }}'
+//
+// See the doc of text/template for more info: https://golang.org/pkg/text/template/
+type PromptTemplates struct {
+ // Prompt is a text/template for the prompt label displayed on the left side of the prompt.
+ Prompt string
+
+ // Prompt is a text/template for the prompt label when IsConfirm is set as true.
+ Confirm string
+
+ // Valid is a text/template for the prompt label when the value entered is valid.
+ Valid string
+
+ // Invalid is a text/template for the prompt label when the value entered is invalid.
+ Invalid string
+
+ // Success is a text/template for the prompt label when the user has pressed entered and the value has been
+ // deemed valid by the validation function. The label will keep using this template even when the prompt ends
+ // inside the console.
+ Success string
+
+ // Prompt is a text/template for the prompt label when the value is invalid due to an error triggered by
+ // the prompt's validation function.
+ ValidationError string
+
+ // FuncMap is a map of helper functions that can be used inside of templates according to the text/template
+ // documentation.
+ //
+ // By default, FuncMap contains the color functions used to color the text in templates. If FuncMap
+ // is overridden, the colors functions must be added in the override from promptui.FuncMap to work.
+ FuncMap template.FuncMap
+
+ prompt *template.Template
+ valid *template.Template
+ invalid *template.Template
+ validation *template.Template
+ success *template.Template
+}
+
+// Run executes the prompt. Its displays the label and default value if any, asking the user to enter a value.
+// Run will keep the prompt alive until it has been canceled from the command prompt or it has received a valid
+// value. It will return the value and an error if any occurred during the prompt's execution.
+func (p *Prompt) Run() (string, error) {
+ var err error
+
+ err = p.prepareTemplates()
+ if err != nil {
+ return "", err
+ }
+
+ c := &readline.Config{
+ Stdin: p.Stdin,
+ Stdout: p.Stdout,
+ EnableMask: p.Mask != 0,
+ MaskRune: p.Mask,
+ HistoryLimit: -1,
+ VimMode: p.IsVimMode,
+ UniqueEditLine: true,
+ }
+
+ err = c.Init()
+ if err != nil {
+ return "", err
+ }
+
+ rl, err := readline.NewEx(c)
+ if err != nil {
+ return "", err
+ }
+ // we're taking over the cursor, so stop showing it.
+ rl.Write([]byte(hideCursor))
+ sb := screenbuf.New(rl)
+
+ validFn := func(x string) error {
+ return nil
+ }
+ if p.Validate != nil {
+ validFn = p.Validate
+ }
+
+ var inputErr error
+ input := p.Default
+ if p.IsConfirm {
+ input = ""
+ }
+ eraseDefault := input != "" && !p.AllowEdit
+ cur := NewCursor(input, p.Pointer, eraseDefault)
+
+ listen := func(input []rune, pos int, key rune) ([]rune, int, bool) {
+ _, _, keepOn := cur.Listen(input, pos, key)
+ err := validFn(cur.Get())
+ var prompt []byte
+
+ if err != nil {
+ prompt = render(p.Templates.invalid, p.Label)
+ } else {
+ prompt = render(p.Templates.valid, p.Label)
+ if p.IsConfirm {
+ prompt = render(p.Templates.prompt, p.Label)
+ }
+ }
+
+ echo := cur.Format()
+ if p.Mask != 0 {
+ echo = cur.FormatMask(p.Mask)
+ }
+
+ prompt = append(prompt, []byte(echo)...)
+ sb.Reset()
+ sb.Write(prompt)
+ if inputErr != nil {
+ validation := render(p.Templates.validation, inputErr)
+ sb.Write(validation)
+ inputErr = nil
+ }
+ sb.Flush()
+ return nil, 0, keepOn
+ }
+
+ c.SetListener(listen)
+
+ for {
+ _, err = rl.Readline()
+ inputErr = validFn(cur.Get())
+ if inputErr == nil {
+ break
+ }
+
+ if err != nil {
+ break
+ }
+ }
+
+ if err != nil {
+ switch err {
+ case readline.ErrInterrupt:
+ err = ErrInterrupt
+ case io.EOF:
+ err = ErrEOF
+ }
+ if err.Error() == "Interrupt" {
+ err = ErrInterrupt
+ }
+ sb.Reset()
+ sb.WriteString("")
+ sb.Flush()
+ rl.Write([]byte(showCursor))
+ rl.Close()
+ return "", err
+ }
+
+ echo := cur.Get()
+ if p.Mask != 0 {
+ echo = cur.GetMask(p.Mask)
+ }
+
+ prompt := render(p.Templates.success, p.Label)
+ prompt = append(prompt, []byte(echo)...)
+
+ if p.IsConfirm {
+ lowerDefault := strings.ToLower(p.Default)
+ if strings.ToLower(cur.Get()) != "y" && (lowerDefault != "y" || (lowerDefault == "y" && cur.Get() != "")) {
+ prompt = render(p.Templates.invalid, p.Label)
+ err = ErrAbort
+ }
+ }
+
+ if p.HideEntered {
+ clearScreen(sb)
+ } else {
+ sb.Reset()
+ sb.Write(prompt)
+ sb.Flush()
+ }
+
+ rl.Write([]byte(showCursor))
+ rl.Close()
+
+ return cur.Get(), err
+}
+
+func (p *Prompt) prepareTemplates() error {
+ tpls := p.Templates
+ if tpls == nil {
+ tpls = &PromptTemplates{}
+ }
+
+ if tpls.FuncMap == nil {
+ tpls.FuncMap = FuncMap
+ }
+
+ bold := Styler(FGBold)
+
+ if p.IsConfirm {
+ if tpls.Confirm == "" {
+ confirm := "y/N"
+ if strings.ToLower(p.Default) == "y" {
+ confirm = "Y/n"
+ }
+ tpls.Confirm = fmt.Sprintf(`{{ "%s" | bold }} {{ . | bold }}? {{ "[%s]" | faint }} `, IconInitial, confirm)
+ }
+
+ tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Confirm)
+ if err != nil {
+ return err
+ }
+
+ tpls.prompt = tpl
+ } else {
+ if tpls.Prompt == "" {
+ tpls.Prompt = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconInitial), bold(":"))
+ }
+
+ tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Prompt)
+ if err != nil {
+ return err
+ }
+
+ tpls.prompt = tpl
+ }
+
+ if tpls.Valid == "" {
+ tpls.Valid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":"))
+ }
+
+ tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Valid)
+ if err != nil {
+ return err
+ }
+
+ tpls.valid = tpl
+
+ if tpls.Invalid == "" {
+ tpls.Invalid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconBad), bold(":"))
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Invalid)
+ if err != nil {
+ return err
+ }
+
+ tpls.invalid = tpl
+
+ if tpls.ValidationError == "" {
+ tpls.ValidationError = `{{ ">>" | red }} {{ . | red }}`
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.ValidationError)
+ if err != nil {
+ return err
+ }
+
+ tpls.validation = tpl
+
+ if tpls.Success == "" {
+ tpls.Success = fmt.Sprintf("{{ . | faint }}%s ", Styler(FGFaint)(":"))
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Success)
+ if err != nil {
+ return err
+ }
+
+ tpls.success = tpl
+
+ p.Templates = tpls
+
+ return nil
+}