Anchor validation false positives after upgrading to 1.6
First of all, thanks for the very useful new anchor validation feature! Upgrading to MkDocs 1.6, I was able to fix many stale anchors in our documentation. However, in the process, I came across a few false positives – the anchors are correct, but MkDocs reports them nonetheless. This is particularly the case when using the Tabbed extension with combine_header_slug, which allows to prepend the slug of the nearest header to the tab.
I believe this needs to be fixed in MkDocs, since it might be some kind of ordering issue when running anchor validation, but I'm tagging @facelessuser here for visibility. By using the Tabbed extension, anchor links to tabs are much more readable, something that many users asked for on the Material for MkDocs issue tracker.
Example
The following example is used for illustration. You can also download it here: anchor-validation-bug.zip
index.md
# Page with tabs
## Headline
=== "Tab A"
Anchor for this tab is `#headline-tab-a`
=== "Tab B"
Anchor for this tab is `#headline-tab-b`
foo.md
# Links to tabs
- [Tab A](index.md#headline-tab-a)
- [Tab B](index.md#headline-tab-b)
MkDocs will not detect those links and report them as non-existent:
INFO - Cleaning site directory
INFO - Doc file 'foo.md' contains a link 'index.md#headline-tab-a', but the doc 'index.md' does not contain an anchor '#headline-tab-a'.
INFO - Doc file 'foo.md' contains a link 'index.md#headline-tab-b', but the doc 'index.md' does not contain an anchor '#headline-tab-b'.
INFO - Documentation built in 0.12 seconds
When running the example, it's easy to see that anchor are correct and work as expected.
pymdownx Tabbed seems to register its treeprocessor updating anchors (slugs) with priority 4.
https://github.com/facelessuser/pymdown-extensions/blob/c8856a3bca3840b538ae3d03298a7d6ecf279541/pymdownx/tabbed.py#L416
...while MkDocs registers its treeprocessor reading anchors with priority 5.
https://github.com/mkdocs/mkdocs/blob/fb1d106747930b094bc464189d4b1c349fc541c6/mkdocs/structure/pages.py#L343
It means MkDocs gets anchors before Tabbed had a chance to update them. To fix this, either Tabbed should increase its treeprocessor priority, or MkDocs should lower its own (or both). The MkDocs priority has to be strictly lower than pymdownx's.
Same has happend to me while using Caption Block Pymdown Extension
- https://github.com/facelessuser/pymdown-extensions/issues/2529
It means MkDocs gets anchors before Tabbed had a chance to update them. To fix this, either Tabbed should increase its treeprocessor priority, or MkDocs should lower its own (or both). The MkDocs priority has to be strictly lower than pymdownx's.
I just saw this. MkDocs, if they are going to validate anchors, needs to ensure they check as late as possible. There may be reasons a plugin requires to do things later. If MkDocs wants to be reliable, they should plan for worst case. I will have to check if there is an explicit reason I chose the priority I did. But if I can do earlier, its a small thing I can do.
But keep in mind, Markdown extensions don't care about MkDocs, or better put, they may not be designed with MkDocs in mind, MkDocs should be defensive of this and hold off as long as they can. MkDocs is not the only consumer of Python Markdown, and many users may not be aware of or use MkDocs.
It looks like Tabs is taking extra effort to produce unique IDs after Toc has resolved its unique IDs, that's why we chose what we did. This is precisely why MkDocs should wait until as late as possible. I think this is indeed an MkDocs issue. Caption does not take the same pains (not currently at least) to produce unique IDs, but it may in the future.
Thanks @facelessuser! Sounds good, I note this should be fixed in MkDocs directly :slightly_smiling_face:
To clarify in case there is any debate on this point, when we introduced IDs in Tabs being created from titles, there was a risk of duplicate IDs, and additionally, duplicate IDs with existing headers.
If we chose a priority before Toc, when someone adds Tabbed, to an existing project, we increase the chance that existing header IDs may change due to a Tab creating an ID before Toc does, then Toc must de-duplicate their ID. The choice was made that Tab IDs would be lower priority. This means Tab would allow Toc to keep whatever titles it resolves, and we would de-duplicate ours. We felt this is less hostile to users.
@squidfunk, would this same fix address the anchor validation false positives I'm getting on links to a code selection? I was about to raise an issue over on your github, but if it's the same fix, I'll just follow this issue.
@feasgal only if you select single lines, and not multiple lines. Multi-line selection requires JavaScript (GitHub does the same on their code blocks) to resolve to the starting and ending anchors. Example:
- https://squidfunk.github.io/mkdocs-material/reference/code-blocks/#__codelineno-4-2 (single, actual anchor)
- https://squidfunk.github.io/mkdocs-material/reference/code-blocks/#__codelineno-4-2:3 (multi, not a real anchor)
I think it's a good idea to discuss whether MkDocs should allow to ignore some anchors during validation, i.e., those that are generated and consumed in JavaScript. For Material or MkDocs, it's only code selection, but there might be other themes impacted.
Edit: Before we consider this a downstream issue for Material for MkDocs, it would be good to learn whether the maintainers here think that this should be fixed in MkDocs or not. Material for MkDocs itself cannot add validation settings, as it's only a theme, but we could somehow try to patch around the behavior of MkDocs as we did several times in the past years. Nonetheless, I'm not a fan of adding more and more hacks, so IMHO, at least discussing potential ways to fix this in MkDocs would be the right thing to do.
@squidfunk @feasgal I'm personally not opposed to this kind of enhancements, but am not the one taking the decisions 😊
I'm just not sure to understand exactly when/how the anchors you mention are generated/used and how MkDocs would deal with that. If interested, someone should open an issue with a clear reproduction of the problem 🙂
The original issue here is pretty clear and we know what must be fixed (the tree processor priority).
@pawamoy You're right, this should probably be handled as a separate issue. However, I thought it might be useful to start a discussion first, whether this would actually be considered an issue with MkDocs, or if we need to work around it.