diff --git a/CHANGELOG.md b/CHANGELOG.md index d44ed75097..367c7bfab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Documenter.jl changelog +## Version `v0.27.23` + +* ![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]) +* ![Bugfix][badge-bugfix] The PDF/LaTeX output now handles hard Markdown line breaks (i.e. `Markdown.LineBreak` nodes). ([#1908][github-1908]) +* ![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]) + ## Version `v0.27.22` * ![Maintenance][badge-maintenance] Documenter is now compatible with DocStringExtensions v0.9. ([#1885][github-1885], [#1886][github-1886]) @@ -1086,10 +1092,14 @@ [github-1871]: https://github.com/JuliaDocs/Documenter.jl/pull/1871 [github-1885]: https://github.com/JuliaDocs/Documenter.jl/issues/1885 [github-1886]: https://github.com/JuliaDocs/Documenter.jl/pull/1886 +[github-1908]: https://github.com/JuliaDocs/Documenter.jl/pull/1908 +[github-1909]: https://github.com/JuliaDocs/Documenter.jl/pull/1909 +[julia-38054]: https://github.com/JuliaLang/julia/issues/38054 [julia-38079]: https://github.com/JuliaLang/julia/issues/38079 [julia-39841]: https://github.com/JuliaLang/julia/pull/39841 +[julia-43652]: https://github.com/JuliaLang/julia/issues/43652 [julia-45174]: https://github.com/JuliaLang/julia/issues/45174 [julialangorg-1272]: https://github.com/JuliaLang/www.julialang.org/issues/1272 diff --git a/assets/latex/documenter.sty b/assets/latex/documenter.sty index 1bccffff9c..2f815d7323 100644 --- a/assets/latex/documenter.sty +++ b/assets/latex/documenter.sty @@ -85,3 +85,9 @@ \usepackage{graphicx} \usepackage[export]{adjustbox} % + +% Some internal link targets are implemented with \label, some with \hypertarget, +% but they require different links. This inserts a \hyperref if a corresponding label exists, +% and \hyperlink if it doesn't. +\def\hyperlinkref#1#2{\@ifundefined{r@#1}{\hyperlink{#1}{#2}}{\hyperref[#1]{#2}}} +% diff --git a/src/Anchors.jl b/src/Anchors.jl index f0e9af1b93..b0a8968b78 100644 --- a/src/Anchors.jl +++ b/src/Anchors.jl @@ -124,14 +124,16 @@ function anchor(m::AnchorMap, id, file, n) nothing end +""" +Create a label from an anchor. +""" +label(a::Anchor) = (a.nth == 1) ? a.id : string(a.id, "-", a.nth) + """ Create an HTML fragment from an anchor. """ function fragment(a::Anchor) - frag = string("#", a.id) - if a.nth > 1 - frag = string(frag, "-", a.nth) - end + frag = string("#", label(a)) # TODO: Sanitize the fragment return frag end diff --git a/src/Writers/LaTeXWriter.jl b/src/Writers/LaTeXWriter.jl index 7b2b2a8f84..2f70afdd90 100644 --- a/src/Writers/LaTeXWriter.jl +++ b/src/Writers/LaTeXWriter.jl @@ -85,6 +85,10 @@ Context(io) = Context{typeof(io)}(io, false, Dict(), 1, "") _print(c::Context, args...) = Base.print(c.io, args...) _println(c::Context, args...) = Base.println(c.io, args...) +# Labels in the TeX file are hashes of plain text labels. +# To keep the plain text label (for debugging), say _hash(x) = x +_hash(x) = string(hash(x)) + const STYLE = joinpath(dirname(@__FILE__), "..", "..", "assets", "latex", "documenter.sty") const DEFAULT_PREAMBLE_PATH = joinpath(dirname(@__FILE__), "..", "..", "assets", "latex", "preamble.tex") @@ -180,7 +184,7 @@ function compile_tex(doc::Documents.Document, settings::LaTeX, fileprefix::Strin Sys.which("latexmk") === nothing && (@error "LaTeXWriter: latexmk command not found."; return false) @info "LaTeXWriter: using latexmk to compile tex." try - piperun(`latexmk -f -interaction=nonstopmode -view=none -lualatex -shell-escape $(fileprefix).tex`, clearlogs = true) + piperun(`latexmk -f -interaction=batchmode -halt-on-error -view=none -lualatex -shell-escape $(fileprefix).tex`, clearlogs = true) return true catch err logs = cp(pwd(), mktempdir(); force=true) @@ -208,7 +212,7 @@ function compile_tex(doc::Documents.Document, settings::LaTeX, fileprefix::Strin mkdir /home/zeptodoctor/build cd /home/zeptodoctor/build cp -r /mnt/. . - latexmk -f -interaction=nonstopmode -view=none -lualatex -shell-escape $(fileprefix).tex + latexmk -f -interaction=batchmode -halt-on-error -view=none -lualatex -shell-escape $(fileprefix).tex """ try piperun(`docker run -itd -u zeptodoctor --name latex-container -v $(pwd()):/mnt/ --rm juliadocs/documenter-latex:$(DOCKER_IMAGE_TAG)`, clearlogs = true) @@ -282,9 +286,9 @@ function latex(io::IO, vec::Vector, page, doc) end function latex(io::IO, anchor::Anchors.Anchor, page, doc) - id = string(hash(string(anchor.id, "-", anchor.nth))) - _println(io, "\n\\hypertarget{", id, "}{}\n") + id = _hash(Anchors.label(anchor)) latex(io, anchor.object, page, doc) + _println(io, "\n\\label{", id, "}{}\n") end @@ -297,10 +301,9 @@ function latex(io::IO, node::Documents.DocsNodes, page, doc) end function latex(io::IO, node::Documents.DocsNode, page, doc) - id = string(hash(string(node.anchor.id))) + id = _hash(Anchors.label(node.anchor)) # Docstring header based on the name of the binding and it's category. - _println(io, "\\hypertarget{", id, "}{} ") - _print(io, "\\hyperlink{", id, "}{\\texttt{") + _print(io, "\\hypertarget{", id, "}{\\texttt{") latexesc(io, string(node.object.binding)) _print(io, "}} ") _println(io, " -- {", Utilities.doccat(node.object), ".}\n") @@ -346,9 +349,9 @@ function latex(io::IO, index::Documents.IndexNode, page, doc) _println(io, "\\begin{itemize}") for (object, _, page, mod, cat) in index.elements - id = string(hash(string(Utilities.slugify(object)))) + id = _hash(string(Utilities.slugify(object))) text = string(object.binding) - _print(io, "\\item \\hyperlink{") + _print(io, "\\item \\hyperlinkref{") _print(io, id, "}{\\texttt{") latexesc(io, text) _println(io, "}}") @@ -366,7 +369,6 @@ function latex(io::IO, contents::Documents.ContentsNode, page, doc) for (count, path, anchor) in contents.elements header = anchor.object level = Utilities.header_level(header) - id = string(hash(string(anchor.id, "-", anchor.nth))) # If we're changing depth, we need to make sure we always print the # correct number of \begin{itemize} and \end{itemize} statements. if level > depth @@ -384,7 +386,8 @@ function latex(io::IO, contents::Documents.ContentsNode, page, doc) end end # Print the corresponding \item statement - _print(io, "\\item \\hyperlink{", id, "}{") + id = _hash(Anchors.label(anchor)) + _print(io, "\\item \\hyperlinkref{", id, "}{") latexinline(io, header.text) _println(io, "}") end @@ -690,8 +693,8 @@ function latexinline(io::IO, md::Markdown.Link) else if occursin(".md#", md.url) file, target = split(md.url, ".md#"; limit = 2) - id = string(hash(target)) - wrapinline(io, "hyperlink") do + id = _hash(target) + wrapinline(io, "hyperlinkref") do _print(io, id) end else @@ -715,6 +718,9 @@ function latexinline(io, hr::Markdown.HorizontalRule) _println(io, "\\rule{\\textwidth}{1pt}}") end +function latexinline(io, hr::Markdown.LineBreak) + _println(io, "\\\\") +end # Metadata Nodes get dropped from the final output for every format but are needed throughout # rest of the build and so we just leave them in place and print a blank line in their place. diff --git a/test/examples/src.latex_simple/index.md b/test/examples/src.latex_simple/index.md index fe88160b6c..e826523e9b 100644 --- a/test/examples/src.latex_simple/index.md +++ b/test/examples/src.latex_simple/index.md @@ -121,3 +121,9 @@ LaTeXEquation2(raw""" \end{array}\right] """) ``` + +## `LineBreak` node + +This sentence\ +should be over **multiple\ +lines**.