add prefix completer

This commit is contained in:
Cheney 2015-09-26 00:31:09 +08:00
parent 04f86e9c53
commit d07044cdb6
5 changed files with 98 additions and 34 deletions

View File

@ -6,6 +6,10 @@ import (
"io" "io"
) )
type AutoCompleter interface {
Do(line []rune, pos int) (newLine [][]rune, offset int)
}
type opCompleter struct { type opCompleter struct {
w io.Writer w io.Writer
op *Operation op *Operation

61
complete_helper.go Normal file
View File

@ -0,0 +1,61 @@
package readline
type PrefixCompleter struct {
Name []rune
Children []*PrefixCompleter
}
func NewPrefixCompleter(pc ...*PrefixCompleter) *PrefixCompleter {
return PcItem("", pc...)
}
func PcItem(name string, pc ...*PrefixCompleter) *PrefixCompleter {
if len(pc) != 0 {
name += " "
}
return &PrefixCompleter{
Name: []rune(name),
Children: pc,
}
}
func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
line = line[:pos]
goNext := false
var lineCompleter *PrefixCompleter
for _, child := range p.Children {
if len(line) >= len(child.Name) {
if RunesHasPrefix(line, child.Name) {
newLine = append(newLine, child.Name)
offset = len(child.Name)
lineCompleter = child
goNext = true
}
} else {
if RunesHasPrefix(child.Name, line) {
newLine = append(newLine, child.Name[len(line):])
offset = len(line)
lineCompleter = child
}
}
}
if len(newLine) != 1 {
return
}
tmpLine := make([]rune, 0, len(line))
for i := offset; i < len(line); i++ {
if line[offset] == ' ' {
continue
}
tmpLine = append(tmpLine, line[i:]...)
return lineCompleter.Do(tmpLine, len(tmpLine))
}
if goNext {
return lineCompleter.Do(nil, 0)
}
return
}

View File

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"io" "io"
"log" "log"
"strconv" "strconv"
@ -18,30 +17,25 @@ bye: quit
`[1:]) `[1:])
} }
type Completer struct { var completer = readline.NewPrefixCompleter(
} readline.PcItem("say",
readline.PcItem("hello"),
func (c *Completer) Do(line []rune, pos int) (newLine [][]rune, off int) { readline.PcItem("bye"),
list := [][]rune{ ),
[]rune("sayhello"), []rune("help"), []rune("bye"), readline.PcItem("bye"),
} readline.PcItem("help"),
for i := 0; i <= 100; i++ { readline.PcItem("go",
list = append(list, []rune(fmt.Sprintf("com%d", i))) readline.PcItem("build"),
} readline.PcItem("install"),
line = line[:pos] readline.PcItem("test"),
for _, r := range list { ),
if strings.HasPrefix(string(r), string(line)) { )
newLine = append(newLine, r[len(line):])
}
}
return newLine, len(line)
}
func main() { func main() {
l, err := readline.NewEx(&readline.Config{ l, err := readline.NewEx(&readline.Config{
Prompt: "\033[31m»\033[0m ", Prompt: "\033[31m»\033[0m ",
HistoryFile: "/tmp/readline.tmp", HistoryFile: "/tmp/readline.tmp",
AutoComplete: new(Completer), AutoComplete: completer,
}) })
if err != nil { if err != nil {
panic(err) panic(err)
@ -54,18 +48,24 @@ func main() {
if err != nil { if err != nil {
break break
} }
switch line {
case "help": switch {
case line == "help":
usage(l.Stderr()) usage(l.Stderr())
case "sayhello": case strings.HasPrefix(line, "say"):
line := strings.TrimSpace(line[3:])
if len(line) == 0 {
log.Println("say what?")
break
}
go func() { go func() {
for _ = range time.Tick(time.Second) { for _ = range time.Tick(time.Second) {
log.Println("hello") log.Println(line)
} }
}() }()
case "bye": case line == "bye":
goto exit goto exit
case "": case line == "":
default: default:
log.Println("you said:", strconv.Quote(line)) log.Println("you said:", strconv.Quote(line))
} }

View File

@ -7,14 +7,6 @@ type Instance struct {
o *Operation o *Operation
} }
type AutoCompleter interface {
Do(line []rune, pos int) (newLine [][]rune, offset int)
}
type AutoCompleteHinter interface {
Hint(line []rune, pos int) ([]rune, bool)
}
type Config struct { type Config struct {
Prompt string Prompt string
HistoryFile string HistoryFile string

View File

@ -270,3 +270,10 @@ func EqualRunes(r, r2 []rune) bool {
} }
return true return true
} }
func RunesHasPrefix(r, prefix []rune) bool {
if len(r) < len(prefix) {
return false
}
return EqualRunes(r[:len(prefix)], prefix)
}