Format empty lines in stub files like black's preview style (#7206)

## Summary

Fix all but one empty line differences with the black preview style in
typeshed. The remaining differences are breaking with type comments and
trailing commas in function definitions.

I compared the empty line differences with the preview mode of black
since stable has some oddities that would have been hard to replicate
(https://github.com/psf/black/issues/3861). Additionally, it assumes the
style proposed in https://github.com/psf/black/issues/3862.

An edge case that also surfaced with typeshed are newline before
trailing module comments.

**main**

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1632 |
| django | 0.99966 | 2760 | 58 |
| transformers | 0.99930 | 2587 | 447 |
| twine | 1.00000 | 33 | 0 |
| **typeshed** | 0.99978 | 3496 | **2173** |
| warehouse | 0.99825 | 648 | 22 |
| zulip | 0.99950 | 1437 | 27 |

**PR**
| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1632 |
| django | 0.99966 | 2760 | 58 |
| transformers | 0.99930 | 2587 | 447 |
| twine | 1.00000 | 33 | 0 |
| **typeshed** | 0.99983 | 3496 | **18** |
| warehouse | 0.99825 | 648 | 22 |
| zulip | 0.99950 | 1437 | 27 |


Closes #6723

## Test Plan

The main driver was the typeshed diff. I added new test cases for all
kinds of possible empty line combinations in stub files, test cases for
newlines before trailing module comments.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
konsti 2023-09-11 10:03:59 +02:00 committed by GitHub
parent 7440e54ec6
commit 3a2c3a7398
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 858 additions and 77 deletions

View file

@ -2,6 +2,7 @@ use std::borrow::Cow;
use ruff_formatter::{format_args, write, FormatError, FormatOptions, SourceCode};
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_python_ast::PySourceType;
use ruff_python_trivia::{lines_after, lines_after_ignoring_trivia, lines_before};
use ruff_text_size::{Ranged, TextLen, TextRange};
@ -485,11 +486,22 @@ fn strip_comment_prefix(comment_text: &str) -> FormatResult<&str> {
///
/// This builder will insert two empty lines before the comment.
/// ```
pub(crate) const fn empty_lines_before_trailing_comments(
comments: &[SourceComment],
expected: u32,
) -> FormatEmptyLinesBeforeTrailingComments {
FormatEmptyLinesBeforeTrailingComments { comments, expected }
pub(crate) fn empty_lines_before_trailing_comments<'a>(
f: &PyFormatter,
comments: &'a [SourceComment],
) -> FormatEmptyLinesBeforeTrailingComments<'a> {
// Black has different rules for stub vs. non-stub and top level vs. indented
let empty_lines = match (f.options().source_type(), f.context().node_level()) {
(PySourceType::Stub, NodeLevel::TopLevel) => 1,
(PySourceType::Stub, _) => 0,
(_, NodeLevel::TopLevel) => 2,
(_, _) => 1,
};
FormatEmptyLinesBeforeTrailingComments {
comments,
empty_lines,
}
}
#[derive(Copy, Clone, Debug)]
@ -497,7 +509,7 @@ pub(crate) struct FormatEmptyLinesBeforeTrailingComments<'a> {
/// The trailing comments of the node.
comments: &'a [SourceComment],
/// The expected number of empty lines before the trailing comments.
expected: u32,
empty_lines: u32,
}
impl Format<PyFormatContext<'_>> for FormatEmptyLinesBeforeTrailingComments<'_> {
@ -508,7 +520,7 @@ impl Format<PyFormatContext<'_>> for FormatEmptyLinesBeforeTrailingComments<'_>
.find(|comment| comment.line_position().is_own_line())
{
let actual = lines_before(comment.start(), f.context().source()).saturating_sub(1);
for _ in actual..self.expected {
for _ in actual..self.empty_lines {
write!(f, [empty_line()])?;
}
}