Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
`from x import ( # fmt: skip`) when a standalone comment is among the bracket's
contents: the whole statement is now preserved instead of being reformatted (and
previously crashing) (#5161)
- Preserve comments and blank lines outside requested ranges when formatting with
`--line-ranges` (#5175)

### Preview style

Expand Down
11 changes: 9 additions & 2 deletions src/black/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ class ProtoComment:
consumed: int # how many characters of the original leaf's prefix did we consume
form_feed: bool # is there a form feed before the comment
leading_whitespace: str # leading whitespace before the comment, if any
original_value: str # original comment text, before normalization


def generate_comments(leaf: LN, mode: Mode) -> Iterator[Leaf]:
def generate_comments(
leaf: LN, mode: Mode, *, preserve_comment_formatting: bool = False
) -> Iterator[Leaf]:
"""Clean the prefix of the `leaf` and generate comments from it, if any.

Comments in lib2to3 are shoved into the whitespace prefix. This happens
Expand All @@ -82,7 +85,10 @@ def generate_comments(leaf: LN, mode: Mode) -> Iterator[Leaf]:
):
total_consumed = pc.consumed
prefix = make_simple_prefix(pc.newlines, pc.form_feed)
yield Leaf(pc.type, pc.value, prefix=prefix)
value = pc.value
if preserve_comment_formatting:
value = pc.leading_whitespace + pc.original_value
yield Leaf(pc.type, value, prefix=prefix)
normalize_trailing_prefix(leaf, total_consumed)


Expand Down Expand Up @@ -127,6 +133,7 @@ def list_comments(prefix: str, *, is_endmarker: bool, mode: Mode) -> list[ProtoC
consumed=consumed,
form_feed=form_feed,
leading_whitespace=whitespace,
original_value=line.rstrip(),
)
)
form_feed = False
Expand Down
15 changes: 14 additions & 1 deletion src/black/linegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,20 @@ def visit_default(self, node: LN) -> Iterator[Line]:
"""Default `visit_*()` implementation. Recurses to children of `node`."""
if isinstance(node, Leaf):
any_open_brackets = self.current_line.bracket_tracker.any_open_brackets()
for comment in generate_comments(node, mode=self.mode):
preserve_comment_formatting = (
node.type == STANDALONE_COMMENT
and node.fmt_pass_converted_first_leaf is not None
and node.line_ranges_converted
)
for comment in generate_comments(
node,
mode=self.mode,
preserve_comment_formatting=preserve_comment_formatting,
):
if preserve_comment_formatting:
indent = " " * self.current_line.depth
if indent and comment.value.startswith(indent):
comment.value = comment.value[len(indent) :]
if any_open_brackets:
# any comment within brackets is subject to splitting
self.current_line.append(comment)
Expand Down
3 changes: 2 additions & 1 deletion src/black/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,8 @@ def _maybe_empty_lines(self, current_line: Line) -> tuple[int, int]:
# Consume the first leaf's extra newlines.
first_leaf = current_line.leaves[0]
before = first_leaf.prefix.count("\n")
before = min(before, max_allowed)
if not current_line.is_fmt_pass_converted():
before = min(before, max_allowed)
first_leaf.prefix = ""
else:
before = 0
Expand Down
2 changes: 2 additions & 0 deletions src/black/ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ def _convert_node_to_standalone_comment(node: LN) -> None:
value,
prefix=prefix,
fmt_pass_converted_first_leaf=first,
line_ranges_converted=True,
),
)

Expand Down Expand Up @@ -392,6 +393,7 @@ def _convert_nodes_to_standalone_comment(nodes: Sequence[LN], *, newline: Leaf)
value,
prefix=prefix,
fmt_pass_converted_first_leaf=first,
line_ranges_converted=True,
),
)

Expand Down
4 changes: 4 additions & 0 deletions src/blib2to3/pytree.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ class Leaf(Base):
# code, and `fmt_pass_converted_first_leaf` points to the first Leaf in the
# converted code.
fmt_pass_converted_first_leaf: Optional["Leaf"] = None
# True when this Leaf is converted from unchanged code for --line-ranges.
line_ranges_converted: bool = False

def __init__(
self,
Expand All @@ -391,6 +393,7 @@ def __init__(
fixers_applied: list[Any] = [],
opening_bracket: Optional["Leaf"] = None,
fmt_pass_converted_first_leaf: Optional["Leaf"] = None,
line_ranges_converted: bool = False,
) -> None:
"""
Initializer.
Expand All @@ -410,6 +413,7 @@ def __init__(
self.children = []
self.opening_bracket = opening_bracket
self.fmt_pass_converted_first_leaf = fmt_pass_converted_first_leaf
self.line_ranges_converted = line_ranges_converted

def __repr__(self) -> str:
"""Return a canonical string representation."""
Expand Down
46 changes: 46 additions & 0 deletions tests/data/cases/line_ranges_preserve_outside_prefix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# flags: --line-ranges=2-10
print("format me" )
# format whitespace
# format whitespace
# format whitespace
print( "format me" )
# format whitespace
# format whitespace
# format whitespace
print( "format me")



print("don't format me" )
# don't format whitespace
# don't format whitespace
# don't format whitespace
print( "don't format me" )
# don't format whitespace
# don't format whitespace
# don't format whitespace
print( "don't format me")

# output
# flags: --line-ranges=2-10
print("format me")
# format whitespace
# format whitespace
# format whitespace
print("format me")
# format whitespace
# format whitespace
# format whitespace
print("format me")



print("don't format me" )
# don't format whitespace
# don't format whitespace
# don't format whitespace
print( "don't format me" )
# don't format whitespace
# don't format whitespace
# don't format whitespace
print( "don't format me")
Loading