Commited dependencies

This commit is contained in:
2018-04-02 14:09:29 +01:00
parent 08be7ec383
commit 080d61728c
317 changed files with 156388 additions and 0 deletions

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

@@ -0,0 +1 @@
vendor

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

@@ -0,0 +1,10 @@
language: go
go:
- 1.8.x
- 1.9.x
branches:
only:
- master
install: make bootstrap

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

@@ -0,0 +1,30 @@
# 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.2.1] - 2017-11-30
### Fixed
- `SelectWithAdd` panicking on `.Run` due to lack of keys setup
## [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).

129
vendor/github.com/manifoldco/promptui/Gopkg.lock generated vendored Normal file
View File

@@ -0,0 +1,129 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/alecthomas/gometalinter"
packages = ["."]
revision = "bae2f1293d092fd8167939d5108d1b025eaef9de"
version = "v1.2.1"
[[projects]]
branch = "master"
name = "github.com/alecthomas/units"
packages = ["."]
revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
[[projects]]
branch = "master"
name = "github.com/chzyer/readline"
packages = ["."]
revision = "6a4bc7b4feaeff8feb63f87d5fb2cf3e3610a559"
[[projects]]
name = "github.com/client9/misspell"
packages = [".","cmd/misspell"]
revision = "59894abde931a32630d4e884a09c682ed20c5c7c"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "github.com/golang/lint"
packages = [".","golint"]
revision = "6aaf7c34af0f4c36a57e0c429bace4d706d8e931"
[[projects]]
branch = "master"
name = "github.com/google/shlex"
packages = ["."]
revision = "6f45313302b9c56850fc17f99e40caebce98c716"
[[projects]]
branch = "master"
name = "github.com/gordonklaus/ineffassign"
packages = ["."]
revision = "da3d65debb9bff70fcfb6f277a8db31e8200de20"
[[projects]]
branch = "master"
name = "github.com/juju/ansiterm"
packages = [".","tabwriter"]
revision = "35c59b9e0fe275705a71bf5d58ee293f27efbbc4"
[[projects]]
branch = "master"
name = "github.com/kisielk/gotool"
packages = [".","internal/load"]
revision = "d6ce6262d87e3a4e153e86023ff56ae771554a41"
[[projects]]
branch = "master"
name = "github.com/lunixbochs/vtclean"
packages = ["."]
revision = "d14193dfc626125c831501c1c42340b4248e1f5a"
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
name = "github.com/nicksnyder/go-i18n"
packages = ["i18n","i18n/bundle","i18n/language","i18n/translation"]
revision = "ca33e78c8a430e2df435b02f63a3944fa8e9ea11"
version = "v1.9.0"
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "16398bac157da96aa88f98a2df640c7f32af1da2"
version = "v1.0.1"
[[projects]]
branch = "master"
name = "github.com/tsenart/deadcode"
packages = ["."]
revision = "210d2dc333e90c7e3eedf4f2242507a8e83ed4ab"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "686000749eaec0b8855b8eef5336cf63899fe51d"
[[projects]]
branch = "master"
name = "golang.org/x/tools"
packages = ["go/ast/astutil","go/buildutil","go/gcexportdata","go/gcimporter15","go/loader","go/types/typeutil"]
revision = "9bd2f442688b66c5289262d70f537c2ecf81d7de"
[[projects]]
branch = "v3-unstable"
name = "gopkg.in/alecthomas/kingpin.v3-unstable"
packages = ["."]
revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306"
[[projects]]
branch = "v2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
[[projects]]
name = "honnef.co/go/tools"
packages = ["cmd/gosimple","internal/sharedcheck","lint","lint/lintutil","simple","ssa","ssa/ssautil","version"]
revision = "e5147431c7c056bd6ef33ad2f23c846f835571dd"
version = "2017.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "160169cbbea61d01890b2670b2cc5448b5b8dd6ebbb18f57bd677c0c7d1f8a42"
solver-name = "gps-cdcl"
solver-version = 1

16
vendor/github.com/manifoldco/promptui/Gopkg.toml generated vendored Normal file
View File

@@ -0,0 +1,16 @@
required=[
"honnef.co/go/tools/cmd/gosimple",
"github.com/alecthomas/gometalinter",
"github.com/client9/misspell/cmd/misspell",
"github.com/golang/lint/golint",
"github.com/gordonklaus/ineffassign",
"github.com/tsenart/deadcode",
]
[[constraint]]
name = "github.com/chzyer/readline"
branch = "master"
[[constraint]]
name = "github.com/juju/master"
branch = "master"

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.

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

@@ -0,0 +1,55 @@
LINTERS=\
gofmt \
golint \
gosimple \
vet \
misspell \
ineffassign \
deadcode
ci: $(LINTERS) test
.PHONY: ci
#################################################
# Bootstrapping for base golang package deps
#################################################
CMD_PKGS=\
github.com/golang/lint/golint \
honnef.co/go/tools/cmd/gosimple \
github.com/client9/misspell/cmd/misspell \
github.com/gordonklaus/ineffassign \
github.com/tsenart/deadcode \
github.com/alecthomas/gometalinter
define VENDOR_BIN_TMPL
vendor/bin/$(notdir $(1)): vendor
go build -o $$@ ./vendor/$(1)
VENDOR_BINS += vendor/bin/$(notdir $(1))
endef
$(foreach cmd_pkg,$(CMD_PKGS),$(eval $(call VENDOR_BIN_TMPL,$(cmd_pkg))))
$(patsubst %,%-bin,$(filter-out gofmt vet,$(LINTERS))): %-bin: vendor/bin/%
gofmt-bin vet-bin:
bootstrap:
which dep || go get -u github.com/golang/dep/cmd/dep
vendor: Gopkg.lock
dep ensure
.PHONY: bootstrap $(CMD_PKGS)
#################################################
# Test and linting
#################################################
test: vendor
@CGO_ENABLED=0 go test -v $$(go list ./... | grep -v vendor)
$(LINTERS): %: vendor/bin/gometalinter %-bin vendor
PATH=`pwd`/vendor/bin:$$PATH gometalinter --tests --disable-all --vendor \
--deadline=5m -s data ./... --enable $@
.PHONY: $(LINTERS) test

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

@@ -0,0 +1,106 @@
# 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)

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

@@ -0,0 +1,88 @@
package promptui
import (
"fmt"
"strconv"
"strings"
"text/template"
)
const esc = "\033["
type attribute int
// Foreground weight/decoration attributes.
const (
reset attribute = iota
FGBold
FGFaint
FGItalic
FGUnderline
)
// Foreground color attributes
const (
FGBlack attribute = iota + 30
FGRed
FGGreen
FGYellow
FGBlue
FGMagenta
FGCyan
FGWhite
)
// 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.
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),
"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 returns a func that applies the attributes given in the Styler call
// to the provided string.
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)
}
}

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

@@ -0,0 +1,197 @@
package list
import (
"fmt"
"reflect"
"strings"
)
// Searcher can be implemented to allow the list to search for results.
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. Items must be a slice type and size must
// be greater than 0.
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 method for that.
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
}
// 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.
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
}

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

@@ -0,0 +1,325 @@
package promptui
import (
"fmt"
"io"
"strings"
"text/template"
"github.com/chzyer/readline"
"github.com/manifoldco/promptui/screenbuf"
)
const cursor = "\u2588"
// Prompt represents a single line text field input.
type Prompt struct {
// Label is the value displayed on the command line prompt. It can be any
// value one would pass to a text/template Execute(), including just a string.
Label interface{}
Default string // Default is the initial value to populate in the prompt
// Validate is optional. If set, this function is used to validate the input
// after each character entry.
Validate ValidateFunc
// If mask is set, this value is displayed instead of the actual input
// characters.
Mask rune
// Templates can be used to customize the prompt output. If nil is passed, the
// default templates are used.
Templates *PromptTemplates
IsConfirm bool
IsVimMode bool
stdin io.Reader
stdout io.Writer
}
// PromptTemplates allow a prompt to be customized following stdlib
// text/template syntax. If any field is blank a default template is used.
type PromptTemplates struct {
// Prompt is a text/template for the initial prompt question.
Prompt string
// Prompt is a text/template if the prompt is a confirmation.
Confirm string
// Valid is a text/template for when the current input is valid.
Valid string
// Invalid is a text/template for when the current input is invalid.
Invalid string
// Success is a text/template for the successful result.
Success string
// Prompt is a text/template when there is a validation error.
ValidationError string
// FuncMap is a map of helpers for the templates. If nil, the default helpers
// are used.
FuncMap template.FuncMap
prompt *template.Template
valid *template.Template
invalid *template.Template
validation *template.Template
success *template.Template
}
// Run runs the prompt, returning the validated input.
func (p *Prompt) Run() (string, error) {
c := &readline.Config{}
err := c.Init()
if err != nil {
return "", err
}
err = p.prepareTemplates()
if err != nil {
return "", err
}
if p.stdin != nil {
c.Stdin = p.stdin
}
if p.stdout != nil {
c.Stdout = p.stdout
}
if p.Mask != 0 {
c.EnableMask = true
c.MaskRune = p.Mask
}
if p.IsVimMode {
c.VimMode = true
}
c.HistoryLimit = -1
c.UniqueEditLine = true
rl, err := readline.NewEx(c)
if err != nil {
return "", err
}
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
eraseDefault := input != ""
c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {
if line != nil {
input += string(line)
}
switch key {
case 0: // empty
case readline.CharEnter:
return nil, 0, false
case readline.CharBackspace:
if eraseDefault {
eraseDefault = false
input = ""
}
if len(input) > 0 {
input = input[:len(input)-1]
}
default:
if eraseDefault {
eraseDefault = false
input = string(line)
}
}
err := validFn(input)
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 := input
if p.Mask != 0 {
echo = strings.Repeat(string(p.Mask), len(echo))
}
prompt = append(prompt, []byte(echo+cursor)...)
sb.Reset()
sb.Write(prompt)
if inputErr != nil {
validation := render(p.Templates.validation, inputErr)
sb.Write(validation)
inputErr = nil
}
sb.Flush()
return nil, 0, true
})
for {
_, err = rl.Readline()
inputErr = validFn(input)
if inputErr == nil {
break
}
if err != nil {
switch err {
case readline.ErrInterrupt:
err = ErrInterrupt
case io.EOF:
err = ErrEOF
}
break
}
}
if err != nil {
if err.Error() == "Interrupt" {
err = ErrInterrupt
}
sb.Reset()
sb.WriteString("")
sb.Flush()
rl.Write([]byte(showCursor))
rl.Close()
return "", err
}
echo := input
if p.Mask != 0 {
echo = strings.Repeat(string(p.Mask), len(echo))
}
prompt := render(p.Templates.valid, p.Label)
prompt = append(prompt, []byte(echo)...)
if p.IsConfirm && strings.ToLower(echo) != "y" {
prompt = render(p.Templates.invalid, p.Label)
err = ErrAbort
}
sb.Reset()
sb.Write(prompt)
sb.Flush()
rl.Write([]byte(showCursor))
rl.Close()
return input, 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 {
p.Default = ""
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 = `{{ . | faint }}`
}
tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Success)
if err != nil {
return err
}
tpls.success = tpl
p.Templates = tpls
return nil
}

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

@@ -0,0 +1,18 @@
// Package promptui provides ui elements for the command line prompt.
package promptui
import "errors"
// ErrEOF is returned from prompts when EOF is encountered.
var ErrEOF = errors.New("^D")
// ErrInterrupt is returned from prompts when an interrupt (ctrl-c) is
// encountered.
var ErrInterrupt = errors.New("^C")
// ErrAbort is returned when confirm prompts are supplied "n"
var ErrAbort = errors.New("")
// ValidateFunc validates the given input. It should return a ValidationError
// if the input is not valid.
type ValidateFunc func(string) error

View File

@@ -0,0 +1,138 @@
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
flush 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
}
// 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 fail 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 {
for i := 0; i < s.height; i++ {
_, err := s.buf.Write(moveUp)
if err != nil {
return 0, err
}
_, err = s.buf.Write(clearLine)
if err != nil {
return 0, err
}
}
s.cursor = 0
s.height = 0
s.reset = false
}
switch {
case s.cursor == s.height:
n, err := s.buf.Write(clearLine)
if err != nil {
return n, err
}
line := append(b, []byte("\n")...)
n, err = s.buf.Write(line)
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.
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))
}

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

@@ -0,0 +1,500 @@
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 returned from SelectWithAdd when add is selected.
const SelectedAdd = -1
// Select represents a list for selecting a single item
type Select struct {
// Label is the value displayed on the command line prompt. It can be any
// value one would pass to a text/template Execute(), including just a string.
Label interface{}
// Items are the items to use in the list. It can be any slice type one would
// pass to a text/template execute, including a string slice.
Items interface{}
// Size is the number of items that should appear on the select before
// scrolling. If it is 0, defaults to 5.
Size int
// IsVimMode sets whether readline is using Vim mode.
IsVimMode bool
// Templates can be used to customize the select output. If nil is passed, the
// default templates are used.
Templates *SelectTemplates
// Keys can be used to change movement and search keys.
Keys *SelectKeys
// Searcher can be implemented to teach the select how to search for items.
Searcher list.Searcher
label string
list *list.List
}
// SelectKeys defines which keys can be used for movement and search.
type SelectKeys struct {
Next Key // Next defaults to down arrow key
Prev Key // Prev defaults to up arrow key
PageUp Key // PageUp defaults to left arrow key
PageDown Key // PageDown defaults to right arrow key
Search Key // Search defaults to '/' key
}
// Key defines a keyboard code and a display representation for the help
// Check https://github.com/chzyer/readline for a list of codes
type Key struct {
Code rune
Display string
}
// SelectTemplates allow a select prompt to be customized following stdlib
// text/template syntax. If any field is blank a default template is used.
type SelectTemplates struct {
// Active is a text/template for the label.
Label string
// Active is a text/template for when an item is current active.
Active string
// Inactive is a text/template for when an item is not current active.
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.
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 helpers for the templates. If nil, the default helpers
// are used.
FuncMap template.FuncMap
label *template.Template
active *template.Template
inactive *template.Template
selected *template.Template
details *template.Template
help *template.Template
}
// Run runs the Select list. It returns the index of the selected element,
// and its value.
func (s *Select) Run() (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(0, ' ')
}
func (s *Select) innerRun(starting int, top rune) (int, string, error) {
stdin := readline.NewCancelableStdin(os.Stdin)
c := &readline.Config{}
err := c.Init()
if err != nil {
return 0, "", err
}
c.Stdin = 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)
var searchInput []rune
canSearch := s.Searcher != nil
searchMode := false
c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {
switch {
case key == readline.CharEnter:
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
searchInput = nil
s.list.CancelSearch()
} else {
searchMode = true
}
case key == readline.CharBackspace:
if !canSearch || !searchMode {
break
}
if len(searchInput) > 1 {
searchInput = searchInput[:len(searchInput)-1]
s.list.Search(string(searchInput))
} else {
searchInput = nil
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 {
searchInput = append(searchInput, line...)
s.list.Search(string(searchInput))
}
}
if searchMode {
header := fmt.Sprintf("Search: %s%s", string(searchInput), cursor)
sb.WriteString(header)
} else {
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]
output := render(s.Templates.selected, item)
sb.Reset()
sb.Write(output)
sb.Flush()
rl.Write([]byte(showCursor))
rl.Close()
return s.list.Index(), fmt.Sprintf("%v", item), err
}
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, or selecting
// a newly created item.
type SelectWithAdd struct {
Label string // Label is the value displayed on the command line prompt.
Items []string // Items are the items to use in the list.
AddLabel string // The label used in the item list for creating a new item.
// Validate is optional. If set, this function is used to validate the input
// after each character entry.
Validate ValidateFunc
IsVimMode bool // Whether readline is using Vim mode.
}
// Run runs the Select list. It returns the index of the selected element,
// and its value. If a new element is created, -1 is returned as the index.
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,
Size: 5,
list: list,
}
s.setKeys()
err = s.prepareTemplates()
if err != nil {
return 0, "", err
}
selected, value, err := s.innerRun(1, '+')
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,
}
value, err := p.Run()
return SelectedAdd, value, err
}
func (s *Select) setKeys() {
if s.Keys != nil {
return
}
s.Keys = &SelectKeys{
Prev: Key{Code: readline.CharPrev, Display: "↑"},
Next: Key{Code: readline.CharNext, Display: "↓"},
PageUp: Key{Code: readline.CharBackward, Display: "←"},
PageDown: Key{Code: readline.CharForward, Display: "→"},
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()
}

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

@@ -0,0 +1,12 @@
// +build !windows
package promptui
// Icons used for displaying prompts or status
var (
IconInitial = Styler(FGBlue)("?")
IconGood = Styler(FGGreen)("✔")
IconWarn = Styler(FGYellow)("⚠")
IconBad = Styler(FGRed)("✗")
IconSelect = Styler(FGBold)("▸")
)

View File

@@ -0,0 +1,10 @@
package promptui
// Icons used for displaying prompts or status
var (
IconInitial = Styler(FGBlue)("?")
IconGood = Styler(FGGreen)("v")
IconWarn = Styler(FGYellow)("!")
IconBad = Styler(FGRed)("x")
IconSelect = Styler(FGBold)(">")
)