From 2a5f1c8bfcc1d83671532e3629ce101411651368 Mon Sep 17 00:00:00 2001 From: Tugdual Saunier Date: Mon, 10 Jun 2024 16:51:45 +0200 Subject: [PATCH] Adds a new hook to tweak command description at runtime For one feature I'm currently implementing I need to be able to tweak a command description based on some runtime information. My main use case is to customize the description (basically rendering it as a template but with some context values that we can't provide generically). So I ended up with this solution. The idea is to allow one to register a hook that will be called during command help rendering to compute the command description. --- command.go | 2 ++ funcs.go | 4 ++++ help.go | 4 ++++ help_test.go | 25 +++++++++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/command.go b/command.go index 7109a81..f68555b 100644 --- a/command.go +++ b/command.go @@ -44,6 +44,8 @@ type Command struct { Usage string // A longer explanation of how the command works Description string + // or a function responsible to render the description + DescriptionFunc DescriptionFunc // The category the command is part of Category string // An action to execute before any sub-subcommands are run, but after the context is ready diff --git a/funcs.go b/funcs.go index 5de3a57..ae8e818 100644 --- a/funcs.go +++ b/funcs.go @@ -33,6 +33,10 @@ type ActionFunc func(*Context) error // CommandNotFoundFunc is executed if the proper command cannot be found type CommandNotFoundFunc func(*Context, string) error +// DescriptionFunc is used by the help generation to display a description when +// its computation is intensive or needs runtime information +type DescriptionFunc func(*Command, *Application) string + // FlagStringFunc is used by the help generation to display a flag, which is // expected to be a single line. type FlagStringFunc func(Flag) string diff --git a/help.go b/help.go index 4b8b601..9ec14d4 100644 --- a/help.go +++ b/help.go @@ -149,6 +149,10 @@ func ShowAppHelp(c *Context) error { // ShowCommandHelp prints help for the given command func ShowCommandHelp(ctx *Context, command string) error { if c := ctx.App.Command(command); c != nil { + if c.DescriptionFunc != nil { + c.Description = c.DescriptionFunc(c, ctx.App) + } + HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) return nil } diff --git a/help_test.go b/help_test.go index 8e67c4f..9876b93 100644 --- a/help_test.go +++ b/help_test.go @@ -237,6 +237,31 @@ func TestShowCommandHelp_CommandAliases(t *testing.T) { } } +func TestShowCommandHelp_DescriptionFunc(t *testing.T) { + app := &Application{ + Commands: []*Command{ + { + Name: "frobbly", + Description: "this is not my custom description", + DescriptionFunc: func(*Command, *Application) string { + return "this is my custom description" + }, + Action: func(ctx *Context) error { + return nil + }, + }, + }, + } + + output := &bytes.Buffer{} + app.Writer = output + app.Run([]string{"foo", "help", "frobbly"}) + + if !strings.Contains(output.String(), "this is my custom description") { + t.Errorf("expected output to include result of DescriptionFunc; got: %q", output.String()) + } +} + func TestShowAppHelp_HiddenCommand(t *testing.T) { app := &Application{ Commands: []*Command{