Skip to content

Commit

Permalink
✨ NEW: Add myst_fence_as_directive config (#742)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisjsewell committed Mar 7, 2023
1 parent 1e440e6 commit 8508bf7
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 2 deletions.
18 changes: 18 additions & 0 deletions myst_parser/config/main.py
Expand Up @@ -166,6 +166,14 @@ def _test_slug_func(text: str) -> str:
return text[::-1]


def check_fence_as_directive(
inst: "MdParserConfig", field: dc.Field, value: Any
) -> None:
"""Check that the extensions are a sequence of known strings"""
deep_iterable(instance_of(str), instance_of((list, tuple, set)))(inst, field, value)
setattr(inst, field.name, set(value))


@dc.dataclass()
class MdParserConfig:
"""Configuration options for the Markdown Parser.
Expand Down Expand Up @@ -250,6 +258,16 @@ def __repr__(self) -> str:
},
)

fence_as_directive: Set[str] = dc.field(
default_factory=set,
metadata={
"validator": check_fence_as_directive,
"help": "Interpret a code fence as a directive, for certain language names. "
"This can be useful for fences like dot and mermaid, "
"and interoperability with other Markdown renderers.",
},
)

number_code_blocks: Sequence[str] = dc.field(
default_factory=list,
metadata={
Expand Down
22 changes: 20 additions & 2 deletions myst_parser/mdit_to_docutils/base.py
Expand Up @@ -743,6 +743,13 @@ def render_fence(self, token: SyntaxTreeNode) -> None:
return self.render_restructuredtext(token)
if name.startswith("{") and name.endswith("}"):
return self.render_directive(token, name[1:-1], arguments)
if name in self.md_config.fence_as_directive:
options = {k: str(v) for k, v in token.attrs.items()}
if "id" in options:
options["name"] = options.pop("id")
return self.render_directive(
token, name, arguments, additional_options=options
)

if not name and self.sphinx_env is not None:
# use the current highlight setting, via the ``highlight`` directive,
Expand Down Expand Up @@ -1664,7 +1671,12 @@ def render_restructuredtext(self, token: SyntaxTreeNode) -> None:
self.current_node.extend(newdoc.children)

def render_directive(
self, token: SyntaxTreeNode, name: str, arguments: str
self,
token: SyntaxTreeNode,
name: str,
arguments: str,
*,
additional_options: dict[str, str] | None = None,
) -> None:
"""Render special fenced code blocks as directives.
Expand All @@ -1673,7 +1685,13 @@ def render_directive(
:param arguments: The remaining text on the same line as the directive name.
"""
position = token_line(token)
nodes_list = self.run_directive(name, arguments, token.content, position)
nodes_list = self.run_directive(
name,
arguments,
token.content,
position,
additional_options=additional_options,
)
self.current_node += nodes_list

def run_directive(
Expand Down
28 changes: 28 additions & 0 deletions tests/test_renderers/fixtures/myst-config.txt
Expand Up @@ -468,3 +468,31 @@ My paragraph
<reference id_link="True" refid="title">
reversed
.

[fence_as_directive] --myst-fence-as-directive=unknown,admonition --myst-enable-extensions=attrs_block
.
```unknown
```

{#myname .class1}
{a=b}
```admonition title
content
```
.
<document source="<string>">
<system_message level="2" line="1" source="<string>" type="WARNING">
<paragraph>
Unknown directive type: 'unknown' [myst.directive_unknown]
<system_message level="2" line="6" source="<string>" type="WARNING">
<paragraph>
'admonition': Unknown option keys: ['a'] (allowed: ['class', 'name']) [myst.directive_parse]
<admonition classes="class1" ids="myname" names="myname">
<title>
title
<paragraph>
content

<string>:1: (WARNING/2) Unknown directive type: 'unknown' [myst.directive_unknown]
<string>:6: (WARNING/2) 'admonition': Unknown option keys: ['a'] (allowed: ['class', 'name']) [myst.directive_parse]
.

0 comments on commit 8508bf7

Please sign in to comment.