mirror of https://github.com/mpastell/Weave.jl
move around code into separate files
parent
db89118b4c
commit
119b3332aa
13
src/Weave.jl
13
src/Weave.jl
|
@ -1,6 +1,7 @@
|
|||
module Weave
|
||||
|
||||
using Highlights, Mustache, Requires
|
||||
using Printf
|
||||
|
||||
|
||||
const PKG_DIR = normpath(@__DIR__, "..")
|
||||
|
@ -12,7 +13,12 @@ const WEAVE_OPTION_DEPRECATE_ID = "weave_option_duplicate_id"
|
|||
|
||||
# keeps paths of sample documents for easy try
|
||||
const EXAMPLE_FOLDER = normpath(PKG_DIR, "examples")
|
||||
|
||||
const WEAVE_VERSION = try
|
||||
'v' * Pkg.TOML.parsefile(normpath(PKG_DIR, "Project.toml"))["version"]
|
||||
catch
|
||||
""
|
||||
end
|
||||
weave_info() = WEAVE_VERSION, string(Date(now()))
|
||||
|
||||
function __init__()
|
||||
@require Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" include("plots.jl")
|
||||
|
@ -333,6 +339,11 @@ include("run.jl")
|
|||
include("cache.jl")
|
||||
include("formats.jl")
|
||||
include("format.jl")
|
||||
include("rendering/common.jl")
|
||||
include("rendering/htmlformats.jl")
|
||||
include("rendering/markdownformats.jl")
|
||||
include("rendering/texformats.jl")
|
||||
include("rendering/variousformats.jl")
|
||||
include("pandoc.jl")
|
||||
include("converter.jl")
|
||||
|
||||
|
|
309
src/format.jl
309
src/format.jl
|
@ -6,6 +6,7 @@ using REPL.REPLCompletions: latex_symbols
|
|||
function format(doc, template = nothing, highlight_theme = nothing; css = nothing)
|
||||
docformat = doc.format
|
||||
|
||||
# This could instead be made defaults in Base.@kwdef type declaration
|
||||
# Complete format dictionaries with defaults
|
||||
get!(docformat.formatdict, :termstart, docformat.formatdict[:codestart])
|
||||
get!(docformat.formatdict, :termend, docformat.formatdict[:codeend])
|
||||
|
@ -27,50 +28,6 @@ end
|
|||
|
||||
render_doc(_, body, args...) = body
|
||||
|
||||
function render_doc(::JMarkdown2HTML, body, doc, template, css, highlight_theme)
|
||||
_, weave_source = splitdir(abspath(doc.source))
|
||||
weave_version, weave_date = weave_info()
|
||||
|
||||
return Mustache.render(
|
||||
get_html_template(template);
|
||||
body = body,
|
||||
stylesheet = get_stylesheet(css),
|
||||
highlight_stylesheet = get_highlight_stylesheet(MIME("text/html"), highlight_theme),
|
||||
header_script = doc.header_script,
|
||||
weave_source = weave_source,
|
||||
weave_version = weave_version,
|
||||
weave_date = weave_date,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
function render_doc(::JMarkdown2tex, body, doc, template, _, highlight_theme)
|
||||
return Mustache.render(
|
||||
get_tex_template(template);
|
||||
body = body,
|
||||
highlight = get_highlight_stylesheet(MIME("text/latex"), highlight_theme),
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
function render_doc(::Tex, body, doc, template, _, highlight_theme)
|
||||
return Mustache.render(
|
||||
get_tex_template(template);
|
||||
body = body,
|
||||
highlight = get_highlight_stylesheet(MIME("text/latex"), highlight_theme),
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
function render_doc(::TexMinted, body, doc, template, _, highlight_theme)
|
||||
return Mustache.render(
|
||||
get_tex_template(template);
|
||||
body = body,
|
||||
highlight = get_highlight_stylesheet(MIME("text/latex"), highlight_theme),
|
||||
minted = true,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
get_highlight_theme(::Nothing) = Highlights.Themes.DefaultTheme
|
||||
get_highlight_theme(highlight_theme::Type{<:Highlights.AbstractTheme}) = highlight_theme
|
||||
|
@ -89,267 +46,3 @@ get_highlight_stylesheet(mime, highlight_theme) =
|
|||
get_highlight_stylesheet(mime, get_highlight_theme(highlight_theme))
|
||||
get_highlight_stylesheet(mime, highlight_theme::Type{<:Highlights.AbstractTheme}) =
|
||||
sprint((io, x) -> Highlights.stylesheet(io, mime, x), highlight_theme)
|
||||
|
||||
const WEAVE_VERSION = try
|
||||
'v' * Pkg.TOML.parsefile(normpath(PKG_DIR, "Project.toml"))["version"]
|
||||
catch
|
||||
""
|
||||
end
|
||||
|
||||
weave_info() = WEAVE_VERSION, string(Date(now()))
|
||||
|
||||
# TODO: is there any other format where we want to restore headers ?
|
||||
const HEADER_PRESERVE_DOCTYPES = ("github", "hugo")
|
||||
|
||||
function restore_header!(doc)
|
||||
doc.doctype in HEADER_PRESERVE_DOCTYPES || return # don't restore
|
||||
|
||||
# only strips Weave headers
|
||||
delete!(doc.header, WEAVE_OPTION_NAME)
|
||||
if haskey(doc.header, WEAVE_OPTION_NAME_DEPRECATED)
|
||||
@warn "Weave: `options` key is deprecated. Use `weave_options` key instead." _id = WEAVE_OPTION_DEPRECATE_ID maxlog = 1
|
||||
delete!(doc.header, WEAVE_OPTION_NAME_DEPRECATED)
|
||||
end
|
||||
isempty(doc.header) && return
|
||||
|
||||
# restore remained headers as `DocChunk`
|
||||
header_text = "---\n$(YAML.write(doc.header))---"
|
||||
pushfirst!(doc.chunks, DocChunk(header_text, 0, 0))
|
||||
end
|
||||
|
||||
format_chunk(chunk::DocChunk, docformat) = join((format_inline(c) for c in chunk.content))
|
||||
|
||||
format_inline(inline::InlineText) = inline.content
|
||||
|
||||
function format_inline(inline::InlineCode)
|
||||
isempty(inline.rich_output) || return inline.rich_output
|
||||
isempty(inline.figures) || return inline.figures[end]
|
||||
return inline.output
|
||||
end
|
||||
|
||||
function format_chunk(chunk::DocChunk, docformat::TexFormat)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.latex)
|
||||
write(out, addlines(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end], inline)
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addlines(inline.output, inline))
|
||||
end
|
||||
end
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.latex)
|
||||
out = take2string!(out)
|
||||
return docformat.formatdict[:keep_unicode] ? out : uc2tex(out)
|
||||
end
|
||||
|
||||
function format_chunk(chunk::DocChunk, docformat::JMarkdown2HTML)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.html)
|
||||
write(out, addlines(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end])
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addlines(inline.output, inline))
|
||||
end
|
||||
end
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.html)
|
||||
return take2string!(out)
|
||||
end
|
||||
|
||||
function clear_buffer_and_format!(io::IOBuffer, out::IOBuffer, render_function)
|
||||
text = take2string!(io)
|
||||
m = Markdown.parse(text, flavor = WeaveMarkdown.weavemd)
|
||||
write(out, string(render_function(m)))
|
||||
end
|
||||
|
||||
addlines(op, inline) = inline.ctype === :line ? string('\n', op, '\n') : op
|
||||
|
||||
function format_chunk(chunk::CodeChunk, docformat)
|
||||
formatdict = docformat.formatdict
|
||||
|
||||
# Fill undefined options with format specific defaults
|
||||
isnothing(chunk.options[:out_width]) && (chunk.options[:out_width] = formatdict[:out_width])
|
||||
isnothing(chunk.options[:fig_pos]) && (chunk.options[:fig_pos] = formatdict[:fig_pos])
|
||||
|
||||
# Only use floats if chunk has caption or sets fig_env
|
||||
if !isnothing(chunk.options[:fig_cap]) && isnothing(chunk.options[:fig_env])
|
||||
(chunk.options[:fig_env] = formatdict[:fig_env])
|
||||
end
|
||||
|
||||
haskey(formatdict, :indent) && (chunk.content = indent(chunk.content, formatdict[:indent]))
|
||||
|
||||
chunk.content = format_code(chunk.content, docformat)
|
||||
|
||||
if !chunk.options[:eval]
|
||||
return if chunk.options[:echo]
|
||||
string(formatdict[:codestart], '\n', chunk.content, formatdict[:codeend])
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
if chunk.options[:term]
|
||||
result = format_termchunk(chunk, docformat)
|
||||
else
|
||||
result = if chunk.options[:echo]
|
||||
# Convert to output format and highlight (html, tex...) if needed
|
||||
string(formatdict[:codestart], chunk.content, formatdict[:codeend], '\n')
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
if (strip(chunk.output) ≠ "" || strip(chunk.rich_output) ≠ "") &&
|
||||
(chunk.options[:results] ≠ "hidden")
|
||||
if chunk.options[:results] ≠ "markup" && chunk.options[:results] ≠ "hold"
|
||||
strip(chunk.output) ≠ "" && (result *= "$(chunk.output)\n")
|
||||
strip(chunk.rich_output) ≠ "" && (result *= "$(chunk.rich_output)\n")
|
||||
else
|
||||
if chunk.options[:wrap]
|
||||
chunk.output =
|
||||
'\n' * wraplines(chunk.output, chunk.options[:line_width])
|
||||
chunk.output = format_output(chunk.output, docformat)
|
||||
else
|
||||
chunk.output = '\n' * rstrip(chunk.output)
|
||||
chunk.output = format_output(chunk.output, docformat)
|
||||
end
|
||||
|
||||
if haskey(formatdict, :indent)
|
||||
chunk.output = indent(chunk.output, formatdict[:indent])
|
||||
end
|
||||
strip(chunk.output) ≠ "" && (
|
||||
result *= "$(formatdict[:outputstart])$(chunk.output)\n$(formatdict[:outputend])\n"
|
||||
)
|
||||
strip(chunk.rich_output) ≠ "" && (result *= chunk.rich_output * '\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Handle figures
|
||||
if chunk.options[:fig] && length(chunk.figures) > 0
|
||||
if chunk.options[:include]
|
||||
result *= formatfigures(chunk, docformat)
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
format_output(result, docformat) = result
|
||||
|
||||
format_output(result, docformat::JMarkdown2HTML) = Markdown.htmlesc(result)
|
||||
|
||||
function format_output(result, docformat::TexFormat)
|
||||
# Highligts has some extra escaping defined, eg of $, ", ...
|
||||
result_escaped = sprint(
|
||||
(io, x) ->
|
||||
Highlights.Format.escape(io, MIME("text/latex"), x, charescape = true),
|
||||
result,
|
||||
)
|
||||
docformat.formatdict[:keep_unicode] || return uc2tex(result_escaped, true)
|
||||
return result_escaped
|
||||
end
|
||||
|
||||
format_code(code, docformat) = code
|
||||
|
||||
# return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
|
||||
function format_code(code, docformat::TexFormat)
|
||||
ret = highlight_code(MIME("text/latex"), code, docformat.formatdict[:highlight_theme])
|
||||
docformat.formatdict[:keep_unicode] || return uc2tex(ret)
|
||||
return ret
|
||||
end
|
||||
|
||||
# Convert unicode to tex, escape listings if needed
|
||||
function uc2tex(s, escape = false)
|
||||
for key in keys(latex_symbols)
|
||||
if escape
|
||||
s = replace(s, latex_symbols[key] => "(*@\\ensuremath{$(texify(key))}@*)")
|
||||
else
|
||||
s = replace(s, latex_symbols[key] => "\\ensuremath{$(texify(key))}")
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
# Make julia symbols (\bf* etc.) valid latex
|
||||
function texify(s)
|
||||
return if occursin(r"^\\bf[A-Z]$", s)
|
||||
replace(s, "\\bf" => "\\bm{\\mathrm{") * "}}"
|
||||
elseif startswith(s, "\\bfrak")
|
||||
replace(s, "\\bfrak" => "\\bm{\\mathfrak{") * "}}"
|
||||
elseif startswith(s, "\\bf")
|
||||
replace(s, "\\bf" => "\\bm{\\") * "}"
|
||||
elseif startswith(s, "\\frak")
|
||||
replace(s, "\\frak" => "\\mathfrak{") * "}"
|
||||
else
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
format_code(code, docformat::JMarkdown2HTML) =
|
||||
highlight_code(MIME("text/html"), code, docformat.formatdict[:highlight_theme])
|
||||
|
||||
format_code(code, docformat::Pandoc2HTML) =
|
||||
highlight_code(MIME("text/html"), code, docformat.formatdict[:highlight_theme])
|
||||
|
||||
function format_termchunk(chunk, docformat)
|
||||
return if should_render(chunk)
|
||||
fd = docformat.formatdict
|
||||
string(fd[:termstart], chunk.output, '\n', fd[:termend], '\n')
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
format_termchunk(chunk, docformat::JMarkdown2HTML) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/html"), chunk.output, docformat.formatdict[:highlight_theme]) : ""
|
||||
|
||||
format_termchunk(chunk, docformat::Pandoc2HTML) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/html"), chunk.output, docformat.formatdict[:highlight_theme]) : ""
|
||||
|
||||
# return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
|
||||
format_termchunk(chunk, docformat::TexFormat) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/latex"), chunk.output, docformat.formatdict[:highlight_theme]) : ""
|
||||
|
||||
should_render(chunk) = chunk.options[:echo] && chunk.options[:results] ≠ "hidden"
|
||||
|
||||
highlight_code(mime, code, highlight_theme) =
|
||||
highlight(mime, strip(code), Highlights.Lexers.JuliaLexer, highlight_theme)
|
||||
highlight_term(mime, output, highlight_theme) =
|
||||
highlight(mime, strip(output), Highlights.Lexers.JuliaConsoleLexer, highlight_theme)
|
||||
highlight(mime, output, lexer, theme = Highlights.Themes.DefaultTheme) =
|
||||
sprint((io, x) -> Highlights.highlight(io, mime, x, lexer, theme), output)
|
||||
|
||||
indent(text, nindent) = join(map(x -> string(repeat(' ', nindent), x), split(text, '\n')), '\n')
|
||||
|
||||
function wraplines(text, line_width = 75)
|
||||
result = AbstractString[]
|
||||
lines = split(text, '\n')
|
||||
for line in lines
|
||||
if length(line) > line_width
|
||||
push!(result, wrapline(line, line_width))
|
||||
else
|
||||
push!(result, line)
|
||||
end
|
||||
end
|
||||
|
||||
return strip(join(result, '\n'))
|
||||
end
|
||||
|
||||
function wrapline(text, line_width = 75)
|
||||
result = ""
|
||||
while length(text) > line_width
|
||||
result *= first(text, line_width) * '\n'
|
||||
text = chop(text, head = line_width, tail = 0)
|
||||
end
|
||||
result *= text
|
||||
end
|
||||
|
|
466
src/formats.jl
466
src/formats.jl
|
@ -28,469 +28,3 @@ macro define_format(ex)
|
|||
end
|
||||
# TODO: do some assertion for necessary fields of `formatdict`
|
||||
register_format!(format_name::AbstractString, format::WeaveFormat) = push!(FORMATS, format_name => format)
|
||||
|
||||
# HTML
|
||||
# ----
|
||||
|
||||
@define_format JMarkdown2HTML
|
||||
register_format!("md2html", JMarkdown2HTML(Dict(
|
||||
:description => "Julia markdown to html",
|
||||
:codestart => "\n",
|
||||
:codeend => "\n",
|
||||
:outputstart => "<pre class=\"output\">",
|
||||
:outputend => "</pre>\n",
|
||||
:fig_ext => ".png",
|
||||
:mimetypes => [
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"image/svg+xml",
|
||||
"text/html",
|
||||
"text/markdown",
|
||||
"text/plain",
|
||||
],
|
||||
:extension => "html",
|
||||
)))
|
||||
|
||||
@define_format Pandoc2HTML
|
||||
register_format!("pandoc2html", Pandoc2HTML(Dict(
|
||||
:description => "Markdown to HTML (requires Pandoc 2)",
|
||||
:codestart => "\n",
|
||||
:codeend => "\n",
|
||||
:outputstart => "\n",
|
||||
:outputend => "\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
:mimetypes => [
|
||||
"image/png",
|
||||
"image/svg+xml",
|
||||
"image/jpg",
|
||||
"text/html",
|
||||
"text/markdown",
|
||||
"text/plain",
|
||||
],
|
||||
)))
|
||||
|
||||
|
||||
# PDF and Tex
|
||||
# -----------
|
||||
|
||||
abstract type TexFormat <: WeaveFormat end
|
||||
|
||||
@define_format JMarkdown2tex <: TexFormat
|
||||
let t = JMarkdown2tex(Dict(
|
||||
:description => "Julia markdown to latex",
|
||||
:codestart => "",
|
||||
:codeend => "",
|
||||
:outputstart => "\\begin{lstlisting}",
|
||||
:outputend => "\\end{lstlisting}\n",
|
||||
:fig_ext => ".pdf",
|
||||
:extension => "tex",
|
||||
:out_width => "\\linewidth",
|
||||
:mimetypes => [
|
||||
"application/pdf",
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"text/latex",
|
||||
"text/markdown",
|
||||
"text/plain",
|
||||
],
|
||||
:keep_unicode => false,
|
||||
))
|
||||
register_format!("md2pdf", t)
|
||||
register_format!("md2tex", t)
|
||||
end
|
||||
|
||||
@define_format Tex <: TexFormat
|
||||
register_format!("tex", Tex(Dict(
|
||||
:description => "Latex with custom code environments",
|
||||
:codestart => "\\begin{juliacode}",
|
||||
:codeend => "\\end{juliacode}",
|
||||
:outputstart => "\\begin{juliaout}",
|
||||
:outputend => "\\end{juliaout}",
|
||||
:termstart => "\\begin{juliaterm}",
|
||||
:termend => "\\end{juliaterm}",
|
||||
:fig_ext => ".pdf",
|
||||
:extension => "tex",
|
||||
:out_width => "\\linewidth",
|
||||
:fig_env => "figure",
|
||||
:fig_pos => "htpb",
|
||||
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
|
||||
:keep_unicode => false,
|
||||
)))
|
||||
|
||||
@define_format TexMinted <: TexFormat
|
||||
register_format!("texminted", TexMinted(Dict(
|
||||
:description => "Latex using minted for highlighting",
|
||||
:codestart =>
|
||||
"\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}",
|
||||
:codeend => "\\end{minted}",
|
||||
:outputstart =>
|
||||
"\\begin{minted}[fontsize=\\small, xleftmargin=0.5em, mathescape, frame = leftline]{text}",
|
||||
:outputend => "\\end{minted}",
|
||||
:termstart =>
|
||||
"\\begin{minted}[fontsize=\\footnotesize, xleftmargin=0.5em, mathescape]{jlcon}",
|
||||
:termend => "\\end{minted}",
|
||||
:fig_ext => ".pdf",
|
||||
:extension => "tex",
|
||||
:out_width => "\\linewidth",
|
||||
:fig_env => "figure",
|
||||
:fig_pos => "htpb",
|
||||
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
|
||||
:keep_unicode => false,
|
||||
)))
|
||||
|
||||
|
||||
# pandoc
|
||||
# ------
|
||||
|
||||
@define_format Pandoc
|
||||
let p = Pandoc(Dict(
|
||||
:description => "Pandoc markdown",
|
||||
:codestart => "~~~~{.julia}",
|
||||
:codeend => "~~~~~~~~~~~~~\n\n",
|
||||
:outputstart => "~~~~",
|
||||
:outputend => "~~~~\n\n",
|
||||
:fig_ext => ".png",
|
||||
:out_width => nothing,
|
||||
:extension => "md",
|
||||
# Prefer png figures for markdown conversion, svg doesn't work with latex
|
||||
:mimetypes =>
|
||||
["image/png", "image/jpg", "image/svg+xml", "text/markdown", "text/plain"],
|
||||
))
|
||||
register_format!("pandoc", p)
|
||||
register_format!("pandoc2pdf", p)
|
||||
end
|
||||
|
||||
|
||||
# markdown
|
||||
# --------
|
||||
|
||||
@define_format GitHubMarkdown
|
||||
register_format!("github", GitHubMarkdown(Dict(
|
||||
:description => "GitHub markdown",
|
||||
:codestart => "````julia",
|
||||
:codeend => "````\n\n",
|
||||
:outputstart => "````",
|
||||
:outputend => "````\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
:mimetypes =>
|
||||
["image/png", "image/svg+xml", "image/jpg", "text/markdown", "text/plain"],
|
||||
)))
|
||||
|
||||
@define_format Hugo
|
||||
register_format!("hugo", Hugo(Dict(
|
||||
:description => "Hugo markdown (using shortcodes)",
|
||||
:codestart => "````julia",
|
||||
:codeend => "````\n\n",
|
||||
:outputstart => "````",
|
||||
:outputend => "````\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
:uglyURLs => false, # if `false`, prepend figure path by `..`
|
||||
)))
|
||||
|
||||
@define_format MultiMarkdown
|
||||
register_format!("multimarkdown", MultiMarkdown(Dict(
|
||||
:description => "MultiMarkdown",
|
||||
:codestart => "````julia",
|
||||
:codeend => "````\n\n",
|
||||
:outputstart => "````",
|
||||
:outputend => "````\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
)))
|
||||
|
||||
|
||||
# Rest
|
||||
# ----
|
||||
|
||||
@define_format Rest
|
||||
register_format!("rst", Rest(Dict(
|
||||
:description => "reStructuredText and Sphinx",
|
||||
:codestart => ".. code-block:: julia\n",
|
||||
:codeend => "\n\n",
|
||||
:outputstart => "::\n",
|
||||
:outputend => "\n\n",
|
||||
:indent => 4,
|
||||
:fig_ext => ".png",
|
||||
:extension => "rst",
|
||||
:out_width => "15 cm",
|
||||
)))
|
||||
|
||||
|
||||
# Ansii
|
||||
# -----
|
||||
|
||||
# asciidoc -b html5 -a source-highlighter=pygments ...
|
||||
@define_format AsciiDoc
|
||||
register_format!("asciidoc", AsciiDoc(Dict(
|
||||
:description => "AsciiDoc",
|
||||
:codestart => "[source,julia]\n--------------------------------------",
|
||||
:codeend => "--------------------------------------\n\n",
|
||||
:outputstart => "--------------------------------------",
|
||||
:outputend => "--------------------------------------\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "txt",
|
||||
:out_width => "600",
|
||||
)))
|
||||
|
||||
|
||||
# TODO: move this functions where used
|
||||
# ------------------------------------
|
||||
|
||||
using Printf
|
||||
|
||||
|
||||
function md_length_to_latex(def, reference)
|
||||
if occursin("%", def)
|
||||
_def = tryparse(Float64, replace(def, "%" => ""))
|
||||
_def == nothing && return def
|
||||
perc = round(_def / 100, digits = 2)
|
||||
return "$perc$reference"
|
||||
end
|
||||
return def
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::JMarkdown2HTML)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
# Set size
|
||||
attribs = ""
|
||||
width == nothing || (attribs = "width=\"$width\"")
|
||||
(attribs != "" && height != nothing) && (attribs *= ",")
|
||||
height == nothing || (attribs *= " height=\"$height\" ")
|
||||
|
||||
if caption != nothing
|
||||
result *= """<figure>\n"""
|
||||
end
|
||||
|
||||
for fig in fignames
|
||||
figstring *= """<img src="$fig" $attribs />\n"""
|
||||
end
|
||||
|
||||
result *= figstring
|
||||
|
||||
if caption != nothing
|
||||
result *= """
|
||||
<figcaption>$caption</figcaption>
|
||||
"""
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= "</figure>\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::TexFormat)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
if f_env == nothing && caption != nothing
|
||||
f_env = "figure"
|
||||
end
|
||||
|
||||
(f_pos == nothing) && (f_pos = "!h")
|
||||
# Set size
|
||||
attribs = ""
|
||||
width == nothing || (attribs = "width=$(md_length_to_latex(width,"\\linewidth"))")
|
||||
(attribs != "" && height != nothing) && (attribs *= ",")
|
||||
height == nothing || (attribs *= "height=$(md_length_to_latex(height,"\\paperheight"))")
|
||||
|
||||
if f_env != nothing
|
||||
result *= "\\begin{$f_env}"
|
||||
(f_pos != "") && (result *= "[$f_pos]")
|
||||
result *= "\n"
|
||||
end
|
||||
|
||||
for fig in fignames
|
||||
if splitext(fig)[2] == ".tex" # Tikz figures
|
||||
figstring *= "\\resizebox{$width}{!}{\\input{$fig}}\n"
|
||||
else
|
||||
if isempty(attribs)
|
||||
figstring *= "\\includegraphics{$fig}\n"
|
||||
else
|
||||
figstring *= "\\includegraphics[$attribs]{$fig}\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Figure environment
|
||||
if caption != nothing
|
||||
result *= string("\\center\n", "$figstring", "\\caption{$caption}\n")
|
||||
else
|
||||
result *= figstring
|
||||
end
|
||||
|
||||
if chunk.options[:label] != nothing && f_env != nothing
|
||||
label = chunk.options[:label]
|
||||
result *= "\\label{fig:$label}\n"
|
||||
end
|
||||
|
||||
if f_env != nothing
|
||||
result *= "\\end{$f_env}\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
formatfigures(chunk, docformat::Pandoc2HTML) = formatfigures(chunk, pandoc)
|
||||
|
||||
function formatfigures(chunk, docformat::Pandoc)
|
||||
fignames = chunk.figures
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
caption = chunk.options[:fig_cap]
|
||||
label = get(chunk.options, :label, nothing)
|
||||
result = ""
|
||||
figstring = ""
|
||||
attribs = ""
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
|
||||
# Build figure attibutes
|
||||
attribs = String[]
|
||||
width == nothing || push!(attribs, "width=$width")
|
||||
height == nothing || push!(attribs, "height=$height")
|
||||
label == nothing || push!(attribs, "#fig:$label")
|
||||
attribs = isempty(attribs) ? "" : "{" * join(attribs, " ") * "}"
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption]($(fignames[1]))$attribs\n"
|
||||
for fig in fignames[2:end]
|
||||
result *= "![]($fig)$attribs\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![]($fig)$attribs\\ \n\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::GitHubMarkdown)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption]($(fignames[1]))\n"
|
||||
for fig in fignames[2:end]
|
||||
result *= "![]($fig)\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![]($fig)\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::Hugo)
|
||||
relpath = docformat.formatdict[:uglyURLs] ? "" : ".."
|
||||
function format_shortcode(index_and_fig)
|
||||
index, fig = index_and_fig
|
||||
if index > 1
|
||||
@warn("Only the first figure gets a caption.")
|
||||
title_spec = ""
|
||||
else
|
||||
caption = chunk.options[:fig_cap]
|
||||
title_spec = caption == nothing ? "" : "title=\"$(caption)\" "
|
||||
end
|
||||
"{{< figure src=\"$(joinpath(relpath, fig))\" $(title_spec) >}}"
|
||||
end
|
||||
mapreduce(format_shortcode, *, enumerate(chunk.figures), init = "")
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::MultiMarkdown)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
if chunk.options[:out_width] == nothing
|
||||
width = ""
|
||||
else
|
||||
width = "width=$(chunk.options[:out_width])"
|
||||
end
|
||||
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption][$(fignames[1])]\n\n"
|
||||
result *= "[$(fignames[1])]: $(fignames[1]) $width\n"
|
||||
for fig in fignames[2:end]
|
||||
result *= "![][$fig]\n\n"
|
||||
result *= "[$fig]: $fig $width\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![][$fig]\n\n"
|
||||
result *= "[$fig]: $fig $width\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::Rest)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
for fig in fignames
|
||||
figstring *= @sprintf(".. image:: %s\n :width: %s\n\n", fig, width)
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= string(
|
||||
".. figure:: $(fignames[1])\n",
|
||||
" :width: $width\n\n",
|
||||
" $caption\n\n",
|
||||
)
|
||||
else
|
||||
result *= figstring
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::AsciiDoc)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
for fig in fignames
|
||||
figstring *= @sprintf("image::%s[width=%s]\n", fig, width)
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= string("image::$(fignames[1])", "[width=$width,", "title=\"$caption\"]")
|
||||
else
|
||||
result *= figstring
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
|
||||
# TODO: is there any other format where we want to restore headers ?
|
||||
# make this field of format struct
|
||||
const HEADER_PRESERVE_DOCTYPES = ("github", "hugo")
|
||||
|
||||
|
||||
function restore_header!(doc)
|
||||
doc.doctype in HEADER_PRESERVE_DOCTYPES || return # don't restore
|
||||
|
||||
# only strips Weave headers
|
||||
delete!(doc.header, WEAVE_OPTION_NAME)
|
||||
if haskey(doc.header, WEAVE_OPTION_NAME_DEPRECATED)
|
||||
@warn "Weave: `options` key is deprecated. Use `weave_options` key instead." _id = WEAVE_OPTION_DEPRECATE_ID maxlog = 1
|
||||
delete!(doc.header, WEAVE_OPTION_NAME_DEPRECATED)
|
||||
end
|
||||
isempty(doc.header) && return
|
||||
|
||||
# restore remained headers as `DocChunk`
|
||||
header_text = "---\n$(YAML.write(doc.header))---"
|
||||
pushfirst!(doc.chunks, DocChunk(header_text, 0, 0))
|
||||
end
|
||||
|
||||
format_chunk(chunk::DocChunk, docformat) = join((format_inline(c) for c in chunk.content))
|
||||
|
||||
format_inline(inline::InlineText) = inline.content
|
||||
|
||||
function format_inline(inline::InlineCode)
|
||||
isempty(inline.rich_output) || return inline.rich_output
|
||||
isempty(inline.figures) || return inline.figures[end]
|
||||
return inline.output
|
||||
end
|
||||
|
||||
|
||||
function clear_buffer_and_format!(io::IOBuffer, out::IOBuffer, render_function)
|
||||
text = take2string!(io)
|
||||
m = Markdown.parse(text, flavor = WeaveMarkdown.weavemd)
|
||||
write(out, string(render_function(m)))
|
||||
end
|
||||
|
||||
addlines(op, inline) = inline.ctype === :line ? string('\n', op, '\n') : op
|
||||
|
||||
function format_chunk(chunk::CodeChunk, docformat)
|
||||
formatdict = docformat.formatdict
|
||||
|
||||
# Fill undefined options with format specific defaults
|
||||
isnothing(chunk.options[:out_width]) && (chunk.options[:out_width] = formatdict[:out_width])
|
||||
isnothing(chunk.options[:fig_pos]) && (chunk.options[:fig_pos] = formatdict[:fig_pos])
|
||||
|
||||
# Only use floats if chunk has caption or sets fig_env
|
||||
if !isnothing(chunk.options[:fig_cap]) && isnothing(chunk.options[:fig_env])
|
||||
(chunk.options[:fig_env] = formatdict[:fig_env])
|
||||
end
|
||||
|
||||
haskey(formatdict, :indent) && (chunk.content = indent(chunk.content, formatdict[:indent]))
|
||||
|
||||
chunk.content = format_code(chunk.content, docformat)
|
||||
|
||||
if !chunk.options[:eval]
|
||||
return if chunk.options[:echo]
|
||||
string(formatdict[:codestart], '\n', chunk.content, formatdict[:codeend])
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
if chunk.options[:term]
|
||||
result = format_termchunk(chunk, docformat)
|
||||
else
|
||||
result = if chunk.options[:echo]
|
||||
# Convert to output format and highlight (html, tex...) if needed
|
||||
string(formatdict[:codestart], chunk.content, formatdict[:codeend], '\n')
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
if (strip(chunk.output) ≠ "" || strip(chunk.rich_output) ≠ "") &&
|
||||
(chunk.options[:results] ≠ "hidden")
|
||||
if chunk.options[:results] ≠ "markup" && chunk.options[:results] ≠ "hold"
|
||||
strip(chunk.output) ≠ "" && (result *= "$(chunk.output)\n")
|
||||
strip(chunk.rich_output) ≠ "" && (result *= "$(chunk.rich_output)\n")
|
||||
else
|
||||
if chunk.options[:wrap]
|
||||
chunk.output =
|
||||
'\n' * wraplines(chunk.output, chunk.options[:line_width])
|
||||
chunk.output = format_output(chunk.output, docformat)
|
||||
else
|
||||
chunk.output = '\n' * rstrip(chunk.output)
|
||||
chunk.output = format_output(chunk.output, docformat)
|
||||
end
|
||||
|
||||
if haskey(formatdict, :indent)
|
||||
chunk.output = indent(chunk.output, formatdict[:indent])
|
||||
end
|
||||
strip(chunk.output) ≠ "" && (
|
||||
result *= "$(formatdict[:outputstart])$(chunk.output)\n$(formatdict[:outputend])\n"
|
||||
)
|
||||
strip(chunk.rich_output) ≠ "" && (result *= chunk.rich_output * '\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Handle figures
|
||||
if chunk.options[:fig] && length(chunk.figures) > 0
|
||||
if chunk.options[:include]
|
||||
result *= formatfigures(chunk, docformat)
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
format_code(code, docformat) = code
|
||||
|
||||
format_output(result, docformat) = result
|
||||
|
||||
|
||||
# Make julia symbols (\bf* etc.) valid latex
|
||||
function texify(s)
|
||||
return if occursin(r"^\\bf[A-Z]$", s)
|
||||
replace(s, "\\bf" => "\\bm{\\mathrm{") * "}}"
|
||||
elseif startswith(s, "\\bfrak")
|
||||
replace(s, "\\bfrak" => "\\bm{\\mathfrak{") * "}}"
|
||||
elseif startswith(s, "\\bf")
|
||||
replace(s, "\\bf" => "\\bm{\\") * "}"
|
||||
elseif startswith(s, "\\frak")
|
||||
replace(s, "\\frak" => "\\mathfrak{") * "}"
|
||||
else
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
function format_termchunk(chunk, docformat)
|
||||
return if should_render(chunk)
|
||||
fd = docformat.formatdict
|
||||
string(fd[:termstart], chunk.output, '\n', fd[:termend], '\n')
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
should_render(chunk) = chunk.options[:echo] && chunk.options[:results] ≠ "hidden"
|
||||
|
||||
highlight_code(mime, code, highlight_theme) =
|
||||
highlight(mime, strip(code), Highlights.Lexers.JuliaLexer, highlight_theme)
|
||||
highlight_term(mime, output, highlight_theme) =
|
||||
highlight(mime, strip(output), Highlights.Lexers.JuliaConsoleLexer, highlight_theme)
|
||||
highlight(mime, output, lexer, theme = Highlights.Themes.DefaultTheme) =
|
||||
sprint((io, x) -> Highlights.highlight(io, mime, x, lexer, theme), output)
|
||||
|
||||
|
||||
|
||||
indent(text, nindent) = join(map(x -> string(repeat(' ', nindent), x), split(text, '\n')), '\n')
|
||||
|
||||
function wraplines(text, line_width = 75)
|
||||
result = AbstractString[]
|
||||
lines = split(text, '\n')
|
||||
for line in lines
|
||||
if length(line) > line_width
|
||||
push!(result, wrapline(line, line_width))
|
||||
else
|
||||
push!(result, line)
|
||||
end
|
||||
end
|
||||
|
||||
return strip(join(result, '\n'))
|
||||
end
|
||||
|
||||
function wrapline(text, line_width = 75)
|
||||
result = ""
|
||||
while length(text) > line_width
|
||||
result *= first(text, line_width) * '\n'
|
||||
text = chop(text, head = line_width, tail = 0)
|
||||
end
|
||||
result *= text
|
||||
end
|
|
@ -0,0 +1,137 @@
|
|||
# HTML
|
||||
# ----
|
||||
|
||||
@define_format JMarkdown2HTML
|
||||
register_format!("md2html", JMarkdown2HTML(Dict(
|
||||
:description => "Julia markdown to html",
|
||||
:codestart => "\n",
|
||||
:codeend => "\n",
|
||||
:outputstart => "<pre class=\"output\">",
|
||||
:outputend => "</pre>\n",
|
||||
:fig_ext => ".png",
|
||||
:mimetypes => [
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"image/svg+xml",
|
||||
"text/html",
|
||||
"text/markdown",
|
||||
"text/plain",
|
||||
],
|
||||
:extension => "html",
|
||||
)))
|
||||
|
||||
@define_format Pandoc2HTML
|
||||
register_format!("pandoc2html", Pandoc2HTML(Dict(
|
||||
:description => "Markdown to HTML (requires Pandoc 2)",
|
||||
:codestart => "\n",
|
||||
:codeend => "\n",
|
||||
:outputstart => "\n",
|
||||
:outputend => "\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
:mimetypes => [
|
||||
"image/png",
|
||||
"image/svg+xml",
|
||||
"image/jpg",
|
||||
"text/html",
|
||||
"text/markdown",
|
||||
"text/plain",
|
||||
],
|
||||
)))
|
||||
|
||||
|
||||
function render_doc(::JMarkdown2HTML, body, doc, template, css, highlight_theme)
|
||||
_, weave_source = splitdir(abspath(doc.source))
|
||||
weave_version, weave_date = weave_info()
|
||||
|
||||
return Mustache.render(
|
||||
get_html_template(template);
|
||||
body = body,
|
||||
stylesheet = get_stylesheet(css),
|
||||
highlight_stylesheet = get_highlight_stylesheet(MIME("text/html"), highlight_theme),
|
||||
header_script = doc.header_script,
|
||||
weave_source = weave_source,
|
||||
weave_version = weave_version,
|
||||
weave_date = weave_date,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
function format_chunk(chunk::DocChunk, docformat::JMarkdown2HTML)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.html)
|
||||
write(out, addlines(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end])
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addlines(inline.output, inline))
|
||||
end
|
||||
end
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.html)
|
||||
return take2string!(out)
|
||||
end
|
||||
|
||||
format_output(result, docformat::JMarkdown2HTML) = Markdown.htmlesc(result)
|
||||
|
||||
format_code(code, docformat::JMarkdown2HTML) =
|
||||
highlight_code(MIME("text/html"), code, docformat.formatdict[:highlight_theme])
|
||||
|
||||
format_code(code, docformat::Pandoc2HTML) =
|
||||
highlight_code(MIME("text/html"), code, docformat.formatdict[:highlight_theme])
|
||||
|
||||
|
||||
|
||||
format_termchunk(chunk, docformat::JMarkdown2HTML) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/html"), chunk.output, docformat.formatdict[:highlight_theme]) : ""
|
||||
|
||||
format_termchunk(chunk, docformat::Pandoc2HTML) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/html"), chunk.output, docformat.formatdict[:highlight_theme]) : ""
|
||||
|
||||
|
||||
function formatfigures(chunk, docformat::JMarkdown2HTML)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
# Set size
|
||||
attribs = ""
|
||||
width == nothing || (attribs = "width=\"$width\"")
|
||||
(attribs != "" && height != nothing) && (attribs *= ",")
|
||||
height == nothing || (attribs *= " height=\"$height\" ")
|
||||
|
||||
if caption != nothing
|
||||
result *= """<figure>\n"""
|
||||
end
|
||||
|
||||
for fig in fignames
|
||||
figstring *= """<img src="$fig" $attribs />\n"""
|
||||
end
|
||||
|
||||
result *= figstring
|
||||
|
||||
if caption != nothing
|
||||
result *= """
|
||||
<figcaption>$caption</figcaption>
|
||||
"""
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= "</figure>\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
formatfigures(chunk, docformat::Pandoc2HTML) = formatfigures(chunk, pandoc)
|
|
@ -0,0 +1,111 @@
|
|||
# markdown
|
||||
# --------
|
||||
|
||||
@define_format GitHubMarkdown
|
||||
register_format!("github", GitHubMarkdown(Dict(
|
||||
:description => "GitHub markdown",
|
||||
:codestart => "````julia",
|
||||
:codeend => "````\n\n",
|
||||
:outputstart => "````",
|
||||
:outputend => "````\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
:mimetypes =>
|
||||
["image/png", "image/svg+xml", "image/jpg", "text/markdown", "text/plain"],
|
||||
)))
|
||||
|
||||
@define_format Hugo
|
||||
register_format!("hugo", Hugo(Dict(
|
||||
:description => "Hugo markdown (using shortcodes)",
|
||||
:codestart => "````julia",
|
||||
:codeend => "````\n\n",
|
||||
:outputstart => "````",
|
||||
:outputend => "````\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
:uglyURLs => false, # if `false`, prepend figure path by `..`
|
||||
)))
|
||||
|
||||
@define_format MultiMarkdown
|
||||
register_format!("multimarkdown", MultiMarkdown(Dict(
|
||||
:description => "MultiMarkdown",
|
||||
:codestart => "````julia",
|
||||
:codeend => "````\n\n",
|
||||
:outputstart => "````",
|
||||
:outputend => "````\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function formatfigures(chunk, docformat::GitHubMarkdown)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption]($(fignames[1]))\n"
|
||||
for fig in fignames[2:end]
|
||||
result *= "![]($fig)\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![]($fig)\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::Hugo)
|
||||
relpath = docformat.formatdict[:uglyURLs] ? "" : ".."
|
||||
function format_shortcode(index_and_fig)
|
||||
index, fig = index_and_fig
|
||||
if index > 1
|
||||
@warn("Only the first figure gets a caption.")
|
||||
title_spec = ""
|
||||
else
|
||||
caption = chunk.options[:fig_cap]
|
||||
title_spec = caption == nothing ? "" : "title=\"$(caption)\" "
|
||||
end
|
||||
"{{< figure src=\"$(joinpath(relpath, fig))\" $(title_spec) >}}"
|
||||
end
|
||||
mapreduce(format_shortcode, *, enumerate(chunk.figures), init = "")
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::MultiMarkdown)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
if chunk.options[:out_width] == nothing
|
||||
width = ""
|
||||
else
|
||||
width = "width=$(chunk.options[:out_width])"
|
||||
end
|
||||
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption][$(fignames[1])]\n\n"
|
||||
result *= "[$(fignames[1])]: $(fignames[1]) $width\n"
|
||||
for fig in fignames[2:end]
|
||||
result *= "![][$fig]\n\n"
|
||||
result *= "[$fig]: $fig $width\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![][$fig]\n\n"
|
||||
result *= "[$fig]: $fig $width\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
|
@ -0,0 +1,247 @@
|
|||
# PDF and Tex
|
||||
# -----------
|
||||
|
||||
abstract type TexFormat <: WeaveFormat end
|
||||
|
||||
@define_format JMarkdown2tex <: TexFormat
|
||||
let t = JMarkdown2tex(Dict(
|
||||
:description => "Julia markdown to latex",
|
||||
:codestart => "",
|
||||
:codeend => "",
|
||||
:outputstart => "\\begin{lstlisting}",
|
||||
:outputend => "\\end{lstlisting}\n",
|
||||
:fig_ext => ".pdf",
|
||||
:extension => "tex",
|
||||
:out_width => "\\linewidth",
|
||||
:mimetypes => [
|
||||
"application/pdf",
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"text/latex",
|
||||
"text/markdown",
|
||||
"text/plain",
|
||||
],
|
||||
:keep_unicode => false,
|
||||
))
|
||||
register_format!("md2pdf", t)
|
||||
register_format!("md2tex", t)
|
||||
end
|
||||
|
||||
# Base.@kwdef mutable struct JMarkdown2tex <: TexFormat
|
||||
# codestart = ""
|
||||
# codeend = ""
|
||||
# outputstart = "\\begin{lstlisting}",
|
||||
# outputend = "\\end{lstlisting}\n",
|
||||
# fig_ext = ".pdf",
|
||||
# extension = "tex",
|
||||
# out_width = "\\linewidth",
|
||||
# mimetypes => [
|
||||
# "application/pdf",
|
||||
# "image/png",
|
||||
# "image/jpg",
|
||||
# "text/latex",
|
||||
# "text/markdown",
|
||||
# "text/plain",
|
||||
# ],
|
||||
# keep_unicode => false,
|
||||
# end
|
||||
# register_format!("md2tex", JMarkdown2tex())
|
||||
|
||||
@define_format Tex <: TexFormat
|
||||
register_format!("tex", Tex(Dict(
|
||||
:description => "Latex with custom code environments",
|
||||
:codestart => "\\begin{juliacode}",
|
||||
:codeend => "\\end{juliacode}",
|
||||
:outputstart => "\\begin{juliaout}",
|
||||
:outputend => "\\end{juliaout}",
|
||||
:termstart => "\\begin{juliaterm}",
|
||||
:termend => "\\end{juliaterm}",
|
||||
:fig_ext => ".pdf",
|
||||
:extension => "tex",
|
||||
:out_width => "\\linewidth",
|
||||
:fig_env => "figure",
|
||||
:fig_pos => "htpb",
|
||||
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
|
||||
:keep_unicode => false,
|
||||
)))
|
||||
|
||||
@define_format TexMinted <: TexFormat
|
||||
register_format!("texminted", TexMinted(Dict(
|
||||
:description => "Latex using minted for highlighting",
|
||||
:codestart =>
|
||||
"\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}",
|
||||
:codeend => "\\end{minted}",
|
||||
:outputstart =>
|
||||
"\\begin{minted}[fontsize=\\small, xleftmargin=0.5em, mathescape, frame = leftline]{text}",
|
||||
:outputend => "\\end{minted}",
|
||||
:termstart =>
|
||||
"\\begin{minted}[fontsize=\\footnotesize, xleftmargin=0.5em, mathescape]{jlcon}",
|
||||
:termend => "\\end{minted}",
|
||||
:fig_ext => ".pdf",
|
||||
:extension => "tex",
|
||||
:out_width => "\\linewidth",
|
||||
:fig_env => "figure",
|
||||
:fig_pos => "htpb",
|
||||
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
|
||||
:keep_unicode => false,
|
||||
)))
|
||||
|
||||
|
||||
|
||||
|
||||
#### These function are identical
|
||||
function render_doc(::JMarkdown2tex, body, doc, template, _, highlight_theme)
|
||||
return Mustache.render(
|
||||
get_tex_template(template);
|
||||
body = body,
|
||||
highlight = get_highlight_stylesheet(MIME("text/latex"), highlight_theme),
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
function render_doc(::Tex, body, doc, template, _, highlight_theme)
|
||||
return Mustache.render(
|
||||
get_tex_template(template);
|
||||
body = body,
|
||||
highlight = get_highlight_stylesheet(MIME("text/latex"), highlight_theme),
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
function render_doc(::TexMinted, body, doc, template, _, highlight_theme)
|
||||
return Mustache.render(
|
||||
get_tex_template(template);
|
||||
body = body,
|
||||
highlight = get_highlight_stylesheet(MIME("text/latex"), highlight_theme),
|
||||
minted = true,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
# very similar to export to html
|
||||
function format_chunk(chunk::DocChunk, docformat::TexFormat)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.latex)
|
||||
write(out, addlines(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end], inline)
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addlines(inline.output, inline))
|
||||
end
|
||||
end
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.latex)
|
||||
out = take2string!(out)
|
||||
return docformat.formatdict[:keep_unicode] ? out : uc2tex(out)
|
||||
end
|
||||
|
||||
function format_output(result, docformat::TexFormat)
|
||||
# Highligts has some extra escaping defined, eg of $, ", ...
|
||||
result_escaped = sprint(
|
||||
(io, x) ->
|
||||
Highlights.Format.escape(io, MIME("text/latex"), x, charescape = true),
|
||||
result,
|
||||
)
|
||||
docformat.formatdict[:keep_unicode] || return uc2tex(result_escaped, true)
|
||||
return result_escaped
|
||||
end
|
||||
|
||||
# return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
|
||||
function format_code(code, docformat::TexFormat)
|
||||
ret = highlight_code(MIME("text/latex"), code, docformat.formatdict[:highlight_theme])
|
||||
docformat.formatdict[:keep_unicode] || return uc2tex(ret)
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
# Convert unicode to tex, escape listings if needed
|
||||
function uc2tex(s, escape = false)
|
||||
for key in keys(latex_symbols)
|
||||
if escape
|
||||
s = replace(s, latex_symbols[key] => "(*@\\ensuremath{$(texify(key))}@*)")
|
||||
else
|
||||
s = replace(s, latex_symbols[key] => "\\ensuremath{$(texify(key))}")
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
|
||||
# return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
|
||||
format_termchunk(chunk, docformat::TexFormat) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/latex"), chunk.output, docformat.formatdict[:highlight_theme]) : ""
|
||||
|
||||
|
||||
function formatfigures(chunk, docformat::TexFormat)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
if f_env == nothing && caption != nothing
|
||||
f_env = "figure"
|
||||
end
|
||||
|
||||
(f_pos == nothing) && (f_pos = "!h")
|
||||
# Set size
|
||||
attribs = ""
|
||||
width == nothing || (attribs = "width=$(md_length_to_latex(width,"\\linewidth"))")
|
||||
(attribs != "" && height != nothing) && (attribs *= ",")
|
||||
height == nothing || (attribs *= "height=$(md_length_to_latex(height,"\\paperheight"))")
|
||||
|
||||
if f_env != nothing
|
||||
result *= "\\begin{$f_env}"
|
||||
(f_pos != "") && (result *= "[$f_pos]")
|
||||
result *= "\n"
|
||||
end
|
||||
|
||||
for fig in fignames
|
||||
if splitext(fig)[2] == ".tex" # Tikz figures
|
||||
figstring *= "\\resizebox{$width}{!}{\\input{$fig}}\n"
|
||||
else
|
||||
if isempty(attribs)
|
||||
figstring *= "\\includegraphics{$fig}\n"
|
||||
else
|
||||
figstring *= "\\includegraphics[$attribs]{$fig}\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Figure environment
|
||||
if caption != nothing
|
||||
result *= string("\\center\n", "$figstring", "\\caption{$caption}\n")
|
||||
else
|
||||
result *= figstring
|
||||
end
|
||||
|
||||
if chunk.options[:label] != nothing && f_env != nothing
|
||||
label = chunk.options[:label]
|
||||
result *= "\\label{fig:$label}\n"
|
||||
end
|
||||
|
||||
if f_env != nothing
|
||||
result *= "\\end{$f_env}\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
function md_length_to_latex(def, reference)
|
||||
if occursin("%", def)
|
||||
_def = tryparse(Float64, replace(def, "%" => ""))
|
||||
_def == nothing && return def
|
||||
perc = round(_def / 100, digits = 2)
|
||||
return "$perc$reference"
|
||||
end
|
||||
return def
|
||||
end
|
|
@ -0,0 +1,136 @@
|
|||
# pandoc
|
||||
# ------
|
||||
|
||||
@define_format Pandoc
|
||||
let p = Pandoc(Dict(
|
||||
:description => "Pandoc markdown",
|
||||
:codestart => "~~~~{.julia}",
|
||||
:codeend => "~~~~~~~~~~~~~\n\n",
|
||||
:outputstart => "~~~~",
|
||||
:outputend => "~~~~\n\n",
|
||||
:fig_ext => ".png",
|
||||
:out_width => nothing,
|
||||
:extension => "md",
|
||||
# Prefer png figures for markdown conversion, svg doesn't work with latex
|
||||
:mimetypes =>
|
||||
["image/png", "image/jpg", "image/svg+xml", "text/markdown", "text/plain"],
|
||||
))
|
||||
register_format!("pandoc", p)
|
||||
register_format!("pandoc2pdf", p)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
# Rest
|
||||
# ----
|
||||
|
||||
@define_format Rest
|
||||
register_format!("rst", Rest(Dict(
|
||||
:description => "reStructuredText and Sphinx",
|
||||
:codestart => ".. code-block:: julia\n",
|
||||
:codeend => "\n\n",
|
||||
:outputstart => "::\n",
|
||||
:outputend => "\n\n",
|
||||
:indent => 4,
|
||||
:fig_ext => ".png",
|
||||
:extension => "rst",
|
||||
:out_width => "15 cm",
|
||||
)))
|
||||
|
||||
|
||||
# Ansii
|
||||
# -----
|
||||
|
||||
# asciidoc -b html5 -a source-highlighter=pygments ...
|
||||
@define_format AsciiDoc
|
||||
register_format!("asciidoc", AsciiDoc(Dict(
|
||||
:description => "AsciiDoc",
|
||||
:codestart => "[source,julia]\n--------------------------------------",
|
||||
:codeend => "--------------------------------------\n\n",
|
||||
:outputstart => "--------------------------------------",
|
||||
:outputend => "--------------------------------------\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "txt",
|
||||
:out_width => "600",
|
||||
)))
|
||||
|
||||
|
||||
|
||||
|
||||
function formatfigures(chunk, docformat::Pandoc)
|
||||
fignames = chunk.figures
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
caption = chunk.options[:fig_cap]
|
||||
label = get(chunk.options, :label, nothing)
|
||||
result = ""
|
||||
figstring = ""
|
||||
attribs = ""
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
|
||||
# Build figure attibutes
|
||||
attribs = String[]
|
||||
width == nothing || push!(attribs, "width=$width")
|
||||
height == nothing || push!(attribs, "height=$height")
|
||||
label == nothing || push!(attribs, "#fig:$label")
|
||||
attribs = isempty(attribs) ? "" : "{" * join(attribs, " ") * "}"
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption]($(fignames[1]))$attribs\n"
|
||||
for fig in fignames[2:end]
|
||||
result *= "![]($fig)$attribs\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![]($fig)$attribs\\ \n\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
function formatfigures(chunk, docformat::Rest)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
for fig in fignames
|
||||
figstring *= @sprintf(".. image:: %s\n :width: %s\n\n", fig, width)
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= string(
|
||||
".. figure:: $(fignames[1])\n",
|
||||
" :width: $width\n\n",
|
||||
" $caption\n\n",
|
||||
)
|
||||
else
|
||||
result *= figstring
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::AsciiDoc)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
for fig in fignames
|
||||
figstring *= @sprintf("image::%s[width=%s]\n", fig, width)
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= string("image::$(fignames[1])", "[width=$width,", "title=\"$caption\"]")
|
||||
else
|
||||
result *= figstring
|
||||
return result
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue