diff --git a/CHANGELOG.md b/CHANGELOG.md index 0436cecdf7..b72b3754e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ * ![Enhancement][badge-enhancement] Videos can now be included in the HTML output using the image syntax (`![]()`) if the file extension matches a known format (`.webm`, `.mp4`, `.ogg`, `.ogm`, `.ogv`, `.avi`). ([#1034][github-1034]) +* ![Enhancement][badge-enhancement] The PDF output now uses the DejaVu Sans and DejaVu Sans Mono fonts to provide better Unicode coverage. ([#803][github-803], [#1066][github-1066]) + * ![Bugfix][badge-bugfix] The HTML output now outputs HTML files for pages that are not referenced in the `pages` keyword too (Documenter finds them according to their extension). But they do exists outside of the standard navigation hierarchy (as defined by `pages`). This fixes a bug where these pages could still be referenced by `@ref` links and `@contents` blocks, but in the HTML output, the links ended up being broken. ([#1031][github-1031], [#1047][github-1047]) * ![Bugfix][badge-bugfix] `makedocs` now throws an error when the format objects (`Documenter.HTML`, `LaTeX`, `Markdown`) get passed positionally. The format types are no longer subtypes of `Documenter.Plugin`. ([#1046][github-1046], [#1061][github-1061]) @@ -308,6 +310,7 @@ [github-794]: https://github.com/JuliaDocs/Documenter.jl/pull/794 [github-795]: https://github.com/JuliaDocs/Documenter.jl/pull/795 [github-802]: https://github.com/JuliaDocs/Documenter.jl/pull/802 +[github-803]: https://github.com/JuliaDocs/Documenter.jl/issues/803 [github-804]: https://github.com/JuliaDocs/Documenter.jl/pull/804 [github-813]: https://github.com/JuliaDocs/Documenter.jl/pull/813 [github-816]: https://github.com/JuliaDocs/Documenter.jl/pull/816 @@ -375,6 +378,7 @@ [github-1054]: https://github.com/JuliaDocs/Documenter.jl/pull/1054 [github-1061]: https://github.com/JuliaDocs/Documenter.jl/pull/1061 [github-1062]: https://github.com/JuliaDocs/Documenter.jl/pull/1062 +[github-1066]: https://github.com/JuliaDocs/Documenter.jl/pull/1066 [documenterlatex]: https://github.com/JuliaDocs/DocumenterLaTeX.jl [documentermarkdown]: https://github.com/JuliaDocs/DocumenterMarkdown.jl diff --git a/assets/latex/documenter.sty b/assets/latex/documenter.sty index 8774c63200..7d84323366 100644 --- a/assets/latex/documenter.sty +++ b/assets/latex/documenter.sty @@ -1,9 +1,14 @@ % font settings \usepackage{fontspec, newunicodechar, polyglossia} -\setsansfont{Lato}[Scale=MatchLowercase, Ligatures=TeX] -\setmonofont{Roboto Mono}[Scale=MatchLowercase] +\setsansfont{DejaVu Sans}[Scale=MatchLowercase, Ligatures=TeX] +\setmonofont{DejaVu Sans Mono}[Scale=MatchLowercase] \renewcommand{\familydefault}{\sfdefault} +% DejaVu Sans Mono does not have the xor symbol. So we hack around that by replacing all +% instances of it with calls to \unicodeveebar, which prints this single character as with +% DejaVu Sans instead. +\newfontfamily\unicodeveebarfont{DejaVu Sans}[Scale=MatchLowercase] +\newcommand\unicodeveebar{{\unicodeveebarfont ⊻}} % % colours diff --git a/docs/src/man/other-formats.md b/docs/src/man/other-formats.md index aca6287dc9..106a98e68a 100644 --- a/docs/src/man/other-formats.md +++ b/docs/src/man/other-formats.md @@ -171,8 +171,7 @@ The following is required to build the documentation: * You need `pdflatex` command to be installed and available to Documenter. * You need the [minted](https://ctan.org/pkg/minted) LaTeX package and its backend source highlighter [Pygments](http://pygments.org/) installed. -* You need the [Lato](http://www.latofonts.com/lato-free-fonts/) and - [Roboto Mono](https://fonts.google.com/specimen/Roboto+Mono) fonts installed. +* You need the [_DejaVu Sans_ and _DejaVu Sans Mono_](https://dejavu-fonts.github.io/) fonts installed. ### Compiling using docker image diff --git a/src/Writers/LaTeXWriter.jl b/src/Writers/LaTeXWriter.jl index a7041d192c..185e98b2cd 100644 --- a/src/Writers/LaTeXWriter.jl +++ b/src/Writers/LaTeXWriter.jl @@ -128,6 +128,13 @@ function render(doc::Documents.Document, settings::LaTeX=LaTeX()) # compile .tex and copy over the .pdf file if compile_tex return true status = compile_tex(doc, settings, texfile) status && cp(pdffile, joinpath(doc.user.root, doc.user.build, pdffile); force = true) + + # Debug: if DOCUMENTER_LATEX_DEBUG environment variable is set, copy the LaTeX + # source files over to a directory under doc.user.root. + if haskey(ENV, "DOCUMENTER_LATEX_DEBUG") + sources = cp(pwd(), mktempdir(doc.user.root), force=true) + @info "LaTeX sources copied for debugging to $(sources)" + end end end end @@ -391,23 +398,38 @@ function latex(io::IO, code::Markdown.Code) # the julia-repl is called "jlcon" in Pygments language = (language == "julia-repl") ? "jlcon" : language if language in LEXER - _print(io, "\n\\begin{minted}") + _print(io, "\n\\begin{minted}[escapeinside=\\%\\%]") _println(io, "{", language, "}") - _println(io, code.code) + _print_code_escapes(io, code.code) _println(io, "\\end{minted}\n") else - _println(io, "\n\\begin{lstlisting}") - _println(io, code.code) + _println(io, "\n\\begin{lstlisting}[escapeinside=\\%\\%]") + _print_code_escapes(io, code.code) _println(io, "\\end{lstlisting}\n") end end +function _print_code_escapes(io, s::AbstractString) + for ch in s + ch === '%' ? _print(io, "%\\%%") : + ch === '⊻' ? _print(io, "%\\unicodeveebar%") : + _print(io, ch) + end +end + function latexinline(io::IO, code::Markdown.Code) _print(io, "\\texttt{") - latexesc(io, code.code) + _print_code_escapes_inline(io, code.code) _print(io, "}") end +function _print_code_escapes_inline(io, s::AbstractString) + for ch in s + ch === '⊻' ? _print(io, "\\unicodeveebar{}") : + latexesc(io, ch) + end +end + function latex(io::IO, md::Markdown.Paragraph) for md in md.content latexinline(io, md) @@ -605,9 +627,11 @@ for ch in "&%\$#_{}" _latexescape_chars[ch] = "\\$ch" end +latexesc(io, ch::AbstractChar) = _print(io, get(_latexescape_chars, ch, ch)) + function latexesc(io, s::AbstractString) for ch in s - _print(io, get(_latexescape_chars, ch, ch)) + latexesc(io, ch) end end diff --git a/test/examples/make.jl b/test/examples/make.jl index e368f0f03b..f28ccd26d0 100644 --- a/test/examples/make.jl +++ b/test/examples/make.jl @@ -135,7 +135,8 @@ htmlbuild_pages = Any[ "expandorder/00.md", "expandorder/01.md", "expandorder/AA.md", - ] + ], + "unicode.md", ] @info("Building mock package docs: HTMLWriter / local build") diff --git a/test/examples/src/unicode.md b/test/examples/src/unicode.md new file mode 100644 index 0000000000..d1b1929a84 --- /dev/null +++ b/test/examples/src/unicode.md @@ -0,0 +1,113 @@ +# Unicode + +Some unicode tests here. + +In main sans-serif font: + +* Checkmark: "✓" +* Cicled plus: "⊕" +* XOR: "⊻" +* Exists: "∀", forall: "∃" + +`\begin{lstlisting}` is used for non-highlighted blocks: + +``` +xor: ⊻ +forall: ∀ +exists: ∃ +check: ✓ +oplus: ⊕ + +What about the other edge cases: \ % \% %\ %% %\%% +``` + +`\begin{minted}` is used for highlighted blocks: + +```julia +xor: ⊻ +forall: ∀ +exists: ∃ +check: ✓ +oplus: ⊕ +``` + +Inlines: + +`xor: ⊻ -> %\unicodeveebar% <-` + +`forall: ∀, exists: ∃, check: ✓` + +`%\%%\unicodeveebar, oplus: ⊕` + +## Drawings etc + +``` +┌────────────────────────────────────────────────────────────────────────────┐ +│ ┌───────────────┐ │ +│ HTTP.request(method, uri, headers, body) -> │ HTTP.Response ├──────────────┼┐ +│ │ └───────────────┘ ││ +│ │ ││ +│ │ ┌──────────────────────────────────────┐ ┌──────────────────┐ ││ +│ └───▶│ request(RedirectLayer, ...) │ │ HTTP.StatusError │ ││ +│ └─┬────────────────────────────────────┴─┐ └─────────▲────────┘ ││ +│ │ request(BasicAuthLayer, ...) │ │ ││ +│ └─┬────────────────────────────────────┴─┐ │ ││ +│ │ request(CookieLayer, ...) │ │ ││ +│ └─┬────────────────────────────────────┴─┐ │ ││ +│ │ request(CanonicalizeLayer, ...) │ │ ││ +│ └─┬────────────────────────────────────┴─┐ │ ││ +│ │ request(MessageLayer, ...) ├─────────┼──────┐ ││ +``` + +```julia + ┌──────────────────────────────────────────────────────────────────────┐ +1 │ ▗▄▞▀▀▀▀▀▀▀▄▄ │ + │ ▄▞▘ ▀▄▖ │ + │ ▄▀ ▝▚▖ │ + │ ▗▞ ▝▄ │ + │ ▞▘ ▝▚▖ │ + │ ▗▀ ▝▚ │ + │ ▞▘ ▀▖ │ + │ ▗▞ ▝▄ │ + │ ▄▘ ▚▖ │ + │ ▗▞ ▝▄ │ + │ ▄▘ ▚▖ │ + │ ▗▀ ▝▚ │ + │ ▗▞▘ ▀▄ │ + │ ▄▀▘ ▀▚▖ │ +0 │ ▄▄▄▄▀▀ ▝▀▚▄▄▄▖│ + └──────────────────────────────────────────────────────────────────────┘ + 0 70 +``` + +``` +2×4 DataFrames.DataFrame +│ Row │ a │ b │ c │ d │ +│ │ Int64 │ Float64 │ Int64 │ String │ +├─────┼───────┼─────────┼───────┼────────┤ +│ 1 │ 2 │ 2.0 │ 2 │ John │ +│ 2 │ 2 │ 2.0 │ 2 │ Sally │ +``` + +```julia +function map_filter_iterators(xs, init) + ret = iterate(xs) + ret === nothing && return + acc = init + @goto filter + local state, x + while true + while true # input + ret = iterate(xs, state) # + ret === nothing && return acc # + @label filter # + x, state = ret # + iseven(x) && break # filter : + end # : + y = 2x # imap : : + acc += y # + : : : + end # : : : : + # + <-- imap <-------- filter <-- input + return acc +end +``` diff --git a/test/examples/tests.jl b/test/examples/tests.jl index 6a240b0589..d3d76ee7d6 100644 --- a/test/examples/tests.jl +++ b/test/examples/tests.jl @@ -50,7 +50,7 @@ end @test realpath(doc.internal.assets) == realpath(joinpath(dirname(@__FILE__), "..", "..", "assets")) - @test length(doc.blueprint.pages) == 14 + @test length(doc.blueprint.pages) == 15 let headers = doc.internal.headers @test Documenter.Anchors.exists(headers, "Documentation")