confirm.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package survey
  2. import (
  3. "fmt"
  4. "regexp"
  5. "gopkg.in/AlecAivazis/survey.v1/core"
  6. )
  7. // Confirm is a regular text input that accept yes/no answers. Response type is a bool.
  8. type Confirm struct {
  9. core.Renderer
  10. Message string
  11. Default bool
  12. Help string
  13. }
  14. // data available to the templates when processing
  15. type ConfirmTemplateData struct {
  16. Confirm
  17. Answer string
  18. ShowHelp bool
  19. }
  20. // Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
  21. var ConfirmQuestionTemplate = `
  22. {{- if .ShowHelp }}{{- color "cyan"}}{{ HelpIcon }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
  23. {{- color "green+hb"}}{{ QuestionIcon }} {{color "reset"}}
  24. {{- color "default+hb"}}{{ .Message }} {{color "reset"}}
  25. {{- if .Answer}}
  26. {{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
  27. {{- else }}
  28. {{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ HelpInputRune }} for help]{{color "reset"}} {{end}}
  29. {{- color "white"}}{{if .Default}}(Y/n) {{else}}(y/N) {{end}}{{color "reset"}}
  30. {{- end}}`
  31. // the regex for answers
  32. var (
  33. yesRx = regexp.MustCompile("^(?i:y(?:es)?)$")
  34. noRx = regexp.MustCompile("^(?i:n(?:o)?)$")
  35. )
  36. func yesNo(t bool) string {
  37. if t {
  38. return "Yes"
  39. }
  40. return "No"
  41. }
  42. func (c *Confirm) getBool(showHelp bool) (bool, error) {
  43. cursor := c.NewCursor()
  44. rr := c.NewRuneReader()
  45. rr.SetTermMode()
  46. defer rr.RestoreTermMode()
  47. // start waiting for input
  48. for {
  49. line, err := rr.ReadLine(0)
  50. if err != nil {
  51. return false, err
  52. }
  53. // move back up a line to compensate for the \n echoed from terminal
  54. cursor.PreviousLine(1)
  55. val := string(line)
  56. // get the answer that matches the
  57. var answer bool
  58. switch {
  59. case yesRx.Match([]byte(val)):
  60. answer = true
  61. case noRx.Match([]byte(val)):
  62. answer = false
  63. case val == "":
  64. answer = c.Default
  65. case val == string(core.HelpInputRune) && c.Help != "":
  66. err := c.Render(
  67. ConfirmQuestionTemplate,
  68. ConfirmTemplateData{Confirm: *c, ShowHelp: true},
  69. )
  70. if err != nil {
  71. // use the default value and bubble up
  72. return c.Default, err
  73. }
  74. showHelp = true
  75. continue
  76. default:
  77. // we didnt get a valid answer, so print error and prompt again
  78. if err := c.Error(fmt.Errorf("%q is not a valid answer, please try again.", val)); err != nil {
  79. return c.Default, err
  80. }
  81. err := c.Render(
  82. ConfirmQuestionTemplate,
  83. ConfirmTemplateData{Confirm: *c, ShowHelp: showHelp},
  84. )
  85. if err != nil {
  86. // use the default value and bubble up
  87. return c.Default, err
  88. }
  89. continue
  90. }
  91. return answer, nil
  92. }
  93. // should not get here
  94. return c.Default, nil
  95. }
  96. /*
  97. Prompt prompts the user with a simple text field and expects a reply followed
  98. by a carriage return.
  99. likesPie := false
  100. prompt := &survey.Confirm{ Message: "What is your name?" }
  101. survey.AskOne(prompt, &likesPie, nil)
  102. */
  103. func (c *Confirm) Prompt() (interface{}, error) {
  104. // render the question template
  105. err := c.Render(
  106. ConfirmQuestionTemplate,
  107. ConfirmTemplateData{Confirm: *c},
  108. )
  109. if err != nil {
  110. return "", err
  111. }
  112. // get input and return
  113. return c.getBool(false)
  114. }
  115. // Cleanup overwrite the line with the finalized formatted version
  116. func (c *Confirm) Cleanup(val interface{}) error {
  117. // if the value was previously true
  118. ans := yesNo(val.(bool))
  119. // render the template
  120. return c.Render(
  121. ConfirmQuestionTemplate,
  122. ConfirmTemplateData{Confirm: *c, Answer: ans},
  123. )
  124. }