diff --git a/docs/conf.py b/docs/conf.py index 9ec14302..26da6195 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -161,6 +161,7 @@ def run_apidoc(app): ("py:class", "docutils.nodes.document"), ("py:class", "docutils.nodes.docinfo"), ("py:class", "docutils.nodes.Element"), + ("py:class", "docutils.nodes.Node"), ("py:class", "docutils.nodes.field_list"), ("py:class", "docutils.nodes.problematic"), ("py:class", "docutils.nodes.pending"), diff --git a/myst_parser/docutils_renderer.py b/myst_parser/docutils_renderer.py index b4011ea2..66aabe82 100644 --- a/myst_parser/docutils_renderer.py +++ b/myst_parser/docutils_renderer.py @@ -1046,7 +1046,7 @@ def render_myst_role(self, token: SyntaxTreeNode) -> None: role_func, messages = roles.role( name, self.language_module_rst, lineno, self.reporter ) - inliner = MockInliner(self, lineno) + inliner = MockInliner(self) if role_func: nodes, messages2 = role_func(name, rawsource, text, lineno, inliner) # return nodes, messages + messages2 diff --git a/myst_parser/mocking.py b/myst_parser/mocking.py index 68a1414a..15786a50 100644 --- a/myst_parser/mocking.py +++ b/myst_parser/mocking.py @@ -5,7 +5,7 @@ import re import sys from pathlib import Path -from typing import TYPE_CHECKING, List, Optional, Tuple, Type +from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Type from docutils import nodes from docutils.parsers.rst import Directive, DirectiveError @@ -31,28 +31,50 @@ class MockInliner: This is parsed to role functions. """ - def __init__(self, renderer: "DocutilsRenderer", lineno: int): + def __init__(self, renderer: "DocutilsRenderer"): + """Initialize the mock inliner.""" self._renderer = renderer + # here we mock that the `parse` method has already been called + # which is where these attributes are set (via the RST state Memo) self.document = renderer.document self.reporter = renderer.document.reporter + self.language = renderer.language_module_rst + self.parent = renderer.current_node + if not hasattr(self.reporter, "get_source_and_line"): - # TODO this is called by some roles, - # but I can't see how that would work in RST? + # In docutils this is set by `RSTState.runtime_init` self.reporter.get_source_and_line = lambda l: (self.document["source"], l) - self.parent = renderer.current_node - self.language = renderer.language_module_rst + self.rfc_url = "rfc%d.html" def problematic( self, text: str, rawsource: str, message: nodes.system_message ) -> nodes.problematic: + """Record a system message from parsing.""" msgid = self.document.set_id(message, self.parent) - problematic = nodes.problematic(rawsource, rawsource, refid=msgid) + problematic = nodes.problematic(rawsource, text, refid=msgid) prbid = self.document.set_id(problematic) message.add_backref(prbid) return problematic - # TODO add parse method + def parse( + self, text: str, lineno: int, memo: Any, parent: nodes.Node + ) -> Tuple[List[nodes.Node], List[nodes.system_message]]: + """Parse the text and return a list of nodes.""" + # note the only place this is normally called, + # is by `RSTState.inline_text`, or in directives: `self.state.inline_text`, + # and there the state parses its own parent + # self.reporter = memo.reporter + # self.document = memo.document + # self.language = memo.language + with self._renderer.current_node_context(parent): + # the parent is never actually appended to though, + # so we make a temporary parent to parse into + container = nodes.Element() + with self._renderer.current_node_context(container): + self._renderer.nested_render_text(text, lineno, inline=True) + + return container.children, [] def __getattr__(self, name: str): """This method is only be called if the attribute requested has not @@ -87,7 +109,7 @@ def __init__( self.document = renderer.document self.reporter = renderer.document.reporter self.state_machine = state_machine - self.inliner = MockInliner(renderer, lineno) + self.inliner = MockInliner(renderer) class Struct: document = self.document @@ -172,12 +194,7 @@ def inline_text( :returns: (list of nodes, list of messages) """ - container = nodes.Element() - with self._renderer.current_node_context(container): - self._renderer.nested_render_text(text, lineno, inline=True) - - # TODO return messages? - return container.children, [] + return self.inliner.parse(text, lineno, self.memo, self._renderer.current_node) # U+2014 is an em-dash: attribution_pattern = re.compile("^((?:---?(?!-)|\u2014) *)(.+)")