From 0584d64047001f148ac1f2980ea9df73f1872b55 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sat, 22 Feb 2025 22:06:02 +0900 Subject: [PATCH] command: implement help builder Signed-off-by: Ophestra --- command/command.go | 7 +++++-- command/help.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++ command/node.go | 3 +++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 command/help.go diff --git a/command/command.go b/command/command.go index 79833b3..55f0ead 100644 --- a/command/command.go +++ b/command/command.go @@ -1,7 +1,10 @@ // Package command implements generic nested command parsing. package command -import "flag" +import ( + "flag" + "strings" +) type ( // HandlerFunc is called when matching a directly handled subcommand tree. @@ -13,7 +16,7 @@ type ( // FlagDefiner is a deferred flag definer value, usually encapsulating the default value. FlagDefiner interface { // Define defines the flag in set. - Define(set *flag.FlagSet, p any, name, usage string) + Define(b *strings.Builder, set *flag.FlagSet, p any, name, usage string) } Command interface { diff --git a/command/help.go b/command/help.go new file mode 100644 index 0000000..315ab95 --- /dev/null +++ b/command/help.go @@ -0,0 +1,48 @@ +package command + +import ( + "errors" + "fmt" + "io" + "strings" + "text/tabwriter" +) + +var ErrHelp = errors.New("help requested") + +type helpBuilder struct { + n *node + prefix []string +} + +func (h *helpBuilder) writeHelp(w io.Writer) error { + if _, err := fmt.Fprintf(w, + "\nUsage:\t%s%s COMMAND [OPTIONS]\n\nCommands:\n", + strings.Join(h.prefix, " "), &h.n.su); err != nil { + return err + } + + tw := tabwriter.NewWriter(w, 0, 1, 4, ' ', 0) + if err := h.writeCommands(h.n.child, tw); err != nil { + return err + } + if err := tw.Flush(); err != nil { + return err + } + + _, err := w.Write([]byte{'\n'}) + if err == nil { + err = ErrHelp + } + return err +} + +func (h *helpBuilder) writeCommands(n *node, w io.Writer) error { + if n == nil { + return nil + } + if _, err := fmt.Fprintf(w, "\t%s\t%s\n", n.name, n.usage); err != nil { + return err + } + return h.writeCommands(n.next, w) +} diff --git a/command/node.go b/command/node.go index 9ed2149..c7805b5 100644 --- a/command/node.go +++ b/command/node.go @@ -3,6 +3,7 @@ package command import ( "flag" "io" + "strings" ) type node struct { @@ -11,8 +12,10 @@ type node struct { out io.Writer logf LogFunc + help *helpBuilder f HandlerFunc + su strings.Builder set *flag.FlagSet }