1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
package readline
import (
"bytes"
"strings"
"github.com/ergochat/readline/internal/runes"
)
// PrefixCompleter implements AutoCompleter via a recursive tree.
type PrefixCompleter struct {
// Name is the name of a command, subcommand, or argument eligible for completion.
Name string
// Callback is optional; if defined, it takes the current line and returns
// a list of possible completions associated with the current node (i.e.
// in place of Name).
Callback func(string) []string
// Children is a list of possible completions that can follow the current node.
Children []*PrefixCompleter
nameRunes []rune // just a cache
}
var _ AutoCompleter = (*PrefixCompleter)(nil)
func (p *PrefixCompleter) Tree(prefix string) string {
buf := bytes.NewBuffer(nil)
p.print(prefix, 0, buf)
return buf.String()
}
func prefixPrint(p *PrefixCompleter, prefix string, level int, buf *bytes.Buffer) {
if strings.TrimSpace(p.Name) != "" {
buf.WriteString(prefix)
if level > 0 {
buf.WriteString("├")
buf.WriteString(strings.Repeat("─", (level*4)-2))
buf.WriteString(" ")
}
buf.WriteString(p.Name)
buf.WriteByte('\n')
level++
}
for _, ch := range p.Children {
ch.print(prefix, level, buf)
}
}
func (p *PrefixCompleter) print(prefix string, level int, buf *bytes.Buffer) {
prefixPrint(p, prefix, level, buf)
}
func (p *PrefixCompleter) getName() []rune {
if p.nameRunes == nil {
if p.Name != "" {
p.nameRunes = []rune(p.Name)
} else {
p.nameRunes = make([]rune, 0)
}
}
return p.nameRunes
}
func (p *PrefixCompleter) getDynamicNames(line []rune) [][]rune {
var result [][]rune
for _, name := range p.Callback(string(line)) {
nameRunes := []rune(name)
nameRunes = append(nameRunes, ' ')
result = append(result, nameRunes)
}
return result
}
func (p *PrefixCompleter) SetChildren(children []*PrefixCompleter) {
p.Children = children
}
func NewPrefixCompleter(pc ...*PrefixCompleter) *PrefixCompleter {
return PcItem("", pc...)
}
func PcItem(name string, pc ...*PrefixCompleter) *PrefixCompleter {
name += " "
result := &PrefixCompleter{
Name: name,
Children: pc,
}
result.getName() // initialize nameRunes member
return result
}
func PcItemDynamic(callback func(string) []string, pc ...*PrefixCompleter) *PrefixCompleter {
return &PrefixCompleter{
Callback: callback,
Children: pc,
}
}
func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
return doInternal(p, line, pos, line)
}
func doInternal(p *PrefixCompleter, line []rune, pos int, origLine []rune) (newLine [][]rune, offset int) {
line = runes.TrimSpaceLeft(line[:pos])
goNext := false
var lineCompleter *PrefixCompleter
for _, child := range p.Children {
var childNames [][]rune
if child.Callback != nil {
childNames = child.getDynamicNames(origLine)
} else {
childNames = make([][]rune, 1)
childNames[0] = child.getName()
}
for _, childName := range childNames {
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 doInternal(lineCompleter, tmpLine, len(tmpLine), origLine)
}
if goNext {
return doInternal(lineCompleter, nil, 0, origLine)
}
return
}
|