119625d8cSopenharmony_ci// Internal
219625d8cSopenharmony_ciuse crate::builder::StyledStr;
319625d8cSopenharmony_ciuse crate::builder::{Arg, ArgGroup, ArgPredicate, Command, PossibleValue};
419625d8cSopenharmony_ciuse crate::error::{Error, Result as ClapResult};
519625d8cSopenharmony_ciuse crate::output::Usage;
619625d8cSopenharmony_ciuse crate::parser::{ArgMatcher, ParseState};
719625d8cSopenharmony_ciuse crate::util::ChildGraph;
819625d8cSopenharmony_ciuse crate::util::FlatMap;
919625d8cSopenharmony_ciuse crate::util::FlatSet;
1019625d8cSopenharmony_ciuse crate::util::Id;
1119625d8cSopenharmony_ciuse crate::INTERNAL_ERROR_MSG;
1219625d8cSopenharmony_ci
1319625d8cSopenharmony_cipub(crate) struct Validator<'cmd> {
1419625d8cSopenharmony_ci    cmd: &'cmd Command,
1519625d8cSopenharmony_ci    required: ChildGraph<Id>,
1619625d8cSopenharmony_ci}
1719625d8cSopenharmony_ci
1819625d8cSopenharmony_ciimpl<'cmd> Validator<'cmd> {
1919625d8cSopenharmony_ci    pub(crate) fn new(cmd: &'cmd Command) -> Self {
2019625d8cSopenharmony_ci        let required = cmd.required_graph();
2119625d8cSopenharmony_ci        Validator { cmd, required }
2219625d8cSopenharmony_ci    }
2319625d8cSopenharmony_ci
2419625d8cSopenharmony_ci    pub(crate) fn validate(
2519625d8cSopenharmony_ci        &mut self,
2619625d8cSopenharmony_ci        parse_state: ParseState,
2719625d8cSopenharmony_ci        matcher: &mut ArgMatcher,
2819625d8cSopenharmony_ci    ) -> ClapResult<()> {
2919625d8cSopenharmony_ci        debug!("Validator::validate");
3019625d8cSopenharmony_ci        let conflicts = Conflicts::with_args(self.cmd, matcher);
3119625d8cSopenharmony_ci        let has_subcmd = matcher.subcommand_name().is_some();
3219625d8cSopenharmony_ci
3319625d8cSopenharmony_ci        if let ParseState::Opt(a) = parse_state {
3419625d8cSopenharmony_ci            debug!("Validator::validate: needs_val_of={:?}", a);
3519625d8cSopenharmony_ci
3619625d8cSopenharmony_ci            let o = &self.cmd[&a];
3719625d8cSopenharmony_ci            let should_err = if let Some(v) = matcher.args.get(o.get_id()) {
3819625d8cSopenharmony_ci                v.all_val_groups_empty() && o.get_min_vals() != 0
3919625d8cSopenharmony_ci            } else {
4019625d8cSopenharmony_ci                true
4119625d8cSopenharmony_ci            };
4219625d8cSopenharmony_ci            if should_err {
4319625d8cSopenharmony_ci                return Err(Error::empty_value(
4419625d8cSopenharmony_ci                    self.cmd,
4519625d8cSopenharmony_ci                    &get_possible_values_cli(o)
4619625d8cSopenharmony_ci                        .iter()
4719625d8cSopenharmony_ci                        .filter(|pv| !pv.is_hide_set())
4819625d8cSopenharmony_ci                        .map(|n| n.get_name().to_owned())
4919625d8cSopenharmony_ci                        .collect::<Vec<_>>(),
5019625d8cSopenharmony_ci                    o.to_string(),
5119625d8cSopenharmony_ci                ));
5219625d8cSopenharmony_ci            }
5319625d8cSopenharmony_ci        }
5419625d8cSopenharmony_ci
5519625d8cSopenharmony_ci        if !has_subcmd && self.cmd.is_arg_required_else_help_set() {
5619625d8cSopenharmony_ci            let num_user_values = matcher
5719625d8cSopenharmony_ci                .args()
5819625d8cSopenharmony_ci                .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
5919625d8cSopenharmony_ci                .count();
6019625d8cSopenharmony_ci            if num_user_values == 0 {
6119625d8cSopenharmony_ci                let message = self.cmd.write_help_err(false);
6219625d8cSopenharmony_ci                return Err(Error::display_help_error(self.cmd, message));
6319625d8cSopenharmony_ci            }
6419625d8cSopenharmony_ci        }
6519625d8cSopenharmony_ci        if !has_subcmd && self.cmd.is_subcommand_required_set() {
6619625d8cSopenharmony_ci            let bn = self
6719625d8cSopenharmony_ci                .cmd
6819625d8cSopenharmony_ci                .get_bin_name()
6919625d8cSopenharmony_ci                .unwrap_or_else(|| self.cmd.get_name());
7019625d8cSopenharmony_ci            return Err(Error::missing_subcommand(
7119625d8cSopenharmony_ci                self.cmd,
7219625d8cSopenharmony_ci                bn.to_string(),
7319625d8cSopenharmony_ci                self.cmd
7419625d8cSopenharmony_ci                    .all_subcommand_names()
7519625d8cSopenharmony_ci                    .map(|s| s.to_owned())
7619625d8cSopenharmony_ci                    .collect::<Vec<_>>(),
7719625d8cSopenharmony_ci                Usage::new(self.cmd)
7819625d8cSopenharmony_ci                    .required(&self.required)
7919625d8cSopenharmony_ci                    .create_usage_with_title(&[]),
8019625d8cSopenharmony_ci            ));
8119625d8cSopenharmony_ci        }
8219625d8cSopenharmony_ci
8319625d8cSopenharmony_ci        ok!(self.validate_conflicts(matcher, &conflicts));
8419625d8cSopenharmony_ci        if !(self.cmd.is_subcommand_negates_reqs_set() && has_subcmd) {
8519625d8cSopenharmony_ci            ok!(self.validate_required(matcher, &conflicts));
8619625d8cSopenharmony_ci        }
8719625d8cSopenharmony_ci
8819625d8cSopenharmony_ci        Ok(())
8919625d8cSopenharmony_ci    }
9019625d8cSopenharmony_ci
9119625d8cSopenharmony_ci    fn validate_conflicts(
9219625d8cSopenharmony_ci        &mut self,
9319625d8cSopenharmony_ci        matcher: &ArgMatcher,
9419625d8cSopenharmony_ci        conflicts: &Conflicts,
9519625d8cSopenharmony_ci    ) -> ClapResult<()> {
9619625d8cSopenharmony_ci        debug!("Validator::validate_conflicts");
9719625d8cSopenharmony_ci
9819625d8cSopenharmony_ci        ok!(self.validate_exclusive(matcher));
9919625d8cSopenharmony_ci
10019625d8cSopenharmony_ci        for (arg_id, _) in matcher
10119625d8cSopenharmony_ci            .args()
10219625d8cSopenharmony_ci            .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
10319625d8cSopenharmony_ci            .filter(|(arg_id, _)| self.cmd.find(arg_id).is_some())
10419625d8cSopenharmony_ci        {
10519625d8cSopenharmony_ci            debug!("Validator::validate_conflicts::iter: id={:?}", arg_id);
10619625d8cSopenharmony_ci            let conflicts = conflicts.gather_conflicts(self.cmd, arg_id);
10719625d8cSopenharmony_ci            ok!(self.build_conflict_err(arg_id, &conflicts, matcher));
10819625d8cSopenharmony_ci        }
10919625d8cSopenharmony_ci
11019625d8cSopenharmony_ci        Ok(())
11119625d8cSopenharmony_ci    }
11219625d8cSopenharmony_ci
11319625d8cSopenharmony_ci    fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> {
11419625d8cSopenharmony_ci        debug!("Validator::validate_exclusive");
11519625d8cSopenharmony_ci        let args_count = matcher
11619625d8cSopenharmony_ci            .args()
11719625d8cSopenharmony_ci            .filter(|(arg_id, matched)| {
11819625d8cSopenharmony_ci                matched.check_explicit(&crate::builder::ArgPredicate::IsPresent)
11919625d8cSopenharmony_ci                    // Avoid including our own groups by checking none of them.  If a group is present, the
12019625d8cSopenharmony_ci                    // args for the group will be.
12119625d8cSopenharmony_ci                    && self.cmd.find(arg_id).is_some()
12219625d8cSopenharmony_ci            })
12319625d8cSopenharmony_ci            .count();
12419625d8cSopenharmony_ci        if args_count <= 1 {
12519625d8cSopenharmony_ci            // Nothing present to conflict with
12619625d8cSopenharmony_ci            return Ok(());
12719625d8cSopenharmony_ci        }
12819625d8cSopenharmony_ci
12919625d8cSopenharmony_ci        matcher
13019625d8cSopenharmony_ci            .args()
13119625d8cSopenharmony_ci            .filter(|(_, matched)| matched.check_explicit(&crate::builder::ArgPredicate::IsPresent))
13219625d8cSopenharmony_ci            .filter_map(|(id, _)| {
13319625d8cSopenharmony_ci                debug!("Validator::validate_exclusive:iter:{:?}", id);
13419625d8cSopenharmony_ci                self.cmd
13519625d8cSopenharmony_ci                    .find(id)
13619625d8cSopenharmony_ci                    // Find `arg`s which are exclusive but also appear with other args.
13719625d8cSopenharmony_ci                    .filter(|&arg| arg.is_exclusive_set() && args_count > 1)
13819625d8cSopenharmony_ci            })
13919625d8cSopenharmony_ci            // Throw an error for the first conflict found.
14019625d8cSopenharmony_ci            .try_for_each(|arg| {
14119625d8cSopenharmony_ci                Err(Error::argument_conflict(
14219625d8cSopenharmony_ci                    self.cmd,
14319625d8cSopenharmony_ci                    arg.to_string(),
14419625d8cSopenharmony_ci                    Vec::new(),
14519625d8cSopenharmony_ci                    Usage::new(self.cmd)
14619625d8cSopenharmony_ci                        .required(&self.required)
14719625d8cSopenharmony_ci                        .create_usage_with_title(&[]),
14819625d8cSopenharmony_ci                ))
14919625d8cSopenharmony_ci            })
15019625d8cSopenharmony_ci    }
15119625d8cSopenharmony_ci
15219625d8cSopenharmony_ci    fn build_conflict_err(
15319625d8cSopenharmony_ci        &self,
15419625d8cSopenharmony_ci        name: &Id,
15519625d8cSopenharmony_ci        conflict_ids: &[Id],
15619625d8cSopenharmony_ci        matcher: &ArgMatcher,
15719625d8cSopenharmony_ci    ) -> ClapResult<()> {
15819625d8cSopenharmony_ci        if conflict_ids.is_empty() {
15919625d8cSopenharmony_ci            return Ok(());
16019625d8cSopenharmony_ci        }
16119625d8cSopenharmony_ci
16219625d8cSopenharmony_ci        debug!("Validator::build_conflict_err: name={:?}", name);
16319625d8cSopenharmony_ci        let mut seen = FlatSet::new();
16419625d8cSopenharmony_ci        let conflicts = conflict_ids
16519625d8cSopenharmony_ci            .iter()
16619625d8cSopenharmony_ci            .flat_map(|c_id| {
16719625d8cSopenharmony_ci                if self.cmd.find_group(c_id).is_some() {
16819625d8cSopenharmony_ci                    self.cmd.unroll_args_in_group(c_id)
16919625d8cSopenharmony_ci                } else {
17019625d8cSopenharmony_ci                    vec![c_id.clone()]
17119625d8cSopenharmony_ci                }
17219625d8cSopenharmony_ci            })
17319625d8cSopenharmony_ci            .filter_map(|c_id| {
17419625d8cSopenharmony_ci                seen.insert(c_id.clone()).then(|| {
17519625d8cSopenharmony_ci                    let c_arg = self.cmd.find(&c_id).expect(INTERNAL_ERROR_MSG);
17619625d8cSopenharmony_ci                    c_arg.to_string()
17719625d8cSopenharmony_ci                })
17819625d8cSopenharmony_ci            })
17919625d8cSopenharmony_ci            .collect();
18019625d8cSopenharmony_ci
18119625d8cSopenharmony_ci        let former_arg = self.cmd.find(name).expect(INTERNAL_ERROR_MSG);
18219625d8cSopenharmony_ci        let usg = self.build_conflict_err_usage(matcher, conflict_ids);
18319625d8cSopenharmony_ci        Err(Error::argument_conflict(
18419625d8cSopenharmony_ci            self.cmd,
18519625d8cSopenharmony_ci            former_arg.to_string(),
18619625d8cSopenharmony_ci            conflicts,
18719625d8cSopenharmony_ci            usg,
18819625d8cSopenharmony_ci        ))
18919625d8cSopenharmony_ci    }
19019625d8cSopenharmony_ci
19119625d8cSopenharmony_ci    fn build_conflict_err_usage(
19219625d8cSopenharmony_ci        &self,
19319625d8cSopenharmony_ci        matcher: &ArgMatcher,
19419625d8cSopenharmony_ci        conflicting_keys: &[Id],
19519625d8cSopenharmony_ci    ) -> Option<StyledStr> {
19619625d8cSopenharmony_ci        let used_filtered: Vec<Id> = matcher
19719625d8cSopenharmony_ci            .args()
19819625d8cSopenharmony_ci            .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
19919625d8cSopenharmony_ci            .map(|(n, _)| n)
20019625d8cSopenharmony_ci            .filter(|n| {
20119625d8cSopenharmony_ci                // Filter out the args we don't want to specify.
20219625d8cSopenharmony_ci                self.cmd.find(n).map_or(false, |a| !a.is_hide_set())
20319625d8cSopenharmony_ci            })
20419625d8cSopenharmony_ci            .filter(|key| !conflicting_keys.contains(key))
20519625d8cSopenharmony_ci            .cloned()
20619625d8cSopenharmony_ci            .collect();
20719625d8cSopenharmony_ci        let required: Vec<Id> = used_filtered
20819625d8cSopenharmony_ci            .iter()
20919625d8cSopenharmony_ci            .filter_map(|key| self.cmd.find(key))
21019625d8cSopenharmony_ci            .flat_map(|arg| arg.requires.iter().map(|item| &item.1))
21119625d8cSopenharmony_ci            .filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key))
21219625d8cSopenharmony_ci            .chain(used_filtered.iter())
21319625d8cSopenharmony_ci            .cloned()
21419625d8cSopenharmony_ci            .collect();
21519625d8cSopenharmony_ci        Usage::new(self.cmd)
21619625d8cSopenharmony_ci            .required(&self.required)
21719625d8cSopenharmony_ci            .create_usage_with_title(&required)
21819625d8cSopenharmony_ci    }
21919625d8cSopenharmony_ci
22019625d8cSopenharmony_ci    fn gather_requires(&mut self, matcher: &ArgMatcher) {
22119625d8cSopenharmony_ci        debug!("Validator::gather_requires");
22219625d8cSopenharmony_ci        for (name, matched) in matcher
22319625d8cSopenharmony_ci            .args()
22419625d8cSopenharmony_ci            .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
22519625d8cSopenharmony_ci        {
22619625d8cSopenharmony_ci            debug!("Validator::gather_requires:iter:{:?}", name);
22719625d8cSopenharmony_ci            if let Some(arg) = self.cmd.find(name) {
22819625d8cSopenharmony_ci                let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> {
22919625d8cSopenharmony_ci                    let required = matched.check_explicit(val);
23019625d8cSopenharmony_ci                    required.then(|| req_arg.clone())
23119625d8cSopenharmony_ci                };
23219625d8cSopenharmony_ci
23319625d8cSopenharmony_ci                for req in self.cmd.unroll_arg_requires(is_relevant, arg.get_id()) {
23419625d8cSopenharmony_ci                    self.required.insert(req);
23519625d8cSopenharmony_ci                }
23619625d8cSopenharmony_ci            } else if let Some(g) = self.cmd.find_group(name) {
23719625d8cSopenharmony_ci                debug!("Validator::gather_requires:iter:{:?}:group", name);
23819625d8cSopenharmony_ci                for r in &g.requires {
23919625d8cSopenharmony_ci                    self.required.insert(r.clone());
24019625d8cSopenharmony_ci                }
24119625d8cSopenharmony_ci            }
24219625d8cSopenharmony_ci        }
24319625d8cSopenharmony_ci    }
24419625d8cSopenharmony_ci
24519625d8cSopenharmony_ci    fn validate_required(&mut self, matcher: &ArgMatcher, conflicts: &Conflicts) -> ClapResult<()> {
24619625d8cSopenharmony_ci        debug!("Validator::validate_required: required={:?}", self.required);
24719625d8cSopenharmony_ci        self.gather_requires(matcher);
24819625d8cSopenharmony_ci
24919625d8cSopenharmony_ci        let mut missing_required = Vec::new();
25019625d8cSopenharmony_ci        let mut highest_index = 0;
25119625d8cSopenharmony_ci
25219625d8cSopenharmony_ci        let is_exclusive_present = matcher
25319625d8cSopenharmony_ci            .args()
25419625d8cSopenharmony_ci            .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
25519625d8cSopenharmony_ci            .any(|(id, _)| {
25619625d8cSopenharmony_ci                self.cmd
25719625d8cSopenharmony_ci                    .find(id)
25819625d8cSopenharmony_ci                    .map(|arg| arg.is_exclusive_set())
25919625d8cSopenharmony_ci                    .unwrap_or_default()
26019625d8cSopenharmony_ci            });
26119625d8cSopenharmony_ci        debug!(
26219625d8cSopenharmony_ci            "Validator::validate_required: is_exclusive_present={}",
26319625d8cSopenharmony_ci            is_exclusive_present
26419625d8cSopenharmony_ci        );
26519625d8cSopenharmony_ci
26619625d8cSopenharmony_ci        for arg_or_group in self
26719625d8cSopenharmony_ci            .required
26819625d8cSopenharmony_ci            .iter()
26919625d8cSopenharmony_ci            .filter(|r| !matcher.check_explicit(r, &ArgPredicate::IsPresent))
27019625d8cSopenharmony_ci        {
27119625d8cSopenharmony_ci            debug!("Validator::validate_required:iter:aog={:?}", arg_or_group);
27219625d8cSopenharmony_ci            if let Some(arg) = self.cmd.find(arg_or_group) {
27319625d8cSopenharmony_ci                debug!("Validator::validate_required:iter: This is an arg");
27419625d8cSopenharmony_ci                if !is_exclusive_present && !self.is_missing_required_ok(arg, conflicts) {
27519625d8cSopenharmony_ci                    debug!(
27619625d8cSopenharmony_ci                        "Validator::validate_required:iter: Missing {:?}",
27719625d8cSopenharmony_ci                        arg.get_id()
27819625d8cSopenharmony_ci                    );
27919625d8cSopenharmony_ci                    missing_required.push(arg.get_id().clone());
28019625d8cSopenharmony_ci                    if !arg.is_last_set() {
28119625d8cSopenharmony_ci                        highest_index = highest_index.max(arg.get_index().unwrap_or(0));
28219625d8cSopenharmony_ci                    }
28319625d8cSopenharmony_ci                }
28419625d8cSopenharmony_ci            } else if let Some(group) = self.cmd.find_group(arg_or_group) {
28519625d8cSopenharmony_ci                debug!("Validator::validate_required:iter: This is a group");
28619625d8cSopenharmony_ci                if !self
28719625d8cSopenharmony_ci                    .cmd
28819625d8cSopenharmony_ci                    .unroll_args_in_group(&group.id)
28919625d8cSopenharmony_ci                    .iter()
29019625d8cSopenharmony_ci                    .any(|a| matcher.check_explicit(a, &ArgPredicate::IsPresent))
29119625d8cSopenharmony_ci                {
29219625d8cSopenharmony_ci                    debug!(
29319625d8cSopenharmony_ci                        "Validator::validate_required:iter: Missing {:?}",
29419625d8cSopenharmony_ci                        group.get_id()
29519625d8cSopenharmony_ci                    );
29619625d8cSopenharmony_ci                    missing_required.push(group.get_id().clone());
29719625d8cSopenharmony_ci                }
29819625d8cSopenharmony_ci            }
29919625d8cSopenharmony_ci        }
30019625d8cSopenharmony_ci
30119625d8cSopenharmony_ci        // Validate the conditionally required args
30219625d8cSopenharmony_ci        for a in self
30319625d8cSopenharmony_ci            .cmd
30419625d8cSopenharmony_ci            .get_arguments()
30519625d8cSopenharmony_ci            .filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
30619625d8cSopenharmony_ci        {
30719625d8cSopenharmony_ci            let mut required = false;
30819625d8cSopenharmony_ci
30919625d8cSopenharmony_ci            for (other, val) in &a.r_ifs {
31019625d8cSopenharmony_ci                if matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) {
31119625d8cSopenharmony_ci                    debug!(
31219625d8cSopenharmony_ci                        "Validator::validate_required:iter: Missing {:?}",
31319625d8cSopenharmony_ci                        a.get_id()
31419625d8cSopenharmony_ci                    );
31519625d8cSopenharmony_ci                    required = true;
31619625d8cSopenharmony_ci                }
31719625d8cSopenharmony_ci            }
31819625d8cSopenharmony_ci
31919625d8cSopenharmony_ci            let match_all = a.r_ifs_all.iter().all(|(other, val)| {
32019625d8cSopenharmony_ci                matcher.check_explicit(other, &ArgPredicate::Equals(val.into()))
32119625d8cSopenharmony_ci            });
32219625d8cSopenharmony_ci            if match_all && !a.r_ifs_all.is_empty() {
32319625d8cSopenharmony_ci                debug!(
32419625d8cSopenharmony_ci                    "Validator::validate_required:iter: Missing {:?}",
32519625d8cSopenharmony_ci                    a.get_id()
32619625d8cSopenharmony_ci                );
32719625d8cSopenharmony_ci                required = true;
32819625d8cSopenharmony_ci            }
32919625d8cSopenharmony_ci
33019625d8cSopenharmony_ci            if (!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
33119625d8cSopenharmony_ci                && self.fails_arg_required_unless(a, matcher)
33219625d8cSopenharmony_ci            {
33319625d8cSopenharmony_ci                debug!(
33419625d8cSopenharmony_ci                    "Validator::validate_required:iter: Missing {:?}",
33519625d8cSopenharmony_ci                    a.get_id()
33619625d8cSopenharmony_ci                );
33719625d8cSopenharmony_ci                required = true;
33819625d8cSopenharmony_ci            }
33919625d8cSopenharmony_ci
34019625d8cSopenharmony_ci            if required {
34119625d8cSopenharmony_ci                missing_required.push(a.get_id().clone());
34219625d8cSopenharmony_ci                if !a.is_last_set() {
34319625d8cSopenharmony_ci                    highest_index = highest_index.max(a.get_index().unwrap_or(0));
34419625d8cSopenharmony_ci                }
34519625d8cSopenharmony_ci            }
34619625d8cSopenharmony_ci        }
34719625d8cSopenharmony_ci
34819625d8cSopenharmony_ci        // For display purposes, include all of the preceding positional arguments
34919625d8cSopenharmony_ci        if !self.cmd.is_allow_missing_positional_set() {
35019625d8cSopenharmony_ci            for pos in self
35119625d8cSopenharmony_ci                .cmd
35219625d8cSopenharmony_ci                .get_positionals()
35319625d8cSopenharmony_ci                .filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
35419625d8cSopenharmony_ci            {
35519625d8cSopenharmony_ci                if pos.get_index() < Some(highest_index) {
35619625d8cSopenharmony_ci                    debug!(
35719625d8cSopenharmony_ci                        "Validator::validate_required:iter: Missing {:?}",
35819625d8cSopenharmony_ci                        pos.get_id()
35919625d8cSopenharmony_ci                    );
36019625d8cSopenharmony_ci                    missing_required.push(pos.get_id().clone());
36119625d8cSopenharmony_ci                }
36219625d8cSopenharmony_ci            }
36319625d8cSopenharmony_ci        }
36419625d8cSopenharmony_ci
36519625d8cSopenharmony_ci        if !missing_required.is_empty() {
36619625d8cSopenharmony_ci            ok!(self.missing_required_error(matcher, missing_required));
36719625d8cSopenharmony_ci        }
36819625d8cSopenharmony_ci
36919625d8cSopenharmony_ci        Ok(())
37019625d8cSopenharmony_ci    }
37119625d8cSopenharmony_ci
37219625d8cSopenharmony_ci    fn is_missing_required_ok(&self, a: &Arg, conflicts: &Conflicts) -> bool {
37319625d8cSopenharmony_ci        debug!("Validator::is_missing_required_ok: {}", a.get_id());
37419625d8cSopenharmony_ci        if !conflicts.gather_conflicts(self.cmd, a.get_id()).is_empty() {
37519625d8cSopenharmony_ci            debug!("Validator::is_missing_required_ok: true (self)");
37619625d8cSopenharmony_ci            return true;
37719625d8cSopenharmony_ci        }
37819625d8cSopenharmony_ci        for group_id in self.cmd.groups_for_arg(a.get_id()) {
37919625d8cSopenharmony_ci            if !conflicts.gather_conflicts(self.cmd, &group_id).is_empty() {
38019625d8cSopenharmony_ci                debug!("Validator::is_missing_required_ok: true ({})", group_id);
38119625d8cSopenharmony_ci                return true;
38219625d8cSopenharmony_ci            }
38319625d8cSopenharmony_ci        }
38419625d8cSopenharmony_ci        false
38519625d8cSopenharmony_ci    }
38619625d8cSopenharmony_ci
38719625d8cSopenharmony_ci    // Failing a required unless means, the arg's "unless" wasn't present, and neither were they
38819625d8cSopenharmony_ci    fn fails_arg_required_unless(&self, a: &Arg, matcher: &ArgMatcher) -> bool {
38919625d8cSopenharmony_ci        debug!("Validator::fails_arg_required_unless: a={:?}", a.get_id());
39019625d8cSopenharmony_ci        let exists = |id| matcher.check_explicit(id, &ArgPredicate::IsPresent);
39119625d8cSopenharmony_ci
39219625d8cSopenharmony_ci        (a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists))
39319625d8cSopenharmony_ci            && !a.r_unless.iter().any(exists)
39419625d8cSopenharmony_ci    }
39519625d8cSopenharmony_ci
39619625d8cSopenharmony_ci    // `req_args`: an arg to include in the error even if not used
39719625d8cSopenharmony_ci    fn missing_required_error(
39819625d8cSopenharmony_ci        &self,
39919625d8cSopenharmony_ci        matcher: &ArgMatcher,
40019625d8cSopenharmony_ci        raw_req_args: Vec<Id>,
40119625d8cSopenharmony_ci    ) -> ClapResult<()> {
40219625d8cSopenharmony_ci        debug!("Validator::missing_required_error; incl={:?}", raw_req_args);
40319625d8cSopenharmony_ci        debug!(
40419625d8cSopenharmony_ci            "Validator::missing_required_error: reqs={:?}",
40519625d8cSopenharmony_ci            self.required
40619625d8cSopenharmony_ci        );
40719625d8cSopenharmony_ci
40819625d8cSopenharmony_ci        let usg = Usage::new(self.cmd).required(&self.required);
40919625d8cSopenharmony_ci
41019625d8cSopenharmony_ci        let req_args = {
41119625d8cSopenharmony_ci            #[cfg(feature = "usage")]
41219625d8cSopenharmony_ci            {
41319625d8cSopenharmony_ci                usg.get_required_usage_from(&raw_req_args, Some(matcher), true)
41419625d8cSopenharmony_ci                    .into_iter()
41519625d8cSopenharmony_ci                    .map(|s| s.to_string())
41619625d8cSopenharmony_ci                    .collect::<Vec<_>>()
41719625d8cSopenharmony_ci            }
41819625d8cSopenharmony_ci
41919625d8cSopenharmony_ci            #[cfg(not(feature = "usage"))]
42019625d8cSopenharmony_ci            {
42119625d8cSopenharmony_ci                raw_req_args
42219625d8cSopenharmony_ci                    .iter()
42319625d8cSopenharmony_ci                    .map(|id| {
42419625d8cSopenharmony_ci                        if let Some(arg) = self.cmd.find(id) {
42519625d8cSopenharmony_ci                            arg.to_string()
42619625d8cSopenharmony_ci                        } else if let Some(_group) = self.cmd.find_group(id) {
42719625d8cSopenharmony_ci                            self.cmd.format_group(id).to_string()
42819625d8cSopenharmony_ci                        } else {
42919625d8cSopenharmony_ci                            debug_assert!(false, "id={:?} is unknown", id);
43019625d8cSopenharmony_ci                            "".to_owned()
43119625d8cSopenharmony_ci                        }
43219625d8cSopenharmony_ci                    })
43319625d8cSopenharmony_ci                    .collect::<Vec<_>>()
43419625d8cSopenharmony_ci            }
43519625d8cSopenharmony_ci        };
43619625d8cSopenharmony_ci
43719625d8cSopenharmony_ci        debug!(
43819625d8cSopenharmony_ci            "Validator::missing_required_error: req_args={:#?}",
43919625d8cSopenharmony_ci            req_args
44019625d8cSopenharmony_ci        );
44119625d8cSopenharmony_ci
44219625d8cSopenharmony_ci        let used: Vec<Id> = matcher
44319625d8cSopenharmony_ci            .args()
44419625d8cSopenharmony_ci            .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
44519625d8cSopenharmony_ci            .map(|(n, _)| n)
44619625d8cSopenharmony_ci            .filter(|n| {
44719625d8cSopenharmony_ci                // Filter out the args we don't want to specify.
44819625d8cSopenharmony_ci                self.cmd.find(n).map_or(false, |a| !a.is_hide_set())
44919625d8cSopenharmony_ci            })
45019625d8cSopenharmony_ci            .cloned()
45119625d8cSopenharmony_ci            .chain(raw_req_args)
45219625d8cSopenharmony_ci            .collect();
45319625d8cSopenharmony_ci
45419625d8cSopenharmony_ci        Err(Error::missing_required_argument(
45519625d8cSopenharmony_ci            self.cmd,
45619625d8cSopenharmony_ci            req_args,
45719625d8cSopenharmony_ci            usg.create_usage_with_title(&used),
45819625d8cSopenharmony_ci        ))
45919625d8cSopenharmony_ci    }
46019625d8cSopenharmony_ci}
46119625d8cSopenharmony_ci
46219625d8cSopenharmony_ci#[derive(Default, Clone, Debug)]
46319625d8cSopenharmony_cistruct Conflicts {
46419625d8cSopenharmony_ci    potential: FlatMap<Id, Vec<Id>>,
46519625d8cSopenharmony_ci}
46619625d8cSopenharmony_ci
46719625d8cSopenharmony_ciimpl Conflicts {
46819625d8cSopenharmony_ci    fn with_args(cmd: &Command, matcher: &ArgMatcher) -> Self {
46919625d8cSopenharmony_ci        let mut potential = FlatMap::new();
47019625d8cSopenharmony_ci        potential.extend_unchecked(
47119625d8cSopenharmony_ci            matcher
47219625d8cSopenharmony_ci                .args()
47319625d8cSopenharmony_ci                .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
47419625d8cSopenharmony_ci                .map(|(id, _)| {
47519625d8cSopenharmony_ci                    let conf = gather_direct_conflicts(cmd, id);
47619625d8cSopenharmony_ci                    (id.clone(), conf)
47719625d8cSopenharmony_ci                }),
47819625d8cSopenharmony_ci        );
47919625d8cSopenharmony_ci        Self { potential }
48019625d8cSopenharmony_ci    }
48119625d8cSopenharmony_ci
48219625d8cSopenharmony_ci    fn gather_conflicts(&self, cmd: &Command, arg_id: &Id) -> Vec<Id> {
48319625d8cSopenharmony_ci        debug!("Conflicts::gather_conflicts: arg={:?}", arg_id);
48419625d8cSopenharmony_ci        let mut conflicts = Vec::new();
48519625d8cSopenharmony_ci
48619625d8cSopenharmony_ci        let arg_id_conflicts_storage;
48719625d8cSopenharmony_ci        let arg_id_conflicts = if let Some(arg_id_conflicts) = self.get_direct_conflicts(arg_id) {
48819625d8cSopenharmony_ci            arg_id_conflicts
48919625d8cSopenharmony_ci        } else {
49019625d8cSopenharmony_ci            // `is_missing_required_ok` is a case where we check not-present args for conflicts
49119625d8cSopenharmony_ci            arg_id_conflicts_storage = gather_direct_conflicts(cmd, arg_id);
49219625d8cSopenharmony_ci            &arg_id_conflicts_storage
49319625d8cSopenharmony_ci        };
49419625d8cSopenharmony_ci        for (other_arg_id, other_arg_id_conflicts) in self.potential.iter() {
49519625d8cSopenharmony_ci            if arg_id == other_arg_id {
49619625d8cSopenharmony_ci                continue;
49719625d8cSopenharmony_ci            }
49819625d8cSopenharmony_ci
49919625d8cSopenharmony_ci            if arg_id_conflicts.contains(other_arg_id) {
50019625d8cSopenharmony_ci                conflicts.push(other_arg_id.clone());
50119625d8cSopenharmony_ci            }
50219625d8cSopenharmony_ci            if other_arg_id_conflicts.contains(arg_id) {
50319625d8cSopenharmony_ci                conflicts.push(other_arg_id.clone());
50419625d8cSopenharmony_ci            }
50519625d8cSopenharmony_ci        }
50619625d8cSopenharmony_ci
50719625d8cSopenharmony_ci        debug!("Conflicts::gather_conflicts: conflicts={:?}", conflicts);
50819625d8cSopenharmony_ci        conflicts
50919625d8cSopenharmony_ci    }
51019625d8cSopenharmony_ci
51119625d8cSopenharmony_ci    fn get_direct_conflicts(&self, arg_id: &Id) -> Option<&[Id]> {
51219625d8cSopenharmony_ci        self.potential.get(arg_id).map(Vec::as_slice)
51319625d8cSopenharmony_ci    }
51419625d8cSopenharmony_ci}
51519625d8cSopenharmony_ci
51619625d8cSopenharmony_cifn gather_direct_conflicts(cmd: &Command, id: &Id) -> Vec<Id> {
51719625d8cSopenharmony_ci    let conf = if let Some(arg) = cmd.find(id) {
51819625d8cSopenharmony_ci        gather_arg_direct_conflicts(cmd, arg)
51919625d8cSopenharmony_ci    } else if let Some(group) = cmd.find_group(id) {
52019625d8cSopenharmony_ci        gather_group_direct_conflicts(group)
52119625d8cSopenharmony_ci    } else {
52219625d8cSopenharmony_ci        debug_assert!(false, "id={id:?} is unknown");
52319625d8cSopenharmony_ci        Vec::new()
52419625d8cSopenharmony_ci    };
52519625d8cSopenharmony_ci    debug!("Conflicts::gather_direct_conflicts id={id:?}, conflicts={conf:?}",);
52619625d8cSopenharmony_ci    conf
52719625d8cSopenharmony_ci}
52819625d8cSopenharmony_ci
52919625d8cSopenharmony_cifn gather_arg_direct_conflicts(cmd: &Command, arg: &Arg) -> Vec<Id> {
53019625d8cSopenharmony_ci    let mut conf = arg.blacklist.clone();
53119625d8cSopenharmony_ci    for group_id in cmd.groups_for_arg(arg.get_id()) {
53219625d8cSopenharmony_ci        let group = cmd.find_group(&group_id).expect(INTERNAL_ERROR_MSG);
53319625d8cSopenharmony_ci        conf.extend(group.conflicts.iter().cloned());
53419625d8cSopenharmony_ci        if !group.multiple {
53519625d8cSopenharmony_ci            for member_id in &group.args {
53619625d8cSopenharmony_ci                if member_id != arg.get_id() {
53719625d8cSopenharmony_ci                    conf.push(member_id.clone());
53819625d8cSopenharmony_ci                }
53919625d8cSopenharmony_ci            }
54019625d8cSopenharmony_ci        }
54119625d8cSopenharmony_ci    }
54219625d8cSopenharmony_ci
54319625d8cSopenharmony_ci    // Overrides are implicitly conflicts
54419625d8cSopenharmony_ci    conf.extend(arg.overrides.iter().cloned());
54519625d8cSopenharmony_ci
54619625d8cSopenharmony_ci    conf
54719625d8cSopenharmony_ci}
54819625d8cSopenharmony_ci
54919625d8cSopenharmony_cifn gather_group_direct_conflicts(group: &ArgGroup) -> Vec<Id> {
55019625d8cSopenharmony_ci    group.conflicts.clone()
55119625d8cSopenharmony_ci}
55219625d8cSopenharmony_ci
55319625d8cSopenharmony_cipub(crate) fn get_possible_values_cli(a: &Arg) -> Vec<PossibleValue> {
55419625d8cSopenharmony_ci    if !a.is_takes_value_set() {
55519625d8cSopenharmony_ci        vec![]
55619625d8cSopenharmony_ci    } else {
55719625d8cSopenharmony_ci        a.get_value_parser()
55819625d8cSopenharmony_ci            .possible_values()
55919625d8cSopenharmony_ci            .map(|pvs| pvs.collect())
56019625d8cSopenharmony_ci            .unwrap_or_default()
56119625d8cSopenharmony_ci    }
56219625d8cSopenharmony_ci}
563