mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-14 06:15:13 +00:00
Format BoolOp (#4986)
This commit is contained in:
parent
db301c14bd
commit
653dbb6d17
18 changed files with 804 additions and 446 deletions
215
crates/ruff_python_formatter/src/expression/binary_like.rs
Normal file
215
crates/ruff_python_formatter/src/expression/binary_like.rs
Normal file
|
@ -0,0 +1,215 @@
|
|||
//! This module provides helper utilities to format an expression that has a left side, an operator,
|
||||
//! and a right side (binary like).
|
||||
|
||||
use crate::expression::parentheses::Parentheses;
|
||||
use crate::prelude::*;
|
||||
use ruff_formatter::{format_args, write};
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
/// Trait to implement a binary like syntax that has a left operand, an operator, and a right operand.
|
||||
pub(super) trait FormatBinaryLike<'ast> {
|
||||
/// The type implementing the formatting of the operator.
|
||||
type FormatOperator: Format<PyFormatContext<'ast>>;
|
||||
|
||||
/// Formats the binary like expression to `f`.
|
||||
fn fmt_binary(
|
||||
&self,
|
||||
parentheses: Option<Parentheses>,
|
||||
f: &mut PyFormatter<'ast, '_>,
|
||||
) -> FormatResult<()> {
|
||||
let left = self.left()?;
|
||||
let operator = self.operator();
|
||||
let right = self.right()?;
|
||||
|
||||
let layout = if parentheses == Some(Parentheses::Custom) {
|
||||
self.binary_layout()
|
||||
} else {
|
||||
BinaryLayout::Default
|
||||
};
|
||||
|
||||
match layout {
|
||||
BinaryLayout::Default => self.fmt_default(f),
|
||||
BinaryLayout::ExpandLeft => {
|
||||
let left = left.format().memoized();
|
||||
let right = right.format().memoized();
|
||||
write!(
|
||||
f,
|
||||
[best_fitting![
|
||||
// Everything on a single line
|
||||
format_args![group(&left), space(), operator, space(), right],
|
||||
// Break the left over multiple lines, keep the right flat
|
||||
format_args![
|
||||
group(&left).should_expand(true),
|
||||
space(),
|
||||
operator,
|
||||
space(),
|
||||
right
|
||||
],
|
||||
// The content doesn't fit, indent the content and break before the operator.
|
||||
format_args![
|
||||
text("("),
|
||||
block_indent(&format_args![
|
||||
left,
|
||||
hard_line_break(),
|
||||
operator,
|
||||
space(),
|
||||
right
|
||||
]),
|
||||
text(")")
|
||||
]
|
||||
]
|
||||
.with_mode(BestFittingMode::AllLines)]
|
||||
)
|
||||
}
|
||||
BinaryLayout::ExpandRight => {
|
||||
let left_group = f.group_id("BinaryLeft");
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
// Wrap the left in a group and gives it an id. The printer first breaks the
|
||||
// right side if `right` contains any line break because the printer breaks
|
||||
// sequences of groups from right to left.
|
||||
// Indents the left side if the group breaks.
|
||||
group(&format_args![
|
||||
if_group_breaks(&text("(")),
|
||||
indent_if_group_breaks(
|
||||
&format_args![
|
||||
soft_line_break(),
|
||||
left.format(),
|
||||
soft_line_break_or_space(),
|
||||
operator,
|
||||
space()
|
||||
],
|
||||
left_group
|
||||
)
|
||||
])
|
||||
.with_group_id(Some(left_group)),
|
||||
// Wrap the right in a group and indents its content but only if the left side breaks
|
||||
group(&indent_if_group_breaks(&right.format(), left_group)),
|
||||
// If the left side breaks, insert a hard line break to finish the indent and close the open paren.
|
||||
if_group_breaks(&format_args![hard_line_break(), text(")")])
|
||||
.with_group_id(Some(left_group))
|
||||
]
|
||||
)
|
||||
}
|
||||
BinaryLayout::ExpandRightThenLeft => {
|
||||
// The formatter expands group-sequences from right to left, and expands both if
|
||||
// there isn't enough space when expanding only one of them.
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
group(&left.format()),
|
||||
space(),
|
||||
operator,
|
||||
space(),
|
||||
group(&right.format())
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines which binary layout to use.
|
||||
fn binary_layout(&self) -> BinaryLayout {
|
||||
if let (Ok(left), Ok(right)) = (self.left(), self.right()) {
|
||||
BinaryLayout::from_left_right(left, right)
|
||||
} else {
|
||||
BinaryLayout::Default
|
||||
}
|
||||
}
|
||||
|
||||
/// Formats the node according to the default layout.
|
||||
fn fmt_default(&self, f: &mut PyFormatter<'ast, '_>) -> FormatResult<()>;
|
||||
|
||||
/// Returns the left operator
|
||||
fn left(&self) -> FormatResult<&Expr>;
|
||||
|
||||
/// Returns the right operator.
|
||||
fn right(&self) -> FormatResult<&Expr>;
|
||||
|
||||
/// Returns the object that formats the operator.
|
||||
fn operator(&self) -> Self::FormatOperator;
|
||||
}
|
||||
|
||||
fn can_break_expr(expr: &Expr) -> bool {
|
||||
use ruff_python_ast::prelude::*;
|
||||
|
||||
match expr {
|
||||
Expr::Tuple(ExprTuple {
|
||||
elts: expressions, ..
|
||||
})
|
||||
| Expr::List(ExprList {
|
||||
elts: expressions, ..
|
||||
})
|
||||
| Expr::Set(ExprSet {
|
||||
elts: expressions, ..
|
||||
})
|
||||
| Expr::Dict(ExprDict {
|
||||
values: expressions,
|
||||
..
|
||||
}) => !expressions.is_empty(),
|
||||
Expr::Call(ExprCall { args, keywords, .. }) => !(args.is_empty() && keywords.is_empty()),
|
||||
Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::GeneratorExp(_) => true,
|
||||
Expr::UnaryOp(ExprUnaryOp { operand, .. }) => match operand.as_ref() {
|
||||
Expr::BinOp(_) => true,
|
||||
_ => can_break_expr(operand.as_ref()),
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub(super) enum BinaryLayout {
|
||||
/// Put each operand on their own line if either side expands
|
||||
Default,
|
||||
|
||||
/// Try to expand the left to make it fit. Add parentheses if the left or right don't fit.
|
||||
///
|
||||
///```python
|
||||
/// [
|
||||
/// a,
|
||||
/// b
|
||||
/// ] & c
|
||||
///```
|
||||
ExpandLeft,
|
||||
|
||||
/// Try to expand the right to make it fix. Add parentheses if the left or right don't fit.
|
||||
///
|
||||
/// ```python
|
||||
/// a & [
|
||||
/// b,
|
||||
/// c
|
||||
/// ]
|
||||
/// ```
|
||||
ExpandRight,
|
||||
|
||||
/// Both the left and right side can be expanded. Try in the following order:
|
||||
/// * expand the right side
|
||||
/// * expand the left side
|
||||
/// * expand both sides
|
||||
///
|
||||
/// to make the expression fit
|
||||
///
|
||||
/// ```python
|
||||
/// [
|
||||
/// a,
|
||||
/// b
|
||||
/// ] & [
|
||||
/// c,
|
||||
/// d
|
||||
/// ]
|
||||
/// ```
|
||||
ExpandRightThenLeft,
|
||||
}
|
||||
|
||||
impl BinaryLayout {
|
||||
pub(super) fn from_left_right(left: &Expr, right: &Expr) -> BinaryLayout {
|
||||
match (can_break_expr(left), can_break_expr(right)) {
|
||||
(false, false) => BinaryLayout::Default,
|
||||
(true, false) => BinaryLayout::ExpandLeft,
|
||||
(false, true) => BinaryLayout::ExpandRight,
|
||||
(true, true) => BinaryLayout::ExpandRightThenLeft,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
use crate::comments::{trailing_comments, Comments};
|
||||
use crate::expression::binary_like::{BinaryLayout, FormatBinaryLike};
|
||||
use crate::expression::parentheses::{
|
||||
default_expression_needs_parentheses, NeedsParentheses, Parenthesize,
|
||||
};
|
||||
use crate::expression::Parentheses;
|
||||
use crate::prelude::*;
|
||||
use crate::FormatNodeRule;
|
||||
use ruff_formatter::{
|
||||
format_args, write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions,
|
||||
};
|
||||
use ruff_python_ast::node::AstNode;
|
||||
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions};
|
||||
use rustpython_parser::ast::{
|
||||
Constant, Expr, ExprAttribute, ExprBinOp, ExprConstant, ExprUnaryOp, Operator, UnaryOp,
|
||||
};
|
||||
|
@ -29,132 +27,7 @@ impl FormatRuleWithOptions<ExprBinOp, PyFormatContext<'_>> for FormatExprBinOp {
|
|||
|
||||
impl FormatNodeRule<ExprBinOp> for FormatExprBinOp {
|
||||
fn fmt_fields(&self, item: &ExprBinOp, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
let ExprBinOp {
|
||||
left,
|
||||
right,
|
||||
op,
|
||||
range: _,
|
||||
} = item;
|
||||
|
||||
let layout = if self.parentheses == Some(Parentheses::Custom) {
|
||||
BinaryLayout::from(item)
|
||||
} else {
|
||||
BinaryLayout::Default
|
||||
};
|
||||
|
||||
match layout {
|
||||
BinaryLayout::Default => {
|
||||
let comments = f.context().comments().clone();
|
||||
let operator_comments = comments.dangling_comments(item.as_any_node_ref());
|
||||
let needs_space = !is_simple_power_expression(item);
|
||||
|
||||
let before_operator_space = if needs_space {
|
||||
soft_line_break_or_space()
|
||||
} else {
|
||||
soft_line_break()
|
||||
};
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
left.format(),
|
||||
before_operator_space,
|
||||
op.format(),
|
||||
trailing_comments(operator_comments),
|
||||
]
|
||||
)?;
|
||||
|
||||
// Format the operator on its own line if the right side has any leading comments.
|
||||
if comments.has_leading_comments(right.as_ref()) {
|
||||
write!(f, [hard_line_break()])?;
|
||||
} else if needs_space {
|
||||
write!(f, [space()])?;
|
||||
}
|
||||
|
||||
write!(f, [group(&right.format())])
|
||||
}
|
||||
|
||||
BinaryLayout::ExpandLeft => {
|
||||
let left = left.format().memoized();
|
||||
let right = right.format().memoized();
|
||||
write!(
|
||||
f,
|
||||
[best_fitting![
|
||||
// Everything on a single line
|
||||
format_args![left, space(), op.format(), space(), right],
|
||||
// Break the left over multiple lines, keep the right flat
|
||||
format_args![
|
||||
group(&left).should_expand(true),
|
||||
space(),
|
||||
op.format(),
|
||||
space(),
|
||||
right
|
||||
],
|
||||
// The content doesn't fit, indent the content and break before the operator.
|
||||
format_args![
|
||||
text("("),
|
||||
block_indent(&format_args![
|
||||
left,
|
||||
hard_line_break(),
|
||||
op.format(),
|
||||
space(),
|
||||
right
|
||||
]),
|
||||
text(")")
|
||||
]
|
||||
]
|
||||
.with_mode(BestFittingMode::AllLines)]
|
||||
)
|
||||
}
|
||||
|
||||
BinaryLayout::ExpandRight => {
|
||||
let left_group = f.group_id("BinaryLeft");
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
// Wrap the left in a group and gives it an id. The printer first breaks the
|
||||
// right side if `right` contains any line break because the printer breaks
|
||||
// sequences of groups from right to left.
|
||||
// Indents the left side if the group breaks.
|
||||
group(&format_args![
|
||||
if_group_breaks(&text("(")),
|
||||
indent_if_group_breaks(
|
||||
&format_args![
|
||||
soft_line_break(),
|
||||
left.format(),
|
||||
soft_line_break_or_space(),
|
||||
op.format(),
|
||||
space()
|
||||
],
|
||||
left_group
|
||||
)
|
||||
])
|
||||
.with_group_id(Some(left_group)),
|
||||
// Wrap the right in a group and indents its content but only if the left side breaks
|
||||
group(&indent_if_group_breaks(&right.format(), left_group)),
|
||||
// If the left side breaks, insert a hard line break to finish the indent and close the open paren.
|
||||
if_group_breaks(&format_args![hard_line_break(), text(")")])
|
||||
.with_group_id(Some(left_group))
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
BinaryLayout::ExpandRightThenLeft => {
|
||||
// The formatter expands group-sequences from right to left, and expands both if
|
||||
// there isn't enough space when expanding only one of them.
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
group(&left.format()),
|
||||
space(),
|
||||
op.format(),
|
||||
space(),
|
||||
group(&right.format())
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
item.fmt_binary(self.parentheses, f)
|
||||
}
|
||||
|
||||
fn fmt_dangling_comments(&self, _node: &ExprBinOp, _f: &mut PyFormatter) -> FormatResult<()> {
|
||||
|
@ -163,6 +36,60 @@ impl FormatNodeRule<ExprBinOp> for FormatExprBinOp {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> FormatBinaryLike<'ast> for ExprBinOp {
|
||||
type FormatOperator = FormatOwnedWithRule<Operator, FormatOperator, PyFormatContext<'ast>>;
|
||||
|
||||
fn fmt_default(&self, f: &mut PyFormatter<'ast, '_>) -> FormatResult<()> {
|
||||
let ExprBinOp {
|
||||
range: _,
|
||||
left,
|
||||
op,
|
||||
right,
|
||||
} = self;
|
||||
|
||||
let comments = f.context().comments().clone();
|
||||
let operator_comments = comments.dangling_comments(self);
|
||||
let needs_space = !is_simple_power_expression(self);
|
||||
|
||||
let before_operator_space = if needs_space {
|
||||
soft_line_break_or_space()
|
||||
} else {
|
||||
soft_line_break()
|
||||
};
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
left.format(),
|
||||
before_operator_space,
|
||||
op.format(),
|
||||
trailing_comments(operator_comments),
|
||||
]
|
||||
)?;
|
||||
|
||||
// Format the operator on its own line if the right side has any leading comments.
|
||||
if comments.has_leading_comments(right.as_ref()) {
|
||||
write!(f, [hard_line_break()])?;
|
||||
} else if needs_space {
|
||||
write!(f, [space()])?;
|
||||
}
|
||||
|
||||
write!(f, [group(&right.format())])
|
||||
}
|
||||
|
||||
fn left(&self) -> FormatResult<&Expr> {
|
||||
Ok(&self.left)
|
||||
}
|
||||
|
||||
fn right(&self) -> FormatResult<&Expr> {
|
||||
Ok(&self.right)
|
||||
}
|
||||
|
||||
fn operator(&self) -> Self::FormatOperator {
|
||||
self.op.into_format()
|
||||
}
|
||||
}
|
||||
|
||||
const fn is_simple_power_expression(expr: &ExprBinOp) -> bool {
|
||||
expr.op.is_pow() && is_simple_power_operand(&expr.left) && is_simple_power_operand(&expr.right)
|
||||
}
|
||||
|
@ -235,7 +162,7 @@ impl NeedsParentheses for ExprBinOp {
|
|||
) -> Parentheses {
|
||||
match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) {
|
||||
Parentheses::Optional => {
|
||||
if BinaryLayout::from(self) == BinaryLayout::Default
|
||||
if self.binary_layout() == BinaryLayout::Default
|
||||
|| comments.has_leading_comments(self.right.as_ref())
|
||||
|| comments.has_dangling_comments(self)
|
||||
{
|
||||
|
@ -248,85 +175,3 @@ impl NeedsParentheses for ExprBinOp {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum BinaryLayout {
|
||||
/// Put each operand on their own line if either side expands
|
||||
Default,
|
||||
|
||||
/// Try to expand the left to make it fit. Add parentheses if the left or right don't fit.
|
||||
///
|
||||
///```python
|
||||
/// [
|
||||
/// a,
|
||||
/// b
|
||||
/// ] & c
|
||||
///```
|
||||
ExpandLeft,
|
||||
|
||||
/// Try to expand the right to make it fix. Add parentheses if the left or right don't fit.
|
||||
///
|
||||
/// ```python
|
||||
/// a & [
|
||||
/// b,
|
||||
/// c
|
||||
/// ]
|
||||
/// ```
|
||||
ExpandRight,
|
||||
|
||||
/// Both the left and right side can be expanded. Try in the following order:
|
||||
/// * expand the right side
|
||||
/// * expand the left side
|
||||
/// * expand both sides
|
||||
///
|
||||
/// to make the expression fit
|
||||
///
|
||||
/// ```python
|
||||
/// [
|
||||
/// a,
|
||||
/// b
|
||||
/// ] & [
|
||||
/// c,
|
||||
/// d
|
||||
/// ]
|
||||
/// ```
|
||||
ExpandRightThenLeft,
|
||||
}
|
||||
|
||||
impl BinaryLayout {
|
||||
fn from(expr: &ExprBinOp) -> Self {
|
||||
match (can_break(&expr.left), can_break(&expr.right)) {
|
||||
(false, false) => Self::Default,
|
||||
(true, false) => Self::ExpandLeft,
|
||||
(false, true) => Self::ExpandRight,
|
||||
(true, true) => Self::ExpandRightThenLeft,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn can_break(expr: &Expr) -> bool {
|
||||
use ruff_python_ast::prelude::*;
|
||||
|
||||
match expr {
|
||||
Expr::Tuple(ExprTuple {
|
||||
elts: expressions, ..
|
||||
})
|
||||
| Expr::List(ExprList {
|
||||
elts: expressions, ..
|
||||
})
|
||||
| Expr::Set(ExprSet {
|
||||
elts: expressions, ..
|
||||
})
|
||||
| Expr::Dict(ExprDict {
|
||||
values: expressions,
|
||||
..
|
||||
}) => !expressions.is_empty(),
|
||||
Expr::Call(ExprCall { args, keywords, .. }) => !(args.is_empty() && keywords.is_empty()),
|
||||
Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::GeneratorExp(_) => true,
|
||||
Expr::UnaryOp(ExprUnaryOp { operand, .. }) => match operand.as_ref() {
|
||||
Expr::BinOp(_) => true,
|
||||
_ => can_break(operand.as_ref()),
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,87 @@
|
|||
use crate::comments::Comments;
|
||||
use crate::comments::{leading_comments, Comments};
|
||||
use crate::expression::binary_like::{BinaryLayout, FormatBinaryLike};
|
||||
use crate::expression::parentheses::{
|
||||
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
|
||||
};
|
||||
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
|
||||
use ruff_formatter::{write, Buffer, FormatResult};
|
||||
use rustpython_parser::ast::ExprBoolOp;
|
||||
use crate::prelude::*;
|
||||
use ruff_formatter::{
|
||||
write, FormatError, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions,
|
||||
};
|
||||
use rustpython_parser::ast::{BoolOp, Expr, ExprBoolOp};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatExprBoolOp;
|
||||
pub struct FormatExprBoolOp {
|
||||
parentheses: Option<Parentheses>,
|
||||
}
|
||||
|
||||
impl FormatRuleWithOptions<ExprBoolOp, PyFormatContext<'_>> for FormatExprBoolOp {
|
||||
type Options = Option<Parentheses>;
|
||||
fn with_options(mut self, options: Self::Options) -> Self {
|
||||
self.parentheses = options;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatNodeRule<ExprBoolOp> for FormatExprBoolOp {
|
||||
fn fmt_fields(&self, _item: &ExprBoolOp, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
write!(
|
||||
f,
|
||||
[not_yet_implemented_custom_text(
|
||||
"NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2"
|
||||
)]
|
||||
)
|
||||
fn fmt_fields(&self, item: &ExprBoolOp, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
item.fmt_binary(self.parentheses, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> FormatBinaryLike<'ast> for ExprBoolOp {
|
||||
type FormatOperator = FormatOwnedWithRule<BoolOp, FormatBoolOp, PyFormatContext<'ast>>;
|
||||
|
||||
fn binary_layout(&self) -> BinaryLayout {
|
||||
match self.values.as_slice() {
|
||||
[left, right] => BinaryLayout::from_left_right(left, right),
|
||||
[..] => BinaryLayout::Default,
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_default(&self, f: &mut PyFormatter<'ast, '_>) -> FormatResult<()> {
|
||||
let ExprBoolOp {
|
||||
range: _,
|
||||
op,
|
||||
values,
|
||||
} = self;
|
||||
|
||||
let mut values = values.iter();
|
||||
let comments = f.context().comments().clone();
|
||||
|
||||
let Some(first) = values.next() else {
|
||||
return Ok(())
|
||||
};
|
||||
|
||||
write!(f, [group(&first.format())])?;
|
||||
|
||||
for value in values {
|
||||
let leading_value_comments = comments.leading_comments(value);
|
||||
// Format the expressions leading comments **before** the operator
|
||||
if leading_value_comments.is_empty() {
|
||||
write!(f, [soft_line_break_or_space()])?;
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
[hard_line_break(), leading_comments(leading_value_comments)]
|
||||
)?;
|
||||
}
|
||||
|
||||
write!(f, [op.format(), space(), group(&value.format())])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn left(&self) -> FormatResult<&Expr> {
|
||||
self.values.first().ok_or(FormatError::SyntaxError)
|
||||
}
|
||||
|
||||
fn right(&self) -> FormatResult<&Expr> {
|
||||
self.values.last().ok_or(FormatError::SyntaxError)
|
||||
}
|
||||
|
||||
fn operator(&self) -> Self::FormatOperator {
|
||||
self.op.into_format()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +92,53 @@ impl NeedsParentheses for ExprBoolOp {
|
|||
source: &str,
|
||||
comments: &Comments,
|
||||
) -> Parentheses {
|
||||
default_expression_needs_parentheses(self.into(), parenthesize, source, comments)
|
||||
match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) {
|
||||
Parentheses::Optional => match self.binary_layout() {
|
||||
BinaryLayout::Default => Parentheses::Optional,
|
||||
|
||||
BinaryLayout::ExpandRight
|
||||
| BinaryLayout::ExpandLeft
|
||||
| BinaryLayout::ExpandRightThenLeft
|
||||
if self
|
||||
.values
|
||||
.last()
|
||||
.map_or(false, |right| comments.has_leading_comments(right)) =>
|
||||
{
|
||||
Parentheses::Optional
|
||||
}
|
||||
_ => Parentheses::Custom,
|
||||
},
|
||||
parentheses => parentheses,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FormatBoolOp;
|
||||
|
||||
impl<'ast> AsFormat<PyFormatContext<'ast>> for BoolOp {
|
||||
type Format<'a> = FormatRefWithRule<'a, BoolOp, FormatBoolOp, PyFormatContext<'ast>>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
FormatRefWithRule::new(self, FormatBoolOp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> IntoFormat<PyFormatContext<'ast>> for BoolOp {
|
||||
type Format = FormatOwnedWithRule<BoolOp, FormatBoolOp, PyFormatContext<'ast>>;
|
||||
|
||||
fn into_format(self) -> Self::Format {
|
||||
FormatOwnedWithRule::new(self, FormatBoolOp)
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatRule<BoolOp, PyFormatContext<'_>> for FormatBoolOp {
|
||||
fn fmt(&self, item: &BoolOp, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||
let operator = match item {
|
||||
BoolOp::And => "and",
|
||||
BoolOp::Or => "or",
|
||||
};
|
||||
|
||||
text(operator).fmt(f)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ impl FormatNodeRule<ExprUnaryOp> for FormatExprUnaryOp {
|
|||
// ```
|
||||
let leading_operand_comments = comments.leading_comments(operand.as_ref());
|
||||
let trailing_operator_comments_end =
|
||||
leading_operand_comments.partition_point(|p| p.position().is_end_of_line());
|
||||
leading_operand_comments.partition_point(|p| p.line_position().is_end_of_line());
|
||||
let (trailing_operator_comments, leading_operand_comments) =
|
||||
leading_operand_comments.split_at(trailing_operator_comments_end);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use ruff_formatter::{
|
|||
};
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
mod binary_like;
|
||||
pub(crate) mod expr_attribute;
|
||||
pub(crate) mod expr_await;
|
||||
pub(crate) mod expr_bin_op;
|
||||
|
@ -59,7 +60,7 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
|
|||
);
|
||||
|
||||
let format_expr = format_with(|f| match item {
|
||||
Expr::BoolOp(expr) => expr.format().fmt(f),
|
||||
Expr::BoolOp(expr) => expr.format().with_options(Some(parentheses)).fmt(f),
|
||||
Expr::NamedExpr(expr) => expr.format().fmt(f),
|
||||
Expr::BinOp(expr) => expr.format().with_options(Some(parentheses)).fmt(f),
|
||||
Expr::UnaryOp(expr) => expr.format().fmt(f),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue