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
23 changes: 17 additions & 6 deletions src/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,19 +176,30 @@ def parse_update_instructions(comment_body):
# treated as global to avoid misclassifying example filenames as per-file
# instructions.
global_lines = []
in_code_fence = False
fence_char = None
for line in lines:
stripped = line.strip()
if not stripped:
global_lines.append("")
continue
# Toggle code fence state on lines starting with triple backticks
# or triple tildes (handles language specifiers like ```python)
if stripped.startswith("```") or stripped.startswith("~~~"):
in_code_fence = not in_code_fence
# Track code fence state with delimiter awareness: a fence opened
# with backticks can only be closed by backticks, and likewise for
# tildes (CommonMark spec §4.5).
if stripped.startswith("```"):
if fence_char is None:
fence_char = "`"
elif fence_char == "`":
fence_char = None
global_lines.append(stripped)
continue
if in_code_fence:
if stripped.startswith("~~~"):
if fence_char is None:
fence_char = "~"
elif fence_char == "~":
fence_char = None
global_lines.append(stripped)
continue
if fence_char is not None:
global_lines.append(stripped)
continue
file_match = file_pattern.match(stripped)
Expand Down
27 changes: 27 additions & 0 deletions tests/test_comment_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,33 @@ def test_unclosed_code_fence_treats_rest_as_global(self):
assert "config.md: another example" in global_inst
assert file_inst == {}

def test_cross_delimiter_fence_not_closed(self):
"""A backtick-opened fence should not be closed by tilde delimiters."""
comment = "[update-docs] Update the docs:\n```\n~~~\nfile.rst: add a new section\n```\n"
global_inst, file_inst = parse_update_instructions(comment)
# ~~~ should not close the backtick fence, so file.rst line
# remains inside the fence and is not a per-file instruction
assert "file.rst" not in file_inst
assert "file.rst: add a new section" in global_inst

def test_cross_delimiter_tilde_opened_backtick_no_close(self):
"""A tilde-opened fence should not be closed by backtick delimiters."""
comment = (
"[update-docs] see this:\n"
"~~~\n"
"```\n"
"config.rst: update settings\n"
"~~~\n"
"health.md: fix intro"
)
global_inst, file_inst = parse_update_instructions(comment)
# ``` should not close the tilde fence, so config.rst stays global
assert "config.rst" not in file_inst
assert "config.rst: update settings" in global_inst
# health.md is after the tilde fence closes, so it is per-file
assert "health.md" in file_inst
assert file_inst["health.md"] == "fix intro"


# ── _resolve_file_instructions ───────────────────────────────────────────────

Expand Down
Loading