Skip to content

Commit d5a18a6

Browse files
committed
Indent lambda parameters if parameters wrap
1 parent 3e218fa commit d5a18a6

9 files changed

Lines changed: 785 additions & 54 deletions

File tree

crates/ruff_python_ast/src/nodes.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,6 +2313,14 @@ impl Parameters {
23132313
&& self.vararg.is_none()
23142314
&& self.kwarg.is_none()
23152315
}
2316+
2317+
pub fn len(&self) -> usize {
2318+
self.posonlyargs.len()
2319+
+ self.args.len()
2320+
+ usize::from(self.vararg.is_some())
2321+
+ self.kwonlyargs.len()
2322+
+ usize::from(self.kwarg.is_some())
2323+
}
23162324
}
23172325

23182326
/// An alternative type of AST `arg`. This is used for each function argument that might have a default value.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{
3+
"preview": "disabled"
4+
},
5+
{
6+
"preview": "enabled"
7+
}
8+
]

crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ def f(
125125
*x: x
126126
)
127127

128+
(
129+
lambda
130+
# comment
131+
*x,
132+
**y: x
133+
)
134+
128135
(
129136
lambda
130137
# comment 1
@@ -135,13 +142,32 @@ def f(
135142
x
136143
)
137144

145+
(
146+
lambda
147+
# comment 1
148+
*
149+
# comment 2
150+
x,
151+
**y:
152+
# comment 3
153+
x
154+
)
155+
138156
(
139157
lambda # comment 1
140158
* # comment 2
141159
x: # comment 3
142160
x
143161
)
144162

163+
(
164+
lambda # comment 1
165+
* # comment 2
166+
x,
167+
y: # comment 3
168+
x
169+
)
170+
145171
lambda *x\
146172
:x
147173

@@ -196,6 +222,17 @@ def f(
196222
x
197223
)
198224

225+
(
226+
lambda # 1
227+
# 2
228+
x, # 3
229+
# 4
230+
y
231+
: # 5
232+
# 6
233+
x
234+
)
235+
199236
(
200237
lambda
201238
x,
@@ -204,6 +241,71 @@ def f(
204241
z
205242
)
206243

244+
245+
# Leading
246+
lambda x: (
247+
lambda y: lambda z: x
248+
+ y
249+
+ y
250+
+ y
251+
+ y
252+
+ y
253+
+ y
254+
+ y
255+
+ y
256+
+ y
257+
+ y
258+
+ y
259+
+ y
260+
+ y
261+
+ y
262+
+ y
263+
+ y
264+
+ y
265+
+ y
266+
+ y
267+
+ y
268+
+ y
269+
+ z # Trailing
270+
) # Trailing
271+
272+
273+
# Leading
274+
lambda x: lambda y: lambda z: [
275+
x,
276+
y,
277+
y,
278+
y,
279+
y,
280+
y,
281+
y,
282+
y,
283+
y,
284+
y,
285+
y,
286+
y,
287+
y,
288+
y,
289+
y,
290+
y,
291+
y,
292+
y,
293+
y,
294+
y,
295+
y,
296+
y,
297+
y,
298+
y,
299+
y,
300+
y,
301+
y,
302+
y,
303+
y,
304+
y,
305+
z
306+
] # Trailing
307+
# Trailing
308+
207309
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d
208310

209311
# Regression tests for https://github.com/astral-sh/ruff/issues/8179

crates/ruff_python_formatter/src/context.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ impl<'a> PyFormatContext<'a> {
4343
pub(crate) fn comments(&self) -> &Comments<'a> {
4444
&self.comments
4545
}
46+
47+
pub(crate) const fn is_preview(&self) -> bool {
48+
self.options.preview().is_enabled()
49+
}
50+
51+
pub(crate) const fn is_stable(&self) -> bool {
52+
!self.is_preview()
53+
}
4654
}
4755

4856
impl FormatContext for PyFormatContext<'_> {

crates/ruff_python_formatter/src/expression/expr_lambda.rs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use ruff_formatter::write;
1+
use ruff_formatter::{format_args, write};
22
use ruff_python_ast::AnyNodeRef;
33
use ruff_python_ast::ExprLambda;
44
use ruff_text_size::Ranged;
55

6-
use crate::comments::{dangling_comments, SourceComment};
7-
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
6+
use crate::comments::{dangling_comments, leading_comments, SourceComment};
7+
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parenthesize};
8+
use crate::expression::{has_own_parentheses, maybe_parenthesize_expression};
89
use crate::other::parameters::ParametersParentheses;
910
use crate::prelude::*;
1011

@@ -25,31 +26,49 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
2526
write!(f, [token("lambda")])?;
2627

2728
if let Some(parameters) = parameters {
28-
// In this context, a dangling comment can either be a comment between the `lambda` the
29+
// In this context, a dangling comment can either be a comment between the `lambda` and the
2930
// parameters, or a comment between the parameters and the body.
3031
let (dangling_before_parameters, dangling_after_parameters) = dangling
3132
.split_at(dangling.partition_point(|comment| comment.end() < parameters.start()));
3233

3334
if dangling_before_parameters.is_empty() {
3435
write!(f, [space()])?;
35-
} else {
36-
write!(f, [dangling_comments(dangling_before_parameters)])?;
3736
}
3837

39-
write!(
40-
f,
41-
[parameters
42-
.format()
43-
.with_options(ParametersParentheses::Never)]
44-
)?;
38+
group(&format_with(|f: &mut PyFormatter| {
39+
if f.context().node_level().is_parenthesized()
40+
&& (parameters.len() > 1 || !dangling_before_parameters.is_empty())
41+
{
42+
let end_of_line_start = dangling_before_parameters
43+
.partition_point(|comment| comment.line_position().is_end_of_line());
44+
let (same_line_comments, own_line_comments) =
45+
dangling_before_parameters.split_at(end_of_line_start);
4546

46-
write!(f, [token(":")])?;
47+
dangling_comments(same_line_comments).fmt(f)?;
4748

48-
if dangling_after_parameters.is_empty() {
49-
write!(f, [space()])?;
50-
} else {
51-
write!(f, [dangling_comments(dangling_after_parameters)])?;
52-
}
49+
soft_block_indent(&format_args![
50+
leading_comments(own_line_comments),
51+
parameters
52+
.format()
53+
.with_options(ParametersParentheses::Never),
54+
])
55+
.fmt(f)
56+
} else {
57+
parameters
58+
.format()
59+
.with_options(ParametersParentheses::Never)
60+
.fmt(f)
61+
}?;
62+
63+
token(":").fmt(f)?;
64+
65+
if dangling_after_parameters.is_empty() {
66+
space().fmt(f)
67+
} else {
68+
dangling_comments(dangling_after_parameters).fmt(f)
69+
}
70+
}))
71+
.fmt(f)?;
5372
} else {
5473
write!(f, [token(":")])?;
5574

@@ -61,7 +80,12 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
6180
}
6281
}
6382

64-
write!(f, [body.format()])
83+
// Avoid parenthesizing lists, dictionaries, etc.
84+
if f.context().is_stable() || has_own_parentheses(body, f.context()).is_some() {
85+
body.format().fmt(f)
86+
} else {
87+
maybe_parenthesize_expression(body, item, Parenthesize::IfBreaksOrIfRequired).fmt(f)
88+
}
6589
}
6690

6791
fn fmt_dangling_comments(

crates/ruff_python_formatter/src/expression/expr_named_expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl NeedsParentheses for ExprNamedExpr {
6969
|| parent.is_stmt_delete()
7070
|| parent.is_stmt_for()
7171
|| parent.is_stmt_function_def()
72+
|| parent.is_expr_lambda()
7273
{
7374
OptionalParentheses::Always
7475
} else {

crates/ruff_python_formatter/src/options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ impl PyFormatOptions {
108108
self.line_ending
109109
}
110110

111-
pub fn preview(&self) -> PreviewMode {
111+
pub const fn preview(&self) -> PreviewMode {
112112
self.preview
113113
}
114114

crates/ruff_python_formatter/src/other/parameters.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,14 +240,10 @@ impl FormatNodeRule<Parameters> for FormatParameters {
240240
Ok(())
241241
});
242242

243-
let num_parameters = posonlyargs.len()
244-
+ args.len()
245-
+ usize::from(vararg.is_some())
246-
+ kwonlyargs.len()
247-
+ usize::from(kwarg.is_some());
243+
let num_parameters = item.len();
248244

249245
if self.parentheses == ParametersParentheses::Never {
250-
write!(f, [group(&format_inner), dangling_comments(dangling)])
246+
write!(f, [format_inner, dangling_comments(dangling)])
251247
} else if num_parameters == 0 {
252248
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
253249
// No parameters, format any dangling comments between `()`

0 commit comments

Comments
 (0)