argc/
param.rs

1use crate::parser::{is_choice_value_terminate, is_default_value_terminate};
2use crate::utils::{argc_var_name, escape_shell_words, sanitize_var_name, to_cobol_case, MAX_ARGS};
3use crate::ArgcValue;
4
5use anyhow::{bail, Result};
6use indexmap::IndexMap;
7use serde::Serialize;
8
9pub(crate) trait Param {
10    fn data(&self) -> &ParamData;
11    fn data_mut(&mut self) -> &mut ParamData;
12    fn id(&self) -> &str;
13    fn var_name(&self) -> String;
14    fn tag_name(&self) -> &str;
15    fn guard(&self) -> Result<()>;
16    fn multiple_values(&self) -> bool;
17    #[allow(unused)]
18    fn render_source(&self) -> String;
19
20    fn describe_oneline(&self) -> &str {
21        match self.describe().split_once('\n') {
22            Some((v, _)) => v,
23            None => self.describe(),
24        }
25    }
26    fn render_describe(&self) -> String {
27        self.data().render_describe(self.describe(), self.id())
28    }
29    fn describe(&self) -> &str {
30        &self.data().describe
31    }
32    fn describe_mut(&mut self) -> &mut String {
33        &mut self.data_mut().describe
34    }
35    fn required(&self) -> bool {
36        self.data().required()
37    }
38    fn delimiter(&self) -> Option<char> {
39        self.data().args_delimiter()
40    }
41    fn terminated(&self) -> bool {
42        self.data().terminated()
43    }
44    fn choice(&self) -> Option<&ChoiceValue> {
45        self.data().choice.as_ref()
46    }
47    fn choice_fn(&self) -> Option<(&String, &bool)> {
48        self.data().choice_fn()
49    }
50    fn choice_values(&self) -> Option<&Vec<String>> {
51        self.data().choice_values()
52    }
53    fn default(&self) -> Option<&DefaultValue> {
54        self.data().default.as_ref()
55    }
56    fn default_fn(&self) -> Option<&String> {
57        self.data().default_fn()
58    }
59    fn default_value(&self) -> Option<&String> {
60        self.data().default_value()
61    }
62    fn bind_env(&self) -> Option<String> {
63        self.data().normalize_bind_env(self.id())
64    }
65}
66
67#[derive(Debug, PartialEq, Eq, Clone)]
68pub(crate) struct FlagOptionParam {
69    data: ParamData,
70    id: String,
71    short: Option<String>,
72    long_prefix: String,
73    prefixed: bool,
74    assigned: bool,
75    raw_notations: Vec<String>,
76    notations: Vec<String>,
77    inherited: bool,
78}
79
80impl Param for FlagOptionParam {
81    fn data(&self) -> &ParamData {
82        &self.data
83    }
84
85    fn data_mut(&mut self) -> &mut ParamData {
86        &mut self.data
87    }
88
89    fn id(&self) -> &str {
90        &self.id
91    }
92
93    fn var_name(&self) -> String {
94        argc_var_name(self.id())
95    }
96
97    fn tag_name(&self) -> &str {
98        if self.is_flag() {
99            "@flag"
100        } else {
101            "@option"
102        }
103    }
104
105    fn guard(&self) -> Result<()> {
106        if self.notations.len() > 1 {
107            if self.assigned {
108                bail!("cannot combine assign and multiple notations")
109            }
110            if self.prefixed {
111                bail!("cannot combine prefix and multiple notations")
112            }
113            if self.delimiter().is_some() {
114                bail!("cannot combine delmiter and multiple notations")
115            }
116        }
117        if self.prefixed && self.bind_env().is_some() {
118            bail!("cannot bind env with prefixed options")
119        }
120        Ok(())
121    }
122
123    fn multiple_values(&self) -> bool {
124        self.data().multiple() || self.num_args().1 > 1
125    }
126
127    fn render_source(&self) -> String {
128        let mut output = vec![];
129        if let Some(short) = &self.short {
130            output.push(short.to_string());
131        };
132        let mut name_suffix = String::new();
133        if self.prefixed || self.data.name.ends_with('-') {
134            name_suffix.push('-');
135        }
136        if self.assigned || self.data.name.ends_with(':') {
137            name_suffix.push(':');
138        }
139        output.push(format!(
140            "{}{}",
141            self.long_prefix,
142            self.data.render_source_of_name_value(&name_suffix)
143        ));
144
145        if let Some(env) = &self.data.env {
146            match env {
147                Some(v) => output.push(format!("${v}")),
148                None => output.push("$$".into()),
149            }
150        }
151
152        for raw_notation in &self.raw_notations {
153            output.push(format!("<{raw_notation}>"));
154        }
155
156        if !self.data.describe.is_empty() {
157            output.push(self.data.describe.clone());
158        }
159
160        output.join(" ")
161    }
162}
163
164impl FlagOptionParam {
165    pub(crate) fn new(
166        mut data: ParamData,
167        flag: bool,
168        short: Option<&str>,
169        long_prefix: &str,
170        row_notations: &[&str],
171    ) -> Self {
172        let (mut prefixed, mut assigned) = (false, false);
173        if let Some(new_name) = data.name.strip_suffix("::") {
174            data.name = format!("{new_name}:");
175        } else if let Some(new_name) = data.name.strip_suffix(':') {
176            data.name = new_name.to_string();
177            assigned = true;
178        }
179        if let Some(new_name) = data.name.strip_suffix("--") {
180            data.name = format!("{new_name}-");
181        } else if let Some(new_name) = data.name.strip_suffix('-') {
182            data.name = new_name.to_string();
183            prefixed = true;
184        }
185        let name = data.name.clone();
186        let id = if long_prefix.starts_with('+') {
187            format!("plus_{name}")
188        } else {
189            name.clone()
190        };
191        let raw_notations: Vec<String> = row_notations.iter().map(|v| v.to_string()).collect();
192        let mut notations = if flag {
193            vec![]
194        } else if raw_notations.is_empty() {
195            vec![to_cobol_case(&name)]
196        } else {
197            raw_notations.iter().map(|v| to_cobol_case(v)).collect()
198        };
199        if data.terminated() {
200            let last_arg = notations.last_mut().unwrap();
201            last_arg.push('~')
202        }
203        Self {
204            short: short.map(|v| v.to_string()),
205            long_prefix: long_prefix.to_string(),
206            prefixed,
207            assigned,
208            data,
209            id,
210            raw_notations,
211            notations,
212            inherited: false,
213        }
214    }
215
216    #[cfg(feature = "export")]
217    pub(crate) fn export(&self) -> FlagOptionValue {
218        FlagOptionValue {
219            id: self.id().to_string(),
220            long_name: self.long_name(),
221            short_name: self.short.clone(),
222            describe: self.describe().to_string(),
223            flag: self.is_flag(),
224            notations: self.notations.clone(),
225            required: self.required(),
226            multiple_values: self.multiple_values(),
227            multiple_occurs: self.multiple_occurs(),
228            num_args: self.num_args(),
229            delimiter: self.delimiter(),
230            terminated: self.terminated(),
231            prefixed: self.prefixed,
232            assigned: self.assigned,
233            default: self.data().default.clone(),
234            choice: self.data().choice.clone(),
235            env: self.bind_env(),
236            inherited: self.inherited,
237        }
238    }
239
240    pub(crate) fn is_flag(&self) -> bool {
241        self.notations.is_empty()
242    }
243
244    pub(crate) fn is_option(&self) -> bool {
245        !self.is_flag()
246    }
247
248    pub(crate) fn assigned(&self) -> bool {
249        self.assigned
250    }
251
252    pub(crate) fn prefixed(&self) -> bool {
253        self.prefixed
254    }
255
256    pub(crate) fn short(&self) -> &Option<String> {
257        &self.short
258    }
259
260    pub(crate) fn long_prefix(&self) -> &str {
261        &self.long_prefix
262    }
263
264    pub(crate) fn notations(&self) -> &[String] {
265        &self.notations
266    }
267
268    pub(crate) fn multiple_occurs(&self) -> bool {
269        self.data().multiple()
270    }
271
272    pub(crate) fn num_args(&self) -> (usize, usize) {
273        let len = self.notations.len();
274        if self.terminated()
275            || self
276                .notation_modifier()
277                .map(|v| matches!(v, '*' | '+'))
278                .unwrap_or_default()
279        {
280            let min = if self.notation_modifier() == Some('*') {
281                len - 1
282            } else {
283                len
284            };
285            (min, MAX_ARGS)
286        } else if self.notation_modifier() == Some('?') {
287            (len - 1, len)
288        } else {
289            (len, len)
290        }
291    }
292
293    pub(crate) fn notation_modifier(&self) -> Option<char> {
294        self.notations
295            .last()
296            .and_then(|name| ['*', '+', '?'].into_iter().find(|v| name.ends_with(*v)))
297    }
298
299    pub(crate) fn long_name(&self) -> String {
300        format!("{}{}", self.long_prefix, self.data.name)
301    }
302
303    pub(crate) fn render_first_notation(&self) -> String {
304        format!("<{}>", self.notations[0])
305    }
306
307    pub(crate) fn render_name_notations(&self) -> String {
308        let mut output = self.long_name();
309        if !self.is_flag() {
310            let ch = if self.assigned { '=' } else { ' ' };
311            output.push(ch);
312            output.push_str(&self.render_notations());
313        }
314        output
315    }
316
317    pub(crate) fn render_notations(&self) -> String {
318        let mut list = vec![];
319        if self.notations.len() == 1 {
320            let name: &String = &self.notations[0];
321            let value = match (self.required(), self.multiple_occurs()) {
322                (true, true) => format!("<{name}>..."),
323                (false, true) => format!("[{name}]..."),
324                (_, false) => format!("<{name}>"),
325            };
326            list.push(value);
327        } else {
328            let values = self
329                .notations
330                .iter()
331                .map(|v| format!("<{v}>"))
332                .collect::<Vec<String>>();
333            list.extend(values);
334        }
335        list.join(" ")
336    }
337
338    pub(crate) fn render_body(&self) -> String {
339        let mut output = String::new();
340        if self.short.is_none() && self.long_prefix.len() == 1 && self.data.name.len() == 1 {
341            output.push_str(&self.long_name());
342        } else {
343            if let Some(short) = &self.short {
344                output.push_str(&format!("{short}, "))
345            } else {
346                output.push_str("    ")
347            };
348            output.push_str(&format!("{:>2}", self.long_prefix));
349            output.push_str(&self.data.name);
350        }
351
352        if self.is_flag() {
353            if self.multiple_occurs() {
354                output.push_str("...")
355            }
356        } else {
357            let ch = if self.assigned { '=' } else { ' ' };
358            output.push(ch);
359            output.push_str(&self.render_notations());
360        }
361        output
362    }
363
364    pub(crate) fn to_argc_value(&self, args: &[(&str, &[&str])]) -> Option<ArgcValue> {
365        let id = self.id().to_string();
366        if self.prefixed {
367            let mut map: IndexMap<String, Vec<String>> = IndexMap::new();
368            for (arg, value) in args {
369                if let Some(arg_suffix) = self
370                    .list_names()
371                    .into_iter()
372                    .find_map(|v| arg.strip_prefix(&v))
373                {
374                    let key = match arg_suffix.split_once('=') {
375                        Some((arg_suffix, _)) => arg_suffix,
376                        None => arg_suffix,
377                    };
378                    if let Some(values) = map.get_mut(key) {
379                        values.extend(value.iter().map(|v| v.to_string()));
380                    } else {
381                        map.insert(
382                            key.to_string(),
383                            value.iter().map(|v| v.to_string()).collect(),
384                        );
385                    }
386                }
387            }
388            if map.is_empty() {
389                None
390            } else {
391                Some(ArgcValue::Map(id, map))
392            }
393        } else {
394            let values: Vec<&[&str]> = args.iter().map(|(_, value)| *value).collect();
395            if self.is_flag() {
396                if values.is_empty() {
397                    None
398                } else {
399                    Some(ArgcValue::Single(id, values.len().to_string()))
400                }
401            } else {
402                if values.is_empty() {
403                    match &self.data.default {
404                        Some(DefaultValue::Value(value)) => {
405                            return Some(ArgcValue::Single(id, value.clone()));
406                        }
407                        Some(DefaultValue::Fn(f)) => {
408                            return Some(ArgcValue::SingleFn(id, f.clone()));
409                        }
410                        None => return None,
411                    }
412                }
413                if self.multiple_values() {
414                    let values: Vec<String> = values
415                        .iter()
416                        .flat_map(|v| v.iter().map(|v| v.to_string()))
417                        .collect();
418                    Some(ArgcValue::Multiple(id, values))
419                } else if self.notations.len() > 1 {
420                    Some(ArgcValue::Multiple(
421                        id,
422                        values[0].iter().map(|v| v.to_string()).collect(),
423                    ))
424                } else {
425                    Some(ArgcValue::Single(id, must_get_first(values[0])))
426                }
427            }
428        }
429    }
430
431    pub(crate) fn set_inherit(&mut self) {
432        self.inherited = true;
433    }
434
435    pub(crate) fn create_help_flag(short: Option<&str>, long_prefix: &str, describe: &str) -> Self {
436        let mut param_data = ParamData::new("help");
437        param_data.describe = describe.to_string();
438        FlagOptionParam::new(param_data, true, short, long_prefix, &[])
439    }
440
441    pub(crate) fn create_version_flag(
442        short: Option<&str>,
443        long_prefix: &str,
444        describe: &str,
445    ) -> Self {
446        let mut param_data = ParamData::new("version");
447        param_data.describe = describe.to_string();
448        FlagOptionParam::new(param_data, true, short, long_prefix, &[])
449    }
450
451    pub(crate) fn match_prefix<'a>(&self, arg: &'a str) -> Option<&'a str> {
452        if self.prefixed {
453            self.list_names().iter().find_map(|v| {
454                if arg.starts_with(v) {
455                    Some(&arg[..v.len()])
456                } else {
457                    None
458                }
459            })
460        } else {
461            None
462        }
463    }
464
465    pub(crate) fn is_match(&self, name: &str) -> bool {
466        self.id() == name
467            || self.list_names().iter().any(|v| {
468                if self.prefixed {
469                    name.starts_with(v)
470                } else {
471                    v == name
472                }
473            })
474    }
475
476    pub(crate) fn list_names(&self) -> Vec<String> {
477        let mut output = vec![];
478        output.push(self.long_name());
479        if let Some(short) = &self.short {
480            output.push(short.clone());
481        }
482        output
483    }
484}
485
486#[cfg(feature = "export")]
487#[derive(Debug, Serialize)]
488pub struct FlagOptionValue {
489    pub id: String,
490    pub long_name: String,
491    pub short_name: Option<String>,
492    pub describe: String,
493    pub flag: bool,
494    pub notations: Vec<String>,
495    pub required: bool,
496    pub multiple_values: bool,
497    pub multiple_occurs: bool,
498    pub num_args: (usize, usize),
499    pub delimiter: Option<char>,
500    pub terminated: bool,
501    pub prefixed: bool,
502    pub assigned: bool,
503    pub default: Option<DefaultValue>,
504    pub choice: Option<ChoiceValue>,
505    pub env: Option<String>,
506    pub inherited: bool,
507}
508
509#[derive(Debug, PartialEq, Eq, Clone)]
510pub(crate) struct PositionalParam {
511    data: ParamData,
512    raw_notation: Option<String>,
513    notation: String,
514}
515
516impl Param for PositionalParam {
517    fn data(&self) -> &ParamData {
518        &self.data
519    }
520
521    fn data_mut(&mut self) -> &mut ParamData {
522        &mut self.data
523    }
524
525    fn id(&self) -> &str {
526        &self.data().name
527    }
528
529    fn var_name(&self) -> String {
530        argc_var_name(self.id())
531    }
532
533    fn tag_name(&self) -> &str {
534        "@arg"
535    }
536
537    fn guard(&self) -> Result<()> {
538        Ok(())
539    }
540
541    fn multiple_values(&self) -> bool {
542        self.data.multiple() || self.terminated()
543    }
544
545    fn render_source(&self) -> String {
546        let mut output = vec![self.data.render_source_of_name_value("")];
547
548        if let Some(env) = &self.data.env {
549            match env {
550                Some(v) => output.push(format!("${v}")),
551                None => output.push("$$".into()),
552            }
553        }
554        if let Some(raw_notation) = self.raw_notation.as_ref() {
555            output.push(format!("<{raw_notation}>"));
556        }
557        if !self.data.describe.is_empty() {
558            output.push(self.data.describe.clone());
559        }
560        output.join(" ")
561    }
562}
563
564impl PositionalParam {
565    pub(crate) fn new(data: ParamData, raw_notation: Option<&str>) -> Self {
566        let name = data.name.clone();
567        PositionalParam {
568            data,
569            raw_notation: raw_notation.map(|v| v.to_string()),
570            notation: raw_notation
571                .or(Some(&name))
572                .map(to_cobol_case)
573                .unwrap_or_default(),
574        }
575    }
576
577    #[cfg(feature = "export")]
578    pub(crate) fn export(&self) -> PositionalValue {
579        PositionalValue {
580            id: self.id().to_string(),
581            describe: self.describe().to_string(),
582            notation: self.notation.clone(),
583            required: self.required(),
584            multiple: self.multiple_values(),
585            delimiter: self.delimiter(),
586            terminated: self.terminated(),
587            default: self.data().default.clone(),
588            choice: self.data().choice.clone(),
589            env: self.bind_env(),
590        }
591    }
592
593    pub(crate) fn notation(&self) -> &str {
594        &self.notation
595    }
596
597    pub(crate) fn render_notation(&self) -> String {
598        let name: &String = &self.notation;
599        match (self.required(), self.multiple_values()) {
600            (true, true) => format!("<{name}>..."),
601            (true, false) => format!("<{name}>"),
602            (false, true) => format!("[{name}]..."),
603            (false, false) => format!("[{name}]"),
604        }
605    }
606
607    pub(crate) fn to_argc_value(&self, values: &[&str]) -> Option<ArgcValue> {
608        let id = self.id().to_string();
609        if values.is_empty() {
610            match &self.data.default {
611                Some(DefaultValue::Value(value)) => {
612                    return Some(ArgcValue::PositionalSingle(id, value.clone()));
613                }
614                Some(DefaultValue::Fn(f)) => {
615                    return Some(ArgcValue::PositionalSingleFn(id, f.clone()));
616                }
617                None => return None,
618            }
619        }
620        if self.multiple_values() {
621            let values: Vec<String> = values.iter().map(|v| v.to_string()).collect();
622            Some(ArgcValue::PositionalMultiple(id, values))
623        } else {
624            Some(ArgcValue::PositionalSingle(id, must_get_first(values)))
625        }
626    }
627}
628
629#[cfg(feature = "export")]
630#[derive(Debug, Serialize)]
631pub struct PositionalValue {
632    pub id: String,
633    pub describe: String,
634    pub notation: String,
635    pub required: bool,
636    pub multiple: bool,
637    pub delimiter: Option<char>,
638    pub terminated: bool,
639    pub default: Option<DefaultValue>,
640    pub choice: Option<ChoiceValue>,
641    pub env: Option<String>,
642}
643
644#[derive(Debug, PartialEq, Eq, Clone)]
645pub(crate) struct EnvParam {
646    data: ParamData,
647    inherited: bool,
648}
649
650impl Param for EnvParam {
651    fn data(&self) -> &ParamData {
652        &self.data
653    }
654
655    fn data_mut(&mut self) -> &mut ParamData {
656        &mut self.data
657    }
658
659    fn id(&self) -> &str {
660        &self.data().name
661    }
662
663    fn var_name(&self) -> String {
664        self.id().to_string()
665    }
666
667    fn tag_name(&self) -> &str {
668        "@env"
669    }
670
671    fn guard(&self) -> Result<()> {
672        if !matches!(
673            self.data().modifier,
674            Modifier::Optional | Modifier::Required
675        ) {
676            bail!("can only be a single value")
677        }
678        if self.data.env.is_some() {
679            bail!("cannot bind another env")
680        }
681        Ok(())
682    }
683
684    fn multiple_values(&self) -> bool {
685        false
686    }
687
688    fn render_source(&self) -> String {
689        let mut output = vec![self.data.render_source_of_name_value("")];
690        if let Some(env) = &self.data.env {
691            match env {
692                Some(v) => output.push(format!("${v}")),
693                None => output.push("$$".into()),
694            }
695        }
696        if !self.data.describe.is_empty() {
697            output.push(self.data.describe.clone());
698        }
699        output.join(" ")
700    }
701}
702
703impl EnvParam {
704    pub(crate) fn new(data: ParamData) -> Self {
705        Self {
706            data,
707            inherited: false,
708        }
709    }
710
711    #[cfg(feature = "export")]
712    pub(crate) fn export(&self) -> EnvValue {
713        EnvValue {
714            id: self.id().to_string(),
715            describe: self.describe().to_string(),
716            required: self.required(),
717            default: self.data().default.clone(),
718            choice: self.data().choice.clone(),
719            inherited: self.inherited,
720        }
721    }
722
723    pub(crate) fn render_body(&self) -> String {
724        let marker = if self.required() { "*" } else { "" };
725        format!("{}{}", self.id(), marker)
726    }
727
728    pub(crate) fn get_env_value(&self) -> Option<ArgcValue> {
729        let id = self.id().to_string();
730        let default = self.data.default.clone()?;
731        let value = match default {
732            DefaultValue::Value(value) => ArgcValue::Env(id, value),
733            DefaultValue::Fn(value) => ArgcValue::EnvFn(id, value),
734        };
735        Some(value)
736    }
737
738    pub(crate) fn set_inherit(&mut self) {
739        self.inherited = true;
740    }
741}
742
743#[cfg(feature = "export")]
744#[derive(Debug, Serialize)]
745pub struct EnvValue {
746    pub id: String,
747    pub describe: String,
748    pub required: bool,
749    pub default: Option<DefaultValue>,
750    pub choice: Option<ChoiceValue>,
751    pub inherited: bool,
752}
753
754#[derive(Debug, PartialEq, Eq, Clone)]
755pub(crate) struct ParamData {
756    pub(crate) name: String,
757    pub(crate) describe: String,
758    pub(crate) choice: Option<ChoiceValue>,
759    pub(crate) default: Option<DefaultValue>,
760    pub(crate) modifier: Modifier,
761    pub(crate) env: Option<Option<String>>,
762}
763
764impl ParamData {
765    pub(crate) fn new(name: &str) -> Self {
766        Self {
767            name: name.to_string(),
768            describe: String::new(),
769            choice: None,
770            default: None,
771            modifier: Modifier::Optional,
772            env: None,
773        }
774    }
775
776    pub(crate) fn required(&self) -> bool {
777        self.modifier.required() && self.default.is_none()
778    }
779
780    pub(crate) fn multiple(&self) -> bool {
781        self.modifier.multiple()
782    }
783
784    pub(crate) fn args_delimiter(&self) -> Option<char> {
785        match &self.modifier {
786            Modifier::DelimiterRequired(c) | Modifier::DelimiterOptional(c) => Some(*c),
787            _ => None,
788        }
789    }
790
791    pub(crate) fn terminated(&self) -> bool {
792        matches!(self.modifier, Modifier::Terminated)
793    }
794
795    pub(crate) fn choice_fn(&self) -> Option<(&String, &bool)> {
796        match &self.choice {
797            Some(ChoiceValue::Fn(f, v)) => Some((f, v)),
798            _ => None,
799        }
800    }
801
802    pub(crate) fn choice_values(&self) -> Option<&Vec<String>> {
803        match &self.choice {
804            Some(ChoiceValue::Values(v)) => Some(v),
805            _ => None,
806        }
807    }
808
809    pub(crate) fn default_fn(&self) -> Option<&String> {
810        match &self.default {
811            Some(DefaultValue::Fn(f)) => Some(f),
812            _ => None,
813        }
814    }
815
816    pub(crate) fn default_value(&self) -> Option<&String> {
817        match &self.default {
818            Some(DefaultValue::Value(v)) => Some(v),
819            _ => None,
820        }
821    }
822
823    pub(crate) fn normalize_bind_env(&self, id: &str) -> Option<String> {
824        let env = match self.env.as_ref()? {
825            Some(v) => v.clone(),
826            None => sanitize_var_name(id).to_uppercase(),
827        };
828        Some(env)
829    }
830
831    #[allow(unused)]
832    pub(crate) fn render_source_of_name_value(&self, name_suffix: &str) -> String {
833        let mut output = format!("{}{name_suffix}", self.name);
834        output.push_str(&self.modifier.render());
835        match (&self.choice, &self.default) {
836            (Some(ChoiceValue::Values(values)), None) => {
837                output.push_str(&format!("[{}]", Self::render_choice_values(values)));
838            }
839            (Some(ChoiceValue::Values(values)), Some(DefaultValue::Value(_))) => {
840                output.push_str(&format!("[={}]", Self::render_choice_values(values)));
841            }
842            (Some(ChoiceValue::Fn(f, validate)), _) => {
843                let prefix = if *validate { "" } else { "?" };
844                output.push_str(&format!("[{prefix}`{f}`]"));
845            }
846            (None, Some(DefaultValue::Value(value))) => {
847                output.push_str(&format!("={}", Self::render_default_value(value)));
848            }
849            (None, Some(DefaultValue::Fn(f))) => {
850                output.push_str(&format!("=`{f}`"));
851            }
852            _ => {}
853        }
854        output
855    }
856
857    pub(crate) fn render_describe(&self, describe: &str, id: &str) -> String {
858        let mut output = describe.to_string();
859        let multiline = describe.contains('\n');
860        let mut documented = false;
861        let sep = if multiline { '\n' } else { ' ' };
862        if let Some(ChoiceValue::Values(values)) = &self.choice {
863            documented = values.iter().all(|v| describe.contains(v));
864            if !documented {
865                if !output.is_empty() {
866                    output.push(sep)
867                }
868                let values: Vec<String> = values.iter().map(|v| escape_shell_words(v)).collect();
869                output.push_str(&format!("[possible values: {}]", values.join(", ")));
870            }
871        }
872        if !documented {
873            if let Some(DefaultValue::Value(value)) = &self.default {
874                if !output.is_empty() {
875                    output.push(sep)
876                }
877                output.push_str(&format!("[default: {}]", escape_shell_words(value)));
878            }
879        }
880        if let Some(env) = self.normalize_bind_env(id) {
881            if !describe.contains(&env) && !output.is_empty() {
882                output.push(sep)
883            }
884            output.push_str(&format!("[env: {env}]"));
885        }
886        output
887    }
888
889    fn render_choice_values(values: &[String]) -> String {
890        let values: Vec<String> = values
891            .iter()
892            .map(|value| {
893                if value.chars().any(is_choice_value_terminate) {
894                    format!("\"{value}\"")
895                } else {
896                    value.to_string()
897                }
898            })
899            .collect();
900        values.join("|")
901    }
902
903    fn render_default_value(value: &str) -> String {
904        if value.chars().any(is_default_value_terminate) {
905            format!("\"{value}\"")
906        } else {
907            value.to_string()
908        }
909    }
910}
911
912#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
913#[serde(tag = "type", content = "value")]
914pub(crate) enum Modifier {
915    Optional,
916    Required,
917    MultipleOptional,
918    MultipleRequired,
919    DelimiterOptional(char),
920    DelimiterRequired(char),
921    Terminated,
922}
923
924impl Modifier {
925    pub(crate) fn multiple(&self) -> bool {
926        match self {
927            Self::Optional => false,
928            Self::Required => false,
929            Self::MultipleOptional => true,
930            Self::MultipleRequired => true,
931            Self::DelimiterOptional(_) => true,
932            Self::DelimiterRequired(_) => true,
933            Self::Terminated => false,
934        }
935    }
936
937    pub(crate) fn required(&self) -> bool {
938        match self {
939            Self::Optional => false,
940            Self::Required => true,
941            Self::MultipleOptional => false,
942            Self::MultipleRequired => true,
943            Self::DelimiterOptional(_) => false,
944            Self::DelimiterRequired(_) => true,
945            Self::Terminated => false,
946        }
947    }
948
949    #[allow(unused)]
950    pub(crate) fn render(&self) -> String {
951        match self {
952            Self::Optional => "".into(),
953            Self::Required => "!".into(),
954            Self::MultipleOptional => "*".into(),
955            Self::MultipleRequired => "+".into(),
956            Self::DelimiterOptional(c) => format!("*{c}"),
957            Self::DelimiterRequired(c) => format!("+{c}"),
958            Self::Terminated => "~".to_string(),
959        }
960    }
961}
962
963#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
964#[serde(tag = "type", content = "data")]
965pub enum ChoiceValue {
966    Values(Vec<String>),
967    Fn(String, bool),
968}
969
970#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
971#[serde(tag = "type", content = "value")]
972pub enum DefaultValue {
973    Value(String),
974    Fn(String),
975}
976
977fn must_get_first(value: &[&str]) -> String {
978    if value.is_empty() {
979        String::new()
980    } else {
981        value[0].to_string()
982    }
983}