Skip to content

Commit

Permalink
Improve dummy_implementations preview style
Browse files Browse the repository at this point in the history
* Only collapse dummy blocks if the parent is a function definition or class definition
* Don't insert empty lines between two function definitions if the preceding statement is a dummy definition and the two definitions aren't separated by an empty line. Not enforcing an empty lines allows grouping overloaded function definitions.

Signed-off-by: Micha Reiser <micha@reiser.io>
  • Loading branch information
MichaReiser committed Dec 22, 2023
1 parent 3cc719b commit 760d12e
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 294 deletions.
Expand Up @@ -253,4 +253,23 @@ def y():
# empty line(s) at the end of the file due to nested function
if True:
def nested_trailing_function():
pass
pass


def overload1(): ... # trailing comment
def overload1(a: int): ...

def overload2(): ... # trailing comment

def overload2(a: int): ...

def overload3():
...
# trailing comment
def overload3(a: int): ...

def overload4():
...
# trailing comment

def overload4(a: int): ...
10 changes: 7 additions & 3 deletions crates/ruff_python_formatter/src/statement/clause.rs
Expand Up @@ -392,9 +392,13 @@ pub(crate) fn clause_body<'a>(

impl Format<PyFormatContext<'_>> for FormatClauseBody<'_> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
// In stable, stubs are only collapsed in stub files, in preview this is consistently
// applied everywhere
if (f.options().source_type().is_stub() || is_dummy_implementations_enabled(f.context()))
// In stable, stubs are only collapsed in stub files, in preview stubs in functions
// or classes are collapsed too
let should_collapse_stub = f.options().source_type().is_stub()
|| (is_dummy_implementations_enabled(f.context())
&& matches!(self.kind, SuiteKind::Function | SuiteKind::Class));

if should_collapse_stub
&& contains_only_an_ellipsis(self.body, f.context().comments())
&& self.trailing_comments.is_empty()
{
Expand Down
34 changes: 27 additions & 7 deletions crates/ruff_python_formatter/src/statement/suite.rs
Expand Up @@ -12,7 +12,8 @@ use crate::context::{NodeLevel, TopLevelStatementPosition, WithIndentLevel, With
use crate::expression::expr_string_literal::ExprStringLiteralKind;
use crate::prelude::*;
use crate::preview::{
is_module_docstring_newlines_enabled, is_no_blank_line_before_class_docstring_enabled,
is_dummy_implementations_enabled, is_module_docstring_newlines_enabled,
is_no_blank_line_before_class_docstring_enabled,
};
use crate::statement::stmt_expr::FormatStmtExpr;
use crate::verbatim::{
Expand Down Expand Up @@ -261,12 +262,31 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
f,
)?;
} else {
match self.kind {
SuiteKind::TopLevel => {
write!(f, [empty_line(), empty_line()])?;
}
SuiteKind::Function | SuiteKind::Class | SuiteKind::Other => {
empty_line().fmt(f)?;
// Preserve empty lines after a stub implementation but don't insert a new one if there isn't any present in the source.
// This is useful when having multiple function overloads that should be grouped to getter by omitting new lines between them.
let is_preceding_stub_function_without_empty_line =
is_dummy_implementations_enabled(f.context())
&& following.is_function_def_stmt()
&& preceding
.as_function_def_stmt()
.is_some_and(|preceding_stub| {
contains_only_an_ellipsis(
&preceding_stub.body,
f.context().comments(),
) && lines_after_ignoring_end_of_line_trivia(
preceding_stub.end(),
f.context().source(),
) < 2
});

if !is_preceding_stub_function_without_empty_line {
match self.kind {
SuiteKind::TopLevel => {
write!(f, [empty_line(), empty_line()])?;
}
SuiteKind::Function | SuiteKind::Class | SuiteKind::Other => {
empty_line().fmt(f)?;
}
}
}
}
Expand Down

This file was deleted.

0 comments on commit 760d12e

Please sign in to comment.