Specifying anchor names in reST
Asked Answered
A

3

15

I'm creating HTML from reST using the rst2html tool which comes with docutils. It seems that the code already assigns id attributes to the individual sections, which can be used as fragment identifiers in a URL, i.e. as anchors to jump to a specific part of the page. Those id values are based on the text of the section headline. When I change the wording of that headline, the identifier will change as well, rendering old URLs invalid.

Is there a way to specify the name to use as an identifier for a given section, so that I can edit the headline without invalidating links? Would there be a way if I were to call the docutils publisher myself, from my own script?

Astigmatic answered 30/11, 2012 at 8:39 Comment(0)
G
3

I don't think you can set an explicit id in reST sections, but I could be mistaken.

If you'd rather have numbered ids, which will depend on the ordering of the sections in the document tree, rather than their titles, you can do it with a small change to document.set_id() method in docutils/nodes.py (at line 997 on my version.)

Here is the patch:

 def set_id(self, node, msgnode=None):
     for id in node['ids']:
         if id in self.ids and self.ids[id] is not node:
             msg = self.reporter.severe('Duplicate ID: "%s".' % id)
             if msgnode != None:
                 msgnode += msg
     if not node['ids']:
-        for name in node['names']:
-            id = self.settings.id_prefix + make_id(name)
-            if id and id not in self.ids:
-                break
-        else:
+        if True: #forcing numeric ids
             id = ''
             while not id or id in self.ids:
                 id = (self.settings.id_prefix +
                       self.settings.auto_id_prefix + str(self.id_start))
                 self.id_start += 1
         node['ids'].append(id)
     self.ids[id] = node
     return id

I just tested it and it generates the section ids as id1, id2...

If you don't want to change this system-wide file, you can probably monkey-patch it from a custom rst2html command.

Gouda answered 14/3, 2013 at 14:2 Comment(3)
numeric IDs aren't that much better in my case, but monkey-patching that function was still a useful suggestion: I can extract a rather stable ID from my section title. Works well for my current application. I'll leave the bounty open in case someone has some more elegant suggestion, but if not it's yours.Astigmatic
Default ids depend on the section titles, and not their position. Numeric ids depend on their position, and not on their title. I don't think there is a third way, in general, unless you come up with some kind of custom code, which depends on the way you name your sections.Gouda
While you cannot set an id, you can set a "reference name" for (almost) any rST element. Docutils will use this as base for an id employing the same rules a for the auto-generated section ids, so keeping an old anchor valid is simple.Moriyama
R
4

I'm not sure if I really understand your question.

You can create explicit hyperlink targets to arbitrary locations in your document which can be used to reference these locations independent of the implicit hyperlink targets created by docutils:

.. _my_rstfile:

------------------
This is my rstfile
------------------

.. _a-section:

First Chapter
-------------

This a link to a-section_ which is located in my_rstfile_.

As it seems that you want to create links between multiple rst files I would however advise to use Sphinx as it can handle references to arbitrary locations between different files and has some more advantages, like a toctree and theming. You can use sphinx not only for source code documentation, but for general text processing. Something like an example is the Sphinx documentation itself (there are hundreds of other examples on readthedocs).

Invoking Sphinx should be simple using sphinx-quickstart. You can simply add your exiting rst-files to the toctree in index.rst and run make html. If you want to document python code you can use sphinx-apidoc which will automatically generate an API documentation.

Rossi answered 17/3, 2013 at 11:8 Comment(10)
The problem with this kind of explicit hyperlink target is that the links from the auto-generated table of content won't be using these. So if someone selects a TOC item and then copies the resulting URL, the fragment identifier in that URL might become invalid later on. But it would be a possibility, at least for links from external documents. And I'll have a closer look at Sphinx.Astigmatic
So I think sphinx would be the best option, as it is designed for that. I slightly updated my answer.Rossi
For this specific task, using Sphinx with html and singlehtml builds looks very promising, although I still have to rewrite my documents to make that work, so I can't yet tell how satisfied I will be with the results. I still would like to know about tweaking basic rst2html into using custom anchors. Which means I might end up using Sphinx as you suggested, and still granting the bounty to Tobia, as his answer more closely matches my question. Hope you don't mind too much.Astigmatic
To be honest: I don't think, that referencing to numbered sections is a good way, as you will possibly change the ordering afterwards. You wouldn't do that in latex for instance. So I think that my solution matches your question better: explicit hyperlink targets are a better option. Sphinx is still a better option as it handles some things automatically and is designed for this purpose. Further more, I don't think that you have to rewrite your documents, they should work as they are (the opposite doesn't work in all cases: sphinx introduces some more roles, that docutils doesn't know).Rossi
OK, I simply dropped my one existing document into the index.rst created by quickstart. The resulting anchors for the individual sections, as used by the auto-generated TOC, are again formed from the section titles, not from the explicit link targets preceeding these titles. Only the document as a whole has an anchor formed from the file name. So for this to be useful, I'll have to split my documentation into one file per function. Then it might work, although I'd like to find some way to omit this document- prefix in the singlehtml build.Astigmatic
It is perfectly fine if the links are generated from the section titles: if you have multiple documents sphinx will generate labels and links for the sections in every document. If your are trying to document python functions, you could even use sphinx-apidoc which automatically generates an api documentation, however I don't really know your usecase.Rossi
Note that the whole document structure is generated at once, so all references are correctly resolved, even if you change document names or section titles.Rossi
I'm documenting functions which some Java code provides for a application-specific scripting language, so no native python involved. I maintain the project started by someone else, and the documentation came as rst, so I'd like to keep it that way. But anchors generated from titles will fail to remain constant under title changes. With sphinx there is even a nice rollover ¶ to create permalinks, so the chances of users bookmarking these are even more increased.Astigmatic
let us continue this discussion in chatRossi
The explicit target is attached to the section element in addition to the automatically generated one. This means that by preceding an edited section title with .. _the old section title: links with the "old" fragment indicator will continue to work.Moriyama
G
3

I don't think you can set an explicit id in reST sections, but I could be mistaken.

If you'd rather have numbered ids, which will depend on the ordering of the sections in the document tree, rather than their titles, you can do it with a small change to document.set_id() method in docutils/nodes.py (at line 997 on my version.)

Here is the patch:

 def set_id(self, node, msgnode=None):
     for id in node['ids']:
         if id in self.ids and self.ids[id] is not node:
             msg = self.reporter.severe('Duplicate ID: "%s".' % id)
             if msgnode != None:
                 msgnode += msg
     if not node['ids']:
-        for name in node['names']:
-            id = self.settings.id_prefix + make_id(name)
-            if id and id not in self.ids:
-                break
-        else:
+        if True: #forcing numeric ids
             id = ''
             while not id or id in self.ids:
                 id = (self.settings.id_prefix +
                       self.settings.auto_id_prefix + str(self.id_start))
                 self.id_start += 1
         node['ids'].append(id)
     self.ids[id] = node
     return id

I just tested it and it generates the section ids as id1, id2...

If you don't want to change this system-wide file, you can probably monkey-patch it from a custom rst2html command.

Gouda answered 14/3, 2013 at 14:2 Comment(3)
numeric IDs aren't that much better in my case, but monkey-patching that function was still a useful suggestion: I can extract a rather stable ID from my section title. Works well for my current application. I'll leave the bounty open in case someone has some more elegant suggestion, but if not it's yours.Astigmatic
Default ids depend on the section titles, and not their position. Numeric ids depend on their position, and not on their title. I don't think there is a third way, in general, unless you come up with some kind of custom code, which depends on the way you name your sections.Gouda
While you cannot set an id, you can set a "reference name" for (almost) any rST element. Docutils will use this as base for an id employing the same rules a for the auto-generated section ids, so keeping an old anchor valid is simple.Moriyama
B
2

I made a Sphinx extension to solve this problem. The extension takes the preceding internal target and uses that as the section's ID. Example (from bmu's answer):

.. _a-section:

First Chapter
-------------

The permalink on "First Chapter" would point to #a-section instead of #first-chapter. If there's multiple, it'll take the last one.

Link to the extension: https://github.com/GeeTransit/sphinx-better-subsection

Buchheim answered 15/4, 2022 at 23:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.