executablebooks / MyST-Parser

An extended commonmark compliant parser, with bridges to docutils/sphinx
https://myst-parser.readthedocs.io
MIT License
759 stars 196 forks source link

[Sphinx] `eval-rst` fails to parse links correctly #771

Open chrysle opened 1 year ago

chrysle commented 1 year ago

Describe the bug

context

The MyST parser is used as an extension to the Sphinx build system.

I converted the Sphinx index, which was written in ReStructuredText, to Markdown, and included the RST README, as described here. Then the documentation was built running sphinx.

expectation I expected the RST content of the included file to be parsed correctly.

bug However, MyST parser was unable to connect links with separate target definition with their targets.

Instead there was the following error:

../README.rst:<line>: ERROR: Unknown target name: "<target name>"

for each such link.

problem This is a big problem for Markdown-RST compatbility.

Reproduce the bug

See jazzband/pip-tools#1874 for a demonstration of the problem.

List your environment

Sphinx: 7.0.1 MyST-Parser: 1.0.0 Python: 3.7+ OS: Ubuntu 22.04 LTS x86_64

welcome[bot] commented 1 year ago

Thanks for opening your first issue here! Engagement like this is essential for open source projects! :hugs:
If you haven't done so already, check out EBP's Code of Conduct. Also, please try to follow the issue template as it helps other community members to contribute more effectively.
If your issue is a feature request, others may react to it, to raise its prominence (see Feature Voting).
Welcome to the EBP community! :tada:

NMAC427 commented 1 year ago

I was able to hack together a patch (in myst_parser/mdit_to_docutils/base.py that fixes this issue. However, as I'm not too familiar with how docutils works, I'm not entirely sure if this is a proper fix or just a hack.

def render_restructuredtext(self, token: SyntaxTreeNode) -> None:
    """Render the content of the token as restructuredtext."""
    # copy necessary elements (source, line no, env, reporter)
    newdoc = make_document()
    newdoc["source"] = self.document["source"]
    newdoc.settings = self.document.settings
    newdoc.reporter = self.reporter
    # pad the line numbers artificially so they offset with the fence block
    pseudosource = ("\n" * token_line(token)) + token.content
    # actually parse the rst into our document
    MockRSTParser().parse(pseudosource, newdoc)

    for node in newdoc:
        if node["names"]:
            self.document.note_explicit_target(node, node)

    for name, nodes in newdoc.refnames.items():
        self.document.note_refname(nodes[0])

    for name, node in newdoc.substitution_defs.items():
        self.document.note_substitution_def(node, name, newdoc)

    self.current_node.extend(newdoc.children)

The main issue that I'm experiencing with this is that I can define the same target name mutliple times without raising a Duplicate target name error.