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
matrix:
version:
- '1.4'
- '1.5'
os:
- ubuntu-latest
- macOS-latest

View File

@ -3,7 +3,7 @@ language: julia
jobs:
include:
- stage: "Documentation"
julia: 1
julia: 1.5
os: linux
script:
- 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
### 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:
- `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"
uuid = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"
version = "0.10.2"
version = "0.10.6"
[deps]
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
author : Shuhei Kadowaki
date: `j Date(now())`
date: `j import Dates; Dates.Date(Dates.now())`
---
```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
You can pass arguments as `Dict` to the weaved document using the `args` argument
to `weave`. The arguments will be available as `WEAVE_ARGS` variable in the document.
You can pass arbitrary object to the weaved document using [`weave`](@ref)'s optional argument `args`.
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
date ranges of input data from a database or from files with similar format giving the
filename as input.
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.
In order to pass a filename to a document you need call `weave` using:
```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.
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`
## `include_weave`

View File

@ -102,7 +102,7 @@ Weave an input document to output file.
* `:doc`: Path of the source document (default)
* `:pwd`: Julia working directory
* `"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.
- `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`
@ -127,7 +127,7 @@ function weave(
doctype::Union{Nothing,AbstractString} = nothing,
informat::Union{Nothing,AbstractString} = nothing,
out_path::Union{Symbol,AbstractString} = :doc,
args::Dict = Dict(),
args::Any = Dict(),
mod::Union{Module,Nothing} = nothing,
fig_path::Union{Nothing,AbstractString} = nothing,
fig_ext::Union{Nothing,AbstractString} = nothing,

View File

@ -5,23 +5,15 @@ using ..Weave: isnothing, take2string!
using Markdown
import Markdown: @trigger, @breaking, Code, MD, withstream, startswith, LaTeX
function __init__()
# NOTE:
# overwriting `Markdown.latex` function should be done here in order to allow
# incremental precompilations
Markdown.eval(
quote
function latex(io::IO, tex::Markdown.LaTeX)
math_envs = ["align", "equation", "eqnarray"]
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,
)
# Note that this definition causes a "Method overwritten" warning,
# but defining this function in __init__() is not legal in julia v1.5
function Markdown.latex(io::IO, tex::Markdown.LaTeX)
math_envs = ["align", "equation", "eqnarray"]
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
mutable struct Comment

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ function run_doc(
doc::WeaveDoc;
doctype::Union{Nothing,AbstractString} = nothing,
out_path::Union{Symbol,AbstractString} = :doc,
args::Dict = Dict(),
args::Any = Dict(),
mod::Union{Module,Nothing} = nothing,
fig_path::Union{Nothing,AbstractString} = nothing,
fig_ext::Union{Nothing,AbstractString} = nothing,
@ -20,8 +20,9 @@ function run_doc(
doc.format = deepcopy(get_format(doctype))
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)
fig_path = if (endswith(doctype, "2pdf") && cache === :off) || endswith(doctype, "2html")
basename(mktempdir(abspath(cwd)))
@ -29,7 +30,7 @@ function run_doc(
DEFAULT_FIG_PATH
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
@static Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/"))
set_rc_params(doc, fig_path, fig_ext)
@ -38,7 +39,7 @@ function run_doc(
# New sandbox for each document with args exposed
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
@ -139,27 +140,17 @@ function embed_figures!(chunk::CodeChunk, cwd)
chunk.figures[i] = img2base64(fig, cwd)
end
end
function embed_figures!(chunks::Vector{CodeChunk}, cwd)
for chunk in chunks
embed_figures!(chunk, cwd)
end
end
embed_figures!(chunks, cwd) = embed_figures!.(chunks, Ref(cwd))
function img2base64(fig, cwd)
ext = splitext(fig)[2]
f = open(joinpath(cwd, fig), "r")
raw = read(f)
close(f)
if ext == ".png"
return "data:image/png;base64," * stringmime(MIME("image/png"), raw)
elseif ext == ".svg"
return "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw)
elseif ext == ".gif"
return "data:image/gif;base64," * stringmime(MIME("image/gif"), raw)
else
return (fig)
end
return ext == ".png" ? "data:image/png;base64," * stringmime(MIME("image/png"), raw) :
ext == ".svg" ? "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw) :
ext == ".gif" ? "data:image/gif;base64," * stringmime(MIME("image/gif"), raw) :
fig
end
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
try
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
err = unwrap_load_err(_err)
error || throw(err)
@ -273,15 +264,9 @@ function eval_chunk(doc::WeaveDoc, chunk::CodeChunk, report::Report, mod::Module
execute_posthooks!(chunk)
chunks = if chunk.options[:term]
collect_term_results(chunk)
elseif chunk.options[:hold]
collect_hold_results(chunk)
else
collect_results(chunk)
end
return chunks
return chunk.options[:term] ? collect_term_results(chunk) :
chunk.options[:hold] ? collect_hold_results(chunk) :
collect_results(chunk)
end
# 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")
return splice!(preexecution_hooks, i)
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[]
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")
return splice!(postexecution_hooks, i)
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)
@ -340,11 +333,7 @@ function get_figname(report::Report, chunk; fignum = nothing, ext = nothing)
end
function set_rc_params(doc::WeaveDoc, fig_path, fig_ext)
if isnothing(fig_ext)
doc.chunk_defaults[:fig_ext] = doc.format.fig_ext
else
doc.chunk_defaults[:fig_ext] = fig_ext
end
doc.chunk_defaults[:fig_ext] = isnothing(fig_ext) ? doc.format.fig_ext : fig_ext
doc.chunk_defaults[:fig_path] = fig_path
end
@ -352,11 +341,9 @@ function collect_results(chunk::CodeChunk)
content = ""
result_chunks = CodeChunk[]
for r in chunk.result
content *= r.code
# Check if there is any output from chunk
if strip(r.stdout) == "" && isempty(r.figures) && strip(r.rich_output) == ""
content *= r.code
else
content = "\n" * content * r.code
if any(!isempty strip, (r.stdout, r.rich_output)) || !isempty(r.figures)
rchunk = CodeChunk(
content,
chunk.number,
@ -364,15 +351,14 @@ function collect_results(chunk::CodeChunk)
chunk.optionstring,
copy(chunk.options),
)
content = ""
rchunk.figures = r.figures
rchunk.output = r.stdout
rchunk.rich_output = r.rich_output
rchunk.figures = r.figures
push!(result_chunks, rchunk)
content = ""
end
end
if !isempty(content)
startswith(content, "\n") || (content = "\n" * content)
rchunk = CodeChunk(
content,
chunk.number,