Repository: AlecAivazis/survey (go)

Issue:
Add support for changing the color of the different runes/prompts
Creating a CLI with this currently and would be nice if I could change the color of the QuestionIcon application wide

Pull request description:
Icon format
This PR changes our handling of icons from a `String` to a `struct` with `Format` and `Text`. This lets the `WithIcon` option be used to change the color and formatting of the icon. I considered an API like what was suggested in #193 however since it would force the user to always set the color even if they just wanted to change the icon, I decided it was too cumbersome to use. 

example:
```golang
survey.AskOne(prompt, &number, survey.WithIcons(function(icons *survey.IconSet) {
    icons.Question.Text = "??"
    icons.Question.Format = "yellow+hb"
}))
```

Fixes #141 

Patch:
diff --git a/README.md b/README.md
index 8419b4f..d8ea4ad 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,7 @@ for the old `v1` version, see [here](https://godoc.org/gopkg.in/AlecAivazis/surv
 1. [Help Text](#help-text)
    1. [Changing the input rune](#changing-the-input-run)
 1. [Custom Types](#custom-types)
-1. [Customizing Output](#customizing-output)
+1. [Changing the Icons ](#changing-the-icons)
 1. [Testing](#testing)
 
 ## Examples
@@ -189,16 +189,13 @@ 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.
 
 By default, the select prompt is limited to showing 7 options at a time
-and will paginate lists of options longer than that. To increase, you can either
-set the `PageSize` field on the prompt:
+and will paginate lists of options longer than that. This can be changed a number of ways:
 
 ```golang
-prompt := &survey.Select{..., PageSize: 10}
-```
-
-Or pass an an `AskOpt` to `survey.Ask` or `survey.AskOne`:
+// as a field on a single select
+prompt := &survey.MultiSelect{..., PageSize: 10}
 
-```golang
+// or as an option to Ask or AskOne
 survey.AskOne(prompt, &days, survey.WithPageSize(10))
 ```
 
@@ -218,16 +215,13 @@ 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.
 
 By default, the MultiSelect prompt is limited to showing 7 options at a time
-and will paginate lists of options longer than that. To increase, you can either
-set the `PageSize` field on the prompt:
+and will paginate lists of options longer than that. This can be changed a number of ways:
 
 ```golang
+// as a field on a single select
 prompt := &survey.MultiSelect{..., PageSize: 10}
-```
-
-Or pass an an `AskOpt` to `survey.Ask` or `survey.AskOne`:
 
-```golang
+// or as an option to Ask or AskOne
 survey.AskOne(prompt, &days, survey.WithPageSize(10))
 ```
 
@@ -299,7 +293,7 @@ q := &survey.Question{
 }
 ```
 
-Validators can be passed to `survey.AskOne` by using `survey.WithValidator`:
+Validators can be provided with `survey.WithValidator`:
 
 ```golang
 color := ""
@@ -336,7 +330,7 @@ All of the prompts have a `Help` field which can be defined to provide more info
 ### Changing the input rune
 
 In some situations, `?` is a perfectly valid response. To handle this, you can change the rune that survey
-looks for by passing an `AskOpt` to `Ask` or `AskOne`:
+looks for with `WithHelpInput`:
 
 ```golang
 import (
@@ -382,10 +376,10 @@ survey.AskOne(
 )
 ```
 
-## Customizing Output
+## Changing the Icons
 
-Customizing the icons and various parts of survey can easily be done by passing the `WithIcons` option
-to `Ask` or `AskOne`:
+Changing the icons and their color/format can be done by passing the `WithIcons` option. The format
+follows the patterns outlined [here](https://github.com/mgutz/ansi#style-format).:
 
 ```golang
 import (
@@ -400,20 +394,22 @@ prompt := &survey.Input{
 
 survey.AskOne(prompt, &number, survey.WithIcons(function(icons *survey.IconSet) {
     // you can set any icons
-    icons.Question = "⁇"
+    icons.Question.Text = "⁇"
+    // for more information on formatting the icons, see here: https://github.com/mgutz/ansi#style-format
+    icons.Question.Format = "yellow+hb"
 }))
 ```
 
-The icons available for updating are:
+The icons and their default text and format are summarized below:
 
-| name           | default | description                                                   |
-| -------------- | ------- | ------------------------------------------------------------- |
-| Error          | X       | Before an error                                               |
-| Help           | i       | Before help text                                              |
-| Question       | ?       | Before the message of a prompt                                |
-| SelectFocus    | >       | Marks the current focus in `Select` and `MultiSelect` prompts |
-| UnmarkedOption | [ ]     | Marks an unselected option in a `MultiSelect` prompt          |
-| MarkedOption   | [x]     | Marks a chosen selection in a `MultiSelect` prompt            |
+| name           | text | format     | description                                                   |
+| -------------- | ---- | ---------- | ------------------------------------------------------------- |
+| Error          | X    | red        | Before an error                                               |
+| Help           | i    | cyan       | Before help text                                              |
+| Question       | ?    | green+hb   | Before the message of a prompt                                |
+| SelectFocus    | >    | green      | Marks the current focus in `Select` and `MultiSelect` prompts |
+| UnmarkedOption | [ ]  | default+hb | Marks an unselected option in a `MultiSelect` prompt          |
+| MarkedOption   | [x]  | cyan+b     | Marks a chosen selection in a `MultiSelect` prompt            |
 
 ## Testing
 
diff --git a/confirm.go b/confirm.go
index 9880835..8e5d7ef 100644
--- a/confirm.go
+++ b/confirm.go
@@ -23,8 +23,8 @@ type ConfirmTemplateData struct {
 
 // Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
 var ConfirmQuestionTemplate = `
-{{- if .ShowHelp }}{{- color "cyan"}}{{ .Config.Icons.Help }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
-{{- color "green+hb"}}{{ .Config.Icons.Question }} {{color "reset"}}
+{{- 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"}}
diff --git a/editor.go b/editor.go
index 1762df7..ec6a141 100644
--- a/editor.go
+++ b/editor.go
@@ -46,8 +46,8 @@ type EditorTemplateData struct {
 
 // Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
 var EditorQuestionTemplate = `
-{{- if .ShowHelp }}{{- color "cyan"}}{{ .Config.Icons.Help }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
-{{- color "green+hb"}}{{ .Config.Icons.Question }} {{color "reset"}}
+{{- 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 .ShowAnswer}}
   {{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
diff --git a/input.go b/input.go
index 993ba4a..958ce71 100644
--- a/input.go
+++ b/input.go
@@ -26,8 +26,8 @@ type InputTemplateData struct {
 
 // Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
 var InputQuestionTemplate = `
-{{- if .ShowHelp }}{{- color "cyan"}}{{ .Config.Icons.Help }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
-{{- color "green+hb"}}{{ .Config.Icons.Question }} {{color "reset"}}
+{{- 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 .ShowAnswer}}
   {{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
diff --git a/multiline.go b/multiline.go
index 9b0d165..8368705 100644
--- a/multiline.go
+++ b/multiline.go
@@ -24,8 +24,8 @@ type MultilineTemplateData struct {
 
 // Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
 var MultilineQuestionTemplate = `
-{{- if .ShowHelp }}{{- color "cyan"}}{{ .Config.Icons.Help }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
-{{- color "green+hb"}}{{ .Config.Icons.Question }} {{color "reset"}}
+{{- 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 .ShowAnswer}}
   {{- "\n"}}{{color "cyan"}}{{.Answer}}{{color "reset"}}
diff --git a/multiselect.go b/multiselect.go
index 66a3a75..ff88e02 100644
--- a/multiselect.go
+++ b/multiselect.go
@@ -47,16 +47,16 @@ type MultiSelectTemplateData struct {
 }
 
 var MultiSelectQuestionTemplate = `
-{{- if .ShowHelp }}{{- color "cyan"}}{{ .Config.Icons.Help }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
-{{- color "green+hb"}}{{ .Config.Icons.Question }} {{color "reset"}}
+{{- 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 }}{{ .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)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
   {{- "\n"}}
   {{- range $ix, $option := .PageEntries}}
-    {{- if eq $ix $.SelectedIndex }}{{color "cyan"}}{{ $.Config.Icons.SelectFocus }}{{color "reset"}}{{else}} {{end}}
-    {{- if index $.Checked $option }}{{color "green"}} {{ $.Config.Icons.MarkedOption }} {{else}}{{color "default+hb"}} {{ $.Config.Icons.UnmarkedOption }} {{end}}
+    {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}}
+    {{- if index $.Checked $option }}{{color $.Config.Icons.MarkedOption.Format }} {{ $.Config.Icons.MarkedOption.Text }} {{else}}{{color $.Config.Icons.UnmarkedOption.Format }} {{ $.Config.Icons.UnmarkedOption.Text }} {{end}}
     {{- color "reset"}}
     {{- " "}}{{$option}}{{"\n"}}
   {{- end}}
diff --git a/password.go b/password.go
index 6bfee64..d80dc68 100644
--- a/password.go
+++ b/password.go
@@ -29,8 +29,8 @@ type PasswordTemplateData struct {
 
 // PasswordQuestionTemplate is a template with color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
 var PasswordQuestionTemplate = `
-{{- if .ShowHelp }}{{- color "cyan"}}{{ .Config.Icons.Help }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
-{{- color "green+hb"}}{{ .Config.Icons.Question }} {{color "reset"}}
+{{- 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 and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ .Config.HelpInput }} for help]{{color "reset"}} {{end}}`
 
diff --git a/renderer.go b/renderer.go
index 863e7fc..b367262 100644
--- a/renderer.go
+++ b/renderer.go
@@ -16,10 +16,10 @@ type Renderer struct {
 
 type ErrorTemplateData struct {
 	Error error
-	Icon  string
+	Icon  Icon
 }
 
-var ErrorTemplate = `{{color "red"}}{{ .Icon }} Sorry, your reply was invalid: {{ .Error.Error }}{{color "reset"}}
+var ErrorTemplate = `{{color .Icon.Format }}{{ .Icon.Text }} Sorry, your reply was invalid: {{ .Error.Error }}{{color "reset"}}
 `
 
 func (r *Renderer) WithStdio(stdio terminal.Stdio) {
diff --git a/select.go b/select.go
index cfee27c..b81336a 100644
--- a/select.go
+++ b/select.go
@@ -45,15 +45,15 @@ type SelectTemplateData struct {
 }
 
 var SelectQuestionTemplate = `
-{{- if .ShowHelp }}{{- color "cyan"}}{{ .Config.Icons.Help }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
-{{- color "green+hb"}}{{ .Config.Icons.Question }} {{color "reset"}}
+{{- 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 }}{{ .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)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
   {{- "\n"}}
   {{- range $ix, $choice := .PageEntries}}
-    {{- if eq $ix $.SelectedIndex }}{{color "cyan+b"}}{{ $.Config.Icons.SelectFocus }} {{else}}{{color "default+hb"}}  {{end}}
+    {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }} {{else}}{{color "default+hb"}}  {{end}}
     {{- $choice}}
     {{- color "reset"}}{{"\n"}}
   {{- end}}
diff --git a/survey.go b/survey.go
index 7b72bc5..6a6d709 100644
--- a/survey.go
+++ b/survey.go
@@ -22,12 +22,30 @@ func defaultAskOptions() *AskOptions {
 			PageSize:  7,
 			HelpInput: "?",
 			Icons: IconSet{
-				Error:          "X",
-				Help:           "?",
-				Question:       "?",
-				MarkedOption:   "[x]",
-				UnmarkedOption: "[ ]",
-				SelectFocus:    ">",
+				Error: Icon{
+					Text:   "X",
+					Format: "red",
+				},
+				Help: Icon{
+					Text:   "?",
+					Format: "cyan",
+				},
+				Question: Icon{
+					Text:   "?",
+					Format: "green+hb",
+				},
+				MarkedOption: Icon{
+					Text:   "[x]",
+					Format: "green",
+				},
+				UnmarkedOption: Icon{
+					Text:   "[ ]",
+					Format: "default+hb",
+				},
+				SelectFocus: Icon{
+					Text:   ">",
+					Format: "cyan+b",
+				},
 			},
 			Filter: func(filter string, options []string) (answer []string) {
 				filter = strings.ToLower(filter)
@@ -41,16 +59,29 @@ func defaultAskOptions() *AskOptions {
 		},
 	}
 }
+func defaultPromptConfig() *PromptConfig {
+	return &defaultAskOptions().PromptConfig
+}
+
+func defaultIcons() *IconSet {
+	return &defaultPromptConfig().Icons
+}
+
+// Icon holds the text and format to show for a particular icon
+type Icon struct {
+	Text   string
+	Format string
+}
 
-// IconSet holds the strings to use for various prompts
+// IconSet holds the icons to use for various prompts
 type IconSet struct {
-	HelpInput      string
-	Error          string
-	Help           string
-	Question       string
-	MarkedOption   string
-	UnmarkedOption string
-	SelectFocus    string
+	HelpInput      Icon
+	Error          Icon
+	Help           Icon
+	Question       Icon
+	MarkedOption   Icon
+	UnmarkedOption Icon
+	SelectFocus    Icon
 }
 
 // Validator is a function passed to a Question after a user has provided a response.


Test patch:
diff --git a/confirm_test.go b/confirm_test.go
index 3dbe6c1..8e1ed94 100644
--- a/confirm_test.go
+++ b/confirm_test.go
@@ -30,31 +30,31 @@ func TestConfirmRender(t *testing.T) {
 			"Test Confirm question output with default true",
 			Confirm{Message: "Is pizza your favorite food?", Default: true},
 			ConfirmTemplateData{},
-			fmt.Sprintf("%s Is pizza your favorite food? (Y/n) ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s Is pizza your favorite food? (Y/n) ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Confirm question output with default false",
 			Confirm{Message: "Is pizza your favorite food?", Default: false},
 			ConfirmTemplateData{},
-			fmt.Sprintf("%s Is pizza your favorite food? (y/N) ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s Is pizza your favorite food? (y/N) ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Confirm answer output",
 			Confirm{Message: "Is pizza your favorite food?"},
 			ConfirmTemplateData{Answer: "Yes"},
-			fmt.Sprintf("%s Is pizza your favorite food? Yes\n", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s Is pizza your favorite food? Yes\n", defaultIcons().Question.Text),
 		},
 		{
 			"Test Confirm with help but help message is hidden",
 			Confirm{Message: "Is pizza your favorite food?", Help: "This is helpful"},
 			ConfirmTemplateData{},
-			fmt.Sprintf("%s Is pizza your favorite food? [%s for help] (y/N) ", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s Is pizza your favorite food? [%s for help] (y/N) ", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Confirm help output with help message shown",
 			Confirm{Message: "Is pizza your favorite food?", Help: "This is helpful"},
 			ConfirmTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s Is pizza your favorite food? (y/N) ", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s Is pizza your favorite food? (y/N) ", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 	}
 
@@ -66,7 +66,7 @@ func TestConfirmRender(t *testing.T) {
 		test.data.Confirm = test.prompt
 
 		// set the runtime config
-		test.data.Config = &defaultAskOptions().PromptConfig
+		test.data.Config = defaultPromptConfig()
 
 		err = test.prompt.Render(
 			ConfirmQuestionTemplate,
@@ -132,7 +132,7 @@ func TestConfirmPrompt(t *testing.T) {
 				c.ExpectString(
 					fmt.Sprintf(
 						"Is pizza your favorite food? [%s for help] (y/N)",
-						string(defaultAskOptions().PromptConfig.HelpInput),
+						string(defaultPromptConfig().HelpInput),
 					),
 				)
 				c.SendLine("?")
diff --git a/editor_test.go b/editor_test.go
index 539c860..b670437 100644
--- a/editor_test.go
+++ b/editor_test.go
@@ -31,49 +31,49 @@ func TestEditorRender(t *testing.T) {
 			"Test Editor question output without default",
 			Editor{Message: "What is your favorite month:"},
 			EditorTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [Enter to launch editor] ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: [Enter to launch editor] ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Editor question output with default",
 			Editor{Message: "What is your favorite month:", Default: "April"},
 			EditorTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: (April) [Enter to launch editor] ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: (April) [Enter to launch editor] ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Editor question output with HideDefault",
 			Editor{Message: "What is your favorite month:", Default: "April", HideDefault: true},
 			EditorTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [Enter to launch editor] ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: [Enter to launch editor] ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Editor answer output",
 			Editor{Message: "What is your favorite month:"},
 			EditorTemplateData{Answer: "October", ShowAnswer: true},
-			fmt.Sprintf("%s What is your favorite month: October\n", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: October\n", defaultIcons().Question.Text),
 		},
 		{
 			"Test Editor question output without default but with help hidden",
 			Editor{Message: "What is your favorite month:", Help: "This is helpful"},
 			EditorTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [%s for help] [Enter to launch editor] ", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s What is your favorite month: [%s for help] [Enter to launch editor] ", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Editor question output with default and with help hidden",
 			Editor{Message: "What is your favorite month:", Default: "April", Help: "This is helpful"},
 			EditorTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [%s for help] (April) [Enter to launch editor] ", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s What is your favorite month: [%s for help] (April) [Enter to launch editor] ", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Editor question output without default but with help shown",
 			Editor{Message: "What is your favorite month:", Help: "This is helpful"},
 			EditorTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: [Enter to launch editor] ", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: [Enter to launch editor] ", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 		{
 			"Test Editor question output with default and with help shown",
 			Editor{Message: "What is your favorite month:", Default: "April", Help: "This is helpful"},
 			EditorTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: (April) [Enter to launch editor] ", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: (April) [Enter to launch editor] ", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 	}
 
@@ -85,7 +85,7 @@ func TestEditorRender(t *testing.T) {
 		test.data.Editor = test.prompt
 
 		// set the icon set
-		test.data.Config = &defaultAskOptions().PromptConfig
+		test.data.Config = defaultPromptConfig()
 
 		err = test.prompt.Render(
 			EditorQuestionTemplate,
@@ -184,7 +184,7 @@ func TestEditorPrompt(t *testing.T) {
 				c.ExpectString(
 					fmt.Sprintf(
 						"Edit git commit message [%s for help] [Enter to launch editor]",
-						string(defaultAskOptions().PromptConfig.HelpInput),
+						string(defaultPromptConfig().HelpInput),
 					),
 				)
 				c.SendLine("?")
diff --git a/input_test.go b/input_test.go
index 99ff1a4..564d15b 100644
--- a/input_test.go
+++ b/input_test.go
@@ -30,43 +30,43 @@ func TestInputRender(t *testing.T) {
 			"Test Input question output without default",
 			Input{Message: "What is your favorite month:"},
 			InputTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Input question output with default",
 			Input{Message: "What is your favorite month:", Default: "April"},
 			InputTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: (April) ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: (April) ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Input answer output",
 			Input{Message: "What is your favorite month:"},
 			InputTemplateData{Answer: "October", ShowAnswer: true},
-			fmt.Sprintf("%s What is your favorite month: October\n", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: October\n", defaultIcons().Question.Text),
 		},
 		{
 			"Test Input question output without default but with help hidden",
 			Input{Message: "What is your favorite month:", Help: "This is helpful"},
 			InputTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [%s for help] ", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s What is your favorite month: [%s for help] ", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Input question output with default and with help hidden",
 			Input{Message: "What is your favorite month:", Default: "April", Help: "This is helpful"},
 			InputTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [%s for help] (April) ", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s What is your favorite month: [%s for help] (April) ", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Input question output without default but with help shown",
 			Input{Message: "What is your favorite month:", Help: "This is helpful"},
 			InputTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: ", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: ", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 		{
 			"Test Input question output with default and with help shown",
 			Input{Message: "What is your favorite month:", Default: "April", Help: "This is helpful"},
 			InputTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: (April) ", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: (April) ", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 	}
 
@@ -78,7 +78,7 @@ func TestInputRender(t *testing.T) {
 		test.data.Input = test.prompt
 
 		// set the runtime config
-		test.data.Config = &defaultAskOptions().PromptConfig
+		test.data.Config = defaultPromptConfig()
 
 		err = test.prompt.Render(
 			InputQuestionTemplate,
diff --git a/multiline_test.go b/multiline_test.go
index bebfee3..fceacfb 100644
--- a/multiline_test.go
+++ b/multiline_test.go
@@ -30,43 +30,43 @@ func TestMultilineRender(t *testing.T) {
 			"Test Multiline question output without default",
 			Multiline{Message: "What is your favorite month:"},
 			MultilineTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [Enter 2 empty lines to finish]", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: [Enter 2 empty lines to finish]", defaultIcons().Question.Text),
 		},
 		{
 			"Test Multiline question output with default",
 			Multiline{Message: "What is your favorite month:", Default: "April"},
 			MultilineTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: (April) [Enter 2 empty lines to finish]", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: (April) [Enter 2 empty lines to finish]", defaultIcons().Question.Text),
 		},
 		{
 			"Test Multiline answer output",
 			Multiline{Message: "What is your favorite month:"},
 			MultilineTemplateData{Answer: "October", ShowAnswer: true},
-			fmt.Sprintf("%s What is your favorite month: \nOctober", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s What is your favorite month: \nOctober", defaultIcons().Question.Text),
 		},
 		{
 			"Test Multiline question output without default but with help hidden",
 			Multiline{Message: "What is your favorite month:", Help: "This is helpful"},
 			MultilineTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: [Enter 2 empty lines to finish]", string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s What is your favorite month: [Enter 2 empty lines to finish]", string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Multiline question output with default and with help hidden",
 			Multiline{Message: "What is your favorite month:", Default: "April", Help: "This is helpful"},
 			MultilineTemplateData{},
-			fmt.Sprintf("%s What is your favorite month: (April) [Enter 2 empty lines to finish]", string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s What is your favorite month: (April) [Enter 2 empty lines to finish]", string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Multiline question output without default but with help shown",
 			Multiline{Message: "What is your favorite month:", Help: "This is helpful"},
 			MultilineTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: [Enter 2 empty lines to finish]", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: [Enter 2 empty lines to finish]", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 		{
 			"Test Multiline question output with default and with help shown",
 			Multiline{Message: "What is your favorite month:", Default: "April", Help: "This is helpful"},
 			MultilineTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: (April) [Enter 2 empty lines to finish]", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s What is your favorite month: (April) [Enter 2 empty lines to finish]", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 	}
 
@@ -77,7 +77,7 @@ func TestMultilineRender(t *testing.T) {
 		test.prompt.WithStdio(terminal.Stdio{Out: w})
 		test.data.Multiline = test.prompt
 		// set the icon set
-		test.data.Config = &defaultAskOptions().PromptConfig
+		test.data.Config = defaultPromptConfig()
 
 		err = test.prompt.Render(
 			MultilineQuestionTemplate,
diff --git a/multiselect_test.go b/multiselect_test.go
index 3475420..28a0b30 100644
--- a/multiselect_test.go
+++ b/multiselect_test.go
@@ -47,11 +47,11 @@ func TestMultiSelectRender(t *testing.T) {
 			},
 			strings.Join(
 				[]string{
-					fmt.Sprintf("%s Pick your words:  [Use arrows to move, space to select, type to filter]", defaultAskOptions().PromptConfig.Icons.Question),
-					fmt.Sprintf("  %s  foo", defaultAskOptions().PromptConfig.Icons.UnmarkedOption),
-					fmt.Sprintf("  %s  bar", defaultAskOptions().PromptConfig.Icons.MarkedOption),
-					fmt.Sprintf("%s %s  baz", defaultAskOptions().PromptConfig.Icons.SelectFocus, defaultAskOptions().PromptConfig.Icons.UnmarkedOption),
-					fmt.Sprintf("  %s  buz\n", defaultAskOptions().PromptConfig.Icons.MarkedOption),
+					fmt.Sprintf("%s Pick your words:  [Use arrows to move, space to select, type to filter]", defaultIcons().Question.Text),
+					fmt.Sprintf("  %s  foo", defaultIcons().UnmarkedOption.Text),
+					fmt.Sprintf("  %s  bar", defaultIcons().MarkedOption.Text),
+					fmt.Sprintf("%s %s  baz", defaultIcons().SelectFocus.Text, defaultIcons().UnmarkedOption.Text),
+					fmt.Sprintf("  %s  buz\n", defaultIcons().MarkedOption.Text),
 				},
 				"\n",
 			),
@@ -63,7 +63,7 @@ func TestMultiSelectRender(t *testing.T) {
 				Answer:     "foo, buz",
 				ShowAnswer: true,
 			},
-			fmt.Sprintf("%s Pick your words: foo, buz\n", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s Pick your words: foo, buz\n", defaultIcons().Question.Text),
 		},
 		{
 			"Test MultiSelect question output with help hidden",
@@ -75,11 +75,11 @@ func TestMultiSelectRender(t *testing.T) {
 			},
 			strings.Join(
 				[]string{
-					fmt.Sprintf("%s Pick your words:  [Use arrows to move, space to select, type to filter, %s for more help]", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
-					fmt.Sprintf("  %s  foo", defaultAskOptions().PromptConfig.Icons.UnmarkedOption),
-					fmt.Sprintf("  %s  bar", defaultAskOptions().PromptConfig.Icons.MarkedOption),
-					fmt.Sprintf("%s %s  baz", defaultAskOptions().PromptConfig.Icons.SelectFocus, defaultAskOptions().PromptConfig.Icons.UnmarkedOption),
-					fmt.Sprintf("  %s  buz\n", defaultAskOptions().PromptConfig.Icons.MarkedOption),
+					fmt.Sprintf("%s Pick your words:  [Use arrows to move, space to select, type to filter, %s for more help]", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
+					fmt.Sprintf("  %s  foo", defaultIcons().UnmarkedOption.Text),
+					fmt.Sprintf("  %s  bar", defaultIcons().MarkedOption.Text),
+					fmt.Sprintf("%s %s  baz", defaultIcons().SelectFocus.Text, defaultIcons().UnmarkedOption.Text),
+					fmt.Sprintf("  %s  buz\n", defaultIcons().MarkedOption.Text),
 				},
 				"\n",
 			),
@@ -95,12 +95,12 @@ func TestMultiSelectRender(t *testing.T) {
 			},
 			strings.Join(
 				[]string{
-					fmt.Sprintf("%s This is helpful", defaultAskOptions().PromptConfig.Icons.Help),
-					fmt.Sprintf("%s Pick your words:  [Use arrows to move, space to select, type to filter]", defaultAskOptions().PromptConfig.Icons.Question),
-					fmt.Sprintf("  %s  foo", defaultAskOptions().PromptConfig.Icons.UnmarkedOption),
-					fmt.Sprintf("  %s  bar", defaultAskOptions().PromptConfig.Icons.MarkedOption),
-					fmt.Sprintf("%s %s  baz", defaultAskOptions().PromptConfig.Icons.SelectFocus, defaultAskOptions().PromptConfig.Icons.UnmarkedOption),
-					fmt.Sprintf("  %s  buz\n", defaultAskOptions().PromptConfig.Icons.MarkedOption),
+					fmt.Sprintf("%s This is helpful", defaultIcons().Help.Text),
+					fmt.Sprintf("%s Pick your words:  [Use arrows to move, space to select, type to filter]", defaultIcons().Question.Text),
+					fmt.Sprintf("  %s  foo", defaultIcons().UnmarkedOption.Text),
+					fmt.Sprintf("  %s  bar", defaultIcons().MarkedOption.Text),
+					fmt.Sprintf("%s %s  baz", defaultIcons().SelectFocus.Text, defaultIcons().UnmarkedOption.Text),
+					fmt.Sprintf("  %s  buz\n", defaultIcons().MarkedOption.Text),
 				},
 				"\n",
 			),
@@ -115,7 +115,7 @@ func TestMultiSelectRender(t *testing.T) {
 		test.data.MultiSelect = test.prompt
 
 		// set the icon set
-		test.data.Config = &defaultAskOptions().PromptConfig
+		test.data.Config = defaultPromptConfig()
 
 		err = test.prompt.Render(
 			MultiSelectQuestionTemplate,
diff --git a/password_test.go b/password_test.go
index 3687c50..ba86a4f 100644
--- a/password_test.go
+++ b/password_test.go
@@ -26,19 +26,19 @@ func TestPasswordRender(t *testing.T) {
 			"Test Password question output",
 			Password{Message: "Tell me your secret:"},
 			PasswordTemplateData{},
-			fmt.Sprintf("%s Tell me your secret: ", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s Tell me your secret: ", defaultIcons().Question.Text),
 		},
 		{
 			"Test Password question output with help hidden",
 			Password{Message: "Tell me your secret:", Help: "This is helpful"},
 			PasswordTemplateData{},
-			fmt.Sprintf("%s Tell me your secret: [%s for help] ", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
+			fmt.Sprintf("%s Tell me your secret: [%s for help] ", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
 		},
 		{
 			"Test Password question output with help shown",
 			Password{Message: "Tell me your secret:", Help: "This is helpful"},
 			PasswordTemplateData{ShowHelp: true},
-			fmt.Sprintf("%s This is helpful\n%s Tell me your secret: ", defaultAskOptions().PromptConfig.Icons.Help, defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s This is helpful\n%s Tell me your secret: ", defaultIcons().Help.Text, defaultIcons().Question.Text),
 		},
 	}
 
@@ -46,7 +46,7 @@ func TestPasswordRender(t *testing.T) {
 		test.data.Password = test.prompt
 
 		// set the icon set
-		test.data.Config = &defaultAskOptions().PromptConfig
+		test.data.Config = defaultPromptConfig()
 
 		actual, err := core.RunTemplate(
 			PasswordQuestionTemplate,
diff --git a/renderer_test.go b/renderer_test.go
index 19fcaf5..8dda698 100755
--- a/renderer_test.go
+++ b/renderer_test.go
@@ -15,14 +15,14 @@ func TestValidationError(t *testing.T) {
 		ErrorTemplate,
 		&ErrorTemplateData{
 			Error: err,
-			Icon:  defaultAskOptions().PromptConfig.Icons.Error,
+			Icon:  defaultIcons().Error,
 		},
 	)
 	if err != nil {
 		t.Errorf("Failed to run template to format error: %s", err)
 	}
 
-	expected := fmt.Sprintf("%s Sorry, your reply was invalid: Football is not a valid month\n", defaultAskOptions().PromptConfig.Icons.Error)
+	expected := fmt.Sprintf("%s Sorry, your reply was invalid: Football is not a valid month\n", defaultIcons().Error.Text)
 
 	if actual != expected {
 		t.Errorf("Formatted error was not formatted correctly. Found:\n%s\nExpected:\n%s", actual, expected)
diff --git a/select_test.go b/select_test.go
index b05dbb9..4802cc4 100644
--- a/select_test.go
+++ b/select_test.go
@@ -43,10 +43,10 @@ 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]", defaultAskOptions().PromptConfig.Icons.Question),
+					fmt.Sprintf("%s Pick your word:  [Use arrows to move, space to select, type to filter]", defaultIcons().Question.Text),
 					"  foo",
 					"  bar",
-					fmt.Sprintf("%s baz", defaultAskOptions().PromptConfig.Icons.SelectFocus),
+					fmt.Sprintf("%s baz", defaultIcons().SelectFocus.Text),
 					"  buz\n",
 				},
 				"\n",
@@ -56,7 +56,7 @@ func TestSelectRender(t *testing.T) {
 			"Test Select answer output",
 			prompt,
 			SelectTemplateData{Answer: "buz", ShowAnswer: true, PageEntries: prompt.Options},
-			fmt.Sprintf("%s Pick your word: buz\n", defaultAskOptions().PromptConfig.Icons.Question),
+			fmt.Sprintf("%s Pick your word: buz\n", defaultIcons().Question.Text),
 		},
 		{
 			"Test Select question output with help hidden",
@@ -64,10 +64,10 @@ 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]", defaultAskOptions().PromptConfig.Icons.Question, string(defaultAskOptions().PromptConfig.HelpInput)),
+					fmt.Sprintf("%s Pick your word:  [Use arrows to move, space to select, type to filter, %s for more help]", defaultIcons().Question.Text, string(defaultPromptConfig().HelpInput)),
 					"  foo",
 					"  bar",
-					fmt.Sprintf("%s baz", defaultAskOptions().PromptConfig.Icons.SelectFocus),
+					fmt.Sprintf("%s baz", defaultIcons().SelectFocus.Text),
 					"  buz\n",
 				},
 				"\n",
@@ -79,11 +79,11 @@ func TestSelectRender(t *testing.T) {
 			SelectTemplateData{SelectedIndex: 2, ShowHelp: true, PageEntries: prompt.Options},
 			strings.Join(
 				[]string{
-					fmt.Sprintf("%s This is helpful", defaultAskOptions().PromptConfig.Icons.Help),
-					fmt.Sprintf("%s Pick your word:  [Use arrows to move, space to select, type to filter]", defaultAskOptions().PromptConfig.Icons.Question),
+					fmt.Sprintf("%s This is helpful", defaultIcons().Help.Text),
+					fmt.Sprintf("%s Pick your word:  [Use arrows to move, space to select, type to filter]", defaultIcons().Question.Text),
 					"  foo",
 					"  bar",
-					fmt.Sprintf("%s baz", defaultAskOptions().PromptConfig.Icons.SelectFocus),
+					fmt.Sprintf("%s baz", defaultIcons().SelectFocus.Text),
 					"  buz\n",
 				},
 				"\n",
@@ -99,7 +99,7 @@ func TestSelectRender(t *testing.T) {
 		test.data.Select = test.prompt
 
 		// set the icon set
-		test.data.Config = &defaultAskOptions().PromptConfig
+		test.data.Config = defaultPromptConfig()
 
 		err = test.prompt.Render(
 			SelectQuestionTemplate,
diff --git a/survey_test.go b/survey_test.go
index a08958e..717bb68 100644
--- a/survey_test.go
+++ b/survey_test.go
@@ -37,7 +37,7 @@ func RunPromptTest(t *testing.T, test PromptTest) {
 			p.WithStdio(stdio)
 		}
 
-		answer, err = test.prompt.Prompt(&defaultAskOptions().PromptConfig)
+		answer, err = test.prompt.Prompt(defaultPromptConfig())
 		return err
 	})
 	require.Equal(t, test.expected, answer)
diff --git a/tests/util/test.go b/tests/util/test.go
index 453d349..9cbf4cd 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, survey.WithValidator(entry.Validate))
+		err := survey.AskOne(entry.Prompt, entry.Value)
 		if err != nil {
 			fmt.Printf("AskOne on %v's prompt failed: %v.", entry.Name, err.Error())
 			break