Add prompt.Input and prompt.Choose

This commit is contained in:
c-bata 2017-08-10 01:03:43 +09:00
parent 2921d1d259
commit 0194c52454
6 changed files with 108 additions and 17 deletions

View File

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/c-bata/go-prompt"
"strings"
)
func executor(in string) {
@ -11,13 +12,18 @@ func executor(in string) {
}
func completer(in string) []prompt.Suggest {
args := strings.Split(in, " ")
last := args[0]
if len(args) > 0 {
last = args[len(args) - 1]
}
s := []prompt.Suggest{
{Text: "users", Description: "user table"},
{Text: "sites", Description: "sites table"},
{Text: "articles", Description: "articles table"},
{Text: "comments", Description: "comments table"},
}
return prompt.FilterHasPrefix(s, in, true)
return prompt.FilterHasPrefix(s, last, true)
}
func main() {

15
_example/input/main.go Normal file
View File

@ -0,0 +1,15 @@
package main
import (
"fmt"
"github.com/c-bata/go-prompt"
)
func main() {
fruits := []string{"Apple", "Banana", "Bilberry", "Coconuts"}
fmt.Println("What fruits do you like?")
f := prompt.Choose("> ", fruits)
fmt.Println("You like " + f)
}

View File

@ -2,7 +2,7 @@ package prompt
import "strings"
type CompletionFilter func([]Suggest, string, bool) []Suggest
type Filter func([]Suggest, string, bool) []Suggest
func FilterHasPrefix(completions []Suggest, sub string, ignoreCase bool) []Suggest {
if sub == "" {

View File

@ -8,7 +8,7 @@ import (
func TestFilter(t *testing.T) {
var scenarioTable = []struct {
scenario string
filter CompletionFilter
filter Filter
list []Suggest
substr string
ignoreCase bool

40
input.go Normal file
View File

@ -0,0 +1,40 @@
package prompt
func dummyExecutor(in string) { return }
func Input(prefix string, completer Completer, opts ...option) string {
pt := New(dummyExecutor, completer)
pt.renderer.prefixTextColor = DefaultColor
pt.renderer.prefix = prefix
for _, opt := range opts {
if err := opt(pt); err != nil {
panic(err)
}
}
return pt.Input()
}
func Choose(prefix string, choices []string, opts ...option) string {
completer := newChoiceCompleter(choices, FilterHasPrefix)
pt := New(dummyExecutor, completer)
pt.renderer.prefixTextColor = DefaultColor
pt.renderer.prefix = prefix
for _, opt := range opts {
if err := opt(pt); err != nil {
panic(err)
}
}
return pt.Input()
}
func newChoiceCompleter(choices []string, filter Filter) Completer {
s := make([]Suggest, len(choices))
for i := range choices {
s[i] = Suggest{Text: choices[i]}
}
return func(x string) []Suggest {
return filter(s, x, true)
}
}

View File

@ -34,21 +34,11 @@ func (p *Prompt) Run() {
p.setUp()
defer p.tearDown()
if os.Getenv(envEnableLog) != "true" {
log.SetOutput(ioutil.Discard)
} else if f, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil {
log.SetOutput(ioutil.Discard)
} else {
defer f.Close()
log.SetOutput(f)
log.Println("[INFO] Logging is enabled.")
}
p.renderer.Render(p.buf, p.completion)
bufCh := make(chan []byte, 128)
stopReadBufCh := make(chan struct{})
go p.readBuffer(bufCh, stopReadBufCh)
go readBuffer(bufCh, stopReadBufCh)
exitCh := make(chan int)
winSizeCh := make(chan *WinSize)
@ -74,7 +64,7 @@ func (p *Prompt) Run() {
// Set raw mode
p.in.Setup()
go p.readBuffer(bufCh, stopReadBufCh)
go readBuffer(bufCh, stopReadBufCh)
} else {
p.completion.Update(p.buf.Text())
p.renderer.Render(p.buf, p.completion)
@ -170,7 +160,47 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) {
return
}
func (p *Prompt) Input() string {
p.setUp()
defer p.tearDown()
p.renderer.Render(p.buf, p.completion)
bufCh := make(chan []byte, 128)
stopReadBufCh := make(chan struct{})
go readBuffer(bufCh, stopReadBufCh)
for {
select {
case b := <-bufCh:
if shouldExit, e := p.feed(b); shouldExit {
p.renderer.BreakLine(p.buf)
return ""
} else if e != nil {
// Stop goroutine to run readBuffer function
stopReadBufCh <- struct{}{}
return e.input
} else {
p.completion.Update(p.buf.Text())
p.renderer.Render(p.buf, p.completion)
}
default:
time.Sleep(10 * time.Millisecond)
}
}
}
func (p *Prompt) setUp() {
// Logging
if os.Getenv(envEnableLog) != "true" {
log.SetOutput(ioutil.Discard)
} else if f, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil {
log.SetOutput(ioutil.Discard)
} else {
defer f.Close()
log.SetOutput(f)
log.Println("[INFO] Logging is enabled.")
}
p.in.Setup()
p.renderer.Setup()
p.renderer.UpdateWinSize(p.in.GetWinSize())
@ -181,7 +211,7 @@ func (p *Prompt) tearDown() {
p.renderer.TearDown()
}
func (p *Prompt) readBuffer(bufCh chan []byte, stopCh chan struct{}) {
func readBuffer(bufCh chan []byte, stopCh chan struct{}) {
buf := make([]byte, 1024)
log.Printf("[INFO] readBuffer start")
@ -189,7 +219,7 @@ func (p *Prompt) readBuffer(bufCh chan []byte, stopCh chan struct{}) {
time.Sleep(10 * time.Millisecond)
select {
case <-stopCh:
log.Print("[INFO] stop p.readBuffer")
log.Print("[INFO] stop readBuffer")
return
default:
if n, err := syscall.Read(syscall.Stdin, buf); err == nil {