From 3b5f4faf76bea4c0ea3204cef8b1daec9123500b Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Thu, 1 Jan 2015 16:17:52 -0800 Subject: [PATCH] Padded help output, because why not. --- chat/command.go | 26 ++++++++++------------ chat/help.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 chat/help.go diff --git a/chat/command.go b/chat/command.go index 26650ea..9047b4d 100644 --- a/chat/command.go +++ b/chat/command.go @@ -3,7 +3,6 @@ package chat import ( "errors" "fmt" - "sort" "strings" "sync" ) @@ -23,22 +22,25 @@ var ErrMissingPrefix = errors.New("command missing prefix") // 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{}, } } @@ -52,7 +54,7 @@ func (c *Commands) Add(cmd Command) error { return ErrMissingPrefix } - c.commands[cmd.Prefix] = cmd + c.commands[cmd.Prefix] = &cmd return nil } @@ -91,13 +93,9 @@ func (c *Commands) Help() string { 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 diff --git a/chat/help.go b/chat/help.go new file mode 100644 index 0000000..c6e6856 --- /dev/null +++ b/chat/help.go @@ -0,0 +1,58 @@ +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) +}