Skip to content

Commit

Permalink
Fix non-text/plain output for Markdown
Browse files Browse the repository at this point in the history
and LaTeX output by capturing several
output representations and let each writer
choose which one to render,
fixes  #916, fixes fredrikekre/Literate.jl#49.

Co-authored-by: Morten Piibeleht <morten.piibeleht@gmail.com>
Co-authored-by: Fredrik Ekre <ekrefredrik@gmail.com>
  • Loading branch information
fredrikekre and mortenpi committed Feb 6, 2019
1 parent 43cb56a commit c80099f
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
* ![Enhancement][badge-enhancement] Docstrings from `@docs`-blocks are now included in the
rendered docs even if some part(s) of the block failed. ([#928][github-928], [#935][github-935])

* ![Enhancement][badge-enhancement] The Markdown and LaTeX output writers can now handle multimedia
output, such as images, from `@example` blocks. ([#938][github-938])

## Version `v0.21.1`

* ![Bugfix][badge-bugfix] `@repl` blocks now work correctly together with quoted
Expand Down Expand Up @@ -200,6 +203,7 @@
[github-928]: https://github.com/JuliaDocs/Documenter.jl/pull/928
[github-929]: https://github.com/JuliaDocs/Documenter.jl/pull/929
[github-935]: https://github.com/JuliaDocs/Documenter.jl/pull/935
[github-938]: https://github.com/JuliaDocs/Documenter.jl/pull/938

[documenterlatex]: https://github.com/JuliaDocs/DocumenterLaTeX.jl
[documentermarkdown]: https://github.com/JuliaDocs/DocumenterMarkdown.jl
Expand Down
4 changes: 4 additions & 0 deletions src/Documents.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ struct RawNode
text::String
end

struct MultiOutput
content::Vector
end

# Navigation
# ----------------------

Expand Down
22 changes: 4 additions & 18 deletions src/Expanders.jl
Original file line number Diff line number Diff line change
Expand Up @@ -562,28 +562,14 @@ function Selectors.runner(::Type{ExampleBlocks}, x, page, doc)
content = []
input = droplines(x.code)

# Special-case support for displaying SVG and PNG graphics. TODO: make this more general.
output = if showable(MIME"text/html"(), result)
Documents.RawHTML(Base.invokelatest(stringmime, MIME"text/html"(), result))
elseif showable(MIME"image/svg+xml"(), result)
Documents.RawHTML(Base.invokelatest(stringmime, MIME"image/svg+xml"(), result))
elseif showable(MIME"image/png"(), result)
Documents.RawHTML(string("<img src=\"data:image/png;base64,", Base.invokelatest(stringmime, MIME"image/png"(), result), "\" />"))
elseif showable(MIME"image/webp"(), result)
Documents.RawHTML(string("<img src=\"data:image/webp;base64,", Base.invokelatest(stringmime, MIME"image/webp"(), result), "\" />"))
elseif showable(MIME"image/gif"(), result)
Documents.RawHTML(string("<img src=\"data:image/gif;base64,", Base.invokelatest(stringmime, MIME"image/gif"(), result), "\" />"))
elseif showable(MIME"image/jpeg"(), result)
Documents.RawHTML(string("<img src=\"data:image/jpeg;base64,", Base.invokelatest(stringmime, MIME"image/jpeg"(), result), "\" />"))
else
Markdown.Code(Documenter.DocTests.result_to_string(buffer, result))
end
# Generate different in different formats and let each writer select
output = Base.invokelatest(Utilities.display_dict, result)

# Only add content when there's actually something to add.
isempty(input) || push!(content, Markdown.Code("julia", input))
isempty(output.code) || push!(content, output)
isempty(output) || push!(content, output)
# ... and finally map the original code block to the newly generated ones.
page.mapping[x] = Markdown.MD(content)
page.mapping[x] = Documents.MultiOutput(content)
end

# @repl
Expand Down
14 changes: 14 additions & 0 deletions src/Utilities/Utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,20 @@ function mdparse(s::AbstractString; mode=:single)
end
end

# Capturing output in different representations similar to IJulia.jl
import Base64: stringmime
function display_dict(x)
out = Dict{MIME,Any}()
# Always generate text/plain
out[MIME"text/plain"()] = stringmime(MIME"text/plain"(), x)
for m in [MIME"text/html"(), MIME"image/svg+xml"(), MIME"image/png"(),
MIME"image/webp"(), MIME"image/gif"(), MIME"image/jpeg"(),
MIME"text/latex"()]
showable(m, x) && (out[m] = stringmime(m, x))
end
return out
end

include("DOM.jl")
include("MDFlatten.jl")
include("TextDiff.jl")
Expand Down
25 changes: 25 additions & 0 deletions src/Writers/HTMLWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,31 @@ end

mdconvert(html::Documents.RawHTML, parent; kwargs...) = Tag(Symbol("#RAW#"))(html.code)

# Select the "best" representation for HTML output.
mdconvert(mo::Documents.MultiOutput, parent; kwargs...) =
Base.invokelatest(mdconvert, mo.content, parent; kwargs...)
function mdconvert(d::Dict{MIME,Any}, parent; kwargs...)
if haskey(d, MIME"text/html"())
out = Documents.RawHTML(d[MIME"text/html"()])
elseif haskey(d, MIME"image/svg+xml"())
out = Documents.RawHTML(d[MIME"image/svg+xml"()])
elseif haskey(d, MIME"image/png"())
out = Documents.RawHTML(string("<img src=\"data:image/png;base64,", d[MIME"image/png"()], "\" />"))
elseif haskey(d, MIME"image/webp"())
out = Documents.RawHTML(string("<img src=\"data:image/webp;base64,", d[MIME"image/webp"()], "\" />"))
elseif haskey(d, MIME"image/gif"())
out = Documents.RawHTML(string("<img src=\"data:image/gif;base64,", d[MIME"image/gif"()], "\" />"))
elseif haskey(d, MIME"image/jpeg"())
out = Documents.RawHTML(string("<img src=\"data:image/jpeg;base64,", d[MIME"image/jpeg"()], "\" />"))
elseif haskey(d, MIME"text/latex"())
out = Utilities.mdparse(d[MIME"text/latex"()]; mode = :single)
elseif haskey(d, MIME"text/plain"())
out = Markdown.Code(d[MIME"text/plain"()])
else
error("this should never happen.")
end
return mdconvert(out, parent; kwargs...)
end

# fixlinks!
# ------------------------------------------------------------------------------
Expand Down
33 changes: 33 additions & 0 deletions src/Writers/LaTeXWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,39 @@ function latex(io::IO, node::Documents.EvalNode, page, doc)
node.result === nothing ? nothing : latex(io, node.result, page, doc)
end

# Select the "best" representation for LaTeX output.
using Base64: base64decode
function latex(io::IO, mo::Documents.MultiOutput)
foreach(x->Base.invokelatest(latex, io, x), mo.content)
end
function latex(io::IO, d::Dict{MIME,Any})
filename = String(rand('a':'z', 7))
if haskey(d, MIME"image/png"())
write("$(filename).png", base64decode(d[MIME"image/png"()]))
_println(io, """
\\begin{figure}[H]
\\centering
\\includegraphics{$(filename)}
\\end{figure}
""")
elseif haskey(d, MIME"image/jpeg"())
write("$(filename).jpeg", base64decode(d[MIME"image/jpeg"()]))
_println(io, """
\\begin{figure}[H]
\\centering
\\includegraphics{$(filename)}
\\end{figure}
""")
elseif haskey(d, MIME"text/latex"())
latex(io, Utilities.mdparse(d[MIME"text/latex"()]; mode = :single))
elseif haskey(d, MIME"text/plain"())
latex(io, Markdown.Code(d[MIME"text/plain"()]))
else
error("this should never happen.")
end
return nothing
end


## Basic Nodes. AKA: any other content that hasn't been handled yet.

Expand Down
43 changes: 43 additions & 0 deletions src/Writers/MarkdownWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,49 @@ function render(io::IO, mime::MIME"text/plain", node::Documents.EvalNode, page,
node.result === nothing ? nothing : render(io, mime, node.result, page, doc)
end

# Select the "best" representation for Markdown output.
using Base64: base64decode
function render(io::IO, mime::MIME"text/plain", d::Documents.MultiOutput, page, doc)
foreach(x -> Base.invokelatest(render, io, mime, x, page, doc), d.content)
end
function render(io::IO, mime::MIME"text/plain", d::Dict{MIME,Any}, page, doc)
filename = String(rand('a':'z', 7))
if haskey(d, MIME"text/html"())
println(io, d[MIME"text/html"()])
elseif haskey(d, MIME"image/svg+xml"())
# NOTE: It seems that we can't simply save the SVG images as a file and include them
# as browsers seem to need to have the xmlns attribute set in the <svg> tag if you
# want to include it with <img>. However, setting that attribute is up to the code
# creating the SVG image.
println(io, d[MIME"image/svg+xml"()])
elseif haskey(d, MIME"image/png"())
write(joinpath(dirname(page.build), "$(filename).png"), base64decode(d[MIME"image/png"()]))
println(io, """
![]($(filename).png)
""")
elseif haskey(d, MIME"image/webp"())
write(joinpath(dirname(page.build), "$(filename).webp"), base64decode(d[MIME"image/webp"()]))
println(io, """
![]($(filename).webp)
""")
elseif haskey(d, MIME"image/jpeg"())
write(joinpath(dirname(page.build), "$(filename).jpeg"), base64decode(d[MIME"image/jpeg"()]))
println(io, """
![]($(filename).jpeg)
""")
elseif haskey(d, MIME"image/gif"())
write(joinpath(dirname(page.build), "$(filename).gif"), base64decode(d[MIME"image/gif"()]))
println(io, """
![]($(filename).gif)
""")
elseif haskey(d, MIME"text/plain"())
render(io, mime, MarkdownStdlib.Code(d[MIME"text/plain"()]), page, doc)
else
error("this should never happen.")
end
return nothing
end


## Basic Nodes. AKA: any other content that hasn't been handled yet.

Expand Down
2 changes: 1 addition & 1 deletion test/examples/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extra_javascript:
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML
- assets/mathjaxhelper.js

docs_dir: 'build'
docs_dir: 'builds/markdown'

pages:
- Home: index.md
Expand Down

0 comments on commit c80099f

Please sign in to comment.