diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/newlines.pyi b/crates/ruff_python_formatter/resources/test/fixtures/ruff/newlines.pyi new file mode 100644 index 0000000000..0d33408ecb --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/newlines.pyi @@ -0,0 +1,161 @@ +### +# Blank lines around functions +### + +x = 1 + +# comment + +def f(): + pass + + +if True: + x = 1 + +# comment + +def f(): + pass + + +x = 1 + + + +# comment + +def f(): + pass + + +x = 1 + + + +# comment +def f(): + pass + + +x = 1 + +# comment + +# comment +def f(): + pass + +x = 1 + +# comment +# comment + +def f(): + pass + +x = 1 + +# comment +# comment +def f(): + pass + + +x = 1 + + +# comment + + + +# comment + + + +def f(): + pass +# comment + + +def f(): + pass + +# comment + +def f(): + pass + + +# comment + +### +# Blank lines around imports. +### + +def f(): + import x + # comment + import y + + +def f(): + import x + + # comment + import y + + +def f(): + import x + # comment + + import y + + +def f(): + import x + # comment + + + import y + + +def f(): + import x + + + # comment + import y + + +def f(): + import x + + # comment + + import y + + +def f(): + import x # comment + # comment + + import y + + +def f(): pass # comment +# comment + +x = 1 + + +def f(): + pass + + + + +# comment + +x = 1 diff --git a/crates/ruff_python_formatter/src/comments/format.rs b/crates/ruff_python_formatter/src/comments/format.rs index a5004da717..a2dbfd601a 100644 --- a/crates/ruff_python_formatter/src/comments/format.rs +++ b/crates/ruff_python_formatter/src/comments/format.rs @@ -308,7 +308,14 @@ impl Format> for FormatEmptyLines { NodeLevel::TopLevel => match self.lines { 0 | 1 => write!(f, [hard_line_break()]), 2 => write!(f, [empty_line()]), - _ => write!(f, [empty_line(), empty_line()]), + _ => match f.options().source_type() { + PySourceType::Stub => { + write!(f, [empty_line()]) + } + PySourceType::Python | PySourceType::Ipynb => { + write!(f, [empty_line(), empty_line()]) + } + }, }, NodeLevel::CompoundStatement => match self.lines { diff --git a/crates/ruff_python_formatter/src/statement/suite.rs b/crates/ruff_python_formatter/src/statement/suite.rs index 0faf69a9d2..7573b3e397 100644 --- a/crates/ruff_python_formatter/src/statement/suite.rs +++ b/crates/ruff_python_formatter/src/statement/suite.rs @@ -1,7 +1,7 @@ use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions}; use ruff_python_ast::helpers::is_compound_statement; use ruff_python_ast::node::AnyNodeRef; -use ruff_python_ast::{self as ast, Constant, Expr, ExprConstant, Stmt, Suite}; +use ruff_python_ast::{self as ast, Constant, Expr, ExprConstant, PySourceType, Stmt, Suite}; use ruff_python_trivia::{lines_after, lines_after_ignoring_trivia, lines_before}; use ruff_text_size::{Ranged, TextRange}; @@ -192,7 +192,14 @@ impl FormatRule> for FormatSuite { SuiteKind::TopLevel => { match lines_after_ignoring_trivia(preceding.end(), source) { 0..=2 => empty_line().fmt(f)?, - _ => write!(f, [empty_line(), empty_line()])?, + _ => match source_type { + PySourceType::Stub => { + empty_line().fmt(f)?; + } + PySourceType::Python | PySourceType::Ipynb => { + write!(f, [empty_line(), empty_line()])?; + } + }, } } SuiteKind::Function | SuiteKind::Class | SuiteKind::Other => { @@ -225,8 +232,15 @@ impl FormatRule> for FormatSuite { match lines_before(start, source) { 0 | 1 => hard_line_break().fmt(f)?, 2 => empty_line().fmt(f)?, - 3.. => match self.kind { - SuiteKind::TopLevel => write!(f, [empty_line(), empty_line()])?, + _ => match self.kind { + SuiteKind::TopLevel => match source_type { + PySourceType::Stub => { + empty_line().fmt(f)?; + } + PySourceType::Python | PySourceType::Ipynb => { + write!(f, [empty_line(), empty_line()])?; + } + }, SuiteKind::Function | SuiteKind::Class | SuiteKind::Other => { empty_line().fmt(f)?; } @@ -280,7 +294,14 @@ impl FormatRule> for FormatSuite { NodeLevel::TopLevel => match count_lines(end) { 0 | 1 => hard_line_break().fmt(f)?, 2 => empty_line().fmt(f)?, - _ => write!(f, [empty_line(), empty_line()])?, + _ => match source_type { + PySourceType::Stub => { + empty_line().fmt(f)?; + } + PySourceType::Python | PySourceType::Ipynb => { + write!(f, [empty_line(), empty_line()])?; + } + }, }, NodeLevel::CompoundStatement => match count_lines(end) { 0 | 1 => hard_line_break().fmt(f)?, diff --git a/crates/ruff_python_formatter/tests/snapshots/format@newlines.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/format@newlines.pyi.snap new file mode 100644 index 0000000000..cf9a8722b2 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@newlines.pyi.snap @@ -0,0 +1,311 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/newlines.pyi +--- +## Input +```py +### +# Blank lines around functions +### + +x = 1 + +# comment + +def f(): + pass + + +if True: + x = 1 + +# comment + +def f(): + pass + + +x = 1 + + + +# comment + +def f(): + pass + + +x = 1 + + + +# comment +def f(): + pass + + +x = 1 + +# comment + +# comment +def f(): + pass + +x = 1 + +# comment +# comment + +def f(): + pass + +x = 1 + +# comment +# comment +def f(): + pass + + +x = 1 + + +# comment + + + +# comment + + + +def f(): + pass +# comment + + +def f(): + pass + +# comment + +def f(): + pass + + +# comment + +### +# Blank lines around imports. +### + +def f(): + import x + # comment + import y + + +def f(): + import x + + # comment + import y + + +def f(): + import x + # comment + + import y + + +def f(): + import x + # comment + + + import y + + +def f(): + import x + + + # comment + import y + + +def f(): + import x + + # comment + + import y + + +def f(): + import x # comment + # comment + + import y + + +def f(): pass # comment +# comment + +x = 1 + + +def f(): + pass + + + + +# comment + +x = 1 +``` + +## Output +```py +### +# Blank lines around functions +### + +x = 1 + +# comment + +def f(): + pass + +if True: + x = 1 + +# comment + +def f(): + pass + +x = 1 + +# comment + +def f(): + pass + +x = 1 + +# comment +def f(): + pass + +x = 1 + +# comment + +# comment +def f(): + pass + +x = 1 + +# comment +# comment + +def f(): + pass + +x = 1 + +# comment +# comment +def f(): + pass + +x = 1 + +# comment + +# comment + +def f(): + pass + +# comment + +def f(): + pass + +# comment + +def f(): + pass + +# comment + +### +# Blank lines around imports. +### + +def f(): + import x + + # comment + import y + +def f(): + import x + + # comment + import y + +def f(): + import x + # comment + + import y + +def f(): + import x + # comment + + import y + +def f(): + import x + + # comment + import y + +def f(): + import x + + # comment + + import y + +def f(): + import x # comment + # comment + + import y + +def f(): + pass # comment + +# comment + +x = 1 + +def f(): + pass + +# comment + +x = 1 +``` + + +