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
go build ./tools 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 check: $(sources) build docreflect_test.go
go test -count 1 ./... 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 $(prefix)/bin
cp .build/wand.1 $(prefix)/share/man/man1 cp .build/wand.1 $(prefix)/share/man/man1
uninstall:
rm $(prefix)/bin/wand
rm $(prefix)/share/man/man1/wand.1
clean: clean:
go clean ./... go clean ./...
rm -rf .build rm -rf .build

View File

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

View File

@ -9,7 +9,7 @@ wand <subcommand>
## Description: ## 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 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 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: ## Options:
- --cache-dir, -d string: CacheDir specifies a custom cache dir for wand. Default: ~/.wand. - --cache-dir, -d string: 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 - --clear-cache, -c bool: clears the cached artifacts resulting from a previous execution before the current
current execution. execution.
- --import string \[\*\]: Import lists the packages required for the expression to be executed. It accepts - --import string \[\*\]: lists the packages required for the expression to be executed. It accepts versioned
versioned package specifications, or it uses the latest version. When a package spec is prefixed with alias= package specifications, or it uses the latest version. When a package spec is prefixed with alias= or .=, it
or .=, it will import the for the expression with the specified alias or inline. 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 - --no-cache, -f bool: causes the execution to avoid relying on the cached artifacts resulting from a previous
previous execution. execution.
- --replace-module string \[\*\]: ReplaceModule replaces imported go modules with local or other versions of the - --replace-module string \[\*\]: replaces imported go modules with local or other versions of the given modules.
given modules. The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit -replace
-replace command. command.
- --help: Show help. - --help: Show help.
Hints: Hints:
@ -55,8 +55,8 @@ wand docreflect <subcommand>
#### Description: #### Description:
Docreflect generates documentation from the go docs of a package to be included in the compiled binary and generates documentation from the go docs of a package to be included in the compiled binary and accessed by the
accessed by the automatic help and documentation generator. automatic help and documentation generator.
The packageName parameter specifies the package name for the generated Go code. 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. - --help: Show help.
### wand manpages ### wand man
#### Synopsis: #### Synopsis:
``` ```
wand manpages [options]... [--] <commandDir string> wand man [options]... [--] <commandDir string>
wand manpages <subcommand> wand man <subcommand>
``` ```
#### Description: #### Description:
Man generates a man page in roff format for a command defined with wand. It relies on the go doc entries generates a man page in roff format for a command defined with wand. It relies on the go doc entries extracted
extracted by Docreflect. by Docreflect.
#### Options: #### Options:
- --date-string string: DateString provides the value for the release date field in a man page. - --date-string string: 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. - --version string: provides the value for the release version field in a man page.
- --help: Show help. - --help: Show help.
### wand markdown ### wand markdown
@ -98,12 +98,12 @@ wand markdown <subcommand>
#### Description: #### 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. Docreflect.
#### Options: #### 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. - --help: Show help.
### wand exec (default) ### wand exec (default)
@ -117,7 +117,7 @@ wand exec <subcommand>
#### Description: #### 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 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 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: #### Options:
- --cache-dir, -d string: CacheDir specifies a custom cache dir for wand. Default: ~/.wand. - --cache-dir, -d string: 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 - --clear-cache, -c bool: clears the cached artifacts resulting from a previous execution before the current
current execution. execution.
- --import string \[\*\]: Import lists the packages required for the expression to be executed. It accepts - --import string \[\*\]: lists the packages required for the expression to be executed. It accepts versioned
versioned package specifications, or it uses the latest version. When a package spec is prefixed with alias= package specifications, or it uses the latest version. When a package spec is prefixed with alias= or .=, it
or .=, it will import the for the expression with the specified alias or inline. 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 - --no-cache, -f bool: causes the execution to avoid relying on the cached artifacts resulting from a previous
previous execution. execution.
- --replace-module string \[\*\]: ReplaceModule replaces imported go modules with local or other versions of the - --replace-module string \[\*\]: replaces imported go modules with local or other versions of the given modules.
given modules. The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit The format of the items is: \<module-path\>=\<replacement-module-path\>, like for the go mod edit -replace
-replace command. command.
- --help: Show help. - --help: Show help.
### wand version ### 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", "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.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.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", "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.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)") 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 Generated with https://code.squareroundforest.org/arpio/docreflect
*/ */
package wand package wand
import "code.squareroundforest.org/arpio/docreflect" import "code.squareroundforest.org/arpio/docreflect"
func init() { func init() {
docreflect.Register("code.squareroundforest.org/arpio/wand/internal/tests/testlib", "") 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.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.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.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.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", "")
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.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", "")
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.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.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.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.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.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 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 { func docCommandNameText(cmd Cmd, fullCommand []string) []string {
command := strings.Join(fullCommand, " ") command := strings.Join(fullCommand, " ")
fdoc := docreflect.Function(reflect.ValueOf(cmd.impl)) fdoc := docreflect.Function(reflect.ValueOf(cmd.impl))
fdoc = strings.TrimSpace(fdoc) fdoc = strings.TrimSpace(fdoc)
fdoc = trimName(fdoc, cmd.name)
fdocp := paragraphs(fdoc) fdocp := paragraphs(fdoc)
if len(fdocp) == 0 { if len(fdocp) == 0 {
return []string{command} return []string{command}
@ -338,6 +353,7 @@ func docs(cmd Cmd) []Entry {
fdoc := docreflect.Function(reflect.ValueOf(implCmd.impl)) fdoc := docreflect.Function(reflect.ValueOf(implCmd.impl))
fdoc = strings.TrimSpace(fdoc) fdoc = strings.TrimSpace(fdoc)
fdoc = trimName(fdoc, implCmd.name)
fdocp := paragraphs(fdoc) fdocp := paragraphs(fdoc)
if len(fdocp) == 0 { if len(fdocp) == 0 {
return nil return nil
@ -362,7 +378,9 @@ func docOptions(cmd Cmd, conf Config, titleLevel, wrapWidth, hintStyle int) []En
for _, fi := range f { for _, fi := range f {
fields[fi.Name()] = append(fields[fi.Name()], fi) fields[fi.Name()] = append(fields[fi.Name()], fi)
if d := docs[fi.Name()]; d == "" { 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 hasNonHelp = true
description = docreflect.Function(reflect.ValueOf(sc.impl)) description = docreflect.Function(reflect.ValueOf(sc.impl))
description = strings.TrimSpace(description) description = strings.TrimSpace(description)
description = trimName(description, sc.name)
descriptionP := paragraphs(description) descriptionP := paragraphs(description)
if len(descriptionP) > 0 { if len(descriptionP) > 0 {
description = firstSentence(descriptionP[0]) description = firstSentence(descriptionP[0])

View File

@ -255,10 +255,10 @@ Synopsis:
Options: Options:
--bar string [*]: Bars, any number. --bar string [*]: Bars, any number.
--duration duration: Duration is another option. --duration duration: is another option.
--foo int: Foo is an option. --foo int: is an option.
--some any: Some is an option of any type. --some any: is an option of any type.
--time time: Time is the third option here. --time time: is the third option here.
--help: Show help. --help: Show help.
Hints: Hints:
@ -284,10 +284,10 @@ Synopsis:
Options: Options:
--bar string [*]: Bars, any number. --bar string [*]: Bars, any number.
--duration duration: Duration is another option. --duration duration: is another option.
--foo int: Foo is an option. --foo int: is an option.
--some any: Some is an option of any type. --some any: is an option of any type.
--time time: Time is the third option here. --time time: is the third option here.
--help: Show help. --help: Show help.
Hints: Hints:
@ -425,14 +425,14 @@ Subcommands:
}) })
t.Run("description", func(t *testing.T) { t.Run("description", func(t *testing.T) {
const expect = `foo - Foo sums three numbers const expect = `foo - sums three numbers
Synopsis: Synopsis:
foo [options]... [--] <a int> <b int> <c int> foo [options]... [--] <a int> <b int> <c int>
foo <subcommand> 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. The input numbers can be any integer.
@ -515,7 +515,7 @@ Options:
Subcommands: Subcommands:
foo: Foo sums three numbers foo: sums three numbers
help: Show help. help: Show help.
version: Show version information. version: Show version information.
@ -543,7 +543,7 @@ func TestMan(t *testing.T) {
.sp 1v .sp 1v
.in 4 .in 4
.ti 4 .ti 4
foo - Foo sums three numbers foo - sums three numbers
.br .br
.sp 1v .sp 1v
.in 0 .in 0
@ -564,7 +564,7 @@ foo - Foo sums three numbers
.sp 1v .sp 1v
.in 4 .in 4
.ti 4 .ti 4
Foo sums three numbers. It prints the sum to stdout. sums three numbers. It prints the sum to stdout.
.br .br
.sp 1v .sp 1v
.in 4 .in 4
@ -965,19 +965,19 @@ foo
.br .br
.in 25 .in 25
.ti 4 .ti 4
--duration duration:\~Duration is another option. --duration duration:\~is another option.
.br .br
.in 25 .in 25
.ti 4 .ti 4
--foo int:\~\~\~\~\~\~\~\~\~\~\~Foo is an option. --foo int:\~\~\~\~\~\~\~\~\~\~\~is an option.
.br .br
.in 25 .in 25
.ti 4 .ti 4
--some any:\~\~\~\~\~\~\~\~\~\~Some is an option of any type. --some any:\~\~\~\~\~\~\~\~\~\~is an option of any type.
.br .br
.in 25 .in 25
.ti 4 .ti 4
--time time:\~\~\~\~\~\~\~\~\~Time is the third option here. --time time:\~\~\~\~\~\~\~\~\~is the third option here.
.br .br
.in 25 .in 25
.ti 4 .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) { func TestMarkdown(t *testing.T) {
t.Run("basic", func(t *testing.T) { t.Run("basic", func(t *testing.T) {
const expect = `# foo - Foo sums three numbers const expect = `# foo - sums three numbers
## Synopsis: ## Synopsis:
@ -1658,7 +1658,7 @@ foo <subcommand>
## Description: ## 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. The input numbers can be any integer.
@ -1738,10 +1738,10 @@ foo <subcommand>
## Options: ## Options:
- --bar string \[\*\]: Bars, any number. - --bar string \[\*\]: Bars, any number.
- --duration duration: Duration is another option. - --duration duration: is another option.
- --foo int: Foo is an option. - --foo int: is an option.
- --some any: Some is an option of any type. - --some any: is an option of any type.
- --time time: Time is the third option here. - --time time: is the third option here.
- --config: Configuration file. - --config: Configuration file.
- --help: Show help. - --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. // Docreflect.
func Markdown(out io.Writer, o MarkdownOptions, commandDir string) error { func Markdown(out io.Writer, o MarkdownOptions, commandDir string) error {
return execCommandDir( return execCommandDir(