commands.go raw
1 package cmds
2
3 // Commands are a slice of Command entries
4 type Commands []Command
5
6 // Command is a specification for a command and can include any number of subcommands
7 type Command struct {
8 Name string
9 Title string
10 Description string
11 Entrypoint func(c interface{}) error
12 Commands Commands
13 Colorizer func(a ...interface{}) string
14 AppText string
15 Parent *Command
16 }
17
18 func (c Commands) PopulateParents(parent *Command) {
19 if parent != nil {
20 T.Ln("backlinking children of", parent.Name)
21 }
22 for i := range c {
23 c[i].Parent = parent
24 c[i].Commands.PopulateParents(&c[i])
25 }
26 }
27
28 // GetAllCommands returns all of the available command names
29 func (c Commands) GetAllCommands() (o []string) {
30 c.ForEach(func(cm Command) bool {
31 o = append(o, cm.Name)
32 o = append(o, cm.Commands.GetAllCommands()...)
33 return true
34 }, 0, 0,
35 )
36 return
37 }
38
39 var tabs = "\t\t\t\t\t"
40
41 // Find the Command you are looking for. Note that the namespace is assumed to be flat, no duplicated names on different
42 // levels, as it returns on the first one it finds, which goes depth-first recursive
43 func (c Commands) Find(
44 name string, hereDepth, hereDist int, skipFirst bool,
45 ) (found bool, depth, dist int, cm *Command, e error) {
46 if c == nil {
47 dist = hereDist
48 depth = hereDepth
49 return
50 }
51 if hereDist == 0 {
52 D.Ln("searching for command:", name)
53 }
54 depth = hereDepth + 1
55 T.Ln(tabs[:depth]+"->", depth)
56 dist = hereDist
57 for i := range c {
58 T.Ln(tabs[:depth]+"walking", c[i].Name, depth, dist)
59 dist++
60 if c[i].Name == name {
61 if skipFirst {
62 continue
63 }
64 dist--
65 T.Ln(tabs[:depth]+"found", name, "at depth", depth, "distance", dist)
66 found = true
67 cm = &c[i]
68 e = nil
69 return
70 }
71 if found, depth, dist, cm, e = c[i].Commands.Find(name, depth, dist, false); E.Chk(e) {
72 T.Ln(tabs[:depth]+"error", c[i].Name)
73 return
74 }
75 if found {
76 return
77 }
78 }
79 T.Ln(tabs[:hereDepth]+"<-", hereDepth)
80 if hereDepth == 0 {
81 D.Ln("search text", name, "not found")
82 }
83 depth--
84 return
85 }
86
87 func (c Commands) ForEach(fn func(Command) bool, hereDepth, hereDist int) (ret bool, depth, dist int, e error) {
88 if c == nil {
89 dist = hereDist
90 depth = hereDepth
91 return
92 }
93 depth = hereDepth + 1
94 T.Ln(tabs[:depth]+"->", depth)
95 dist = hereDist
96 for i := range c {
97 T.Ln(tabs[:depth]+"walking", c[i].Name, depth, dist)
98 if !fn(c[i]) {
99 // if the closure returns false break out of the loop
100 return
101 }
102 }
103 T.Ln(tabs[:hereDepth]+"<-", hereDepth)
104 depth--
105 return
106 }
107