Example #1
0
    def render_internal_link(self, token: SyntaxTreeNode) -> None:
        """Render link token `[text](link "title")`,
        where the link has not been identified as an external URL.
        """
        destination = unquote(cast(str, token.attrGet("href") or ""))

        # make the path relative to an "including" document
        # this is set when using the `relative-docs` option of the MyST `include` directive
        relative_include = self.md_env.get("relative-docs", None)
        if relative_include is not None and destination.startswith(
                relative_include[0]):
            source_dir, include_dir = relative_include[1:]
            destination = os.path.relpath(
                os.path.join(include_dir, os.path.normpath(destination)),
                source_dir)

        potential_path = (
            Path(self.doc_env.doc2path(self.doc_env.docname)).parent /
            destination
            if self.doc_env.srcdir  # not set in some test situations
            else None)
        if (potential_path and potential_path.is_file() and not any(
                destination.endswith(suffix)
                for suffix in self.doc_env.config.source_suffix)):
            wrap_node = addnodes.download_reference(
                refdoc=self.doc_env.docname,
                reftarget=destination,
                reftype="myst",
                refdomain=None,  # Added to enable cross-linking
                refexplicit=len(token.children or []) > 0,
                refwarn=False,
            )
            classes = ["xref", "download", "myst"]
            text = destination if not token.children else ""
        else:
            wrap_node = addnodes.pending_xref(
                refdoc=self.doc_env.docname,
                reftarget=destination,
                reftype="myst",
                refdomain=None,  # Added to enable cross-linking
                refexplicit=len(token.children or []) > 0,
                refwarn=True,
            )
            classes = ["xref", "myst"]
            text = ""

        self.add_line_and_source_path(wrap_node, token)
        title = token.attrGet("title")
        if title:
            wrap_node["title"] = title
        self.current_node.append(wrap_node)

        inner_node = nodes.inline("", text, classes=classes)
        wrap_node.append(inner_node)
        with self.current_node_context(inner_node):
            self.render_children(token)
    def render_image(self, token: SyntaxTreeNode) -> None:
        img_node = nodes.image()
        self.add_line_and_source_path(img_node, token)
        destination = cast(str, token.attrGet("src") or "")

        if self.config.get("relative-images",
                           None) is not None and not is_external_url(
                               destination, None, True):
            # make the path relative to an "including" document
            destination = os.path.normpath(
                os.path.join(
                    self.config.get("relative-images", ""),
                    os.path.normpath(destination),
                ))

        img_node["uri"] = destination

        img_node["alt"] = self.renderInlineAsText(token.children or [])
        title = token.attrGet("title")
        if title:
            img_node["title"] = token.attrGet("title")
        self.current_node.append(img_node)
    def render_link(self, token: SyntaxTreeNode) -> None:
        if token.markup == "autolink":
            return self.render_autolink(token)

        ref_node = nodes.reference()
        self.add_line_and_source_path(ref_node, token)
        destination = cast(str, token.attrGet("href") or "")

        if self.config.get("relative-docs",
                           None) is not None and destination.startswith(
                               self.config["relative-docs"][0]):
            # make the path relative to an "including" document
            source_dir, include_dir = self.config["relative-docs"][1:]
            destination = os.path.relpath(
                os.path.join(include_dir, os.path.normpath(destination)),
                source_dir)

        ref_node["refuri"] = destination  # type: ignore[index]

        title = token.attrGet("title")
        if title:
            ref_node["title"] = title  # type: ignore[index]
        next_node = ref_node

        # TODO currently any reference with a fragment # is deemed external
        # (if anchors are not enabled)
        # This comes from recommonmark, but I am not sure of the rationale for it
        if is_external_url(
                destination,
                self.config.get("myst_url_schemes", None),
                "heading_anchors"
                not in self.config.get("myst_extensions", []),
        ):
            self.current_node.append(next_node)
            with self.current_node_context(ref_node):
                self.render_children(token)
        else:
            self.handle_cross_reference(token, destination)
Example #4
0
    def handle_cross_reference(self, token: SyntaxTreeNode,
                               destination: str) -> None:
        """Create nodes for references that are not immediately resolvable."""
        wrap_node = addnodes.pending_xref(
            refdoc=self.doc_env.docname,
            reftarget=unquote(destination),
            reftype="myst",
            refdomain=None,  # Added to enable cross-linking
            refexplicit=len(token.children or []) > 0,
            refwarn=True,
        )
        self.add_line_and_source_path(wrap_node, token)
        title = token.attrGet("title")
        if title:
            wrap_node["title"] = title
        self.current_node.append(wrap_node)

        inner_node = nodes.inline("", "", classes=["xref", "myst"])
        wrap_node.append(inner_node)
        with self.current_node_context(inner_node):
            self.render_children(token)
Example #5
0
    def render_heading(self, token: SyntaxTreeNode) -> None:
        """This extends the docutils method, to allow for the addition of heading ids.
        These ids are computed by the ``markdown-it-py`` ``anchors_plugin``
        as "slugs" which are unique to a document.

        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

        section = self.current_node
        doc_slug = self.doc_env.doc2path(self.doc_env.docname,
                                         base=False) + "#" + slug

        # save the reference in the standard domain, so that it can be handled properly
        domain = cast(StandardDomain, self.doc_env.get_domain("std"))
        if doc_slug in domain.labels:
            other_doc = self.doc_env.doc2path(domain.labels[doc_slug][0])
            self.create_warning(
                f"duplicate label {doc_slug}, other instance in {other_doc}",
                line=section.line,
                subtype="anchor",
            )
        labelid = section["ids"][0]
        domain.anonlabels[doc_slug] = self.doc_env.docname, labelid
        domain.labels[doc_slug] = (
            self.doc_env.docname,
            labelid,
            clean_astext(section[0]),
        )

        self.doc_env.metadata[self.doc_env.docname]["myst_anchors"] = True
        section["myst-anchor"] = doc_slug
 def render_autolink(self, token: SyntaxTreeNode) -> None:
     refuri = target = escapeHtml(token.attrGet("href")
                                  or "")  # type: ignore[arg-type]
     ref_node = nodes.reference(target, target, refuri=refuri)
     self.add_line_and_source_path(ref_node, token)
     self.current_node.append(ref_node)