aboutsummaryrefslogtreecommitdiffhomepage
path: root/command
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-08-07 20:32:24 +0900
committerOphestra <cat@gensokyo.uk>2026-08-07 20:32:24 +0900
commitf1dd3a085b029ecf29b75373c0f7c982dbe72b88 (patch)
treec373765b74aa7257c87761f02f5ab24e2d2de6ee /command
parentb37c1d899349fef9e7af38940ae0c2d507c433a9 (diff)
command: hard wrap help message flags
This greatly improves readability when lots of flags are registered. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'command')
-rw-r--r--command/builder.go4
-rw-r--r--command/flag.go8
-rw-r--r--command/help.go24
-rw-r--r--command/node.go3
-rw-r--r--command/parse_test.go40
5 files changed, 49 insertions, 30 deletions
diff --git a/command/builder.go b/command/builder.go
index d3b0c3f5..174010ea 100644
--- a/command/builder.go
+++ b/command/builder.go
@@ -23,8 +23,8 @@ func newNode(output io.Writer, logf LogFunc, name, usage string) *node {
n.set.SetOutput(output)
n.set.Usage = func() {
_ = n.writeHelp()
- if n.suffix.Len() > 0 {
- _, _ = fmt.Fprintln(output, "Flags:")
+ if len(n.suffix) > 0 {
+ _, _ = fmt.Fprintln(output, "flags:")
n.set.PrintDefaults()
_, _ = fmt.Fprintln(output)
}
diff --git a/command/flag.go b/command/flag.go
index cb85a648..d7eb6cb2 100644
--- a/command/flag.go
+++ b/command/flag.go
@@ -16,7 +16,13 @@ func (e FlagError) Is(target error) bool {
}
func (n *node) Flag(p any, name string, value FlagDefiner, usage string) Node {
- value.Define(&n.suffix, n.set, p, name, usage)
+ var buf strings.Builder
+ value.Define(&buf, n.set, p, name, usage)
+ s := buf.String()
+ if len(s) > 0 && s[0] == ' ' {
+ s = s[1:]
+ }
+ n.suffix = append(n.suffix, s)
return n
}
diff --git a/command/help.go b/command/help.go
index cb22ce50..5bf58f6a 100644
--- a/command/help.go
+++ b/command/help.go
@@ -1,6 +1,7 @@
package command
import (
+ "bytes"
"errors"
"fmt"
"io"
@@ -13,14 +14,31 @@ var ErrHelp = errors.New("help requested")
func (n *node) PrintHelp() { _ = n.writeHelp() }
func (n *node) writeHelp() error {
+ prefix := strings.Join(append(n.prefix, n.name), " ")
+ var buf strings.Builder
+ offset := 7 + len(prefix)
+ line := offset + 14
+ w := bytes.Repeat([]byte{' '}, offset+1)
+ w[0] = '\n'
+
+ for _, flag := range n.suffix {
+ line += len(flag) + 1
+ if line >= 80 {
+ line = offset + len(flag) + 1
+ buf.Write(w)
+ }
+ buf.WriteByte(' ')
+ buf.WriteString(flag)
+ }
+
if _, err := fmt.Fprintf(n.out,
- "\nUsage:\t%s [-h | --help]%s COMMAND [OPTIONS]\n",
- strings.Join(append(n.prefix, n.name), " "), &n.suffix,
+ "usage: %s [-h | --help]%s <command> [<args>]\n",
+ prefix, &buf,
); err != nil {
return err
}
if n.child != nil {
- if _, err := fmt.Fprint(n.out, "\nCommands:\n"); err != nil {
+ if _, err := fmt.Fprint(n.out, "\ncommands:\n"); err != nil {
return err
}
}
diff --git a/command/node.go b/command/node.go
index b6f84bf8..0dcdf162 100644
--- a/command/node.go
+++ b/command/node.go
@@ -3,7 +3,6 @@ package command
import (
"flag"
"io"
- "strings"
)
// A node represents a command.
@@ -17,7 +16,7 @@ type node struct {
// Names of commands preceding node.
prefix []string
// Short user-facing representations of flags received by node.
- suffix strings.Builder
+ suffix []string
f HandlerFunc
set *flag.FlagSet
diff --git a/command/parse_test.go b/command/parse_test.go
index c2956c6f..adbb0c30 100644
--- a/command/parse_test.go
+++ b/command/parse_test.go
@@ -70,7 +70,7 @@ func TestParse(t *testing.T) {
"d=0 out of order string flag",
buildTestCommand,
[]string{"string", "--string", "64d3b4b7b21788585845060e2199a78f"},
- "flag provided but not defined: -string\n\nUsage:\ttest string [-h | --help] COMMAND [OPTIONS]\n\n", "",
+ "flag provided but not defined: -string\nusage: test string [-h | --help] <command> [<args>]\n\n", "",
errors.New("flag provided but not defined: -string"),
},
{
@@ -120,7 +120,7 @@ func TestParse(t *testing.T) {
"d=1 empty sub help",
buildTestCommand,
[]string{"empty", "-h"},
- "\nUsage:\ttest empty [-h | --help] COMMAND [OPTIONS]\n\n", "", flag.ErrHelp,
+ "usage: test empty [-h | --help] <command> [<args>]\n\n", "", flag.ErrHelp,
},
{
"d=1 no match",
@@ -151,10 +151,10 @@ func TestParse(t *testing.T) {
"d=0 help",
buildTestCommand,
[]string{},
- `
-Usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>] [--repeat <value>] COMMAND [OPTIONS]
+ `usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>]
+ [--repeat <value>] <command> [<args>]
-Commands:
+commands:
error return an error
print wraps Fprint
string print string passed by flag
@@ -171,10 +171,10 @@ Commands:
"d=0 help flag",
buildTestCommand,
[]string{"-h"},
- `
-Usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>] [--repeat <value>] COMMAND [OPTIONS]
+ `usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>]
+ [--repeat <value>] <command> [<args>]
-Commands:
+commands:
error return an error
print wraps Fprint
string print string passed by flag
@@ -185,7 +185,7 @@ Commands:
succeed this command succeeds
deep top level of command tree with various levels
-Flags:
+flags:
-fail
fail early
-int int
@@ -203,10 +203,9 @@ Flags:
"d=1 help",
buildTestCommand,
[]string{"join"},
- `
-Usage: test join [-h | --help] COMMAND [OPTIONS]
+ `usage: test join [-h | --help] <command> [<args>]
-Commands:
+commands:
out write result to wout
log log result to wlog
@@ -216,10 +215,9 @@ Commands:
"d=1 help flag",
buildTestCommand,
[]string{"join", "-h"},
- `
-Usage: test join [-h | --help] COMMAND [OPTIONS]
+ `usage: test join [-h | --help] <command> [<args>]
-Commands:
+commands:
out write result to wout
log log result to wlog
@@ -230,10 +228,9 @@ Commands:
"d=2 help",
buildTestCommand,
[]string{"deep", "d=2"},
- `
-Usage: test deep d=2 [-h | --help] COMMAND [OPTIONS]
+ `usage: test deep d=2 [-h | --help] <command> [<args>]
-Commands:
+commands:
d=3 relative third level
`, "", command.ErrHelp,
@@ -242,10 +239,9 @@ Commands:
"d=2 help flag",
buildTestCommand,
[]string{"deep", "d=2", "-h"},
- `
-Usage: test deep d=2 [-h | --help] COMMAND [OPTIONS]
+ `usage: test deep d=2 [-h | --help] <command> [<args>]
-Commands:
+commands:
d=3 relative third level
`, "", flag.ErrHelp,
@@ -261,7 +257,7 @@ Commands:
t.Errorf("Parse: error = %v; wantErr %v", err, tc.wantErr)
}
if got := wout.String(); got != tc.want {
- t.Errorf("Parse: %s want %s", got, tc.want)
+ t.Errorf("Parse:\n%s\nwant\n%s", got, tc.want)
}
if gotLog := wlog.String(); gotLog != tc.wantLog {
t.Errorf("Parse: log = %s wantLog %s", gotLog, tc.wantLog)