import (
"errors"
"fmt"
- "sort"
"strings"
"sync"
)
// Command is a definition of a handler for a command.
type Command struct {
- Prefix string
+ // The command's key, such as /foo
+ Prefix string
+ // Extra help regarding arguments
PrefixHelp string
- Help string
- Handler func(*Channel, CommandMsg) error
+ // If omitted, command is hidden from /help
+ Help string
+ Handler func(*Channel, CommandMsg) error
}
// Commands is a registry of available commands.
type Commands struct {
- commands map[string]Command
+ commands map[string]*Command
sync.RWMutex
}
// NewCommands returns a new Commands registry.
func NewCommands() *Commands {
return &Commands{
- commands: map[string]Command{},
+ commands: map[string]*Command{},
}
}
return ErrMissingPrefix
}
- c.commands[cmd.Prefix] = cmd
+ c.commands[cmd.Prefix] = &cmd
return nil
}
c.RLock()
defer c.RUnlock()
- r := []string{}
- for _, cmd := range c.commands {
- r = append(r, fmt.Sprintf("%s %s - %s", cmd.Prefix, cmd.PrefixHelp, cmd.Help))
- }
- sort.Strings(r)
-
- return strings.Join(r, Newline)
+ // TODO: Could cache this...
+ help := NewCommandsHelp(c)
+ return help.String()
}
var defaultCmdHandlers *Commands
--- /dev/null
+package chat
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+)
+
+type helpItem struct {
+ Prefix string
+ Text string
+}
+
+type help struct {
+ items []helpItem
+ prefixWidth int
+}
+
+// NewCommandsHelp creates a help container from a commands container.
+func NewCommandsHelp(c *Commands) *help {
+ lookup := map[string]struct{}{}
+ h := help{
+ items: []helpItem{},
+ }
+ for _, cmd := range c.commands {
+ if cmd.Help == "" {
+ // Skip hidden commands.
+ continue
+ }
+ _, exists := lookup[cmd.Prefix]
+ if exists {
+ // Duplicate (alias)
+ continue
+ }
+ lookup[cmd.Prefix] = struct{}{}
+ prefix := fmt.Sprintf("%s %s", cmd.Prefix, cmd.PrefixHelp)
+ h.add(helpItem{prefix, cmd.Help})
+ }
+ return &h
+}
+
+func (h *help) add(item helpItem) {
+ h.items = append(h.items, item)
+ if len(item.Prefix) > h.prefixWidth {
+ h.prefixWidth = len(item.Prefix)
+ }
+}
+
+func (h help) String() string {
+ r := []string{}
+ format := fmt.Sprintf("%%-%ds - %%s", h.prefixWidth)
+ for _, item := range h.items {
+ r = append(r, fmt.Sprintf(format, item.Prefix, item.Text))
+ }
+
+ sort.Strings(r)
+ return strings.Join(r, Newline)
+}