summaryrefslogtreecommitdiff
path: root/vendor/github.com/manifoldco/promptui
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2020-11-13 18:28:17 +0100
committerGitHub <noreply@github.com>2020-11-13 18:28:17 +0100
commit738d62ea960af439bd545820e1853cbd73464493 (patch)
tree61a859c039565897f865db052ad7c3bee8b03bfb /vendor/github.com/manifoldco/promptui
parent2993e97dec9d998d2eca7c5aee918b1429596a85 (diff)
parent8e4a42aa429c6dec0d5face7c69554d8a0677e96 (diff)
downloadpodman-738d62ea960af439bd545820e1853cbd73464493.tar.gz
podman-738d62ea960af439bd545820e1853cbd73464493.tar.bz2
podman-738d62ea960af439bd545820e1853cbd73464493.zip
Merge pull request #7964 from vrothberg/shortnames
short-name aliasing
Diffstat (limited to 'vendor/github.com/manifoldco/promptui')
-rw-r--r--vendor/github.com/manifoldco/promptui/.gitignore3
-rw-r--r--vendor/github.com/manifoldco/promptui/.golangci.yml26
-rw-r--r--vendor/github.com/manifoldco/promptui/.travis.yml14
-rw-r--r--vendor/github.com/manifoldco/promptui/CHANGELOG.md123
-rw-r--r--vendor/github.com/manifoldco/promptui/CODE_OF_CONDUCT.md73
-rw-r--r--vendor/github.com/manifoldco/promptui/LICENSE.md29
-rw-r--r--vendor/github.com/manifoldco/promptui/Makefile49
-rw-r--r--vendor/github.com/manifoldco/promptui/README.md107
-rw-r--r--vendor/github.com/manifoldco/promptui/codes.go120
-rw-r--r--vendor/github.com/manifoldco/promptui/cursor.go232
-rw-r--r--vendor/github.com/manifoldco/promptui/go.mod16
-rw-r--r--vendor/github.com/manifoldco/promptui/go.sum23
-rw-r--r--vendor/github.com/manifoldco/promptui/keycodes.go29
-rw-r--r--vendor/github.com/manifoldco/promptui/keycodes_other.go10
-rw-r--r--vendor/github.com/manifoldco/promptui/keycodes_windows.go10
-rw-r--r--vendor/github.com/manifoldco/promptui/list/list.go237
-rw-r--r--vendor/github.com/manifoldco/promptui/prompt.go341
-rw-r--r--vendor/github.com/manifoldco/promptui/promptui.go27
-rw-r--r--vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go151
-rw-r--r--vendor/github.com/manifoldco/promptui/select.go637
-rw-r--r--vendor/github.com/manifoldco/promptui/styles.go23
-rw-r--r--vendor/github.com/manifoldco/promptui/styles_windows.go21
22 files changed, 2301 insertions, 0 deletions
diff --git a/vendor/github.com/manifoldco/promptui/.gitignore b/vendor/github.com/manifoldco/promptui/.gitignore
new file mode 100644
index 000000000..8ee1778b5
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/.gitignore
@@ -0,0 +1,3 @@
+vendor
+all-cover.txt
+bin/
diff --git a/vendor/github.com/manifoldco/promptui/.golangci.yml b/vendor/github.com/manifoldco/promptui/.golangci.yml
new file mode 100644
index 000000000..e232bfbe5
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/.golangci.yml
@@ -0,0 +1,26 @@
+run:
+ deadline: 5m
+
+issues:
+ # Disable maximums so we see all issues
+ max-per-linter: 0
+ max-same-issues: 0
+
+ # golangci-lint ignores missing docstrings by default. That's no good!
+ exclude-use-default: false
+
+linters:
+ disable-all: true
+ enable:
+ - misspell
+ - golint
+ - goimports
+ - ineffassign
+ - deadcode
+ - gofmt
+ - govet
+ - structcheck
+ - unconvert
+ - megacheck
+ - typecheck
+ - varcheck
diff --git a/vendor/github.com/manifoldco/promptui/.travis.yml b/vendor/github.com/manifoldco/promptui/.travis.yml
new file mode 100644
index 000000000..01c16c440
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/.travis.yml
@@ -0,0 +1,14 @@
+dist: bionic
+language: go
+
+go:
+ - "1.12.x"
+ - "1.13.x"
+
+branches:
+ only:
+ - master
+
+after_success:
+ # only report coverage for go-version 1.11
+ - if [[ $TRAVIS_GO_VERSION =~ ^1\.11 ]] ; then bash <(curl -s https://codecov.io/bash) -f all-cover.txt; fi
diff --git a/vendor/github.com/manifoldco/promptui/CHANGELOG.md b/vendor/github.com/manifoldco/promptui/CHANGELOG.md
new file mode 100644
index 000000000..563e9d00a
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/CHANGELOG.md
@@ -0,0 +1,123 @@
+# CHANGELOG
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## Unreleased
+
+## [0.8.0] - 2020-09-28
+
+### Added
+
+- Support ctrl-h for backspace
+- Allow hiding entered data after submit
+- Allow masking input with an empty rune to hide input length
+
+### Fixed
+
+- Fix echo of cursor after input is finished
+- Better support for keycodes on Windows
+
+
+## [0.7.0] - 2020-01-11
+
+### Added
+
+- Add support for configurable Stdin/Stdout on Prompt
+- Add support for setting initial cursor position
+- Switch to golangci-lint for linting
+
+### Removed
+
+- Removed support for Go 1.11
+
+### Fixed
+
+- Reduce tool-based deps, hopefully fixing any install issues
+
+## [0.6.0] - 2019-11-29
+
+### Added
+
+- Support configurable stdin
+
+### Fixed
+
+- Correct the dep on go-i18n
+
+## [0.5.0] - 2019-11-29
+
+### Added
+
+- Now building and testing on go 1.11, go 1.12, and go 1.13
+
+### Removed
+
+- Removed support for Go versions that don't include modules.
+
+## [0.4.0] - 2019-02-19
+
+### Added
+
+- The text displayed when an item was successfully selected can be hidden
+
+## [0.3.2] - 2018-11-26
+
+### Added
+
+- Support Go modules
+
+### Fixed
+
+- Fix typos in PromptTemplates documentation
+
+## [0.3.1] - 2018-07-26
+
+### Added
+
+- Improved documentation for GoDoc
+- Navigation keys information for Windows
+
+### Fixed
+
+- `success` template was not properly displayed after a successful prompt.
+
+## [0.3.0] - 2018-05-22
+
+### Added
+
+- Background colors codes and template helpers
+- `AllowEdit` for prompt to prevent deletion of the default value by any key
+- Added `StartInSearchMode` to allow starting the prompt in search mode
+
+### Fixed
+
+- `<Enter>` key press on Windows
+- `juju/ansiterm` dependency
+- `chzyer/readline#136` new api with ReadCloser
+- Deleting UTF-8 characters sequence
+
+## [0.2.1] - 2017-11-30
+
+### Fixed
+
+- `SelectWithAdd` panicking on `.Run` due to lack of keys setup
+- Backspace key on Windows
+
+## [0.2.0] - 2017-11-16
+
+### Added
+
+- `Select` items can now be searched
+
+## [0.1.0] - 2017-11-02
+
+### Added
+
+- extract `promptui` from [torus](https://github.com/manifoldco/torus-cli) as a
+ standalone lib.
+- `promptui.Prompt` provides a single input line to capture user information.
+- `promptui.Select` provides a list of options to choose from. Users can
+ navigate through the list either one item at time or by pagination
diff --git a/vendor/github.com/manifoldco/promptui/CODE_OF_CONDUCT.md b/vendor/github.com/manifoldco/promptui/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..cc58cce02
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/CODE_OF_CONDUCT.md
@@ -0,0 +1,73 @@
+# Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age,
+body size, disability, ethnicity, gender identity and expression, level of
+experience, nationality, personal appearance, race, religion, or sexual
+identity and orientation.
+
+## Our Standards
+
+Examples of behaviour that contributes to creating a positive environment
+include:
+
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+
+Examples of unacceptable behaviour by participants include:
+
+- The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behaviour and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behaviour.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviours that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an
+appointed representative at an online or offline event. Representation of a
+project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at
+[hello@manifold.co](mailto:hello@manifold.co). All complaints will be reviewed
+and investigated and will result in a response that is deemed necessary and
+appropriate to the circumstances. The project team is obligated to maintain
+confidentiality with regard to the reporter of an incident. Further details of
+specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
+available at
+[http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4).
diff --git a/vendor/github.com/manifoldco/promptui/LICENSE.md b/vendor/github.com/manifoldco/promptui/LICENSE.md
new file mode 100644
index 000000000..3ae687b2c
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/LICENSE.md
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2017, Arigato Machine Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/manifoldco/promptui/Makefile b/vendor/github.com/manifoldco/promptui/Makefile
new file mode 100644
index 000000000..078a5613a
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/Makefile
@@ -0,0 +1,49 @@
+export GO111MODULE := on
+export PATH := ./bin:$(PATH)
+
+ci: bootstrap lint cover
+.PHONY: ci
+
+#################################################
+# Bootstrapping for base golang package and tool deps
+#################################################
+
+bootstrap:
+ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.21.0
+.PHONY: bootstrap
+
+mod-update:
+ go get -u -m
+ go mod tidy
+
+mod-tidy:
+ go mod tidy
+
+.PHONY: $(CMD_PKGS)
+.PHONY: mod-update mod-tidy
+
+#################################################
+# Test and linting
+#################################################
+# Run all the linters
+lint:
+ bin/golangci-lint run ./...
+.PHONY: lint
+
+test:
+ CGO_ENABLED=0 go test $$(go list ./... | grep -v generated)
+.PHONY: test
+
+COVER_TEST_PKGS:=$(shell find . -type f -name '*_test.go' | rev | cut -d "/" -f 2- | rev | grep -v generated | sort -u)
+$(COVER_TEST_PKGS:=-cover): %-cover: all-cover.txt
+ @CGO_ENABLED=0 go test -v -coverprofile=$@.out -covermode=atomic ./$*
+ @if [ -f $@.out ]; then \
+ grep -v "mode: atomic" < $@.out >> all-cover.txt; \
+ rm $@.out; \
+ fi
+
+all-cover.txt:
+ echo "mode: atomic" > all-cover.txt
+
+cover: all-cover.txt $(COVER_TEST_PKGS:=-cover)
+.PHONY: cover all-cover.txt
diff --git a/vendor/github.com/manifoldco/promptui/README.md b/vendor/github.com/manifoldco/promptui/README.md
new file mode 100644
index 000000000..4fd4dc6d4
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/README.md
@@ -0,0 +1,107 @@
+# promptui
+
+Interactive prompt for command-line applications.
+
+We built Promptui because we wanted to make it easy and fun to explore cloud
+services with [manifold cli](https://github.com/manifoldco/manifold-cli).
+
+[Code of Conduct](./CODE_OF_CONDUCT.md) |
+[Contribution Guidelines](./.github/CONTRIBUTING.md)
+
+[![GitHub release](https://img.shields.io/github/tag/manifoldco/promptui.svg?label=latest)](https://github.com/manifoldco/promptui/releases)
+[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/manifoldco/promptui)
+[![Travis](https://img.shields.io/travis/manifoldco/promptui/master.svg)](https://travis-ci.org/manifoldco/promptui)
+[![Go Report Card](https://goreportcard.com/badge/github.com/manifoldco/promptui)](https://goreportcard.com/report/github.com/manifoldco/promptui)
+[![License](https://img.shields.io/badge/license-BSD-blue.svg)](./LICENSE.md)
+
+## Overview
+
+![promptui](https://media.giphy.com/media/xUNda0Ngb5qsogLsBi/giphy.gif)
+
+Promptui is a library providing a simple interface to create command-line
+prompts for go. It can be easily integrated into
+[spf13/cobra](https://github.com/spf13/cobra),
+[urfave/cli](https://github.com/urfave/cli) or any cli go application.
+
+Promptui has two main input modes:
+
+- `Prompt` provides a single line for user input. Prompt supports
+ optional live validation, confirmation and masking the input.
+
+- `Select` provides a list of options to choose from. Select supports
+ pagination, search, detailed view and custom templates.
+
+For a full list of options check [GoDoc](https://godoc.org/github.com/manifoldco/promptui).
+
+## Basic Usage
+
+### Prompt
+
+```go
+package main
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+
+ "github.com/manifoldco/promptui"
+)
+
+func main() {
+ validate := func(input string) error {
+ _, err := strconv.ParseFloat(input, 64)
+ if err != nil {
+ return errors.New("Invalid number")
+ }
+ return nil
+ }
+
+ prompt := promptui.Prompt{
+ Label: "Number",
+ Validate: validate,
+ }
+
+ result, err := prompt.Run()
+
+ if err != nil {
+ fmt.Printf("Prompt failed %v\n", err)
+ return
+ }
+
+ fmt.Printf("You choose %q\n", result)
+}
+```
+
+### Select
+
+```go
+package main
+
+import (
+ "fmt"
+
+ "github.com/manifoldco/promptui"
+)
+
+func main() {
+ prompt := promptui.Select{
+ Label: "Select Day",
+ Items: []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
+ "Saturday", "Sunday"},
+ }
+
+ _, result, err := prompt.Run()
+
+ if err != nil {
+ fmt.Printf("Prompt failed %v\n", err)
+ return
+ }
+
+ fmt.Printf("You choose %q\n", result)
+}
+```
+
+### More Examples
+
+See full list of [examples](https://github.com/manifoldco/promptui/tree/master/_examples)
diff --git a/vendor/github.com/manifoldco/promptui/codes.go b/vendor/github.com/manifoldco/promptui/codes.go
new file mode 100644
index 000000000..8138c40d6
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/codes.go
@@ -0,0 +1,120 @@
+package promptui
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "text/template"
+)
+
+const esc = "\033["
+
+type attribute int
+
+// The possible state of text inside the application, either Bold, faint, italic or underline.
+//
+// These constants are called through the use of the Styler function.
+const (
+ reset attribute = iota
+
+ FGBold
+ FGFaint
+ FGItalic
+ FGUnderline
+)
+
+// The possible colors of text inside the application.
+//
+// These constants are called through the use of the Styler function.
+const (
+ FGBlack attribute = iota + 30
+ FGRed
+ FGGreen
+ FGYellow
+ FGBlue
+ FGMagenta
+ FGCyan
+ FGWhite
+)
+
+// The possible background colors of text inside the application.
+//
+// These constants are called through the use of the Styler function.
+const (
+ BGBlack attribute = iota + 40
+ BGRed
+ BGGreen
+ BGYellow
+ BGBlue
+ BGMagenta
+ BGCyan
+ BGWhite
+)
+
+// ResetCode is the character code used to reset the terminal formatting
+var ResetCode = fmt.Sprintf("%s%dm", esc, reset)
+
+const (
+ hideCursor = esc + "?25l"
+ showCursor = esc + "?25h"
+ clearLine = esc + "2K"
+)
+
+// FuncMap defines template helpers for the output. It can be extended as a regular map.
+//
+// The functions inside the map link the state, color and background colors strings detected in templates to a Styler
+// function that applies the given style using the corresponding constant.
+var FuncMap = template.FuncMap{
+ "black": Styler(FGBlack),
+ "red": Styler(FGRed),
+ "green": Styler(FGGreen),
+ "yellow": Styler(FGYellow),
+ "blue": Styler(FGBlue),
+ "magenta": Styler(FGMagenta),
+ "cyan": Styler(FGCyan),
+ "white": Styler(FGWhite),
+ "bgBlack": Styler(BGBlack),
+ "bgRed": Styler(BGRed),
+ "bgGreen": Styler(BGGreen),
+ "bgYellow": Styler(BGYellow),
+ "bgBlue": Styler(BGBlue),
+ "bgMagenta": Styler(BGMagenta),
+ "bgCyan": Styler(BGCyan),
+ "bgWhite": Styler(BGWhite),
+ "bold": Styler(FGBold),
+ "faint": Styler(FGFaint),
+ "italic": Styler(FGItalic),
+ "underline": Styler(FGUnderline),
+}
+
+func upLine(n uint) string {
+ return movementCode(n, 'A')
+}
+
+func movementCode(n uint, code rune) string {
+ return esc + strconv.FormatUint(uint64(n), 10) + string(code)
+}
+
+// Styler is a function that accepts multiple possible styling transforms from the state,
+// color and background colors constants and transforms them into a templated string
+// to apply those styles in the CLI.
+//
+// The returned styling function accepts a string that will be extended with
+// the wrapping function's styling attributes.
+func Styler(attrs ...attribute) func(interface{}) string {
+ attrstrs := make([]string, len(attrs))
+ for i, v := range attrs {
+ attrstrs[i] = strconv.Itoa(int(v))
+ }
+
+ seq := strings.Join(attrstrs, ";")
+
+ return func(v interface{}) string {
+ end := ""
+ s, ok := v.(string)
+ if !ok || !strings.HasSuffix(s, ResetCode) {
+ end = ResetCode
+ }
+ return fmt.Sprintf("%s%sm%v%s", esc, seq, v, end)
+ }
+}
diff --git a/vendor/github.com/manifoldco/promptui/cursor.go b/vendor/github.com/manifoldco/promptui/cursor.go
new file mode 100644
index 000000000..7f0961bdb
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/cursor.go
@@ -0,0 +1,232 @@
+package promptui
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Pointer is A specific type that translates a given set of runes into a given
+// set of runes pointed at by the cursor.
+type Pointer func(to []rune) []rune
+
+func defaultCursor(ignored []rune) []rune {
+ return []rune("\u2588")
+}
+
+func blockCursor(input []rune) []rune {
+ return []rune(fmt.Sprintf("\\e[7m%s\\e[0m", string(input)))
+}
+
+func pipeCursor(input []rune) []rune {
+ marker := []rune("|")
+ out := []rune{}
+ out = append(out, marker...)
+ out = append(out, input...)
+ return out
+}
+
+var (
+ // DefaultCursor is a big square block character. Obscures whatever was
+ // input.
+ DefaultCursor Pointer = defaultCursor
+ // BlockCursor is a cursor which highlights a character by inverting colors
+ // on it.
+ BlockCursor Pointer = blockCursor
+ // PipeCursor is a pipe character "|" which appears before the input
+ // character.
+ PipeCursor Pointer = pipeCursor
+)
+
+// Cursor tracks the state associated with the movable cursor
+// The strategy is to keep the prompt, input pristine except for requested
+// modifications. The insertion of the cursor happens during a `format` call
+// and we read in new input via an `Update` call
+type Cursor struct {
+ // shows where the user inserts/updates text
+ Cursor Pointer
+ // what the user entered, and what we will echo back to them, after
+ // insertion of the cursor and prefixing with the prompt
+ input []rune
+ // Put the cursor before this slice
+ Position int
+ erase bool
+}
+
+// NewCursor create a new cursor, with the DefaultCursor, the specified input,
+// and position at the end of the specified starting input.
+func NewCursor(startinginput string, pointer Pointer, eraseDefault bool) Cursor {
+ if pointer == nil {
+ pointer = defaultCursor
+ }
+ cur := Cursor{Cursor: pointer, Position: len(startinginput), input: []rune(startinginput), erase: eraseDefault}
+ if eraseDefault {
+ cur.Start()
+ } else {
+ cur.End()
+ }
+ return cur
+}
+
+func (c *Cursor) String() string {
+ return fmt.Sprintf(
+ "Cursor: %s, input %s, Position %d",
+ string(c.Cursor([]rune(""))), string(c.input), c.Position)
+}
+
+// End is a convenience for c.Place(len(c.input)) so you don't have to know how I
+// indexed.
+func (c *Cursor) End() {
+ c.Place(len(c.input))
+}
+
+// Start is convenience for c.Place(0) so you don't have to know how I
+// indexed.
+func (c *Cursor) Start() {
+ c.Place(0)
+}
+
+// ensures we are in bounds.
+func (c *Cursor) correctPosition() {
+ if c.Position > len(c.input) {
+ c.Position = len(c.input)
+ }
+
+ if c.Position < 0 {
+ c.Position = 0
+ }
+}
+
+// insert the cursor rune array into r before the provided index
+func format(a []rune, c *Cursor) string {
+ i := c.Position
+ var b []rune
+
+ out := make([]rune, 0)
+ if i < len(a) {
+ b = c.Cursor(a[i : i+1])
+ out = append(out, a[:i]...) // does not include i
+ out = append(out, b...) // add the cursor
+ out = append(out, a[i+1:]...) // add the rest after i
+ } else {
+ b = c.Cursor([]rune{})
+ out = append(out, a...)
+ out = append(out, b...)
+ }
+ return string(out)
+}
+
+// Format renders the input with the Cursor appropriately positioned.
+func (c *Cursor) Format() string {
+ r := c.input
+ // insert the cursor
+ return format(r, c)
+}
+
+// FormatMask replaces all input runes with the mask rune.
+func (c *Cursor) FormatMask(mask rune) string {
+ if mask == ' ' {
+ return format([]rune{}, c)
+ }
+
+ r := make([]rune, len(c.input))
+ for i := range r {
+ r[i] = mask
+ }
+ return format(r, c)
+}
+
+// Update inserts newinput into the input []rune in the appropriate place.
+// The cursor is moved to the end of the inputed sequence.
+func (c *Cursor) Update(newinput string) {
+ a := c.input
+ b := []rune(newinput)
+ i := c.Position
+ a = append(a[:i], append(b, a[i:]...)...)
+ c.input = a
+ c.Move(len(b))
+}
+
+// Get returns a copy of the input
+func (c *Cursor) Get() string {
+ return string(c.input)
+}
+
+// GetMask returns a mask string with length equal to the input
+func (c *Cursor) GetMask(mask rune) string {
+ return strings.Repeat(string(mask), len(c.input))
+}
+
+// Replace replaces the previous input with whatever is specified, and moves the
+// cursor to the end position
+func (c *Cursor) Replace(input string) {
+ c.input = []rune(input)
+ c.End()
+}
+
+// Place moves the cursor to the absolute array index specified by position
+func (c *Cursor) Place(position int) {
+ c.Position = position
+ c.correctPosition()
+}
+
+// Move moves the cursor over in relative terms, by shift indices.
+func (c *Cursor) Move(shift int) {
+ // delete the current cursor
+ c.Position = c.Position + shift
+ c.correctPosition()
+}
+
+// Backspace removes the rune that precedes the cursor
+//
+// It handles being at the beginning or end of the row, and moves the cursor to
+// the appropriate position.
+func (c *Cursor) Backspace() {
+ a := c.input
+ i := c.Position
+ if i == 0 {
+ // Shrug
+ return
+ }
+ if i == len(a) {
+ c.input = a[:i-1]
+ } else {
+ c.input = append(a[:i-1], a[i:]...)
+ }
+ // now it's pointing to the i+1th element
+ c.Move(-1)
+}
+
+// Listen is a readline Listener that updates internal cursor state appropriately.
+func (c *Cursor) Listen(line []rune, pos int, key rune) ([]rune, int, bool) {
+ if line != nil {
+ // no matter what, update our internal representation.
+ c.Update(string(line))
+ }
+
+ switch key {
+ case 0: // empty
+ case KeyEnter:
+ return []rune(c.Get()), c.Position, false
+ case KeyBackspace, KeyCtrlH:
+ if c.erase {
+ c.erase = false
+ c.Replace("")
+ }
+ c.Backspace()
+ case KeyForward:
+ // the user wants to edit the default, despite how we set it up. Let
+ // them.
+ c.erase = false
+ c.Move(1)
+ case KeyBackward:
+ c.Move(-1)
+ default:
+ if c.erase {
+ c.erase = false
+ c.Replace("")
+ c.Update(string(key))
+ }
+ }
+
+ return []rune(c.Get()), c.Position, true
+}
diff --git a/vendor/github.com/manifoldco/promptui/go.mod b/vendor/github.com/manifoldco/promptui/go.mod
new file mode 100644
index 000000000..760a44deb
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/go.mod
@@ -0,0 +1,16 @@
+module github.com/manifoldco/promptui
+
+go 1.12
+
+require (
+ github.com/chzyer/logex v1.1.10 // indirect
+ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
+ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
+ github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a
+ github.com/kr/pretty v0.1.0 // indirect
+ github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a // indirect
+ github.com/mattn/go-colorable v0.0.9 // indirect
+ github.com/mattn/go-isatty v0.0.4 // indirect
+ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b // indirect
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
+)
diff --git a/vendor/github.com/manifoldco/promptui/go.sum b/vendor/github.com/manifoldco/promptui/go.sum
new file mode 100644
index 000000000..be5f99025
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/go.sum
@@ -0,0 +1,23 @@
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
+github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
+github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b h1:MQE+LT/ABUuuvEZ+YQAMSXindAdUh7slEmAkup74op4=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/vendor/github.com/manifoldco/promptui/keycodes.go b/vendor/github.com/manifoldco/promptui/keycodes.go
new file mode 100644
index 000000000..ef5cd6f0a
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/keycodes.go
@@ -0,0 +1,29 @@
+package promptui
+
+import "github.com/chzyer/readline"
+
+// These runes are used to identify the commands entered by the user in the command prompt. They map
+// to specific actions of promptui in prompt mode and can be remapped if necessary.
+var (
+ // KeyEnter is the default key for submission/selection.
+ KeyEnter rune = readline.CharEnter
+
+ // KeyCtrlH is the key for deleting input text.
+ KeyCtrlH rune = readline.CharCtrlH
+
+ // KeyPrev is the default key to go up during selection.
+ KeyPrev rune = readline.CharPrev
+ KeyPrevDisplay = "↑"
+
+ // KeyNext is the default key to go down during selection.
+ KeyNext rune = readline.CharNext
+ KeyNextDisplay = "↓"
+
+ // KeyBackward is the default key to page up during selection.
+ KeyBackward rune = readline.CharBackward
+ KeyBackwardDisplay = "←"
+
+ // KeyForward is the default key to page down during selection.
+ KeyForward rune = readline.CharForward
+ KeyForwardDisplay = "→"
+)
diff --git a/vendor/github.com/manifoldco/promptui/keycodes_other.go b/vendor/github.com/manifoldco/promptui/keycodes_other.go
new file mode 100644
index 000000000..789feae4c
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/keycodes_other.go
@@ -0,0 +1,10 @@
+// +build !windows
+
+package promptui
+
+import "github.com/chzyer/readline"
+
+var (
+ // KeyBackspace is the default key for deleting input text.
+ KeyBackspace rune = readline.CharBackspace
+)
diff --git a/vendor/github.com/manifoldco/promptui/keycodes_windows.go b/vendor/github.com/manifoldco/promptui/keycodes_windows.go
new file mode 100644
index 000000000..737d1566e
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/keycodes_windows.go
@@ -0,0 +1,10 @@
+// +build windows
+
+package promptui
+
+// source: https://msdn.microsoft.com/en-us/library/aa243025(v=vs.60).aspx
+
+var (
+ // KeyBackspace is the default key for deleting input text inside a command line prompt.
+ KeyBackspace rune = 8
+)
diff --git a/vendor/github.com/manifoldco/promptui/list/list.go b/vendor/github.com/manifoldco/promptui/list/list.go
new file mode 100644
index 000000000..c98a39cfa
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/list/list.go
@@ -0,0 +1,237 @@
+package list
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// Searcher is a base function signature that is used inside select when activating the search mode.
+// If defined, it is called on each items of the select and should return a boolean for whether or not
+// the item fits the searched term.
+type Searcher func(input string, index int) bool
+
+// NotFound is an index returned when no item was selected. This could
+// happen due to a search without results.
+const NotFound = -1
+
+// List holds a collection of items that can be displayed with an N number of
+// visible items. The list can be moved up, down by one item of time or an
+// entire page (ie: visible size). It keeps track of the current selected item.
+type List struct {
+ items []*interface{}
+ scope []*interface{}
+ cursor int // cursor holds the index of the current selected item
+ size int // size is the number of visible options
+ start int
+ Searcher Searcher
+}
+
+// New creates and initializes a list of searchable items. The items attribute must be a slice type with a
+// size greater than 0. Error will be returned if those two conditions are not met.
+func New(items interface{}, size int) (*List, error) {
+ if size < 1 {
+ return nil, fmt.Errorf("list size %d must be greater than 0", size)
+ }
+
+ if items == nil || reflect.TypeOf(items).Kind() != reflect.Slice {
+ return nil, fmt.Errorf("items %v is not a slice", items)
+ }
+
+ slice := reflect.ValueOf(items)
+ values := make([]*interface{}, slice.Len())
+
+ for i := range values {
+ item := slice.Index(i).Interface()
+ values[i] = &item
+ }
+
+ return &List{size: size, items: values, scope: values}, nil
+}
+
+// Prev moves the visible list back one item. If the selected item is out of
+// view, the new select item becomes the last visible item. If the list is
+// already at the top, nothing happens.
+func (l *List) Prev() {
+ if l.cursor > 0 {
+ l.cursor--
+ }
+
+ if l.start > l.cursor {
+ l.start = l.cursor
+ }
+}
+
+// Search allows the list to be filtered by a given term. The list must
+// implement the searcher function signature for this functionality to work.
+func (l *List) Search(term string) {
+ term = strings.Trim(term, " ")
+ l.cursor = 0
+ l.start = 0
+ l.search(term)
+}
+
+// CancelSearch stops the current search and returns the list to its
+// original order.
+func (l *List) CancelSearch() {
+ l.cursor = 0
+ l.start = 0
+ l.scope = l.items
+}
+
+func (l *List) search(term string) {
+ var scope []*interface{}
+
+ for i, item := range l.items {
+ if l.Searcher(term, i) {
+ scope = append(scope, item)
+ }
+ }
+
+ l.scope = scope
+}
+
+// Start returns the current render start position of the list.
+func (l *List) Start() int {
+ return l.start
+}
+
+// SetStart sets the current scroll position. Values out of bounds will be
+// clamped.
+func (l *List) SetStart(i int) {
+ if i < 0 {
+ i = 0
+ }
+ if i > l.cursor {
+ l.start = l.cursor
+ } else {
+ l.start = i
+ }
+}
+
+// SetCursor sets the position of the cursor in the list. Values out of bounds
+// will be clamped.
+func (l *List) SetCursor(i int) {
+ max := len(l.scope) - 1
+ if i >= max {
+ i = max
+ }
+ if i < 0 {
+ i = 0
+ }
+ l.cursor = i
+
+ if l.start > l.cursor {
+ l.start = l.cursor
+ } else if l.start+l.size <= l.cursor {
+ l.start = l.cursor - l.size + 1
+ }
+}
+
+// Next moves the visible list forward one item. If the selected item is out of
+// view, the new select item becomes the first visible item. If the list is
+// already at the bottom, nothing happens.
+func (l *List) Next() {
+ max := len(l.scope) - 1
+
+ if l.cursor < max {
+ l.cursor++
+ }
+
+ if l.start+l.size <= l.cursor {
+ l.start = l.cursor - l.size + 1
+ }
+}
+
+// PageUp moves the visible list backward by x items. Where x is the size of the
+// visible items on the list. The selected item becomes the first visible item.
+// If the list is already at the bottom, the selected item becomes the last
+// visible item.
+func (l *List) PageUp() {
+ start := l.start - l.size
+ if start < 0 {
+ l.start = 0
+ } else {
+ l.start = start
+ }
+
+ cursor := l.start
+
+ if cursor < l.cursor {
+ l.cursor = cursor
+ }
+}
+
+// PageDown moves the visible list forward by x items. Where x is the size of
+// the visible items on the list. The selected item becomes the first visible
+// item.
+func (l *List) PageDown() {
+ start := l.start + l.size
+ max := len(l.scope) - l.size
+
+ switch {
+ case len(l.scope) < l.size:
+ l.start = 0
+ case start > max:
+ l.start = max
+ default:
+ l.start = start
+ }
+
+ cursor := l.start
+
+ if cursor == l.cursor {
+ l.cursor = len(l.scope) - 1
+ } else if cursor > l.cursor {
+ l.cursor = cursor
+ }
+}
+
+// CanPageDown returns whether a list can still PageDown().
+func (l *List) CanPageDown() bool {
+ max := len(l.scope)
+ return l.start+l.size < max
+}
+
+// CanPageUp returns whether a list can still PageUp().
+func (l *List) CanPageUp() bool {
+ return l.start > 0
+}
+
+// Index returns the index of the item currently selected inside the searched list. If no item is selected,
+// the NotFound (-1) index is returned.
+func (l *List) Index() int {
+ selected := l.scope[l.cursor]
+
+ for i, item := range l.items {
+ if item == selected {
+ return i
+ }
+ }
+
+ return NotFound
+}
+
+// Items returns a slice equal to the size of the list with the current visible
+// items and the index of the active item in this list.
+func (l *List) Items() ([]interface{}, int) {
+ var result []interface{}
+ max := len(l.scope)
+ end := l.start + l.size
+
+ if end > max {
+ end = max
+ }
+
+ active := NotFound
+
+ for i, j := l.start, 0; i < end; i, j = i+1, j+1 {
+ if l.cursor == i {
+ active = j
+ }
+
+ result = append(result, *l.scope[i])
+ }
+
+ return result, active
+}
diff --git a/vendor/github.com/manifoldco/promptui/prompt.go b/vendor/github.com/manifoldco/promptui/prompt.go
new file mode 100644
index 000000000..8e35123b0
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/prompt.go
@@ -0,0 +1,341 @@
+package promptui
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "text/template"
+
+ "github.com/chzyer/readline"
+ "github.com/manifoldco/promptui/screenbuf"
+)
+
+// Prompt represents a single line text field input with options for validation and input masks.
+type Prompt struct {
+ // Label is the value displayed on the command line prompt.
+ //
+ // The value for Label can be a simple string or a struct that will need to be accessed by dot notation
+ // inside the templates. For example, `{{ .Name }}` will display the name property of a struct.
+ Label interface{}
+
+ // Default is the initial value for the prompt. This value will be displayed next to the prompt's label
+ // and the user will be able to view or change it depending on the options.
+ Default string
+
+ // AllowEdit lets the user edit the default value. If false, any key press
+ // other than <Enter> automatically clears the default value.
+ AllowEdit bool
+
+ // Validate is an optional function that fill be used against the entered value in the prompt to validate it.
+ Validate ValidateFunc
+
+ // Mask is an optional rune that sets which character to display instead of the entered characters. This
+ // allows hiding private information like passwords.
+ Mask rune
+
+ // HideEntered sets whether to hide the text after the user has pressed enter.
+ HideEntered bool
+
+ // Templates can be used to customize the prompt output. If nil is passed, the
+ // default templates are used. See the PromptTemplates docs for more info.
+ Templates *PromptTemplates
+
+ // IsConfirm makes the prompt ask for a yes or no ([Y/N]) question rather than request an input. When set,
+ // most properties related to input will be ignored.
+ IsConfirm bool
+
+ // IsVimMode enables vi-like movements (hjkl) and editing.
+ IsVimMode bool
+
+ // the Pointer defines how to render the cursor.
+ Pointer Pointer
+
+ Stdin io.ReadCloser
+ Stdout io.WriteCloser
+}
+
+// PromptTemplates allow a prompt to be customized following stdlib
+// text/template syntax. Custom state, colors and background color are available for use inside
+// the templates and are documented inside the Variable section of the docs.
+//
+// Examples
+//
+// text/templates use a special notation to display programmable content. Using the double bracket notation,
+// the value can be printed with specific helper functions. For example
+//
+// This displays the value given to the template as pure, unstylized text.
+// '{{ . }}'
+//
+// This displays the value colored in cyan
+// '{{ . | cyan }}'
+//
+// This displays the value colored in red with a cyan background-color
+// '{{ . | red | cyan }}'
+//
+// See the doc of text/template for more info: https://golang.org/pkg/text/template/
+type PromptTemplates struct {
+ // Prompt is a text/template for the prompt label displayed on the left side of the prompt.
+ Prompt string
+
+ // Prompt is a text/template for the prompt label when IsConfirm is set as true.
+ Confirm string
+
+ // Valid is a text/template for the prompt label when the value entered is valid.
+ Valid string
+
+ // Invalid is a text/template for the prompt label when the value entered is invalid.
+ Invalid string
+
+ // Success is a text/template for the prompt label when the user has pressed entered and the value has been
+ // deemed valid by the validation function. The label will keep using this template even when the prompt ends
+ // inside the console.
+ Success string
+
+ // Prompt is a text/template for the prompt label when the value is invalid due to an error triggered by
+ // the prompt's validation function.
+ ValidationError string
+
+ // FuncMap is a map of helper functions that can be used inside of templates according to the text/template
+ // documentation.
+ //
+ // By default, FuncMap contains the color functions used to color the text in templates. If FuncMap
+ // is overridden, the colors functions must be added in the override from promptui.FuncMap to work.
+ FuncMap template.FuncMap
+
+ prompt *template.Template
+ valid *template.Template
+ invalid *template.Template
+ validation *template.Template
+ success *template.Template
+}
+
+// Run executes the prompt. Its displays the label and default value if any, asking the user to enter a value.
+// Run will keep the prompt alive until it has been canceled from the command prompt or it has received a valid
+// value. It will return the value and an error if any occurred during the prompt's execution.
+func (p *Prompt) Run() (string, error) {
+ var err error
+
+ err = p.prepareTemplates()
+ if err != nil {
+ return "", err
+ }
+
+ c := &readline.Config{
+ Stdin: p.Stdin,
+ Stdout: p.Stdout,
+ EnableMask: p.Mask != 0,
+ MaskRune: p.Mask,
+ HistoryLimit: -1,
+ VimMode: p.IsVimMode,
+ UniqueEditLine: true,
+ }
+
+ err = c.Init()
+ if err != nil {
+ return "", err
+ }
+
+ rl, err := readline.NewEx(c)
+ if err != nil {
+ return "", err
+ }
+ // we're taking over the cursor, so stop showing it.
+ rl.Write([]byte(hideCursor))
+ sb := screenbuf.New(rl)
+
+ validFn := func(x string) error {
+ return nil
+ }
+ if p.Validate != nil {
+ validFn = p.Validate
+ }
+
+ var inputErr error
+ input := p.Default
+ if p.IsConfirm {
+ input = ""
+ }
+ eraseDefault := input != "" && !p.AllowEdit
+ cur := NewCursor(input, p.Pointer, eraseDefault)
+
+ listen := func(input []rune, pos int, key rune) ([]rune, int, bool) {
+ _, _, keepOn := cur.Listen(input, pos, key)
+ err := validFn(cur.Get())
+ var prompt []byte
+
+ if err != nil {
+ prompt = render(p.Templates.invalid, p.Label)
+ } else {
+ prompt = render(p.Templates.valid, p.Label)
+ if p.IsConfirm {
+ prompt = render(p.Templates.prompt, p.Label)
+ }
+ }
+
+ echo := cur.Format()
+ if p.Mask != 0 {
+ echo = cur.FormatMask(p.Mask)
+ }
+
+ prompt = append(prompt, []byte(echo)...)
+ sb.Reset()
+ sb.Write(prompt)
+ if inputErr != nil {
+ validation := render(p.Templates.validation, inputErr)
+ sb.Write(validation)
+ inputErr = nil
+ }
+ sb.Flush()
+ return nil, 0, keepOn
+ }
+
+ c.SetListener(listen)
+
+ for {
+ _, err = rl.Readline()
+ inputErr = validFn(cur.Get())
+ if inputErr == nil {
+ break
+ }
+
+ if err != nil {
+ break
+ }
+ }
+
+ if err != nil {
+ switch err {
+ case readline.ErrInterrupt:
+ err = ErrInterrupt
+ case io.EOF:
+ err = ErrEOF
+ }
+ if err.Error() == "Interrupt" {
+ err = ErrInterrupt
+ }
+ sb.Reset()
+ sb.WriteString("")
+ sb.Flush()
+ rl.Write([]byte(showCursor))
+ rl.Close()
+ return "", err
+ }
+
+ echo := cur.Get()
+ if p.Mask != 0 {
+ echo = cur.GetMask(p.Mask)
+ }
+
+ prompt := render(p.Templates.success, p.Label)
+ prompt = append(prompt, []byte(echo)...)
+
+ if p.IsConfirm {
+ lowerDefault := strings.ToLower(p.Default)
+ if strings.ToLower(cur.Get()) != "y" && (lowerDefault != "y" || (lowerDefault == "y" && cur.Get() != "")) {
+ prompt = render(p.Templates.invalid, p.Label)
+ err = ErrAbort
+ }
+ }
+
+ if p.HideEntered {
+ clearScreen(sb)
+ } else {
+ sb.Reset()
+ sb.Write(prompt)
+ sb.Flush()
+ }
+
+ rl.Write([]byte(showCursor))
+ rl.Close()
+
+ return cur.Get(), err
+}
+
+func (p *Prompt) prepareTemplates() error {
+ tpls := p.Templates
+ if tpls == nil {
+ tpls = &PromptTemplates{}
+ }
+
+ if tpls.FuncMap == nil {
+ tpls.FuncMap = FuncMap
+ }
+
+ bold := Styler(FGBold)
+
+ if p.IsConfirm {
+ if tpls.Confirm == "" {
+ confirm := "y/N"
+ if strings.ToLower(p.Default) == "y" {
+ confirm = "Y/n"
+ }
+ tpls.Confirm = fmt.Sprintf(`{{ "%s" | bold }} {{ . | bold }}? {{ "[%s]" | faint }} `, IconInitial, confirm)
+ }
+
+ tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Confirm)
+ if err != nil {
+ return err
+ }
+
+ tpls.prompt = tpl
+ } else {
+ if tpls.Prompt == "" {
+ tpls.Prompt = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconInitial), bold(":"))
+ }
+
+ tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Prompt)
+ if err != nil {
+ return err
+ }
+
+ tpls.prompt = tpl
+ }
+
+ if tpls.Valid == "" {
+ tpls.Valid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":"))
+ }
+
+ tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Valid)
+ if err != nil {
+ return err
+ }
+
+ tpls.valid = tpl
+
+ if tpls.Invalid == "" {
+ tpls.Invalid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconBad), bold(":"))
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Invalid)
+ if err != nil {
+ return err
+ }
+
+ tpls.invalid = tpl
+
+ if tpls.ValidationError == "" {
+ tpls.ValidationError = `{{ ">>" | red }} {{ . | red }}`
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.ValidationError)
+ if err != nil {
+ return err
+ }
+
+ tpls.validation = tpl
+
+ if tpls.Success == "" {
+ tpls.Success = fmt.Sprintf("{{ . | faint }}%s ", Styler(FGFaint)(":"))
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Success)
+ if err != nil {
+ return err
+ }
+
+ tpls.success = tpl
+
+ p.Templates = tpls
+
+ return nil
+}
diff --git a/vendor/github.com/manifoldco/promptui/promptui.go b/vendor/github.com/manifoldco/promptui/promptui.go
new file mode 100644
index 000000000..6248e5859
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/promptui.go
@@ -0,0 +1,27 @@
+// Package promptui is a library providing a simple interface to create command-line prompts for go.
+// It can be easily integrated into spf13/cobra, urfave/cli or any cli go application.
+//
+// promptui has two main input modes:
+//
+// Prompt provides a single line for user input. It supports optional live validation,
+// confirmation and masking the input.
+//
+// Select provides a list of options to choose from. It supports pagination, search,
+// detailed view and custom templates.
+package promptui
+
+import "errors"
+
+// ErrEOF is the error returned from prompts when EOF is encountered.
+var ErrEOF = errors.New("^D")
+
+// ErrInterrupt is the error returned from prompts when an interrupt (ctrl-c) is
+// encountered.
+var ErrInterrupt = errors.New("^C")
+
+// ErrAbort is the error returned when confirm prompts are supplied "n"
+var ErrAbort = errors.New("")
+
+// ValidateFunc is a placeholder type for any validation functions that validates a given input. It should return
+// a ValidationError if the input is not valid.
+type ValidateFunc func(string) error
diff --git a/vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go b/vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go
new file mode 100644
index 000000000..861390045
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go
@@ -0,0 +1,151 @@
+package screenbuf
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+const esc = "\033["
+
+var (
+ clearLine = []byte(esc + "2K\r")
+ moveUp = []byte(esc + "1A")
+ moveDown = []byte(esc + "1B")
+)
+
+// ScreenBuf is a convenient way to write to terminal screens. It creates,
+// clears and, moves up or down lines as needed to write the output to the
+// terminal using ANSI escape codes.
+type ScreenBuf struct {
+ w io.Writer
+ buf *bytes.Buffer
+ reset bool
+ cursor int
+ height int
+}
+
+// New creates and initializes a new ScreenBuf.
+func New(w io.Writer) *ScreenBuf {
+ return &ScreenBuf{buf: &bytes.Buffer{}, w: w}
+}
+
+// Reset truncates the underlining buffer and marks all its previous lines to be
+// cleared during the next Write.
+func (s *ScreenBuf) Reset() {
+ s.buf.Reset()
+ s.reset = true
+}
+
+// Clear clears all previous lines and the output starts from the top.
+func (s *ScreenBuf) Clear() error {
+ for i := 0; i < s.height; i++ {
+ _, err := s.buf.Write(moveUp)
+ if err != nil {
+ return err
+ }
+ _, err = s.buf.Write(clearLine)
+ if err != nil {
+ return err
+ }
+ }
+ s.cursor = 0
+ s.height = 0
+ s.reset = false
+ return nil
+}
+
+// Write writes a single line to the underlining buffer. If the ScreenBuf was
+// previously reset, all previous lines are cleared and the output starts from
+// the top. Lines with \r or \n will cause an error since they can interfere with the
+// terminal ability to move between lines.
+func (s *ScreenBuf) Write(b []byte) (int, error) {
+ if bytes.ContainsAny(b, "\r\n") {
+ return 0, fmt.Errorf("%q should not contain either \\r or \\n", b)
+ }
+
+ if s.reset {
+ if err := s.Clear(); err != nil {
+ return 0, err
+ }
+ }
+
+ switch {
+ case s.cursor == s.height:
+ n, err := s.buf.Write(clearLine)
+ if err != nil {
+ return n, err
+ }
+
+ n, err = s.buf.Write(b)
+ if err != nil {
+ return n, err
+ }
+
+ _, err = s.buf.Write([]byte("\n"))
+ if err != nil {
+ return n, err
+ }
+
+ s.height++
+ s.cursor++
+ return n, nil
+ case s.cursor < s.height:
+ n, err := s.buf.Write(clearLine)
+ if err != nil {
+ return n, err
+ }
+ n, err = s.buf.Write(b)
+ if err != nil {
+ return n, err
+ }
+ n, err = s.buf.Write(moveDown)
+ if err != nil {
+ return n, err
+ }
+ s.cursor++
+ return n, nil
+ default:
+ return 0, fmt.Errorf("Invalid write cursor position (%d) exceeded line height: %d", s.cursor, s.height)
+ }
+}
+
+// Flush writes any buffered data to the underlying io.Writer, ensuring that any pending data is displayed.
+func (s *ScreenBuf) Flush() error {
+ for i := s.cursor; i < s.height; i++ {
+ if i < s.height {
+ _, err := s.buf.Write(clearLine)
+ if err != nil {
+ return err
+ }
+ }
+ _, err := s.buf.Write(moveDown)
+ if err != nil {
+ return err
+ }
+ }
+
+ _, err := s.buf.WriteTo(s.w)
+ if err != nil {
+ return err
+ }
+
+ s.buf.Reset()
+
+ for i := 0; i < s.height; i++ {
+ _, err := s.buf.Write(moveUp)
+ if err != nil {
+ return err
+ }
+ }
+
+ s.cursor = 0
+
+ return nil
+}
+
+// WriteString is a convenient function to write a new line passing a string.
+// Check ScreenBuf.Write() for a detailed explanation of the function behaviour.
+func (s *ScreenBuf) WriteString(str string) (int, error) {
+ return s.Write([]byte(str))
+}
diff --git a/vendor/github.com/manifoldco/promptui/select.go b/vendor/github.com/manifoldco/promptui/select.go
new file mode 100644
index 000000000..19b9e0c2e
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/select.go
@@ -0,0 +1,637 @@
+package promptui
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "text/template"
+
+ "github.com/chzyer/readline"
+ "github.com/juju/ansiterm"
+ "github.com/manifoldco/promptui/list"
+ "github.com/manifoldco/promptui/screenbuf"
+)
+
+// SelectedAdd is used internally inside SelectWithAdd when the add option is selected in select mode.
+// Since -1 is not a possible selected index, this ensure that add mode is always unique inside
+// SelectWithAdd's logic.
+const SelectedAdd = -1
+
+// Select represents a list of items used to enable selections, they can be used as search engines, menus
+// or as a list of items in a cli based prompt.
+type Select struct {
+ // Label is the text displayed on top of the list to direct input. The IconInitial value "?" will be
+ // appended automatically to the label so it does not need to be added.
+ //
+ // The value for Label can be a simple string or a struct that will need to be accessed by dot notation
+ // inside the templates. For example, `{{ .Name }}` will display the name property of a struct.
+ Label interface{}
+
+ // Items are the items to display inside the list. It expect a slice of any kind of values, including strings.
+ //
+ // If using a slice of strings, promptui will use those strings directly into its base templates or the
+ // provided templates. If using any other type in the slice, it will attempt to transform it into a string
+ // before giving it to its templates. Custom templates will override this behavior if using the dot notation
+ // inside the templates.
+ //
+ // For example, `{{ .Name }}` will display the name property of a struct.
+ Items interface{}
+
+ // Size is the number of items that should appear on the select before scrolling is necessary. Defaults to 5.
+ Size int
+
+ // CursorPos is the initial position of the cursor.
+ CursorPos int
+
+ // IsVimMode sets whether to use vim mode when using readline in the command prompt. Look at
+ // https://godoc.org/github.com/chzyer/readline#Config for more information on readline.
+ IsVimMode bool
+
+ // HideHelp sets whether to hide help information.
+ HideHelp bool
+
+ // HideSelected sets whether to hide the text displayed after an item is successfully selected.
+ HideSelected bool
+
+ // Templates can be used to customize the select output. If nil is passed, the
+ // default templates are used. See the SelectTemplates docs for more info.
+ Templates *SelectTemplates
+
+ // Keys is the set of keys used in select mode to control the command line interface. See the SelectKeys docs for
+ // more info.
+ Keys *SelectKeys
+
+ // Searcher is a function that can be implemented to refine the base searching algorithm in selects.
+ //
+ // Search is a function that will receive the searched term and the item's index and should return a boolean
+ // for whether or not the terms are alike. It is unimplemented by default and search will not work unless
+ // it is implemented.
+ Searcher list.Searcher
+
+ // StartInSearchMode sets whether or not the select mode should start in search mode or selection mode.
+ // For search mode to work, the Search property must be implemented.
+ StartInSearchMode bool
+
+ list *list.List
+
+ // A function that determines how to render the cursor
+ Pointer Pointer
+
+ Stdin io.ReadCloser
+ Stdout io.WriteCloser
+}
+
+// SelectKeys defines the available keys used by select mode to enable the user to move around the list
+// and trigger search mode. See the Key struct docs for more information on keys.
+type SelectKeys struct {
+ // Next is the key used to move to the next element inside the list. Defaults to down arrow key.
+ Next Key
+
+ // Prev is the key used to move to the previous element inside the list. Defaults to up arrow key.
+ Prev Key
+
+ // PageUp is the key used to jump back to the first element inside the list. Defaults to left arrow key.
+ PageUp Key
+
+ // PageUp is the key used to jump forward to the last element inside the list. Defaults to right arrow key.
+ PageDown Key
+
+ // Search is the key used to trigger the search mode for the list. Default to the "/" key.
+ Search Key
+}
+
+// Key defines a keyboard code and a display representation for the help menu.
+type Key struct {
+ // Code is a rune that will be used to compare against typed keys with readline.
+ // Check https://github.com/chzyer/readline for a list of codes
+ Code rune
+
+ // Display is the string that will be displayed inside the help menu to help inform the user
+ // of which key to use on his keyboard for various functions.
+ Display string
+}
+
+// SelectTemplates allow a select list to be customized following stdlib
+// text/template syntax. Custom state, colors and background color are available for use inside
+// the templates and are documented inside the Variable section of the docs.
+//
+// Examples
+//
+// text/templates use a special notation to display programmable content. Using the double bracket notation,
+// the value can be printed with specific helper functions. For example
+//
+// This displays the value given to the template as pure, unstylized text. Structs are transformed to string
+// with this notation.
+// '{{ . }}'
+//
+// This displays the name property of the value colored in cyan
+// '{{ .Name | cyan }}'
+//
+// This displays the label property of value colored in red with a cyan background-color
+// '{{ .Label | red | cyan }}'
+//
+// See the doc of text/template for more info: https://golang.org/pkg/text/template/
+//
+// Notes
+//
+// Setting any of these templates will remove the icons from the default templates. They must
+// be added back in each of their specific templates. The styles.go constants contains the default icons.
+type SelectTemplates struct {
+ // Label is a text/template for the main command line label. Defaults to printing the label as it with
+ // the IconInitial.
+ Label string
+
+ // Active is a text/template for when an item is currently active within the list.
+ Active string
+
+ // Inactive is a text/template for when an item is not currently active inside the list. This
+ // template is used for all items unless they are active or selected.
+ Inactive string
+
+ // Selected is a text/template for when an item was successfully selected.
+ Selected string
+
+ // Details is a text/template for when an item current active to show
+ // additional information. It can have multiple lines.
+ //
+ // Detail will always be displayed for the active element and thus can be used to display additional
+ // information on the element beyond its label.
+ //
+ // promptui will not trim spaces and tabs will be displayed if the template is indented.
+ Details string
+
+ // Help is a text/template for displaying instructions at the top. By default
+ // it shows keys for movement and search.
+ Help string
+
+ // FuncMap is a map of helper functions that can be used inside of templates according to the text/template
+ // documentation.
+ //
+ // By default, FuncMap contains the color functions used to color the text in templates. If FuncMap
+ // is overridden, the colors functions must be added in the override from promptui.FuncMap to work.
+ FuncMap template.FuncMap
+
+ label *template.Template
+ active *template.Template
+ inactive *template.Template
+ selected *template.Template
+ details *template.Template
+ help *template.Template
+}
+
+// SearchPrompt is the prompt displayed in search mode.
+var SearchPrompt = "Search: "
+
+// Run executes the select list. It displays the label and the list of items, asking the user to chose any
+// value within to list. Run will keep the prompt alive until it has been canceled from
+// the command prompt or it has received a valid value. It will return the value and an error if any
+// occurred during the select's execution.
+func (s *Select) Run() (int, string, error) {
+ return s.RunCursorAt(s.CursorPos, 0)
+}
+
+// RunCursorAt executes the select list, initializing the cursor to the given
+// position. Invalid cursor positions will be clamped to valid values. It
+// displays the label and the list of items, asking the user to chose any value
+// within to list. Run will keep the prompt alive until it has been canceled
+// from the command prompt or it has received a valid value. It will return
+// the value and an error if any occurred during the select's execution.
+func (s *Select) RunCursorAt(cursorPos, scroll int) (int, string, error) {
+ if s.Size == 0 {
+ s.Size = 5
+ }
+
+ l, err := list.New(s.Items, s.Size)
+ if err != nil {
+ return 0, "", err
+ }
+ l.Searcher = s.Searcher
+
+ s.list = l
+
+ s.setKeys()
+
+ err = s.prepareTemplates()
+ if err != nil {
+ return 0, "", err
+ }
+ return s.innerRun(cursorPos, scroll, ' ')
+}
+
+func (s *Select) innerRun(cursorPos, scroll int, top rune) (int, string, error) {
+ c := &readline.Config{
+ Stdin: s.Stdin,
+ Stdout: s.Stdout,
+ }
+ err := c.Init()
+ if err != nil {
+ return 0, "", err
+ }
+
+ c.Stdin = readline.NewCancelableStdin(c.Stdin)
+
+ if s.IsVimMode {
+ c.VimMode = true
+ }
+
+ c.HistoryLimit = -1
+ c.UniqueEditLine = true
+
+ rl, err := readline.NewEx(c)
+ if err != nil {
+ return 0, "", err
+ }
+
+ rl.Write([]byte(hideCursor))
+ sb := screenbuf.New(rl)
+
+ cur := NewCursor("", s.Pointer, false)
+
+ canSearch := s.Searcher != nil
+ searchMode := s.StartInSearchMode
+ s.list.SetCursor(cursorPos)
+ s.list.SetStart(scroll)
+
+ c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {
+ switch {
+ case key == KeyEnter:
+ return nil, 0, true
+ case key == s.Keys.Next.Code || (key == 'j' && !searchMode):
+ s.list.Next()
+ case key == s.Keys.Prev.Code || (key == 'k' && !searchMode):
+ s.list.Prev()
+ case key == s.Keys.Search.Code:
+ if !canSearch {
+ break
+ }
+
+ if searchMode {
+ searchMode = false
+ cur.Replace("")
+ s.list.CancelSearch()
+ } else {
+ searchMode = true
+ }
+ case key == KeyBackspace || key == KeyCtrlH:
+ if !canSearch || !searchMode {
+ break
+ }
+
+ cur.Backspace()
+ if len(cur.Get()) > 0 {
+ s.list.Search(cur.Get())
+ } else {
+ s.list.CancelSearch()
+ }
+ case key == s.Keys.PageUp.Code || (key == 'h' && !searchMode):
+ s.list.PageUp()
+ case key == s.Keys.PageDown.Code || (key == 'l' && !searchMode):
+ s.list.PageDown()
+ default:
+ if canSearch && searchMode {
+ cur.Update(string(line))
+ s.list.Search(cur.Get())
+ }
+ }
+
+ if searchMode {
+ header := SearchPrompt + cur.Format()
+ sb.WriteString(header)
+ } else if !s.HideHelp {
+ help := s.renderHelp(canSearch)
+ sb.Write(help)
+ }
+
+ label := render(s.Templates.label, s.Label)
+ sb.Write(label)
+
+ items, idx := s.list.Items()
+ last := len(items) - 1
+
+ for i, item := range items {
+ page := " "
+
+ switch i {
+ case 0:
+ if s.list.CanPageUp() {
+ page = "↑"
+ } else {
+ page = string(top)
+ }
+ case last:
+ if s.list.CanPageDown() {
+ page = "↓"
+ }
+ }
+
+ output := []byte(page + " ")
+
+ if i == idx {
+ output = append(output, render(s.Templates.active, item)...)
+ } else {
+ output = append(output, render(s.Templates.inactive, item)...)
+ }
+
+ sb.Write(output)
+ }
+
+ if idx == list.NotFound {
+ sb.WriteString("")
+ sb.WriteString("No results")
+ } else {
+ active := items[idx]
+
+ details := s.renderDetails(active)
+ for _, d := range details {
+ sb.Write(d)
+ }
+ }
+
+ sb.Flush()
+
+ return nil, 0, true
+ })
+
+ for {
+ _, err = rl.Readline()
+
+ if err != nil {
+ switch {
+ case err == readline.ErrInterrupt, err.Error() == "Interrupt":
+ err = ErrInterrupt
+ case err == io.EOF:
+ err = ErrEOF
+ }
+ break
+ }
+
+ _, idx := s.list.Items()
+ if idx != list.NotFound {
+ break
+ }
+
+ }
+
+ if err != nil {
+ if err.Error() == "Interrupt" {
+ err = ErrInterrupt
+ }
+ sb.Reset()
+ sb.WriteString("")
+ sb.Flush()
+ rl.Write([]byte(showCursor))
+ rl.Close()
+ return 0, "", err
+ }
+
+ items, idx := s.list.Items()
+ item := items[idx]
+
+ if s.HideSelected {
+ clearScreen(sb)
+ } else {
+ sb.Reset()
+ sb.Write(render(s.Templates.selected, item))
+ sb.Flush()
+ }
+
+ rl.Write([]byte(showCursor))
+ rl.Close()
+
+ return s.list.Index(), fmt.Sprintf("%v", item), err
+}
+
+// ScrollPosition returns the current scroll position.
+func (s *Select) ScrollPosition() int {
+ return s.list.Start()
+}
+
+func (s *Select) prepareTemplates() error {
+ tpls := s.Templates
+ if tpls == nil {
+ tpls = &SelectTemplates{}
+ }
+
+ if tpls.FuncMap == nil {
+ tpls.FuncMap = FuncMap
+ }
+
+ if tpls.Label == "" {
+ tpls.Label = fmt.Sprintf("%s {{.}}: ", IconInitial)
+ }
+
+ tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Label)
+ if err != nil {
+ return err
+ }
+
+ tpls.label = tpl
+
+ if tpls.Active == "" {
+ tpls.Active = fmt.Sprintf("%s {{ . | underline }}", IconSelect)
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Active)
+ if err != nil {
+ return err
+ }
+
+ tpls.active = tpl
+
+ if tpls.Inactive == "" {
+ tpls.Inactive = " {{.}}"
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Inactive)
+ if err != nil {
+ return err
+ }
+
+ tpls.inactive = tpl
+
+ if tpls.Selected == "" {
+ tpls.Selected = fmt.Sprintf(`{{ "%s" | green }} {{ . | faint }}`, IconGood)
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Selected)
+ if err != nil {
+ return err
+ }
+ tpls.selected = tpl
+
+ if tpls.Details != "" {
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Details)
+ if err != nil {
+ return err
+ }
+
+ tpls.details = tpl
+ }
+
+ if tpls.Help == "" {
+ tpls.Help = fmt.Sprintf(`{{ "Use the arrow keys to navigate:" | faint }} {{ .NextKey | faint }} ` +
+ `{{ .PrevKey | faint }} {{ .PageDownKey | faint }} {{ .PageUpKey | faint }} ` +
+ `{{ if .Search }} {{ "and" | faint }} {{ .SearchKey | faint }} {{ "toggles search" | faint }}{{ end }}`)
+ }
+
+ tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Help)
+ if err != nil {
+ return err
+ }
+
+ tpls.help = tpl
+
+ s.Templates = tpls
+
+ return nil
+}
+
+// SelectWithAdd represents a list for selecting a single item inside a list of items with the possibility to
+// add new items to the list.
+type SelectWithAdd struct {
+ // Label is the text displayed on top of the list to direct input. The IconInitial value "?" will be
+ // appended automatically to the label so it does not need to be added.
+ Label string
+
+ // Items are the items to display inside the list. Each item will be listed individually with the
+ // AddLabel as the first item of the list.
+ Items []string
+
+ // AddLabel is the label used for the first item of the list that enables adding a new item.
+ // Selecting this item in the list displays the add item prompt using promptui/prompt.
+ AddLabel string
+
+ // Validate is an optional function that fill be used against the entered value in the prompt to validate it.
+ // If the value is valid, it is returned to the callee to be added in the list.
+ Validate ValidateFunc
+
+ // IsVimMode sets whether to use vim mode when using readline in the command prompt. Look at
+ // https://godoc.org/github.com/chzyer/readline#Config for more information on readline.
+ IsVimMode bool
+
+ // a function that defines how to render the cursor
+ Pointer Pointer
+
+ // HideHelp sets whether to hide help information.
+ HideHelp bool
+}
+
+// Run executes the select list. Its displays the label and the list of items, asking the user to chose any
+// value within to list or add his own. Run will keep the prompt alive until it has been canceled from
+// the command prompt or it has received a valid value.
+//
+// If the addLabel is selected in the list, this function will return a -1 index with the added label and no error.
+// Otherwise, it will return the index and the value of the selected item. In any case, if an error is triggered, it
+// will also return the error as its third return value.
+func (sa *SelectWithAdd) Run() (int, string, error) {
+ if len(sa.Items) > 0 {
+ newItems := append([]string{sa.AddLabel}, sa.Items...)
+
+ list, err := list.New(newItems, 5)
+ if err != nil {
+ return 0, "", err
+ }
+
+ s := Select{
+ Label: sa.Label,
+ Items: newItems,
+ IsVimMode: sa.IsVimMode,
+ HideHelp: sa.HideHelp,
+ Size: 5,
+ list: list,
+ Pointer: sa.Pointer,
+ }
+ s.setKeys()
+
+ err = s.prepareTemplates()
+ if err != nil {
+ return 0, "", err
+ }
+
+ selected, value, err := s.innerRun(1, 0, '+')
+ if err != nil || selected != 0 {
+ return selected - 1, value, err
+ }
+
+ // XXX run through terminal for windows
+ os.Stdout.Write([]byte(upLine(1) + "\r" + clearLine))
+ }
+
+ p := Prompt{
+ Label: sa.AddLabel,
+ Validate: sa.Validate,
+ IsVimMode: sa.IsVimMode,
+ Pointer: sa.Pointer,
+ }
+ value, err := p.Run()
+ return SelectedAdd, value, err
+}
+
+func (s *Select) setKeys() {
+ if s.Keys != nil {
+ return
+ }
+ s.Keys = &SelectKeys{
+ Prev: Key{Code: KeyPrev, Display: KeyPrevDisplay},
+ Next: Key{Code: KeyNext, Display: KeyNextDisplay},
+ PageUp: Key{Code: KeyBackward, Display: KeyBackwardDisplay},
+ PageDown: Key{Code: KeyForward, Display: KeyForwardDisplay},
+ Search: Key{Code: '/', Display: "/"},
+ }
+}
+
+func (s *Select) renderDetails(item interface{}) [][]byte {
+ if s.Templates.details == nil {
+ return nil
+ }
+
+ var buf bytes.Buffer
+ w := ansiterm.NewTabWriter(&buf, 0, 0, 8, ' ', 0)
+
+ err := s.Templates.details.Execute(w, item)
+ if err != nil {
+ fmt.Fprintf(w, "%v", item)
+ }
+
+ w.Flush()
+
+ output := buf.Bytes()
+
+ return bytes.Split(output, []byte("\n"))
+}
+
+func (s *Select) renderHelp(b bool) []byte {
+ keys := struct {
+ NextKey string
+ PrevKey string
+ PageDownKey string
+ PageUpKey string
+ Search bool
+ SearchKey string
+ }{
+ NextKey: s.Keys.Next.Display,
+ PrevKey: s.Keys.Prev.Display,
+ PageDownKey: s.Keys.PageDown.Display,
+ PageUpKey: s.Keys.PageUp.Display,
+ SearchKey: s.Keys.Search.Display,
+ Search: b,
+ }
+
+ return render(s.Templates.help, keys)
+}
+
+func render(tpl *template.Template, data interface{}) []byte {
+ var buf bytes.Buffer
+ err := tpl.Execute(&buf, data)
+ if err != nil {
+ return []byte(fmt.Sprintf("%v", data))
+ }
+ return buf.Bytes()
+}
+
+func clearScreen(sb *screenbuf.ScreenBuf) {
+ sb.Reset()
+ sb.Clear()
+ sb.Flush()
+}
diff --git a/vendor/github.com/manifoldco/promptui/styles.go b/vendor/github.com/manifoldco/promptui/styles.go
new file mode 100644
index 000000000..d7698c9cf
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/styles.go
@@ -0,0 +1,23 @@
+// +build !windows
+
+package promptui
+
+// These are the default icons used by promptui for select and prompts. These should not be overridden and instead
+// customized through the use of custom templates
+var (
+ // IconInitial is the icon used when starting in prompt mode and the icon next to the label when
+ // starting in select mode.
+ IconInitial = Styler(FGBlue)("?")
+
+ // IconGood is the icon used when a good answer is entered in prompt mode.
+ IconGood = Styler(FGGreen)("✔")
+
+ // IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode.
+ IconWarn = Styler(FGYellow)("⚠")
+
+ // IconBad is the icon used when a bad answer is entered in prompt mode.
+ IconBad = Styler(FGRed)("✗")
+
+ // IconSelect is the icon used to identify the currently selected item in select mode.
+ IconSelect = Styler(FGBold)("▸")
+)
diff --git a/vendor/github.com/manifoldco/promptui/styles_windows.go b/vendor/github.com/manifoldco/promptui/styles_windows.go
new file mode 100644
index 000000000..36de268a6
--- /dev/null
+++ b/vendor/github.com/manifoldco/promptui/styles_windows.go
@@ -0,0 +1,21 @@
+package promptui
+
+// These are the default icons used bu promptui for select and prompts. They can either be overridden directly
+// from these variable or customized through the use of custom templates
+var (
+ // IconInitial is the icon used when starting in prompt mode and the icon next to the label when
+ // starting in select mode.
+ IconInitial = Styler(FGBlue)("?")
+
+ // IconGood is the icon used when a good answer is entered in prompt mode.
+ IconGood = Styler(FGGreen)("v")
+
+ // IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode.
+ IconWarn = Styler(FGYellow)("!")
+
+ // IconBad is the icon used when a bad answer is entered in prompt mode.
+ IconBad = Styler(FGRed)("x")
+
+ // IconSelect is the icon used to identify the currently selected item in select mode.
+ IconSelect = Styler(FGBold)(">")
+)