rust-lang/rustfmt

Configuring rustfmt formatting with the builder pattern

Closed this issue · 6 comments

Update: The initial example in this issue is incorrect. See this reply for a more descriptive example #6383 (comment).

Maybe just a personal preference but the rustfmt formatting below makes code much less concise.

-    let uuid: String = rand::thread_rng().sample_iter(&Alphanumeric).take(16).map(char::from).collect();
+    let uuid: String = rand::thread_rng()
+        .sample_iter(&Alphanumeric)
+        .take(16)
+        .map(char::from)
+        .collect();

I tried max_width and use_small_heuristics but they don't work with the builder pattern and a few other cases.

Appreciate any ideas to to configure rustfmt with the builder patten.

Alternatively, another option is to disable breaking code alltogether but didn't found that either.

You want all the code on one line?

use_small_heuristics="MAX" should allow you to take advantage of all the width available to you. That said, if the chain you're trying to format exceeds the max_width then rustfmt is going to format it vertically.

running with both max_width=100 and use_small_heuristics="MAX"

fn main() {
    let uuid: String = rand::thread_rng().sample_iter(&Alphanumeric).take(16).map(char::from).collect();
}

If you really want to keep it all on one line even if it exceeds the max_width, then you're only other option is to skip formatting with the #[rustfmt::skip] attribute:

running with default configs and #[rustfmt::skip]

fn main() {
    #[rustfmt::skip]
    let uuid: String = rand::thread_rng().sample_iter(&Alphanumeric).take(16).map(char::from).collect();
}

@ytmimi Thanks for your answer. My initial example was incorrect. Here's a better one.

This code won't be formatted which is expected.

vec![1, 2, 3].iter().map(|v| v * 2).map(|v| v * 3).map(|v| v * 4).map(|v| v * 5).map(|v| v * 6).for_each(|v| {
        println!("{:?}", v);
});

This code will be formatted but the resulted code is not ideal.

- vec![1, 2, 3].iter().map(|v| v * 2).map(|v| v * 3).map(|v| v * 4).map(|v| v * 5).map(|v| v * 6).map(|v| v * 7)
-         .for_each(|v| { println!("{:?}", v); });
+ vec![1, 2, 3]
+         .iter()
+         .map(|v| v * 2)
+         .map(|v| v * 3)
+         .map(|v| v * 4)
+         .map(|v| v * 5)
+         .map(|v| v * 6)
+         .map(|v| v * 7)
+         .for_each(|v| {
+             println!("{:?}", v);
+         });

What I would expect:

vec![1, 2, 3].iter().map(|v| v * 2).map(|v| v * 3).map(|v| v * 4).map(|v| v * 5).map(|v| v * 6)
        .map(|v| v * 7).for_each(|v| { println!("{:?}", v); });

The corresponding rustfmt.toml:

max_width = 120
use_small_heuristics = "Max"

What I would expect:

Rust has a standard Style Guide that defines the style behavior Rustfmt's default adheres to.

The formatting you are seeing is entirely expected and correct, and rustfmt doesn't currently have features that would provide the option for you to get your preferred formatting.

From what you've shared here I'd describe your preferred style to take up as little vertical space as possible at the expense of more horizontal scrolling. rustfmt could technically be extended to support that, but that's pretty niche and not a forced-rewrite type of mode that I could ever see us having sufficient bandwidth and priority to work on ourselves.

I still anticipate that shortly after we finish up our 2024 edition work that I'll get back to #4306 which would allow you to get your preferred output, though you might have to manually add/remove some linebreaks yourself (rustfmt just wouldn't remove/add them on your behalf)

What I would expect:

Rust has a standard Style Guide that defines the style behavior Rustfmt's default adheres to.

While Rust has a style guide, the style guide itself states "This should not be interpreted as forbidding developers from following a non-default style, or forbidding tools from adding any particular configuration options.". Besides, there's a reason that rustfmt.toml exists and that's to configure the style guide.

The formatting you are seeing is entirely expected and correct, and rustfmt doesn't currently have features that would provide the option for you to get your preferred formatting.

Never said that formatting is incorrect, quite the opposite being talking about personal preference.

From what you've shared here I'd describe your preferred style to take up as little vertical space as possible at the expense of more horizontal scrolling. rustfmt could technically be extended to support that, but that's pretty niche and not a forced-rewrite type of mode that I could ever see us having sufficient bandwidth and priority to work on ourselves.

It's not that much about vertical space as to group related functions together (closely related to the issue you referenced below). Not sure if that's so niche as it provides more semantic meaning to the code and people in the issue seem to want this feature too.

I still anticipate that shortly after we finish up our 2024 edition work that I'll get back to #4306 which would allow you to get your preferred output, though you might have to manually add/remove some linebreaks yourself (rustfmt just wouldn't remove/add them on your behalf)

While the issue discusses what happens when max_width is hit, this behaviour exists even if the max_width is not hit and even if the function chains fit, they are split in multiple lines.

It's unclear what sort of response you might have been expecting from your last comment, but there's not really anything more that can be said here that's not just going to be repeating what's already been said.

So the last comment I'll make in summary is:

Here's the rules on chains - https://doc.rust-lang.org/stable/style-guide/expressions.html#chains-of-fields-and-method-calls and why the formatting happens the way that it does.

The style you prefer isn't possible today. rustfmt cannot currently be configured to take any arbitrarily formatted input and rewrite it into your preferred format, and that's not something that we'll work on (fyi I'm also a member of the style team, very familiar with the style guide and the dynamic between rustfmt and the style guide, and the style guide text you quoted unequivocally does not oblige rustfmt to support any and all configuration options and alternative styles)

However, there are some pre-existing planned future enhancements that once implemented should allow you to be able to maintain your preferred style. I'd suggest subscribing to #4306, and we'll also try to post an update back here once that's available on nightly

It's unclear what sort of response you might have been expecting from your last comment, but there's not really anything more that can be said here that's not just going to be repeating what's already been said.

I was looking to better understand the rules of chaining function calls, the link you shared helps.

The only thing that's unclear for me now the following formatting using use_small_heuristics = "Max".

If the first for_each come fits in max_width, this is the result:

-    vec![1, 2, 3].iter().map(|v| v * 2).map(|v| v * 3).map(|v| v * 4).map(|v| v * 5).for_each(|v| {
-        println!("{:?}", v);
-    });
+    vec![1, 2, 3].iter().map(|v| v * 2).map(|v| v * 3).map(|v| v * 4).map(|v| v * 5).for_each(
+        |v| {
+            println!("{:?}", v);
+        },
+    );

If it doesn't fit in max_width, this happens:

-    vec![1, 2, 3].iter().map(|v| v * 2).map(|v| v * 3).map(|v| v * 4).map(|v| v * 5).map(|v| v * 6).for_each(|v| {
-        println!("{:?}", v);
-    });
+    vec![1, 2, 3]
+        .iter()
+        .map(|v| v * 2)
+        .map(|v| v * 3)
+        .map(|v| v * 4)
+        .map(|v| v * 5)
+        .map(|v| v * 6)
+        .for_each(|v| {
+            println!("{:?}", v);
+        });

The style you prefer isn't possible today. rustfmt cannot currently be configured to take any arbitrarily formatted input and rewrite it into your preferred format, and that's not something that we'll work on (fyi I'm also a member of the style team, very familiar with the style guide and the dynamic between rustfmt and the style guide, and the style guide text you quoted unequivocally does not oblige rustfmt to support any and all configuration options and alternative styles)

Never said anything about oblige. I was just trying to find out how things work. Besides, I like Rust style guide more than any other language and appreciate the work that is done here.