package server import ( "strings" "sort" "log" ) 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), path ...string) { node := cmds for _, name := range path { v := node.m[name] if v == nil { v = newNode() node.m[name] = v } node = v } if node.c != nil { s := strings.Join(path, " ") log.Panicf("handler already registered at '%s'", s) } node.c = &cmd{ name: strings.Join(path, " "), 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) } }