Skip to content

Commit

Permalink
Prefer splitting right hand side of assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Dec 1, 2023
1 parent 1de4fcd commit 0550d40
Show file tree
Hide file tree
Showing 26 changed files with 462 additions and 233 deletions.
12 changes: 10 additions & 2 deletions crates/ruff_python_formatter/src/builders.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ruff_formatter::{write, Argument, Arguments};
use ruff_formatter::{write, Argument, Arguments, GroupId};
use ruff_text_size::{Ranged, TextRange, TextSize};

use crate::context::{NodeLevel, WithNodeLevel};
Expand All @@ -12,12 +12,14 @@ where
{
ParenthesizeIfExpands {
inner: Argument::new(content),
group_id: None,
indent: true,
}
}

pub(crate) struct ParenthesizeIfExpands<'a, 'ast> {
inner: Argument<'a, PyFormatContext<'ast>>,
group_id: Option<GroupId>,
indent: bool,
}

Expand All @@ -26,6 +28,11 @@ impl ParenthesizeIfExpands<'_, '_> {
self.indent = indent;
self
}

pub(crate) fn with_group_id(mut self, id: Option<GroupId>) -> Self {
self.group_id = id;
self
}
}

impl<'ast> Format<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> {
Expand All @@ -45,7 +52,8 @@ impl<'ast> Format<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> {
};

if_group_breaks(&token(")")).fmt(f)
}))]
}))
.with_group_id(self.group_id)]
)
}
}
Expand Down
4 changes: 4 additions & 0 deletions crates/ruff_python_formatter/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ impl<'a> PyFormatContext<'a> {
..self
}
}

pub(crate) const fn is_preview(&self) -> bool {
self.options.is_preview()
}
}

impl FormatContext for PyFormatContext<'_> {
Expand Down
11 changes: 10 additions & 1 deletion crates/ruff_python_formatter/src/expression/expr_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use crate::expression::parentheses::{
};
use crate::expression::CallChainLayout;
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprAttribute {
Expand Down Expand Up @@ -137,7 +139,7 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
impl NeedsParentheses for ExprAttribute {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
// Checks if there are any own line comments in an attribute chain (a.b.c).
Expand All @@ -156,6 +158,13 @@ impl NeedsParentheses for ExprAttribute {
context.source(),
) {
OptionalParentheses::Never
} else if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
match self.value.needs_parentheses(self.into(), context) {
OptionalParentheses::BestFit => OptionalParentheses::Multiline,
parentheses => parentheses,
}
} else {
self.value.needs_parentheses(self.into(), context)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use ruff_python_ast::ExprBooleanLiteral;

use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprBooleanLiteral;
Expand All @@ -20,9 +22,15 @@ impl FormatNodeRule<ExprBooleanLiteral> for FormatExprBooleanLiteral {
impl NeedsParentheses for ExprBooleanLiteral {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
_context: &PyFormatContext,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::BestFit
if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
OptionalParentheses::Multiline
} else {
OptionalParentheses::BestFit
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::expression::expr_string_literal::is_multiline_string;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::expression::string::{AnyString, FormatString};
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprBytesLiteral;
Expand All @@ -28,13 +30,17 @@ impl FormatNodeRule<ExprBytesLiteral> for FormatExprBytesLiteral {
impl NeedsParentheses for ExprBytesLiteral {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
if self.value.is_implicit_concatenated() {
OptionalParentheses::Multiline
} else if is_multiline_string(self.into(), context.source()) {
OptionalParentheses::Never
} else if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
OptionalParentheses::Multiline
} else {
OptionalParentheses::BestFit
}
Expand Down
11 changes: 10 additions & 1 deletion crates/ruff_python_formatter/src/expression/expr_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::expression::parentheses::{
};
use crate::expression::CallChainLayout;
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprCall {
Expand Down Expand Up @@ -87,7 +89,7 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
impl NeedsParentheses for ExprCall {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
if CallChainLayout::from_expression(
Expand All @@ -105,6 +107,13 @@ impl NeedsParentheses for ExprCall {
context.source(),
) {
OptionalParentheses::Never
} else if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
match self.func.needs_parentheses(self.into(), context) {
OptionalParentheses::BestFit => OptionalParentheses::Multiline,
parentheses => parentheses,
}
} else {
self.func.needs_parentheses(self.into(), context)
}
Expand Down
12 changes: 10 additions & 2 deletions crates/ruff_python_formatter/src/expression/expr_f_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use ruff_python_ast::ExprFString;

use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

use super::string::{AnyString, FormatString};

Expand All @@ -31,13 +33,19 @@ impl FormatNodeRule<ExprFString> for FormatExprFString {
impl NeedsParentheses for ExprFString {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
if self.value.is_implicit_concatenated() {
OptionalParentheses::Multiline
} else if memchr2(b'\n', b'\r', context.source()[self.range].as_bytes()).is_none() {
OptionalParentheses::BestFit
if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
OptionalParentheses::Multiline
} else {
OptionalParentheses::BestFit
}
} else {
OptionalParentheses::Never
}
Expand Down
14 changes: 11 additions & 3 deletions crates/ruff_python_formatter/src/expression/expr_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use ruff_python_ast::ExprName;
use crate::comments::SourceComment;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprName;
Expand Down Expand Up @@ -38,10 +40,16 @@ impl FormatNodeRule<ExprName> for FormatExprName {
impl NeedsParentheses for ExprName {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
_context: &PyFormatContext,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::BestFit
if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
OptionalParentheses::Multiline
} else {
OptionalParentheses::BestFit
}
}
}

Expand Down
14 changes: 11 additions & 3 deletions crates/ruff_python_formatter/src/expression/expr_none_literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use ruff_python_ast::ExprNoneLiteral;

use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprNoneLiteral;
Expand All @@ -16,9 +18,15 @@ impl FormatNodeRule<ExprNoneLiteral> for FormatExprNoneLiteral {
impl NeedsParentheses for ExprNoneLiteral {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
_context: &PyFormatContext,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::BestFit
if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
OptionalParentheses::Multiline
} else {
OptionalParentheses::BestFit
}
}
}
14 changes: 11 additions & 3 deletions crates/ruff_python_formatter/src/expression/expr_number_literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use ruff_text_size::{Ranged, TextSize};

use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprNumberLiteral;
Expand Down Expand Up @@ -56,10 +58,16 @@ impl FormatNodeRule<ExprNumberLiteral> for FormatExprNumberLiteral {
impl NeedsParentheses for ExprNumberLiteral {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
_context: &PyFormatContext,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::BestFit
if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
OptionalParentheses::Multiline
} else {
OptionalParentheses::BestFit
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::expression::string::{
AnyString, FormatString, StringLayout, StringPrefix, StringQuotes,
};
use crate::prelude::*;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::is_assignment_with_splittable_targets;

#[derive(Default)]
pub struct FormatExprStringLiteral {
Expand Down Expand Up @@ -43,13 +45,17 @@ impl FormatNodeRule<ExprStringLiteral> for FormatExprStringLiteral {
impl NeedsParentheses for ExprStringLiteral {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
if self.value.is_implicit_concatenated() {
OptionalParentheses::Multiline
} else if is_multiline_string(self.into(), context.source()) {
OptionalParentheses::Never
} else if is_prefer_splitting_right_hand_side_of_assignments_enabled(context)
&& is_assignment_with_splittable_targets(parent, context)
{
OptionalParentheses::Multiline
} else {
OptionalParentheses::BestFit
}
Expand Down
10 changes: 5 additions & 5 deletions crates/ruff_python_formatter/src/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::expression::parentheses::{
OptionalParentheses, Parentheses, Parenthesize,
};
use crate::prelude::*;
use crate::PyFormatOptions;
use crate::preview::is_hug_parens_with_braces_and_square_brackets_enabled;

mod binary_like;
pub(crate) mod expr_attribute;
Expand Down Expand Up @@ -129,7 +129,7 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
let node_comments = comments.leading_dangling_trailing(expression);
if !node_comments.has_leading() && !node_comments.has_trailing() {
parenthesized("(", &format_expr, ")")
.with_indent(!is_expression_huggable(expression, f.options()))
.with_indent(!is_expression_huggable(expression, f.context()))
.fmt(f)
} else {
format_with_parentheses_comments(expression, &node_comments, f)
Expand Down Expand Up @@ -448,7 +448,7 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
OptionalParentheses::Never => match parenthesize {
Parenthesize::IfBreaksOrIfRequired => {
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never))
.with_indent(!is_expression_huggable(expression, f.options()))
.with_indent(!is_expression_huggable(expression, f.context()))
.fmt(f)
}

Expand Down Expand Up @@ -1061,8 +1061,8 @@ pub(crate) fn has_own_parentheses(
/// ]
/// )
/// ```
pub(crate) fn is_expression_huggable(expr: &Expr, options: &PyFormatOptions) -> bool {
if !options.preview().is_enabled() {
pub(crate) fn is_expression_huggable(expr: &Expr, context: &PyFormatContext) -> bool {
if !is_hug_parens_with_braces_and_square_brackets_enabled(context) {
return false;
}

Expand Down
14 changes: 5 additions & 9 deletions crates/ruff_python_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod options;
pub(crate) mod other;
pub(crate) mod pattern;
mod prelude;
mod preview;
mod shared_traits;
pub(crate) mod statement;
pub(crate) mod type_param;
Expand Down Expand Up @@ -180,7 +181,7 @@ mod tests {

use ruff_python_parser::{parse_ok_tokens, AsMode};

use crate::{format_module_ast, format_module_source, PyFormatOptions};
use crate::{format_module_ast, format_module_source, PreviewMode, PyFormatOptions};

/// Very basic test intentionally kept very similar to the CLI
#[test]
Expand Down Expand Up @@ -208,13 +209,7 @@ if True:
#[test]
fn quick_test() {
let source = r#"
def main() -> None:
if True:
some_very_long_variable_name_abcdefghijk = Foo()
some_very_long_variable_name_abcdefghijk = some_very_long_variable_name_abcdefghijk[
some_very_long_variable_name_abcdefghijk.some_very_long_attribute_name
== "This is a very long string abcdefghijk"
]
this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 0
"#;
let source_type = PySourceType::Python;
Expand All @@ -223,7 +218,8 @@ def main() -> None:
// Parse the AST.
let source_path = "code_inline.py";
let module = parse_ok_tokens(tokens, source, source_type.as_mode(), source_path).unwrap();
let options = PyFormatOptions::from_extension(Path::new(source_path));
let options = PyFormatOptions::from_extension(Path::new(source_path))
.with_preview(PreviewMode::Enabled);
let formatted = format_module_ast(&module, &comment_ranges, source, options).unwrap();

// Uncomment the `dbg` to print the IR.
Expand Down

0 comments on commit 0550d40

Please sign in to comment.