107 lines
2.4 KiB
Go
107 lines
2.4 KiB
Go
package cmds
|
|
|
|
// Commands are a slice of Command entries
|
|
type Commands []Command
|
|
|
|
// Command is a specification for a command and can include any number of subcommands
|
|
type Command struct {
|
|
Name string
|
|
Title string
|
|
Description string
|
|
Entrypoint func(c interface{}) error
|
|
Commands Commands
|
|
Colorizer func(a ...interface{}) string
|
|
AppText string
|
|
Parent *Command
|
|
}
|
|
|
|
func (c Commands) PopulateParents(parent *Command) {
|
|
if parent != nil {
|
|
T.Ln("backlinking children of", parent.Name)
|
|
}
|
|
for i := range c {
|
|
c[i].Parent = parent
|
|
c[i].Commands.PopulateParents(&c[i])
|
|
}
|
|
}
|
|
|
|
// GetAllCommands returns all of the available command names
|
|
func (c Commands) GetAllCommands() (o []string) {
|
|
c.ForEach(func(cm Command) bool {
|
|
o = append(o, cm.Name)
|
|
o = append(o, cm.Commands.GetAllCommands()...)
|
|
return true
|
|
}, 0, 0,
|
|
)
|
|
return
|
|
}
|
|
|
|
var tabs = "\t\t\t\t\t"
|
|
|
|
// Find the Command you are looking for. Note that the namespace is assumed to be flat, no duplicated names on different
|
|
// levels, as it returns on the first one it finds, which goes depth-first recursive
|
|
func (c Commands) Find(
|
|
name string, hereDepth, hereDist int, skipFirst bool,
|
|
) (found bool, depth, dist int, cm *Command, e error) {
|
|
if c == nil {
|
|
dist = hereDist
|
|
depth = hereDepth
|
|
return
|
|
}
|
|
if hereDist == 0 {
|
|
D.Ln("searching for command:", name)
|
|
}
|
|
depth = hereDepth + 1
|
|
T.Ln(tabs[:depth]+"->", depth)
|
|
dist = hereDist
|
|
for i := range c {
|
|
T.Ln(tabs[:depth]+"walking", c[i].Name, depth, dist)
|
|
dist++
|
|
if c[i].Name == name {
|
|
if skipFirst {
|
|
continue
|
|
}
|
|
dist--
|
|
T.Ln(tabs[:depth]+"found", name, "at depth", depth, "distance", dist)
|
|
found = true
|
|
cm = &c[i]
|
|
e = nil
|
|
return
|
|
}
|
|
if found, depth, dist, cm, e = c[i].Commands.Find(name, depth, dist, false); E.Chk(e) {
|
|
T.Ln(tabs[:depth]+"error", c[i].Name)
|
|
return
|
|
}
|
|
if found {
|
|
return
|
|
}
|
|
}
|
|
T.Ln(tabs[:hereDepth]+"<-", hereDepth)
|
|
if hereDepth == 0 {
|
|
D.Ln("search text", name, "not found")
|
|
}
|
|
depth--
|
|
return
|
|
}
|
|
|
|
func (c Commands) ForEach(fn func(Command) bool, hereDepth, hereDist int) (ret bool, depth, dist int, e error) {
|
|
if c == nil {
|
|
dist = hereDist
|
|
depth = hereDepth
|
|
return
|
|
}
|
|
depth = hereDepth + 1
|
|
T.Ln(tabs[:depth]+"->", depth)
|
|
dist = hereDist
|
|
for i := range c {
|
|
T.Ln(tabs[:depth]+"walking", c[i].Name, depth, dist)
|
|
if !fn(c[i]) {
|
|
// if the closure returns false break out of the loop
|
|
return
|
|
}
|
|
}
|
|
T.Ln(tabs[:hereDepth]+"<-", hereDepth)
|
|
depth--
|
|
return
|
|
}
|