use crate::env::{StringWrapper, VariableEnvironment};
use crate::eval::{Fields, TildeExpansion, WordEval, WordEvalConfig};
use futures_core::future::BoxFuture;
pub async fn double_quoted<W, I, E>(
words: I,
env: &mut E,
) -> Result<BoxFuture<'static, Fields<W::EvalResult>>, W::Error>
where
I: IntoIterator<Item = W>,
W: WordEval<E>,
W::EvalResult: 'static + Send,
E: ?Sized + VariableEnvironment<Var = W::EvalResult>,
E::VarName: std::borrow::Borrow<String>,
{
do_double_quoted(words.into_iter(), env).await
}
async fn do_double_quoted<W, I, E>(
words: I,
env: &mut E,
) -> Result<BoxFuture<'static, Fields<W::EvalResult>>, W::Error>
where
I: Iterator<Item = W>,
W: WordEval<E>,
W::EvalResult: 'static + Send,
E: ?Sized + VariableEnvironment<Var = W::EvalResult>,
E::VarName: std::borrow::Borrow<String>,
{
let cfg = WordEvalConfig {
tilde_expansion: TildeExpansion::None,
split_fields_further: false,
};
let mut all_fields = Vec::new();
let mut cur_field: Option<String> = None;
macro_rules! append {
($val:expr) => {{
let val = $val;
match cur_field {
Some(ref mut cur) => cur.push_str(val.as_str()),
None => cur_field = Some(val.into_owned()),
};
}};
}
for w in words {
match w.eval_with_config(env, cfg).await?.await {
Fields::Zero => {}
Fields::Single(s) => append!(s),
f @ Fields::Split(_) | f @ Fields::Star(_) => append!(f.join_with_ifs(env)),
Fields::At(v) if v.is_empty() => {}
Fields::At(mut v) => {
let last = v.pop().unwrap();
let mut iter = v.into_iter();
match iter.next() {
None => append!(last),
Some(first) => {
append!(first);
all_fields.push(cur_field.take().unwrap().into());
all_fields.extend(iter);
cur_field = Some(last.into_owned());
}
}
}
}
}
if let Some(s) = cur_field {
all_fields.push(s.into());
}
let ret = Fields::from(all_fields);
Ok(Box::pin(async move { ret }))
}