Add prompt.Input and prompt.Choose
This commit is contained in:
parent
2921d1d259
commit
0194c52454
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/c-bata/go-prompt"
|
"github.com/c-bata/go-prompt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func executor(in string) {
|
func executor(in string) {
|
||||||
@ -11,13 +12,18 @@ func executor(in string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func completer(in string) []prompt.Suggest {
|
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{
|
s := []prompt.Suggest{
|
||||||
{Text: "users", Description: "user table"},
|
{Text: "users", Description: "user table"},
|
||||||
{Text: "sites", Description: "sites table"},
|
{Text: "sites", Description: "sites table"},
|
||||||
{Text: "articles", Description: "articles table"},
|
{Text: "articles", Description: "articles table"},
|
||||||
{Text: "comments", Description: "comments table"},
|
{Text: "comments", Description: "comments table"},
|
||||||
}
|
}
|
||||||
return prompt.FilterHasPrefix(s, in, true)
|
return prompt.FilterHasPrefix(s, last, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
15
_example/input/main.go
Normal file
15
_example/input/main.go
Normal 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)
|
||||||
|
}
|
@ -2,7 +2,7 @@ package prompt
|
|||||||
|
|
||||||
import "strings"
|
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 {
|
func FilterHasPrefix(completions []Suggest, sub string, ignoreCase bool) []Suggest {
|
||||||
if sub == "" {
|
if sub == "" {
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
var scenarioTable = []struct {
|
var scenarioTable = []struct {
|
||||||
scenario string
|
scenario string
|
||||||
filter CompletionFilter
|
filter Filter
|
||||||
list []Suggest
|
list []Suggest
|
||||||
substr string
|
substr string
|
||||||
ignoreCase bool
|
ignoreCase bool
|
||||||
|
40
input.go
Normal file
40
input.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
58
prompt.go
58
prompt.go
@ -34,21 +34,11 @@ func (p *Prompt) Run() {
|
|||||||
p.setUp()
|
p.setUp()
|
||||||
defer p.tearDown()
|
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)
|
p.renderer.Render(p.buf, p.completion)
|
||||||
|
|
||||||
bufCh := make(chan []byte, 128)
|
bufCh := make(chan []byte, 128)
|
||||||
stopReadBufCh := make(chan struct{})
|
stopReadBufCh := make(chan struct{})
|
||||||
go p.readBuffer(bufCh, stopReadBufCh)
|
go readBuffer(bufCh, stopReadBufCh)
|
||||||
|
|
||||||
exitCh := make(chan int)
|
exitCh := make(chan int)
|
||||||
winSizeCh := make(chan *WinSize)
|
winSizeCh := make(chan *WinSize)
|
||||||
@ -74,7 +64,7 @@ func (p *Prompt) Run() {
|
|||||||
|
|
||||||
// Set raw mode
|
// Set raw mode
|
||||||
p.in.Setup()
|
p.in.Setup()
|
||||||
go p.readBuffer(bufCh, stopReadBufCh)
|
go readBuffer(bufCh, stopReadBufCh)
|
||||||
} else {
|
} else {
|
||||||
p.completion.Update(p.buf.Text())
|
p.completion.Update(p.buf.Text())
|
||||||
p.renderer.Render(p.buf, p.completion)
|
p.renderer.Render(p.buf, p.completion)
|
||||||
@ -170,7 +160,47 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) {
|
|||||||
return
|
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() {
|
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.in.Setup()
|
||||||
p.renderer.Setup()
|
p.renderer.Setup()
|
||||||
p.renderer.UpdateWinSize(p.in.GetWinSize())
|
p.renderer.UpdateWinSize(p.in.GetWinSize())
|
||||||
@ -181,7 +211,7 @@ func (p *Prompt) tearDown() {
|
|||||||
p.renderer.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)
|
buf := make([]byte, 1024)
|
||||||
|
|
||||||
log.Printf("[INFO] readBuffer start")
|
log.Printf("[INFO] readBuffer start")
|
||||||
@ -189,7 +219,7 @@ func (p *Prompt) readBuffer(bufCh chan []byte, stopCh chan struct{}) {
|
|||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
select {
|
select {
|
||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
log.Print("[INFO] stop p.readBuffer")
|
log.Print("[INFO] stop readBuffer")
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
if n, err := syscall.Read(syscall.Stdin, buf); err == nil {
|
if n, err := syscall.Read(syscall.Stdin, buf); err == nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user