Add vendor dependencies as part git repo

This commit is contained in:
Sam Stoelinga
2022-09-29 16:34:47 -07:00
parent a3b77e3e71
commit b624df4c39
3233 changed files with 1071657 additions and 0 deletions

3
vendor/github.com/manifoldco/promptui/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
vendor
all-cover.txt
bin/

26
vendor/github.com/manifoldco/promptui/.golangci.yml generated vendored Normal file
View File

@ -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

14
vendor/github.com/manifoldco/promptui/.travis.yml generated vendored Normal file
View File

@ -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

130
vendor/github.com/manifoldco/promptui/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,130 @@
# 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.9.0] - 2021-10-30
### Fixed
- Resolve license incompatibility in tabwriter
## [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

View File

@ -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).

29
vendor/github.com/manifoldco/promptui/LICENSE.md generated vendored Normal file
View File

@ -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.

49
vendor/github.com/manifoldco/promptui/Makefile generated vendored Normal file
View File

@ -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

107
vendor/github.com/manifoldco/promptui/README.md generated vendored Normal file
View File

@ -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)

120
vendor/github.com/manifoldco/promptui/codes.go generated vendored Normal file
View File

@ -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)
}
}

232
vendor/github.com/manifoldco/promptui/cursor.go generated vendored Normal file
View File

@ -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
}

29
vendor/github.com/manifoldco/promptui/keycodes.go generated vendored Normal file
View File

@ -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 = "→"
)

View File

@ -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
)

View File

@ -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
)

237
vendor/github.com/manifoldco/promptui/list/list.go generated vendored Normal file
View File

@ -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
}

341
vendor/github.com/manifoldco/promptui/prompt.go generated vendored Normal file
View File

@ -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
}

27
vendor/github.com/manifoldco/promptui/promptui.go generated vendored Normal file
View File

@ -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

View File

@ -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))
}

638
vendor/github.com/manifoldco/promptui/select.go generated vendored Normal file
View File

@ -0,0 +1,638 @@
package promptui
import (
"bytes"
"fmt"
"io"
"os"
"text/tabwriter"
"text/template"
"github.com/chzyer/readline"
"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 := tabwriter.NewWriter(&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()
}

23
vendor/github.com/manifoldco/promptui/styles.go generated vendored Normal file
View File

@ -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)("▸")
)

View File

@ -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)(">")
)