Compare commits

..

No commits in common. "master" and "v0.10.3" have entirely different histories.

25 changed files with 193 additions and 186 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.5' - '1.4'
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.5 julia: 1
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,19 +1,6 @@
## Release notes for Weave.jl ## Release notes for Weave.jl
### v0.10.6 2020/10/03 ### v0.10 - 2020/05/18
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.12" version = "0.10.3"
[deps] [deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
@ -12,17 +12,15 @@ Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
RelocatableFolders = "05181044-ff0b-4ac5-8273-598c1e38db00"
Requires = "ae029012-a4dd-5104-9daa-d747884805df" Requires = "ae029012-a4dd-5104-9daa-d747884805df"
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
[compat] [compat]
Highlights = "0.3.1, 0.4, 0.5" Highlights = "0.3.1, 0.4"
JSON = "0.21" JSON = "0.21"
Mustache = "0.4.1, 0.5, 1" Mustache = "0.4.1, 0.5, 1"
Plots = "0.28, 0.29, 1.0" Plots = "0.28, 0.29, 1.0"
RelocatableFolders = "0.1,0.2,0.3,1"
Requires = "1.0" Requires = "1.0"
YAML = "0.3, 0.4" YAML = "0.3, 0.4"
julia = "1.2" julia = "1.2"

View File

@ -97,8 +97,3 @@ Thanks for the important additions, fixes and comments.
- [DiffEqTutorials.jl](https://github.com/JuliaDiffEq/DiffEqTutorials.jl) uses Weave to output tutorials (`.jmd` documents) to html, pdf and Jupyter notebooks. - [DiffEqTutorials.jl](https://github.com/JuliaDiffEq/DiffEqTutorials.jl) uses Weave to output tutorials (`.jmd` documents) to html, pdf and Jupyter notebooks.
- [TuringTutorials](https://github.com/TuringLang/TuringTutorials) uses Weave to convert notebooks to html. - [TuringTutorials](https://github.com/TuringLang/TuringTutorials) uses Weave to convert notebooks to html.
## Related packages
- [Literate.jl](https://github.com/fredrikekre/Literate.jl) can be used to generate Markdown and Jupyter notebooks directly from Julia source files with markdown in comments.
- [Quarto](https://quarto.org) can generate Jupyter notebooks, HTML, or PDF directly from a Markdown format containing Julia code blocks, and also works with R and Python.

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 import Dates; Dates.Date(Dates.now())` date: `j Date(now())`
--- ---
```julia; echo = false ```julia; echo = false
using Dates using Datas
``` ```
``` ```

View File

@ -130,7 +130,7 @@ e.g. to include a Plots figure in markdown you can use:
``` ```
or to produce any HTML output: or to produce any HTML output:
``` ```
! display("text/html", HTML("Header from julia")); ! display("text/html", "Header from julia");
``` ```
### Script Format ### Script Format
@ -165,12 +165,29 @@ See [Header Configuration](@ref) section for more details.
## Passing Runtime Arguments to Documents ## Passing Runtime Arguments to Documents
You can pass arbitrary object to the weaved document using [`weave`](@ref)'s optional argument `args`. You can pass arguments as `Dict` to the weaved document using the `args` argument
It will be available as `WEAVE_ARGS` variable in the `weave`d document. to `weave`. The arguments will be available as `WEAVE_ARGS` variable in the 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.
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` 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.
## `include_weave` ## `include_weave`

View File

@ -1,13 +1,14 @@
module Weave module Weave
using Highlights, Mustache, Requires, Pkg, REPL, RelocatableFolders, Base64 using Highlights, Mustache, Requires, Pkg, REPL
# directories # directories
const PKG_DIR = normpath(@__DIR__, "..") const PKG_DIR = normpath(@__DIR__, "..")
const TEMPLATE_DIR = @path joinpath(PKG_DIR, "templates") const TEMPLATE_DIR = normpath(PKG_DIR, "templates")
const STYLESHEET_DIR = @path joinpath(PKG_DIR, "stylesheets") const STYLESHEET_DIR = normpath(PKG_DIR, "stylesheets")
# keeps paths of sample documents for easy try # keeps paths of sample documents for easy try
const EXAMPLE_FOLDER = @path joinpath(PKG_DIR, "examples") const EXAMPLE_FOLDER = normpath(PKG_DIR, "examples")
# constant names # constant names
const WEAVE_OPTION_NAME = "weave_options" const WEAVE_OPTION_NAME = "weave_options"
@ -101,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::Any = Dict()`: A runtime object that is available as `WEAVE_ARGS` while `weave`ing - `args::Dict = Dict()`: Arguments to be passed to the weaved document; will be available as `WEAVE_ARGS` in the document
- `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`
@ -126,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::Any = Dict(), args::Dict = 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,
@ -243,16 +244,8 @@ function specific_options!(weave_options, doctype)
end end
get_out_path(doc, out_path, ext::Nothing = nothing) = get_out_path(doc, out_path, doc.format.extension) get_out_path(doc, out_path, ext::Nothing = nothing) = get_out_path(doc, out_path, doc.format.extension)
function get_out_path(doc, out_path, ext) get_out_path(doc, out_path, ext) = abspath(get_cwd(doc, out_path), string(doc.basename , '.', ext))
if (out_path === :doc) || (out_path === :pwd)
abspath(get_cwd(doc, out_path), string(doc.basename, '.', ext))
elseif isempty(splitext(out_path)[2]) # directory given
abspath(get_cwd(doc, out_path), string(doc.basename, '.', ext))
else
# out_path is given, but if extension is explitly provided override this will override the extension
abspath(string(splitext(out_path)[1], '.', ext))
end
end
""" """
notebook(source::AbstractString; kwargs...) notebook(source::AbstractString; kwargs...)

View File

@ -5,11 +5,9 @@ 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
# HACK: that this definition is type-piracy. It is required since `Markdown` # Note that this definition causes a "Method overwritten" warning,
# does not have a built in system for contextual rendering by users. `io` here # but defining this function in __init__() is not legal in julia v1.5
# should always be either `IOBuffer` or `IOContext` since it is reached via function Markdown.latex(io::IO, tex::Markdown.LaTeX)
# `sprint` in all user-facing code paths in `Markdown`.
function Markdown.latex(io::Union{IOBuffer,IOContext}, tex::Markdown.LaTeX)
math_envs = ["align", "equation", "eqnarray"] math_envs = ["align", "equation", "eqnarray"]
use_dollars = use_dollars =
!any([occursin("\\begin{$me", tex.formula) for me in math_envs]) !any([occursin("\\begin{$me", tex.formula) for me in math_envs])

View File

@ -1,6 +1,6 @@
module WeavePlots module WeavePlots
using ..Base64, ..Plots, ..Weave using Base64, ..Plots, ..Weave
# Pre-execute hooks to set the plot size for the chunk # Pre-execute hooks to set the plot size for the chunk
@ -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

@ -5,7 +5,7 @@ function parse_markdown(document_body; is_pandoc = false)
r"^<<(?<options>.*?)>>=\s*$", r"^<<(?<options>.*?)>>=\s*$",
r"^@\s*$" r"^@\s*$"
else else
r"^[`~]{3}(\{?)julia\s*([;,\{]?)\s*(?<options>.*?)(\}|\s*)$", r"^[`~]{3}(\{?)julia\s*([;,]?)\s*(?<options>.*?)(\}|\s*)$",
r"^[`~]{3}\s*$" r"^[`~]{3}\s*$"
end end
return header, parse_markdown_body(document_body, code_start, code_end, offset) return header, parse_markdown_body(document_body, code_start, code_end, offset)

View File

@ -44,14 +44,18 @@ function render_chunk(docformat::WeaveFormat, chunk::CodeChunk)
chunk.content = render_code(docformat, chunk.content) chunk.content = render_code(docformat, chunk.content)
echo = chunk.options[:echo] if !chunk.options[:eval]
return if chunk.options[:echo]
chunk.options[:eval] || return echo ? string(docformat.codestart, chunk.content, docformat.codeend) : "" string(docformat.codestart, '\n', 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 echo result = if chunk.options[: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
@ -122,7 +126,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, docformat.termend) string(docformat.termstart, chunk.output, '\n', docformat.termend, '\n')
else else
"" ""
end end

View File

@ -1,24 +0,0 @@
abstract type ExportFormat <: WeaveFormat end
function Base.getproperty(sf::T, s::Symbol) where {T<:ExportFormat}
hasfield(T, s) && return getfield(sf, s)
return getproperty(sf.primaryformat, s)
end
function Base.setproperty!(sf::T, s::Symbol, v) where {T<:ExportFormat}
if hasfield(T, s)
setfield!(sf, s, v)
else
setproperty!(sf.primaryformat, s, v)
end
end
function Base.hasproperty(sf::T, s::Symbol) where {T<:ExportFormat}
hasfield(T, s) || hasproperty(sf.primaryformat, s)
end
render_doc(df::ExportFormat, body, doc) = render_doc(df.primaryformat, body, doc)
render_chunk(df::ExportFormat, chunk) = render_chunk(df.primaryformat, chunk)
# Need to define these to avoid ambiguities
render_chunk(df::ExportFormat, chunk::DocChunk) = render_chunk(df.primaryformat, chunk)
render_chunk(df::ExportFormat, chunk::CodeChunk) = render_chunk(df.primaryformat, chunk)
render_output(df::ExportFormat, output) = render_output(df.primaryformat, output)

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\">"
@ -124,9 +124,23 @@ end
# Pandoc # Pandoc
# ------ # ------
Base.@kwdef mutable struct Pandoc2HTML <: ExportFormat Base.@kwdef mutable struct Pandoc2HTML <: HTMLFormat
description = "HTML via intermediate Pandoc Markdown (requires Pandoc 2)" description = "HTML via intermediate Pandoc Markdown (requires Pandoc 2)"
primaryformat = Pandoc() extension = "md"
codestart = "\n"
codeend = "\n"
termstart = codestart
termend = codeend
outputstart = "\n"
outputend = "\n"
mimetypes = ["image/png", "image/svg+xml", "image/jpg", "text/html", "text/markdown", "text/plain"]
fig_ext = ".png"
out_width = nothing
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
preserve_header = true
template_path = nothing template_path = nothing
stylesheet_path = nothing stylesheet_path = nothing
highlight_theme = nothing highlight_theme = nothing

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" codeend = "````\n\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" codeend = "````\n\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" codeend = "````\n\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" codeend = "\n\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" codeend = "--------------------------------------\n\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" codeend = "~~~~~~~~~~~~~\n\n"
termstart = codestart termstart = codestart
termend = codeend termend = codeend
outputstart = "~~~~" outputstart = "~~~~"
@ -54,14 +54,28 @@ Base.@kwdef mutable struct Pandoc <: PandocFormat
end end
register_format!("pandoc", Pandoc()) register_format!("pandoc", Pandoc())
const DEFAULT_PANDOC_OPTIONS = String[] const DEFAULT_PANDOC_OPTIONS = String[]
Base.@kwdef mutable struct Pandoc2PDF <: ExportFormat Base.@kwdef mutable struct Pandoc2PDF <: PandocFormat
description = "PDF via intermediate Pandoc Markdown" description = "PDF via intermediate Pandoc Markdown"
primaryformat = Pandoc() extension = "md"
pandoc_options = DEFAULT_PANDOC_OPTIONS codestart = "~~~~{.julia}"
codeend = "~~~~~~~~~~~~~\n\n"
termstart = codestart
termend = codeend
outputstart = "~~~~"
outputend = "~~~~\n\n"
# Prefer png figures for markdown conversion, svg doesn't work with latex
mimetypes = ["image/png", "image/jpg", "image/svg+xml", "text/markdown", "text/plain"]
fig_ext = ".png"
out_width = nothing
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
preserve_header = true
header_template = normpath(TEMPLATE_DIR, "pandoc2pdf_header.txt") header_template = normpath(TEMPLATE_DIR, "pandoc2pdf_header.txt")
pandoc_options = DEFAULT_PANDOC_OPTIONS
end end
register_format!("pandoc2pdf", Pandoc2PDF()) register_format!("pandoc2pdf", Pandoc2PDF())

View File

@ -23,9 +23,9 @@ function render_doc(doc::WeaveDoc)
return render_doc(docformat, body, doc) return render_doc(docformat, body, doc)
end end
include("exportformat.jl")
include("common.jl") include("common.jl")
include("pandocformats.jl")
include("htmlformats.jl") include("htmlformats.jl")
include("texformats.jl") include("texformats.jl")
include("pandocformats.jl")
include("miscformats.jl") include("miscformats.jl")

View File

@ -34,10 +34,7 @@ render_output(docformat::LaTeXFormat, output) = unicode2latex(docformat, output,
render_code(docformat::LaTeXFormat, code) = unicode2latex(docformat, code, true) render_code(docformat::LaTeXFormat, code) = unicode2latex(docformat, code, true)
render_termchunk(docformat::LaTeXFormat, chunk) = render_termchunk(docformat::LaTeXFormat, chunk) = string(docformat.termstart, chunk.output, docformat.termend, "\n")
string(docformat.termstart,
unicode2latex(docformat, chunk.output, true),
docformat.termend, "\n")
# from julia symbols (e.g. "\bfhoge") to valid latex # from julia symbols (e.g. "\bfhoge") to valid latex
const UNICODE2LATEX = let const UNICODE2LATEX = let
@ -152,11 +149,11 @@ end
Base.@kwdef mutable struct LaTeXMinted <: LaTeXFormat Base.@kwdef mutable struct LaTeXMinted <: LaTeXFormat
description = "LaTeX using minted package for code highlighting" description = "LaTeX using minted package for code highlighting"
extension = "tex" extension = "tex"
codestart = "\\begin{minted}[texcomments = true, mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}" codestart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}"
codeend = "\\end{minted}" codeend = "\\end{minted}"
termstart = "\\begin{minted}[texcomments = true, mathescape, fontsize=\\footnotesize, xleftmargin=0.5em]{jlcon}" termstart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\footnotesize, xleftmargin=0.5em]{jlcon}"
termend = "\\end{minted}" termend = "\\end{minted}"
outputstart = "\\begin{minted}[texcomments = true, mathescape, fontsize=\\small, xleftmargin=0.5em, frame = leftline]{text}" outputstart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\small, xleftmargin=0.5em, frame = leftline]{text}"
outputend = "\\end{minted}" outputend = "\\end{minted}"
mimetypes = ["application/pdf", "image/png", "text/latex", "text/plain"] mimetypes = ["application/pdf", "image/png", "text/latex", "text/plain"]
fig_ext = ".pdf" fig_ext = ".pdf"
@ -201,14 +198,8 @@ function render_code(docformat::WeaveLaTeXFormat, code)
unicode2latex(docformat, ret, false) unicode2latex(docformat, ret, false)
end end
function render_termchunk(docformat::WeaveLaTeXFormat, chunk) render_termchunk(docformat::WeaveLaTeXFormat, chunk) =
if should_render(chunk) should_render(chunk) ? highlight_term(MIME("text/latex"), chunk.output, docformat.highlight_theme) : ""
ret = highlight_term(MIME("text/latex"), chunk.output, docformat.highlight_theme)
unicode2latex(docformat, ret, true)
else
""
end
end
function render_doc(docformat::WeaveLaTeXFormat, body, doc) function render_doc(docformat::WeaveLaTeXFormat, body, doc)
return Mustache.render( return Mustache.render(
@ -242,23 +233,44 @@ Base.@kwdef mutable struct WeaveLaTeX <: WeaveLaTeXFormat
tex_deps = "" tex_deps = ""
# how to escape latex in verbatim/code environment # how to escape latex in verbatim/code environment
escape_starter = "(*@" escape_starter = "(*@"
escape_closer = "@*)" escape_closer = reverse(escape_starter)
end end
register_format!("md2tex", WeaveLaTeX()) register_format!("md2tex", WeaveLaTeX())
# will be used by `write_doc` # will be used by `write_doc`
const DEFAULT_LATEX_CMD = ["xelatex", "-shell-escape", "-halt-on-error"] const DEFAULT_LATEX_CMD = ["xelatex", "-shell-escape", "-halt-on-error"]
Base.@kwdef mutable struct WeaveLaTeX2PDF <: WeaveLaTeXFormat
Base.@kwdef mutable struct LaTeX2PDF <: ExportFormat description = "PDF via Weave-styled LaTeX"
primaryformat = WeaveLaTeX() extension = "tex"
description = "PDF via LaTeX" codestart = ""
codeend = ""
termstart = codestart
termend = codeend
outputstart = "\\begin{lstlisting}"
outputend = "\\end{lstlisting}\n"
mimetypes = ["application/pdf", "image/png", "image/jpg", "text/latex", "text/markdown", "text/plain"]
fig_ext = ".pdf"
out_width = "\\linewidth"
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
highlight_theme = nothing
template = nothing
keep_unicode = false
tex_deps = ""
latex_cmd = DEFAULT_LATEX_CMD latex_cmd = DEFAULT_LATEX_CMD
# how to escape latex in verbatim/code environment
escape_starter = "(*@"
escape_closer = reverse(escape_starter)
end end
register_format!("md2pdf", LaTeX2PDF()) register_format!("md2pdf", WeaveLaTeX2PDF())
register_format!("minted2pdf", LaTeX2PDF(primaryformat=LaTeXMinted()))
function set_format_options!(docformat::LaTeX2PDF; latex_cmd = DEFAULT_LATEX_CMD, _kwargs...) function set_format_options!(docformat::WeaveLaTeX2PDF; template = nothing, highlight_theme = nothing, keep_unicode = false, latex_cmd = DEFAULT_LATEX_CMD, _kwargs...)
docformat.template =
get_mustache_template(isnothing(template) ? normpath(TEMPLATE_DIR, "md2pdf.tpl") : template)
docformat.highlight_theme = get_highlight_theme(highlight_theme)
docformat.keep_unicode |= keep_unicode
docformat.latex_cmd = latex_cmd docformat.latex_cmd = latex_cmd
set_format_options!(docformat.primaryformat; _kwargs...)
end end

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::Any = Dict(), args::Dict = 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,9 +20,8 @@ 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)
mkpath(cwd) isdir(cwd) || mkdir(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)))
@ -30,7 +29,7 @@ function run_doc(
DEFAULT_FIG_PATH DEFAULT_FIG_PATH
end end
end end
mkpath(normpath(cwd, fig_path)) let d = normpath(cwd, fig_path); isdir(d) || mkdir(d); end
# 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)
@ -39,7 +38,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)
Core.eval(mod, :(WEAVE_ARGS = $(args))) @eval mod WEAVE_ARGS = $args
mimetypes = doc.format.mimetypes mimetypes = doc.format.mimetypes
@ -90,8 +89,6 @@ function run_doc(
@info "Weaved all chunks" progress=1 _id=PROGRESS_ID @info "Weaved all chunks" progress=1 _id=PROGRESS_ID
cd_back() cd_back()
popdisplay(report) # ensure display pops out even if internal error occurs popdisplay(report) # ensure display pops out even if internal error occurs
# Temporary fig_path is not automatically removed because it contains files so...
!isnothing(fig_path) && startswith(fig_path, "jl_") && rm(normpath(cwd, fig_path), force=true, recursive=true)
end end
return doc return doc
@ -142,17 +139,27 @@ 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)
return ext == ".png" ? "data:image/png;base64," * stringmime(MIME("image/png"), raw) : if ext == ".png"
ext == ".svg" ? "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw) : return "data:image/png;base64," * stringmime(MIME("image/png"), raw)
ext == ".gif" ? "data:image/gif;base64," * stringmime(MIME("image/gif"), raw) : elseif ext == ".svg"
fig 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
end end
function run_chunk(chunk::DocChunk, doc, report, mod) function run_chunk(chunk::DocChunk, doc, report, mod)
@ -218,7 +225,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) && !REPL.ends_with_semicolon(code) && display(obj) !isnothing(obj) && display(obj)
catch _err catch _err
err = unwrap_load_err(_err) err = unwrap_load_err(_err)
error || throw(err) error || throw(err)
@ -266,9 +273,15 @@ function eval_chunk(doc::WeaveDoc, chunk::CodeChunk, report::Report, mod::Module
execute_posthooks!(chunk) execute_posthooks!(chunk)
return chunk.options[:term] ? collect_term_results(chunk) : chunks = if chunk.options[:term]
chunk.options[:hold] ? collect_hold_results(chunk) : collect_term_results(chunk)
elseif chunk.options[:hold]
collect_hold_results(chunk)
else
collect_results(chunk) 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,
@ -279,11 +292,7 @@ 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
function execute_prehooks!(chunk::CodeChunk) execute_prehooks!(chunk::CodeChunk) = for prehook in preexecution_hooks; Base.invokelatest(prehook, chunk); end
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)
@ -292,11 +301,7 @@ 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
function execute_posthooks!(chunk::CodeChunk) execute_posthooks!(chunk::CodeChunk) = for posthook in postexecution_hooks; Base.invokelatest(posthook, chunk); end
for posthook in postexecution_hooks
Base.invokelatest(posthook, chunk)
end
end
""" """
clear_module!(mod::Module) clear_module!(mod::Module)
@ -335,7 +340,11 @@ 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)
doc.chunk_defaults[:fig_ext] = isnothing(fig_ext) ? doc.format.fig_ext : 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_path] = fig_path doc.chunk_defaults[:fig_path] = fig_path
end end
@ -343,9 +352,11 @@ 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 any(!isempty strip, (r.stdout, r.rich_output)) || !isempty(r.figures) if strip(r.stdout) == "" && isempty(r.figures) && strip(r.rich_output) == ""
content *= r.code
else
content = "\n" * content * r.code
rchunk = CodeChunk( rchunk = CodeChunk(
content, content,
chunk.number, chunk.number,
@ -353,14 +364,15 @@ 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,

View File

@ -1,4 +1,4 @@
function write_doc(docformat::LaTeX2PDF, doc, rendered, out_path) function write_doc(docformat::WeaveLaTeX2PDF, doc, rendered, out_path)
cd_back = let d = pwd(); () -> cd(d); end cd_back = let d = pwd(); () -> cd(d); end
cd(doc.cwd) cd(doc.cwd)
try try

View File

@ -61,7 +61,7 @@ function write_doc(docformat::Pandoc2PDF, doc, rendered, out_path)
cmd = `pandoc -f markdown+raw_tex -s --pdf-engine=xelatex --highlight-style=tango cmd = `pandoc -f markdown+raw_tex -s --pdf-engine=xelatex --highlight-style=tango
$filt $citeproc $(docformat.pandoc_options) $filt $citeproc $(docformat.pandoc_options)
--include-in-header=$(docformat.header_template) --include-in-header=$(docformat.header_template)
-o $(out)` -V fontsize=12pt -o $(out)`
proc = open(cmd, "r+") proc = open(cmd, "r+")
println(proc.in, rendered) println(proc.in, rendered)
close(proc.in) close(proc.in)

View File

@ -3,7 +3,7 @@ using Weave.Dates
test_doctypes = filter(first.(Weave.list_out_formats())) do doctype test_doctypes = filter(first.(Weave.list_out_formats())) do doctype
# don't test doctypes which need external programs # don't test doctypes which need external programs
doctype ("pandoc2html", "pandoc2pdf", "md2pdf", "minted2pdf") doctype ("pandoc2html", "pandoc2pdf", "md2pdf")
end end
function test_func(body) function test_func(body)
@ -24,6 +24,7 @@ using Dates
Date(now()) Date(now())
``` ```
""" """
for doctype in test_doctypes for doctype in test_doctypes
test_mock_weave(test_func, julia_markdown_body; informat = "markdown", doctype = doctype) test_mock_weave(test_func, julia_markdown_body; informat = "markdown", doctype = doctype)
end end

View File

@ -72,10 +72,6 @@ let opts = get_options("```julia, opt1 = 1, opt2 = \"2\"\n```")
@test (:opt1 => 1) in opts @test (:opt1 => 1) in opts
@test (:opt2 => "2") in opts @test (:opt2 => "2") in opts
end end
let opts = get_options("```julia{opt1 = 1, opt2 = \"2\"}\n```")
@test (:opt1 => 1) in opts
@test (:opt2 => "2") in opts
end
end end

View File

@ -46,14 +46,4 @@ Core.eval(m, :(const a = $ary))
Weave.clear_module!(m) Weave.clear_module!(m)
@test_broken Base.summarysize(m) < size @test_broken Base.summarysize(m) < size
julia_markdown_body = """
this is just to test the `out_path` option
"""
f_in = tempname()
f_out = tempname() * ".md"
write(f_in, julia_markdown_body)
f = weave(f_in; out_path=f_out)
@test isfile(f_out)
end # @testset "clear_module!" end # @testset "clear_module!"

View File

@ -6,18 +6,18 @@
doc = mock_run(""" doc = mock_run("""
```julia ```julia
using DataFrames using DataFrames
DataFrame(a=rand(10)) DataFrame(rand(10,3))
``` ```
"""; doctype = "md2html") """; doctype = "md2html")
@test isdefined(doc.chunks[1], :rich_output) @test isdefined(doc.chunks[1], :rich_output)
@test count("<tr", doc.chunks[1].rich_output) == 12 # additonal 2 for name and type row @test count("<tr>", doc.chunks[1].rich_output) == 12 # additonal 2 for name and type row
# limit # limit
n = 100000 n = 100000
doc = mock_run(""" doc = mock_run("""
```julia ```julia
using DataFrames using DataFrames
DataFrame(a=rand($n)) DataFrame(rand($n,3))
``` ```
"""; doctype = "md2html") """; doctype = "md2html")
@test isdefined(doc.chunks[1], :rich_output) @test isdefined(doc.chunks[1], :rich_output)