diff --git a/src/lib/builtins/variables.rs b/src/lib/builtins/variables.rs index 6fcf3dd4ca1ddbced10496c3f1fb36fa32187536..cbd24b9f844a2c316eb016f49097798358761fae 100644 --- a/src/lib/builtins/variables.rs +++ b/src/lib/builtins/variables.rs @@ -151,7 +151,7 @@ mod test { struct VariableExpander(pub Variables); impl Expander for VariableExpander { - fn string(&self, var: &str, _: bool) -> Option<types::Str> { self.0.get::<types::Str>(var) } + fn string(&self, var: &str) -> Option<types::Str> { self.0.get::<types::Str>(var) } } // TODO: Rewrite tests now that let is part of the grammar. @@ -184,7 +184,7 @@ mod test { variables.set("FOO", "BAR"); let return_status = drop_variable(&mut variables, &["drop", "FOO"]); assert_eq!(SUCCESS, return_status); - let expanded = expand_string("$FOO", &VariableExpander(variables), false).join(""); + let expanded = expand_string("$FOO", &VariableExpander(variables)).join(""); assert_eq!("", expanded); } @@ -208,7 +208,7 @@ mod test { variables.set("FOO", array!["BAR"]); let return_status = drop_array(&mut variables, &["drop", "-a", "FOO"]); assert_eq!(SUCCESS, return_status); - let expanded = expand_string("@FOO", &VariableExpander(variables), false).join(""); + let expanded = expand_string("@FOO", &VariableExpander(variables)).join(""); assert_eq!("", expanded); } diff --git a/src/lib/parser/assignments/checker.rs b/src/lib/parser/assignments/checker.rs index ed72981f15cc55d74159189eecb9f6c05a9193ac..36df3456aabc23625043b7a62d443bb5212af731 100644 --- a/src/lib/parser/assignments/checker.rs +++ b/src/lib/parser/assignments/checker.rs @@ -79,7 +79,7 @@ fn get_map_of<E: Expander>( shell: &E, expression: &str, ) -> Result<Value, TypeError> { - let array = expand_string(expression, shell, false); + let array = expand_string(expression, shell); let inner_kind = match primitive_type { Primitive::HashMap(ref inner) => inner, diff --git a/src/lib/parser/loops.rs b/src/lib/parser/loops.rs index 8040c881e239d0059a1057d31d1a81861d0c1e43..af7b291eddb487b887424546c42e114499bb6e93 100644 --- a/src/lib/parser/loops.rs +++ b/src/lib/parser/loops.rs @@ -14,7 +14,7 @@ impl ForValueExpression { pub(crate) fn new<E: Expander>(expression: &[types::Str], expanders: &E) -> ForValueExpression { let output: Vec<_> = expression .iter() - .flat_map(|expression| expand_string(expression, expanders, true)) + .flat_map(|expression| expand_string(expression, expanders)) .collect(); if output.is_empty() { diff --git a/src/lib/parser/pipelines/mod.rs b/src/lib/parser/pipelines/mod.rs index 921e14d9a37a1cd82a80abff706f619b1a172529..9b1bf3df9399346d9032f086af32924636832be4 100644 --- a/src/lib/parser/pipelines/mod.rs +++ b/src/lib/parser/pipelines/mod.rs @@ -79,15 +79,15 @@ impl PipeItem { for input in &mut self.inputs { *input = match input { - Input::File(ref s) => Input::File(expand_string(s, shell, false).join(" ").into()), + Input::File(ref s) => Input::File(expand_string(s, shell).join(" ").into()), Input::HereString(ref s) => { - Input::HereString(expand_string(s, shell, true).join(" ").into()) + Input::HereString(expand_string(s, shell).join(" ").into()) } }; } for output in &mut self.outputs { - output.file = expand_string(output.file.as_str(), shell, false).join(" ").into(); + output.file = expand_string(output.file.as_str(), shell).join(" ").into(); } } diff --git a/src/lib/parser/shell_expand/mod.rs b/src/lib/parser/shell_expand/mod.rs index 7b213599615d9e613116c744cbca32a5c4245a34..e7585d29d110211ac37fe7a8b8e747cb999f0d33 100644 --- a/src/lib/parser/shell_expand/mod.rs +++ b/src/lib/parser/shell_expand/mod.rs @@ -33,7 +33,7 @@ pub(crate) trait Expander: Sized { /// Expand an array variable with some selection. fn array(&self, _name: &str, _selection: &Select) -> Option<types::Array> { None } /// Expand a string variable given if it's quoted / unquoted - fn string(&self, _name: &str, _quoted: bool) -> Option<types::Str> { None } + fn string(&self, _name: &str) -> Option<types::Str> { None } /// Expand a subshell expression. fn command(&self, _command: &str) -> Option<types::Str> { None } /// Iterating upon key-value maps. @@ -42,7 +42,7 @@ pub(crate) trait Expander: Sized { fn map_values<'a>(&'a self, _name: &str, _select: &Select) -> Option<Array> { None } /// Get a string that exists in the shell. fn get_string(&self, value: &str) -> Value { - Value::Str(types::Str::from(expand_string(value, self, false).join(" "))) + Value::Str(types::Str::from(expand_string(value, self).join(" "))) } /// Select the proper values from an iterator fn select<I: Iterator<Item = types::Str>>(vals: I, select: &Select, n: usize) -> Option<Array> { @@ -56,7 +56,7 @@ pub(crate) trait Expander: Sized { } } /// Get an array that exists in the shell. - fn get_array(&self, value: &str) -> Value { Value::Array(expand_string(value, self, false)) } + fn get_array(&self, value: &str) -> Value { Value::Array(expand_string(value, self)) } } fn expand_process<E: Expander>( @@ -64,59 +64,12 @@ fn expand_process<E: Expander>( command: &str, selection: &Select, expander: &E, - quoted: bool, ) { - if let Some(mut output) = expander.command(command) { - if !output.is_empty() && quoted { + if let Some(output) = expander.command(command) { + if !output.is_empty() { let output: &str = if let Some(pos) = output.rfind(|x| x != '\n') { &output[..=pos] } else { &output }; - slice(current, output, &selection) - } else if !output.is_empty() { - // The following code should produce the same result as - // slice(current, - // &output.split_whitespace().collect::<Vec<_>>().join(" "), - // selection) - // We optimize it so that no additional allocation is made. - - unsafe { - let bytes = output.as_bytes_mut(); - let mut left_mut_pos = 0; - let mut right_pos = 0; - let mut prev_is_whitespace = true; - - unsafe fn next_char(b: &[u8]) -> Option<char> { - str::from_utf8_unchecked(b).chars().next() - } - - while let Some(c) = next_char(&bytes[right_pos..]) { - let is_whitespace = char::is_whitespace(c); - let char_len_utf8 = c.len_utf8(); - - if !prev_is_whitespace || !is_whitespace { - if is_whitespace { - bytes[left_mut_pos] = b' '; - left_mut_pos += 1; - } else { - for i in 0..char_len_utf8 { - bytes[left_mut_pos + i] = bytes[right_pos + i]; - } - left_mut_pos += char_len_utf8; - } - } - - right_pos += char_len_utf8; - prev_is_whitespace = is_whitespace; - } - - slice( - current, - str::from_utf8_unchecked(&bytes[..left_mut_pos]).trim_end(), - &selection, - ); - // `output` is not a valid utf8 string now. - // We drop it here to prevent accidental usage afterward. - ::std::mem::drop(output); - } + slice(current, output, &selection); } } } @@ -127,11 +80,10 @@ fn expand_brace<E: Expander>( tokens: &mut Vec<BraceToken>, nodes: &[&str], expand_func: &E, - reverse_quoting: bool, ) { let mut temp = Vec::new(); for word in - nodes.iter().flat_map(|node| expand_string_no_glob(node, expand_func, reverse_quoting)) + nodes.iter().flat_map(|node| expand_string_no_glob(node, expand_func)) { match parse_range(&word) { Some(elements) => temp.extend(elements), @@ -157,7 +109,7 @@ fn array_expand<E: Expander>( ) -> types::Array { match selection { Select::None => types::Array::new(), - Select::All => elements.iter().flat_map(|e| expand_string(e, expand_func, false)).collect(), + Select::All => elements.iter().flat_map(|e| expand_string(e, expand_func)).collect(), Select::Index(index) => array_nth(elements, expand_func, *index).into_iter().collect(), Select::Range(range) => array_range(elements, expand_func, *range), Select::Key(_) => types::Array::new(), @@ -165,7 +117,7 @@ fn array_expand<E: Expander>( } fn array_nth<E: Expander>(elements: &[&str], expand_func: &E, index: Index) -> Option<types::Str> { - let mut expanded = elements.iter().flat_map(|e| expand_string(e, expand_func, false)); + let mut expanded = elements.iter().flat_map(|e| expand_string(e, expand_func)); match index { Index::Forward(n) => expanded.nth(n), Index::Backward(n) => expanded.rev().nth(n), @@ -175,7 +127,7 @@ fn array_nth<E: Expander>(elements: &[&str], expand_func: &E, index: Index) -> O fn array_range<E: Expander>(elements: &[&str], expand_func: &E, range: Range) -> types::Array { let expanded = elements .iter() - .flat_map(|e| expand_string(e, expand_func, false)) + .flat_map(|e| expand_string(e, expand_func)) .collect::<types::Array>(); if let Some((start, length)) = range.bounds(expanded.len()) { expanded.into_iter().skip(start).take(length).collect() @@ -218,7 +170,6 @@ fn slice<S: AsRef<str>>(output: &mut small::String, expanded: S, selection: &Sel pub(crate) fn expand_string<E: Expander>( original: &str, expand_func: &E, - reverse_quoting: bool, ) -> types::Array { let mut token_buffer = Vec::new(); let mut contains_brace = false; @@ -262,13 +213,12 @@ pub(crate) fn expand_string<E: Expander>( if original.is_empty() { token_buffer.push(WordToken::Normal("".into(), true, false)); } - expand_tokens(&token_buffer, expand_func, reverse_quoting, contains_brace) + expand_tokens(&token_buffer, expand_func, contains_brace) } fn expand_string_no_glob<E: Expander>( original: &str, expand_func: &E, - reverse_quoting: bool, ) -> types::Array { let mut token_buffer = Vec::new(); let mut contains_brace = false; @@ -282,13 +232,12 @@ fn expand_string_no_glob<E: Expander>( if original.is_empty() { token_buffer.push(WordToken::Normal("".into(), true, false)); } - expand_tokens(&token_buffer, expand_func, reverse_quoting, contains_brace) + expand_tokens(&token_buffer, expand_func, contains_brace) } fn expand_braces<E: Expander>( word_tokens: &[WordToken], expand_func: &E, - reverse_quoting: bool, ) -> types::Array { let mut expanded_words = types::Array::new(); let mut output = small::String::new(); @@ -310,21 +259,21 @@ fn expand_braces<E: Expander>( } WordToken::ArrayProcess(command, _, ref index) => match *index { Select::All => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); output.push_str(&temp); } Select::Index(Index::Forward(id)) => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); output.push_str(temp.split_whitespace().nth(id).unwrap_or_default()); } Select::Index(Index::Backward(id)) => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); output.push_str( temp.split_whitespace().rev().nth(id).unwrap_or_default(), ); } Select::Range(range) => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); let len = temp.split_whitespace().count(); if let Some((start, length)) = range.bounds(len) { let mut iter = temp.split_whitespace().skip(start).take(length); @@ -351,20 +300,18 @@ fn expand_braces<E: Expander>( tokens, nodes, expand_func, - reverse_quoting, ), WordToken::Whitespace(whitespace) => output.push_str(whitespace), - WordToken::Process(command, quoted, ref index) => { + WordToken::Process(command, ref index) => { expand_process( output, command, &index, expand_func, - quoted ^ reverse_quoting, ); } - WordToken::Variable(text, quoted, ref index) => { - if let Some(expanded) = expand_func.string(text, quoted ^ reverse_quoting) { + WordToken::Variable(text, ref index) => { + if let Some(expanded) = expand_func.string(text) { slice(output, expanded, &index); }; } @@ -438,19 +385,19 @@ fn expand_single_array_token<E: Expander>( } WordToken::ArrayProcess(command, _, ref index) => match *index { Select::All => { - expand_process(&mut output, command, &Select::All, expand_func, false); + expand_process(&mut output, command, &Select::All, expand_func); Some(output.split_whitespace().map(From::from).collect::<types::Array>()) } Select::Index(Index::Forward(id)) => { - expand_process(&mut output, command, &Select::All, expand_func, false); + expand_process(&mut output, command, &Select::All, expand_func); Some(output.split_whitespace().nth(id).map(Into::into).into_iter().collect()) } Select::Index(Index::Backward(id)) => { - expand_process(&mut output, command, &Select::All, expand_func, false); + expand_process(&mut output, command, &Select::All, expand_func); Some(output.split_whitespace().rev().nth(id).map(Into::into).into_iter().collect()) } Select::Range(range) => { - expand_process(&mut output, command, &Select::All, expand_func, false); + expand_process(&mut output, command, &Select::All, expand_func); if let Some((start, length)) = range.bounds(output.split_whitespace().count()) { Some( output @@ -474,7 +421,6 @@ fn expand_single_array_token<E: Expander>( fn expand_single_string_token<E: Expander>( token: &WordToken, expand_func: &E, - reverse_quoting: bool, ) -> types::Array { let mut output = small::String::new(); let mut expanded_words = types::Array::new(); @@ -485,11 +431,11 @@ fn expand_single_string_token<E: Expander>( expand(&mut output, &mut expanded_words, expand_func, text.as_ref(), do_glob, tilde); } WordToken::Whitespace(text) => output.push_str(text), - WordToken::Process(command, quoted, ref index) => { - expand_process(&mut output, command, &index, expand_func, quoted ^ reverse_quoting); + WordToken::Process(command, ref index) => { + expand_process(&mut output, command, &index, expand_func); } - WordToken::Variable(text, quoted, ref index) => { - if let Some(expanded) = expand_func.string(text, quoted ^ reverse_quoting) { + WordToken::Variable(text, ref index) => { + if let Some(expanded) = expand_func.string(text) { slice(&mut output, expanded, &index); } } @@ -565,17 +511,16 @@ fn expand<E: Expander>( pub(crate) fn expand_tokens<E: Expander>( token_buffer: &[WordToken], expand_func: &E, - reverse_quoting: bool, contains_brace: bool, ) -> types::Array { if !token_buffer.is_empty() { if contains_brace { - return expand_braces(&token_buffer, expand_func, reverse_quoting); + return expand_braces(&token_buffer, expand_func); } else if token_buffer.len() == 1 { let token = &token_buffer[0]; return match expand_single_array_token(token, expand_func) { Some(array) => array, - None => expand_single_string_token(token, expand_func, reverse_quoting), + None => expand_single_string_token(token, expand_func), }; } @@ -597,22 +542,22 @@ pub(crate) fn expand_tokens<E: Expander>( } WordToken::ArrayProcess(command, _, ref index) => match index { Select::All => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); output.push_str(&temp); } Select::Index(Index::Forward(id)) => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); output .push_str(temp.split_whitespace().nth(*id).unwrap_or_default()); } Select::Index(Index::Backward(id)) => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); output.push_str( temp.split_whitespace().rev().nth(*id).unwrap_or_default(), ); } Select::Range(range) => { - expand_process(temp, command, &Select::All, expand_func, false); + expand_process(temp, command, &Select::All, expand_func); if let Some((start, length)) = range.bounds(temp.split_whitespace().count()) { @@ -646,13 +591,11 @@ pub(crate) fn expand_tokens<E: Expander>( WordToken::Whitespace(text) => { output.push_str(text); } - WordToken::Process(command, quoted, ref index) => { - let quoted = if reverse_quoting { !quoted } else { quoted }; - expand_process(output, command, &index, expand_func, quoted); + WordToken::Process(command, ref index) => { + expand_process(output, command, &index, expand_func); } - WordToken::Variable(text, quoted, ref index) => { - if let Some(expanded) = - expand_func.string(text, quoted ^ reverse_quoting) + WordToken::Variable(text, ref index) => { + if let Some(expanded) = expand_func.string(text) { slice(output, expanded, &index); } @@ -686,7 +629,7 @@ fn expand_arithmetic<E: Expander>(output: &mut small::String, input: &str, expan if !var.is_empty() { // We have reached the end of a potential variable, so we expand it and push // it onto the result - out.push_str(expander.string(&var, false).as_ref().unwrap_or(var)); + out.push_str(expander.string(&var).as_ref().unwrap_or(var)); } }; @@ -722,7 +665,7 @@ mod test { struct VariableExpander; impl Expander for VariableExpander { - fn string(&self, variable: &str, _: bool) -> Option<types::Str> { + fn string(&self, variable: &str) -> Option<types::Str> { match variable { "A" => Some("1".into()), "B" => Some("test".into()), @@ -742,26 +685,18 @@ mod test { } #[test] - fn expand_process_quoted() { + fn expand_process_test() { let mut output = small::String::new(); let line = " Mary had\ta little \n\t lamb\t"; - expand_process(&mut output, line, &Select::All, &CommandExpander, true); + expand_process(&mut output, line, &Select::All, &CommandExpander); assert_eq!(output.as_str(), line); } - #[test] - fn expand_process_unquoted() { - let mut output = small::String::new(); - let line = " Mary had\ta\u{2009}little \n\t lamb 😉😉\t"; - expand_process(&mut output, line, &Select::All, &CommandExpander, false); - assert_eq!(output.as_str(), "Mary had a little lamb 😉😉"); - } - #[test] fn expand_variable_normal_variable() { let input = "$FOO:NOT:$BAR"; let expected = "FOO:NOT:BAR"; - let expanded = expand_string(input, &VariableExpander, false); + let expanded = expand_string(input, &VariableExpander); assert_eq!(array![expected], expanded); } @@ -770,7 +705,7 @@ mod test { let line = "pro{digal,grammer,cessed,totype,cedures,ficiently,ving,spective,jections}"; let expected = "prodigal programmer processed prototype procedures proficiently proving \ prospective projections"; - let expanded = expand_string(line, &VariableExpander, false); + let expanded = expand_string(line, &VariableExpander); assert_eq!( expected.split_whitespace().map(|x| x.into()).collect::<types::Array>(), expanded @@ -781,7 +716,7 @@ mod test { fn expand_braces_v2() { let line = "It{{em,alic}iz,erat}e{d,}"; let expected = "Itemized Itemize Italicized Italicize Iterated Iterate"; - let expanded = expand_string(line, &VariableExpander, false); + let expanded = expand_string(line, &VariableExpander); assert_eq!( expected.split_whitespace().map(|x| x.into()).collect::<types::Array>(), expanded @@ -790,13 +725,13 @@ mod test { #[test] fn expand_variables_with_colons() { - let expanded = expand_string("$FOO:$BAR", &VariableExpander, false); + let expanded = expand_string("$FOO:$BAR", &VariableExpander); assert_eq!(array!["FOO:BAR"], expanded); } #[test] fn expand_multiple_variables() { - let expanded = expand_string("${B}${C}...${D}", &VariableExpander, false); + let expanded = expand_string("${B}${C}...${D}", &VariableExpander); assert_eq!(array!["testing...1 2 3"], expanded); } @@ -804,7 +739,7 @@ mod test { fn expand_variable_alongside_braces() { let line = "$A{1,2}"; let expected = array!["11", "12"]; - let expanded = expand_string(line, &VariableExpander, false); + let expanded = expand_string(line, &VariableExpander); assert_eq!(expected, expanded); } @@ -812,7 +747,7 @@ mod test { fn expand_variable_within_braces() { let line = "1{$A,2}"; let expected = array!["11", "12"]; - let expanded = expand_string(line, &VariableExpander, false); + let expanded = expand_string(line, &VariableExpander); assert_eq!(&expected, &expanded); } @@ -824,21 +759,21 @@ mod test { let expected = array!["1"]; let idxs = vec!["-3", "0", "..-2"]; for idx in idxs { - assert_eq!(expected, expand_string(&base(idx), &expander, false)); + assert_eq!(expected, expand_string(&base(idx), &expander)); } } { let expected = array!["2", "3"]; let idxs = vec!["1...2", "1...-1"]; for idx in idxs { - assert_eq!(expected, expand_string(&base(idx), &expander, false)); + assert_eq!(expected, expand_string(&base(idx), &expander)); } } { let expected = types::Array::new(); let idxs = vec!["-17", "4..-4"]; for idx in idxs { - assert_eq!(expected, expand_string(&base(idx), &expander, false)); + assert_eq!(expected, expand_string(&base(idx), &expander)); } } } @@ -854,7 +789,7 @@ mod test { (array!["bar", "baz", "bat"], "1...3"), ]; for (expected, idx) in cases { - assert_eq!(expected, expand_string(&line(idx), &expander, false)); + assert_eq!(expected, expand_string(&line(idx), &expander)); } } @@ -862,10 +797,10 @@ mod test { fn arith_expression() { let line = "$((A * A - (A + A)))"; let expected = array!["-1"]; - assert_eq!(expected, expand_string(line, &VariableExpander, false)); + assert_eq!(expected, expand_string(line, &VariableExpander)); let line = "$((3 * 10 - 27))"; let expected = array!["3"]; - assert_eq!(expected, expand_string(line, &VariableExpander, false)); + assert_eq!(expected, expand_string(line, &VariableExpander)); } #[test] @@ -873,7 +808,7 @@ mod test { let cases = vec![(array!["5"], "$len([0 1 2 3 4])"), (array!["FxOxO"], "$join(@chars('FOO') 'x')")]; for (expected, input) in cases { - assert_eq!(expected, expand_string(input, &VariableExpander, false)); + assert_eq!(expected, expand_string(input, &VariableExpander)); } } } diff --git a/src/lib/parser/shell_expand/words/methods/arrays.rs b/src/lib/parser/shell_expand/words/methods/arrays.rs index 09a8a1acd4cf46c031a7d753eeff8daadb22f115..10e9ad500002836cd013d4d96c3b9c2ca9fd068e 100644 --- a/src/lib/parser/shell_expand/words/methods/arrays.rs +++ b/src/lib/parser/shell_expand/words/methods/arrays.rs @@ -66,7 +66,7 @@ impl<'a> ArrayMethod<'a> { match self.pattern { Pattern::StringPattern(string) => { if let Ok(value) = - expand_string(string, expand_func, false).join(" ").parse::<usize>() + expand_string(string, expand_func).join(" ").parse::<usize>() { if value < variable.len() { let (l, r) = variable.split_at(value); @@ -87,7 +87,7 @@ impl<'a> ArrayMethod<'a> { let res = match (&self.pattern, &self.selection) { (_, Select::None) => Some("".into()).into_iter().collect(), (&Pattern::StringPattern(pattern), Select::All) => variable - .split(unescape(&expand_string(pattern, expand_func, false).join(" "))?.as_str()) + .split(unescape(&expand_string(pattern, expand_func).join(" "))?.as_str()) .map(From::from) .collect(), (&Pattern::Whitespace, Select::All) => variable @@ -96,7 +96,7 @@ impl<'a> ArrayMethod<'a> { .map(From::from) .collect(), (&Pattern::StringPattern(pattern), Select::Index(Index::Forward(id))) => variable - .split(&unescape(&expand_string(pattern, expand_func, false).join(" "))?.as_str()) + .split(&unescape(&expand_string(pattern, expand_func).join(" "))?.as_str()) .nth(*id) .map(From::from) .into_iter() @@ -109,7 +109,7 @@ impl<'a> ArrayMethod<'a> { .into_iter() .collect(), (&Pattern::StringPattern(pattern), Select::Index(Index::Backward(id))) => variable - .rsplit(&unescape(&expand_string(pattern, expand_func, false).join(" "))?.as_str()) + .rsplit(&unescape(&expand_string(pattern, expand_func).join(" "))?.as_str()) .nth(*id) .map(From::from) .into_iter() @@ -122,7 +122,7 @@ impl<'a> ArrayMethod<'a> { .into_iter() .collect(), (&Pattern::StringPattern(pattern), Select::Range(range)) => { - let expansion = unescape(&expand_string(pattern, expand_func, false).join(" "))?; + let expansion = unescape(&expand_string(pattern, expand_func).join(" "))?; let iter = variable.split(expansion.as_str()); if let Some((start, length)) = range.bounds(iter.clone().count()) { iter.skip(start).take(length).map(From::from).collect() @@ -154,7 +154,7 @@ impl<'a> ArrayMethod<'a> { if let Some(array) = expand_func.array(self.variable, &Select::All) { array } else if is_expression(self.variable) { - expand_string(self.variable, expand_func, false) + expand_string(self.variable, expand_func) } else { Array::new() } @@ -162,10 +162,10 @@ impl<'a> ArrayMethod<'a> { #[inline] fn resolve_var<E: Expander>(&self, expand_func: &E) -> types::Str { - if let Some(variable) = expand_func.string(self.variable, false) { + if let Some(variable) = expand_func.string(self.variable) { variable } else if is_expression(self.variable) { - types::Str::from_string(expand_string(self.variable, expand_func, false).join(" ")) + types::Str::from_string(expand_string(self.variable, expand_func).join(" ")) } else { "".into() } @@ -218,7 +218,7 @@ mod test { } } - fn string(&self, variable: &str, _: bool) -> Option<types::Str> { + fn string(&self, variable: &str) -> Option<types::Str> { match variable { "FOO" => Some("FOOBAR".into()), "SPACEDFOO" => Some("FOO BAR".into()), diff --git a/src/lib/parser/shell_expand/words/methods/mod.rs b/src/lib/parser/shell_expand/words/methods/mod.rs index 407d1f08bdfe04d8948d00f3c04c42ad4a641e70..90a780f2f7bc3cb70beb025ddc20f277c0fc3802 100644 --- a/src/lib/parser/shell_expand/words/methods/mod.rs +++ b/src/lib/parser/shell_expand/words/methods/mod.rs @@ -23,12 +23,12 @@ pub(crate) struct MethodArgs<'a, 'b, E: 'b + Expander> { impl<'a, 'b, E: 'b + Expander> MethodArgs<'a, 'b, E> { pub(crate) fn array<'c>(&'c self) -> impl Iterator<Item = small::String> + 'c { ArgumentSplitter::new(self.args) - .flat_map(move |x| expand_string(x, self.expand, false).into_iter()) + .flat_map(move |x| expand_string(x, self.expand).into_iter()) .map(|s| unescape(&s).unwrap_or_default()) } pub(crate) fn join(self, pattern: &str) -> small::String { - unescape(&expand_string(self.args, self.expand, false).join(pattern)).unwrap_or_default() + unescape(&expand_string(self.args, self.expand).join(pattern)).unwrap_or_default() } pub(crate) fn new(args: &'a str, expand: &'b E) -> MethodArgs<'a, 'b, E> { diff --git a/src/lib/parser/shell_expand/words/methods/strings.rs b/src/lib/parser/shell_expand/words/methods/strings.rs index 3b973141839e4db72a4d4b1c5939ee1a07c03714..e10d1d42f74bb8b020783dfdc315c3949b9bc594 100644 --- a/src/lib/parser/shell_expand/words/methods/strings.rs +++ b/src/lib/parser/shell_expand/words/methods/strings.rs @@ -103,10 +103,10 @@ impl<'a> StringMethod<'a> { macro_rules! string_eval { ($variable:ident $method:tt) => {{ let pattern = pattern.join(" "); - let is_true = if let Some(value) = expand.string($variable, false) { + let is_true = if let Some(value) = expand.string($variable) { value.$method(pattern.as_str()) } else if is_expression($variable) { - expand_string($variable, expand, false).join(" ").$method(pattern.as_str()) + expand_string($variable, expand).join(" ").$method(pattern.as_str()) } else { false }; @@ -116,7 +116,7 @@ impl<'a> StringMethod<'a> { macro_rules! path_eval { ($method:tt) => {{ - if let Some(value) = expand.string(variable, false) { + if let Some(value) = expand.string(variable) { output.push_str( Path::new(&*value) .$method() @@ -124,7 +124,7 @@ impl<'a> StringMethod<'a> { .unwrap_or(value.as_str()), ); } else if is_expression(variable) { - let word = expand_string(variable, expand, false).join(" "); + let word = expand_string(variable, expand).join(" "); output.push_str( Path::new(&word) .$method() @@ -137,10 +137,10 @@ impl<'a> StringMethod<'a> { macro_rules! string_case { ($method:tt) => {{ - if let Some(value) = expand.string(variable, false) { + if let Some(value) = expand.string(variable) { output.push_str(value.$method().as_str()); } else if is_expression(variable) { - let word = expand_string(variable, expand, false).join(" "); + let word = expand_string(variable, expand).join(" "); output.push_str(word.$method().as_str()); } }}; @@ -148,10 +148,10 @@ impl<'a> StringMethod<'a> { macro_rules! get_var { () => {{ - if let Some(value) = expand.string(variable, false) { + if let Some(value) = expand.string(variable) { value } else { - small::String::from(expand_string(variable, expand, false).join(" ")) + small::String::from(expand_string(variable, expand).join(" ")) } }}; } @@ -232,47 +232,47 @@ impl<'a> StringMethod<'a> { } else if is_expression(variable) { slice( output, - expand_string(variable, expand, false).join(&pattern), + expand_string(variable, expand).join(&pattern), &self.selection, ); } } "len" => { if variable.starts_with('@') || is_array(variable) { - let expanded = expand_string(variable, expand, false); + let expanded = expand_string(variable, expand); output.push_str(&expanded.len().to_string()); - } else if let Some(value) = expand.string(variable, false) { + } else if let Some(value) = expand.string(variable) { let count = UnicodeSegmentation::graphemes(value.as_str(), true).count(); output.push_str(&count.to_string()); } else if is_expression(variable) { - let word = expand_string(variable, expand, false).join(" "); + let word = expand_string(variable, expand).join(" "); let count = UnicodeSegmentation::graphemes(word.as_str(), true).count(); output.push_str(&count.to_string()); } } "len_bytes" => { - if let Some(value) = expand.string(variable, false) { + if let Some(value) = expand.string(variable) { output.push_str(&value.as_bytes().len().to_string()); } else if is_expression(variable) { - let word = expand_string(variable, expand, false).join(" "); + let word = expand_string(variable, expand).join(" "); output.push_str(&word.as_bytes().len().to_string()); } } "reverse" => { - if let Some(value) = expand.string(variable, false) { + if let Some(value) = expand.string(variable) { let rev_graphs = UnicodeSegmentation::graphemes(value.as_str(), true).rev(); output.push_str(rev_graphs.collect::<String>().as_str()); } else if is_expression(variable) { - let word = expand_string(variable, expand, false).join(" "); + let word = expand_string(variable, expand).join(" "); let rev_graphs = UnicodeSegmentation::graphemes(word.as_str(), true).rev(); output.push_str(rev_graphs.collect::<String>().as_str()); } } "find" => { - let out = if let Some(value) = expand.string(variable, false) { + let out = if let Some(value) = expand.string(variable) { value.find(pattern.join(" ").as_str()) } else if is_expression(variable) { - expand_string(variable, expand, false) + expand_string(variable, expand) .join(" ") .find(pattern.join(" ").as_str()) } else { @@ -281,10 +281,10 @@ impl<'a> StringMethod<'a> { output.push_str(&out.map(|i| i as isize).unwrap_or(-1).to_string()); } "unescape" => { - let out = if let Some(value) = expand.string(variable, false) { + let out = if let Some(value) = expand.string(variable) { value } else if is_expression(variable) { - expand_string(variable, expand, false).join(" ").into() + expand_string(variable, expand).join(" ").into() } else { return; }; @@ -294,10 +294,10 @@ impl<'a> StringMethod<'a> { }; } "escape" => { - let word = if let Some(value) = expand.string(variable, false) { + let word = if let Some(value) = expand.string(variable) { value } else if is_expression(variable) { - expand_string(variable, expand, false).join(" ").into() + expand_string(variable, expand).join(" ").into() } else { return; }; @@ -307,10 +307,10 @@ impl<'a> StringMethod<'a> { }; } "or" => { - let first_str = if let Some(value) = expand.string(variable, false) { + let first_str = if let Some(value) = expand.string(variable) { value } else if is_expression(variable) { - expand_string(variable, expand, false).join(" ").into() + expand_string(variable, expand).join(" ").into() } else { small::String::new() }; @@ -365,7 +365,7 @@ mod test { struct VariableExpander; impl Expander for VariableExpander { - fn string(&self, variable: &str, _: bool) -> Option<types::Str> { + fn string(&self, variable: &str) -> Option<types::Str> { match variable { "FOO" => Some("FOOBAR".into()), "BAZ" => Some(" BARBAZ ".into()), diff --git a/src/lib/parser/shell_expand/words/mod.rs b/src/lib/parser/shell_expand/words/mod.rs index d31a4617c427fa4ea84156f3c6f0a1cbf0d5b881..1cb3c2ab13e65a1649ed8dfa121b2cde0ccd7f19 100644 --- a/src/lib/parser/shell_expand/words/mod.rs +++ b/src/lib/parser/shell_expand/words/mod.rs @@ -35,10 +35,10 @@ pub(crate) enum WordToken<'a> { Whitespace(&'a str), Brace(Vec<&'a str>), Array(Vec<&'a str>, Select), - Variable(&'a str, bool, Select), + Variable(&'a str, Select), ArrayVariable(&'a str, bool, Select), ArrayProcess(&'a str, bool, Select), - Process(&'a str, bool, Select), + Process(&'a str, Select), StringMethod(StringMethod<'a>), ArrayMethod(ArrayMethod<'a>), Arithmetic(&'a str), @@ -284,13 +284,11 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { let _ = iterator.next(); WordToken::Process( output, - self.flags.contains(Flags::DQUOTE), self.read_selection(iterator), ) } else { WordToken::Process( output, - self.flags.contains(Flags::DQUOTE), Select::All, ) }; @@ -482,7 +480,7 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { for character in iterator { if let b']' = character { let value = - expand_string(&self.data[start..self.read], self.expanders, false).join(" "); + expand_string(&self.data[start..self.read], self.expanders).join(" "); let selection = match value.parse::<Select>() { Ok(selection) => selection, Err(_) => Select::None, @@ -600,13 +598,11 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { return if character == b'[' { WordToken::Variable( variable, - self.flags.contains(Flags::DQUOTE), self.read_selection(iterator), ) } else { WordToken::Variable( variable, - self.flags.contains(Flags::DQUOTE), Select::All, ) }; @@ -616,7 +612,7 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { self.read += 1; } - WordToken::Variable(&self.data[start..], self.flags.contains(Flags::DQUOTE), Select::All) + WordToken::Variable(&self.data[start..], Select::All) } // Contains the logic for parsing braced variables @@ -631,7 +627,6 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { self.read += 1; return WordToken::Variable( output, - self.flags.contains(Flags::DQUOTE), Select::All, ); } diff --git a/src/lib/parser/shell_expand/words/tests.rs b/src/lib/parser/shell_expand/words/tests.rs index df4f64a68af36e85930dd9fd03e6d2fd1025ffea..2f66dd24bdb54f65abf44bcc2890a2c899276dc6 100644 --- a/src/lib/parser/shell_expand/words/tests.rs +++ b/src/lib/parser/shell_expand/words/tests.rs @@ -95,7 +95,6 @@ fn array_process_within_string_process() { WordToken::Whitespace(" "), WordToken::Process( "let free=[@(free -h)]; echo @free[6]@free[8]/@free[7]", - false, Select::All, ), ], @@ -146,9 +145,9 @@ fn nested_processes() { let expected = vec![ WordToken::Normal("echo".into(), false, false), WordToken::Whitespace(" "), - WordToken::Process("echo $(echo one)", false, Select::All), + WordToken::Process("echo $(echo one)", Select::All), WordToken::Whitespace(" "), - WordToken::Process("echo one $(echo two) three", false, Select::All), + WordToken::Process("echo one $(echo two) three", Select::All), ]; compare(input, expected); } @@ -159,7 +158,7 @@ fn words_process_with_quotes() { let expected = vec![ WordToken::Normal("echo".into(), false, false), WordToken::Whitespace(" "), - WordToken::Process("git branch | rg '[*]' | awk '{print $2}'", false, Select::All), + WordToken::Process("git branch | rg '[*]' | awk '{print $2}'", Select::All), ]; compare(input, expected); @@ -167,7 +166,7 @@ fn words_process_with_quotes() { let expected = vec![ WordToken::Normal("echo".into(), false, false), WordToken::Whitespace(" "), - WordToken::Process("git branch | rg \"[*]\" | awk '{print $2}'", false, Select::All), + WordToken::Process("git branch | rg \"[*]\" | awk '{print $2}'", Select::All), ]; compare(input, expected); } @@ -178,18 +177,18 @@ fn test_words() { let expected = vec![ WordToken::Normal("echo".into(), false, false), WordToken::Whitespace(" "), - WordToken::Variable("ABC", false, Select::All), + WordToken::Variable("ABC", Select::All), WordToken::Whitespace(" "), - WordToken::Variable("ABC", true, Select::All), + WordToken::Variable("ABC", Select::All), WordToken::Whitespace(" "), WordToken::Normal("one".into(), false, false), WordToken::Brace(vec!["$ABC", "$ABC"]), WordToken::Whitespace(" "), WordToken::Normal("~".into(), false, true), WordToken::Whitespace(" "), - WordToken::Process("echo foo", false, Select::All), + WordToken::Process("echo foo", Select::All), WordToken::Whitespace(" "), - WordToken::Process("seq 1 100", true, Select::All), + WordToken::Process("seq 1 100", Select::All), ]; compare(input, expected); } @@ -258,7 +257,7 @@ fn test_braces() { struct WithVars; impl Expander for WithVars { - fn string(&self, var: &str, _: bool) -> Option<types::Str> { + fn string(&self, var: &str) -> Option<types::Str> { match var { "pkmn1" => Some("Pokémon".into()), "pkmn2" => Some("Poke\u{0301}mon".into()), diff --git a/src/lib/shell/binary/prompt.rs b/src/lib/shell/binary/prompt.rs index 32ec04ace9b901bfe6c4125ca4bcb214567bf7be..680ee0990552a1537f64e52e38d02798f220c985 100644 --- a/src/lib/shell/binary/prompt.rs +++ b/src/lib/shell/binary/prompt.rs @@ -11,7 +11,7 @@ pub(crate) fn prompt(shell: &mut Shell) -> String { if blocks == 0 { prompt_fn(shell).unwrap_or_else(|| { - expand_string(&shell.get_str_or_empty("PROMPT"), shell, false).join(" ") + expand_string(&shell.get_str_or_empty("PROMPT"), shell).join(" ") }) } else { " ".repeat(blocks) diff --git a/src/lib/shell/flow.rs b/src/lib/shell/flow.rs index ea322b3b49e55c25b2274213faa1d943186a2fa7..19a9d6839dadc290a60cbedb9425748651ffd347 100644 --- a/src/lib/shell/flow.rs +++ b/src/lib/shell/flow.rs @@ -316,12 +316,12 @@ impl FlowLogic for Shell { // matches("foo", "bar") // ``` let is_array = is_array(expression.as_ref()); - let value = expand_string(expression.as_ref(), self, false); + let value = expand_string(expression.as_ref(), self); for case in cases.iter() { if case .value .as_ref() - .map(|v| expand_string(&v, self, false)) + .map(|v| expand_string(&v, self)) .filter(|v| v.iter().all(|v| !value.contains(v))) .is_none() { diff --git a/src/lib/shell/job.rs b/src/lib/shell/job.rs index 1a12895a669a1c123e6ca18f03954add13d0e785..cb9acea3f187d7a63c8a42e5530d42011c997320 100644 --- a/src/lib/shell/job.rs +++ b/src/lib/shell/job.rs @@ -58,7 +58,7 @@ impl fmt::Debug for Job { /// Expands a given argument and returns it as an `Array`. fn expand_arg(arg: &str, shell: &Shell) -> types::Array { - let res = expand_string(&arg, shell, false); + let res = expand_string(&arg, shell); if res.is_empty() { array![""] } else { diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs index e4c9c6495fd837ed7509b93d865b731306e71bf6..9c6a84be573c93bcfaa58ef4ef0c55993d6200e9 100644 --- a/src/lib/shell/mod.rs +++ b/src/lib/shell/mod.rs @@ -477,14 +477,11 @@ impl<'a> Expander for Shell { } /// Expand a string variable given if its quoted / unquoted - fn string(&self, name: &str, quoted: bool) -> Option<types::Str> { - use crate::ascii_helpers::AsciiReplace; + fn string(&self, name: &str) -> Option<types::Str> { if name == "?" { Some(types::Str::from(self.previous_status.to_string())) - } else if quoted { - self.get::<types::Str>(name) } else { - self.get::<types::Str>(name).map(|x| x.ascii_replace('\n', ' ')) + self.get::<types::Str>(name) } } diff --git a/src/lib/shell/variables/mod.rs b/src/lib/shell/variables/mod.rs index 2716463cd57c71c7f0e9b2b310e22aa21ef1e26c..b4714cde85cc85760cf1047193cde684fb59c86e 100644 --- a/src/lib/shell/variables/mod.rs +++ b/src/lib/shell/variables/mod.rs @@ -707,13 +707,13 @@ mod tests { struct VariableExpander(pub Variables); impl Expander for VariableExpander { - fn string(&self, var: &str, _: bool) -> Option<types::Str> { self.0.get::<types::Str>(var) } + fn string(&self, var: &str) -> Option<types::Str> { self.0.get::<types::Str>(var) } } #[test] fn undefined_variable_expands_to_empty_string() { let variables = Variables::default(); - let expanded = expand_string("$FOO", &VariableExpander(variables), false).join(""); + let expanded = expand_string("$FOO", &VariableExpander(variables)).join(""); assert_eq!("", &expanded); } @@ -721,7 +721,7 @@ mod tests { fn set_var_and_expand_a_variable() { let mut variables = Variables::default(); variables.set("FOO", "BAR"); - let expanded = expand_string("$FOO", &VariableExpander(variables), false).join(""); + let expanded = expand_string("$FOO", &VariableExpander(variables)).join(""); assert_eq!("BAR", &expanded); }