rework mode selection begin

arg-parsing-better
Avril 4 years ago
parent 994a394631
commit 172462b48e
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -115,82 +115,23 @@ pub enum Mode
fn parse<I: IntoIterator<Item=String>>(args: I) -> eyre::Result<Mode>
{
let suggestion_intended_arg = || "If this was intended as a path instead of an option, use option `-` before it.";
//let mut cfg = config::Config::default();
let mut buffer = parsing::Output::new();
let mut args = args.into_iter();
let mut cfg = Config::default();
let mut reading = true;
while let Some(opt) = args.next()
while let Some(arg) = args.next()
{
if reading {
match opt.trim()
{
"--help" => return Ok(Mode::Help),
"-" => reading = false,
"--threads" => {
let max = args.next().ok_or(eyre!("`--threads` expects a parameter"))
.with_suggestion(suggestion_intended_arg.clone())?;
cfg.max_tasks = NonZeroUsize::new(max.parse::<usize>()
.wrap_err(eyre!("`--threads` expects a non-negative number"))
.with_suggestion(suggestion_intended_arg.clone())
.with_section(move || max.header("Parameter given was"))?);
},
"-M" => cfg.max_tasks = None, // this is the default, but it is possible an earlier command mutated it, so doing nothing here would be a bug for that corner case
"-m" => {
cfg.max_tasks = config::max_tasks_cpus();
},
"-q" => {
cfg.output_level = config::OutputLevel::Quiet;
},
"-Q" => {
cfg.output_level = config::OutputLevel::Silent;
},
"-v" => {
cfg.output_level = config::OutputLevel::Verbose;
},
#[cfg(feature="inspect")] "-D" => {
cfg.serialise_output = Some(config::OutputSerialisationMode::Stdout);
},
#[cfg(feature="inspect")] "-R" => {
cfg.serialise_output = Some(config::OutputSerialisationMode::RawStdout);
},
#[cfg(feature="inspect")] "--save" => {
let file = args.next().ok_or(eyre!("`--save` expects a filename parameter"))
.with_suggestion(suggestion_intended_arg.clone())?;
cfg.serialise_output = Some(config::OutputSerialisationMode::File(file.into()));
},
#[cfg(feature="inspect")] "--save-raw" => {
let file = args.next().ok_or(eyre!("`--save-raw` expects a filename parameter"))
.with_suggestion(suggestion_intended_arg.clone())?;
#[cfg(feature="prealloc")] {
cfg.serialise_output = Some(config::OutputSerialisationMode::PreallocFile(file.into()));
}
#[cfg(not(feature="prealloc"))] {
cfg.serialise_output = Some(config::OutputSerialisationMode::RawFile(file.into()));
}
},
"--recursive" => {
let max = args.next().ok_or(eyre!("`--recursive` expects a parameter"))
.with_suggestion(suggestion_intended_arg.clone())?;
cfg.recursive = max.parse::<usize>()
.wrap_err(eyre!("`--recursive` expects a non-negative number"))
.with_suggestion(suggestion_intended_arg.clone())
.with_section(move || max.header("Parameter given was"))?.into();
},
"-r" => cfg.recursive = config::Recursion::Unlimited,
_ => {
cfg.paths.push(opt.into());
reading = false;
}
}
continue;
} else {
cfg.paths.push(opt.into());
match parsing::parse_next(&mut args, &mut buffer, arg)? {
parsing::Continue::No => {
parsing::consume(args, &mut buffer);
break;
},
parsing::Continue::Abort(Some(change_to)) => return Ok(change_to.try_into_mode(buffer).unwrap()),
parsing::Continue::Abort(_) => break,
_ => (),
}
}
Ok(Mode::Normal(cfg))
parsing::into_mode(buffer)
}

@ -34,6 +34,16 @@ pub enum Argument
impl Argument
{
/// Convert into a mode change if this is a mode change
// We consume the whole output here in case the mode change needs to traverse it for information. As of now, we have only one non-`Normal` mode: `Help`, which doesn't require any extra information.
pub fn try_into_mode(self, _rest: Output) -> Result<Mode, (Self, Output)>
{
match self {
Self::ModeChangeHelp => Ok(Mode::Help),
no => Err((no, _rest)),
}
}
/// Insert this `Argument` into config
pub fn insert_into_cfg(self, cfg: &mut Config)
{
@ -212,15 +222,18 @@ impl Argument
}
/// Should we continue parsing and/or reading arguments?
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Copy)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Continue
{
/// Keep parsing the arguments
Yes,
/// Stop parsing arguments, add the rest of args as `Input`s
No,
/// On mode change, we don't need to parse the rest of the argument. Stop reading entirely.
Abort,
/// On mode change, we don't need to parse the rest of the argument. Stop reading entirely, and optionally return the last one here, which must be a mode change argument.
///
/// Returning this when the contained value is `Some` immediately terminates parsing and precedes to mode-switch. However, if it is `None`, parsing of chained short args is allowed to continue, although `Abort(None)` will be returned at the end regardless of subsequent `Continue` results from that change (unless one is an `Abort(Some(_))`, which immediately returns itself.)
// Box `Argument` to reduce the size of `Continue`, as it is returned from functions often and when its value is set to `Some` it will always be the last `Argument` processed anyway and the only one to be boxed here at all.
Abort(Option<Box<Argument>>),
}
impl Continue
@ -234,6 +247,16 @@ impl Continue
false
}
}
/// Is this an abort?
#[inline] pub fn is_abort(&self) -> bool
{
if let Self::Abort(_) = self {
true
} else {
false
}
}
}
impl Default for Continue
@ -305,6 +328,13 @@ where I: Iterator<Item=String>
Ok(Continue::Yes)
}
/// Consume this iterator into `Input`s
pub fn consume<I>(args: I, output: &mut Output)
where I: IntoIterator<Item=String>
{
output.extend(args.into_iter().map(Argument::Input));
}
pub fn parse_next<I>(args: &mut I, output: &mut Output, this: String) -> eyre::Result<Continue>
where I: Iterator<Item=String>
{
@ -324,8 +354,7 @@ where I: Iterator<Item=String>
}
},
"--help" => {
keep_reading = Continue::Abort;
Argument::ModeChangeHelp
return Ok(Continue::Abort(Some(Box::new(Argument::ModeChangeHelp))));
},
"-" => {
return Ok(Continue::No);
@ -345,8 +374,9 @@ where I: Iterator<Item=String>
single if single.starts_with("-") => {
for ch in single.chars().skip(1) {
match parse_single(args, output, ch)? {
abort @ Continue::Abort(Some(_)) => return Ok(abort),
x @ Continue::No |
x @ Continue::Abort => keep_reading = x,
x @ Continue::Abort(_) if !x.is_abort() => keep_reading = x,
_ => (),
}
}
@ -363,3 +393,32 @@ where I: Iterator<Item=String>
Ok(keep_reading)
}
/// Converts parsed argument lists into a respective mode.
///
/// # Notes
/// These functions assume the mode has already been correctly calculated to be the mode pertaining to that function.
mod modes {
use super::*;
use config::Config;
/// Consume a parsed list of arguments in `Normal` mode into a `Normal` mode `Config` object.
pub fn normal(args: Output) -> eyre::Result<config::Config>
{
let mut cfg = Config::default();
//TODO: Consume `args` into `cfg` for Normal mode, then return `cfg.`
Ok(cfg)
}
}
/// Consume this parsed list of arguments into a `Mode` and return it
pub fn into_mode(args: Output) -> eyre::Result<Mode>
{
//TODO: Find out what mode `args` is in.
//TODO: pass `args` to the respective mode generation function in mode `modes`, and wrap that mode around its return value.
todo!()
}

Loading…
Cancel
Save