Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sphinx :doc: role doesn't work #1065

Open
CendioOssman opened this issue Mar 17, 2022 · 5 comments
Open

sphinx :doc: role doesn't work #1065

CendioOssman opened this issue Mar 17, 2022 · 5 comments
Labels

Comments

@CendioOssman
Copy link

The Sphinx role :doc: for referencing other documents doesn't generate a link

Description of problem
The following example doesn't work:

index.rst:

Main Title
======

This is the big document. For more stuff see :doc:`subdoc`.

.. toctree::

   subdoc

subdoc.rst:

Subtitle
======

Here is some more stuff

The reference will have the correct text "Subtitle", but it will not be a clickable link. The styling will also be wrong (see #805).

What is the expected output? What do you see instead?

The output should be: "This is the big document. For more stuff see Subtitle."

🖥 Versions
python -V: 3.6.12

pip freeze | grep rst2pdf: 0.98

pip freeze | grep reportlab: 3.6.1

pip freeze | grep Sphinx: 4.2.0

Which operating system are you using?

Linux

Additional information

This works fine with Sphinx's singlehtml builder, so it isn't an inherent problem with merging documents. Perhaps the FIXME about using inline_all_toctrees() would generate the correct nodes and resolve this?

@CendioOssman
Copy link
Author

I dug a bit deeper and singlehtml does quite a bit of magic to get this working. There are three parts to this:

  • It converts start_of_file nodes to <span> elements with id set to document-<docname>. These serves as anchors to refer to.
  • Instead of letting get_target_uri() return '' (since there is just one document), it returns #document-<docname> for all local references.
  • However the above means that normal references end up being #document-docname#section-id. So it has a cleanup phase after resolve_references() where it goes through all reference nodes and cleans up the double fragments.

Not sure how to map this to rst2pdf yet, but I'll see if I can find a workaround.

@CendioOssman
Copy link
Author

It was a bit tricky, but I got this Sphinx extension finally as a workaround:

#
# Extension that fixes :doc: references for rst2pdf
#

from docutils import nodes
from sphinx import addnodes
from sphinx.util import docname_join
from sphinx.util.nodes import clean_astext, make_refnode
from sphinx.transforms.post_transforms import SphinxPostTransform

class PDFDocReferenceTransform(SphinxPostTransform):
    # Needs to be lower than Sphinx reference resolver
    default_priority = 9

    def is_supported(self):
        return self.app.builder.name == "pdf"

    def run(self):
        # Add a fake target at each document boundary
        for node in self.document.traverse(addnodes.start_of_file):
            target = nodes.target('', '', ids=['document-%s' % node['docname']])
            self.document.note_explicit_target(target)
            node.insert(0, target)

        # Do what Sphinx normally does for :doc:, but with a
        # better reference node
        for node in self.document.traverse(addnodes.pending_xref):
            if node['reftype'] != 'doc':
                continue

            fromdocname = node['refdoc']
            docname = docname_join(node['refdoc'], node['reftarget'])

            if node['refexplicit']:
                caption = node.astext()
            else:
                caption = clean_astext(self.env.titles[docname])

            # FIXME: For some reason Sphinx uses 'doc' as the class,
            #        rather than 'std' and 'std-doc'
            innernode = nodes.inline(caption, caption, classes=['doc'])
            newnode = make_refnode(self.app.builder, fromdocname,
                                   docname, 'document-' + docname, innernode)

            node.replace_self(newnode)

def setup(app):
    app.add_post_transform(PDFDocReferenceTransform)

    return { "parallel_read_safe": True,
             "parallel_write_safe": True }

@lornajane
Copy link
Contributor

Thanks for mentioning this and sharing your sphinx extension! Are you publishing these somewhere? Also are you using rst2pdf directly or asking Sphinx to build the PDF output itself? I'm not exactly sure how to replicate what's described here.

@CendioOssman
Copy link
Author

I'm just publishing them here. I'm hoping they are just a temporary workaround until rst2pdf handles this itself. :)

I'm indeed using Sphinx, not calling rst2pdf directly. So this is something I think should be handled by pdfbuilderas that is the bridge between Sphinx and rst2pdf.

@lornajane
Copy link
Contributor

Just passing by to say that I've been using sphinx a little more myself and finding lots of tools don't quite support these references! Hopefully people are finding the extension if they need it and we can also update rst2pdf some time to handle more sphinx-specific features

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants