diff --git a/cmd/hakurei/command_test.go b/cmd/hakurei/command_test.go index b90688e5..61374cd8 100644 --- a/cmd/hakurei/command_test.go +++ b/cmd/hakurei/command_test.go @@ -19,10 +19,9 @@ func TestHelp(t *testing.T) { want string }{ { - "main", []string{}, ` -Usage: hakurei [-h | --help] [-v] [--insecure] [--json] COMMAND [OPTIONS] + "main", []string{}, `usage: hakurei [-h | --help] [-v] [--insecure] [--json] [] -Commands: +commands: run Load and start container from configuration file exec Configure and start a permissive container show Show live or local instance configuration @@ -35,10 +34,14 @@ Commands: `, }, { - "exec", []string{"exec", "-h"}, ` -Usage: hakurei exec [-h | --help] [--dbus-config ] [--dbus-system ] [--mpris] [--dbus-log] [--id ] [-a ] [-g ] [-d ] [-u ] [--policy ] [--priority ] [--private-runtime] [--private-tmpdir] [--wayland] [-X] [--dbus] [--pipewire] [--pulse] COMMAND [OPTIONS] + "exec", []string{"exec", "-h"}, `usage: hakurei exec [-h | --help] [--dbus-config ] + [--dbus-system ] [--mpris] [--dbus-log] + [--id ] [-a ] [-g ] [-d ] + [-u ] [--policy ] [--priority ] + [--private-runtime] [--private-tmpdir] [--wayland] [-X] + [--dbus] [--pipewire] [--pulse] [] -Flags: +flags: -X Enable direct connection to X11 -a int Application identity 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 []\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] []\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] []\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 ] [--int ] [--repeat ] COMMAND [OPTIONS] + `usage: test [-h | --help] [-v] [--fail] [--string ] [--int ] + [--repeat ] [] -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 ] [--int ] [--repeat ] COMMAND [OPTIONS] + `usage: test [-h | --help] [-v] [--fail] [--string ] [--int ] + [--repeat ] [] -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] [] -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] [] -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] [] -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] [] -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)