-
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
Indent statements in suppressed ranges #6507
Conversation
Current dependencies on/for this PR:
This comment was auto-generated by Graphite. |
PR Check ResultsEcosystem✅ ecosystem check detected no changes. BenchmarkLinux
Windows
|
ce43cf6
to
09bc0d9
Compare
33e5b05
to
0883745
Compare
0883745
to
e4b26f2
Compare
613d18e
to
5622dac
Compare
e4b26f2
to
12f9bbc
Compare
crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/.editorconfig
Outdated
Show resolved
Hide resolved
/// This implementation makes use of this fact and assumes a tab size of 1. | ||
/// * The source document is correctly indented because it is valid Python code (or the formatter would have failed parsing the code). | ||
#[derive(Copy, Clone)] | ||
struct Indentation(u32); |
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.
There's already an Indentation
in ruff_python_parser, do we want to give this one a different name?
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.
Do you have a recommendation? I wasn't able to come up with a good name.
I'm not too concerned about the naming conflict, considering that this is a private type.
/// Notice how the `not_formatted + b` expression statement gets the same indentation as the `print` statement above, | ||
/// but the indentation of the expression remains unchanged. It changes the indentation to: | ||
/// * Prevent syntax errors because of different indentation levels between formatted and suppressed statements. | ||
/// * Align with the `fmt: skip` where statements are indented as well, but inner expressions are formatted as is. |
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.
i like the docstring solution of only stripping the shared leading indentation, through docstring we would also already have the utils for that, except for own line comments.
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.
I would like that too. But we would need to track two different indentations:
- One to strip before statements
- The shared leading indentation, for comments
It may otherwise result in invalid code if a comment has less indentation than the statements. I think we consider introducing this complexity if we get reports that our fmt: off breaks the intended formatting (or e.g. test if the entire suite is disabled, and if so, don't fix up the indent)
// Is there any remaining content after the last token? If so, return it as the last | ||
// logical line. | ||
return if self.last_line_end < self.content_end { | ||
let content_start = self.last_line_end; | ||
self.last_line_end = self.content_end; | ||
Some(Ok(LogicalLine { | ||
content_range: TextRange::new(content_start, self.content_end), | ||
contains_newlines, | ||
has_trailing_newline: false, |
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.
what would that content be and how do we know whether it contains newlines?
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.
I extended the comment to mention what content it is and changed contains_newlines
to always be No
because the lexer would otherwise return a Newline
token.
crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/indent.py
Show resolved
Hide resolved
5622dac
to
05cbaab
Compare
12f9bbc
to
bdab1c2
Compare
bdab1c2
to
df98068
Compare
Summary
This PR implements logic to fix up the indentation of suppressed statement ranges to prevent that formatting the following file results in a syntax error:
fmt: skip
andfmt: off
behavior (re-indents the statement, but not its content)It may be a bit surprising that this PR also changes the indentation of comments. This is necessary to avoid that a comment getting associated with a different node after formatting once, if the indentation sequence changed:
For example, if we format the following with an indent of 4 spaces:
The output without re-indenting comments would be:
This results in an instability because the end of body comments of
test
now have a smaller indentation thanpass
, resulting in the formatter associating these as trailing comments of the functiontest
rather than thepass
statement. Now,fmt: on
suddenly re-enables formatting ofdisabled + formatting;
The re-formatting of comments and statements may be controversial inside of a
fmt: off..fmt: on
region but the benefits of being able to format files with suppressed ranges rather than just failing if the indentations end up miss matching outweighs the maybe surprising behavior mainly because it results in no chance if the statements are correctly indented.Test Plan
I added new test cases, including test cases with mixed indentation.