2014-12-08 09:25:57 +01:00
|
|
|
module Weave
|
2016-12-15 14:49:21 +01:00
|
|
|
import Highlights
|
2020-03-26 09:35:05 +01:00
|
|
|
using Mustache
|
2018-07-26 19:32:10 +02:00
|
|
|
using Requires
|
|
|
|
|
|
|
|
function __init__()
|
2020-03-17 02:57:36 +01:00
|
|
|
@require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" Base.include(Main, joinpath(@__DIR__, "plots.jl"))
|
|
|
|
@require Gadfly="c91e804a-d5a3-530f-b6f0-dfbca275c004" Base.include(Main, joinpath(@__DIR__, "gadfly.jl"))
|
2018-07-26 19:32:10 +02:00
|
|
|
end
|
2014-11-25 00:10:48 +01:00
|
|
|
|
2016-04-19 14:23:48 +02:00
|
|
|
"""
|
2020-03-26 09:35:05 +01:00
|
|
|
list_out_formats()
|
2016-04-19 14:23:48 +02:00
|
|
|
|
|
|
|
List supported output formats
|
|
|
|
"""
|
2014-12-05 22:33:54 +01:00
|
|
|
function list_out_formats()
|
2020-05-06 16:37:04 +02:00
|
|
|
for format = keys(formats)
|
|
|
|
println(string(format,": ", formats[format].description))
|
|
|
|
end
|
2014-12-05 22:33:54 +01:00
|
|
|
end
|
2014-12-03 08:21:56 +01:00
|
|
|
|
2014-11-25 00:10:48 +01:00
|
|
|
|
2016-04-19 14:23:48 +02:00
|
|
|
"""
|
2020-03-27 10:45:04 +01:00
|
|
|
tangle(source::AbstractString; kwargs...)
|
2016-04-19 14:23:48 +02:00
|
|
|
|
|
|
|
Tangle source code from input document to .jl file.
|
2015-01-01 22:36:58 +01:00
|
|
|
|
2020-03-27 10:45:04 +01:00
|
|
|
## Keyword options
|
2020-03-26 09:35:05 +01:00
|
|
|
|
2020-03-27 10:45:04 +01:00
|
|
|
- `informat::Union{Symbol,AbstractString} = :auto`: Input document format. `:auto` will set it automatically based on file extension. You can also specify either of `"script"`, `"markdown"`, `"notebook"`, or `"noweb"`
|
|
|
|
- `out_path::Union{Symbol,AbstractString} = :doc`: Path where the output is generated can be either of:
|
2020-03-26 09:35:05 +01:00
|
|
|
* `: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"`
|
2016-04-19 14:23:48 +02:00
|
|
|
"""
|
2020-03-26 09:35:05 +01:00
|
|
|
function tangle(
|
2020-03-26 17:49:48 +01:00
|
|
|
source::AbstractString;
|
2020-03-26 09:35:05 +01:00
|
|
|
out_path::Union{Symbol,AbstractString} = :doc,
|
|
|
|
informat::Union{Symbol,AbstractString} = :auto
|
2020-05-06 16:37:04 +02:00
|
|
|
)
|
2015-01-06 23:01:25 +01:00
|
|
|
doc = read_doc(source, informat)
|
2016-04-24 14:02:03 +02:00
|
|
|
doc.cwd = get_cwd(doc, out_path)
|
2015-01-01 22:36:58 +01:00
|
|
|
|
2016-04-24 14:02:03 +02:00
|
|
|
outname = get_outname(out_path, doc, ext = "jl")
|
2016-04-27 13:51:15 +02:00
|
|
|
|
2016-04-24 14:02:03 +02:00
|
|
|
open(outname, "w") do io
|
2020-05-06 16:37:04 +02:00
|
|
|
for chunk in doc.chunks
|
|
|
|
if typeof(chunk) == CodeChunk
|
|
|
|
options = merge(doc.chunk_defaults, chunk.options)
|
|
|
|
options[:tangle] && write(io, chunk.content*"\n")
|
|
|
|
end
|
|
|
|
end
|
2014-12-21 08:25:45 +01:00
|
|
|
end
|
2020-05-06 16:37:04 +02:00
|
|
|
doc.cwd == pwd() && (outname = basename(outname))
|
|
|
|
@info("Writing to file $outname")
|
2014-12-21 08:25:45 +01:00
|
|
|
end
|
2014-12-03 08:21:56 +01:00
|
|
|
|
2016-04-24 14:02:03 +02:00
|
|
|
|
2016-04-19 14:23:48 +02:00
|
|
|
"""
|
2020-03-27 10:45:04 +01:00
|
|
|
weave(source::AbstractString; kwargs...)
|
2016-04-19 14:23:48 +02:00
|
|
|
|
|
|
|
Weave an input document to output file.
|
2015-01-01 22:32:15 +01:00
|
|
|
|
2020-03-26 09:35:05 +01:00
|
|
|
## Keyword options
|
|
|
|
|
2020-03-27 10:45:04 +01:00
|
|
|
- `doctype::Union{Symbol,AbstractString} = :auto`: Output document format. `:auto` will set it automatically based on file extension. You can also manually specify it; see [`list_out_formats()`](@ref) for the supported formats
|
|
|
|
- `informat::Union{Symbol,AbstractString} = :auto`: Input document format. `:auto` will set it automatically based on file extension. You can also specify either of `"script"`, `"markdown"`, `"notebook"`, or `"noweb"`
|
|
|
|
- `out_path::Union{Symbol,AbstractString} = :doc`: Path where the output is generated can be either of:
|
2020-03-26 09:35:05 +01:00
|
|
|
* `: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"`
|
2020-03-27 10:45:04 +01:00
|
|
|
- `args::Dict = Dict()`: Arguments to be passed to the weaved document; will be available as `WEAVE_ARGS` in the document
|
|
|
|
- `mod::Union{Module,Symbol} = :sandbox`: Module where Weave `eval`s code. Defaults to `:sandbox` to create new sandbox module. You also can also pass a `Module` e.g. `Main`
|
|
|
|
- `fig_path::AbstractString = "figures"`: Where figures will be generated, relative to `out_path`
|
|
|
|
- `fig_ext::Union{Nothing,AbstractString} = nothing`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`
|
|
|
|
- `cache_path::AbstractString = "cache"`: Where of cached output will be saved
|
|
|
|
- `cache::Symbol = :off`: Controls caching of code:
|
2020-03-26 09:35:05 +01:00
|
|
|
* `:off` means no caching (default)
|
|
|
|
* `:all` caches everything
|
|
|
|
* `:user` caches based on chunk options
|
|
|
|
* `:refresh` runs all code chunks and save new cache
|
2020-03-27 10:45:04 +01:00
|
|
|
- `throw_errors::Bool = false`: If `false` errors are included in output document and the whole document is executed. If `true` errors are thrown when they occur
|
|
|
|
- `template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing`: Template (file path) or `Mustache.MustacheTokens`s for `md2html` or `md2tex` formats
|
|
|
|
- `highlight_theme::Union{Nothing,Type{<:Highlights.AbstractTheme}} = nothing`: Theme used for syntax highlighting (defaults to `Highlights.Themes.DefaultTheme`)
|
|
|
|
- `css::Union{Nothing,AbstractString} = nothing`: Path of a CSS file used for md2html format
|
|
|
|
- `pandoc_options::Vector{<:AbstractString} = String[]`: `String`s of options to pass to pandoc for `pandoc2html` and `pandoc2pdf` formats, e.g. `["--toc", "-N"]`
|
|
|
|
- `latex_cmd::AbstractString = "xelatex"`: The command used to make PDF file from .tex
|
|
|
|
- `latex_keep_unicode::Bool = false`: If `true`, do not convert unicode characters to their respective latex representation. This is especially useful if a font and tex-engine with support for unicode characters are used
|
2020-03-26 09:35:05 +01:00
|
|
|
|
|
|
|
!!! note
|
|
|
|
Run Weave from terminal and try to avoid weaving from IJulia or ESS; they tend to mess with capturing output.
|
2016-04-19 14:23:48 +02:00
|
|
|
"""
|
2020-03-26 09:35:05 +01:00
|
|
|
function weave(
|
|
|
|
source::AbstractString;
|
|
|
|
doctype::Union{Symbol,AbstractString} = :auto,
|
|
|
|
informat::Union{Symbol,AbstractString} = :auto,
|
|
|
|
out_path::Union{Symbol,AbstractString} = :doc,
|
|
|
|
args::Dict = Dict(),
|
|
|
|
mod::Union{Module,Symbol} = :sandbox,
|
|
|
|
fig_path::AbstractString = "figures",
|
|
|
|
fig_ext::Union{Nothing,AbstractString} = nothing,
|
|
|
|
cache_path::AbstractString = "cache",
|
|
|
|
cache::Symbol = :off,
|
|
|
|
throw_errors::Bool = false,
|
|
|
|
template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing,
|
|
|
|
highlight_theme::Union{Nothing,Type{<:Highlights.AbstractTheme}} = nothing,
|
|
|
|
css::Union{Nothing,AbstractString} = nothing,
|
|
|
|
pandoc_options::Vector{<:AbstractString} = String[],
|
|
|
|
latex_cmd::AbstractString = "xelatex",
|
|
|
|
latex_keep_unicode::Bool = false
|
|
|
|
)
|
2016-04-20 10:16:50 +02:00
|
|
|
doc = read_doc(source, informat)
|
2019-03-05 15:44:10 +01:00
|
|
|
doctype == :auto && (doctype = detect_doctype(doc.source))
|
|
|
|
doc.doctype = doctype
|
2019-03-04 10:10:02 +01:00
|
|
|
|
|
|
|
# Read args from document header, overrides command line args
|
|
|
|
if haskey(doc.header, "options")
|
|
|
|
(doctype, informat, out_path, args, mod, fig_path, fig_ext,
|
|
|
|
cache_path, cache, throw_errors, template, highlight_theme, css,
|
2019-03-11 09:23:31 +01:00
|
|
|
pandoc_options, latex_cmd) = header_args(doc, out_path, mod,
|
|
|
|
fig_ext, fig_path,
|
|
|
|
cache_path, cache, throw_errors,
|
|
|
|
template, highlight_theme, css,
|
|
|
|
pandoc_options, latex_cmd)
|
2019-03-04 10:10:02 +01:00
|
|
|
end
|
|
|
|
|
2019-03-10 16:51:19 +01:00
|
|
|
template != nothing && (doc.template = template)
|
2016-12-23 07:34:54 +01:00
|
|
|
highlight_theme != nothing && (doc.highlight_theme = highlight_theme)
|
2016-12-15 14:49:21 +01:00
|
|
|
#theme != nothing && (doc.theme = theme) #Reserved for themes
|
|
|
|
css != nothing && (doc.css = css)
|
|
|
|
|
2020-02-09 13:11:29 +01:00
|
|
|
doc = run(doc, doctype = doctype,
|
2020-02-09 13:13:37 +01:00
|
|
|
mod = mod,
|
|
|
|
out_path=out_path, args = args,
|
|
|
|
fig_path = fig_path, fig_ext = fig_ext, cache_path = cache_path, cache=cache,
|
|
|
|
throw_errors = throw_errors,latex_keep_unicode=latex_keep_unicode)
|
2020-02-09 13:11:29 +01:00
|
|
|
formatted = format(doc)
|
2016-04-20 17:34:24 +02:00
|
|
|
|
2020-02-09 13:11:29 +01:00
|
|
|
outname = get_outname(out_path, doc)
|
|
|
|
|
|
|
|
open(outname, "w") do io
|
|
|
|
write(io, formatted)
|
|
|
|
end
|
2014-12-03 14:41:53 +01:00
|
|
|
|
2020-02-09 13:11:29 +01:00
|
|
|
#Special for that need external programs
|
|
|
|
if doc.doctype == "pandoc2html"
|
|
|
|
mdname = outname
|
|
|
|
outname = get_outname(out_path, doc, ext = "html")
|
|
|
|
pandoc2html(formatted, doc, outname, pandoc_options)
|
|
|
|
rm(mdname)
|
|
|
|
elseif doc.doctype == "pandoc2pdf"
|
|
|
|
mdname = outname
|
|
|
|
outname = get_outname(out_path, doc, ext = "pdf")
|
|
|
|
pandoc2pdf(formatted, doc, outname, pandoc_options)
|
|
|
|
rm(mdname)
|
|
|
|
elseif doc.doctype == "md2pdf"
|
|
|
|
success = run_latex(doc, outname, latex_cmd)
|
|
|
|
success || return
|
|
|
|
outname = get_outname(out_path, doc, ext = "pdf")
|
2016-12-23 09:25:23 +01:00
|
|
|
end
|
2020-02-09 13:11:29 +01:00
|
|
|
|
|
|
|
doc.cwd == pwd() && (outname = basename(outname))
|
|
|
|
@info("Report weaved to $outname")
|
|
|
|
return abspath(outname)
|
2014-11-25 00:10:48 +01:00
|
|
|
end
|
|
|
|
|
2020-03-26 09:35:05 +01:00
|
|
|
weave(doc::AbstractString, doctype::Union{Symbol,AbstractString}) =
|
|
|
|
weave(doc; doctype = doctype)
|
2014-12-03 14:41:53 +01:00
|
|
|
|
2018-01-05 16:42:47 +01:00
|
|
|
"""
|
2020-03-27 10:45:04 +01:00
|
|
|
notebook(source::AbstractString; kwargs...)
|
2020-03-26 09:35:05 +01:00
|
|
|
|
2020-03-27 12:43:33 +01:00
|
|
|
Convert Weave document `source` to Jupyter Notebook and execute the code
|
|
|
|
using [`nbconvert`](https://nbconvert.readthedocs.io/en/latest/).
|
2020-03-26 09:35:05 +01:00
|
|
|
**Ignores** all chunk options.
|
|
|
|
|
|
|
|
## Keyword options
|
|
|
|
|
2020-03-27 10:45:04 +01:00
|
|
|
- `out_path::Union{Symbol,AbstractString} = :pwd`: Path where the output is generated can be either of:
|
2020-03-26 09:35:05 +01:00
|
|
|
* `:doc`: Path of the source document
|
|
|
|
* `:pwd`: Julia working directory (default)
|
|
|
|
* `"somepath"`: `String` of output directory e.g. `"~/outdir"`, or of filename e.g. `"~/outdir/outfile.tex"`
|
|
|
|
- `timeout = -1`: nbconvert cell timeout in seconds. Defaults to `-1` (no timeout)
|
2020-03-27 10:45:04 +01:00
|
|
|
- `nbconvert_options::AbstractString = ""`: `String` of additional options to pass to nbconvert, such as `"--allow-errors"`
|
|
|
|
- `jupyter_path::AbstractString = "jupyter"`: Path/command for the Jupyter you want to use. Defaults to `"jupyter"`, which runs whatever is linked/alias to that
|
2020-03-27 12:43:33 +01:00
|
|
|
|
|
|
|
!!! warning
|
|
|
|
The code is _**not**_ executed by Weave, but by [`nbconvert`](https://nbconvert.readthedocs.io/en/latest/).
|
|
|
|
This means that the output doesn't necessarily always work properly; see [#116](https://github.com/mpastell/Weave.jl/issues/116).
|
|
|
|
|
|
|
|
!!! note
|
|
|
|
In order to _just_ convert Weave document to Jupyter Notebook,
|
|
|
|
use [`convert_doc`](@ref) instead.
|
2018-01-05 16:42:47 +01:00
|
|
|
"""
|
2020-03-26 09:35:05 +01:00
|
|
|
function notebook(
|
|
|
|
source::AbstractString;
|
|
|
|
out_path::Union{Symbol,AbstractString} = :pwd,
|
|
|
|
timeout = -1,
|
|
|
|
nbconvert_options::AbstractString = "",
|
|
|
|
jupyter_path::AbstractString = "jupyter",
|
|
|
|
)
|
|
|
|
doc = read_doc(source)
|
|
|
|
converted = convert_doc(doc, NotebookOutput())
|
|
|
|
doc.cwd = get_cwd(doc, out_path)
|
|
|
|
outfile = get_outname(out_path, doc, ext = "ipynb")
|
2018-01-05 16:42:47 +01:00
|
|
|
|
2020-03-26 09:35:05 +01:00
|
|
|
open(outfile, "w") do f
|
|
|
|
write(f, converted)
|
|
|
|
end
|
2018-01-05 16:42:47 +01:00
|
|
|
|
2020-03-27 10:45:04 +01:00
|
|
|
@info "Running nbconvert"
|
2020-03-26 09:35:05 +01:00
|
|
|
out = read(
|
|
|
|
`$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $outfile $nbconvert_options --output $outfile`,
|
|
|
|
String,
|
|
|
|
)
|
|
|
|
end
|
2019-03-11 13:25:17 +01:00
|
|
|
|
2016-12-20 19:34:24 +01:00
|
|
|
"""
|
2020-03-26 09:35:05 +01:00
|
|
|
include_weave(source::AbstractString, informat::Union{Symbol,AbstractString} = :auto)
|
|
|
|
include_weave(m::Module, source::AbstractString, informat::Union{Symbol,AbstractString} = :auto)
|
2016-12-20 19:34:24 +01:00
|
|
|
|
2020-03-26 09:35:05 +01:00
|
|
|
Include code from Weave document calling `include_string` on all code from doc.
|
|
|
|
Code is run in the path of the include document.
|
2016-12-20 19:34:24 +01:00
|
|
|
"""
|
2020-03-26 09:35:05 +01:00
|
|
|
function include_weave(
|
|
|
|
m::Module,
|
|
|
|
source::AbstractString,
|
|
|
|
informat::Union{Symbol,AbstractString} = :auto,
|
|
|
|
)
|
2019-03-11 13:25:17 +01:00
|
|
|
old_path = pwd()
|
|
|
|
doc = read_doc(source, informat)
|
|
|
|
cd(doc.path)
|
|
|
|
try
|
2020-03-26 09:35:05 +01:00
|
|
|
code = join([x.content for x in filter(x -> isa(x, Weave.CodeChunk), doc.chunks)], "\n")
|
2019-03-11 13:25:17 +01:00
|
|
|
include_string(m, code)
|
|
|
|
catch e
|
|
|
|
throw(e)
|
|
|
|
finally
|
|
|
|
cd(old_path)
|
|
|
|
end
|
2016-12-20 19:34:24 +01:00
|
|
|
end
|
|
|
|
|
2019-03-11 13:25:17 +01:00
|
|
|
include_weave(source, informat=:auto) = include_weave(Main, source, informat)
|
|
|
|
|
2016-04-29 15:41:18 +02:00
|
|
|
#Hooks to run before and after chunks, this is form IJulia,
|
|
|
|
#but note that Weave hooks take the chunk as input
|
|
|
|
const preexecute_hooks = Function[]
|
|
|
|
push_preexecute_hook(f::Function) = push!(preexecute_hooks, f)
|
2019-04-27 19:17:29 +02:00
|
|
|
pop_preexecute_hook(f::Function) = splice!(preexecute_hooks, findfirst(x -> x == f, preexecute_hooks))
|
2016-04-29 15:41:18 +02:00
|
|
|
|
|
|
|
const postexecute_hooks = Function[]
|
|
|
|
push_postexecute_hook(f::Function) = push!(postexecute_hooks, f)
|
2019-04-27 19:17:29 +02:00
|
|
|
pop_postexecute_hook(f::Function) = splice!(postexecute_hooks, findfirst(x -> x == f, postexecute_hooks))
|
2016-04-29 15:41:18 +02:00
|
|
|
|
2015-01-07 15:37:02 +01:00
|
|
|
include("chunks.jl")
|
2019-03-04 10:10:02 +01:00
|
|
|
include("config.jl")
|
2019-02-27 17:21:05 +01:00
|
|
|
include("WeaveMarkdown/markdown.jl")
|
2016-04-27 13:51:15 +02:00
|
|
|
include("display_methods.jl")
|
2014-11-26 22:29:25 +01:00
|
|
|
include("readers.jl")
|
2015-01-07 15:37:02 +01:00
|
|
|
include("run.jl")
|
|
|
|
include("cache.jl")
|
2014-12-02 15:57:00 +01:00
|
|
|
include("formatters.jl")
|
2016-12-13 12:26:34 +01:00
|
|
|
include("format.jl")
|
2016-04-20 14:41:54 +02:00
|
|
|
include("pandoc.jl")
|
2016-12-12 11:39:36 +01:00
|
|
|
include("writers.jl")
|
2016-12-12 13:05:26 +01:00
|
|
|
|
2018-07-26 19:32:10 +02:00
|
|
|
|
2018-01-05 16:42:47 +01:00
|
|
|
export weave, list_out_formats, tangle, convert_doc, notebook,
|
2016-12-20 19:34:24 +01:00
|
|
|
set_chunk_defaults, get_chunk_defaults, restore_chunk_defaults,
|
2016-12-26 12:45:33 +01:00
|
|
|
include_weave
|
2014-11-25 00:10:48 +01:00
|
|
|
end
|