1 | module cli |
2 | |
3 | import time |
4 | |
5 | fn man_flag() Flag { |
6 | return Flag{ |
7 | flag: .bool |
8 | name: 'man' |
9 | description: 'Prints the auto-generated manpage.' |
10 | } |
11 | } |
12 | |
13 | fn man_cmd() Command { |
14 | return Command{ |
15 | name: 'man' |
16 | usage: '<subcommand>' |
17 | description: 'Prints the auto-generated manpage.' |
18 | execute: print_manpage_for_command |
19 | } |
20 | } |
21 | |
22 | // print_manpage_for_command prints the manpage for the |
23 | // command or subcommand in `man_cmd` to stdout |
24 | pub fn print_manpage_for_command(man_cmd Command) ! { |
25 | if man_cmd.args.len > 0 { |
26 | mut cmd := man_cmd.parent |
27 | for arg in man_cmd.args { |
28 | mut found := false |
29 | for sub_cmd in cmd.commands { |
30 | if sub_cmd.name == arg { |
31 | cmd = unsafe { &sub_cmd } |
32 | found = true |
33 | break |
34 | } |
35 | } |
36 | if !found { |
37 | args := man_cmd.args.join(' ') |
38 | println('Invalid command: ${args}') |
39 | return |
40 | } |
41 | } |
42 | print(cmd.manpage()) |
43 | } else { |
44 | if unsafe { man_cmd.parent != 0 } { |
45 | print(man_cmd.parent.manpage()) |
46 | } |
47 | } |
48 | } |
49 | |
50 | // manpage returns a `string` containing the mdoc(7) manpage for |
51 | // this `Command` |
52 | pub fn (cmd Command) manpage() string { |
53 | mut mdoc := '.Dd ${time.now().strftime('%B %d, %Y')}\n' |
54 | mdoc += '.Dt ${cmd.full_name().replace(' ', '-').to_upper()} 1\n' |
55 | mdoc += '.Os\n.Sh NAME\n.Nm ${cmd.full_name().replace(' ', '-')}\n.Nd ${cmd.description}\n' |
56 | mdoc += '.Sh SYNOPSIS\n' |
57 | mdoc += '.Nm ${cmd.root().name}\n' |
58 | if unsafe { cmd.parent != 0 } { |
59 | mut parents := []Command{} |
60 | if !cmd.parent.is_root() { |
61 | parents.prepend(cmd.parent) |
62 | for { |
63 | p := parents[0] |
64 | if p.parent.is_root() { |
65 | break |
66 | } else { |
67 | parents.prepend(p.parent) |
68 | } |
69 | } |
70 | for c in parents { |
71 | mdoc += '.Ar ${c.name}\n' |
72 | } |
73 | } |
74 | mdoc += '.Ar ${cmd.name}\n' |
75 | } |
76 | for flag in cmd.flags { |
77 | mdoc += '.Op' |
78 | if flag.abbrev != '' { |
79 | mdoc += ' Fl ${flag.abbrev}' |
80 | } else { |
81 | if cmd.posix_mode { |
82 | mdoc += ' Fl -${flag.name}' |
83 | } else { |
84 | mdoc += ' Fl ${flag.name}' |
85 | } |
86 | } |
87 | match flag.flag { |
88 | .int, .float, .int_array, .float_array { mdoc += ' Ar num' } |
89 | .string, .string_array { mdoc += ' Ar string' } |
90 | else {} |
91 | } |
92 | mdoc += '\n' |
93 | } |
94 | for i in 0 .. cmd.required_args { |
95 | mdoc += '.Ar arg${i}\n' |
96 | } |
97 | if cmd.commands.len > 0 { |
98 | mdoc += '.Nm ${cmd.root().name}\n' |
99 | if unsafe { cmd.parent != 0 } { |
100 | mut parents := []Command{} |
101 | if !cmd.parent.is_root() { |
102 | parents.prepend(cmd.parent) |
103 | for { |
104 | p := parents[0] |
105 | if p.parent.is_root() { |
106 | break |
107 | } else { |
108 | parents.prepend(p.parent) |
109 | } |
110 | } |
111 | for c in parents { |
112 | mdoc += '.Ar ${c.name}\n' |
113 | } |
114 | } |
115 | mdoc += '.Ar ${cmd.name}\n' |
116 | } |
117 | mdoc += '.Ar subcommand\n' |
118 | } |
119 | |
120 | mdoc += '.Sh DESCRIPTION\n' |
121 | if cmd.man_description != '' { |
122 | mdoc += '${cmd.man_description}\n' |
123 | } else if cmd.description != '' { |
124 | mdoc += '${cmd.description}\n' |
125 | } |
126 | if cmd.flags.len > 0 { |
127 | mdoc += '.Pp\nThe options are as follows:\n' |
128 | mdoc += '.Bl -tag -width indent\n' |
129 | for flag in cmd.flags { |
130 | mdoc += '.It' |
131 | if flag.abbrev != '' { |
132 | mdoc += ' Fl ${flag.abbrev}' |
133 | } |
134 | if cmd.posix_mode { |
135 | mdoc += ' Fl -${flag.name}' |
136 | } else { |
137 | mdoc += ' Fl ${flag.name}' |
138 | } |
139 | mdoc += '\n' |
140 | if flag.description != '' { |
141 | mdoc += '${flag.description}\n' |
142 | } |
143 | } |
144 | mdoc += '.El\n' |
145 | } |
146 | if cmd.commands.len > 0 { |
147 | mdoc += '.Pp\nThe subcommands are as follows:\n' |
148 | mdoc += '.Bl -tag -width indent\n' |
149 | for c in cmd.commands { |
150 | mdoc += '.It Cm ${c.name}\n' |
151 | if c.description != '' { |
152 | mdoc += '${c.description}\n' |
153 | } |
154 | } |
155 | mdoc += '.El\n' |
156 | } |
157 | |
158 | if cmd.commands.len > 0 { |
159 | mdoc += '.Sh SEE ALSO\n' |
160 | mut cmds := []string{} |
161 | if unsafe { cmd.parent != 0 } { |
162 | cmds << cmd.parent.full_name().replace(' ', '-') |
163 | } |
164 | for c in cmd.commands { |
165 | cmds << c.full_name().replace(' ', '-') |
166 | } |
167 | cmds.sort() |
168 | mut i := 1 |
169 | for c in cmds { |
170 | mdoc += '.Xr ${c} 1' |
171 | if i == cmds.len { |
172 | mdoc += '\n' |
173 | } else { |
174 | mdoc += ' ,\n' |
175 | } |
176 | i++ |
177 | } |
178 | } |
179 | |
180 | return mdoc |
181 | } |