diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2017-05-09 20:52:58 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2017-05-09 20:52:58 +0200 |
| commit | a4dfbab3b06360245f6b2fce4b56d6caf2729f8f (patch) | |
| tree | 2ade7c6c25675b36aacaf45d2282e0ec5c158c34 /pkg/cli | |
| parent | 0e56e63c833229ca02f2c62d4ee50cf371b6ac9a (diff) | |
| download | gofu-a4dfbab3b06360245f6b2fce4b56d6caf2729f8f.tar.gz | |
implement TUI instance for when stdin is not a tty
Diffstat (limited to 'pkg/cli')
| -rw-r--r-- | pkg/cli/interface.go | 18 | ||||
| -rw-r--r-- | pkg/cli/query.go | 62 |
2 files changed, 75 insertions, 5 deletions
diff --git a/pkg/cli/interface.go b/pkg/cli/interface.go index 3192d32..c188c77 100644 --- a/pkg/cli/interface.go +++ b/pkg/cli/interface.go @@ -26,18 +26,26 @@ import ( "os" "sort" "strings" + + "golang.org/x/crypto/ssh/terminal" ) //NewInterface creates an Interface instance. -func NewInterface(stdin, stdout, stderr *os.File) (*Interface, error) { - //TODO: check terminal.IsTerminal(int(stdin.Fd())) and choose the TUI instance accordingly - return &Interface{ +func NewInterface(stdin, stdout, stderr *os.File) *Interface { + i := &Interface{ stdin: stdin, stdout: stdout, stderr: stderr, stdinBuf: bufio.NewReader(stdin), - tui: &terminalTUI{}, - }, nil + } + + if terminal.IsTerminal(int(stdin.Fd())) { + i.tui = &terminalTUI{i} + } else { + i.tui = &pipeTUI{i} + } + + return i } //Interface wraps access to the CLI, including input, output and subprocesses. diff --git a/pkg/cli/query.go b/pkg/cli/query.go index 2a6a5bc..ed9e913 100644 --- a/pkg/cli/query.go +++ b/pkg/cli/query.go @@ -19,9 +19,11 @@ package cli import ( + "errors" "fmt" "io" "regexp" + "strconv" "strings" terminal "golang.org/x/crypto/ssh/terminal" @@ -35,6 +37,9 @@ func (e errInterrupted) Error() string { return "Interrupted!" } +//////////////////////////////////////////////////////////////////////////////// +// TUI implementation for when stdin is a terminal + type terminalTUI struct { i *Interface } @@ -218,3 +223,60 @@ func (b *buffer) getNextInput() []byte { return b.getNextInput() //restart } + +//////////////////////////////////////////////////////////////////////////////// +// TUI implementation for when stdin is a pipe + +type pipeTUI struct { + i *Interface +} + +func (t *pipeTUI) ReadLine(prompt string) (string, error) { + str, err := t.i.stdinBuf.ReadString('\n') + str = strings.TrimSpace(str) + if err == nil { + fmt.Fprintf(t.i.stderr, "%s %s\n", strings.TrimSpace(prompt), str) + } + return str, err +} + +func (t *pipeTUI) Confirm(question string) (bool, error) { + question = strings.TrimSpace(question) + str, err := t.ReadLine(question) + if err != nil { + return false, err + } + //recognize /[01tTfF]|true|false/ + ok, err := strconv.ParseBool(str) + if err != nil { + //recognize /[yY]|yes|no/ + ok = strings.HasPrefix(question, "y") || strings.HasPrefix(question, "Y") + } + fmt.Fprintf(t.i.stderr, "%s -> %v (%s)\n", question, ok, str) + return ok, nil +} + +//Query for the pipe TUI is limited to exact matches of the choice text, or +//matching by choice shortcut. +func (t *pipeTUI) Query(prompt string, choices ...Choice) (string, error) { + str, err := t.i.stdinBuf.ReadString('\n') + if err != nil { + return str, err + } + //prefer exact match on choice.Text + for _, choice := range choices { + if choice.Text == str { + fmt.Fprintf(t.i.stderr, "%s -> %s\n", prompt, choice.Text) + return choice.Return, nil + } + } + //allow match on choice.Shortcut + for _, choice := range choices { + if string(choice.Shortcut) == str { + fmt.Fprintf(t.i.stderr, "%s -> %s\n", prompt, choice.Text) + return choice.Return, nil + } + } + fmt.Fprintf(t.i.stderr, "%s -> [%s]\n", prompt, str) + return "", errors.New("cannot match input with available choices") +} |
