Merge remote-tracking branch 'upstream/master'

pull/387/head
Robert Moss 2020-10-02 18:00:36 -07:00
commit c3d1c1a071
149 changed files with 3886 additions and 5689 deletions

31
.github/ISSUE_TEMPLATE/bug.md vendored Normal file
View File

@ -0,0 +1,31 @@
---
name: bug report
about: create a bug report
title: "[BUG]"
labels: bug
assignees: ''
---
<!-- Please search existing issues to avoid duplicates. -->
## description
## versions
> `using InteractiveUtils; versioninfo()`:
<!-- please paste the the output of `using InteractiveUtils; versioninfo()` in the backticks below -->
```julia
```
> `using Pkg; Pkg.status()`:
<!-- please paste the the output of `using Pkg; Pkg.status()` in the backticks below -->
```julia
```
## minimum reproducible steps
<!-- if possible, paste here a minimum reproducible example document and steps -->

11
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View File

@ -0,0 +1,11 @@
---
name: enhancement
about: suggest an enhancement idea
title: "[FR]"
labels: enhancement
assignees: ''
---
<!-- Please search existing issues to avoid duplicates. -->
## description

67
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,67 @@
# TODO: build docs via github-actions
name: CI
on:
push:
branches:
- master
pull_request:
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.allow-failure }}
strategy:
fail-fast: false # don't stop CI even when one of them fails
matrix:
version:
- '1.5'
os:
- ubuntu-latest
- macOS-latest
# - windows-latest # TODO: test on Windows
arch:
- x64
- x86
allow-failure: [false]
include:
# this is so verbose... any other way to simplify this ?
- version: 'nightly'
os: ubuntu-latest
arch: x64
allow-failure: true
- version: 'nightly'
os: ubuntu-latest
arch: x86
allow-failure: true
- version: 'nightly'
os: macOS-latest
arch: x64
allow-failure: true
# - version: 'nightly'
# os: windows-latest
# arch: x64
# allow-failure: true
# - version: 'nightly'
# os: windows-latest
# arch: x86
# allow-failure: true
exclude:
- os: macOS-latest
arch: x86
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: julia-actions/julia-buildpkg@latest
- uses: julia-actions/julia-runtest@latest
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: ./lcov.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}

9
.gitignore vendored
View File

@ -1,6 +1,5 @@
Manifest.toml
src/*.cov
test.jl
examples/figures/
examples/*.md
examples/*.pdf
@ -22,15 +21,9 @@ test/**/*.ipynb
doc/build
doc/site
stable/
doc/Manifest.toml
Manifest.toml
tmp/
.idea
*.*~
*.aux
*.log
*.out
\#*\#
.juliahistory

View File

@ -1,29 +1,12 @@
language: julia
julia:
- 1.0
- 1.3
- 1.4
- nightly
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia --check-bounds=yes -e 'using Pkg; Pkg.build()'
- xvfb-run julia -e 'using Pkg; Pkg.test("Weave", coverage=true)'
after_success:
- julia -e 'using Pkg; cd(Pkg.dir("Weave")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
jobs:
allow_failures:
- julia: 1.4
- julia: nightly
include:
- stage: "Documentation"
julia: 1.3
julia: 1.5
os: linux
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()'
- julia --project=doc/ doc/make.jl
after_success: skip

View File

@ -1,22 +1,20 @@
The Weave.jl package is licensed under the MIT "Expat" License:
Copyright (c) 2020: Contributors
> Copyright (c) 2014-2017: Matti Pastell.
>
> Permission is hereby granted, free of charge, to any person obtaining
> a copy of this software and associated documentation files (the
> "Software"), to deal in the Software without restriction, including
> without limitation the rights to use, copy, modify, merge, publish,
> distribute, sublicense, and/or sell copies of the Software, and to
> permit persons to whom the Software is furnished to do so, subject to
> the following conditions:
>
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

68
NEWS.md
View File

@ -1,20 +1,66 @@
## Release notes for Weave.jl
### 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)
- document metadata in YAML header can be given dynamically (#329)
- headers are now striped more gracefully; only Weave.jl related header is stripped when weaving to `github` or `hugo` document (#329, #305)
- `WeavePlots`/`GadflyPlots` won't be loaded into `Main` module (#322)
- un`const` bindings in a sandbox module are correctly cleared, helping GC free as much memory usage as possible (#317)
- keep latex figures even if weaving failed (#302)
- bunch of documentation improvements (#297, #295)
- code size in HTML header is now not hardcoded, leading to more readable font size (#281)
bug fixes:
- display of "big" object is fixed and limited (#311)
- fix dependencies issues
internal:
- bunch of internal refactors, code clean up (#330, #327, #325, #321, #320, #319, #318, #313)
- internal error now doesn't mess up display system (#316)
- format code base (#312)
breaking change:
- `options` YAML key is deprecated, use `weave_options` key instead (#334)
- `set_chunk_defaults` is now renamed to `set_chunk_defaults!` (#323)
- `restore_chunk_defaults` is now renamed to `restore_chunk_defaults!` (#323)
---
# Release notes for Weave.jl
### v0.4.1
* Disable precompilation due to warnings from depencies
* Disable precompilation due to warnings from dependencies
* Fix deprecation warnings for Julia 0.6
* Fix PyPlot for Julia 0.6
* Support citations in `pandoc2html` and `pandoc2pdf` output
* Fix extra whitespace when `term=true`
* Fix mime type priority for `md2html`
### V0.4.0
* Support passing arguments to document using `args` option
* Add `include_weave` for including code from Weave documents
* Add support for inline code chunks
* Remove generated figure files when publishing to html and pdf
### v0.3.0
* Add support for YAML title block
@ -25,11 +71,13 @@
* Fix extra whitespace from code chunk output
* Improved GR and GLVisualize support with Plots
### v0.2.2
* Add IJulia notebook as input format
* Add `convert_doc` method to convert between input formats
### v0.2.1
* Fix critical hanging on Windows using proper handling of redirect_stdout
@ -37,6 +85,7 @@
output in published HTML documents.
* Fix semicolons for `term=true`
### v0.2
* Move to Julia 0.5 only
@ -57,6 +106,7 @@
- Fix parsing of lone variables from chunks
- Fix error with md2html formatter and dates #38
### v0.1.2
27th April 2016
@ -66,6 +116,7 @@
* Improve doctype autodetection
* Improved regex for parsing markdown input format
### v0.1.1
* Change pandoc output to use inline images if there is no caption.
@ -81,6 +132,7 @@
* Autodetect input and output formats based on filename
* Allow `out_path` be a file or directory.
### v0.1.0
19th April 2016
@ -97,6 +149,7 @@
- Chunks are now represented with their own type. Allows multiple dispatch
and easier implementation of new chunks.
### 0.0.4
4th January 2015
@ -106,6 +159,7 @@
* New option: `out_path` for controlling where weaved documents and figures are saved
* Command line script `bin/weave.jl` for calling weave from command line
### 0.0.3
9th December 2014
@ -121,8 +175,8 @@
7th December 2014
* First release
* Noweb and markdown input formats
* Support for Gadfly, Winston and PyPlot figures
* Term and script chunks
* Support for markdown, tex and rst output
First release:
- Noweb and markdown input formats
- Support for Gadfly, Winston and PyPlot figures
- Term and script chunks
- Support for markdown, tex and rst output

View File

@ -1,6 +1,6 @@
name = "Weave"
uuid = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"
version = "0.9.4"
version = "0.10.6"
[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
@ -9,6 +9,7 @@ Highlights = "eafb193a-b7ab-5a9e-9068-77385905fa72"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
@ -19,18 +20,16 @@ YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
Highlights = "0.3.1, 0.4"
JSON = "0.21"
Mustache = "0.4.1, 0.5, 1"
Plots = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29"
Plots = "0.28, 0.29, 1.0"
Requires = "1.0"
YAML = "0.3, 0.4"
julia = "1"
julia = "1.2"
[extras]
Cairo = "159f3aea-2a34-519c-b102-8c37f9878175"
Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004"
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[targets]
test = ["Test", "Plots", "Gadfly", "Cairo", "Conda", "IJulia"]
test = ["DataFrames", "Test"]

View File

@ -1,27 +1,30 @@
# Weave
[![Build Status](https://travis-ci.org/JunoLab/Weave.jl.svg?branch=master)](https://travis-ci.org/JunoLab/Weave.jl)
![CI](https://github.com/JunoLab/Weave.jl/workflows/CI/badge.svg)
[![codecov](https://codecov.io/gh/JunoLab/Weave.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JunoLab/Weave.jl)
[![](https://img.shields.io/badge/docs-stable-blue.svg)](http://weavejl.mpastell.com/stable/)
[![](https://img.shields.io/badge/docs-dev-blue.svg)](http://weavejl.mpastell.com/dev/)
[![](http://joss.theoj.org/papers/10.21105/joss.00204/status.svg)](http://dx.doi.org/10.21105/joss.00204)
Weave is a scientific report generator/literate programming tool
for Julia. It resembles [Pweave](http://mpastell.com/pweave), Knitr, rmarkdown
and Sweave.
Weave is a scientific report generator/literate programming tool for the [Julia programming language](https://julialang.org/).
It resembles
[Pweave](http://mpastell.com/pweave),
[knitr](https://yihui.org/knitr/),
[R Markdown](https://rmarkdown.rstudio.com/),
and [Sweave](https://stat.ethz.ch/R-manual/R-patched/library/utils/doc/Sweave.pdf).
You can write your documentation and code in input document using Noweb,
Markdown, Script syntax and use `weave` function to execute to document to capture results
and figures.
You can write your documentation and code in input document using Markdown, Noweb or ordinal Julia script syntax,
and then use `weave` function to execute code and generate an output document while capturing results and figures.
**Current features**
* Publish markdown directly to html and pdf using Julia or Pandoc markdown.
* Markdown, script of Noweb syntax for input documents.
* Execute code as terminal or "script" chunks.
* Capture Plots.jl or Gadfly.jl figures
* Supports LaTex, Pandoc, Github markdown, MultiMarkdown, Asciidoc and reStructuredText output
* Simple caching of results
* Convert to and from IJulia notebooks
- Publish markdown directly to HTML and PDF using Julia or [Pandoc](https://pandoc.org/MANUAL.html)
- Execute code as in terminal or in a unit of code chunk
- Capture [Plots.jl](https://github.com/JuliaPlots/Plots.jl) or [Gadfly.jl](https://github.com/GiovineItalia/Gadfly.jl) figures
- Supports various input format: Markdown, [Noweb](https://www.cs.tufts.edu/~nr/noweb/), [Jupyter Notebook](https://jupyter.org/), and ordinal Julia script
- Conversions between those input formats
- Supports various output document formats: HTML, PDF, GitHub markdown, Jupyter Notebook, MultiMarkdown, Asciidoc and reStructuredText
- Simple caching of results
**Citing Weave:** *Pastell, Matti. 2017. Weave.jl: Scientific Reports Using Julia. The Journal of Open Source Software. http://dx.doi.org/10.21105/joss.00204*
@ -37,25 +40,29 @@ using Pkg
Pkg.add("Weave")
```
## Usage
Run from julia using Plots.jl for plots:
```julia
#First add depencies for the example
using Pkg; Pkg.add.(["Plots", "DSP"])
#Use Weave
using Weave
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"), out_path=:pwd)
# add depencies for the example
using Pkg; Pkg.add(["Plots", "DSP"])
filename = normpath(Weave.EXAMPLE_FOLDER, "FIR_design.jmd")
weave(filename, out_path = :pwd)
```
If you have LaTeX installed you can also weave directly to pdf.
```julia
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
out_path=:pwd, doctype="md2pdf")
filename = normpath(Weave.EXAMPLE_FOLDER, "FIR_design.jmd")
weave(filename, out_path = :pwd, doctype = "md2pdf")
```
NOTE: `Weave.EXAMPLE_FOLDER` just points to [`examples` directory](./examples).
## Documentation
Documenter.jl with MKDocs generated documentation:
@ -63,6 +70,7 @@ Documenter.jl with MKDocs generated documentation:
[![](https://img.shields.io/badge/docs-stable-blue.svg)](http://weavejl.mpastell.com/stable/)
[![](https://img.shields.io/badge/docs-dev-blue.svg)](http://weavejl.mpastell.com/dev/)
## Editor support
Install [language-weave](https://atom.io/packages/language-weave) to add Weave support to Juno.
@ -72,13 +80,18 @@ html and pdf output.
The [Julia extension for Visual Studio Code](https://www.julia-vscode.org/)
adds Weave support to [Visual Studio Code](https://code.visualstudio.com/).
## Contributing
I will probably add new features to Weave when I need them myself or if they are requested and not too difficult to implement. You can contribute by opening issues on Github or implementing things yourself and making a pull request. I'd also appreciate example documents written using Weave to add to examples.
You can contribute to this package by opening issues on GitHub or implementing things yourself and making a pull request.
We'd also appreciate more example documents written using Weave.
## Contributors
You can see the list of contributors on Github: https://github.com/mpastell/Weave.jl/graphs/contributors. Thanks for the important additions, fixes and comments.
You can see the list of contributors on GitHub: https://github.com/JunoLab/Weave.jl/graphs/contributors .
Thanks for the important additions, fixes and comments.
## Example projects using Weave

View File

@ -1,32 +0,0 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/1.0/julia-1.0-latest-win64.exe"
branches:
only:
- master
- /release-.*/
notifications:
- provider: Email
on_build_success: false
on_build_failure: false
on_build_status_changed: false
install:
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile(
$env:JULIA_URL,
"C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
#- C:\projects\julia\bin\julia -e "ENV[\"PYTHON\"]=\"\"; Pkg.add(\"PyPlot\")"
- C:\projects\julia\bin\julia -e "using Pkg; Pkg.clone(pwd(), \"Weave\"); Pkg.build(\"Weave\")"
test_script:
- C:\projects\julia\bin\julia --check-bounds=yes -e "using Pkg; Pkg.test(\"Weave\")"

View File

@ -14,14 +14,14 @@ ap = ArgParseSettings("Weave Julia documents using Weave.jl",
help = "source document(s)"
required = true
"--doctype"
default = :auto
default = nothing
help = "output format"
"--plotlib"
arg_type = String
default = "Gadfly"
help = "output format"
"--informat"
default = :auto
default = nothing
help = "output format"
"--out_path"
arg_type = String
@ -43,9 +43,6 @@ args_col = []
#Check for special values of out_path
#args["informat"] == ":auto" && (args["informat"] = :auto)
#args["doctype"] == ":auto" && (args["informat"] = :auto)
if args["out_path"] == ":doc"
args["out_path"] = :doc
elseif args["out_path"] == ":pwd"

BIN
doc/assets/FIR_design.pdf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,11 @@
using Documenter, Weave
CI_FLG = get(ENV, "CI", nothing) == "true"
makedocs(
modules = [Weave],
format = Documenter.HTML(
prettyurls = get(ENV, "CI", nothing) == "true",
prettyurls = CI_FLG,
canonical = "http://weavejl.mpastell.com/stable/",
),
sitename = "Weave.jl",
@ -13,12 +15,13 @@ makedocs(
"usage.md",
"publish.md",
"chunk_options.md",
"header.md",
"notebooks.md",
"function_index.md",
],
)
include("make_examples.jl")
CI_FLG && include("make_examples.jl")
deploydocs(
repo = "github.com/JunoLab/Weave.jl.git",

View File

@ -1,28 +1,30 @@
using Weave
start_dir = pwd()
cd(@__DIR__)
weave("../examples/FIR_design.jmd",
informat="markdown", out_path = "build/examples", doctype = "pandoc")
let start_dir = pwd()
cd(@__DIR__)
weave("../examples/FIR_design.jmd",
informat="markdown", out_path = "build/examples", doctype = "md2html")
weave("../examples/FIR_design.jmd", doctype = "pandoc", out_path = "build/examples")
weave("../examples/FIR_design.jmd", doctype = "md2html", out_path = "build/examples")
weave("../examples/FIR_design_plots.jl", doctype = "md2html", out_path = "build/examples")
cp("../examples/FIR_design.jmd",
"build/examples/FIR_design.jmd", force = true)
# PDF outputs
if haskey(ENV, "TRAVIS")
# in Travis, just cp already generated PDFs
cp("assets/FIR_design.pdf", "build/examples/FIR_design.pdf", force = true)
cp("assets/FIR_design_plots.pdf", "build/examples/FIR_design_plots.pdf", force = true)
else
# otherwise try to generate them
try
weave("../examples/FIR_design.jmd", doctype = "md2pdf", out_path = "assets")
weave("../examples/FIR_design_plots.jl", doctype = "md2pdf", out_path = "assets")
catch err
@error err
end
end
cp("build/examples/FIR_design.md",
"build/examples/FIR_design.txt", force = true)
cp("../examples/FIR_design.jmd", "build/examples/FIR_design.jmd", force = true)
cp("build/examples/FIR_design.md", "build/examples/FIR_design.txt", force = true)
cp("../examples/FIR_design_plots.jl", "build/examples/FIR_design_plots.jl", force = true)
weave("../examples/FIR_design_plots.jl", out_path = "build/examples")
cp("../examples/FIR_design_plots.jl",
"build/examples/FIR_design_plots.jl", force = true)
if !haskey(ENV, "TRAVIS")
weave("../examples/FIR_design.jmd",
informat="markdown", out_path = "build/examples", doctype = "md2pdf")
weave("../examples/FIR_design_plots.jl", doctype = "md2pdf", out_path = "build/examples")
cd(start_dir)
end
cd(start_dir)

View File

@ -1,55 +1,81 @@
# Chunk options
# [Chunk Options](@id chunk-options)
I've mostly followed [Knitr](http://yihui.name/knitr/options)'s naming for chunk options, but not all options are implemented.
Options are separated using ";" and need to be valid Julia expressions. Example: markdown code chunk that saves and displays a 12 cm wide image and hides the source code:
`julia; out_width="12cm"; echo=false`
Weave currently supports the following chunk options with the following defaults:
## Options for code
* `echo = true`. Echo the code in the output document. If `false` the source code will be hidden.
* `results = "markup"`. The output format of the printed results. "markup" for literal block, "hidden" for hidden results or anything else for raw output (I tend to use tex for Latex and rst for rest. Raw output is useful if you want to e.g. create tables from code chunks.
* `eval = true`. Evaluate the code chunk. If false the chunk wont be executed.
* `term=false`. If true the output emulates a REPL session. Otherwise only stdout and figures will be included in output.
* `label`. Chunk label, will be used for figure labels in Latex as fig:label
* `wrap = true`. Wrap long lines from output.
* `line_width = 75`. Line width for wrapped lines.
* `cache = false`. Cache results, depends on `cache` parameter on `weave` function.
* `hold = false`. Hold all results until the end of the chunk.
* `tangle = true`. Set tangle to false to exclude chunk from tangled code.
## Options for figures
* `fig_width`. Figure width passed to plotting library e.g. `800`
* `fig_height` Figure height passed to plotting library
* `out_width`. Width of saved figure in output markup e.g. "50%", "12cm", `0.5\linewidth`
* `out_height`. Height of saved figure in output markup
* `dpi`=96. Resolution of saved figures.
* `fig_cap`. Figure caption.
* `label`. Chunk label, will be used for figure labels in Latex as fig:label
* `fig_ext`. File extension (format) of saved figures.
* `fig_pos="!h"`. Figure position in Latex.
* `fig_env="figure"`. Figure environment in Latex.
You can use chunk options to configure how each chunk is evaluated, rendered, etc.
Most of the ideas came from [chunk options in RMarkdown](http://yihui.name/knitr/options).
## Set default chunk options
## Syntax
You can set the default chunk options (and `weave` arguments) for a document using the YAML header `options` field. e.g to set the default `out_width` of all figures you can use:
Chunk options come after [code chunk](@ref code-chunks) header.
There are two (slightly) different syntax to write them:
- (Julia's toplevel expression) options are separated by semicolon (`;`)
- (RMarkdown style) options are separated by comma (`,`)
Let's take a look at examples. All the following code chunk header are valid,
and so configured to hide the source code from generated output (`echo = false`)
and displays figures with 12cm width (`out_width = "12cm"`):
```md
```julia; echo = false; out_width = "12cm"
```{julia; echo = false; out_width = "12cm"}
```julia, echo = false, out_width = "12cm"
```{julia, echo = false, out_width = "12cm"}
```
## Weave Chunk Options
Weave currently supports the following chunk options:
we've mostly followed [RMarkdown's namings](http://yihui.name/knitr/options), but not all options are implemented.
### Evaluation
- `eval = true`: Evaluate the code chunk. If `false` the chunk wont be executed.
- `error = true`: If `true` [`weave`](@ref) won't stop on errors and rather they will be included in output document. If `false`, [`weave`](@ref) will halt on any of un-caught errors.
- `cache = false`: Cache results, depending on `cache` parameter on [`weave`](@ref) function.
- `tangle = true`: Set tangle to `false` to exclude chunk from tangled code.
### Rendering
- `echo = true`: Echo the code in the output document. If `false` the source code will be hidden.
- `results = "markup"`: The output format of the printed results. `"markup"` for literal block, `"hidden"` for hidden results, or anything else for raw output (I tend to use `"tex"` for Latex and `"rst"` for rest). Raw output is useful if you want to e.g. create tables from code chunks.
- `term = false`: If `true` the output emulates a REPL session. Otherwise only stdout and figures will be included in output.
- `wrap = true`: Wrap long lines from output.
- `line_width = 75`: Line width for wrapped lines.
- `hold = false`: Hold all results until the end of the chunk.
### Figures
- `label = nothing`: Chunk label, will be used for figure labels in Latex as `fig:label`.
- `fig_width = 6`: Figure width passed to plotting library.
- `fig_height = 4`: Figure height passed to plotting library.
- `out_width`: Width of saved figure in output markup e.g. `"50%"`, `"12cm"`, `0.5\linewidth`
- `out_height`: Height of saved figure in output markup
- `dpi = 96`: Resolution of saved figures.
- `fig_cap`: Figure caption.
- `fig_ext`: File extension (format) of saved figures.
- `fig_pos = "!h"`: Figure position in Latex, e.g.: `"ht"`.
- `fig_env = "figure"`: Figure environment in Latex.
## Default Chunk Options
You can set the default chunk options (and `weave` arguments) for a document using `weave_options` key in YAML [Header Configuration](@ref).
E.g. to set the default `out_width` of all figures you can use:
```yaml
---
options:
out_width : 50%
weave_options:
out_width : 50%
---
```
You can also set or change the default chunk options for a document either before weave using the `set_chunk_defaults` function.
```@docs
set_chunk_defaults
set_chunk_defaults!
get_chunk_defaults
restore_chunk_defaults
restore_chunk_defaults!
```

View File

@ -1,20 +1,18 @@
# Getting started
The best way to get started using Weave.jl is to look at the example input and
output documents. Examples for different formats are included in the packages
[`examples`](https://github.com/JunoLab/Weave.jl/tree/master/examples) directory.
The best way to get started using Weave.jl is to look at the example input and output documents.
Examples for different formats are included in the package's [`examples`](https://github.com/JunoLab/Weave.jl/tree/master/examples) directory.
First have a look at source document using markdown code chunks and
[Plots.jl](https://github.com/JuliaPlots/Plots.jl) for figures:
[FIR_design.jmd](../examples/FIR_design.jmd) and then see the
output in different formats:
First have a look at source document using markdown code chunks and [Plots.jl](https://github.com/JuliaPlots/Plots.jl) for figures:
- HTML: [FIR_design.html](../examples/FIR_design.html)
- pdf: [FIR_design.pdf](../examples/FIR_design.pdf)
- Pandoc markdown: [FIR_design.txt](../examples/FIR_design.txt)
All the different format documents below are generated from a single Weave document [`FIR_design.jmd`](../examples/FIR_design.jmd):
- HTML: [`FIR_design.html`](../examples/FIR_design.html)
- PDF: [`FIR_design.pdf`](../examples/FIR_design.pdf)
- Pandoc markdown: [`FIR_design.txt`](../examples/FIR_design.txt)
*Producing pdf output requires that you have XeLateX installed.*
!!! note
Producing PDF output requires that you have XeLateX installed.
Add dependencies for the example if needed:
@ -22,20 +20,22 @@ Add dependencies for the example if needed:
using Pkg; Pkg.add.(["Plots", "DSP"])
```
Weave the files to your working directory using:
Weave the files to your working directory:
```julia
using Weave
#HTML
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
out_path=:pwd,
doctype = "md2html")
#pdf
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
out_path=:pwd,
doctype = "md2pdf")
#Markdown
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
doctype="pandoc",
out_path=:pwd)
filename = normpath(Weave.EXAMPLE_FOLDER, "FIR_design.jmd")
# Julia markdown to HTML
weave(filename; doctype = "md2html", out_path = :pwd)
# Julia markdown to PDF
weave(filename; doctype = "md2pdf", out_path = :pwd)
# Julia markdown to Pandoc markdown
weave(filename; doctype = "pandoc", out_path = :pwd)
```
!!! tips
`Weave.EXAMPLE_FOLDER` points to [the `examples` directory](https://github.com/JunoLab/Weave.jl/tree/master/examples).

101
doc/src/header.md Normal file
View File

@ -0,0 +1,101 @@
# Header Configuration
When `weave`ing a markdown document, you use YAML header to provide additional metadata and configuration options.
A YAML header should be in the beginning of the input document delimited with `---`.
!!! warning
YAML header configuration is only supported when `weave`ing [markdown or Noweb syntax documents](@ref document-syntax).
## Document Metadata
You can set additional document metadata in YAML header.
When `weave`ing to Julia markdown documents to HTML or PDF, Weave respects the following metadata specification:
- `title`
- `author`
- `date`
An example:
```yaml
---
title : Header Example
author : Shuhei Kadowaki
date: 16th May 2020
---
```
!!! note
You can also have other metadata, but they won't appear in the resulting HTML and PDF.
If you weave to Julia markdown to GitHub/Hugo markdown, all the metadata will be preserved.
### Dynamic Metadata
The metadata can be given "dynamically"; if you have [inline code](@ref) within YAML header, they will be evaluated _after_ evaluating all the chunks and replaced with the results.
The example document below will set `date` metadata dynamically.
Note that `Date` is available since the chunk is evaluated first.
```md
---
title : Header Example
author : Shuhei Kadowaki
date: `j import Dates; Dates.Date(Dates.now())`
---
```julia; echo = false
using Dates
```
```
## Configuration Options
Each of keyword arguments of [`weave`](@ref) can be set in the YAML header under `options` field.
You can also set [Chunks Options](@ref) there that will be applied globally.
The example below sets `out_path` and `doctype` options and overwrites `term` and `wrap` chunk options:
```yaml
---
title : Header Example
author : Shuhei Kadowaki
date: 16th May 2020
weave_options:
out_path: relative/path/to/this/document
doctype: github
term: true
wrap: false
---
```
!!! note
- configurations specified within the YAML header have higher precedence than those specified via `weave` keyword arguments
- chunk options specified within each chunk have higher precedence than the global global chunk options specified within the YAML header
!!! warning
As opposed to metadata, _most_ of those configuration options can't be given dynamically (i.e. can't be via inline code),
since they are needed for evaluation of chunks themselves.
But some configuration options that are needed "formatting" document can still be given dynamically:
- `template`
- `css`
- `highlight_theme`
- `pandoc_options`
- `latex_cmd`
- `keep_unicode`
See also: [`weave`](@ref)
## Format Specific Options
The header configurations can be format specific.
Here is how to set different `out_path` for `md2html` and `md2pdf` and set `fig_ext` globally:
```yaml
---
weave_options:
md2html:
out_path : html
md2pdf:
out_path : pdf
fig_ext : .png
---
```

View File

@ -1,4 +1,3 @@
# Weave.jl - Scientific Reports Using Julia
This is the documentation of [Weave.jl](http://github.com/mpastell/weave.jl).
@ -12,20 +11,28 @@ and [Sweave](https://stat.ethz.ch/R-manual/R-patched/library/utils/doc/Sweave.pd
**Current features**
* Markdown, script of Noweb syntax for input documents
* Publish markdown directly to html and pdf using Julia or Pandoc markdown
* Execute code as terminal or "script" chunks
* Capture Plots.jl or Gadfly.jl figures
* Supports LaTex, Pandoc, GitHub markdown, MultiMarkdown, Asciidoc and reStructuredText output
* Simple caching of results
* Convert to and from IJulia notebooks
- Publish markdown directly to HTML and PDF using Julia or [Pandoc](https://pandoc.org/MANUAL.html)
- Execute code as in terminal or in a unit of code chunk
- Capture [Plots.jl](https://github.com/JuliaPlots/Plots.jl) or [Gadfly.jl](https://github.com/GiovineItalia/Gadfly.jl) figures
- Supports various input format: Markdown, [Noweb](https://www.cs.tufts.edu/~nr/noweb/), [Jupyter Notebook](https://jupyter.org/), and ordinal Julia script
- Conversions between those input formats
- Supports various output document formats: HTML, PDF, GitHub markdown, Jupyter Notebook, MultiMarkdown, Asciidoc and reStructuredText
- Simple caching of results
![Weave in Juno demo](https://user-images.githubusercontent.com/40514306/76081328-32f41900-5fec-11ea-958a-375f77f642a2.png)
## Contents
## Index
```@contents
Pages = ["getting_started.md", "usage.md",
"publish.md", "chunk_options.md", "notebooks.md",
"function_index.md"]
Pages = [
"index.md",
"getting_started.md",
"usage.md",
"publish.md",
"chunk_options.md",
"header.md",
"notebooks.md",
"function_index.md",
]
```

View File

@ -3,32 +3,34 @@
## Weaving from Jupyter notebooks
Weave supports using Jupyter notebooks as input format, this means you
can weave notebooks to any supported formats. You can't use chunk options with notebooks.
Weave supports using [Jupyter Notebook](https://jupyter.org/)s as input format.
This means you can [`weave`](@ref) notebooks to any supported formats;
by default, it will be weaved to HTML.
```julia
weave("notebook.ipynb")
weave("notebook.ipynb") # will be weaved to HTML
```
!!! warning
You can't use chunk options with notebooks.
## Output to Jupyter notebooks
As of Weave 0.5.1. there is new `notebook` method to convert Weave documents
to Jupyter notebooks using [nbconvert](http://nbconvert.readthedocs.io/en/latest/execute_api.html). The code **is not executed by Weave**
and the output doesn't always work properly,
see [#116](https://github.com/mpastell/Weave.jl/issues/116).
As of Weave 0.5.1. there is new [`notebook`](@ref) method to convert Weave documents to Jupyter notebooks using
[nbconvert](http://nbconvert.readthedocs.io/en/latest/execute_api.html).
```@docs
notebook
```
You might want to use the `convert_doc` method below instead and run the code in Jupyter.
You can specify `jupyter` used to execute the notebook with the `jupyter_path` keyword argument
(this defaults to the `"jupyter"`, i.e. whatever you have linked to that location).
You can select the `jupyter` used to execute the notebook with the `jupyter_path` argument (this defaults to the string "jupyter," i.e., whatever you have linked to that location.)
Instead, you might want to use the [`convert_doc`](@ref) method below and run the code in Jupyter.
## Converting between formats
You can convert between all supported input formats using the `convert_doc`
function.
You can convert between all supported input formats using the [`convert_doc`](@ref) function.
To convert from script to notebook:
@ -36,12 +38,12 @@ To convert from script to notebook:
convert_doc("examples/FIR_design.jl", "FIR_design.ipynb")
```
and from notebooks to markdown use:
and from notebook to Markdown use:
```julia
convert_doc("FIR_design.ipynb", "FIR_design.jmd")
```
```@docs
convert_doc(infile::String, outfile::String)
convert_doc
```

View File

@ -1,10 +1,12 @@
# Publishing to html and pdf
# Publishing to HTML and PDF
You can also publish any supported input format using markdown for doc chunks to html and pdf documents. Producing pdf output requires that you have pdflatex installed and in your path.
You can also publish any supported input format to HTML and PDF documents.
You can use a YAML header in the beginning of the input document delimited with "---"
to set the document title, author and date e.g.
!!! note
Producing PDF output requires that you have XeLaTex installed and in your path.
You can use a YAML header in the beginning of the input document delimited with `---`
to set the document title, author and date, e.g.:
```
---
title : Weave example
@ -13,37 +15,48 @@ date: 15th December 2016
---
```
Here is a a sample document and output:
[FIR_design_plots.jl](../examples/FIR_design_plots.jl), [FIR_design_plots.html](../examples/FIR_design_plots.html) , [FIR_design_plots.pdf](../examples/FIR_design_plots.pdf).
Here are sample input and outputs:
- input (Julia markdown format): [`FIR_design_plots.jl`](../examples/FIR_design_plots.jl) (its path is bound to `Weave.SAMPLE_JL_DOC`)
- HTML output: [`FIR_design_plots.html`](../examples/FIR_design_plots.html)
- PDF output: [`FIR_design_plots.pdf`](../examples/FIR_design_plots.pdf)
They are generated as follows:
```julia
weave("FIR_design_plots.jl")
weave("FIR_design_plots.jl", docformat = "md2pdf")
weave(Weave.SAMPLE_JL_DOC)) # default to md2html output format
weave(Weave.SAMPLE_JL_DOC; doctype = "md2pdf")
```
**Note:** docformats `md2pdf` and `md2html` use Julia markdown and `pandoc2pdf` and `pandoc2html`
use Pandoc.
!!! tips
`Weave.SAMPLE_JL_DOC` is the path of [FIR_design.jl](../examples/FIR_design.jl).
!!! note
`"md2html"` and `"md2pdf"` assume Julia markdown format as an input,
while `pandoc2pdf` and `pandoc2html` assume Noweb input format (i.e. Pandoc markdown).
## Templates
You can use a custom template with `md2pdf` and `md2html` formats with `template`
argument (e.g) `weave("FIR_design_plots.jl", template = "custom.tpl"`). You can use
the existing templates as starting point.
You can use a custom template with `md2html` and `md2pdf` formats with `template` keyword option,
e.g.: `weave("FIR_design_plots.jl", template = "custom.tpl"`.
For HTML: [julia_html.tpl](https://github.com/mpastell/Weave.jl/blob/master/templates/julia_html.tpl) and LaTex: [julia_tex.tpl](https://github.com/mpastell/Weave.jl/blob/master/templates/julia_tex.tpl)
As starting point, you can use the existing templates:
- HTML (`md2html`): [`md2html.tpl`](https://github.com/JunoLab/Weave.jl/blob/master/templates/md2html.tpl)
- LaTex (`md2pdf`): [`md2pdf.tpl`](https://github.com/JunoLab/Weave.jl/blob/master/templates/md2pdf.tpl)
Templates are rendered using [Mustache.jl](https://github.com/jverzani/Mustache.jl).
## Supported Markdown syntax
The markdown variant used by Weave is [Julia markdown](https://docs.julialang.org/en/v1/stdlib/Markdown/#). In addition Weave supports few additional Markdown features:
The markdown variant used by Weave is [Julia markdown](https://docs.julialang.org/en/v1/stdlib/Markdown/#).
In addition Weave supports few additional Markdown features:
**Comments**
### Comments
You can add comments using html syntax: `<!-- -->`
**Multiline equations**
### Multiline equations
You can add multiline equations using:

View File

@ -1,58 +1,65 @@
# Using Weave
You can write your documentation and code in input document using Markdown, Noweb or script
syntax and use `weave` function to execute to document to capture results and figures.
syntax and use [`weave`](@ref) function to execute to document to capture results and figures.
## Weave
## `weave`
Weave document with markup and julia code using `Plots.jl` for plots,
`out_path = :pwd` makes the results appear in the current working directory.
> A prepared example: [`Weave.SAMPLE_JL_DOC`](../examples/FIR_design.jmd)
```julia
#First add depencies for the example
# First add depencies for the example
using Pkg; Pkg.add.(["Plots", "DSP"])
using Weave
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"), out_path=:pwd)
weave(Weave.SAMPLE_JL_DOC; out_path=:pwd)
```
```@docs
weave(source)
weave
```
## Tangle
## `tangle`
Tangling extracts the code from document:
```@docs
tangle(source)
tangle
```
## Supported output formats
## Supported Output Formats
Weave sets the output format based on the file extension, but you can also set
it using `doctype` option. The rules for detecting the format are:
Weave automatically detects the output format based on the file extension.
The auto output format detection is handled by `detect_doctype(path::AbstractString)`:
```julia
ext == ".jl" && return "md2html"
contains(ext, ".md") && return "md2html"
contains(ext, ".rst") && return "rst"
contains(ext, ".tex") && return "texminted"
contains(ext, ".txt") && return "asciidoc"
return "pandoc"
function detect_doctype(path::AbstractString)
_, ext = lowercase.(splitext(path))
match(r"^\.(jl|.?md|ipynb)", ext) !== nothing && return "md2html"
ext == ".rst" && return "rst"
ext == ".tex" && return "texminted"
ext == ".txt" && return "asciidoc"
return "pandoc"
end
```
You can also manually specify it using the `doctype` keyword option.
You can get a list of supported output formats:
```@docs
list_out_formats
```
```@example
using Weave # hide
list_out_formats()
```
```@docs
list_out_formats()
```
## Document syntax
## [Document Syntax](@id document-syntax)
Weave uses markdown, Noweb or script syntax for defining the code chunks and
documentation chunks. You can also weave Jupyter notebooks. The format is detected based on the file extension, but you can also set it manually using the `informat` parameter.
@ -66,137 +73,109 @@ ext == ".ipynb" && return "notebook"
return "noweb"
```
## Documentation chunks
In Markdown and Noweb input formats documentation chunks are the parts that aren't inside code delimiters. Documentation chunks can be written with several different markup languages.
### Documentation Chunks
## Code chunks
In markdown and Noweb input formats documentation chunks are the parts that aren't inside code delimiters. Documentation chunks can be written with several different markup languages.
### Markdown format
Markdown code chunks are defined using fenced code blocks with options following on the same line. e.g. to hide code from output you can use:
### [Code Chunks](@id code-chunks)
```
```julia; echo=false
Code chunks are written in different ways in different formats.
#### Markdown Format
Weave code chunks are defined using fenced code blocks, same as with [common markdown](https://spec.commonmark.org/0.29/#fenced-code-blocks):
```markdown
```julia
code
...
```
```
[Sample document]( https://github.com/mpastell/Weave.jl/blob/master/examples/FIR_design.jmd)
Weave code chunks can optionally be followed by [chunk options](@ref) on the same line.
E.g. the chunk below will hide code itself from generated output:
```markdown
```julia, echo = false
code
...
```
```
## Inline code
#### Noweb Format
Code chunks start with a line marked with `<<>>=` or `<<options>>=` and end with line marked with `@`.
The code between the start and end markers is executed and the output is captured to the output document.
### [Inline Code](@id inline-code)
You can also add inline code to your documents using
```
`j juliacode`
```
or
```
! juliacode
```
syntax.
syntax. Using the `j code` syntax you can insert code anywhere in a line and with
the `!` syntax the whole line after `!` will be executed. The code will be replaced
with captured output in the weaved document.
If the code produces figures the filename or base64 encoded string will be
added to output e.g. to include a Plots figure in markdown you can use:
The former syntax allows you to insert code _anywhere_ in a line
while the `!` syntax treats the whole line as code,
and the code will be replaced with captured output in the weaved document.
If the code produces figures, the filename or base64 encoded string will be added to output,
e.g. to include a Plots figure in markdown you can use:
```
![A plot](`j plot(1:10)`)
```
or to produce any html output:
or to produce any HTML output:
```
! display("text/html", "Header from julia");
```
### Script Format
### Noweb format
Weave also supports script input format with a markup in comments.
These scripts can be executed normally using Julia or published with Weave.
Code chunks start with a line marked with `<<>>=` or `<<options>>=` and end with line marked with `@`. The code between the start and end markers is executed and the output is captured to the output document. See [chunk options](../chunk_options/).
Lines starting with `#'`, `#%%` or `# %%` are treated as document.
All non-document lines are treated as code.
You can set chunk options using lines starting with `#+` just before code e.g:
```julia
#+ term=true
hoge # some code comes here
```
### Script format
Weave also support script input format with a markup in comments.
These scripts can be executed normally using Julia or published with
Weave. Documentation is in lines starting with
`#'`, `#%%` or `# %%`, and code is executed and results are included
in the weaved document.
All lines that are not documentation are treated as code. You can set chunk options
using lines starting with `#+` just before code e.g. `#+ term=true`.
The format is identical to [Pweave](http://mpastell.com/pweave/pypublish.html)
and the concept is similar to publishing documents with MATLAB or
using Knitr's [spin](http://yihui.name/knitr/demo/stitch/).
The format is identical to [Pweave](http://mpastell.com/pweave/pypublish.html) and the concept is similar to publishing documents with MATLAB or using Knitr's [spin](http://yihui.name/knitr/demo/stitch/).
Weave will remove the first empty space from each line of documentation.
[See sample document:](https://github.com/mpastell/Weave.jl/blob/master/examples/FIR_design.jl)
## Setting document options in header
You can use a YAML header in the beginning of the input document delimited with "---" to set the document title, author and date e.g. and default document options. Each of Weave command line arguments and chunk options can be set in header using `options` field. Below is an example that sets document `out_path` and `doctype` using the header.
!!! tip
- Here are sample documents:
+ [markdown format](https://github.com/JunoLab/Weave.jl/blob/master/examples/FIR_design.jmd)
+ [script format](https://github.com/JunoLab/Weave.jl/blob/master/examples/FIR_design.jl)
- [Details about chunk options](@ref chunk-options)
```yaml
---
title : Weave example
author : Matti Pastell
date: 15th December 2016
options:
out_path : reports/example.md
doctype : github
---
```
## Configuration via YAML Header
You can also set format specific options. Here is how to set different `out_path` for `md2html` and `md2pdf` and set `fig_ext` for both:
When `weave`ing markdown files, you can use YAML header to provide additional metadata and configuration options.
See [Header Configuration](@ref) section for more details.
```
---
options:
md2html:
out_path : html
md2pdf:
out_path : pdf
fig_ext : .png
---
```
## Passing arguments to documents
## Passing Runtime Arguments to Documents
You can pass arguments as dictionary to the weaved document using the `args` argument
to `weave`. The dictionary 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:
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:
## `include_weave`
```
```julia
print(WEAVE_ARGS["filename"])
```
```
You can use the `out_path` argument to control the name of the
output document.
## Include Weave document in Julia
You can call `include_weave` on a Weave document to run the contents
of all code chunks in Julia.
You can call `include_weave` on a Weave document and run all code chunks within in the current session.
```@docs
include_weave

View File

@ -7,7 +7,7 @@
#' # Introduction
#' This an example of a julia script that can be published using
#' [Weave](http://mpastell.github.io/Weave.jl/latest/usage/).
#' [Weave](http://weavejl.mpastell.com/dev/usage/).
#' The script can be executed normally using Julia
#' or published to HTML or pdf with Weave.
#' Text is written in markdown in lines starting with "`#'` " and code

View File

@ -9,7 +9,7 @@ date: 21th April 2016
This an example of a julia script that can be published using
[Weave](http://mpastell.github.io/Weave.jl/latest/usage/).
[Weave](http://weavejl.mpastell.com/dev/usage/).
The script can be executed normally using Julia
or published to HTML or pdf with Weave.
Text is written in markdown in lines starting with "`#'` " and code
@ -22,6 +22,13 @@ If you're viewing the published version have a look at the
[source](FIR_design_plots.jl) to see the markup.
<!-- this setup dependencies, but doesn't appear in the generated document -->
```julia; echo = false; results = "hidden"
using Pkg
"Plots" ∉ keys(Pkg.project().dependencies) && Pkg.add("Plots")
"DSP" ∉ keys(Pkg.project().dependencies) && Pkg.add("DSP")
```
# FIR Filter Design

View File

@ -7,7 +7,7 @@
#' # Introduction
#' This an example of a julia script that can be published using
#' [Weave](http://mpastell.github.io/Weave.jl/latest/usage/).
#' [Weave](http://weavejl.mpastell.com/dev/usage/).
#' The script can be executed normally using Julia
#' or published to HTML or pdf with Weave.
#' Text is written in markdown in lines starting with "`#'` " and code

View File

@ -7,7 +7,7 @@ date : 13th December 2016
# Intro
This a sample [Julia](http://julialang.org/) markdown document that can
be executed using [Weave.jl](https://github.com/mpastell/Weave.jl).
be executed using [Weave.jl](https://github.com/JunoLab/Weave.jl).
The code is delimited from docs using markdown fenced code blocks
markup which can be seen looking at the source document
@ -71,6 +71,6 @@ plot(y = cumsum(randn(1000, 1)), Geom.line)
Read the documentation:
- stable: [http://mpastell.github.io/Weave.jl/stable/](http://mpastell.github.io/Weave.jl/stable/)
- latest: [http://mpastell.github.io/Weave.jl/latest/](http://mpastell.github.io/Weave.jl/latest/)
- latest: [http://weavejl.mpastell.com/dev/](http://weavejl.mpastell.com/dev/)
See other examples in the [Github repo](https://github.com/mpastell/Weave.jl/tree/master/examples)
See other examples in the [GitHub repo](https://github.com/JunoLab/Weave.jl/tree/master/examples)

View File

@ -29,10 +29,10 @@
\section{Intro}
This is a minimal example on using PGF format with Gadfly plots in
\href{https://github.com/mpastell/Weave.jl}{Weave.jl} document.
\href{https://github.com/JunoLab/Weave.jl}{Weave.jl} document.
The source is in github:
\url{https://github.com/mpastell/Weave.jl/blob/master/examples/gadfly_pgf.texw}.
\url{https://github.com/JunoLab/Weave.jl/blob/master/examples/gadfly_pgf.texw}.
You can run this example with first weaving it from Julia using:

View File

@ -5,7 +5,7 @@
# Introduction
This a sample [Julia](http://julialang.org/) noweb document that can
be executed using [Weave.jl](https://github.com/mpastell/Weave.jl).
be executed using [Weave.jl](https://github.com/JunoLab/Weave.jl).
The code is delimited from docs using `<<>>=` and `@` markup which can be seen
looking at the source document `gadfly_sample.mdw` in the examples directory
@ -65,6 +65,6 @@ plot(y = cumsum(randn(1000, 1)), Geom.line)
Read the documentation:
- stable: <http://mpastell.github.io/Weave.jl/stable/>
- latest: <http://mpastell.github.io/Weave.jl/latest/>
- latest: <http://weavejl.mpastell.com/dev/>
See other examples in: <https://github.com/mpastell/Weave.jl/tree/master/examples>
See other examples in: <https://github.com/JunoLab/Weave.jl/tree/master/examples>

View File

@ -3,7 +3,7 @@
This a sample [Julia](http://julialang.org/) noweb document that can
be executed using Weave. Output from code chunks and PyPlot
plots will be included in the weaved document. You also need to install Pweave from Github in order to use Weave.
plots will be included in the weaved document. You also need to install Pweave from GitHub in order to use Weave.
This documented can be turned into Pandoc markdown with captured
result from Julia prompt.

View File

@ -1,7 +1,7 @@
---
title : A minimal beamer example using Weave markdown
author : Matti Pastell
options :
title: A minimal beamer example using Weave markdown
author: Matti Pastell
weave_options:
doctype : md2pdf
out_path : pdf
template : beamer.tpl

View File

@ -1,254 +1,337 @@
module Weave
import Highlights
using Requires
using Highlights, Mustache, Requires, Pkg, REPL
# directories
const PKG_DIR = normpath(@__DIR__, "..")
const TEMPLATE_DIR = normpath(PKG_DIR, "templates")
const STYLESHEET_DIR = normpath(PKG_DIR, "stylesheets")
# keeps paths of sample documents for easy try
const EXAMPLE_FOLDER = normpath(PKG_DIR, "examples")
# constant names
const WEAVE_OPTION_NAME = "weave_options"
const WEAVE_OPTION_NAME_DEPRECATED = "options" # remove this when tagging v0.11
const WEAVE_OPTION_DEPRECATE_ID = "weave_option_duplicate_id"
const DEFAULT_FIG_PATH = "figures"
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" Base.include(Main, joinpath(@__DIR__, "plots.jl"))
@require Gadfly="c91e804a-d5a3-530f-b6f0-dfbca275c004" Base.include(Main, joinpath(@__DIR__, "gadfly.jl"))
@require Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" include("plots.jl")
@require Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004" include("gadfly.jl")
end
"""
`list_out_formats()`
List supported output formats
"""
function list_out_formats()
for format = keys(formats)
println(string(format,": ", formats[format].description))
end
end
# utilitity functions
take2string!(io) = String(take!(io))
joinlines(lines) = join(lines, '\n')
include("types.jl")
include("config.jl")
include("WeaveMarkdown/markdown.jl")
include("display_methods.jl")
include("reader/reader.jl")
include("run.jl")
include("cache.jl")
include("rendering/rendering.jl")
include("writer/writer.jl")
include("converter.jl")
get_format(doctype::AbstractString) = FORMATS[doctype]
"""
`tangle(source ; out_path=:doc, informat="noweb")`
list_out_formats()
List supported output formats with its description.
"""
list_out_formats() = [k => v.description for (k,v) in FORMATS]
"""
tangle(source::AbstractString; kwargs...)
Tangle source code from input document to .jl file.
* `informat`: `"noweb"` of `"markdown"`
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document, `:pwd`: Julia working directory, `"somepath"`, directory name as a string e.g `"/home/mpastell/weaveout"`
or filename as string e.g. ~/outpath/outfile.jl.
## Keyword options
- `informat::Union{Nothing,AbstractString} = nothing`: Input document format. By default (i.e. given `nothing`), Weave 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:
* `: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"`
"""
function tangle(source ; out_path=:doc, informat=:auto)
doc = read_doc(source, informat)
function tangle(
source::AbstractString;
out_path::Union{Symbol,AbstractString} = :doc,
informat::Union{Nothing,AbstractString} = nothing,
)
doc = WeaveDoc(source, informat)
doc.cwd = get_cwd(doc, out_path)
outname = get_outname(out_path, doc, ext = "jl")
out_path = get_out_path(doc, out_path, "jl")
open(outname, "w") do io
for chunk in doc.chunks
if typeof(chunk) == CodeChunk
options = merge(doc.chunk_defaults, chunk.options)
if options[:tangle]
write(io, chunk.content*"\n")
end
end
open(out_path, "w") do io
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
end
end
doc.cwd == pwd() && (outname = basename(outname))
@info("Writing to file $outname")
@info "Tangled to $(out_path)"
end
"""
weave(source ; doctype = :auto,
informat=:auto, out_path=:doc, args = Dict(),
mod::Union{Module, Symbol} = Main,
fig_path = "figures", fig_ext = nothing,
cache_path = "cache", cache=:off,
template = nothing, highlight_theme = nothing, css = nothing,
pandoc_options = "",
latex_cmd = "xelatex")
weave(source::AbstractString; kwargs...)
Weave an input document to output file.
* `doctype`: :auto = set based on file extension or specify one of the supported formats.
See `list_out_formats()`
* `informat`: :auto = set based on file extension or set to `"noweb"`, `"markdown"` or `script`
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document, `:pwd`:
Julia working directory, `"somepath"`: output directory as a String e.g `"/home/mpastell/weaveout"` or filename as
string e.g. ~/outpath/outfile.tex.
* `args`: dictionary of arguments to pass to document. Available as WEAVE_ARGS
* `mod`: Module where Weave `eval`s code. Defaults to `:sandbox`
to create new sandbox module, you can also pass a module e.g. `Main`.
* `fig_path`: where figures will be generated, relative to out_path
* `fig_ext`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`.
* `cache_path`: where of cached output will be saved.
* `cache`: controls caching of code: `:off` = no caching, `:all` = cache everything,
`:user` = cache based on chunk options, `:refresh`, run all code chunks and save new cache.
* `throw_errors`: if `false` errors are included in output document and the whole document is
executed. if `true` errors are thrown when they occur.
* `template`: Template (file path) or MustacheTokens for md2html or md2tex formats.
* `highlight_theme`: Theme (Highlights.AbstractTheme) for used syntax highlighting
* `css`: CSS (file path) used for md2html format
* `pandoc_options`: String array of options to pass to pandoc for `pandoc2html` and
`pandoc2pdf` formats e.g. ["--toc", "-N"]
* `latex_cmd`: the command used to make pdf from .tex
* `latex_keep_unicode`: if set to true (default is false), 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.
## Keyword options
**Note:** Run Weave from terminal and not using IJulia, Juno or ESS, they tend to mess with capturing output.
- `doctype::Union{Nothing,AbstractString} = nothing`: Output document format. By default (i.e. given `nothing`), Weave 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{Nothing,AbstractString} = nothing`: Input document format. By default (i.e. given `nothing`), Weave 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:
* `: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::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`
- `cache_path::AbstractString = "cache"`: Where of cached output will be saved
- `cache::Symbol = :off`: Controls caching of code:
* `:off` means no caching (default)
* `:all` caches everything
* `:user` caches based on chunk options
* `:refresh` runs all code chunks and save new cache
- `template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing`: Template (file path) or `Mustache.MustacheTokens`s for `md2html` or `md2tex` formats
- `css::Union{Nothing,AbstractString} = nothing`: Path of a CSS file used for md2html format
- `highlight_theme::Union{Nothing,Type{<:Highlights.AbstractTheme}} = nothing`: Theme used for syntax highlighting (defaults to `Highlights.Themes.DefaultTheme`)
- `pandoc_options::Vector{<:AbstractString} = $(DEFAULT_PANDOC_OPTIONS)`: `String`s of options to pass to pandoc for `pandoc2html` and `pandoc2pdf` formats, e.g. `["--toc", "-N"]`
- `latex_cmd::Vector{<:AbstractString} = $(DEFAULT_LATEX_CMD)`: The command used to make PDF file from .tex
- `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
!!! note
Run Weave from terminal and try to avoid weaving from IJulia or ESS; they tend to mess with capturing output.
"""
function weave(source ; doctype = :auto,
informat=:auto, out_path=:doc, args = Dict(),
mod::Union{Module, Symbol} = :sandbox,
fig_path = "figures", fig_ext = nothing,
cache_path = "cache", cache=:off,
throw_errors = false,
template = nothing, highlight_theme = nothing, css = nothing,
pandoc_options = String[]::Array{String},
latex_cmd = "xelatex",latex_keep_unicode=false)
function weave(
source::AbstractString;
doctype::Union{Nothing,AbstractString} = nothing,
informat::Union{Nothing,AbstractString} = nothing,
out_path::Union{Symbol,AbstractString} = :doc,
args::Any = Dict(),
mod::Union{Module,Nothing} = nothing,
fig_path::Union{Nothing,AbstractString} = nothing,
fig_ext::Union{Nothing,AbstractString} = nothing,
cache_path::AbstractString = "cache",
cache::Symbol = :off,
template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing,
css::Union{Nothing,AbstractString} = nothing, # TODO: rename to `stylesheet`
highlight_theme::Union{Nothing,Type{<:Highlights.AbstractTheme}} = nothing,
pandoc_options::Vector{<:AbstractString} = DEFAULT_PANDOC_OPTIONS,
latex_cmd::Vector{<:AbstractString} = DEFAULT_LATEX_CMD,
keep_unicode::Bool = false,
)
doc = WeaveDoc(source, informat)
doc = read_doc(source, informat)
doctype == :auto && (doctype = detect_doctype(doc.source))
doc.doctype = doctype
# run document
# ------------
# 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,
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)
# overwrites options with those specified in header, that are needed for running document
# NOTE: these YAML options can NOT be given dynamically
weave_options = get(doc.header, WEAVE_OPTION_NAME, nothing)
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
weave_options = get(doc.header, WEAVE_OPTION_NAME_DEPRECATED, nothing)
end
template != nothing && (doc.template = template)
highlight_theme != nothing && (doc.highlight_theme = highlight_theme)
#theme != nothing && (doc.theme = theme) #Reserved for themes
css != nothing && (doc.css = css)
if !isnothing(weave_options)
doctype = get(weave_options, "doctype", doctype)
specific_options!(weave_options, doctype)
if haskey(weave_options, "out_path")
out_path = let
out_path = weave_options["out_path"]
if out_path == ":doc" || out_path == ":pwd"
Symbol(out_path)
else
normpath(dirname(source), out_path) # resolve relative to this document
end
end
end
mod = get(weave_options, "mod", mod)
mod isa AbstractString && (mod = Main.eval(Meta.parse(mod)))
fig_path = get(weave_options, "fig_path", fig_path)
fig_ext = get(weave_options, "fig_ext", fig_ext)
cache_path = get(weave_options, "cache_path", cache_path)
cache = Symbol(get(weave_options, "cache", cache))
end
try
doc = run(doc, doctype = doctype,
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)
formatted = format(doc)
doc = run_doc(
doc;
doctype = doctype,
mod = mod,
out_path = out_path,
args = args,
fig_path = fig_path,
fig_ext = fig_ext,
cache_path = cache_path,
cache = cache,
)
outname = get_outname(out_path, doc)
# overwrites options with those specified in header, that are needed for rendering/writing document
# NOTE: these YAML options can be given dynamically
if !isnothing(weave_options)
if haskey(weave_options, "template")
template = weave_options["template"]
# resolve relative to this document
template isa AbstractString && (template = normpath(dirname(source), template))
end
if haskey(weave_options, "css")
css = weave_options["css"]
# resolve relative to this document
css isa AbstractString && (css = normpath(dirname(source), css))
end
highlight_theme = get(weave_options, "highlight_theme", highlight_theme)
keep_unicode = get(weave_options, "keep_unicode", keep_unicode)
latex_cmd = get(weave_options, "latex_cmd", latex_cmd)
pandoc_options = get(weave_options, "pandoc_options", pandoc_options)
end
open(outname, "w") do io
write(io, formatted)
end
set_format_options!(
doc;
# general
template = template,
highlight_theme = highlight_theme,
css = css,
# pandoc
pandoc_options = pandoc_options,
# latex
keep_unicode = keep_unicode,
latex_cmd = latex_cmd,
)
#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 && rm(doc.fig_path, force = true, recursive = true)
success || return
outname = get_outname(out_path, doc, ext = "pdf")
end
# render document
# ---------------
rendered = render_doc(doc)
doc.cwd == pwd() && (outname = basename(outname))
@info("Report weaved to $outname")
return abspath(outname)
#catch err
# @warn("Something went wrong during weaving")
# @error(sprint(showerror, err))
# return nothing
finally
doctype == :auto && (doctype = detect_doctype(doc.source))
if occursin("2pdf", doctype)
rm(doc.fig_path, force = true, recursive = true)
elseif occursin("2html", doctype)
rm(doc.fig_path, force = true, recursive = true)
# write documents
# ---------------
out_path = write_doc(doc, rendered, get_out_path(doc, out_path))
@info "Weaved to $(out_path)"
return out_path
end
weave(doc::AbstractString, doctype::Union{Symbol,AbstractString}; kwargs...) =
weave(doc; doctype = doctype, kwargs...)
function specific_options!(weave_options, doctype)
fmts = keys(FORMATS)
for (k,v) in weave_options
if k in fmts
k == doctype && merge!(weave_options, v)
delete!(weave_options, k)
end
end
end
function weave(doc::AbstractString, doctype::AbstractString)
weave(doc, doctype=doctype)
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) = abspath(get_cwd(doc, out_path), string(doc.basename , '.', ext))
"""
notebook(source::AbstractString; kwargs...)
Convert Weave document `source` to Jupyter Notebook and execute the code
using [`nbconvert`](https://nbconvert.readthedocs.io/en/latest/).
**Ignores** all chunk options.
## Keyword options
- `out_path::Union{Symbol,AbstractString} = :pwd`: Path where the output is generated can be either of:
* `: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)
- `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
!!! 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/JunoLab/Weave.jl/issues/116).
!!! note
In order to _just_ convert Weave document to Jupyter Notebook,
use [`convert_doc`](@ref) instead.
"""
function notebook(
source::AbstractString;
out_path::Union{Symbol,AbstractString} = :pwd,
timeout = -1,
nbconvert_options::AbstractString = "",
jupyter_path::AbstractString = "jupyter",
)
doc = WeaveDoc(source)
converted = convert_to_notebook(doc)
doc.cwd = get_cwd(doc, out_path)
out_path = get_out_path(doc, out_path, "ipynb")
write(out_path, converted)
@info "Running nbconvert ..."
return read(
`$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $(out_path) $nbconvert_options --output $(out_path)`,
String,
)
end
"""
notebook(source::String; out_path=:pwd, timeout=-1, nbconvert_options="", jupyter_path = "jupyter")
include_weave(source::AbstractString, informat::Union{Nothing,AbstractString} = nothing)
include_weave(m::Module, source::AbstractString, informat::Union{Nothing,AbstractString} = nothing)
Convert Weave document `source` to Jupyter notebook and execute the code
using nbconvert. **Ignores** all chunk options
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document,
`:pwd`: Julia working directory, `"somepath"`: Path as a
String e.g `"/home/mpastell/weaveout"`
* `timeout`: nbconvert cell timeout in seconds. Defaults to -1 (no timeout)
* `nbconvert_options`: string of additional options to pass to nbconvert, such as `--allow-errors`
* `jupyter_path`: Path/command for the Jupyter you want to use. Defaults to "jupyter," which runs whatever is linked/alias to that.
Include code from Weave document calling `include_string` on all code from doc.
Code is run in the path of the include document.
"""
function notebook(source::String; out_path=:pwd, timeout=-1, nbconvert_options=[], jupyter_path = "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")
open(outfile, "w") do f
write(f, converted)
end
@info("Running nbconvert")
out = read(`$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $outfile $nbconvert_options --output $outfile`, String)
end
"""
include_weave(doc, informat=:auto)
include_weave(m::Module, doc, informat=:auto)
Include code from Weave document calling `include_string` on
all code from doc. Code is run in the path of the include document.
"""
function include_weave(m::Module, source, informat=:auto)
function include_weave(
m::Module,
source::AbstractString,
informat::Union{Nothing,AbstractString} = nothing,
)
old_path = pwd()
doc = read_doc(source, informat)
cd(doc.path)
doc = WeaveDoc(source, informat)
cd(dirname(doc.path))
try
code = join([x.content for x in
filter(x -> isa(x,Weave.CodeChunk), doc.chunks)], "\n")
code = join(
[x.content for x in filter(x -> isa(x, Weave.CodeChunk), doc.chunks)],
"\n",
)
include_string(m, code)
catch e
throw(e)
catch err
throw(err)
finally
cd(old_path)
end
return nothing
end
include_weave(source, informat=:auto) = include_weave(Main, source, informat)
#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)
pop_preexecute_hook(f::Function) = splice!(preexecute_hooks, findfirst(x -> x == f, preexecute_hooks))
const postexecute_hooks = Function[]
push_postexecute_hook(f::Function) = push!(postexecute_hooks, f)
pop_postexecute_hook(f::Function) = splice!(postexecute_hooks, findfirst(x -> x == f, postexecute_hooks))
include("chunks.jl")
include("config.jl")
include("WeaveMarkdown/markdown.jl")
include("display_methods.jl")
include("readers.jl")
include("run.jl")
include("cache.jl")
include("formatters.jl")
include("format.jl")
include("pandoc.jl")
include("writers.jl")
include_weave(source, informat = nothing) = include_weave(Main, source, informat)
export weave, list_out_formats, tangle, convert_doc, notebook,
set_chunk_defaults, get_chunk_defaults, restore_chunk_defaults,
include_weave
export weave,
list_out_formats,
tangle,
convert_doc,
notebook,
set_chunk_defaults!,
get_chunk_defaults,
restore_chunk_defaults!,
include_weave
end

View File

@ -1,16 +1,28 @@
#module Markdown2HTML
# Markdown to HTML writer, Modified from Julia Base.Markdown html writer
using Markdown: MD, Header, Code, Paragraph, BlockQuote, Footnote, Table,
Admonition, List, HorizontalRule, Bold, Italic, Image, Link, LineBreak,
LaTeX, isordered
function tohtml(io::IO, m::MIME"text/html", x)
show(io, m, x)
end
using Markdown:
MD,
Header,
Code,
Paragraph,
BlockQuote,
Footnote,
Table,
Admonition,
List,
HorizontalRule,
Bold,
Italic,
Image,
Link,
LineBreak,
LaTeX,
isordered
function tohtml(io::IO, m::MIME"text/plain", x)
htmlesc(io, sprint(show, m, x))
end
tohtml(io::IO, m::MIME"text/html", x) = show(io, m, x)
tohtml(io::IO, m::MIME"text/plain", x) = htmlesc(io, sprint(show, m, x))
function tohtml(io::IO, m::MIME"image/png", img)
print(io, """<img src="data:image/png;base64,""")
@ -18,11 +30,7 @@ function tohtml(io::IO, m::MIME"image/png", img)
print(io, "\" />")
end
function tohtml(m::MIME"image/svg+xml", img)
show(io, m, img)
end
tohtml(m::MIME"image/svg+xml", img) = show(io, m, img)
# AbstractDisplay infrastructure
@ -35,7 +43,6 @@ end
tohtml(io::IO, x) = tohtml(io, bestmime(x), x)
# Utils
function withtag(f, io::IO, tag, attrs...)
@ -56,10 +63,13 @@ end
tag(io::IO, tag, attrs...) = withtag(nothing, io, tag, attrs...)
const _htmlescape_chars = Dict('<'=>"&lt;", '>'=>"&gt;",
'"'=>"&quot;", '&'=>"&amp;",
# ' '=>"&nbsp;",
)
const _htmlescape_chars = Dict(
'<' => "&lt;",
'>' => "&gt;",
'"' => "&quot;",
'&' => "&amp;",
# ' '=>"&nbsp;",
)
for ch in "'`!\$%()=+{}[]"
_htmlescape_chars[ch] = "&#$(Int(ch));"
end
@ -93,7 +103,7 @@ end
html(io::IO, md::MD) = html(io, md.content)
function html(io::IO, header::Header{l}) where l
function html(io::IO, header::Header{l}) where {l}
withtag(io, "h$l") do
htmlinline(io, header.text)
end
@ -141,7 +151,7 @@ function html(io::IO, md::Admonition)
end
function html(io::IO, md::List)
maybe_attr = md.ordered > 1 ? Any[:start => string(md.ordered)] : []
maybe_attr = md.ordered > 1 ? Any[:start=>string(md.ordered)] : []
withtag(io, isordered(md) ? :ol : :ul, maybe_attr...) do
for item in md.items
println(io)
@ -153,9 +163,7 @@ function html(io::IO, md::List)
end
end
function html(io::IO, md::HorizontalRule)
tag(io, :hr)
end
html(io::IO, md::HorizontalRule) = tag(io, :hr)
function html(io::IO, tex::LaTeX)
withtag(io, :p, :class => "math") do
@ -163,9 +171,7 @@ function html(io::IO, tex::LaTeX)
end
end
function html(io::IO, comment::Comment)
write(io, "\n<!-- $(comment.text) -->\n")
end
html(io::IO, comment::Comment) = write(io, "\n<!-- $(comment.text) -->\n")
function html(io::IO, md::Table)
withtag(io, :table) do
@ -203,9 +209,7 @@ function htmlinline(io::IO, tex::LaTeX)
end
end
function htmlinline(io::IO, md::Union{Symbol,AbstractString})
htmlesc(io, md)
end
htmlinline(io::IO, md::Union{Symbol,AbstractString}) = htmlesc(io, md)
function htmlinline(io::IO, md::Bold)
withtag(io, :strong) do
@ -219,10 +223,7 @@ function htmlinline(io::IO, md::Italic)
end
end
function htmlinline(io::IO, md::Image)
tag(io, :img, :src=>md.url, :alt=>md.alt)
end
htmlinline(io::IO, md::Image) = tag(io, :img, :src => md.url, :alt => md.alt)
function htmlinline(io::IO, f::Footnote)
withtag(io, :a, :href => "#footnote-$(f.id)", :class => "footnote") do
@ -231,23 +232,17 @@ function htmlinline(io::IO, f::Footnote)
end
function htmlinline(io::IO, link::Link)
withtag(io, :a, :href=>link.url) do
withtag(io, :a, :href => link.url) do
htmlinline(io, link.text)
end
end
function htmlinline(io::IO, br::LineBreak)
tag(io, :br)
end
htmlinline(io::IO, br::LineBreak) = tag(io, :br)
function htmlinline(io::IO, comment::Comment)
write(io, "<!-- $(comment.text) -->")
end
htmlinline(io::IO, comment::Comment) = write(io, "<!-- $(comment.text) -->")
htmlinline(io::IO, x) = tohtml(io, x)
# API
html(md) = sprint(html, md)
#end

View File

@ -1,12 +1,9 @@
import Markdown: latex, latexinline
# Remove comments that can occur inside a line
function latexinline(io, comment::WeaveMarkdown.Comment)
write(io, "")
end
function latex(io::IO, comment::WeaveMarkdown.Comment)
function latex(io::IO, comment::Comment)
for line in split(comment.text, r"\r\n|\n")
write(io, "% $line\n")
end
end
latexinline(io, comment::Comment) = write(io, "")

View File

@ -1,29 +1,26 @@
# This module extends the julia markdown parser to improve compatibility with Jupyter, Pandoc etc.
module WeaveMarkdown
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
text::String
end
@breaking true ->
function dollarmath(stream::IO, block::MD)
@breaking true -> function dollarmath(stream::IO, block::MD)
withstream(stream) do
str = Markdown.startswith(stream, r"^\$\$$"m)
isempty(str) && return false
@ -35,29 +32,28 @@ function dollarmath(stream::IO, block::MD)
if !isempty(estr)
estr = Markdown.startswith(stream, r"^\$\$$"m)
if isempty(estr)
push!(block, LaTeX(String(take!(buffer)) |> chomp))
push!(block, LaTeX(take2string!(buffer) |> chomp))
end
return true
else
seek(stream, line_start)
end
write(buffer, readline(stream, keep=true))
write(buffer, readline(stream, keep = true))
end
return false
end
end
@breaking true ->
function topcomment(stream::IO, block::MD)
@breaking true -> function topcomment(stream::IO, block::MD)
buffer = IOBuffer()
withstream(stream) do
str = Markdown.startswith(stream, r"^<!--")
isempty(str) && return false
while !eof(stream)
line = readline(stream, keep=true)
line = readline(stream, keep = true)
write(buffer, line)
if occursin(r"-->$", line)
s = replace(String(take!(buffer)) |> chomp, r"-->$" => "")
s = replace(take2string!(buffer) |> chomp, r"-->$" => "")
push!(block, Comment(s))
return true
end
@ -66,12 +62,11 @@ function topcomment(stream::IO, block::MD)
end
end
@trigger '<' ->
function comment(stream::IO, md::MD)
@trigger '<' -> function comment(stream::IO, md::MD)
withstream(stream) do
Markdown.startswith(stream, "<!--") || return
text = Markdown.readuntil(stream, "-->")
text nothing && return
isnothing(text) && return
return Comment(text)
end
end
@ -88,6 +83,8 @@ for key in keys(Markdown.julia.inner)
end
end
include("html.jl")
include("latex.jl")
end
end # module

View File

@ -1,9 +1,9 @@
#Serialization is imported only if cache is used
# Serialization is imported only if cache is used
function write_cache(doc::WeaveDoc, cache_path)
cache_dir = joinpath(doc.cwd, cache_path)
isdir(cache_dir) || mkpath(cache_dir)
open(joinpath(cache_dir, doc.basename * ".cache"),"w") do io
isdir(cache_dir) || mkpath(cache_dir)
open(joinpath(cache_dir, doc.basename * ".cache"), "w") do io
Serialization.serialize(io, doc)
end
return nothing
@ -11,47 +11,47 @@ end
function read_cache(doc::WeaveDoc, cache_path)
name = joinpath(doc.cwd, cache_path, doc.basename * ".cache")
isfile(name) || return nothing
open(name,"r") do io
isfile(name) || return nothing
open(name, "r") do io
doc = Serialization.deserialize(io)
end
return doc
end
function restore_chunk(chunk::CodeChunk, cached)
chunks = filter(x -> x.number == chunk.number &&
string(typeof(x)) == "Weave.CodeChunk", cached.chunks)
chunks = filter(
x -> x.number == chunk.number && string(typeof(x)) == "Weave.CodeChunk",
cached.chunks,
)
#Chunk types, don't match after loading. Fix by constructing chunks
#from loaded content
new_chunks = Any[]
# Chunk types, don't match after loading. Fix by constructing chunks
# from loaded content
new_chunks = []
for c in chunks
newc = CodeChunk(c.content, c.number, c.start_line, c.optionstring, c.options)
newc.result_no = c.result_no
newc.figures = c.figures
newc.result = c.result
newc.output = c.output
newc.rich_output = c.rich_output
push!(new_chunks, newc)
newc = CodeChunk(c.content, c.number, c.start_line, c.optionstring, c.options)
newc.figures = c.figures
newc.result = c.result
newc.output = c.output
newc.rich_output = c.rich_output
push!(new_chunks, newc)
end
return new_chunks
end
#Restore inline code
# Restore inline code
function restore_chunk(chunk::DocChunk, cached::WeaveDoc)
#Get chunk from cached doc
c_chunk = filter(x -> x.number == chunk.number &&
isa(x, DocChunk), cached.chunks)
# Get chunk from cached doc
c_chunk = filter(x -> x.number == chunk.number && isa(x, DocChunk), cached.chunks)
isempty(c_chunk) && return chunk
c_chunk = c_chunk[1]
#Collect cached code
# Collect cached code
c_inline = filter(x -> isa(x, InlineCode), c_chunk.content)
isempty(c_inline) && return chunk
#Restore cached results for Inline code
# Restore cached results for Inline code
n = length(chunk.content)
for i in 1:n
for i = 1:n
if isa(chunk.content[i], InlineCode)
ci = filter(x -> x.number == chunk.content[i].number, c_inline)
isempty(ci) && continue

View File

@ -1,86 +0,0 @@
import Mustache
abstract type WeaveChunk end
abstract type Inline end
mutable struct WeaveDoc
source::AbstractString
basename::AbstractString
path::AbstractString
chunks::Array{WeaveChunk}
cwd::AbstractString
format
doctype::AbstractString
header_script::String
header::Dict
template::Union{AbstractString, Mustache.MustacheTokens}
css::AbstractString
highlight_theme
fig_path::AbstractString
chunk_defaults::Dict{Symbol,Any}
function WeaveDoc(source, chunks, header)
path, fname = splitdir(abspath(source))
basename = splitext(fname)[1]
new(source, basename, path, chunks, "", nothing, "", "", header,
"", "", Highlights.Themes.DefaultTheme, "", deepcopy(rcParams[:chunk_defaults]))
end
end
struct ChunkOutput
code::AbstractString
stdout::AbstractString
displayed::AbstractString
rich_output::AbstractString
figures::Array{AbstractString}
end
mutable struct CodeChunk <: WeaveChunk
content::AbstractString
number::Int
result_no::Int
start_line::Int
optionstring::AbstractString
options::Dict{Symbol, Any}
output::AbstractString
rich_output::AbstractString
figures::Array{AbstractString}
result::Array{ChunkOutput}
function CodeChunk(content, number, start_line, optionstring, options)
new(rstrip(content) * "\n", number, 0, start_line, optionstring, options, "","", AbstractString[], ChunkOutput[])
end
end
mutable struct DocChunk <: WeaveChunk
content::Array{Inline}
number::Int
start_line::Int
function DocChunk(text::AbstractString, number::Int, start_line::Int, inline_regex = nothing)
chunks = parse_inline(text, inline_regex)
new(chunks, number, start_line)
end
end
mutable struct InlineText <: Inline
content::AbstractString
si::Int
ei::Int
number::Int
end
mutable struct InlineCode <: Inline
content::AbstractString
si::Int
ei::Int
number::Int
ctype::Symbol
output::AbstractString
rich_output::AbstractString
figures::Array{AbstractString}
function InlineCode(content, si, ei, number, ctype)
new(content, si, ei, number, ctype, "", "", AbstractString[])
end
end
struct TermResult end
struct ScriptResult end
struct CollectResult end

View File

@ -1,143 +1,59 @@
import Mustache
#Default options
const defaultParams =
Dict{Symbol,Any}(:storeresults => false,
:doc_number => 0,
:chunk_defaults =>
Dict{Symbol,Any}(
:echo=> true,
:results=> "markup",
:hold => false,
:fig=> true,
:include=> true,
:eval => true,
:tangle => true,
:cache => false,
:fig_cap=> nothing,
#Size in inches
:fig_width => 6,
:fig_height => 4,
:fig_path=> "figures",
:dpi => 96,
:term=> false,
:display => false,
:prompt => "\njulia> ",
:label=> nothing,
:wrap=> true,
:line_width => 75,
:engine=> "julia",
#:option_AbstractString=> "",
#Defined in formats
:fig_ext => nothing,
:fig_pos=> nothing,
:fig_env=> nothing,
:out_width=> nothing,
:out_height=> nothing,
:skip=>false,
:print=>false
)
)
#This one can be changed at runtime, initially a copy of defaults
const rcParams = deepcopy(defaultParams)
# TODO: follow RMarkdown convention more
const _DEFAULT_PARAMS = Dict{Symbol,Any}(
:echo => true,
:results => "markup",
:hold => false,
:fig => true,
:eval => true,
:error => true,
:tangle => true,
:cache => false,
:fig_cap => nothing,
# NOTE: size in inches
:fig_width => 6,
:fig_height => 4,
:fig_path => DEFAULT_FIG_PATH,
:dpi => 96,
:term => false,
:prompt => "julia>",
:label => nothing,
:wrap => true,
:line_width => 75,
:fig_ext => nothing,
:fig_pos => nothing,
:fig_env => nothing,
:out_width => nothing,
:out_height => nothing,
:print => false,
)
const DEFAULT_PARAMS = deepcopy(_DEFAULT_PARAMS) # might be changed at runtime
"""
set_chunk_defaults(opts::Dict{Symbol, Any})
set_chunk_defaults!(k, v)
set_chunk_defaults!(kv::Pair...)
set_chunk_defaults!(opts::AbstractDict)
Set default options for code chunks, use [`get_chunk_defaults`](@ref) to see the current values.
E.g.: set default `dpi` to 200 and `fig_width` to 8
```julia
julia> set_chunk_defaults(Dict{Symbol, Any}(:dpi => 200, fig_width => 8))
```
E.g.: all the three examples below will set default `dpi` to `200` and `fig_width` to `8`:
- `set_chunk_defaults!(:dpi, 200); set_chunk_defaults!(:fig_width, 8)`
- `set_chunk_defaults!(:dpi => 200, :fig_width => 8)`
- `set_chunk_defaults!(Dict(:dpi => 200, :fig_width => 8))`
"""
function set_chunk_defaults(opts::Dict{Symbol, Any})
merge!(rcParams[:chunk_defaults], opts)
return nothing
end
set_chunk_defaults!(k, v) = DEFAULT_PARAMS[k]= v
set_chunk_defaults!(kv::Pair...) = for (k,v) in kv; set_chunk_defaults!(k, v); end
set_chunk_defaults!(opts::AbstractDict) = merge!(DEFAULT_PARAMS, opts)
"""
`get_chunk_defaults()`
get_chunk_defaults()
Get default options used for code chunks.
"""
function get_chunk_defaults()
return(rcParams[:chunk_defaults])
end
get_chunk_defaults() = DEFAULT_PARAMS
"""
`restore_chunk_defaults()`
restore_chunk_defaults!()
Restore Weave.jl default chunk options
Restore Weave.jl default chunk options.
"""
function restore_chunk_defaults()
rcParams[:chunk_defaults] = defaultParams[:chunk_defaults]
return nothing
end
"""Combine format specific and common options from document header"""
function combine_args(args, doctype)
common = Dict()
specific = Dict()
for key in keys(args)
if key keys(Weave.formats)
specific[key] = args[key]
else
common[key] = args[key]
end
end
haskey(specific, doctype) && merge!(common, specific[doctype])
common
end
getvalue(d::Dict, key , default) = haskey(d, key) ? d[key] : default
"""
header_args(doc::WeaveDoc)`
Get weave arguments from document header
"""
function header_args(doc::WeaveDoc, out_path, mod, fig_ext, fig_path,
cache_path, cache, throw_errors,template,
highlight_theme, css,
pandoc_options, latex_cmd)
args = getvalue(doc.header, "options", Dict())
doctype = getvalue(args, "doctype", doc.doctype)
args = combine_args(args, doctype)
informat = getvalue(args, "informat", :auto)
out_path = getvalue(args, "out_path", out_path)
out_path == ":pwd" && (out_path = :pwd)
isa(out_path, Symbol) || (out_path = joinpath(dirname(doc.source), out_path))
mod = Symbol(getvalue(args, "mod", mod))
fig_path = getvalue(args, "fig_path", fig_path)
fig_ext = getvalue(args, "fig_ext", fig_ext)
cache_path = getvalue(args, "cache_path", cache_path)
cache = Symbol(getvalue(args, "cache", cache))
throw_errors = getvalue(args, "throw_errors", throw_errors)
template = getvalue(args, "template", template)
if template != nothing && !isa(template, Mustache.MustacheTokens) && !isempty(template)
template = joinpath(dirname(doc.source), template)
end
highlight_theme = getvalue(args, "highlight_theme", highlight_theme)
css = getvalue(args, "css", css)
pandoc_options = getvalue(args, "pandoc_options", pandoc_options)
latex_cmd = getvalue(args, "latex_cmd", latex_cmd)
return (doctype, informat, out_path, args, mod, fig_path, fig_ext,
cache_path, cache, throw_errors, template, highlight_theme, css,
pandoc_options, latex_cmd)
end
"""
`header_chunk_defaults!(doc::WeaveDoc)`
Get chunk defaults from header and update
"""
function header_chunk_defaults!(doc::WeaveDoc)
for key in keys(doc.chunk_defaults)
if haskey(doc.header["options"], String(key))
doc.chunk_defaults[key] = doc.header["options"][String(key)]
end
end
end
restore_chunk_defaults!() = for (k,v) in _DEFAULT_PARAMS; DEFAULT_PARAMS[k] = v; end

144
src/converter.jl Normal file
View File

@ -0,0 +1,144 @@
using JSON, Mustache
"""
convert_doc(infile::AbstractString, outfile::AbstractString; outformat::Union{Nothing,AbstractString} = nothing)
Convert Weave documents between different formats
- `infile`: Path of the input document
- `outfile`: Path of the output document
- `outformat = nothing`: Output document format (optional). By default (i.e. given `nothing`) Weave will try to automatically detect it from the `outfile`'s extension. You can also specify either of `"script"`, `"markdown"`, `"notebook"`, or `"noweb"`
"""
function convert_doc(
infile::AbstractString,
outfile::AbstractString;
outformat::Union{Nothing,AbstractString} = nothing,
)
doc = WeaveDoc(infile)
if isnothing(outformat)
ext = lowercase(splitext(outfile)[2])
outformat =
ext == ".jl" ? "script" :
ext == ".jmd" ? "markdown" :
ext == ".ipynb" ? "notebook" :
"noweb" # fallback
end
converted = _convert_doc(doc, outformat)
open(outfile, "w") do f
write(f, converted)
end
return outfile
end
function _convert_doc(doc, outformat)
outformat == "script" ? convert_to_script(doc) :
outformat == "markdown" ? convert_to_markdown(doc) :
outformat == "notebook" ? convert_to_notebook(doc) :
convert_to_noweb(doc)
end
function convert_to_script(doc)
output = ""
for chunk in doc.chunks
if typeof(chunk) == Weave.DocChunk
content = join([repr(c) for c in chunk.content], "")
output *= join(["#' " * s for s in split(content, "\n")], "\n")
else
output *= "\n#+ "
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
output *= "\n\n" * lstrip(chunk.content)
output *= "\n"
end
end
return output
end
function convert_to_markdown(doc)
output = ""
for chunk in doc.chunks
if isa(chunk, DocChunk)
output *= join([repr(c) for c in chunk.content], "")
else
output *= "\n" * "```julia"
isempty(chunk.optionstring) || (output *= ";" * chunk.optionstring)
output *= "\n" * lstrip(chunk.content)
output *= "```\n"
end
end
return output
end
function convert_to_notebook(doc)
nb = Dict()
nb["nbformat"] = 4
nb["nbformat_minor"] = 2
metadata = Dict()
kernelspec = Dict()
kernelspec["language"] = "julia"
kernelspec["name"] = "julia-$(VERSION.major).$(VERSION.minor)"
kernelspec["display_name"] = "Julia $(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
metadata["kernelspec"] = kernelspec
language_info = Dict()
language_info["file_extension"] = ".jl"
language_info["mimetype"] = "application/julia"
language_info["name"] = "julia"
language_info["version"] = "$(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
metadata["language_info"] = language_info
cells = []
ex_count = 1
for chunk in doc.chunks
if isa(chunk, DocChunk)
push!(
cells,
Dict(
"cell_type" => "markdown",
"metadata" => Dict(),
"source" => [strip(join([repr(c) for c in chunk.content], ""))],
),
)
else
push!(
cells,
Dict(
"cell_type" => "code",
"metadata" => Dict(),
"source" => [strip(chunk.content)],
"execution_count" => nothing,
"outputs" => [],
),
)
end
end
nb["cells"] = cells
nb["metadata"] = metadata
json_nb = JSON.json(nb, 2)
return json_nb
end
function convert_to_noweb(doc)
output = ""
for chunk in doc.chunks
if isa(chunk, DocChunk)
output *= join([repr(c) for c in chunk.content], "")
else
output *= "\n" * "<<"
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
output *= ">>="
output *= "\n" * lstrip(chunk.content)
output *= "@\n"
end
end
return output
end
Base.repr(c::InlineText) = c.content
Base.repr(c::InlineCode) = "`j $(c.content)`"

View File

@ -1,51 +1,43 @@
using Markdown
import .WeaveMarkdown
using Markdown, .WeaveMarkdown
#Contains report global properties
# Contains report global properties
mutable struct Report <: AbstractDisplay
cwd::AbstractString
basename::AbstractString
formatdict::Dict{Symbol,Any}
pending_code::AbstractString
cur_result::AbstractString
rich_output::AbstractString
fignum::Int
figures::Array{AbstractString}
term_state::Symbol
cur_chunk
mimetypes::Array{AbstractString}
first_plot::Bool
header_script::String
throw_errors::Bool
cwd::String
basename::String
format::WeaveFormat
rich_output::String
fignum::Int
figures::Vector{String}
cur_chunk::Union{Nothing,CodeChunk}
mimetypes::Vector{String}
first_plot::Bool
header_script::String
end
function Report(cwd, basename, formatdict, mimetypes, throw_errors)
Report(cwd, basename, formatdict, "", "", "", 1, AbstractString[], :text, nothing,
mimetypes, true, "", throw_errors)
end
Report(cwd, basename, format, mimetypes) =
Report(cwd, basename, format, "", 1, String[], nothing, mimetypes, true, "")
#Default mimetypes in order, can be overridden for some inside `run method` formats
# Default mimetypes in order, can be overridden for some inside `run method` formats
const default_mime_types = ["image/svg+xml", "image/png", "text/html", "text/plain"]
#const default_mime_types = ["image/png", "image/svg+xml", "text/html", "text/plain"]
#From IJulia as a reminder
#const supported_mime_types = [ "text/html", "text/latex", "image/svg+xml", "image/png", "image/jpeg", "text/plain", "text/markdown" ]
# const default_mime_types = ["image/png", "image/svg+xml", "text/html", "text/plain"]
# From IJulia as a reminder
# const supported_mime_types = [ "text/html", "text/latex", "image/svg+xml", "image/png", "image/jpeg", "text/plain", "text/markdown" ]
const mimetype_ext =
Dict(".png" => "image/png",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".svg" => "image/svg+xml",
".js.svg" => "image/svg+xml",
".pdf" => "application/pdf",
".ps" => "application/postscript",
".tex" => "text/latex"
)
const mimetype_ext = Dict(
".png" => "image/png",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".svg" => "image/svg+xml",
".js.svg" => "image/svg+xml",
".pdf" => "application/pdf",
".ps" => "application/postscript",
".tex" => "text/latex",
)
function Base.display(report::Report, data)
#Set preferred mimetypes for report based on format
# Set preferred mimetypes for report based on format
fig_ext = report.cur_chunk.options[:fig_ext]
for m in unique([mimetype_ext[fig_ext] ; report.mimetypes])
for m in unique([mimetype_ext[fig_ext]; report.mimetypes])
if Base.invokelatest(showable, m, data)
try
if !istextmime(m)
@ -69,19 +61,13 @@ function Base.display(report::Report, data)
end
end
function Base.display(report::Report, m::MIME"image/png", data)
figname = add_figure(report, data, m, ".png")
end
Base.display(report::Report, m::MIME"image/png", data) = add_figure(report, data, m, ".png")
function Base.display(report::Report, m::MIME"image/svg+xml", data)
figname = add_figure(report, data, m, ".svg")
end
Base.display(report::Report, m::MIME"image/svg+xml", data) = add_figure(report, data, m, ".svg")
function Base.display(report::Report, m::MIME"application/pdf", data)
figname = add_figure(report, data, m, ".pdf")
end
Base.display(report::Report, m::MIME"application/pdf", data) = add_figure(report, data, m, ".pdf")
#Text is written to stdout, called from "term" mode chunks
# Text is written to stdout, called from "term" mode chunks
function Base.display(report::Report, m::MIME"text/plain", data)
io = PipeBuffer()
show(IOContext(io, :limit => true), m, data)
@ -100,24 +86,25 @@ function Base.display(report::Report, m::MIME"text/html", data::Exception)
end
function Base.show(io, m::MIME"text/html", data::Exception)
println(io ,"<pre class=\"julia-error\">")
println(io, "<pre class=\"julia-error\">")
println(io, Markdown.htmlesc("ERROR: " * sprint(showerror, data)))
println(io ,"</pre>")
println(io, "</pre>")
end
#Catch "rich_output"
# Catch "rich_output"
function Base.display(report::Report, m::MIME"text/html", data)
s = repr(m, data)
report.rich_output *= "\n" * s
io = IOBuffer()
show(IOContext(io, :limit => true), m, data)
report.rich_output *= string('\n', take2string!(io))
end
#Catch "rich_output"
# Catch "rich_output"
function Base.display(report::Report, m::MIME"text/markdown", data)
s = repr(m, data)
# Convert to "richer" type of possible
for m in report.mimetypes
if m == "text/html" || m == "text/latex"
display(Markdown.parse(s, flavor=WeaveMarkdown.weavemd))
display(Markdown.parse(s, flavor = WeaveMarkdown.weavemd))
break
elseif m == "text/markdown"
report.rich_output *= "\n" * s
@ -128,23 +115,23 @@ end
function Base.display(report::Report, m::MIME"text/latex", data)
s = repr(m, data)
report.rich_output *= "\n" * s
report.rich_output *= string('\n', s)
end
"""Add saved figure name to results and return the name"""
function add_figure(report::Report, data, m, ext)
chunk = report.cur_chunk
full_name, rel_name = get_figname(report, chunk, ext = ext)
chunk = report.cur_chunk
full_name, rel_name = get_figname(report, chunk, ext = ext)
open(full_name, "w") do io
if ext == ".pdf"
write(io, repr(m, data))
else
show(io, m, data)
end
end
open(full_name, "w") do io
if ext == ".pdf"
write(io, repr(m, data))
else
show(io, m, data)
end
end
push!(report.figures, rel_name)
report.fignum += 1
return full_name
push!(report.figures, rel_name)
report.fignum += 1
return full_name
end

View File

@ -1,389 +0,0 @@
import Mustache, Highlights
import .WeaveMarkdown
using Dates
using Markdown
using REPL.REPLCompletions: latex_symbols
function format(doc::WeaveDoc)
formatted = AbstractString[]
docformat = doc.format
#Complete format dictionaries with defaults
formatdict = docformat.formatdict
get!(formatdict, :termstart, formatdict[:codestart])
get!(formatdict, :termend, formatdict[:codeend])
get!(formatdict, :out_width, nothing)
get!(formatdict, :out_height, nothing)
get!(formatdict, :fig_pos, nothing)
get!(formatdict, :fig_env, nothing)
docformat.formatdict[:cwd] = doc.cwd #pass wd to figure formatters
docformat.formatdict[:theme] = doc.highlight_theme
#strip header
if isa(doc.chunks[1], DocChunk)
if !occursin("pandoc", doc.doctype)
doc.chunks[1] = strip_header(doc.chunks[1])
end
end
for chunk in copy(doc.chunks)
result = format_chunk(chunk, formatdict, docformat)
push!(formatted, result)
end
formatted = join(formatted, "\n")
# Render using a template if needed
rendered = render_doc(formatted, doc, doc.format)
return rendered
end
"""
render_doc(formatted::AbstractString, format)
Render formatted document to a template
"""
function render_doc(formatted, doc::WeaveDoc, format)
return formatted
end
function highlight(mime::MIME, source::AbstractString, lexer, theme=Highlights.Themes.DefaultTheme)
return sprint( (io, x) -> Highlights.highlight(io, mime, x, lexer, theme), source)
end
function stylesheet(m::MIME, theme)
return sprint( (io, x) -> Highlights.stylesheet(io, m, x), theme)
end
function render_doc(formatted, doc::WeaveDoc, format::JMarkdown2HTML)
css = stylesheet(MIME("text/html"), doc.highlight_theme)
path, wsource = splitdir(abspath(doc.source))
#wversion = string(Pkg.installed("Weave"))
wversion = ""
wtime = string(Date(now()))
if isempty(doc.css)
theme_css = read(joinpath(dirname(@__FILE__), "../templates/skeleton_css.css"), String)
else
theme_css = read(doc.css, String)
end
if isa(doc.template, Mustache.MustacheTokens)
template = doc.template
elseif isempty(doc.template)
template = Mustache.template_from_file(joinpath(dirname(@__FILE__), "../templates/julia_html.tpl"))
else
template = Mustache.template_from_file(doc.template)
end
return Mustache.render(template; themecss = theme_css,
highlightcss = css, body = formatted, header_script = doc.header_script,
source = wsource, wtime = wtime, wversion = wversion,
[Pair(Symbol(k), v) for (k,v) in doc.header]...)
end
function render_doc(formatted, doc::WeaveDoc, format::JMarkdown2tex)
highlight = stylesheet(MIME("text/latex"), doc.highlight_theme)
path, wsource = splitdir(abspath(doc.source))
#wversion = string(Pkg.installed("Weave"))
wversion = ""
wtime = string(Date(now()))
if isa(doc.template, Mustache.MustacheTokens)
template = doc.template
elseif isempty(doc.template)
template = Mustache.template_from_file(joinpath(dirname(@__FILE__), "../templates/julia_tex.tpl"))
else
template = Mustache.template_from_file(doc.template)
end
return Mustache.render(template; body = formatted,
highlight = highlight,
[Pair(Symbol(k), v) for (k,v) in doc.header]...)
end
function strip_header(chunk::DocChunk)
if occursin(r"^---$(?<header>.+)^---$"ms, chunk.content[1].content)
chunk.content[1].content = lstrip(replace(chunk.content[1].content, r"^---$(?<header>.+)^---$"ms => ""))
end
return chunk
end
function format_chunk(chunk::DocChunk, formatdict, docformat)
return join([format_inline(c) for c in chunk.content], "")
end
function format_inline(inline::InlineText)
return inline.content
end
function format_inline(inline::InlineCode)
isempty(inline.rich_output) || return inline.rich_output
isempty(inline.figures) || return inline.figures[end]
isempty(inline.output) || return inline.output
end
function ioformat!(io::IOBuffer, out::IOBuffer, fun=WeaveMarkdown.latex)
text = String(take!(io))
if !isempty(text)
m = Markdown.parse(text, flavor=WeaveMarkdown.weavemd)
write(out, string(fun(m)))
end
end
function addspace(op, inline)
inline.ctype == :line && (op = "\n$op\n")
return op
end
function format_chunk(chunk::DocChunk, formatdict, docformat::JMarkdown2tex)
out = IOBuffer()
io = IOBuffer()
for inline in chunk.content
if isa(inline, InlineText)
write(io, inline.content)
elseif !isempty(inline.rich_output)
ioformat!(io, out)
write(out, addspace(inline.rich_output, inline))
elseif !isempty(inline.figures)
write(io, inline.figures[end], inline)
elseif !isempty(inline.output)
write(io, addspace(inline.output, inline))
end
end
ioformat!(io, out)
formatdict[:keep_unicode] || return uc2tex(String(take!(out)))
return String(take!(out))
end
function format_chunk(chunk::DocChunk, formatdict, docformat::JMarkdown2HTML)
out = IOBuffer()
io = IOBuffer()
fun = WeaveMarkdown.html
for inline in chunk.content
if isa(inline, InlineText)
write(io, inline.content)
elseif !isempty(inline.rich_output)
ioformat!(io, out, fun)
write(out, addspace(inline.rich_output, inline))
elseif !isempty(inline.figures)
write(io, inline.figures[end])
elseif !isempty(inline.output)
write(io, addspace(inline.output, inline))
end
end
ioformat!(io, out, fun)
return String(take!(out))
end
function format_chunk(chunk::CodeChunk, formatdict, docformat)
#Fill undefined options with format specific defaults
chunk.options[:out_width] == nothing &&
(chunk.options[:out_width] = formatdict[:out_width])
chunk.options[:fig_pos] == nothing &&
(chunk.options[:fig_pos] = formatdict[:fig_pos])
#Only use floats if chunk has caption or sets fig_env
if chunk.options[:fig_cap] != nothing && chunk.options[:fig_env] == nothing
(chunk.options[:fig_env] = formatdict[:fig_env])
end
if haskey(formatdict, :indent)
chunk.content = indent(chunk.content, formatdict[:indent])
end
chunk.content = format_code(chunk.content, docformat)
if !chunk.options[:eval]
if chunk.options[:echo]
result = "$(formatdict[:codestart])\n$(chunk.content)$(formatdict[:codeend])"
return result
else
r = ""
return r
end
end
if chunk.options[:term]
result = format_termchunk(chunk, formatdict, docformat)
else
if chunk.options[:echo]
#Convert to output format and highlight (html, tex...) if needed
result = "$(formatdict[:codestart])$(chunk.content)$(formatdict[:codeend])\n"
else
result = ""
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
function format_output(result::AbstractString, docformat)
return result
end
function format_output(result::AbstractString, docformat::JMarkdown2HTML)
return Markdown.htmlesc(result)
end
function format_output(result::AbstractString, docformat::JMarkdown2tex)
# 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
function format_code(result::AbstractString, docformat)
return result
end
function format_code(result::AbstractString, docformat::JMarkdown2tex)
highlighted = highlight(MIME("text/latex"), strip(result),
Highlights.Lexers.JuliaLexer, docformat.formatdict[:theme])
docformat.formatdict[:keep_unicode] || return uc2tex(highlighted)
return highlighted
#return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
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)
ts = ""
if occursin(r"^\\bf[A-Z]$", s)
ts = replace(s, "\\bf" => "\\bm{\\mathrm{") * "}}"
elseif startswith(s, "\\bfrak")
ts = replace(s, "\\bfrak" => "\\bm{\\mathfrak{") * "}}"
elseif startswith(s, "\\bf")
ts = replace(s, "\\bf" => "\\bm{\\") * "}"
elseif startswith(s, "\\frak")
ts = replace(s, "\\frak" => "\\mathfrak{") * "}"
else
ts = s
end
return ts
end
function format_code(result::AbstractString, docformat::JMarkdown2HTML)
return highlight(MIME("text/html"), strip(result),
Highlights.Lexers.JuliaLexer, docformat.formatdict[:theme])
end
function format_code(result::AbstractString, docformat::Pandoc2HTML)
return highlight(MIME("text/html"), strip(result),
Highlights.Lexers.JuliaLexer, docformat.formatdict[:theme])
end
function format_termchunk(chunk, formatdict, docformat)
if chunk.options[:echo] && chunk.options[:results] != "hidden"
result = "$(formatdict[:termstart])$(chunk.output)\n" * "$(formatdict[:termend])\n"
else
result = ""
end
return result
end
function format_termchunk(chunk, formatdict, docformat::JMarkdown2HTML)
if chunk.options[:echo] && chunk.options[:results] != "hidden"
result = highlight(MIME("text/html"), strip(chunk.output),
Highlights.Lexers.JuliaConsoleLexer, docformat.formatdict[:theme])
else
result = ""
end
return result
end
function format_termchunk(chunk, formatdict, docformat::Pandoc2HTML)
if chunk.options[:echo] && chunk.options[:results] != "hidden"
result = highlight(MIME("text/html"), strip(chunk.output),
Highlights.Lexers.JuliaConsoleLexer, docformat.formatdict[:theme])
else
result = ""
end
return result
end
function format_termchunk(chunk, formatdict, docformat::JMarkdown2tex)
if chunk.options[:echo] && chunk.options[:results] != "hidden"
result = highlight(MIME("text/latex"), strip(chunk.output),
Highlights.Lexers.JuliaConsoleLexer,
docformat.formatdict[:theme])
#return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
else
result = ""
end
return result
end
function indent(text, nindent)
return join(map(x->
string(repeat(" ", nindent), x), split(text, "\n")), "\n")
end
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

View File

@ -1,482 +0,0 @@
using Printf
struct Tex
description::AbstractString
formatdict::Dict{Symbol,Any}
end
const tex = Tex("Latex with custom code environments",
Dict{Symbol,Any}(: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",
:doctype => "tex",
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
:keep_unicode => false,
))
const texminted = Tex("Latex using minted for highlighting",
Dict{Symbol,Any}(
: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",
:doctype => "texminted",
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
:keep_unicode => false,
))
struct Pandoc
description::AbstractString
formatdict::Dict{Symbol,Any}
end
const pandoc = Pandoc("Pandoc markdown",
Dict{Symbol,Any}(
: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"],
:doctype=>"pandoc"
))
struct Pandoc2HTML
description::AbstractString
formatdict::Dict{Symbol,Any}
end
const pdoc2html = Pandoc2HTML("Markdown to HTML (requires Pandoc 2)",
Dict{Symbol,Any}(
: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"],
:doctype=> "pandoc2html"))
struct GithubMarkdown
description::AbstractString
formatdict::Dict{Symbol,Any}
end
const github = GithubMarkdown("Github markdown",
Dict{Symbol,Any}(
: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"],
:doctype=> "github"
))
"""
Formatter for Hugo: https://gohugo.io/
When `uglyURLs` is `false`, prepend figure path by `..`.
"""
struct Hugo
description::AbstractString
formatdict::Dict{Symbol,Any}
uglyURLs::Bool
end
const hugo = Hugo("Hugo markdown (using shortcodes)",
Dict{Symbol,Any}(
:codestart => "````julia",
:codeend => "````\n\n",
:outputstart => "````",
:outputend => "````\n\n",
:fig_ext => ".png",
:extension => "md",
:doctype => "hugo"),
false)
#Julia markdown
struct JMarkdown2HTML
description::AbstractString
formatdict::Dict{Symbol,Any}
end
const md2html = JMarkdown2HTML("Julia markdown to html", Dict{Symbol,Any}(
: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",
:doctype=> "md2html"))
#Julia markdown
struct JMarkdown2tex
description::AbstractString
formatdict::Dict{Symbol,Any}
end
const md2tex = JMarkdown2tex("Julia markdown to latex", Dict{Symbol,Any}(
: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"],
:doctype=> "md2tex",
:keep_unicode=>false))
struct MultiMarkdown
description::AbstractString
formatdict::Dict{Symbol,Any}
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 = 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
const multimarkdown = MultiMarkdown("MultiMarkdown",
Dict{Symbol,Any}(
:codestart => "````julia",
:codeend=> "````\n\n",
:outputstart=> "````",
:outputend=> "````\n\n",
:fig_ext=> ".png",
:extension=> "md",
:doctype=> "github"
))
struct Rest
description::AbstractString
formatdict::Dict{Symbol,Any}
end
const rst = Rest("reStructuredText and Sphinx",
Dict{Symbol,Any}(
:codestart => ".. code-block:: julia\n",
:codeend => "\n\n",
:outputstart => "::\n",
:outputend => "\n\n",
:indent=> 4,
:fig_ext => ".png",
:extension => "rst",
:out_width => "15 cm",
:doctype => "rst"
))
struct AsciiDoc
description::AbstractString
formatdict::Dict{Symbol,Any}
end
#asciidoc -b html5 -a source-highlighter=pygments ...
const adoc = AsciiDoc("AsciiDoc",
Dict{Symbol,Any}(
:codestart => "[source,julia]\n--------------------------------------",
:codeend => "--------------------------------------\n\n",
:outputstart => "--------------------------------------",
:outputend => "--------------------------------------\n\n",
:fig_ext => ".png",
:extension => "txt",
:out_width => "600",
:doctype => "asciidoc"
))
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::Union{Tex,JMarkdown2tex})
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 = 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 = 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 = 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.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 = 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=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=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
#Add new supported formats here
const formats = Dict{AbstractString, Any}("tex" => tex,
"texminted" => texminted,
"pandoc" => pandoc,
"pandoc2html" => pdoc2html,
"pandoc2pdf" => pandoc,
"md2pdf" => md2tex,
"github" => github,
"hugo" => hugo,
"multimarkdown" => multimarkdown,
"rst" => rst,
"asciidoc" => adoc,
"md2html" => md2html,
"md2tex" => md2tex
)

View File

@ -1,12 +1,7 @@
module GadflyPlots
import Gadfly
import Weave
try
import Cairo
catch
@warn("Cairo.jl is required to be installed to generate raster images")
end
using ..Weave, ..Gadfly
Gadfly.set_default_plot_format(:svg)
@ -21,13 +16,13 @@ function Base.display(report::Weave.Report, m::MIME"image/png", p::Gadfly.Plot)
display(report, MIME("image/svg+xml"), p)
end
#Gadfly doesn't call the default display methods, this catches
#all Gadfly plots
# Gadfly doesn't call the default display methods, this catches
# all Gadfly plots
function Base.display(report::Weave.Report, m::MIME"image/svg+xml", p::Gadfly.Plot)
chunk = report.cur_chunk
w = chunk.options[:fig_width]Gadfly.inch
h = chunk.options[:fig_height]Gadfly.inch
w = chunk.options[:fig_width] * Gadfly.inch
h = chunk.options[:fig_height] * Gadfly.inch
format = chunk.options[:fig_ext]
dpi = chunk.options[:dpi]
@ -41,15 +36,16 @@ function Base.display(report::Weave.Report, m::MIME"image/svg+xml", p::Gadfly.Pl
elseif format == ".js.svg"
Gadfly.draw(Gadfly.SVGJS(full_name, w, h), p)
elseif format == ".png"
Gadfly.draw(Gadfly.PNG(full_name, w, h, dpi=dpi), p)
Gadfly.draw(Gadfly.PNG(full_name, w, h, dpi = dpi), p)
elseif format == ".pdf"
Gadfly.draw(Gadfly.PDF(full_name, w, h), p)
elseif format == ".ps"
Gadfly.draw(Gadfly.PS(full_name, w, h), p)
elseif format == ".tex"
Gadfly.draw(Gadfly.PGF(full_name, w, h, true ), p)
Gadfly.draw(Gadfly.PGF(full_name, w, h, true), p)
else
@warn("Can't save figure. Unsupported format, $format")
end
end
end

View File

@ -1,126 +0,0 @@
"""
`pandoc2html(formatted::AbstractString, doc::WeaveDoc)`
Convert output from pandoc markdown to html using Weave.jl template
"""
function pandoc2html(formatted::AbstractString, doc::WeaveDoc, outname::AbstractString, pandoc_options)
weavedir = dirname(@__FILE__)
html_template = joinpath(weavedir, "../templates/pandoc_skeleton.html")
css_template = joinpath(weavedir, "../templates/pandoc_skeleton.css")
css = stylesheet(MIME("text/html"), doc.highlight_theme)
path, wsource = splitdir(abspath(doc.source))
#wversion = string(Pkg.installed("Weave"))
wversion = ""
wtime = string(Date(now()))
#Header is inserted from displayed plots
header_script = doc.header_script
self_contained = (header_script "") ? [] : "--self-contained"
if haskey(doc.header, "bibliography")
filt = "--filter"
citeproc = "pandoc-citeproc"
else
filt = []
citeproc = []
end
#Change path for pandoc
old_wd = pwd()
cd(doc.cwd)
html =""
outname = basename(outname)
open("temp.md", "w") do io
println(io, formatted)
end
try
cmd = `pandoc -f markdown+raw_html -s --mathjax=""
$filt $citeproc $pandoc_options
--template $html_template -H $css_template $self_contained
-V wversion=$wversion -V wtime=$wtime -V wsource=$wsource
-V highlightcss=$css
-V headerscript=$header_script
-o $outname`
proc = open(cmd, "r+")
println(proc.in, formatted)
close(proc.in)
proc_output = read(proc.out, String)
cd(old_wd)
catch e
cd(old_wd)
@warn("Error converting document to HTML")
throw(e)
end
end
"""
`pandoc2pdf(formatted::AbstractString, doc::WeaveDoc)`
Convert output from pandoc markdown to pdf using Weave.jl template
"""
function pandoc2pdf(formatted::AbstractString, doc::WeaveDoc, outname::AbstractString, pandoc_options)
weavedir = dirname(@__FILE__)
header_template = joinpath(weavedir, "../templates/pandoc_header.txt")
path, wsource = splitdir(abspath(doc.source))
#wversion = string(Pkg.installed("Weave"))
wversion = ""
wtime = Date(now())
outname = basename(outname)
#Change path for pandoc
old_wd = pwd()
cd(doc.cwd)
html =""
if haskey(doc.header, "bibliography")
filt = "--filter"
citeproc = "pandoc-citeproc"
else
filt = []
citeproc = []
end
@info("Done executing code. Running xelatex")
try
cmd = `pandoc -f markdown+raw_tex -s --pdf-engine=xelatex --highlight-style=tango
$filt $citeproc $pandoc_options
--include-in-header=$header_template
-V fontsize=12pt -o $outname`
proc = open(cmd, "r+")
println(proc.in, formatted)
close(proc.in)
proc_output = read(proc.out, String)
cd(old_wd)
catch e
cd(old_wd)
@warn("Error converting document to pdf")
throw(e)
end
end
function run_latex(doc::WeaveDoc, outname, latex_cmd = "xelatex")
old_wd = pwd()
cd(doc.cwd)
xname = basename(outname)
@info("Weaved code to $outname. Running $latex_cmd")
textmp = mktempdir(".")
try
out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String)
out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String)
rm(xname)
rm(textmp, recursive=true)
cd(old_wd)
return true
catch e
@warn("Error converting document to pdf. Try running latex manually")
cd(old_wd)
rm(textmp)
return false
end
end

View File

@ -1,69 +1,81 @@
module WeavePlots
using Base64
import Plots
import Weave
using Base64, ..Plots, ..Weave
"""Pre-execute hooks to set the plot size for the chunk """
function plots_set_size(chunk)
w = chunk.options[:fig_width] * chunk.options[:dpi]
h = chunk.options[:fig_height] * chunk.options[:dpi]
Plots.default(size = (w,h))
return chunk
# Pre-execute hooks to set the plot size for the chunk
function plots_set_size!(chunk)
w = chunk.options[:fig_width] * chunk.options[:dpi]
h = chunk.options[:fig_height] * chunk.options[:dpi]
Plots.default(size = (w, h))
end
Weave.push_preexecute_hook(plots_set_size)
Weave.push_preexecution_hook!(plots_set_size!)
#PNG or SVG is not working, output html
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")
start = split(splitted[1], r"(?=<div)")
#script = lstrip(start[1]) #local
# PNG or SVG is not working, output html
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")
start = split(splitted[1], r"(?=<div)")
# script = lstrip(start[1]) # local
div = lstrip(start[2])
plot = join(map(lstrip, splitted[2:end]), "\n")
div = lstrip(start[2])
plot = join(map(lstrip, splitted[2:end]), "\n")
if report.first_plot
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
report.first_plot = false
end
if report.first_plot
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
report.first_plot = false
end
report.rich_output *= "\n" * div * "\n" * plot
end
function Base.display(report::Weave.Report, m::MIME"image/png", data::Plots.Plot{Plots.PlotlyBackend})#
display(report, MIME("image/svg+xml"), data)
function Base.display(
report::Weave.Report,
m::MIME"image/png",
data::Plots.Plot{Plots.PlotlyBackend},
)
display(report, MIME("image/svg+xml"), data)
end
# PNG or SVG is not working, output html
function Base.display(
report::Weave.Report,
m::MIME"image/svg+xml",
plot::Plots.Plot{Plots.PlotlyJSBackend},
)
body = Plots.PlotlyJS.html_body(plot.o.plot)
#PNG or SVG is not working, output html
function Base.display(report::Weave.Report, m::MIME"image/svg+xml", plot::Plots.Plot{Plots.PlotlyJSBackend})
body = Plots.PlotlyJS.html_body(plot.o.plot)
if report.first_plot
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
report.first_plot = false
end
if report.first_plot
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
report.first_plot = false
end
report.rich_output *= "\n" * body
report.rich_output *= "\n" * body
end
function Base.display(report::Weave.Report, m::MIME"image/png", plot::Plots.Plot{Plots.PlotlyJSBackend})
display(report, MIME("image/svg+xml"), data)
function Base.display(
report::Weave.Report,
m::MIME"image/png",
plot::Plots.Plot{Plots.PlotlyJSBackend},
)
display(report, MIME("image/svg+xml"), data)
end
"""Add saved figure name to results and return the name"""
function add_plots_figure(report::Weave.Report, plot::Plots.Plot, ext)
chunk = report.cur_chunk
full_name, rel_name = Weave.get_figname(report, chunk, ext = ext)
chunk = report.cur_chunk
full_name, rel_name = Weave.get_figname(report, chunk, ext = ext)
Plots.savefig(plot, full_name)
push!(report.figures, rel_name)
report.fignum += 1
return full_name
Plots.savefig(plot, full_name)
push!(report.figures, rel_name)
report.fignum += 1
return full_name
end
function Base.display(report::Weave.Report, m::MIME"application/pdf", plot::Plots.Plot)
@ -80,21 +92,21 @@ end
# write out html to view Animated gif
function Base.display(report::Weave.Report, ::MIME"text/html", agif::Plots.AnimatedGif)
ext = agif.filename[end-2:end]
res = ""
if ext == "gif"
img = stringmime(MIME("image/gif"), read(agif.filename))
res = "<img src=\"data:image/gif;base64,$img\" />"
elseif ext in ("mov", "mp4")
#Uncomment to embed mp4, make global or chunk option?
#img = stringmime(MIME("video/$ext"), read(agif.filename))
#res = "<video controls><source src=\"data:video/$(ext);base64,$img\" type=\"video/$ext\"></video>"
res = "<video controls><source src=\"$(relpath(agif.filename))\" type=\"video/$ext\"></video>"
else
error("Cannot show animation with extension $ext: $agif")
end
ext = agif.filename[end-2:end]
res = ""
if ext == "gif"
img = stringmime(MIME("image/gif"), read(agif.filename))
res = "<img src=\"data:image/gif;base64,$img\" />"
elseif ext in ("mov", "mp4")
# Uncomment to embed mp4, make global or chunk option?
# img = stringmime(MIME("video/$ext"), read(agif.filename))
# res = "<video controls><source src=\"data:video/$(ext);base64,$img\" type=\"video/$ext\"></video>"
res = "<video controls><source src=\"$(relpath(agif.filename))\" type=\"video/$ext\"></video>"
else
error("Cannot show animation with extension $ext: $agif")
end
report.rich_output *= "\n" * res * "\n"
report.rich_output *= "\n" * res * "\n"
end
end

95
src/reader/markdown.jl Normal file
View File

@ -0,0 +1,95 @@
function parse_markdown(document_body; is_pandoc = false)
header_text, document_body, offset = separate_header_text(document_body)
header = parse_header(header_text)
code_start, code_end = if is_pandoc
r"^<<(?<options>.*?)>>=\s*$",
r"^@\s*$"
else
r"^[`~]{3}(\{?)julia\s*([;,]?)\s*(?<options>.*?)(\}|\s*)$",
r"^[`~]{3}\s*$"
end
return header, parse_markdown_body(document_body, code_start, code_end, offset)
end
# headers
# -------
const HEADER_REGEX = r"^---$(?<header>((?!---).)+)^---$"ms
# TODO: non-Weave headers should keep live in a doc
# separates header section from `text`
function separate_header_text(text)
m = match(HEADER_REGEX, text)
isnothing(m) && return "", text, 0
header_text = m[:header]
offset = @static if VERSION v"1.4"
count("\n", header_text)
else
count(c->c==='\n', header_text)
end
return header_text, replace(text, HEADER_REGEX => ""; count = 1), offset
end
# HACK:
# YAML.jl can't parse text including ``` characters, so first replace all the inline code
# with these temporary code start/end string
const HEADER_INLINE_START = "<weave_header_inline_start>"
const HEADER_INLINE_END = "<weave_header_inline_end>"
function parse_header(header_text)
isempty(header_text) && return Dict()
pat = INLINE_REGEX => SubstitutionString("$(HEADER_INLINE_START)\\1$(HEADER_INLINE_END)")
header_text = replace(header_text, pat)
return YAML.load(header_text)
end
# body
# ----
function parse_markdown_body(document_body, code_start, code_end, offset)
lines = split(document_body, '\n')
state = :doc
doc_no = 0
code_no = 0
content = ""
start_line = offset
options = OptionDict()
option_string = ""
chunks = WeaveChunk[]
for (line_no, line) in enumerate(lines)
m = match(code_start, line)
if !isnothing(m) && state === :doc
state = :code
option_string = isnothing(m[:options]) ? "" : strip(m[:options])
options = parse_options(option_string)
haskey(options, :label) && (options[:name] = options[:label])
haskey(options, :name) || (options[:name] = nothing)
isempty(strip(content)) || push!(chunks, DocChunk(content, doc_no += 1, start_line))
start_line = line_no + offset
content = ""
continue
end
if occursin(code_end, line) && state === :code
push!(chunks, CodeChunk(content, code_no += 1, start_line, option_string, options))
start_line = line_no + offset
content = ""
state = :doc
continue
end
content *= isone(line_no) ? line : string('\n', line)
end
# Remember the last chunk
isempty(strip(content)) || push!(chunks, DocChunk(content, doc_no += 1, start_line))
return chunks
end

23
src/reader/notebook.jl Normal file
View File

@ -0,0 +1,23 @@
using JSON
function parse_notebook(document_body)
nb = JSON.parse(document_body)
code_no = 0
doc_no = 0
# TODO: handle some of options ?
options = Dict{Symbol,Any}()
opt_string = ""
chunks = map(nb["cells"]) do cell
text = string('\n', join(cell["source"]), '\n')
return if cell["cell_type"] == "code"
CodeChunk(text, code_no += 1, 0, opt_string, options)
else
DocChunk(text, doc_no += 1, 0; notebook = true)
end
end
return Dict(), chunks
end

128
src/reader/reader.jl Normal file
View File

@ -0,0 +1,128 @@
using YAML
function WeaveDoc(source, informat = nothing)
path = abspath(source)
_, fname = splitdir(path)
basename = splitext(fname)[1]
isnothing(informat) && (informat = detect_informat(source))
header, chunks = parse_doc(read(source, String), informat)
# update default chunk options from header
chunk_defaults = deepcopy(get_chunk_defaults())
if (weave_options = get(header, WEAVE_OPTION_NAME, nothing)) !== nothing
for key in keys(chunk_defaults)
if (val = get(weave_options, string(key), nothing)) !== nothing
chunk_defaults[key] = val
end
end
end
if haskey(header, WEAVE_OPTION_NAME_DEPRECATED)
@warn "Weave: `options` key is deprecated. Use `weave_options` key instead." _id = WEAVE_OPTION_DEPRECATE_ID maxlog = 1
for key in keys(chunk_defaults)
if (val = get(header[WEAVE_OPTION_NAME_DEPRECATED], string(key), nothing)) !== nothing
chunk_defaults[key] = val
end
end
end
return WeaveDoc(
source,
basename,
path,
chunks,
"",
nothing,
"",
"",
header,
chunk_defaults,
)
end
"""
detect_informat(path)
Detect Weave input format based on file extension of `path`.
"""
function detect_informat(path)
ext = lowercase(last(splitext(path)))
ext == ".jl" && return "script"
ext == ".jmd" && return "markdown"
ext == ".ipynb" && return "notebook"
return "noweb"
end
function parse_doc(document, informat)
document = replace(document, "\r\n" => "\n") # normalize line ending
return informat == "markdown" ? parse_markdown(document) :
informat == "noweb" ? parse_markdown(document; is_pandoc = true) :
informat == "script" ? parse_script(document) :
informat == "notebook" ? parse_notebook(document) :
error("unsupported input format given: $informat")
end
# inline
# ------
function DocChunk(text::AbstractString, number, start_line; notebook = false)
# don't parse inline code in notebook
content = notebook ? parse_inline(text) : parse_inlines(text)
return DocChunk(content, number, start_line)
end
const INLINE_REGEX = r"`j\s+(.*?)`"
const INLINE_REGEXES = r"`j\s+(.*?)`|^!\s(.*)$"m
# handle code units correctly !
function parse_inlines(str)
ret = Inline[]
s = 1
code_no = text_no = 0
for m in eachmatch(INLINE_REGEXES, str)
e = m.offset
push!(ret, InlineText((str[s:prevind(str,e)]), text_no += 1))
i = findfirst(!isnothing, m.captures)
push!(ret, InlineCode(m.captures[i], code_no += 1, isone(i) ? :inline : :line))
s = e + ncodeunits(m.match)
end
push!(ret, InlineText(str[s:end], text_no += 1))
return ret
end
parse_inline(str) = Inline[InlineText(str, 1)]
# options
# -------
const OptionDict = Dict{Symbol,Any}
function parse_options(str)::OptionDict
str = string('(', str, ')')
ex = Meta.parse(str)
nt = if Meta.isexpr(ex, (
:block, # "(k1 = v1; k2 = v2, ...)"
:tuple, # "(k1 = v1, k2 = v2, ...)"
))
eval(Expr(:tuple, filter(is_valid_kv, ex.args)...))
elseif is_valid_kv(ex) # "(k = v)"
eval(Expr(:tuple, ex))
else
NamedTuple{}()
end
return dict(nt)
end
is_valid_kv(x) = Meta.isexpr(x, :(=))
dict(nt) = Dict((k => v for (k,v) in zip(keys(nt), values(nt)))...)
nt(dict) = NamedTuple{(Symbol.(keys(dict))...,)}((collect(values(dict))...,))
# each input format
# -----------------
include("markdown.jl")
include("script.jl")
include("notebook.jl")

67
src/reader/script.jl Normal file
View File

@ -0,0 +1,67 @@
function parse_script(document_body)
lines = split(document_body, '\n')
doc_line = r"(^#'.*)|(^#%%.*)|(^# %%.*)"
doc_start = r"(^#')|(^#%%)|(^# %%)"
opt_line = r"(^#\+.*$)|(^#%%\+.*$)|(^# %%\+.*$)"
opt_start = r"(^#\+)|(^#%%\+)|(^# %%\+)"
content = ""
state = :code
doc_no = 0
code_no = 0
start_line = 1
options = OptionDict()
option_string = ""
chunks = WeaveChunk[]
for (line_no, line) in enumerate(lines)
if (m = match(doc_line, line)) !== nothing && (m = match(opt_line, line)) === nothing
line = replace(line, doc_start => "", count = 1)
startswith(line, ' ') && (line = replace(line, ' ' => "", count = 1))
if state === :code && !isempty(strip(content))
push!(chunks, CodeChunk(string('\n', strip(content)), code_no += 1, start_line, option_string, options))
content = ""
start_line = line_no
end
state = :doc
elseif (m = match(opt_line, line)) !== nothing
start_line = line_no
if state === :code && !isempty(strip(content))
push!(chunks, CodeChunk(string('\n', strip(content)), code_no += 1, start_line, option_string, options))
content = ""
end
if state === :doc && !isempty(strip(content))
iszero(doc_no) || (content = string('\n', content)) # Add whitespace to doc chunk. Needed for markdown output
push!(chunks, DocChunk(content, doc_no += 1, start_line))
content = ""
end
option_string = replace(line, opt_start => "", count = 1)
options = parse_options(option_string)
haskey(options, :label) && (options[:name] = options[:label])
haskey(options, :name) || (options[:name] = nothing)
state = :code
continue
elseif state === :doc # && strip(line) != "" && strip(content) != ""
state = :code
iszero(doc_no) || (content = string('\n', content)) # Add whitespace to doc chunk. Needed for markdown output
push!(chunks, DocChunk(content, doc_no += 1, start_line))
content = ""
options = Dict{Symbol,Any}()
start_line = line_no
end
content *= string(line, '\n')
end
# Handle the last chunk
chunk = state === :code ?
CodeChunk(string('\n', strip(content)), code_no, start_line, option_string, options) :
DocChunk(content, doc_no, start_line)
push!(chunks, chunk)
return Dict(), chunks
end

View File

@ -1,315 +0,0 @@
import JSON, YAML
pushopt(options::Dict,expr::Expr) = Base.Meta.isexpr(expr,:(=)) && (options[expr.args[1]] = expr.args[2])
mutable struct MarkupInput
codestart::Regex
codeend::Regex
inline::Regex
end
mutable struct ScriptInput
doc_line::Regex
doc_start::Regex
opt_line::Regex
opt_start::Regex
inline::Regex
end
mutable struct NotebookInput
inline
end
const input_formats = Dict{AbstractString, Any}(
"noweb" => MarkupInput(r"^<<(.*?)>>=\s*$",
r"^@\s*$",
r"`j\s+(.*?)`|^!\s(.*)$"m
),
"markdown" => MarkupInput(
r"^[`~]{3,}(?:\{|\{\.|)julia(?:;|)\s*(.*?)(\}|\s*)$",
r"^[`~]{3,}\s*$",
r"`j\s+(.*?)`|^!\s(.*)$"m),
"script" => ScriptInput(
r"(^#'.*)|(^#%%.*)|(^# %%.*)",
r"(^#')|(^#%%)|(^# %%)",
r"(^#\+.*$)|(^#%%\+.*$)|(^# %%\+.*$)",
r"(^#\+)|(^#%%\+)|(^# %%\+)",
r"`j\s+(.*?)`|^!\s(.*)$"m),
"notebook" => NotebookInput(nothing) #Don't parse inline code from notebooks
)
"""Detect the input format based on file extension"""
function detect_informat(source::AbstractString)
ext = lowercase(splitext(source)[2])
ext == ".jl" && return "script"
ext == ".jmd" && return "markdown"
ext == ".ipynb" && return "notebook"
return "noweb"
end
"""Read and parse input document"""
function read_doc(source::AbstractString, format=:auto)
format == :auto && (format = detect_informat(source))
document = read(source, String)
document = replace(document, "\r\n" => "\n")
parsed = parse_doc(document, format)
header = parse_header(parsed[1])
doc = WeaveDoc(source, parsed, header)
haskey(header, "options") && header_chunk_defaults!(doc)
return doc
end
function parse_header(chunk::CodeChunk)
return Dict()
end
function parse_header(chunk::DocChunk)
m = match(r"^---$(?<header>.+)^---$"ms, chunk.content[1].content)
if m !== nothing
header = YAML.load(string(m[:header]))
else
header = Dict()
end
return header
end
function parse_doc(document::AbstractString, format="noweb"::AbstractString)
return parse_doc(document, input_formats[format])
end
"""Parse documents with Weave.jl markup"""
function parse_doc(document::AbstractString, format::MarkupInput)
document = replace(document, "\r\n" => "\n")
lines = split(document, "\n")
codestart = format.codestart
codeend = format.codeend
state = "doc"
docno = 1
codeno = 1
content = ""
start_line = 0
options = Dict()
optionString = ""
parsed = Any[]
for lineno in 1:length(lines)
line = lines[lineno]
if (m = match(codestart, line)) != nothing && state=="doc"
state = "code"
if m.captures[1] == nothing
optionString = ""
else
optionString=strip(m.captures[1])
end
options = Dict{Symbol,Any}()
if length(optionString) > 0
expr = Meta.parse(optionString)
Base.Meta.isexpr(expr,:(=)) && (options[expr.args[1]] = expr.args[2])
Base.Meta.isexpr(expr,:toplevel) && map(pushopt,fill(options,length(expr.args)),expr.args)
end
haskey(options, :label) && (options[:name] = options[:label])
haskey(options, :name) || (options[:name] = nothing)
if !isempty(strip(content))
chunk = DocChunk(content, docno, start_line, format.inline)
docno += 1
push!(parsed, chunk)
end
content = ""
start_line = lineno
continue
end
if occursin(codeend, line) && state=="code"
chunk = CodeChunk(content, codeno, start_line, optionString, options)
codeno+=1
start_line = lineno
content = ""
state = "doc"
push!(parsed, chunk)
continue
end
if lineno == 1
content *= line
else
content *= "\n" * line
end
end
#Remember the last chunk
if strip(content) != ""
chunk = DocChunk(content, docno, start_line, format.inline)
#chunk = Dict{Symbol,Any}(:type => "doc", :content => content,
# :number => docno, :start_line => start_line)
push!(parsed, chunk)
end
return parsed
end
"""Parse .jl scripts with Weave.jl markup"""
function parse_doc(document::AbstractString, format::ScriptInput)
document = replace(document, "\r\n" => "\n")
lines = split(document, "\n")
doc_line = format.doc_line
doc_start = format.doc_start
opt_line = format.opt_line
opt_start = format.opt_start
read = ""
chunks = []
docno = 1
codeno = 1
content = ""
start_line = 1
options = Dict{Symbol,Any}()
optionString = ""
parsed = Any[]
state = "code"
lineno = 1
n_emptylines = 0
for lineno in 1:length(lines)
line = lines[lineno]
if (m = match(doc_line, line)) != nothing && (m = match(opt_line, line)) == nothing
line = replace(line, doc_start => "", count=1)
if startswith(line, " ")
line = replace(line, " " => "", count=1)
end
if state == "code" && strip(read) != ""
chunk = CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
push!(parsed, chunk)
codeno +=1
read = ""
start_line = lineno
end
state = "doc"
elseif (m = match(opt_line, line)) != nothing
start_line = lineno
if state == "code" && strip(read) !=""
chunk = CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
push!(parsed, chunk)
read = ""
codeno +=1
end
if state == "doc" && strip(read) != ""
(docno > 1) && (read = "\n" * read) # Add whitespace to doc chunk. Needed for markdown output
chunk = DocChunk(read, docno, start_line)
push!(parsed, chunk)
read = ""
docno += 1
end
optionString = replace(line, opt_start => "", count=1)
#Get options
options = Dict{Symbol,Any}()
if length(optionString) > 0
expr = Meta.parse(optionString)
Base.Meta.isexpr(expr,:(=)) && (options[expr.args[1]] = expr.args[2])
Base.Meta.isexpr(expr,:toplevel) && map(pushopt,fill(options,length(expr.args)),expr.args)
end
haskey(options, :label) && (options[:name] = options[:label])
haskey(options, :name) || (options[:name] = nothing)
state = "code"
continue
elseif state == "doc" #&& strip(line) != "" && strip(read) != ""
state = "code"
(docno > 1) && (read = "\n" * read) # Add whitespace to doc chunk. Needed for markdown output
chunk = DocChunk(read, docno, start_line, format.inline)
push!(parsed, chunk)
options = Dict{Symbol,Any}()
start_line = lineno
read = ""
docno += 1
end
read *= line * "\n"
if strip(line) == ""
n_emptylines += 1
else
n_emptylines = 0
end
end
# Handle the last chunk
if state == "code"
chunk = CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
push!(parsed, chunk)
else
chunk = DocChunk(read, docno, start_line, format.inline)
push!(parsed, chunk)
end
return parsed
end
"""Parse IJUlia notebook"""
function parse_doc(document::String, format::NotebookInput)
document = replace(document, "\r\n" => "\n")
nb = JSON.parse(document)
parsed = Any[]
options = Dict{Symbol,Any}()
opt_string = ""
docno = 1
codeno = 1
for cell in nb["cells"]
srctext = "\n" * join(cell["source"], "")
if cell["cell_type"] == "code"
chunk = CodeChunk(rstrip(srctext), codeno, 0, opt_string, options)
push!(parsed, chunk)
codeno += 1
else
chunk = DocChunk(srctext * "\n", docno, 0)
push!(parsed, chunk)
docno +=1
end
end
return parsed
end
#Use this if regex is undefined
function parse_inline(text, noex)
return Inline[InlineText(text, 1, length(text), 1)]
end
function parse_inline(text::AbstractString, inline_ex::Regex)
occursin(inline_ex, text) || return Inline[InlineText(text, 1, length(text), 1)]
inline_chunks = eachmatch(inline_ex, text)
s = 1
e = 1
res = Inline[]
textno = 1
codeno = 1
for ic in inline_chunks
s = ic.offset
doc = InlineText(text[e:(s-1)], e, s-1, textno)
textno += 1
push!(res, doc)
e = s + lastindex(ic.match)
ic.captures[1] !== nothing && (ctype = :inline)
ic.captures[2] !== nothing && (ctype = :line)
cap = filter(x -> x !== nothing, ic.captures)[1]
push!(res, InlineCode(cap, s, e, codeno, ctype))
codeno += 1
end
push!(res, InlineText(text[e:end], e, length(text), textno))
return res
end

162
src/rendering/common.jl Normal file
View File

@ -0,0 +1,162 @@
# fallback methods
# ----------------
set_format_options!(docformat::WeaveFormat; _kwargs...) = return
function restore_header!(doc)
(hasproperty(doc.format, :preserve_header) && doc.format.preserve_header) || return
# 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
render_chunk(docformat::WeaveFormat, chunk::DocChunk) = join((render_inline(c) for c in chunk.content))
render_inline(inline::InlineText) = inline.content
function render_inline(inline::InlineCode)
isempty(inline.rich_output) || return inline.rich_output
isempty(inline.figures) || return inline.figures[end]
return inline.output
end
function render_chunk(docformat::WeaveFormat, chunk::CodeChunk)
# Fill undefined options with format specific defaults
isnothing(chunk.options[:out_width]) && (chunk.options[:out_width] = docformat.out_width)
isnothing(chunk.options[:fig_pos]) && (chunk.options[:fig_pos] = docformat.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] = docformat.fig_env)
end
hasproperty(docformat, :indent) && (chunk.content = indent(chunk.content, docformat.indent))
chunk.content = render_code(docformat, chunk.content)
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 echo
# Convert to output format and highlight (html, tex...) if needed
string(docformat.codestart, chunk.content, docformat.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 = render_output(docformat, chunk.output)
else
chunk.output = '\n' * rstrip(chunk.output)
chunk.output = render_output(docformat, chunk.output)
end
hasproperty(docformat, :indent) && (chunk.output = indent(chunk.output, docformat.indent))
strip(chunk.output) "" && (
result *= "$(docformat.outputstart)$(chunk.output)\n$(docformat.outputend)\n"
)
strip(chunk.rich_output) "" && (result *= chunk.rich_output * '\n')
end
end
end
# Handle figures
if chunk.options[:fig] && length(chunk.figures) > 0
result *= render_figures(docformat, chunk)
end
return result
end
render_code(docformat::WeaveFormat, code) = code
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
render_output(docformat::WeaveFormat, output) = output
function render_termchunk(docformat::WeaveFormat, chunk)
return if should_render(chunk)
string(docformat.termstart, chunk.output, docformat.termend)
else
""
end
end
should_render(chunk) = chunk.options[:echo] && chunk.options[:results] "hidden"
render_doc(docformat, body, doc) = body
# utilities
# ---------
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
get_mustache_template(path::AbstractString) = Mustache.template_from_file(path)
get_mustache_template(tpl::Mustache.MustacheTokens) = tpl
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)
get_highlight_theme(::Nothing) = Highlights.Themes.DefaultTheme
get_highlight_theme(highlight_theme::Type{<:Highlights.AbstractTheme}) = highlight_theme
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)

View File

@ -0,0 +1,160 @@
# HTML
# ----
abstract type HTMLFormat <: WeaveFormat end
render_code(docformat::HTMLFormat, code) =
highlight_code(MIME("text/html"), code, docformat.highlight_theme)
render_termchunk(docformat::HTMLFormat, chunk) =
should_render(chunk) ? highlight_term(MIME("text/html"), chunk.output, docformat.highlight_theme) : ""
# Julia markdown
# --------------
Base.@kwdef mutable struct WeaveHTML <: HTMLFormat
description = "Weave-style HTML"
extension = "html"
codestart = '\n'
codeend = '\n'
termstart = codestart
termend = codeend
outputstart = "<pre class=\"output\">"
outputend = "</pre>\n"
mimetypes = ["image/png", "image/jpg", "image/svg+xml",
"text/html", "text/markdown", "text/plain"]
fig_ext = ".png"
out_width = nothing
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
template = nothing
stylesheet = nothing
highlight_theme = nothing
end
register_format!("md2html", WeaveHTML())
function set_format_options!(docformat::WeaveHTML; template = nothing, css = nothing, highlight_theme = nothing, _kwargs...)
template_path = isnothing(template) ? normpath(TEMPLATE_DIR, "md2html.tpl") : template
docformat.template = get_mustache_template(template_path)
stylesheet_path = isnothing(css) ? normpath(STYLESHEET_DIR, "skeleton.css") : css
docformat.stylesheet = read(stylesheet_path, String)
docformat.highlight_theme = get_highlight_theme(highlight_theme)
end
# very similar to tex version of function
function render_chunk(docformat::WeaveHTML, chunk::DocChunk)
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
render_output(docformat::WeaveHTML, output) = Markdown.htmlesc(output)
function render_figures(docformat::WeaveHTML, chunk)
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 = ""
isnothing(width) || (attribs = "width=\"$width\"")
(!isempty(attribs) && !isnothing(height)) && (attribs *= ",")
isnothing(height) || (attribs *= " height=\"$height\" ")
if !isnothing(caption)
result *= """<figure>\n"""
end
for fig in fignames
figstring *= """<img src="$fig" $attribs />\n"""
end
result *= figstring
if !isnothing(caption)
result *= """
<figcaption>$caption</figcaption>
"""
end
if !isnothing(caption)
result *= "</figure>\n"
end
return result
end
function render_doc(docformat::WeaveHTML, body, doc; css = nothing)
_, weave_source = splitdir(abspath(doc.source))
weave_version, weave_date = weave_info()
return Mustache.render(
docformat.template;
body = body,
stylesheet = docformat.stylesheet,
highlight_stylesheet = get_highlight_stylesheet(MIME("text/html"), docformat.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
# Pandoc
# ------
Base.@kwdef mutable struct Pandoc2HTML <: HTMLFormat
description = "HTML via intermediate Pandoc Markdown (requires Pandoc 2)"
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
stylesheet_path = nothing
highlight_theme = nothing
pandoc_options = String[]
end
register_format!("pandoc2html", Pandoc2HTML())
function set_format_options!(docformat::Pandoc2HTML; template = nothing, css = nothing, highlight_theme = nothing, pandoc_options = String[], _kwargs...)
docformat.template_path =
isnothing(template) ? normpath(TEMPLATE_DIR, "pandoc2html.html") : template
docformat.stylesheet_path =
isnothing(css) ? normpath(STYLESHEET_DIR, "pandoc2html_skeleton.css") : css
docformat.highlight_theme = get_highlight_theme(highlight_theme)
docformat.pandoc_options = pandoc_options
end
render_figures(docformat::Pandoc2HTML, chunk) = render_figures(Pandoc(), chunk)

View File

@ -0,0 +1,224 @@
# GitHub markdown
# ---------------
Base.@kwdef mutable struct GitHubMarkdown <: WeaveFormat
description = "GitHub Markdown"
extension = "md"
codestart = "```julia"
codeend = "```\n"
termstart = codestart
termend = codeend
outputstart = "```"
outputend = "```\n\n"
fig_ext = ".png"
mimetypes = ["image/png", "image/svg+xml", "image/jpg",
"text/markdown", "text/plain"]
out_width = nothing
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
preserve_header = true
end
register_format!("github", GitHubMarkdown())
function render_figures(docformat::GitHubMarkdown, chunk)
fignames = chunk.figures
caption = chunk.options[:fig_cap]
result = ""
figstring = ""
length(fignames) > 0 || (return "")
if !isnothing(caption)
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
# Hugo markdown
# -------------
Base.@kwdef mutable struct Hugo <: WeaveFormat
description = "Hugo Markdown (using shortcodes)"
extension = "md"
codestart = "```julia"
codeend = "```\n"
termstart = codestart
termend = codeend
outputstart = "```"
outputend = "```\n\n"
mimetypes = default_mime_types
fig_ext = ".png"
out_width = nothing
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
preserve_header = true
uglyURLs = false # if `false`, prepend figure path by `..`
end
register_format!("hugo", Hugo())
function render_figures(docformat::Hugo, chunk)
relpath = docformat.uglyURLs ? "" : ".."
mapreduce(*, enumerate(chunk.figures), init = "") do (index, fig)
if index > 1
@warn("Only the first figure gets a caption.")
title_spec = ""
else
caption = chunk.options[:fig_cap]
title_spec = isnothing(caption) ? "" : "title=\"$(caption)\" "
end
"{{< figure src=\"$(joinpath(relpath, fig))\" $(title_spec) >}}"
end
end
# multi language markdown
# -----------------------
Base.@kwdef mutable struct MultiMarkdown <: WeaveFormat
description = "MultiMarkdown"
extension = "md"
codestart = "```julia"
codeend = "```\n"
termstart = codestart
termend = codeend
outputstart = "```"
outputend = "```\n\n"
mimetypes = default_mime_types
fig_ext = ".png"
out_width = nothing
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
preserve_header = true
end
register_format!("multimarkdown", MultiMarkdown())
function render_figures(docformat::MultiMarkdown, chunk)
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 !isnothing(caption)
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
# Rest
# ----
Base.@kwdef mutable struct Rest <: WeaveFormat
description = "reStructuredText and Sphinx"
extension = "rst"
codestart = ".. code-block:: julia\n"
codeend = "\n"
termstart = codestart
termend = codeend
outputstart = "::\n"
outputend = "\n\n"
mimetypes = default_mime_types
fig_ext = ".png"
out_width = "15 cm"
out_height = nothing
fig_pos = nothing
fig_env = nothing
# specials
indent = 4
end
register_format!("rst", Rest())
function render_figures(docformat::Rest, chunk)
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 !isnothing(caption)
result *= string(
".. figure:: $(fignames[1])\n",
" :width: $width\n\n",
" $caption\n\n",
)
else
result *= figstring
return result
end
end
# Ansii
# -----
# asciidoc -b html5 -a source-highlighter=pygments ...
Base.@kwdef mutable struct AsciiDoc <: WeaveFormat
description = "AsciiDoc"
extension = "txt"
codestart = "[source,julia]\n--------------------------------------"
codeend = "--------------------------------------\n"
termstart = codestart
termend = codeend
outputstart = "--------------------------------------"
outputend = "--------------------------------------\n\n"
mimetypes = default_mime_types
fig_ext = ".png"
out_width = "600"
out_height = nothing
fig_pos = nothing
fig_env = nothing
end
register_format!("asciidoc", AsciiDoc())
function render_figures(docformat::AsciiDoc, chunk)
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 !isnothing(caption)
result *= string("image::$(fignames[1])", "[width=$width,", "title=\"$caption\"]")
else
result *= figstring
return result
end
end

View File

@ -0,0 +1,84 @@
abstract type PandocFormat <: WeaveFormat end
function render_figures(docformat::PandocFormat, chunk)
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[]
isnothing(width) || push!(attribs, "width=$width")
isnothing(height) || push!(attribs, "height=$height")
isnothing(label) || push!(attribs, "#fig:$label")
attribs = isempty(attribs) ? "" : "{" * join(attribs, " ") * "}"
if !isnothing(caption)
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
Base.@kwdef mutable struct Pandoc <: PandocFormat
description = "Pandoc Markdown"
extension = "md"
codestart = "~~~~{.julia}"
codeend = "~~~~~~~~~~~~~\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
end
register_format!("pandoc", Pandoc())
const DEFAULT_PANDOC_OPTIONS = String[]
Base.@kwdef mutable struct Pandoc2PDF <: PandocFormat
description = "PDF via intermediate Pandoc Markdown"
extension = "md"
codestart = "~~~~{.julia}"
codeend = "~~~~~~~~~~~~~\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")
pandoc_options = DEFAULT_PANDOC_OPTIONS
end
register_format!("pandoc2pdf", Pandoc2PDF())
function set_format_options!(docformat::Pandoc2PDF; pandoc_options = DEFAULT_PANDOC_OPTIONS, _kwargs...)
docformat.pandoc_options = pandoc_options
end

View File

@ -0,0 +1,31 @@
# TODO:
# - 1. Improve argument handling
# - 2. Update code to use UnPack.jl to make it more readable
# - 3. Export new interface
# - 4. Document Interface
using Mustache, Highlights, .WeaveMarkdown, Markdown, Dates, Printf
const FORMATS = Dict{String,WeaveFormat}()
# TODO: do some assertion for necessary fields of `format`
register_format!(format_name::AbstractString, format::WeaveFormat) = push!(FORMATS, format_name => format)
register_format!(_, format) = error("Format needs to be a subtype of WeaveFormat.")
set_format_options!(doc; kwargs...) = set_format_options!(doc.format; kwargs...)
function render_doc(doc::WeaveDoc)
restore_header!(doc)
docformat = doc.format
body = joinlines(render_chunk.(Ref(docformat), copy(doc.chunks)))
return render_doc(docformat, body, doc)
end
include("common.jl")
include("htmlformats.jl")
include("texformats.jl")
include("pandocformats.jl")
include("miscformats.jl")

276
src/rendering/texformats.jl Normal file
View File

@ -0,0 +1,276 @@
# Tex
# ---
abstract type LaTeXFormat <: WeaveFormat end
function set_format_options!(docformat::LaTeXFormat; keep_unicode = false, template = nothing, _kwargs...)
docformat.keep_unicode |= keep_unicode
docformat.template =
get_mustache_template(isnothing(template) ? normpath(TEMPLATE_DIR, "md2pdf.tpl") : template)
end
# very similar to export to html
function render_chunk(docformat::LaTeXFormat, chunk::DocChunk)
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 unicode2latex(docformat, out)
end
render_output(docformat::LaTeXFormat, output) = unicode2latex(docformat, output, true)
render_code(docformat::LaTeXFormat, code) = unicode2latex(docformat, code, true)
render_termchunk(docformat::LaTeXFormat, chunk) = string(docformat.termstart, chunk.output, docformat.termend, "\n")
# from julia symbols (e.g. "\bfhoge") to valid latex
const UNICODE2LATEX = let
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
Dict(unicode => texify(sym) for (sym, unicode) in REPL.REPLCompletions.latex_symbols)
end
function unicode2latex(docformat::LaTeXFormat, s, escape = false)
# Check whether to convert at all and return input if not
docformat.keep_unicode && return s
for (unicode, latex) in UNICODE2LATEX
body = "\\ensuremath{$(latex)}"
target = escape ? string(docformat.escape_starter, body, docformat.escape_closer) : body
s = replace(s, unicode => target)
end
return s
end
function render_figures(docformat::LaTeXFormat, chunk)
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 isnothing(f_env) && !isnothing(caption)
f_env = "figure"
end
(isnothing(f_pos)) && (f_pos = "!h")
# Set size
attribs = ""
isnothing(width) || (attribs = "width=$(md_length_to_latex(width,"\\linewidth"))")
(!isempty(attribs) && !isnothing(height)) && (attribs *= ",")
isnothing(height) || (attribs *= "height=$(md_length_to_latex(height,"\\paperheight"))")
if !isnothing(f_env)
result *= "\\begin{$f_env}"
(!isempty(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 !isnothing(caption)
result *= string("\\center\n", "$figstring", "\\caption{$caption}\n")
else
result *= figstring
end
if !isnothing(chunk.options[:label]) && !isnothing(f_env)
label = chunk.options[:label]
result *= "\\label{fig:$label}\n"
end
if !isnothing(f_env)
result *= "\\end{$f_env}\n"
end
return result
end
function md_length_to_latex(def, reference)
if occursin("%", def)
_def = tryparse(Float64, replace(def, "%" => ""))
isnothing(_def) && return def
perc = round(_def / 100, digits = 2)
return "$perc$reference"
end
return def
end
function render_doc(docformat::LaTeXFormat, body, doc)
return Mustache.render(
docformat.template;
body = body,
highlight = "",
tex_deps = docformat.tex_deps,
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
)
end
# minted Tex
# ----------
Base.@kwdef mutable struct LaTeXMinted <: LaTeXFormat
description = "LaTeX using minted package for code highlighting"
extension = "tex"
codestart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}"
codeend = "\\end{minted}"
termstart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\footnotesize, xleftmargin=0.5em]{jlcon}"
termend = "\\end{minted}"
outputstart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\small, xleftmargin=0.5em, frame = leftline]{text}"
outputend = "\\end{minted}"
mimetypes = ["application/pdf", "image/png", "text/latex", "text/plain"]
fig_ext = ".pdf"
out_width = "\\linewidth"
out_height = nothing
fig_pos = "htpb"
fig_env = "figure"
# specials
keep_unicode = false
template = nothing
tex_deps = "\\usepackage{minted}"
# how to escape latex in verbatim/code environment
escape_starter = "|\$"
escape_closer = reverse(escape_starter)
end
register_format!("texminted", LaTeXMinted())
# Tex (directly to PDF)
# ---------------------
abstract type WeaveLaTeXFormat <: LaTeXFormat end
function set_format_options!(docformat::WeaveLaTeXFormat; template = nothing, highlight_theme = nothing, keep_unicode = false, _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
end
function render_output(docformat::WeaveLaTeXFormat, output)
# Highligts has some extra escaping defined, eg of $, ", ...
output_escaped = sprint(
(io, x) ->
Highlights.Format.escape(io, MIME("text/latex"), x, charescape = true),
output,
)
return unicode2latex(docformat, output_escaped, true)
end
function render_code(docformat::WeaveLaTeXFormat, code)
ret = highlight_code(MIME("text/latex"), code, docformat.highlight_theme)
unicode2latex(docformat, ret, false)
end
render_termchunk(docformat::WeaveLaTeXFormat, chunk) =
should_render(chunk) ? highlight_term(MIME("text/latex"), chunk.output, docformat.highlight_theme) : ""
function render_doc(docformat::WeaveLaTeXFormat, body, doc)
return Mustache.render(
docformat.template;
body = body,
highlight = get_highlight_stylesheet(MIME("text/latex"), docformat.highlight_theme),
tex_deps = docformat.tex_deps,
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
)
end
Base.@kwdef mutable struct WeaveLaTeX <: WeaveLaTeXFormat
description = "Weave-styled LaTeX"
extension = "tex"
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 = ""
# how to escape latex in verbatim/code environment
escape_starter = "(*@"
escape_closer = reverse(escape_starter)
end
register_format!("md2tex", WeaveLaTeX())
# will be used by `write_doc`
const DEFAULT_LATEX_CMD = ["xelatex", "-shell-escape", "-halt-on-error"]
Base.@kwdef mutable struct WeaveLaTeX2PDF <: WeaveLaTeXFormat
description = "PDF via Weave-styled LaTeX"
extension = "tex"
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
# how to escape latex in verbatim/code environment
escape_starter = "(*@"
escape_closer = reverse(escape_starter)
end
register_format!("md2pdf", WeaveLaTeX2PDF())
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
end

View File

@ -1,190 +1,189 @@
using Base64
"""
run(doc::WeaveDoc; doctype = :auto,
mod::Union{Module, Symbol} = :sandbox, out_path=:doc,
args=Dict(), fig_path = "figures", fig_ext = nothing,
cache_path = "cache", cache = :off, throw_errors=false)
Run code chunks and capture output from parsed document.
const PROGRESS_ID = "weave_progress"
* `doctype`: :auto = set based on file extension or specify one of the supported formats.
See `list_out_formats()`
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document, `:pwd`: Julia working directory,
`"somepath"`: Path as a AbstractString e.g `"/home/mpastell/weaveout"`
* `args`: dictionary of arguments to pass to document. Available as WEAVE_ARGS.
* `mod`: Module where Weave `eval`s code. Defaults to `:sandbox`
to create new sandbox module, you can also pass a module e.g. `Main`.
* `fig_path`: where figures will be generated, relative to out_path
* `fig_ext`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`.
* `cache_path`: where of cached output will be saved.
* `cache`: controls caching of code: `:off` = no caching, `:all` = cache everything,
`:user` = cache based on chunk options, `:refresh`, run all code chunks and save new cache.
function run_doc(
doc::WeaveDoc;
doctype::Union{Nothing,AbstractString} = nothing,
out_path::Union{Symbol,AbstractString} = :doc,
args::Any = Dict(),
mod::Union{Module,Nothing} = nothing,
fig_path::Union{Nothing,AbstractString} = nothing,
fig_ext::Union{Nothing,AbstractString} = nothing,
cache_path::AbstractString = "cache",
cache::Symbol = :off,
)
# cache :all, :user, :off, :refresh
**Note:** Run command from terminal and not using IJulia, Juno or ESS, they tend to mess with capturing output.
"""
function Base.run(doc::WeaveDoc; doctype = :auto,
mod::Union{Module, Symbol} = :sandbox, out_path=:doc,
args=Dict(), fig_path = "figures", fig_ext = nothing,
cache_path = "cache", cache = :off, throw_errors=false, latex_keep_unicode=false)
#cache :all, :user, :off, :refresh
doc.doctype = isnothing(doctype) ? (doctype = detect_doctype(doc.source)) : doctype
doc.format = deepcopy(get_format(doctype))
doc.cwd = get_cwd(doc, out_path)
doctype == :auto && (doctype = detect_doctype(doc.source))
doc.doctype = doctype
doc.format = formats[doctype]
cwd = doc.cwd = get_cwd(doc, out_path)
mkpath(cwd)
if (haskey(doc.format.formatdict, :keep_unicode))
doc.format.formatdict[:keep_unicode] = latex_keep_unicode
# 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)))
else
DEFAULT_FIG_PATH
end
end
isdir(doc.cwd) || mkpath(doc.cwd)
if occursin("2pdf", doctype) && cache == :off
fig_path = mktempdir(abspath(doc.cwd))
elseif occursin("2html", doctype)
fig_path = mktempdir(abspath(doc.cwd))
end
cache == :off || @eval import Serialization
#This is needed for latex and should work on all output formats
Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/"))
doc.fig_path = fig_path
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)
#New sandbox for each document with args exposed
if mod == :sandbox
sandbox = "WeaveSandBox$(rcParams[:doc_number])"
mod = Core.eval(Main, Meta.parse("module $sandbox\nend"))
end
@eval mod WEAVE_ARGS = Dict()
merge!(mod.WEAVE_ARGS, args)
cache === :off || @eval import Serialization # XXX: evaluate in a more sensible module
rcParams[:doc_number] += 1
# New sandbox for each document with args exposed
isnothing(mod) && (mod = sandbox = Core.eval(Main, :(module $(gensym(:WeaveSandBox)) end))::Module)
Core.eval(mod, :(const WEAVE_ARGS = $(args)))
if haskey(doc.format.formatdict, :mimetypes)
mimetypes = doc.format.formatdict[:mimetypes]
else
mimetypes = default_mime_types
end
mimetypes = doc.format.mimetypes
report = Report(doc.cwd, doc.basename, doc.format.formatdict, mimetypes, throw_errors)
report = Report(cwd, doc.basename, doc.format, mimetypes)
cd_back = let d = pwd(); () -> cd(d); end
cd(cwd)
pushdisplay(report)
if cache != :off && cache != :refresh
cached = read_cache(doc, cache_path)
cached == nothing && @info("No cached results found, running code")
else
cached = nothing
end
executed = Any[]
n = length(doc.chunks)
for i = 1:n
chunk = doc.chunks[i]
if isa(chunk, CodeChunk)
options = merge(doc.chunk_defaults, chunk.options)
merge!(chunk.options, options)
end
restore = (cache ==:user && typeof(chunk) == CodeChunk && chunk.options[:cache])
if cached != nothing && (cache == :all || restore)
result_chunks = restore_chunk(chunk, cached)
try
if cache !== :off && cache !== :refresh
cached = read_cache(doc, cache_path)
isnothing(cached) && @info "No cached results found, running code"
else
result_chunks = run_chunk(chunk, doc, report, mod)
cached = nothing
end
executed = [executed; result_chunks]
end
executed = []
n = length(filter(chunk->isa(chunk,CodeChunk), doc.chunks))
i = 0
for chunk in doc.chunks
if chunk isa CodeChunk
options = merge(doc.chunk_defaults, chunk.options)
merge!(chunk.options, options)
doc.header_script = report.header_script
@info "Weaving chunk $(chunk.number) from line $(chunk.start_line)" progress=(i)/n _id=PROGRESS_ID
i+=1
end
popdisplay(report)
restore = (cache === :user && chunk isa CodeChunk && chunk.options[:cache])
result_chunks = if cached nothing && (cache === :all || restore)
restore_chunk(chunk, cached)
else
run_chunk(chunk, doc, report, mod)
end
executed = [executed; result_chunks]
end
#Clear variables from used sandbox
mod == :sandbox && clear_sandbox(SandBox)
doc.chunks = executed
replace_header_inline!(doc, report, mod) # evaluate and replace inline code in header
if cache != :off
write_cache(doc, cache_path)
doc.header_script = report.header_script
doc.chunks = executed
cache !== :off && write_cache(doc, cache_path)
@isdefined(sandbox) && clear_module!(sandbox)
catch err
rethrow(err)
finally
@info "Weaved all chunks" progress=1 _id=PROGRESS_ID
cd_back()
popdisplay(report) # ensure display pops out even if internal error occurs
end
return doc
end
"""Detect the output format based on file extension"""
function detect_doctype(source::AbstractString)
ext = lowercase(splitext(source)[2])
ext == ".jl" && return "md2html"
occursin("md", ext) && return "md2html"
occursin("rst", ext) && return "rst"
occursin("tex", ext) && return "texminted"
occursin("txt", ext) && return "asciidoc"
run_doc(doc::WeaveDoc, doctype::Union{Nothing,AbstractString}; kwargs...) =
run_doc(doc; doctype = doctype, kwargs...)
return "pandoc"
"""
detect_doctype(path)
Detect the output format based on file extension.
"""
function detect_doctype(path)
_, ext = lowercase.(splitext(path))
match(r"^\.(jl|.?md|ipynb)", ext) !== nothing && return "md2html"
ext == ".rst" && return "rst"
ext == ".tex" && return "texminted"
ext == ".txt" && return "asciidoc"
return "pandoc"
end
function run_chunk(chunk::CodeChunk, doc::WeaveDoc, report::Report, SandBox::Module)
@info("Weaving chunk $(chunk.number) from line $(chunk.start_line)")
result_chunks = eval_chunk(chunk, report, SandBox)
occursin("2html", report.formatdict[:doctype]) && (result_chunks = embed_figures(result_chunks, report.cwd))
return result_chunks
end
function embed_figures(chunk::CodeChunk, cwd)
chunk.figures = [img2base64(fig, cwd) for fig in chunk.figures]
return chunk
end
function embed_figures(result_chunks, cwd)
for i in 1:length(result_chunks)
figs = result_chunks[i].figures
if !isempty(figs)
result_chunks[i].figures = [img2base64(fig, cwd) for fig in figs]
function get_cwd(doc, out_path)
return if out_path === :doc
dirname(doc.path)
elseif out_path === :pwd
pwd()
else
path, ext = splitext(out_path)
if isempty(ext) # directory given
path
else # file given
dirname(path)
end
end |> abspath
end
function run_chunk(chunk::CodeChunk, doc, report, mod)
result = eval_chunk(doc, chunk, report, mod)
occursin("2html", doc.doctype) && (embed_figures!(result, report.cwd))
return result
end
function embed_figures!(chunk::CodeChunk, cwd)
for (i, fig) in enumerate(chunk.figures)
chunk.figures[i] = img2base64(fig, cwd)
end
end
function embed_figures!(chunks::Vector{CodeChunk}, cwd)
for chunk in chunks
embed_figures!(chunk, cwd)
end
return result_chunks
end
function img2base64(fig, cwd)
ext = splitext(fig)[2]
f = open(joinpath(cwd, fig), "r")
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
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
end
function run_chunk(chunk::DocChunk, doc::WeaveDoc, report::Report, SandBox::Module)
chunk.content = [run_inline(c, doc, report, SandBox) for c in chunk.content]
function run_chunk(chunk::DocChunk, doc, report, mod)
chunk.content = [run_inline(c, doc, report, mod) for c in chunk.content]
return chunk
end
function run_inline(inline::InlineText, doc::WeaveDoc, report::Report, SandBox::Module)
return inline
end
run_inline(inline::InlineText, ::WeaveDoc, ::Report, ::Module) = inline
function run_inline(inline::InlineCode, doc::WeaveDoc, report::Report, SandBox::Module)
#Make a temporary CodeChunk for running code. Collect results and don't wrap
chunk = CodeChunk(inline.content, 0, 0, "", Dict(:hold => true, :wrap => false))
const INLINE_OPTIONS = Dict(
:term => false,
:hold => true,
:wrap => false
)
function run_inline(inline::InlineCode, doc::WeaveDoc, report::Report, mod::Module)
# Make a temporary CodeChunk for running code. Collect results and don't wrap
chunk = CodeChunk(inline.content, 0, 0, "", INLINE_OPTIONS)
options = merge(doc.chunk_defaults, chunk.options)
merge!(chunk.options, options)
chunks = eval_chunk(chunk, report, SandBox)
occursin("2html", report.formatdict[:doctype]) && (chunks = embed_figures(chunks, report.cwd))
chunks = eval_chunk(doc, chunk, report, mod)
occursin("2html", doc.doctype) && (embed_figures!(chunks, report.cwd))
output = chunks[1].output
endswith(output, "\n") && (output = output[1:end-1])
@ -194,260 +193,269 @@ function run_inline(inline::InlineCode, doc::WeaveDoc, report::Report, SandBox::
return inline
end
function reset_report(report::Report)
report.cur_result = ""
report.figures = AbstractString[]
report.term_state = :text
function run_code(doc::WeaveDoc, chunk::CodeChunk, report::Report, mod::Module)
code = chunk.content
path = doc.path
error = chunk.options[:error]
codes = chunk.options[:term] ? split_code(code) : [code]
capture = code -> capture_output(code, mod, path, error, report)
return capture.(codes)
end
function run_code(chunk::CodeChunk, report::Report, SandBox::Module)
expressions = parse_input(chunk.content)
N = length(expressions)
#@show expressions
result_no = 1
results = ChunkOutput[ ]
for (str_expr, expr) = expressions
reset_report(report)
lastline = (result_no == N)
(obj, out) = capture_output(expr, SandBox, chunk.options[:term],
chunk.options[:display], lastline, report.throw_errors)
figures = report.figures #Captured figures
result = ChunkOutput(str_expr, out, report.cur_result, report.rich_output, figures)
report.rich_output = ""
push!(results, result)
result_no += 1
function split_code(code)
res = String[]
e = 1
ex = :init
while true
s = e
ex, e = Meta.parse(code, s)
isnothing(ex) && break
push!(res, strip(code[s:e-1]))
end
return results
return res
end
getstdout() = stdout
function capture_output(code, mod, path, error, report)
reset_report!(report)
function capture_output(expr, SandBox::Module, term, disp,
lastline, throw_errors=false)
#oldSTDOUT = STDOUT
oldSTDOUT = getstdout()
out = nothing
obj = nothing
old = stdout
rw, wr = redirect_stdout()
reader = @async read(rw, String)
try
obj = Core.eval(SandBox, expr)
if (term || disp) && (typeof(expr) != Expr || expr.head != :toplevel)
obj != nothing && display(obj)
#This shows images and lone variables, result can
#Handle last line sepately
elseif lastline && obj != nothing
(typeof(expr) != Expr || expr.head != :toplevel) && display(obj)
local out = nothing
task_local_storage(:SOURCE_PATH, path) do
try
obj = include_string(mod, code, path) # TODO: fix line number
!isnothing(obj) && !REPL.ends_with_semicolon(code) && display(obj)
catch _err
err = unwrap_load_err(_err)
error || throw(err)
display(err)
@warn "ERROR: $(typeof(err)) occurred, including output in Weaved document"
finally
redirect_stdout(old)
close(wr)
out = fetch(reader)
close(rw)
end
catch E
throw_errors && throw(E)
display(E)
@warn("ERROR: $(typeof(E)) occurred, including output in Weaved document")
finally
redirect_stdout(oldSTDOUT)
close(wr)
out = fetch(reader)
close(rw)
end
out = replace(out, r"\u001b\[.*?m" => "") #Remove ANSI color codes
return (obj, out)
return ChunkOutput(code, remove_ansi_control_chars(out), report.rich_output, report.figures)
end
#Parse chunk input to array of expressions
function parse_input(input::AbstractString)
parsed = Tuple{AbstractString, Any}[]
input = lstrip(input)
n = sizeof(input)
pos = 1 #The first character is extra line end
while pos n
oldpos = pos
code, pos = Meta.parse(input, pos)
push!(parsed, (input[oldpos:pos-1] , code ))
end
parsed
function reset_report!(report)
report.rich_output = ""
report.figures = String[]
end
unwrap_load_err(err) = return err
unwrap_load_err(err::LoadError) = return err.error
function eval_chunk(chunk::CodeChunk, report::Report, SandBox::Module)
# https://stackoverflow.com/a/33925425/12113178
remove_ansi_control_chars(s) = replace(s, r"(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]" => "")
function eval_chunk(doc::WeaveDoc, chunk::CodeChunk, report::Report, mod::Module)
if !chunk.options[:eval]
chunk.output = ""
chunk.options[:fig] = false
return chunk
end
#Run preexecute_hooks
for hook in preexecute_hooks
chunk = Base.invokelatest(hook, chunk)
end
execute_prehooks!(chunk)
report.fignum = 1
report.cur_chunk = chunk
if haskey(report.formatdict, :out_width) && chunk.options[:out_width] == nothing
chunk.options[:out_width] = report.formatdict[:out_width]
if hasproperty(report.format, :out_width) && isnothing(chunk.options[:out_width])
chunk.options[:out_width] = report.format.out_width
end
chunk.result = run_code(chunk, report, SandBox)
chunk.result = run_code(doc, chunk, report, mod)
execute_posthooks!(chunk)
#Run post_execute chunks
for hook in postexecute_hooks
chunk = Base.invokelatest(hook, chunk)
end
if chunk.options[:term]
chunks = collect_results(chunk, TermResult())
chunks = if chunk.options[:term]
collect_term_results(chunk)
elseif chunk.options[:hold]
chunks = collect_results(chunk, CollectResult())
collect_hold_results(chunk)
else
chunks = collect_results(chunk, ScriptResult())
collect_results(chunk)
end
#else
# chunk.options[:fig] && (chunk.figures = copy(report.figures))
#end
chunks
return chunks
end
# Hooks to run before and after chunks, this is form IJulia,
const preexecution_hooks = Function[]
push_preexecution_hook!(f::Function) = push!(preexecution_hooks, f)
function pop_preexecution_hook!(f::Function)
i = findfirst(x -> x == f, preexecution_hooks)
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 eval_chunk(chunk::DocChunk, report::Report, SandBox)
# chunk
#end
const postexecution_hooks = Function[]
push_postexecution_hook!(f::Function) = push!(postexecution_hooks, f)
function pop_postexecution_hook!(f::Function)
i = findfirst(x -> x == f, postexecution_hooks)
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
#Set all variables to nothing
function clear_sandbox(SandBox::Module)
for name = names(SandBox, all=true)
if name != :eval && name != names(SandBox)[1]
try eval(SandBox, Meta.parse(AbstractString(AbstractString(name), "=nothing"))) catch; end
"""
clear_module!(mod::Module)
Recursively sets variables in `mod` to `nothing` so that they're GCed.
!!! warning
`const` variables can't be reassigned, as such they can't be cleared.
"""
function clear_module!(mod::Module)
for name in names(mod; all = true)
name === :eval && continue
try
v = getfield(mod, name)
if v isa Module && v != mod
clear_module!(v)
continue
end
isconst(mod, name) && continue # can't clear constant
Core.eval(mod, :($name = nothing))
catch err
@debug err
end
end
end
function get_figname(report::Report, chunk; fignum = nothing, ext = nothing)
figpath = joinpath(report.cwd, chunk.options[:fig_path])
isdir(figpath) || mkpath(figpath)
ext == nothing && (ext = chunk.options[:fig_ext])
fignum == nothing && (fignum = report.fignum)
isnothing(ext) && (ext = chunk.options[:fig_ext])
isnothing(fignum) && (fignum = report.fignum)
chunkid = (chunk.options[:label] == nothing) ? chunk.number : chunk.options[:label]
full_name = joinpath(report.cwd, chunk.options[:fig_path],
"$(report.basename)_$(chunkid)_$(fignum)$ext")
rel_name = "$(chunk.options[:fig_path])/$(report.basename)_$(chunkid)_$(fignum)$ext" #Relative path is used in output
chunkid = isnothing(chunk.options[:label]) ? chunk.number : chunk.options[:label]
basename = string(report.basename, '_', chunkid, '_', fignum, ext)
full_name = normpath(report.cwd, chunk.options[:fig_path], basename)
rel_name = string(chunk.options[:fig_path], '/', basename) # Relative path is used in output
return full_name, rel_name
end
function get_cwd(doc::WeaveDoc, out_path)
#Set the output directory
if out_path == :doc
cwd = doc.path
elseif out_path == :pwd
cwd = pwd()
else
#If there is no extension, use as path
splitted = splitext(out_path)
if splitted[2] == ""
cwd = expanduser(out_path)
else
cwd = splitdir(expanduser(out_path))[1]
end
end
return cwd
end
"""Get output file name based on out_path"""
function get_outname(out_path::Symbol, doc::WeaveDoc; ext = nothing)
ext == nothing && (ext = doc.format.formatdict[:extension])
outname = "$(doc.cwd)/$(doc.basename).$ext"
end
"""Get output file name based on out_path"""
function get_outname(out_path::AbstractString, doc::WeaveDoc; ext = nothing)
ext == nothing && (ext = doc.format.formatdict[:extension])
splitted = splitext(out_path)
if (splitted[2]) == ""
outname = "$(doc.cwd)/$(doc.basename).$ext"
else
outname = expanduser(out_path)
end
end
function set_rc_params(doc::WeaveDoc, fig_path, fig_ext)
formatdict = doc.format.formatdict
if fig_ext == nothing
doc.chunk_defaults[:fig_ext] = formatdict[: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
return nothing
doc.chunk_defaults[:fig_path] = fig_path
end
function collect_results(chunk::CodeChunk, fmt::ScriptResult)
function collect_results(chunk::CodeChunk)
content = ""
result_no = 1
result_chunks = CodeChunk[ ]
for r = chunk.result
#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
rchunk = CodeChunk(content, chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
content = ""
rchunk.result_no = result_no
result_no *=1
result_chunks = CodeChunk[]
for r in chunk.result
content *= r.code
# Check if there is any output from chunk
if any(!isempty strip, (r.stdout, r.rich_output)) || !isempty(r.figures)
rchunk = CodeChunk(
content,
chunk.number,
chunk.start_line,
chunk.optionstring,
copy(chunk.options),
)
rchunk.figures = r.figures
rchunk.output = r.stdout * r.displayed
rchunk.output = r.stdout
rchunk.rich_output = r.rich_output
push!(result_chunks, rchunk)
content = ""
end
end
if content != ""
startswith(content, "\n") || (content = "\n" * content)
rchunk = CodeChunk(content, chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
if !isempty(content)
rchunk = CodeChunk(
content,
chunk.number,
chunk.start_line,
chunk.optionstring,
copy(chunk.options),
)
push!(result_chunks, rchunk)
end
return result_chunks
end
function collect_results(chunk::CodeChunk, fmt::TermResult)
function collect_term_results(chunk::CodeChunk)
output = ""
prompt = chunk.options[:prompt]
result_no = 1
result_chunks = CodeChunk[ ]
for r = chunk.result
output *= prompt * r.code
output *= r.displayed * r.stdout
result_chunks = CodeChunk[]
for r in chunk.result
output *= string('\n', indent_term_code(prompt, r.code), '\n', r.stdout)
if !isempty(r.figures)
rchunk = CodeChunk("", chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
rchunk = CodeChunk(
"",
chunk.number,
chunk.start_line,
chunk.optionstring,
copy(chunk.options),
)
rchunk.output = output
output = ""
rchunk.figures = r.figures
push!(result_chunks, rchunk)
end
end
if output != ""
rchunk = CodeChunk("", chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
rchunk.output = output
if !isempty(output)
rchunk = CodeChunk(
"",
chunk.number,
chunk.start_line,
chunk.optionstring,
copy(chunk.options),
)
rchunk.output = output
push!(result_chunks, rchunk)
end
return result_chunks
end
function collect_results(chunk::CodeChunk, fmt::CollectResult)
result_no = 1
for r =chunk.result
chunk.output *= r.stdout
function indent_term_code(prompt, code)
prompt_with_space = string(prompt, ' ')
n = length(prompt_with_space)
pads = ' ' ^ n
return map(enumerate(split(code, '\n'))) do (i,line)
isone(i) ? string(prompt_with_space, line) : string(pads, line)
end |> joinlines
end
function collect_hold_results(chunk::CodeChunk)
for r in chunk.result
chunk.output *= r.stdout
chunk.rich_output *= r.rich_output
chunk.figures = [chunk.figures; r.figures]
end
return [chunk]
end
const HEADER_INLINE = Regex("$(HEADER_INLINE_START)(?<code>.+)$(HEADER_INLINE_END)")
replace_header_inline!(doc, report, mod) = _replace_header_inline!(doc, doc.header, report, mod)
function _replace_header_inline!(doc, header, report, mod)
replace!(header) do (k,v)
return k =>
v isa Dict ? _replace_header_inline!(doc, v, report, mod) :
!isa(v, AbstractString) ? v :
replace(v, HEADER_INLINE => s -> begin
code = replace(s, HEADER_INLINE => s"\g<code>")
run_inline_code(code, doc, report, mod)
end)
end
return header
end
function run_inline_code(code, doc, report, mod)
inline = InlineCode(code, 1, :inline)
inline = run_inline(inline, doc, report, mod)
return strip(inline.output, '"')
end

72
src/types.jl Normal file
View File

@ -0,0 +1,72 @@
# TODO: concreate typing
abstract type WeaveChunk end
abstract type Inline end
abstract type WeaveFormat end
mutable struct WeaveDoc
source::AbstractString
basename::AbstractString
path::AbstractString
chunks::Vector{WeaveChunk}
cwd::AbstractString
format::Any
doctype::String
header_script::String
header::Dict
chunk_defaults::Dict{Symbol,Any}
end
struct ChunkOutput
code::String
stdout::String
rich_output::String
figures::Vector{String}
end
mutable struct CodeChunk <: WeaveChunk
content::String
number::Int
start_line::Int
optionstring::String
options::Dict{Symbol,Any}
output::AbstractString
rich_output::AbstractString
figures::Vector{String}
result::Vector{ChunkOutput}
end
function CodeChunk(content, number, start_line, optionstring, options)
return CodeChunk(
string(rstrip(content), '\n'), # normalize end of chunk)
number,
start_line,
optionstring,
options,
"",
"",
AbstractString[],
ChunkOutput[]
)
end
mutable struct DocChunk <: WeaveChunk
content::Vector{Inline}
number::Int
start_line::Int
end
struct InlineText <: Inline
content::String
number::Int
end
mutable struct InlineCode <: Inline
content::String
number::Int
ctype::Symbol
output::String
rich_output::String
figures::Vector{String}
end
InlineCode(content, number, ctype) = InlineCode(content, number, ctype, "", "", String[])

19
src/writer/latex.jl Normal file
View File

@ -0,0 +1,19 @@
function write_doc(docformat::WeaveLaTeX2PDF, doc, rendered, out_path)
cd_back = let d = pwd(); () -> cd(d); end
cd(doc.cwd)
try
tex_path = basename(out_path)
write(tex_path, rendered)
cmds = copy(docformat.latex_cmd)
push!(cmds, tex_path)
cmd = Cmd(cmds)
run(cmd); run(cmd) # XXX: is twice enough for every case ?
catch
@warn "Error converting document to pdf. Try running latex manually"
rethrow()
finally
cd_back()
end
return get_out_path(doc, out_path, "pdf")
end

76
src/writer/pandoc.jl Normal file
View File

@ -0,0 +1,76 @@
function write_doc(docformat::Pandoc2HTML, doc, rendered, out_path)
_, weave_source = splitdir(abspath(doc.source))
weave_version, weave_date = weave_info()
# Header is inserted from displayed plots
header_script = doc.header_script
self_contained = (header_script "") ? [] : "--self-contained"
if haskey(doc.header, "bibliography")
filt = "--filter"
citeproc = "pandoc-citeproc"
else
filt = []
citeproc = []
end
out_path = get_out_path(doc, out_path, "html")
cd_back = let d = pwd(); () -> cd(d); end
cd(dirname(out_path))
try
out = basename(out_path)
highlight_stylesheet = get_highlight_stylesheet(MIME("text/html"), docformat.highlight_theme)
cmd = `pandoc -f markdown+raw_html -s --mathjax=""
$filt $citeproc $(docformat.pandoc_options)
--template $(docformat.template_path)
-H $(docformat.stylesheet_path)
$(self_contained)
-V highlight_stylesheet=$(highlight_stylesheet)
-V weave_version=$(weave_version)
-V weave_date=$(weave_date)
-V weave_source=$(weave_source)
-V headerscript=$(header_script)
-o $(out)`
proc = open(cmd, "r+")
println(proc.in, rendered)
close(proc.in)
proc_output = read(proc.out, String)
catch
rethrow() # TODO: just show error content instead of rethrow the err
finally
cd_back()
end
return out_path
end
function write_doc(docformat::Pandoc2PDF, doc, rendered, out_path)
if haskey(doc.header, "bibliography")
filt = "--filter"
citeproc = "pandoc-citeproc"
else
filt = []
citeproc = []
end
out_path = get_out_path(doc, out_path, "pdf")
cd_back = let d = pwd(); () -> cd(d); end
cd(dirname(out_path))
try
out = basename(out_path)
cmd = `pandoc -f markdown+raw_tex -s --pdf-engine=xelatex --highlight-style=tango
$filt $citeproc $(docformat.pandoc_options)
--include-in-header=$(docformat.header_template)
-V fontsize=12pt -o $(out)`
proc = open(cmd, "r+")
println(proc.in, rendered)
close(proc.in)
proc_output = read(proc.out, String)
catch
rethrow()
finally
cd_back()
end
return out_path
end

11
src/writer/writer.jl Normal file
View File

@ -0,0 +1,11 @@
function write_doc(doc, rendered, out_path)
return write_doc(doc.format, doc, rendered, out_path)
end
function write_doc(::WeaveFormat, doc, rendered, out_path)
write(out_path, rendered)
return out_path
end
include("pandoc.jl")
include("latex.jl")

View File

@ -1,179 +0,0 @@
import JSON
import Mustache
mutable struct NotebookOutput
end
mutable struct MarkdownOutput
end
mutable struct NowebOutput
end
mutable struct ScriptOutput
end
const output_formats = Dict{String, Any}(
"noweb" => NowebOutput(),
"notebook" => NotebookOutput(),
"markdown" => MarkdownOutput(),
"script" => ScriptOutput()
)
"""Autodetect format for converter"""
function detect_outformat(outfile::String)
ext = lowercase(splitext(outfile)[2])
ext == ".jl" && return "script"
ext == ".jmd" && return "markdown"
ext == ".ipynb" && return "notebook"
return "noweb"
end
"""
`convert_doc(infile::AbstractString, outfile::AbstractString; format = nothing)`
Convert Weave documents between different formats
* `infile` = Name of the input document
* `outfile` = Name of the output document
* `format` = Output format (optional). Detected from outfile extension, but can
be set to `"script"`, `"markdown"`, `"notebook"` or `"noweb"`.
"""
function convert_doc(infile::AbstractString, outfile::AbstractString; format = nothing)
doc = read_doc(infile)
if format == nothing
format = detect_outformat(outfile)
end
converted = convert_doc(doc, output_formats[format])
open(outfile, "w") do f
write(f, converted)
end
return nothing
end
"""Convert Weave document to Jupyter notebook format"""
function convert_doc(doc::WeaveDoc, format::NotebookOutput)
nb = Dict()
nb["nbformat"] = 4
nb["nbformat_minor"] = 2
metadata = Dict()
kernelspec = Dict()
kernelspec["language"] = "julia"
kernelspec["name"] = "julia-$(VERSION.major).$(VERSION.minor)"
kernelspec["display_name"] = "Julia $(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
metadata["kernelspec"] = kernelspec
language_info = Dict()
language_info["file_extension"] = ".jl"
language_info["mimetype"] = "application/julia"
language_info["name"]= "julia"
language_info["version"] = "$(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
metadata["language_info"] = language_info
cells = []
ex_count = 1
# Handle header
head_tpl = """
{{#:title}}# {{:title}}{{/:title}}
{{#:author}}### {{{:author}}}{{/:author}}
{{#:date}}### {{{:date}}}{{/:date}}
"""
if isa(doc.chunks[1], DocChunk)
doc.chunks[1] = strip_header(doc.chunks[1])
doc.chunks[1].content[1].content = Mustache.render(head_tpl;
[Pair(Symbol(k), v) for (k,v) in doc.header]...) * doc.chunks[1].content[1].content
end
for chunk in doc.chunks
if isa(chunk, DocChunk)
push!(cells,
Dict("cell_type" => "markdown",
"metadata" => Dict(),
"source" => [strip(join([repr(c) for c in chunk.content], ""))])
)
elseif haskey(chunk.options, :skip) && chunk.options[:skip] == "notebook"
continue
else
push!(cells,
Dict("cell_type" => "code",
"metadata" => Dict(),
"source" => [strip(chunk.content)],
"execution_count" => nothing,
"outputs" => []
))
end
end
nb["cells"] = cells
nb["metadata"] = metadata
json_nb = JSON.json(nb, 2)
return json_nb
end
"""Convert Weave document to Jupyter notebook format"""
function convert_doc(doc::WeaveDoc, format::MarkdownOutput)
output = ""
for chunk in doc.chunks
if isa(chunk, DocChunk)
output *= join([repr(c) for c in chunk.content], "")
else
output *= "\n" * "```julia"
isempty(chunk.optionstring) || (output *= ";" * chunk.optionstring)
output *= "\n" * lstrip(chunk.content)
output *= "```\n"
end
end
return output
end
"""Convert Weave document to noweb format"""
function convert_doc(doc::WeaveDoc, format::NowebOutput)
output = ""
for chunk in doc.chunks
if isa(chunk, DocChunk)
output *= join([repr(c) for c in chunk.content], "")
else
output *= "\n" * "<<"
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
output *= ">>="
output *= "\n" * lstrip(chunk.content)
output *= "@\n"
end
end
return output
end
"""Convert Weave document to script format"""
function convert_doc(doc::WeaveDoc, format::ScriptOutput)
output = ""
for chunk in doc.chunks
if typeof(chunk) == Weave.DocChunk
content = join([repr(c) for c in chunk.content], "")
output *= join(["#' " * s for s in split(content, "\n")], "\n")
else
output *= "\n#+ "
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
output *= "\n\n" * lstrip(chunk.content)
output *= "\n"
end
end
return output
end
function Base.repr(c::InlineText)
return c.content
end
function Base.repr(c::InlineCode)
return "`j $(c.content)`"
end

View File

@ -1,54 +0,0 @@
<!DOCTYPE html>
<HTML lang = "en">
<HEAD>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
{{#:title}}<title>{{:title}}</title>{{/:title}}
{{{ :header_script }}}
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]},
TeX: { equationNumbers: { autoNumber: "AMS" } }
});
</script>
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
{{{ :highlightcss }}}
<style type="text/css">
{{{ :themecss }}}
</style>
</HEAD>
<BODY>
<div class ="container">
<div class = "row">
<div class = "col-md-12 twelve columns">
<div class="title">
{{#:title}}<h1 class="title">{{:title}}</h1>{{/:title}}
{{#:author}}<h5>{{{:author}}}</h5>{{/:author}}
{{#:date}}<h5>{{{:date}}}</h5>{{/:date}}
</div>
{{{ :body }}}
<HR/>
<div class="footer"><p>
Published from <a href="{{{:source}}}">{{{:source}}}</a> using
<a href="http://github.com/mpastell/Weave.jl">Weave.jl</a>
{{:wversion}} on {{:wtime}}.
<p></div>
</div>
</div>
</div>
</BODY>
</HTML>

50
templates/md2html.tpl Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<HTML lang = "en">
<HEAD>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
{{#:title}}<title>{{:title}}</title>{{/:title}}
{{{ :header_script }}}
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]},
TeX: { equationNumbers: { autoNumber: "AMS" } }
});
</script>
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
{{{ :highlight_stylesheet }}}
<style type="text/css">
{{{ :stylesheet }}}
</style>
</HEAD>
<BODY>
<div class ="container">
<div class = "row">
<div class = "col-md-12 twelve columns">
<div class="title">
{{#:title}}<h1 class="title">{{:title}}</h1>{{/:title}}
{{#:author}}<h5>{{{:author}}}</h5>{{/:author}}
{{#:date}}<h5>{{{:date}}}</h5>{{/:date}}
</div>
{{{ :body }}}
<HR/>
<div class="footer">
<p>
Published from <a href="{{{:weave_source}}}">{{{:weave_source}}}</a>
using <a href="http://github.com/JunoLab/Weave.jl">Weave.jl</a> {{:weave_version}} on {{:weave_date}}.
</p>
</div>
</div>
</div>
</div>
</BODY>
</HTML>

View File

@ -7,6 +7,9 @@
\usepackage{graphicx}
\usepackage{microtype}
\usepackage{hyperref}
{{#:tex_deps}}
{{{ :tex_deps }}}
{{/:tex_deps}}
\setlength{\parindent}{0pt}
\setlength{\parskip}{1.2ex}

View File

@ -32,7 +32,7 @@ $for(header-includes)$
$header-includes$
$endfor$
$highlightcss$
$highlight_stylesheet$
$if(highlighting-css)$
<style type="text/css">
@ -85,8 +85,8 @@ $endfor$
<HR/>
<div class="footer"><p>
Published from <a href="$wsource$">$wsource$</a> using
<a href="http://github.com/mpastell/Weave.jl">Weave.jl</a> $wversion$ on $wtime$.
Published from <a href="$source$">$source$</a> using
<a href="http://github.com/mpastell/Weave.jl">Weave.jl</a> $weave_version$ on $weave_date$.
<p></div>
</div>

View File

@ -1,7 +1,4 @@
using Weave
using Test
#Test if running document with and without cache works
# Test if running document with and without cache works
isdir("documents/cache") && rm("documents/cache", recursive = true)
weave("documents/chunk_options.noweb", cache=:all)
result = read("documents/chunk_options.md", String)

View File

@ -1,20 +0,0 @@
using Weave
using Test
cleanup = true
VER = "$(VERSION.major).$(VERSION.minor)"
Weave.push_preexecute_hook(identity)
weave("documents/chunk_options.noweb")
Weave.pop_preexecute_hook(identity)
result = read("documents/chunk_options.md", String)
ref = read("documents/chunk_options_ref.md", String)
@test result == ref
cleanup && rm("documents/chunk_options.md")
tangle("documents/chunk_options.noweb", out_path = "documents/tangle")
result = read("documents/tangle/chunk_options.jl", String)
ref = read("documents/tangle/chunk_options.jl.ref", String)
@test ref == result
cleanup && rm("documents/tangle/chunk_options.jl")

View File

@ -1,18 +0,0 @@
using Weave
using Test
cleanup = true
#Test hold and term options
weave("documents/test_hold.mdw", doctype="pandoc", plotlib="Gadfly")
result = read("documents/test_hold.md", String)
ref = read("documents/test_hold_ref.md", String)
@test result == ref
cleanup && rm("documents/test_hold.md")
#Test setting and restoring chunk options
Weave.weave("documents/default_opts.noweb", doctype = "tex")
result = read("documents/default_opts.tex", String)
ref = read("documents/default_opts_ref.tex", String)
@test result == ref
cleanup && rm("documents/default_opts.tex")

View File

@ -1,80 +0,0 @@
#' % FIR filter design with Julia
#' % Matti Pastell
#' % 21th April 2016
#' # Introduction
#' This an example of a julia script that can be published using
#' [Weave](http://mpastell.github.io/Weave.jl/latest/usage/).
#' The script can be executed normally using Julia
#' or published to HTML or pdf with Weave.
#' Text is written in markdown in lines starting with "`#'` " and code
#' is executed and results are included in the published document.
#' Notice that you don't need to define chunk options, but you can using
#' `#+`. just before code e.g. `#+ term=True, caption='Fancy plots.'`.
#' If you're viewing the published version have a look at the
#' [source](FIR_design.jl) to see the markup.
#' # FIR Filter Design
#' We'll implement lowpass, highpass and ' bandpass FIR filters. If
#' you want to read more about DSP I highly recommend [The Scientist
#' and Engineer's Guide to Digital Signal
#' Processing](http://www.dspguide.com/) which is freely available
#' online.
#' ## Calculating frequency response
#' DSP.jl package doesn't (yet) have a method to calculate the
#' the frequency response of a FIR filter so we define it:
using Gadfly, DSP
function FIRfreqz(b::Array, w = range(0, stop=π, length=1024))
n = length(w)
h = Array{ComplexF32}(n)
sw = 0
for i = 1:n
for j = 1:length(b)
sw += b[j]*exp(-im*w[i])^-j
end
h[i] = sw
sw = 0
end
return h
end
#' ## Design Lowpass FIR filter
#' Designing a lowpass FIR filter is very simple to do with DSP.jl, all you
#' need to do is to define the window length, cut off frequency and the
#' window. We will define a lowpass filter with cut off frequency at 5Hz for a signal
#' sampled at 20 Hz.
#' We will use the Hamming window, which is defined as:
#' $w(n) = \alpha - \beta\cos\frac{2\pi n}{N-1}$, where $\alpha=0.54$ and $\beta=0.46$
fs = 20
f = digitalfilter(Lowpass(5, fs = fs), FIRWindow(hamming(61)))
w = range(0, stop=pi, length=1024)
h = FIRfreqz(f, w)
#' ## Plot the frequency and impulse response
h_db = log10(abs(h))
ws = w/pi*(fs/2)
#' The next code chunk is executed in term mode, see the [script](FIR_design.jl) for syntax.
#+ term=true
plot(y = h_db, x = ws, Geom.line,
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Magnitude (db)"))
#' And again with default options
h_phase = unwrap(-atan(imag(h),real(h)))
plot(y = h_phase, x = ws, Geom.line,
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Phase (radians)"))

View File

@ -1,112 +0,0 @@
% FIR filter design with Julia
% Matti Pastell
% 21th April 2016
# Introduction
This an example of a julia script that can be published using
[Weave](http://mpastell.github.io/Weave.jl/latest/usage/).
The script can be executed normally using Julia
or published to HTML or pdf with Weave.
Text is written in markdown in lines starting with "`#'` " and code
is executed and results are included in the published document.
Notice that you don't need to define chunk options, but you can using
`#+`. just before code e.g. `#+ term=True, caption='Fancy plots.'`.
If you're viewing the published version have a look at the
[source](FIR_design.jl) to see the markup.
# FIR Filter Design
We'll implement lowpass, highpass and ' bandpass FIR filters. If
you want to read more about DSP I highly recommend [The Scientist
and Engineer's Guide to Digital Signal
Processing](http://www.dspguide.com/) which is freely available
online.
## Calculating frequency response
DSP.jl package doesn't (yet) have a method to calculate the
the frequency response of a FIR filter so we define it:
~~~~{.julia}
using Gadfly, DSP
function FIRfreqz(b::Array, w = linspace(0, π, 1024))
n = length(w)
h = Array{Complex64}(n)
sw = 0
for i = 1:n
for j = 1:length(b)
sw += b[j]*exp(-im*w[i])^-j
end
h[i] = sw
sw = 0
end
return h
end
~~~~~~~~~~~~~
## Design Lowpass FIR filter
Designing a lowpass FIR filter is very simple to do with DSP.jl, all you
need to do is to define the window length, cut off frequency and the
window. We will define a lowpass filter with cut off frequency at 5Hz for a signal
sampled at 20 Hz.
We will use the Hamming window, which is defined as:
$w(n) = \alpha - \beta\cos\frac{2\pi n}{N-1}$, where $\alpha=0.54$ and $\beta=0.46$
~~~~{.julia}
fs = 20
f = digitalfilter(Lowpass(5, fs = fs), FIRWindow(hamming(61)))
w = linspace(0, pi, 1024)
h = FIRfreqz(f, w)
~~~~~~~~~~~~~
## Plot the frequency and impulse response
~~~~{.julia}
h_db = log10(abs(h))
ws = w/pi*(fs/2)
~~~~~~~~~~~~~
The next code chunk is executed in term mode, see the [script](FIR_design.jl) for syntax.
~~~~{.julia}
julia> plot(y = h_db, x = ws, Geom.line,
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Magnitude (db)"))
Plot(...)
~~~~~~~~~~~~~
![](figures/FIR_design_4_1.png)\
And again with default options
~~~~{.julia}
h_phase = unwrap(-atan2(imag(h),real(h)))
plot(y = h_phase, x = ws, Geom.line,
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Phase (radians)"))
~~~~~~~~~~~~~
![](figures/FIR_design_5_1.png)\

View File

@ -1,6 +0,0 @@
Functions:
<<>>=
f(x)=x^2
println(f(2))
@

View File

@ -1,13 +0,0 @@
Functions:
~~~~{.julia}
f(x)=x^2
println(f(2))
~~~~~~~~~~~~~
~~~~
4
~~~~

View File

@ -1,30 +0,0 @@
<<>>=
using Gadfly
print(1:10)
plot(x = 1:10)
@
<<>>=
import Weave
Weave.set_chunk_defaults(Dict{Symbol, Any}(
:out_width => "\\0.5linewidth",
:results => "tex"
))
@
<<>>=
print(1:10)
plot(x = 1:10)
@
<<echo = false>>=
Weave.restore_chunk_defaults()
@
<<>>=
print(1:10)
plot(x = 1:10)
@

View File

@ -1,43 +0,0 @@
\begin{juliacode}
using Gadfly
print(1:10)
\end{juliacode}
\begin{juliaout}
1:10
\end{juliaout}
\begin{juliacode}
plot(x = 1:10)
\end{juliacode}
\includegraphics[width=\linewidth]{figures/default_opts_1_1.pdf}
\begin{juliacode}
import Weave
Weave.set_chunk_defaults(Dict{Symbol, Any}(
:out_width => "\\0.5linewidth",
:results => "tex"
))
\end{juliacode}
\begin{juliacode}
print(1:10)
\end{juliacode}
1:10
\begin{juliacode}
plot(x = 1:10)
\end{juliacode}
\includegraphics[width=\0.5linewidth]{figures/default_opts_3_1.pdf}
\begin{juliacode}
print(1:10)
\end{juliacode}
\begin{juliaout}
1:10
\end{juliaout}
\begin{juliacode}
plot(x = 1:10)
\end{juliacode}
\includegraphics[width=\linewidth]{figures/default_opts_5_1.pdf}

View File

@ -1,23 +0,0 @@
---
options :
out_path : gadfly
---
~~~~{.julia}
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
~~~~~~~~~~~~~
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.js.svg){#fig:sin_fun}
![cos(x) function.](figures/gadfly_formats_test_2_1.js.svg)
~~~~{.julia}
plot(x=x, y = cos.(2x), Geom.line)
~~~~~~~~~~~~~
![](figures/gadfly_formats_test_cos2_fun_1.js.svg){width=15cm #fig:cos2_fun}\

View File

@ -1,18 +0,0 @@
````julia
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
````
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.pdf)
![cos(x) function.](figures/gadfly_formats_test_2_1.pdf)
````julia
plot(x=x, y = cos.(2x), Geom.line)
````
![](figures/gadfly_formats_test_cos2_fun_1.pdf)

View File

@ -1,18 +0,0 @@
````julia
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
````
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.png)
![cos(x) function.](figures/gadfly_formats_test_2_1.png)
````julia
plot(x=x, y = cos.(2x), Geom.line)
````
![](figures/gadfly_formats_test_cos2_fun_1.png)

View File

@ -1,23 +0,0 @@
---
options :
out_path : gadfly
---
~~~~{.julia}
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
~~~~~~~~~~~~~
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.png){#fig:sin_fun}
![cos(x) function.](figures/gadfly_formats_test_2_1.png)
~~~~{.julia}
plot(x=x, y = cos.(2x), Geom.line)
~~~~~~~~~~~~~
![](figures/gadfly_formats_test_cos2_fun_1.png){width=15cm #fig:cos2_fun}\

View File

@ -1,18 +0,0 @@
````julia
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
````
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.svg)
![cos(x) function.](figures/gadfly_formats_test_2_1.svg)
````julia
plot(x=x, y = cos.(2x), Geom.line)
````
![](figures/gadfly_formats_test_cos2_fun_1.svg)

View File

@ -1,23 +0,0 @@
\begin{juliacode}
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
\end{juliacode}
\begin{figure}[ht]
\center
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_sin_fun_1.pdf}
\caption{sin(x) function.}
\label{fig:sin_fun}
\end{figure}
\begin{figure}[htpb]
\center
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_2_1.pdf}
\caption{cos(x) function.}
\end{figure}
\begin{juliacode}
plot(x=x, y = cos.(2x), Geom.line)
\end{juliacode}
\includegraphics[width=15cm]{figures/gadfly_formats_test_cos2_fun_1.pdf}

View File

@ -1,23 +0,0 @@
\begin{juliacode}
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
\end{juliacode}
\begin{figure}[ht]
\center
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_sin_fun_1.png}
\caption{sin(x) function.}
\label{fig:sin_fun}
\end{figure}
\begin{figure}[htpb]
\center
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_2_1.png}
\caption{cos(x) function.}
\end{figure}
\begin{juliacode}
plot(x=x, y = cos.(2x), Geom.line)
\end{juliacode}
\includegraphics[width=15cm]{figures/gadfly_formats_test_cos2_fun_1.png}

View File

@ -1,23 +0,0 @@
\begin{juliacode}
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
\end{juliacode}
\begin{figure}[ht]
\center
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_sin_fun_1.ps}
\caption{sin(x) function.}
\label{fig:sin_fun}
\end{figure}
\begin{figure}[htpb]
\center
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_2_1.ps}
\caption{cos(x) function.}
\end{figure}
\begin{juliacode}
plot(x=x, y = cos.(2x), Geom.line)
\end{juliacode}
\includegraphics[width=15cm]{figures/gadfly_formats_test_cos2_fun_1.ps}

View File

@ -1,23 +0,0 @@
\begin{juliacode}
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
\end{juliacode}
\begin{figure}[ht]
\center
\resizebox{\linewidth}{!}{\input{figures/gadfly_formats_test_sin_fun_1.tex}}
\caption{sin(x) function.}
\label{fig:sin_fun}
\end{figure}
\begin{figure}[htpb]
\center
\resizebox{\linewidth}{!}{\input{figures/gadfly_formats_test_2_1.tex}}
\caption{cos(x) function.}
\end{figure}
\begin{juliacode}
plot(x=x, y = cos.(2x), Geom.line)
\end{juliacode}
\resizebox{15cm}{!}{\input{figures/gadfly_formats_test_cos2_fun_1.tex}}

View File

@ -1,19 +0,0 @@
---
options :
out_path : gadfly
---
<<fig_cap="sin(x) function."; label="sin_fun"; fig_pos="ht">>=
using Gadfly
x = range(0, stop =2π, step=0.05)
plot(x=x, y = sin.(x), Geom.line)
@
<<echo=false; fig_cap="cos(x) function."; dpi=200>>=
plot(x=x, y = cos.(x), Geom.line)
@
<<label="cos2_fun"; out_width="15cm">>=
plot(x=x, y = cos.(2x), Geom.line)
@

View File

@ -1,12 +0,0 @@
# Gadfly
```{julia;fig_ext=".svg";dpi=300}
using Gadfly
x = collect(range(0, stop=2π, length=200))
plot(
layer(x=x, y = sin.(x), Geom.line),
layer(x=x, y = cos.(x), Geom.line, Theme(default_color=colorant"red")),
Guide.manual_color_key("Legend", ["sin", "cos"], ["deepskyblue", "red"])
)
```

View File

@ -1,12 +0,0 @@
---
options:
md2html :
out_path : html
echo : false
out_width : 30%
---
```julia
repeat("🐐", 10)
```

View File

@ -1,27 +0,0 @@
---
title : Someheader
---
```julia
module Test1
x = 10
y = 20
function testing(x)
return x
end
end
```
Some random text in between
```julia
module Test2
d = Dict("a" => "α")
doc = read("header_test.jmd", String)
end
```

View File

@ -1,23 +0,0 @@
<div class="Random plot">
<p>Some inline output</p>
<pre class='hljl'>
<span class='hljl-nf'>println</span><span class='hljl-p'>(</span><span class='hljl-s'>&quot;Testing output&quot;</span><span class='hljl-p'>)</span>
</pre>
<pre class="output">
Testing output
</pre>
</div>

View File

@ -1,23 +0,0 @@
\begin{frame}[fragile]
\frametitle{Random plot}
Some inline output
\begin{lstlisting}
(*@\HLJLnf{println}@*)(*@\HLJLp{(}@*)(*@\HLJLs{"{}Testing}@*) (*@\HLJLs{output"{}}@*)(*@\HLJLp{)}@*)
\end{lstlisting}
\begin{lstlisting}
Testing output
\end{lstlisting}
\end{frame}

View File

@ -1,17 +0,0 @@
Here's some text
And here's some code
```julia
x = 1
y = 2
@show x + y
```
Here's some more complicated code
```julia
@code_native +(1.0, π)
using Test
@test 1 == 1
```

View File

@ -1,31 +0,0 @@
---
title : A minimal beamer example using Weave markdown
author : Matti Pastell
options :
out_path : inline
---
```julia; echo=false
struct Begin
text
title
end
struct End
text
end
Base.show(io::IO, m::MIME"text/latex", b::Begin) = write(io, "\\begin{$(b.text)}[fragile]\n\\frametitle{$(b.title)}\n")
Base.show(io::IO, m::MIME"text/latex", e::End) = write(io, "\\end{$(e.text)}")
Base.show(io::IO, m::MIME"text/html", b::Begin) = write(io, "<div class=\"$(b.title)\">\n")
Base.show(io::IO, m::MIME"text/html", e::End) = write(io, "</div>")
```
! Begin("frame", "Random plot")
Some inline `j print("output")`
```julia
println("Testing output")
```
! End("frame")

View File

@ -1,31 +0,0 @@
```julia
display("text/markdown",
"""
### Small markdown sample
**Hello** from `code` block.
""")
```
```julia
struct Dummy
s::String
end
function Base.show(io::IO, m::MIME"text/markdown", d::Dummy)
print(io, d.s)
end
Dummy("""
* one
* two
* three
""")
```

View File

@ -1,96 +0,0 @@
````julia
import Base
function Base.show(io::IO, m::MIME"text/html", x::Array)
print(io, "<table>")
for i in 1:size(x,1)
print(io, "<tr>")
[print(io, "<td>$r</td>") for r in x[i,:]]
print(io, "</tr>")
end
print(io, "</table>")
end
#This isn't valid latex, doesn't matter for the test
function Base.show(io::IO, m::MIME"text/latex", x::Array)
println(io, "\\begin{tabular}")
for i in 1:size(x,1)
[print(io, "$r & ") for r in x[i,:]]
print(io, "\\\\")
println(io, " \\hline")
end
print(io, "\\end{tabular")
end
#This isn't valid markdown, doesn't matter for the test
function Base.show(io::IO, m::MIME"text/markdown", x::Array)
println(io, "-----")
for i in 1:size(x,1)
print(io, "| ")
[print(io, "$r | ") for r in x[i,:]]
println(io, "")
end
print(io, "-----")
end
x = [collect(1:3) collect(1:3)]
ca = collect('a':'d')
ca
````
-----
| a |
| b |
| c |
| d |
-----
````julia
display(ca)
display(x)
````
-----
| a |
| b |
| c |
| d |
-----
-----
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
-----
````julia
julia> x
3×2 Array{Int64,2}:
1 1
2 2
3 3
julia> ca
4-element Array{Char,1}:
'a'
'b'
'c'
'd'
````
````julia
using Markdown
m = Markdown.parse("**Some Markdown**")
m
````
**Some Markdown**

View File

@ -1,84 +0,0 @@
<pre class='hljl'>
<span class='hljl-k'>import</span><span class='hljl-t'> </span><span class='hljl-n'>Base</span><span class='hljl-t'>
</span><span class='hljl-k'>function</span><span class='hljl-t'> </span><span class='hljl-n'>Base</span><span class='hljl-oB'>.</span><span class='hljl-nf'>show</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-oB'>::</span><span class='hljl-n'>IO</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>m</span><span class='hljl-oB'>::</span><span class='hljl-so'>MIME&quot;text/html&quot;</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>x</span><span class='hljl-oB'>::</span><span class='hljl-n'>Array</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;&lt;table&gt;&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>i</span><span class='hljl-t'> </span><span class='hljl-kp'>in</span><span class='hljl-t'> </span><span class='hljl-ni'>1</span><span class='hljl-oB'>:</span><span class='hljl-nf'>size</span><span class='hljl-p'>(</span><span class='hljl-n'>x</span><span class='hljl-p'>,</span><span class='hljl-ni'>1</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;&lt;tr&gt;&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-p'>[</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;&lt;td&gt;</span><span class='hljl-si'>$r</span><span class='hljl-s'>&lt;/td&gt;&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'> </span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>r</span><span class='hljl-t'> </span><span class='hljl-kp'>in</span><span class='hljl-t'> </span><span class='hljl-n'>x</span><span class='hljl-p'>[</span><span class='hljl-n'>i</span><span class='hljl-p'>,</span><span class='hljl-oB'>:</span><span class='hljl-p'>]]</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;&lt;/tr&gt;&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;&lt;/table&gt;&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-cs'>#This isn&#39;t valid latex, doesn&#39;t matter for the test</span><span class='hljl-t'>
</span><span class='hljl-k'>function</span><span class='hljl-t'> </span><span class='hljl-n'>Base</span><span class='hljl-oB'>.</span><span class='hljl-nf'>show</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-oB'>::</span><span class='hljl-n'>IO</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>m</span><span class='hljl-oB'>::</span><span class='hljl-so'>MIME&quot;text/latex&quot;</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>x</span><span class='hljl-oB'>::</span><span class='hljl-n'>Array</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-nf'>println</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;</span><span class='hljl-se'>\\</span><span class='hljl-s'>begin{tabular}&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>i</span><span class='hljl-t'> </span><span class='hljl-kp'>in</span><span class='hljl-t'> </span><span class='hljl-ni'>1</span><span class='hljl-oB'>:</span><span class='hljl-nf'>size</span><span class='hljl-p'>(</span><span class='hljl-n'>x</span><span class='hljl-p'>,</span><span class='hljl-ni'>1</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-p'>[</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;</span><span class='hljl-si'>$r</span><span class='hljl-s'> &amp; &quot;</span><span class='hljl-p'>)</span><span class='hljl-t'> </span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>r</span><span class='hljl-t'> </span><span class='hljl-kp'>in</span><span class='hljl-t'> </span><span class='hljl-n'>x</span><span class='hljl-p'>[</span><span class='hljl-n'>i</span><span class='hljl-p'>,</span><span class='hljl-oB'>:</span><span class='hljl-p'>]]</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;</span><span class='hljl-se'>\\\\</span><span class='hljl-s'>&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-nf'>println</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot; </span><span class='hljl-se'>\\</span><span class='hljl-s'>hline&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;</span><span class='hljl-se'>\\</span><span class='hljl-s'>end{tabular&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-cs'>#This isn&#39;t valid markdown, doesn&#39;t matter for the test</span><span class='hljl-t'>
</span><span class='hljl-k'>function</span><span class='hljl-t'> </span><span class='hljl-n'>Base</span><span class='hljl-oB'>.</span><span class='hljl-nf'>show</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-oB'>::</span><span class='hljl-n'>IO</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>m</span><span class='hljl-oB'>::</span><span class='hljl-so'>MIME&quot;text/markdown&quot;</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>x</span><span class='hljl-oB'>::</span><span class='hljl-n'>Array</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-nf'>println</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;-----&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>i</span><span class='hljl-t'> </span><span class='hljl-kp'>in</span><span class='hljl-t'> </span><span class='hljl-ni'>1</span><span class='hljl-oB'>:</span><span class='hljl-nf'>size</span><span class='hljl-p'>(</span><span class='hljl-n'>x</span><span class='hljl-p'>,</span><span class='hljl-ni'>1</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;| &quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-p'>[</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;</span><span class='hljl-si'>$r</span><span class='hljl-s'> | &quot;</span><span class='hljl-p'>)</span><span class='hljl-t'> </span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>r</span><span class='hljl-t'> </span><span class='hljl-kp'>in</span><span class='hljl-t'> </span><span class='hljl-n'>x</span><span class='hljl-p'>[</span><span class='hljl-n'>i</span><span class='hljl-p'>,</span><span class='hljl-oB'>:</span><span class='hljl-p'>]]</span><span class='hljl-t'>
</span><span class='hljl-nf'>println</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-nf'>print</span><span class='hljl-p'>(</span><span class='hljl-n'>io</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;-----&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-n'>x</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-p'>[</span><span class='hljl-nf'>collect</span><span class='hljl-p'>(</span><span class='hljl-ni'>1</span><span class='hljl-oB'>:</span><span class='hljl-ni'>3</span><span class='hljl-p'>)</span><span class='hljl-t'> </span><span class='hljl-nf'>collect</span><span class='hljl-p'>(</span><span class='hljl-ni'>1</span><span class='hljl-oB'>:</span><span class='hljl-ni'>3</span><span class='hljl-p'>)]</span><span class='hljl-t'>
</span><span class='hljl-n'>ca</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>collect</span><span class='hljl-p'>(</span><span class='hljl-sc'>&#39;a&#39;</span><span class='hljl-oB'>:</span><span class='hljl-sc'>&#39;d&#39;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-n'>ca</span>
</pre>
<table><tr><td>a</td></tr><tr><td>b</td></tr><tr><td>c</td></tr><tr><td>d</td></tr></table>
<pre class='hljl'>
<span class='hljl-nf'>display</span><span class='hljl-p'>(</span><span class='hljl-n'>ca</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-nf'>display</span><span class='hljl-p'>(</span><span class='hljl-n'>x</span><span class='hljl-p'>)</span>
</pre>
<table><tr><td>a</td></tr><tr><td>b</td></tr><tr><td>c</td></tr><tr><td>d</td></tr></table>
<table><tr><td>1</td><td>1</td></tr><tr><td>2</td><td>2</td></tr><tr><td>3</td><td>3</td></tr></table>
<pre class='hljl'>
<span class='hljl-nB'>julia&gt; </span><span class='hljl-n'>x</span><span class='hljl-t'>
3×2 Array{Int64,2}:
1 1
2 2
3 3
</span><span class='hljl-nB'>julia&gt; </span><span class='hljl-n'>ca</span><span class='hljl-t'>
4-element Array{Char,1}:
&#39;a&#39;
&#39;b&#39;
&#39;c&#39;
&#39;d&#39;</span>
</pre>
<pre class='hljl'>
<span class='hljl-k'>using</span><span class='hljl-t'> </span><span class='hljl-n'>Markdown</span><span class='hljl-t'>
</span><span class='hljl-n'>m</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-n'>Markdown</span><span class='hljl-oB'>.</span><span class='hljl-nf'>parse</span><span class='hljl-p'>(</span><span class='hljl-s'>&quot;**Some Markdown**&quot;</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-n'>m</span>
</pre>
<div class="markdown"><p><strong>Some Markdown</strong></p>
</div>

View File

@ -1,96 +0,0 @@
~~~~{.julia}
import Base
function Base.show(io::IO, m::MIME"text/html", x::Array)
print(io, "<table>")
for i in 1:size(x,1)
print(io, "<tr>")
[print(io, "<td>$r</td>") for r in x[i,:]]
print(io, "</tr>")
end
print(io, "</table>")
end
#This isn't valid latex, doesn't matter for the test
function Base.show(io::IO, m::MIME"text/latex", x::Array)
println(io, "\\begin{tabular}")
for i in 1:size(x,1)
[print(io, "$r & ") for r in x[i,:]]
print(io, "\\\\")
println(io, " \\hline")
end
print(io, "\\end{tabular")
end
#This isn't valid markdown, doesn't matter for the test
function Base.show(io::IO, m::MIME"text/markdown", x::Array)
println(io, "-----")
for i in 1:size(x,1)
print(io, "| ")
[print(io, "$r | ") for r in x[i,:]]
println(io, "")
end
print(io, "-----")
end
x = [collect(1:3) collect(1:3)]
ca = collect('a':'d')
ca
~~~~~~~~~~~~~
-----
| a |
| b |
| c |
| d |
-----
~~~~{.julia}
display(ca)
display(x)
~~~~~~~~~~~~~
-----
| a |
| b |
| c |
| d |
-----
-----
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
-----
~~~~{.julia}
julia> x
3×2 Array{Int64,2}:
1 1
2 2
3 3
julia> ca
4-element Array{Char,1}:
'a'
'b'
'c'
'd'
~~~~~~~~~~~~~
~~~~{.julia}
using Markdown
m = Markdown.parse("**Some Markdown**")
m
~~~~~~~~~~~~~
**Some Markdown**

View File

@ -1,89 +0,0 @@
\begin{juliacode}
import Base
function Base.show(io::IO, m::MIME"text/html", x::Array)
print(io, "<table>")
for i in 1:size(x,1)
print(io, "<tr>")
[print(io, "<td>$r</td>") for r in x[i,:]]
print(io, "</tr>")
end
print(io, "</table>")
end
#This isn't valid latex, doesn't matter for the test
function Base.show(io::IO, m::MIME"text/latex", x::Array)
println(io, "\\begin{tabular}")
for i in 1:size(x,1)
[print(io, "$r & ") for r in x[i,:]]
print(io, "\\\\")
println(io, " \\hline")
end
print(io, "\\end{tabular")
end
#This isn't valid markdown, doesn't matter for the test
function Base.show(io::IO, m::MIME"text/markdown", x::Array)
println(io, "-----")
for i in 1:size(x,1)
print(io, "| ")
[print(io, "$r | ") for r in x[i,:]]
println(io, "")
end
print(io, "-----")
end
x = [collect(1:3) collect(1:3)]
ca = collect('a':'d')
ca
\end{juliacode}
\begin{tabular}
a & \\ \hline
b & \\ \hline
c & \\ \hline
d & \\ \hline
\end{tabular
\begin{juliacode}
display(ca)
display(x)
\end{juliacode}
\begin{tabular}
a & \\ \hline
b & \\ \hline
c & \\ \hline
d & \\ \hline
\end{tabular
\begin{tabular}
1 & 1 & \\ \hline
2 & 2 & \\ \hline
3 & 3 & \\ \hline
\end{tabular
\begin{juliaterm}
julia> x
3×2 Array{Int64,2}:
1 1
2 2
3 3
julia> ca
4-element Array{Char,1}:
'a'
'b'
'c'
'd'
\end{juliaterm}
\begin{juliacode}
using Markdown
m = Markdown.parse("**Some Markdown**")
m
\end{juliacode}
\textbf{Some Markdown}

View File

@ -1,56 +0,0 @@
[source,julia]
--------------------------------------
using Gadfly
x = linspace(0, 2π, 200)
plot(x=x, y = sin(x), Geom.line)
--------------------------------------
image::figures/gadfly_formats_test_sin_fun_1.png[width=600,title="sin(x) function."]
image::figures/gadfly_formats_test_2_1.png[width=600,title="cos(x) function."]
image::figures/gadfly_formats_test_cos2_fun_1.png[width=600]
[source,julia]
--------------------------------------
julia> x = linspace(0, 2π, 200)
200-element LinSpace{Float64}:
0.0,0.0315738,0.0631476,0.0947214,0.126295,…,6.18846,6.22004,6.25161,6.28319
julia> plot(x=x, y = sin(x), Geom.line)
Plot(...)
--------------------------------------
image::figures/gadfly_formats_test_4_1.png[width=600]
[source,julia]
--------------------------------------
julia> y = 20
20
julia> plot(x=x, y = cos(x), Geom.line)
Plot(...)
--------------------------------------
image::figures/gadfly_formats_test_4_2.png[width=600]
[source,julia]
--------------------------------------
x = linspace(0, 2π, 200)
plot(x=x, y = sin(x), Geom.line)
--------------------------------------
image::figures/gadfly_formats_test_5_1.png[width=15cm]
[source,julia]
--------------------------------------
y = 20
plot(x=x, y = cos(x), Geom.line)
--------------------------------------
image::figures/gadfly_formats_test_5_2.png[width=15cm]

Some files were not shown because too many files have changed in this diff Show More