1use crate::{
2 Action, Context, Flag, FlagValue, Parser, Vector,
3 action::{ActionError, ActionErrorKind::NoActionRegistered, ActionResult},
4 done,
5 parser::MiddleArg,
6};
7
8use core::mem::swap;
9use std::{collections::VecDeque, fmt::Debug};
10
11#[derive(Clone, Default, Debug)]
15pub struct Command {
16 pub name: String,
18 pub action: Option<Action>,
20 pub authors: String,
22 pub copyright: String,
24 pub license: License,
26 pub description: Option<String>,
28 pub usage: String,
30 pub l_flags: Vector<Flag>,
32 pub c_flags: Vector<Flag>,
34 pub alias: Vector<String>,
36 pub version: String,
38 pub sub: Vector<Command>,
40}
41
42macro_rules! run_result{
44 ()=>{
45 Result<ActionResult,ActionError>
46 }
47}
48macro_rules! no_registered_error {
50 ($command:expr,$context:expr) => {
51 Err(ActionError::without_related_error(
52 "no action is registered.".into(),
53 NoActionRegistered,
54 $command,
55 $context,
56 ))
57 };
58}
59macro_rules! check_sub {
61 ($sub:expr, $self:expr) => {
62 check_sub_field!($sub, $self, authors);
63 check_sub_field!($sub, $self, version);
64 check_sub_field!($sub, $self, copyright);
65 check_sub_field!($sub, $self, license: License);
66 };
67}
68macro_rules! check_sub_field {
70 ($sub: expr, $self:expr, $field: ident) => {
71 if $sub.$field.is_empty() {
72 swap(&mut $sub.$field, &mut $self.$field)
73 }
74 };
75 ($sub:expr, $self:expr,$field:ident :Option,) => {
76 if $sub.$field.is_none() {
77 swap(&mut $sub.$field, &mut $self.$field)
78 }
79 };
80 ($sub:expr, $self:expr,$field:ident :License) => {
81 if $sub.$field.is_none() {
82 swap(&mut $sub.$field, &mut $self.$field)
83 }
84 };
85}
86
87pub type LicenseFunc = fn(command: &Command, context: &Context) -> String;
89
90#[derive(Clone)]
91#[derive(Default)]
93pub struct License(pub Option<(String, LicenseFunc)>);
94
95impl Debug for License {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 if let License(Some(val)) = self {
98 write!(f, "Some({},Func for Output)", val.0)
99 } else {
100 write!(f, "None")
101 }
102 }
103}
104
105impl License {
106 pub fn new(inner: Option<(String, LicenseFunc)>) -> Self {
108 License(inner)
109 }
110 pub fn is_some(&self) -> bool {
112 matches!(*self, License(Some(_)))
113 }
114 pub fn is_none(&self) -> bool {
116 matches!(*self, License(None))
117 }
118 pub fn take(&mut self) -> Self {
120 core::mem::take(self)
121 }
122 pub fn expr(&self) -> Option<String> {
124 match self {
125 License(Some((expr, _))) => Some(expr.into()),
126 License(None) => None,
127 }
128 }
129 pub fn expr_unwrap(&self) -> String {
131 match self {
132 License(Some((expr, _))) => expr.clone(),
133 License(None) => panic!("called `License::expr_unwrap()` on a `None` value"),
134 }
135 }
136 pub fn output(&self, cmd: &Command, ctx: &Context) -> Option<String> {
138 match self {
139 License(Some((_, outputter))) => Some(outputter(cmd, ctx)),
140 License(None) => None,
141 }
142 }
143 pub fn output_unwrap(&self, cmd: &Command, ctx: &Context) -> String {
145 match self {
146 License(Some((_, outputter))) => outputter(cmd, ctx),
147 _ => panic!("called `License::expr_unwrap()` on a `None`value"),
148 }
149 }
150 pub fn output_fn(&self) -> Option<LicenseFunc> {
152 match self {
153 License(Some((_, outputter))) => Some(*outputter),
154 License(None) => None,
155 }
156 }
157 pub fn output_fn_unwrap(&self) -> LicenseFunc {
159 match self {
160 License(Some((_, outputter))) => *outputter,
161 _ => panic!("called `License::output_fn_wrap` on a `None` value"),
162 }
163 }
164 pub fn unwrap(self) -> (String, LicenseFunc) {
166 let License(inner) = self;
167 inner.unwrap()
168 }
169}
170
171macro_rules! gen_context_for_self_action {
173 ($raw_args:expr) => {{
174 let mut args = VecDeque::from($raw_args.clone());
175 let exe_path = args.pop_front().unwrap();
176 gen_context_for_self_action!($raw_args, args, exe_path)
177 }};
178 ($raw_args:expr,$args:expr,$exe_path:expr) => {
179 Context::new($raw_args, $args, Vector(None), Vector(None), $exe_path)
180 };
181 ($raw_args:expr,$args:expr,$exe_path:expr, $inter_mediate_args:expr) => {
182 Context::with_all_field(
183 $raw_args,
184 $args,
185 Vector(None),
186 $exe_path,
187 Vector(None),
188 Vector::default(),
189 Vector::default(),
190 Some($inter_mediate_args),
191 Vector(None),
192 )
193 };
194}
195
196macro_rules! gen_context_for_sub_run {
198 ($self:expr,$raw_args:expr,$args:expr,$exe_path:expr) => {
199 gen_context_for_sub_run!(inner, $self, $raw_args, $args, $exe_path, None)
200 };
201 ($self:expr,$raw_args:expr,$args:expr,$exe_path:expr, $inter_mediate_args: expr) => {
202 gen_context_for_sub_run!(
203 inner,
204 $self,
205 $raw_args,
206 $args,
207 $exe_path,
208 Some($inter_mediate_args)
209 )
210 };
211 (inner,$self:expr, $raw_args:expr,$args:expr,$exe_path:expr,$inter_mediate_args:expr) => {
212 Context::with_all_field(
213 $raw_args,
214 $args,
215 Vector::with_first_elem($self.c_flags.take()),
216 $exe_path,
217 $self.derive_route_init_vector(),
218 Vector::default(),
219 Vector::default(),
220 $inter_mediate_args,
221 Vector::default(),
222 )
223 };
224}
225
226impl Command {
227 pub fn new() -> Command {
229 Command::default()
230 }
231
232 pub fn with_base<T: Into<String>>(
234 name: T,
235 authors: T,
236 version: T,
237 description: T,
238 action: Option<Action>,
239 ) -> Command {
240 Command::with_all_field(
241 name.into(),
242 action,
243 authors.into(),
244 String::default(),
245 License(None),
246 Some(description.into()),
247 String::default(),
248 Vector::default(),
249 Vector::default(),
250 Vector::default(),
251 version.into(),
252 Vector::default(),
253 )
254 }
255
256 pub fn with_name<T: Into<String>>(name: T) -> Command {
258 Command {
259 name: name.into(),
260 action: None,
261 authors: String::default(),
262 copyright: String::default(),
263 license: License::default(),
264 description: None,
265 usage: String::default(),
266 l_flags: Vector::default(),
267 c_flags: Vector::default(),
268 alias: Vector::default(),
269 version: String::default(),
270 sub: Vector::default(),
271 }
272 }
273
274 #[allow(clippy::too_many_arguments)]
276 pub fn with_all_field(
277 name: String,
278 action: Option<Action>,
279 authors: String,
280 copyright: String,
281 license: License,
282 description: Option<String>,
283 usage: String,
284 local_flags: Vector<Flag>,
285 common_flags: Vector<Flag>,
286 alias: Vector<String>,
287 version: String,
288 sub: Vector<Command>,
289 ) -> Command {
290 Command {
291 name,
292 action,
293 authors,
294 copyright,
295 license,
296 description,
297 usage,
298 l_flags: local_flags,
299 c_flags: common_flags,
300 alias,
301 version,
302 sub,
303 }
304 }
305
306 pub fn run_with_auto_arg_collect(self) -> run_result!() {
308 match self.sub {
309 Vector(None) => self.single_run(std::env::args().collect::<Vec<String>>()),
310 _ => self.run(std::env::args().collect::<Vec<String>>()),
311 }
312 }
313
314 pub fn single_run(mut self, raw_args: Vec<String>) -> run_result!() {
318 match self.action.take() {
319 Some(action) => {
320 if raw_args.len() < 2 {
321 action(self, gen_context_for_self_action!(raw_args))
322 } else {
323 let mut context = gen_context_for_self_action!(raw_args);
324 context =
326 Parser::default().parse_args_until_end(&self.l_flags, &self.c_flags, context);
327 action(self, context)
328 }
329 }
330 None => match self.sub {
331 Vector(None) => {
332 let c = gen_context_for_self_action!(raw_args);
333 no_registered_error!(self, c)
334 }
335 _ => self.run(raw_args),
336 },
337 }
338 }
339
340 pub fn name<T: Into<String>>(mut self, name: T) -> Command {
342 self.name = name.into();
343 self
344 }
345
346 pub fn usage<T: Into<String>>(mut self, usage: T) -> Self {
348 self.usage = usage.into();
349 self
350 }
351
352 pub fn action(mut self, action: Action) -> Self {
354 self.action = Some(action);
355 self
356 }
357
358 pub fn authors<T: Into<String>>(mut self, authors: T) -> Self {
360 self.authors = authors.into();
361 self
362 }
363
364 pub fn copyright<T: Into<String>>(mut self, copyright: T) -> Self {
366 self.copyright = copyright.into();
367 self
368 }
369
370 pub fn local_flag(mut self, flag: Flag) -> Self {
372 self.l_flags.push(flag);
373 self
374 }
375
376 pub fn local_flags(mut self, flags: Vec<Flag>) -> Self {
378 self.l_flags.append_vec(flags);
379 self
380 }
381
382 pub fn common_flag(mut self, flag: Flag) -> Self {
384 self.c_flags.push(flag);
385 self
386 }
387
388 pub fn command_flags(mut self, flags: Vec<Flag>) -> Self {
390 self.c_flags.append_vec(flags);
391 self
392 }
393
394 pub fn description<T: Into<String>>(mut self, description: T) -> Self {
396 self.description = Some(description.into());
397 self
398 }
399
400 pub fn version<T: Into<String>>(mut self, version: T) -> Self {
402 self.version = version.into();
403 self
404 }
405
406 pub fn sub_command(mut self, sub_command: Command) -> Self {
408 self.sub.push(sub_command);
409 self
410 }
411
412 pub fn sub_commands(mut self, sub_commands: Vec<Command>) -> Self {
414 self.sub.append_vec(sub_commands);
415 self
416 }
417
418 pub fn license(mut self, license: License) -> Self {
420 self.license = license;
421 self
422 }
423
424 pub fn alias<T: Into<String>>(mut self, a: T) -> Self {
426 self.alias.push(a.into());
427 self
428 }
429
430 pub fn is(&self, name_or_alias: &str) -> bool {
433 if name_or_alias == self.name {
434 true
435 } else {
436 match self.alias.inner() {
437 None => false,
438 Some(inner) => inner.iter().any(|a| a == name_or_alias),
439 }
440 }
441 }
442
443 pub fn take_sub(&mut self, name_or_alias: &str) -> Option<Command> {
446 match self.sub {
447 Vector(None) => None,
448 Vector(Some(ref mut inner)) => inner
449 .iter()
450 .position(|c| c.is(name_or_alias))
451 .map(|index| inner.swap_remove(index)),
452 }
453 }
454
455 pub fn get_mut_sub(&mut self, name_or_alias: &str) -> Option<&mut Command> {
457 match self.sub {
458 Vector(None) => None,
459 Vector(Some(ref mut inner)) => match inner.iter().position(|c| c.is(name_or_alias)) {
460 None => None,
461 Some(index) => Some(inner.get_mut(index).unwrap()),
462 },
463 }
464 }
465
466 pub fn has_sub(&self) -> bool {
468 self.sub.has_inner_vec()
469 }
470
471 pub fn derive_route_init_vector(&self) -> Vector<String> {
473 if self.name.is_empty() {
474 Vector(None)
475 } else {
476 Vector(Some(vec![self.name.clone()]))
477 }
478 }
479}
480
481impl From<String> for Command {
482 fn from(name: String) -> Self {
483 Command {
484 name,
485 action: None,
486 authors: String::default(),
487 copyright: String::default(),
488 license: License::default(),
489 description: None,
490 usage: String::default(),
491 l_flags: Vector::default(),
492 c_flags: Vector::default(),
493 alias: Vector::default(),
494 version: String::default(),
495 sub: Vector::default(),
496 }
497 }
498}
499
500pub trait Run<T> {
502 fn run(self, args: T) -> run_result!();
504}
505
506impl Run<Vec<String>> for Command {
507 fn run(self, args: Vec<String>) -> run_result!() {
508 self.run_from_args(args)
509 }
510}
511
512impl Run<Context> for Command {
513 fn run(self, c: Context) -> run_result!() {
514 self.run_with_context(c)
515 }
516}
517
518impl Command {
519 pub fn run_from_args(mut self, raw_args: Vec<String>) -> run_result!() {
521 if self.sub.is_none() {
522 return self.single_run(raw_args);
523 }
524 let mut args = VecDeque::from(raw_args.clone());
525 let exe_path = args.pop_front().unwrap();
526 let head = args.pop_front();
527 if head.is_none() {
528 let c = gen_context_for_self_action!(raw_args, args, exe_path);
530 match self.action {
531 Some(action) => action(self, c),
532 None => no_registered_error!(self, c),
533 }
534 } else {
535 let p = Parser::default();
537 match head {
538 Some(long_flag) if p.long_flag(&long_flag) => {
539 let last = p.long_middle(long_flag);
541 self.assign_run(args, VecDeque::new(), p, raw_args, exe_path, last)
542 }
543 Some(short_flag) if p.flag(&short_flag) => {
544 let last = p.short_middle(short_flag);
546 self.assign_run(args, VecDeque::new(), p, raw_args, exe_path, last)
547 }
548 Some(arg) => {
549 match self.take_sub(&arg) {
550 None => {
551 args.push_front(arg);
553 let mut c = gen_context_for_self_action!(raw_args, args, exe_path);
554 match self.action {
555 None => no_registered_error!(self, c),
556 Some(action) => {
557 c = p.parse_args_until_end(&self.l_flags, &self.c_flags, c);
558 action(self, c)
559 }
560 }
561 }
562 Some(sub) => {
563 let c = gen_context_for_sub_run!(self, raw_args, args, exe_path);
565 let r = sub.run(c);
566 self.handle_sub_result(r)
568 }
569 }
570 }
571 _ => {
572 panic!("unexpected error");
574 }
575 }
576 }
577 }
578
579 pub fn run_with_context(mut self, mut context: Context) -> run_result!() {
581 if self.sub.is_none() {
582 let p = Parser::default();
584 let (mut context, non_flag_args) =
585 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, context, true);
586 if let Some(mut non_flag_args) = non_flag_args {
587 non_flag_args.append(&mut context.args);
588 context.args = non_flag_args;
589 }
590 context = p.parse_args_until_end(&self.l_flags, &self.c_flags, context);
591 match self.action {
592 Some(action) => action(self, context),
593 None => no_registered_error!(self, context),
594 }
595 } else {
596 let p = Parser::default();
598 match context.args.pop_front() {
599 Some(long_flag) if p.long_flag(&long_flag) => {
600 let last = p.long_middle(long_flag);
601 self.assign_context(context, p, VecDeque::new(), last)
602 }
603 Some(short_flag) if p.flag(&short_flag) => {
604 let last = p.short_middle(short_flag);
605 self.assign_context(context, p, VecDeque::new(), last)
606 }
607 Some(arg) => {
608 match self.take_sub(&arg) {
610 Some(mut sub) => {
611 context.common_flags.push(self.c_flags.take());
612 check_sub!(sub, self);
613 context.routes.push(self.name.clone());
614 let r = sub.run(context);
615 self.handle_sub_result(r)
616 }
617 None => match self.action {
618 None => no_registered_error!(self, context),
619 Some(action) => {
620 let c = match p.parse_inter_mediate_args(
621 &self.l_flags,
622 &self.c_flags,
623 context,
624 true,
625 ) {
626 (mut context, None) => {
627 context =
628 p.parse_args_until_end(&self.l_flags, &self.c_flags, context);
629 context.args.push_front(arg);
630 context
631 }
632 (mut context, Some(mut non_flag_args)) => {
633 context =
634 p.parse_args_until_end(&self.l_flags, &self.c_flags, context);
635 context.args.push_front(arg);
636 non_flag_args.append(&mut context.args);
637 context.args = non_flag_args;
638 context
639 }
640 };
641 action(self, c)
642 }
643 },
644 }
645 }
646 None => {
647 match self.action {
649 Some(action) => {
650 let (mut context, non_flag_args) =
651 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, context, true);
652 if let Some(mut non_flag_args) = non_flag_args {
653 non_flag_args.append(&mut context.args);
654 context.args = non_flag_args;
655 }
656 action(self, context)
657 }
658 None => {
659 let (mut context, non_flag_args) =
660 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, context, true);
661 if let Some(mut non_flag_args) = non_flag_args {
662 non_flag_args.append(&mut context.args);
663 context.args = non_flag_args;
664 }
665 no_registered_error!(self, context)
666 }
667 }
668 }
669 }
670 }
671 }
672
673 pub fn assign_context(
676 mut self,
677 mut c: Context,
678 p: Parser,
679 mut inter_mediate_args: VecDeque<MiddleArg>,
680 last: MiddleArg,
681 ) -> run_result!() {
682 let (next_non_flag, args, _inter_mediate_args, last) =
683 p.middle_parse(c.args, inter_mediate_args, last);
684 inter_mediate_args = _inter_mediate_args;
685 match next_non_flag {
687 Some(arg) => match self.take_sub(&arg) {
688 Some(mut sub) => {
689 c.common_flags.push(self.c_flags.take());
691 c.args = args;
692 inter_mediate_args.push_back(last);
693 if let Some(mut parsing_args) = c.parsing_args {
694 parsing_args.append(&mut inter_mediate_args);
695 c.parsing_args = Some(parsing_args);
696 } else {
697 c.parsing_args = Some(inter_mediate_args);
698 }
699 check_sub!(sub, self);
700 c.routes.push(self.name.clone());
701 let r = sub.run(c);
702 self.handle_sub_result(r)
703 }
704 None => match &last {
705 MiddleArg::LongFlag(_, FlagValue::None)
706 | MiddleArg::ShortFlag(_, FlagValue::None) => {
707 inter_mediate_args.push_back(last);
709 inter_mediate_args.push_back(MiddleArg::Normal(arg));
710 c.args = args;
711 match c.args.pop_front() {
712 Some(long_flag) if p.long_flag(&long_flag) => {
713 let last = p.long_middle(long_flag);
714 self.assign_context(c, p, inter_mediate_args, last)
715 }
716 Some(short_flag) if p.flag(&short_flag) => {
717 let last = p.short_middle(short_flag);
718 self.assign_context(c, p, inter_mediate_args, last)
719 }
720 Some(arg) => match self.take_sub(&arg) {
721 Some(mut sub) => {
722 c.common_flags.push(self.c_flags.take());
723 if let Some(mut parsing_args) = c.parsing_args {
724 parsing_args.append(&mut inter_mediate_args);
725 c.parsing_args = Some(parsing_args);
726 } else {
727 c.parsing_args = Some(inter_mediate_args);
728 }
729 c.routes.push(self.name.clone());
730 check_sub!(sub, self);
731 let r = sub.run(c);
732 self.handle_sub_result(r)
733 }
734 None => {
735 if let Some(mut parsing_args) = c.parsing_args {
736 parsing_args.append(&mut inter_mediate_args);
737 c.parsing_args = Some(parsing_args);
738 } else {
739 c.parsing_args = Some(inter_mediate_args);
740 }
741 let (mut c, non_flag_args) =
742 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, c, false);
743 c = p.parse_args_until_end(&self.l_flags, &self.c_flags, c);
744 c.args.push_front(arg);
745 if let Some(mut non_flag_args) = non_flag_args {
746 non_flag_args.append(&mut c.args);
747 c.args = non_flag_args;
748 }
749 match self.action {
750 Some(action) => action(self, c),
751 None => no_registered_error!(self, c),
752 }
753 }
754 },
755 None => {
756 if let Some(mut parsing_args) = c.parsing_args {
757 parsing_args.append(&mut inter_mediate_args);
758 c.parsing_args = Some(parsing_args);
759 } else {
760 c.parsing_args = Some(inter_mediate_args);
761 }
762 let (mut c, args) =
763 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, c, false);
764
765 if let Some(mut args) = args {
766 args.append(&mut c.args);
767 c.args = args;
768 }
769 match self.action {
770 Some(action) => action(self, c),
771 None => no_registered_error!(self, c),
772 }
773 }
774 }
775 }
776 _ => {
777 inter_mediate_args.push_back(last);
778 c.args = args;
779 if let Some(mut parsing_args) = c.parsing_args {
780 parsing_args.append(&mut inter_mediate_args);
781 c.parsing_args = Some(parsing_args);
782 }
783 let (mut c, non_flag_args) =
784 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, c, false);
785 c = p.parse_args_until_end(&self.l_flags, &self.c_flags, c);
786 c.args.push_front(arg);
787 if let Some(mut non_flag_args) = non_flag_args {
788 non_flag_args.append(&mut c.args);
789 c.args = non_flag_args;
790 }
791 match self.action {
792 Some(action) => action(self, c),
793 None => no_registered_error!(self, c),
794 }
795 }
796 },
797 },
798 None => {
799 inter_mediate_args.push_back(last);
800 c.args = args;
801 if let Some(mut parsing_args) = c.parsing_args {
802 parsing_args.append(&mut inter_mediate_args);
803 c.parsing_args = Some(parsing_args);
804 } else {
805 c.parsing_args = Some(inter_mediate_args);
806 }
807 let (mut c, non_flag_args) =
808 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, c, false);
809 if let Some(non_flag_args) = non_flag_args {
811 c.args = non_flag_args;
813 }
814 match self.action {
815 Some(action) => action(self, c),
816 None => no_registered_error!(self, c),
817 }
818 }
819 }
820 }
821
822 pub fn assign_run(
825 mut self,
826 mut args: VecDeque<String>,
827 mut inter_mediate_args: VecDeque<MiddleArg>,
828 p: Parser,
829 raw_args: Vec<String>,
830 exe_path: String,
831 last: MiddleArg,
832 ) -> run_result!() {
833 let (next_non_flag, _args, _inter_mediate_args, last) =
834 p.middle_parse(args, inter_mediate_args, last);
835 inter_mediate_args = _inter_mediate_args;
836 args = _args;
837 match next_non_flag {
838 Some(arg) => {
839 match self.take_sub(&arg) {
840 Some(sub) => {
841 inter_mediate_args.push_back(last);
842 let c =
843 gen_context_for_sub_run!(self, raw_args, args, exe_path, inter_mediate_args);
844
845 sub.run(c)
846 }
847 None => {
848 match &last {
850 MiddleArg::LongFlag(_, FlagValue::None)
851 | MiddleArg::ShortFlag(_, FlagValue::None) => {
852 inter_mediate_args.push_back(last);
854 inter_mediate_args.push_back(MiddleArg::Normal(arg));
855 match args.pop_front() {
856 Some(long_flag) if p.long_flag(&long_flag) => {
857 let last = p.long_middle(long_flag);
858 self.assign_run(args, inter_mediate_args, p, raw_args, exe_path, last)
859 }
860 Some(short_flag) if p.flag(&short_flag) => {
861 let last = p.short_middle(short_flag);
862 self.assign_run(args, inter_mediate_args, p, raw_args, exe_path, last)
863 }
864 Some(arg) => match self.take_sub(&arg) {
865 Some(sub) => {
866 let c = gen_context_for_sub_run!(
867 self,
868 raw_args,
869 args,
870 exe_path,
871 inter_mediate_args
872 );
873
874 sub.run(c)
875 }
876 None => {
877 let c = gen_context_for_self_action!(
879 raw_args,
880 args,
881 exe_path,
882 inter_mediate_args
883 );
884 let (mut c, non_flag_args) = p.parse_inter_mediate_args(
885 &self.l_flags,
886 &self.c_flags,
887 c,
888 false,
889 );
890 c = p.parse_args_until_end(&self.l_flags, &self.c_flags, c);
891 c.args.push_front(arg);
892 if let Some(mut non_flag_args) = non_flag_args {
893 non_flag_args.append(&mut c.args);
894 c.args = non_flag_args;
895 };
896 match self.action {
897 Some(action) => action(self, c),
898 None => no_registered_error!(self, c),
899 }
900 }
901 },
902 None => {
903 let c = gen_context_for_self_action!(
905 raw_args,
906 args,
907 exe_path,
908 inter_mediate_args
909 );
910 let (mut c, non_flag_args) =
911 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, c, false);
912 if let Some(mut non_flag_args) = non_flag_args {
913 non_flag_args.append(&mut c.args);
914 c.args = non_flag_args;
915 }
916 match self.action {
917 Some(action) => action(self, c),
918 None => no_registered_error!(self, c),
919 }
920 }
921 }
922 }
923 _ => {
924 inter_mediate_args.push_back(last);
926 let c = gen_context_for_self_action!(
929 raw_args,
930 args,
931 exe_path,
932 inter_mediate_args
933 );
934 let (mut c, non_flag_args) =
935 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, c, false);
936 c = p.parse_args_until_end(&self.l_flags, &self.c_flags, c);
937 c.args.push_front(arg);
938 if let Some(mut non_flag_args) = non_flag_args {
939 non_flag_args.append(&mut c.args);
940 c.args = non_flag_args;
941 }
942 match self.action {
943 Some(action) => action(self, c),
944 _ => no_registered_error!(self, c),
945 }
946 }
947 }
948 }
949 }
950 }
951 None => {
952 inter_mediate_args.push_back(last);
955 let context =
956 gen_context_for_self_action!(raw_args, args, exe_path, inter_mediate_args);
957 let (mut c, non_flag_args) =
958 p.parse_inter_mediate_args(&self.l_flags, &self.c_flags, context, false);
959 if let Some(mut non_flag_args) = non_flag_args {
960 non_flag_args.append(&mut c.args);
961 c.args = non_flag_args;
962 }
963
964 match self.action {
965 Some(action) => action(self, c),
966 None => no_registered_error!(self, c),
967 }
968 }
969 }
970 }
971
972 pub fn handle_sub_result(mut self, mut req: Result<ActionResult, ActionError>) -> run_result!() {
976 match req {
977 done!() => {
978 req
980 }
981 Ok(ActionResult::ParentActionRequest(mut cmd, mut ctx)) => {
982 ctx.routes.pop(); self.c_flags = ctx.common_flags.remove_last(); check_sub!(self, cmd); let action = cmd.action.unwrap(); self.sub.push(cmd); action(self, ctx)
989 }
990 Err(ref mut err) => {
991 if !err.printed {
992 println!("error: {err}");
993 }
994 err.printed = true;
995 req
996 }
997 _ => req,
998 }
999 }
1000}
1001#[cfg(test)]
1002mod tests {
1003 use crate::license;
1004
1005 use super::super::parser::ParseError;
1006 use super::super::{Flag, FlagType};
1007 use super::*;
1008
1009 fn cnv_arg(mut v: Vec<&str>) -> Vec<String> {
1010 v.iter_mut().map(|s| s.to_owned()).collect()
1011 }
1012
1013 #[test]
1014 fn test_single_run() {
1015 let mut arg = vec![
1016 "exe_path".to_string(),
1017 "test".to_string(),
1018 "test".to_string(),
1019 ];
1020 let root = base_root().action(|_, c| {
1021 println!("test_action: {c:?}");
1022 let raw_args = vec![
1023 "exe_path".to_string(),
1024 "test".to_string(),
1025 "test".to_string(),
1026 ];
1027 let expect_args = {
1028 let mut vd = VecDeque::from(raw_args.clone());
1029 vd.pop_front();
1030 vd
1031 };
1032 assert_eq!(c.raw_args, raw_args);
1033 assert_eq!(c.args, expect_args);
1034 assert_eq!(c.exe_path, String::from("exe_path"));
1035 assert_eq!(c.routes, Vector(None));
1036 done!()
1037 });
1038
1039 let _ = root.single_run(arg.clone());
1040
1041 arg.push("--common=C_after".into());
1042 arg.push("--local=L_after".into());
1043 arg.insert(1, "--common=C_before".into());
1044 arg.insert(1, "--local=L_before".into());
1045 let root = Command::with_name("root")
1046 .action(|cmd, c| {
1047 println!("test_action: {c:?}");
1048 let raw_args: Vec<String> = vec![
1049 "exe_path".to_string(),
1050 "--local=L_before".to_string(),
1051 "--common=C_before".to_string(),
1052 "test".to_string(),
1053 "test".to_string(),
1054 "--common=C_after".to_string(),
1055 "--local=L_after".to_string(),
1056 ];
1057 let expect_args = VecDeque::from(vec!["test".to_string(), "test".to_string()]);
1058 assert_eq!(c.raw_args, raw_args);
1059 assert_eq!(c.args, expect_args);
1060 assert_eq!(c.exe_path, String::from("exe_path"));
1061 assert_eq!(c.routes, Vector(None));
1062 let l_flag_values = Vector::from(vec![
1063 (
1064 "local".to_string(),
1065 FlagValue::String("L_before".to_owned()),
1066 ),
1067 ("local".to_string(), FlagValue::String("L_after".into())),
1068 ]);
1069 assert_eq!(c.local_flags_values, l_flag_values);
1070 let c_flag_values = Vector::from(vec![
1071 (
1072 "common".to_string(),
1073 FlagValue::String("C_before".to_owned()),
1074 ),
1075 ("common".to_string(), FlagValue::String("C_after".into())),
1076 ]);
1077 assert_eq!(c.common_flags_values, c_flag_values);
1078 assert_eq!(cmd.version, "root_version".to_owned());
1079 assert_eq!(cmd.copyright, "root_copyright".to_owned());
1080 assert_eq!(cmd.license.unwrap().0, String::from("root_license"));
1081 done!()
1082 })
1083 .common_flag(Flag::new("common", FlagType::String, "sample common flag"))
1084 .local_flag(Flag::new("local", FlagType::String, "sample local flag"))
1085 .version("root_version")
1086 .copyright("root_copyright")
1087 .license(license!(
1088 "root_license".into(),
1089 content=>"root_license_content".into()
1090 ));
1091
1092 let _ = root.single_run(arg);
1093 }
1094
1095 #[test]
1096 fn run_root() {
1097 let arg = vec![
1098 "exe_path".to_string(),
1099 "test".to_string(),
1100 "test".to_string(),
1101 "--local".to_string(),
1102 "test".to_string(),
1103 ];
1104 let root = Command::new()
1105 .action(|mut cmd, c| {
1106 println!("test_action: {c:?}");
1107 let raw_args = vec![
1108 "exe_path".to_string(),
1109 "test".to_string(),
1110 "test".to_string(),
1111 "--local".to_string(),
1112 "test".to_string(),
1113 ];
1114 let expect_args = VecDeque::from(vec!["test".to_string(), "test".to_string()]);
1115 assert_eq!(c.raw_args, raw_args);
1116 assert_eq!(c.args, expect_args);
1117 assert_eq!(c.exe_path, String::from("exe_path"));
1118 assert_eq!(
1119 c.get_local_flag_value_of("local", &cmd),
1120 Some(FlagValue::String("test".into()))
1121 );
1122 assert_eq!(
1123 c.get_flag_value_of("local", &cmd),
1124 Some(FlagValue::String("test".into()))
1125 );
1126 assert_eq!(
1127 c.get_flag_value_of("common", &cmd),
1128 Some(FlagValue::String(String::default()))
1129 );
1130 assert_eq!(c.routes, Vector(None));
1131 assert_eq!(cmd.version, "root_version".to_owned());
1132 assert_eq!(cmd.copyright, "root_copyright".to_owned());
1133 let License(inner) = cmd.license.take();
1134 let inner = inner.unwrap();
1135 assert_eq!(inner.0, String::from("root_license"));
1136 assert_eq!(inner.1(&cmd, &c), String::from("root_license_content"));
1137 done!()
1138 })
1139 .common_flag(Flag::new("common", FlagType::String, "sample common flag"))
1140 .local_flag(Flag::new("local", FlagType::String, "sample local flag"))
1141 .sub_command(Command::with_name("sub").action(|_, _| {
1142 println!("sub");
1143 done!()
1144 }))
1145 .version("root_version")
1146 .copyright("root_copyright")
1147 .license(license!(
1148 expr=>"root_license".into(),
1149 content=>"root_license_content".into()
1150 ));
1151 let _ = root.run(arg);
1152 }
1153
1154 fn base_root() -> Command {
1155 Command::new()
1156 .local_flag(Flag::new_string("local").short_alias('l'))
1157 .local_flag(Flag::new_bool("lafter").short_alias('a'))
1158 .common_flag(Flag::new_bool("common").short_alias('c'))
1159 .common_flag(Flag::new_string("cstr").short_alias('s'))
1160 .common_flag(Flag::new_bool("cafter"))
1161 .version("root_version")
1162 .copyright("root_copyright")
1163 .license(license!(
1164 "root_license".into(),
1165 content=>"root_license_content".into(),
1166 ))
1167 .authors("root_authors")
1168 }
1169
1170 macro_rules! assert_attrs {
1171 ($prefix:expr, $context:expr,$command:expr) => {
1172 let prefix = String::from($prefix);
1173 assert_eq!($command.authors, prefix.clone() + "authors");
1174 assert_eq!($command.version, prefix.clone() + "version");
1175 assert_eq!($command.copyright, prefix.clone() + "copyright");
1176 assert_eq!(
1177 (
1178 $command.license.expr_unwrap(),
1179 $command.license.output_unwrap(&$command, &$context)
1180 ),
1181 (prefix.clone() + "license", prefix + "license_content")
1182 );
1183 };
1184 }
1185 #[test]
1186 fn run_root_with_flag_before_normal_arg() {
1187 let mut arg = cnv_arg(vec!["exe_path", "--local=test"]);
1188 let root = base_root().sub_command(Command::with_name("sub").action(|c, _| {
1189 panic!("not root, in sub: {c:?}");
1190 }));
1191 arg.push("test".into());
1192 let _ = root
1193 .clone()
1194 .action(|cmd, c| {
1195 println!("c: {c:?}");
1196 assert_eq!(
1197 cnv_arg(vec!["exe_path", "--local=test", "test"]),
1198 c.raw_args
1199 );
1200 assert_eq!(
1201 c.get_flag_value_of("local", &cmd).unwrap(),
1202 FlagValue::String("test".into())
1203 );
1204 assert_eq!(c.routes, Vector(None));
1205 assert_attrs!("root_", c, cmd);
1206 done!()
1207 })
1208 .run(arg.clone());
1209 arg[2] = "--common".into();
1210 let _ = root
1211 .clone()
1212 .action(|cur_cmd, c| {
1213 println!("c: {c:?}");
1214 assert_eq!(
1215 cnv_arg(vec!["exe_path", "--local=test", "--common"]),
1216 c.raw_args
1217 );
1218 assert_eq!(
1219 c.get_flag_value_of("local", &cur_cmd).unwrap(),
1220 FlagValue::String("test".into())
1221 );
1222 assert_eq!(
1223 c.get_flag_value_of("common", &cur_cmd).unwrap(),
1224 FlagValue::Bool(true)
1225 );
1226 assert_eq!(c.routes, Vector(None));
1227 assert_attrs!("root_", c, cur_cmd);
1228 done!()
1229 })
1230 .run(arg.clone());
1231
1232 arg.push("test".into());
1233 let _ = root
1234 .clone()
1235 .action(|cc, c| {
1236 println!("{c:?}");
1237 assert_eq!(
1238 cnv_arg(vec!["exe_path", "--local=test", "--common", "test"]),
1239 c.raw_args
1240 );
1241 assert_eq!(VecDeque::from(vec!["test".to_string()]), c.args);
1242 assert_eq!(
1243 c.get_flag_value_of("local", &cc).unwrap(),
1244 FlagValue::String("test".into())
1245 );
1246 assert_eq!(
1247 c.get_flag_value_of("common", &cc).unwrap(),
1248 FlagValue::Bool(true)
1249 );
1250 assert_eq!(c.routes, Vector(None));
1251 assert_attrs!("root_", c, cc);
1252 done!()
1253 })
1254 .run(arg.clone());
1255
1256 println!("arg after flags");
1257 arg.push("arg".into());
1258 arg.push("ex_arg".into());
1259 arg.push("--lafter".into());
1260 arg.push("--cafter".into());
1261 let _ = root
1262 .clone()
1263 .action(|cur, c| {
1264 println!("{c:?}");
1265 assert_eq!(
1266 cnv_arg(vec![
1267 "exe_path",
1268 "--local=test",
1269 "--common",
1270 "test",
1271 "arg",
1272 "ex_arg",
1273 "--lafter",
1274 "--cafter"
1275 ]),
1276 c.raw_args
1277 );
1278 assert_eq!(
1279 VecDeque::from(cnv_arg(vec!["test", "arg", "ex_arg"])),
1280 c.args
1281 );
1282 assert_eq!(
1283 c.get_flag_value_of("local", &cur).unwrap(),
1284 FlagValue::String("test".into())
1285 );
1286 assert_eq!(
1287 c.get_flag_value_of("common", &cur).unwrap(),
1288 FlagValue::Bool(true)
1289 );
1290 assert_eq!(
1291 c.get_flag_value_of("cafter", &cur).unwrap(),
1292 FlagValue::Bool(true)
1293 );
1294 assert_eq!(
1295 c.get_flag_value_of("lafter", &cur).unwrap(),
1296 FlagValue::Bool(true)
1297 );
1298 assert_eq!(c.routes, Vector(None));
1299 assert_attrs!("root_", c, cur);
1300 done!()
1301 })
1302 .run(arg.clone());
1303
1304 arg.remove(5);
1305 arg.remove(4);
1306 arg.insert(5, "arg".into());
1307
1308 let _ = root
1309 .clone()
1310 .action(|cur_cmd, c| {
1311 println!("{c:?}");
1312 assert_eq!(
1313 c.raw_args,
1314 cnv_arg(vec![
1315 "exe_path",
1316 "--local=test",
1317 "--common",
1318 "test",
1319 "--lafter",
1320 "arg",
1321 "--cafter"
1322 ])
1323 );
1324 assert_eq!(VecDeque::from(cnv_arg(vec!["test", "arg"])), c.args);
1325 assert_eq!(
1326 c.get_flag_value_of("local", &cur_cmd).unwrap(),
1327 FlagValue::String("test".into())
1328 );
1329 assert_eq!(
1330 c.get_flag_value_of("common", &cur_cmd).unwrap(),
1331 FlagValue::Bool(true)
1332 );
1333 assert_eq!(
1334 c.get_flag_value_of("cafter", &cur_cmd).unwrap(),
1335 FlagValue::Bool(true)
1336 );
1337 assert_eq!(
1338 c.get_flag_value_of("lafter", &cur_cmd).unwrap(),
1339 FlagValue::Bool(true)
1340 );
1341 assert_eq!(c.routes, Vector(None));
1342 assert_attrs!("root_", c, cur_cmd);
1343 done!()
1344 })
1345 .run(arg.clone());
1346
1347 arg.push("ex_arg".into());
1348 let _ = root
1349 .clone()
1350 .action(|cmd, c| {
1351 println!("{c:?}");
1352 assert_eq!(
1353 c.raw_args,
1354 cnv_arg(vec![
1355 "exe_path",
1356 "--local=test",
1357 "--common",
1358 "test",
1359 "--lafter",
1360 "arg",
1361 "--cafter",
1362 "ex_arg"
1363 ])
1364 );
1365 assert_eq!(
1366 VecDeque::from(cnv_arg(vec!["test", "arg", "ex_arg"])),
1367 c.args
1368 );
1369 assert_eq!(
1370 c.get_flag_value_of("local", &cmd).unwrap(),
1371 FlagValue::String("test".into())
1372 );
1373 assert_eq!(
1374 c.get_flag_value_of("common", &cmd).unwrap(),
1375 FlagValue::Bool(true)
1376 );
1377 assert_eq!(
1378 c.get_flag_value_of("cafter", &cmd).unwrap(),
1379 FlagValue::Bool(true)
1380 );
1381 assert_eq!(
1382 c.get_flag_value_of("lafter", &cmd).unwrap(),
1383 FlagValue::Bool(true)
1384 );
1385 assert_eq!(c.routes, Vector(None));
1386 assert_attrs!("root_", c, cmd);
1387 done!()
1388 })
1389 .run(arg.clone());
1390 arg[4] = "-a".into();
1391 let _ = root
1392 .clone()
1393 .action(|cmd, c| {
1394 println!("{c:?}");
1395 assert_eq!(
1396 c.raw_args,
1397 cnv_arg(vec![
1398 "exe_path",
1399 "--local=test",
1400 "--common",
1401 "test",
1402 "-a",
1403 "arg",
1404 "--cafter",
1405 "ex_arg"
1406 ])
1407 );
1408 assert_eq!(
1409 VecDeque::from(cnv_arg(vec!["test", "arg", "ex_arg"])),
1410 c.args
1411 );
1412 assert_eq!(
1413 c.get_flag_value_of("local", &cmd).unwrap(),
1414 FlagValue::String("test".into())
1415 );
1416 assert_eq!(
1417 c.get_flag_value_of("common", &cmd).unwrap(),
1418 FlagValue::Bool(true)
1419 );
1420 assert_eq!(
1421 c.get_flag_value_of("cafter", &cmd).unwrap(),
1422 FlagValue::Bool(true)
1423 );
1424 assert_eq!(
1425 c.get_flag_value_of("lafter", &cmd).unwrap(),
1426 FlagValue::Bool(true)
1427 );
1428 assert_eq!(c.routes, Vector(None));
1429 assert_attrs!("root_", c, cmd);
1430 done!()
1431 })
1432 .run(arg.clone());
1433 }
1434
1435 #[test]
1436 fn run_node() {
1437 let mut arg = cnv_arg(vec![
1438 "exe_path", "sub", "test", "--common", "test", "--cstr", "strt", "-b", "--local",
1439 ]);
1440 let root = base_root().action(|c, _| {
1441 println!("test_action: {c:?}");
1442 panic!("not sub");
1443 });
1444 let sub = Command::with_name("sub")
1445 .local_flag(Flag::new_bool("bool").short_alias('b'))
1446 .local_flag(Flag::new_string("string").short_alias('s'))
1447 .common_flag(Flag::new_bool("cl"))
1448 .sub_command(Command::with_name("leaf").action(|c, _| {
1449 println!("Context: {c:?}");
1450 panic!("in leaf")
1451 }))
1452 .authors("sub_authors")
1453 .version("sub_version")
1454 .copyright("sub_copyright")
1455 .license(license!(
1456 "sub_license".into(),
1457 content=>"sub_license_content".into(),
1458 ));
1459 let _ = root
1460 .clone()
1461 .sub_command(sub.clone().action(|cmd, c| {
1462 println!("{c:?}");
1463 let raw_args = cnv_arg(vec![
1464 "exe_path", "sub", "test", "--common", "test", "--cstr", "strt", "-b", "--local",
1465 ]);
1466 let expect_args = VecDeque::from(vec!["test".to_string(), "test".to_string()]);
1467 assert_eq!(c.exe_path, String::from("exe_path"));
1468 assert_eq!(c.raw_args, raw_args);
1469 assert_eq!(c.args, expect_args);
1470 assert_eq!(
1471 c.get_flag_value_of("common", &cmd),
1472 Some(FlagValue::Bool(true))
1473 );
1474 assert_eq!(
1475 c.get_flag_value_of("bool", &cmd).unwrap(),
1476 FlagValue::Bool(true)
1477 );
1478 assert_eq!(c.get_flag_value_of("commons", &cmd), None);
1479 assert_eq!(c.get_flag_value_of("local", &cmd), None);
1480 assert_eq!(c.routes, Vector(None));
1481 assert_attrs!("sub_", c, cmd);
1482 done!()
1483 }))
1484 .run(arg.clone());
1485
1486 println!("サブコマンド前フラグのテスト");
1487 arg = cnv_arg(vec!["exe_path", "--cstr=test", "-b", "sub"]);
1488 let _ = root
1489 .clone()
1490 .name("root")
1491 .sub_command(sub.clone().action(|cmd, c| {
1492 println!("c: {c:?}");
1493 assert_eq!(
1494 c.raw_args,
1495 cnv_arg(vec!["exe_path", "--cstr=test", "-b", "sub"])
1496 );
1497 assert_eq!(
1498 c.get_flag_value_of("cstr", &cmd).unwrap(),
1499 FlagValue::String("test".into())
1500 );
1501 assert_eq!(
1502 c.get_flag_value_of("bool", &cmd).unwrap(),
1503 FlagValue::Bool(true)
1504 );
1505 assert_eq!(c.routes, Vector(Some(vec!["root".to_string()])));
1506 assert_attrs!("sub_", c, cmd);
1507 done!()
1508 }))
1509 .run(arg.clone());
1510
1511 println!("サブコマンド探しをする場合");
1512 arg[1] = "--cstr".into();
1513 arg.insert(2, "test".into());
1514
1515 let _ = root
1516 .clone()
1517 .sub_command(sub.clone().action(|cmd, c| {
1518 println!("c:{c:?}");
1519 assert_eq!(
1520 c.raw_args,
1521 cnv_arg(vec!["exe_path", "--cstr", "test", "-b", "sub"])
1522 );
1523 assert_eq!(
1524 c.get_flag_value_of("cstr", &cmd).unwrap(),
1525 FlagValue::String("test".into())
1526 );
1527 assert_eq!(
1528 c.get_flag_value_of("bool", &cmd).unwrap(),
1529 FlagValue::Bool(true)
1530 );
1531 assert_eq!(c.routes, Vector(None));
1532 assert_attrs!("sub_", c, cmd);
1533 done!()
1534 }))
1535 .run(arg.clone());
1536
1537 arg.remove(2);
1538 arg[1] = "--cstr=test".into();
1539 arg.push("test_arg".into());
1540 arg.push("--cafter".into());
1541 arg.push("test_arg2".into());
1542 arg.push("--string".into());
1543 arg.push("testStr".into());
1544 let _ = root
1545 .clone()
1546 .sub_command(sub.clone().action(|cmd, c| {
1547 println!("{c:?}");
1548 assert_eq!(
1549 c.raw_args,
1550 cnv_arg(vec![
1551 "exe_path",
1552 "--cstr=test",
1553 "-b",
1554 "sub",
1555 "test_arg",
1556 "--cafter",
1557 "test_arg2",
1558 "--string",
1559 "testStr"
1560 ])
1561 );
1562 assert_eq!(c.args, cnv_arg(vec!["test_arg", "test_arg2"]));
1563 assert_eq!(
1564 c.get_flag_value_of("cstr", &cmd).unwrap(),
1565 FlagValue::String("test".into())
1566 );
1567 assert_eq!(
1568 c.get_flag_value_of("bool", &cmd).unwrap(),
1569 FlagValue::Bool(true)
1570 );
1571 assert_eq!(
1572 c.get_flag_value_of("cafter", &cmd).unwrap(),
1573 FlagValue::Bool(true)
1574 );
1575 assert_eq!(c.get_local_flag_value_of("cafter", &cmd), None);
1576 assert_eq!(
1577 c.get_flag_value_of("string", &cmd).unwrap(),
1578 FlagValue::String("testStr".into())
1579 );
1580 assert_eq!(c.routes, Vector(None));
1581 assert_attrs!("sub_", c, cmd);
1582 done!()
1583 }))
1584 .run(arg.clone());
1585
1586 println!("\r\n\r\nサブサブコマンドが存在する場合の判別系\r\n");
1587 arg.remove(4);
1588 let _ = root
1589 .clone()
1590 .sub_command(sub.clone().action(|cmd, c| {
1591 println!("result_c: {c:?}");
1592 assert_eq!(
1593 c.raw_args,
1594 cnv_arg(vec![
1595 "exe_path",
1596 "--cstr=test",
1597 "-b",
1598 "sub",
1599 "--cafter",
1600 "test_arg2",
1601 "--string",
1602 "testStr"
1603 ])
1604 );
1605 assert_eq!(c.args, vec!["test_arg2".to_string()]);
1606 assert_eq!(
1607 c.get_common_flag_value_of("cstr", &cmd).unwrap(),
1608 FlagValue::String("test".into())
1609 );
1610 assert_eq!(
1611 c.get_local_flag_value_of("string", &cmd).unwrap(),
1612 FlagValue::String("testStr".into())
1613 );
1614 assert_eq!(
1615 c.get_inputted_common_flag_value_of("cafter").unwrap(),
1616 FlagValue::None
1617 );
1618 assert_eq!(c.routes, Vector(None));
1619 assert_attrs!("sub_", c, cmd);
1620 done!()
1621 }))
1622 .run(arg.clone());
1623 println!("\r\n\r\nサブサブコマンドが存在する場合の判別系その2\r\n");
1624 arg.push("ex_arg".into());
1625 arg[5] = "test_arg".to_owned();
1626
1627 let _ = root
1628 .clone()
1629 .sub_command(sub.clone().action(|cmd, c| {
1630 println!("C: {c:?}");
1631 assert_eq!(
1632 c.raw_args,
1633 cnv_arg(vec![
1634 "exe_path",
1635 "--cstr=test",
1636 "-b",
1637 "sub",
1638 "--cafter",
1639 "test_arg",
1640 "--string",
1641 "testStr",
1642 "ex_arg"
1643 ])
1644 );
1645 assert_eq!(c.args, cnv_arg(vec!["test_arg", "ex_arg"]));
1646 assert_eq!(c.routes, Vector(None));
1647 assert_attrs!("sub_", c, cmd);
1648 done!()
1649 }))
1650 .run(arg.clone());
1651 arg[6] = "--string=testStr".into();
1652 arg[8] = "test_arg2".into();
1653 arg.remove(7);
1654 arg.push("test_arg3".into());
1655 arg.push("--common".into());
1656 arg.push("test_arg4".into());
1657
1658 let _ = root
1659 .clone()
1660 .sub_command(sub.clone().action(|cmd, c| {
1661 println!("C: {c:?}");
1662 assert_eq!(
1663 c.raw_args,
1664 cnv_arg(vec![
1665 "exe_path",
1666 "--cstr=test",
1667 "-b",
1668 "sub",
1669 "--cafter",
1670 "test_arg",
1671 "--string=testStr",
1672 "test_arg2",
1673 "test_arg3",
1674 "--common",
1675 "test_arg4"
1676 ])
1677 );
1678 assert_eq!(
1679 c.args,
1680 vec![
1681 "test_arg".to_owned(),
1682 "test_arg2".to_owned(),
1683 "test_arg3".to_owned(),
1684 "test_arg4".to_owned()
1685 ]
1686 );
1687 assert_eq!(
1688 c.get_common_flag_value_of("cstr", &cmd).unwrap(),
1689 FlagValue::String("test".into())
1690 );
1691 assert_eq!(
1692 c.get_local_flag_value_of("bool", &cmd).unwrap(),
1693 FlagValue::Bool(true)
1694 );
1695 assert_eq!(
1696 c.get_common_flag_value_of("cafter", &cmd).unwrap(),
1697 FlagValue::Bool(true)
1698 );
1699 assert_eq!(
1700 c.get_flag_value_of("string", &cmd).unwrap(),
1701 FlagValue::String("testStr".into())
1702 );
1703 assert_eq!(c.routes, Vector(None));
1704 assert_attrs!("sub_", c, cmd);
1705 done!()
1706 }))
1707 .run(arg.clone());
1708
1709 arg.pop();
1710 arg.remove(8);
1711 arg.remove(7);
1712 arg.remove(5);
1713
1714 let _ = root
1715 .clone()
1716 .sub_command(sub.clone().action(|cmd, c| {
1717 println!("c: {c:?}");
1718 assert_eq!(
1719 c.raw_args,
1720 cnv_arg(vec![
1721 "exe_path",
1722 "--cstr=test",
1723 "-b",
1724 "sub",
1725 "--cafter",
1726 "--string=testStr",
1727 "--common"
1728 ])
1729 );
1730 assert_eq!(c.args.len(), 0);
1731 assert_eq!(
1732 c.get_flag_value_of("cstr", &cmd).unwrap(),
1733 FlagValue::String("test".into())
1734 );
1735 assert_eq!(
1736 c.get_flag_value_of("bool", &cmd).unwrap(),
1737 FlagValue::Bool(true)
1738 );
1739 assert_eq!(
1740 c.get_flag_value_of("cafter", &cmd).unwrap(),
1741 FlagValue::Bool(true)
1742 );
1743 assert_eq!(
1744 c.get_flag_value_of("string", &cmd).unwrap(),
1745 FlagValue::String("testStr".into())
1746 );
1747 assert_eq!(
1748 c.get_flag_value_of("common", &cmd).unwrap(),
1749 FlagValue::Bool(true)
1750 );
1751 assert_eq!(c.routes, Vector(None));
1752 assert_attrs!("sub_", c, cmd);
1753 done!()
1754 }))
1755 .run(arg.clone());
1756 }
1757
1758 #[test]
1759 fn run_leaf() {
1760 let arg = vec![
1761 "exe_path".to_string(),
1762 "sub".to_string(),
1763 "leaf".to_string(),
1764 "--common".to_string(),
1765 "test".to_string(),
1766 "-c".to_string(),
1767 "--local".to_string(),
1768 ];
1769 let root = Command::new()
1770 .action(|c, _| {
1771 println!("test_action: {c:?}");
1772 panic!("not sub");
1773 })
1774 .common_flag(Flag::new("common", FlagType::String, "sample common flag"))
1775 .common_flag(Flag::new_string("cshort").short_alias('c'))
1776 .local_flag(Flag::new("local", FlagType::default(), "sample local flag"))
1777 .sub_command(
1778 Command::with_name("sub")
1779 .action(|c, _| {
1780 panic!("sub: {c:?}");
1781 })
1782 .version("sub_version")
1783 .copyright("sub_copyright")
1784 .license(license!(
1785 "sub_license".into(),
1786 content=>"root_license_content".into(),
1787 ))
1788 .authors("sub_authors")
1789 .sub_command(
1790 Command::with_name("leaf")
1791 .action(|cmd, c| {
1792 println!("{c:?}");
1793 let raw_args = vec![
1794 "exe_path".to_string(),
1795 "sub".to_string(),
1796 "leaf".to_string(),
1797 "--common".to_string(),
1799 "test".to_string(),
1800 "-c".to_string(),
1801 "--local".to_string(),
1802 ];
1803 let expect_args = VecDeque::new();
1805 assert_eq!(c.exe_path, String::from("exe_path"));
1806 assert_eq!(c.raw_args, raw_args);
1807 assert_eq!(c.args, expect_args);
1808 assert_eq!(
1809 c.get_flag_value_of("common", &cmd),
1810 Some(FlagValue::String("test".into()))
1811 );
1812 assert_eq!(
1813 c.get_inputted_flag_value_of("cshort").unwrap(),
1814 FlagValue::None
1815 );
1816 assert_eq!(
1817 c.get_flag_value_of("cshort", &cmd).unwrap(),
1818 FlagValue::String("".into())
1819 );
1820 assert_eq!(
1821 c.get_flag_value_of("local", &cmd).unwrap(),
1822 FlagValue::Bool(true)
1823 );
1824 assert_eq!(c.get_common_flag_value_of("local", &cmd), None);
1825 assert_eq!(c.routes, Vector(Some(vec!["sub".to_string()])));
1826 assert_attrs!("leaf_", c, cmd);
1827 done!()
1828 })
1829 .local_flag(Flag::new_bool("local").short_alias('l'))
1830 .version("leaf_version")
1831 .copyright("leaf_copyright")
1832 .license(license!(
1833 "leaf_license".into(),
1834 content=>"leaf_license_content".into(),
1835 ))
1836 .authors("leaf_authors"),
1837 ),
1838 );
1839 let _ = root.run(arg.clone());
1840 }
1841
1842 #[test]
1843 fn run_leaf_with_flag_before_normal_flag() {
1844 let root = base_root().action(|c, _| {
1845 panic!("root action: {c:?} - not leaf");
1846 });
1847 let sub = Command::with_name("sub")
1848 .local_flag(Flag::new_bool("sub_local"))
1849 .local_flag(Flag::new_string("sub_lstr"))
1850 .common_flag(Flag::new_bool("sub_common"))
1851 .local_flag(Flag::new_string("sub_cstr"))
1852 .action(|c, _| {
1853 panic!("sub action: {c:?} - not leaf");
1854 });
1855 let leaf = Command::with_name("leaf")
1856 .common_flag(Flag::new_bool("cbool").short_alias('o'))
1857 .common_flag(Flag::new_string("cs"))
1858 .local_flag(Flag::new_bool("lbool").short_alias('b'))
1859 .local_flag(Flag::new_string("lsafter").short_alias('a'))
1860 .local_flag(Flag::new_string("lsbefore").short_alias('s'))
1861 .authors("leaf_authors")
1862 .copyright("leaf_copyright")
1863 .version("leaf_version")
1864 .license(license!(
1865 "leaf_license".to_owned(),
1866 content=>"leaf_license_content".to_owned(),
1867 ));
1868
1869 let run_leaf: fn(Command, Command, Command, Action, Vec<String>) -> () =
1870 |root, sub, leaf, action, args| {
1871 let _ = root
1872 .sub_command(sub.sub_command(leaf.action(action)))
1873 .run(args);
1874 };
1875
1876 let mut args = cnv_arg(vec!["exe_path", "--lbool", "sub", "--lsbefore", "leaf"]);
1877
1878 run_leaf(
1879 root.clone().name("root"),
1880 sub.clone(),
1881 leaf.clone(),
1882 |cmd, c| {
1883 println!("{c:?}");
1884 assert_eq!(
1885 c.raw_args,
1886 cnv_arg(vec!["exe_path", "--lbool", "sub", "--lsbefore", "leaf"])
1887 );
1888 assert_eq!(c.args, VecDeque::new());
1889 assert_eq!(
1890 c.get_flag_value_of("lbool", &cmd).unwrap(),
1891 FlagValue::Bool(true)
1892 );
1893 assert_eq!(
1894 c.get_flag_value_of("lsbefore", &cmd).unwrap(),
1895 FlagValue::String("".into())
1896 );
1897 assert_eq!(
1898 c.routes,
1899 Vector(Some(vec!["root".to_string(), "sub".to_owned(),]))
1900 );
1901 assert_attrs!("leaf_", c, cmd);
1902 done!()
1903 },
1904 args.clone(),
1905 );
1906
1907 args.push("arg".into());
1908
1909 run_leaf(
1910 root.clone(),
1911 sub.clone(),
1912 leaf.clone(),
1913 |cmd, c| {
1914 println!("{c:?}");
1915 assert_eq!(
1916 c.raw_args,
1917 cnv_arg(vec![
1918 "exe_path",
1919 "--lbool",
1920 "sub",
1921 "--lsbefore",
1922 "leaf",
1923 "arg"
1924 ])
1925 );
1926 assert_eq!(c.args, VecDeque::from(vec![String::from("arg")]));
1927 assert_eq!(
1928 c.get_flag_value_of("lbool", &cmd).unwrap(),
1929 FlagValue::Bool(true)
1930 );
1931 assert_eq!(
1932 c.get_flag_value_of("lsbefore", &cmd).unwrap(),
1933 FlagValue::String("".into())
1934 );
1935 assert_eq!(c.routes, Vector(Some(vec!["sub".to_owned()])));
1936 assert_attrs!("leaf_", c, cmd);
1937 done!()
1938 },
1939 args.clone(),
1940 );
1941 args.push("-o".into());
1942 run_leaf(
1943 root.clone(),
1944 sub.clone(),
1945 leaf.clone(),
1946 |cmd, c| {
1947 println!("{c:?}");
1948 assert_eq!(
1949 c.raw_args,
1950 cnv_arg(vec![
1951 "exe_path",
1952 "--lbool",
1953 "sub",
1954 "--lsbefore",
1955 "leaf",
1956 "arg",
1957 "-o"
1958 ])
1959 );
1960 assert_eq!(
1961 c.get_flag_value_of("lbool", &cmd).unwrap(),
1962 FlagValue::Bool(true)
1963 );
1964 assert_eq!(c.args, VecDeque::from(vec!["arg".to_string()]));
1965 assert_eq!(
1966 c.get_flag_value_of("lsbefore", &cmd).unwrap(),
1967 FlagValue::String("".into())
1968 );
1969 assert_eq!(
1970 c.get_flag_value_of("cbool", &cmd).unwrap(),
1971 FlagValue::Bool(true)
1972 );
1973 assert_eq!(c.routes, Vector(Some(vec!["sub".to_owned()])));
1974 assert_attrs!("leaf_", c, cmd);
1975 done!()
1976 },
1977 args.clone(),
1978 );
1979 args.pop();
1980 args.insert(4, "before_arg".into());
1981
1982 run_leaf(
1983 root.clone(),
1984 sub.clone(),
1985 leaf.clone(),
1986 |cmd, c| {
1987 println!("{c:?}");
1988 assert_eq!(
1989 c.raw_args,
1990 cnv_arg(vec![
1991 "exe_path",
1992 "--lbool",
1993 "sub",
1994 "--lsbefore",
1995 "before_arg",
1996 "leaf",
1997 "arg"
1998 ])
1999 );
2000 assert_eq!(c.args, VecDeque::from(vec!["arg".to_string()]));
2001 assert_eq!(c.args, VecDeque::from(vec![String::from("arg")]));
2002 assert_eq!(
2003 c.get_flag_value_of("lbool", &cmd).unwrap(),
2004 FlagValue::Bool(true)
2005 );
2006 assert_eq!(
2007 c.get_flag_value_of("lsbefore", &cmd).unwrap(),
2008 FlagValue::String("before_arg".into())
2009 );
2010 assert_eq!(c.routes, Vector(Some(vec!["sub".to_owned()])));
2011 assert_attrs!("leaf_", c, cmd);
2012 done!()
2013 },
2014 args.clone(),
2015 );
2016 }
2017
2018 #[test]
2019 fn test_flag_type() {
2020 let arg = vec![
2021 "exe_path".to_string(),
2022 "sub".to_string(),
2023 "leaf".to_string(),
2024 "test".to_string(),
2025 "--common".to_string(),
2026 "test".to_string(),
2027 "-c".to_string(),
2028 "--local".to_string(),
2029 "-y".to_string(),
2030 "-i".to_string(),
2031 "111".to_string(),
2032 "--float".to_string(),
2033 "10.0".to_string(),
2034 ];
2035
2036 let leaf = Command::with_name("leaf")
2037 .action(|cmd, c| {
2038 println!("sub_action: {c:?}");
2039 let raw_args = vec![
2040 "exe_path".to_string(),
2041 "sub".to_string(),
2042 "leaf".to_string(),
2043 "test".to_string(),
2044 "--common".to_string(),
2045 "test".to_string(),
2046 "-c".to_string(),
2047 "--local".to_string(),
2048 "-y".to_string(),
2049 "-i".to_string(),
2050 "111".to_string(),
2051 "--float".to_string(),
2052 "10.0".to_string(),
2053 ];
2054 let expect_args = VecDeque::from(vec!["test".to_string(), "test".to_owned()]);
2055 assert_eq!(c.exe_path, String::from("exe_path"));
2056 assert_eq!(c.raw_args, raw_args);
2057 assert_eq!(c.args, expect_args);
2058 assert_eq!(
2059 c.get_flag_value_of("common", &cmd),
2060 Some(FlagValue::Bool(true))
2061 );
2062 assert_eq!(
2063 c.get_inputted_flag_value_of("commons"),
2064 Some(FlagValue::None)
2065 );
2066 assert_eq!(
2067 c.get_flag_value_of("commons", &cmd),
2068 Some(FlagValue::String("".into()))
2069 );
2070 assert_eq!(c.get_flag_value_of("local", &cmd), None);
2071 assert_eq!(c.get_inputted_common_flag_value_of("yes"), None);
2072 assert_eq!(
2073 c.get_local_flag_value_of("yes", &cmd),
2074 Some(FlagValue::Bool(true))
2075 );
2076 assert_eq!(
2077 c.get_flag_value_of("yes", &cmd),
2078 Some(FlagValue::Bool(true))
2079 );
2080 let expect_error_args = {
2081 let mut vd = VecDeque::new();
2082 vd.push_back(MiddleArg::LongFlag("local".into(), FlagValue::None));
2083 vd
2084 };
2085 assert_eq!(c.get_flag_value_of("int", &cmd), Some(FlagValue::Int(111)));
2086 assert_eq!(
2087 c.get_flag_value_of("float", &cmd),
2088 Some(FlagValue::Float(10.into()))
2089 );
2090
2091 assert_eq!(
2092 c.error_info_list,
2093 Vector::from(vec![(
2094 MiddleArg::LongFlag("local".into(), FlagValue::None),
2095 ParseError::NoExistLong,
2096 ParseError::NoExistLong
2097 )])
2098 );
2099 assert_attrs!("sub_", c, cmd);
2100 assert_eq!(c.parsing_args.unwrap(), expect_error_args);
2101 done!()
2102 })
2103 .local_flag(Flag::new_bool("yes").short_alias('y'))
2104 .local_flag(Flag::new_int("int").short_alias('i'))
2105 .local_flag(Flag::new_float("float").short_alias('f'))
2106 .authors("sub_authors")
2107 .version("sub_version")
2108 .copyright("sub_copyright")
2109 .license(license!(
2110 "sub_license".into(),
2111 content=>"sub_license_content".into(),
2112 ));
2113 let root = Command::new()
2114 .action(|c, _| {
2115 println!("test_action: {c:?}");
2116 panic!("not sub");
2117 })
2118 .common_flag(Flag::new(
2119 "common",
2120 FlagType::default(),
2121 "sample common flag",
2122 ))
2123 .common_flag(Flag::new_string("commons").short_alias('c'))
2124 .common_flag(Flag::new_string("yes").short_alias('y'))
2125 .local_flag(Flag::new("local", FlagType::default(), "sample local flag"))
2126 .sub_command(
2127 Command::with_name("sub")
2128 .action(|c, _| {
2129 println!("sub: {c:?}");
2130 panic!("not leaf");
2131 })
2132 .sub_command(leaf),
2133 );
2134 let _ = root.run(arg.clone());
2135 }
2136}
2137
2138pub mod presets {
2140
2141 use crate::Vector;
2142 use crate::default_usage;
2143
2144 use super::{Action, Command, License};
2145
2146 pub fn usage<T: Into<String>>(name: T) -> String {
2148 default_usage!(name as var)
2149 }
2150
2151 pub fn root_with_base<T: Into<String>>(
2153 name: T,
2154 authors: T,
2155 version: T,
2156 description: T,
2157 action: Option<Action>,
2158 ) -> Command {
2159 let name = name.into();
2160 let usage = default_usage!(nameString=>name.clone());
2161 Command::with_all_field(
2162 name,
2163 action,
2164 authors.into(),
2165 String::default(),
2166 License(None),
2167 Some(description.into()),
2168 usage,
2169 Vector::default(),
2170 Vector::default(),
2171 Vector::default(),
2172 version.into(),
2173 Vector::default(),
2174 )
2175 }
2176
2177 pub fn preset_version() -> Command {
2179 Command::with_all_field(
2180 String::from("version"),
2181 Some(func::version_print),
2182 String::default(),
2183 String::default(),
2184 License::default(),
2185 Some(String::from("show version")),
2186 String::default(),
2187 Vector::default(),
2188 Vector::default(),
2189 Vector::default(),
2190 String::default(),
2191 Vector::default(),
2192 )
2193 }
2194
2195 pub mod func {
2197 use crate::{FlagType, action_result};
2198
2199 use super::super::{Command, Context, Flag, Vector};
2200 use std::cmp::max;
2201
2202 pub fn version_print(cmd: Command, ctx: Context) -> action_result!() {
2204 crate::check_help!(cmd, ctx, help_tablize_with_alias_dedup);
2205 println!("{}", cmd.version);
2206 crate::done!()
2207 }
2208
2209 macro_rules! _add_help_with_flag_dudup {
2211 ($help:ident,$iter:expr,$nl_list:ident,$s_list:ident,$suffix:ident,$name_and_alias_min_width:ident,$sp:ident,$indent:ident) => {
2212 for f in $iter {
2213 let mut all_dup = true;
2214 let first_help_width = $help.len();
2215 if let Vector(Some(short_alias)) = &f.short_alias {
2216 for s in short_alias.iter() {
2217 if !$s_list.contains(&s) {
2218 if (!all_dup) {
2219 $help.push(',');
2220 }
2221 all_dup = false;
2222 $help.push_str("-");
2223 $help.push(*s);
2224 $s_list.push(s);
2225 }
2226 }
2227 } else {
2228 $help.push_str(&$indent);
2229 }
2230 if !$nl_list.contains(&&f.name) {
2231 $help.push_str(if all_dup { " --" } else { ", --" });
2232 all_dup = false;
2233 $help.push_str(&f.name);
2234 $nl_list.push(&f.name);
2235 }
2236 if let Vector(Some(long_alias)) = &f.long_alias {
2237 for long in long_alias.iter() {
2238 if !$nl_list.contains(&long) {
2239 $nl_list.push(long);
2240 if all_dup {
2241 $help.push_str(" --");
2242 all_dup = false;
2243 } else {
2244 $help.push_str(", --");
2245 }
2246 $help.push_str(long);
2247 }
2248 }
2249 }
2250 if all_dup {
2251 $help.truncate(first_help_width);
2252 } else {
2253 let name_and_alias_width = $help.len() - first_help_width;
2254 if name_and_alias_width < $name_and_alias_min_width {
2255 $help.push_str(
2256 $sp.repeat($name_and_alias_min_width - name_and_alias_width)
2257 .as_str(),
2258 );
2259 }
2260 $help.push('\t');
2261 $help.push_str(&f.description);
2262 $help.push_str(&$suffix);
2263 $help.push('\n');
2264 }
2265 }
2266 };
2267 }
2268
2269 fn flag_help_simple(
2272 flag: &Flag,
2273 append_to: String,
2274 name_and_alias_min_width: usize,
2275 ) -> String {
2276 let mut help = append_to;
2277 let first_help_width = help.len();
2278
2279 if let Vector(Some(short_alias)) = &flag.short_alias {
2280 help = short_alias
2281 .iter()
2282 .fold(help, |help, s| format!("{help}-{s},"));
2283 } else {
2284 help += " ";
2285 }
2286 help = help + " --" + &flag.name;
2287 if let Vector(Some(long_alias)) = &flag.long_alias {
2288 help = long_alias.iter().fold(help, |help, l| {
2289 format!("{help}, --{l}")
2291 })
2292 };
2293 help = add_type_suffix(help, &flag.flag_type);
2294 let name_and_alias_width = help.len() - first_help_width;
2295
2296 if name_and_alias_width < name_and_alias_min_width {
2297 help += &" ".repeat(name_and_alias_min_width - name_and_alias_width);
2298 }
2299
2300 help + "\t" + &flag.description + "\n"
2301 }
2302 pub fn help_with_alias_dedup(cmd: &Command, ctx: &Context) -> String {
2304 let mut help = String::new();
2305 let indent_size: usize = 3;
2306 let sp = String::from(" ");
2307 let indent = sp.repeat(indent_size);
2308 if let Some(description) = &cmd.description {
2309 help.push_str(description);
2310 help.push_str("\n\n");
2311 }
2312 help += &format!("Usage:\n{}{}\n", &indent, cmd.usage);
2313 let name_and_alias_min_width = 12;
2314 let routes = ctx.routes.clone();
2315 let mut routes: Vec<String> = if routes.len() < ctx.depth() {
2316 let mut routes: Vec<String> = routes.into();
2317 routes.insert(
2318 0,
2319 std::path::Path::new(ctx.exe_path())
2320 .file_stem()
2321 .unwrap_or(std::ffi::OsStr::new("root"))
2322 .to_str()
2323 .unwrap_or("root")
2324 .to_owned(),
2325 );
2326 routes
2327 } else {
2328 routes.into()
2329 };
2330 if cmd.l_flags.has_at_least_one()
2331 || cmd.c_flags.has_at_least_one()
2332 || ctx.common_flags.has_at_least_one()
2333 {
2334 help.push_str("\nFlags: \n");
2335
2336 let mut nl_list = Vec::<&String>::new();
2337 let mut s_list = Vec::<&char>::new();
2338
2339 if let Vector(Some(l_flags)) = &cmd.l_flags {
2340 let mut i = l_flags.iter().rev();
2341 if let Some(f) = i.next() {
2342 help = flag_help_simple(f, help, name_and_alias_min_width);
2344 nl_list.push(&f.name);
2345 if let Vector(Some(la)) = &f.long_alias {
2346 let mut la = la.iter().collect();
2347 nl_list.append(&mut la);
2348 };
2349 if let Vector(Some(sa)) = &f.short_alias {
2350 let mut sa = sa.iter().collect();
2351 s_list.append(&mut sa)
2352 }
2353 let emp_str = String::new();
2354 _add_help_with_flag_dudup!(
2355 help,
2356 i,
2357 nl_list,
2358 s_list,
2359 emp_str,
2360 name_and_alias_min_width,
2361 sp,
2362 indent
2363 )
2364 }
2365 }
2366
2367 if let Vector(Some(c_flags)) = &cmd.c_flags {
2370 let suffix = if !cmd.sub.is_empty() {
2371 format!(
2372 "[also available in sub command{} under here]",
2373 (if cmd.sub.len() < 2 { "" } else { "s" })
2374 )
2375 } else {
2376 String::new()
2377 };
2378 _add_help_with_flag_dudup!(
2379 help,
2380 c_flags.iter().rev(),
2381 nl_list,
2382 s_list,
2383 suffix,
2384 name_and_alias_min_width,
2385 sp,
2386 indent
2387 );
2388 }
2389
2390 if let Vector(Some(cfs)) = &ctx.common_flags {
2392 for (c_index, c_flags) in cfs.iter().enumerate().rev() {
2393 if let Vector(Some(c_flags)) = c_flags {
2394 let suffix = match routes.get(c_index) {
2395 Some(cmd_name) => sp.clone() + "(inherited from " + cmd_name + ")",
2396 None => String::new(),
2397 };
2398
2399 _add_help_with_flag_dudup!(
2400 help,
2401 c_flags.iter().rev(),
2402 nl_list,
2403 s_list,
2404 suffix,
2405 name_and_alias_min_width,
2406 sp,
2407 indent
2408 );
2409 }
2410 }
2411 }
2412 }
2413
2414 if let Vector(Some(sub)) = &cmd.sub {
2416 let mut iter = sub.iter();
2417 if let Some(sub_command) = iter.next() {
2418 help.push_str("Sub Command");
2419 if sub.len() > 1 {
2420 help.push('s');
2421 }
2422 help.push_str(": \n");
2423 help = help + &indent + &sub_command.name;
2425 let mut na_list = vec![&sub_command.name];
2426 let mut name_and_alias_width = sub_command.name.len();
2427 if let Vector(Some(alias)) = &sub_command.alias {
2428 let mut a = alias.iter().collect();
2429 na_list.append(&mut a);
2430 for a in alias {
2431 help = help + ", " + a;
2432 name_and_alias_width += a.len() + 2;
2433 }
2434 }
2435 if name_and_alias_width < name_and_alias_min_width {
2436 help = help + &sp.repeat(name_and_alias_min_width - name_and_alias_width);
2437 }
2438 if let Some(description) = &sub_command.description {
2439 help = help + "\t" + description
2440 }
2441 help += "\n";
2442
2443 for sub_cmd in iter {
2444 let mut all_dup = true;
2445 let help_first_width = help.len();
2446 if !na_list.contains(&&sub_cmd.name) {
2447 na_list.push(&sub_cmd.name);
2448 help = help + &indent + &sub_cmd.name;
2449 all_dup = false;
2450 }
2451 if let Vector(Some(alias)) = &sub_cmd.alias {
2452 for a in alias {
2453 if !na_list.contains(&a) {
2454 na_list.push(a);
2455 if all_dup {
2456 help = help + &indent + a;
2457 } else {
2458 help = help + ", " + a;
2459 }
2460 all_dup = false;
2461 }
2462 }
2463 }
2464 if !all_dup {
2465 let name_and_alias_width = help_first_width - help.len();
2466 if name_and_alias_width < name_and_alias_min_width {
2467 help += &sp.repeat(name_and_alias_min_width - name_and_alias_width);
2468 }
2469 if let Some(description) = &sub_cmd.description {
2470 help = help + "\t" + description;
2471 }
2472 help += "\n"
2473 }
2474 }
2475 }
2476 if routes.len() < 2 && !cmd.name.is_empty() {
2477 routes[0] = cmd.name.clone();
2478 }
2479 let exe_suffix = std::env::consts::EXE_SUFFIX;
2480 if !exe_suffix.is_empty() {
2481 routes[0].push('[');
2482 routes[0].push_str(exe_suffix);
2483 routes[0].push(']')
2484 }
2485 help = help + &routes.join(" ") + "<subcommand> --help for more information.";
2486 help += "\n";
2487 }
2488 help
2489 }
2490
2491 pub fn add_type_suffix(to: String, ft: &FlagType) -> String {
2493 match &ft {
2494 FlagType::Bool => to,
2495 FlagType::String => to + " <string>",
2496 FlagType::Int => to + " <int>",
2497 FlagType::Float => to + " <float>",
2498 }
2499 }
2500
2501 pub fn help(cmd: &Command, ctx: &Context) -> String {
2503 let mut help = String::new();
2504 let indent_size: usize = 3;
2505 let sp = String::from(" ");
2506 let indent: String = sp.repeat(indent_size);
2507 if let Some(description) = &cmd.description {
2508 help.push_str(description);
2509 help.push_str("\n\n");
2510 }
2511 help += &format!("Usage:\n{}{}\n\n", &indent, cmd.usage);
2512
2513 let l_flags: &Vector<Flag> = &cmd.l_flags;
2515 let ctx_c_flags: &Vector<Vector<Flag>> = &ctx.common_flags;
2516
2517 help.push_str("Flags(If exist flags have same alias and specified by user, inputted value will be interpreted as the former flag's value): \n");
2518 let head: String;
2519 let cl_label;
2520 let name_and_alias_field_min_width: usize = 7;
2521 if (ctx_c_flags.sum_of_length() + cmd.c_flags.len()) > 0 && cmd.l_flags.has_at_least_one()
2522 {
2523 head = indent.repeat(2);
2525 cl_label = true;
2526 } else {
2527 head = indent.clone();
2529 cl_label = false;
2530 }
2531
2532 if let Vector(Some(l_flags)) = l_flags {
2533 if cl_label {
2534 help.push_str(&indent);
2535 help.push_str("[Local]: \n");
2536 }
2537 help = l_flags.iter().rfold(help, |help, l_flag| {
2538 flag_help_simple(l_flag, help + &head, name_and_alias_field_min_width + 10)
2539 });
2540 }
2541 let depth = ctx.depth();
2542 let mut common_head = true;
2543 if let Vector(Some(c_flags)) = &cmd.c_flags {
2544 if cl_label {
2545 help = help
2546 + &indent + "[Common"
2547 + &format!(
2548 "(common flags are available in this command and sub command{} under this command)]: \n",
2549 (if cmd.sub.len() < 2 { "" } else { "s" })
2550 );
2551 }
2552
2553 for cf in c_flags {
2554 help = flag_help_simple(cf, help + &head, name_and_alias_field_min_width)
2555 }
2556
2557 common_head = false;
2558 }
2559 if let Vector(Some(c_flags)) = ctx_c_flags {
2560 let route_without_root = depth > ctx.routes.len();
2561 if cl_label && common_head {
2562 help = help + &indent + "Common ";
2563 }
2564 help = c_flags
2565 .iter()
2566 .enumerate()
2567 .rfold(help, |help, (index, c_flags)| -> String {
2568 if let Vector(Some(c_flags)) = c_flags {
2570 let mut help = help;
2571 if cl_label {
2572 let mut from_owned: String;
2573 let from = if route_without_root {
2574 if index < 1 {
2575 let cur_path = std::path::Path::new(ctx.exe_path());
2576 from_owned = cur_path
2577 .file_stem()
2578 .unwrap_or(std::ffi::OsStr::new("root"))
2579 .to_str()
2580 .unwrap_or("root")
2581 .to_owned();
2582 match cur_path.extension() {
2583 None => {}
2584 Some(val) => {
2585 from_owned += &format!("[.{}]", val.to_str().unwrap_or("exe"))
2586 }
2587 }
2588
2589 &from_owned
2590 } else {
2591 ctx.routes.get(index - 1).unwrap()
2592 }
2593 } else {
2594 ctx.routes.get(index).unwrap()
2595 };
2596 if common_head {
2597 help += &format!("[inherited from {from}]: \n")
2598 } else {
2599 common_head = false;
2600 help += &format!("{}[inherited from {}]: \n", &indent, from)
2601 }
2602 }
2603
2604 help = c_flags.iter().rfold(help, |help, c_flag| -> String {
2605 flag_help_simple(c_flag, help + &head, name_and_alias_field_min_width)
2606 });
2607 help
2608 } else {
2609 help
2610 }
2611 });
2612 help += "\n";
2613 }
2614
2615 if let Vector(Some(sub_commands)) = &cmd.sub {
2616 help += &format!(
2617 "Sub Command{}: \n",
2618 if sub_commands.len() < 2 { "" } else { "s" }
2619 );
2620 help = sub_commands.iter().fold(help, |help, sub_command| {
2621 let mut help = help + &indent + &sub_command.name;
2623 let mut name_and_alias_width = sub_command.name.len();
2624 if let Vector(Some(alias)) = &sub_command.alias {
2625 let (h_str, w) = alias
2626 .iter()
2627 .fold((help, name_and_alias_width), |(help, w), alias| {
2628 (help + ", " + alias, w + 2 + alias.len())
2629 });
2630 help = h_str;
2631 name_and_alias_width = w;
2632 }
2633 if name_and_alias_width < name_and_alias_field_min_width {
2634 help += &sp.repeat(name_and_alias_field_min_width - name_and_alias_width);
2635 }
2636
2637 help = if let Some(description) = &sub_command.description {
2638 help + "\t" + description
2639 } else {
2640 help
2641 };
2642 help + "\n"
2643 });
2644 let loc_owned: String;
2645 let location: &str = {
2646 if cmd.name.is_empty() {
2647 let path = std::path::Path::new(ctx.exe_path());
2648 let mut l: String = path
2649 .file_stem()
2650 .unwrap_or(std::ffi::OsStr::new("root"))
2651 .to_str()
2652 .unwrap_or("root")
2653 .to_owned();
2654 match path.extension() {
2655 None => {}
2656 Some(ext) => {
2657 l = l + "[." + ext.to_str().unwrap_or("exe") + "]";
2658 }
2659 }
2660 loc_owned = l;
2661 &loc_owned
2662 } else {
2663 if depth < 1 {
2665 &cmd.name
2667 } else {
2668 loc_owned = if let Vector(Some(routes)) = &ctx.routes {
2669 routes.iter().rfold(
2670 {
2671 if depth > routes.len() {
2672 let path = std::path::Path::new(ctx.exe_path());
2673 let mut l = path
2674 .file_stem()
2675 .unwrap_or(std::ffi::OsStr::new("root"))
2676 .to_str()
2677 .unwrap_or("root")
2678 .to_owned();
2679 match path.extension() {
2680 None => {}
2681 Some(val) => {
2682 l = l + "[." + val.to_str().unwrap_or("exe") + "]";
2683 }
2684 }
2685 l
2686 } else {
2687 String::new()
2688 }
2689 },
2690 |str, route| {
2691 str + &sp + route
2693 },
2694 )
2695 } else {
2696 panic!("Routes of context should be not none under sub command.")
2697 };
2698 &loc_owned
2699 }
2700 }
2701 };
2702 help = help + "\n" + &format!("{location} <subcommand> --help for more information.");
2703 help += "\n";
2704 }
2705
2706 help
2707 }
2708
2709 pub fn flag_help_tablize(
2711 append_to: String,
2712 f: &Flag,
2713 sp: &str,
2714 s_max_num: usize, nl_width: usize,
2716 pre_d_space: &str,
2717 ) -> String {
2718 let mut help = append_to;
2719 help = help + &sp.repeat((s_max_num - f.short_alias.len()) * 4);
2721 if let Vector(Some(short_alias)) = &f.short_alias {
2722 for s in short_alias {
2723 help.push('-');
2724 help.push(*s);
2725 help.push_str(", ");
2726 }
2727 }
2728 let prev_help_len = help.len();
2729 help.push_str("--");
2730 help.push_str(&f.name);
2731 if let Vector(Some(long_alias)) = &f.long_alias {
2732 for l in long_alias {
2733 help.push_str(", --");
2734 help.push_str(l);
2735 }
2736 }
2737 help = add_type_suffix(help, &f.flag_type);
2738 let _nl_width = help.len() - prev_help_len;
2739 if _nl_width < nl_width {
2740 help.push_str(&sp.repeat(nl_width - _nl_width));
2741 }
2742 help.push_str(pre_d_space);
2743 help.push_str(&f.description);
2744 help.push('\n');
2745
2746 help
2747 }
2748
2749 pub fn help_tablize(cmd: &Command, ctx: &Context) -> String {
2751 let mut help = String::new();
2752 let indent_size: usize = 3;
2753 let sp = String::from(" ");
2754 let indent: String = sp.repeat(indent_size);
2755 if let Some(description) = &cmd.description {
2756 help.push_str(description);
2757 help.push_str("\n\n");
2758 }
2759 help = help + "Usage:\n" + &indent + &cmd.usage + "\n\n";
2760
2761 if cmd.l_flags.len() + cmd.c_flags.len() + ctx.common_flags.sum_of_length() > 0 {
2762 help.push_str("Flags(If exist flags have same alias and specified by user, inputted value will be interpreted as the former flag's value): \n");
2764
2765 let nl_width = |flag: &Flag| match &flag.long_alias {
2766 Vector(None) => flag.name.len() + flag_type_suffix_len(&flag.flag_type),
2767 Vector(Some(long_aliases)) => {
2768 long_aliases.iter().fold(
2769 flag.name.len() + flag_type_suffix_len(&flag.flag_type),
2770 |width, long_alias| width + long_alias.len(),
2771 ) + long_aliases.len() * 4
2772 }
2773 };
2774
2775 let max_calc =
2776 |flags: &Vector<Flag>, s_width_max: &mut usize, nl_width_max: &mut usize| {
2777 if let Vector(Some(flags)) = flags {
2778 for f in flags {
2779 *s_width_max = max(*s_width_max, f.short_alias.len());
2780 *nl_width_max = max(*nl_width_max, nl_width(f));
2781 }
2782 }
2783 };
2784 let l_flags = &cmd.l_flags;
2786 let c_flags = &cmd.c_flags;
2787 let ctx_c_flags = &ctx.common_flags;
2788 let mut s_width_max: usize = 1; let mut nl_width_max: usize = 8;
2792 max_calc(l_flags, &mut s_width_max, &mut nl_width_max);
2793 max_calc(c_flags, &mut s_width_max, &mut nl_width_max);
2794 if let Vector(Some(ctx_c_flags)) = ctx_c_flags {
2795 for ccf in ctx_c_flags {
2796 max_calc(ccf, &mut s_width_max, &mut nl_width_max);
2797 }
2798 }
2799
2800 let head: String;
2801 let cl_label: bool;
2802 if cmd.l_flags.has_at_least_one() {
2803 head = indent.repeat(2);
2805 cl_label = true;
2806 } else {
2807 head = indent.clone();
2808 cl_label = false;
2809 }
2810
2811 let gap = sp.repeat(2);
2812 if let Vector(Some(l_flags)) = l_flags {
2813 if cl_label {
2814 help.push_str(&indent);
2815 help.push_str("[Local]: \n");
2816 }
2817 for l in l_flags.iter().rev() {
2818 help.push_str(&head);
2819 help = flag_help_tablize(help, l, &sp, s_width_max, nl_width_max, &gap);
2820 }
2821 }
2822
2823 if let Vector(Some(c_flags)) = c_flags {
2824 if cl_label {
2825 help.push_str(&indent);
2826 help.push_str("[Common (available in this command and sub command");
2827 if cmd.sub.len() > 1 {
2828 help.push('s');
2829 }
2830 help.push_str(" under this command)]: \n");
2831 }
2832 for c in c_flags.iter().rev() {
2833 help.push_str(&head);
2834 help = flag_help_tablize(help, c, &sp, s_width_max, nl_width_max, &gap)
2835 }
2836 }
2837
2838 if let Vector(Some(ctx_c_flags)) = ctx_c_flags {
2839 let route_without_root = ctx.depth() > ctx.routes.len();
2840 for (index, cc_flags) in ctx_c_flags.iter().enumerate().rev() {
2841 if let Vector(Some(cc_flags)) = cc_flags {
2842 help.push_str("[Common, inherited from ");
2843 if route_without_root {
2844 if index < 1 {
2845 help.push_str(&root_str(ctx.exe_path()))
2846 } else {
2847 match ctx.routes.get(index - 1) {
2848 Some(val) => help.push_str(val),
2849 None => help.push_str("unknown"),
2850 }
2851 }
2852 } else {
2853 match ctx.routes.get(index) {
2854 Some(val) => help.push_str(val),
2855 None => help.push_str("unknown"),
2856 }
2857 }
2858 help.push_str("]: \n");
2859 for c in cc_flags {
2860 help.push_str(&head);
2861 help = flag_help_tablize(help, c, &sp, s_width_max, nl_width_max, &gap);
2862 }
2863 }
2864 }
2865 }
2866 }
2867
2868 if let Vector(Some(sub_commands)) = &cmd.sub {
2869 help += "Sub Command";
2870 if sub_commands.len() > 1 {
2871 help.push('s');
2872 }
2873 help += ": \n";
2874 let mut na_max_width: usize = 10;
2875 for sc in sub_commands {
2876 match &sc.alias {
2877 Vector(None) => na_max_width = max(na_max_width, sc.name.len()),
2878 Vector(Some(alias)) => {
2879 na_max_width = max(
2880 na_max_width,
2881 alias
2882 .iter()
2883 .fold(sc.name.len() + 2 * alias.len(), |sum, a| sum + a.len()),
2884 );
2885 }
2886 }
2887 }
2888
2889 na_max_width += 3;
2890
2891 for sc in sub_commands {
2892 let help_pref_len = help.len();
2893 help = help + &sc.name;
2894 if let Vector(Some(alias)) = &sc.alias {
2895 help = alias.iter().fold(help, |help, a| help + ", " + a)
2896 }
2897 let sp_num = na_max_width - help.len() + help_pref_len;
2898 help = help + &sp.repeat(sp_num);
2899 if let Some(description) = &sc.description {
2900 help.push_str(description);
2901 }
2902 help.push('\n');
2903 }
2904
2905 help.push_str("\nSee '");
2906 if ctx.depth() > 0 {
2907 if ctx.depth() > ctx.routes.len() {
2908 help.push_str(&root_str(ctx.exe_path()));
2909 help.push_str(&sp);
2910 }
2911 if let Vector(Some(routes)) = &ctx.routes {
2912 for route in routes {
2913 help.push_str(route);
2914 help.push_str(&sp);
2915 }
2916 }
2917 help.push_str(&cmd.name);
2918 help.push_str(" <subcommand> --help' for more information");
2919 } else {
2920 let root = if cmd.name.is_empty() {
2921 root_str(ctx.exe_path())
2922 } else {
2923 cmd.name.clone()
2924 };
2925
2926 help.push_str(&root);
2927 help.push_str("<subcommand> --help' for more information.")
2928 }
2929 }
2930
2931 help
2932 }
2933
2934 macro_rules! _flag_tablize_dedup {
2936 ($iter:expr,$nl_col_width:ident,$s_col_width:ident,$nl_list:ident,$s_list:ident,$s_columns:ident,$nl_columns:ident) => {
2937 for f in $iter {
2938 let mut alias_exist = false;
2939 if let Vector(Some(sa)) = &f.short_alias {
2940 let mut dedup_s = Vec::<&char>::new();
2941 for s in sa.iter() {
2942 if !$s_list.contains(&s) {
2943 dedup_s.push(s);
2944 $s_list.push(s);
2945 alias_exist = true;
2946 }
2947 }
2948 $s_col_width = max(dedup_s.len(), $s_col_width);
2949 $s_columns.push_back(dedup_s);
2950 } else {
2951 $s_columns.push_back(vec![]);
2952 }
2953 let mut dedup_nl = Vec::<&String>::new();
2954 let mut nl_width;
2955 if !$nl_list.contains(&&f.name) {
2956 $nl_list.push(&f.name);
2957 dedup_nl.push(&f.name);
2958 nl_width = f.name.len();
2959 alias_exist = true;
2960 } else {
2961 nl_width = 0;
2962 }
2963 if let Vector(Some(long_alias)) = &f.long_alias {
2964 for la in long_alias {
2965 if !$nl_list.contains(&la) {
2966 $nl_list.push(la);
2967 dedup_nl.push(la);
2968 nl_width += la.len();
2969 alias_exist = true;
2970 }
2971 }
2972 }
2973 if alias_exist {
2974 match dedup_nl.len() {
2975 1 => {
2976 nl_width += flag_type_suffix_len(&f.flag_type);
2977 }
2978 x if x > 1 => {
2979 nl_width += match &f.flag_type {
2980 FlagType::Bool => x * 4,
2981 FlagType::String => x * 4 + 9,
2982 FlagType::Int => x * 4 + 6,
2983 FlagType::Float => x * 4 + 8,
2984 };
2985 }
2986 _ => {}
2987 }
2988 }
2989 $nl_columns.push_back(dedup_nl);
2990 $nl_col_width = max(nl_width, $nl_col_width);
2991 }
2992 };
2993 }
2994
2995 fn add_short_flags_str(append_to: &mut String, s_list: Vec<&char>) {
2999 append_to.push('-');
3000 let mut si = s_list.into_iter();
3001 append_to.push(*si.next().unwrap());
3002 for s in si {
3003 append_to.push_str(", -");
3004 append_to.push(*s);
3005 }
3006 }
3007
3008 fn flag_type_suffix_len(ft: &FlagType) -> usize {
3010 match &ft {
3011 FlagType::Bool => 2,
3012 FlagType::String => 11, FlagType::Int => 8, FlagType::Float => 10, }
3016 }
3017
3018 fn add_long_flags_str_to_prev_flags(
3021 append_to: &mut String,
3022 nl_iter: std::vec::IntoIter<&String>,
3023 ) {
3024 for nl in nl_iter {
3025 append_to.push_str(", --");
3026 append_to.push_str(nl);
3027 }
3028 }
3029
3030 fn add_long_flags_str(append_to: &mut String, mut nl_iter: std::vec::IntoIter<&String>) {
3032 append_to.push_str("--");
3033 append_to.push_str(nl_iter.next().unwrap());
3034 add_long_flags_str_to_prev_flags(append_to, nl_iter);
3035 }
3036
3037 fn add_flags_help_str(
3052 mut append_to: String,
3053 flags: &[Flag],
3054 s_columns: &mut std::collections::VecDeque<Vec<&char>>,
3055 nl_columns: &mut std::collections::VecDeque<Vec<&String>>,
3056 s_col_width: usize,
3057 nl_col_width: usize,
3058 gap_width: usize,
3059 suffix: &str,
3060 prefix: &str,
3061 sp: &str,
3062 ) -> String {
3063 for f in flags.iter().rev() {
3064 append_to.push_str(prefix);
3065 let s_list = s_columns.pop_front().unwrap();
3066 let nl_list = nl_columns.pop_front().unwrap();
3067 if s_list.is_empty() {
3068 if !nl_list.is_empty() {
3069 append_to.push_str(&sp.repeat(s_col_width));
3070 let prev_help_len = append_to.len();
3071 add_long_flags_str(&mut append_to, nl_list.into_iter());
3072 append_to = add_type_suffix(append_to, &f.flag_type);
3073 let nl_len = append_to.len() - prev_help_len;
3074 append_to = append_to
3075 + &sp.repeat(nl_col_width + gap_width - nl_len)
3076 + &f.description
3077 + suffix;
3078 }
3079 } else {
3080 append_to = append_to + &sp.repeat(s_col_width - (s_list.len() * 4));
3081 add_short_flags_str(&mut append_to, s_list);
3082 if nl_list.is_empty() {
3083 append_to = add_type_suffix(append_to, &f.flag_type)
3084 + &sp.repeat(4 + nl_col_width)
3085 + &f.description
3086 + suffix;
3087 } else {
3088 let prev_help_len = append_to.len();
3089 add_long_flags_str_to_prev_flags(&mut append_to, nl_list.into_iter());
3090 append_to = add_type_suffix(append_to, &f.flag_type);
3091 let nl_len = append_to.len() - prev_help_len - 2;
3092 append_to = append_to
3093 + &sp.repeat(nl_col_width + gap_width - nl_len)
3094 + &f.description
3095 + suffix;
3096 }
3097 }
3098 }
3099 append_to
3100 }
3101
3102 pub fn help_tablize_with_alias_dedup(cmd: &Command, ctx: &Context) -> String {
3104 let mut help = String::new();
3105 let indent_size = 3;
3106 let sp = String::from(" ");
3107 let indent: String = sp.repeat(indent_size);
3108 if let Some(description) = &cmd.description {
3109 help.push_str(description);
3110 help.push_str("\n\n");
3111 }
3112 help = help + "Usage:\n" + &indent + &cmd.usage + "\n";
3113
3114 let flag_num = cmd.l_flags.len() + cmd.c_flags.len() + ctx.common_flags.sum_of_length();
3115 if flag_num > 0 {
3116 let mut nl_col_width = 5;
3117 let mut s_col_width = 1;
3118 help.push_str("\nFlags: \n");
3119
3120 let mut nl_list = Vec::<&String>::new();
3121 let mut s_list = Vec::<&char>::new();
3122 let mut s_columns = std::collections::VecDeque::<Vec<&char>>::with_capacity(flag_num);
3123 let mut nl_columns =
3124 std::collections::VecDeque::<Vec<&String>>::with_capacity(flag_num);
3125 if let Vector(Some(l_flags)) = &cmd.l_flags {
3126 let mut l = l_flags.iter().rev();
3127 if let Some(f) = l.next() {
3128 nl_list.push(&f.name);
3129 let mut nl_width = f.name.len() + 2;
3130 if let Vector(Some(la)) = &f.long_alias {
3131 let mut la: Vec<&String> = la.iter().collect();
3132 nl_width += 4 * la.len();
3133 for l in la.iter() {
3134 nl_width += l.len();
3135 }
3136 nl_list.append(&mut la);
3137 }
3138 nl_width += flag_type_suffix_len(&f.flag_type);
3139 nl_col_width = max(nl_width, nl_col_width);
3140 nl_columns.push_back(nl_list.clone());
3141 if let Vector(Some(sa)) = &f.short_alias {
3142 let mut sa: Vec<&char> = sa.iter().collect();
3143 s_col_width = max(sa.len(), s_col_width);
3144 s_list.append(&mut sa);
3145 }
3146 s_columns.push_back(s_list.clone());
3147 _flag_tablize_dedup!(
3148 l,
3149 nl_col_width,
3150 s_col_width,
3151 nl_list,
3152 s_list,
3153 s_columns,
3154 nl_columns
3155 );
3156 }
3157 }
3158 if let Vector(Some(c_flags)) = &cmd.c_flags {
3159 _flag_tablize_dedup!(
3160 c_flags.iter().rev(),
3161 nl_col_width,
3162 s_col_width,
3163 nl_list,
3164 s_list,
3165 s_columns,
3166 nl_columns
3167 );
3168 }
3169 if let Vector(Some(cfs)) = &ctx.common_flags {
3170 for c_flags in cfs.iter().rev() {
3171 if let Vector(Some(c_flags)) = c_flags {
3172 _flag_tablize_dedup!(
3173 c_flags.iter().rev(),
3174 nl_col_width,
3175 s_col_width,
3176 nl_list,
3177 s_list,
3178 s_columns,
3179 nl_columns
3180 )
3181 }
3182 }
3183 }
3184 drop(s_list);
3185 drop(nl_list);
3186 s_col_width *= 4;
3188 let gap_width = 3;
3189 if let Vector(Some(l_flags)) = &cmd.l_flags {
3190 let suffix = "\n";
3191 help = add_flags_help_str(
3192 help,
3193 l_flags,
3194 &mut s_columns,
3195 &mut nl_columns,
3196 s_col_width,
3197 nl_col_width,
3198 gap_width,
3199 suffix,
3200 &indent,
3201 &sp,
3202 )
3203 }
3204
3205 if let Vector(Some(c_flags)) = &cmd.c_flags {
3206 let suffix = match &cmd.sub {
3207 Vector(Some(subs)) if subs.len() > 1 => {
3208 " [common: also available in sub commands under here]\n"
3209 }
3210 Vector(Some(subs)) if !subs.is_empty() => {
3211 " [common: also available in sub command under here]\n"
3212 }
3213 _ => "\n",
3214 };
3215 help = add_flags_help_str(
3216 help,
3217 c_flags,
3218 &mut s_columns,
3219 &mut nl_columns,
3220 s_col_width,
3221 nl_col_width,
3222 gap_width,
3223 suffix,
3224 &indent,
3225 &sp,
3226 )
3227 }
3228
3229 if let Vector(Some(c_flags_list)) = &ctx.common_flags {
3230 let route_without_root = ctx.depth() > ctx.routes.len();
3231 for (index, c_flags) in c_flags_list.iter().enumerate().rev() {
3232 if let Vector(Some(c_flags)) = c_flags {
3233 let mut suffix = sp.clone() + "[common: inherited from ";
3234 if route_without_root {
3235 if index < 1 {
3236 suffix.push_str(&root_str(ctx.exe_path()))
3237 } else {
3238 match ctx.routes.get(index - 1) {
3239 Some(val) => suffix.push_str(val),
3240 None => suffix.push_str("unknown"),
3241 }
3242 }
3243 } else {
3244 match ctx.routes.get(index) {
3245 Some(val) => suffix.push_str(val),
3246 None => suffix.push_str("unknown"),
3247 }
3248 }
3249 suffix.push_str("]\n");
3250
3251 help = add_flags_help_str(
3252 help,
3253 c_flags,
3254 &mut s_columns,
3255 &mut nl_columns,
3256 s_col_width,
3257 nl_col_width,
3258 gap_width,
3259 &suffix,
3260 &indent,
3261 &sp,
3262 );
3263 }
3264 }
3265 }
3266 }
3267
3268 if let Vector(Some(sub_commands)) = &cmd.sub {
3269 help += "\nSub Command";
3270 if sub_commands.len() > 1 {
3271 help.push('s');
3272 }
3273 help += ": \n";
3274
3275 let mut na_max_width: usize = 12;
3277 for sc in sub_commands {
3278 match &sc.alias {
3279 Vector(None) => na_max_width = max(na_max_width, sc.name.len()),
3280 Vector(Some(alias)) => {
3281 na_max_width = max(
3282 na_max_width,
3283 alias
3284 .iter()
3285 .fold(sc.name.len() + 2 * alias.len(), |sum, a| sum + a.len()),
3286 );
3287 }
3288 }
3289 }
3290 na_max_width += 3;
3291
3292 for sc in sub_commands {
3293 let help_pref_len = help.len();
3294 help = help + &indent + &sc.name;
3295 if let Vector(Some(alias)) = &sc.alias {
3296 for a in alias {
3297 help = help + a;
3298 }
3299 }
3300 let sp_num = na_max_width + help_pref_len - help.len();
3301 help = help + &sp.repeat(sp_num);
3302 if let Some(description) = &sc.description {
3303 help.push_str(description);
3304 }
3305 help.push('\n');
3306 }
3307
3308 help.push_str("\nSee '");
3309 if ctx.depth() > 0 {
3310 if ctx.depth() > ctx.routes.len() {
3311 help.push_str(&root_str(ctx.exe_path()));
3312 help.push_str(&sp);
3313 }
3314 if let Vector(Some(routes)) = &ctx.routes {
3315 for route in routes {
3316 help.push_str(route);
3317 help.push_str(&sp);
3318 }
3319 }
3320 help.push_str(&cmd.name);
3321 } else {
3322 let root = if cmd.name.is_empty() {
3323 root_str(ctx.exe_path())
3324 } else {
3325 cmd.name.clone()
3326 };
3327 help.push_str(&root);
3328 }
3329 help.push_str(" <subcommand> --help' for more information");
3330 }
3331
3332 help
3333 }
3334
3335 pub fn root_str(exe_path: &str) -> String {
3337 let exe_path = std::path::Path::new(exe_path);
3338 let mut root_string = exe_path
3339 .file_stem()
3340 .unwrap_or(std::ffi::OsStr::new("root"))
3341 .to_str()
3342 .unwrap_or("root")
3343 .to_owned();
3344 if let Some(val) = exe_path.extension() {
3345 match val.to_str() {
3346 Some(val) => root_string = root_string + "[." + val + "]",
3347 None => match std::env::consts::EXE_SUFFIX {
3348 "" => {}
3349 val => root_string = root_string + "[" + val + "]",
3350 },
3351 }
3352 }
3353
3354 root_string
3355 }
3356
3357 #[cfg(test)]
3358 mod test {
3359 use super::super::Command;
3360 use super::help_tablize_with_alias_dedup;
3361 use crate::{
3362 Context, Flag, action_result, checks, copyright, crate_authors, crate_license,
3363 crate_version, done, flags, license, preset_help_command, vector,
3364 };
3365
3366 #[test]
3367 fn presets_help_func_test() {
3368 let act = |cmd: Command, ctx: Context| -> action_result!() {
3369 checks!(cmd, ctx, [error, help, version, license]);
3370 println!("check passed!");
3371 done!()
3372 };
3373 let raw_args = vec!["help".to_owned(), "--help".to_owned()];
3374 let _r = Command::with_all_field(
3375 "root".to_owned(),
3376 Some(act),
3377 crate_authors!().to_owned(),
3378 copyright!(2022, suquiya),
3379 license!(crate_license!().to_owned(),file_path=>"../LICENSE"),
3380 Some(crate_authors!().to_owned()),
3381 "root [subcommand] [options]".to_owned(),
3382 flags!(),
3383 flags!(help, license, authors, copyright, version),
3384 vector![],
3385 crate_version!().to_owned(),
3386 vector![preset_help_command!(help_tablize_with_alias_dedup)],
3387 )
3388 .run_from_args(raw_args);
3389 }
3390 }
3391 }
3392}