Skip to content

Commit affed94

Browse files
committed
Add help summaries.
1 parent 9e8c2c7 commit affed94

2 files changed

Lines changed: 164 additions & 2 deletions

File tree

src/help-generator_.toit

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@ It finds the selected command and prints its help.
1616
*/
1717
help-command_ path/Path arguments/List --ui/Ui:
1818
command/Command := path.last
19+
show-all := false
1920

2021
for i := 0; i < arguments.size; i++:
2122
argument := arguments[i]
2223
if argument == "--": break
2324

24-
// Simply drop all options.
25+
if argument == "--all":
26+
show-all = true
27+
continue
28+
29+
// Simply drop all other options.
2530
if argument.starts-with "-":
2631
continue
2732

@@ -32,7 +37,24 @@ help-command_ path/Path arguments/List --ui/Ui:
3237
command = subcommand
3338
path += command
3439

35-
emit-help_ path --ui=ui
40+
if show-all:
41+
emit-help-all_ path --ui=ui
42+
else:
43+
emit-help_ path --ui=ui
44+
45+
/**
46+
Emits the help for all commands in the subtree rooted at the given command.
47+
48+
The command is identified by the $path where the command is the last element.
49+
*/
50+
emit-help-all_ path/Path --ui/Ui:
51+
ui.emit --kind=Ui.RESULT
52+
--structured=:
53+
build-json-help-all_ path
54+
--text=:
55+
generator := HelpGenerator path
56+
generator.build-all-commands
57+
generator.to-string
3658

3759
/**
3860
Emits the help for the given command.
@@ -48,6 +70,35 @@ emit-help_ path/Path --ui/Ui:
4870
generator.build-all
4971
generator.to-string
5072

73+
build-json-help-all_ path/Path -> Map:
74+
return build-json-command-tree_ path.last --is-root=(path.size == 1)
75+
76+
build-json-command-tree_ command/Command --is-root/bool=false -> Map:
77+
sub-list := []
78+
sorted := command.subcommands_.sort: | a/Command b/Command | a.name.compare-to b.name
79+
sorted.do: | sub/Command |
80+
if sub.is-hidden_: continue.do
81+
sub-list.add (build-json-command-tree_ sub)
82+
83+
if is-root:
84+
has-help := false
85+
has-completion := false
86+
command.subcommands_.do: | sub/Command |
87+
if sub.name == "help": has-help = true
88+
sub.aliases_.do: if it == "help": has-help = true
89+
if sub.name == "completion": has-completion = true
90+
sub.aliases_.do: if it == "completion": has-completion = true
91+
if not has-help:
92+
sub-list.add {"name": "help", "help": "Show help for a command.", "subcommands": []}
93+
if not has-completion:
94+
sub-list.add {"name": "completion", "help": "Generate shell completion scripts.", "subcommands": []}
95+
96+
return {
97+
"name": command.name,
98+
"help": command.short-help,
99+
"subcommands": sub-list,
100+
}
101+
51102
build-json-help_ path/Path -> Map:
52103
// Local block to build json objects for the given command.
53104
// Adds the converted json object to the out-map.
@@ -254,6 +305,53 @@ class HelpGenerator:
254305
sorted-commands := commands-and-help.sort: | a/List b/List | a[0].compare-to b[0]
255306
write-table_ sorted-commands --indentation=2
256307

308+
/**
309+
Builds a hierarchical summary of all commands in the subtree.
310+
311+
Recursively lists all subcommands with indentation showing nesting.
312+
Hidden commands are excluded. At root level, auto-added 'help' and
313+
'completion' entries are included.
314+
*/
315+
build-all-commands -> none:
316+
rows := []
317+
collect-commands-recursive_ command_ rows --indent=0 --is-root=is-root-command_
318+
if rows.is-empty: return
319+
write-table_ rows
320+
321+
/**
322+
Collects all commands recursively into $rows as [indented-name, short-help] pairs.
323+
*/
324+
collect-commands-recursive_ command/Command rows/List --indent/int --is-root/bool=false -> none:
325+
// Each entry is [name, help, subcommand-or-null].
326+
entries := []
327+
command.subcommands_.do: | subcommand/Command |
328+
if subcommand.is-hidden_: continue.do
329+
entries.add [subcommand.name, subcommand.short-help, subcommand]
330+
331+
if is-root:
332+
has-help := false
333+
has-completion := false
334+
command.subcommands_.do: | sub/Command |
335+
if sub.name == "help": has-help = true
336+
sub.aliases_.do: if it == "help": has-help = true
337+
if sub.name == "completion": has-completion = true
338+
sub.aliases_.do: if it == "completion": has-completion = true
339+
if not has-help:
340+
entries.add ["help", "Show help for a command.", null]
341+
if not has-completion:
342+
entries.add ["completion", "Generate shell completion scripts.", null]
343+
344+
sorted := entries.sort: | a/List b/List |
345+
(a[0] as string).compare-to (b[0] as string)
346+
347+
prefix := " " * indent
348+
sorted.do: | entry/List |
349+
name := entry[0] as string
350+
help-str := entry[1] as string
351+
rows.add ["$prefix$name", help-str]
352+
if entry[2]:
353+
collect-commands-recursive_ (entry[2] as Command) rows --indent=(indent + 2)
354+
257355
/**
258356
Builds the local options section.
259357

tests/help_test.toit

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ main:
1616
test-options
1717
test-examples
1818
test-short-help
19+
test-help-all
1920

2021
check-output expected/string [block]:
2122
ui := TestUi
@@ -870,3 +871,66 @@ test-short-help:
870871
expected = "Test command."
871872
actual = cmd.short-help
872873
expect-equals expected actual
874+
875+
test-help-all:
876+
sub-sub := cli.Command "sub2"
877+
--help="Even more nested info."
878+
--run=:: null
879+
880+
sub1 := cli.Command "sub1"
881+
--help="Sub info."
882+
--subcommands=[sub-sub]
883+
884+
tool-foo := cli.Command "foo"
885+
--help="The foo tool."
886+
--run=:: null
887+
888+
tool-bar := cli.Command "bar"
889+
--help="The bar tool."
890+
--run=:: null
891+
892+
tool := cli.Command "tool"
893+
--help="Tools for xyz."
894+
--subcommands=[tool-foo, tool-bar]
895+
896+
hidden-cmd := cli.Command "secret"
897+
--help="Secret command."
898+
--hidden
899+
--run=:: null
900+
901+
execute := cli.Command "execute"
902+
--help="Runs toto."
903+
--run=:: null
904+
905+
root := cli.Command "root"
906+
--help="Root command."
907+
--subcommands=[tool, execute, sub1, hidden-cmd]
908+
909+
expected := """
910+
completion Generate shell completion scripts.
911+
execute Runs toto.
912+
help Show help for a command.
913+
sub1 Sub info.
914+
sub2 Even more nested info.
915+
tool Tools for xyz.
916+
bar The bar tool.
917+
foo The foo tool.
918+
"""
919+
check-output expected: | cli/cli.Cli |
920+
root.run ["help", "--all"] --cli=cli --invoked-command="bin/app"
921+
922+
// Test --all on a subcommand.
923+
expected = """
924+
bar The bar tool.
925+
foo The foo tool.
926+
"""
927+
check-output expected: | cli/cli.Cli |
928+
root.run ["help", "--all", "tool"] --cli=cli --invoked-command="bin/app"
929+
930+
// Test --all on a leaf command (no subcommands).
931+
expected = ""
932+
ui := TestUi
933+
cli-obj := cli.Cli "test" --ui=ui
934+
root.run ["help", "--all", "execute"] --cli=cli-obj --invoked-command="bin/app"
935+
all-output := ui.stdout + ui.stderr
936+
expect-equals (expected + "\n") all-output

0 commit comments

Comments
 (0)