Skip to content

Feature request: option for rustfmt to leave line breaks alone #5085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ghost opened this issue Nov 14, 2021 · 1 comment
Closed

Feature request: option for rustfmt to leave line breaks alone #5085

ghost opened this issue Nov 14, 2021 · 1 comment

Comments

@ghost
Copy link

ghost commented Nov 14, 2021

Rustfmt currently considers itself responsible for breaking long lines and un-breaking short broken lines. It's approach to doing so seems to be that if a statement can't fit on 1 line, every single dot-separated part of the statement must get its own line, even if some of them are very small and would look better together. One example is https://lemmy.ml/post/88273, but I see it do this kind of thing constantly. Meanwhile if the max line length is increased enough to prevent it from doing this, it un-breaks everything to stuff it onto 1 line rather than preserving statements that were hand-formatted onto 2 or 3 lines.

Rather than modifying its line-break behavior or adding more options to control it, what I'd like to see is just an option that makes rustfmt consider line breaks to not be its responsibility - it would still apply other formats, such as trailing commas, brace style, import organization, and binop separator stuff, but would not break or un-break lines of code due to length. This is, as far as I can tell, how the Go formatter works, and I have never seen the Go formatter be anything but helpful.

Edit: Another case is when rustfmt breaks a long let binding onto 2 lines:

	let message =
		e!(pending.first(), "received handshake complete but we have no message to send", ());

As you can see, the line is quite long and a good candidate for breaking, but rustfmt's decision to break it at the = sign means that the brunt of the line isn't broken and is still very long and noisy. If I hand-modify it to break after pending.first(), instead of at the = sign, rustfmt reformats it to the above.

@calebcartwright
Copy link
Member

Thanks for reaching out with your suggestion, and assuming you're also the author of the post linked in the issue description, sorry to hear you hate rustfmt! However, I'm going to close this because the actionable item around chains specifically is already being tracked in a different issue, #4306, and the broader holistic ask of the issue isn't feasible.

For more context, you should be aware that rustfmt is the pretty-printer style of code formatter, similar in philosophy to Python's black or JavaScript/TypeScript's prettier. rustfmt does not directly process your input files and each of their respective tokens, but instead, rustfmt walks the AST of the input program which is produced as the output of the compiler's parsing stage.

This was done intentionally as a means to achieve the original style goals for Rust of trying to have style consistency not only within a given code base, but Rust code in general across codebases. That consisted of an RFC-driven process (https://github.com/rust-dev-tools/fmt-rfcs) that codifies the various styling rules, with rustfmt as the implementation tool that applied the corresponding rules to each AST node it encountered to produce code that was formatted in compliance with style guide. So it's not that rustfmt is directly modifying your input, it's heuristically producing an output based on the contents represented in the AST and logic based on the respective style guide rules.

As with most things in life, there's tradeoffs with this decision, one notable drawback meaning that no one loves every aspect of the resultant style, and it does steamroll handcrafted styles that the author likely found to be subjectively "superior". For many people the output typically falls somewhere between "good" and "I'd do it differently but I guess I can live with it", but obviously some will encounter parts/cases they strongly dislike.

For those types of scenarios we offer an attribute-based skip system that can be used inline to tell rustfmt to leave a particular statement, expression, etc. alone, and sometimes it's feasible for us to provide configuration options that users can leverage to have rustfmt produce a different output. However, it's not feasible/practical to provide any and all formatting behavior via configuration options, and that includes the broader request of this issue to let the input file line breaks drive the formatting behavior given the above context. That'd require an entirely different formatting strategy and isn't something that we can simply plug into rustfmt.

All that being said, we realize that line breaks/wraps can be particularly disruptive with certain constructs, like chains, and we are accordingly exploring options to give users more flexibility, perhaps even using the line breaks within the chains to inform/influence the logic that handles chains.

I also think there's a good chance that at some point down the road we'll have a configuration surface that users can leverage to control the strategy used internally for the RHS of assignments (e.g. #4886)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants