improve definition sentences in docs

This commit is contained in:
Arpad Ryszka 2026-01-07 21:43:12 +01:00
parent d88d4cf2fc
commit 07f334cb9e
8 changed files with 101 additions and 79 deletions

View File

@ -10,7 +10,7 @@ lib: $(sources) iniparser.gen.go docreflect.gen.go
go build
go build ./tools
build: lib .build/wand cmd/wand/readme.md
build: lib .build/wand .build/wand.1 cmd/wand/readme.md
check: $(sources) build docreflect_test.go
go test -count 1 ./...
@ -69,6 +69,10 @@ install: .build/wand .build/wand.1 $(prefix)/bin $(prefix)/share/man/man1
cp .build/wand $(prefix)/bin
cp .build/wand.1 $(prefix)/share/man/man1
uninstall:
rm $(prefix)/bin/wand
rm $(prefix)/share/man/man1/wand.1
clean:
go clean ./...
rm -rf .build

View File

@ -9,7 +9,7 @@ var version = "dev"
func main() {
docreflect := Command("docreflect", tools.Docreflect)
man := Command("manpages", tools.Man)
man := Command("man", tools.Man)
md := Command("markdown", tools.Markdown)
exec := Command("exec", tools.Exec)
wand := Group("wand", docreflect, man, md, Default(exec))

View File

@ -9,7 +9,7 @@ wand <subcommand>
## Description:
Exec executes a Go function expression parameterized by the subsequent command line arguments.
executes a Go function expression parameterized by the subsequent command line arguments.
It has two modes. When called with arguments, the first argument must be the function expression, and the rest
of the arguments the command line flags and positional arguments. When no arguments are provided, it starts
@ -19,17 +19,17 @@ executing the input expressions until the input is closed (Ctrl+D).
## Options:
- --cache-dir, -d string: CacheDir specifies a custom cache dir for wand. Default: ~/.wand.
- --clear-cache, -c bool: ClearCache clears the cached artifacts resulting from a previous execution before the
current execution.
- --import string \[\*\]: Import lists the packages required for the expression to be executed. It accepts
versioned package specifications, or it uses the latest version. When a package spec is prefixed with alias=
or .=, it will import the for the expression with the specified alias or inline.
- --no-cache, -f bool: NoCache causes the execution to avoid relying on the cached artifacts resulting from a
previous execution.
- --replace-module string \[\*\]: ReplaceModule replaces imported go modules with local or other versions of the
given modules. The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit
-replace command.
- --cache-dir, -d string: specifies a custom cache dir for wand. Default: ~/.wand.
- --clear-cache, -c bool: clears the cached artifacts resulting from a previous execution before the current
execution.
- --import string \[\*\]: lists the packages required for the expression to be executed. It accepts versioned
package specifications, or it uses the latest version. When a package spec is prefixed with alias= or .=, it
will import the for the expression with the specified alias or inline.
- --no-cache, -f bool: causes the execution to avoid relying on the cached artifacts resulting from a previous
execution.
- --replace-module string \[\*\]: replaces imported go modules with local or other versions of the given modules.
The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit -replace
command.
- --help: Show help.
Hints:
@ -55,8 +55,8 @@ wand docreflect <subcommand>
#### Description:
Docreflect generates documentation from the go docs of a package to be included in the compiled binary and
accessed by the automatic help and documentation generator.
generates documentation from the go docs of a package to be included in the compiled binary and accessed by the
automatic help and documentation generator.
The packageName parameter specifies the package name for the generated Go code.
@ -67,24 +67,24 @@ recommended to use package paths unless special circumstances.
- --help: Show help.
### wand manpages
### wand man
#### Synopsis:
```
wand manpages [options]... [--] <commandDir string>
wand manpages <subcommand>
wand man [options]... [--] <commandDir string>
wand man <subcommand>
```
#### Description:
Man generates a man page in roff format for a command defined with wand. It relies on the go doc entries
extracted by Docreflect.
generates a man page in roff format for a command defined with wand. It relies on the go doc entries extracted
by Docreflect.
#### Options:
- --date-string string: DateString provides the value for the release date field in a man page.
- --version string: Version provides the value for the release version field in a man page.
- --date-string string: provides the value for the release date field in a man page.
- --version string: provides the value for the release version field in a man page.
- --help: Show help.
### wand markdown
@ -98,12 +98,12 @@ wand markdown <subcommand>
#### Description:
Man generates a markdown page for a command defined with wand. It relies on the go doc entries extracted by
generates a markdown page for a command defined with wand. It relies on the go doc entries extracted by
Docreflect.
#### Options:
- --level int: Level provides a default title level offset for the titles in a markdown document.
- --level int: provides a default title level offset for the titles in a markdown document.
- --help: Show help.
### wand exec (default)
@ -117,7 +117,7 @@ wand exec <subcommand>
#### Description:
Exec executes a Go function expression parameterized by the subsequent command line arguments.
executes a Go function expression parameterized by the subsequent command line arguments.
It has two modes. When called with arguments, the first argument must be the function expression, and the rest
of the arguments the command line flags and positional arguments. When no arguments are provided, it starts
@ -127,17 +127,17 @@ executing the input expressions until the input is closed (Ctrl+D).
#### Options:
- --cache-dir, -d string: CacheDir specifies a custom cache dir for wand. Default: ~/.wand.
- --clear-cache, -c bool: ClearCache clears the cached artifacts resulting from a previous execution before the
current execution.
- --import string \[\*\]: Import lists the packages required for the expression to be executed. It accepts
versioned package specifications, or it uses the latest version. When a package spec is prefixed with alias=
or .=, it will import the for the expression with the specified alias or inline.
- --no-cache, -f bool: NoCache causes the execution to avoid relying on the cached artifacts resulting from a
previous execution.
- --replace-module string \[\*\]: ReplaceModule replaces imported go modules with local or other versions of the
given modules. The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit
-replace command.
- --cache-dir, -d string: specifies a custom cache dir for wand. Default: ~/.wand.
- --clear-cache, -c bool: clears the cached artifacts resulting from a previous execution before the current
execution.
- --import string \[\*\]: lists the packages required for the expression to be executed. It accepts versioned
package specifications, or it uses the latest version. When a package spec is prefixed with alias= or .=, it
will import the for the expression with the specified alias or inline.
- --no-cache, -f bool: causes the execution to avoid relying on the cached artifacts resulting from a previous
execution.
- --replace-module string \[\*\]: replaces imported go modules with local or other versions of the given modules.
The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit -replace
command.
- --help: Show help.
### wand version

View File

@ -20,7 +20,7 @@ func init() {
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.ManOptions", "ManOptions represents input options for generating man pages for a command created with wand.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.ManOptions.DateString", "DateString provides the value for the release date field in a man page.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.ManOptions.Version", "Version provides the value for the release version field in a man page.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.Markdown", "Man generates a markdown page for a command defined with wand. It relies on the go doc entries extracted by\nDocreflect.\n\nfunc(out, o, commandDir)")
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.Markdown", "Markdown generates a markdown page for a command defined with wand. It relies on the go doc entries extracted by\nDocreflect.\n\nfunc(out, o, commandDir)")
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.MarkdownOptions", "MarkdownOptions represents input options for generating markdown documents for a command created with wand.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.MarkdownOptions.Level", "Level provides a default title level offset for the titles in a markdown document.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/tools.commandReader", "\nfunc(in)")

View File

@ -2,22 +2,21 @@
Generated with https://code.squareroundforest.org/arpio/docreflect
*/
package wand
import "code.squareroundforest.org/arpio/docreflect"
func init() {
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib", "")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Bar", "\nfunc(out, a, b, c)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Baz", "\nfunc(o)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.CustomHelp", "\nfunc(o)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Foo", "Foo sums three numbers.\nIt prints the sum to stdout.\n\nThe input numbers can be any integer.\n\nfunc(a, b, c)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.OptionWithHelp", "")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.OptionWithHelp.Help", "Custom help.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options", "")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Bar", "Bars, any number.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Duration", "Duration is another option.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Foo", "Foo is an option.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Some", "Some is an option of any type.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Time", "Time is the third option here.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib", "")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Bar", "\nfunc(out, a, b, c)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Baz", "\nfunc(o)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.CustomHelp", "\nfunc(o)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Foo", "Foo sums three numbers.\nIt prints the sum to stdout.\n\nThe input numbers can be any integer.\n\nfunc(a, b, c)")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.OptionWithHelp", "")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.OptionWithHelp.Help", "Custom help.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options", "")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Bar", "Bars, any number.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Duration", "Duration is another option.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Foo", "Foo is an option.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Some", "Some is an option of any type.\n")
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib.Options.Time", "Time is the third option here.\n")
}

21
help.go
View File

@ -225,10 +225,25 @@ func implementationCommand(cmd Cmd) Cmd {
return cmd
}
func trimName(doc, name string) string {
firstWord, rest, found := strings.Cut(doc, " ")
if !found {
return doc
}
firstWord = strings.TrimSpace(firstWord)
if strcase.ToKebab(firstWord) != strcase.ToKebab(name) {
return doc
}
return strings.TrimSpace(rest)
}
func docCommandNameText(cmd Cmd, fullCommand []string) []string {
command := strings.Join(fullCommand, " ")
fdoc := docreflect.Function(reflect.ValueOf(cmd.impl))
fdoc = strings.TrimSpace(fdoc)
fdoc = trimName(fdoc, cmd.name)
fdocp := paragraphs(fdoc)
if len(fdocp) == 0 {
return []string{command}
@ -338,6 +353,7 @@ func docs(cmd Cmd) []Entry {
fdoc := docreflect.Function(reflect.ValueOf(implCmd.impl))
fdoc = strings.TrimSpace(fdoc)
fdoc = trimName(fdoc, implCmd.name)
fdocp := paragraphs(fdoc)
if len(fdocp) == 0 {
return nil
@ -362,7 +378,9 @@ func docOptions(cmd Cmd, conf Config, titleLevel, wrapWidth, hintStyle int) []En
for _, fi := range f {
fields[fi.Name()] = append(fields[fi.Name()], fi)
if d := docs[fi.Name()]; d == "" {
docs[fi.Name()] = docreflect.Field(s, fi.Path()...)
fdocs := docreflect.Field(s, fi.Path()...)
fdocs = trimName(fdocs, fi.Name())
docs[fi.Name()] = fdocs
}
}
}
@ -575,6 +593,7 @@ func docListSubcommands(cmd Cmd, fullCommand []string, level, wrapWidth int) []E
hasNonHelp = true
description = docreflect.Function(reflect.ValueOf(sc.impl))
description = strings.TrimSpace(description)
description = trimName(description, sc.name)
descriptionP := paragraphs(description)
if len(descriptionP) > 0 {
description = firstSentence(descriptionP[0])

View File

@ -255,10 +255,10 @@ Synopsis:
Options:
--bar string [*]: Bars, any number.
--duration duration: Duration is another option.
--foo int: Foo is an option.
--some any: Some is an option of any type.
--time time: Time is the third option here.
--duration duration: is another option.
--foo int: is an option.
--some any: is an option of any type.
--time time: is the third option here.
--help: Show help.
Hints:
@ -284,10 +284,10 @@ Synopsis:
Options:
--bar string [*]: Bars, any number.
--duration duration: Duration is another option.
--foo int: Foo is an option.
--some any: Some is an option of any type.
--time time: Time is the third option here.
--duration duration: is another option.
--foo int: is an option.
--some any: is an option of any type.
--time time: is the third option here.
--help: Show help.
Hints:
@ -425,14 +425,14 @@ Subcommands:
})
t.Run("description", func(t *testing.T) {
const expect = `foo - Foo sums three numbers
const expect = `foo - sums three numbers
Synopsis:
foo [options]... [--] <a int> <b int> <c int>
foo <subcommand>
Foo sums three numbers. It prints the sum to stdout.
sums three numbers. It prints the sum to stdout.
The input numbers can be any integer.
@ -515,7 +515,7 @@ Options:
Subcommands:
foo: Foo sums three numbers
foo: sums three numbers
help: Show help.
version: Show version information.
@ -543,7 +543,7 @@ func TestMan(t *testing.T) {
.sp 1v
.in 4
.ti 4
foo - Foo sums three numbers
foo - sums three numbers
.br
.sp 1v
.in 0
@ -564,7 +564,7 @@ foo - Foo sums three numbers
.sp 1v
.in 4
.ti 4
Foo sums three numbers. It prints the sum to stdout.
sums three numbers. It prints the sum to stdout.
.br
.sp 1v
.in 4
@ -965,19 +965,19 @@ foo
.br
.in 25
.ti 4
--duration duration:\~Duration is another option.
--duration duration:\~is another option.
.br
.in 25
.ti 4
--foo int:\~\~\~\~\~\~\~\~\~\~\~Foo is an option.
--foo int:\~\~\~\~\~\~\~\~\~\~\~is an option.
.br
.in 25
.ti 4
--some any:\~\~\~\~\~\~\~\~\~\~Some is an option of any type.
--some any:\~\~\~\~\~\~\~\~\~\~is an option of any type.
.br
.in 25
.ti 4
--time time:\~\~\~\~\~\~\~\~\~Time is the third option here.
--time time:\~\~\~\~\~\~\~\~\~is the third option here.
.br
.in 25
.ti 4
@ -1647,7 +1647,7 @@ Config files marked as optional don't need to be present in the file system, but
func TestMarkdown(t *testing.T) {
t.Run("basic", func(t *testing.T) {
const expect = `# foo - Foo sums three numbers
const expect = `# foo - sums three numbers
## Synopsis:
@ -1658,7 +1658,7 @@ foo <subcommand>
## Description:
Foo sums three numbers. It prints the sum to stdout.
sums three numbers. It prints the sum to stdout.
The input numbers can be any integer.
@ -1738,10 +1738,10 @@ foo <subcommand>
## Options:
- --bar string \[\*\]: Bars, any number.
- --duration duration: Duration is another option.
- --foo int: Foo is an option.
- --some any: Some is an option of any type.
- --time time: Time is the third option here.
- --duration duration: is another option.
- --foo int: is an option.
- --some any: is an option of any type.
- --time time: is the third option here.
- --config: Configuration file.
- --help: Show help.

View File

@ -72,7 +72,7 @@ func Man(out io.Writer, o ManOptions, commandDir string) error {
)
}
// Man generates a markdown page for a command defined with wand. It relies on the go doc entries extracted by
// Markdown generates a markdown page for a command defined with wand. It relies on the go doc entries extracted by
// Docreflect.
func Markdown(out io.Writer, o MarkdownOptions, commandDir string) error {
return execCommandDir(