Implement tab completion
The liner library used in internal/reader has a
system for tab completion, so we might as well
use it.
Change-Id: Ic85eeb01263b96e0aaf2a751f2658337ff67a5f6
diff --git a/cmd/sb/internal/reader/reader.go b/cmd/sb/internal/reader/reader.go
index d4a0db1..9c481b2 100644
--- a/cmd/sb/internal/reader/reader.go
+++ b/cmd/sb/internal/reader/reader.go
@@ -13,6 +13,8 @@
"text/scanner"
"github.com/peterh/liner"
+ "v.io/x/lib/cmdline"
+ "v.io/x/ref/cmd/sb/commands"
)
type T struct {
@@ -121,6 +123,8 @@
line: liner.NewLiner(),
}
i.line.SetCtrlCAborts(true)
+ i.line.SetCompleter(complete)
+ i.line.SetTabCompletionStyle(liner.TabPrints)
return newT(i)
}
@@ -139,3 +143,43 @@
func (i *interactive) AppendHistory(query string) {
i.line.AppendHistory(query)
}
+
+func complete(line string) []string {
+ // get command list to tab-complete on
+ tokens := strings.Split(line, " ")
+ cmds := commands.Commands
+ for _, token := range tokens[:len(tokens)-1] {
+ nextCommand := find(token, cmds)
+ if nextCommand == nil {
+ return nil
+ } else {
+ cmds = nextCommand.Children
+ }
+ }
+
+ lineMinusLastToken := strings.Join(tokens[:len(tokens)-1], " ")
+ if len(lineMinusLastToken) > 0 {
+ lineMinusLastToken += " "
+ }
+
+ // tab complete on command list
+ lastToken := tokens[len(tokens)-1]
+ var ret []string
+ for _, cmd := range cmds {
+ name := cmd.Name
+ if strings.HasPrefix(name, lastToken) {
+ ret = append(ret, lineMinusLastToken+name)
+ }
+ }
+
+ return ret
+}
+
+func find(name string, cmds []*cmdline.Command) *cmdline.Command {
+ for _, cmd := range cmds {
+ if cmd.Name == name {
+ return cmd
+ }
+ }
+ return nil
+}