usage/docs/
models.rs

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 config: SpecConfig,
12    pub version: Option<String>,
13    pub usage: String,
14    // pub complete: IndexMap<String, SpecComplete>,
15    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 mounts: Vec<SpecMount>,
33    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 complete: IndexMap<String, SpecComplete>,
50    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            // config: SpecConfig::from(&spec.config),
109            version: spec.version,
110            usage: spec.usage,
111            // complete: spec.complete,
112            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            // mounts: cmd.mounts.iter().map(SpecMount::from).collect(),
137            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            // complete: cmd.complete.clone(),
154            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}