@@ -36,15 +36,21 @@ type Parser struct {
36
36
37
37
// ParserConfig is the only type to config `Parser`, programmers only need to use this type to control `Parser` action
38
38
type ParserConfig struct {
39
- Usage string // manual usage display
40
- EpiLog string // message after help
41
- DisableHelp bool // disable help entry register [-h/--help]
42
- ContinueOnHelp bool // set true to: continue program after default help is printed
43
- DisableDefaultShowHelp bool // set false to: default show help when there is no args to parse (default action)
44
- DefaultAction func () // set default action to replace default help action
45
- AddShellCompletion bool // set true to register shell completion entry [--completion]
46
- WithHint bool // argument help message with argument default value hint
47
- MaxHeaderLength int // max argument header length in help menu, help info will start at new line if argument meta info is too long
39
+ Usage string // manual usage display
40
+ EpiLog string // message after help
41
+
42
+ DisableHelp bool // disable help entry register [-h/--help]
43
+ ContinueOnHelp bool // set true to: continue program after default help is printed
44
+ DisableDefaultShowHelp bool // set false to: default show help when there is no args to parse (default action)
45
+
46
+ DefaultAction func () // set default action to replace default help action
47
+ AddShellCompletion bool // set true to register shell completion entry [--completion]
48
+ WithHint bool // argument help message with argument default value hint
49
+ MaxHeaderLength int // max argument header length in help menu, help info will start at new line if argument meta info is too long
50
+
51
+ WithColor bool // enable colorful help message if the terminal has support for color
52
+ EnsureColor bool // use color code for sure, skip terminal env check
53
+ ColorSchema * ColorSchema // use given color schema to draw help info
48
54
}
49
55
50
56
// NewParser create the parser object with optional name & description & ParserConfig
@@ -56,17 +62,20 @@ func NewParser(name string, description string, config *ParserConfig) *Parser {
56
62
name = strings .ReplaceAll (path .Base (os .Args [0 ]), " " , "" ) // avoid space for shell complete code generate
57
63
}
58
64
parser := & Parser {
59
- name : name ,
60
- description : description ,
61
- config : config ,
65
+ name : name ,
66
+ description : description ,
67
+ config : config ,
68
+
62
69
entries : []* arg {},
63
70
entryMap : make (map [string ]* arg ),
64
71
entryGroup : make (map [string ][]* arg ),
65
72
entryGroupOrder : []string {},
66
- positionArgs : []* arg {},
67
- positionalPool : make (map [string ]* arg ),
68
- subParser : []* Parser {},
69
- subParserMap : make (map [string ]* Parser ),
73
+
74
+ positionArgs : []* arg {},
75
+ positionalPool : make (map [string ]* arg ),
76
+
77
+ subParser : []* Parser {},
78
+ subParserMap : make (map [string ]* Parser ),
70
79
}
71
80
if ! config .DisableHelp {
72
81
parser .showHelp = parser .Flag ("h" , "help" ,
@@ -156,12 +165,29 @@ func (p *Parser) PrintHelp() {
156
165
fmt .Println (p .FormatHelp ())
157
166
}
158
167
159
- // FormatHelp only format help message for manual use, for example: decide when to print help message
168
+ // FormatHelp only format help message for manual use, you can decide when to print help message
160
169
func (p * Parser ) FormatHelp () string {
161
- result := p .formatUsage ()
170
+ if ! p .config .WithColor {
171
+ return p .FormatHelpWithColor (NoColor )
172
+ }
173
+
174
+ if p .config .EnsureColor || checkTerminalColorSupport () {
175
+ schema := DefaultColor
176
+ if p .config .ColorSchema != nil {
177
+ schema = p .config .ColorSchema
178
+ }
179
+ return p .FormatHelpWithColor (schema )
180
+ }
181
+
182
+ return p .FormatHelpWithColor (NoColor )
183
+ }
184
+
185
+ func (p * Parser ) FormatHelpWithColor (schema * ColorSchema ) string {
186
+ result := wrapperColor (p .formatUsage (), schema .Usage )
162
187
if p .description != "" {
163
- result += "\n \n " + p .description
188
+ result += "\n \n " + wrapperColor ( p .description , schema . Description )
164
189
}
190
+ // calculate header length
165
191
headerLength := 10 // here set minimum header length, the code after will find the max length of headers
166
192
for _ , parser := range p .subParser {
167
193
l := len (parser .name )
@@ -170,13 +196,13 @@ func (p *Parser) FormatHelp() string {
170
196
}
171
197
}
172
198
for _ , arg := range p .positionArgs {
173
- l := len ( arg .formatHelpHeader () )
199
+ l , _ := arg .formatHelpHeader (schema . Argument , schema . Meta )
174
200
if l > headerLength {
175
201
headerLength = l
176
202
}
177
203
}
178
204
for _ , arg := range p .entries {
179
- l := len ( arg .formatHelpHeader () )
205
+ l , _ := arg .formatHelpHeader (schema . Argument , schema . Meta )
180
206
if l > headerLength {
181
207
headerLength = l
182
208
}
@@ -187,15 +213,19 @@ func (p *Parser) FormatHelp() string {
187
213
headerLength = p .config .MaxHeaderLength
188
214
helpBreak = true
189
215
}
216
+ // sub command
190
217
if len (p .subParser ) > 0 {
191
- section := "\n \n commands:"
218
+ section := "\n \n " + wrapperColor ( "commands:" , schema . GroupTitle )
192
219
for _ , parser := range p .subParser {
193
- section += "\n " + formatHelpRow (parser .name , parser .description , headerLength , helpBreak )
220
+ section += "\n " + formatHelpRow (wrapperColor (parser .name , schema .Command ), parser .description ,
221
+ len (parser .name ), headerLength , helpBreak )
194
222
}
195
223
result += section
196
224
}
197
225
withHint := p .config .WithHint
198
- if len (p .positionArgs ) > 0 { // dealing positional arguments present
226
+
227
+ // positional arguments
228
+ if len (p .positionArgs ) > 0 {
199
229
section := ""
200
230
for _ , arg := range p .positionArgs {
201
231
if arg .Group != "" || arg .HideEntry {
@@ -205,13 +235,16 @@ func (p *Parser) FormatHelp() string {
205
235
if withHint && ! arg .NoHint {
206
236
help = arg .formatHelpWithExtraInfo ()
207
237
}
208
- section += "\n " + formatHelpRow (arg .formatHelpHeader (), help , headerLength , helpBreak )
238
+ size , header := arg .formatHelpHeader (schema .Argument , schema .Meta )
239
+ section += "\n " + formatHelpRow (header , help , size , headerLength , helpBreak )
209
240
}
210
241
if section != "" {
211
- section = "\n \n positionals:" + section
242
+ section = "\n \n " + wrapperColor ( "positionals:" , schema . GroupTitle ) + section
212
243
}
213
244
result += section
214
245
}
246
+
247
+ // optional arguments
215
248
if len (p .entries ) > 0 { // dealing optional arguments present
216
249
parsed := make (map [string ]bool )
217
250
section := ""
@@ -231,28 +264,36 @@ func (p *Parser) FormatHelp() string {
231
264
if withHint && ! arg .NoHint {
232
265
help = arg .formatHelpWithExtraInfo ()
233
266
}
234
- section += "\n " + formatHelpRow (arg .formatHelpHeader (), help , headerLength , helpBreak )
267
+ size , header := arg .formatHelpHeader (schema .Argument , schema .Meta )
268
+ section += "\n " + formatHelpRow (header , help , size , headerLength , helpBreak )
235
269
}
236
270
if section != "" {
237
- section = "\n \n options:" + section
271
+ section = "\n \n " + wrapperColor ( "options:" , schema . GroupTitle ) + section
238
272
}
239
273
result += section
240
274
}
241
- for _ , group := range p .entryGroupOrder { // dealing arguments group present
242
- section := fmt .Sprintf ("\n \n %s:" , group )
275
+
276
+ // argument groups
277
+ for _ , group := range p .entryGroupOrder {
278
+ section := "\n \n " + wrapperColor (group + ":" , schema .GroupTitle )
243
279
content := ""
244
280
for _ , arg := range p .entryGroup [group ] {
245
281
if arg .HideEntry {
246
282
continue
247
283
}
248
- content += "\n " + formatHelpRow (arg .formatHelpHeader (), arg .Help , headerLength , helpBreak )
284
+ help := arg .Help
285
+ if withHint && ! arg .NoHint {
286
+ help = arg .formatHelpWithExtraInfo ()
287
+ }
288
+ size , header := arg .formatHelpHeader (schema .Argument , schema .Meta )
289
+ content += "\n " + formatHelpRow (header , help , size , headerLength , helpBreak )
249
290
}
250
291
if content != "" {
251
292
result += section + content
252
293
}
253
294
}
254
295
if p .config .EpiLog != "" {
255
- result += "\n \n " + p .config .EpiLog
296
+ result += "\n \n " + wrapperColor ( p .config .EpiLog , schema . Epilog )
256
297
}
257
298
258
299
return result
0 commit comments