From c2622589efb03e73e12bd812e646d8124f611a90 Mon Sep 17 00:00:00 2001 From: Klapptnot Date: Thu, 17 Jul 2025 10:36:06 -0300 Subject: [PATCH] fix quotation rules (#16089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description This script as example for demonstration ```nushell def miku [] { print "Hiii world! 初音ミクはみんなのことが大好きだよ!" } def main [leek: int, fn: closure] { print $"Miku has ($leek) leeks 🩵" do $fn } ``` --- `escape_for_string_arg` quoting strings misses, where `|` and `;` did split the command into 2+ commands ```console ~:► nu ./miku.nu '32' '{miku}' Miku has 32 leeks 🩵 Hiii world! 初音ミクはみんなのことが大好きだよ! ~:► nu ./miku.nu '32' '{miku};ls|' where type == dir Miku has 32 leeks 🩵 Hiii world! 初音ミクはみんなのことが大好きだよ! ╭────┬─────────────┬──────┬────────┬──────────────╮ │ # │ name │ type │ size │ modified │ ├────┼─────────────┼──────┼────────┼──────────────┤ │ 0 │ Desktop │ dir │ 4.0 kB │ 5 months ago │ │ 1 │ Documents │ dir │ 4.0 kB │ a day ago │ │ 2 │ Downloads │ dir │ 4.0 kB │ a day ago │ │ 3 │ Music │ dir │ 4.0 kB │ 9 months ago │ │ 4 │ Pictures │ dir │ 4.0 kB │ 3 weeks ago │ │ 5 │ Public │ dir │ 4.0 kB │ 9 months ago │ │ 6 │ Templates │ dir │ 4.0 kB │ 3 months ago │ │ 7 │ Videos │ dir │ 4.0 kB │ 9 months ago │ │ 8 │ __pycache__ │ dir │ 4.0 kB │ 3 weeks ago │ │ 9 │ bin │ dir │ 4.0 kB │ 3 days ago │ │ 10 │ repos │ dir │ 4.0 kB │ a day ago │ │ 11 │ trash │ dir │ 4.0 kB │ 3 days ago │ ╰────┴─────────────┴──────┴────────┴──────────────╯ ``` # User-Facing Changes This adjustment won't need a change, aside from clarifying the following behavior, which is unintuitive and potentially ambiguous ```console ~:► nu ./miku.nu '32' {miku} Miku has 32 leeks 🩵 Hiii world! 初音ミクはみんなのことが大好きだよ! ~:► nu ./miku.nu '32' { miku } Error: nu::parser::parse_mismatch × Parse mismatch during operation. ╭─[:1:9] 1 │ main 32 "{ miku }" · ─────┬──── · ╰── expected block, closure or record ╰──── ~:► nu ./miku.nu '32' '{' miku '}' Miku has 32 leeks 🩵 Hiii world! 初音ミクはみんなのことが大好きだよ! ``` --- crates/nu-parser/src/deparse.rs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/crates/nu-parser/src/deparse.rs b/crates/nu-parser/src/deparse.rs index a06bc5b6dc..6a88f2540f 100644 --- a/crates/nu-parser/src/deparse.rs +++ b/crates/nu-parser/src/deparse.rs @@ -2,9 +2,16 @@ use nu_utils::escape_quote_string; fn string_should_be_quoted(input: &str) -> bool { input.starts_with('$') - || input - .chars() - .any(|c| c == ' ' || c == '(' || c == '\'' || c == '`' || c == '"' || c == '\\') + || input.chars().any(|c| { + c == ' ' + || c == '(' + || c == '\'' + || c == '`' + || c == '"' + || c == '\\' + || c == ';' + || c == '|' + }) } // Escape rules: @@ -51,14 +58,17 @@ mod test { #[test] fn test_quote_special() { - // check for input arg like this: - // nu b.nu "two words" $nake "`123" - assert_eq!( - escape_for_script_arg("two words"), - r#""two words""#.to_string() - ); - assert_eq!(escape_for_script_arg("$nake"), r#""$nake""#.to_string()); - assert_eq!(escape_for_script_arg("`123"), r#""`123""#.to_string()); + let cases = vec![ + ("two words", r#""two words""#), + ("$nake", r#""$nake""#), + ("`123", r#""`123""#), + ("this|cat", r#""this|cat""#), + ("this;cat", r#""this;cat""#), + ]; + + for (input, expected) in cases { + assert_eq!(escape_for_script_arg(input).as_str(), expected); + } } #[test]