66 "os"
77 "regexp"
88 "strings"
9- "text/template"
109)
1110
1211var (
@@ -28,17 +27,20 @@ type Application struct {
2827 Name string
2928 Help string
3029
31- author string
32- version string
33- errorWriter io.Writer // Destination for errors.
34- usageWriter io.Writer // Destination for usage
35- usageTemplate string
36- usageFuncs template.FuncMap
37- validator ApplicationValidator
38- terminate func (status int ) // See Terminate()
39- noInterspersed bool // can flags be interspersed with args (or must they come first)
40- defaultEnvars bool
41- completion bool
30+ author string
31+ version string
32+ errorWriter io.Writer // Destination for errors.
33+ usageWriter io.Writer // Destination for usage
34+ hiddenHelpWriter io.Writer // Desitination for hidden help commands.
35+ usageTemplate string
36+ usageFuncs map [string ]interface {}
37+ templateRenderer func (a * Application , context * ParseContext , indent int , tmpl string ) error
38+ usageRenderer UsageRenderer
39+ validator ApplicationValidator
40+ terminate func (status int ) // See Terminate()
41+ noInterspersed bool // can flags be interspersed with args (or must they come first)
42+ defaultEnvars bool
43+ completion bool
4244
4345 // Help flag. Exposed for user customisation.
4446 HelpFlag * FlagClause
@@ -51,12 +53,12 @@ type Application struct {
5153// New creates a new Kingpin application instance.
5254func New (name , help string ) * Application {
5355 a := & Application {
54- Name : name ,
55- Help : help ,
56- errorWriter : os .Stderr , // Left for backwards compatibility purposes.
57- usageWriter : os .Stderr ,
58- usageTemplate : DefaultUsageTemplate ,
59- terminate : os .Exit ,
56+ Name : name ,
57+ Help : help ,
58+ errorWriter : os .Stderr , // Left for backwards compatibility purposes.
59+ usageWriter : os .Stderr ,
60+ hiddenHelpWriter : os . Stdout ,
61+ terminate : os .Exit ,
6062 }
6163 a .flagGroup = newFlagGroup ()
6264 a .argGroup = newArgGroup ()
@@ -73,45 +75,57 @@ func New(name, help string) *Application {
7375 return a
7476}
7577
78+ // renderHiddenFlag renders usage for hidden help flags (--help-long, --help-man, etc.).
79+ // A custom UsageRenderer does NOT override these — they are distinct output formats
80+ // (man pages, completion scripts) that should always produce their advertised output.
81+ // UsageFuncs overrides ARE applied, since they provide template helper functions that
82+ // may be needed by the template path.
83+ func (a * Application ) renderHiddenFlag (c * ParseContext , renderer UsageRenderer , tmpl string ) error {
84+ if a .usageFuncs != nil && a .templateRenderer != nil {
85+ return a .templateRenderer (a , c , 2 , tmpl )
86+ }
87+ return a .usageForContextWithUsageRenderer (c , 2 , renderer )
88+ }
89+
7690func (a * Application ) generateLongHelp (c * ParseContext ) error {
77- a .Writer (os . Stdout )
78- if err := a .UsageForContextWithTemplate (c , 2 , LongHelpTemplate ); err != nil {
91+ a .Writer (a . hiddenHelpWriter )
92+ if err := a .renderHiddenFlag (c , RenderLongHelp , LongHelpTemplate ); err != nil {
7993 return err
8094 }
8195 a .terminate (0 )
8296 return nil
8397}
8498
8599func (a * Application ) generateManPage (c * ParseContext ) error {
86- a .Writer (os . Stdout )
87- if err := a .UsageForContextWithTemplate (c , 2 , ManPageTemplate ); err != nil {
100+ a .Writer (a . hiddenHelpWriter )
101+ if err := a .renderHiddenFlag (c , RenderManPage , ManPageTemplate ); err != nil {
88102 return err
89103 }
90104 a .terminate (0 )
91105 return nil
92106}
93107
94108func (a * Application ) generateBashCompletionScript (c * ParseContext ) error {
95- a .Writer (os . Stdout )
96- if err := a .UsageForContextWithTemplate (c , 2 , BashCompletionTemplate ); err != nil {
109+ a .Writer (a . hiddenHelpWriter )
110+ if err := a .renderHiddenFlag (c , RenderBashCompletion , BashCompletionTemplate ); err != nil {
97111 return err
98112 }
99113 a .terminate (0 )
100114 return nil
101115}
102116
103117func (a * Application ) generateZSHCompletionScript (c * ParseContext ) error {
104- a .Writer (os . Stdout )
105- if err := a .UsageForContextWithTemplate (c , 2 , ZshCompletionTemplate ); err != nil {
118+ a .Writer (a . hiddenHelpWriter )
119+ if err := a .renderHiddenFlag (c , RenderZshCompletion , ZshCompletionTemplate ); err != nil {
106120 return err
107121 }
108122 a .terminate (0 )
109123 return nil
110124}
111125
112126func (a * Application ) generateFishCompletionScript (c * ParseContext ) error {
113- a .Writer (os . Stdout )
114- if err := a .UsageForContextWithTemplate (c , 2 , FishCompletionTemplate ); err != nil {
127+ a .Writer (a . hiddenHelpWriter )
128+ if err := a .renderHiddenFlag (c , RenderFishCompletion , FishCompletionTemplate ); err != nil {
115129 return err
116130 }
117131 a .terminate (0 )
@@ -152,22 +166,47 @@ func (a *Application) ErrorWriter(w io.Writer) *Application {
152166 return a
153167}
154168
155- // UsageWriter sets the io.Writer to use for errors .
169+ // UsageWriter sets the io.Writer to use for usage .
156170func (a * Application ) UsageWriter (w io.Writer ) * Application {
157171 a .usageWriter = w
158172 return a
159173}
160174
175+ // HiddenHelpWriter sets the io.Writer to use for usage of hidden help commands.
176+ func (a * Application ) HiddenHelpWriter (w io.Writer ) * Application {
177+ a .hiddenHelpWriter = w
178+ return a
179+ }
180+
161181// UsageTemplate specifies the text template to use when displaying usage
162182// information. The default is UsageTemplate.
183+ //
184+ // Note: calling this method causes text/template to be linked into the binary,
185+ // which prevents dead code elimination of reflect.MethodByName. Programs that
186+ // want smaller binaries should use UsageRenderer instead.
163187func (a * Application ) UsageTemplate (template string ) * Application {
164188 a .usageTemplate = template
189+ a .templateRenderer = templateRenderFunc
165190 return a
166191}
167192
168- // UsageFuncs adds extra functions that can be used in the usage template.
169- func (a * Application ) UsageFuncs (funcs template.FuncMap ) * Application {
193+ // UsageFuncs adds extra functions that can be used in the usage template
194+ //
195+ // Note: calling this method causes text/template to be linked into the binary,
196+ // which prevents dead code elimination of reflect.MethodByName. Programs that
197+ // want smaller binaries should use UsageRenderer instead..
198+ func (a * Application ) UsageFuncs (funcs map [string ]interface {}) * Application {
170199 a .usageFuncs = funcs
200+ a .templateRenderer = templateRenderFunc
201+ return a
202+ }
203+
204+ // UsageRenderer registers a custom UsageRenderer for the primary --help output.
205+ // It does not affect hidden help flags (--help-long, --help-man, completion scripts),
206+ // which always use their built-in renderers or the template path if UsageFuncs is set.
207+ // For backward compatibility, UsageTemplate takes precedence over UsageRenderer.
208+ func (a * Application ) UsageRenderer (fn UsageRenderer ) * Application {
209+ a .usageRenderer = fn
171210 return a
172211}
173212
0 commit comments