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