Skip to content

Commit

Permalink
MathJax3 support (#1367)
Browse files Browse the repository at this point in the history
  • Loading branch information
simeonschaub authored Aug 6, 2020
1 parent 8d5260e commit b66e4ca
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 56 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

## Version `v0.25.2`

* ![Deprecation][badge-deprecation] The `Documenter.MathJax` type, used to specify the mathematics rendering engine in the HTML output, is now deprecated in favor of `Documenter.MathJax2`. ([#1362][github-1362], [#1367][github-1367])

**For upgrading:** simply replace `MathJax` with `MathJax2`. I.e. instead of

```
makedocs(
format = Documenter.HTML(mathengine = Documenter.MathJax(...), ...),
...
)
```

you should have

```
makedocs(
format = Documenter.HTML(mathengine = Documenter.MathJax2(...), ...),
...
)
```

* ![Enhancement][badge-enhancement] It is now possible to use MathJax v3 as the mathematics rendering in the HTML output. This can be done by passing `Documenter.MathJax3` as the `mathengine` keyword to `HTML`. ([#1362][github-1362], [#1367][github-1367])

* ![Bugfix][badge-bugfix] REPL doctest output lines starting with `#` right after the input code part are now correctly treated as being part of the output (unless prepended with 7 spaces, in line with the standard heuristic). ([#1369][github-1369])

## Version `v0.25.1`
Expand Down Expand Up @@ -611,7 +633,9 @@
[github-1355]: https://github.com/JuliaDocs/Documenter.jl/pull/1355
[github-1357]: https://github.com/JuliaDocs/Documenter.jl/pull/1357
[github-1360]: https://github.com/JuliaDocs/Documenter.jl/pull/1360
[github-1362]: https://github.com/JuliaDocs/Documenter.jl/issues/1362
[github-1365]: https://github.com/JuliaDocs/Documenter.jl/pull/1365
[github-1367]: https://github.com/JuliaDocs/Documenter.jl/pull/1367
[github-1368]: https://github.com/JuliaDocs/Documenter.jl/pull/1368
[github-1369]: https://github.com/JuliaDocs/Documenter.jl/pull/1369

Expand Down
5 changes: 3 additions & 2 deletions src/Documenter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ include("Deps.jl")

import .Utilities: Selectors
import .Writers.HTMLWriter: HTML, asset
import .Writers.HTMLWriter.RD: KaTeX, MathJax
import .Writers.HTMLWriter.RD: KaTeX, MathJax, MathJax2, MathJax3

# User Interface.
# ---------------
export Deps, makedocs, deploydocs, hide, doctest, DocMeta, KaTeX, MathJax, asset
export Deps, makedocs, deploydocs, hide, doctest, DocMeta, asset,
KaTeX, MathJax, MathJax2, MathJax3

"""
makedocs(
Expand Down
120 changes: 88 additions & 32 deletions src/Writers/HTMLWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,15 @@ struct KaTeX <: MathEngine
end

"""
MathJax(config::Dict = <default>, override = false)
MathJax2(config::Dict = <default>, override = false)
An instance of the `MathJax` type can be passed to [`HTML`](@ref) via the `mathengine`
keyword to specify that the [MathJax rendering engine](https://www.mathjax.org/) should be
An instance of the `MathJax2` type can be passed to [`HTML`](@ref) via the `mathengine`
keyword to specify that the [MathJax v2 rendering engine](https://www.mathjax.org/) should be
used in the HTML output to render mathematical expressions.
A dictionary can be passed via the `config` argument to configure MathJax. It gets passed to
the [`MathJax.Hub.Config`](https://docs.mathjax.org/en/latest/options/) function. By
default, Documenter set custom configuration for `tex2jax`, `config`, `jax`, `extensions`
the [`MathJax.Hub.Config`](https://docs.mathjax.org/en/v2.7-latest/options/) function. By
default, Documenter sets custom configurations for `tex2jax`, `config`, `jax`, `extensions`
and `Tex`.
By default, the user-provided dictionary gets _merged_ with the default dictionary (i.e. the
Expand All @@ -188,29 +188,70 @@ setting your own `tex2jax` value will override the default). This can be overrid
setting `override` to `true`, in which case the default values are ignored and only the
user-provided dictionary is used.
"""
struct MathJax <: MathEngine
struct MathJax2 <: MathEngine
config :: Dict{Symbol,Any}
function MathJax(config::Union{Dict,Nothing} = nothing, override=false)
function MathJax2(config::Union{Dict,Nothing} = nothing, override=false)
default = Dict(
:tex2jax => Dict(
"inlineMath" => [["\$","\$"], ["\\(","\\)"]],
"processEscapes" => true
),
:config => ["MMLorHTML.js"],
:jax => [
"input/TeX",
"output/HTML-CSS",
"output/NativeMML"
],
:extensions => [
"MathMenu.js",
"MathZoom.js",
"TeX/AMSmath.js",
"TeX/AMSsymbols.js",
"TeX/autobold.js",
"TeX/autoload-all.js"
],
:TeX => Dict(:equationNumbers => Dict(:autoNumber => "AMS"))
:tex2jax => Dict(
"inlineMath" => [["\$","\$"], ["\\(","\\)"]],
"processEscapes" => true
),
:config => ["MMLorHTML.js"],
:jax => [
"input/TeX",
"output/HTML-CSS",
"output/NativeMML"
],
:extensions => [
"MathMenu.js",
"MathZoom.js",
"TeX/AMSmath.js",
"TeX/AMSsymbols.js",
"TeX/autobold.js",
"TeX/autoload-all.js"
],
:TeX => Dict(:equationNumbers => Dict(:autoNumber => "AMS"))
)
new((config === nothing) ? default : override ? config : merge(default, config))
end
end

@deprecate MathJax(config::Union{Dict,Nothing} = nothing, override=false) MathJax2(config, override) false
@doc "deprecated – Use [`MathJax2`](@ref) instead" MathJax

"""
MathJax3(config::Dict = <default>, override = false)
An instance of the `MathJax3` type can be passed to [`HTML`](@ref) via the `mathengine`
keyword to specify that the [MathJax v3 rendering engine](https://www.mathjax.org/) should be
used in the HTML output to render mathematical expressions.
A dictionary can be passed via the `config` argument to configure MathJax. It gets passed to
[`Window.MathJax`](https://docs.mathjax.org/en/latest/options/) function. By default,
Documenter specifies in the key `tex` that `\$...\$` and `\\(...\\)` denote inline math, that AMS
style tags should be used and the `base`, `ams` and `autoload` packages should be imported.
The key `options`, by default, specifies which HTML classes to ignore and which to process
using MathJax.
By default, the user-provided dictionary gets _merged_ with the default dictionary (i.e. the
resulting configuration dictionary will contain the values from both dictionaries, but e.g.
setting your own `tex` value will override the default). This can be overridden by
setting `override` to `true`, in which case the default values are ignored and only the
user-provided dictionary is used.
"""
struct MathJax3 <: MathEngine
config :: Dict{Symbol,Any}
function MathJax3(config::Union{Dict,Nothing} = nothing, override=false)
default = Dict(
:tex => Dict(
"inlineMath" => [["\$","\$"], ["\\(","\\)"]],
"tags" => "ams",
"packages" => ["base", "ams", "autoload"],
),
:options => Dict(
"ignoreHtmlClass" => "tex2jax_ignore",
"processHtmlClass" => "tex2jax_process",
)
)
new((config === nothing) ? default : override ? config : merge(default, config))
end
Expand Down Expand Up @@ -276,10 +317,11 @@ you would set `highlights = ["llvm", "yaml"]`. Note that no verification is done
provided language names are sane.
**`mathengine`** specifies which LaTeX rendering engine will be used to render the math
blocks. The options are either [KaTeX](https://katex.org/) (default) or
[MathJax](https://www.mathjax.org/), enabled by passing an instance of [`KaTeX`](@ref) or
[`MathJax`](@ref) objects, respectively. The rendering engine can further be customized by
passing options to the [`KaTeX`](@ref) or [`MathJax`](@ref) constructors.
blocks. The options are either [KaTeX](https://katex.org/) (default),
[MathJax v2](https://www.mathjax.org/), or [MathJax v3](https://www.mathjax.org/), enabled by
passing an instance of [`KaTeX`](@ref), [`MathJax2`](@ref), or
[`MathJax3`](@ref) objects, respectively. The rendering engine can further be customized by
passing options to the [`KaTeX`](@ref) or [`MathJax2`](@ref)/[`MathJax3`](@ref) constructors.
**`lang`** can be used to specify the language tag of each HTML page. Default is `"en"`.
Expand Down Expand Up @@ -382,7 +424,7 @@ end
module RD
using JSON
using ....Utilities.JSDependencies: RemoteLibrary, Snippet, RequireJS, jsescape, json_jsescape
using ..HTMLWriter: KaTeX, MathJax
using ..HTMLWriter: KaTeX, MathJax, MathJax2, MathJax3

const requirejs_cdn = "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"
const google_fonts = "https://fonts.googleapis.com/css?family=Lato|Roboto+Mono"
Expand Down Expand Up @@ -464,7 +506,7 @@ module RD
"""
))
end
function mathengine!(r::RequireJS, engine::MathJax)
function mathengine!(r::RequireJS, engine::MathJax2)
push!(r, RemoteLibrary(
"mathjax",
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS_HTML",
Expand All @@ -476,6 +518,20 @@ module RD
"""
))
end
function mathengine!(r::RequireJS, engine::MathJax3)
push!(r, Snippet([], [],
"""
window.MathJax = $(json_jsescape(engine.config, 2));
(function () {
var script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.0.5/es5/tex-svg.js';
script.async = true;
document.head.appendChild(script);
})();
"""
))
end
mathengine(::RequireJS, ::Nothing) = nothing
end

Expand Down
51 changes: 39 additions & 12 deletions test/examples/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ isdefined(@__MODULE__, :examples_root) && error("examples_root is already define
EXAMPLE_BUILDS = if haskey(ENV, "DOCUMENTER_TEST_EXAMPLES")
split(ENV["DOCUMENTER_TEST_EXAMPLES"])
else
["markdown", "html", "html-local"]
["markdown", "html", "html-mathjax3", "html-local"]
end

# Modules `Mod` and `AutoDocs`
Expand Down Expand Up @@ -164,14 +164,12 @@ htmlbuild_pages = Any[
"example-output.md",
]

# Build with pretty URLs and canonical links and a PNG logo
examples_html_doc = if "html" in EXAMPLE_BUILDS
@info("Building mock package docs: HTMLWriter / deployment build")
function html_doc(build_directory, mathengine)
@quietly withassets("images/logo.png", "images/logo.jpg", "images/logo.gif") do
makedocs(
debug = true,
root = examples_root,
build = "builds/html",
build = "builds/$(build_directory)",
doctestfilters = [r"Ptr{0x[0-9]+}"],
sitename = "Documenter example",
pages = htmlbuild_pages,
Expand All @@ -187,23 +185,52 @@ examples_html_doc = if "html" in EXAMPLE_BUILDS
],
prettyurls = true,
canonical = "https://example.com/stable",
mathengine = MathJax(Dict(:TeX => Dict(
:equationNumbers => Dict(:autoNumber => "AMS"),
:Macros => Dict(
:ket => ["|#1\\rangle", 1],
:bra => ["\\langle#1|", 1],
),
))),
mathengine = mathengine,
highlights = ["erlang", "erlang-repl"],
footer = "This footer has been customized.",
)
)
end
end

# Build with pretty URLs and canonical links and a PNG logo
examples_html_doc = if "html" in EXAMPLE_BUILDS
@info("Building mock package docs: HTMLWriter / deployment build")
html_doc("html",
MathJax2(Dict(
:TeX => Dict(
:equationNumbers => Dict(:autoNumber => "AMS"),
:Macros => Dict(
:ket => ["|#1\\rangle", 1],
:bra => ["\\langle#1|", 1],
:pdv => ["\\frac{\\partial^{#1} #2}{\\partial #3^{#1}}", 3, ""],
),
),
)),
)
else
@info "Skipping build: HTML/deploy" EXAMPLE_BUILDS get(ENV, "DOCUMENTER_TEST_EXAMPLES", nothing)
nothing
end

# same as HTML, but with MathJax3
examples_html_mathjax3_doc = if "html-mathjax3" in EXAMPLE_BUILDS
@info("Building mock package docs: HTMLWriter / deployment build using MathJax v3")
html_doc("html-mathjax3",
MathJax3(Dict(
:loader => Dict("load" => ["[tex]/physics"]),
:tex => Dict(
"inlineMath" => [["\$","\$"], ["\\(","\\)"]],
"tags" => "ams",
"packages" => ["base", "ams", "autoload", "physics"],
),
)),
)
else
@info "Skipping build: HTML/deploy MathJax v3" EXAMPLE_BUILDS get(ENV, "DOCUMENTER_TEST_EXAMPLES", nothing)
nothing
end

# HTML: local build with pretty URLs off
examples_html_local_doc = if "html-local" in EXAMPLE_BUILDS
@info("Building mock package docs: HTMLWriter / local build")
Expand Down
30 changes: 24 additions & 6 deletions test/examples/src/man/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,17 +356,35 @@ With explicit alignment.
The following example only works on the deploy build where

```julia
mathengine = Documenter.MathJax(Dict(:TeX => Dict(
:equationNumbers => Dict(:autoNumber => "AMS"),
:Macros => Dict(
:ket => ["|#1\\rangle", 1],
:bra => ["\\langle#1|", 1],
mathengine = MathJax2(Dict(
:TeX => Dict(
:equationNumbers => Dict(:autoNumber => "AMS"),
:Macros => Dict(
:ket => ["|#1\\rangle", 1],
:bra => ["\\langle#1|", 1],
:pdv => ["\\frac{\\partial^{#1} #2}{\\partial #3^{#1}}", 3, ""],
),
),
)))
)),
```
or on MathJax v3, the
[physics package](http://mirrors.ibiblio.org/CTAN/macros/latex/contrib/physics/physics.pdf)
can be loaded:

```julia
mathengine = MathJax3(Dict(
:loader => Dict("load" => ["[tex]/physics"]),
:tex => Dict(
"inlineMath" => [["\$","\$"], ["\\(","\\)"]],
"tags" => "ams",
"packages" => ["base", "ams", "autoload", "physics"],
),
)),
```

```math
\bra{x}\ket{y}
\pdv[n]{f}{x}
```

The following at-raw block only renders correctly on the deploy build, where
Expand Down
14 changes: 10 additions & 4 deletions test/examples/tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ elseif (@__MODULE__) !== Main && !isdefined(Main, :examples_root)
end

@testset "Examples" begin
@testset "HTML: deploy" begin
doc = Main.examples_html_doc

@testset "HTML: deploy/$name" for (doc, name) in [
(Main.examples_html_doc, "html"), (Main.examples_html_mathjax3_doc, "html-mathjax3")
]
@test isa(doc, Documenter.Documents.Document)

let build_dir = joinpath(examples_root, "builds", "html")
let build_dir = joinpath(examples_root, "builds", name)
@test joinpath(build_dir, "index.html") |> isfile
@test joinpath(build_dir, "omitted", "index.html") |> isfile
@test joinpath(build_dir, "hidden", "index.html") |> isfile
Expand All @@ -42,6 +42,12 @@ end

# Assets
@test joinpath(build_dir, "assets", "documenter.js") |> isfile
documenter_js = read(joinpath(build_dir, "assets", "documenter.js"), String)
if name == "html-mathjax3"
@test occursin("https://cdnjs.cloudflare.com/ajax/libs/mathjax/3", documenter_js)
else # name == "html", uses MathJax2
@test occursin("https://cdnjs.cloudflare.com/ajax/libs/mathjax/2", documenter_js)
end

# This build includes erlang and erlang-repl highlighting
documenterjs = String(read(joinpath(build_dir, "assets", "documenter.js")))
Expand Down

0 comments on commit b66e4ca

Please sign in to comment.