diff --git a/acmd.go b/acmd.go index 582616b..a4a4af5 100644 --- a/acmd.go +++ b/acmd.go @@ -374,25 +374,44 @@ func printCommands(cfg Config, cmds []Command) { minwidth, tabwidth, padding, padchar, flags := 0, 0, 11, byte(' '), uint(0) tw := tabwriter.NewWriter(cfg.Output, minwidth, tabwidth, padding, padchar, flags) for _, cmd := range cmds { - if cmd.IsHidden { + + if len(cmd.Subcommands) == 0 { + printCommand(cfg, tw, "", cmd) continue } - desc := cmd.Description - if desc == "" { - desc = "" - } - fmt.Fprintf(tw, " %s\t%s\n", cmd.Name, desc) - - if cfg.VerboseHelp && cmd.FlagSet != nil { - fset := cmd.FlagSet.Flags() - old := fset.Output() - fmt.Fprintf(tw, " ") - fset.SetOutput(tw) - fset.Usage() - fset.SetOutput(old) + for _, subcmd := range cmd.Subcommands { + printCommand(cfg, tw, cmd.Name, subcmd) } + } fmt.Fprint(tw, "\n") tw.Flush() } + +func printCommand(cfg Config, tw *tabwriter.Writer, pre string, cmd Command) { + var name string = cmd.Name + + if cmd.IsHidden { + return + } + desc := cmd.Description + if desc == "" { + desc = "" + } + + if pre != "" { + name = fmt.Sprintf("%s %s", pre, cmd.Name) + } + + fmt.Fprintf(tw, " %s\t%s\n", name, desc) + + if cfg.VerboseHelp && cmd.FlagSet != nil { + fset := cmd.FlagSet.Flags() + old := fset.Output() + fmt.Fprintf(tw, " ") + fset.SetOutput(tw) + fset.Usage() + fset.SetOutput(old) + } +} diff --git a/acmd_test.go b/acmd_test.go index a55fd3b..3c41227 100644 --- a/acmd_test.go +++ b/acmd_test.go @@ -391,6 +391,38 @@ func TestExit(t *testing.T) { mustEqual(t, buf.String(), wantOutput) } +func TestCommand_Help_SubCommands(t *testing.T) { + buf := &bytes.Buffer{} + cmds := []Command{ + {Name: "cmd", Subcommands: []Command{ + {Name: "sub1", ExecFunc: nopFunc, Description: "show sub1"}, + {Name: "sub2", ExecFunc: nopFunc, Description: "show sub2"}, + }}, + } + r := RunnerOf(cmds, Config{ + Args: []string{"./myapp", "help"}, + AppName: "myapp", + Output: buf, + }) + failIfErr(t, r.Run()) + + if !strings.Contains(buf.String(), "cmd sub1") { + t.Fatal("should show subcommand help") + } + + if !strings.Contains(buf.String(), "cmd sub2") { + t.Fatal("should show subcommand help") + } + + if !strings.Contains(buf.String(), "show sub1") { + t.Fatal("should show subcommand help") + } + + if !strings.Contains(buf.String(), "show sub2") { + t.Fatal("should show subcommand help") + } +} + func failIfOk(t testing.TB, err error) { t.Helper() if err == nil {