diff --git a/myst_parser/parsers/directives.py b/myst_parser/parsers/directives.py index d2512831..4f4f7ae3 100644 --- a/myst_parser/parsers/directives.py +++ b/myst_parser/parsers/directives.py @@ -192,7 +192,10 @@ def _parse_directive_options( content_lines = content.splitlines() yaml_lines = [] while content_lines: - if not content_lines[0].lstrip().startswith(":"): + stripped = content_lines[0].lstrip() + # Stop at lines that don't start with a colon or have 3+ colons, which are colon fences + # (e.g. nested directives like `::::{other}`) + if not stripped.startswith(":") or stripped.startswith(":::"): break yaml_lines.append(content_lines.pop(0).lstrip()[1:]) options_block = "\n".join(yaml_lines) diff --git a/tests/test_renderers/test_parse_directives.py b/tests/test_renderers/test_parse_directives.py index 3813cc97..36eba61b 100644 --- a/tests/test_renderers/test_parse_directives.py +++ b/tests/test_renderers/test_parse_directives.py @@ -120,3 +120,10 @@ def test_additional_options(): ) assert len(result.warnings) == 1 assert "Unknown option" in result.warnings[0].msg + + +def test_colon_options_stop_at_colon_fence(): + """Options parsing should stop when encountering a colon fence (3+ colons).""" + result = parse_directive_text(Note, "", ":class: xxx\n::::{other}\ncontent\n::::") + assert result.options == {"class": ["xxx"]} + assert result.body == ["::::{other}", "content", "::::"]