aboutsummaryrefslogtreecommitdiffhomepage
path: root/command
diff options
context:
space:
mode:
Diffstat (limited to 'command')
-rw-r--r--command/builder.go1
-rw-r--r--command/builder_test.go20
-rw-r--r--command/command.go32
-rw-r--r--command/command_test.go (renamed from command/unreachable_test.go)0
-rw-r--r--command/node.go5
-rw-r--r--command/wrap.go14
6 files changed, 48 insertions, 24 deletions
diff --git a/command/builder.go b/command/builder.go
index c0782c66..d3b0c3f5 100644
--- a/command/builder.go
+++ b/command/builder.go
@@ -13,6 +13,7 @@ func New(output io.Writer, logf LogFunc, name string, early HandlerFunc) Command
return c
}
+// newNode initialises a subcommand tree and returns its address.
func newNode(output io.Writer, logf LogFunc, name, usage string) *node {
n := &node{
name: name, usage: usage,
diff --git a/command/builder_test.go b/command/builder_test.go
index 7b9a1701..05e29358 100644
--- a/command/builder_test.go
+++ b/command/builder_test.go
@@ -18,8 +18,14 @@ func TestBuild(t *testing.T) {
t.Run("direct zero length", func(t *testing.T) {
wantPanic := "invalid subcommand"
- t.Run("zero length name", func(t *testing.T) { defer checkRecover(t, "Command", wantPanic); c.Command("", "usage", stubHandler) })
- t.Run("zero length usage", func(t *testing.T) { defer checkRecover(t, "Command", wantPanic); c.Command("name", "", stubHandler) })
+ t.Run("zero length name", func(t *testing.T) {
+ defer checkRecover(t, "Command", wantPanic)
+ c.Command("", "usage", stubHandler)
+ })
+ t.Run("zero length usage", func(t *testing.T) {
+ defer checkRecover(t, "Command", wantPanic)
+ c.Command("name", "", stubHandler)
+ })
})
t.Run("direct adopt unique names", func(t *testing.T) {
@@ -34,8 +40,14 @@ func TestBuild(t *testing.T) {
t.Run("zero length", func(t *testing.T) {
wantPanic := "invalid subcommand tree"
- t.Run("zero length name", func(t *testing.T) { defer checkRecover(t, "New", wantPanic); c.New("", "usage") })
- t.Run("zero length usage", func(t *testing.T) { defer checkRecover(t, "New", wantPanic); c.New("name", "") })
+ t.Run("zero length name", func(t *testing.T) {
+ defer checkRecover(t, "New", wantPanic)
+ c.New("", "usage")
+ })
+ t.Run("zero length usage", func(t *testing.T) {
+ defer checkRecover(t, "New", wantPanic)
+ c.New("name", "")
+ })
})
t.Run("direct adopt unique names", func(t *testing.T) {
diff --git a/command/command.go b/command/command.go
index 5533c4ef..f3b699bc 100644
--- a/command/command.go
+++ b/command/command.go
@@ -6,36 +6,43 @@ import (
"strings"
)
-// UsageInternal causes the command to be hidden from help text when set as the usage string.
-const UsageInternal = "internal"
+// UsageInternal is a special usage string that hides the command from the
+// generated help message.
+const UsageInternal = "\x00"
type (
// HandlerFunc is called when matching a directly handled subcommand tree.
HandlerFunc = func(args []string) error
- // LogFunc is the function signature of a printf function.
+ // LogFunc is the function signature of a printf function. The zero value
+ // implies [log.Printf].
LogFunc = func(format string, a ...any)
- // FlagDefiner is a deferred flag definer value, usually encapsulating the default value.
+ // FlagDefiner is a deferred flag definer value, usually encapsulating the
+ // default value.
FlagDefiner interface {
// Define defines the flag in set.
Define(b *strings.Builder, set *flag.FlagSet, p any, name, usage string)
}
+ // A Flag is satisfied by command objects capable of receiving flags.
Flag[T any] interface {
// Flag defines a generic flag type in Node's flag set.
Flag(p any, name string, value FlagDefiner, usage string) T
}
+ // A Command is the root of a command tree.
Command interface {
Parse(arguments []string) error
- // MustParse determines exit outcomes for Parse errors
- // and calls handleError if [HandlerFunc] returns a non-nil error.
+ // MustParse determines exit outcomes for Parse errors and calls
+ // handleError if [HandlerFunc] returns a non-nil error.
MustParse(arguments []string, handleError func(error))
baseNode[Command]
}
+
+ // A Node is a subcommand under a [Command].
Node baseNode[Node]
baseNode[T any] interface {
@@ -53,3 +60,16 @@ type (
Flag[T]
}
)
+
+// rootNode satisfies baseNode for [Command].
+type rootNode struct{ *node }
+
+func (r rootNode) Command(name, usage string, f HandlerFunc) Command {
+ r.node.Command(name, usage, f)
+ return r
+}
+
+func (r rootNode) Flag(p any, name string, value FlagDefiner, usage string) Command {
+ r.node.Flag(p, name, value, usage)
+ return r
+}
diff --git a/command/unreachable_test.go b/command/command_test.go
index 9e8c19c9..9e8c19c9 100644
--- a/command/unreachable_test.go
+++ b/command/command_test.go
diff --git a/command/node.go b/command/node.go
index 4d09c975..b6f84bf8 100644
--- a/command/node.go
+++ b/command/node.go
@@ -6,6 +6,7 @@ import (
"strings"
)
+// A node represents a command.
type node struct {
child, next *node
name, usage string
@@ -13,13 +14,16 @@ type node struct {
out io.Writer
logf LogFunc
+ // Names of commands preceding node.
prefix []string
+ // Short user-facing representations of flags received by node.
suffix strings.Builder
f HandlerFunc
set *flag.FlagSet
}
+// adopt adds v as the last child of n.
func (n *node) adopt(v *node) bool {
if n.child != nil {
return n.child.append(v)
@@ -28,6 +32,7 @@ func (n *node) adopt(v *node) bool {
return true
}
+// append adds v as the last sibling of n.
func (n *node) append(v *node) bool {
if n.name == v.name {
return false
diff --git a/command/wrap.go b/command/wrap.go
deleted file mode 100644
index ee08a61a..00000000
--- a/command/wrap.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package command
-
-// the top level node wants [Command] returned for its builder methods
-type rootNode struct{ *node }
-
-func (r rootNode) Command(name, usage string, f HandlerFunc) Command {
- r.node.Command(name, usage, f)
- return r
-}
-
-func (r rootNode) Flag(p any, name string, value FlagDefiner, usage string) Command {
- r.node.Flag(p, name, value, usage)
- return r
-}