Skip to content

Commit

Permalink
馃憣 IMPROVE: Convert nested headings to rubrics (#497)
Browse files Browse the repository at this point in the history
Handle disallowed nested headings, by converting them to `rubric` nodes
  • Loading branch information
chrisjsewell committed Jan 9, 2022
1 parent e0cf7da commit 9039a43
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 3 deletions.
10 changes: 9 additions & 1 deletion myst_parser/docutils_renderer.py
Expand Up @@ -584,12 +584,20 @@ def blocks_mathjax_processing(self) -> bool:
def render_heading(self, token: SyntaxTreeNode) -> None:

if self.md_env.get("match_titles", None) is False:
# this can occur if a nested parse is performed by a directive
# (such as an admonition) which contains a header.
# this would break the document structure
self.create_warning(
"Header nested in this element can lead to unexpected outcomes",
"Disallowed nested header found, converting to rubric",
line=token_line(token, default=0),
subtype="nested_header",
append_to=self.current_node,
)
rubric = nodes.rubric(token.content, "")
self.add_line_and_source_path(rubric, token)
with self.current_node_context(rubric, append=True):
self.render_children(token)
return

# Test if we're replacing a section level first
level = int(token.tag[1])
Expand Down
11 changes: 10 additions & 1 deletion myst_parser/mocking.py
Expand Up @@ -133,7 +133,16 @@ def nested_parse(
state_machine_class=None,
state_machine_kwargs=None,
) -> None:
"""Perform a nested parse of the input block, with ``node`` as the parent."""
"""Perform a nested parse of the input block, with ``node`` as the parent.
:param block: The block of lines to parse.
:param input_offset: The offset of the first line of block,
to the starting line of the state (i.e. directive).
:param node: The parent node to attach the parsed content to.
:param match_titles: Whether to to allow the parsing of headings
(normally this is false,
since nested heading would break the document structure)
"""
sm_match_titles = self.state_machine.match_titles
render_match_titles = self._renderer.md_env.get("match_titles", None)
self.state_machine.match_titles = self._renderer.md_env[
Expand Down
5 changes: 5 additions & 0 deletions myst_parser/sphinx_renderer.py
Expand Up @@ -135,6 +135,11 @@ def render_heading(self, token: SyntaxTreeNode) -> None:
The approach is similar to ``sphinx.ext.autosectionlabel``
"""
super().render_heading(token)

if not isinstance(self.current_node, nodes.section):
return

# create the slug string
slug = cast(str, token.attrGet("id"))
if slug is None:
return
Expand Down
2 changes: 1 addition & 1 deletion tests/test_renderers/fixtures/reporter_warnings.md
Expand Up @@ -136,7 +136,7 @@ header nested in admonition
# Header
```
.
<string>:2: (WARNING/2) Header nested in this element can lead to unexpected outcomes
<string>:2: (WARNING/2) Disallowed nested header found, converting to rubric
.

nested parse warning
Expand Down

0 comments on commit 9039a43

Please sign in to comment.