-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Fix format named expr comments #5705
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
use crate::comments::dangling_comments; | ||
use crate::context::PyFormatContext; | ||
use crate::expression::parentheses::{ | ||
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, | ||
}; | ||
use crate::{AsFormat, FormatNodeRule, PyFormatter}; | ||
use ruff_formatter::prelude::{space, text}; | ||
use ruff_formatter::prelude::{soft_line_break, space, text}; | ||
use ruff_formatter::{write, Buffer, FormatResult}; | ||
use rustpython_parser::ast::ExprNamedExpr; | ||
|
||
|
@@ -17,16 +18,37 @@ impl FormatNodeRule<ExprNamedExpr> for FormatExprNamedExpr { | |
value, | ||
range: _, | ||
} = item; | ||
write!( | ||
f, | ||
[ | ||
target.format(), | ||
space(), | ||
text(":="), | ||
space(), | ||
value.format(), | ||
] | ||
) | ||
|
||
write!(f, [target.format()])?; | ||
|
||
let comments = f.context().comments().clone(); | ||
let trailing_target_comments = comments.trailing_comments(target.as_ref()); | ||
let leading_value_comments = comments.leading_comments(value.as_ref()); | ||
let dangling_item_comments = comments.dangling_comments(item); | ||
|
||
if trailing_target_comments.is_empty() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i tried making a single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's |
||
write!(f, [space()])?; | ||
} else { | ||
write!(f, [soft_line_break()])?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the reason for this being a soft line break? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as opposed to? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a |
||
} | ||
|
||
write!(f, [text(":="), dangling_comments(dangling_item_comments)])?; | ||
|
||
if leading_value_comments.is_empty() { | ||
write!(f, [space()])?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens when there are dangling_item_comments but no leading leading_value_comments? this would make a good test case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch. definitely something not what i expected. will continue investigating |
||
} else { | ||
write!(f, [soft_line_break()])?; | ||
} | ||
write!(f, [value.format()]) | ||
} | ||
|
||
fn fmt_dangling_comments( | ||
&self, | ||
_node: &ExprNamedExpr, | ||
_f: &mut PyFormatter, | ||
) -> FormatResult<()> { | ||
// Handled in `fmt_fields` | ||
Ok(()) | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--- | ||
source: crates/ruff_python_formatter/src/trivia.rs | ||
expression: test_case.tokens() | ||
--- | ||
[ | ||
Token { | ||
kind: Colon, | ||
range: 0..1, | ||
}, | ||
Token { | ||
kind: Colon, | ||
range: 1..2, | ||
}, | ||
Token { | ||
kind: Colon, | ||
range: 2..3, | ||
}, | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
source: crates/ruff_python_formatter/src/trivia.rs | ||
expression: test_case.tokens() | ||
--- | ||
[ | ||
Token { | ||
kind: Walrus, | ||
range: 0..2, | ||
}, | ||
Token { | ||
kind: Walrus, | ||
range: 2..4, | ||
}, | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -185,6 +185,10 @@ pub(crate) enum TokenKind { | |
/// `.`. | ||
Dot, | ||
|
||
/// `:=`. | ||
/// TODO: name? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
Walrus, | ||
|
||
/// `else` | ||
Else, | ||
|
||
|
@@ -322,6 +326,15 @@ impl<'a> SimpleTokenizer<'a> { | |
|
||
'\\' => TokenKind::Continuation, | ||
|
||
':' => { | ||
if self.cursor.first() == '=' { | ||
self.cursor.bump(); | ||
TokenKind::Walrus | ||
} else { | ||
TokenKind::Colon | ||
} | ||
} | ||
|
||
c => { | ||
let kind = if is_identifier_start(c) { | ||
self.cursor.eat_while(is_identifier_continuation); | ||
|
@@ -457,6 +470,9 @@ impl<'a> SimpleTokenizer<'a> { | |
self.cursor = savepoint; | ||
TokenKind::Other | ||
} | ||
} else if c == '=' && self.cursor.last() == ':' { | ||
self.cursor.bump_back(); | ||
TokenKind::Walrus | ||
} else { | ||
TokenKind::from_non_trivia_char(c) | ||
}; | ||
|
@@ -687,6 +703,26 @@ mod tests { | |
test_case.assert_reverse_tokenization(); | ||
} | ||
|
||
#[test] | ||
fn tokenize_colon() { | ||
let source = ":::"; | ||
|
||
let test_case = tokenize(source); | ||
|
||
assert_debug_snapshot!(test_case.tokens()); | ||
test_case.assert_reverse_tokenization(); | ||
} | ||
|
||
#[test] | ||
fn tokenize_walrus() { | ||
let source = ":=:="; | ||
|
||
let test_case = tokenize(source); | ||
|
||
assert_debug_snapshot!(test_case.tokens()); | ||
test_case.assert_reverse_tokenization(); | ||
} | ||
|
||
#[test] | ||
fn tokenize_continuation() { | ||
let source = "( \\\n )"; | ||
|
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.
Hey. Just wanted to let you know that I'm working on changing
NeedsParentheses
to pass through the parent node. This should make it straightforward to implement the correct parentheses logic for the walrus operator.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.
👍
atm i can't even figure out what's causing these parens to be added. parenthesize gets set to "ifbreaks" and nothing is breaking...
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.
This PR ships the infrastructure: #5708
The parentheses are added because
FormatExpr
first calls intoNeedsParentheses
to determine if parentheses are necessaryruff/crates/ruff_python_formatter/src/expression/mod.rs
Line 65 in 33a9177
And the implementation of
NamedExpr
returnsAlways
ruff/crates/ruff_python_formatter/src/expression/expr_named_expr.rs
Lines 39 to 44 in 33a9177
We should implement the same rules as in https://github.com/psf/black/blob/d1248ca9beaf0ba526d265f4108836d89cf551b7/src/black/linegen.py#L1381-L1395 (requires access to the parent node)
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.
aah. thanks
do i understand correctly that his is separate to (i.e. won't help with) parens for generator comprehensions (that we were discussing yesterday)?
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.
That's correct. The problem is related but needs a separate fix (and I first need to figure out what even the expected output is... I have suspicion I know how it's supposed to behave but I haven't verified it yet)