use crate::{
+ args::State,
+ buffer::MetaInfo,
+ error::{Message, MissingItem},
+ Doc, Error, Meta, Parser,
+};
+use std::marker::PhantomData;
+
+pub struct ParseFallbackWith<T, P, F, E> {
+ pub(crate) inner: P,
+ pub(crate) inner_res: PhantomData<T>,
+ pub(crate) fallback: F,
+ pub(crate) value_str: String,
+ pub(crate) err: PhantomData<E>,
+}
+
+impl<T, P, F, E> Parser<T> for ParseFallbackWith<T, P, F, E>
+where
+ P: Parser<T>,
+ F: Fn() -> Result<T, E>,
+ E: ToString,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ let mut clone = args.clone();
+ match self.inner.eval(&mut clone) {
+ Ok(ok) => {
+ std::mem::swap(args, &mut clone);
+ Ok(ok)
+ }
+ Err(Error(e)) => {
+ #[cfg(feature = "autocomplete")]
+ args.swap_comps(&mut clone);
+ if e.can_catch() {
+ match (self.fallback)() {
+ Ok(ok) => Ok(ok),
+ Err(e) => Err(Error(Message::PureFailed(e.to_string()))),
+ }
+ } else {
+ Err(Error(e))
+ }
+ }
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ let m = Meta::Optional(Box::new(self.inner.meta()));
+ if self.value_str.is_empty() {
+ m
+ } else {
+ let buf = Doc::from(self.value_str.as_str());
+ Meta::Suffix(Box::new(m), Box::new(buf))
+ }
+ }
+}
+
+pub struct ParseGroupHelp<P> {
+ pub(crate) inner: P,
+ pub(crate) message: Doc,
+}
+
+impl<T, P> Parser<T> for ParseGroupHelp<P>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ #[cfg(feature = "autocomplete")]
+ let mut comp_items = Vec::new();
+ #[cfg(feature = "autocomplete")]
+ args.swap_comps_with(&mut comp_items);
+
+ #[allow(clippy::let_and_return)]
+ let res = self.inner.eval(args);
+
+ #[cfg(feature = "autocomplete")]
+ args.swap_comps_with(&mut comp_items);
+ #[cfg(feature = "autocomplete")]
+ args.push_with_group(&self.message.to_completion(), &mut comp_items);
+
+ res
+ }
+
+ fn meta(&self) -> Meta {
+ let meta = Box::new(self.inner.meta());
+ Meta::Subsection(meta, Box::new(self.message.clone()))
+ }
+}
+
+pub struct ParseWithGroupHelp<P, F> {
+ pub(crate) inner: P,
+ pub(crate) f: F,
+}
+
+impl<T, P, F> Parser<T> for ParseWithGroupHelp<P, F>
+where
+ P: Parser<T>,
+ F: Fn(MetaInfo) -> Doc,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ self.inner.eval(args)
+ }
+
+ fn meta(&self) -> Meta {
+ let meta = self.inner.meta();
+ let buf = (self.f)(MetaInfo(&meta));
+
+ Meta::Subsection(Box::new(meta), Box::new(buf))
+ }
+}
+
+pub struct ParseSome<P> {
+ pub(crate) inner: P,
+ pub(crate) message: &'static str,
+ pub(crate) catch: bool,
+}
+
+impl<P> ParseSome<P> {
+ #[must_use]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/some_catch.md"))]
+ pub fn catch(mut self) -> Self {
+ self.catch = true;
+ self
+ }
+}
+
+impl<T, P> Parser<Vec<T>> for ParseSome<P>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<Vec<T>, Error> {
+ let mut res = Vec::new();
+ let mut len = usize::MAX;
+
+ while let Some(val) = parse_option(&self.inner, &mut len, args, self.catch)? {
+ res.push(val);
+ }
+
+ if res.is_empty() {
+ Err(Error(Message::ParseSome(self.message)))
+ } else {
+ Ok(res)
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
+ }
+}
+
+pub struct ParseCollect<P, C, T> {
+ pub(crate) inner: P,
+ pub(crate) catch: bool,
+ pub(crate) ctx: PhantomData<(C, T)>,
+}
+
+impl<T, C, P> ParseCollect<P, C, T> {
+ #[must_use]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/some_catch.md"))]
+ pub fn catch(mut self) -> Self {
+ self.catch = true;
+ self
+ }
+}
+
+impl<T, C, P> Parser<C> for ParseCollect<P, C, T>
+where
+ P: Parser<T>,
+ C: FromIterator<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<C, Error> {
+ let mut len = usize::MAX;
+ std::iter::from_fn(|| parse_option(&self.inner, &mut len, args, self.catch).transpose())
+ .collect::<Result<C, Error>>()
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
+ }
+}
+
+pub struct ParseHide<P> {
+ pub(crate) inner: P,
+}
+
+impl<T, P> Parser<T> for ParseHide<P>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ #[cfg(feature = "autocomplete")]
+ let mut comps = Vec::new();
+
+ #[cfg(feature = "autocomplete")]
+ args.swap_comps_with(&mut comps);
+
+ #[allow(clippy::let_and_return)]
+ let res = self.inner.eval(args);
+
+ #[cfg(feature = "autocomplete")]
+ args.swap_comps_with(&mut comps);
+ if let Err(Error(Message::Missing(_))) = res {
+ Err(Error(Message::Missing(Vec::new())))
+ } else {
+ res
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Skip
+ }
+}
+
+pub struct ParseUsage<P> {
+ pub(crate) inner: P,
+ pub(crate) usage: Doc,
+}
+impl<T, P> Parser<T> for ParseUsage<P>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ self.inner.eval(args)
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::CustomUsage(Box::new(self.inner.meta()), Box::new(self.usage.clone()))
+ }
+}
+
+pub struct ParseOrElse<T> {
+ pub(crate) this: Box<dyn Parser<T>>,
+ pub(crate) that: Box<dyn Parser<T>>,
+}
+
+impl<T> Parser<T> for ParseOrElse<T> {
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ #[cfg(feature = "autocomplete")]
+ let mut comp_items = Vec::new();
+ #[cfg(feature = "autocomplete")]
+ args.swap_comps_with(&mut comp_items);
+
+ let mut args_a = args.clone();
+ let mut args_b = args.clone();
+
+ let (res_a, err_a) = match self.this.eval(&mut args_a) {
+ Ok(ok) => (Some(ok), None),
+ Err(err) => (None, Some(err)),
+ };
+
+ let (res_b, err_b) = match self.that.eval(&mut args_b) {
+ Ok(ok) => (Some(ok), None),
+ Err(err) => (None, Some(err)),
+ };
+
+ if this_or_that_picks_first(
+ err_a,
+ err_b,
+ args,
+ &mut args_a,
+ &mut args_b,
+ #[cfg(feature = "autocomplete")]
+ comp_items,
+ )? {
+ Ok(res_a.unwrap())
+ } else {
+ Ok(res_b.unwrap())
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ self.this.meta().or(self.that.meta())
+ }
+}
+
+fn this_or_that_picks_first(
+ err_a: Option<Error>,
+ err_b: Option<Error>,
+ args: &mut State,
+ args_a: &mut State,
+ args_b: &mut State,
+
+ #[cfg(feature = "autocomplete")] mut comp_stash: Vec<crate::complete_gen::Comp>,
+) -> Result<bool, Error> {
+ match Ord::cmp(&args_a.depth(), &args_b.depth()) {
+ std::cmp::Ordering::Less => {
+ std::mem::swap(args, args_b);
+ #[cfg(feature = "autocomplete")]
+ if let Some(comp) = args.comp_mut() {
+ comp.extend_comps(comp_stash);
+ }
+ return match err_b {
+ Some(err) => Err(err),
+ None => Ok(false),
+ };
+ }
+ std::cmp::Ordering::Equal => {}
+ std::cmp::Ordering::Greater => {
+ std::mem::swap(args, args_a);
+ #[cfg(feature = "autocomplete")]
+ if let Some(comp) = args.comp_mut() {
+ comp.extend_comps(comp_stash);
+ }
+ return match err_a {
+ Some(err) => Err(err),
+ None => Ok(true),
+ };
+ }
+ }
+
+ #[allow(clippy::let_and_return)] let res = match (err_a, err_b) {
+ (None, None) => {
+ if args.len() == args_a.len() && args.len() == args_b.len() {
+ Ok((true, None))
+ } else {
+ Ok(args_a.pick_winner(args_b))
+ }
+ }
+ (Some(e1), Some(e2)) => Err(e1.combine_with(e2)),
+ (a_ok, _) => Ok((a_ok.is_none(), None)),
+ };
+
+ #[cfg(feature = "autocomplete")]
+ {
+ let mut keep_a = true;
+ let mut keep_b = true;
+ if args_a.len() != args_b.len() {
+ if let (Some(_), Some(_)) = (args_a.comp_mut(), args_b.comp_mut()) {
+ 'check: for (ix, arg) in args_a.items.iter().enumerate() {
+ if ix + 1 == args_a.items.len() {
+ let os = arg.os_str();
+ if os.is_empty() || os == "-" || os == "--" {
+ break 'check;
+ }
+ }
+ if let (Some(a), Some(b)) = (args_a.present(ix), args_b.present(ix)) {
+ match (a, b) {
+ (false, true) => {
+ keep_b = false;
+ break 'check;
+ }
+ (true, false) => {
+ keep_a = false;
+ break 'check;
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+ }
+
+ if let (Some(a), Some(b)) = (args_a.comp_mut(), args_b.comp_mut()) {
+ if keep_a {
+ comp_stash.extend(a.drain_comps());
+ }
+ if keep_b {
+ comp_stash.extend(b.drain_comps());
+ }
+ }
+ }
+
+ match res {
+ Ok((true, ix)) => {
+ if let Some(win) = ix {
+ args_a.save_conflicts(args_b, win);
+ }
+ std::mem::swap(args, args_a);
+ }
+ Ok((false, ix)) => {
+ if let Some(win) = ix {
+ args_b.save_conflicts(args_a, win);
+ }
+ std::mem::swap(args, args_b);
+ }
+ Err(_) => {}
+ }
+
+ #[cfg(feature = "autocomplete")]
+ if let Some(comp) = args.comp_mut() {
+ comp.extend_comps(comp_stash);
+ }
+
+ Ok(res?.0)
+}
+
+pub struct ParseWith<T, P, F, E, R> {
+ pub(crate) inner: P,
+ pub(crate) inner_res: PhantomData<T>,
+ pub(crate) parse_fn: F,
+ pub(crate) res: PhantomData<R>,
+ pub(crate) err: PhantomData<E>,
+}
+
+impl<T, P, F, E, R> Parser<R> for ParseWith<T, P, F, E, R>
+where
+ P: Parser<T>,
+ F: Fn(T) -> Result<R, E>,
+ E: ToString,
+{
+ fn eval(&self, args: &mut State) -> Result<R, Error> {
+ let t = self.inner.eval(args)?;
+ match (self.parse_fn)(t) {
+ Ok(r) => Ok(r),
+ Err(e) => Err(Error(Message::ParseFailed(args.current, e.to_string()))),
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ self.inner.meta()
+ }
+}
+
+pub struct ParseFallback<P, T> {
+ pub(crate) inner: P,
+ pub(crate) value: T,
+ pub(crate) value_str: String,
+}
+
+impl<P, T> Parser<T> for ParseFallback<P, T>
+where
+ P: Parser<T>,
+ T: Clone,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ let mut clone = args.clone();
+ match self.inner.eval(&mut clone) {
+ Ok(ok) => {
+ std::mem::swap(args, &mut clone);
+ Ok(ok)
+ }
+ Err(Error(e)) => {
+ #[cfg(feature = "autocomplete")]
+ args.swap_comps(&mut clone);
+ if e.can_catch() {
+ Ok(self.value.clone())
+ } else {
+ Err(Error(e))
+ }
+ }
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ let m = Meta::Optional(Box::new(self.inner.meta()));
+ if self.value_str.is_empty() {
+ m
+ } else {
+ let buf = Doc::from(self.value_str.as_str());
+ Meta::Suffix(Box::new(m), Box::new(buf))
+ }
+ }
+}
+
+impl<P, T: std::fmt::Display> ParseFallback<P, T> {
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback.md"))]
+ #[must_use]
+ pub fn display_fallback(mut self) -> Self {
+ self.value_str = format!("[default: {}]", self.value);
+ self
+ }
+}
+
+impl<P, T: std::fmt::Debug> ParseFallback<P, T> {
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/deb_fallback_with.md"))]
+ #[must_use]
+ pub fn debug_fallback(mut self) -> Self {
+ self.value_str = format!("[default: {:?}]", self.value);
+ self
+ }
+}
+
+impl<P, T: std::fmt::Display, F, E> ParseFallbackWith<T, P, F, E>
+where
+ F: Fn() -> Result<T, E>,
+{
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback_with.md"))]
+ #[must_use]
+ pub fn display_fallback(mut self) -> Self {
+ if let Ok(val) = (self.fallback)() {
+ self.value_str = format!("[default: {}]", val);
+ }
+ self
+ }
+}
+
+impl<P, T: std::fmt::Debug, F, E> ParseFallbackWith<T, P, F, E>
+where
+ F: Fn() -> Result<T, E>,
+{
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/deb_fallback.md"))]
+ #[must_use]
+ pub fn debug_fallback(mut self) -> Self {
+ if let Ok(val) = (self.fallback)() {
+ self.value_str = format!("[default: {:?}]", val);
+ }
+ self
+ }
+}
+
+pub struct ParseGuard<P, F> {
+ pub(crate) inner: P,
+ pub(crate) check: F,
+ pub(crate) message: &'static str,
+}
+
+impl<T, P, F> Parser<T> for ParseGuard<P, F>
+where
+ P: Parser<T>,
+ F: Fn(&T) -> bool,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ let t = self.inner.eval(args)?;
+ if (self.check)(&t) {
+ Ok(t)
+ } else {
+ Err(Error(Message::GuardFailed(args.current, self.message)))
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ self.inner.meta()
+ }
+}
+
+pub struct ParseCount<P, T> {
+ pub(crate) inner: P,
+ pub(crate) ctx: PhantomData<T>,
+}
+
+impl<T, P> Parser<usize> for ParseCount<P, T>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<usize, Error> {
+ let mut res = 0;
+ let mut current = args.len();
+ let mut len = usize::MAX;
+ while (parse_option(&self.inner, &mut len, args, false)?).is_some() {
+ res += 1;
+ if current == args.len() {
+ break;
+ }
+ current = args.len();
+ }
+ Ok(res)
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Many(Box::new(Meta::Optional(Box::new(self.inner.meta()))))
+ }
+}
+
+pub struct ParseLast<P> {
+ pub(crate) inner: P,
+}
+
+impl<T, P> Parser<T> for ParseLast<P>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ let mut last = None;
+ let mut current = args.len();
+ let mut len = usize::MAX;
+ while let Some(val) = parse_option(&self.inner, &mut len, args, false)? {
+ last = Some(val);
+ if current == args.len() {
+ break;
+ }
+ current = args.len();
+ }
+ if let Some(last) = last {
+ Ok(last)
+ } else {
+ self.inner.eval(args)
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
+ }
+}
+
+pub struct ParseOptional<P> {
+ pub(crate) inner: P,
+ pub(crate) catch: bool,
+}
+
+impl<T, P> Parser<Option<T>> for ParseOptional<P>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<Option<T>, Error> {
+ let mut len = usize::MAX;
+ parse_option(&self.inner, &mut len, args, self.catch)
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Optional(Box::new(self.inner.meta()))
+ }
+}
+
+impl<P> ParseOptional<P> {
+ #[must_use]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/optional_catch.md"))]
+ pub fn catch(mut self) -> Self {
+ self.catch = true;
+ self
+ }
+}
+
+pub struct ParseMany<P> {
+ pub(crate) inner: P,
+ pub(crate) catch: bool,
+}
+
+impl<P> ParseMany<P> {
+ #[must_use]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/many_catch.md"))]
+ pub fn catch(mut self) -> Self {
+ self.catch = true;
+ self
+ }
+}
+
+fn parse_option<P, T>(
+ parser: &P,
+ len: &mut usize,
+ args: &mut State,
+ catch: bool,
+) -> Result<Option<T>, Error>
+where
+ P: Parser<T>,
+{
+ let mut orig_args = args.clone();
+ match parser.eval(args) {
+ Ok(val) => Ok(if args.len() < *len {
+ *len = args.len();
+ Some(val)
+ } else {
+ None
+ }),
+ Err(Error(err)) => {
+ let missing = matches!(err, Message::Missing(_));
+
+ if catch || (missing && orig_args.len() == args.len()) || (!missing && err.can_catch())
+ {
+ std::mem::swap(&mut orig_args, args);
+ #[cfg(feature = "autocomplete")]
+ if orig_args.comp_mut().is_some() {
+ args.swap_comps(&mut orig_args);
+ }
+ Ok(None)
+ } else {
+ Err(Error(err))
+ }
+ }
+ }
+}
+
+impl<T, P> Parser<Vec<T>> for ParseMany<P>
+where
+ P: Parser<T>,
+{
+ fn eval(&self, args: &mut State) -> Result<Vec<T>, Error> {
+ let mut len = usize::MAX;
+ std::iter::from_fn(|| parse_option(&self.inner, &mut len, args, self.catch).transpose())
+ .collect::<Result<Vec<T>, Error>>()
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Many(Box::new(Meta::Optional(Box::new(self.inner.meta()))))
+ }
+}
+
+pub struct ParsePure<T>(pub(crate) T);
+impl<T: Clone + 'static> Parser<T> for ParsePure<T> {
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ args.current = None;
+ Ok(self.0.clone())
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Skip
+ }
+}
+
+pub struct ParsePureWith<T, F, E>(pub(crate) F)
+where
+ F: Fn() -> Result<T, E>,
+ E: ToString;
+impl<T: Clone + 'static, F: Fn() -> Result<T, E>, E: ToString> Parser<T>
+ for ParsePureWith<T, F, E>
+{
+ fn eval(&self, _args: &mut State) -> Result<T, Error> {
+ match (self.0)() {
+ Ok(ok) => Ok(ok),
+ Err(e) => Err(Error(Message::PureFailed(e.to_string()))),
+ }
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Skip
+ }
+}
+
+pub struct ParseFail<T> {
+ pub(crate) field1: &'static str,
+ pub(crate) field2: PhantomData<T>,
+}
+impl<T> Parser<T> for ParseFail<T> {
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ args.current = None;
+ Err(Error(Message::ParseFail(self.field1)))
+ }
+
+ fn meta(&self) -> Meta {
+ Meta::Skip
+ }
+}
+
+pub struct ParseMap<T, P, F, R> {
+ pub(crate) inner: P,
+ pub(crate) inner_res: PhantomData<T>,
+ pub(crate) map_fn: F,
+ pub(crate) res: PhantomData<R>,
+}
+impl<P, T, F, R> Parser<R> for ParseMap<T, P, F, R>
+where
+ F: Fn(T) -> R,
+ P: Parser<T> + Sized,
+{
+ fn eval(&self, args: &mut State) -> Result<R, Error> {
+ let t = self.inner.eval(args)?;
+ Ok((self.map_fn)(t))
+ }
+
+ fn meta(&self) -> Meta {
+ self.inner.meta()
+ }
+}
+
+pub struct ParseCon<P> {
+ pub inner: P,
+ pub meta: Meta,
+ pub failfast: bool,
+}
+
+impl<T, P> Parser<T> for ParseCon<P>
+where
+ P: Fn(bool, &mut State) -> Result<T, Error>,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ let res = (self.inner)(self.failfast, args);
+ args.current = None;
+ res
+ }
+
+ fn meta(&self) -> Meta {
+ self.meta.clone()
+ }
+}
+
+impl<T> ParseCon<T> {
+ #[must_use]
+
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_0.md"))]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_1.md"))]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_command.md"))]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_3.md"))]
+ #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_4.md"))]
+ pub fn adjacent(mut self) -> ParseAdjacent<Self> {
+ self.failfast = true;
+ ParseAdjacent { inner: self }
+ }
+}
+
+#[cfg(feature = "autocomplete")]
+pub struct ParseComp<P, F> {
+ pub(crate) inner: P,
+ pub(crate) op: F,
+ pub(crate) group: Option<String>,
+}
+
+#[cfg(feature = "autocomplete")]
+impl<P, F> ParseComp<P, F> {
+ #[must_use]
+ pub fn group(mut self, group: impl Into<String>) -> Self {
+ self.group = Some(group.into());
+ self
+ }
+}
+
+#[cfg(feature = "autocomplete")]
+impl<P, T, F, M> Parser<T> for ParseComp<P, F>
+where
+ P: Parser<T> + Sized,
+ M: Into<String>,
+ F: Fn(&T) -> Vec<(M, Option<M>)>,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ let mut comp_items = Vec::new();
+ args.swap_comps_with(&mut comp_items);
+
+ let res = self.inner.eval(args);
+
+ args.swap_comps_with(&mut comp_items);
+
+ if let Some(comp) = &mut args.comp_mut() {
+ if res.is_err() {
+ comp.extend_comps(comp_items);
+ return res;
+ }
+ }
+
+ let res = res?;
+
+ let depth = args.depth();
+ if let Some(comp) = &mut args.comp_mut() {
+ for ci in comp_items {
+ let is_meta = ci.is_metavar();
+ if let Some(is_arg) = is_meta {
+ let suggestions = (self.op)(&res);
+ if suggestions.len() != 1 {
+ comp.push_comp(ci);
+ }
+ for (replacement, description) in suggestions {
+ let group = self.group.clone();
+ comp.push_value(
+ replacement.into(),
+ description.map(Into::into),
+ group,
+ depth,
+ is_arg,
+ );
+ }
+ } else {
+ comp.push_comp(ci);
+ }
+ }
+ }
+ Ok(res)
+ }
+
+ fn meta(&self) -> Meta {
+ self.inner.meta()
+ }
+}
+
+pub struct ParseAdjacent<P> {
+ pub(crate) inner: P,
+}
+impl<P, T> Parser<T> for ParseAdjacent<P>
+where
+ P: Parser<T> + Sized,
+{
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ let original_scope = args.scope();
+
+ let first_item;
+ let inner_meta = self.inner.meta();
+ let mut best_error = if let Some(item) = Meta::first_item(&inner_meta) {
+ first_item = item;
+ let missing_item = MissingItem {
+ item: item.clone(),
+ position: original_scope.start,
+ scope: original_scope.clone(),
+ };
+ Message::Missing(vec![missing_item])
+ } else {
+ unreachable!("bpaf usage BUG: adjacent should start with a required argument");
+ };
+ let mut best_args = args.clone();
+ let mut best_consumed = 0;
+
+ for (start, width, mut this_arg) in args.ranges(first_item) {
+ let mut scratch = this_arg.clone();
+ scratch.set_scope(start..start + width);
+ let before = scratch.len();
+
+ if before == 0 {
+ continue;
+ }
+
+ let _ = self.inner.eval(&mut scratch);
+
+ if before == scratch.len() {
+ continue;
+ }
+
+ this_arg.set_scope(start..original_scope.end);
+ let before = this_arg.len();
+
+ if original_scope.end - start > before {
+ this_arg.set_scope(this_arg.adjacently_available_from(start));
+ }
+
+ loop {
+ match self.inner.eval(&mut this_arg) {
+ Ok(res) => {
+ if let Some(adj_scope) = this_arg.adjacent_scope(args) {
+ this_arg = args.clone();
+ this_arg.set_scope(adj_scope);
+ } else {
+ std::mem::swap(args, &mut this_arg);
+ args.set_scope(original_scope);
+ return Ok(res);
+ }
+ }
+ Err(Error(err)) => {
+ let consumed = before - this_arg.len();
+ if consumed > best_consumed {
+ best_consumed = consumed;
+ std::mem::swap(&mut best_args, &mut this_arg);
+ best_error = err;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ std::mem::swap(args, &mut best_args);
+ Err(Error(best_error))
+ }
+
+ fn meta(&self) -> Meta {
+ let meta = self.inner.meta();
+ Meta::Adjacent(Box::new(meta))
+ }
+}
+
+impl<T> Parser<T> for Box<dyn Parser<T>> {
+ fn eval(&self, args: &mut State) -> Result<T, Error> {
+ self.as_ref().eval(args)
+ }
+ fn meta(&self) -> Meta {
+ self.as_ref().meta()
+ }
+}
+