diff --git a/src/arg/mod.rs b/src/arg/mod.rs index abdb587..d707a36 100644 --- a/src/arg/mod.rs +++ b/src/arg/mod.rs @@ -115,82 +115,23 @@ pub enum Mode fn parse>(args: I) -> eyre::Result { - 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::() - .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::() - .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) } diff --git a/src/arg/parsing.rs b/src/arg/parsing.rs index 48c5b4a..bfdb73d 100644 --- a/src/arg/parsing.rs +++ b/src/arg/parsing.rs @@ -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 + { + 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>), } 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 Ok(Continue::Yes) } +/// Consume this iterator into `Input`s +pub fn consume(args: I, output: &mut Output) +where I: IntoIterator +{ + output.extend(args.into_iter().map(Argument::Input)); +} + pub fn parse_next(args: &mut I, output: &mut Output, this: String) -> eyre::Result where I: Iterator { @@ -324,8 +354,7 @@ where I: Iterator } }, "--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 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 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 + { + 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 +{ + //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!() +}