From e5b9c39f4e53ce86c0b1af2fb077913cf28f9365 Mon Sep 17 00:00:00 2001 From: John Costa Date: Fri, 27 Mar 2026 17:15:32 -0700 Subject: [PATCH] fix(autofmt): remove extra whitespace before commas in for-loop tuple patterns (#5384) * fix(autofmt): remove extra whitespace before commas in for-loop tuple patterns `dx fmt` was adding spaces before commas in for-loop destructuring patterns (e.g. `for (index , name , value)`) because `TokenStream::Display` inserts spaces between every token. Route the pattern through prettyplease via a new `unparse_pat` helper, following the existing `unparse_expr` pattern. Fixes #5348 * style: apply rustfmt to writer.rs --------- Co-authored-by: Jonathan Kelley --- packages/autofmt/src/prettier_please.rs | 30 +++++++++++++++++++ packages/autofmt/src/writer.rs | 6 +--- packages/autofmt/tests/samples.rs | 1 + .../autofmt/tests/samples/forloop_tuple.rsx | 17 +++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 packages/autofmt/tests/samples/forloop_tuple.rsx diff --git a/packages/autofmt/src/prettier_please.rs b/packages/autofmt/src/prettier_please.rs index 2b24c9dbf..88c6e4a58 100644 --- a/packages/autofmt/src/prettier_please.rs +++ b/packages/autofmt/src/prettier_please.rs @@ -7,6 +7,10 @@ impl Writer<'_> { pub fn unparse_expr(&mut self, expr: &Expr) -> String { unparse_expr(expr, self.raw_src, &self.out.indent) } + + pub fn unparse_pat(&self, pat: &syn::Pat) -> String { + unparse_pat(pat) + } } // we use weird unicode alternatives to avoid conflicts with the actual rsx! macro @@ -163,6 +167,32 @@ pub fn unparse_inner(expr: &Expr) -> String { unwrapped(wrapped) } +/// Unparse a pattern into a properly formatted string using prettyplease. +/// +/// Wraps the pattern in `fn main() { for PAT in () {} }`, formats with prettyplease, +/// then extracts just the pattern text between "for " and " in". +pub fn unparse_pat(pat: &syn::Pat) -> String { + let file = File { + shebang: None, + attrs: vec![], + items: vec![Item::Verbatim(quote::quote! { + fn main() { + for #pat in () {} + } + })], + }; + let formatted = prettyplease::unparse(&file); + let after_for = formatted + .find("for ") + .map(|i| i + 4) + .expect("prettyplease output missing 'for' keyword in pattern wrapper"); + let before_in = formatted[after_for..] + .find(" in ") + .map(|i| i + after_for) + .expect("prettyplease output missing 'in' keyword in pattern wrapper"); + formatted[after_for..before_in].trim().to_string() +} + // Split off the fn main and then cut the tabs off the front fn unwrapped(raw: String) -> String { let mut o = raw diff --git a/packages/autofmt/src/writer.rs b/packages/autofmt/src/writer.rs index 26e2aa594..cac750b4b 100644 --- a/packages/autofmt/src/writer.rs +++ b/packages/autofmt/src/writer.rs @@ -153,11 +153,7 @@ impl<'a> Writer<'a> { } fn write_for_loop(&mut self, forloop: &ForLoop) -> std::fmt::Result { - write!( - self.out, - "for {} in ", - forloop.pat.clone().into_token_stream(), - )?; + write!(self.out, "for {} in ", self.unparse_pat(&forloop.pat),)?; self.write_inline_expr(&forloop.expr)?; diff --git a/packages/autofmt/tests/samples.rs b/packages/autofmt/tests/samples.rs index b2ec30a75..4bb494929 100644 --- a/packages/autofmt/tests/samples.rs +++ b/packages/autofmt/tests/samples.rs @@ -64,4 +64,5 @@ twoway![ expr_on_conditional, blank_lines, blank_lines_preserved, + forloop_tuple, ]; diff --git a/packages/autofmt/tests/samples/forloop_tuple.rsx b/packages/autofmt/tests/samples/forloop_tuple.rsx new file mode 100644 index 000000000..f9bb37521 --- /dev/null +++ b/packages/autofmt/tests/samples/forloop_tuple.rsx @@ -0,0 +1,17 @@ +rsx! { + for (index, name, value) in data.iter() { + div { "{index}: {name} = {value}" } + } + + for item in items { + div { "{item}" } + } + + for (a, b) in pairs.iter().enumerate() { + span { "{a}-{b}" } + } + + for (_, value) in pairs { + span { "{value}" } + } +}