Repository: AlecAivazis/survey (go)

Issue:
"space to select" doesn't apply to survey.Select
`survey.Select` has this `SelectQuestionTemplate` which says:

![image](https://user-images.githubusercontent.com/159209/58765259-0d4e5680-8526-11e9-8484-f27e9621e39b.png)

but "space to select" is actually not an option here. I think it's meant to work only for `survey.MultiSelect`. Hitting space here works does "type to filter".

Pull request description:
Fix help message for Select
Fixes #218.

Patch:
diff --git a/README.md b/README.md
index 5ac53ff..823ce05 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,6 @@
 
 A library for building interactive prompts.
 
-
 <img width="550" src="https://thumbs.gfycat.com/VillainousGraciousKouprey-size_restricted.gif"/>
 
 ```go
@@ -57,7 +56,7 @@ func main() {
 }
 ```
 
-*NOTE*: This page describes the API for the upcoming `v2` release which has not been made available yet. For documentation
+_NOTE_: This page describes the API for the upcoming `v2` release which has not been made available yet. For documentation
 for the old `v1` version, see [here](https://godoc.org/gopkg.in/AlecAivazis/survey.v1).
 
 ## Table of Contents
@@ -104,7 +103,7 @@ name := ""
 prompt := &survey.Input{
     Message: "ping",
 }
-survey.AskOne(prompt, &name, nil)
+survey.AskOne(prompt, &name)
 ```
 
 ### Multiline
@@ -116,7 +115,7 @@ text := ""
 prompt := &survey.Multiline{
     Message: "ping",
 }
-survey.AskOne(prompt, &text, nil)
+survey.AskOne(prompt, &text)
 ```
 
 ### Password
@@ -128,7 +127,7 @@ password := ""
 prompt := &survey.Password{
     Message: "Please type your password",
 }
-survey.AskOne(prompt, &password, nil)
+survey.AskOne(prompt, &password)
 ```
 
 ### Confirm
@@ -140,7 +139,7 @@ name := false
 prompt := &survey.Confirm{
     Message: "Do you like pie?",
 }
-survey.AskOne(prompt, &name, nil)
+survey.AskOne(prompt, &name)
 ```
 
 ### Select
@@ -153,7 +152,7 @@ prompt := &survey.Select{
     Message: "Choose a color:",
     Options: []string{"red", "blue", "green"},
 }
-survey.AskOne(prompt, &color, nil)
+survey.AskOne(prompt, &color)
 ```
 
 The user can also press `esc` to toggle the ability cycle through the options with the j and k keys to do down and up respectively.
@@ -176,7 +175,7 @@ prompt := &survey.MultiSelect{
     Message: "What days do you prefer:",
     Options: []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},
 }
-survey.AskOne(prompt, &days, nil)
+survey.AskOne(prompt, &days)
 ```
 
 The user can also press `esc` to toggle the ability cycle through the options with the j and k keys to do down and up respectively.
@@ -241,6 +240,16 @@ q := &survey.Question{
 }
 ```
 
+Validators can be passed to `survey.AskOne` by using `survey.WithValidator`:
+
+```golang
+color := ""
+prompt := &survey.Input{ Message: "Whats your name?" }
+
+// you can pass multiple validators here and survey will make sure each one passes
+survey.AskOne(prompt, &color, survey.WithValidator(survey.Required))
+```
+
 ### Built-in Validators
 
 `survey` comes prepackaged with a few validators to fit common situations. Currently these
@@ -284,7 +293,7 @@ prompt := &survey.Input{
 
 surveyCore.HelpInputRune = '^'
 
-survey.AskOne(prompt, &number, nil)
+survey.AskOne(prompt, &number)
 ```
 
 ## Custom Types
diff --git a/confirm.go b/confirm.go
index d19813c..8a74125 100644
--- a/confirm.go
+++ b/confirm.go
@@ -110,7 +110,7 @@ by a carriage return.
 
 	likesPie := false
 	prompt := &survey.Confirm{ Message: "What is your name?" }
-	survey.AskOne(prompt, &likesPie, nil)
+	survey.AskOne(prompt, &likesPie)
 */
 func (c *Confirm) Prompt() (interface{}, error) {
 	// render the question template
diff --git a/core/template.go b/core/template.go
index 7a3a190..cdbafa8 100644
--- a/core/template.go
+++ b/core/template.go
@@ -33,23 +33,6 @@ var (
 	SelectFocusIcon = ">"
 )
 
-/*
-  SetFancyIcons changes the err, help, marked, and focus input icons to their
-  fancier forms. These forms may not be compatible with most terminals.
-  This function will not touch the QuestionIcon as its fancy and non fancy form
-  are the same.
-*/
-func SetFancyIcons() {
-	ErrorIcon = "✘"
-	HelpIcon = "ⓘ"
-	// QuestionIcon fancy and non-fancy form are the same
-
-	MarkedOptionIcon = "◉"
-	UnmarkedOptionIcon = "◯"
-
-	SelectFocusIcon = "❯"
-}
-
 var TemplateFuncs = map[string]interface{}{
 	// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
 	"color": func(color string) string {
diff --git a/editor.go b/editor.go
index facf1a8..ccd20ac 100644
--- a/editor.go
+++ b/editor.go
@@ -23,7 +23,7 @@ Response type is a string.
 
 	message := ""
 	prompt := &survey.Editor{ Message: "What is your commit message?" }
-	survey.AskOne(prompt, &message, nil)
+	survey.AskOne(prompt, &message)
 */
 type Editor struct {
 	core.Renderer
diff --git a/input.go b/input.go
index 3086e27..8d4bf5d 100644
--- a/input.go
+++ b/input.go
@@ -10,7 +10,7 @@ and accepts the input with the enter key. Response type is a string.
 
 	name := ""
 	prompt := &survey.Input{ Message: "What is your name?" }
-	survey.AskOne(prompt, &name, nil)
+	survey.AskOne(prompt, &name)
 */
 type Input struct {
 	core.Renderer
diff --git a/multiselect.go b/multiselect.go
index 5045d24..ada15e1 100644
--- a/multiselect.go
+++ b/multiselect.go
@@ -17,7 +17,7 @@ for them to select using the arrow keys and enter. Response type is a slice of s
 		Message: "What days do you prefer:",
 		Options: []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},
 	}
-	survey.AskOne(prompt, &days, nil)
+	survey.AskOne(prompt, &days)
 */
 type MultiSelect struct {
 	core.Renderer
diff --git a/password.go b/password.go
index ec438b1..91473dc 100644
--- a/password.go
+++ b/password.go
@@ -13,7 +13,7 @@ type is a string.
 
 	password := ""
 	prompt := &survey.Password{ Message: "Please type your password" }
-	survey.AskOne(prompt, &password, nil)
+	survey.AskOne(prompt, &password)
 */
 type Password struct {
 	core.Renderer
diff --git a/select.go b/select.go
index edb07f7..0fc0000 100644
--- a/select.go
+++ b/select.go
@@ -16,7 +16,7 @@ for them to select using the arrow keys and enter. Response type is a string.
 		Message: "Choose a color:",
 		Options: []string{"red", "blue", "green"},
 	}
-	survey.AskOne(prompt, &color, nil)
+	survey.AskOne(prompt, &color)
 */
 type Select struct {
 	core.Renderer
@@ -50,7 +50,7 @@ var SelectQuestionTemplate = `
 {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}}
 {{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}}
 {{- else}}
-  {{- "  "}}{{- color "cyan"}}[Use arrows to move, space to select, type to filter{{- if and .Help (not .ShowHelp)}}, {{ HelpInputRune }} for more help{{end}}]{{color "reset"}}
+  {{- "  "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ HelpInputRune }} for more help{{end}}]{{color "reset"}}
   {{- "\n"}}
   {{- range $ix, $choice := .PageEntries}}
     {{- if eq $ix $.SelectedIndex}}{{color "cyan+b"}}{{ SelectFocusIcon }} {{else}}{{color "default+hb"}}  {{end}}
diff --git a/survey.go b/survey.go
index 9ca1601..b456123 100644
--- a/survey.go
+++ b/survey.go
@@ -59,7 +59,8 @@ type AskOpt func(options *AskOptions) error
 
 // AskOptions provides additional options on ask.
 type AskOptions struct {
-	Stdio terminal.Stdio
+	Stdio      terminal.Stdio
+	Validators []Validator
 }
 
 // WithStdio specifies the standard input, output and error files survey
@@ -73,6 +74,17 @@ func WithStdio(in terminal.FileReader, out terminal.FileWriter, err io.Writer) A
 	}
 }
 
+// WithValidator specifies a validator to use while prompting the user
+func WithValidator(v Validator) AskOpt {
+	return func(options *AskOptions) error {
+		// add the provided validator to the list
+		options.Validators = append(options.Validators, v)
+
+		// nothing went wrong
+		return nil
+	}
+}
+
 type wantsStdio interface {
 	WithStdio(terminal.Stdio)
 }
@@ -87,11 +99,11 @@ in the documentation. For example:
 		Message: "name",
 	}
 
-	survey.AskOne(prompt, &name, nil)
+	survey.AskOne(prompt, &name)
 
 */
-func AskOne(p Prompt, response interface{}, v Validator, opts ...AskOpt) error {
-	err := Ask([]*Question{{Prompt: p, Validate: v}}, response, opts...)
+func AskOne(p Prompt, response interface{}, opts ...AskOpt) error {
+	err := Ask([]*Question{{Prompt: p}}, response, opts...)
 	if err != nil {
 		return err
 	}
@@ -123,7 +135,7 @@ matching name. For example:
 	err := survey.Ask(qs, &answers)
 */
 func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
-
+	// build up the configuration options
 	options := DefaultAskOptions
 	for _, opt := range opts {
 		if err := opt(&options); err != nil {
@@ -151,10 +163,22 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
 			return err
 		}
 
-		// if there is a validate handler for this question
+		// build up a list of validators that we have to apply to this question
+		validators := []Validator{}
+
+		// make sure to include the question specific one
 		if q.Validate != nil {
+			validators = append(validators, q.Validate)
+		}
+		// add any "global" validators
+		for _, validator := range options.Validators {
+			validators = append(validators, validator)
+		}
+
+		// apply every validator to thte response
+		for _, validator := range validators {
 			// wait for a valid response
-			for invalid := q.Validate(ans); invalid != nil; invalid = q.Validate(ans) {
+			for invalid := validator(ans); invalid != nil; invalid = validator(ans) {
 				err := q.Prompt.Error(invalid)
 				// if there was a problem
 				if err != nil {


Test patch:
diff --git a/select_test.go b/select_test.go
index 913b739..57e6b28 100644
--- a/select_test.go
+++ b/select_test.go
@@ -43,7 +43,7 @@ func TestSelectRender(t *testing.T) {
 			SelectTemplateData{SelectedIndex: 2, PageEntries: prompt.Options},
 			strings.Join(
 				[]string{
-					fmt.Sprintf("%s Pick your word:  [Use arrows to move, space to select, type to filter]", core.QuestionIcon),
+					fmt.Sprintf("%s Pick your word:  [Use arrows to move, type to filter]", core.QuestionIcon),
 					"  foo",
 					"  bar",
 					fmt.Sprintf("%s baz", core.SelectFocusIcon),
@@ -64,7 +64,7 @@ func TestSelectRender(t *testing.T) {
 			SelectTemplateData{SelectedIndex: 2, PageEntries: prompt.Options},
 			strings.Join(
 				[]string{
-					fmt.Sprintf("%s Pick your word:  [Use arrows to move, space to select, type to filter, %s for more help]", core.QuestionIcon, string(core.HelpInputRune)),
+					fmt.Sprintf("%s Pick your word:  [Use arrows to move, type to filter, %s for more help]", core.QuestionIcon, string(core.HelpInputRune)),
 					"  foo",
 					"  bar",
 					fmt.Sprintf("%s baz", core.SelectFocusIcon),
@@ -80,7 +80,7 @@ func TestSelectRender(t *testing.T) {
 			strings.Join(
 				[]string{
 					fmt.Sprintf("%s This is helpful", core.HelpIcon),
-					fmt.Sprintf("%s Pick your word:  [Use arrows to move, space to select, type to filter]", core.QuestionIcon),
+					fmt.Sprintf("%s Pick your word:  [Use arrows to move, type to filter]", core.QuestionIcon),
 					"  foo",
 					"  bar",
 					fmt.Sprintf("%s baz", core.SelectFocusIcon),
diff --git a/survey_test.go b/survey_test.go
index b482542..fe02056 100644
--- a/survey_test.go
+++ b/survey_test.go
@@ -151,7 +151,7 @@ func TestAsk(t *testing.T) {
 				c.SendLine("")
 
 				// Select
-				c.ExpectString("Choose a color:  [Use arrows to move, space to select, type to filter]")
+				c.ExpectString("Choose a color:  [Use arrows to move, type to filter]")
 				c.SendLine("yellow")
 				c.ExpectEOF()
 			},
diff --git a/tests/ask.go b/tests/ask.go
index 3a5797a..aa8f2f6 100644
--- a/tests/ask.go
+++ b/tests/ask.go
@@ -42,7 +42,7 @@ func main() {
 
 	fmt.Println("Asking one.")
 	answer := ""
-	err = survey.AskOne(simpleQs[0].Prompt, &answer, nil)
+	err = survey.AskOne(simpleQs[0].Prompt, &answer)
 	if err != nil {
 		fmt.Println(err.Error())
 		return
@@ -51,7 +51,7 @@ func main() {
 
 	fmt.Println("Asking one with validation.")
 	vAns := ""
-	err = survey.AskOne(&survey.Input{Message: "What is your name?"}, &vAns, survey.Required)
+	err = survey.AskOne(&survey.Input{Message: "What is your name?"}, &vAns, survey.WithValidator(survey.Required))
 	if err != nil {
 		fmt.Println(err.Error())
 		return
diff --git a/tests/longSelect.go b/tests/longSelect.go
index c40a618..325681b 100644
--- a/tests/longSelect.go
+++ b/tests/longSelect.go
@@ -19,5 +19,5 @@ func main() {
 			"j",
 		},
 	}
-	survey.AskOne(prompt, &color, nil)
+	survey.AskOne(prompt, &color)
 }
diff --git a/tests/util/test.go b/tests/util/test.go
index 1ce209d..453d349 100644
--- a/tests/util/test.go
+++ b/tests/util/test.go
@@ -26,7 +26,7 @@ func RunTable(table []TestTableEntry) {
 		// tell the user what we are going to ask them
 		fmt.Println(entry.Name)
 		// perform the ask
-		err := survey.AskOne(entry.Prompt, entry.Value, entry.Validate)
+		err := survey.AskOne(entry.Prompt, entry.Value, survey.WithValidator(entry.Validate))
 		if err != nil {
 			fmt.Printf("AskOne on %v's prompt failed: %v.", entry.Name, err.Error())
 			break
@@ -42,7 +42,7 @@ func RunErrorTable(table []TestTableEntry) {
 		// tell the user what we are going to ask them
 		fmt.Println(entry.Name)
 		// perform the ask
-		err := survey.AskOne(entry.Prompt, entry.Value, entry.Validate)
+		err := survey.AskOne(entry.Prompt, entry.Value, survey.WithValidator(entry.Validate))
 		if err == nil {
 			fmt.Printf("AskOne on %v's prompt didn't fail.", entry.Name)
 			break