Add support for optional argument/flag with optional value

TakesValue::Optional introduced which allows for an optional flag with
an optional value (equivalent to getopts' optflagopt mode).

Can be used where a default value for a modifier could exist, but the
user might prefer to override.

Will be used to implement #284, permitting --time to default to "sort by
modification date" for compatibility with GNU/posix ls but keeping
support for exa's previous behavior.
This commit is contained in:
Mahmoud Al-Qudsi 2017-09-13 18:48:59 -05:00
parent aa2e3a5d9e
commit 36cf5df044

View File

@ -92,6 +92,9 @@ pub enum TakesValue {
/// This flag will throw an error if theres a value after it. /// This flag will throw an error if theres a value after it.
Forbidden, Forbidden,
/// This flag may be followed by a value to override its defaults
Optional,
} }
@ -171,7 +174,7 @@ impl Args {
let arg = self.lookup_long(before)?; let arg = self.lookup_long(before)?;
let flag = Flag::Long(arg.long); let flag = Flag::Long(arg.long);
match arg.takes_value { match arg.takes_value {
Necessary => result_flags.push((flag, Some(after))), Necessary|Optional => result_flags.push((flag, Some(after))),
Forbidden => return Err(ParseError::ForbiddenValue { flag }) Forbidden => return Err(ParseError::ForbiddenValue { flag })
} }
} }
@ -190,6 +193,14 @@ impl Args {
else { else {
return Err(ParseError::NeedsValue { flag }) return Err(ParseError::NeedsValue { flag })
} }
},
Optional => {
if let Some(next_arg) = inputs.next() {
result_flags.push((flag, Some(next_arg)));
}
else {
result_flags.push((flag, None));
}
} }
} }
} }
@ -220,7 +231,7 @@ impl Args {
let arg = self.lookup_short(*byte)?; let arg = self.lookup_short(*byte)?;
let flag = Flag::Short(*byte); let flag = Flag::Short(*byte);
match arg.takes_value { match arg.takes_value {
Forbidden => result_flags.push((flag, None)), Forbidden|Optional => result_flags.push((flag, None)),
Necessary => return Err(ParseError::NeedsValue { flag }) Necessary => return Err(ParseError::NeedsValue { flag })
} }
} }
@ -229,7 +240,7 @@ impl Args {
let arg = self.lookup_short(*arg_with_value)?; let arg = self.lookup_short(*arg_with_value)?;
let flag = Flag::Short(arg.short.unwrap()); let flag = Flag::Short(arg.short.unwrap());
match arg.takes_value { match arg.takes_value {
Necessary => result_flags.push((flag, Some(after))), Necessary|Optional => result_flags.push((flag, Some(after))),
Forbidden => return Err(ParseError::ForbiddenValue { flag }) Forbidden => return Err(ParseError::ForbiddenValue { flag })
} }
} }
@ -252,7 +263,7 @@ impl Args {
let flag = Flag::Short(*byte); let flag = Flag::Short(*byte);
match arg.takes_value { match arg.takes_value {
Forbidden => result_flags.push((flag, None)), Forbidden => result_flags.push((flag, None)),
Necessary => { Necessary|Optional => {
if index < bytes.len() - 1 { if index < bytes.len() - 1 {
let remnants = &bytes[index+1 ..]; let remnants = &bytes[index+1 ..];
result_flags.push((flag, Some(OsStr::from_bytes(remnants)))); result_flags.push((flag, Some(OsStr::from_bytes(remnants))));
@ -262,10 +273,19 @@ impl Args {
result_flags.push((flag, Some(next_arg))); result_flags.push((flag, Some(next_arg)));
} }
else { else {
return Err(ParseError::NeedsValue { flag }) match arg.takes_value {
Forbidden => assert!(false),
Necessary => {
return Err(ParseError::NeedsValue { flag });
},
Optional => {
result_flags.push((flag, None));
} }
} }
} }
}
}
} }
} }
} }