Skip to content

Commit

Permalink
feat(parser): Expose ValueSource
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Feb 8, 2022
1 parent edf9d05 commit f004524
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 53 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub use crate::build::{
App, AppFlags, AppSettings, Arg, ArgFlags, ArgGroup, ArgSettings, PossibleValue, ValueHint,
};
pub use crate::error::Error;
pub use crate::parse::{ArgMatches, Indices, OsValues, Values};
pub use crate::parse::{ArgMatches, Indices, OsValues, ValueSource, Values};
#[cfg(feature = "color")]
pub use crate::util::color::ColorChoice;

Expand Down
14 changes: 7 additions & 7 deletions src/parse/arg_matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{collections::HashMap, ffi::OsString, mem, ops::Deref};
// Internal
use crate::{
build::{App, Arg, ArgPredicate, ArgSettings},
parse::{ArgMatches, MatchedArg, SubCommand, ValueType},
parse::{ArgMatches, MatchedArg, SubCommand, ValueSource},
util::Id,
};

Expand Down Expand Up @@ -129,7 +129,7 @@ impl ArgMatcher {
let id = &arg.id;
debug!("ArgMatcher::inc_occurrence_of_arg: id={:?}", id);
let ma = self.entry(id).or_insert(MatchedArg::new());
ma.update_ty(ValueType::CommandLine);
ma.update_ty(ValueSource::CommandLine);
ma.set_ignore_case(arg.is_set(ArgSettings::IgnoreCase));
ma.invalid_utf8_allowed(arg.is_set(ArgSettings::AllowInvalidUtf8));
ma.inc_occurrences();
Expand All @@ -138,19 +138,19 @@ impl ArgMatcher {
pub(crate) fn inc_occurrence_of_group(&mut self, id: &Id) {
debug!("ArgMatcher::inc_occurrence_of_group: id={:?}", id);
let ma = self.entry(id).or_insert(MatchedArg::new());
ma.update_ty(ValueType::CommandLine);
ma.update_ty(ValueSource::CommandLine);
ma.inc_occurrences();
}

pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType, append: bool) {
pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource, append: bool) {
if append {
self.append_val_to(arg, val, ty);
} else {
self.push_val_to(arg, val, ty);
}
}

fn push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) {
fn push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
// We will manually inc occurrences later(for flexibility under
// specific circumstances, like only add one occurrence for flag
// when we met: `--flag=one,two`).
Expand All @@ -159,7 +159,7 @@ impl ArgMatcher {
ma.push_val(val);
}

fn append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) {
fn append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
let ma = self.entry(arg).or_default();
ma.update_ty(ty);
ma.append_val(val);
Expand All @@ -170,7 +170,7 @@ impl ArgMatcher {
ma.new_val_group();
}

pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueType) {
pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueSource) {
let ma = self.entry(arg).or_default();
ma.update_ty(ty);
ma.push_index(idx);
Expand Down
43 changes: 38 additions & 5 deletions src/parse/matches/arg_matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ use std::{
use indexmap::IndexMap;

// Internal
use crate::{
parse::MatchedArg,
util::{Id, Key},
{Error, INVALID_UTF8},
};
use crate::parse::MatchedArg;
use crate::parse::ValueSource;
use crate::util::{Id, Key};
use crate::{Error, INVALID_UTF8};

/// Container for parse results.
///
Expand Down Expand Up @@ -627,6 +626,40 @@ impl ArgMatches {
self.args.contains_key(&id)
}

/// Check if an argument was present at runtime.
///
/// *NOTE:* This will always return `true` if [`default_value`] has been set.
/// [`occurrences_of`] can be used to check if a value is present at runtime.
///
/// # Panics
///
/// If `id` is is not a valid argument or group name.
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d'))
/// .get_matches_from(vec![
/// "myprog", "-d"
/// ]);
///
/// assert!(m.is_present("debug"));
/// ```
///
/// [`default_value`]: crate::Arg::default_value()
/// [`occurrences_of`]: ArgMatches::occurrences_of()
pub fn value_source<T: Key>(&self, id: T) -> Option<ValueSource> {
let id = Id::from(id);

#[cfg(debug_assertions)]
let value = self.get_arg(&id);

value.map(MatchedArg::source)
}

/// The number of times an argument was used at runtime.
///
/// If an argument isn't present it will return `0`.
Expand Down
22 changes: 9 additions & 13 deletions src/parse/matches/matched_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ use std::{
};

use crate::build::ArgPredicate;
use crate::parse::ValueSource;
use crate::util::eq_ignore_case;
use crate::INTERNAL_ERROR_MSG;

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct MatchedArg {
occurs: u64,
ty: ValueType,
ty: ValueSource,
indices: Vec<usize>,
vals: Vec<Vec<OsString>>,
ignore_case: bool,
Expand All @@ -23,7 +24,7 @@ impl MatchedArg {
pub(crate) fn new() -> Self {
MatchedArg {
occurs: 0,
ty: ValueType::Unknown,
ty: ValueSource::Unknown,
indices: Vec::new(),
vals: Vec::new(),
ignore_case: false,
Expand Down Expand Up @@ -118,7 +119,7 @@ impl MatchedArg {
}

pub(crate) fn check_explicit(&self, predicate: ArgPredicate) -> bool {
if self.ty == ValueType::DefaultValue {
if self.ty == ValueSource::DefaultValue {
return false;
}

Expand All @@ -135,7 +136,11 @@ impl MatchedArg {
}
}

pub(crate) fn update_ty(&mut self, ty: ValueType) {
pub(crate) fn source(&self) -> ValueSource {
self.ty
}

pub(crate) fn update_ty(&mut self, ty: ValueSource) {
self.ty = self.ty.max(ty);
}

Expand All @@ -158,15 +163,6 @@ impl Default for MatchedArg {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum ValueType {
Unknown,
DefaultValue,
#[cfg(feature = "env")]
EnvVariable,
CommandLine,
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
10 changes: 5 additions & 5 deletions src/parse/matches/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
mod arg_matches;
mod matched_arg;
mod value_source;

pub(crate) use self::{
arg_matches::SubCommand,
matched_arg::{MatchedArg, ValueType},
};
pub use arg_matches::{ArgMatches, Indices, OsValues, Values};
pub use value_source::ValueSource;

pub use self::arg_matches::{ArgMatches, Indices, OsValues, Values};
pub(crate) use arg_matches::SubCommand;
pub(crate) use matched_arg::MatchedArg;
12 changes: 12 additions & 0 deletions src/parse/matches/value_source.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/// Origin of the argument's value
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ValueSource {
/// Origin is unknown
Unknown,
/// Value came [`Arg::default_value`][crate::Arg::default_value]
DefaultValue,
/// Value came [`Arg::env`][crate::Arg::env]
EnvVariable,
/// Value was passed in on the command-line
CommandLine,
}
12 changes: 5 additions & 7 deletions src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ pub mod matches;
mod parser;
mod validator;

pub(crate) use self::{
arg_matcher::ArgMatcher,
matches::{MatchedArg, SubCommand, ValueType},
parser::{Input, ParseState, Parser},
validator::Validator,
};
pub(crate) use self::arg_matcher::ArgMatcher;
pub(crate) use self::matches::{MatchedArg, SubCommand};
pub(crate) use self::parser::{Input, ParseState, Parser};
pub(crate) use self::validator::Validator;

pub use self::matches::{ArgMatches, Indices, OsValues, Values};
pub use self::matches::{ArgMatches, Indices, OsValues, ValueSource, Values};
30 changes: 15 additions & 15 deletions src/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::mkeymap::KeyType;
use crate::output::{fmt::Colorizer, Help, HelpWriter, Usage};
use crate::parse::features::suggestions;
use crate::parse::{ArgMatcher, SubCommand};
use crate::parse::{Validator, ValueType};
use crate::parse::{Validator, ValueSource};
use crate::util::{color::ColorChoice, ChildGraph, Id};
use crate::{INTERNAL_ERROR_MSG, INVALID_UTF8};

Expand Down Expand Up @@ -376,7 +376,7 @@ impl<'help, 'app> Parser<'help, 'app> {
&self.app[id],
&arg_os,
matcher,
ValueType::CommandLine,
ValueSource::CommandLine,
true,
trailing_values,
);
Expand Down Expand Up @@ -417,7 +417,7 @@ impl<'help, 'app> Parser<'help, 'app> {
p,
&arg_os,
matcher,
ValueType::CommandLine,
ValueSource::CommandLine,
append,
trailing_values,
);
Expand Down Expand Up @@ -457,7 +457,7 @@ impl<'help, 'app> Parser<'help, 'app> {
sc_m.add_val_to(
&Id::empty_hash(),
v.to_os_string(),
ValueType::CommandLine,
ValueSource::CommandLine,
false,
);
sc_m.get_mut(&Id::empty_hash())
Expand Down Expand Up @@ -1116,7 +1116,7 @@ impl<'help, 'app> Parser<'help, 'app> {
opt,
opt.default_missing_vals.iter().map(OsString::from),
matcher,
ValueType::CommandLine,
ValueSource::CommandLine,
false,
);
};
Expand Down Expand Up @@ -1144,7 +1144,7 @@ impl<'help, 'app> Parser<'help, 'app> {
opt,
v,
matcher,
ValueType::CommandLine,
ValueSource::CommandLine,
false,
trailing_values,
);
Expand All @@ -1165,7 +1165,7 @@ impl<'help, 'app> Parser<'help, 'app> {
arg: &Arg<'help>,
val: &RawOsStr,
matcher: &mut ArgMatcher,
ty: ValueType,
ty: ValueSource,
append: bool,
trailing_values: bool,
) -> ParseResult {
Expand Down Expand Up @@ -1214,7 +1214,7 @@ impl<'help, 'app> Parser<'help, 'app> {
arg: &Arg<'help>,
vals: impl Iterator<Item = OsString>,
matcher: &mut ArgMatcher,
ty: ValueType,
ty: ValueSource,
append: bool,
) {
// If not appending, create a new val group and then append vals in.
Expand All @@ -1234,7 +1234,7 @@ impl<'help, 'app> Parser<'help, 'app> {
arg: &Arg<'help>,
val: OsString,
matcher: &mut ArgMatcher,
ty: ValueType,
ty: ValueSource,
append: bool,
) {
debug!("Parser::add_single_val_to_arg: adding val...{:?}", val);
Expand Down Expand Up @@ -1263,7 +1263,7 @@ impl<'help, 'app> Parser<'help, 'app> {
debug!("Parser::parse_flag");

self.inc_occurrence_of_arg(matcher, flag);
matcher.add_index_to(&flag.id, self.cur_idx.get(), ValueType::CommandLine);
matcher.add_index_to(&flag.id, self.cur_idx.get(), ValueSource::CommandLine);

ParseResult::ValuesDone
}
Expand Down Expand Up @@ -1297,20 +1297,20 @@ impl<'help, 'app> Parser<'help, 'app> {

for o in self.app.get_opts() {
debug!("Parser::add_defaults:iter:{}:", o.name);
self.add_value(o, matcher, ValueType::DefaultValue, trailing_values);
self.add_value(o, matcher, ValueSource::DefaultValue, trailing_values);
}

for p in self.app.get_positionals() {
debug!("Parser::add_defaults:iter:{}:", p.name);
self.add_value(p, matcher, ValueType::DefaultValue, trailing_values);
self.add_value(p, matcher, ValueSource::DefaultValue, trailing_values);
}
}

fn add_value(
&self,
arg: &Arg<'help>,
matcher: &mut ArgMatcher,
ty: ValueType,
ty: ValueSource,
trailing_values: bool,
) {
if !arg.default_vals_ifs.is_empty() {
Expand Down Expand Up @@ -1457,7 +1457,7 @@ impl<'help, 'app> Parser<'help, 'app> {
a,
&val,
matcher,
ValueType::EnvVariable,
ValueSource::EnvVariable,
false,
trailing_values,
);
Expand All @@ -1480,7 +1480,7 @@ impl<'help, 'app> Parser<'help, 'app> {
let predicate = str_to_bool(val.to_str_lossy());
debug!("Parser::add_env: Found boolean literal `{}`", predicate);
if predicate {
matcher.add_index_to(&a.id, self.cur_idx.get(), ValueType::EnvVariable);
matcher.add_index_to(&a.id, self.cur_idx.get(), ValueSource::EnvVariable);
}
}

Expand Down

0 comments on commit f004524

Please sign in to comment.