mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-18 01:20:24 +00:00
Insert newline after nested function or class statements (#7946)
**Summary** Insert a newline after nested function and class definitions, unless there is a trailing own line comment. We need to e.g. format ```python if platform.system() == "Linux": if sys.version > (3, 10): def f(): print("old") else: def f(): print("new") f() ``` as ```python if platform.system() == "Linux": if sys.version > (3, 10): def f(): print("old") else: def f(): print("new") f() ``` even though `f()` is directly preceded by an if statement, not a function or class definition. See the comments and fixtures for trailing own line comment handling. **Test Plan** I checked that the new content of `newlines.py` matches black's formatting. --------- Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
parent
dda4ceda71
commit
0c3123e07e
8 changed files with 430 additions and 77 deletions
|
@ -155,13 +155,65 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
|
|||
while let Some(following) = iter.next() {
|
||||
let following_comments = comments.leading_dangling_trailing(following);
|
||||
|
||||
let needs_empty_lines = if is_class_or_function_definition(following) {
|
||||
// Here we insert empty lines even if the preceding has a trailing own line comment
|
||||
true
|
||||
} else {
|
||||
// Find nested class or function definitions that need an empty line after them.
|
||||
//
|
||||
// ```python
|
||||
// def f():
|
||||
// if True:
|
||||
//
|
||||
// def double(s):
|
||||
// return s + s
|
||||
//
|
||||
// print("below function")
|
||||
// ```
|
||||
std::iter::successors(
|
||||
Some(AnyNodeRef::from(preceding)),
|
||||
AnyNodeRef::last_child_in_body,
|
||||
)
|
||||
.take_while(|last_child|
|
||||
// If there is a comment between preceding and following the empty lines were
|
||||
// inserted before the comment by preceding and there are no extra empty lines
|
||||
// after the comment.
|
||||
// ```python
|
||||
// class Test:
|
||||
// def a(self):
|
||||
// pass
|
||||
// # trailing comment
|
||||
//
|
||||
//
|
||||
// # two lines before, one line after
|
||||
//
|
||||
// c = 30
|
||||
// ````
|
||||
// This also includes nested class/function definitions, so we stop recursing
|
||||
// once we see a node with a trailing own line comment:
|
||||
// ```python
|
||||
// def f():
|
||||
// if True:
|
||||
//
|
||||
// def double(s):
|
||||
// return s + s
|
||||
//
|
||||
// # nested trailing own line comment
|
||||
// print("below function with trailing own line comment")
|
||||
// ```
|
||||
!comments.has_trailing_own_line(*last_child))
|
||||
.any(|last_child| {
|
||||
matches!(
|
||||
last_child,
|
||||
AnyNodeRef::StmtFunctionDef(_) | AnyNodeRef::StmtClassDef(_)
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
// Add empty lines before and after a function or class definition. If the preceding
|
||||
// node is a function or class, and contains trailing comments, then the statement
|
||||
// itself will add the requisite empty lines when formatting its comments.
|
||||
if (is_class_or_function_definition(preceding)
|
||||
&& !preceding_comments.has_trailing_own_line())
|
||||
|| is_class_or_function_definition(following)
|
||||
{
|
||||
if needs_empty_lines {
|
||||
if source_type.is_stub() {
|
||||
stub_file_empty_lines(
|
||||
self.kind,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue