package server import ( "log" "sort" "strings" ) type cmd struct { name string f func(r *request) } type node struct { c *cmd m map[string]*node } var cmds = newNode() func init() { newCmd(help, "help") } func newNode() *node { return &node{m: map[string]*node{}} } func newCmd(f func(r *request), where string) { path := strings.Fields(where) node := cmds for _, name := range path { if name == "" { panic("invalid command path") } v := node.m[name] if v == nil { v = newNode() node.m[name] = v } node = v } if node.c != nil { log.Panicf("handler already registered at '%s'", where) } node.c = &cmd{ name: where, f: f, } } func getCmd(path []string) (*cmd, []string) { node := cmds for n, name := range path { node = node.m[name] if node == nil { return nil, nil } if node.c != nil { return node.c, path[n+1:] } } return nil, nil } func help(r *request) { var ss []string var walker func([]string, *node) walker = func(path []string, node *node) { if node.c != nil { ss = append(ss, strings.Join(path, " ")) return } n := len(path) path = append(path, "") for k, v := range node.m { path[n] = k walker(path, v) } } root := cmds for _, s := range r.args { root = root.m[s] if root == nil { break } } if root == nil { r.Print("nothing to help") return } if root.c != nil { r.Print("usage: ", root.c.name, " [...]") return } walker(nil, root) sort.Strings(ss) for _, s := range ss { r.Println(s) } }