Merge branch 'master' into exportaswrapper

pull/380/head
Shuhei Kadowaki 2020-10-03 13:38:33 +09:00
commit 955675d89a
14 changed files with 87 additions and 117 deletions

View File

@ -15,7 +15,7 @@ jobs:
fail-fast: false # don't stop CI even when one of them fails fail-fast: false # don't stop CI even when one of them fails
matrix: matrix:
version: version:
- '1.4' - '1.5'
os: os:
- ubuntu-latest - ubuntu-latest
- macOS-latest - macOS-latest

View File

@ -3,7 +3,7 @@ language: julia
jobs: jobs:
include: include:
- stage: "Documentation" - stage: "Documentation"
julia: 1 julia: 1.5
os: linux os: linux
script: script:
- julia --project=doc/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - julia --project=doc/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'

15
NEWS.md
View File

@ -1,6 +1,19 @@
## Release notes for Weave.jl ## Release notes for Weave.jl
### v0.10 - 2020/05/18 ### v0.10.6 2020/10/03
improvements:
- cleaned up chunk rendering (removed unnecessary extra newlines): #401
- `WEAVE_ARGS` now can take arbitrary objects: https://github.com/JunoLab/Weave.jl/commit/c24a2621359b5d0af1bb6825f488e58cc11b8a9e
- improved docs: #397 by @baggepinnen
bug fixes
- fixed #398: #399
- removed unnecessary quote for markdown output: https://github.com/JunoLab/Weave.jl/commit/a1830e05029f33195627ec5dedbacb30af23947e
- fixed #386: #396 by @torfjelde
### v0.10 2020/05/18
improvements: improvements:
- `weave` is now integrated with Juno's progress bar; just call `weave` function inside Juno or use `julia-client: weave-to-html(pdf)` command (#331) - `weave` is now integrated with Juno's progress bar; just call `weave` function inside Juno or use `julia-client: weave-to-html(pdf)` command (#331)

View File

@ -1,6 +1,6 @@
name = "Weave" name = "Weave"
uuid = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9" uuid = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"
version = "0.10.2" version = "0.10.6"
[deps] [deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

View File

@ -39,11 +39,11 @@ Note that `Date` is available since the chunk is evaluated first.
--- ---
title : Header Example title : Header Example
author : Shuhei Kadowaki author : Shuhei Kadowaki
date: `j Date(now())` date: `j import Dates; Dates.Date(Dates.now())`
--- ---
```julia; echo = false ```julia; echo = false
using Datas using Dates
``` ```
``` ```

View File

@ -165,29 +165,12 @@ See [Header Configuration](@ref) section for more details.
## Passing Runtime Arguments to Documents ## Passing Runtime Arguments to Documents
You can pass arguments as `Dict` to the weaved document using the `args` argument You can pass arbitrary object to the weaved document using [`weave`](@ref)'s optional argument `args`.
to `weave`. The arguments will be available as `WEAVE_ARGS` variable in the document. It will be available as `WEAVE_ARGS` variable in the `weave`d document.
This makes it possible to create the same report easily for e.g. different This makes it possible to create the same report easily for e.g. different date ranges of input data from a database or from files with similar format giving the filename as input.
date ranges of input data from a database or from files with similar format giving the
filename as input.
In order to pass a filename to a document you need call `weave` using: E.g. if you call `weave("weavefile.jmd", args = (datalocation = "somedata.h5",))`, and then you can retrieve the `datalocation` in `weavefile.jmd` as follows: `WEAVE_ARGS.datalocation`
```julia
weave("mydoc.jmd", args = Dict("filename" => "somedata.h5"))
```
and you can access the filename from document as follows:
```
```julia
print(WEAVE_ARGS["filename"])
```
```
You can use the `out_path` argument to control the name of the
output document.
## `include_weave` ## `include_weave`

View File

@ -102,7 +102,7 @@ Weave an input document to output file.
* `:doc`: Path of the source document (default) * `:doc`: Path of the source document (default)
* `:pwd`: Julia working directory * `:pwd`: Julia working directory
* `"somepath"`: `String` of output directory e.g. `"~/outdir"`, or of filename e.g. `"~/outdir/outfile.tex"` * `"somepath"`: `String` of output directory e.g. `"~/outdir"`, or of filename e.g. `"~/outdir/outfile.tex"`
- `args::Dict = Dict()`: Arguments to be passed to the weaved document; will be available as `WEAVE_ARGS` in the document - `args::Any = Dict()`: A runtime object that is available as `WEAVE_ARGS` while `weave`ing
- `mod::Union{Module,Nothing} = nothing`: Module where Weave `eval`s code. You can pass a `Module` object, otherwise create an new sandbox module. - `mod::Union{Module,Nothing} = nothing`: Module where Weave `eval`s code. You can pass a `Module` object, otherwise create an new sandbox module.
- `fig_path::Union{Nothing,AbstractString} = nothing`: Where figures will be generated, relative to `out_path`. By default (i.e. given `nothing`), Weave will automatically create `$(DEFAULT_FIG_PATH)` directory. - `fig_path::Union{Nothing,AbstractString} = nothing`: Where figures will be generated, relative to `out_path`. By default (i.e. given `nothing`), Weave will automatically create `$(DEFAULT_FIG_PATH)` directory.
- `fig_ext::Union{Nothing,AbstractString} = nothing`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype` - `fig_ext::Union{Nothing,AbstractString} = nothing`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`
@ -127,7 +127,7 @@ function weave(
doctype::Union{Nothing,AbstractString} = nothing, doctype::Union{Nothing,AbstractString} = nothing,
informat::Union{Nothing,AbstractString} = nothing, informat::Union{Nothing,AbstractString} = nothing,
out_path::Union{Symbol,AbstractString} = :doc, out_path::Union{Symbol,AbstractString} = :doc,
args::Dict = Dict(), args::Any = Dict(),
mod::Union{Module,Nothing} = nothing, mod::Union{Module,Nothing} = nothing,
fig_path::Union{Nothing,AbstractString} = nothing, fig_path::Union{Nothing,AbstractString} = nothing,
fig_ext::Union{Nothing,AbstractString} = nothing, fig_ext::Union{Nothing,AbstractString} = nothing,

View File

@ -5,23 +5,15 @@ using ..Weave: isnothing, take2string!
using Markdown using Markdown
import Markdown: @trigger, @breaking, Code, MD, withstream, startswith, LaTeX import Markdown: @trigger, @breaking, Code, MD, withstream, startswith, LaTeX
# Note that this definition causes a "Method overwritten" warning,
function __init__() # but defining this function in __init__() is not legal in julia v1.5
# NOTE: function Markdown.latex(io::IO, tex::Markdown.LaTeX)
# overwriting `Markdown.latex` function should be done here in order to allow math_envs = ["align", "equation", "eqnarray"]
# incremental precompilations use_dollars =
Markdown.eval( !any([occursin("\\begin{$me", tex.formula) for me in math_envs])
quote use_dollars && write(io, "\\[")
function latex(io::IO, tex::Markdown.LaTeX) write(io, string("\n", tex.formula, "\n"))
math_envs = ["align", "equation", "eqnarray"] use_dollars && write(io, "\\]\n")
use_dollars =
!any([occursin("\\begin{$me", tex.formula) for me in math_envs])
use_dollars && write(io, "\\[")
write(io, string("\n", tex.formula, "\n"))
use_dollars && write(io, "\\]\n")
end
end,
)
end end
mutable struct Comment mutable struct Comment

View File

@ -17,7 +17,7 @@ function Base.display(
report::Weave.Report, report::Weave.Report,
m::MIME"image/svg+xml", m::MIME"image/svg+xml",
data::Plots.Plot{Plots.PlotlyBackend}, data::Plots.Plot{Plots.PlotlyBackend},
)# )
# Remove extra spaces from start of line for pandoc # Remove extra spaces from start of line for pandoc
s = repr(MIME("text/html"), data) s = repr(MIME("text/html"), data)
splitted = split(s, "\n") splitted = split(s, "\n")
@ -39,7 +39,7 @@ function Base.display(
report::Weave.Report, report::Weave.Report,
m::MIME"image/png", m::MIME"image/png",
data::Plots.Plot{Plots.PlotlyBackend}, data::Plots.Plot{Plots.PlotlyBackend},
)# )
display(report, MIME("image/svg+xml"), data) display(report, MIME("image/svg+xml"), data)
end end

View File

@ -44,18 +44,14 @@ function render_chunk(docformat::WeaveFormat, chunk::CodeChunk)
chunk.content = render_code(docformat, chunk.content) chunk.content = render_code(docformat, chunk.content)
if !chunk.options[:eval] echo = chunk.options[:echo]
return if chunk.options[:echo]
string(docformat.codestart, '\n', chunk.content, docformat.codeend) chunk.options[:eval] || return echo ? string(docformat.codestart, chunk.content, docformat.codeend) : ""
else
""
end
end
if chunk.options[:term] if chunk.options[:term]
result = render_termchunk(docformat, chunk) result = render_termchunk(docformat, chunk)
else else
result = if chunk.options[:echo] result = if echo
# Convert to output format and highlight (html, tex...) if needed # Convert to output format and highlight (html, tex...) if needed
string(docformat.codestart, chunk.content, docformat.codeend, '\n') string(docformat.codestart, chunk.content, docformat.codeend, '\n')
else else
@ -126,7 +122,7 @@ render_output(docformat::WeaveFormat, output) = output
function render_termchunk(docformat::WeaveFormat, chunk) function render_termchunk(docformat::WeaveFormat, chunk)
return if should_render(chunk) return if should_render(chunk)
string(docformat.termstart, chunk.output, '\n', docformat.termend, '\n') string(docformat.termstart, chunk.output, docformat.termend)
else else
"" ""
end end

View File

@ -15,8 +15,8 @@ render_termchunk(docformat::HTMLFormat, chunk) =
Base.@kwdef mutable struct WeaveHTML <: HTMLFormat Base.@kwdef mutable struct WeaveHTML <: HTMLFormat
description = "Weave-style HTML" description = "Weave-style HTML"
extension = "html" extension = "html"
codestart = "\n" codestart = '\n'
codeend = "\n" codeend = '\n'
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "<pre class=\"output\">" outputstart = "<pre class=\"output\">"

View File

@ -4,12 +4,12 @@
Base.@kwdef mutable struct GitHubMarkdown <: WeaveFormat Base.@kwdef mutable struct GitHubMarkdown <: WeaveFormat
description = "GitHub Markdown" description = "GitHub Markdown"
extension = "md" extension = "md"
codestart = "````julia" codestart = "```julia"
codeend = "````\n\n" codeend = "```\n"
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "````" outputstart = "```"
outputend = "````\n\n" outputend = "```\n\n"
fig_ext = ".png" fig_ext = ".png"
mimetypes = ["image/png", "image/svg+xml", "image/jpg", mimetypes = ["image/png", "image/svg+xml", "image/jpg",
"text/markdown", "text/plain"] "text/markdown", "text/plain"]
@ -50,12 +50,12 @@ end
Base.@kwdef mutable struct Hugo <: WeaveFormat Base.@kwdef mutable struct Hugo <: WeaveFormat
description = "Hugo Markdown (using shortcodes)" description = "Hugo Markdown (using shortcodes)"
extension = "md" extension = "md"
codestart = "````julia" codestart = "```julia"
codeend = "````\n\n" codeend = "```\n"
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "````" outputstart = "```"
outputend = "````\n\n" outputend = "```\n\n"
mimetypes = default_mime_types mimetypes = default_mime_types
fig_ext = ".png" fig_ext = ".png"
out_width = nothing out_width = nothing
@ -88,12 +88,12 @@ end
Base.@kwdef mutable struct MultiMarkdown <: WeaveFormat Base.@kwdef mutable struct MultiMarkdown <: WeaveFormat
description = "MultiMarkdown" description = "MultiMarkdown"
extension = "md" extension = "md"
codestart = "````julia" codestart = "```julia"
codeend = "````\n\n" codeend = "```\n"
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "````" outputstart = "```"
outputend = "````\n\n" outputend = "```\n\n"
mimetypes = default_mime_types mimetypes = default_mime_types
fig_ext = ".png" fig_ext = ".png"
out_width = nothing out_width = nothing
@ -143,7 +143,7 @@ Base.@kwdef mutable struct Rest <: WeaveFormat
description = "reStructuredText and Sphinx" description = "reStructuredText and Sphinx"
extension = "rst" extension = "rst"
codestart = ".. code-block:: julia\n" codestart = ".. code-block:: julia\n"
codeend = "\n\n" codeend = "\n"
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "::\n" outputstart = "::\n"
@ -190,7 +190,7 @@ Base.@kwdef mutable struct AsciiDoc <: WeaveFormat
description = "AsciiDoc" description = "AsciiDoc"
extension = "txt" extension = "txt"
codestart = "[source,julia]\n--------------------------------------" codestart = "[source,julia]\n--------------------------------------"
codeend = "--------------------------------------\n\n" codeend = "--------------------------------------\n"
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "--------------------------------------" outputstart = "--------------------------------------"

View File

@ -37,7 +37,7 @@ Base.@kwdef mutable struct Pandoc <: PandocFormat
description = "Pandoc Markdown" description = "Pandoc Markdown"
extension = "md" extension = "md"
codestart = "~~~~{.julia}" codestart = "~~~~{.julia}"
codeend = "~~~~~~~~~~~~~\n\n" codeend = "~~~~~~~~~~~~~\n"
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "~~~~" outputstart = "~~~~"

View File

@ -7,7 +7,7 @@ function run_doc(
doc::WeaveDoc; doc::WeaveDoc;
doctype::Union{Nothing,AbstractString} = nothing, doctype::Union{Nothing,AbstractString} = nothing,
out_path::Union{Symbol,AbstractString} = :doc, out_path::Union{Symbol,AbstractString} = :doc,
args::Dict = Dict(), args::Any = Dict(),
mod::Union{Module,Nothing} = nothing, mod::Union{Module,Nothing} = nothing,
fig_path::Union{Nothing,AbstractString} = nothing, fig_path::Union{Nothing,AbstractString} = nothing,
fig_ext::Union{Nothing,AbstractString} = nothing, fig_ext::Union{Nothing,AbstractString} = nothing,
@ -20,8 +20,9 @@ function run_doc(
doc.format = deepcopy(get_format(doctype)) doc.format = deepcopy(get_format(doctype))
cwd = doc.cwd = get_cwd(doc, out_path) cwd = doc.cwd = get_cwd(doc, out_path)
isdir(cwd) || mkdir(cwd) mkpath(cwd)
# TODO: provide a way not to create `fig_path` ?
if isnothing(fig_path) if isnothing(fig_path)
fig_path = if (endswith(doctype, "2pdf") && cache === :off) || endswith(doctype, "2html") fig_path = if (endswith(doctype, "2pdf") && cache === :off) || endswith(doctype, "2html")
basename(mktempdir(abspath(cwd))) basename(mktempdir(abspath(cwd)))
@ -29,7 +30,7 @@ function run_doc(
DEFAULT_FIG_PATH DEFAULT_FIG_PATH
end end
end end
let d = normpath(cwd, fig_path); isdir(d) || mkdir(d); end mkpath(normpath(cwd, fig_path))
# This is needed for latex and should work on all output formats # This is needed for latex and should work on all output formats
@static Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/")) @static Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/"))
set_rc_params(doc, fig_path, fig_ext) set_rc_params(doc, fig_path, fig_ext)
@ -38,7 +39,7 @@ function run_doc(
# New sandbox for each document with args exposed # New sandbox for each document with args exposed
isnothing(mod) && (mod = sandbox = Core.eval(Main, :(module $(gensym(:WeaveSandBox)) end))::Module) isnothing(mod) && (mod = sandbox = Core.eval(Main, :(module $(gensym(:WeaveSandBox)) end))::Module)
@eval mod WEAVE_ARGS = $args Core.eval(mod, :(WEAVE_ARGS = $(args)))
mimetypes = doc.format.mimetypes mimetypes = doc.format.mimetypes
@ -139,27 +140,17 @@ function embed_figures!(chunk::CodeChunk, cwd)
chunk.figures[i] = img2base64(fig, cwd) chunk.figures[i] = img2base64(fig, cwd)
end end
end end
embed_figures!(chunks, cwd) = embed_figures!.(chunks, Ref(cwd))
function embed_figures!(chunks::Vector{CodeChunk}, cwd)
for chunk in chunks
embed_figures!(chunk, cwd)
end
end
function img2base64(fig, cwd) function img2base64(fig, cwd)
ext = splitext(fig)[2] ext = splitext(fig)[2]
f = open(joinpath(cwd, fig), "r") f = open(joinpath(cwd, fig), "r")
raw = read(f) raw = read(f)
close(f) close(f)
if ext == ".png" return ext == ".png" ? "data:image/png;base64," * stringmime(MIME("image/png"), raw) :
return "data:image/png;base64," * stringmime(MIME("image/png"), raw) ext == ".svg" ? "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw) :
elseif ext == ".svg" ext == ".gif" ? "data:image/gif;base64," * stringmime(MIME("image/gif"), raw) :
return "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw) fig
elseif ext == ".gif"
return "data:image/gif;base64," * stringmime(MIME("image/gif"), raw)
else
return (fig)
end
end end
function run_chunk(chunk::DocChunk, doc, report, mod) function run_chunk(chunk::DocChunk, doc, report, mod)
@ -225,7 +216,7 @@ function capture_output(code, mod, path, error, report)
task_local_storage(:SOURCE_PATH, path) do task_local_storage(:SOURCE_PATH, path) do
try try
obj = include_string(mod, code, path) # TODO: fix line number obj = include_string(mod, code, path) # TODO: fix line number
!isnothing(obj) && display(obj) !isnothing(obj) && !REPL.ends_with_semicolon(code) && display(obj)
catch _err catch _err
err = unwrap_load_err(_err) err = unwrap_load_err(_err)
error || throw(err) error || throw(err)
@ -273,15 +264,9 @@ function eval_chunk(doc::WeaveDoc, chunk::CodeChunk, report::Report, mod::Module
execute_posthooks!(chunk) execute_posthooks!(chunk)
chunks = if chunk.options[:term] return chunk.options[:term] ? collect_term_results(chunk) :
collect_term_results(chunk) chunk.options[:hold] ? collect_hold_results(chunk) :
elseif chunk.options[:hold] collect_results(chunk)
collect_hold_results(chunk)
else
collect_results(chunk)
end
return chunks
end end
# Hooks to run before and after chunks, this is form IJulia, # Hooks to run before and after chunks, this is form IJulia,
@ -292,7 +277,11 @@ function pop_preexecution_hook!(f::Function)
isnothing(i) && error("this function has not been registered in the pre-execution hook yet") isnothing(i) && error("this function has not been registered in the pre-execution hook yet")
return splice!(preexecution_hooks, i) return splice!(preexecution_hooks, i)
end end
execute_prehooks!(chunk::CodeChunk) = for prehook in preexecution_hooks; Base.invokelatest(prehook, chunk); end function execute_prehooks!(chunk::CodeChunk)
for prehook in preexecution_hooks
Base.invokelatest(prehook, chunk)
end
end
const postexecution_hooks = Function[] const postexecution_hooks = Function[]
push_postexecution_hook!(f::Function) = push!(postexecution_hooks, f) push_postexecution_hook!(f::Function) = push!(postexecution_hooks, f)
@ -301,7 +290,11 @@ function pop_postexecution_hook!(f::Function)
isnothing(i) && error("this function has not been registered in the post-execution hook yet") isnothing(i) && error("this function has not been registered in the post-execution hook yet")
return splice!(postexecution_hooks, i) return splice!(postexecution_hooks, i)
end end
execute_posthooks!(chunk::CodeChunk) = for posthook in postexecution_hooks; Base.invokelatest(posthook, chunk); end function execute_posthooks!(chunk::CodeChunk)
for posthook in postexecution_hooks
Base.invokelatest(posthook, chunk)
end
end
""" """
clear_module!(mod::Module) clear_module!(mod::Module)
@ -340,11 +333,7 @@ function get_figname(report::Report, chunk; fignum = nothing, ext = nothing)
end end
function set_rc_params(doc::WeaveDoc, fig_path, fig_ext) function set_rc_params(doc::WeaveDoc, fig_path, fig_ext)
if isnothing(fig_ext) doc.chunk_defaults[:fig_ext] = isnothing(fig_ext) ? doc.format.fig_ext : fig_ext
doc.chunk_defaults[:fig_ext] = doc.format.fig_ext
else
doc.chunk_defaults[:fig_ext] = fig_ext
end
doc.chunk_defaults[:fig_path] = fig_path doc.chunk_defaults[:fig_path] = fig_path
end end
@ -352,11 +341,9 @@ function collect_results(chunk::CodeChunk)
content = "" content = ""
result_chunks = CodeChunk[] result_chunks = CodeChunk[]
for r in chunk.result for r in chunk.result
content *= r.code
# Check if there is any output from chunk # Check if there is any output from chunk
if strip(r.stdout) == "" && isempty(r.figures) && strip(r.rich_output) == "" if any(!isempty strip, (r.stdout, r.rich_output)) || !isempty(r.figures)
content *= r.code
else
content = "\n" * content * r.code
rchunk = CodeChunk( rchunk = CodeChunk(
content, content,
chunk.number, chunk.number,
@ -364,15 +351,14 @@ function collect_results(chunk::CodeChunk)
chunk.optionstring, chunk.optionstring,
copy(chunk.options), copy(chunk.options),
) )
content = ""
rchunk.figures = r.figures
rchunk.output = r.stdout rchunk.output = r.stdout
rchunk.rich_output = r.rich_output rchunk.rich_output = r.rich_output
rchunk.figures = r.figures
push!(result_chunks, rchunk) push!(result_chunks, rchunk)
content = ""
end end
end end
if !isempty(content) if !isempty(content)
startswith(content, "\n") || (content = "\n" * content)
rchunk = CodeChunk( rchunk = CodeChunk(
content, content,
chunk.number, chunk.number,