summaryrefslogtreecommitdiff
path: root/pkg/server/cmds.go
blob: 6eabbdee700ff95fa6117e4cdc0ee8b48777f548 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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), where string) {
	path := strings.Split(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)
	}
}