From c287322d86763dcb37e6634793c61b0ddf05c35c Mon Sep 17 00:00:00 2001 From: AdminXVII <xavier.lheureux@icloud.com> Date: Sat, 6 Jul 2019 17:19:20 +0000 Subject: [PATCH] Simpler & more efficient expand token --- src/lib/expansion/mod.rs | 91 ++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/src/lib/expansion/mod.rs b/src/lib/expansion/mod.rs index 3a815af6..8033b628 100644 --- a/src/lib/expansion/mod.rs +++ b/src/lib/expansion/mod.rs @@ -151,61 +151,29 @@ pub trait Expander: Sized { _ => None, } } + /// Get an array that exists in the shell. fn get_array(&self, value: &str) -> Result<Args, Self::Error> { self.expand_string(value) } + /// Performs shell expansions to an input string, efficiently returning the final /// expanded form. Shells must provide their own batteries for expanding tilde /// and variable words. fn expand_string(&self, original: &str) -> Result<Args, Self::Error> { + if original.is_empty() { + return Ok(args![""]); + } + let mut token_buffer = Vec::new(); let mut contains_brace = false; for word in WordIterator::new(original, self, true) { let word = word?; - match word { - WordToken::Brace(_) => { - contains_brace = true; - token_buffer.push(word); - } - WordToken::ArrayVariable(data, contains_quote, selection) => { - if let Select::Key(key) = selection { - if key.contains(' ') { - let keys = key.split(' '); - token_buffer.reserve(2 * keys.size_hint().0); - for index in keys { - let select = index - .parse::<Select<types::Str>>() - .map_err(|_| Error::IndexParsingError(index.into()))?; - token_buffer.push(WordToken::ArrayVariable( - data, - contains_quote, - select, - )); - token_buffer.push(WordToken::Whitespace(" ")); - } - token_buffer.pop(); // Pop out the last unneeded whitespace token - } else { - token_buffer.push(WordToken::ArrayVariable( - data, - contains_quote, - Select::Key(key), - )); - } - } else { - token_buffer.push(WordToken::ArrayVariable( - data, - contains_quote, - selection, - )); - } - } - _ => token_buffer.push(word), + if let WordToken::Brace(_) = word { + contains_brace = true; } + token_buffer.push(word) } - if original.is_empty() { - token_buffer.push(WordToken::Normal("".into(), true, false)); - } self.expand_tokens(&token_buffer, contains_brace) } } @@ -361,6 +329,33 @@ trait ExpanderInternal: Expander { WordToken::Array(ref elements, ref index) => { self.array_expand(elements, index).map_err(Into::into) } + WordToken::ArrayVariable(array, quoted, Select::Key(ref key)) if key.contains(' ') => { + if quoted { + let mut output = types::Str::new(); + for index in key.split(' ') { + let select = index + .parse::<Select<types::Str>>() + .map_err(|_| Error::IndexParsingError(index.into()))?; + let _ = write!( + &mut output, + "{}", + self.array(array, &select)?.iter().format(" ") + ); + output.push(' '); + } + output.pop(); // Pop out the last unneeded whitespace token + Ok(args![output]) + } else { + let mut out = Args::with_capacity(10); + for index in key.split(' ') { + let select = index + .parse::<Select<types::Str>>() + .map_err(|_| Error::IndexParsingError(index.into()))?; + out.extend(self.array(array, &select)?); + } + Ok(out) + } + } WordToken::ArrayVariable(array, quoted, ref index) => { let array = self.array(array, index)?; if quoted { @@ -504,6 +499,20 @@ trait ExpanderInternal: Expander { self.array_expand(elements, index)?.iter().format(" ") ); } + WordToken::ArrayVariable(array, _, Select::Key(ref key)) if key.contains(' ') => { + for index in key.split(' ') { + let select = index + .parse::<Select<types::Str>>() + .map_err(|_| Error::IndexParsingError(index.into()))?; + let _ = write!( + &mut output, + "{}", + self.array(array, &select)?.iter().format(" ") + ); + output.push(' '); + } + output.pop(); // Pop out the last unneeded whitespace token + } WordToken::ArrayVariable(array, _, ref index) => { let _ = write!(&mut output, "{}", self.array(array, index)?.iter().format(" ")); } -- GitLab