Implemented basic system

This commit is contained in:
2018-04-02 15:40:10 +01:00
parent 080d61728c
commit 3a482ca3f7
11 changed files with 135 additions and 30 deletions

6
Gopkg.lock generated
View File

@@ -23,14 +23,14 @@
revision = "d14193dfc626125c831501c1c42340b4248e1f5a" revision = "d14193dfc626125c831501c1c42340b4248e1f5a"
[[projects]] [[projects]]
branch = "master"
name = "github.com/manifoldco/promptui" name = "github.com/manifoldco/promptui"
packages = [ packages = [
".", ".",
"list", "list",
"screenbuf" "screenbuf"
] ]
revision = "f6438f6153008ee1b9ba5446d5333bbe63b622b7" revision = "c0c0d3afc6a03bcb5c1df10b70b862a650db9f9b"
version = "v0.2.1"
[[projects]] [[projects]]
name = "github.com/mattn/go-colorable" name = "github.com/mattn/go-colorable"
@@ -53,6 +53,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "cf91849954be7c3fae75bdd76d47e30e3722e6f17661cadf45058fc4d1a70b3c" inputs-digest = "c5a19c2965341aa002c255d5d4897641f71d9b408c488d91893ad7c8ce3f1c42"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -27,7 +27,7 @@
[[constraint]] [[constraint]]
name = "github.com/manifoldco/promptui" name = "github.com/manifoldco/promptui"
version = "0.2.1" branch = "master"
[prune] [prune]
go-tests = true go-tests = true

20
main.go
View File

@@ -23,6 +23,7 @@ import (
"os" "os"
"os/user" "os/user"
"strings" "strings"
"os/exec"
) )
type host struct { type host struct {
@@ -94,11 +95,12 @@ func main() {
return strings.Contains(name, input) return strings.Contains(name, input)
} }
hostTemplate := "{{\"[\" | bold}}{{.Name | cyan | bold }}{{\"]\" | bold}} {{ .User |bold }} @ {{ .HostName | bold }}"
templates := &promptui.SelectTemplates{ templates := &promptui.SelectTemplates{
Label: "{{ . }}", Label: "{{ . }}",
Active: ">{{ .User | cyan }}@({{ .HostName | red }})", Active: fmt.Sprintf(">%s", hostTemplate),
Inactive: " {{ .User | cyan }}@({{ .HostName | red }})", Inactive: fmt.Sprintf(" %s", hostTemplate),
Selected: "{{ .User | cyan }}@({{ .HostName | red }})", Selected: "{{\"Connecting to\"|bold}} {{.Name|cyan|bold}}",
} }
prompt := promptui.Select{ prompt := promptui.Select{
@@ -109,12 +111,16 @@ func main() {
Searcher: searcher, Searcher: searcher,
} }
i, _, err := prompt.Run() i, _, promptErr := prompt.Run()
if err != nil { if promptErr != nil {
fmt.Printf("Prompt failed %v\n", err) fmt.Print("No option selected")
return return
} }
fmt.Printf("You choose number %d: %s\n", i+1, hosts[i].Name) cmd := exec.Command("ssh", hosts[i].Name)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
} }

View File

@@ -7,11 +7,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased ## Unreleased
### 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
## [0.2.1] - 2017-11-30 ## [0.2.1] - 2017-11-30
### Fixed ### Fixed
- `SelectWithAdd` panicking on `.Run` due to lack of keys setup - `SelectWithAdd` panicking on `.Run` due to lack of keys setup
- Backspace key on Windows
## [0.2.0] - 2017-11-16 ## [0.2.0] - 2017-11-16

View File

@@ -124,6 +124,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "160169cbbea61d01890b2670b2cc5448b5b8dd6ebbb18f57bd677c0c7d1f8a42" inputs-digest = "b683f37352cca49de9eefac440a2fbc8d84e1946237577881122b2fe86c9d950"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -12,5 +12,5 @@ required=[
branch = "master" branch = "master"
[[constraint]] [[constraint]]
name = "github.com/juju/master" name = "github.com/juju/ansiterm"
branch = "master" branch = "master"

View File

@@ -33,6 +33,18 @@ const (
FGWhite FGWhite
) )
// Background color attributes
const (
BGBlack attribute = iota + 40
BGRed
BGGreen
BGYellow
BGBlue
BGMagenta
BGCyan
BGWhite
)
// ResetCode is the character code used to reset the terminal formatting // ResetCode is the character code used to reset the terminal formatting
var ResetCode = fmt.Sprintf("%s%dm", esc, reset) var ResetCode = fmt.Sprintf("%s%dm", esc, reset)
@@ -53,6 +65,14 @@ var FuncMap = template.FuncMap{
"magenta": Styler(FGMagenta), "magenta": Styler(FGMagenta),
"cyan": Styler(FGCyan), "cyan": Styler(FGCyan),
"white": Styler(FGWhite), "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), "bold": Styler(FGBold),
"faint": Styler(FGFaint), "faint": Styler(FGFaint),
"italic": Styler(FGItalic), "italic": Styler(FGItalic),

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

@@ -0,0 +1,25 @@
// +build !windows
package promptui
import "github.com/chzyer/readline"
var (
// KeyEnter is the default key for submission/selection
KeyEnter rune = readline.CharEnter
// KeyBackspace is the default key for deleting input text
KeyBackspace rune = readline.CharBackspace
// KeyPrev is the default key to go up during selection
KeyPrev rune = readline.CharPrev
// KeyNext is the default key to go down during selection
KeyNext rune = readline.CharNext
// KeyBackward is the default key to page up during selection
KeyBackward rune = readline.CharBackward
// KeyForward is the default key to page down during selection
KeyForward rune = readline.CharForward
)

View File

@@ -0,0 +1,25 @@
package promptui
// source: https://msdn.microsoft.com/en-us/library/aa243025(v=vs.60).aspx
var (
// KeyEnter is the default key for submission/selection
KeyEnter rune = 13
// KeyBackspace is the default key for deleting input text
KeyBackspace rune = 8
// FIXME: keys below are not triggered by readline, not working on Windows
// KeyPrev is the default key to go up during selection
KeyPrev rune = 38
// KeyNext is the default key to go down during selection
KeyNext rune = 40
// KeyBackward is the default key to page up during selection
KeyBackward rune = 37
// KeyForward is the default key to page down during selection
KeyForward rune = 39
)

View File

@@ -20,6 +20,10 @@ type Prompt struct {
Default string // Default is the initial value to populate in the prompt Default string // Default is the initial value to populate in the prompt
// 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 optional. If set, this function is used to validate the input // Validate is optional. If set, this function is used to validate the input
// after each character entry. // after each character entry.
Validate ValidateFunc Validate ValidateFunc
@@ -32,11 +36,14 @@ type Prompt struct {
// default templates are used. // default templates are used.
Templates *PromptTemplates Templates *PromptTemplates
// IsConfirm sets the prompt to be a [y/N] question.
IsConfirm bool IsConfirm bool
// IsVimMode enables vi-like movements (hjkl) and editing.
IsVimMode bool IsVimMode bool
stdin io.Reader stdin io.ReadCloser
stdout io.Writer stdout io.WriteCloser
} }
// PromptTemplates allow a prompt to be customized following stdlib // PromptTemplates allow a prompt to be customized following stdlib
@@ -122,7 +129,10 @@ func (p *Prompt) Run() (string, error) {
var inputErr error var inputErr error
input := p.Default input := p.Default
eraseDefault := input != "" if p.IsConfirm {
input = ""
}
eraseDefault := input != "" && !p.AllowEdit
c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) { c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {
if line != nil { if line != nil {
@@ -131,15 +141,16 @@ func (p *Prompt) Run() (string, error) {
switch key { switch key {
case 0: // empty case 0: // empty
case readline.CharEnter: case KeyEnter:
return nil, 0, false return nil, 0, false
case readline.CharBackspace: case KeyBackspace:
if eraseDefault { if eraseDefault {
eraseDefault = false eraseDefault = false
input = "" input = ""
} }
if len(input) > 0 { if len(input) > 0 {
input = input[:len(input)-1] r := []rune(input)
input = string(r[:len(r)-1])
} }
default: default:
if eraseDefault { if eraseDefault {
@@ -220,9 +231,12 @@ func (p *Prompt) Run() (string, error) {
prompt := render(p.Templates.valid, p.Label) prompt := render(p.Templates.valid, p.Label)
prompt = append(prompt, []byte(echo)...) prompt = append(prompt, []byte(echo)...)
if p.IsConfirm && strings.ToLower(echo) != "y" { if p.IsConfirm {
prompt = render(p.Templates.invalid, p.Label) lowerDefault := strings.ToLower(p.Default)
err = ErrAbort if strings.ToLower(echo) != "y" && (lowerDefault != "y" || (lowerDefault == "y" && echo != "")) {
prompt = render(p.Templates.invalid, p.Label)
err = ErrAbort
}
} }
sb.Reset() sb.Reset()
@@ -247,7 +261,6 @@ func (p *Prompt) prepareTemplates() error {
bold := Styler(FGBold) bold := Styler(FGBold)
if p.IsConfirm { if p.IsConfirm {
p.Default = ""
if tpls.Confirm == "" { if tpls.Confirm == "" {
confirm := "y/N" confirm := "y/N"
if strings.ToLower(p.Default) == "y" { if strings.ToLower(p.Default) == "y" {

View File

@@ -43,6 +43,9 @@ type Select struct {
// Searcher can be implemented to teach the select how to search for items. // Searcher can be implemented to teach the select how to search for items.
Searcher list.Searcher Searcher list.Searcher
// Starts the prompt in search mode.
StartInSearchMode bool
label string label string
list *list.List list *list.List
@@ -150,11 +153,11 @@ func (s *Select) innerRun(starting int, top rune) (int, string, error) {
var searchInput []rune var searchInput []rune
canSearch := s.Searcher != nil canSearch := s.Searcher != nil
searchMode := false searchMode := s.StartInSearchMode
c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) { c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {
switch { switch {
case key == readline.CharEnter: case key == KeyEnter:
return nil, 0, true return nil, 0, true
case key == s.Keys.Next.Code || (key == 'j' && !searchMode): case key == s.Keys.Next.Code || (key == 'j' && !searchMode):
s.list.Next() s.list.Next()
@@ -172,7 +175,7 @@ func (s *Select) innerRun(starting int, top rune) (int, string, error) {
} else { } else {
searchMode = true searchMode = true
} }
case key == readline.CharBackspace: case key == KeyBackspace:
if !canSearch || !searchMode { if !canSearch || !searchMode {
break break
} }
@@ -442,10 +445,10 @@ func (s *Select) setKeys() {
return return
} }
s.Keys = &SelectKeys{ s.Keys = &SelectKeys{
Prev: Key{Code: readline.CharPrev, Display: "↑"}, Prev: Key{Code: KeyPrev, Display: "↑"},
Next: Key{Code: readline.CharNext, Display: "↓"}, Next: Key{Code: KeyNext, Display: "↓"},
PageUp: Key{Code: readline.CharBackward, Display: "←"}, PageUp: Key{Code: KeyBackward, Display: "←"},
PageDown: Key{Code: readline.CharForward, Display: "→"}, PageDown: Key{Code: KeyForward, Display: "→"},
Search: Key{Code: '/', Display: "/"}, Search: Key{Code: '/', Display: "/"},
} }
} }