-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Implement pattern-based formatter for rust-code on top of rust-analyzer #1665
Comments
Some more links from IntelliJ: Block describes a non-whitespace bit of a syntax tree in the formatting model: https://github.com/JetBrains/intellij-community/blob/c722fdd3333a4fdb9657feede3fb14849d6868a8/platform/lang-api/src/com/intellij/formatting/Block.java Spacing describes constraints on the space between the nodes: https://github.com/JetBrains/intellij-community/blob/c722fdd3333a4fdb9657feede3fb14849d6868a8/platform/lang-api/src/com/intellij/formatting/Spacing.java Indent describes how the block should be indented: https://github.com/JetBrains/intellij-community/blob/c722fdd3333a4fdb9657feede3fb14849d6868a8/platform/lang-api/src/com/intellij/formatting/Indent.java Note how all these bits are reflected in the printout in the comment above. Finally, FormattingModel provide interface for changing stuff: |
cc #1678 |
More links: WhiteSpace is an object-level mutable representation of ws: https://github.com/JetBrains/intellij-community/blob/cae745952ee47fe305403dd9b23beceee5f2ad21/platform/lang-impl/src/com/intellij/formatting/WhiteSpace.java AbstractBlockWrapper is a mutable counterpart of I think allowing only for preceding whitespace makes sense, it should make things simpler |
Considering the number of options of rustfmt, this doesn't really seem easily doable? Would it make sense to start with a simpler gofmt style formatter to start with and have the rustfmt compatible version be another project? |
We should be compatible with default rustfmt options
…On Tuesday, 13 August 2019, Vincent Prouillet ***@***.***> wrote:
To be clear, the goal is not to implement a different code style for
rustfmt: code, already formatted by rustfmt, should not be changed by
ra-fmt.
Considering the number of options of rustfmt, this doesn't really seem
easily doable?
Would it make sense to start with a simpler gofmt style formatter to start
with and have the rustfmt compatible version be another project?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#1665>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AANB3M3XWHYW5LDEUBFGVYLQEHHVRANCNFSM4IKKUCCQ>
.
|
I've rencently went back to working on nixpkgs-fmt for a bit, and gained another useful insight: it is helpful to split formatting into two phases:
in nixpkgs-fmt, we tried to handle both at once. They were two separate phases, but they mutated the single data structure. Now I think it makes sense to fully reify syntax tree between the two phases (and that's what we've switched to in nixpkgs-fmt). And if we do that, it makes sense to start with cc #4182 |
Would I've been entertaining the thought of an alternative rust formater that could be used more easily as a library and integrated into things like dprint as a WASM plugin. |
Yes, and yes. |
If all you care about is WASM, rustc itself can compile to wasm32-wasi with a couple of minor changes: rust-lang/miri#722 (comment) This means that rustfmt probably can be compiled to wasm32-wasi too. |
if/when we do this, we totally should call the thing |
Goal
We need to implement Rust code formatter on top of ra_syntax's concrete syntax tree.
Long-term, I am almost sure that we should just port rustfmt, with two modifications:
However, I think it would be valuable to experiment a bit short-medium term!
There are two kinds of code formatters out there:
Rustfmt, JavaScript's prettier and Python's black are examples of the first breed.
Gofmt and IntelliJ formatter are examples of the second kind.
At https://users.rust-lang.org/t/how-are-you-using-rustfmt-and-clippy/31082/20?u=matklad, some folks suggested that they prefer gofmt style to rustfmt.
So I think it makes sense to just implement that on top of rust-analyzer, as an experiment.
To be clear, the goal is not to implement a different code style for rustfmt: code, already formatted by rustfmt, should not be changed by ra-fmt.
However, ra-fmt should be more flexible about line breaks, allowing to layout code, manually, in a more readable way than rustfmt's style.
Actual Task
So, how does one actually implements a rule-based formatter?
The core idea is to implement formatting as a set of rules like "
=>
token should be surrounded by exactly one whitespace inside match arm", than walk through each syntax node and apply the matching rules to each node.So, formatter is typically split into DLS for defining rules and engine for applying them.
Examples
For example, here's the set of rules for Kotlin:
https://github.com/JetBrains/kotlin/tree/7d173ed3856e429739b55d8c3892e1b85ca41571/idea/formatter/src/org/jetbrains/kotlin/idea/formatter
Here's the DLS definition form IntelliJ:
https://github.com/JetBrains/intellij-community/tree/5c3f54c486856d513c33088a76c7805d312d7ae7/platform/lang-api/src/com/intellij/formatting
And here's the IntelliJ's engine:
https://github.com/JetBrains/intellij-community/tree/5c3f54c486856d513c33088a76c7805d312d7ae7/platform/lang-impl/src/com/intellij/formatting/engine
In a smaller scale, all three parts are implemented in nixpkgs-fmt:
https://github.com/nix-community/nixpkgs-fmt
And of course there's a set of rules that IntelliJ Rust is using:
https://github.com/intellij-rust/intellij-rust/tree/ccf1c54db8e77db90764e32651c8503564a05bc0/src/main/kotlin/org/rust/ide/formatter
Fmt Model
While one can apply formatting operations directly to the syntax tree, I think it's a good idea to introduce an intermediate formatting model tree.
The benefits are:
A good place to look at would be this line:
https://github.com/intellij-rust/intellij-rust/blob/ccf1c54db8e77db90764e32651c8503564a05bc0/src/main/kotlin/org/rust/ide/formatter/RsFormattingModelBuilder.kt#L27
Uncomment it to see how the actual model looks like
for
I get
Note how's stuff after
.
is split in it's own block!The model in nixpkgs-fmt uses explitic whitespace, but uses existing syntax nodes for blocks.
I feel like for rust we should also add fmt-blocks, precisely to deal with chained calls problem.
Passes
After fmt model is build, you run severl passes over it, which fix particula aspects of formatting.
Impl Plan
The rough plan is:
This should live in
ra_fmt
crate and use syntax tree fromra_syntax
crate.The text was updated successfully, but these errors were encountered: