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}