-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Add initial formatter implementation #2883
Conversation
@@ -0,0 +1,31 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meant to remove most of these -- dropped one commit. Hold on...
0b99775
to
ddd458a
Compare
8223c0e
to
6f806bc
Compare
ddd458a
to
297b466
Compare
\cc @MichaReiser |
1a62ae7
to
9f83f01
Compare
Need to find a way to ignore the "unused" snapshot files, which are intentionally unused. |
Why are they intentionally unused? I assume you could change the file extension. |
They're copied over from Black, so they represent the "desired" output (essentially, the spec). The formatter fails on a bunch of them right now, so only those that it knowingly passes are used, and we'll increase that set over time. |
6f806bc
to
b377c1c
Compare
9f83f01
to
87b07c6
Compare
b377c1c
to
06a5f8d
Compare
87b07c6
to
e6e0978
Compare
6dc9fa3
to
00835f8
Compare
This PR makes the formatter code more idiomatic by: * Unifying sequential `write!` calls into a single `write` * Replace `format_args![item]` with `item` (`format_args` is to format multiple arguments). You can think of `format_args` as a `Format` implementation for tuples of arbitrary size * Return an object that implements `Format` for `join_names` so that it can be used as part of the DSL `write!(f, [space, join_names(names)])` * Use `space` instead of `text(" ")`
…ize` (#2) Remove the `rome_rowan` dependency from `ruff_fmt` and use `rome_text_size` directly. This is just an aesthetic cleanup that does not improve compile time because `ruff_fmt` depends on `rome_formatter` which depends on `rome_rowan`.
Adds a smoke test to `ruff_fmt` to debug formatter changes. This PR changes the return value of `fmt` to `Result<Formatted>` to allow printing the formatted IR in the quick test. The motivation behind returning `Formatted` is that the IR represents the formatted source code. Printing it only changes its representation from the IR to a string.
It's nice to be able to track tests that are "almost" passing, modulo string normalization, so this PR adds a dedicated section for snippets that fit that description.
Removes all the other fixtures, runs the conversion script over all remaining cases, and removes the `.bak` files.
e6e0978
to
811a2e2
Compare
I find these crate names to be very confusing ... what is the difference? |
The former is language-agnostic formatting infrastructure. The latter is a Python source code formatter. |
Ah right looking at the rome crates I see that there are several language-specific |
I would find it interesting if ruff could format toml and JSON files, raw SQL statements in backend code, graphql queries, etc. to have the same experience as with Prettier. It doesn't just format your JavaScript code, but also other languages that are commonly embedded into JavaScript |
Summary
This PR contains the code for the autoformatter proof-of-concept.
Crate structure
The primary formatting hook is the
fmt
function incrates/ruff_python_formatter/src/lib.rs
.The current formatter approach is outlined in
crates/ruff_python_formatter/src/lib.rs
, and is structured as follows:crates/ruff_python_formatter/src/trivia.rs
, extract a variety of trivia tokens from the token stream. These include comments, trailing commas, and empty lines.crates/ruff_python_formatter/src/cst.rs
, convert the AST to a CST structure. As of now, the CST is nearly identical to the AST, except that every node gets atrivia
vector. But we might want to modify it further.crates/ruff_python_formatter/src/attachment.rs
, attach each trivia token to the corresponding CST node. The logic for this is mostly indecorate_trivia
and is ported almost directly from Prettier (given each token, find its preceding, following, and enclosing nodes, then attach the token to the appropriate node in a second pass).crates/ruff_python_formatter/src/newlines.rs
, normalize newlines to match Black’s preferences. This involves traversing the CST and inserting or removingTriviaToken
values as we go.format!
on the CST, which delegates to type-specific formatter implementations (e.g.,crates/ruff_python_formatter/src/format/stmt.rs
forStmt
nodes, and similar forExpr
nodes; the others are trivial). Those type-specific implementations delegate to kind-specific functions (e.g.,format_func_def
).Testing and iteration
The formatter is being developed against the Black test suite, which was copied over in-full to
crates/ruff_python_formatter/resources/test/fixtures/black
.The Black fixtures had to be modified to create
[insta](/~https://github.com/mitsuhiko/insta)
-compatible snapshots, which now exist in the repo.My approach thus far has been to try and improve coverage by tackling fixtures one-by-one.
What works, and what doesn’t
StmtKind::Try
).