From c126d4d301c3ab1febc0c5fcaa4bed224c78c6e5 Mon Sep 17 00:00:00 2001 From: Riccardo Strina Date: Sat, 21 Feb 2026 17:22:00 +0100 Subject: [PATCH 1/2] Quote args containing spaces in ArgsStringOrList When ArgsStringOrList::List elements contain spaces, they are now wrapped in double quotes before joining. This prevents the debugger from splitting paths with spaces into multiple arguments. Add tests covering list with spaces, list without spaces, single element with spaces, empty list, and single string passthrough. --- src/util.rs | 68 ++++++++++++++++++- testdata/args_empty_list.json | 3 + testdata/args_list_no_spaces.json | 3 + testdata/args_single_element_with_spaces.json | 3 + testdata/args_single_string.json | 3 + testdata/args_with_spaces.json | 3 + 6 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 testdata/args_empty_list.json create mode 100644 testdata/args_list_no_spaces.json create mode 100644 testdata/args_single_element_with_spaces.json create mode 100644 testdata/args_single_string.json create mode 100644 testdata/args_with_spaces.json diff --git a/src/util.rs b/src/util.rs index 8a7d558..ae0cdfe 100644 --- a/src/util.rs +++ b/src/util.rs @@ -414,7 +414,7 @@ pub fn should_use_local_or_download( /// A type that can be deserialized from either a single string or a list of strings. /// /// When serialized, it always produces a single string. If it was a list, -/// the elements are joined with a space. +/// the elements are joined with a space, quoting elements that contain spaces. #[derive(Deserialize, Debug, Clone)] #[serde(untagged)] pub enum ArgsStringOrList { @@ -429,7 +429,71 @@ impl Serialize for ArgsStringOrList { { match self { ArgsStringOrList::String(s) => serializer.serialize_str(s), - ArgsStringOrList::List(l) => serializer.serialize_str(&l.join(" ")), + ArgsStringOrList::List(l) => { + let quoted: Vec = l + .iter() + .map(|s| if s.contains(' ') { format!("\"{}\"", s) } else { s.clone() }) + .collect(); + serializer.serialize_str("ed.join(" ")) + } } } } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[derive(Deserialize, Serialize)] + struct ArgsWrapper { + args: ArgsStringOrList, + } + + #[test] + fn test_args_list_with_spaces_quotes_elements() { + let json = std::fs::read_to_string("testdata/args_with_spaces.json").unwrap(); + let wrapper: ArgsWrapper = serde_json::from_str(&json).unwrap(); + let serialized = serde_json::to_value(&wrapper).unwrap(); + assert_eq!( + serialized["args"], + r#""C:\path with spaces\some file.txt" arg2"# + ); + } + + #[test] + fn test_args_single_string_preserved_as_is() { + let json = std::fs::read_to_string("testdata/args_single_string.json").unwrap(); + let wrapper: ArgsWrapper = serde_json::from_str(&json).unwrap(); + let serialized = serde_json::to_value(&wrapper).unwrap(); + assert_eq!( + serialized["args"], + r#"C:\path with spaces\some file.txt"# + ); + } + + #[test] + fn test_args_list_no_spaces_not_quoted() { + let json = std::fs::read_to_string("testdata/args_list_no_spaces.json").unwrap(); + let wrapper: ArgsWrapper = serde_json::from_str(&json).unwrap(); + let serialized = serde_json::to_value(&wrapper).unwrap(); + assert_eq!(serialized["args"], "arg1 arg2"); + } + + #[test] + fn test_args_single_element_with_spaces_quoted() { + let json = + std::fs::read_to_string("testdata/args_single_element_with_spaces.json").unwrap(); + let wrapper: ArgsWrapper = serde_json::from_str(&json).unwrap(); + let serialized = serde_json::to_value(&wrapper).unwrap(); + assert_eq!(serialized["args"], r#""path with spaces""#); + } + + #[test] + fn test_args_empty_list() { + let json = std::fs::read_to_string("testdata/args_empty_list.json").unwrap(); + let wrapper: ArgsWrapper = serde_json::from_str(&json).unwrap(); + let serialized = serde_json::to_value(&wrapper).unwrap(); + assert_eq!(serialized["args"], ""); + } +} diff --git a/testdata/args_empty_list.json b/testdata/args_empty_list.json new file mode 100644 index 0000000..21a41b3 --- /dev/null +++ b/testdata/args_empty_list.json @@ -0,0 +1,3 @@ +{ + "args": [] +} diff --git a/testdata/args_list_no_spaces.json b/testdata/args_list_no_spaces.json new file mode 100644 index 0000000..917d7b8 --- /dev/null +++ b/testdata/args_list_no_spaces.json @@ -0,0 +1,3 @@ +{ + "args": ["arg1", "arg2"] +} diff --git a/testdata/args_single_element_with_spaces.json b/testdata/args_single_element_with_spaces.json new file mode 100644 index 0000000..54bd527 --- /dev/null +++ b/testdata/args_single_element_with_spaces.json @@ -0,0 +1,3 @@ +{ + "args": ["path with spaces"] +} diff --git a/testdata/args_single_string.json b/testdata/args_single_string.json new file mode 100644 index 0000000..6e344aa --- /dev/null +++ b/testdata/args_single_string.json @@ -0,0 +1,3 @@ +{ + "args": "C:\\path with spaces\\some file.txt" +} diff --git a/testdata/args_with_spaces.json b/testdata/args_with_spaces.json new file mode 100644 index 0000000..c53f037 --- /dev/null +++ b/testdata/args_with_spaces.json @@ -0,0 +1,3 @@ +{ + "args": ["C:\\path with spaces\\some file.txt", "arg2"] +} From b98c99db5fb9c9e0eccccde6b84ec1483cebcded Mon Sep 17 00:00:00 2001 From: Riccardo Strina Date: Sat, 21 Feb 2026 17:31:46 +0100 Subject: [PATCH 2/2] Apply formatting --- src/util.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/util.rs b/src/util.rs index ae0cdfe..2f4984b 100644 --- a/src/util.rs +++ b/src/util.rs @@ -432,7 +432,13 @@ impl Serialize for ArgsStringOrList { ArgsStringOrList::List(l) => { let quoted: Vec = l .iter() - .map(|s| if s.contains(' ') { format!("\"{}\"", s) } else { s.clone() }) + .map(|s| { + if s.contains(' ') { + format!("\"{}\"", s) + } else { + s.clone() + } + }) .collect(); serializer.serialize_str("ed.join(" ")) } @@ -466,10 +472,7 @@ mod tests { let json = std::fs::read_to_string("testdata/args_single_string.json").unwrap(); let wrapper: ArgsWrapper = serde_json::from_str(&json).unwrap(); let serialized = serde_json::to_value(&wrapper).unwrap(); - assert_eq!( - serialized["args"], - r#"C:\path with spaces\some file.txt"# - ); + assert_eq!(serialized["args"], r#"C:\path with spaces\some file.txt"#); } #[test]