mirror of https://github.com/chzyer/readline.git
Change implementation drastically.
Signed-off-by: Dan Cripe <dan@quattronetworks.com>
This commit is contained in:
parent
cd2d269a73
commit
f89cf57370
59
complete.go
59
complete.go
|
@ -9,13 +9,56 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type AutoCompleter interface {
|
type AutoCompleter interface {
|
||||||
// Readline will pass the whole line and current offset to it
|
GetName() []rune
|
||||||
// Completer need to pass all the candidates, and how long they shared the same characters in line
|
GetChildren() []AutoCompleter
|
||||||
// Example:
|
}
|
||||||
// Do("g", 1) => ["o", "it", "it-shell", "rep"], 1
|
|
||||||
// Do("gi", 2) => ["t", "t-shell"], 1
|
func Do(ac AutoCompleter, line []rune, pos int) (newLine [][]rune, offset int) {
|
||||||
// Do("git", 3) => ["", "-shell"], 0
|
line = line[:pos]
|
||||||
Do(line []rune, pos int) (newLine [][]rune, length int)
|
goNext := false
|
||||||
|
var lineCompleter AutoCompleter
|
||||||
|
|
||||||
|
for _, child := range ac.GetChildren() {
|
||||||
|
childName := child.GetName()
|
||||||
|
if len(line) >= len(childName) {
|
||||||
|
if runes.HasPrefix(line, childName) {
|
||||||
|
if len(line) == len(childName) {
|
||||||
|
newLine = append(newLine, []rune{' '})
|
||||||
|
} else {
|
||||||
|
newLine = append(newLine, childName)
|
||||||
|
}
|
||||||
|
offset = len(childName)
|
||||||
|
lineCompleter = child
|
||||||
|
goNext = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if runes.HasPrefix(childName, line) {
|
||||||
|
newLine = append(newLine, childName[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[i] == ' ' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpLine = append(tmpLine, line[i:]...)
|
||||||
|
return Do(lineCompleter, tmpLine, len(tmpLine))
|
||||||
|
}
|
||||||
|
|
||||||
|
if goNext {
|
||||||
|
return Do(lineCompleter, nil, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type opCompleter struct {
|
type opCompleter struct {
|
||||||
|
@ -75,7 +118,7 @@ func (o *opCompleter) OnComplete() {
|
||||||
|
|
||||||
o.ExitCompleteSelectMode()
|
o.ExitCompleteSelectMode()
|
||||||
o.candidateSource = rs
|
o.candidateSource = rs
|
||||||
newLines, offset := o.ac.Do(rs, buf.idx)
|
newLines, offset := Do(o.ac, rs, buf.idx)
|
||||||
if len(newLines) == 0 {
|
if len(newLines) == 0 {
|
||||||
o.ExitCompleteMode(false)
|
o.ExitCompleteMode(false)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,128 +1,27 @@
|
||||||
package readline
|
package readline
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/chzyer/readline/runes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DynChildrenFunc func() [][]rune
|
|
||||||
|
|
||||||
type PrefixCompleter struct {
|
type PrefixCompleter struct {
|
||||||
Name []rune
|
Name []rune
|
||||||
Children []*PrefixCompleter
|
Children []AutoCompleter
|
||||||
DynChildren DynChildrenFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func empty() [][]rune {
|
func (p PrefixCompleter) GetName() []rune {
|
||||||
return [][]rune{}
|
return p.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PrefixCompleter) Tree(prefix string) string {
|
func (p PrefixCompleter) GetChildren() []AutoCompleter {
|
||||||
buf := bytes.NewBuffer(nil)
|
return p.Children
|
||||||
p.Print(prefix, 0, buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PrefixCompleter) Print(prefix string, level int, buf *bytes.Buffer) {
|
func NewPrefixCompleter(pc ...AutoCompleter) AutoCompleter {
|
||||||
if strings.TrimSpace(string(p.Name)) != "" {
|
|
||||||
buf.WriteString(prefix)
|
|
||||||
if level > 0 {
|
|
||||||
buf.WriteString("├")
|
|
||||||
buf.WriteString(strings.Repeat("─", (level*4)-2))
|
|
||||||
buf.WriteString(" ")
|
|
||||||
}
|
|
||||||
buf.WriteString(string(p.Name) + "\n")
|
|
||||||
level++
|
|
||||||
}
|
|
||||||
for _, ch := range p.Children {
|
|
||||||
ch.Print(prefix, level, buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPrefixCompleter(pc ...*PrefixCompleter) *PrefixCompleter {
|
|
||||||
return PcItem("", pc...)
|
return PcItem("", pc...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PcDyn(name string, term DynChildrenFunc) *PrefixCompleter {
|
func PcItem(name string, pc ...AutoCompleter) AutoCompleter {
|
||||||
name += " "
|
name += " "
|
||||||
return &PrefixCompleter{
|
result := AutoCompleter(PrefixCompleter{
|
||||||
Name: []rune(name),
|
|
||||||
DynChildren: term,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PcItem(name string, pc ...*PrefixCompleter) *PrefixCompleter {
|
|
||||||
name += " "
|
|
||||||
return &PrefixCompleter{
|
|
||||||
Name: []rune(name),
|
Name: []rune(name),
|
||||||
Children: pc,
|
Children: pc,
|
||||||
DynChildren: empty,
|
})
|
||||||
}
|
return result
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
|
|
||||||
end := PcItem("")
|
|
||||||
line = line[:pos]
|
|
||||||
goNext := false
|
|
||||||
var lineCompleter *PrefixCompleter
|
|
||||||
for _, child := range p.Children {
|
|
||||||
if len(line) >= len(child.Name) {
|
|
||||||
if runes.HasPrefix(line, child.Name) {
|
|
||||||
if len(line) == len(child.Name) {
|
|
||||||
newLine = append(newLine, []rune{' '})
|
|
||||||
} else {
|
|
||||||
newLine = append(newLine, child.Name)
|
|
||||||
}
|
|
||||||
offset = len(child.Name)
|
|
||||||
lineCompleter = child
|
|
||||||
goNext = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if runes.HasPrefix(child.Name, line) {
|
|
||||||
newLine = append(newLine, child.Name[len(line):])
|
|
||||||
offset = len(line)
|
|
||||||
lineCompleter = child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, dynChild := range p.DynChildren() {
|
|
||||||
if len(line) >= len(dynChild) {
|
|
||||||
if runes.HasPrefix(line, dynChild) {
|
|
||||||
if len(line) == len(dynChild) {
|
|
||||||
newLine = append(newLine, []rune{' '})
|
|
||||||
} else {
|
|
||||||
newLine = append(newLine, dynChild)
|
|
||||||
}
|
|
||||||
offset = len(dynChild)
|
|
||||||
lineCompleter = end
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if runes.HasPrefix(dynChild, line) {
|
|
||||||
newLine = append(newLine, dynChild[len(line):])
|
|
||||||
offset = len(line)
|
|
||||||
lineCompleter = end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(newLine) != 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpLine := make([]rune, 0, len(line))
|
|
||||||
for i := offset; i < len(line); i++ {
|
|
||||||
if line[i] == ' ' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpLine = append(tmpLine, line[i:]...)
|
|
||||||
return lineCompleter.Do(tmpLine, len(tmpLine))
|
|
||||||
}
|
|
||||||
|
|
||||||
if goNext {
|
|
||||||
return lineCompleter.Do(nil, 0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue