forked from toolshed/abra
		
	
		
			
				
	
	
		
			155 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package survey
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"regexp"
 | 
						|
)
 | 
						|
 | 
						|
// Confirm is a regular text input that accept yes/no answers. Response type is a bool.
 | 
						|
type Confirm struct {
 | 
						|
	Renderer
 | 
						|
	Message string
 | 
						|
	Default bool
 | 
						|
	Help    string
 | 
						|
}
 | 
						|
 | 
						|
// data available to the templates when processing
 | 
						|
type ConfirmTemplateData struct {
 | 
						|
	Confirm
 | 
						|
	Answer   string
 | 
						|
	ShowHelp bool
 | 
						|
	Config   *PromptConfig
 | 
						|
}
 | 
						|
 | 
						|
// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
 | 
						|
var ConfirmQuestionTemplate = `
 | 
						|
{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
 | 
						|
{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
 | 
						|
{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
 | 
						|
{{- if .Answer}}
 | 
						|
  {{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
 | 
						|
{{- else }}
 | 
						|
  {{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ .Config.HelpInput }} for help]{{color "reset"}} {{end}}
 | 
						|
  {{- color "white"}}{{if .Default}}(Y/n) {{else}}(y/N) {{end}}{{color "reset"}}
 | 
						|
{{- end}}`
 | 
						|
 | 
						|
// the regex for answers
 | 
						|
var (
 | 
						|
	yesRx = regexp.MustCompile("^(?i:y(?:es)?)$")
 | 
						|
	noRx  = regexp.MustCompile("^(?i:n(?:o)?)$")
 | 
						|
)
 | 
						|
 | 
						|
func yesNo(t bool) string {
 | 
						|
	if t {
 | 
						|
		return "Yes"
 | 
						|
	}
 | 
						|
	return "No"
 | 
						|
}
 | 
						|
 | 
						|
func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) {
 | 
						|
	cursor := c.NewCursor()
 | 
						|
	rr := c.NewRuneReader()
 | 
						|
	_ = rr.SetTermMode()
 | 
						|
	defer func() {
 | 
						|
		_ = rr.RestoreTermMode()
 | 
						|
	}()
 | 
						|
 | 
						|
	// start waiting for input
 | 
						|
	for {
 | 
						|
		line, err := rr.ReadLine(0)
 | 
						|
		if err != nil {
 | 
						|
			return false, err
 | 
						|
		}
 | 
						|
		// move back up a line to compensate for the \n echoed from terminal
 | 
						|
		cursor.PreviousLine(1)
 | 
						|
		val := string(line)
 | 
						|
 | 
						|
		// get the answer that matches the
 | 
						|
		var answer bool
 | 
						|
		switch {
 | 
						|
		case yesRx.Match([]byte(val)):
 | 
						|
			answer = true
 | 
						|
		case noRx.Match([]byte(val)):
 | 
						|
			answer = false
 | 
						|
		case val == "":
 | 
						|
			answer = c.Default
 | 
						|
		case val == config.HelpInput && c.Help != "":
 | 
						|
			err := c.Render(
 | 
						|
				ConfirmQuestionTemplate,
 | 
						|
				ConfirmTemplateData{
 | 
						|
					Confirm:  *c,
 | 
						|
					ShowHelp: true,
 | 
						|
					Config:   config,
 | 
						|
				},
 | 
						|
			)
 | 
						|
			if err != nil {
 | 
						|
				// use the default value and bubble up
 | 
						|
				return c.Default, err
 | 
						|
			}
 | 
						|
			showHelp = true
 | 
						|
			continue
 | 
						|
		default:
 | 
						|
			// we didnt get a valid answer, so print error and prompt again
 | 
						|
			//lint:ignore ST1005 it should be fine for this error message to have punctuation
 | 
						|
			if err := c.Error(config, fmt.Errorf("%q is not a valid answer, please try again.", val)); err != nil {
 | 
						|
				return c.Default, err
 | 
						|
			}
 | 
						|
			err := c.Render(
 | 
						|
				ConfirmQuestionTemplate,
 | 
						|
				ConfirmTemplateData{
 | 
						|
					Confirm:  *c,
 | 
						|
					ShowHelp: showHelp,
 | 
						|
					Config:   config,
 | 
						|
				},
 | 
						|
			)
 | 
						|
			if err != nil {
 | 
						|
				// use the default value and bubble up
 | 
						|
				return c.Default, err
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		return answer, nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
Prompt prompts the user with a simple text field and expects a reply followed
 | 
						|
by a carriage return.
 | 
						|
 | 
						|
	likesPie := false
 | 
						|
	prompt := &survey.Confirm{ Message: "What is your name?" }
 | 
						|
	survey.AskOne(prompt, &likesPie)
 | 
						|
*/
 | 
						|
func (c *Confirm) Prompt(config *PromptConfig) (interface{}, error) {
 | 
						|
	// render the question template
 | 
						|
	err := c.Render(
 | 
						|
		ConfirmQuestionTemplate,
 | 
						|
		ConfirmTemplateData{
 | 
						|
			Confirm: *c,
 | 
						|
			Config:  config,
 | 
						|
		},
 | 
						|
	)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	// get input and return
 | 
						|
	return c.getBool(false, config)
 | 
						|
}
 | 
						|
 | 
						|
// Cleanup overwrite the line with the finalized formatted version
 | 
						|
func (c *Confirm) Cleanup(config *PromptConfig, val interface{}) error {
 | 
						|
	// if the value was previously true
 | 
						|
	ans := yesNo(val.(bool))
 | 
						|
 | 
						|
	// render the template
 | 
						|
	return c.Render(
 | 
						|
		ConfirmQuestionTemplate,
 | 
						|
		ConfirmTemplateData{
 | 
						|
			Confirm: *c,
 | 
						|
			Answer:  ans,
 | 
						|
			Config:  config,
 | 
						|
		},
 | 
						|
	)
 | 
						|
}
 |