mirror of https://github.com/mpastell/Weave.jl
Compare commits
193 Commits
Author | SHA1 | Date |
---|---|---|
Sebastian Pfitzner | 77793c775c | |
Sheehan Olver | ad0885ce00 | |
Sebastian Pfitzner | e10aaefd94 | |
Sebastian Pfitzner | 8ad4e876d3 | |
Sebastian Pfitzner | af2a6e14c9 | |
Sebastian Pfitzner | 20aaefec0a | |
Gerhard Aigner | 2a78676d41 | |
Gerhard Aigner | 59332c1768 | |
Sebastian Pfitzner | db28a69d94 | |
Sheehan Olver | 0b96591f39 | |
Sebastian Pfitzner | a38cec95db | |
Sebastian Pfitzner | 562f8e4ab3 | |
Sebastian Pfitzner | 9f666b3bb5 | |
KristofferC | a63577f69c | |
Xing Shi Cai | 7e0f5641c2 | |
Nicholas W. M. Ritchie | b022a54458 | |
Nicholas W. M. Ritchie | b669a14038 | |
Sebastian Pfitzner | b7941c2811 | |
ExpandingMan | d40e95a4bb | |
xgdgsc | df47ea191f | |
Sebastian Pfitzner | 381de22c7d | |
github-actions[bot] | 06b259a7b0 | |
Sebastian Pfitzner | 749c0c262c | |
Sebastian Pfitzner | 696db1d82b | |
Mike | d4c65729e4 | |
Mike | 1dfb8d76d6 | |
Sebastian Pfitzner | 48c99c791f | |
Sebastian Pfitzner | ec3f464c37 | |
Mike | 4c60bd8d64 | |
Sebastian Pfitzner | e1d31c2ef6 | |
Shuhei Kadowaki | 99916dd70c | |
Sebastian Pfitzner | 6b6f82bed4 | |
Shuhei Kadowaki | b1de7efede | |
Nathan Hattersley | 849cc20e88 | |
Shuhei Kadowaki | 10de1057a3 | |
Shuhei Kadowaki | e753f70f7a | |
PGunnink | 8dc0441b90 | |
Shuhei Kadowaki | c9fc740d72 | |
Shuhei Kadowaki | cc5913e812 | |
JonasIsensee | e02d5ce2fd | |
Shuhei Kadowaki | b583ac2e40 | |
Shuhei Kadowaki | 955675d89a | |
Shuhei Kadowaki | 196d4ca7ce | |
Shuhei Kadowaki | d3a7f2aea7 | |
Shuhei Kadowaki | 7d361bb40d | |
Shuhei Kadowaki | e927495a62 | |
Shuhei Kadowaki | 78befc61b5 | |
Shuhei Kadowaki | c24a262135 | |
Shuhei Kadowaki | 3e8200c2f8 | |
Shuhei Kadowaki | 8f23084471 | |
Shuhei Kadowaki | a1830e0502 | |
Shuhei Kadowaki | 0e662ecdec | |
Fredrik Bagge Carlson | fa71830479 | |
Shuhei Kadowaki | 21d7fbdbea | |
Shuhei Kadowaki | fe3711074b | |
Tor Erlend Fjelde | 766847ec65 | |
Shuhei Kadowaki | 46a0f8bff4 | |
Oscar Dowson | 51f905ca83 | |
Sebastian Pfitzner | b5ba227e75 | |
Sebastian Pfitzner | 74768a7e0f | |
Jonas Isensee | 90d8c8430f | |
Jonas Isensee | a61ade7778 | |
Jonas Isensee | 8ac94989f1 | |
Jonas Isensee | 191282c1e5 | |
Shuhei Kadowaki | d8eca00fd8 | |
Shuhei Kadowaki | 957d12e751 | |
Shuhei Kadowaki | 82c7c2a8c6 | |
Shuhei Kadowaki | ba5bc9ca08 | |
Shuhei Kadowaki | 5f0d9d4627 | |
Shuhei Kadowaki | 676ecc64f9 | |
Shuhei Kadowaki | 2a509d8f96 | |
Shuhei Kadowaki | 9b2a1228cd | |
Shuhei Kadowaki | 785768c728 | |
Shuhei Kadowaki | 7e9c4fb99d | |
Shuhei Kadowaki | 29546b7716 | |
Shuhei Kadowaki | db5308b286 | |
Shuhei Kadowaki | 174585e504 | |
Shuhei Kadowaki | 8206ca2d14 | |
Shuhei Kadowaki | 092adb6805 | |
Shuhei Kadowaki | 872f7c7153 | |
Shuhei Kadowaki | 5ae1fd5cf1 | |
Shuhei Kadowaki | bd447ec8e3 | |
Jonas Isensee | 3dfe817584 | |
Jonas Isensee | 12e148af18 | |
Shuhei Kadowaki | 03079a5dac | |
Shuhei Kadowaki | e179bd098e | |
Shuhei Kadowaki | 4a96f2c19a | |
Shuhei Kadowaki | 7955308a0a | |
Shuhei Kadowaki | 21835644a0 | |
Shuhei Kadowaki | 5a585f845a | |
Shuhei Kadowaki | f077609798 | |
Shuhei Kadowaki | 46a0da597d | |
Shuhei Kadowaki | 2070610a58 | |
Shuhei Kadowaki | 7d6fddc749 | |
Shuhei Kadowaki | dadce5110c | |
Shuhei Kadowaki | 5d3dd15733 | |
Shuhei Kadowaki | 608bb3df4a | |
Shuhei Kadowaki | b569740915 | |
Shuhei Kadowaki | 972869da47 | |
Shuhei Kadowaki | e0a9d044cd | |
Shuhei Kadowaki | 912387c331 | |
Jonas Isensee | 1135c5ddfa | |
Shuhei Kadowaki | c1bc2fd5c5 | |
Shuhei Kadowaki | d586c24792 | |
Shuhei Kadowaki | d468912332 | |
Shuhei Kadowaki | 753afe24d7 | |
Shuhei Kadowaki | c0e7e66ec3 | |
Shuhei Kadowaki | fd07d2db3f | |
Shuhei Kadowaki | 8d95e159e2 | |
Shuhei Kadowaki | 9fac56f681 | |
Shuhei Kadowaki | b709ce8aef | |
Shuhei Kadowaki | 4a89b04759 | |
Shuhei Kadowaki | ec986b387b | |
Jonas Isensee | 5c853150c8 | |
Shuhei Kadowaki | f8b1c5104b | |
Shuhei Kadowaki | d88675d521 | |
Shuhei Kadowaki | e52c30f72e | |
Shuhei Kadowaki | 66c33e6679 | |
Shuhei Kadowaki | cdd653e028 | |
Shuhei Kadowaki | 8515c0dcde | |
Shuhei Kadowaki | 3a7cb360af | |
Shuhei Kadowaki | c7b566aaaa | |
Jonas Isensee | 630ac466e7 | |
Shuhei Kadowaki | 3e6cda8950 | |
Shuhei Kadowaki | f1d8838bc5 | |
Shuhei Kadowaki | 3faa8e2d95 | |
Shuhei Kadowaki | 3ddb1375eb | |
Shuhei Kadowaki | 73bf7fe77f | |
Shuhei Kadowaki | 533667b9ad | |
Shuhei Kadowaki | aa7fd311d8 | |
Shuhei Kadowaki | 0760591021 | |
Shuhei Kadowaki | 04b24ea83b | |
Shuhei Kadowaki | 4b12f3da99 | |
Shuhei Kadowaki | c6b23d4541 | |
Shuhei Kadowaki | ae48729cff | |
Shuhei Kadowaki | 19b4a7974f | |
Shuhei Kadowaki | 0bdab33630 | |
Shuhei Kadowaki | 55d2c975cd | |
Shuhei Kadowaki | ae0dc70ffa | |
Jonas Isensee | 543f99a915 | |
Jonas Isensee | b5477d27ff | |
Jonas Isensee | 9875bc10f7 | |
Jonas Isensee | 45adb8992f | |
Jonas Isensee | 3eba5de7f4 | |
Jonas Isensee | 62d56846f4 | |
Jonas Isensee | 770496b3af | |
Jonas Isensee | 6e99822905 | |
Jonas Isensee | 119b3332aa | |
Shuhei Kadowaki | 9ccf3a2c5e | |
Shuhei Kadowaki | db89118b4c | |
Shuhei Kadowaki | e7637de643 | |
Shuhei Kadowaki | e0e9ae8753 | |
Shuhei Kadowaki | 5b959a972c | |
Shuhei Kadowaki | 788f926067 | |
Fredrik Bagge Carlson | c87782f451 | |
Shuhei Kadowaki | 96de887308 | |
Shuhei Kadowaki | aa63b20e7c | |
Shuhei Kadowaki | cc936f5377 | |
Shuhei Kadowaki | f4ed10b625 | |
Shuhei Kadowaki | 2fdd09b585 | |
Jonas Isensee | e20042848d | |
Shuhei Kadowaki | 1e9ba19db4 | |
Shuhei Kadowaki | 14b56f1667 | |
Shuhei Kadowaki | 227ab2cbf8 | |
Shuhei Kadowaki | 84e91104d5 | |
Shuhei Kadowaki | 44ed8788d5 | |
Shuhei Kadowaki | 022bb216eb | |
Shuhei Kadowaki | e43a2843af | |
Shuhei Kadowaki | bb4ebb105e | |
Shuhei Kadowaki | b0db8b991c | |
Shuhei Kadowaki | dd0c51b6e5 | |
Shuhei Kadowaki | 3d4f04902c | |
Shuhei Kadowaki | e9c9274896 | |
Shuhei Kadowaki | 542f3e3225 | |
Shuhei Kadowaki | 976d822f58 | |
Shuhei Kadowaki | 819079c0f6 | |
Shuhei Kadowaki | b62a744dfe | |
Shuhei Kadowaki | eca4ed2559 | |
Shuhei Kadowaki | 9b55d7e924 | |
Shuhei Kadowaki | 0fc915b748 | |
Shuhei Kadowaki | 39d3d8d91c | |
Shuhei Kadowaki | 125d73982e | |
Shuhei Kadowaki | 0bc0d3b510 | |
Shuhei Kadowaki | b8b9b095b7 | |
Shuhei Kadowaki | 48adeff932 | |
Shuhei Kadowaki | a7de8f5f58 | |
Shuhei Kadowaki | 60fc450c88 | |
Shuhei Kadowaki | 1fb40645ed | |
Shuhei Kadowaki | 9ca328f468 | |
Shuhei Kadowaki | d84504267b | |
Shuhei Kadowaki | 29ff436a00 | |
Shuhei Kadowaki | 3c76b804dc | |
Shuhei Kadowaki | f71a491847 |
|
@ -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 }}
|
|
@ -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
|
||||
|
|
16
.travis.yml
16
.travis.yml
|
@ -1,23 +1,9 @@
|
|||
language: julia
|
||||
|
||||
julia:
|
||||
- 1 # current stable
|
||||
- 1.0 # lts
|
||||
- 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: nightly
|
||||
include:
|
||||
- stage: "Documentation"
|
||||
julia: 1
|
||||
julia: 1.5
|
||||
os: linux
|
||||
script:
|
||||
- julia --project=doc/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
|
||||
|
|
15
NEWS.md
15
NEWS.md
|
@ -1,6 +1,19 @@
|
|||
## Release notes for Weave.jl
|
||||
|
||||
### v0.10 - 2020/05/18
|
||||
### v0.10.6 – 2020/10/03
|
||||
|
||||
improvements:
|
||||
- cleaned up chunk rendering (removed unnecessary extra newlines): #401
|
||||
- `WEAVE_ARGS` now can take arbitrary objects: https://github.com/JunoLab/Weave.jl/commit/c24a2621359b5d0af1bb6825f488e58cc11b8a9e
|
||||
- improved docs: #397 by @baggepinnen
|
||||
|
||||
bug fixes
|
||||
- fixed #398: #399
|
||||
- removed unnecessary quote for markdown output: https://github.com/JunoLab/Weave.jl/commit/a1830e05029f33195627ec5dedbacb30af23947e
|
||||
- fixed #386: #396 by @torfjelde
|
||||
|
||||
|
||||
### v0.10 – 2020/05/18
|
||||
|
||||
improvements:
|
||||
- `weave` is now integrated with Juno's progress bar; just call `weave` function inside Juno or use `julia-client: weave-to-html(pdf)` command (#331)
|
||||
|
|
13
Project.toml
13
Project.toml
|
@ -1,6 +1,6 @@
|
|||
name = "Weave"
|
||||
uuid = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"
|
||||
version = "0.10.2"
|
||||
version = "0.10.12"
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
|
@ -12,27 +12,26 @@ Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
|
|||
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
|
||||
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
|
||||
RelocatableFolders = "05181044-ff0b-4ac5-8273-598c1e38db00"
|
||||
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
|
||||
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
|
||||
|
||||
[compat]
|
||||
Highlights = "0.3.1, 0.4"
|
||||
Highlights = "0.3.1, 0.4, 0.5"
|
||||
JSON = "0.21"
|
||||
Mustache = "0.4.1, 0.5, 1"
|
||||
Plots = "0.28, 0.29, 1.0"
|
||||
RelocatableFolders = "0.1,0.2,0.3,1"
|
||||
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 = ["Cairo", "Conda", "DataFrames", "Gadfly", "IJulia", "Plots", "Test"]
|
||||
test = ["DataFrames", "Test"]
|
||||
|
|
11
README.md
11
README.md
|
@ -1,12 +1,12 @@
|
|||
# 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.
|
||||
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/),
|
||||
|
@ -97,3 +97,8 @@ Thanks for the important additions, fixes and comments.
|
|||
|
||||
- [DiffEqTutorials.jl](https://github.com/JuliaDiffEq/DiffEqTutorials.jl) uses Weave to output tutorials (`.jmd` documents) to html, pdf and Jupyter notebooks.
|
||||
- [TuringTutorials](https://github.com/TuringLang/TuringTutorials) uses Weave to convert notebooks to html.
|
||||
|
||||
## Related packages
|
||||
|
||||
- [Literate.jl](https://github.com/fredrikekre/Literate.jl) can be used to generate Markdown and Jupyter notebooks directly from Julia source files with markdown in comments.
|
||||
- [Quarto](https://quarto.org) can generate Jupyter notebooks, HTML, or PDF directly from a Markdown format containing Julia code blocks, and also works with R and Python.
|
||||
|
|
|
@ -14,8 +14,8 @@ makedocs(
|
|||
"getting_started.md",
|
||||
"usage.md",
|
||||
"publish.md",
|
||||
"header.md",
|
||||
"chunk_options.md",
|
||||
"header.md",
|
||||
"notebooks.md",
|
||||
"function_index.md",
|
||||
],
|
||||
|
|
|
@ -1,43 +1,66 @@
|
|||
# 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:
|
||||
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).
|
||||
|
||||
|
||||
## Options for Code
|
||||
## Syntax
|
||||
|
||||
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 won’t 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.
|
||||
- `eval = true`: Evaluate the code chunk. If `false` the chunk won’t be executed.
|
||||
- `term = false`: If `true` the output emulates a REPL session. Otherwise only stdout and figures will be included in output.
|
||||
- `label = nothing`: 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, depending 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.
|
||||
|
||||
### Figures
|
||||
|
||||
## Options for 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.
|
||||
- `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, e.g.: `"ht"`.
|
||||
- `fig_env = "figure"`: Figure environment in Latex.
|
||||
|
||||
|
||||
## Set Default Chunk Options
|
||||
## 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:
|
||||
|
|
|
@ -39,11 +39,11 @@ Note that `Date` is available since the chunk is evaluated first.
|
|||
---
|
||||
title : Header Example
|
||||
author : Shuhei Kadowaki
|
||||
date: `j Date(now())`
|
||||
date: `j import Dates; Dates.Date(Dates.now())`
|
||||
---
|
||||
|
||||
```julia; echo = false
|
||||
using Datas
|
||||
using Dates
|
||||
```
|
||||
```
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ Pages = [
|
|||
"getting_started.md",
|
||||
"usage.md",
|
||||
"publish.md",
|
||||
"header.md",
|
||||
"chunk_options.md",
|
||||
"header.md",
|
||||
"notebooks.md",
|
||||
"function_index.md",
|
||||
]
|
||||
|
|
|
@ -41,8 +41,8 @@ e.g.: `weave("FIR_design_plots.jl", template = "custom.tpl"`.
|
|||
|
||||
As starting point, you can use the existing templates:
|
||||
|
||||
- HTML (`md2html`): [julia_html.tpl](https://github.com/mpastell/Weave.jl/blob/master/templates/julia_html.tpl)
|
||||
- LaTex (`md2pdf`): [julia_tex.tpl](https://github.com/mpastell/Weave.jl/blob/master/templates/julia_tex.tpl)
|
||||
- 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).
|
||||
|
||||
|
|
|
@ -73,62 +73,69 @@ ext == ".ipynb" && return "notebook"
|
|||
return "noweb"
|
||||
```
|
||||
|
||||
## Documentation Chunks
|
||||
|
||||
### 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.
|
||||
|
||||
## Code Chunks
|
||||
|
||||
### Markdown Format
|
||||
### [Code Chunks](@id code-chunks)
|
||||
|
||||
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 are written in different ways in different formats.
|
||||
|
||||
```
|
||||
```julia; echo=false
|
||||
#### 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](@id 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");
|
||||
! display("text/html", HTML("Header from julia"));
|
||||
```
|
||||
|
||||
|
||||
### 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. See [chunk options](../chunk_options/).
|
||||
|
||||
|
||||
### Script Format
|
||||
|
||||
Weave also support script input format with a markup in comments.
|
||||
Weave also supports script input format with a markup in comments.
|
||||
These scripts can be executed normally using Julia or published with Weave.
|
||||
|
||||
Lines starting with `#'`, `#%%` or `# %%` are treated as document.
|
||||
|
@ -143,7 +150,11 @@ hoge # some code comes here
|
|||
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)
|
||||
!!! 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)
|
||||
|
||||
|
||||
## Configuration via YAML Header
|
||||
|
@ -154,29 +165,12 @@ See [Header Configuration](@ref) section for more details.
|
|||
|
||||
## Passing Runtime Arguments to Documents
|
||||
|
||||
You can pass arguments as `Dict` to the weaved document using the `args` argument
|
||||
to `weave`. The arguments will be available as `WEAVE_ARGS` variable in the document.
|
||||
You can pass arbitrary object to the weaved document using [`weave`](@ref)'s optional argument `args`.
|
||||
It will be available as `WEAVE_ARGS` variable in the `weave`d document.
|
||||
|
||||
This makes it possible to create the same report easily for e.g. different
|
||||
date ranges of input data from a database or from files with similar format giving the
|
||||
filename as input.
|
||||
This makes it possible to create the same report easily for e.g. different date ranges of input data from a database or from files with similar format giving the filename as input.
|
||||
|
||||
In order to pass a filename to a document you need call `weave` using:
|
||||
|
||||
```julia
|
||||
weave("mydoc.jmd", args = Dict("filename" => "somedata.h5"))
|
||||
```
|
||||
|
||||
and you can access the filename from document as follows:
|
||||
|
||||
```
|
||||
```julia
|
||||
print(WEAVE_ARGS["filename"])
|
||||
```
|
||||
```
|
||||
|
||||
You can use the `out_path` argument to control the name of the
|
||||
output document.
|
||||
E.g. if you call `weave("weavefile.jmd", args = (datalocation = "somedata.h5",))`, and then you can retrieve the `datalocation` in `weavefile.jmd` as follows: `WEAVE_ARGS.datalocation`
|
||||
|
||||
|
||||
## `include_weave`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
192
src/Weave.jl
192
src/Weave.jl
|
@ -1,38 +1,57 @@
|
|||
module Weave
|
||||
|
||||
using Highlights, Mustache, Requires
|
||||
|
||||
using Highlights, Mustache, Requires, Pkg, REPL, RelocatableFolders, Base64
|
||||
|
||||
# directories
|
||||
const PKG_DIR = normpath(@__DIR__, "..")
|
||||
const TEMPLATE_DIR = normpath(PKG_DIR, "templates")
|
||||
const TEMPLATE_DIR = @path joinpath(PKG_DIR, "templates")
|
||||
const STYLESHEET_DIR = @path joinpath(PKG_DIR, "stylesheets")
|
||||
# keeps paths of sample documents for easy try
|
||||
const EXAMPLE_FOLDER = @path joinpath(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"
|
||||
|
||||
# keeps paths of sample documents for easy try
|
||||
const EXAMPLE_FOLDER = normpath(PKG_DIR, "examples")
|
||||
|
||||
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" include("plots.jl")
|
||||
@require Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004" include("gadfly.jl")
|
||||
end
|
||||
|
||||
@static @isdefined(isnothing) || begin
|
||||
isnothing(::Any) = false
|
||||
isnothing(::Nothing) = true
|
||||
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]
|
||||
|
||||
"""
|
||||
list_out_formats()
|
||||
|
||||
List supported output formats
|
||||
List supported output formats with its description.
|
||||
"""
|
||||
function list_out_formats()
|
||||
for format in keys(formats)
|
||||
println(string(format, ": ", formats[format].description))
|
||||
end
|
||||
end
|
||||
list_out_formats() = [k => v.description for (k,v) in FORMATS]
|
||||
|
||||
"""
|
||||
tangle(source::AbstractString; kwargs...)
|
||||
|
@ -55,9 +74,9 @@ function tangle(
|
|||
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
|
||||
open(out_path, "w") do io
|
||||
for chunk in doc.chunks
|
||||
if typeof(chunk) == CodeChunk
|
||||
options = merge(doc.chunk_defaults, chunk.options)
|
||||
|
@ -65,8 +84,8 @@ function tangle(
|
|||
end
|
||||
end
|
||||
end
|
||||
doc.cwd == pwd() && (outname = basename(outname))
|
||||
@info("Writing to file $outname")
|
||||
|
||||
@info "Tangled to $(out_path)"
|
||||
end
|
||||
|
||||
"""
|
||||
|
@ -82,9 +101,9 @@ Weave an input document to output file.
|
|||
* `:doc`: Path of the source document (default)
|
||||
* `:pwd`: Julia working directory
|
||||
* `"somepath"`: `String` of output directory e.g. `"~/outdir"`, or of filename e.g. `"~/outdir/outfile.tex"`
|
||||
- `args::Dict = Dict()`: Arguments to be passed to the weaved document; will be available as `WEAVE_ARGS` in the document
|
||||
- `args::Any = Dict()`: A runtime object that is available as `WEAVE_ARGS` while `weave`ing
|
||||
- `mod::Union{Module,Nothing} = nothing`: Module where Weave `eval`s code. You can pass a `Module` object, otherwise create an new sandbox module.
|
||||
- `fig_path::AbstractString = "figures"`: Where figures will be generated, relative to `out_path`
|
||||
- `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:
|
||||
|
@ -92,12 +111,11 @@ Weave an input document to output file.
|
|||
* `:all` caches everything
|
||||
* `:user` caches based on chunk options
|
||||
* `:refresh` runs all code chunks and save new cache
|
||||
- `throw_errors::Bool = false`: If `false` errors are included in output document and the whole document is executed. If `true` errors are thrown when they occur
|
||||
- `template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing`: Template (file path) or `Mustache.MustacheTokens`s for `md2html` or `md2tex` formats
|
||||
- `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} = String[]`: `String`s of options to pass to pandoc for `pandoc2html` and `pandoc2pdf` formats, e.g. `["--toc", "-N"]`
|
||||
- `latex_cmd::AbstractString = "xelatex"`: The command used to make PDF file from .tex
|
||||
- `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
|
||||
|
@ -108,18 +126,17 @@ function weave(
|
|||
doctype::Union{Nothing,AbstractString} = nothing,
|
||||
informat::Union{Nothing,AbstractString} = nothing,
|
||||
out_path::Union{Symbol,AbstractString} = :doc,
|
||||
args::Dict = Dict(),
|
||||
args::Any = Dict(),
|
||||
mod::Union{Module,Nothing} = nothing,
|
||||
fig_path::AbstractString = "figures",
|
||||
fig_path::Union{Nothing,AbstractString} = nothing,
|
||||
fig_ext::Union{Nothing,AbstractString} = nothing,
|
||||
cache_path::AbstractString = "cache",
|
||||
cache::Symbol = :off,
|
||||
throw_errors::Bool = false,
|
||||
template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing,
|
||||
css::Union{Nothing,AbstractString} = nothing,
|
||||
css::Union{Nothing,AbstractString} = nothing, # TODO: rename to `stylesheet`
|
||||
highlight_theme::Union{Nothing,Type{<:Highlights.AbstractTheme}} = nothing,
|
||||
pandoc_options::Vector{<:AbstractString} = String[],
|
||||
latex_cmd::AbstractString = "xelatex",
|
||||
pandoc_options::Vector{<:AbstractString} = DEFAULT_PANDOC_OPTIONS,
|
||||
latex_cmd::Vector{<:AbstractString} = DEFAULT_LATEX_CMD,
|
||||
keep_unicode::Bool = false,
|
||||
)
|
||||
doc = WeaveDoc(source, informat)
|
||||
|
@ -154,7 +171,6 @@ function weave(
|
|||
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))
|
||||
throw_errors = get(weave_options, "throw_errors", throw_errors)
|
||||
end
|
||||
|
||||
doc = run_doc(
|
||||
|
@ -167,69 +183,57 @@ function weave(
|
|||
fig_ext = fig_ext,
|
||||
cache_path = cache_path,
|
||||
cache = cache,
|
||||
throw_errors = throw_errors,
|
||||
)
|
||||
|
||||
# format document
|
||||
# ---------------
|
||||
|
||||
# overwrites options with those specified in header, that are needed for formatting document
|
||||
# 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
|
||||
# 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
|
||||
# resolve relative to this document
|
||||
css isa AbstractString && (css = normpath(dirname(source), css))
|
||||
end
|
||||
highlight_theme = get(weave_options, "highlight_theme", highlight_theme)
|
||||
pandoc_options = get(weave_options, "pandoc_options", pandoc_options)
|
||||
latex_cmd = get(weave_options, "latex_cmd", latex_cmd)
|
||||
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
|
||||
|
||||
isnothing(template) || (doc.template = template)
|
||||
isnothing(highlight_theme) || (doc.highlight_theme = highlight_theme)
|
||||
# isnothing(theme) || (doc.theme = theme) # Reserved for themes
|
||||
isnothing(css) || (doc.css = css)
|
||||
get!(doc.format.formatdict, :keep_unicode, keep_unicode)
|
||||
formatted = format(doc)
|
||||
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,
|
||||
)
|
||||
|
||||
outname = get_outname(out_path, doc)
|
||||
# render document
|
||||
# ---------------
|
||||
rendered = render_doc(doc)
|
||||
|
||||
open(io->write(io,formatted), outname, "w")
|
||||
# write documents
|
||||
# ---------------
|
||||
out_path = write_doc(doc, rendered, get_out_path(doc, out_path))
|
||||
|
||||
# document generation via external programs
|
||||
doctype = doc.doctype
|
||||
if doctype == "pandoc2html"
|
||||
mdname = outname
|
||||
outname = get_outname(out_path, doc, ext = "html")
|
||||
pandoc2html(formatted, doc, outname, pandoc_options)
|
||||
rm(mdname)
|
||||
elseif doctype == "pandoc2pdf"
|
||||
mdname = outname
|
||||
outname = get_outname(out_path, doc, ext = "pdf")
|
||||
pandoc2pdf(formatted, doc, outname, pandoc_options)
|
||||
rm(mdname)
|
||||
elseif doctype == "md2pdf"
|
||||
run_latex(doc, outname, latex_cmd)
|
||||
outname = get_outname(out_path, doc, ext = "pdf")
|
||||
end
|
||||
|
||||
doc.cwd == pwd() && (outname = basename(outname))
|
||||
@info "Report weaved to $outname"
|
||||
return abspath(outname)
|
||||
@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)
|
||||
fmts = keys(FORMATS)
|
||||
for (k,v) in weave_options
|
||||
if k in fmts
|
||||
k == doctype && merge!(weave_options, v)
|
||||
|
@ -238,6 +242,17 @@ function specific_options!(weave_options, doctype)
|
|||
end
|
||||
end
|
||||
|
||||
get_out_path(doc, out_path, ext::Nothing = nothing) = get_out_path(doc, out_path, doc.format.extension)
|
||||
function get_out_path(doc, out_path, ext)
|
||||
if (out_path === :doc) || (out_path === :pwd)
|
||||
abspath(get_cwd(doc, out_path), string(doc.basename, '.', ext))
|
||||
elseif isempty(splitext(out_path)[2]) # directory given
|
||||
abspath(get_cwd(doc, out_path), string(doc.basename, '.', ext))
|
||||
else
|
||||
# out_path is given, but if extension is explitly provided override this will override the extension
|
||||
abspath(string(splitext(out_path)[1], '.', ext))
|
||||
end
|
||||
end
|
||||
"""
|
||||
notebook(source::AbstractString; kwargs...)
|
||||
|
||||
|
@ -257,7 +272,7 @@ using [`nbconvert`](https://nbconvert.readthedocs.io/en/latest/).
|
|||
|
||||
!!! warning
|
||||
The code is _**not**_ executed by Weave, but by [`nbconvert`](https://nbconvert.readthedocs.io/en/latest/).
|
||||
This means that the output doesn't necessarily always work properly; see [#116](https://github.com/mpastell/Weave.jl/issues/116).
|
||||
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,
|
||||
|
@ -273,15 +288,13 @@ function notebook(
|
|||
doc = WeaveDoc(source)
|
||||
converted = convert_to_notebook(doc)
|
||||
doc.cwd = get_cwd(doc, out_path)
|
||||
outfile = get_outname(out_path, doc, ext = "ipynb")
|
||||
out_path = get_out_path(doc, out_path, "ipynb")
|
||||
|
||||
open(outfile, "w") do f
|
||||
write(f, converted)
|
||||
end
|
||||
write(out_path, converted)
|
||||
|
||||
@info "Running nbconvert"
|
||||
@info "Running nbconvert ..."
|
||||
return read(
|
||||
`$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $outfile $nbconvert_options --output $outfile`,
|
||||
`$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $(out_path) $nbconvert_options --output $(out_path)`,
|
||||
String,
|
||||
)
|
||||
end
|
||||
|
@ -300,7 +313,7 @@ function include_weave(
|
|||
)
|
||||
old_path = pwd()
|
||||
doc = WeaveDoc(source, informat)
|
||||
cd(doc.path)
|
||||
cd(dirname(doc.path))
|
||||
try
|
||||
code = join(
|
||||
[x.content for x in filter(x -> isa(x, Weave.CodeChunk), doc.chunks)],
|
||||
|
@ -317,29 +330,6 @@ end
|
|||
|
||||
include_weave(source, informat = nothing) = 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("types.jl")
|
||||
include("config.jl")
|
||||
include("WeaveMarkdown/markdown.jl")
|
||||
include("display_methods.jl")
|
||||
include("reader/reader.jl")
|
||||
include("run.jl")
|
||||
include("cache.jl")
|
||||
include("formatters.jl")
|
||||
include("format.jl")
|
||||
include("pandoc.jl")
|
||||
include("converter.jl")
|
||||
|
||||
export weave,
|
||||
list_out_formats,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# module Markdown2HTML
|
||||
# Markdown to HTML writer, Modified from Julia Base.Markdown html writer
|
||||
|
||||
using Markdown:
|
||||
MD,
|
||||
Header,
|
||||
|
@ -19,13 +19,10 @@ using Markdown:
|
|||
LaTeX,
|
||||
isordered
|
||||
|
||||
function tohtml(io::IO, m::MIME"text/html", x)
|
||||
show(io, m, x)
|
||||
end
|
||||
|
||||
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,""")
|
||||
|
@ -33,9 +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
|
||||
|
||||
|
@ -168,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
|
||||
|
@ -178,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
|
||||
|
@ -218,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
|
||||
|
@ -234,9 +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
|
||||
|
@ -250,18 +237,12 @@ function htmlinline(io::IO, link::Link)
|
|||
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
|
||||
|
|
|
@ -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, "")
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
# 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,
|
||||
)
|
||||
# HACK: that this definition is type-piracy. It is required since `Markdown`
|
||||
# does not have a built in system for contextual rendering by users. `io` here
|
||||
# should always be either `IOBuffer` or `IOContext` since it is reached via
|
||||
# `sprint` in all user-facing code paths in `Markdown`.
|
||||
function Markdown.latex(io::Union{IOBuffer,IOContext}, 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
|
||||
|
@ -37,7 +34,7 @@ end
|
|||
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
|
||||
|
@ -58,7 +55,7 @@ end
|
|||
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
|
||||
|
@ -71,7 +68,7 @@ end
|
|||
withstream(stream) do
|
||||
Markdown.startswith(stream, "<!--") || return
|
||||
text = Markdown.readuntil(stream, "-->")
|
||||
text ≡ nothing && return
|
||||
isnothing(text) && return
|
||||
return Comment(text)
|
||||
end
|
||||
end
|
||||
|
@ -88,6 +85,8 @@ for key in keys(Markdown.julia.inner)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
include("html.jl")
|
||||
include("latex.jl")
|
||||
end
|
||||
|
||||
end # module
|
||||
|
|
|
@ -29,7 +29,6 @@ function restore_chunk(chunk::CodeChunk, cached)
|
|||
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
|
||||
|
|
|
@ -1,64 +1,58 @@
|
|||
# Default options
|
||||
const defaultParams = Dict{Symbol,Any}(
|
||||
:storeresults => false,
|
||||
: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,
|
||||
),
|
||||
# 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,
|
||||
)
|
||||
# This one can be changed at runtime, initially a copy of defaults
|
||||
const rcParams = deepcopy(defaultParams)
|
||||
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(: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))`
|
||||
"""
|
||||
set_chunk_defaults!(opts::Dict{Symbol,Any}) = merge!(rcParams[:chunk_defaults], opts)
|
||||
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 default options used for code chunks.
|
||||
"""
|
||||
get_chunk_defaults() = rcParams[:chunk_defaults]
|
||||
get_chunk_defaults() = DEFAULT_PARAMS
|
||||
|
||||
"""
|
||||
restore_chunk_defaults!()
|
||||
|
||||
Restore Weave.jl default chunk options.
|
||||
"""
|
||||
restore_chunk_defaults!() = rcParams[:chunk_defaults] = defaultParams[:chunk_defaults]
|
||||
restore_chunk_defaults!() = for (k,v) in _DEFAULT_PARAMS; DEFAULT_PARAMS[k] = v; end
|
||||
|
|
|
@ -102,8 +102,6 @@ function convert_to_notebook(doc)
|
|||
"source" => [strip(join([repr(c) for c in chunk.content], ""))],
|
||||
),
|
||||
)
|
||||
elseif haskey(chunk.options, :skip) && chunk.options[:skip] == "notebook"
|
||||
continue
|
||||
else
|
||||
push!(
|
||||
cells,
|
||||
|
|
|
@ -2,40 +2,20 @@ using Markdown, .WeaveMarkdown
|
|||
|
||||
# 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
|
||||
cwd::String
|
||||
basename::String
|
||||
format::WeaveFormat
|
||||
rich_output::String
|
||||
fignum::Int
|
||||
figures::Array{AbstractString}
|
||||
term_state::Symbol
|
||||
cur_chunk::Any
|
||||
mimetypes::Array{AbstractString}
|
||||
figures::Vector{String}
|
||||
cur_chunk::Union{Nothing,CodeChunk}
|
||||
mimetypes::Vector{String}
|
||||
first_plot::Bool
|
||||
header_script::String
|
||||
throw_errors::Bool
|
||||
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
|
||||
const default_mime_types = ["image/svg+xml", "image/png", "text/html", "text/plain"]
|
||||
|
@ -111,7 +91,7 @@ end
|
|||
function Base.display(report::Report, m::MIME"text/html", data)
|
||||
io = IOBuffer()
|
||||
show(IOContext(io, :limit => true), m, data)
|
||||
report.rich_output *= "\n" * String(take!(io))
|
||||
report.rich_output *= string('\n', take2string!(io))
|
||||
end
|
||||
|
||||
# Catch "rich_output"
|
||||
|
@ -131,7 +111,7 @@ 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"""
|
||||
|
|
407
src/format.jl
407
src/format.jl
|
@ -1,407 +0,0 @@
|
|||
using Mustache, Highlights, .WeaveMarkdown, Markdown, Dates, Pkg
|
||||
using REPL.REPLCompletions: latex_symbols
|
||||
|
||||
function format(doc)
|
||||
format = doc.format
|
||||
|
||||
# Complete format dictionaries with defaults
|
||||
formatdict = format.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)
|
||||
|
||||
formatdict[:cwd] = doc.cwd # pass wd to figure formatters
|
||||
formatdict[:theme] = doc.highlight_theme
|
||||
|
||||
restore_header!(doc)
|
||||
|
||||
formatted = String[]
|
||||
for chunk in copy(doc.chunks)
|
||||
result = format_chunk(chunk, formatdict, format)
|
||||
push!(formatted, result)
|
||||
end
|
||||
formatted = join(formatted, "\n")
|
||||
|
||||
# Render using a template if needed
|
||||
return render_doc(formatted, doc)
|
||||
end
|
||||
|
||||
render_doc(formatted, doc) = render_doc(formatted, doc, doc.format)
|
||||
|
||||
render_doc(formatted, doc, format) = formatted
|
||||
|
||||
function render_doc(formatted, doc, format::JMarkdown2HTML)
|
||||
template = if isa(doc.template, Mustache.MustacheTokens)
|
||||
doc.template
|
||||
else
|
||||
template_path = isempty(doc.template) ? normpath(TEMPLATE_DIR, "julia_html.tpl") : doc.template
|
||||
Mustache.template_from_file(template_path)
|
||||
end
|
||||
|
||||
themepath = isempty(doc.css) ? normpath(TEMPLATE_DIR, "skeleton_css.css") : doc.css
|
||||
themecss = read(themepath, String)
|
||||
|
||||
highlightcss = stylesheet(MIME("text/html"), doc.highlight_theme)
|
||||
|
||||
_, source = splitdir(abspath(doc.source))
|
||||
wversion, wdate = weave_info()
|
||||
|
||||
return Mustache.render(
|
||||
template;
|
||||
body = formatted,
|
||||
themecss = themecss,
|
||||
highlightcss = highlightcss,
|
||||
header_script = doc.header_script,
|
||||
source = source,
|
||||
wversion = wversion,
|
||||
wdate = wdate,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
function render_doc(formatted, doc, format::JMarkdown2tex)
|
||||
template = if isa(doc.template, Mustache.MustacheTokens)
|
||||
doc.template
|
||||
else
|
||||
template_path = isempty(doc.template) ? normpath(TEMPLATE_DIR, "julia_tex.tpl") : doc.template
|
||||
Mustache.template_from_file(template_path)
|
||||
end
|
||||
|
||||
highlight = stylesheet(MIME("text/latex"), doc.highlight_theme)
|
||||
|
||||
return Mustache.render(
|
||||
template;
|
||||
body = formatted,
|
||||
highlight = highlight,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
stylesheet(m::MIME, theme) = sprint((io, x) -> Highlights.stylesheet(io, m, x), theme)
|
||||
|
||||
const WEAVE_VERSION = try
|
||||
'v' * Pkg.TOML.parsefile(normpath(PKG_DIR, "Project.toml"))["version"]
|
||||
catch
|
||||
""
|
||||
end
|
||||
|
||||
weave_info() = WEAVE_VERSION, string(Date(now()))
|
||||
|
||||
# TODO: is there any other format where we want to restore headers ?
|
||||
const HEADER_PRESERVE_DOCTYPES = ("github", "hugo")
|
||||
|
||||
function restore_header!(doc)
|
||||
doc.doctype in HEADER_PRESERVE_DOCTYPES || return # don't restore
|
||||
|
||||
# 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
|
||||
|
||||
format_chunk(chunk::DocChunk, formatdict, docformat) = join((format_inline(c) for c in chunk.content))
|
||||
|
||||
format_inline(inline::InlineText) = inline.content
|
||||
|
||||
function format_inline(inline::InlineCode)
|
||||
isempty(inline.rich_output) || return inline.rich_output
|
||||
isempty(inline.figures) || return inline.figures[end]
|
||||
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
|
||||
|
||||
addspace(op, inline) = (inline.ctype === :line && (op = "\n$op\n"); op)
|
||||
|
||||
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
|
||||
|
||||
format_output(result, docformat) = result
|
||||
|
||||
format_output(result, docformat::JMarkdown2HTML) = Markdown.htmlesc(result)
|
||||
|
||||
function format_output(result, 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
|
||||
|
||||
format_code(result, docformat) = result
|
||||
|
||||
function format_code(result, 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, docformat::JMarkdown2HTML)
|
||||
return highlight(
|
||||
MIME("text/html"),
|
||||
strip(result),
|
||||
Highlights.Lexers.JuliaLexer,
|
||||
docformat.formatdict[:theme],
|
||||
)
|
||||
end
|
||||
|
||||
function format_code(result, 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 highlight(
|
||||
mime::MIME,
|
||||
output,
|
||||
lexer,
|
||||
theme = Highlights.Themes.DefaultTheme,
|
||||
)
|
||||
return sprint((io, x) -> Highlights.highlight(io, mime, x, lexer, theme), output)
|
||||
end
|
||||
|
||||
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
|
|
@ -1,529 +0,0 @@
|
|||
# so dirty, refactor
|
||||
|
||||
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 in 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 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 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 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
|
||||
|
||||
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 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
|
||||
|
||||
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 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
|
||||
|
||||
function formatfigures(chunk, docformat::Rest)
|
||||
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 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 in 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(
|
||||
"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,
|
||||
)
|
122
src/pandoc.jl
122
src/pandoc.jl
|
@ -1,122 +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")
|
||||
highlightcss = stylesheet(MIME("text/html"), doc.highlight_theme)
|
||||
|
||||
path, wsource = splitdir(abspath(doc.source))
|
||||
wversion, wdate = 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
|
||||
|
||||
# Change path for pandoc
|
||||
cd_back = let d = pwd(); () -> cd(d); end
|
||||
cd(doc.cwd)
|
||||
outname = basename(outname)
|
||||
|
||||
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 wdate=$wdate -V wsource=$wsource
|
||||
-V highlightcss=$highlightcss
|
||||
-V headerscript=$header_script
|
||||
-o $outname`
|
||||
proc = open(cmd, "r+")
|
||||
println(proc.in, formatted)
|
||||
close(proc.in)
|
||||
proc_output = read(proc.out, String)
|
||||
catch
|
||||
@warn "Error converting document to HTML"
|
||||
rethrow() # TODO: just show error content instead of rethrow the err
|
||||
finally
|
||||
cd_back()
|
||||
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))
|
||||
outname = basename(outname)
|
||||
|
||||
# Change path for pandoc
|
||||
cd_back = let d = pwd(); () -> cd(d); end
|
||||
cd(doc.cwd)
|
||||
|
||||
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)
|
||||
catch
|
||||
@warn "Error converting document to pdf"
|
||||
rethrow()
|
||||
finally
|
||||
cd_back()
|
||||
end
|
||||
end
|
||||
|
||||
function run_latex(doc::WeaveDoc, outname, latex_cmd = "xelatex")
|
||||
cd_back = let d = pwd(); () -> cd(d); end
|
||||
cd(doc.cwd)
|
||||
|
||||
xname = basename(outname)
|
||||
@info "Weaved code to $outname . Running $latex_cmd" # space before '.' added for link to be clickable in Juno terminal
|
||||
textmp = mktempdir(".")
|
||||
try
|
||||
cmd = `$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`
|
||||
run(cmd); run(cmd) # XXX: is twice enough for every case ?
|
||||
catch
|
||||
@warn "Error converting document to pdf. Try running latex manually"
|
||||
rethrow()
|
||||
finally
|
||||
rm(xname)
|
||||
rm(textmp, recursive = true)
|
||||
cd_back()
|
||||
end
|
||||
end
|
11
src/plots.jl
11
src/plots.jl
|
@ -1,24 +1,23 @@
|
|||
module WeavePlots
|
||||
|
||||
using Base64, ..Plots, ..Weave
|
||||
using ..Base64, ..Plots, ..Weave
|
||||
|
||||
|
||||
# Pre-execute hooks to set the plot size for the chunk
|
||||
function plots_set_size(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
|
||||
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")
|
||||
|
@ -40,7 +39,7 @@ function Base.display(
|
|||
report::Weave.Report,
|
||||
m::MIME"image/png",
|
||||
data::Plots.Plot{Plots.PlotlyBackend},
|
||||
)#
|
||||
)
|
||||
display(report, MIME("image/svg+xml"), data)
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ function parse_markdown(document_body; is_pandoc = false)
|
|||
r"^<<(?<options>.*?)>>=\s*$",
|
||||
r"^@\s*$"
|
||||
else
|
||||
r"^[`~]{3}(?:\{?)julia(?:;?)\s*(?<options>.*?)(\}|\s*)$",
|
||||
r"^[`~]{3}(\{?)julia\s*([;,\{]?)\s*(?<options>.*?)(\}|\s*)$",
|
||||
r"^[`~]{3}\s*$"
|
||||
end
|
||||
return header, parse_markdown_body(document_body, code_start, code_end, offset)
|
||||
|
@ -49,72 +49,47 @@ end
|
|||
function parse_markdown_body(document_body, code_start, code_end, offset)
|
||||
lines = split(document_body, '\n')
|
||||
|
||||
state = "doc"
|
||||
|
||||
docno = 1
|
||||
codeno = 1
|
||||
state = :doc
|
||||
doc_no = 0
|
||||
code_no = 0
|
||||
content = ""
|
||||
start_line = offset
|
||||
|
||||
options = Dict()
|
||||
optionString = ""
|
||||
chunks = WeaveChunk[]
|
||||
for (lineno, line) in enumerate(lines)
|
||||
m = match(code_start, line)
|
||||
if !isnothing(m) && state == "doc"
|
||||
state = "code"
|
||||
if m.captures[1] == nothing
|
||||
optionString = ""
|
||||
else
|
||||
optionString = strip(m.captures[1])
|
||||
end
|
||||
options = OptionDict()
|
||||
option_string = ""
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
if !isempty(strip(content))
|
||||
chunk = DocChunk(content, docno, start_line)
|
||||
docno += 1
|
||||
push!(chunks, chunk)
|
||||
end
|
||||
isempty(strip(content)) || push!(chunks, DocChunk(content, doc_no += 1, start_line))
|
||||
|
||||
start_line = line_no + offset
|
||||
content = ""
|
||||
start_line = lineno + offset
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
if occursin(code_end, line) && state == "code"
|
||||
chunk = CodeChunk(content, codeno, start_line, optionString, options)
|
||||
if occursin(code_end, line) && state === :code
|
||||
push!(chunks, CodeChunk(content, code_no += 1, start_line, option_string, options))
|
||||
|
||||
codeno += 1
|
||||
start_line = lineno + offset
|
||||
start_line = line_no + offset
|
||||
content = ""
|
||||
state = "doc"
|
||||
push!(chunks, chunk)
|
||||
state = :doc
|
||||
continue
|
||||
end
|
||||
|
||||
if lineno == 1
|
||||
content *= line
|
||||
else
|
||||
content *= "\n" * line
|
||||
end
|
||||
content *= isone(line_no) ? line : string('\n', line)
|
||||
end
|
||||
|
||||
# Remember the last chunk
|
||||
if strip(content) != ""
|
||||
chunk = DocChunk(content, docno, start_line)
|
||||
# chunk = Dict{Symbol,Any}(:type => "doc", :content => content,
|
||||
# :number => docno, :start_line => start_line)
|
||||
push!(chunks, chunk)
|
||||
end
|
||||
isempty(strip(content)) || push!(chunks, DocChunk(content, doc_no += 1, start_line))
|
||||
|
||||
return chunks
|
||||
end
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
using JSON
|
||||
|
||||
|
||||
function parse_notebook(document_body)
|
||||
nb = JSON.parse(document_body)
|
||||
chunks = WeaveChunk[]
|
||||
code_no = 0
|
||||
doc_no = 0
|
||||
|
||||
# TODO: handle some of options ?
|
||||
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!(chunks, chunk)
|
||||
codeno += 1
|
||||
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
|
||||
chunk = DocChunk(srctext * "\n", docno, 0; notebook = true)
|
||||
push!(chunks, chunk)
|
||||
docno += 1
|
||||
DocChunk(text, doc_no += 1, 0; notebook = true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
using JSON, YAML
|
||||
using YAML
|
||||
|
||||
|
||||
function WeaveDoc(source, informat = nothing)
|
||||
path, fname = splitdir(abspath(source))
|
||||
path = abspath(source)
|
||||
_, fname = splitdir(path)
|
||||
basename = splitext(fname)[1]
|
||||
|
||||
isnothing(informat) && (informat = detect_informat(source))
|
||||
|
@ -36,10 +37,6 @@ function WeaveDoc(source, informat = nothing)
|
|||
"",
|
||||
"",
|
||||
header,
|
||||
"",
|
||||
"",
|
||||
Highlights.Themes.DefaultTheme,
|
||||
"",
|
||||
chunk_defaults,
|
||||
)
|
||||
end
|
||||
|
@ -68,12 +65,6 @@ function parse_doc(document, informat)
|
|||
error("unsupported input format given: $informat")
|
||||
end
|
||||
|
||||
function pushopt(options::Dict, expr::Expr)
|
||||
if Base.Meta.isexpr(expr, :(=))
|
||||
options[expr.args[1]] = expr.args[2]
|
||||
end
|
||||
end
|
||||
|
||||
# inline
|
||||
# ------
|
||||
|
||||
|
@ -86,34 +77,51 @@ end
|
|||
const INLINE_REGEX = r"`j\s+(.*?)`"
|
||||
const INLINE_REGEXES = r"`j\s+(.*?)`|^!\s(.*)$"m
|
||||
|
||||
function parse_inlines(text)::Vector{Inline}
|
||||
occursin(INLINE_REGEXES, text) || return parse_inline(text)
|
||||
|
||||
inline_chunks = eachmatch(INLINE_REGEXES, text)
|
||||
# handle code units correctly !
|
||||
function parse_inlines(str)
|
||||
ret = Inline[]
|
||||
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
|
||||
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!(res, InlineText(text[e:end], e, length(text), textno))
|
||||
|
||||
return res
|
||||
push!(ret, InlineText(str[s:end], text_no += 1))
|
||||
return ret
|
||||
end
|
||||
|
||||
parse_inline(text) = Inline[InlineText(text, 1, length(text), 1)]
|
||||
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")
|
||||
|
|
|
@ -1,89 +1,67 @@
|
|||
function parse_script(document_body)
|
||||
lines = split(document_body, "\n")
|
||||
lines = split(document_body, '\n')
|
||||
|
||||
doc_line = r"(^#'.*)|(^#%%.*)|(^# %%.*)"
|
||||
doc_start = r"(^#')|(^#%%)|(^# %%)"
|
||||
opt_line = r"(^#\+.*$)|(^#%%\+.*$)|(^# %%\+.*$)"
|
||||
opt_start = r"(^#\+)|(^#%%\+)|(^# %%\+)"
|
||||
|
||||
read = ""
|
||||
docno = 1
|
||||
codeno = 1
|
||||
content = ""
|
||||
state = :code
|
||||
doc_no = 0
|
||||
code_no = 0
|
||||
start_line = 1
|
||||
options = Dict{Symbol,Any}()
|
||||
optionString = ""
|
||||
|
||||
options = OptionDict()
|
||||
option_string = ""
|
||||
|
||||
chunks = WeaveChunk[]
|
||||
state = "code"
|
||||
|
||||
for lineno = 1:length(lines)
|
||||
line = lines[lineno]
|
||||
if (m = match(doc_line, line)) != nothing && (m = match(opt_line, line)) == nothing
|
||||
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)
|
||||
if startswith(line, " ")
|
||||
line = replace(line, " " => "", 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
|
||||
if state == "code" && strip(read) != ""
|
||||
chunk =
|
||||
CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
|
||||
push!(chunks, chunk)
|
||||
codeno += 1
|
||||
read = ""
|
||||
start_line = lineno
|
||||
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
|
||||
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!(chunks, 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!(chunks, chunk)
|
||||
read = ""
|
||||
docno += 1
|
||||
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
|
||||
|
||||
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
|
||||
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"
|
||||
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)
|
||||
push!(chunks, chunk)
|
||||
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 = lineno
|
||||
read = ""
|
||||
docno += 1
|
||||
start_line = line_no
|
||||
end
|
||||
read *= line * "\n"
|
||||
content *= string(line, '\n')
|
||||
end
|
||||
|
||||
# Handle the last chunk
|
||||
if state == "code"
|
||||
chunk = CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
|
||||
push!(chunks, chunk)
|
||||
else
|
||||
chunk = DocChunk(read, docno, start_line)
|
||||
push!(chunks, chunk)
|
||||
end
|
||||
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
|
||||
|
|
|
@ -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)
|
|
@ -0,0 +1,24 @@
|
|||
abstract type ExportFormat <: WeaveFormat end
|
||||
|
||||
function Base.getproperty(sf::T, s::Symbol) where {T<:ExportFormat}
|
||||
hasfield(T, s) && return getfield(sf, s)
|
||||
return getproperty(sf.primaryformat, s)
|
||||
end
|
||||
function Base.setproperty!(sf::T, s::Symbol, v) where {T<:ExportFormat}
|
||||
if hasfield(T, s)
|
||||
setfield!(sf, s, v)
|
||||
else
|
||||
setproperty!(sf.primaryformat, s, v)
|
||||
end
|
||||
end
|
||||
function Base.hasproperty(sf::T, s::Symbol) where {T<:ExportFormat}
|
||||
hasfield(T, s) || hasproperty(sf.primaryformat, s)
|
||||
end
|
||||
|
||||
render_doc(df::ExportFormat, body, doc) = render_doc(df.primaryformat, body, doc)
|
||||
|
||||
render_chunk(df::ExportFormat, chunk) = render_chunk(df.primaryformat, chunk)
|
||||
# Need to define these to avoid ambiguities
|
||||
render_chunk(df::ExportFormat, chunk::DocChunk) = render_chunk(df.primaryformat, chunk)
|
||||
render_chunk(df::ExportFormat, chunk::CodeChunk) = render_chunk(df.primaryformat, chunk)
|
||||
render_output(df::ExportFormat, output) = render_output(df.primaryformat, output)
|
|
@ -0,0 +1,146 @@
|
|||
# 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 <: ExportFormat
|
||||
description = "HTML via intermediate Pandoc Markdown (requires Pandoc 2)"
|
||||
primaryformat = Pandoc()
|
||||
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)
|
|
@ -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
|
|
@ -0,0 +1,70 @@
|
|||
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 <: ExportFormat
|
||||
description = "PDF via intermediate Pandoc Markdown"
|
||||
primaryformat = Pandoc()
|
||||
pandoc_options = DEFAULT_PANDOC_OPTIONS
|
||||
header_template = normpath(TEMPLATE_DIR, "pandoc2pdf_header.txt")
|
||||
end
|
||||
register_format!("pandoc2pdf", Pandoc2PDF())
|
||||
|
||||
function set_format_options!(docformat::Pandoc2PDF; pandoc_options = DEFAULT_PANDOC_OPTIONS, _kwargs...)
|
||||
docformat.pandoc_options = pandoc_options
|
||||
end
|
|
@ -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("exportformat.jl")
|
||||
include("common.jl")
|
||||
include("pandocformats.jl")
|
||||
include("htmlformats.jl")
|
||||
include("texformats.jl")
|
||||
include("miscformats.jl")
|
|
@ -0,0 +1,264 @@
|
|||
# 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,
|
||||
unicode2latex(docformat, chunk.output, true),
|
||||
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}[texcomments = true, mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}"
|
||||
codeend = "\\end{minted}"
|
||||
termstart = "\\begin{minted}[texcomments = true, mathescape, fontsize=\\footnotesize, xleftmargin=0.5em]{jlcon}"
|
||||
termend = "\\end{minted}"
|
||||
outputstart = "\\begin{minted}[texcomments = true, 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
|
||||
|
||||
function render_termchunk(docformat::WeaveLaTeXFormat, chunk)
|
||||
if should_render(chunk)
|
||||
ret = highlight_term(MIME("text/latex"), chunk.output, docformat.highlight_theme)
|
||||
unicode2latex(docformat, ret, true)
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
function render_doc(docformat::WeaveLaTeXFormat, body, doc)
|
||||
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 = "@*)"
|
||||
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 LaTeX2PDF <: ExportFormat
|
||||
primaryformat = WeaveLaTeX()
|
||||
description = "PDF via LaTeX"
|
||||
latex_cmd = DEFAULT_LATEX_CMD
|
||||
end
|
||||
register_format!("md2pdf", LaTeX2PDF())
|
||||
register_format!("minted2pdf", LaTeX2PDF(primaryformat=LaTeXMinted()))
|
||||
|
||||
function set_format_options!(docformat::LaTeX2PDF; latex_cmd = DEFAULT_LATEX_CMD, _kwargs...)
|
||||
docformat.latex_cmd = latex_cmd
|
||||
set_format_options!(docformat.primaryformat; _kwargs...)
|
||||
end
|
388
src/run.jl
388
src/run.jl
|
@ -3,71 +3,49 @@ using Base64
|
|||
|
||||
const PROGRESS_ID = "weave_progress"
|
||||
|
||||
"""
|
||||
run_doc(doc::WeaveDoc; kwargs...)
|
||||
|
||||
Run code chunks and capture output from the parsed document.
|
||||
|
||||
## Keyword options
|
||||
|
||||
- `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
|
||||
- `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::Dict = Dict()`: Arguments to be passed to the weaved document; will be available as `WEAVE_ARGS` in the document
|
||||
- `mod::Union{Module,Nothing} = nothing`: Module where Weave `eval`s code. You can pass a `Module` object, otherwise create an new sandbox module.
|
||||
- `fig_path::AbstractString = "figures"`: Where figures will be generated, relative to `out_path`
|
||||
- `fig_ext::Union{Nothing,AbstractString} = nothing`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`
|
||||
- `cache_path::AbstractString = "cache"`: Where of cached output will be saved
|
||||
- `cache::Symbol = :off`: Controls caching of code:
|
||||
* `:off` means no caching (default)
|
||||
* `:all` caches everything
|
||||
* `:user` caches based on chunk options
|
||||
* `:refresh` runs all code chunks and save new cache
|
||||
- `throw_errors::Bool = false`: If `false` errors are included in output document and the whole document is executed. If `true` errors are thrown when they occur
|
||||
|
||||
!!! note
|
||||
Run Weave from terminal and try to avoid weaving from IJulia or ESS; they tend to mess with capturing output.
|
||||
"""
|
||||
function run_doc(
|
||||
doc::WeaveDoc;
|
||||
doctype::Union{Nothing,AbstractString} = nothing,
|
||||
out_path::Union{Symbol,AbstractString} = :doc,
|
||||
args::Dict = Dict(),
|
||||
args::Any = Dict(),
|
||||
mod::Union{Module,Nothing} = nothing,
|
||||
fig_path::AbstractString = "figures",
|
||||
fig_path::Union{Nothing,AbstractString} = nothing,
|
||||
fig_ext::Union{Nothing,AbstractString} = nothing,
|
||||
cache_path::AbstractString = "cache",
|
||||
cache::Symbol = :off,
|
||||
throw_errors::Bool = false,
|
||||
)
|
||||
# cache :all, :user, :off, :refresh
|
||||
|
||||
doc.doctype = isnothing(doctype) ? (doctype = detect_doctype(doc.source)) : doctype
|
||||
doc.format = deepcopy(formats[doctype])
|
||||
doc.format = deepcopy(get_format(doctype))
|
||||
|
||||
doc.cwd = get_cwd(doc, out_path)
|
||||
isdir(doc.cwd) || mkpath(doc.cwd)
|
||||
if (occursin("2pdf", doctype) && cache == :off) || occursin("2html", doctype)
|
||||
fig_path = mktempdir(abspath(doc.cwd))
|
||||
cwd = doc.cwd = get_cwd(doc, out_path)
|
||||
mkpath(cwd)
|
||||
|
||||
# TODO: provide a way not to create `fig_path` ?
|
||||
if isnothing(fig_path)
|
||||
fig_path = if (endswith(doctype, "2pdf") && cache === :off) || endswith(doctype, "2html")
|
||||
basename(mktempdir(abspath(cwd)))
|
||||
else
|
||||
DEFAULT_FIG_PATH
|
||||
end
|
||||
end
|
||||
mkpath(normpath(cwd, fig_path))
|
||||
# This is needed for latex and should work on all output formats
|
||||
@static Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/"))
|
||||
set_rc_params(doc, fig_path, fig_ext)
|
||||
|
||||
cache === :off || @eval import Serialization # XXX: evaluate in a more sensible module
|
||||
|
||||
# This is needed for latex and should work on all output formats
|
||||
@static Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/"))
|
||||
|
||||
doc.fig_path = fig_path
|
||||
set_rc_params(doc, fig_path, fig_ext)
|
||||
|
||||
# New sandbox for each document with args exposed
|
||||
isnothing(mod) && (mod = sandbox = Core.eval(Main, :(module $(gensym(:WeaveSandBox)) end))::Module)
|
||||
@eval mod WEAVE_ARGS = $args
|
||||
Core.eval(mod, :(WEAVE_ARGS = $(args)))
|
||||
|
||||
mimetypes = get(doc.format.formatdict, :mimetypes, default_mime_types)
|
||||
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)
|
||||
try
|
||||
if cache !== :off && cache !== :refresh
|
||||
|
@ -110,7 +88,10 @@ function run_doc(
|
|||
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
|
||||
# Temporary fig_path is not automatically removed because it contains files so...
|
||||
!isnothing(fig_path) && startswith(fig_path, "jl_") && rm(normpath(cwd, fig_path), force=true, recursive=true)
|
||||
end
|
||||
|
||||
return doc
|
||||
|
@ -135,9 +116,24 @@ function detect_doctype(path)
|
|||
return "pandoc"
|
||||
end
|
||||
|
||||
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(chunk, report, mod)
|
||||
occursin("2html", report.formatdict[:doctype]) && (embed_figures!(result, report.cwd))
|
||||
result = eval_chunk(doc, chunk, report, mod)
|
||||
occursin("2html", doc.doctype) && (embed_figures!(result, report.cwd))
|
||||
return result
|
||||
end
|
||||
|
||||
|
@ -146,27 +142,17 @@ function embed_figures!(chunk::CodeChunk, cwd)
|
|||
chunk.figures[i] = img2base64(fig, cwd)
|
||||
end
|
||||
end
|
||||
|
||||
function embed_figures!(chunks::Vector{CodeChunk}, cwd)
|
||||
for chunk in chunks
|
||||
embed_figures!(chunk, cwd)
|
||||
end
|
||||
end
|
||||
embed_figures!(chunks, cwd) = embed_figures!.(chunks, Ref(cwd))
|
||||
|
||||
function img2base64(fig, cwd)
|
||||
ext = splitext(fig)[2]
|
||||
f = open(joinpath(cwd, fig), "r")
|
||||
raw = read(f)
|
||||
close(f)
|
||||
if ext == ".png"
|
||||
return "data:image/png;base64," * stringmime(MIME("image/png"), raw)
|
||||
elseif ext == ".svg"
|
||||
return "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw)
|
||||
elseif ext == ".gif"
|
||||
return "data:image/gif;base64," * stringmime(MIME("image/gif"), raw)
|
||||
else
|
||||
return (fig)
|
||||
end
|
||||
return ext == ".png" ? "data:image/png;base64," * stringmime(MIME("image/png"), raw) :
|
||||
ext == ".svg" ? "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw) :
|
||||
ext == ".gif" ? "data:image/gif;base64," * stringmime(MIME("image/gif"), raw) :
|
||||
fig
|
||||
end
|
||||
|
||||
function run_chunk(chunk::DocChunk, doc, report, mod)
|
||||
|
@ -174,7 +160,7 @@ function run_chunk(chunk::DocChunk, doc, report, mod)
|
|||
return chunk
|
||||
end
|
||||
|
||||
run_inline(inline::InlineText, doc::WeaveDoc, report::Report, SandBox::Module) = inline
|
||||
run_inline(inline::InlineText, ::WeaveDoc, ::Report, ::Module) = inline
|
||||
|
||||
const INLINE_OPTIONS = Dict(
|
||||
:term => false,
|
||||
|
@ -182,14 +168,14 @@ const INLINE_OPTIONS = Dict(
|
|||
:wrap => false
|
||||
)
|
||||
|
||||
function run_inline(inline::InlineCode, doc::WeaveDoc, report::Report, SandBox::Module)
|
||||
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]) && (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])
|
||||
|
@ -199,115 +185,117 @@ 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) in 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
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
# TODO: run in document source path
|
||||
function capture_output(expr, SandBox::Module, term, disp, lastline, throw_errors = false)
|
||||
out = nothing
|
||||
obj = nothing
|
||||
old = stdout
|
||||
rw, wr = redirect_stdout()
|
||||
reader = @async read(rw, String)
|
||||
try
|
||||
obj = Core.eval(SandBox, expr)
|
||||
!isnothing(obj) && ((term || disp) || lastline) && display(obj)
|
||||
catch err
|
||||
throw_errors && 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
|
||||
out = replace(out, r"\u001b\[.*?m" => "") # remove ANSI color codes
|
||||
return (obj, out)
|
||||
end
|
||||
|
||||
# Parse chunk input to array of expressions
|
||||
function parse_input(s)
|
||||
res = []
|
||||
s = lstrip(s)
|
||||
n = sizeof(s)
|
||||
pos = 1 # The first character is extra line end
|
||||
while (oldpos = pos) ≤ n
|
||||
ex, pos = Meta.parse(s, pos)
|
||||
push!(res, (s[oldpos:pos-1], ex))
|
||||
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 res
|
||||
end
|
||||
|
||||
function eval_chunk(chunk::CodeChunk, report::Report, SandBox::Module)
|
||||
function capture_output(code, mod, path, error, report)
|
||||
reset_report!(report)
|
||||
|
||||
old = stdout
|
||||
rw, wr = redirect_stdout()
|
||||
reader = @async read(rw, String)
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
return ChunkOutput(code, remove_ansi_control_chars(out), report.rich_output, report.figures)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
# 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) && isnothing(chunk.options[:out_width])
|
||||
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)
|
||||
|
||||
# Run post_execute chunks
|
||||
for hook in postexecute_hooks
|
||||
chunk = Base.invokelatest(hook, chunk)
|
||||
execute_posthooks!(chunk)
|
||||
|
||||
return chunk.options[:term] ? collect_term_results(chunk) :
|
||||
chunk.options[:hold] ? collect_hold_results(chunk) :
|
||||
collect_results(chunk)
|
||||
end
|
||||
|
||||
# Hooks to run before and after chunks, this is form IJulia,
|
||||
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
|
||||
function execute_prehooks!(chunk::CodeChunk)
|
||||
for prehook in preexecution_hooks
|
||||
Base.invokelatest(prehook, chunk)
|
||||
end
|
||||
end
|
||||
|
||||
if chunk.options[:term]
|
||||
chunks = collect_results(chunk, TermResult())
|
||||
elseif chunk.options[:hold]
|
||||
chunks = collect_results(chunk, CollectResult())
|
||||
else
|
||||
chunks = collect_results(chunk, ScriptResult())
|
||||
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
|
||||
function execute_posthooks!(chunk::CodeChunk)
|
||||
for posthook in postexecution_hooks
|
||||
Base.invokelatest(posthook, chunk)
|
||||
end
|
||||
|
||||
# else
|
||||
# chunk.options[:fig] && (chunk.figures = copy(report.figures))
|
||||
# end
|
||||
|
||||
return chunks
|
||||
end
|
||||
|
||||
"""
|
||||
|
@ -336,77 +324,28 @@ function clear_module!(mod::Module)
|
|||
end
|
||||
|
||||
function get_figname(report::Report, chunk; fignum = nothing, ext = nothing)
|
||||
figpath = joinpath(report.cwd, chunk.options[:fig_path])
|
||||
isdir(figpath) || mkpath(figpath)
|
||||
isnothing(ext) && (ext = chunk.options[:fig_ext])
|
||||
isnothing(fignum) && (fignum = report.fignum)
|
||||
|
||||
chunkid = isnothing(chunk.options[:label]) ? 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
|
||||
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)
|
||||
isnothing(ext) && (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)
|
||||
isnothing(ext) && (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 isnothing(fig_ext)
|
||||
doc.chunk_defaults[:fig_ext] = formatdict[:fig_ext]
|
||||
else
|
||||
doc.chunk_defaults[:fig_ext] = fig_ext
|
||||
end
|
||||
doc.chunk_defaults[:fig_ext] = isnothing(fig_ext) ? doc.format.fig_ext : fig_ext
|
||||
doc.chunk_defaults[:fig_path] = fig_path
|
||||
return nothing
|
||||
end
|
||||
|
||||
function collect_results(chunk::CodeChunk, fmt::ScriptResult)
|
||||
function collect_results(chunk::CodeChunk)
|
||||
content = ""
|
||||
result_no = 1
|
||||
result_chunks = CodeChunk[]
|
||||
for r in chunk.result
|
||||
content *= r.code
|
||||
# Check if there is any output from chunk
|
||||
if strip(r.stdout) == "" && isempty(r.figures) && strip(r.rich_output) == ""
|
||||
content *= r.code
|
||||
else
|
||||
content = "\n" * content * r.code
|
||||
if any(!isempty ∘ strip, (r.stdout, r.rich_output)) || !isempty(r.figures)
|
||||
rchunk = CodeChunk(
|
||||
content,
|
||||
chunk.number,
|
||||
|
@ -414,17 +353,14 @@ function collect_results(chunk::CodeChunk, fmt::ScriptResult)
|
|||
chunk.optionstring,
|
||||
copy(chunk.options),
|
||||
)
|
||||
content = ""
|
||||
rchunk.result_no = result_no
|
||||
result_no *= 1
|
||||
rchunk.figures = r.figures
|
||||
rchunk.output = r.stdout * r.displayed
|
||||
rchunk.output = r.stdout
|
||||
rchunk.rich_output = r.rich_output
|
||||
rchunk.figures = r.figures
|
||||
push!(result_chunks, rchunk)
|
||||
content = ""
|
||||
end
|
||||
end
|
||||
if content != ""
|
||||
startswith(content, "\n") || (content = "\n" * content)
|
||||
if !isempty(content)
|
||||
rchunk = CodeChunk(
|
||||
content,
|
||||
chunk.number,
|
||||
|
@ -438,14 +374,12 @@ function collect_results(chunk::CodeChunk, fmt::ScriptResult)
|
|||
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 in chunk.result
|
||||
output *= prompt * r.code
|
||||
output *= r.displayed * r.stdout
|
||||
output *= string('\n', indent_term_code(prompt, r.code), '\n', r.stdout)
|
||||
if !isempty(r.figures)
|
||||
rchunk = CodeChunk(
|
||||
"",
|
||||
|
@ -460,7 +394,7 @@ function collect_results(chunk::CodeChunk, fmt::TermResult)
|
|||
push!(result_chunks, rchunk)
|
||||
end
|
||||
end
|
||||
if output != ""
|
||||
if !isempty(output)
|
||||
rchunk = CodeChunk(
|
||||
"",
|
||||
chunk.number,
|
||||
|
@ -475,8 +409,16 @@ function collect_results(chunk::CodeChunk, fmt::TermResult)
|
|||
return result_chunks
|
||||
end
|
||||
|
||||
function collect_results(chunk::CodeChunk, fmt::CollectResult)
|
||||
result_no = 1
|
||||
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
|
||||
|
@ -503,7 +445,7 @@ function _replace_header_inline!(doc, header, report, mod)
|
|||
end
|
||||
|
||||
function run_inline_code(code, doc, report, mod)
|
||||
inline = InlineCode(code, 1, 1, 1, :inline)
|
||||
inline = InlineCode(code, 1, :inline)
|
||||
inline = run_inline(inline, doc, report, mod)
|
||||
return strip(inline.output, '"')
|
||||
end
|
||||
|
|
74
src/types.jl
74
src/types.jl
|
@ -1,6 +1,8 @@
|
|||
# TODO: concreate typing
|
||||
|
||||
abstract type WeaveChunk end
|
||||
abstract type Inline end
|
||||
abstract type WeaveFormat end
|
||||
|
||||
mutable struct WeaveDoc
|
||||
source::AbstractString
|
||||
|
@ -12,49 +14,41 @@ mutable struct WeaveDoc
|
|||
doctype::String
|
||||
header_script::String
|
||||
header::Dict
|
||||
template::Union{AbstractString,Mustache.MustacheTokens}
|
||||
css::AbstractString
|
||||
highlight_theme::Type{<:Highlights.AbstractTheme}
|
||||
fig_path::AbstractString
|
||||
chunk_defaults::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
struct ChunkOutput
|
||||
code::AbstractString
|
||||
stdout::AbstractString
|
||||
displayed::AbstractString
|
||||
rich_output::AbstractString
|
||||
figures::Vector{AbstractString}
|
||||
code::String
|
||||
stdout::String
|
||||
rich_output::String
|
||||
figures::Vector{String}
|
||||
end
|
||||
|
||||
mutable struct CodeChunk <: WeaveChunk
|
||||
content::AbstractString
|
||||
content::String
|
||||
number::Int
|
||||
result_no::Int
|
||||
start_line::Int
|
||||
optionstring::AbstractString
|
||||
optionstring::String
|
||||
options::Dict{Symbol,Any}
|
||||
output::AbstractString
|
||||
rich_output::AbstractString
|
||||
figures::Vector{AbstractString}
|
||||
figures::Vector{String}
|
||||
result::Vector{ChunkOutput}
|
||||
function CodeChunk(content, number, start_line, optionstring, options)
|
||||
new(
|
||||
rstrip(content) * "\n",
|
||||
number,
|
||||
0,
|
||||
start_line,
|
||||
optionstring,
|
||||
options,
|
||||
"",
|
||||
"",
|
||||
AbstractString[],
|
||||
ChunkOutput[],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
abstract type Inline 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}
|
||||
|
@ -62,27 +56,17 @@ mutable struct DocChunk <: WeaveChunk
|
|||
start_line::Int
|
||||
end
|
||||
|
||||
mutable struct InlineText <: Inline
|
||||
content::AbstractString
|
||||
si::Int
|
||||
ei::Int
|
||||
struct InlineText <: Inline
|
||||
content::String
|
||||
number::Int
|
||||
end
|
||||
|
||||
mutable struct InlineCode <: Inline
|
||||
content::AbstractString
|
||||
si::Int
|
||||
ei::Int
|
||||
content::String
|
||||
number::Int
|
||||
ctype::Symbol
|
||||
output::AbstractString
|
||||
rich_output::AbstractString
|
||||
figures::Vector{AbstractString}
|
||||
function InlineCode(content, si, ei, number, ctype)
|
||||
new(content, si, ei, number, ctype, "", "", AbstractString[])
|
||||
end
|
||||
output::String
|
||||
rich_output::String
|
||||
figures::Vector{String}
|
||||
end
|
||||
|
||||
struct TermResult end
|
||||
struct ScriptResult end
|
||||
struct CollectResult end
|
||||
InlineCode(content, number, ctype) = InlineCode(content, number, ctype, "", "", String[])
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
function write_doc(docformat::LaTeX2PDF, 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
|
|
@ -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)
|
||||
-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
|
|
@ -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")
|
|
@ -16,10 +16,10 @@
|
|||
<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 }}}
|
||||
{{{ :highlight_stylesheet }}}
|
||||
|
||||
<style type="text/css">
|
||||
{{{ :themecss }}}
|
||||
{{{ :stylesheet }}}
|
||||
</style>
|
||||
</HEAD>
|
||||
|
||||
|
@ -38,8 +38,8 @@
|
|||
<HR/>
|
||||
<div class="footer">
|
||||
<p>
|
||||
Published from <a href="{{{:source}}}">{{{:source}}}</a>
|
||||
using <a href="http://github.com/JunoLab/Weave.jl">Weave.jl</a> {{:wversion}} on {{:wdate}}.
|
||||
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>
|
|
@ -7,6 +7,9 @@
|
|||
\usepackage{graphicx}
|
||||
\usepackage{microtype}
|
||||
\usepackage{hyperref}
|
||||
{{#:tex_deps}}
|
||||
{{{ :tex_deps }}}
|
||||
{{/:tex_deps}}
|
||||
\setlength{\parindent}{0pt}
|
||||
\setlength{\parskip}{1.2ex}
|
||||
|
|
@ -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 $wdate$.
|
||||
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>
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
|
@ -1,6 +0,0 @@
|
|||
Functions:
|
||||
|
||||
<<>>=
|
||||
f(x)=x^2
|
||||
println(f(2))
|
||||
@
|
|
@ -1,13 +0,0 @@
|
|||
Functions:
|
||||
|
||||
~~~~{.julia}
|
||||
f(x)=x^2
|
||||
println(f(2))
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
~~~~
|
||||
4
|
||||
~~~~
|
||||
|
||||
|
|
@ -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.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}\
|
||||
|
|
@ -1,17 +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)
|
|
@ -1,17 +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)
|
|
@ -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){#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}\
|
||||
|
|
@ -1,17 +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)
|
|
@ -1,22 +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}
|
|
@ -1,22 +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}
|
|
@ -1,22 +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}
|
|
@ -1,22 +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}}
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
weave_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)
|
||||
@
|
|
@ -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"])
|
||||
)
|
||||
```
|
|
@ -1,22 +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'>"Testing output"</span><span class='hljl-p'>)</span>
|
||||
</pre>
|
||||
|
||||
|
||||
<pre class="output">
|
||||
Testing output
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
|
@ -1,22 +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}
|
||||
|
|
@ -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
|
||||
```
|
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
title: A minimal beamer example using Weave markdown
|
||||
author: Matti Pastell
|
||||
weave_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")
|
|
@ -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
|
||||
|
||||
""")
|
||||
```
|
|
@ -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**
|
||||
|
|
@ -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"text/html"</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'>"<table>"</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'>"<tr>"</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'>"<td></span><span class='hljl-si'>$r</span><span class='hljl-s'></td>"</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'>"</tr>"</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'>"</table>"</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't valid latex, doesn'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"text/latex"</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'>"</span><span class='hljl-se'>\\</span><span class='hljl-s'>begin{tabular}"</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'>"</span><span class='hljl-si'>$r</span><span class='hljl-s'> & "</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'>"</span><span class='hljl-se'>\\\\</span><span class='hljl-s'>"</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'>" </span><span class='hljl-se'>\\</span><span class='hljl-s'>hline"</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'>"</span><span class='hljl-se'>\\</span><span class='hljl-s'>end{tabular"</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't valid markdown, doesn'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"text/markdown"</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'>"-----"</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'>"| "</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'>"</span><span class='hljl-si'>$r</span><span class='hljl-s'> | "</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'>""</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'>"-----"</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'>'a'</span><span class='hljl-oB'>:</span><span class='hljl-sc'>'d'</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> </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> </span><span class='hljl-n'>ca</span><span class='hljl-t'>
|
||||
4-element Array{Char,1}:
|
||||
'a'
|
||||
'b'
|
||||
'c'
|
||||
'd'</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'>"**Some Markdown**"</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>
|
||||
|
|
@ -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**
|
||||
|
|
@ -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}
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
using Plots
|
||||
pyplot()
|
||||
x = range(0, stop=2*pi, length=50)
|
||||
println(x)
|
||||
p = plot(x = x, y = sin(x), size =(900,300))
|
||||
|
||||
plot(x = x, y = sin(x))
|
||||
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
|
||||
plot(y = cumsum(randn(1000, 1)))
|
|
@ -1,60 +0,0 @@
|
|||
~~~~{.julia}
|
||||
using Plots
|
||||
pyplot()
|
||||
x = linspace(0, 2*pi)
|
||||
println(x)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
~~~~
|
||||
linspace(0.0,6.283185307179586,50)
|
||||
~~~~
|
||||
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
p = plot(x, sin(x), size =(900,300))
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
julia> plot(x, sin(x))
|
||||
|
||||
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/plotsjl_test_2_1.png)\
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/plotsjl_test_3_1.png)\
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
julia> plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
|
||||
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/plotsjl_test_4_1.png)\
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
julia> scatter!(rand(100),markersize=6,c=:orange)
|
||||
|
||||
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/plotsjl_test_4_2.png)\
|
||||
|
||||
|
||||
![A random walk.](figures/plotsjl_test_random_1.png)
|
|
@ -1,47 +0,0 @@
|
|||
\begin{juliacode}
|
||||
using Plots
|
||||
pyplot()
|
||||
x = linspace(0, 2*pi)
|
||||
println(x)
|
||||
\end{juliacode}
|
||||
\begin{juliaout}
|
||||
linspace(0.0,6.283185307179586,50)
|
||||
\end{juliaout}
|
||||
|
||||
\begin{juliacode}
|
||||
p = plot(x, sin(x), size =(900,300))
|
||||
\end{juliacode}
|
||||
|
||||
\begin{juliaterm}
|
||||
julia> plot(x, sin(x))
|
||||
|
||||
|
||||
\end{juliaterm}
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_2_1.pdf}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_3_1.pdf}
|
||||
|
||||
\begin{juliaterm}
|
||||
julia> plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
|
||||
|
||||
\end{juliaterm}
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_4_1.pdf}
|
||||
|
||||
\begin{juliaterm}
|
||||
julia> scatter!(rand(100),markersize=6,c=:orange)
|
||||
|
||||
|
||||
\end{juliaterm}
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_4_2.pdf}
|
||||
|
||||
\begin{figure}[htpb]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_random_1.pdf}
|
||||
\caption{A random walk.}
|
||||
\label{fig:random}
|
||||
\end{figure}
|
|
@ -1,41 +0,0 @@
|
|||
~~~~{.julia}
|
||||
using Plots
|
||||
gr()
|
||||
x = range(0, stop=2π, length=50)
|
||||
println(x)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
~~~~
|
||||
0.0:0.1282282715750936:6.283185307179586
|
||||
~~~~
|
||||
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
p = plot(x, sin.(x), size =(900,300))
|
||||
p
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/plotsjl_test_gr_1_1.png)\
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
plot(x, sin.(x))
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/plotsjl_test_gr_2_1.png)\
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/plotsjl_test_gr_3_1.png)\
|
||||
|
||||
|
||||
![A random walk.](figures/plotsjl_test_gr_random_1.png){#fig:random}
|
|
@ -1,33 +0,0 @@
|
|||
\begin{juliacode}
|
||||
using Plots
|
||||
gr()
|
||||
x = range(0, stop=2π, length=50)
|
||||
println(x)
|
||||
\end{juliacode}
|
||||
\begin{juliaout}
|
||||
0.0:0.1282282715750936:6.283185307179586
|
||||
\end{juliaout}
|
||||
|
||||
\begin{juliacode}
|
||||
p = plot(x, sin.(x), size =(900,300))
|
||||
p
|
||||
\end{juliacode}
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_gr_1_1.pdf}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x, sin.(x))
|
||||
\end{juliacode}
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_gr_2_1.pdf}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_gr_3_1.pdf}
|
||||
|
||||
\begin{figure}[htpb]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/plotsjl_test_gr_random_1.pdf}
|
||||
\caption{A random walk.}
|
||||
\label{fig:random}
|
||||
\end{figure}
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
|
||||
```julia
|
||||
using Plots
|
||||
pyplot()
|
||||
x = linspace(0, 2*pi)
|
||||
println(x)
|
||||
p = plot(x, sin(x), size =(900,300))
|
||||
```
|
||||
|
||||
|
||||
```julia; term=true
|
||||
plot(x, sin(x))
|
||||
```
|
||||
|
||||
```julia
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
```
|
||||
|
||||
```julia; term=true
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
```
|
||||
|
||||
|
||||
```{julia;echo=false; fig_cap="A random walk."; label="random"}
|
||||
plot(cumsum(randn(1000, 1)))
|
||||
```
|
|
@ -1,25 +0,0 @@
|
|||
|
||||
|
||||
```julia
|
||||
using Plots
|
||||
gr()
|
||||
x = range(0, stop=2π, length=50)
|
||||
println(x)
|
||||
p = plot(x, sin.(x), size =(900,300))
|
||||
p
|
||||
```
|
||||
|
||||
|
||||
```julia
|
||||
plot(x, sin.(x))
|
||||
```
|
||||
|
||||
```julia
|
||||
plot(rand(100) / 3,reg=true,fill=(0,:green))
|
||||
scatter!(rand(100),markersize=6,c=:orange)
|
||||
```
|
||||
|
||||
|
||||
```{julia;echo=false; fig_cap="A random walk."; label="random"}
|
||||
plot(cumsum(randn(1000, 1), dims=1))
|
||||
```
|
|
@ -1,58 +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
|
||||
```
|
||||
|
||||
```julia; hold=true
|
||||
display(ca)
|
||||
display(x)
|
||||
```
|
||||
|
||||
```julia; term=true
|
||||
x
|
||||
ca
|
||||
```
|
||||
|
||||
|
||||
```julia
|
||||
using Markdown
|
||||
m = Markdown.parse("**Some Markdown**")
|
||||
m
|
||||
```
|
|
@ -1,37 +0,0 @@
|
|||
|
||||
y= [2, 5, 12]
|
||||
|
||||
|
||||
x = 1:10
|
||||
d = Dict("Weave" => "testing")
|
||||
y = [2, 4 ,8]
|
||||
|
||||
|
||||
x = [12, 10]
|
||||
println(y)
|
||||
println(x)
|
||||
|
||||
|
||||
println("Results without code")
|
||||
println(x)
|
||||
|
||||
|
||||
y = 1:5
|
||||
println(y)
|
||||
|
||||
|
||||
a = "Don't print me"
|
||||
println(a)
|
||||
|
||||
|
||||
println("No markup for results.")
|
||||
|
||||
|
||||
println(collect(0:10:1000))
|
||||
|
||||
|
||||
println(collect(0:10:1000))
|
||||
|
||||
|
||||
println(collect(0:10:1000))
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
```julia
|
||||
p = Array(linspace(0, 2π))
|
||||
```
|
||||
|
||||
```julia;term=true
|
||||
p = Array(linspace(0, 2π))
|
||||
```
|
||||
|
||||
```julia;term=true
|
||||
p = Array(linspace(0, 2π));
|
||||
```
|
|
@ -1,73 +0,0 @@
|
|||
|
||||
~~~~{.julia}
|
||||
p = Array(linspace(0, 2π))
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
julia> p = Array(linspace(0, 2π))
|
||||
50-element Array{Float64,1}:
|
||||
0.0
|
||||
0.128228
|
||||
0.256457
|
||||
0.384685
|
||||
0.512913
|
||||
0.641141
|
||||
0.76937
|
||||
0.897598
|
||||
1.02583
|
||||
1.15405
|
||||
1.28228
|
||||
1.41051
|
||||
1.53874
|
||||
1.66697
|
||||
1.7952
|
||||
1.92342
|
||||
2.05165
|
||||
2.17988
|
||||
2.30811
|
||||
2.43634
|
||||
2.56457
|
||||
2.69279
|
||||
2.82102
|
||||
2.94925
|
||||
3.07748
|
||||
3.20571
|
||||
3.33394
|
||||
3.46216
|
||||
3.59039
|
||||
3.71862
|
||||
3.84685
|
||||
3.97508
|
||||
4.1033
|
||||
4.23153
|
||||
4.35976
|
||||
4.48799
|
||||
4.61622
|
||||
4.74445
|
||||
4.87267
|
||||
5.0009
|
||||
5.12913
|
||||
5.25736
|
||||
5.38559
|
||||
5.51382
|
||||
5.64204
|
||||
5.77027
|
||||
5.8985
|
||||
6.02673
|
||||
6.15496
|
||||
6.28319
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
julia> p = Array(linspace(0, 2π));
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# NOTE:
|
||||
# This test file does end to end tests, while we don't want to check the details in the generated documents.
|
||||
# Rather, we just assert we can `weave` all the supported formats without errors here.
|
||||
|
||||
# TODO:
|
||||
# - more complex example
|
||||
# - integration with other libraries, like Plots
|
||||
|
||||
@testset "end2end simple" begin
|
||||
include("test_simple.jl")
|
||||
end # @testset "end2end"
|
|
@ -0,0 +1,47 @@
|
|||
using Weave.Dates
|
||||
|
||||
|
||||
test_doctypes = filter(first.(Weave.list_out_formats())) do doctype
|
||||
# don't test doctypes which need external programs
|
||||
doctype ∉ ("pandoc2html", "pandoc2pdf", "md2pdf", "minted2pdf")
|
||||
end
|
||||
|
||||
function test_func(body)
|
||||
@test !isempty(body)
|
||||
date_str = string(Date(now()))
|
||||
@test occursin(date_str, body)
|
||||
end
|
||||
|
||||
# julia markdown
|
||||
julia_markdown_body = """
|
||||
# doc chunk
|
||||
|
||||
this is text with `j :inline` code
|
||||
|
||||
code chunk:
|
||||
```julia
|
||||
using Dates
|
||||
Date(now())
|
||||
```
|
||||
"""
|
||||
for doctype in test_doctypes
|
||||
test_mock_weave(test_func, julia_markdown_body; informat = "markdown", doctype = doctype)
|
||||
end
|
||||
|
||||
# TODO: test noweb format
|
||||
|
||||
# julia script
|
||||
julia_script_body = """
|
||||
#' # doc chunk
|
||||
#'
|
||||
#' this is text with `j :inline` code
|
||||
#'
|
||||
#' code chunk:
|
||||
#+
|
||||
|
||||
using Dates
|
||||
Date(now())
|
||||
"""
|
||||
for doctype in test_doctypes
|
||||
test_mock_weave(test_func, julia_script_body; informat = "script", doctype = doctype)
|
||||
end
|
|
@ -1,49 +0,0 @@
|
|||
using Weave
|
||||
using Test
|
||||
|
||||
# Make a dummy codehunk with figure
|
||||
chunk = Weave.CodeChunk("plot(x)", 1, 1, "", Dict())
|
||||
options = merge(Weave.get_chunk_defaults(), chunk.options)
|
||||
merge!(chunk.options, options)
|
||||
chunk.figures = ["figs/figures_plot1.png"]
|
||||
|
||||
@test Weave.formatfigures(chunk, Weave.md2tex) == "\\includegraphics{figs/figures_plot1.png}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.tex) == "\\includegraphics{figs/figures_plot1.png}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.texminted) == "\\includegraphics{figs/figures_plot1.png}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.pandoc) == "![](figs/figures_plot1.png)\\ \n\n"
|
||||
@test Weave.formatfigures(chunk, Weave.github) == "![](figs/figures_plot1.png)\n"
|
||||
@test Weave.formatfigures(chunk, Weave.hugo) == "{{< figure src=\"../figs/figures_plot1.png\" >}}"
|
||||
@test Weave.formatfigures(chunk, Weave.multimarkdown) == "![][figs/figures_plot1.png]\n\n[figs/figures_plot1.png]: figs/figures_plot1.png \n"
|
||||
@test Weave.formatfigures(chunk, Weave.md2html) == "<img src=\"figs/figures_plot1.png\" />\n"
|
||||
|
||||
chunk.options[:out_width] = "100%"
|
||||
@test Weave.formatfigures(chunk, Weave.adoc) == "image::figs/figures_plot1.png[width=100%]\n"
|
||||
@test Weave.formatfigures(chunk, Weave.rst) == ".. image:: figs/figures_plot1.png\n :width: 100%\n\n"
|
||||
|
||||
chunk.options[:fig_cap] = "Nice plot"
|
||||
@test Weave.formatfigures(chunk, Weave.tex) == "\\begin{figure}[!h]\n\\center\n\\includegraphics[width=1.0\\linewidth]{figs/figures_plot1.png}\n\\caption{Nice plot}\n\\end{figure}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.pandoc) == "![Nice plot](figs/figures_plot1.png){width=100%}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.md2tex) == "\\begin{figure}[!h]\n\\center\n\\includegraphics[width=1.0\\linewidth]{figs/figures_plot1.png}\n\\caption{Nice plot}\n\\end{figure}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.md2html) == "<figure>\n<img src=\"figs/figures_plot1.png\" width=\"100%\" />\n<figcaption>Nice plot</figcaption>\n</figure>\n"
|
||||
@test Weave.formatfigures(chunk, Weave.rst) == ".. figure:: figs/figures_plot1.png\n :width: 100%\n\n Nice plot\n\n"
|
||||
@test Weave.formatfigures(chunk, Weave.multimarkdown) == "![Nice plot][figs/figures_plot1.png]\n\n[figs/figures_plot1.png]: figs/figures_plot1.png width=100%\n"
|
||||
@test Weave.formatfigures(chunk, Weave.adoc) == "image::figs/figures_plot1.png[width=100%,title=\"Nice plot\"]"
|
||||
|
||||
chunk.options[:label] = "somefig"
|
||||
@test Weave.formatfigures(chunk, Weave.pandoc) == "![Nice plot](figs/figures_plot1.png){width=100% #fig:somefig}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.tex) == "\\begin{figure}[!h]\n\\center\n\\includegraphics[width=1.0\\linewidth]{figs/figures_plot1.png}\n\\caption{Nice plot}\n\\label{fig:somefig}\n\\end{figure}\n"
|
||||
@test Weave.formatfigures(chunk, Weave.tex) == Weave.formatfigures(chunk, Weave.md2tex)
|
||||
|
||||
chunk.options[:label] = nothing
|
||||
chunk.options[:fig_cap] = nothing
|
||||
chunk.options[:fig_env] = "center"
|
||||
chunk.options[:fig_pos] = ""
|
||||
@test Weave.formatfigures(chunk, Weave.tex) == "\\begin{center}\n\\includegraphics[width=1.0\\linewidth]{figs/figures_plot1.png}\n\\end{center}\n"
|
||||
|
||||
chunk.options[:out_width] = "50%"
|
||||
chunk.options[:out_height] = "75 %"
|
||||
@test Weave.formatfigures(chunk, Weave.tex) == "\\begin{center}\n\\includegraphics[width=0.5\\linewidth,height=0.75\\paperheight]{figs/figures_plot1.png}\n\\end{center}\n"
|
||||
|
||||
chunk.options[:out_width] = "A%"
|
||||
chunk.options[:out_height] = "0.5\\textwidth"
|
||||
@test Weave.formatfigures(chunk, Weave.tex) == "\\begin{center}\n\\includegraphics[width=A%,height=0.5\\textwidth]{figs/figures_plot1.png}\n\\end{center}\n"
|
|
@ -1,122 +0,0 @@
|
|||
# Test rendering of doc chunks
|
||||
content = """
|
||||
# Test chunk
|
||||
|
||||
Test rendering \$\alpha\$
|
||||
"""
|
||||
|
||||
dchunk = Weave.DocChunk(content, 1, 1)
|
||||
|
||||
pformat = Weave.formats["github"]
|
||||
f = Weave.format_chunk(dchunk, pformat.formatdict, pformat)
|
||||
@test f == content
|
||||
|
||||
docformat = Weave.formats["md2html"]
|
||||
f_check = "<h1>Test chunk</h1>\n<p>Test rendering <span class=\"math\">\$\alpha\$</span></p>\n"
|
||||
f = Weave.format_chunk(dchunk, docformat.formatdict, docformat)
|
||||
@test f_check == f
|
||||
|
||||
# Test with actual doc
|
||||
|
||||
parsed = Weave.WeaveDoc("documents/chunk_options.noweb")
|
||||
doc = run_doc(parsed, doctype = "md2html")
|
||||
|
||||
c_check = "<pre class='hljl'>\n<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-ni'>12</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-ni'>10</span><span class='hljl-p'>]</span><span class='hljl-t'>\n</span><span class='hljl-nf'>println</span><span class='hljl-p'>(</span><span class='hljl-n'>y</span><span class='hljl-p'>)</span>\n</pre>\n"
|
||||
doc.format.formatdict[:theme] = doc.highlight_theme
|
||||
c = Weave.format_code(doc.chunks[3].content, doc.format)
|
||||
@test c_check == c
|
||||
|
||||
o_check = "\nprintln(x)\n"
|
||||
o = Weave.format_output(doc.chunks[4].content, doc.format)
|
||||
@test o_check == o
|
||||
|
||||
doc.template = "templates/mini.tpl"
|
||||
rendered = Weave.render_doc("Hello", doc)
|
||||
@test rendered == "\nHello\n"
|
||||
|
||||
# Tex format
|
||||
parsed = Weave.WeaveDoc("documents/chunk_options.noweb")
|
||||
doc = run_doc(parsed, doctype = "md2tex")
|
||||
|
||||
c_check = "\\begin{lstlisting}\n(*@\\HLJLnf{println}@*)(*@\\HLJLp{(}@*)(*@\\HLJLn{x}@*)(*@\\HLJLp{)}@*)\n\\end{lstlisting}\n"
|
||||
doc.format.formatdict[:theme] = doc.highlight_theme
|
||||
c = Weave.format_code(doc.chunks[4].content, doc.format)
|
||||
@test c_check == c
|
||||
|
||||
o_check = "\nx = [12, 10]\nprintln(y)\n"
|
||||
o = Weave.format_output(doc.chunks[3].content, doc.format)
|
||||
@test o_check == o
|
||||
|
||||
doc.template = "templates/mini.tpl"
|
||||
rendered = Weave.render_doc("Hello", doc)
|
||||
@test rendered == "\nHello\n"
|
||||
|
||||
# Test wrapping
|
||||
|
||||
cows = repeat("🐄", 100)
|
||||
testcows = """
|
||||
🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄
|
||||
🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄🐄"""
|
||||
|
||||
wcows = Weave.wrapline(cows)
|
||||
|
||||
@test wcows == testcows
|
||||
@test length(split(wcows, "\n")[1]) == 75
|
||||
@test length(split(wcows, "\n")[2]) == 25
|
||||
|
||||
|
||||
tfied = "\\ensuremath{\\bm{\\mathrm{L}}} \\ensuremath{\\bm{\\mathfrak{F}}} \\ensuremath{\\bm{\\iota}} \\ensuremath{\\mathfrak{A}} \\ensuremath{\\bm{\\varTheta}}"
|
||||
|
||||
@test Weave.uc2tex("𝐋 𝕱 𝛊 𝔄 𝚹") == tfied
|
||||
|
||||
# Test markdown output from chunks
|
||||
parsed = Weave.WeaveDoc("documents/markdown_output.jmd")
|
||||
doc = run_doc(parsed, doctype = "md2html")
|
||||
@test doc.chunks[1].rich_output == "\n<div class=\"markdown\"><h3>Small markdown sample</h3>\n<p><strong>Hello</strong> from <code>code</code> block.</p>\n</div>"
|
||||
@test doc.chunks[2].rich_output == "\n<div class=\"markdown\"><ul>\n<li><p>one</p>\n</li>\n<li><p>two</p>\n</li>\n<li><p>three</p>\n</li>\n</ul>\n</div>"
|
||||
|
||||
ldoc = run_doc(parsed, doctype = "md2tex")
|
||||
@test ldoc.chunks[1].rich_output == "\n\\subsubsection{Small markdown sample}\n\\textbf{Hello} from \\texttt{code} block.\n\n"
|
||||
@test ldoc.chunks[2].rich_output == "\n\\begin{itemize}\n\\item one\n\n\n\\item two\n\n\n\\item three\n\n\\end{itemize}\n"
|
||||
|
||||
mdoc = run_doc(parsed, doctype = "github")
|
||||
@test mdoc.chunks[1].rich_output == "\n\n### Small markdown sample\n\n**Hello** from `code` block.\n\n"
|
||||
@test mdoc.chunks[2].rich_output == "\n\n* one\n* two\n* three\n\n"
|
||||
|
||||
|
||||
# Test disable escaping of unicode
|
||||
@testset "escape/unescape unicode characters" begin
|
||||
|
||||
content = """
|
||||
# Test chunk
|
||||
α
|
||||
"""
|
||||
chunk = Weave.DocChunk(content, 1, 1)
|
||||
fmt = deepcopy(Weave.formats["md2tex"])
|
||||
fmtdict = fmt.formatdict
|
||||
|
||||
f = Weave.format_chunk(chunk, fmtdict, fmt)
|
||||
@test f == "\\section{Test chunk}\n\\ensuremath{\\alpha}\n\n"
|
||||
|
||||
fmtdict[:keep_unicode] = true
|
||||
f = Weave.format_chunk(chunk, fmtdict, fmt)
|
||||
@test f == "\\section{Test chunk}\nα\n\n"
|
||||
|
||||
|
||||
str = """
|
||||
```julia
|
||||
α = 10
|
||||
```
|
||||
"""
|
||||
doc = mock_doc(str; doctype = "md2tex")
|
||||
doc = Weave.format(doc)
|
||||
@test occursin(Weave.uc2tex("α"), doc)
|
||||
@test !occursin("α", doc)
|
||||
|
||||
doc = mock_doc(str; doctype = "md2tex")
|
||||
doc.format.formatdict[:keep_unicode] = true
|
||||
doc = Weave.format(doc)
|
||||
@test occursin("α", doc)
|
||||
@test !occursin(Weave.uc2tex("α"), doc)
|
||||
|
||||
end
|
|
@ -1,31 +0,0 @@
|
|||
# Test for Gadfly with different chunk options and figure formatsusing Weave
|
||||
|
||||
using Gadfly, Cairo
|
||||
|
||||
|
||||
function test_gadfly(doctype, fig_ext)
|
||||
out = weave(
|
||||
joinpath(@__DIR__ , "documents/gadfly_formats_test.jnw"),
|
||||
doctype = doctype,
|
||||
fig_ext = fig_ext
|
||||
)
|
||||
result = read(out, String)
|
||||
# cp(out, out*fig_ext*"."*doctype, force=true) # Used when adding new tests
|
||||
ref = read(out*fig_ext*"."*doctype, String)
|
||||
@test result == ref
|
||||
rm(out)
|
||||
end
|
||||
|
||||
test_gadfly("github", ".png")
|
||||
test_gadfly("github", ".pdf")
|
||||
test_gadfly("github", ".svg")
|
||||
test_gadfly("pandoc", ".png")
|
||||
test_gadfly("pandoc", ".js.svg")
|
||||
test_gadfly("tex", ".pdf")
|
||||
test_gadfly("tex", ".png")
|
||||
test_gadfly("tex", ".ps")
|
||||
test_gadfly("tex", ".tex")
|
||||
|
||||
p = Gadfly.plot(x=1:10, y=1:10)
|
||||
@test showable(MIME"application/pdf"(), p) == true
|
||||
@test showable(MIME"application/png"(), p) == true
|
|
@ -1,47 +0,0 @@
|
|||
using Mustache
|
||||
|
||||
# Test parsing
|
||||
|
||||
doc = """
|
||||
|
||||
! println("Something")
|
||||
|
||||
Some markdown with inline stuff and `j code`
|
||||
|
||||
! Not julia code but `j show("is")`
|
||||
|
||||
"""
|
||||
|
||||
ms = collect(eachmatch(Weave.INLINE_REGEXES, doc))
|
||||
@test ms[1][2] == "println(\"Something\")"
|
||||
@test ms[2][1] == "code"
|
||||
@test ms[3][1] == "show(\"is\")"
|
||||
|
||||
let
|
||||
_, chunks = Weave.parse_markdown(doc)
|
||||
chunk = first(chunks)
|
||||
@test length(chunk.content) == 7
|
||||
@test chunk.content[2].content == ms[1][2]
|
||||
@test chunk.content[4].content == ms[2][1]
|
||||
@test chunk.content[6].content == ms[3][1]
|
||||
end
|
||||
|
||||
let
|
||||
_, chunks = Weave.parse_markdown(doc)
|
||||
chunk = first(chunks)
|
||||
@test all([chunk.content[i].content == chunk.content[i].content for i in 1:7])
|
||||
end
|
||||
|
||||
# Test with document
|
||||
|
||||
tpl = mt"""
|
||||
{{{ :body }}}
|
||||
"""
|
||||
|
||||
out = weave(joinpath(@__DIR__, "documents", "markdown_beamer.jmd"), doctype="md2html", template=tpl)
|
||||
@test read(out, String) == read(out*".ref", String)
|
||||
rm(out)
|
||||
|
||||
out = weave(joinpath(@__DIR__, "documents", "markdown_beamer.jmd"), doctype="md2tex", template=tpl)
|
||||
@test read(out, String) == read(out*".ref", String)
|
||||
rm(out)
|
|
@ -1,6 +1,9 @@
|
|||
using Test
|
||||
import Weave: WeaveMarkdown
|
||||
import Markdown
|
||||
# TODO: make this more sensible:
|
||||
# - separate tests for
|
||||
# 1. features that are "copy-and-pasted" from `Markdown` module
|
||||
# 2. features that are extended by Weave
|
||||
|
||||
using Weave: WeaveMarkdown, Markdown
|
||||
|
||||
# Test markdown2html writer
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -1,7 +0,0 @@
|
|||
file = joinpath(@__DIR__, "documents", "jupyter_test.jmd")
|
||||
using IJulia, Conda
|
||||
|
||||
Conda.add("nbconvert") # should be the same as IJulia.JUPYTER, i.e. the miniconda Python
|
||||
|
||||
Weave.notebook(file, jupyter_path = IJulia.JUPYTER)
|
||||
@test "jupyter_test.ipynb" ∈ readdir(@__DIR__) # test if the result was weaved
|
|
@ -1,22 +0,0 @@
|
|||
using Plots
|
||||
|
||||
|
||||
function pljtest(source, resfile, doctype)
|
||||
weave("documents/$source", out_path = "documents/plotsjl/$resfile", doctype=doctype)
|
||||
result = read("documents/plotsjl/$resfile", String)
|
||||
ref = read("documents/plotsjl/$resfile.ref", String)
|
||||
@test result == ref
|
||||
rm("documents/plotsjl/$resfile")
|
||||
end
|
||||
|
||||
pljtest("plotsjl_test_gr.jmd", "plotsjl_test_gr.md", "pandoc")
|
||||
pljtest("plotsjl_test_gr.jmd", "plotsjl_test_gr.tex", "tex")
|
||||
|
||||
# test cache with plots
|
||||
isdir("documents/cache") && rm("documents/cache", recursive = true)
|
||||
weave("documents/plotsjl_test_gr.jmd", cache=:all)
|
||||
result = read("documents/plotsjl_test_gr.html", String)
|
||||
rm("documents/plotsjl_test_gr.html")
|
||||
weave("documents/plotsjl_test_gr.jmd", cache=:all)
|
||||
cached_result = read("documents/plotsjl_test_gr.html", String)
|
||||
@test result == cached_result
|
|
@ -0,0 +1,102 @@
|
|||
using Weave: parse_options, parse_markdown
|
||||
|
||||
|
||||
@testset "`parse_options`" begin
|
||||
|
||||
# general
|
||||
@test isempty(parse_options(""))
|
||||
@test (:opt => nothing) in parse_options("opt = nothing")
|
||||
|
||||
# Weave style -- semicolon separated
|
||||
let opts = parse_options("opt1 = 1; opt2 = \"2\"")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
# robust parsing
|
||||
@test let opts = parse_options("invalid; valid = nothing")
|
||||
@test (:valid => nothing) in opts
|
||||
true
|
||||
end
|
||||
|
||||
# RMarkdown style -- comma separated
|
||||
let opts = parse_options("opt1 = 1, opt2 = \"2\"")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
# robust parsing
|
||||
@test let opts = parse_options("invalid, valid = nothing")
|
||||
@test (:valid => nothing) in opts
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@testset "`parse_markdown` Julia markdown format" begin
|
||||
|
||||
get_options(str) =
|
||||
(chunk = first(last(parse_markdown(str))); @test hasproperty(chunk, :options); chunk.options)
|
||||
|
||||
# Julia markdown
|
||||
@test get_options("```julia\n```") |> length === 1
|
||||
@test get_options("```julia \n```") |> length === 1
|
||||
@test get_options("```{julia}\n```") |> length === 1
|
||||
@test get_options("```{julia }\n```") |> length === 1
|
||||
|
||||
# Weave style -- semicolon separated
|
||||
@test get_options("```julia;\n```") |> length === 1
|
||||
@test get_options("```julia ;\n```") |> length === 1
|
||||
@test get_options("```julia; \n```") |> length === 1
|
||||
@test (:opt => nothing) in get_options("```julia; opt = nothing\n```")
|
||||
@test (:opt => nothing) in get_options("```{julia; opt = nothing}\n```")
|
||||
let opts = get_options("```julia; opt1 = 1; opt2 = \"2\"\n```")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
let opts = get_options("```{julia; opt1 = 1; opt2 = \"2\"}\n```")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
|
||||
# RMarkdown style -- comma separated
|
||||
@test get_options("```julia,\n```") |> length === 1
|
||||
@test get_options("```julia ,\n```") |> length === 1
|
||||
@test get_options("```julia, \n```") |> length === 1
|
||||
@test (:opt => nothing) in get_options("```julia, opt = nothing\n```")
|
||||
@test (:opt => nothing) in get_options("```{julia, opt = nothing}\n```")
|
||||
let opts = get_options("```{julia, opt1 = 1, opt2 = \"2\"}\n```")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
let opts = get_options("```julia, opt1 = 1, opt2 = \"2\"\n```")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
let opts = get_options("```julia{opt1 = 1, opt2 = \"2\"}\n```")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@testset "`parse_markdown` pandoc format" begin
|
||||
|
||||
get_options(str) =
|
||||
(chunk = first(last(parse_markdown(str; is_pandoc = true))); @test hasproperty(chunk, :options); chunk.options)
|
||||
|
||||
@test get_options("<<>>=\n@") |> length === 1
|
||||
@test (:opt => nothing) in get_options("<<opt = nothing>>=\n@")
|
||||
let opts = get_options("<<opt1 = 1; opt2 = \"2\">>=\n@")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
let opts = get_options("<<opt1 = 1, opt2 = \"2\">>=\n@")
|
||||
@test (:opt1 => 1) in opts
|
||||
@test (:opt2 => "2") in opts
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
# TODO: tests for `"script"` format ?
|
|
@ -0,0 +1,99 @@
|
|||
# TODO: test evaluation
|
||||
|
||||
using Weave.Mustache
|
||||
using Weave: parse_inlines, InlineText, InlineCode
|
||||
|
||||
|
||||
@testset "`parse_inlines` basic" begin
|
||||
|
||||
@test filter(parse_inlines("text")) do chunk
|
||||
chunk isa InlineCode
|
||||
end |> isempty
|
||||
|
||||
@test filter(parse_inlines("text")) do chunk
|
||||
chunk isa InlineText &&
|
||||
chunk.content == "text"
|
||||
end |> length === 1
|
||||
|
||||
@test filter(parse_inlines("`j code`")) do chunk
|
||||
chunk isa InlineCode &&
|
||||
chunk.ctype === :inline &&
|
||||
chunk.content == "code"
|
||||
end |> length == 1
|
||||
|
||||
@test filter(parse_inlines("! code")) do chunk
|
||||
chunk isa InlineCode &&
|
||||
chunk.ctype === :line &&
|
||||
chunk.content == "code"
|
||||
end |> length == 1
|
||||
|
||||
@test filter(parse_inlines("text ! maybe_intended_to_be_code")) do chunk # invalid inline chunk
|
||||
chunk isa InlineText &&
|
||||
chunk.content == "maybe_intended_to_be_code"
|
||||
end |> isempty
|
||||
|
||||
end
|
||||
|
||||
|
||||
@testset "`parse_inlines` multiple lines" begin
|
||||
|
||||
str = """
|
||||
- item1
|
||||
- `j code`
|
||||
- item2
|
||||
"""
|
||||
chunks = parse_inlines(str)
|
||||
|
||||
let chunk = chunks[1]
|
||||
@test chunk isa InlineText
|
||||
@test occursin("- item1", chunk.content)
|
||||
end
|
||||
|
||||
let chunk = chunks[2]
|
||||
@test chunk isa InlineCode
|
||||
@test occursin("code", chunk.content)
|
||||
end
|
||||
|
||||
let chunk = chunks[3]
|
||||
@test chunk isa InlineText
|
||||
@test occursin("- item2", chunk.content)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@testset "`parse_inlines` unicode handling" begin
|
||||
|
||||
str = """
|
||||
- eng1 `j :eng1`
|
||||
- eng2`j :eng2`
|
||||
- 日本語1 `j :日本語1`
|
||||
- 日本語2`j :日本語2`
|
||||
"""
|
||||
chunks = parse_inlines(str)
|
||||
|
||||
@test filter(chunks) do chunk
|
||||
chunk isa InlineCode &&
|
||||
chunk.number === 1 &&
|
||||
chunk.content == ":eng1"
|
||||
end |> length === 1
|
||||
|
||||
@test filter(chunks) do chunk
|
||||
chunk isa InlineCode &&
|
||||
chunk.number === 2 &&
|
||||
chunk.content == ":eng2"
|
||||
end |> length === 1
|
||||
|
||||
@test filter(chunks) do chunk
|
||||
chunk isa InlineCode &&
|
||||
chunk.number === 3 &&
|
||||
chunk.content == ":日本語1"
|
||||
end |> length === 1
|
||||
|
||||
@test filter(chunks) do chunk
|
||||
chunk isa InlineCode &&
|
||||
chunk.number === 4 &&
|
||||
chunk.content == ":日本語2"
|
||||
end |> length === 1
|
||||
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
@testset "unicode to latex conversion" begin
|
||||
unicode2latex(args...) = Weave.unicode2latex(get_format("md2tex"), args...)
|
||||
|
||||
# unit test
|
||||
let
|
||||
s = unicode2latex("α = 10")
|
||||
@test !occursin("α", s)
|
||||
@test occursin("alpha", s)
|
||||
end
|
||||
|
||||
# end2end
|
||||
let
|
||||
str = """
|
||||
```julia
|
||||
α = 10
|
||||
```
|
||||
"""
|
||||
doc = mock_run(str; doctype = "md2tex")
|
||||
Weave.set_format_options!(doc.format)
|
||||
rendered = Weave.render_doc(doc)
|
||||
@test occursin("alpha", rendered)
|
||||
@test !occursin("α", rendered)
|
||||
|
||||
doc = mock_run(str; doctype = "md2tex")
|
||||
Weave.set_format_options!(doc.format; keep_unicode = true)
|
||||
rendered = Weave.render_doc(doc)
|
||||
@test !occursin("alpha", rendered)
|
||||
@test occursin("α", rendered)
|
||||
end
|
||||
end # @testset "rendering tex formats"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue