sphinx icon indicating copy to clipboard operation
sphinx copied to clipboard

wrong html with label before section

Open sehmaschine opened this issue 10 years ago • 17 comments

The HTML which is produced with labels before section is quite arbitrary. It sometimes works, but most of the time it doesn't.

Here's an example:

.. _attachments-fields:

Felder
++++++

This should lead to:

<div class="section" id="attachments-fields">
    <span id="id2"></span>
    <h3>Felder
        <a class="headerlink" href="#attachments-fields" title="Permalink to this headline">¶</a>
    </h3>

But it actually produces this:

<div class="section" id="felder">
    <span id="attachments-fields"></span>
    <h3>Felder
        <a class="headerlink" href="#felder" title="Permalink to this headline">¶</a>
    </h3>

sehmaschine avatar Jul 17 '15 08:07 sehmaschine

I guess it is a little random which of the several IDs gets assigned as "id", and which is used as supplementary "id"s.

Is there a concrete problem with this behavior?

birkenfeld avatar Jul 24 '15 13:07 birkenfeld

Sphinx (docutils) uses label as a id preferentially if the label is provided. In that sense, it's stable I think.

shimizukawa avatar Jul 24 '15 13:07 shimizukawa

@shimizukawa When you look at the example above, I think it's not quite true that the label is being used. That's exactly the problem. @birkenfeld The main problem is that it's hard to reference the anchor. Sometimes it's the label, sometimes the section ID. It's completely arbitrary.

sehmaschine avatar Jul 29 '15 07:07 sehmaschine

@sehmaschine you are right. I retract my word.

I tried rst2html docutils command and it generates same output. In my investigation, it seems that it's a specification of docutils. docutils uses such label as a reference target instead of implicit target. OTOH, docutils marks section title as a implicit target.

IMO, we shouldn't change the rule from sphinx side.

memo:

http://repo.or.cz/w/docutils.git/blob/HEAD:/docutils/docutils/parsers/rst/states.py#l389

 375     def new_subsection(self, title, lineno, messages):
 ...
 389         self.document.note_implicit_target(section_node, section_node)

note_implicit_target makes id from section title

http://repo.or.cz/w/docutils.git/blob/HEAD:/docutils/docutils/parsers/rst/states.py#l1923

1917     def make_target(self, block, block_text, lineno, target_name):
...
1923             self.document.note_indirect_target(target)

make_target is called from hyperlink_target (=label).

shimizukawa avatar Aug 01 '15 17:08 shimizukawa

I stil think it is a bug. I cann't explict set label name under some condition, it's rediculous. In my case, i want to generate a page for FAQ, which is full of Q&A, each of it should have a anchor to be referenced.

kkzhang avatar Aug 05 '15 08:08 kkzhang

It seems you can refer the anchor point with #attachments-fields URI-fragment. Do you mind about the URI-fragment of permalink <a class="headerlink" href="#felder" title="Permalink to this headline">¶</a>?

Internally, section titles can have multiple node IDs. The first one is generated from its title ("Felder" -> felder). Remainings come from the user-defined labels. The HTML writer of Sphinx generates the permalink from the first one of the section title.

I understand you'd like to use an user-defined label to its permalink. But I wonder how we should do when users gives multiple labels to the section title:

.. _foo:
.. _bar:
.. _baz:

folder
++++++

So I vote -1 for changing this behavior.

tk0miya avatar Jan 17 '21 10:01 tk0miya

For internal links within my documentation, I can link to a section using :ref:, as recommended in Sphinx's own documentation:

Using ref is advised over standard reStructuredText links to sections (like `Section title`_) because it works [...] when section headings are changed

But if someone copies the "permalink" from the section header, that link will break as soon as I reword the header. On an FAQ page with one section per question, that might happen quite often. Apparently the "permalink" isn't so permanent after all.

If I'm the one sharing the link, then I can work around this by sharing a link to the hidden label anchor, even if I have to look in the HTML or RST source to find it. But what about my users sharing links with each other?

I understand you'd like to use an user-defined label to its permalink. But I wonder how we should do when users gives multiple labels to the section title:

In that case, all the labels are at the same point in the document, so they're functionally equivalent, and all of them are more permanent than the section title. Would there be any downside to Sphinx just using the first one?

As well as the "permalink" links in the section headers, this would also apply to section links from tables of contents and sidebars.

mhsmith avatar Feb 28 '21 20:02 mhsmith

For anyone stumbling on this issue, I created a Sphinx extension that checks for targets preceding section headers and uses them as the section ID.

With this input:

.. _attachments-fields:

Felder
++++++

The following HTML is produced:

<section id="attachments-fields">
    <span id="felder"></span>
    <h3>Felder
        <a class="headerlink" href="#attachments-fields"
            title="Permalink to this headline">
            ¶
        </a>
    </h3>
</section>

The permalink is the one manually specified (#attachment-fields), not the one generated from the title (#felder).

When multiple targets exists, the last one is used (easier to remember + simpler implementation).

This change is backward compatible too. :ref:`attachments-fields` points to the section header and so does Felder_. Old permalinks also work (because the #felder element still exists). If the section ID happens to be id2 or similar, it'll still have id2 because the extension reorders the section's IDs after they're generated.

Extension: https://github.com/GeeTransit/sphinx-better-subsection See it in action: https://geetransit.github.io/sphinx-better-subsection/_generated/CHANGELOG/

GeeTransit avatar Apr 16 '22 00:04 GeeTransit

@GeeTransit Thanks, this is great! But still think this should be fixed in Sphinx itself.

mhsmith avatar Apr 16 '22 20:04 mhsmith

I also agree that Sphinx should use the target for the permalink. It's a bit weird that :ref:`attachment-fields` is more permanent than the permalink. For now, I'm fine with using an extension to patch this behaviour.

I'm happy to create a pull request that adds the extension's PreferSectionTarget transformer into sphinx/transforms/__init__.py though.

GeeTransit avatar Apr 17 '22 06:04 GeeTransit

Note that this can almost be worked around by forcing sphinx to use the provided id by literally stealing the one it would otherwise use.

.. _felder:
.. _attachments-fields:

Felder
++++++
<div class="section" id="attachments-fields">
  <span id="felder"></span>
  <span id="id1"></span>
  <h1>Felder<a class="headerlink" href="#attachments-fields" title="Permalink to this headline">¶</a></h1>
</div>

This is even worse of a hack. Please remove the wontfix tag, it is clearly demonstrated above that it can be fixed, but needing to use an addon is a severe deficiency of Sphinx itself.

rymiel avatar Nov 21 '22 15:11 rymiel

I'm not sure when a patch landed but it appears that we now generate something like

<section id="felder">
	<span id="attachments-fields"></span>
	<h1>Felder<a class="headerlink" href="#felder" title="Link to this heading"></a></h1>
</section>

With multiple IDs, IIRC we stack them on top of each other and re-order them in reverse order:


.. id-inner:
.. id-outer:

Title
=====

produces

<section id="title">
	<span id="id-outer"></span>
	<span id="id-inner"></span>
	<h1>Title<a class="headerlink" href="#title" title="Link to this heading">¶</a></h1>
</section>

Now, having href=title is fine to me because it is reflected on the browser side (and you don't have an obscure 'id-outer' or 'id-inner' when you click on 'Title'). You can still use the internal IDs (that are somewhat more permamant than a title) in another RST document and it is possible to still use the URI fragment of any of the span's ids (though you won't land properly on the exact title tag but in some phantom span).

So I think this issue is "solved" though not as it was done in the proposed extension. I'm closing it now but feel free to argue or open a new issue if you want to suggest a better alternative (I'm inclined to keep the current behaviour which appears to solve the original issue).

's a bit weird that :ref:attachment-fields is more permanent than the permalink

For me it's fine to be more permalink because it can be used by intersphinx. You don't really want to update your docs everytime the external project changes a title, but it's an other issue about finding the correct ID to use though.

picnixz avatar Mar 17 '24 10:03 picnixz

I've explained the problem with the current behavior in my previous comment. The reader of the document is being told that something is a "permalink", when in fact it will break the moment the section title changes in any way. It isn't reasonable to expect them to look in the HTML source to find an actually-permanent span ID, nor will it occur to them to do so.

mhsmith avatar Mar 17 '24 12:03 mhsmith

Actually, we don't call it a "permalink" anymore so we don't really lie to the reader anymore (I think this was changed last year or so). Now, even if we do have a "permalink", the issue remains that once you change the ID, you also change the ID that is being used so, unless you really generate a true permalink (which is independent of both the title and the possible ids being added), there is nothing we can really do =/

Now, anyone is free to make a PR that would solve both issues and where the ID wouldn't change if for instance you add an ID before or after the one you originally used (or if an extension adds an ID using a transformation/post-transformation).

picnixz avatar Mar 17 '24 12:03 picnixz

Thanks: I think in most cases there would only be one ID, and it won't ever change (at least not as often as the title), so in that case it would make sense to use it as the user-visible anchor.

mhsmith avatar Mar 17 '24 13:03 mhsmith

I was also surprised by the current anchor selection. Sometimes it used the title sometimes the label. This is not really helpful. From my point of view it should pick the label right above the section title.

sebhub avatar Jun 06 '24 07:06 sebhub

I can confirm, that the sphinx-better-subsection extension does exactly what I would have expected as the default behaviour from Sphinx.

sebhub avatar Jun 06 '24 07:06 sebhub

This is a duplicate of #1703.

gmilde avatar Jun 26 '25 19:06 gmilde

So it is, but it might be better to close #1703 and leave this issue open, because this issue contains much more detailed discussion, and a workaround.

mhsmith avatar Jun 27 '25 11:06 mhsmith

Yet another problem with this behaviour is that with non-Latin headers, ids are just "section-N", which obviously breaks from simply adding a subsection anywhere but at the end of a document. Labelling sections would be the way to fix that, but...

Also, section labels seem to be ignored by contents directive (and likely toctree as well), but it's likely docutils issue ;(

skrattaren avatar Jun 27 '25 11:06 skrattaren

So it is, but it might be better to close #1703 and leave this issue open, because this issue contains much more detailed discussion, and a workaround.

Agreed. However, #1703 has the better title.

gmilde avatar Jun 27 '25 22:06 gmilde