mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-23 13:05:06 +00:00
Generalize comment-after-bracket handling to lists, sets, etc. (#6320)
## Summary We already support preserving the end-of-line comment in calls and type parameters, as in: ```python foo( # comment bar, ) ``` This PR adds the same behavior for lists, sets, comprehensions, etc., such that we preserve: ```python [ # comment 1, 2, 3, ] ``` And related cases.
This commit is contained in:
parent
d3aa8b4ee0
commit
1d8759d5df
20 changed files with 265 additions and 99 deletions
|
@ -478,7 +478,7 @@ impl<Context> std::fmt::Debug for LineSuffix<'_, Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a boundary for line suffixes that forces the printer to print all pending line suffixes.
|
/// Inserts a boundary for line suffixes that forces the printer to print all pending line suffixes.
|
||||||
/// Helpful if a line sufix shouldn't pass a certain point.
|
/// Helpful if a line suffix shouldn't pass a certain point.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
///
|
///
|
||||||
|
|
|
@ -86,3 +86,10 @@ selected_choices = {
|
||||||
k: str(v)
|
k: str(v)
|
||||||
for vvvvvvvvvvvvvvvvvvvvvvv in value if str(v) not in self.choices.field.empty_values
|
for vvvvvvvvvvvvvvvvvvvvvvv in value if str(v) not in self.choices.field.empty_values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
k: v
|
||||||
|
for ( # foo
|
||||||
|
|
||||||
|
x, aaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaay) in z
|
||||||
|
}
|
||||||
|
|
|
@ -25,3 +25,9 @@ len(
|
||||||
# trailing
|
# trailing
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
len(
|
||||||
|
# leading
|
||||||
|
a for b in c
|
||||||
|
# trailing
|
||||||
|
)
|
||||||
|
|
|
@ -32,3 +32,15 @@ c1 = [ # trailing open bracket
|
||||||
2, # trailing item
|
2, # trailing item
|
||||||
# leading close bracket
|
# leading close bracket
|
||||||
] # trailing close bracket
|
] # trailing close bracket
|
||||||
|
|
||||||
|
|
||||||
|
[ # end-of-line comment
|
||||||
|
]
|
||||||
|
|
||||||
|
[ # end-of-line comment
|
||||||
|
# own-line comment
|
||||||
|
]
|
||||||
|
|
||||||
|
[ # end-of-line comment
|
||||||
|
1
|
||||||
|
]
|
||||||
|
|
|
@ -2,10 +2,7 @@ use std::cmp::Ordering;
|
||||||
|
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_python_ast::whitespace::indentation;
|
use ruff_python_ast::whitespace::indentation;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{self as ast, Comprehension, Expr, MatchCase, Parameters, Ranged};
|
||||||
self as ast, Comprehension, Expr, ExprAttribute, ExprBinOp, ExprIfExp, ExprSlice, ExprStarred,
|
|
||||||
MatchCase, Parameters, Ranged,
|
|
||||||
};
|
|
||||||
use ruff_python_trivia::{
|
use ruff_python_trivia::{
|
||||||
indentation_at_offset, PythonWhitespace, SimpleToken, SimpleTokenKind, SimpleTokenizer,
|
indentation_at_offset, PythonWhitespace, SimpleToken, SimpleTokenKind, SimpleTokenizer,
|
||||||
};
|
};
|
||||||
|
@ -50,9 +47,9 @@ pub(super) fn place_comment<'a>(
|
||||||
locator,
|
locator,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
AnyNodeRef::ExprDict(_) | AnyNodeRef::Keyword(_) => {
|
AnyNodeRef::Keyword(_) => handle_dict_unpacking_comment(comment, locator),
|
||||||
handle_dict_unpacking_comment(comment, locator)
|
AnyNodeRef::ExprDict(_) => handle_dict_unpacking_comment(comment, locator)
|
||||||
}
|
.then_with(|comment| handle_bracketed_end_of_line_comment(comment, locator)),
|
||||||
AnyNodeRef::ExprIfExp(expr_if) => handle_expr_if_comment(comment, expr_if, locator),
|
AnyNodeRef::ExprIfExp(expr_if) => handle_expr_if_comment(comment, expr_if, locator),
|
||||||
AnyNodeRef::ExprSlice(expr_slice) => handle_slice_comments(comment, expr_slice, locator),
|
AnyNodeRef::ExprSlice(expr_slice) => handle_slice_comments(comment, expr_slice, locator),
|
||||||
AnyNodeRef::ExprStarred(starred) => {
|
AnyNodeRef::ExprStarred(starred) => {
|
||||||
|
@ -77,6 +74,13 @@ pub(super) fn place_comment<'a>(
|
||||||
handle_leading_class_with_decorators_comment(comment, class_def)
|
handle_leading_class_with_decorators_comment(comment, class_def)
|
||||||
}
|
}
|
||||||
AnyNodeRef::StmtImportFrom(import_from) => handle_import_from_comment(comment, import_from),
|
AnyNodeRef::StmtImportFrom(import_from) => handle_import_from_comment(comment, import_from),
|
||||||
|
AnyNodeRef::ExprList(_)
|
||||||
|
| AnyNodeRef::ExprSet(_)
|
||||||
|
| AnyNodeRef::ExprGeneratorExp(_)
|
||||||
|
| AnyNodeRef::ExprListComp(_)
|
||||||
|
| AnyNodeRef::ExprSetComp(_)
|
||||||
|
| AnyNodeRef::ExprDictComp(_)
|
||||||
|
| AnyNodeRef::ExprTuple(_) => handle_bracketed_end_of_line_comment(comment, locator),
|
||||||
_ => CommentPlacement::Default(comment),
|
_ => CommentPlacement::Default(comment),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -633,7 +637,7 @@ fn handle_parameters_separator_comment<'a>(
|
||||||
/// ```
|
/// ```
|
||||||
fn handle_trailing_binary_expression_left_or_operator_comment<'a>(
|
fn handle_trailing_binary_expression_left_or_operator_comment<'a>(
|
||||||
comment: DecoratedComment<'a>,
|
comment: DecoratedComment<'a>,
|
||||||
binary_expression: &'a ExprBinOp,
|
binary_expression: &'a ast::ExprBinOp,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
) -> CommentPlacement<'a> {
|
) -> CommentPlacement<'a> {
|
||||||
// Only if there's a preceding node (in which case, the preceding node is `left`).
|
// Only if there's a preceding node (in which case, the preceding node is `left`).
|
||||||
|
@ -797,10 +801,10 @@ fn handle_module_level_own_line_comment_before_class_or_function_comment<'a>(
|
||||||
/// ```
|
/// ```
|
||||||
fn handle_slice_comments<'a>(
|
fn handle_slice_comments<'a>(
|
||||||
comment: DecoratedComment<'a>,
|
comment: DecoratedComment<'a>,
|
||||||
expr_slice: &'a ExprSlice,
|
expr_slice: &'a ast::ExprSlice,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
) -> CommentPlacement<'a> {
|
) -> CommentPlacement<'a> {
|
||||||
let ExprSlice {
|
let ast::ExprSlice {
|
||||||
range: _,
|
range: _,
|
||||||
lower,
|
lower,
|
||||||
upper,
|
upper,
|
||||||
|
@ -907,7 +911,7 @@ fn handle_leading_class_with_decorators_comment<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles comments between `**` and the variable name in dict unpacking
|
/// Handles comments between `**` and the variable name in dict unpacking
|
||||||
/// It attaches these to the appropriate value node
|
/// It attaches these to the appropriate value node.
|
||||||
///
|
///
|
||||||
/// ```python
|
/// ```python
|
||||||
/// {
|
/// {
|
||||||
|
@ -945,7 +949,7 @@ fn handle_dict_unpacking_comment<'a>(
|
||||||
|
|
||||||
// if the remaining tokens from the previous node are exactly `**`,
|
// if the remaining tokens from the previous node are exactly `**`,
|
||||||
// re-assign the comment to the one that follows the stars
|
// re-assign the comment to the one that follows the stars
|
||||||
let mut count = 0;
|
let mut count = 0u32;
|
||||||
|
|
||||||
// we start from the preceding node but we skip its token
|
// we start from the preceding node but we skip its token
|
||||||
if let Some(token) = tokens.next() {
|
if let Some(token) = tokens.next() {
|
||||||
|
@ -992,7 +996,7 @@ fn handle_dict_unpacking_comment<'a>(
|
||||||
/// ```
|
/// ```
|
||||||
fn handle_attribute_comment<'a>(
|
fn handle_attribute_comment<'a>(
|
||||||
comment: DecoratedComment<'a>,
|
comment: DecoratedComment<'a>,
|
||||||
attribute: &'a ExprAttribute,
|
attribute: &'a ast::ExprAttribute,
|
||||||
) -> CommentPlacement<'a> {
|
) -> CommentPlacement<'a> {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
comment.preceding_node().is_some(),
|
comment.preceding_node().is_some(),
|
||||||
|
@ -1039,10 +1043,10 @@ fn handle_attribute_comment<'a>(
|
||||||
/// happens if the comments are in a weird position but it also doesn't hurt handling it.
|
/// happens if the comments are in a weird position but it also doesn't hurt handling it.
|
||||||
fn handle_expr_if_comment<'a>(
|
fn handle_expr_if_comment<'a>(
|
||||||
comment: DecoratedComment<'a>,
|
comment: DecoratedComment<'a>,
|
||||||
expr_if: &'a ExprIfExp,
|
expr_if: &'a ast::ExprIfExp,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
) -> CommentPlacement<'a> {
|
) -> CommentPlacement<'a> {
|
||||||
let ExprIfExp {
|
let ast::ExprIfExp {
|
||||||
range: _,
|
range: _,
|
||||||
test,
|
test,
|
||||||
body,
|
body,
|
||||||
|
@ -1096,7 +1100,7 @@ fn handle_expr_if_comment<'a>(
|
||||||
/// ```
|
/// ```
|
||||||
fn handle_trailing_expression_starred_star_end_of_line_comment<'a>(
|
fn handle_trailing_expression_starred_star_end_of_line_comment<'a>(
|
||||||
comment: DecoratedComment<'a>,
|
comment: DecoratedComment<'a>,
|
||||||
starred: &'a ExprStarred,
|
starred: &'a ast::ExprStarred,
|
||||||
) -> CommentPlacement<'a> {
|
) -> CommentPlacement<'a> {
|
||||||
if comment.line_position().is_own_line() {
|
if comment.line_position().is_own_line() {
|
||||||
return CommentPlacement::Default(comment);
|
return CommentPlacement::Default(comment);
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
use crate::builders::empty_parenthesized_with_dangling_comments;
|
|
||||||
use crate::comments::leading_comments;
|
|
||||||
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::FormatNodeRule;
|
|
||||||
use ruff_formatter::{format_args, write};
|
use ruff_formatter::{format_args, write};
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_python_ast::Ranged;
|
use ruff_python_ast::Ranged;
|
||||||
use ruff_python_ast::{Expr, ExprDict};
|
use ruff_python_ast::{Expr, ExprDict};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
|
use crate::builders::empty_parenthesized_with_dangling_comments;
|
||||||
|
use crate::comments::leading_comments;
|
||||||
|
use crate::expression::parentheses::{
|
||||||
|
parenthesized_with_dangling_comments, NeedsParentheses, OptionalParentheses,
|
||||||
|
};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::FormatNodeRule;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FormatExprDict;
|
pub struct FormatExprDict;
|
||||||
|
|
||||||
|
@ -64,14 +67,12 @@ impl FormatNodeRule<ExprDict> for FormatExprDict {
|
||||||
|
|
||||||
debug_assert_eq!(keys.len(), values.len());
|
debug_assert_eq!(keys.len(), values.len());
|
||||||
|
|
||||||
|
let comments = f.context().comments().clone();
|
||||||
|
let dangling = comments.dangling_comments(item);
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
let comments = f.context().comments().clone();
|
return empty_parenthesized_with_dangling_comments(text("{"), dangling, text("}"))
|
||||||
return empty_parenthesized_with_dangling_comments(
|
.fmt(f);
|
||||||
text("{"),
|
|
||||||
comments.dangling_comments(item),
|
|
||||||
text("}"),
|
|
||||||
)
|
|
||||||
.fmt(f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let format_pairs = format_with(|f| {
|
let format_pairs = format_with(|f| {
|
||||||
|
@ -85,7 +86,7 @@ impl FormatNodeRule<ExprDict> for FormatExprDict {
|
||||||
joiner.finish()
|
joiner.finish()
|
||||||
});
|
});
|
||||||
|
|
||||||
parenthesized("{", &format_pairs, "}").fmt(f)
|
parenthesized_with_dangling_comments("{", dangling, &format_pairs, "}").fmt(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_dangling_comments(&self, _node: &ExprDict, _f: &mut PyFormatter) -> FormatResult<()> {
|
fn fmt_dangling_comments(&self, _node: &ExprDict, _f: &mut PyFormatter) -> FormatResult<()> {
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
use crate::context::PyFormatContext;
|
|
||||||
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
|
|
||||||
use crate::AsFormat;
|
|
||||||
use crate::{FormatNodeRule, FormattedIterExt, PyFormatter};
|
|
||||||
use ruff_formatter::prelude::{
|
use ruff_formatter::prelude::{
|
||||||
format_args, format_with, group, soft_line_break_or_space, space, text,
|
format_args, format_with, group, soft_line_break_or_space, space, text,
|
||||||
};
|
};
|
||||||
|
@ -9,6 +5,13 @@ use ruff_formatter::{write, Buffer, FormatResult};
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_python_ast::ExprDictComp;
|
use ruff_python_ast::ExprDictComp;
|
||||||
|
|
||||||
|
use crate::context::PyFormatContext;
|
||||||
|
use crate::expression::parentheses::{
|
||||||
|
parenthesized_with_dangling_comments, NeedsParentheses, OptionalParentheses,
|
||||||
|
};
|
||||||
|
use crate::AsFormat;
|
||||||
|
use crate::{FormatNodeRule, FormattedIterExt, PyFormatter};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FormatExprDictComp;
|
pub struct FormatExprDictComp;
|
||||||
|
|
||||||
|
@ -27,10 +30,14 @@ impl FormatNodeRule<ExprDictComp> for FormatExprDictComp {
|
||||||
.finish()
|
.finish()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let comments = f.context().comments().clone();
|
||||||
|
let dangling = comments.dangling_comments(item);
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[parenthesized(
|
[parenthesized_with_dangling_comments(
|
||||||
"{",
|
"{",
|
||||||
|
dangling,
|
||||||
&group(&format_args!(
|
&group(&format_args!(
|
||||||
group(&key.format()),
|
group(&key.format()),
|
||||||
text(":"),
|
text(":"),
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
use ruff_formatter::{format_args, write, Buffer, FormatResult, FormatRuleWithOptions};
|
||||||
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
|
use ruff_python_ast::ExprGeneratorExp;
|
||||||
|
|
||||||
|
use crate::comments::leading_comments;
|
||||||
use crate::context::PyFormatContext;
|
use crate::context::PyFormatContext;
|
||||||
use crate::expression::parentheses::parenthesized;
|
use crate::expression::parentheses::parenthesized_with_dangling_comments;
|
||||||
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
|
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::AsFormat;
|
use crate::AsFormat;
|
||||||
use crate::{FormatNodeRule, PyFormatter};
|
use crate::{FormatNodeRule, PyFormatter};
|
||||||
use ruff_formatter::{format_args, write, Buffer, FormatResult, FormatRuleWithOptions};
|
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
|
||||||
use ruff_python_ast::ExprGeneratorExp;
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Default)]
|
#[derive(Eq, PartialEq, Debug, Default)]
|
||||||
pub enum GeneratorExpParentheses {
|
pub enum GeneratorExpParentheses {
|
||||||
|
@ -48,10 +50,14 @@ impl FormatNodeRule<ExprGeneratorExp> for FormatExprGeneratorExp {
|
||||||
.finish()
|
.finish()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let comments = f.context().comments().clone();
|
||||||
|
let dangling = comments.dangling_comments(item);
|
||||||
|
|
||||||
if self.parentheses == GeneratorExpParentheses::StripIfOnlyFunctionArg {
|
if self.parentheses == GeneratorExpParentheses::StripIfOnlyFunctionArg {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[
|
[
|
||||||
|
leading_comments(dangling),
|
||||||
group(&elt.format()),
|
group(&elt.format()),
|
||||||
soft_line_break_or_space(),
|
soft_line_break_or_space(),
|
||||||
group(&joined),
|
group(&joined),
|
||||||
|
@ -60,8 +66,9 @@ impl FormatNodeRule<ExprGeneratorExp> for FormatExprGeneratorExp {
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[parenthesized(
|
[parenthesized_with_dangling_comments(
|
||||||
"(",
|
"(",
|
||||||
|
dangling,
|
||||||
&format_args!(
|
&format_args!(
|
||||||
group(&elt.format()),
|
group(&elt.format()),
|
||||||
soft_line_break_or_space(),
|
soft_line_break_or_space(),
|
||||||
|
@ -72,6 +79,15 @@ impl FormatNodeRule<ExprGeneratorExp> for FormatExprGeneratorExp {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fmt_dangling_comments(
|
||||||
|
&self,
|
||||||
|
_node: &ExprGeneratorExp,
|
||||||
|
_f: &mut PyFormatter,
|
||||||
|
) -> FormatResult<()> {
|
||||||
|
// Handled as part of `fmt_fields`
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NeedsParentheses for ExprGeneratorExp {
|
impl NeedsParentheses for ExprGeneratorExp {
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
use crate::builders::empty_parenthesized_with_dangling_comments;
|
use ruff_formatter::prelude::{format_with, text};
|
||||||
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::FormatNodeRule;
|
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_python_ast::{ExprList, Ranged};
|
use ruff_python_ast::{ExprList, Ranged};
|
||||||
|
|
||||||
|
use crate::builders::empty_parenthesized_with_dangling_comments;
|
||||||
|
use crate::expression::parentheses::{
|
||||||
|
parenthesized_with_dangling_comments, NeedsParentheses, OptionalParentheses,
|
||||||
|
};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::FormatNodeRule;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FormatExprList;
|
pub struct FormatExprList;
|
||||||
|
|
||||||
|
@ -24,18 +28,13 @@ impl FormatNodeRule<ExprList> for FormatExprList {
|
||||||
.fmt(f);
|
.fmt(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(
|
|
||||||
dangling.is_empty(),
|
|
||||||
"A non-empty expression list has dangling comments"
|
|
||||||
);
|
|
||||||
|
|
||||||
let items = format_with(|f| {
|
let items = format_with(|f| {
|
||||||
f.join_comma_separated(item.end())
|
f.join_comma_separated(item.end())
|
||||||
.nodes(elts.iter())
|
.nodes(elts.iter())
|
||||||
.finish()
|
.finish()
|
||||||
});
|
});
|
||||||
|
|
||||||
parenthesized("[", &items, "]").fmt(f)
|
parenthesized_with_dangling_comments("[", dangling, &items, "]").fmt(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_dangling_comments(&self, _node: &ExprList, _f: &mut PyFormatter) -> FormatResult<()> {
|
fn fmt_dangling_comments(&self, _node: &ExprList, _f: &mut PyFormatter) -> FormatResult<()> {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
|
use ruff_formatter::{format_args, write, FormatResult};
|
||||||
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
|
use ruff_python_ast::ExprListComp;
|
||||||
|
|
||||||
use crate::context::PyFormatContext;
|
use crate::context::PyFormatContext;
|
||||||
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
|
use crate::expression::parentheses::{
|
||||||
|
parenthesized_with_dangling_comments, NeedsParentheses, OptionalParentheses,
|
||||||
|
};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::AsFormat;
|
use crate::AsFormat;
|
||||||
use crate::{FormatNodeRule, PyFormatter};
|
use crate::{FormatNodeRule, PyFormatter};
|
||||||
use ruff_formatter::{format_args, write, Buffer, FormatResult};
|
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
|
||||||
use ruff_python_ast::ExprListComp;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FormatExprListComp;
|
pub struct FormatExprListComp;
|
||||||
|
@ -24,10 +27,14 @@ impl FormatNodeRule<ExprListComp> for FormatExprListComp {
|
||||||
.finish()
|
.finish()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let comments = f.context().comments().clone();
|
||||||
|
let dangling = comments.dangling_comments(item);
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[parenthesized(
|
[parenthesized_with_dangling_comments(
|
||||||
"[",
|
"[",
|
||||||
|
dangling,
|
||||||
&group(&format_args![
|
&group(&format_args![
|
||||||
group(&elt.format()),
|
group(&elt.format()),
|
||||||
soft_line_break_or_space(),
|
soft_line_break_or_space(),
|
||||||
|
@ -37,6 +44,15 @@ impl FormatNodeRule<ExprListComp> for FormatExprListComp {
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fmt_dangling_comments(
|
||||||
|
&self,
|
||||||
|
_node: &ExprListComp,
|
||||||
|
_f: &mut PyFormatter,
|
||||||
|
) -> FormatResult<()> {
|
||||||
|
// Handled as part of `fmt_fields`
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NeedsParentheses for ExprListComp {
|
impl NeedsParentheses for ExprListComp {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_python_ast::{ExprSet, Ranged};
|
use ruff_python_ast::{ExprSet, Ranged};
|
||||||
|
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use crate::expression::parentheses::{
|
||||||
|
parenthesized_with_dangling_comments, NeedsParentheses, OptionalParentheses,
|
||||||
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
|
};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::FormatNodeRule;
|
use crate::FormatNodeRule;
|
||||||
|
|
||||||
|
@ -21,7 +22,15 @@ impl FormatNodeRule<ExprSet> for FormatExprSet {
|
||||||
.finish()
|
.finish()
|
||||||
});
|
});
|
||||||
|
|
||||||
parenthesized("{", &joined, "}").fmt(f)
|
let comments = f.context().comments().clone();
|
||||||
|
let dangling = comments.dangling_comments(item);
|
||||||
|
|
||||||
|
parenthesized_with_dangling_comments("{", dangling, &joined, "}").fmt(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_dangling_comments(&self, _node: &ExprSet, _f: &mut PyFormatter) -> FormatResult<()> {
|
||||||
|
// Handled as part of `fmt_fields`
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
use crate::context::PyFormatContext;
|
|
||||||
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::AsFormat;
|
|
||||||
use crate::{FormatNodeRule, PyFormatter};
|
|
||||||
use ruff_formatter::{format_args, write, Buffer, FormatResult};
|
use ruff_formatter::{format_args, write, Buffer, FormatResult};
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_python_ast::ExprSetComp;
|
use ruff_python_ast::ExprSetComp;
|
||||||
|
|
||||||
|
use crate::context::PyFormatContext;
|
||||||
|
use crate::expression::parentheses::{
|
||||||
|
parenthesized_with_dangling_comments, NeedsParentheses, OptionalParentheses,
|
||||||
|
};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::AsFormat;
|
||||||
|
use crate::{FormatNodeRule, PyFormatter};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FormatExprSetComp;
|
pub struct FormatExprSetComp;
|
||||||
|
|
||||||
|
@ -24,10 +27,14 @@ impl FormatNodeRule<ExprSetComp> for FormatExprSetComp {
|
||||||
.finish()
|
.finish()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let comments = f.context().comments().clone();
|
||||||
|
let dangling = comments.dangling_comments(item);
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[parenthesized(
|
[parenthesized_with_dangling_comments(
|
||||||
"{",
|
"{",
|
||||||
|
dangling,
|
||||||
&group(&format_args!(
|
&group(&format_args!(
|
||||||
group(&elt.format()),
|
group(&elt.format()),
|
||||||
soft_line_break_or_space(),
|
soft_line_break_or_space(),
|
||||||
|
@ -37,6 +44,11 @@ impl FormatNodeRule<ExprSetComp> for FormatExprSetComp {
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fmt_dangling_comments(&self, _node: &ExprSetComp, _f: &mut PyFormatter) -> FormatResult<()> {
|
||||||
|
// Handled as part of `fmt_fields`
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NeedsParentheses for ExprSetComp {
|
impl NeedsParentheses for ExprSetComp {
|
||||||
|
|
|
@ -6,7 +6,9 @@ use ruff_formatter::{format_args, write, FormatRuleWithOptions};
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
|
|
||||||
use crate::builders::{empty_parenthesized_with_dangling_comments, parenthesize_if_expands};
|
use crate::builders::{empty_parenthesized_with_dangling_comments, parenthesize_if_expands};
|
||||||
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
|
use crate::expression::parentheses::{
|
||||||
|
parenthesized_with_dangling_comments, NeedsParentheses, OptionalParentheses,
|
||||||
|
};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Default)]
|
#[derive(Eq, PartialEq, Debug, Default)]
|
||||||
|
@ -31,7 +33,6 @@ pub enum TupleParentheses {
|
||||||
|
|
||||||
/// Handle the special cases where we don't include parentheses at all.
|
/// Handle the special cases where we don't include parentheses at all.
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// Black never formats tuple targets of for loops with parentheses if inside a comprehension.
|
/// Black never formats tuple targets of for loops with parentheses if inside a comprehension.
|
||||||
/// For example, tuple targets will always be formatted on the same line, except when an element supports
|
/// For example, tuple targets will always be formatted on the same line, except when an element supports
|
||||||
/// line-breaking in an un-parenthesized context.
|
/// line-breaking in an un-parenthesized context.
|
||||||
|
@ -104,6 +105,9 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
||||||
ctx: _,
|
ctx: _,
|
||||||
} = item;
|
} = item;
|
||||||
|
|
||||||
|
let comments = f.context().comments().clone();
|
||||||
|
let dangling = comments.dangling_comments(item);
|
||||||
|
|
||||||
// Handle the edge cases of an empty tuple and a tuple with one element
|
// Handle the edge cases of an empty tuple and a tuple with one element
|
||||||
//
|
//
|
||||||
// there can be dangling comments, and they can be in two
|
// there can be dangling comments, and they can be in two
|
||||||
|
@ -116,13 +120,8 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
||||||
// In all other cases comments get assigned to a list element
|
// In all other cases comments get assigned to a list element
|
||||||
match elts.as_slice() {
|
match elts.as_slice() {
|
||||||
[] => {
|
[] => {
|
||||||
let comments = f.context().comments().clone();
|
return empty_parenthesized_with_dangling_comments(text("("), dangling, text(")"))
|
||||||
return empty_parenthesized_with_dangling_comments(
|
.fmt(f);
|
||||||
text("("),
|
|
||||||
comments.dangling_comments(item),
|
|
||||||
text(")"),
|
|
||||||
)
|
|
||||||
.fmt(f);
|
|
||||||
}
|
}
|
||||||
[single] => match self.parentheses {
|
[single] => match self.parentheses {
|
||||||
TupleParentheses::Preserve
|
TupleParentheses::Preserve
|
||||||
|
@ -133,7 +132,13 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
||||||
_ =>
|
_ =>
|
||||||
// A single element tuple always needs parentheses and a trailing comma, except when inside of a subscript
|
// A single element tuple always needs parentheses and a trailing comma, except when inside of a subscript
|
||||||
{
|
{
|
||||||
parenthesized("(", &format_args![single.format(), text(",")], ")").fmt(f)
|
parenthesized_with_dangling_comments(
|
||||||
|
"(",
|
||||||
|
dangling,
|
||||||
|
&format_args![single.format(), text(",")],
|
||||||
|
")",
|
||||||
|
)
|
||||||
|
.fmt(f)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// If the tuple has parentheses, we generally want to keep them. The exception are for
|
// If the tuple has parentheses, we generally want to keep them. The exception are for
|
||||||
|
@ -142,9 +147,11 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
||||||
// Unlike other expression parentheses, tuple parentheses are part of the range of the
|
// Unlike other expression parentheses, tuple parentheses are part of the range of the
|
||||||
// tuple itself.
|
// tuple itself.
|
||||||
_ if is_parenthesized(*range, elts, f.context().source())
|
_ if is_parenthesized(*range, elts, f.context().source())
|
||||||
&& self.parentheses != TupleParentheses::NeverPreserve =>
|
&& !(self.parentheses == TupleParentheses::NeverPreserve
|
||||||
|
&& dangling.is_empty()) =>
|
||||||
{
|
{
|
||||||
parenthesized("(", &ExprSequence::new(item), ")").fmt(f)
|
parenthesized_with_dangling_comments("(", dangling, &ExprSequence::new(item), ")")
|
||||||
|
.fmt(f)
|
||||||
}
|
}
|
||||||
_ => match self.parentheses {
|
_ => match self.parentheses {
|
||||||
TupleParentheses::Never => {
|
TupleParentheses::Never => {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use ruff_python_ast::Ranged;
|
|
||||||
|
|
||||||
use ruff_formatter::prelude::tag::Condition;
|
use ruff_formatter::prelude::tag::Condition;
|
||||||
use ruff_formatter::{format_args, write, Argument, Arguments};
|
use ruff_formatter::{format_args, write, Argument, Arguments};
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
|
use ruff_python_ast::Ranged;
|
||||||
use ruff_python_trivia::{first_non_trivia_token, SimpleToken, SimpleTokenKind, SimpleTokenizer};
|
use ruff_python_trivia::{first_non_trivia_token, SimpleToken, SimpleTokenKind, SimpleTokenizer};
|
||||||
|
|
||||||
|
use crate::comments::{dangling_comments, SourceComment};
|
||||||
use crate::context::{NodeLevel, WithNodeLevel};
|
use crate::context::{NodeLevel, WithNodeLevel};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
@ -110,6 +110,26 @@ where
|
||||||
{
|
{
|
||||||
FormatParenthesized {
|
FormatParenthesized {
|
||||||
left,
|
left,
|
||||||
|
comments: &[],
|
||||||
|
content: Argument::new(content),
|
||||||
|
right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats `content` enclosed by the `left` and `right` parentheses, along with any dangling
|
||||||
|
/// comments that on the parentheses themselves.
|
||||||
|
pub(crate) fn parenthesized_with_dangling_comments<'content, 'ast, Content>(
|
||||||
|
left: &'static str,
|
||||||
|
comments: &'content [SourceComment],
|
||||||
|
content: &'content Content,
|
||||||
|
right: &'static str,
|
||||||
|
) -> FormatParenthesized<'content, 'ast>
|
||||||
|
where
|
||||||
|
Content: Format<PyFormatContext<'ast>>,
|
||||||
|
{
|
||||||
|
FormatParenthesized {
|
||||||
|
left,
|
||||||
|
comments,
|
||||||
content: Argument::new(content),
|
content: Argument::new(content),
|
||||||
right,
|
right,
|
||||||
}
|
}
|
||||||
|
@ -117,6 +137,7 @@ where
|
||||||
|
|
||||||
pub(crate) struct FormatParenthesized<'content, 'ast> {
|
pub(crate) struct FormatParenthesized<'content, 'ast> {
|
||||||
left: &'static str,
|
left: &'static str,
|
||||||
|
comments: &'content [SourceComment],
|
||||||
content: Argument<'content, PyFormatContext<'ast>>,
|
content: Argument<'content, PyFormatContext<'ast>>,
|
||||||
right: &'static str,
|
right: &'static str,
|
||||||
}
|
}
|
||||||
|
@ -124,12 +145,22 @@ pub(crate) struct FormatParenthesized<'content, 'ast> {
|
||||||
impl<'ast> Format<PyFormatContext<'ast>> for FormatParenthesized<'_, 'ast> {
|
impl<'ast> Format<PyFormatContext<'ast>> for FormatParenthesized<'_, 'ast> {
|
||||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
|
||||||
let inner = format_with(|f| {
|
let inner = format_with(|f| {
|
||||||
group(&format_args![
|
if self.comments.is_empty() {
|
||||||
text(self.left),
|
group(&format_args![
|
||||||
&soft_block_indent(&Arguments::from(&self.content)),
|
text(self.left),
|
||||||
text(self.right)
|
&soft_block_indent(&Arguments::from(&self.content)),
|
||||||
])
|
text(self.right)
|
||||||
.fmt(f)
|
])
|
||||||
|
.fmt(f)
|
||||||
|
} else {
|
||||||
|
group(&format_args![
|
||||||
|
text(self.left),
|
||||||
|
&line_suffix(&dangling_comments(self.comments)),
|
||||||
|
&group(&soft_block_indent(&Arguments::from(&self.content))),
|
||||||
|
text(self.right)
|
||||||
|
])
|
||||||
|
.fmt(f)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let current_level = f.context().node_level();
|
let current_level = f.context().node_level();
|
||||||
|
|
|
@ -70,8 +70,7 @@ x={ # dangling end of line comment
|
||||||
## Output
|
## Output
|
||||||
```py
|
```py
|
||||||
# before
|
# before
|
||||||
{
|
{ # open
|
||||||
# open
|
|
||||||
key: value # key # colon # value
|
key: value # key # colon # value
|
||||||
} # close
|
} # close
|
||||||
# after
|
# after
|
||||||
|
|
|
@ -92,6 +92,13 @@ selected_choices = {
|
||||||
k: str(v)
|
k: str(v)
|
||||||
for vvvvvvvvvvvvvvvvvvvvvvv in value if str(v) not in self.choices.field.empty_values
|
for vvvvvvvvvvvvvvvvvvvvvvv in value if str(v) not in self.choices.field.empty_values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
k: v
|
||||||
|
for ( # foo
|
||||||
|
|
||||||
|
x, aaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaay) in z
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
@ -201,11 +208,9 @@ selected_choices = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Leading
|
# Leading
|
||||||
{
|
{ # Leading
|
||||||
# Leading
|
|
||||||
k: v # Trailing
|
k: v # Trailing
|
||||||
for a, a, a, a, a, a, a, a, a, a, (
|
for a, a, a, a, a, a, a, a, a, a, ( # Trailing
|
||||||
# Trailing
|
|
||||||
a,
|
a,
|
||||||
a,
|
a,
|
||||||
a,
|
a,
|
||||||
|
@ -241,6 +246,11 @@ selected_choices = {
|
||||||
for vvvvvvvvvvvvvvvvvvvvvvv in value
|
for vvvvvvvvvvvvvvvvvvvvvvv in value
|
||||||
if str(v) not in self.choices.field.empty_values
|
if str(v) not in self.choices.field.empty_values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
k: v
|
||||||
|
for (x, aaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaayaaaay) in z # foo
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,12 @@ len(
|
||||||
# trailing
|
# trailing
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
len(
|
||||||
|
# leading
|
||||||
|
a for b in c
|
||||||
|
# trailing
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
@ -56,6 +62,13 @@ f((1) for _ in (a))
|
||||||
|
|
||||||
# black keeps these atm, but intends to remove them in the future:
|
# black keeps these atm, but intends to remove them in the future:
|
||||||
# https://github.com/psf/black/issues/2943
|
# https://github.com/psf/black/issues/2943
|
||||||
|
len(
|
||||||
|
# leading
|
||||||
|
a
|
||||||
|
for b in c
|
||||||
|
# trailing
|
||||||
|
)
|
||||||
|
|
||||||
len(
|
len(
|
||||||
# leading
|
# leading
|
||||||
a
|
a
|
||||||
|
|
|
@ -38,6 +38,18 @@ c1 = [ # trailing open bracket
|
||||||
2, # trailing item
|
2, # trailing item
|
||||||
# leading close bracket
|
# leading close bracket
|
||||||
] # trailing close bracket
|
] # trailing close bracket
|
||||||
|
|
||||||
|
|
||||||
|
[ # end-of-line comment
|
||||||
|
]
|
||||||
|
|
||||||
|
[ # end-of-line comment
|
||||||
|
# own-line comment
|
||||||
|
]
|
||||||
|
|
||||||
|
[ # end-of-line comment
|
||||||
|
1
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
@ -66,14 +78,22 @@ b3 = [
|
||||||
]
|
]
|
||||||
|
|
||||||
# Comment placement in non-empty lists
|
# Comment placement in non-empty lists
|
||||||
c1 = [
|
c1 = [ # trailing open bracket
|
||||||
# trailing open bracket
|
|
||||||
# leading item
|
# leading item
|
||||||
1,
|
1,
|
||||||
# between
|
# between
|
||||||
2, # trailing item
|
2, # trailing item
|
||||||
# leading close bracket
|
# leading close bracket
|
||||||
] # trailing close bracket
|
] # trailing close bracket
|
||||||
|
|
||||||
|
|
||||||
|
[] # end-of-line comment
|
||||||
|
|
||||||
|
[ # end-of-line comment
|
||||||
|
# own-line comment
|
||||||
|
]
|
||||||
|
|
||||||
|
[1] # end-of-line comment
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -248,14 +248,12 @@ f4 = ( # end-of-line
|
||||||
) # trailing
|
) # trailing
|
||||||
|
|
||||||
# Comments in other tuples
|
# Comments in other tuples
|
||||||
g1 = (
|
g1 = ( # a
|
||||||
# a
|
|
||||||
# b
|
# b
|
||||||
1, # c
|
1, # c
|
||||||
# d
|
# d
|
||||||
) # e
|
) # e
|
||||||
g2 = (
|
g2 = ( # a
|
||||||
# a
|
|
||||||
# b
|
# b
|
||||||
1, # c
|
1, # c
|
||||||
# d
|
# d
|
||||||
|
|
|
@ -204,8 +204,7 @@ raise hello( # sould I stay here
|
||||||
# just a comment here
|
# just a comment here
|
||||||
) # trailing comment
|
) # trailing comment
|
||||||
|
|
||||||
raise (
|
raise ( # sould I stay here
|
||||||
# sould I stay here
|
|
||||||
test,
|
test,
|
||||||
# just a comment here
|
# just a comment here
|
||||||
) # trailing comment
|
) # trailing comment
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue