/confirm.go

https://github.com/AlecAivazis/survey · Go · 153 lines · 116 code · 13 blank · 24 comment · 18 complexity · bb72375e77fe1bd3344f047511d57aa8 MD5 · raw file

  1. package survey
  2. import (
  3. "fmt"
  4. "regexp"
  5. )
  6. // Confirm is a regular text input that accept yes/no answers. Response type is a bool.
  7. type Confirm struct {
  8. Renderer
  9. Message string
  10. Default bool
  11. Help string
  12. }
  13. // data available to the templates when processing
  14. type ConfirmTemplateData struct {
  15. Confirm
  16. Answer string
  17. ShowHelp bool
  18. Config *PromptConfig
  19. }
  20. // Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
  21. var ConfirmQuestionTemplate = `
  22. {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
  23. {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{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"}}[{{ .Config.HelpInput }} 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, config *PromptConfig) (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 == config.HelpInput && c.Help != "":
  66. err := c.Render(
  67. ConfirmQuestionTemplate,
  68. ConfirmTemplateData{
  69. Confirm: *c,
  70. ShowHelp: true,
  71. Config: config,
  72. },
  73. )
  74. if err != nil {
  75. // use the default value and bubble up
  76. return c.Default, err
  77. }
  78. showHelp = true
  79. continue
  80. default:
  81. // we didnt get a valid answer, so print error and prompt again
  82. if err := c.Error(config, fmt.Errorf("%q is not a valid answer, please try again.", val)); err != nil {
  83. return c.Default, err
  84. }
  85. err := c.Render(
  86. ConfirmQuestionTemplate,
  87. ConfirmTemplateData{
  88. Confirm: *c,
  89. ShowHelp: showHelp,
  90. Config: config,
  91. },
  92. )
  93. if err != nil {
  94. // use the default value and bubble up
  95. return c.Default, err
  96. }
  97. continue
  98. }
  99. return answer, nil
  100. }
  101. // should not get here
  102. return c.Default, nil
  103. }
  104. /*
  105. Prompt prompts the user with a simple text field and expects a reply followed
  106. by a carriage return.
  107. likesPie := false
  108. prompt := &survey.Confirm{ Message: "What is your name?" }
  109. survey.AskOne(prompt, &likesPie)
  110. */
  111. func (c *Confirm) Prompt(config *PromptConfig) (interface{}, error) {
  112. // render the question template
  113. err := c.Render(
  114. ConfirmQuestionTemplate,
  115. ConfirmTemplateData{
  116. Confirm: *c,
  117. Config: config,
  118. },
  119. )
  120. if err != nil {
  121. return "", err
  122. }
  123. // get input and return
  124. return c.getBool(false, config)
  125. }
  126. // Cleanup overwrite the line with the finalized formatted version
  127. func (c *Confirm) Cleanup(config *PromptConfig, val interface{}) error {
  128. // if the value was previously true
  129. ans := yesNo(val.(bool))
  130. // render the template
  131. return c.Render(
  132. ConfirmQuestionTemplate,
  133. ConfirmTemplateData{
  134. Confirm: *c,
  135. Answer: ans,
  136. Config: config,
  137. },
  138. )
  139. }