[
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nContributions are always welcome; however, please read this document in its\nentirety before submitting a Pull Request or Reporting a bug.\n\n### Table of Contents\n\n- [Reporting a bug](#reporting-a-bug)\n  - [Security disclosure](#security-disclosure)\n- [Creating an issue](#creating-an-issue)\n- [Feature requests](#feature-requests)\n- [Opening a pull request](#opening-a-pull-request)\n- [Code of Conduct](#code-of-conduct)\n- [License](#license)\n- [Contributor license agreement](#contributor-license-agreement)\n\n---------------\n\n# Reporting a Bug\n\nThink you've found a bug? Let us know!\n\n### Security disclosure\n\nSecurity is a top priority for us. If you have encountered a security issue\nplease responsibly disclose it by following our [security\ndisclosure](../docs/security.md) document.\n\n# Creating an Issue\n\nYour issue must follow these guidelines for it to be considered:\n\n#### Before submitting\n\n- Check you’re on the latest version, we may have already fixed your bug!\n- [Search our issue\n  tracker](https://github.com/manifoldco/promptui/issues/search&type=issues)\n  for your problem, someone may have already reported it\n\n# Opening a Pull Request\n\nTo contribute, [fork](https://help.github.com/articles/fork-a-repo/)\n`promptui`, commit your changes, and [open a pull\nrequest](https://help.github.com/articles/using-pull-requests/).\n\nYour request will be reviewed as soon as possible. You may be asked to make\nchanges to your submission during the review process.\n\n#### Before submitting\n\n- Test your change thoroughly\n- you can run `make bootstrap && make` to ensure that the continuous integration\n  build will succeed\n\n\n# Code of Conduct\n\nAll community members are expected to adhere to our [code of\nconduct](../CODE_OF_CONDUCT.md).\n\n\n# License\n\nManifold's promptui is released under the [BSD 3-Clause\nLicense](../LICENSE.md).\n\n\n# Contributor license agreement\n\nFor legal purposes all contributors must sign a [contributor license\nagreement](https://cla-assistant.io/manifoldco/promptui), either for an\nindividual or corporation, before a pull request can be accepted.\n\nYou will be prompted to sign the agreement by CLA Assistant (bot) when you open\na Pull Request for the first time.\n"
  },
  {
    "path": ".github/listbot.md",
    "content": "**Author**\n\n- [ ] Changelog has been updated\n"
  },
  {
    "path": ".gitignore",
    "content": "vendor\nall-cover.txt\nbin/\n"
  },
  {
    "path": ".golangci.yml",
    "content": "run:\n  deadline: 5m\n\nissues:\n  # Disable maximums so we see all issues\n  max-per-linter: 0\n  max-same-issues: 0\n\n  # golangci-lint ignores missing docstrings by default. That's no good!\n  exclude-use-default: false\n\nlinters:\n  disable-all: true\n  enable:\n    - misspell\n    - golint\n    - goimports\n    - ineffassign\n    - deadcode\n    - gofmt\n    - govet\n    - structcheck\n    - unconvert\n    - megacheck\n    - typecheck\n    - varcheck\n"
  },
  {
    "path": ".travis.yml",
    "content": "dist: bionic\nlanguage: go\n\ngo:\n  - \"1.12.x\"\n  - \"1.13.x\"\n\nbranches:\n  only:\n    - master\n\nafter_success:\n  # only report coverage for go-version 1.11\n  - if [[ $TRAVIS_GO_VERSION =~ ^1\\.11 ]] ; then bash <(curl -s https://codecov.io/bash) -f all-cover.txt; fi\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# CHANGELOG\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/)\nand this project adheres to [Semantic Versioning](http://semver.org/).\n\n## Unreleased\n\n## [0.9.0] - 2021-10-30\n\n### Fixed\n\n- Resolve license incompatibility in tabwriter\n\n\n## [0.8.0] - 2020-09-28\n\n### Added\n\n- Support ctrl-h for backspace\n- Allow hiding entered data after submit\n- Allow masking input with an empty rune to hide input length\n\n### Fixed\n\n- Fix echo of cursor after input is finished\n- Better support for keycodes on Windows\n\n\n## [0.7.0] - 2020-01-11\n\n### Added\n\n- Add support for configurable Stdin/Stdout on Prompt\n- Add support for setting initial cursor position\n- Switch to golangci-lint for linting\n\n### Removed\n\n- Removed support for Go 1.11\n\n### Fixed\n\n- Reduce tool-based deps, hopefully fixing any install issues\n\n## [0.6.0] - 2019-11-29\n\n### Added\n\n- Support configurable stdin\n\n### Fixed\n\n- Correct the dep on go-i18n\n\n## [0.5.0] - 2019-11-29\n\n### Added\n\n- Now building and testing on go 1.11, go 1.12, and go 1.13\n\n### Removed\n\n- Removed support for Go versions that don't include modules.\n\n## [0.4.0] - 2019-02-19\n\n### Added\n\n- The text displayed when an item was successfully selected can be hidden\n\n## [0.3.2] - 2018-11-26\n\n### Added\n\n- Support Go modules\n\n### Fixed\n\n- Fix typos in PromptTemplates documentation\n\n## [0.3.1] - 2018-07-26\n\n### Added\n\n- Improved documentation for GoDoc\n- Navigation keys information for Windows\n\n### Fixed\n\n- `success` template was not properly displayed after a successful prompt.\n\n## [0.3.0] - 2018-05-22\n\n### Added\n\n- Background colors codes and template helpers\n- `AllowEdit` for prompt to prevent deletion of the default value by any key\n- Added `StartInSearchMode` to allow starting the prompt in search mode\n\n### Fixed\n\n- `<Enter>` key press on Windows\n- `juju/ansiterm` dependency\n- `chzyer/readline#136` new api with ReadCloser\n- Deleting UTF-8 characters sequence\n\n## [0.2.1] - 2017-11-30\n\n### Fixed\n\n- `SelectWithAdd` panicking on `.Run` due to lack of keys setup\n- Backspace key on Windows\n\n## [0.2.0] - 2017-11-16\n\n### Added\n\n- `Select` items can now be searched\n\n## [0.1.0] - 2017-11-02\n\n### Added\n\n- extract `promptui` from [torus](https://github.com/manifoldco/torus-cli) as a\n  standalone lib.\n- `promptui.Prompt` provides a single input line to capture user information.\n- `promptui.Select` provides a list of options to choose from. Users can\n  navigate through the list either one item at time or by pagination\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age,\nbody size, disability, ethnicity, gender identity and expression, level of\nexperience, nationality, personal appearance, race, religion, or sexual\nidentity and orientation.\n\n## Our Standards\n\nExamples of behaviour that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behaviour by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehaviour and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behaviour.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviours that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an\nappointed representative at an online or offline event. Representation of a\nproject may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at\n[hello@manifold.co](mailto:hello@manifold.co). All complaints will be reviewed\nand investigated and will result in a response that is deemed necessary and\nappropriate to the circumstances. The project team is obligated to maintain\nconfidentiality with regard to the reporter of an incident. Further details of\nspecific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the Contributor Covenant, version 1.4,\navailable at\n[http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4).\n"
  },
  {
    "path": "LICENSE.md",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2017, Arigato Machine Inc.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "Makefile",
    "content": "export GO111MODULE := on\nexport PATH := ./bin:$(PATH)\n\nci: bootstrap lint cover\n.PHONY: ci\n\n#################################################\n# Bootstrapping for base golang package and tool deps\n#################################################\n\nbootstrap:\n\tcurl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.21.0\n.PHONY: bootstrap\n\nmod-update:\n\tgo get -u -m\n\tgo mod tidy\n\nmod-tidy:\n\tgo mod tidy\n\n.PHONY: $(CMD_PKGS)\n.PHONY: mod-update mod-tidy\n\n#################################################\n# Test and linting\n#################################################\n# Run all the linters\nlint:\n\tbin/golangci-lint run ./...\n.PHONY: lint\n\ntest:\n\tCGO_ENABLED=0 go test $$(go list ./... | grep -v generated)\n.PHONY: test\n\nCOVER_TEST_PKGS:=$(shell find . -type f -name '*_test.go' | rev | cut -d \"/\" -f 2- | rev | grep -v generated | sort -u)\n$(COVER_TEST_PKGS:=-cover): %-cover: all-cover.txt\n\t@CGO_ENABLED=0 go test -v -coverprofile=$@.out -covermode=atomic ./$*\n\t@if [ -f $@.out ]; then \\\n\t\tgrep -v \"mode: atomic\" < $@.out >> all-cover.txt; \\\n\t\trm $@.out; \\\n\tfi\n\nall-cover.txt:\n\techo \"mode: atomic\" > all-cover.txt\n\ncover: all-cover.txt $(COVER_TEST_PKGS:=-cover)\n.PHONY: cover all-cover.txt\n"
  },
  {
    "path": "README.md",
    "content": "# promptui\n\nInteractive prompt for command-line applications.\n\nWe built Promptui because we wanted to make it easy and fun to explore cloud\nservices with [manifold cli](https://github.com/manifoldco/manifold-cli).\n\n[Code of Conduct](./CODE_OF_CONDUCT.md) |\n[Contribution Guidelines](./.github/CONTRIBUTING.md)\n\n[![GitHub release](https://img.shields.io/github/tag/manifoldco/promptui.svg?label=latest)](https://github.com/manifoldco/promptui/releases)\n[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/manifoldco/promptui)\n[![Travis](https://img.shields.io/travis/manifoldco/promptui/master.svg)](https://travis-ci.org/manifoldco/promptui)\n[![Go Report Card](https://goreportcard.com/badge/github.com/manifoldco/promptui)](https://goreportcard.com/report/github.com/manifoldco/promptui)\n[![License](https://img.shields.io/badge/license-BSD-blue.svg)](./LICENSE.md)\n\n## Overview\n\n![promptui](https://media.giphy.com/media/xUNda0Ngb5qsogLsBi/giphy.gif)\n\nPromptui is a library providing a simple interface to create command-line\nprompts for go. It can be easily integrated into\n[spf13/cobra](https://github.com/spf13/cobra),\n[urfave/cli](https://github.com/urfave/cli) or any cli go application.\n\nPromptui has two main input modes:\n\n- `Prompt` provides a single line for user input. Prompt supports\n  optional live validation, confirmation and masking the input.\n\n- `Select` provides a list of options to choose from. Select supports\n  pagination, search, detailed view and custom templates.\n\nFor a full list of options check [GoDoc](https://godoc.org/github.com/manifoldco/promptui).\n\n## Basic Usage\n\n### Prompt\n\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\tvalidate := func(input string) error {\n\t\t_, err := strconv.ParseFloat(input, 64)\n\t\tif err != nil {\n\t\t\treturn errors.New(\"Invalid number\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tprompt := promptui.Prompt{\n\t\tLabel:    \"Number\",\n\t\tValidate: validate,\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %q\\n\", result)\n}\n```\n\n### Select\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\tprompt := promptui.Select{\n\t\tLabel: \"Select Day\",\n\t\tItems: []string{\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\",\n\t\t\t\"Saturday\", \"Sunday\"},\n\t}\n\n\t_, result, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %q\\n\", result)\n}\n```\n\n### More Examples\n\nSee full list of [examples](https://github.com/manifoldco/promptui/tree/master/_examples)\n"
  },
  {
    "path": "_examples/confirm/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\tprompt := promptui.Prompt{\n\t\tLabel:     \"Delete Resource\",\n\t\tIsConfirm: true,\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %q\\n\", result)\n}\n"
  },
  {
    "path": "_examples/custom_prompt/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\ntype pepper struct {\n\tName     string\n\tHeatUnit int\n\tPeppers  int\n}\n\nfunc main() {\n\tvalidate := func(input string) error {\n\t\t_, err := strconv.ParseFloat(input, 64)\n\t\treturn err\n\t}\n\n\ttemplates := &promptui.PromptTemplates{\n\t\tPrompt:  \"{{ . }} \",\n\t\tValid:   \"{{ . | green }} \",\n\t\tInvalid: \"{{ . | red }} \",\n\t\tSuccess: \"{{ . | bold }} \",\n\t}\n\n\tprompt := promptui.Prompt{\n\t\tLabel:     \"Spicy Level\",\n\t\tTemplates: templates,\n\t\tValidate:  validate,\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You answered %s\\n\", result)\n}\n"
  },
  {
    "path": "_examples/custom_select/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\ntype pepper struct {\n\tName     string\n\tHeatUnit int\n\tPeppers  int\n}\n\nfunc main() {\n\tpeppers := []pepper{\n\t\t{Name: \"Bell Pepper\", HeatUnit: 0, Peppers: 0},\n\t\t{Name: \"Banana Pepper\", HeatUnit: 100, Peppers: 1},\n\t\t{Name: \"Poblano\", HeatUnit: 1000, Peppers: 2},\n\t\t{Name: \"Jalapeño\", HeatUnit: 3500, Peppers: 3},\n\t\t{Name: \"Aleppo\", HeatUnit: 10000, Peppers: 4},\n\t\t{Name: \"Tabasco\", HeatUnit: 30000, Peppers: 5},\n\t\t{Name: \"Malagueta\", HeatUnit: 50000, Peppers: 6},\n\t\t{Name: \"Habanero\", HeatUnit: 100000, Peppers: 7},\n\t\t{Name: \"Red Savina Habanero\", HeatUnit: 350000, Peppers: 8},\n\t\t{Name: \"Dragon’s Breath\", HeatUnit: 855000, Peppers: 9},\n\t}\n\n\ttemplates := &promptui.SelectTemplates{\n\t\tLabel:    \"{{ . }}?\",\n\t\tActive:   \"\\U0001F336 {{ .Name | cyan }} ({{ .HeatUnit | red }})\",\n\t\tInactive: \"  {{ .Name | cyan }} ({{ .HeatUnit | red }})\",\n\t\tSelected: \"\\U0001F336 {{ .Name | red | cyan }}\",\n\t\tDetails: `\n--------- Pepper ----------\n{{ \"Name:\" | faint }}\t{{ .Name }}\n{{ \"Heat Unit:\" | faint }}\t{{ .HeatUnit }}\n{{ \"Peppers:\" | faint }}\t{{ .Peppers }}`,\n\t}\n\n\tsearcher := func(input string, index int) bool {\n\t\tpepper := peppers[index]\n\t\tname := strings.Replace(strings.ToLower(pepper.Name), \" \", \"\", -1)\n\t\tinput = strings.Replace(strings.ToLower(input), \" \", \"\", -1)\n\n\t\treturn strings.Contains(name, input)\n\t}\n\n\tprompt := promptui.Select{\n\t\tLabel:     \"Spicy Level\",\n\t\tItems:     peppers,\n\t\tTemplates: templates,\n\t\tSize:      4,\n\t\tSearcher:  searcher,\n\t}\n\n\ti, _, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose number %d: %s\\n\", i+1, peppers[i].Name)\n}\n"
  },
  {
    "path": "_examples/prompt/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\tvalidate := func(input string) error {\n\t\t_, err := strconv.ParseFloat(input, 64)\n\t\tif err != nil {\n\t\t\treturn errors.New(\"Invalid number\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tprompt := promptui.Prompt{\n\t\tLabel:    \"Number\",\n\t\tValidate: validate,\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %q\\n\", result)\n}\n"
  },
  {
    "path": "_examples/prompt_default/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os/user\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\tvalidate := func(input string) error {\n\t\tif len(input) < 3 {\n\t\t\treturn errors.New(\"Username must have more than 3 characters\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tvar username string\n\tu, err := user.Current()\n\tif err == nil {\n\t\tusername = u.Username\n\t}\n\n\tprompt := promptui.Prompt{\n\t\tLabel:    \"Username\",\n\t\tValidate: validate,\n\t\tDefault:  username,\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"Your username is %q\\n\", result)\n}\n"
  },
  {
    "path": "_examples/prompt_password/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\tvalidate := func(input string) error {\n\t\tif len(input) < 6 {\n\t\t\treturn errors.New(\"Password must have more than 6 characters\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tprompt := promptui.Prompt{\n\t\tLabel:    \"Password\",\n\t\tValidate: validate,\n\t\tMask:     '*',\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"Your password is %q\\n\", result)\n}\n"
  },
  {
    "path": "_examples/select/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\tprompt := promptui.Select{\n\t\tLabel: \"Select Day\",\n\t\tItems: []string{\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\",\n\t\t\t\"Saturday\", \"Sunday\"},\n\t}\n\n\t_, result, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %q\\n\", result)\n}\n"
  },
  {
    "path": "_examples/select_add/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/manifoldco/promptui\"\n)\n\nfunc main() {\n\titems := []string{\"Vim\", \"Emacs\", \"Sublime\", \"VSCode\", \"Atom\"}\n\tindex := -1\n\tvar result string\n\tvar err error\n\n\tfor index < 0 {\n\t\tprompt := promptui.SelectWithAdd{\n\t\t\tLabel:    \"What's your text editor\",\n\t\t\tItems:    items,\n\t\t\tAddLabel: \"Other\",\n\t\t}\n\n\t\tindex, result, err = prompt.Run()\n\n\t\tif index == -1 {\n\t\t\titems = append(items, result)\n\t\t}\n\t}\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %s\\n\", result)\n}\n"
  },
  {
    "path": "codes.go",
    "content": "package promptui\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n)\n\nconst esc = \"\\033[\"\n\ntype attribute int\n\n// The possible state of text inside the application, either Bold, faint, italic or underline.\n//\n// These constants are called through the use of the Styler function.\nconst (\n\treset attribute = iota\n\n\tFGBold\n\tFGFaint\n\tFGItalic\n\tFGUnderline\n)\n\n// The possible colors of text inside the application.\n//\n// These constants are called through the use of the Styler function.\nconst (\n\tFGBlack attribute = iota + 30\n\tFGRed\n\tFGGreen\n\tFGYellow\n\tFGBlue\n\tFGMagenta\n\tFGCyan\n\tFGWhite\n)\n\n// The possible background colors of text inside the application.\n//\n// These constants are called through the use of the Styler function.\nconst (\n\tBGBlack attribute = iota + 40\n\tBGRed\n\tBGGreen\n\tBGYellow\n\tBGBlue\n\tBGMagenta\n\tBGCyan\n\tBGWhite\n)\n\n// ResetCode is the character code used to reset the terminal formatting\nvar ResetCode = fmt.Sprintf(\"%s%dm\", esc, reset)\n\nconst (\n\thideCursor = esc + \"?25l\"\n\tshowCursor = esc + \"?25h\"\n\tclearLine  = esc + \"2K\"\n)\n\n// FuncMap defines template helpers for the output. It can be extended as a regular map.\n//\n// The functions inside the map link the state, color and background colors strings detected in templates to a Styler\n// function that applies the given style using the corresponding constant.\nvar FuncMap = template.FuncMap{\n\t\"black\":     Styler(FGBlack),\n\t\"red\":       Styler(FGRed),\n\t\"green\":     Styler(FGGreen),\n\t\"yellow\":    Styler(FGYellow),\n\t\"blue\":      Styler(FGBlue),\n\t\"magenta\":   Styler(FGMagenta),\n\t\"cyan\":      Styler(FGCyan),\n\t\"white\":     Styler(FGWhite),\n\t\"bgBlack\":   Styler(BGBlack),\n\t\"bgRed\":     Styler(BGRed),\n\t\"bgGreen\":   Styler(BGGreen),\n\t\"bgYellow\":  Styler(BGYellow),\n\t\"bgBlue\":    Styler(BGBlue),\n\t\"bgMagenta\": Styler(BGMagenta),\n\t\"bgCyan\":    Styler(BGCyan),\n\t\"bgWhite\":   Styler(BGWhite),\n\t\"bold\":      Styler(FGBold),\n\t\"faint\":     Styler(FGFaint),\n\t\"italic\":    Styler(FGItalic),\n\t\"underline\": Styler(FGUnderline),\n}\n\nfunc upLine(n uint) string {\n\treturn movementCode(n, 'A')\n}\n\nfunc movementCode(n uint, code rune) string {\n\treturn esc + strconv.FormatUint(uint64(n), 10) + string(code)\n}\n\n// Styler is a function that accepts multiple possible styling transforms from the state,\n// color and background colors constants and transforms them into a templated string\n// to apply those styles in the CLI.\n//\n// The returned styling function accepts a string that will be extended with\n// the wrapping function's styling attributes.\nfunc Styler(attrs ...attribute) func(interface{}) string {\n\tattrstrs := make([]string, len(attrs))\n\tfor i, v := range attrs {\n\t\tattrstrs[i] = strconv.Itoa(int(v))\n\t}\n\n\tseq := strings.Join(attrstrs, \";\")\n\n\treturn func(v interface{}) string {\n\t\tend := \"\"\n\t\ts, ok := v.(string)\n\t\tif !ok || !strings.HasSuffix(s, ResetCode) {\n\t\t\tend = ResetCode\n\t\t}\n\t\treturn fmt.Sprintf(\"%s%sm%v%s\", esc, seq, v, end)\n\t}\n}\n"
  },
  {
    "path": "codes_test.go",
    "content": "package promptui\n\nimport \"testing\"\n\nfunc TestStyler(t *testing.T) {\n\tt.Run(\"renders a single code\", func(t *testing.T) {\n\t\tred := Styler(FGRed)(\"hi\")\n\t\texpected := \"\\033[31mhi\\033[0m\"\n\t\tif red != expected {\n\t\t\tt.Errorf(\"style did not match: %s != %s\", red, expected)\n\t\t}\n\t})\n\n\tt.Run(\"combines multiple codes\", func(t *testing.T) {\n\t\tboldRed := Styler(FGRed, FGBold)(\"hi\")\n\t\texpected := \"\\033[31;1mhi\\033[0m\"\n\t\tif boldRed != expected {\n\t\t\tt.Errorf(\"style did not match: %s != %s\", boldRed, expected)\n\t\t}\n\t})\n\n\tt.Run(\"should not repeat reset codes for nested styles\", func(t *testing.T) {\n\t\tred := Styler(FGRed)(\"hi\")\n\t\tboldRed := Styler(FGBold)(red)\n\t\texpected := \"\\033[1m\\033[31mhi\\033[0m\"\n\t\tif boldRed != expected {\n\t\t\tt.Errorf(\"style did not match: %s != %s\", boldRed, expected)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "cursor.go",
    "content": "package promptui\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Pointer is A specific type that translates a given set of runes into a given\n// set of runes pointed at by the cursor.\ntype Pointer func(to []rune) []rune\n\nfunc defaultCursor(ignored []rune) []rune {\n\treturn []rune(\"\\u2588\")\n}\n\nfunc blockCursor(input []rune) []rune {\n\treturn []rune(fmt.Sprintf(\"\\\\e[7m%s\\\\e[0m\", string(input)))\n}\n\nfunc pipeCursor(input []rune) []rune {\n\tmarker := []rune(\"|\")\n\tout := []rune{}\n\tout = append(out, marker...)\n\tout = append(out, input...)\n\treturn out\n}\n\nvar (\n\t// DefaultCursor is a big square block character. Obscures whatever was\n\t// input.\n\tDefaultCursor Pointer = defaultCursor\n\t// BlockCursor is a cursor which highlights a character by inverting colors\n\t// on it.\n\tBlockCursor Pointer = blockCursor\n\t// PipeCursor is a pipe character \"|\" which appears before the input\n\t// character.\n\tPipeCursor Pointer = pipeCursor\n)\n\n// Cursor tracks the state associated with the movable cursor\n// The strategy is to keep the prompt, input pristine except for requested\n// modifications. The insertion of the cursor happens during a `format` call\n// and we read in new input via an `Update` call\ntype Cursor struct {\n\t// shows where the user inserts/updates text\n\tCursor Pointer\n\t// what the user entered, and what we will echo back to them, after\n\t// insertion of the cursor and prefixing with the prompt\n\tinput []rune\n\t// Put the cursor before this slice\n\tPosition int\n\terase    bool\n}\n\n// NewCursor create a new cursor, with the DefaultCursor, the specified input,\n// and position at the end of the specified starting input.\nfunc NewCursor(startinginput string, pointer Pointer, eraseDefault bool) Cursor {\n\tif pointer == nil {\n\t\tpointer = defaultCursor\n\t}\n\tcur := Cursor{Cursor: pointer, Position: len(startinginput), input: []rune(startinginput), erase: eraseDefault}\n\tif eraseDefault {\n\t\tcur.Start()\n\t} else {\n\t\tcur.End()\n\t}\n\treturn cur\n}\n\nfunc (c *Cursor) String() string {\n\treturn fmt.Sprintf(\n\t\t\"Cursor: %s, input %s, Position %d\",\n\t\tstring(c.Cursor([]rune(\"\"))), string(c.input), c.Position)\n}\n\n// End is a convenience for c.Place(len(c.input)) so you don't have to know how I\n// indexed.\nfunc (c *Cursor) End() {\n\tc.Place(len(c.input))\n}\n\n// Start is convenience for c.Place(0) so you don't have to know how I\n// indexed.\nfunc (c *Cursor) Start() {\n\tc.Place(0)\n}\n\n// ensures we are in bounds.\nfunc (c *Cursor) correctPosition() {\n\tif c.Position > len(c.input) {\n\t\tc.Position = len(c.input)\n\t}\n\n\tif c.Position < 0 {\n\t\tc.Position = 0\n\t}\n}\n\n// insert the cursor rune array into r before the provided index\nfunc format(a []rune, c *Cursor) string {\n\ti := c.Position\n\tvar b []rune\n\n\tout := make([]rune, 0)\n\tif i < len(a) {\n\t\tb = c.Cursor(a[i : i+1])\n\t\tout = append(out, a[:i]...)   // does not include i\n\t\tout = append(out, b...)       // add the cursor\n\t\tout = append(out, a[i+1:]...) // add the rest after i\n\t} else {\n\t\tb = c.Cursor([]rune{})\n\t\tout = append(out, a...)\n\t\tout = append(out, b...)\n\t}\n\treturn string(out)\n}\n\n// Format renders the input with the Cursor appropriately positioned.\nfunc (c *Cursor) Format() string {\n\tr := c.input\n\t// insert the cursor\n\treturn format(r, c)\n}\n\n// FormatMask replaces all input runes with the mask rune.\nfunc (c *Cursor) FormatMask(mask rune) string {\n\tif mask == ' ' {\n\t\treturn format([]rune{}, c)\n\t}\n\n\tr := make([]rune, len(c.input))\n\tfor i := range r {\n\t\tr[i] = mask\n\t}\n\treturn format(r, c)\n}\n\n// Update inserts newinput into the input []rune in the appropriate place.\n// The cursor is moved to the end of the inputed sequence.\nfunc (c *Cursor) Update(newinput string) {\n\ta := c.input\n\tb := []rune(newinput)\n\ti := c.Position\n\ta = append(a[:i], append(b, a[i:]...)...)\n\tc.input = a\n\tc.Move(len(b))\n}\n\n// Get returns a copy of the input\nfunc (c *Cursor) Get() string {\n\treturn string(c.input)\n}\n\n// GetMask returns a mask string with length equal to the input\nfunc (c *Cursor) GetMask(mask rune) string {\n\treturn strings.Repeat(string(mask), len(c.input))\n}\n\n// Replace replaces the previous input with whatever is specified, and moves the\n// cursor to the end position\nfunc (c *Cursor) Replace(input string) {\n\tc.input = []rune(input)\n\tc.End()\n}\n\n// Place moves the cursor to the absolute array index specified by position\nfunc (c *Cursor) Place(position int) {\n\tc.Position = position\n\tc.correctPosition()\n}\n\n// Move moves the cursor over in relative terms, by shift indices.\nfunc (c *Cursor) Move(shift int) {\n\t// delete the current cursor\n\tc.Position = c.Position + shift\n\tc.correctPosition()\n}\n\n// Backspace removes the rune that precedes the cursor\n//\n// It handles being at the beginning or end of the row, and moves the cursor to\n// the appropriate position.\nfunc (c *Cursor) Backspace() {\n\ta := c.input\n\ti := c.Position\n\tif i == 0 {\n\t\t// Shrug\n\t\treturn\n\t}\n\tif i == len(a) {\n\t\tc.input = a[:i-1]\n\t} else {\n\t\tc.input = append(a[:i-1], a[i:]...)\n\t}\n\t// now it's pointing to the i+1th element\n\tc.Move(-1)\n}\n\n// Listen is a readline Listener that updates internal cursor state appropriately.\nfunc (c *Cursor) Listen(line []rune, pos int, key rune) ([]rune, int, bool) {\n\tif line != nil {\n\t\t// no matter what, update our internal representation.\n\t\tc.Update(string(line))\n\t}\n\n\tswitch key {\n\tcase 0: // empty\n\tcase KeyEnter:\n\t\treturn []rune(c.Get()), c.Position, false\n\tcase KeyBackspace, KeyCtrlH:\n\t\tif c.erase {\n\t\t\tc.erase = false\n\t\t\tc.Replace(\"\")\n\t\t}\n\t\tc.Backspace()\n\tcase KeyForward:\n\t\t// the user wants to edit the default, despite how we set it up. Let\n\t\t// them.\n\t\tc.erase = false\n\t\tc.Move(1)\n\tcase KeyBackward:\n\t\tc.Move(-1)\n\tdefault:\n\t\tif c.erase {\n\t\t\tc.erase = false\n\t\t\tc.Replace(\"\")\n\t\t\tc.Update(string(key))\n\t\t}\n\t}\n\n\treturn []rune(c.Get()), c.Position, true\n}\n"
  },
  {
    "path": "cursor_test.go",
    "content": "package promptui\n\nimport \"testing\"\n\nfunc TestDefinedCursors(t *testing.T) {\n\tt.Run(\"pipeCursor\", func(t *testing.T) {\n\t\tp := string(pipeCursor([]rune{}))\n\t\tif p != \"|\" {\n\t\t\tt.Fatalf(\"%x!=%x\", \"|\", p)\n\t\t}\n\t})\n}\n\nfunc TestCursor(t *testing.T) {\n\tt.Run(\"empty\", func(t *testing.T) {\n\t\tcursor := Cursor{Cursor: pipeCursor}\n\t\tcursor.End()\n\t\tf := cursor.Format()\n\t\tif f != \"|\" {\n\t\t\tt.Errorf(\"% x!=% x\", \"|\", cursor.Format())\n\t\t}\n\n\t\tcursor.Update(\"sup\")\n\t\tif cursor.Format() != \"sup|\" {\n\t\t\tt.Errorf(\"% x!=% x\", \"sup|\", cursor.Format())\n\t\t}\n\t})\n\n\tt.Run(\"Cursor at end, append additional\", func(t *testing.T) {\n\t\tcursor := Cursor{input: []rune(\"a\"), Cursor: pipeCursor}\n\t\tcursor.End()\n\t\tf := cursor.Format()\n\t\tif f != \"a|\" {\n\t\t\tt.Errorf(\"% x!=% x\", \"a|\", cursor.Format())\n\t\t}\n\n\t\tcursor.Update(\" hi\")\n\t\tif cursor.Format() != \"a hi|\" {\n\t\t\tt.Errorf(\"% x!=% x\", \"a hi!\", cursor.Format())\n\t\t}\n\t})\n\n\tt.Run(\"Cursor at at end, backspace\", func(t *testing.T) {\n\t\tcursor := Cursor{input: []rune(\"default\"), Cursor: pipeCursor}\n\t\tcursor.Place(len(cursor.input))\n\t\tcursor.Backspace()\n\n\t\tif cursor.Format() != \"defaul|\" {\n\t\t\tt.Errorf(\"expected defaul|; found %s\", cursor.Format())\n\t\t}\n\n\t\tcursor.Update(\" hi\")\n\t\tif cursor.Format() != \"defaul hi|\" {\n\t\t\tt.Errorf(\"expected 'defaul hi|'; found '%s'\", cursor.Format())\n\t\t}\n\t})\n\n\tt.Run(\"Cursor at beginning, append additional\", func(t *testing.T) {\n\t\tcursor := Cursor{input: []rune(\"default\"), Cursor: pipeCursor}\n\t\tt.Log(\"init\", cursor.String())\n\t\tcursor.Backspace()\n\t\tif cursor.Format() != \"|default\" {\n\t\t\tt.Errorf(\"expected |default; found %s\", cursor.Format())\n\t\t}\n\n\t\tcursor.Update(\"hi \")\n\t\tt.Log(\"after add\", cursor.String())\n\t\tif cursor.Format() != \"hi |default\" {\n\t\t\tt.Errorf(\"expected 'hi |default'; found '%s'\", cursor.Format())\n\t\t}\n\t\tcursor.Backspace()\n\t\tt.Log(\"after backspace\", cursor.String())\n\t\tif cursor.Format() != \"hi|default\" {\n\t\t\tt.Errorf(\"expected 'hi|default'; found '%s'\", cursor.Format())\n\t\t}\n\n\t\tcursor.Backspace()\n\t\tt.Log(\"after backspace\", cursor.String())\n\t\tif cursor.Format() != \"h|default\" {\n\t\t\tt.Errorf(\"expected 'h|default'; found '%s'\", cursor.Format())\n\t\t}\n\t})\n\n\tt.Run(\"Move\", func(t *testing.T) {\n\t\tcursor := Cursor{input: []rune(\"default\"), Cursor: pipeCursor}\n\t\tif cursor.Format() != \"|default\" {\n\t\t\tt.Errorf(\"expected |default; found %s\", cursor.Format())\n\t\t}\n\t\tcursor.Move(-1)\n\t\tif cursor.Format() != \"|default\" {\n\t\t\tt.Errorf(\"moved backwards from beginning |default; found %s\", cursor.Format())\n\t\t}\n\n\t\tcursor.Move(1)\n\t\tif cursor.Format() != \"d|efault\" {\n\t\t\tt.Errorf(\"expected 'd|efault'; found '%s'\", cursor.Format())\n\t\t}\n\t\tcursor.Move(10)\n\t\tif cursor.Format() != \"default|\" {\n\t\t\tt.Errorf(\"expected 'default|'; found '%s'\", cursor.Format())\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "example_main_test.go",
    "content": "package promptui\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n)\n\n// This is an example for the Prompt mode of promptui. In this example, a prompt is created\n// with a validator function that validates the given value to make sure its a number.\n// If successful, it will output the chosen number in a formatted message.\nfunc Example_prompt() {\n\tvalidate := func(input string) error {\n\t\t_, err := strconv.ParseFloat(input, 64)\n\t\tif err != nil {\n\t\t\treturn errors.New(\"Invalid number\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tprompt := Prompt{\n\t\tLabel:    \"Number\",\n\t\tValidate: validate,\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %q\\n\", result)\n}\n\n// This is an example for the Select mode of promptui. In this example, a select is created with\n// the days of the week as its items. When an item is selected, the selected day will be displayed\n// in a formatted message.\nfunc Example_select() {\n\tprompt := Select{\n\t\tLabel: \"Select Day\",\n\t\tItems: []string{\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\",\n\t\t\t\"Saturday\", \"Sunday\"},\n\t}\n\n\t_, result, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %q\\n\", result)\n}\n"
  },
  {
    "path": "example_prompt_test.go",
    "content": "package promptui\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\n// This example shows how to use the prompt validator and templates to create a stylized prompt.\n// The validator will make sure the value entered is a parseable float while the templates will\n// color the value to show validity.\nfunc ExamplePrompt() {\n\t// The validate function follows the required validator signature.\n\tvalidate := func(input string) error {\n\t\t_, err := strconv.ParseFloat(input, 64)\n\t\treturn err\n\t}\n\n\t// Each template displays the data received from the prompt with some formatting.\n\ttemplates := &PromptTemplates{\n\t\tPrompt:  \"{{ . }} \",\n\t\tValid:   \"{{ . | green }} \",\n\t\tInvalid: \"{{ . | red }} \",\n\t\tSuccess: \"{{ . | bold }} \",\n\t}\n\n\tprompt := Prompt{\n\t\tLabel:     \"Spicy Level\",\n\t\tTemplates: templates,\n\t\tValidate:  validate,\n\t}\n\n\tresult, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\t// The result of the prompt, if valid, is displayed in a formatted message.\n\tfmt.Printf(\"You answered %s\\n\", result)\n}\n"
  },
  {
    "path": "example_select_test.go",
    "content": "package promptui\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Any type can be given to the select's item as long as the templates properly implement the dot notation\n// to display it.\ntype pepper struct {\n\tName     string\n\tHeatUnit int\n\tPeppers  int\n}\n\n// This examples shows a complex and customized select.\nfunc ExampleSelect() {\n\t// The select will show a series of peppers stored inside a slice of structs. To display the content of the struct,\n\t// the usual dot notation is used inside the templates to select the fields and color them.\n\tpeppers := []pepper{\n\t\t{Name: \"Bell Pepper\", HeatUnit: 0, Peppers: 0},\n\t\t{Name: \"Banana Pepper\", HeatUnit: 100, Peppers: 1},\n\t\t{Name: \"Poblano\", HeatUnit: 1000, Peppers: 2},\n\t\t{Name: \"Jalapeño\", HeatUnit: 3500, Peppers: 3},\n\t\t{Name: \"Aleppo\", HeatUnit: 10000, Peppers: 4},\n\t\t{Name: \"Tabasco\", HeatUnit: 30000, Peppers: 5},\n\t\t{Name: \"Malagueta\", HeatUnit: 50000, Peppers: 6},\n\t\t{Name: \"Habanero\", HeatUnit: 100000, Peppers: 7},\n\t\t{Name: \"Red Savina Habanero\", HeatUnit: 350000, Peppers: 8},\n\t\t{Name: \"Dragon’s Breath\", HeatUnit: 855000, Peppers: 9},\n\t}\n\n\t// The Active and Selected templates set a small pepper icon next to the name colored and the heat unit for the\n\t// active template. The details template is show at the bottom of the select's list and displays the full info\n\t// for that pepper in a multi-line template.\n\ttemplates := &SelectTemplates{\n\t\tLabel:    \"{{ . }}?\",\n\t\tActive:   \"\\U0001F336 {{ .Name | cyan }} ({{ .HeatUnit | red }})\",\n\t\tInactive: \"  {{ .Name | cyan }} ({{ .HeatUnit | red }})\",\n\t\tSelected: \"\\U0001F336 {{ .Name | red | cyan }}\",\n\t\tDetails: `\n--------- Pepper ----------\n{{ \"Name:\" | faint }}\t{{ .Name }}\n{{ \"Heat Unit:\" | faint }}\t{{ .HeatUnit }}\n{{ \"Peppers:\" | faint }}\t{{ .Peppers }}`,\n\t}\n\n\t// A searcher function is implemented which enabled the search mode for the select. The function follows\n\t// the required searcher signature and finds any pepper whose name contains the searched string.\n\tsearcher := func(input string, index int) bool {\n\t\tpepper := peppers[index]\n\t\tname := strings.Replace(strings.ToLower(pepper.Name), \" \", \"\", -1)\n\t\tinput = strings.Replace(strings.ToLower(input), \" \", \"\", -1)\n\n\t\treturn strings.Contains(name, input)\n\t}\n\n\tprompt := Select{\n\t\tLabel:     \"Spicy Level\",\n\t\tItems:     peppers,\n\t\tTemplates: templates,\n\t\tSize:      4,\n\t\tSearcher:  searcher,\n\t}\n\n\ti, _, err := prompt.Run()\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\t// The selected pepper will be displayed with its name and index in a formatted message.\n\tfmt.Printf(\"You choose number %d: %s\\n\", i+1, peppers[i].Name)\n}\n"
  },
  {
    "path": "example_selectwithadd_test.go",
    "content": "package promptui\n\nimport \"fmt\"\n\n// This example shows how to create a SelectWithAdd that will add each new item it is given to the\n// list of items until one is chosen.\nfunc ExampleSelectWithAdd() {\n\titems := []string{\"Vim\", \"Emacs\", \"Sublime\", \"VSCode\", \"Atom\"}\n\tindex := -1\n\tvar result string\n\tvar err error\n\n\tfor index < 0 {\n\t\tprompt := SelectWithAdd{\n\t\t\tLabel:    \"What's your text editor\",\n\t\t\tItems:    items,\n\t\t\tAddLabel: \"Add your own\",\n\t\t}\n\n\t\tindex, result, err = prompt.Run()\n\n\t\tif index == -1 {\n\t\t\titems = append(items, result)\n\t\t}\n\t}\n\n\tif err != nil {\n\t\tfmt.Printf(\"Prompt failed %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"You choose %s\\n\", result)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/manifoldco/promptui\n\ngo 1.12\n\nrequire (\n\tgithub.com/chzyer/logex v1.1.10 // indirect\n\tgithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e\n\tgithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect\n\tgolang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngolang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b h1:MQE+LT/ABUuuvEZ+YQAMSXindAdUh7slEmAkup74op4=\ngolang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\n"
  },
  {
    "path": "keycodes.go",
    "content": "package promptui\n\nimport \"github.com/chzyer/readline\"\n\n// These runes are used to identify the commands entered by the user in the command prompt. They map\n// to specific actions of promptui in prompt mode and can be remapped if necessary.\nvar (\n\t// KeyEnter is the default key for submission/selection.\n\tKeyEnter rune = readline.CharEnter\n\n\t// KeyCtrlH is the key for deleting input text.\n\tKeyCtrlH rune = readline.CharCtrlH\n\n\t// KeyPrev is the default key to go up during selection.\n\tKeyPrev        rune = readline.CharPrev\n\tKeyPrevDisplay      = \"↑\"\n\n\t// KeyNext is the default key to go down during selection.\n\tKeyNext        rune = readline.CharNext\n\tKeyNextDisplay      = \"↓\"\n\n\t// KeyBackward is the default key to page up during selection.\n\tKeyBackward        rune = readline.CharBackward\n\tKeyBackwardDisplay      = \"←\"\n\n\t// KeyForward is the default key to page down during selection.\n\tKeyForward        rune = readline.CharForward\n\tKeyForwardDisplay      = \"→\"\n)\n"
  },
  {
    "path": "keycodes_other.go",
    "content": "// +build !windows\n\npackage promptui\n\nimport \"github.com/chzyer/readline\"\n\nvar (\n\t// KeyBackspace is the default key for deleting input text.\n\tKeyBackspace rune = readline.CharBackspace\n)\n"
  },
  {
    "path": "keycodes_windows.go",
    "content": "// +build windows\n\npackage promptui\n\n// source: https://msdn.microsoft.com/en-us/library/aa243025(v=vs.60).aspx\n\nvar (\n\t// KeyBackspace is the default key for deleting input text inside a command line prompt.\n\tKeyBackspace rune = 8\n)\n"
  },
  {
    "path": "list/list.go",
    "content": "package list\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n)\n\n// Searcher is a base function signature that is used inside select when activating the search mode.\n// If defined, it is called on each items of the select and should return a boolean for whether or not\n// the item fits the searched term.\ntype Searcher func(input string, index int) bool\n\n// NotFound is an index returned when no item was selected. This could\n// happen due to a search without results.\nconst NotFound = -1\n\n// List holds a collection of items that can be displayed with an N number of\n// visible items. The list can be moved up, down by one item of time or an\n// entire page (ie: visible size). It keeps track of the current selected item.\ntype List struct {\n\titems    []*interface{}\n\tscope    []*interface{}\n\tcursor   int // cursor holds the index of the current selected item\n\tsize     int // size is the number of visible options\n\tstart    int\n\tSearcher Searcher\n}\n\n// New creates and initializes a list of searchable items. The items attribute must be a slice type with a\n// size greater than 0. Error will be returned if those two conditions are not met.\nfunc New(items interface{}, size int) (*List, error) {\n\tif size < 1 {\n\t\treturn nil, fmt.Errorf(\"list size %d must be greater than 0\", size)\n\t}\n\n\tif items == nil || reflect.TypeOf(items).Kind() != reflect.Slice {\n\t\treturn nil, fmt.Errorf(\"items %v is not a slice\", items)\n\t}\n\n\tslice := reflect.ValueOf(items)\n\tvalues := make([]*interface{}, slice.Len())\n\n\tfor i := range values {\n\t\titem := slice.Index(i).Interface()\n\t\tvalues[i] = &item\n\t}\n\n\treturn &List{size: size, items: values, scope: values}, nil\n}\n\n// Prev moves the visible list back one item. If the selected item is out of\n// view, the new select item becomes the last visible item. If the list is\n// already at the top, nothing happens.\nfunc (l *List) Prev() {\n\tif l.cursor > 0 {\n\t\tl.cursor--\n\t}\n\n\tif l.start > l.cursor {\n\t\tl.start = l.cursor\n\t}\n}\n\n// Search allows the list to be filtered by a given term. The list must\n// implement the searcher function signature for this functionality to work.\nfunc (l *List) Search(term string) {\n\tterm = strings.Trim(term, \" \")\n\tl.cursor = 0\n\tl.start = 0\n\tl.search(term)\n}\n\n// CancelSearch stops the current search and returns the list to its\n// original order.\nfunc (l *List) CancelSearch() {\n\tl.cursor = 0\n\tl.start = 0\n\tl.scope = l.items\n}\n\nfunc (l *List) search(term string) {\n\tvar scope []*interface{}\n\n\tfor i, item := range l.items {\n\t\tif l.Searcher(term, i) {\n\t\t\tscope = append(scope, item)\n\t\t}\n\t}\n\n\tl.scope = scope\n}\n\n// Start returns the current render start position of the list.\nfunc (l *List) Start() int {\n\treturn l.start\n}\n\n// SetStart sets the current scroll position. Values out of bounds will be\n// clamped.\nfunc (l *List) SetStart(i int) {\n\tif i < 0 {\n\t\ti = 0\n\t}\n\tif i > l.cursor {\n\t\tl.start = l.cursor\n\t} else {\n\t\tl.start = i\n\t}\n}\n\n// SetCursor sets the position of the cursor in the list. Values out of bounds\n// will be clamped.\nfunc (l *List) SetCursor(i int) {\n\tmax := len(l.scope) - 1\n\tif i >= max {\n\t\ti = max\n\t}\n\tif i < 0 {\n\t\ti = 0\n\t}\n\tl.cursor = i\n\n\tif l.start > l.cursor {\n\t\tl.start = l.cursor\n\t} else if l.start+l.size <= l.cursor {\n\t\tl.start = l.cursor - l.size + 1\n\t}\n}\n\n// Next moves the visible list forward one item. If the selected item is out of\n// view, the new select item becomes the first visible item. If the list is\n// already at the bottom, nothing happens.\nfunc (l *List) Next() {\n\tmax := len(l.scope) - 1\n\n\tif l.cursor < max {\n\t\tl.cursor++\n\t}\n\n\tif l.start+l.size <= l.cursor {\n\t\tl.start = l.cursor - l.size + 1\n\t}\n}\n\n// PageUp moves the visible list backward by x items. Where x is the size of the\n// visible items on the list. The selected item becomes the first visible item.\n// If the list is already at the bottom, the selected item becomes the last\n// visible item.\nfunc (l *List) PageUp() {\n\tstart := l.start - l.size\n\tif start < 0 {\n\t\tl.start = 0\n\t} else {\n\t\tl.start = start\n\t}\n\n\tcursor := l.start\n\n\tif cursor < l.cursor {\n\t\tl.cursor = cursor\n\t}\n}\n\n// PageDown moves the visible list forward by x items. Where x is the size of\n// the visible items on the list. The selected item becomes the first visible\n// item.\nfunc (l *List) PageDown() {\n\tstart := l.start + l.size\n\tmax := len(l.scope) - l.size\n\n\tswitch {\n\tcase len(l.scope) < l.size:\n\t\tl.start = 0\n\tcase start > max:\n\t\tl.start = max\n\tdefault:\n\t\tl.start = start\n\t}\n\n\tcursor := l.start\n\n\tif cursor == l.cursor {\n\t\tl.cursor = len(l.scope) - 1\n\t} else if cursor > l.cursor {\n\t\tl.cursor = cursor\n\t}\n}\n\n// CanPageDown returns whether a list can still PageDown().\nfunc (l *List) CanPageDown() bool {\n\tmax := len(l.scope)\n\treturn l.start+l.size < max\n}\n\n// CanPageUp returns whether a list can still PageUp().\nfunc (l *List) CanPageUp() bool {\n\treturn l.start > 0\n}\n\n// Index returns the index of the item currently selected inside the searched list. If no item is selected,\n// the NotFound (-1) index is returned.\nfunc (l *List) Index() int {\n\tselected := l.scope[l.cursor]\n\n\tfor i, item := range l.items {\n\t\tif item == selected {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn NotFound\n}\n\n// Items returns a slice equal to the size of the list with the current visible\n// items and the index of the active item in this list.\nfunc (l *List) Items() ([]interface{}, int) {\n\tvar result []interface{}\n\tmax := len(l.scope)\n\tend := l.start + l.size\n\n\tif end > max {\n\t\tend = max\n\t}\n\n\tactive := NotFound\n\n\tfor i, j := l.start, 0; i < end; i, j = i+1, j+1 {\n\t\tif l.cursor == i {\n\t\t\tactive = j\n\t\t}\n\n\t\tresult = append(result, *l.scope[i])\n\t}\n\n\treturn result, active\n}\n"
  },
  {
    "path": "list/list_test.go",
    "content": "package list\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestListNew(t *testing.T) {\n\tt.Run(\"when items a slice nil\", func(t *testing.T) {\n\t\t_, err := New([]int{1, 2, 3}, 3)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Expected no errors, error %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"when items is nil\", func(t *testing.T) {\n\t\t_, err := New(nil, 3)\n\t\tif err == nil {\n\t\t\tt.Errorf(\"Expected error got none\")\n\t\t}\n\t})\n\n\tt.Run(\"when items is not a slice\", func(t *testing.T) {\n\t\t_, err := New(\"1,2,3\", 3)\n\t\tif err == nil {\n\t\t\tt.Errorf(\"Expected error got none\")\n\t\t}\n\t})\n}\n\nfunc TestListMovement(t *testing.T) {\n\tletters := []rune{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}\n\n\tl, err := New(letters, 4)\n\tif err != nil {\n\t\tt.Fatalf(\"Expected no error, got %v\", err)\n\t}\n\n\ttcs := []struct {\n\t\texpect   []rune\n\t\tmove     string\n\t\tselected rune\n\t}{\n\t\t{move: \"next\", selected: 'b', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"prev\", selected: 'a', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"prev\", selected: 'a', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"next\", selected: 'b', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"next\", selected: 'c', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"next\", selected: 'd', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"next\", selected: 'e', expect: []rune{'b', 'c', 'd', 'e'}},\n\t\t{move: \"prev\", selected: 'd', expect: []rune{'b', 'c', 'd', 'e'}},\n\t\t{move: \"up\", selected: 'a', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"up\", selected: 'a', expect: []rune{'a', 'b', 'c', 'd'}},\n\t\t{move: \"down\", selected: 'e', expect: []rune{'e', 'f', 'g', 'h'}},\n\t\t{move: \"down\", selected: 'g', expect: []rune{'g', 'h', 'i', 'j'}},\n\t\t{move: \"down\", selected: 'j', expect: []rune{'g', 'h', 'i', 'j'}},\n\t}\n\n\tfor _, tc := range tcs {\n\t\tt.Run(fmt.Sprintf(\"list %s\", tc.move), func(t *testing.T) {\n\t\t\tswitch tc.move {\n\t\t\tcase \"next\":\n\t\t\t\tl.Next()\n\t\t\tcase \"prev\":\n\t\t\t\tl.Prev()\n\t\t\tcase \"up\":\n\t\t\t\tl.PageUp()\n\t\t\tcase \"down\":\n\t\t\t\tl.PageDown()\n\t\t\tdefault:\n\t\t\t\tt.Fatalf(\"unknown move %q\", tc.move)\n\t\t\t}\n\n\t\t\tlist, idx := l.Items()\n\n\t\t\tgot := castList(list)\n\n\t\t\tif !reflect.DeepEqual(tc.expect, got) {\n\t\t\t\tt.Errorf(\"expected %q, got %q\", tc.expect, got)\n\t\t\t}\n\n\t\t\tselected := list[idx]\n\n\t\t\tif tc.selected != selected {\n\t\t\t\tt.Errorf(\"expected selected to be %q, got %q\", tc.selected, selected)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestListPageDown(t *testing.T) {\n\tt.Run(\"when list has fewer items than page size\", func(t *testing.T) {\n\t\tletters := []rune{'a', 'b'}\n\t\tl, err := New(letters, 4)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Expected no error, got %v\", err)\n\t\t}\n\n\t\tl.PageDown()\n\t\tlist, idx := l.Items()\n\n\t\texpected := 'b'\n\t\tselected := list[idx]\n\n\t\tif selected != expected {\n\t\t\tt.Errorf(\"expected selected to be %q, got %q\", expected, selected)\n\t\t}\n\t})\n}\n\nfunc TestListComparion(t *testing.T) {\n\tt.Run(\"when item supports comparison\", func(t *testing.T) {\n\t\ttype comparable struct {\n\t\t\tNumber int\n\t\t}\n\n\t\tstructs := []comparable{\n\t\t\t{Number: 1},\n\t\t\t{Number: 2},\n\t\t}\n\n\t\tl, err := New(structs, 4)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Expected no error, got %v\", err)\n\t\t}\n\n\t\tidx := l.Index()\n\n\t\tif idx != 0 {\n\t\t\tt.Errorf(\"expected index to be first, got %d\", idx)\n\t\t}\n\t})\n\n\tt.Run(\"when item doesn't support comparison\", func(t *testing.T) {\n\t\ttype uncomparable struct {\n\t\t\tNumbers []int\n\t\t}\n\n\t\tstructs := []uncomparable{\n\t\t\t{Numbers: []int{1}},\n\t\t\t{Numbers: []int{2}},\n\t\t}\n\n\t\tl, err := New(structs, 4)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Expected no error, got %v\", err)\n\t\t}\n\n\t\tidx := l.Index()\n\n\t\tif idx != 0 {\n\t\t\tt.Errorf(\"expected index to be first, got %d\", idx)\n\t\t}\n\t})\n}\n\nfunc castList(list []interface{}) []rune {\n\tresult := make([]rune, len(list))\n\tfor i, l := range list {\n\t\tresult[i] = l.(rune)\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "prompt.go",
    "content": "package promptui\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/chzyer/readline\"\n\t\"github.com/manifoldco/promptui/screenbuf\"\n)\n\n// Prompt represents a single line text field input with options for validation and input masks.\ntype Prompt struct {\n\t// Label is the value displayed on the command line prompt.\n\t//\n\t// The value for Label can be a simple string or a struct that will need to be accessed by dot notation\n\t// inside the templates. For example, `{{ .Name }}` will display the name property of a struct.\n\tLabel interface{}\n\n\t// Default is the initial value for the prompt. This value will be displayed next to the prompt's label\n\t// and the user will be able to view or change it depending on the options.\n\tDefault string\n\n\t// AllowEdit lets the user edit the default value. If false, any key press\n\t// other than <Enter> automatically clears the default value.\n\tAllowEdit bool\n\n\t// Validate is an optional function that fill be used against the entered value in the prompt to validate it.\n\tValidate ValidateFunc\n\n\t// Mask is an optional rune that sets which character to display instead of the entered characters. This\n\t// allows hiding private information like passwords.\n\tMask rune\n\n\t// HideEntered sets whether to hide the text after the user has pressed enter.\n\tHideEntered bool\n\n\t// Templates can be used to customize the prompt output. If nil is passed, the\n\t// default templates are used. See the PromptTemplates docs for more info.\n\tTemplates *PromptTemplates\n\n\t// IsConfirm makes the prompt ask for a yes or no ([Y/N]) question rather than request an input. When set,\n\t// most properties related to input will be ignored.\n\tIsConfirm bool\n\n\t// IsVimMode enables vi-like movements (hjkl) and editing.\n\tIsVimMode bool\n\n\t// the Pointer defines how to render the cursor.\n\tPointer Pointer\n\n\tStdin  io.ReadCloser\n\tStdout io.WriteCloser\n}\n\n// PromptTemplates allow a prompt to be customized following stdlib\n// text/template syntax. Custom state, colors and background color are available for use inside\n// the templates and are documented inside the Variable section of the docs.\n//\n// Examples\n//\n// text/templates use a special notation to display programmable content. Using the double bracket notation,\n// the value can be printed with specific helper functions. For example\n//\n// This displays the value given to the template as pure, unstylized text.\n// \t'{{ . }}'\n//\n// This displays the value colored in cyan\n// \t'{{ . | cyan }}'\n//\n// This displays the value colored in red with a cyan background-color\n// \t'{{ . | red | cyan }}'\n//\n// See the doc of text/template for more info: https://golang.org/pkg/text/template/\ntype PromptTemplates struct {\n\t// Prompt is a text/template for the prompt label displayed on the left side of the prompt.\n\tPrompt string\n\n\t// Prompt is a text/template for the prompt label when IsConfirm is set as true.\n\tConfirm string\n\n\t// Valid is a text/template for the prompt label when the value entered is valid.\n\tValid string\n\n\t// Invalid is a text/template for the prompt label when the value entered is invalid.\n\tInvalid string\n\n\t// Success is a text/template for the prompt label when the user has pressed entered and the value has been\n\t// deemed valid by the validation function. The label will keep using this template even when the prompt ends\n\t// inside the console.\n\tSuccess string\n\n\t// Prompt is a text/template for the prompt label when the value is invalid due to an error triggered by\n\t// the prompt's validation function.\n\tValidationError string\n\n\t// FuncMap is a map of helper functions that can be used inside of templates according to the text/template\n\t// documentation.\n\t//\n\t// By default, FuncMap contains the color functions used to color the text in templates. If FuncMap\n\t// is overridden, the colors functions must be added in the override from promptui.FuncMap to work.\n\tFuncMap template.FuncMap\n\n\tprompt     *template.Template\n\tvalid      *template.Template\n\tinvalid    *template.Template\n\tvalidation *template.Template\n\tsuccess    *template.Template\n}\n\n// Run executes the prompt. Its displays the label and default value if any, asking the user to enter a value.\n// Run will keep the prompt alive until it has been canceled from the command prompt or it has received a valid\n// value. It will return the value and an error if any occurred during the prompt's execution.\nfunc (p *Prompt) Run() (string, error) {\n\tvar err error\n\n\terr = p.prepareTemplates()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tc := &readline.Config{\n\t\tStdin:          p.Stdin,\n\t\tStdout:         p.Stdout,\n\t\tEnableMask:     p.Mask != 0,\n\t\tMaskRune:       p.Mask,\n\t\tHistoryLimit:   -1,\n\t\tVimMode:        p.IsVimMode,\n\t\tUniqueEditLine: true,\n\t}\n\n\terr = c.Init()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\trl, err := readline.NewEx(c)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t// we're taking over the cursor,  so stop showing it.\n\trl.Write([]byte(hideCursor))\n\tsb := screenbuf.New(rl)\n\n\tvalidFn := func(x string) error {\n\t\treturn nil\n\t}\n\tif p.Validate != nil {\n\t\tvalidFn = p.Validate\n\t}\n\n\tvar inputErr error\n\tinput := p.Default\n\tif p.IsConfirm {\n\t\tinput = \"\"\n\t}\n\teraseDefault := input != \"\" && !p.AllowEdit\n\tcur := NewCursor(input, p.Pointer, eraseDefault)\n\n\tlisten := func(input []rune, pos int, key rune) ([]rune, int, bool) {\n\t\t_, _, keepOn := cur.Listen(input, pos, key)\n\t\terr := validFn(cur.Get())\n\t\tvar prompt []byte\n\n\t\tif err != nil {\n\t\t\tprompt = render(p.Templates.invalid, p.Label)\n\t\t} else {\n\t\t\tprompt = render(p.Templates.valid, p.Label)\n\t\t\tif p.IsConfirm {\n\t\t\t\tprompt = render(p.Templates.prompt, p.Label)\n\t\t\t}\n\t\t}\n\n\t\techo := cur.Format()\n\t\tif p.Mask != 0 {\n\t\t\techo = cur.FormatMask(p.Mask)\n\t\t}\n\n\t\tprompt = append(prompt, []byte(echo)...)\n\t\tsb.Reset()\n\t\tsb.Write(prompt)\n\t\tif inputErr != nil {\n\t\t\tvalidation := render(p.Templates.validation, inputErr)\n\t\t\tsb.Write(validation)\n\t\t\tinputErr = nil\n\t\t}\n\t\tsb.Flush()\n\t\treturn nil, 0, keepOn\n\t}\n\n\tc.SetListener(listen)\n\n\tfor {\n\t\t_, err = rl.Readline()\n\t\tinputErr = validFn(cur.Get())\n\t\tif inputErr == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif err != nil {\n\t\tswitch err {\n\t\tcase readline.ErrInterrupt:\n\t\t\terr = ErrInterrupt\n\t\tcase io.EOF:\n\t\t\terr = ErrEOF\n\t\t}\n\t\tif err.Error() == \"Interrupt\" {\n\t\t\terr = ErrInterrupt\n\t\t}\n\t\tsb.Reset()\n\t\tsb.WriteString(\"\")\n\t\tsb.Flush()\n\t\trl.Write([]byte(showCursor))\n\t\trl.Close()\n\t\treturn \"\", err\n\t}\n\n\techo := cur.Get()\n\tif p.Mask != 0 {\n\t\techo = cur.GetMask(p.Mask)\n\t}\n\n\tprompt := render(p.Templates.success, p.Label)\n\tprompt = append(prompt, []byte(echo)...)\n\n\tif p.IsConfirm {\n\t\tlowerDefault := strings.ToLower(p.Default)\n\t\tif strings.ToLower(cur.Get()) != \"y\" && (lowerDefault != \"y\" || (lowerDefault == \"y\" && cur.Get() != \"\")) {\n\t\t\tprompt = render(p.Templates.invalid, p.Label)\n\t\t\terr = ErrAbort\n\t\t}\n\t}\n\n\tif p.HideEntered {\n\t\tclearScreen(sb)\n\t} else {\n\t\tsb.Reset()\n\t\tsb.Write(prompt)\n\t\tsb.Flush()\n\t}\n\n\trl.Write([]byte(showCursor))\n\trl.Close()\n\n\treturn cur.Get(), err\n}\n\nfunc (p *Prompt) prepareTemplates() error {\n\ttpls := p.Templates\n\tif tpls == nil {\n\t\ttpls = &PromptTemplates{}\n\t}\n\n\tif tpls.FuncMap == nil {\n\t\ttpls.FuncMap = FuncMap\n\t}\n\n\tbold := Styler(FGBold)\n\n\tif p.IsConfirm {\n\t\tif tpls.Confirm == \"\" {\n\t\t\tconfirm := \"y/N\"\n\t\t\tif strings.ToLower(p.Default) == \"y\" {\n\t\t\t\tconfirm = \"Y/n\"\n\t\t\t}\n\t\t\ttpls.Confirm = fmt.Sprintf(`{{ \"%s\" | bold }} {{ . | bold }}? {{ \"[%s]\" | faint }} `, IconInitial, confirm)\n\t\t}\n\n\t\ttpl, err := template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Confirm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttpls.prompt = tpl\n\t} else {\n\t\tif tpls.Prompt == \"\" {\n\t\t\ttpls.Prompt = fmt.Sprintf(\"%s {{ . | bold }}%s \", bold(IconInitial), bold(\":\"))\n\t\t}\n\n\t\ttpl, err := template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Prompt)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttpls.prompt = tpl\n\t}\n\n\tif tpls.Valid == \"\" {\n\t\ttpls.Valid = fmt.Sprintf(\"%s {{ . | bold }}%s \", bold(IconGood), bold(\":\"))\n\t}\n\n\ttpl, err := template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Valid)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.valid = tpl\n\n\tif tpls.Invalid == \"\" {\n\t\ttpls.Invalid = fmt.Sprintf(\"%s {{ . | bold }}%s \", bold(IconBad), bold(\":\"))\n\t}\n\n\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Invalid)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.invalid = tpl\n\n\tif tpls.ValidationError == \"\" {\n\t\ttpls.ValidationError = `{{ \">>\" | red }} {{ . | red }}`\n\t}\n\n\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.ValidationError)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.validation = tpl\n\n\tif tpls.Success == \"\" {\n\t\ttpls.Success = fmt.Sprintf(\"{{ . | faint }}%s \", Styler(FGFaint)(\":\"))\n\t}\n\n\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Success)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.success = tpl\n\n\tp.Templates = tpls\n\n\treturn nil\n}\n"
  },
  {
    "path": "promptui.go",
    "content": "// Package promptui is a library providing a simple interface to create command-line prompts for go.\n// It can be easily integrated into spf13/cobra, urfave/cli or any cli go application.\n//\n// promptui has two main input modes:\n//\n// Prompt provides a single line for user input. It supports optional live validation,\n// confirmation and masking the input.\n//\n// Select provides a list of options to choose from. It supports pagination, search,\n// detailed view and custom templates.\npackage promptui\n\nimport \"errors\"\n\n// ErrEOF is the error returned from prompts when EOF is encountered.\nvar ErrEOF = errors.New(\"^D\")\n\n// ErrInterrupt is the error returned from prompts when an interrupt (ctrl-c) is\n// encountered.\nvar ErrInterrupt = errors.New(\"^C\")\n\n// ErrAbort is the error returned when confirm prompts are supplied \"n\"\nvar ErrAbort = errors.New(\"\")\n\n// ValidateFunc is a placeholder type for any validation functions that validates a given input. It should return\n// a ValidationError if the input is not valid.\ntype ValidateFunc func(string) error\n"
  },
  {
    "path": "screenbuf/screenbuf.go",
    "content": "package screenbuf\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n)\n\nconst esc = \"\\033[\"\n\nvar (\n\tclearLine = []byte(esc + \"2K\\r\")\n\tmoveUp    = []byte(esc + \"1A\")\n\tmoveDown  = []byte(esc + \"1B\")\n)\n\n// ScreenBuf is a convenient way to write to terminal screens. It creates,\n// clears and, moves up or down lines as needed to write the output to the\n// terminal using ANSI escape codes.\ntype ScreenBuf struct {\n\tw      io.Writer\n\tbuf    *bytes.Buffer\n\treset  bool\n\tcursor int\n\theight int\n}\n\n// New creates and initializes a new ScreenBuf.\nfunc New(w io.Writer) *ScreenBuf {\n\treturn &ScreenBuf{buf: &bytes.Buffer{}, w: w}\n}\n\n// Reset truncates the underlining buffer and marks all its previous lines to be\n// cleared during the next Write.\nfunc (s *ScreenBuf) Reset() {\n\ts.buf.Reset()\n\ts.reset = true\n}\n\n// Clear clears all previous lines and the output starts from the top.\nfunc (s *ScreenBuf) Clear() error {\n\tfor i := 0; i < s.height; i++ {\n\t\t_, err := s.buf.Write(moveUp)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = s.buf.Write(clearLine)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\ts.cursor = 0\n\ts.height = 0\n\ts.reset = false\n\treturn nil\n}\n\n// Write writes a single line to the underlining buffer. If the ScreenBuf was\n// previously reset, all previous lines are cleared and the output starts from\n// the top. Lines with \\r or \\n will cause an error since they can interfere with the\n// terminal ability to move between lines.\nfunc (s *ScreenBuf) Write(b []byte) (int, error) {\n\tif bytes.ContainsAny(b, \"\\r\\n\") {\n\t\treturn 0, fmt.Errorf(\"%q should not contain either \\\\r or \\\\n\", b)\n\t}\n\n\tif s.reset {\n\t\tif err := s.Clear(); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\tswitch {\n\tcase s.cursor == s.height:\n\t\tn, err := s.buf.Write(clearLine)\n\t\tif err != nil {\n\t\t\treturn n, err\n\t\t}\n\n\t\tn, err = s.buf.Write(b)\n\t\tif err != nil {\n\t\t\treturn n, err\n\t\t}\n\n\t\t_, err = s.buf.Write([]byte(\"\\n\"))\n\t\tif err != nil {\n\t\t\treturn n, err\n\t\t}\n\n\t\ts.height++\n\t\ts.cursor++\n\t\treturn n, nil\n\tcase s.cursor < s.height:\n\t\tn, err := s.buf.Write(clearLine)\n\t\tif err != nil {\n\t\t\treturn n, err\n\t\t}\n\t\tn, err = s.buf.Write(b)\n\t\tif err != nil {\n\t\t\treturn n, err\n\t\t}\n\t\tn, err = s.buf.Write(moveDown)\n\t\tif err != nil {\n\t\t\treturn n, err\n\t\t}\n\t\ts.cursor++\n\t\treturn n, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"Invalid write cursor position (%d) exceeded line height: %d\", s.cursor, s.height)\n\t}\n}\n\n// Flush writes any buffered data to the underlying io.Writer, ensuring that any pending data is displayed.\nfunc (s *ScreenBuf) Flush() error {\n\tfor i := s.cursor; i < s.height; i++ {\n\t\tif i < s.height {\n\t\t\t_, err := s.buf.Write(clearLine)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t_, err := s.buf.Write(moveDown)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t_, err := s.buf.WriteTo(s.w)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts.buf.Reset()\n\n\tfor i := 0; i < s.height; i++ {\n\t\t_, err := s.buf.Write(moveUp)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\ts.cursor = 0\n\n\treturn nil\n}\n\n// WriteString is a convenient function to write a new line passing a string.\n// Check ScreenBuf.Write() for a detailed explanation of the function behaviour.\nfunc (s *ScreenBuf) WriteString(str string) (int, error) {\n\treturn s.Write([]byte(str))\n}\n"
  },
  {
    "path": "screenbuf/screenbuf_test.go",
    "content": "package screenbuf\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestScreen(t *testing.T) {\n\t// overwrite regular movement codes for easier visualization\n\tclearLine = []byte(\"\\\\c\")\n\tmoveUp = []byte(\"\\\\u\")\n\tmoveDown = []byte(\"\\\\d\")\n\n\tvar buf bytes.Buffer\n\ts := New(&buf)\n\n\ttcs := []struct {\n\t\tscenario string\n\t\tlines    []string\n\t\texpect   string\n\t\tcursor   int\n\t\theight   int\n\t\tflush    bool\n\t\treset    bool\n\t\tclear    bool\n\t}{\n\t\t{\n\t\t\tscenario: \"initial write\",\n\t\t\tlines:    []string{\"Line One\"},\n\t\t\texpect:   \"\\\\cLine One\\n\",\n\t\t\tcursor:   1,\n\t\t\theight:   1,\n\t\t},\n\t\t{\n\t\t\tscenario: \"write of with same number of lines\",\n\t\t\tlines:    []string{\"Line One\"},\n\t\t\texpect:   \"\\\\u\\\\cLine One\\\\d\",\n\t\t\tcursor:   1,\n\t\t\theight:   1,\n\t\t},\n\t\t{\n\t\t\tscenario: \"write of with more lines\",\n\t\t\tlines:    []string{\"Line One\", \"Line Two\"},\n\t\t\texpect:   \"\\\\u\\\\cLine One\\\\d\\\\cLine Two\\n\",\n\t\t\tcursor:   2,\n\t\t\theight:   2,\n\t\t},\n\t\t{\n\t\t\tscenario: \"write of with fewer lines\",\n\t\t\tlines:    []string{\"line One\"},\n\t\t\texpect:   \"\\\\u\\\\u\\\\cline One\\\\d\\\\c\\\\d\",\n\t\t\tcursor:   1,\n\t\t\theight:   2,\n\t\t},\n\t\t{\n\t\t\tscenario: \"write of way more lines\",\n\t\t\tlines:    []string{\"line one\", \"line two\", \"line three\", \"line four\", \"line five\"},\n\t\t\texpect:   \"\\\\u\\\\u\\\\cline one\\\\d\\\\cline two\\\\d\\\\cline three\\n\\\\cline four\\n\\\\cline five\\n\",\n\t\t\tcursor:   5,\n\t\t\theight:   5,\n\t\t},\n\t\t{\n\t\t\tscenario: \"write of way less lines\",\n\t\t\tlines:    []string{\"line one\", \"line two\"},\n\t\t\texpect:   \"\\\\u\\\\u\\\\u\\\\u\\\\u\\\\cline one\\\\d\\\\cline two\\\\d\\\\c\\\\d\\\\c\\\\d\\\\c\\\\d\",\n\t\t\tcursor:   2,\n\t\t\theight:   5,\n\t\t},\n\t\t{\n\t\t\tscenario: \"write of way more lines\",\n\t\t\tlines:    []string{\"line one\", \"line two\", \"line three\", \"line four\", \"line five\"},\n\t\t\texpect:   \"\\\\u\\\\u\\\\u\\\\u\\\\u\\\\cline one\\\\d\\\\cline two\\\\d\\\\cline three\\\\d\\\\cline four\\\\d\\\\cline five\\\\d\",\n\t\t\tcursor:   5,\n\t\t\theight:   5,\n\t\t},\n\t\t{\n\t\t\tscenario: \"reset and write\",\n\t\t\tlines:    []string{\"line one\", \"line two\"},\n\t\t\texpect:   \"\\\\u\\\\c\\\\u\\\\c\\\\u\\\\c\\\\u\\\\c\\\\u\\\\c\\\\cline one\\n\\\\cline two\\n\",\n\t\t\tcursor:   2,\n\t\t\theight:   2,\n\t\t\treset:    true,\n\t\t},\n\t\t{\n\t\t\tscenario: \"clear all previous lines\",\n\t\t\tlines:    []string{\"line one\", \"line two\"},\n\t\t\texpect:   \"\\\\u\\\\u\\\\cline one\\\\d\\\\cline two\\\\d\\\\u\\\\c\\\\u\\\\c\",\n\t\t\tcursor:   0,\n\t\t\theight:   0,\n\t\t\tclear:    true,\n\t\t},\n\t}\n\n\tfor _, tc := range tcs {\n\t\tt.Run(tc.scenario, func(t *testing.T) {\n\t\t\tbuf.Reset()\n\t\t\tif tc.reset {\n\t\t\t\ts.Reset()\n\t\t\t}\n\n\t\t\tfor _, line := range tc.lines {\n\t\t\t\t_, err := s.WriteString(line)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"expected no error, got %v\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif tc.clear {\n\t\t\t\tif err := s.Clear(); err != nil {\n\t\t\t\t\tt.Errorf(\"expected no error, got %d\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif tc.cursor != s.cursor {\n\t\t\t\tt.Errorf(\"expected cursor %d, got %d\", tc.cursor, s.cursor)\n\t\t\t}\n\n\t\t\terr := s.Flush()\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"expected no error, got %v\", err)\n\t\t\t}\n\n\t\t\tgot := buf.String()\n\n\t\t\tif tc.expect != got {\n\t\t\t\tt.Errorf(\"expected %q, got %q\", tc.expect, got)\n\t\t\t}\n\n\t\t\tif tc.height != s.height {\n\t\t\t\tt.Errorf(\"expected height %d, got %d\", tc.height, s.height)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "select.go",
    "content": "package promptui\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"text/tabwriter\"\n\t\"text/template\"\n\n\t\"github.com/chzyer/readline\"\n\t\"github.com/manifoldco/promptui/list\"\n\t\"github.com/manifoldco/promptui/screenbuf\"\n)\n\n// SelectedAdd is used internally inside SelectWithAdd when the add option is selected in select mode.\n// Since -1 is not a possible selected index, this ensure that add mode is always unique inside\n// SelectWithAdd's logic.\nconst SelectedAdd = -1\n\n// Select represents a list of items used to enable selections, they can be used as search engines, menus\n// or as a list of items in a cli based prompt.\ntype Select struct {\n\t// Label is the text displayed on top of the list to direct input. The IconInitial value \"?\" will be\n\t// appended automatically to the label so it does not need to be added.\n\t//\n\t// The value for Label can be a simple string or a struct that will need to be accessed by dot notation\n\t// inside the templates. For example, `{{ .Name }}` will display the name property of a struct.\n\tLabel interface{}\n\n\t// Items are the items to display inside the list. It expect a slice of any kind of values, including strings.\n\t//\n\t// If using a slice of strings, promptui will use those strings directly into its base templates or the\n\t// provided templates. If using any other type in the slice, it will attempt to transform it into a string\n\t// before giving it to its templates. Custom templates will override this behavior if using the dot notation\n\t// inside the templates.\n\t//\n\t// For example, `{{ .Name }}` will display the name property of a struct.\n\tItems interface{}\n\n\t// Size is the number of items that should appear on the select before scrolling is necessary. Defaults to 5.\n\tSize int\n\n\t// CursorPos is the initial position of the cursor.\n\tCursorPos int\n\n\t// IsVimMode sets whether to use vim mode when using readline in the command prompt. Look at\n\t// https://godoc.org/github.com/chzyer/readline#Config for more information on readline.\n\tIsVimMode bool\n\n\t// HideHelp sets whether to hide help information.\n\tHideHelp bool\n\n\t// HideSelected sets whether to hide the text displayed after an item is successfully selected.\n\tHideSelected bool\n\n\t// Templates can be used to customize the select output. If nil is passed, the\n\t// default templates are used. See the SelectTemplates docs for more info.\n\tTemplates *SelectTemplates\n\n\t// Keys is the set of keys used in select mode to control the command line interface. See the SelectKeys docs for\n\t// more info.\n\tKeys *SelectKeys\n\n\t// Searcher is a function that can be implemented to refine the base searching algorithm in selects.\n\t//\n\t// Search is a function that will receive the searched term and the item's index and should return a boolean\n\t// for whether or not the terms are alike. It is unimplemented by default and search will not work unless\n\t// it is implemented.\n\tSearcher list.Searcher\n\n\t// StartInSearchMode sets whether or not the select mode should start in search mode or selection mode.\n\t// For search mode to work, the Search property must be implemented.\n\tStartInSearchMode bool\n\n\tlist *list.List\n\n\t// A function that determines how to render the cursor\n\tPointer Pointer\n\n\tStdin  io.ReadCloser\n\tStdout io.WriteCloser\n}\n\n// SelectKeys defines the available keys used by select mode to enable the user to move around the list\n// and trigger search mode. See the Key struct docs for more information on keys.\ntype SelectKeys struct {\n\t// Next is the key used to move to the next element inside the list. Defaults to down arrow key.\n\tNext Key\n\n\t// Prev is the key used to move to the previous element inside the list. Defaults to up arrow key.\n\tPrev Key\n\n\t// PageUp is the key used to jump back to the first element inside the list. Defaults to left arrow key.\n\tPageUp Key\n\n\t// PageUp is the key used to jump forward to the last element inside the list. Defaults to right arrow key.\n\tPageDown Key\n\n\t// Search is the key used to trigger the search mode for the list. Default to the \"/\" key.\n\tSearch Key\n}\n\n// Key defines a keyboard code and a display representation for the help menu.\ntype Key struct {\n\t// Code is a rune that will be used to compare against typed keys with readline.\n\t// Check https://github.com/chzyer/readline for a list of codes\n\tCode rune\n\n\t// Display is the string that will be displayed inside the help menu to help inform the user\n\t// of which key to use on his keyboard for various functions.\n\tDisplay string\n}\n\n// SelectTemplates allow a select list to be customized following stdlib\n// text/template syntax. Custom state, colors and background color are available for use inside\n// the templates and are documented inside the Variable section of the docs.\n//\n// Examples\n//\n// text/templates use a special notation to display programmable content. Using the double bracket notation,\n// the value can be printed with specific helper functions. For example\n//\n// This displays the value given to the template as pure, unstylized text. Structs are transformed to string\n// with this notation.\n// \t'{{ . }}'\n//\n// This displays the name property of the value colored in cyan\n// \t'{{ .Name | cyan }}'\n//\n// This displays the label property of value colored in red with a cyan background-color\n// \t'{{ .Label | red | cyan }}'\n//\n// See the doc of text/template for more info: https://golang.org/pkg/text/template/\n//\n// Notes\n//\n// Setting any of these templates will remove the icons from the default templates. They must\n// be added back in each of their specific templates. The styles.go constants contains the default icons.\ntype SelectTemplates struct {\n\t// Label is a text/template for the main command line label. Defaults to printing the label as it with\n\t// the IconInitial.\n\tLabel string\n\n\t// Active is a text/template for when an item is currently active within the list.\n\tActive string\n\n\t// Inactive is a text/template for when an item is not currently active inside the list. This\n\t// template is used for all items unless they are active or selected.\n\tInactive string\n\n\t// Selected is a text/template for when an item was successfully selected.\n\tSelected string\n\n\t// Details is a text/template for when an item current active to show\n\t// additional information. It can have multiple lines.\n\t//\n\t// Detail will always be displayed for the active element and thus can be used to display additional\n\t// information on the element beyond its label.\n\t//\n\t// promptui will not trim spaces and tabs will be displayed if the template is indented.\n\tDetails string\n\n\t// Help is a text/template for displaying instructions at the top. By default\n\t// it shows keys for movement and search.\n\tHelp string\n\n\t// FuncMap is a map of helper functions that can be used inside of templates according to the text/template\n\t// documentation.\n\t//\n\t// By default, FuncMap contains the color functions used to color the text in templates. If FuncMap\n\t// is overridden, the colors functions must be added in the override from promptui.FuncMap to work.\n\tFuncMap template.FuncMap\n\n\tlabel    *template.Template\n\tactive   *template.Template\n\tinactive *template.Template\n\tselected *template.Template\n\tdetails  *template.Template\n\thelp     *template.Template\n}\n\n// SearchPrompt is the prompt displayed in search mode.\nvar SearchPrompt = \"Search: \"\n\n// Run executes the select list. It displays the label and the list of items, asking the user to chose any\n// value within to list. Run will keep the prompt alive until it has been canceled from\n// the command prompt or it has received a valid value. It will return the value and an error if any\n// occurred during the select's execution.\nfunc (s *Select) Run() (int, string, error) {\n\treturn s.RunCursorAt(s.CursorPos, 0)\n}\n\n// RunCursorAt executes the select list, initializing the cursor to the given\n// position. Invalid cursor positions will be clamped to valid values.  It\n// displays the label and the list of items, asking the user to chose any value\n// within to list. Run will keep the prompt alive until it has been canceled\n// from the command prompt or it has received a valid value. It will return\n// the value and an error if any occurred during the select's execution.\nfunc (s *Select) RunCursorAt(cursorPos, scroll int) (int, string, error) {\n\tif s.Size == 0 {\n\t\ts.Size = 5\n\t}\n\n\tl, err := list.New(s.Items, s.Size)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\tl.Searcher = s.Searcher\n\n\ts.list = l\n\n\ts.setKeys()\n\n\terr = s.prepareTemplates()\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\treturn s.innerRun(cursorPos, scroll, ' ')\n}\n\nfunc (s *Select) innerRun(cursorPos, scroll int, top rune) (int, string, error) {\n\tc := &readline.Config{\n\t\tStdin:  s.Stdin,\n\t\tStdout: s.Stdout,\n\t}\n\terr := c.Init()\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tc.Stdin = readline.NewCancelableStdin(c.Stdin)\n\n\tif s.IsVimMode {\n\t\tc.VimMode = true\n\t}\n\n\tc.HistoryLimit = -1\n\tc.UniqueEditLine = true\n\n\trl, err := readline.NewEx(c)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\trl.Write([]byte(hideCursor))\n\tsb := screenbuf.New(rl)\n\n\tcur := NewCursor(\"\", s.Pointer, false)\n\n\tcanSearch := s.Searcher != nil\n\tsearchMode := s.StartInSearchMode\n\ts.list.SetCursor(cursorPos)\n\ts.list.SetStart(scroll)\n\n\tc.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {\n\t\tswitch {\n\t\tcase key == KeyEnter:\n\t\t\treturn nil, 0, true\n\t\tcase key == s.Keys.Next.Code || (key == 'j' && !searchMode):\n\t\t\ts.list.Next()\n\t\tcase key == s.Keys.Prev.Code || (key == 'k' && !searchMode):\n\t\t\ts.list.Prev()\n\t\tcase key == s.Keys.Search.Code:\n\t\t\tif !canSearch {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif searchMode {\n\t\t\t\tsearchMode = false\n\t\t\t\tcur.Replace(\"\")\n\t\t\t\ts.list.CancelSearch()\n\t\t\t} else {\n\t\t\t\tsearchMode = true\n\t\t\t}\n\t\tcase key == KeyBackspace || key == KeyCtrlH:\n\t\t\tif !canSearch || !searchMode {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcur.Backspace()\n\t\t\tif len(cur.Get()) > 0 {\n\t\t\t\ts.list.Search(cur.Get())\n\t\t\t} else {\n\t\t\t\ts.list.CancelSearch()\n\t\t\t}\n\t\tcase key == s.Keys.PageUp.Code || (key == 'h' && !searchMode):\n\t\t\ts.list.PageUp()\n\t\tcase key == s.Keys.PageDown.Code || (key == 'l' && !searchMode):\n\t\t\ts.list.PageDown()\n\t\tdefault:\n\t\t\tif canSearch && searchMode {\n\t\t\t\tcur.Update(string(line))\n\t\t\t\ts.list.Search(cur.Get())\n\t\t\t}\n\t\t}\n\n\t\tif searchMode {\n\t\t\theader := SearchPrompt + cur.Format()\n\t\t\tsb.WriteString(header)\n\t\t} else if !s.HideHelp {\n\t\t\thelp := s.renderHelp(canSearch)\n\t\t\tsb.Write(help)\n\t\t}\n\n\t\tlabel := render(s.Templates.label, s.Label)\n\t\tsb.Write(label)\n\n\t\titems, idx := s.list.Items()\n\t\tlast := len(items) - 1\n\n\t\tfor i, item := range items {\n\t\t\tpage := \" \"\n\n\t\t\tswitch i {\n\t\t\tcase 0:\n\t\t\t\tif s.list.CanPageUp() {\n\t\t\t\t\tpage = \"↑\"\n\t\t\t\t} else {\n\t\t\t\t\tpage = string(top)\n\t\t\t\t}\n\t\t\tcase last:\n\t\t\t\tif s.list.CanPageDown() {\n\t\t\t\t\tpage = \"↓\"\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toutput := []byte(page + \" \")\n\n\t\t\tif i == idx {\n\t\t\t\toutput = append(output, render(s.Templates.active, item)...)\n\t\t\t} else {\n\t\t\t\toutput = append(output, render(s.Templates.inactive, item)...)\n\t\t\t}\n\n\t\t\tsb.Write(output)\n\t\t}\n\n\t\tif idx == list.NotFound {\n\t\t\tsb.WriteString(\"\")\n\t\t\tsb.WriteString(\"No results\")\n\t\t} else {\n\t\t\tactive := items[idx]\n\n\t\t\tdetails := s.renderDetails(active)\n\t\t\tfor _, d := range details {\n\t\t\t\tsb.Write(d)\n\t\t\t}\n\t\t}\n\n\t\tsb.Flush()\n\n\t\treturn nil, 0, true\n\t})\n\n\tfor {\n\t\t_, err = rl.Readline()\n\n\t\tif err != nil {\n\t\t\tswitch {\n\t\t\tcase err == readline.ErrInterrupt, err.Error() == \"Interrupt\":\n\t\t\t\terr = ErrInterrupt\n\t\t\tcase err == io.EOF:\n\t\t\t\terr = ErrEOF\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\t_, idx := s.list.Items()\n\t\tif idx != list.NotFound {\n\t\t\tbreak\n\t\t}\n\n\t}\n\n\tif err != nil {\n\t\tif err.Error() == \"Interrupt\" {\n\t\t\terr = ErrInterrupt\n\t\t}\n\t\tsb.Reset()\n\t\tsb.WriteString(\"\")\n\t\tsb.Flush()\n\t\trl.Write([]byte(showCursor))\n\t\trl.Close()\n\t\treturn 0, \"\", err\n\t}\n\n\titems, idx := s.list.Items()\n\titem := items[idx]\n\n\tif s.HideSelected {\n\t\tclearScreen(sb)\n\t} else {\n\t\tsb.Reset()\n\t\tsb.Write(render(s.Templates.selected, item))\n\t\tsb.Flush()\n\t}\n\n\trl.Write([]byte(showCursor))\n\trl.Close()\n\n\treturn s.list.Index(), fmt.Sprintf(\"%v\", item), err\n}\n\n// ScrollPosition returns the current scroll position.\nfunc (s *Select) ScrollPosition() int {\n\treturn s.list.Start()\n}\n\nfunc (s *Select) prepareTemplates() error {\n\ttpls := s.Templates\n\tif tpls == nil {\n\t\ttpls = &SelectTemplates{}\n\t}\n\n\tif tpls.FuncMap == nil {\n\t\ttpls.FuncMap = FuncMap\n\t}\n\n\tif tpls.Label == \"\" {\n\t\ttpls.Label = fmt.Sprintf(\"%s {{.}}: \", IconInitial)\n\t}\n\n\ttpl, err := template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Label)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.label = tpl\n\n\tif tpls.Active == \"\" {\n\t\ttpls.Active = fmt.Sprintf(\"%s {{ . | underline }}\", IconSelect)\n\t}\n\n\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Active)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.active = tpl\n\n\tif tpls.Inactive == \"\" {\n\t\ttpls.Inactive = \"  {{.}}\"\n\t}\n\n\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Inactive)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.inactive = tpl\n\n\tif tpls.Selected == \"\" {\n\t\ttpls.Selected = fmt.Sprintf(`{{ \"%s\" | green }} {{ . | faint }}`, IconGood)\n\t}\n\n\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Selected)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttpls.selected = tpl\n\n\tif tpls.Details != \"\" {\n\t\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Details)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttpls.details = tpl\n\t}\n\n\tif tpls.Help == \"\" {\n\t\ttpls.Help = fmt.Sprintf(`{{ \"Use the arrow keys to navigate:\" | faint }} {{ .NextKey | faint }} ` +\n\t\t\t`{{ .PrevKey | faint }} {{ .PageDownKey | faint }} {{ .PageUpKey | faint }} ` +\n\t\t\t`{{ if .Search }} {{ \"and\" | faint }} {{ .SearchKey | faint }} {{ \"toggles search\" | faint }}{{ end }}`)\n\t}\n\n\ttpl, err = template.New(\"\").Funcs(tpls.FuncMap).Parse(tpls.Help)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttpls.help = tpl\n\n\ts.Templates = tpls\n\n\treturn nil\n}\n\n// SelectWithAdd represents a list for selecting a single item inside a list of items with the possibility to\n// add new items to the list.\ntype SelectWithAdd struct {\n\t// Label is the text displayed on top of the list to direct input. The IconInitial value \"?\" will be\n\t// appended automatically to the label so it does not need to be added.\n\tLabel string\n\n\t// Items are the items to display inside the list. Each item will be listed individually with the\n\t// AddLabel as the first item of the list.\n\tItems []string\n\n\t// AddLabel is the label used for the first item of the list that enables adding a new item.\n\t// Selecting this item in the list displays the add item prompt using promptui/prompt.\n\tAddLabel string\n\n\t// Validate is an optional function that fill be used against the entered value in the prompt to validate it.\n\t// If the value is valid, it is returned to the callee to be added in the list.\n\tValidate ValidateFunc\n\n\t// IsVimMode sets whether to use vim mode when using readline in the command prompt. Look at\n\t// https://godoc.org/github.com/chzyer/readline#Config for more information on readline.\n\tIsVimMode bool\n\n\t// a function that defines how to render the cursor\n\tPointer Pointer\n\n\t// HideHelp sets whether to hide help information.\n\tHideHelp bool\n}\n\n// Run executes the select list. Its displays the label and the list of items, asking the user to chose any\n// value within to list or add his own. Run will keep the prompt alive until it has been canceled from\n// the command prompt or it has received a valid value.\n//\n// If the addLabel is selected in the list, this function will return a -1 index with the added label and no error.\n// Otherwise, it will return the index and the value of the selected item. In any case, if an error is triggered, it\n// will also return the error as its third return value.\nfunc (sa *SelectWithAdd) Run() (int, string, error) {\n\tif len(sa.Items) > 0 {\n\t\tnewItems := append([]string{sa.AddLabel}, sa.Items...)\n\n\t\tlist, err := list.New(newItems, 5)\n\t\tif err != nil {\n\t\t\treturn 0, \"\", err\n\t\t}\n\n\t\ts := Select{\n\t\t\tLabel:     sa.Label,\n\t\t\tItems:     newItems,\n\t\t\tIsVimMode: sa.IsVimMode,\n\t\t\tHideHelp:  sa.HideHelp,\n\t\t\tSize:      5,\n\t\t\tlist:      list,\n\t\t\tPointer:   sa.Pointer,\n\t\t}\n\t\ts.setKeys()\n\n\t\terr = s.prepareTemplates()\n\t\tif err != nil {\n\t\t\treturn 0, \"\", err\n\t\t}\n\n\t\tselected, value, err := s.innerRun(1, 0, '+')\n\t\tif err != nil || selected != 0 {\n\t\t\treturn selected - 1, value, err\n\t\t}\n\n\t\t// XXX run through terminal for windows\n\t\tos.Stdout.Write([]byte(upLine(1) + \"\\r\" + clearLine))\n\t}\n\n\tp := Prompt{\n\t\tLabel:     sa.AddLabel,\n\t\tValidate:  sa.Validate,\n\t\tIsVimMode: sa.IsVimMode,\n\t\tPointer:   sa.Pointer,\n\t}\n\tvalue, err := p.Run()\n\treturn SelectedAdd, value, err\n}\n\nfunc (s *Select) setKeys() {\n\tif s.Keys != nil {\n\t\treturn\n\t}\n\ts.Keys = &SelectKeys{\n\t\tPrev:     Key{Code: KeyPrev, Display: KeyPrevDisplay},\n\t\tNext:     Key{Code: KeyNext, Display: KeyNextDisplay},\n\t\tPageUp:   Key{Code: KeyBackward, Display: KeyBackwardDisplay},\n\t\tPageDown: Key{Code: KeyForward, Display: KeyForwardDisplay},\n\t\tSearch:   Key{Code: '/', Display: \"/\"},\n\t}\n}\n\nfunc (s *Select) renderDetails(item interface{}) [][]byte {\n\tif s.Templates.details == nil {\n\t\treturn nil\n\t}\n\n\tvar buf bytes.Buffer\n\n\tw := tabwriter.NewWriter(&buf, 0, 0, 8, ' ', 0)\n\n\terr := s.Templates.details.Execute(w, item)\n\tif err != nil {\n\t\tfmt.Fprintf(w, \"%v\", item)\n\t}\n\n\tw.Flush()\n\n\toutput := buf.Bytes()\n\n\treturn bytes.Split(output, []byte(\"\\n\"))\n}\n\nfunc (s *Select) renderHelp(b bool) []byte {\n\tkeys := struct {\n\t\tNextKey     string\n\t\tPrevKey     string\n\t\tPageDownKey string\n\t\tPageUpKey   string\n\t\tSearch      bool\n\t\tSearchKey   string\n\t}{\n\t\tNextKey:     s.Keys.Next.Display,\n\t\tPrevKey:     s.Keys.Prev.Display,\n\t\tPageDownKey: s.Keys.PageDown.Display,\n\t\tPageUpKey:   s.Keys.PageUp.Display,\n\t\tSearchKey:   s.Keys.Search.Display,\n\t\tSearch:      b,\n\t}\n\n\treturn render(s.Templates.help, keys)\n}\n\nfunc render(tpl *template.Template, data interface{}) []byte {\n\tvar buf bytes.Buffer\n\terr := tpl.Execute(&buf, data)\n\tif err != nil {\n\t\treturn []byte(fmt.Sprintf(\"%v\", data))\n\t}\n\treturn buf.Bytes()\n}\n\nfunc clearScreen(sb *screenbuf.ScreenBuf) {\n\tsb.Reset()\n\tsb.Clear()\n\tsb.Flush()\n}\n"
  },
  {
    "path": "select_test.go",
    "content": "package promptui\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/manifoldco/promptui/screenbuf\"\n)\n\nfunc TestSelectTemplateRender(t *testing.T) {\n\tt.Run(\"when using default style\", func(t *testing.T) {\n\t\tvalues := []string{\"Zero\"}\n\t\ts := Select{\n\t\t\tLabel: \"Select Number\",\n\t\t\tItems: values,\n\t\t}\n\t\terr := s.prepareTemplates()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Unexpected error preparing templates %v\", err)\n\t\t}\n\n\t\tresult := string(render(s.Templates.label, s.Label))\n\t\texp := \"\\x1b[34m?\\x1b[0m Select Number: \"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected label to eq %q, got %q\", exp, result)\n\t\t}\n\n\t\tresult = string(render(s.Templates.active, values[0]))\n\t\texp = \"\\x1b[1m▸\\x1b[0m \\x1b[4mZero\\x1b[0m\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected active item to eq %q, got %q\", exp, result)\n\t\t}\n\n\t\tresult = string(render(s.Templates.inactive, values[0]))\n\t\texp = \"  Zero\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected inactive item to eq %q, got %q\", exp, result)\n\t\t}\n\n\t\tresult = string(render(s.Templates.selected, values[0]))\n\t\texp = \"\\x1b[32m\\x1b[32m✔\\x1b[0m \\x1b[2mZero\\x1b[0m\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected selected item to eq %q, got %q\", exp, result)\n\t\t}\n\t})\n\n\tt.Run(\"when using custom style\", func(t *testing.T) {\n\t\ttype pepper struct {\n\t\t\tName        string\n\t\t\tHeatUnit    int\n\t\t\tPeppers     int\n\t\t\tDescription string\n\t\t}\n\t\tpeppers := []pepper{\n\t\t\t{\n\t\t\t\tName:        \"Bell Pepper\",\n\t\t\t\tHeatUnit:    0,\n\t\t\t\tPeppers:     1,\n\t\t\t\tDescription: \"Not very spicy!\",\n\t\t\t},\n\t\t}\n\n\t\ttemplates := &SelectTemplates{\n\t\t\tLabel:    \"{{ . }}?\",\n\t\t\tActive:   \"\\U0001F525 {{ .Name | bold }} ({{ .HeatUnit | red | italic }})\",\n\t\t\tInactive: \"   {{ .Name | bold }} ({{ .HeatUnit | red | italic }})\",\n\t\t\tSelected: \"\\U0001F525 {{ .Name | red | bold }}\",\n\t\t\tDetails: `Name: {{.Name}}\nPeppers: {{.Peppers}}\nDescription: {{.Description}}`,\n\t\t}\n\n\t\ts := Select{\n\t\t\tLabel:     \"Spicy Level\",\n\t\t\tItems:     peppers,\n\t\t\tTemplates: templates,\n\t\t}\n\n\t\terr := s.prepareTemplates()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Unexpected error preparing templates %v\", err)\n\t\t}\n\n\t\tresult := string(render(s.Templates.label, s.Label))\n\t\texp := \"Spicy Level?\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected label to eq %q, got %q\", exp, result)\n\t\t}\n\n\t\tresult = string(render(s.Templates.active, peppers[0]))\n\t\texp = \"🔥 \\x1b[1mBell Pepper\\x1b[0m (\\x1b[3m\\x1b[31m0\\x1b[0m)\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected active item to eq %q, got %q\", exp, result)\n\t\t}\n\n\t\tresult = string(render(s.Templates.inactive, peppers[0]))\n\t\texp = \"   \\x1b[1mBell Pepper\\x1b[0m (\\x1b[3m\\x1b[31m0\\x1b[0m)\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected inactive item to eq %q, got %q\", exp, result)\n\t\t}\n\n\t\tresult = string(render(s.Templates.selected, peppers[0]))\n\t\texp = \"🔥 \\x1b[1m\\x1b[31mBell Pepper\\x1b[0m\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected selected item to eq %q, got %q\", exp, result)\n\t\t}\n\n\t\tresult = string(render(s.Templates.details, peppers[0]))\n\t\texp = \"Name: Bell Pepper\\nPeppers: 1\\nDescription: Not very spicy!\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected selected item to eq %q, got %q\", exp, result)\n\t\t}\n\t})\n\n\tt.Run(\"when a template is invalid\", func(t *testing.T) {\n\t\ttemplates := &SelectTemplates{\n\t\t\tLabel: \"{{ . \",\n\t\t}\n\n\t\ts := Select{\n\t\t\tLabel:     \"Spicy Level\",\n\t\t\tTemplates: templates,\n\t\t}\n\n\t\terr := s.prepareTemplates()\n\t\tif err == nil {\n\t\t\tt.Fatalf(\"Expected error got none\")\n\t\t}\n\t})\n\n\tt.Run(\"when a template render fails\", func(t *testing.T) {\n\t\ttemplates := &SelectTemplates{\n\t\t\tLabel: \"{{ .InvalidName }}\",\n\t\t}\n\n\t\ts := Select{\n\t\t\tLabel:     struct{ Name string }{Name: \"Pepper\"},\n\t\t\tItems:     []string{},\n\t\t\tTemplates: templates,\n\t\t}\n\n\t\terr := s.prepareTemplates()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Unexpected error preparing templates %v\", err)\n\t\t}\n\n\t\tresult := string(render(s.Templates.label, s.Label))\n\t\texp := \"{Pepper}\"\n\t\tif result != exp {\n\t\t\tt.Errorf(\"Expected label to eq %q, got %q\", exp, result)\n\t\t}\n\t})\n}\n\nfunc TestClearScreen(t *testing.T) {\n\tvar buf bytes.Buffer\n\tsb := screenbuf.New(&buf)\n\n\tsb.WriteString(\"test\")\n\tclearScreen(sb)\n\n\tgot := buf.String()\n\texcept := \"\\x1b[1A\\x1b[2K\\r\"\n\n\tif except != got {\n\t\tt.Errorf(\"expected %q, got %q\", except, got)\n\t}\n}\n"
  },
  {
    "path": "styles.go",
    "content": "// +build !windows\n\npackage promptui\n\n// These are the default icons used by promptui for select and prompts. These should not be overridden and instead\n// customized through the use of custom templates\nvar (\n\t// IconInitial is the icon used when starting in prompt mode and the icon next to the label when\n\t// starting in select mode.\n\tIconInitial = Styler(FGBlue)(\"?\")\n\n\t// IconGood is the icon used when a good answer is entered in prompt mode.\n\tIconGood = Styler(FGGreen)(\"✔\")\n\n\t// IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode.\n\tIconWarn = Styler(FGYellow)(\"⚠\")\n\n\t// IconBad is the icon used when a bad answer is entered in prompt mode.\n\tIconBad = Styler(FGRed)(\"✗\")\n\n\t// IconSelect is the icon used to identify the currently selected item in select mode.\n\tIconSelect = Styler(FGBold)(\"▸\")\n)\n"
  },
  {
    "path": "styles_windows.go",
    "content": "package promptui\n\n// These are the default icons used bu promptui for select and prompts. They can either be overridden directly\n// from these variable or customized through the use of custom templates\nvar (\n\t// IconInitial is the icon used when starting in prompt mode and the icon next to the label when\n\t// starting in select mode.\n\tIconInitial = Styler(FGBlue)(\"?\")\n\n\t// IconGood is the icon used when a good answer is entered in prompt mode.\n\tIconGood = Styler(FGGreen)(\"v\")\n\n\t// IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode.\n\tIconWarn = Styler(FGYellow)(\"!\")\n\n\t// IconBad is the icon used when a bad answer is entered in prompt mode.\n\tIconBad = Styler(FGRed)(\"x\")\n\n\t// IconSelect is the icon used to identify the currently selected item in select mode.\n\tIconSelect = Styler(FGBold)(\">\")\n)\n"
  }
]