Skip to content
Merged
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
29 changes: 21 additions & 8 deletions src/cfengine_cli/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,10 @@ def _format_block_header(node: Node, fmt: Formatter) -> list[Node]:
def _needs_blank_line_before(child: Node, indent: int, line_length: int) -> bool:
"""Check if a blank separator line should precede this child node."""
prev = child.prev_named_sibling
# Empty comments preceding this child will be dropped — look past them
# so we evaluate against the real prior content.
while prev and prev.type == "comment" and _is_empty_comment(prev):
prev = prev.prev_named_sibling
if not prev:
return False

Expand Down Expand Up @@ -743,12 +747,6 @@ def _needs_blank_line_before(child: Node, indent: int, line_length: int) -> bool
if child.type == "comment":
if _is_empty_comment(child):
return False
# Empty comments preceding this one will be dropped — look past them
# so we treat the comment as following the real prior content.
while prev and prev.type == "comment" and _is_empty_comment(prev):
prev = prev.prev_named_sibling
if prev is None:
return False
# Top-level comment after a complete block — visually separates them
if prev.type in BLOCK_TYPES:
return True
Expand Down Expand Up @@ -783,12 +781,27 @@ def _needs_blank_line_before(child: Node, indent: int, line_length: int) -> bool


def _is_empty_comment(node: Node) -> bool:
"""Check if a bare '#' comment should be dropped (not between other comments)."""
"""Check if a bare '#' comment should be dropped.

A run of bare '#' between two non-empty comments collapses to a
single '#' — the first in the run is kept, the rest are dropped.
Bare '#' not flanked by real comments is always dropped."""
if text(node).strip() != "#":
return False
prev = node.prev_named_sibling
# Not the first in a run of '#' — a kept '#' precedes us, drop.
if prev and prev.type == "comment" and text(prev).strip() == "#":
return True
# First in a run — kept only if a non-empty comment sits on each side
# (forward search walks past the rest of the run to find one).
if not (prev and prev.type == "comment"):
return True
nxt = node.next_named_sibling
return not (prev and prev.type == "comment" and nxt and nxt.type == "comment")
while nxt and nxt.type == "comment" and text(nxt).strip() == "#":
nxt = nxt.next_named_sibling
if not (nxt and nxt.type == "comment"):
return True
return False


def _skip_comments(sibling: Node | None, direction: str = "next") -> Node | None:
Expand Down
21 changes: 21 additions & 0 deletions tests/format/006_remove_empty_comments.expected.cf
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# explanation
#
# one more line
bundle agent main
{
# comment
Expand All @@ -22,3 +25,21 @@ bundle agent c
reports:
"hello";
}

bundle agent d
{
reports:
"hello";

any::
"world";
}

bundle agent e
{
reports:
"hello";

any::
"world";
}
50 changes: 50 additions & 0 deletions tests/format/006_remove_empty_comments.input.cf
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
#
#
#
#
#
# explanation
#
#
#
#
# one more line
#
#
#
#
bundle agent main
{
#
Expand Down Expand Up @@ -28,3 +43,38 @@ bundle agent c
reports:
"hello";
}
#
bundle agent d
{
#
reports:
#
"hello";
#
any::
#
"world";
}

#
#
#
bundle agent e
{
#
#
#
reports:
#
#
#
"hello";
#
#
#
any::
#
#
#
"world";
}
Loading