Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leading, Dangling, and Trailing comments formatting #4785

Merged
merged 2 commits into from
Jun 2, 2023

Conversation

MichaReiser
Copy link
Member

Summary

This PR implements the basic leading, dangling, and trailing comments formatting and adds it to the FormatNodeRule.

This PR does not yet formatt the content of the comment. This will be implemented in the next PR.

Test Plan

The comments are now included in the formatted output, which is good. I wasn't able to really verify if they are all placed correctly because we only format top-level statements.

I recommend that we fine tune the formatting when we have better coverage and know which comments are formatted incorrectly.

@MichaReiser
Copy link
Member Author

MichaReiser commented Jun 1, 2023

@MichaReiser MichaReiser requested a review from konstin June 1, 2023 14:21
@MichaReiser MichaReiser added internal An internal refactor or improvement formatter Related to the formatter labels Jun 1, 2023

/// What's the enclosing level of the outer node.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
pub(crate) enum NodeLevel {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super happy with this because it will require that any code that formats an indented block needs to set the level to NodeLevel::Statement.

The reason why I introduced it is because the formatting logic needs to know whether two empty lines are acceptable or not (or any, in the case of parenthesized expressions)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we need even more granular states here? E.g., Black has different rules for docstrings within classes vs. docstrings within functions (requires one newline for the former, allows one newline for the latter):

def f():
    """foo"""
    x = 1


class F:
    """foo"""

    x = 1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly, but I would prefer adding global state when possible (it comes at a cost that we need to snapshot the state and restore it if we ever add error handling support to the formatter).

Away we could do docstring formatting without adding any additional global state is to:

  • Get the first statement
  • Test if it is a docstring
  • If so, format it, and insert the appropriate number of newlines after
  • Otherwise format it as usual

@MichaReiser MichaReiser force-pushed the format-leading-comments branch from 60f2b16 to 66615bb Compare June 1, 2023 14:28
@github-actions
Copy link
Contributor

github-actions bot commented Jun 1, 2023

PR Check Results

Ecosystem

✅ ecosystem check detected no changes.

Benchmark

Linux

group                                      main                                   pr
-----                                      ----                                   --
linter/all-rules/large/dataset.py          1.00     14.0±0.04ms     2.9 MB/sec    1.00     14.0±0.03ms     2.9 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      3.4±0.01ms     4.9 MB/sec    1.00      3.4±0.01ms     4.9 MB/sec
linter/all-rules/numpy/globals.py          1.00    426.9±0.46µs     6.9 MB/sec    1.00    427.4±4.48µs     6.9 MB/sec
linter/all-rules/pydantic/types.py         1.00      5.9±0.02ms     4.3 MB/sec    1.00      5.9±0.01ms     4.4 MB/sec
linter/default-rules/large/dataset.py      1.01      6.8±0.01ms     6.0 MB/sec    1.00      6.8±0.01ms     6.0 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.00   1507.1±1.48µs    11.0 MB/sec    1.00   1501.4±4.32µs    11.1 MB/sec
linter/default-rules/numpy/globals.py      1.00    170.0±1.04µs    17.4 MB/sec    1.01    170.9±4.06µs    17.3 MB/sec
linter/default-rules/pydantic/types.py     1.00      3.1±0.01ms     8.2 MB/sec    1.00      3.1±0.01ms     8.2 MB/sec
parser/large/dataset.py                    1.01      5.2±0.00ms     7.8 MB/sec    1.00      5.1±0.01ms     7.9 MB/sec
parser/numpy/ctypeslib.py                  1.01   1019.0±0.51µs    16.3 MB/sec    1.00   1009.1±1.20µs    16.5 MB/sec
parser/numpy/globals.py                    1.01    105.5±0.25µs    28.0 MB/sec    1.00    104.3±0.20µs    28.3 MB/sec
parser/pydantic/types.py                   1.01      2.2±0.00ms    11.4 MB/sec    1.00      2.2±0.00ms    11.5 MB/sec

Windows

group                                      main                                   pr
-----                                      ----                                   --
linter/all-rules/large/dataset.py          1.01     23.0±0.98ms  1810.0 KB/sec    1.00     22.7±0.90ms  1834.4 KB/sec
linter/all-rules/numpy/ctypeslib.py        1.01      5.7±0.27ms     2.9 MB/sec    1.00      5.7±0.28ms     2.9 MB/sec
linter/all-rules/numpy/globals.py          1.03   682.6±37.30µs     4.3 MB/sec    1.00   663.5±36.93µs     4.4 MB/sec
linter/all-rules/pydantic/types.py         1.01      9.6±0.43ms     2.7 MB/sec    1.00      9.5±0.41ms     2.7 MB/sec
linter/default-rules/large/dataset.py      1.00     11.0±0.38ms     3.7 MB/sec    1.00     11.0±0.42ms     3.7 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.00      2.3±0.10ms     7.2 MB/sec    1.01      2.3±0.08ms     7.1 MB/sec
linter/default-rules/numpy/globals.py      1.02   278.9±17.23µs    10.6 MB/sec    1.00   273.9±15.02µs    10.8 MB/sec
linter/default-rules/pydantic/types.py     1.00      4.9±0.20ms     5.2 MB/sec    1.02      5.0±0.22ms     5.1 MB/sec
parser/large/dataset.py                    1.03      8.6±0.25ms     4.7 MB/sec    1.00      8.4±0.30ms     4.8 MB/sec
parser/numpy/ctypeslib.py                  1.01  1650.0±74.84µs    10.1 MB/sec    1.00  1626.0±68.17µs    10.2 MB/sec
parser/numpy/globals.py                    1.01   167.8±11.29µs    17.6 MB/sec    1.00    165.6±8.74µs    17.8 MB/sec
parser/pydantic/types.py                   1.02      3.7±0.14ms     6.9 MB/sec    1.00      3.6±0.21ms     7.0 MB/sec

@MichaReiser MichaReiser mentioned this pull request Jun 1, 2023
crates/ruff_python_formatter/src/comments/format.rs Outdated Show resolved Hide resolved
crates/ruff_python_formatter/src/comments/format.rs Outdated Show resolved Hide resolved

/// What's the enclosing level of the outer node.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
pub(crate) enum NodeLevel {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we need even more granular states here? E.g., Black has different rules for docstrings within classes vs. docstrings within functions (requires one newline for the former, allows one newline for the latter):

def f():
    """foo"""
    x = 1


class F:
    """foo"""

    x = 1

Base automatically changed from add-to-ref-node-helpers to main June 2, 2023 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
formatter Related to the formatter internal An internal refactor or improvement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants