Skip to content

Commit

Permalink
feat: support default vectors for repeating arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Nov 2, 2023
1 parent 1c632b0 commit 60447c2
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 11 deletions.
8 changes: 8 additions & 0 deletions argh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,14 @@ impl<T> ParseValueSlot for ParseValueSlotTy<Vec<T>, T> {
}
}

// `ParseValueSlotTy<Option<Vec<T>>, T>` is used as the slot for optional repeating arguments.
impl<T> ParseValueSlot for ParseValueSlotTy<Option<Vec<T>>, T> {
fn fill_slot(&mut self, arg: &str, value: &str) -> Result<(), String> {
self.slot.get_or_insert_with(Vec::new).push((self.parse_func)(arg, value)?);
Ok(())
}
}

/// A type which can be the receiver of a `Flag`.
pub trait Flag {
/// Creates a default instance of the flag value;
Expand Down
8 changes: 6 additions & 2 deletions argh_derive/src/args_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,14 @@ fn impl_args_info_data<'a>(
Optionality::None => quote! { argh::Optionality::Required },
Optionality::Defaulted(_) => quote! { argh::Optionality::Optional },
Optionality::Optional => quote! { argh::Optionality::Optional },
Optionality::Repeating if field.attrs.greedy.is_some() => {
Optionality::Repeating | Optionality::DefaultedRepeating(_)
if field.attrs.greedy.is_some() =>
{
quote! { argh::Optionality::Greedy }
}
Optionality::Repeating => quote! { argh::Optionality::Repeating },
Optionality::Repeating | Optionality::DefaultedRepeating(_) => {
quote! { argh::Optionality::Repeating }
}
};

match field.kind {
Expand Down
7 changes: 5 additions & 2 deletions argh_derive/src/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ fn positional_usage(out: &mut String, field: &StructField<'_>) {
}
let name = field.positional_arg_name();
out.push_str(&name);
if field.optionality == Optionality::Repeating {
if matches!(field.optionality, Optionality::Repeating | Optionality::DefaultedRepeating(_)) {
out.push_str("...");
}
if field.attrs.greedy.is_none() {
Expand Down Expand Up @@ -194,7 +194,10 @@ fn option_usage(out: &mut String, field: &StructField<'_>) {
} else {
out.push_str(long_name.trim_start_matches("--"));
}
if field.optionality == Optionality::Repeating {
if matches!(
field.optionality,
Optionality::Repeating | Optionality::DefaultedRepeating(_)
) {
out.push_str("...");
}
out.push('>');
Expand Down
31 changes: 27 additions & 4 deletions argh_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum Optionality {
Defaulted(TokenStream),
Optional,
Repeating,
DefaultedRepeating(TokenStream),
}

impl PartialEq<Optionality> for Optionality {
Expand Down Expand Up @@ -159,8 +160,14 @@ impl<'a> StructField<'a> {
tree
})
.collect();
optionality = Optionality::Defaulted(tokens);
ty_without_wrapper = &field.ty;
let inner = if let Some(x) = ty_inner(&["Vec"], &field.ty) {
optionality = Optionality::DefaultedRepeating(tokens);
x
} else {
optionality = Optionality::Defaulted(tokens);
&field.ty
};
ty_without_wrapper = inner;
} else {
let mut inner = None;
optionality = if let Some(x) = ty_inner(&["Option"], &field.ty) {
Expand Down Expand Up @@ -653,6 +660,9 @@ fn declare_local_storage_for_from_args_fields<'a>(
Optionality::None | Optionality::Defaulted(_) => {
quote! { std::option::Option<#field_type> }
}
Optionality::DefaultedRepeating(_) => {
quote! { std::option::Option<std::vec::Vec<#field_type>> }
}
};

match field.kind {
Expand Down Expand Up @@ -698,7 +708,7 @@ fn unwrap_from_args_fields<'a>(
Optionality::Optional | Optionality::Repeating => {
quote! { #field_name: #field_name.slot }
}
Optionality::Defaulted(tokens) => {
Optionality::Defaulted(tokens) | Optionality::DefaultedRepeating(tokens) => {
quote! {
#field_name: #field_name.slot.unwrap_or_else(|| #tokens)
}
Expand All @@ -708,7 +718,7 @@ fn unwrap_from_args_fields<'a>(
FieldKind::SubCommand => match field.optionality {
Optionality::None => quote! { #field_name: #field_name.unwrap() },
Optionality::Optional | Optionality::Repeating => field_name.into_token_stream(),
Optionality::Defaulted(_) => unreachable!(),
Optionality::Defaulted(_) | Optionality::DefaultedRepeating(_) => unreachable!(),
},
}
})
Expand Down Expand Up @@ -738,6 +748,9 @@ fn declare_local_storage_for_redacted_fields<'a>(
Optionality::Repeating => {
quote! { std::vec::Vec<String> }
}
Optionality::DefaultedRepeating(_) => {
quote! { std::option::Option<std::vec::Vec<String>> }
}
Optionality::None | Optionality::Optional | Optionality::Defaulted(_) => {
quote! { std::option::Option<String> }
}
Expand All @@ -756,6 +769,9 @@ fn declare_local_storage_for_redacted_fields<'a>(
Optionality::Repeating => {
quote! { std::vec::Vec<String> }
}
Optionality::DefaultedRepeating(_) => {
quote! { std::option::Option<std::vec::Vec<String>> }
}
Optionality::None | Optionality::Optional | Optionality::Defaulted(_) => {
quote! { std::option::Option<String> }
}
Expand Down Expand Up @@ -798,6 +814,13 @@ fn unwrap_redacted_fields<'a>(
__redacted.extend(#field_name.slot.into_iter());
}
}
Optionality::DefaultedRepeating(_) => {
quote! {
if let Some(__field_name) = #field_name.slot {
__redacted.extend(__field_name.into_iter());
}
}
}
Optionality::None | Optionality::Optional | Optionality::Defaulted(_) => {
quote! {
if let Some(__field_name) = #field_name.slot {
Expand Down
6 changes: 3 additions & 3 deletions argh_shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub struct FlagInfo<'a> {
/// The long string of the flag.
pub long: &'a str,
/// The single character short indicator
/// for trhis flag.
/// for this flag.
pub short: Option<char>,
/// The description of the flag.
pub description: &'a str,
Expand All @@ -102,7 +102,7 @@ pub enum FlagInfoKind<'a> {
Option { arg_name: &'a str },
}

/// The optionality defines the requirments related
/// The optionality defines the requirements related
/// to the presence of the argument on the command line.
#[derive(Debug, Default, PartialEq, Eq, serde::Serialize)]
pub enum Optionality {
Expand All @@ -117,7 +117,7 @@ pub enum Optionality {
/// or more times.
Repeating,
/// Greedy is used for positional arguments which
/// capture the all command line input upto the next flag or
/// capture the all command line input up to the next flag or
/// the end of the input.
Greedy,
}
Expand Down

0 comments on commit 60447c2

Please sign in to comment.