{"id":15292648,"url":"https://github.com/alecaivazis/survey","last_synced_at":"2025-10-07T04:32:41.795Z","repository":{"id":37432038,"uuid":"72362833","full_name":"AlecAivazis/survey","owner":"AlecAivazis","description":"A golang library for building interactive and accessible prompts with full support for windows and posix terminals.","archived":true,"fork":false,"pushed_at":"2024-04-07T12:46:27.000Z","size":3773,"stargazers_count":4090,"open_issues_count":75,"forks_count":355,"subscribers_count":30,"default_branch":"master","last_synced_at":"2024-11-08T11:52:11.044Z","etag":null,"topics":["cli","command-line","golang","interactive","prompt","unix","windows"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AlecAivazis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-30T17:03:15.000Z","updated_at":"2024-11-06T20:43:50.000Z","dependencies_parsed_at":"2024-04-29T12:03:07.351Z","dependency_job_id":null,"html_url":"https://github.com/AlecAivazis/survey","commit_stats":{"total_commits":459,"total_committers":73,"mean_commits":6.287671232876712,"dds":0.3485838779956427,"last_synced_commit":"160123ed7175f77bc8625b59c44b8dc03f5333e3"},"previous_names":["alecaivazis/survey","go-survey/survey","alecaivazis/probe"],"tags_count":82,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlecAivazis%2Fsurvey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlecAivazis%2Fsurvey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlecAivazis%2Fsurvey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlecAivazis%2Fsurvey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AlecAivazis","download_url":"https://codeload.github.com/AlecAivazis/survey/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235593342,"owners_count":19015137,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line","golang","interactive","prompt","unix","windows"],"created_at":"2024-09-30T16:25:21.635Z","updated_at":"2025-10-07T04:32:41.342Z","avatar_url":"https://github.com/AlecAivazis.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Survey\n\n[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg)](https://pkg.go.dev/github.com/AlecAivazis/survey/v2)\n\nA library for building interactive and accessible prompts on terminals supporting ANSI escape sequences.\n\n⚠️ This project is no longer maintained. For an alternative, please check out: https://github.com/charmbracelet/bubbletea ⚠️\n\nHey everyone! I finally came to terms with the fact that I can no longer dedicate enough time to keep this library alive. \nThis project outgrew my wildest expectations and was such a great experience. If someone else wants to take over maintainence,\nplease reach out\n\n\n\u003cimg width=\"550\" src=\"https://thumbs.gfycat.com/VillainousGraciousKouprey-size_restricted.gif\"/\u003e\n\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/AlecAivazis/survey/v2\"\n)\n\n// the questions to ask\nvar qs = []*survey.Question{\n    {\n        Name:     \"name\",\n        Prompt:   \u0026survey.Input{Message: \"What is your name?\"},\n        Validate: survey.Required,\n        Transform: survey.Title,\n    },\n    {\n        Name: \"color\",\n        Prompt: \u0026survey.Select{\n            Message: \"Choose a color:\",\n            Options: []string{\"red\", \"blue\", \"green\"},\n            Default: \"red\",\n        },\n    },\n    {\n        Name: \"age\",\n        Prompt:   \u0026survey.Input{Message: \"How old are you?\"},\n    },\n}\n\nfunc main() {\n    // the answers will be written to this struct\n    answers := struct {\n        Name          string                  // survey will match the question and field names\n        FavoriteColor string `survey:\"color\"` // or you can tag fields to match a specific name\n        Age           int                     // if the types don't match, survey will convert it\n    }{}\n\n    // perform the questions\n    err := survey.Ask(qs, \u0026answers)\n    if err != nil {\n        fmt.Println(err.Error())\n        return\n    }\n\n    fmt.Printf(\"%s chose %s.\", answers.Name, answers.FavoriteColor)\n}\n```\n\n## Examples\n\nExamples can be found in the `examples/` directory. Run them\nto see basic behavior:\n\n```bash\ngo run examples/simple.go\ngo run examples/validation.go\n```\n\n## Running the Prompts\n\nThere are two primary ways to execute prompts and start collecting information from your users: `Ask` and\n`AskOne`. The primary difference is whether you are interested in collecting a single piece of information\nor if you have a list of questions to ask whose answers should be collected in a single struct.\nFor most basic usecases, `Ask` should be enough. However, for surveys with complicated branching logic,\nwe recommend that you break out your questions into multiple calls to both of these functions to fit your needs.\n\n### Configuring the Prompts\n\nMost prompts take fine-grained configuration through fields on the structs you instantiate. It is also\npossible to change survey's default behaviors by passing `AskOpts` to either `Ask` or `AskOne`. Examples\nin this document will do both interchangeably:\n\n```golang\nprompt := \u0026Select{\n    Message: \"Choose a color:\",\n    Options: []string{\"red\", \"blue\", \"green\"},\n    // can pass a validator directly\n    Validate: survey.Required,\n}\n\n// or define a default for the single call to `AskOne`\n// the answer will get written to the color variable\nsurvey.AskOne(prompt, \u0026color, survey.WithValidator(survey.Required))\n\n// or define a default for every entry in a list of questions\n// the answer will get copied into the matching field of the struct as shown above\nsurvey.Ask(questions, \u0026answers, survey.WithValidator(survey.Required))\n```\n\n## Prompts\n\n### Input\n\n\u003cimg src=\"https://thumbs.gfycat.com/LankyBlindAmericanpainthorse-size_restricted.gif\" width=\"400px\"/\u003e\n\n```golang\nname := \"\"\nprompt := \u0026survey.Input{\n    Message: \"ping\",\n}\nsurvey.AskOne(prompt, \u0026name)\n```\n\n#### Suggestion Options\n\n\u003cimg src=\"https://i.imgur.com/Q7POpA1.gif\" width=\"800px\"/\u003e\n\n```golang\nfile := \"\"\nprompt := \u0026survey.Input{\n    Message: \"inform a file to save:\",\n    Suggest: func (toComplete string) []string {\n        files, _ := filepath.Glob(toComplete + \"*\")\n        return files\n    },\n}\n}\nsurvey.AskOne(prompt, \u0026file)\n```\n\n### Multiline\n\n\u003cimg src=\"https://thumbs.gfycat.com/ImperfectShimmeringBeagle-size_restricted.gif\" width=\"400px\"/\u003e\n\n```golang\ntext := \"\"\nprompt := \u0026survey.Multiline{\n    Message: \"ping\",\n}\nsurvey.AskOne(prompt, \u0026text)\n```\n\n### Password\n\n\u003cimg src=\"https://thumbs.gfycat.com/CompassionateSevereHypacrosaurus-size_restricted.gif\" width=\"400px\" /\u003e\n\n```golang\npassword := \"\"\nprompt := \u0026survey.Password{\n    Message: \"Please type your password\",\n}\nsurvey.AskOne(prompt, \u0026password)\n```\n\n### Confirm\n\n\u003cimg src=\"https://thumbs.gfycat.com/UnkemptCarefulGermanpinscher-size_restricted.gif\" width=\"400px\"/\u003e\n\n```golang\nname := false\nprompt := \u0026survey.Confirm{\n    Message: \"Do you like pie?\",\n}\nsurvey.AskOne(prompt, \u0026name)\n```\n\n### Select\n\n\u003cimg src=\"https://thumbs.gfycat.com/GrimFilthyAmazonparrot-size_restricted.gif\" width=\"450px\"/\u003e\n\n```golang\ncolor := \"\"\nprompt := \u0026survey.Select{\n    Message: \"Choose a color:\",\n    Options: []string{\"red\", \"blue\", \"green\"},\n}\nsurvey.AskOne(prompt, \u0026color)\n```\n\nFields and values that come from a `Select` prompt can be one of two different things. If you pass an `int`\nthe field will have the value of the selected index. If you instead pass a string, the string value selected\nwill be written to the field.\n\nThe 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.\n\nBy default, the select prompt is limited to showing 7 options at a time\nand will paginate lists of options longer than that. This can be changed a number of ways:\n\n```golang\n// as a field on a single select\nprompt := \u0026survey.MultiSelect{..., PageSize: 10}\n\n// or as an option to Ask or AskOne\nsurvey.AskOne(prompt, \u0026days, survey.WithPageSize(10))\n```\n\n#### Select options description\n\nThe optional description text can be used to add extra information to each option listed in the select prompt:\n\n```golang\ncolor := \"\"\nprompt := \u0026survey.Select{\n    Message: \"Choose a color:\",\n    Options: []string{\"red\", \"blue\", \"green\"},\n    Description: func(value string, index int) string {\n        if value == \"red\" {\n            return \"My favorite color\"\n        }\n        return \"\"\n    },\n}\nsurvey.AskOne(prompt, \u0026color)\n\n// Assuming that the user chose \"red - My favorite color\":\nfmt.Println(color) //=\u003e \"red\"\n```\n\n### MultiSelect\n\n![Example](img/multi-select-all-none.gif)\n\n```golang\ndays := []string{}\nprompt := \u0026survey.MultiSelect{\n    Message: \"What days do you prefer:\",\n    Options: []string{\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"},\n}\nsurvey.AskOne(prompt, \u0026days)\n```\n\nFields and values that come from a `MultiSelect` prompt can be one of two different things. If you pass an `int`\nthe field will have a slice of the selected indices. If you instead pass a string, a slice of the string values\nselected will be written to the field.\n\nThe 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.\n\nBy default, the MultiSelect prompt is limited to showing 7 options at a time\nand will paginate lists of options longer than that. This can be changed a number of ways:\n\n```golang\n// as a field on a single select\nprompt := \u0026survey.MultiSelect{..., PageSize: 10}\n\n// or as an option to Ask or AskOne\nsurvey.AskOne(prompt, \u0026days, survey.WithPageSize(10))\n```\n\n### Editor\n\nLaunches the user's preferred editor (defined by the \\$VISUAL or \\$EDITOR environment variables) on a\ntemporary file. Once the user exits their editor, the contents of the temporary file are read in as\nthe result. If neither of those are present, notepad (on Windows) or vim (Linux or Mac) is used.\n\nYou can also specify a [pattern](https://golang.org/pkg/io/ioutil/#TempFile) for the name of the temporary file. This\ncan be useful for ensuring syntax highlighting matches your usecase.\n\n```golang\nprompt := \u0026survey.Editor{\n    Message: \"Shell code snippet\",\n    FileName: \"*.sh\",\n}\n\nsurvey.AskOne(prompt, \u0026content)\n```\n\n## Filtering Options\n\nBy default, the user can filter for options in Select and MultiSelects by typing while the prompt\nis active. This will filter out all options that don't contain the typed string anywhere in their name, ignoring case.\n\nA custom filter function can also be provided to change this behavior:\n\n```golang\nfunc myFilter(filterValue string, optValue string, optIndex int) bool {\n    // only include the option if it includes the filter and has length greater than 5\n    return strings.Contains(optValue, filterValue) \u0026\u0026 len(optValue) \u003e= 5\n}\n\n// configure it for a specific prompt\n\u0026Select{\n    Message: \"Choose a color:\",\n    Options: []string{\"red\", \"blue\", \"green\"},\n    Filter: myFilter,\n}\n\n// or define a default for all of the questions\nsurvey.AskOne(prompt, \u0026color, survey.WithFilter(myFilter))\n```\n\n## Keeping the filter active\n\nBy default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone.\n\nHowever the user can prevent this from happening and keep the filter active for multiple selections in a e.g. MultiSelect:\n\n```golang\n// configure it for a specific prompt\n\u0026Select{\n    Message:    \"Choose a color:\",\n    Options:    []string{\"light-green\", \"green\", \"dark-green\", \"red\"},\n    KeepFilter: true,\n}\n\n// or define a default for all of the questions\nsurvey.AskOne(prompt, \u0026color, survey.WithKeepFilter(true))\n```\n\n## Validation\n\nValidating individual responses for a particular question can be done by defining a\n`Validate` field on the `survey.Question` to be validated. This function takes an\n`interface{}` type and returns an error to show to the user, prompting them for another\nresponse. Like usual, validators can be provided directly to the prompt or with `survey.WithValidator`:\n\n```golang\nq := \u0026survey.Question{\n    Prompt: \u0026survey.Input{Message: \"Hello world validation\"},\n    Validate: func (val interface{}) error {\n        // since we are validating an Input, the assertion will always succeed\n        if str, ok := val.(string) ; !ok || len(str) \u003e 10 {\n            return errors.New(\"This response cannot be longer than 10 characters.\")\n        }\n\treturn nil\n    },\n}\n\ncolor := \"\"\nprompt := \u0026survey.Input{ Message: \"Whats your name?\" }\n\n// you can pass multiple validators here and survey will make sure each one passes\nsurvey.AskOne(prompt, \u0026color, survey.WithValidator(survey.Required))\n```\n\n### Built-in Validators\n\n`survey` comes prepackaged with a few validators to fit common situations. Currently these\nvalidators include:\n\n| name         | valid types    | description                                                      | notes                                                                                 |\n| ------------ | -------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- |\n| Required     | any            | Rejects zero values of the response type                         | Boolean values pass straight through since the zero value (false) is a valid response |\n| MinLength(n) | string         | Enforces that a response is at least the given length            |                                                                                       |\n| MaxLength(n) | string         | Enforces that a response is no longer than the given length      |                                                                                       |\n| MaxItems(n)  | []OptionAnswer | Enforces that a response has no more selections of the indicated |                                                                                       |\n| MinItems(n)  | []OptionAnswer | Enforces that a response has no less selections of the indicated |                                                                                       |\n\n## Help Text\n\nAll of the prompts have a `Help` field which can be defined to provide more information to your users:\n\n\u003cimg src=\"https://thumbs.gfycat.com/CloudyRemorsefulFossa-size_restricted.gif\" width=\"400px\" style=\"margin-top: 8px\"/\u003e\n\n```golang\n\u0026survey.Input{\n    Message: \"What is your phone number:\",\n    Help:    \"Phone number should include the area code\",\n}\n```\n\n## Removing the \"Select All\" and \"Select None\" options\n\nBy default, users can select all of the multi-select options using the right arrow key. To prevent users from being able to do this (and remove the `\u003cright\u003e to all` message from the prompt), use the option `WithRemoveSelectAll`:\n\n```golang\nimport (\n    \"github.com/AlecAivazis/survey/v2\"\n)\n\nnumber := \"\"\nprompt := \u0026survey.Input{\n    Message: \"This question has the select all option removed\",\n}\n\nsurvey.AskOne(prompt, \u0026number, survey.WithRemoveSelectAll())\n```\n\nAlso by default, users can use the left arrow key to unselect all of the options. To prevent users from being able to do this (and remove the `\u003cleft\u003e to none` message from the prompt), use the option `WithRemoveSelectNone`:\n\n```golang\nimport (\n    \"github.com/AlecAivazis/survey/v2\"\n)\n\nnumber := \"\"\nprompt := \u0026survey.Input{\n    Message: \"This question has the select all option removed\",\n}\n\nsurvey.AskOne(prompt, \u0026number, survey.WithRemoveSelectNone())\n```\n\n\n### Changing the input rune\n\nIn some situations, `?` is a perfectly valid response. To handle this, you can change the rune that survey\nlooks for with `WithHelpInput`:\n\n```golang\nimport (\n    \"github.com/AlecAivazis/survey/v2\"\n)\n\nnumber := \"\"\nprompt := \u0026survey.Input{\n    Message: \"If you have this need, please give me a reasonable message.\",\n    Help:    \"I couldn't come up with one.\",\n}\n\nsurvey.AskOne(prompt, \u0026number, survey.WithHelpInput('^'))\n```\n\n## Changing the Icons\n\nChanging the icons and their color/format can be done by passing the `WithIcons` option. The format\nfollows the patterns outlined [here](https://github.com/mgutz/ansi#style-format). For example:\n\n```golang\nimport (\n    \"github.com/AlecAivazis/survey/v2\"\n)\n\nnumber := \"\"\nprompt := \u0026survey.Input{\n    Message: \"If you have this need, please give me a reasonable message.\",\n    Help:    \"I couldn't come up with one.\",\n}\n\nsurvey.AskOne(prompt, \u0026number, survey.WithIcons(func(icons *survey.IconSet) {\n    // you can set any icons\n    icons.Question.Text = \"⁇\"\n    // for more information on formatting the icons, see here: https://github.com/mgutz/ansi#style-format\n    icons.Question.Format = \"yellow+hb\"\n}))\n```\n\nThe icons and their default text and format are summarized below:\n\n| name           | text | format     | description                                                   |\n| -------------- | ---- | ---------- | ------------------------------------------------------------- |\n| Error          | X    | red        | Before an error                                               |\n| Help           | i    | cyan       | Before help text                                              |\n| Question       | ?    | green+hb   | Before the message of a prompt                                |\n| SelectFocus    | \u003e    | green      | Marks the current focus in `Select` and `MultiSelect` prompts |\n| UnmarkedOption | [ ]  | default+hb | Marks an unselected option in a `MultiSelect` prompt          |\n| MarkedOption   | [x]  | cyan+b     | Marks a chosen selection in a `MultiSelect` prompt            |\n\n## Custom Types\n\nsurvey will assign prompt answers to your custom types if they implement this interface:\n\n```golang\ntype Settable interface {\n    WriteAnswer(field string, value interface{}) error\n}\n```\n\nHere is an example how to use them:\n\n```golang\ntype MyValue struct {\n    value string\n}\nfunc (my *MyValue) WriteAnswer(name string, value interface{}) error {\n     my.value = value.(string)\n}\n\nmyval := MyValue{}\nsurvey.AskOne(\n    \u0026survey.Input{\n        Message: \"Enter something:\",\n    },\n    \u0026myval\n)\n```\n\n## Testing\n\nYou can test your program's interactive prompts using [go-expect](https://github.com/Netflix/go-expect). The library\ncan be used to expect a match on stdout and respond on stdin. Since `os.Stdout` in a `go test` process is not a TTY,\nif you are manipulating the cursor or using `survey`, you will need a way to interpret terminal / ANSI escape sequences\nfor things like `CursorLocation`. `vt10x.NewVT10XConsole` will create a `go-expect` console that also multiplexes\nstdio to an in-memory [virtual terminal](https://github.com/hinshun/vt10x).\n\nFor some examples, you can see any of the tests in this repo.\n\n## FAQ\n\n### What kinds of IO are supported by `survey`?\n\nsurvey aims to support most terminal emulators; it expects support for ANSI escape sequences.\nThis means that reading from piped stdin or writing to piped stdout is **not supported**,\nand likely to break your application in these situations. See [#337](https://github.com/AlecAivazis/survey/pull/337#issue-581351617)\n\n### Why isn't Ctrl-C working?\n\nOrdinarily, when you type Ctrl-C, the terminal recognizes this as the QUIT button and delivers a SIGINT signal to the process, which terminates it.\nHowever, Survey temporarily configures the terminal to deliver control codes as ordinary input bytes.\nWhen Survey reads a ^C byte (ASCII \\x03, \"end of text\"), it interrupts the current survey and returns a\n`github.com/AlecAivazis/survey/v2/terminal.InterruptErr` from `Ask` or `AskOne`.\nIf you want to stop the process, handle the returned error in your code:\n\n```go\nerr := survey.AskOne(prompt, \u0026myVar)\nif err != nil {\n\tif err == terminal.InterruptErr {\n\t\tlog.Fatal(\"interrupted\")\n\t}\n\t...\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecaivazis%2Fsurvey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falecaivazis%2Fsurvey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecaivazis%2Fsurvey/lists"}