I have a procedural macro that parses html.
It looks like rustfmt will format the tokens inside of my macro
For example:
html! { <div>
Hello
</div>}
The word Hello will get moved to the right a bit if I run rustfmt.
This is a problem because I'm using Spans to generate different code based on the locations of different tokens. So running rustfmt changes how the final program behaves.
Don't reformat the tokens inside of a procedural macro call site by default since it can change the behavior of a program
No idea how difficult or easy any of this is so just trying to detail my experience here. Happy to answer any questions or provide any missing context!
Hmm, so are you using rustfmt as a library inside your procedural macro? I am not entirely clear how rustfmt affects your use case.
No not that - sorry for being unclear!
So let's say I have this program that uses my procedural macro
fn main () {
let before_rustfmt = my_macro! { <div>
Hello</div>
}.to_string();
}
Now let's say I run rustfmt on my program and it gets reformatted to something like this:
fn main () {
let after_rustfmt = my_macro! { <div>
Hello</div>
}.to_string();
}
Notice that hello has been moved.
If my_macro is looking at the Span's in order to determine what code to generate, we now have two completely different programs.
For example. Example one might generate this:
<div>\nHello</div> <--- before rustfmt
While example two might generate
<div>\n Hello</div> // <--- after rustfmt
So, in short, if rustfmt is run on a program that uses some procedural macros, and the procedural macro that it uses is looking at Span's, rustfmt can change the behavior of the final compiled program.
Let me know if I failed to communicate the problem!
Thank you for your clarification. rustfmt cannot distinguish between normal macro and procedural macro calls, so skipping procedural macro only seems hard to solve.
One way is to extend rustfmt::skip to take identifiers as arguments, and skip formatting all macro calls whose name match the identifier passed to rustfmt::skip. E.g., we may want something like the following:
// Skip formatting everything whose name is `html`
#![rustfmt::skip(html)]
// Or make it explicit that you only want to skip macro calls
#![rustfmt::skip::macro(html)]
Thanks you for the visual example!
I really like #![rustfmt::skip::macro(html)] - that would work perfectly!
How complex would that be implementation wise?
I don't think implementing this takes that much time, should be a nice weekend project :)
I see that a PR implementing the skip functionality has been merged, so is this fixed?
Can rustfmt::skip::macros be used by the macro author so it'll automatically apply to all consumers or will everyone have to do it (and learn how to do it!) themselves?
yes this is fixed, sorry the issue got left behind opened
Can rustfmt::skip::macros be used by the macro author so it'll automatically apply to all consumers or will everyone have to do it (and learn how to do it!) themselves?
No, rustfmt does not perform name resolution, so the information from a macro definition is not visible to rustfmt.
skip looks to be default behaviour now, I'm running 1.4.14-stable. I'd like to try the opposite. Is there a way to enable formatting within html! macro invocation?
Most helpful comment
skiplooks to be default behaviour now, I'm running1.4.14-stable. I'd like to try the opposite. Is there a way to enable formatting withinhtml!macro invocation?