Skip to content

Commit 61e709c

Browse files
matthias314mortenpi
authored andcommitted
Fix broken PDF links (#1909)
(cherry picked from commit f72552a)
1 parent 5238e5b commit 61e709c

File tree

4 files changed

+30
-15
lines changed

4 files changed

+30
-15
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* ![Enhancement][badge-enhancement] The `native` and `docker` PDF builds now run with the `-interaction=batchmode` (instead of `nonstopmode`) and `-halt-on-error` options to make the LaTeX error logs more readable and to fail the build early. ([#1908][github-1908])
66
* ![Bugfix][badge-bugfix] The PDF/LaTeX output now handles hard Markdown line breaks (i.e. `Markdown.LineBreak` nodes). ([#1908][github-1908])
7+
* ![Bugfix][badge-bugfix] Previously broken links within the PDF output are now fixed. ([JuliaLang/julia#38054][julia-38054], [JuliaLang/julia#43652][julia-43652], [#1909][github-1909])
78

89
## Version `v0.27.22`
910

@@ -1092,10 +1093,13 @@
10921093
[github-1885]: https://github.com/JuliaDocs/Documenter.jl/issues/1885
10931094
[github-1886]: https://github.com/JuliaDocs/Documenter.jl/pull/1886
10941095
[github-1908]: https://github.com/JuliaDocs/Documenter.jl/pull/1908
1096+
[github-1909]: https://github.com/JuliaDocs/Documenter.jl/pull/1909
10951097
<!-- end of issue link definitions -->
10961098

1099+
[julia-38054]: https://github.com/JuliaLang/julia/issues/38054
10971100
[julia-38079]: https://github.com/JuliaLang/julia/issues/38079
10981101
[julia-39841]: https://github.com/JuliaLang/julia/pull/39841
1102+
[julia-43652]: https://github.com/JuliaLang/julia/issues/43652
10991103
[julia-45174]: https://github.com/JuliaLang/julia/issues/45174
11001104
[julialangorg-1272]: https://github.com/JuliaLang/www.julialang.org/issues/1272
11011105

assets/latex/documenter.sty

+6
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,9 @@
8585
\usepackage{graphicx}
8686
\usepackage[export]{adjustbox}
8787
%
88+
89+
% Some internal link targets are implemented with \label, some with \hypertarget,
90+
% but they require different links. This inserts a \hyperref if a corresponding label exists,
91+
% and \hyperlink if it doesn't.
92+
\def\hyperlinkref#1#2{\@ifundefined{r@#1}{\hyperlink{#1}{#2}}{\hyperref[#1]{#2}}}
93+
%

src/Anchors.jl

+6-4
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,16 @@ function anchor(m::AnchorMap, id, file, n)
124124
nothing
125125
end
126126

127+
"""
128+
Create a label from an anchor.
129+
"""
130+
label(a::Anchor) = (a.nth == 1) ? a.id : string(a.id, "-", a.nth)
131+
127132
"""
128133
Create an HTML fragment from an anchor.
129134
"""
130135
function fragment(a::Anchor)
131-
frag = string("#", a.id)
132-
if a.nth > 1
133-
frag = string(frag, "-", a.nth)
134-
end
136+
frag = string("#", label(a))
135137
# TODO: Sanitize the fragment
136138
return frag
137139
end

src/Writers/LaTeXWriter.jl

+14-11
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ Context(io) = Context{typeof(io)}(io, false, Dict(), 1, "")
8585
_print(c::Context, args...) = Base.print(c.io, args...)
8686
_println(c::Context, args...) = Base.println(c.io, args...)
8787

88+
# Labels in the TeX file are hashes of plain text labels.
89+
# To keep the plain text label (for debugging), say _hash(x) = x
90+
_hash(x) = string(hash(x))
91+
8892

8993
const STYLE = joinpath(dirname(@__FILE__), "..", "..", "assets", "latex", "documenter.sty")
9094
const DEFAULT_PREAMBLE_PATH = joinpath(dirname(@__FILE__), "..", "..", "assets", "latex", "preamble.tex")
@@ -282,9 +286,9 @@ function latex(io::IO, vec::Vector, page, doc)
282286
end
283287

284288
function latex(io::IO, anchor::Anchors.Anchor, page, doc)
285-
id = string(hash(string(anchor.id, "-", anchor.nth)))
286-
_println(io, "\n\\hypertarget{", id, "}{}\n")
289+
id = _hash(Anchors.label(anchor))
287290
latex(io, anchor.object, page, doc)
291+
_println(io, "\n\\label{", id, "}{}\n")
288292
end
289293

290294

@@ -297,10 +301,9 @@ function latex(io::IO, node::Documents.DocsNodes, page, doc)
297301
end
298302

299303
function latex(io::IO, node::Documents.DocsNode, page, doc)
300-
id = string(hash(string(node.anchor.id)))
304+
id = _hash(Anchors.label(node.anchor))
301305
# Docstring header based on the name of the binding and it's category.
302-
_println(io, "\\hypertarget{", id, "}{} ")
303-
_print(io, "\\hyperlink{", id, "}{\\texttt{")
306+
_print(io, "\\hypertarget{", id, "}{\\texttt{")
304307
latexesc(io, string(node.object.binding))
305308
_print(io, "}} ")
306309
_println(io, " -- {", Utilities.doccat(node.object), ".}\n")
@@ -346,9 +349,9 @@ function latex(io::IO, index::Documents.IndexNode, page, doc)
346349

347350
_println(io, "\\begin{itemize}")
348351
for (object, _, page, mod, cat) in index.elements
349-
id = string(hash(string(Utilities.slugify(object))))
352+
id = _hash(string(Utilities.slugify(object)))
350353
text = string(object.binding)
351-
_print(io, "\\item \\hyperlink{")
354+
_print(io, "\\item \\hyperlinkref{")
352355
_print(io, id, "}{\\texttt{")
353356
latexesc(io, text)
354357
_println(io, "}}")
@@ -366,7 +369,6 @@ function latex(io::IO, contents::Documents.ContentsNode, page, doc)
366369
for (count, path, anchor) in contents.elements
367370
header = anchor.object
368371
level = Utilities.header_level(header)
369-
id = string(hash(string(anchor.id, "-", anchor.nth)))
370372
# If we're changing depth, we need to make sure we always print the
371373
# correct number of \begin{itemize} and \end{itemize} statements.
372374
if level > depth
@@ -384,7 +386,8 @@ function latex(io::IO, contents::Documents.ContentsNode, page, doc)
384386
end
385387
end
386388
# Print the corresponding \item statement
387-
_print(io, "\\item \\hyperlink{", id, "}{")
389+
id = _hash(Anchors.label(anchor))
390+
_print(io, "\\item \\hyperlinkref{", id, "}{")
388391
latexinline(io, header.text)
389392
_println(io, "}")
390393
end
@@ -690,8 +693,8 @@ function latexinline(io::IO, md::Markdown.Link)
690693
else
691694
if occursin(".md#", md.url)
692695
file, target = split(md.url, ".md#"; limit = 2)
693-
id = string(hash(target))
694-
wrapinline(io, "hyperlink") do
696+
id = _hash(target)
697+
wrapinline(io, "hyperlinkref") do
695698
_print(io, id)
696699
end
697700
else

0 commit comments

Comments
 (0)