mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-23 04:55:09 +00:00
Improve comprehension line break beheavior
<!-- Thank you for contributing to Ruff! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary This PR improves the Black compatibility when it comes to breaking comprehensions. We want to avoid line breaks before the target and `in` whenever possible. Furthermore, `if X is not None` should be grouped together, similar to other binary like expressions <!-- What's the purpose of the change? What does it do, and why? --> ## Test Plan `cargo test` <!-- How was it tested? -->
This commit is contained in:
parent
62a24e1028
commit
8b9193ab1f
11 changed files with 121 additions and 316 deletions
|
@ -33,36 +33,40 @@ impl FormatNodeRule<ExprCompare> for FormatExprCompare {
|
|||
|
||||
let comments = f.context().comments().clone();
|
||||
|
||||
write!(f, [in_parentheses_only_group(&left.format())])?;
|
||||
let inner = format_with(|f| {
|
||||
write!(f, [in_parentheses_only_group(&left.format())])?;
|
||||
|
||||
assert_eq!(comparators.len(), ops.len());
|
||||
assert_eq!(comparators.len(), ops.len());
|
||||
|
||||
for (operator, comparator) in ops.iter().zip(comparators) {
|
||||
let leading_comparator_comments = comments.leading_comments(comparator);
|
||||
if leading_comparator_comments.is_empty() {
|
||||
write!(f, [soft_line_break_or_space()])?;
|
||||
} else {
|
||||
// Format the expressions leading comments **before** the operator
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
hard_line_break(),
|
||||
leading_comments(leading_comparator_comments)
|
||||
]
|
||||
)?;
|
||||
}
|
||||
|
||||
for (operator, comparator) in ops.iter().zip(comparators) {
|
||||
let leading_comparator_comments = comments.leading_comments(comparator);
|
||||
if leading_comparator_comments.is_empty() {
|
||||
write!(f, [soft_line_break_or_space()])?;
|
||||
} else {
|
||||
// Format the expressions leading comments **before** the operator
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
hard_line_break(),
|
||||
leading_comments(leading_comparator_comments)
|
||||
operator.format(),
|
||||
space(),
|
||||
in_parentheses_only_group(&comparator.format())
|
||||
]
|
||||
)?;
|
||||
}
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
operator.format(),
|
||||
space(),
|
||||
in_parentheses_only_group(&comparator.format())
|
||||
]
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Ok(())
|
||||
in_parentheses_only_group(&inner).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,25 @@ use crate::prelude::*;
|
|||
use crate::AsFormat;
|
||||
use crate::{FormatNodeRule, PyFormatter};
|
||||
use ruff_formatter::{format_args, write, Buffer, FormatResult};
|
||||
use rustpython_parser::ast::{Comprehension, Ranged};
|
||||
use rustpython_parser::ast::{Comprehension, Expr, Ranged};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatComprehension;
|
||||
|
||||
impl FormatNodeRule<Comprehension> for FormatComprehension {
|
||||
fn fmt_fields(&self, item: &Comprehension, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
struct Spacer<'a>(&'a Expr);
|
||||
|
||||
impl Format<PyFormatContext<'_>> for Spacer<'_> {
|
||||
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
if f.context().comments().has_leading_comments(self.0) {
|
||||
soft_line_break_or_space().fmt(f)
|
||||
} else {
|
||||
space().fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let Comprehension {
|
||||
range: _,
|
||||
target,
|
||||
|
@ -18,33 +30,40 @@ impl FormatNodeRule<Comprehension> for FormatComprehension {
|
|||
is_async,
|
||||
} = item;
|
||||
|
||||
let comments = f.context().comments().clone();
|
||||
|
||||
if *is_async {
|
||||
write!(f, [text("async"), space()])?;
|
||||
}
|
||||
|
||||
let comments = f.context().comments().clone();
|
||||
let dangling_item_comments = comments.dangling_comments(item);
|
||||
|
||||
let (before_target_comments, before_in_comments) = dangling_item_comments.split_at(
|
||||
dangling_item_comments
|
||||
.partition_point(|comment| comment.slice().end() < target.range().start()),
|
||||
);
|
||||
|
||||
let trailing_in_comments = comments.dangling_comments(iter);
|
||||
|
||||
let in_spacer = format_with(|f| {
|
||||
if before_in_comments.is_empty() {
|
||||
space().fmt(f)
|
||||
} else {
|
||||
soft_line_break_or_space().fmt(f)
|
||||
}
|
||||
});
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
text("for"),
|
||||
trailing_comments(before_target_comments),
|
||||
group(&format_args!(
|
||||
soft_line_break_or_space(),
|
||||
Spacer(target),
|
||||
target.format(),
|
||||
soft_line_break_or_space(),
|
||||
in_spacer,
|
||||
leading_comments(before_in_comments),
|
||||
text("in"),
|
||||
trailing_comments(trailing_in_comments),
|
||||
soft_line_break_or_space(),
|
||||
Spacer(iter),
|
||||
iter.format(),
|
||||
)),
|
||||
]
|
||||
|
@ -64,7 +83,7 @@ impl FormatNodeRule<Comprehension> for FormatComprehension {
|
|||
leading_comments(own_line_if_comments),
|
||||
text("if"),
|
||||
trailing_comments(end_of_line_if_comments),
|
||||
soft_line_break_or_space(),
|
||||
Spacer(if_case),
|
||||
if_case.format(),
|
||||
)));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue