Skip to content

Commit 608d5e2

Browse files
Better TAB complection.
Probably still not perfect, but definitely better than the previous one.
1 parent 525711f commit 608d5e2

File tree

3 files changed

+104
-22
lines changed

3 files changed

+104
-22
lines changed

_testdata/longone/supervise

Whitespace-only changes.

svctl.go

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -164,24 +164,7 @@ func newCtl() *ctl {
164164
}
165165

166166
c.line.SetTabCompletionStyle(liner.TabPrints)
167-
c.line.SetCompleter(func(l string) []string {
168-
s := strings.Split(l, " ")
169-
if len(s) <= 1 {
170-
if len(s) == 0 {
171-
return cmdMatchName("")
172-
}
173-
return cmdMatchName(s[0])
174-
}
175-
services := c.Services(fmt.Sprintf("%s*", s[len(s)-1]), true)
176-
compl := make([]string, len(services))
177-
for i, service := range services {
178-
compl[i] = fmt.Sprintf(
179-
"%s %s ",
180-
strings.Join(s[:len(s)-1], " "), c.serviceName(service),
181-
)
182-
}
183-
return compl
184-
})
167+
c.line.SetWordCompleter(c.completer)
185168

186169
return c
187170
}
@@ -199,6 +182,31 @@ func (c *ctl) Close() {
199182
c.line.Close()
200183
}
201184

185+
func (c *ctl) completer(line string, pos int) (h string, compl []string, t string) {
186+
s := strings.Split(line, " ")
187+
if len(s) == 1 {
188+
return "", cmdMatchName(line), ""
189+
}
190+
i := strings.Count(line[:pos], " ")
191+
192+
if s[0] == "?" || s[0] == "help" {
193+
compl = cmdMatchName(s[i])
194+
} else {
195+
services := c.Services(fmt.Sprintf("%s*", s[i]), true)
196+
197+
compl = make([]string, len(services))
198+
for i, service := range services {
199+
compl[i] = fmt.Sprintf("%s ", c.serviceName(service))
200+
}
201+
}
202+
h = fmt.Sprintf("%s ", strings.Join(s[:i], " "))
203+
t = strings.Join(s[i+1:], " ")
204+
if t != "" {
205+
t = fmt.Sprintf(" %s", t)
206+
}
207+
return
208+
}
209+
202210
// serviceName Returns name of the service, i.e. directory chain relative to current base.
203211
func (c *ctl) serviceName(dir string) string {
204212
if name, err := filepath.Rel(c.basedir, dir); err == nil {

svctl_test.go

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,26 @@ func fatal(err error) {
4242
}
4343
}
4444

45+
func equal(s1, s2 []string) bool {
46+
if len(s1) != len(s2) {
47+
return false
48+
}
49+
for i, s1e := range s1 {
50+
if s1e != s2[i] {
51+
return false
52+
}
53+
}
54+
return true
55+
}
56+
57+
func createRunitDir() string {
58+
dir, err := ioutil.TempDir("", "svctl_tests")
59+
fatal(err)
60+
cmd := exec.Command("cp", "-r", "_testdata/", dir)
61+
fatal(cmd.Run())
62+
return dir
63+
}
64+
4565
type runitRunner struct {
4666
basedir string
4767
runsvdir *exec.Cmd
@@ -52,10 +72,7 @@ type runitRunner struct {
5272
}
5373

5474
func newRunitRunner() *runitRunner {
55-
dir, err := ioutil.TempDir("", "svctl_tests")
56-
fatal(err)
57-
cmd := exec.Command("cp", "-r", "_testdata/", dir)
58-
fatal(cmd.Run())
75+
dir := createRunitDir()
5976

6077
r := &runitRunner{
6178
basedir: path.Join(dir, "_testdata"),
@@ -236,3 +253,60 @@ func TestCmd(t *testing.T) {
236253
svctl.line.Close()
237254
runit.Close()
238255
}
256+
257+
func TestCompleter(t *testing.T) {
258+
allCmds := []string{
259+
"up ", "start ", "down ", "stop ", "r ", "restart ", "once ",
260+
"pause ", "cont ", "hup ", "reload ", "alarm ", "interrupt ",
261+
"quit ", "1 ", "2 ", "term ", "kill ", "status ", "help ", "exit ",
262+
}
263+
defs := []struct {
264+
line string
265+
pos int
266+
267+
head string
268+
completions []string
269+
tail string
270+
}{
271+
{"", 0, "", allCmds, ""},
272+
{"u", 1, "", []string{"up "}, ""},
273+
{"u", 0, "", []string{"up "}, ""},
274+
{"sto", 2, "", []string{"stop "}, ""},
275+
{"stop ", 5, "stop ", []string{"longone ", "o ", "r0 ", "r1 ", "w "}, ""},
276+
{"up r", 4, "up ", []string{"r0 ", "r1 "}, ""},
277+
{"up o r", 6, "up o ", []string{"r0 ", "r1 "}, ""},
278+
{"up lo r", 4, "up ", []string{"longone "}, " r"},
279+
{"? ", 2, "? ", allCmds, ""},
280+
{"help ", 5, "help ", allCmds, ""},
281+
{"? st", 4, "? ", []string{"start ", "stop ", "status "}, ""},
282+
{"? h term", 3, "? ", []string{"hup ", "help "}, " term"},
283+
{"? st term", 3, "? ", []string{"start ", "stop ", "status "}, " term"},
284+
}
285+
286+
dir := createRunitDir()
287+
svctl := ctl{basedir: path.Join(dir, "_testdata")}
288+
289+
for _, def := range defs {
290+
head, completions, tail := svctl.completer(def.line, def.pos)
291+
if head != def.head {
292+
t.Errorf(
293+
"ERROR IN HEAD: `%s` != `%s` for `%s:%d`",
294+
head, def.head, def.line, def.pos,
295+
)
296+
}
297+
if !equal(completions, def.completions) {
298+
t.Errorf(
299+
"ERROR IN COMPLETIONS: `%v` != `%v` for `%s:%d`",
300+
completions, def.completions, def.line, def.pos,
301+
)
302+
}
303+
if tail != def.tail {
304+
t.Errorf(
305+
"ERROR IN TAIL: `%s` != `%s` for `%s:%d`",
306+
tail, def.tail, def.line, def.pos,
307+
)
308+
}
309+
}
310+
311+
os.RemoveAll(dir)
312+
}

0 commit comments

Comments
 (0)