Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/chzyer/readline/complete_helper.go
2875 views
1
package readline
2
3
import (
4
"bytes"
5
"strings"
6
)
7
8
// Caller type for dynamic completion
9
type DynamicCompleteFunc func(string) []string
10
11
type PrefixCompleterInterface interface {
12
Print(prefix string, level int, buf *bytes.Buffer)
13
Do(line []rune, pos int) (newLine [][]rune, length int)
14
GetName() []rune
15
GetChildren() []PrefixCompleterInterface
16
SetChildren(children []PrefixCompleterInterface)
17
}
18
19
type DynamicPrefixCompleterInterface interface {
20
PrefixCompleterInterface
21
IsDynamic() bool
22
GetDynamicNames(line []rune) [][]rune
23
}
24
25
type PrefixCompleter struct {
26
Name []rune
27
Dynamic bool
28
Callback DynamicCompleteFunc
29
Children []PrefixCompleterInterface
30
}
31
32
func (p *PrefixCompleter) Tree(prefix string) string {
33
buf := bytes.NewBuffer(nil)
34
p.Print(prefix, 0, buf)
35
return buf.String()
36
}
37
38
func Print(p PrefixCompleterInterface, prefix string, level int, buf *bytes.Buffer) {
39
if strings.TrimSpace(string(p.GetName())) != "" {
40
buf.WriteString(prefix)
41
if level > 0 {
42
buf.WriteString("├")
43
buf.WriteString(strings.Repeat("─", (level*4)-2))
44
buf.WriteString(" ")
45
}
46
buf.WriteString(string(p.GetName()) + "\n")
47
level++
48
}
49
for _, ch := range p.GetChildren() {
50
ch.Print(prefix, level, buf)
51
}
52
}
53
54
func (p *PrefixCompleter) Print(prefix string, level int, buf *bytes.Buffer) {
55
Print(p, prefix, level, buf)
56
}
57
58
func (p *PrefixCompleter) IsDynamic() bool {
59
return p.Dynamic
60
}
61
62
func (p *PrefixCompleter) GetName() []rune {
63
return p.Name
64
}
65
66
func (p *PrefixCompleter) GetDynamicNames(line []rune) [][]rune {
67
var names = [][]rune{}
68
for _, name := range p.Callback(string(line)) {
69
names = append(names, []rune(name+" "))
70
}
71
return names
72
}
73
74
func (p *PrefixCompleter) GetChildren() []PrefixCompleterInterface {
75
return p.Children
76
}
77
78
func (p *PrefixCompleter) SetChildren(children []PrefixCompleterInterface) {
79
p.Children = children
80
}
81
82
func NewPrefixCompleter(pc ...PrefixCompleterInterface) *PrefixCompleter {
83
return PcItem("", pc...)
84
}
85
86
func PcItem(name string, pc ...PrefixCompleterInterface) *PrefixCompleter {
87
name += " "
88
return &PrefixCompleter{
89
Name: []rune(name),
90
Dynamic: false,
91
Children: pc,
92
}
93
}
94
95
func PcItemDynamic(callback DynamicCompleteFunc, pc ...PrefixCompleterInterface) *PrefixCompleter {
96
return &PrefixCompleter{
97
Callback: callback,
98
Dynamic: true,
99
Children: pc,
100
}
101
}
102
103
func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
104
return doInternal(p, line, pos, line)
105
}
106
107
func Do(p PrefixCompleterInterface, line []rune, pos int) (newLine [][]rune, offset int) {
108
return doInternal(p, line, pos, line)
109
}
110
111
func doInternal(p PrefixCompleterInterface, line []rune, pos int, origLine []rune) (newLine [][]rune, offset int) {
112
line = runes.TrimSpaceLeft(line[:pos])
113
goNext := false
114
var lineCompleter PrefixCompleterInterface
115
for _, child := range p.GetChildren() {
116
childNames := make([][]rune, 1)
117
118
childDynamic, ok := child.(DynamicPrefixCompleterInterface)
119
if ok && childDynamic.IsDynamic() {
120
childNames = childDynamic.GetDynamicNames(origLine)
121
} else {
122
childNames[0] = child.GetName()
123
}
124
125
for _, childName := range childNames {
126
if len(line) >= len(childName) {
127
if runes.HasPrefix(line, childName) {
128
if len(line) == len(childName) {
129
newLine = append(newLine, []rune{' '})
130
} else {
131
newLine = append(newLine, childName)
132
}
133
offset = len(childName)
134
lineCompleter = child
135
goNext = true
136
}
137
} else {
138
if runes.HasPrefix(childName, line) {
139
newLine = append(newLine, childName[len(line):])
140
offset = len(line)
141
lineCompleter = child
142
}
143
}
144
}
145
}
146
147
if len(newLine) != 1 {
148
return
149
}
150
151
tmpLine := make([]rune, 0, len(line))
152
for i := offset; i < len(line); i++ {
153
if line[i] == ' ' {
154
continue
155
}
156
157
tmpLine = append(tmpLine, line[i:]...)
158
return doInternal(lineCompleter, tmpLine, len(tmpLine), origLine)
159
}
160
161
if goNext {
162
return doInternal(lineCompleter, nil, 0, origLine)
163
}
164
return
165
}
166
167