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

View File

@ -7,14 +7,6 @@ type Instance struct {
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 {
Prompt string
HistoryFile string

View File

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