Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix non-text/plain output for Markdown and LaTeX #938

Merged
merged 1 commit into from
Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.2`

* ![Bugfix][badge-bugfix] `linkcheck` now handles servers that do not support `HEAD` requests
Expand Down Expand Up @@ -206,6 +209,7 @@
[github-929]: https://github.com/JuliaDocs/Documenter.jl/pull/929
[github-934]: https://github.com/JuliaDocs/Documenter.jl/pull/934
[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"())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't it make sense to prefer text/latex in latex writer? I don't use latex writer myself so I don't know what's the optimal order, though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it made sense to prioritize more rich formats, such as images, before latex 🤷‍♂️. I don't think it is very commong for things to be showable in both formats so probably doesn't matter.

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"()])
fredrikekre marked this conversation as resolved.
Show resolved Hide resolved
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