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

wrong html with label before section #1961

Open
sehmaschine opened this issue Jul 17, 2015 · 17 comments
Open

wrong html with label before section #1961

sehmaschine opened this issue Jul 17, 2015 · 17 comments

Comments

@sehmaschine
Copy link

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>
@birkenfeld
Copy link
Member

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?

@shimizukawa
Copy link
Member

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

@sehmaschine
Copy link
Author

@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.

@shimizukawa
Copy link
Member

@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).

@kkzhang
Copy link

kkzhang commented Aug 5, 2015

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.

@tk0miya
Copy link
Member

tk0miya commented Jan 17, 2021

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.

@mhsmith
Copy link

mhsmith commented Feb 28, 2021

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.

@GeeTransit
Copy link

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/

@mhsmith
Copy link

mhsmith commented Apr 16, 2022

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

@GeeTransit
Copy link

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.

@AA-Turner AA-Turner added this to the some future version milestone Sep 29, 2022
@rymiel
Copy link

rymiel commented Nov 21, 2022

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 added a commit to llvm/llvm-project that referenced this issue Jan 12, 2023
This allows for the creation of permalinks to specific clang-format
options, for better sharing of a specific option and its options.

(I'm adding the usual clang-format reviewers on this patch because
I don't know any other reviewers that well, perhaps someone with
docs experience should be added instead...)

Note that I wanted to make minimal changes to make this happen and thus
landed on an unideal setup, but to me, it seems like the best out of
worse ones.

I could have made every style option a subheading, which would add
automatically the logic for permalinks and the little paragraph icon for
sharing.

However, this meant that the links themselves would be suboptimal, as
they'd include the whole text of the heading, including the type and
versionbadge, which is needless noise and could change, breaking the
concept of a "permalink". The format of the page could be changed to
put the option names on their own in a heading, and the other info below
it in a paragraph.

As Sphinx seems unwilling to fix sphinx-doc/sphinx#1961,
there isn't a succinct way to change the "id" html field used for
sections

I could have used an add-on (https://github.com/GeeTransit/sphinx-better-subsection),
or made one myself, but I wanted to avoid extra dependencies for no
reason. (plus, I don't know how to make one myself.)

I could have used raw HTML for each heading, but that would immensely
pollute the rst file, which, while it is generated, is currently still
human-readable and it'd be nice for it to stay that way.

Also note that sphinx treats references as case-insensitive, which means
that they will all be lowercased in the resulting HTML. I envisioned
the ability to simply add #OptionName after the URL to get placed right
at the desired config option, which isn't possible without things such
as inline `raw` HTML.

To reconcile that, I added the ¶ paragraph buttons that can be used to
generate the link to the desired section, but since headings are not
actually used, they are faked and literally just a link following each
option, which means they stylistically don't match all other headings.

Also note that this sort-of assumes HTML output. I know Sphinx can
output other formats but I do not know if they are used. A non-html
output could embed unusable ¶ signs everywhere.

I'm okay with this patch being rejected in its current solution, or if
any of the above listed alternatives are better, they could be pursued
instead. In case the downsides of this solution are too much, I will
just create a feature request issue for this and maybe let someone more
experienced with Sphinx handle it, since this is still a feature I would
like to have. (and I do not want to deal with Sphinx at all after
battling with it for a whole day to produce a mediocre result.)

Reviewed By: HazardyKnusperkeks, owenpan, MyDeveloperDay, aaron.ballman

Differential Revision: https://reviews.llvm.org/D138446
CarlosAlbertoEnciso pushed a commit to SNSystems/llvm-debuginfo-analyzer that referenced this issue Jan 13, 2023
This allows for the creation of permalinks to specific clang-format
options, for better sharing of a specific option and its options.

(I'm adding the usual clang-format reviewers on this patch because
I don't know any other reviewers that well, perhaps someone with
docs experience should be added instead...)

Note that I wanted to make minimal changes to make this happen and thus
landed on an unideal setup, but to me, it seems like the best out of
worse ones.

I could have made every style option a subheading, which would add
automatically the logic for permalinks and the little paragraph icon for
sharing.

However, this meant that the links themselves would be suboptimal, as
they'd include the whole text of the heading, including the type and
versionbadge, which is needless noise and could change, breaking the
concept of a "permalink". The format of the page could be changed to
put the option names on their own in a heading, and the other info below
it in a paragraph.

As Sphinx seems unwilling to fix sphinx-doc/sphinx#1961,
there isn't a succinct way to change the "id" html field used for
sections

I could have used an add-on (https://github.com/GeeTransit/sphinx-better-subsection),
or made one myself, but I wanted to avoid extra dependencies for no
reason. (plus, I don't know how to make one myself.)

I could have used raw HTML for each heading, but that would immensely
pollute the rst file, which, while it is generated, is currently still
human-readable and it'd be nice for it to stay that way.

Also note that sphinx treats references as case-insensitive, which means
that they will all be lowercased in the resulting HTML. I envisioned
the ability to simply add #OptionName after the URL to get placed right
at the desired config option, which isn't possible without things such
as inline `raw` HTML.

To reconcile that, I added the ¶ paragraph buttons that can be used to
generate the link to the desired section, but since headings are not
actually used, they are faked and literally just a link following each
option, which means they stylistically don't match all other headings.

Also note that this sort-of assumes HTML output. I know Sphinx can
output other formats but I do not know if they are used. A non-html
output could embed unusable ¶ signs everywhere.

I'm okay with this patch being rejected in its current solution, or if
any of the above listed alternatives are better, they could be pursued
instead. In case the downsides of this solution are too much, I will
just create a feature request issue for this and maybe let someone more
experienced with Sphinx handle it, since this is still a feature I would
like to have. (and I do not want to deal with Sphinx at all after
battling with it for a whole day to produce a mediocre result.)

Reviewed By: HazardyKnusperkeks, owenpan, MyDeveloperDay, aaron.ballman

Differential Revision: https://reviews.llvm.org/D138446
tsibley referenced this issue in nextstrain/docs.nextstrain.org Jul 25, 2023
This is consistent with the existing documentation style guide and a
similar Snakemake style guide¹ written by @tsibley.

This also allows for the addition of a table of contents, which is done
here.

I looked into making the section links future-proof to wording changes,
however could not find a good solution. The closest is using :ref: roles
which adds separately defined links to to the section titles, but those
links aren't used by the TOC or header links themselves.

¹ https://github.com/blab/styleguide/blob/6aa5d7aa42acfa97e57a5ee05a4175f158502cac/nextstrain-builds.md
@picnixz
Copy link
Member

picnixz commented Mar 17, 2024

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.

@mhsmith
Copy link

mhsmith commented Mar 17, 2024

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.

@picnixz
Copy link
Member

picnixz commented Mar 17, 2024

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 picnixz reopened this Mar 17, 2024
@mhsmith
Copy link

mhsmith commented Mar 17, 2024

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.

@sebhub
Copy link
Contributor

sebhub commented Jun 6, 2024

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
Copy link
Contributor

sebhub commented Jun 6, 2024

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

veselypeta pushed a commit to veselypeta/cherillvm that referenced this issue Jun 12, 2024
This allows for the creation of permalinks to specific clang-format
options, for better sharing of a specific option and its options.

(I'm adding the usual clang-format reviewers on this patch because
I don't know any other reviewers that well, perhaps someone with
docs experience should be added instead...)

Note that I wanted to make minimal changes to make this happen and thus
landed on an unideal setup, but to me, it seems like the best out of
worse ones.

I could have made every style option a subheading, which would add
automatically the logic for permalinks and the little paragraph icon for
sharing.

However, this meant that the links themselves would be suboptimal, as
they'd include the whole text of the heading, including the type and
versionbadge, which is needless noise and could change, breaking the
concept of a "permalink". The format of the page could be changed to
put the option names on their own in a heading, and the other info below
it in a paragraph.

As Sphinx seems unwilling to fix sphinx-doc/sphinx#1961,
there isn't a succinct way to change the "id" html field used for
sections

I could have used an add-on (https://github.com/GeeTransit/sphinx-better-subsection),
or made one myself, but I wanted to avoid extra dependencies for no
reason. (plus, I don't know how to make one myself.)

I could have used raw HTML for each heading, but that would immensely
pollute the rst file, which, while it is generated, is currently still
human-readable and it'd be nice for it to stay that way.

Also note that sphinx treats references as case-insensitive, which means
that they will all be lowercased in the resulting HTML. I envisioned
the ability to simply add #OptionName after the URL to get placed right
at the desired config option, which isn't possible without things such
as inline `raw` HTML.

To reconcile that, I added the ¶ paragraph buttons that can be used to
generate the link to the desired section, but since headings are not
actually used, they are faked and literally just a link following each
option, which means they stylistically don't match all other headings.

Also note that this sort-of assumes HTML output. I know Sphinx can
output other formats but I do not know if they are used. A non-html
output could embed unusable ¶ signs everywhere.

I'm okay with this patch being rejected in its current solution, or if
any of the above listed alternatives are better, they could be pursued
instead. In case the downsides of this solution are too much, I will
just create a feature request issue for this and maybe let someone more
experienced with Sphinx handle it, since this is still a feature I would
like to have. (and I do not want to deal with Sphinx at all after
battling with it for a whole day to produce a mediocre result.)

Reviewed By: HazardyKnusperkeks, owenpan, MyDeveloperDay, aaron.ballman

Differential Revision: https://reviews.llvm.org/D138446
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests