Making nushell works better with external args which surrounded by backtick quotes (#13910)

# Description
Fixes: #13431
Fixes: #13578

The issue happened because nushell thinks external program name and
external arg with totally same rule. But actually they are a little bit
different.
When parsing external program name, backtick is a thing and it should be
keeped.
But when parsing external args, backtick is just a mark that it's a
**bareword which may contain space**. So in this context, it's already
useless.

# User-Facing Changes
After the pr, the following command will work as intended.
```nushell
> ^echo `"hello"`
hello
```

# Tests + Formatting
Added 3 test cases.
This commit is contained in:
Wind
2024-10-10 20:57:30 +08:00
committed by GitHub
parent 5002d87af4
commit 1d15bbc95b
2 changed files with 35 additions and 4 deletions

View File

@ -240,10 +240,26 @@ fn parse_unknown_arg(
/// string, where each balanced pair of quotes is parsed as a separate part of the string, and then
/// concatenated together.
///
/// `keep_surround_backtick_quote` should be true when parsing it as command name. Or else it
/// should be false.
///
/// For example, `-foo="bar\nbaz"` becomes `$"-foo=bar\nbaz"`
fn parse_external_string(working_set: &mut StateWorkingSet, span: Span) -> Expression {
let contents = &working_set.get_span_contents(span);
fn parse_external_string(
working_set: &mut StateWorkingSet,
mut span: Span,
keep_surround_bakctick_quote: bool,
) -> Expression {
let mut contents = working_set.get_span_contents(span);
if !keep_surround_bakctick_quote
&& contents.len() > 1
&& contents.starts_with(b"`")
&& contents.ends_with(b"`")
{
contents = &contents[1..contents.len() - 1];
// backtick quote is useless in this case, so span is required to updated.
span = Span::new(span.start + 1, span.end - 1);
}
if contents.starts_with(b"r#") {
parse_raw_string(working_set, span)
} else if contents
@ -441,7 +457,7 @@ fn parse_regular_external_arg(working_set: &mut StateWorkingSet, span: Span) ->
} else if contents.starts_with(b"[") {
parse_list_expression(working_set, span, &SyntaxShape::Any)
} else {
parse_external_string(working_set, span)
parse_external_string(working_set, span, false)
}
}
@ -463,7 +479,7 @@ pub fn parse_external_call(working_set: &mut StateWorkingSet, spans: &[Span]) ->
let arg = parse_expression(working_set, &[head_span]);
Box::new(arg)
} else {
Box::new(parse_external_string(working_set, head_span))
Box::new(parse_external_string(working_set, head_span, true))
};
let args = spans[1..]