options: Add kong.ShortUsageOnError() option
Add kong.ShortUsageOnError() option similar to kong.UsageOnError().
Add tests for UsageOnError and ShortUsageOnError.
Remove the HelpOption summary reset at the beginning of DefaultHelpPrinter:
func DefaultHelpPrinter(options HelpOptions, ctx *Context) error {
- if ctx.Empty() {
- options.Summary = false
- }
⚠️ I'm not really sure what the implications of this are, tests still
seem to pass, but maybe this has unintended side effects.
Julia Ogris authored 3 years ago
Alec Thomas committed 3 years ago
84 | 84 | default: |
85 | 85 | return value.Help + " " + suffix |
86 | 86 | } |
87 | } | |
88 | ||
89 | // DefaultShortHelpPrinter is the default HelpPrinter for short help on error. | |
90 | func DefaultShortHelpPrinter(options HelpOptions, ctx *Context) error { | |
91 | w := newHelpWriter(ctx, options) | |
92 | cmd := ctx.Selected() | |
93 | app := ctx.Model | |
94 | if cmd == nil { | |
95 | w.Printf("Usage: %s%s", app.Name, app.Summary()) | |
96 | w.Printf(`Run "%s --help" for more information.`, app.Name) | |
97 | } else { | |
98 | w.Printf("Usage: %s %s", app.Name, cmd.Summary()) | |
99 | w.Printf(`Run "%s --help" for more information.`, cmd.FullPath()) | |
100 | } | |
101 | return w.Write(ctx.Stdout) | |
87 | 102 | } |
88 | 103 | |
89 | 104 | // DefaultHelpPrinter is the default HelpPrinter. |
1 | 1 | |
2 | 2 | import ( |
3 | 3 | "bytes" |
4 | "fmt" | |
4 | 5 | "strings" |
5 | 6 | "testing" |
6 | 7 | |
511 | 512 | require.Equal(t, expected, w.String()) |
512 | 513 | }) |
513 | 514 | } |
515 | ||
516 | func TestUsageOnError(t *testing.T) { | |
517 | var cli struct { | |
518 | Flag string `help:"A required flag." required` | |
519 | } | |
520 | w := &strings.Builder{} | |
521 | p := mustNew(t, &cli, | |
522 | kong.Writers(w, w), | |
523 | kong.Description("Some description."), | |
524 | kong.Exit(func(int) {}), | |
525 | kong.UsageOnError(), | |
526 | ) | |
527 | _, err := p.Parse([]string{}) | |
528 | p.FatalIfErrorf(err) | |
529 | ||
530 | expected := `Usage: test --flag=STRING | |
531 | ||
532 | Some description. | |
533 | ||
534 | Flags: | |
535 | -h, --help Show context-sensitive help. | |
536 | --flag=STRING A required flag. | |
537 | ||
538 | test: error: missing flags: --flag=STRING | |
539 | ` | |
540 | require.Equal(t, expected, w.String()) | |
541 | } | |
542 | ||
543 | func TestShortUsageOnError(t *testing.T) { | |
544 | var cli struct { | |
545 | Flag string `help:"A required flag." required` | |
546 | } | |
547 | w := &strings.Builder{} | |
548 | p := mustNew(t, &cli, | |
549 | kong.Writers(w, w), | |
550 | kong.Description("Some description."), | |
551 | kong.Exit(func(int) {}), | |
552 | kong.ShortUsageOnError(), | |
553 | ) | |
554 | _, err := p.Parse([]string{}) | |
555 | require.Error(t, err) | |
556 | p.FatalIfErrorf(err) | |
557 | ||
558 | expected := `Usage: test --flag=STRING | |
559 | Run "test --help" for more information. | |
560 | ||
561 | test: error: missing flags: --flag=STRING | |
562 | ` | |
563 | require.Equal(t, expected, w.String()) | |
564 | } | |
565 | ||
566 | func TestCustomShortUsageOnError(t *testing.T) { | |
567 | var cli struct { | |
568 | Flag string `help:"A required flag." required` | |
569 | } | |
570 | w := &strings.Builder{} | |
571 | shortHelp := func(_ kong.HelpOptions, ctx *kong.Context) error { | |
572 | fmt.Fprintln(ctx.Stdout, "🤷 wish I could help") | |
573 | return nil | |
574 | } | |
575 | p := mustNew(t, &cli, | |
576 | kong.Writers(w, w), | |
577 | kong.Description("Some description."), | |
578 | kong.Exit(func(int) {}), | |
579 | kong.ShortHelp(shortHelp), | |
580 | kong.ShortUsageOnError(), | |
581 | ) | |
582 | _, err := p.Parse([]string{}) | |
583 | require.Error(t, err) | |
584 | p.FatalIfErrorf(err) | |
585 | ||
586 | expected := `🤷 wish I could help | |
587 | ||
588 | test: error: missing flags: --flag=STRING | |
589 | ` | |
590 | require.Equal(t, expected, w.String()) | |
591 | } |
30 | 30 | return k |
31 | 31 | } |
32 | 32 | |
33 | type usageOnError int | |
34 | ||
35 | const ( | |
36 | shortUsage usageOnError = iota + 1 | |
37 | fullUsage | |
38 | ) | |
39 | ||
33 | 40 | // Kong is the main parser type. |
34 | 41 | type Kong struct { |
35 | 42 | // Grammar model. |
47 | 54 | registry *Registry |
48 | 55 | |
49 | 56 | noDefaultHelp bool |
50 | usageOnError bool | |
57 | usageOnError usageOnError | |
51 | 58 | help HelpPrinter |
59 | shortHelp HelpPrinter | |
52 | 60 | helpFormatter HelpValueFormatter |
53 | 61 | helpOptions HelpOptions |
54 | 62 | helpFlag *Flag |
83 | 91 | |
84 | 92 | if k.help == nil { |
85 | 93 | k.help = DefaultHelpPrinter |
94 | } | |
95 | ||
96 | if k.shortHelp == nil { | |
97 | k.shortHelp = DefaultShortHelpPrinter | |
86 | 98 | } |
87 | 99 | |
88 | 100 | model, err := build(k, grammar) |
330 | 342 | msg = fmt.Sprintf(args[0].(string), args[1:]...) + ": " + err.Error() |
331 | 343 | } |
332 | 344 | // Maybe display usage information. |
333 | if err, ok := err.(*ParseError); ok && k.usageOnError { | |
334 | options := k.helpOptions | |
335 | _ = k.help(options, err.Context) | |
336 | fmt.Fprintln(k.Stdout) | |
345 | if err, ok := err.(*ParseError); ok { | |
346 | switch k.usageOnError { | |
347 | case fullUsage: | |
348 | _ = k.help(k.helpOptions, err.Context) | |
349 | fmt.Fprintln(k.Stdout) | |
350 | case shortUsage: | |
351 | _ = k.shortHelp(k.helpOptions, err.Context) | |
352 | fmt.Fprintln(k.Stdout) | |
353 | } | |
337 | 354 | } |
338 | 355 | k.Fatalf("%s", msg) |
339 | 356 | } |
191 | 191 | }) |
192 | 192 | } |
193 | 193 | |
194 | // ShortHelp configures the short usage message. | |
195 | // | |
196 | // It should be used together with kong.ShortUsageOnError() to display a | |
197 | // custom short usage message on errors. | |
198 | func ShortHelp(shortHelp HelpPrinter) Option { | |
199 | return OptionFunc(func(k *Kong) error { | |
200 | k.shortHelp = shortHelp | |
201 | return nil | |
202 | }) | |
203 | } | |
204 | ||
194 | 205 | // HelpFormatter configures how the help text is formatted. |
195 | 206 | func HelpFormatter(helpFormatter HelpValueFormatter) Option { |
196 | 207 | return OptionFunc(func(k *Kong) error { |
250 | 261 | // UsageOnError configures Kong to display context-sensitive usage if FatalIfErrorf is called with an error. |
251 | 262 | func UsageOnError() Option { |
252 | 263 | return OptionFunc(func(k *Kong) error { |
253 | k.usageOnError = true | |
264 | k.usageOnError = fullUsage | |
265 | return nil | |
266 | }) | |
267 | } | |
268 | ||
269 | // ShortUsageOnError configures Kong to display context-sensitive short | |
270 | // usage if FatalIfErrorf is called with an error. The default short | |
271 | // usage message can be overridden with kong.ShortHelp(...). | |
272 | func ShortUsageOnError() Option { | |
273 | return OptionFunc(func(k *Kong) error { | |
274 | k.usageOnError = shortUsage | |
254 | 275 | return nil |
255 | 276 | }) |
256 | 277 | } |