Remove custom escaping for external args. (#2095)

Our own custom escaping unfortunately is far too simple to cover all cases.
Instead, the parser will now do no transforms on the args passed to an external
command, letting the process spawning library deal with doing the appropriate
escaping.
This commit is contained in:
Jason Gedge 2020-07-02 19:29:28 -04:00 committed by GitHub
parent 7813063c93
commit 180290f3a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 16 deletions

View file

@ -118,29 +118,18 @@ async fn run_with_stdin(
let value =
evaluate_baseline_expr(arg, &context.registry, &scope.it, &scope.vars, &scope.env)
.await?;
// Skip any arguments that don't really exist, treating them as optional
// FIXME: we may want to preserve the gap in the future, though it's hard to say
// what value we would put in its place.
if value.value.is_none() {
continue;
}
// Do the cleanup that we need to do on any argument going out:
let trimmed_value_string = value.as_string()?.trim_end_matches('\n').to_string();
let value_string;
#[cfg(not(windows))]
{
value_string = trimmed_value_string
.replace('$', "\\$")
.replace('"', "\\\"")
.to_string()
}
#[cfg(windows)]
{
value_string = trimmed_value_string
}
command_args.push(value_string);
command_args.push(trimmed_value_string);
}
let process_args = command_args

View file

@ -512,6 +512,26 @@ fn parse_interpolated_string(
(call, error)
}
/// Parses the given argument using the shape as a guide for how to correctly parse the argument
fn parse_external_arg(
registry: &dyn SignatureRegistry,
lite_arg: &Spanned<String>,
) -> (SpannedExpression, Option<ParseError>) {
if lite_arg.item.starts_with('$') {
return parse_full_column_path(&lite_arg, registry);
}
if lite_arg.item.starts_with('`') && lite_arg.item.len() > 1 && lite_arg.item.ends_with('`') {
// This is an interpolated string
parse_interpolated_string(registry, &lite_arg)
} else {
(
SpannedExpression::new(Expression::string(lite_arg.item.clone()), lite_arg.span),
None,
)
}
}
/// Parses the given argument using the shape as a guide for how to correctly parse the argument
fn parse_arg(
expected_type: SyntaxShape,
@ -1237,7 +1257,7 @@ fn classify_pipeline(
args.push(name);
for lite_arg in &lite_cmd.args {
let (expr, err) = parse_arg(SyntaxShape::String, registry, lite_arg);
let (expr, err) = parse_external_arg(registry, lite_arg);
if error.is_none() {
error = err;
}
@ -1313,7 +1333,7 @@ fn classify_pipeline(
args.push(name);
for lite_arg in &lite_cmd.args {
let (expr, err) = parse_arg(SyntaxShape::String, registry, lite_arg);
let (expr, err) = parse_external_arg(registry, lite_arg);
if error.is_none() {
error = err;
}

View file

@ -192,6 +192,15 @@ mod external_words {
assert_eq!(actual.out, "joturner@foo.bar.baz");
}
#[test]
fn no_escaping_for_single_quoted_strings() {
let actual = nu!(cwd: ".", r#"
nu --testbin cococo 'test "things"'
"#);
assert_eq!(actual.out, "test \"things\"");
}
}
mod nu_commands {