1use crate::docs::markdown::MarkdownRenderer;
2use crate::SpecChoices;
3use indexmap::IndexMap;
4use serde::Serialize;
5
6#[derive(Debug, Clone, serde::Serialize)]
7pub struct Spec {
8 pub name: String,
9 pub bin: String,
10 pub cmd: SpecCommand,
11 pub version: Option<String>,
13 pub usage: String,
14 pub source_code_link_template: Option<String>,
16 pub author: Option<String>,
17 pub about: Option<String>,
18 pub about_long: Option<String>,
19 pub about_md: Option<String>,
20 pub disable_help: Option<bool>,
21 pub min_usage_version: Option<String>,
22 pub rendered: bool,
23}
24
25#[derive(Debug, Serialize, Clone)]
26pub struct SpecCommand {
27 pub full_cmd: Vec<String>,
28 pub usage: String,
29 pub subcommands: IndexMap<String, SpecCommand>,
30 pub args: Vec<SpecArg>,
31 pub flags: Vec<SpecFlag>,
32 pub deprecated: Option<String>,
34 pub hide: bool,
35 pub subcommand_required: bool,
36 pub help: Option<String>,
37 pub help_long: Option<String>,
38 pub help_md: Option<String>,
39 pub name: String,
40 pub aliases: Vec<String>,
41 pub hidden_aliases: Vec<String>,
42 pub before_help: Option<String>,
43 pub before_help_long: Option<String>,
44 pub before_help_md: Option<String>,
45 pub after_help: Option<String>,
46 pub after_help_long: Option<String>,
47 pub after_help_md: Option<String>,
48 pub examples: Vec<SpecExample>,
49 pub rendered: bool,
51}
52
53#[derive(Debug, Default, Clone, Serialize)]
54pub struct SpecFlag {
55 pub name: String,
56 pub usage: String,
57 pub help: Option<String>,
58 pub help_long: Option<String>,
59 pub help_md: Option<String>,
60 pub help_first_line: Option<String>,
61 pub short: Vec<char>,
62 pub long: Vec<String>,
63 pub required: bool,
64 pub deprecated: Option<String>,
65 pub var: bool,
66 pub hide: bool,
67 pub global: bool,
68 pub count: bool,
69 pub arg: Option<SpecArg>,
70 pub default: Option<String>,
71 pub negate: Option<String>,
72 pub rendered: bool,
73}
74
75#[derive(Debug, Default, Serialize, Clone)]
76pub struct SpecExample {
77 pub code: String,
78 pub header: Option<String>,
79 pub help: Option<String>,
80 pub lang: String,
81 pub rendered: bool,
82}
83
84#[derive(Debug, Default, Clone, Serialize)]
85pub struct SpecArg {
86 pub name: String,
87 pub usage: String,
88 pub help: Option<String>,
89 pub help_long: Option<String>,
90 pub help_md: Option<String>,
91 pub help_first_line: Option<String>,
92 pub required: bool,
93 pub var: bool,
94 pub var_min: Option<usize>,
95 pub var_max: Option<usize>,
96 pub hide: bool,
97 pub default: Option<String>,
98 pub choices: Option<SpecChoices>,
99 pub rendered: bool,
100}
101
102impl From<crate::Spec> for Spec {
103 fn from(spec: crate::Spec) -> Self {
104 Self {
105 name: spec.name,
106 bin: spec.bin,
107 cmd: SpecCommand::from(&spec.cmd),
108 version: spec.version,
110 usage: spec.usage,
111 source_code_link_template: spec.source_code_link_template,
113 about: spec.about,
114 about_long: spec.about_long,
115 about_md: spec.about_md,
116 author: spec.author,
117 disable_help: spec.disable_help,
118 min_usage_version: spec.min_usage_version,
119 rendered: false,
120 }
121 }
122}
123
124impl From<&crate::SpecCommand> for SpecCommand {
125 fn from(cmd: &crate::SpecCommand) -> Self {
126 Self {
127 full_cmd: cmd.full_cmd.clone(),
128 usage: cmd.usage.clone(),
129 subcommands: cmd
130 .subcommands
131 .iter()
132 .map(|(k, v)| (k.clone(), SpecCommand::from(v)))
133 .collect(),
134 args: cmd.args.iter().map(SpecArg::from).collect(),
135 flags: cmd.flags.iter().map(SpecFlag::from).collect(),
136 deprecated: cmd.deprecated.clone(),
138 hide: cmd.hide,
139 subcommand_required: cmd.subcommand_required,
140 help: cmd.help.clone(),
141 help_long: cmd.help_long.clone(),
142 help_md: cmd.help_md.clone(),
143 name: cmd.name.clone(),
144 aliases: cmd.aliases.clone(),
145 hidden_aliases: cmd.hidden_aliases.clone(),
146 before_help: cmd.before_help.clone(),
147 before_help_long: cmd.before_help_long.clone(),
148 before_help_md: cmd.before_help_md.clone(),
149 after_help: cmd.after_help.clone(),
150 after_help_long: cmd.after_help_long.clone(),
151 after_help_md: cmd.after_help_md.clone(),
152 examples: cmd.examples.iter().map(SpecExample::from).collect(),
153 rendered: false,
155 }
156 }
157}
158
159impl From<&crate::SpecFlag> for SpecFlag {
160 fn from(flag: &crate::SpecFlag) -> Self {
161 Self {
162 name: flag.name.clone(),
163 usage: flag.usage.clone(),
164 help: flag.help.clone(),
165 help_long: flag.help_long.clone(),
166 help_md: flag.help_md.clone(),
167 help_first_line: flag.help_first_line.clone(),
168 short: flag.short.clone(),
169 long: flag.long.clone(),
170 required: flag.required,
171 deprecated: flag.deprecated.clone(),
172 var: flag.var,
173 hide: flag.hide,
174 global: flag.global,
175 count: flag.count,
176 arg: flag.arg.as_ref().map(SpecArg::from),
177 default: flag.default.clone(),
178 negate: flag.negate.clone(),
179 rendered: false,
180 }
181 }
182}
183
184impl From<&crate::spec::cmd::SpecExample> for SpecExample {
185 fn from(example: &crate::spec::cmd::SpecExample) -> Self {
186 Self {
187 code: example.code.clone(),
188 header: example.header.clone(),
189 help: example.help.clone(),
190 lang: example.lang.clone(),
191 rendered: false,
192 }
193 }
194}
195
196impl From<&crate::SpecArg> for SpecArg {
197 fn from(arg: &crate::SpecArg) -> Self {
198 Self {
199 name: arg.name.clone(),
200 usage: arg.usage.clone(),
201 help: arg.help.clone(),
202 help_long: arg.help_long.clone(),
203 help_md: arg.help_md.clone(),
204 help_first_line: arg.help_first_line.clone(),
205 required: arg.required,
206 var: arg.var,
207 var_min: arg.var_min,
208 var_max: arg.var_max,
209 hide: arg.hide,
210 default: arg.default.clone(),
211 choices: arg.choices.clone(),
212 rendered: false,
213 }
214 }
215}
216
217impl Spec {
218 pub fn render_md(&mut self, renderer: &MarkdownRenderer) {
219 if self.rendered {
220 return;
221 }
222 self.rendered = true;
223 if let Some(h) = &mut self.about_md {
224 *h = renderer.replace_code_fences(h.to_string());
225 }
226 self.cmd.render_md(renderer);
227 }
228}
229
230impl SpecCommand {
231 pub fn all_subcommands(&self) -> Vec<&SpecCommand> {
232 let mut cmds = vec![];
233 for cmd in self.subcommands.values() {
234 cmds.push(cmd);
235 cmds.extend(cmd.all_subcommands());
236 }
237 cmds
238 }
239
240 pub fn render_md(&mut self, renderer: &MarkdownRenderer) {
241 if self.rendered {
242 return;
243 }
244 self.rendered = true;
245 if self.before_help_md.is_none() {
246 if let Some(h) = self.before_help_long.clone().or(self.before_help.clone()) {
247 self.before_help_md = Some(renderer.replace_code_fences(h));
248 }
249 }
250 if self.help_md.is_none() {
251 if let Some(h) = self.help_long.clone().or(self.help.clone()) {
252 self.help_md = Some(renderer.replace_code_fences(h));
253 }
254 }
255 if self.after_help_md.is_none() {
256 if let Some(h) = self.after_help_long.clone().or(self.after_help.clone()) {
257 self.after_help_md = Some(renderer.replace_code_fences(h));
258 }
259 }
260 for flag in &mut self.flags {
261 flag.render_md(renderer);
262 }
263 for arg in &mut self.args {
264 arg.render_md(renderer);
265 }
266 for example in &mut self.examples {
267 example.render_md(renderer);
268 }
269 for cmd in self.subcommands.values_mut() {
270 cmd.render_md(renderer);
271 }
272 }
273}
274
275impl SpecFlag {
276 pub fn render_md(&mut self, renderer: &MarkdownRenderer) {
277 if self.rendered {
278 return;
279 }
280 self.rendered = true;
281 if self.help_md.is_none() {
282 if let Some(h) = self.help_long.clone().or(self.help.clone()) {
283 self.help_md = Some(renderer.replace_code_fences(h));
284 }
285 }
286 }
287}
288
289impl SpecArg {
290 pub fn render_md(&mut self, renderer: &MarkdownRenderer) {
291 if self.rendered {
292 return;
293 }
294 self.rendered = true;
295 if self.help_md.is_none() {
296 if let Some(h) = self.help_long.clone().or(self.help.clone()) {
297 self.help_md = Some(renderer.replace_code_fences(h));
298 }
299 }
300 }
301}
302
303impl SpecExample {
304 pub fn render_md(&mut self, renderer: &MarkdownRenderer) {
305 if self.rendered {
306 return;
307 }
308 self.rendered = true;
309 if let Some(h) = self.help.clone() {
310 self.help = Some(renderer.replace_code_fences(h));
311 }
312 }
313}