mirror of https://github.com/mpastell/Weave.jl
Merge remote-tracking branch 'upstream/master'
commit
c3d1c1a071
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
name: bug report
|
||||
about: create a bug report
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!-- Please search existing issues to avoid duplicates. -->
|
||||
|
||||
## description
|
||||
|
||||
|
||||
## versions
|
||||
|
||||
> `using InteractiveUtils; versioninfo()`:
|
||||
<!-- please paste the the output of `using InteractiveUtils; versioninfo()` in the backticks below -->
|
||||
```julia
|
||||
|
||||
```
|
||||
|
||||
> `using Pkg; Pkg.status()`:
|
||||
<!-- please paste the the output of `using Pkg; Pkg.status()` in the backticks below -->
|
||||
```julia
|
||||
|
||||
```
|
||||
|
||||
|
||||
## minimum reproducible steps
|
||||
|
||||
<!-- if possible, paste here a minimum reproducible example document and steps -->
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
name: enhancement
|
||||
about: suggest an enhancement idea
|
||||
title: "[FR]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!-- Please search existing issues to avoid duplicates. -->
|
||||
|
||||
## description
|
|
@ -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
|
||||
|
|
21
.travis.yml
21
.travis.yml
|
@ -1,29 +1,12 @@
|
|||
language: julia
|
||||
|
||||
julia:
|
||||
- 1.0
|
||||
- 1.3
|
||||
- 1.4
|
||||
- nightly
|
||||
|
||||
script:
|
||||
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||
- julia --check-bounds=yes -e 'using Pkg; Pkg.build()'
|
||||
- xvfb-run julia -e 'using Pkg; Pkg.test("Weave", coverage=true)'
|
||||
after_success:
|
||||
- julia -e 'using Pkg; cd(Pkg.dir("Weave")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
- julia: 1.4
|
||||
- julia: nightly
|
||||
include:
|
||||
- stage: "Documentation"
|
||||
julia: 1.3
|
||||
julia: 1.5
|
||||
os: linux
|
||||
script:
|
||||
- julia --project=doc/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd()));
|
||||
Pkg.instantiate()'
|
||||
- julia --project=doc/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
|
||||
- julia --project=doc/ doc/make.jl
|
||||
after_success: skip
|
||||
|
||||
|
|
40
LICENSE.md
40
LICENSE.md
|
@ -1,22 +1,20 @@
|
|||
The Weave.jl package is licensed under the MIT "Expat" License:
|
||||
Copyright (c) 2020: Contributors
|
||||
|
||||
> Copyright (c) 2014-2017: Matti Pastell.
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining
|
||||
> a copy of this software and associated documentation files (the
|
||||
> "Software"), to deal in the Software without restriction, including
|
||||
> without limitation the rights to use, copy, modify, merge, publish,
|
||||
> distribute, sublicense, and/or sell copies of the Software, and to
|
||||
> permit persons to whom the Software is furnished to do so, subject to
|
||||
> the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be
|
||||
> included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
68
NEWS.md
68
NEWS.md
|
@ -1,20 +1,66 @@
|
|||
## Release notes for Weave.jl
|
||||
|
||||
### v0.10.6 – 2020/10/03
|
||||
|
||||
improvements:
|
||||
- cleaned up chunk rendering (removed unnecessary extra newlines): #401
|
||||
- `WEAVE_ARGS` now can take arbitrary objects: https://github.com/JunoLab/Weave.jl/commit/c24a2621359b5d0af1bb6825f488e58cc11b8a9e
|
||||
- improved docs: #397 by @baggepinnen
|
||||
|
||||
bug fixes
|
||||
- fixed #398: #399
|
||||
- removed unnecessary quote for markdown output: https://github.com/JunoLab/Weave.jl/commit/a1830e05029f33195627ec5dedbacb30af23947e
|
||||
- fixed #386: #396 by @torfjelde
|
||||
|
||||
|
||||
### v0.10 – 2020/05/18
|
||||
|
||||
improvements:
|
||||
- `weave` is now integrated with Juno's progress bar; just call `weave` function inside Juno or use `julia-client: weave-to-html(pdf)` command (#331)
|
||||
- document metadata in YAML header can be given dynamically (#329)
|
||||
- headers are now striped more gracefully; only Weave.jl related header is stripped when weaving to `github` or `hugo` document (#329, #305)
|
||||
- `WeavePlots`/`GadflyPlots` won't be loaded into `Main` module (#322)
|
||||
- un`const` bindings in a sandbox module are correctly cleared, helping GC free as much memory usage as possible (#317)
|
||||
- keep latex figures even if weaving failed (#302)
|
||||
- bunch of documentation improvements (#297, #295)
|
||||
- code size in HTML header is now not hardcoded, leading to more readable font size (#281)
|
||||
|
||||
bug fixes:
|
||||
- display of "big" object is fixed and limited (#311)
|
||||
- fix dependencies issues
|
||||
|
||||
internal:
|
||||
- bunch of internal refactors, code clean up (#330, #327, #325, #321, #320, #319, #318, #313)
|
||||
- internal error now doesn't mess up display system (#316)
|
||||
- format code base (#312)
|
||||
|
||||
breaking change:
|
||||
- `options` YAML key is deprecated, use `weave_options` key instead (#334)
|
||||
- `set_chunk_defaults` is now renamed to `set_chunk_defaults!` (#323)
|
||||
- `restore_chunk_defaults` is now renamed to `restore_chunk_defaults!` (#323)
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Release notes for Weave.jl
|
||||
|
||||
### v0.4.1
|
||||
* Disable precompilation due to warnings from depencies
|
||||
|
||||
* Disable precompilation due to warnings from dependencies
|
||||
* Fix deprecation warnings for Julia 0.6
|
||||
* Fix PyPlot for Julia 0.6
|
||||
* Support citations in `pandoc2html` and `pandoc2pdf` output
|
||||
* Fix extra whitespace when `term=true`
|
||||
* Fix mime type priority for `md2html`
|
||||
|
||||
|
||||
### V0.4.0
|
||||
|
||||
* Support passing arguments to document using `args` option
|
||||
* Add `include_weave` for including code from Weave documents
|
||||
* Add support for inline code chunks
|
||||
* Remove generated figure files when publishing to html and pdf
|
||||
|
||||
|
||||
### v0.3.0
|
||||
|
||||
* Add support for YAML title block
|
||||
|
@ -25,11 +71,13 @@
|
|||
* Fix extra whitespace from code chunk output
|
||||
* Improved GR and GLVisualize support with Plots
|
||||
|
||||
|
||||
### v0.2.2
|
||||
|
||||
* Add IJulia notebook as input format
|
||||
* Add `convert_doc` method to convert between input formats
|
||||
|
||||
|
||||
### v0.2.1
|
||||
|
||||
* Fix critical hanging on Windows using proper handling of redirect_stdout
|
||||
|
@ -37,6 +85,7 @@
|
|||
output in published HTML documents.
|
||||
* Fix semicolons for `term=true`
|
||||
|
||||
|
||||
### v0.2
|
||||
|
||||
* Move to Julia 0.5 only
|
||||
|
@ -57,6 +106,7 @@
|
|||
- Fix parsing of lone variables from chunks
|
||||
- Fix error with md2html formatter and dates #38
|
||||
|
||||
|
||||
### v0.1.2
|
||||
|
||||
27th April 2016
|
||||
|
@ -66,6 +116,7 @@
|
|||
* Improve doctype autodetection
|
||||
* Improved regex for parsing markdown input format
|
||||
|
||||
|
||||
### v0.1.1
|
||||
|
||||
* Change pandoc output to use inline images if there is no caption.
|
||||
|
@ -81,6 +132,7 @@
|
|||
* Autodetect input and output formats based on filename
|
||||
* Allow `out_path` be a file or directory.
|
||||
|
||||
|
||||
### v0.1.0
|
||||
|
||||
19th April 2016
|
||||
|
@ -97,6 +149,7 @@
|
|||
- Chunks are now represented with their own type. Allows multiple dispatch
|
||||
and easier implementation of new chunks.
|
||||
|
||||
|
||||
### 0.0.4
|
||||
|
||||
4th January 2015
|
||||
|
@ -106,6 +159,7 @@
|
|||
* New option: `out_path` for controlling where weaved documents and figures are saved
|
||||
* Command line script `bin/weave.jl` for calling weave from command line
|
||||
|
||||
|
||||
### 0.0.3
|
||||
|
||||
9th December 2014
|
||||
|
@ -121,8 +175,8 @@
|
|||
|
||||
7th December 2014
|
||||
|
||||
* First release
|
||||
* Noweb and markdown input formats
|
||||
* Support for Gadfly, Winston and PyPlot figures
|
||||
* Term and script chunks
|
||||
* Support for markdown, tex and rst output
|
||||
First release:
|
||||
- Noweb and markdown input formats
|
||||
- Support for Gadfly, Winston and PyPlot figures
|
||||
- Term and script chunks
|
||||
- Support for markdown, tex and rst output
|
||||
|
|
13
Project.toml
13
Project.toml
|
@ -1,6 +1,6 @@
|
|||
name = "Weave"
|
||||
uuid = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"
|
||||
version = "0.9.4"
|
||||
version = "0.10.6"
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
|
@ -9,6 +9,7 @@ Highlights = "eafb193a-b7ab-5a9e-9068-77385905fa72"
|
|||
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
|
||||
Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
|
||||
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
|
||||
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
|
||||
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
|
||||
|
@ -19,18 +20,16 @@ YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
|
|||
Highlights = "0.3.1, 0.4"
|
||||
JSON = "0.21"
|
||||
Mustache = "0.4.1, 0.5, 1"
|
||||
Plots = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29"
|
||||
Plots = "0.28, 0.29, 1.0"
|
||||
Requires = "1.0"
|
||||
YAML = "0.3, 0.4"
|
||||
julia = "1"
|
||||
julia = "1.2"
|
||||
|
||||
[extras]
|
||||
Cairo = "159f3aea-2a34-519c-b102-8c37f9878175"
|
||||
Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
|
||||
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
|
||||
Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004"
|
||||
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
|
||||
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||
|
||||
[targets]
|
||||
test = ["Test", "Plots", "Gadfly", "Cairo", "Conda", "IJulia"]
|
||||
test = ["DataFrames", "Test"]
|
||||
|
|
61
README.md
61
README.md
|
@ -1,27 +1,30 @@
|
|||
# Weave
|
||||
|
||||
[![Build Status](https://travis-ci.org/JunoLab/Weave.jl.svg?branch=master)](https://travis-ci.org/JunoLab/Weave.jl)
|
||||
![CI](https://github.com/JunoLab/Weave.jl/workflows/CI/badge.svg)
|
||||
[![codecov](https://codecov.io/gh/JunoLab/Weave.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JunoLab/Weave.jl)
|
||||
[![](https://img.shields.io/badge/docs-stable-blue.svg)](http://weavejl.mpastell.com/stable/)
|
||||
[![](https://img.shields.io/badge/docs-dev-blue.svg)](http://weavejl.mpastell.com/dev/)
|
||||
[![](http://joss.theoj.org/papers/10.21105/joss.00204/status.svg)](http://dx.doi.org/10.21105/joss.00204)
|
||||
|
||||
Weave is a scientific report generator/literate programming tool
|
||||
for Julia. It resembles [Pweave](http://mpastell.com/pweave), Knitr, rmarkdown
|
||||
and Sweave.
|
||||
Weave is a scientific report generator/literate programming tool for the [Julia programming language](https://julialang.org/).
|
||||
It resembles
|
||||
[Pweave](http://mpastell.com/pweave),
|
||||
[knitr](https://yihui.org/knitr/),
|
||||
[R Markdown](https://rmarkdown.rstudio.com/),
|
||||
and [Sweave](https://stat.ethz.ch/R-manual/R-patched/library/utils/doc/Sweave.pdf).
|
||||
|
||||
You can write your documentation and code in input document using Noweb,
|
||||
Markdown, Script syntax and use `weave` function to execute to document to capture results
|
||||
and figures.
|
||||
You can write your documentation and code in input document using Markdown, Noweb or ordinal Julia script syntax,
|
||||
and then use `weave` function to execute code and generate an output document while capturing results and figures.
|
||||
|
||||
**Current features**
|
||||
|
||||
* Publish markdown directly to html and pdf using Julia or Pandoc markdown.
|
||||
* Markdown, script of Noweb syntax for input documents.
|
||||
* Execute code as terminal or "script" chunks.
|
||||
* Capture Plots.jl or Gadfly.jl figures
|
||||
* Supports LaTex, Pandoc, Github markdown, MultiMarkdown, Asciidoc and reStructuredText output
|
||||
* Simple caching of results
|
||||
* Convert to and from IJulia notebooks
|
||||
- Publish markdown directly to HTML and PDF using Julia or [Pandoc](https://pandoc.org/MANUAL.html)
|
||||
- Execute code as in terminal or in a unit of code chunk
|
||||
- Capture [Plots.jl](https://github.com/JuliaPlots/Plots.jl) or [Gadfly.jl](https://github.com/GiovineItalia/Gadfly.jl) figures
|
||||
- Supports various input format: Markdown, [Noweb](https://www.cs.tufts.edu/~nr/noweb/), [Jupyter Notebook](https://jupyter.org/), and ordinal Julia script
|
||||
- Conversions between those input formats
|
||||
- Supports various output document formats: HTML, PDF, GitHub markdown, Jupyter Notebook, MultiMarkdown, Asciidoc and reStructuredText
|
||||
- Simple caching of results
|
||||
|
||||
**Citing Weave:** *Pastell, Matti. 2017. Weave.jl: Scientific Reports Using Julia. The Journal of Open Source Software. http://dx.doi.org/10.21105/joss.00204*
|
||||
|
||||
|
@ -37,25 +40,29 @@ using Pkg
|
|||
Pkg.add("Weave")
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Run from julia using Plots.jl for plots:
|
||||
|
||||
```julia
|
||||
#First add depencies for the example
|
||||
using Pkg; Pkg.add.(["Plots", "DSP"])
|
||||
#Use Weave
|
||||
using Weave
|
||||
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"), out_path=:pwd)
|
||||
|
||||
# add depencies for the example
|
||||
using Pkg; Pkg.add(["Plots", "DSP"])
|
||||
|
||||
filename = normpath(Weave.EXAMPLE_FOLDER, "FIR_design.jmd")
|
||||
weave(filename, out_path = :pwd)
|
||||
```
|
||||
|
||||
If you have LaTeX installed you can also weave directly to pdf.
|
||||
|
||||
```julia
|
||||
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
|
||||
out_path=:pwd, doctype="md2pdf")
|
||||
filename = normpath(Weave.EXAMPLE_FOLDER, "FIR_design.jmd")
|
||||
weave(filename, out_path = :pwd, doctype = "md2pdf")
|
||||
```
|
||||
|
||||
NOTE: `Weave.EXAMPLE_FOLDER` just points to [`examples` directory](./examples).
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Documenter.jl with MKDocs generated documentation:
|
||||
|
@ -63,6 +70,7 @@ Documenter.jl with MKDocs generated documentation:
|
|||
[![](https://img.shields.io/badge/docs-stable-blue.svg)](http://weavejl.mpastell.com/stable/)
|
||||
[![](https://img.shields.io/badge/docs-dev-blue.svg)](http://weavejl.mpastell.com/dev/)
|
||||
|
||||
|
||||
## Editor support
|
||||
|
||||
Install [language-weave](https://atom.io/packages/language-weave) to add Weave support to Juno.
|
||||
|
@ -72,13 +80,18 @@ html and pdf output.
|
|||
The [Julia extension for Visual Studio Code](https://www.julia-vscode.org/)
|
||||
adds Weave support to [Visual Studio Code](https://code.visualstudio.com/).
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
I will probably add new features to Weave when I need them myself or if they are requested and not too difficult to implement. You can contribute by opening issues on Github or implementing things yourself and making a pull request. I'd also appreciate example documents written using Weave to add to examples.
|
||||
You can contribute to this package by opening issues on GitHub or implementing things yourself and making a pull request.
|
||||
We'd also appreciate more example documents written using Weave.
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
You can see the list of contributors on Github: https://github.com/mpastell/Weave.jl/graphs/contributors. Thanks for the important additions, fixes and comments.
|
||||
You can see the list of contributors on GitHub: https://github.com/JunoLab/Weave.jl/graphs/contributors .
|
||||
Thanks for the important additions, fixes and comments.
|
||||
|
||||
|
||||
## Example projects using Weave
|
||||
|
||||
|
|
32
appveyor.yml
32
appveyor.yml
|
@ -1,32 +0,0 @@
|
|||
environment:
|
||||
matrix:
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/1.0/julia-1.0-latest-win64.exe"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /release-.*/
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
on_build_success: false
|
||||
on_build_failure: false
|
||||
on_build_status_changed: false
|
||||
|
||||
install:
|
||||
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
|
||||
# Download most recent Julia Windows binary
|
||||
- ps: (new-object net.webclient).DownloadFile(
|
||||
$env:JULIA_URL,
|
||||
"C:\projects\julia-binary.exe")
|
||||
# Run installer silently, output to C:\projects\julia
|
||||
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
|
||||
|
||||
build_script:
|
||||
# Need to convert from shallow to complete for Pkg.clone to work
|
||||
- IF EXIST .git\shallow (git fetch --unshallow)
|
||||
#- C:\projects\julia\bin\julia -e "ENV[\"PYTHON\"]=\"\"; Pkg.add(\"PyPlot\")"
|
||||
- C:\projects\julia\bin\julia -e "using Pkg; Pkg.clone(pwd(), \"Weave\"); Pkg.build(\"Weave\")"
|
||||
|
||||
test_script:
|
||||
- C:\projects\julia\bin\julia --check-bounds=yes -e "using Pkg; Pkg.test(\"Weave\")"
|
|
@ -14,14 +14,14 @@ ap = ArgParseSettings("Weave Julia documents using Weave.jl",
|
|||
help = "source document(s)"
|
||||
required = true
|
||||
"--doctype"
|
||||
default = :auto
|
||||
default = nothing
|
||||
help = "output format"
|
||||
"--plotlib"
|
||||
arg_type = String
|
||||
default = "Gadfly"
|
||||
help = "output format"
|
||||
"--informat"
|
||||
default = :auto
|
||||
default = nothing
|
||||
help = "output format"
|
||||
"--out_path"
|
||||
arg_type = String
|
||||
|
@ -43,9 +43,6 @@ args_col = []
|
|||
|
||||
#Check for special values of out_path
|
||||
|
||||
#args["informat"] == ":auto" && (args["informat"] = :auto)
|
||||
#args["doctype"] == ":auto" && (args["informat"] = :auto)
|
||||
|
||||
if args["out_path"] == ":doc"
|
||||
args["out_path"] = :doc
|
||||
elseif args["out_path"] == ":pwd"
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,9 +1,11 @@
|
|||
using Documenter, Weave
|
||||
|
||||
CI_FLG = get(ENV, "CI", nothing) == "true"
|
||||
|
||||
makedocs(
|
||||
modules = [Weave],
|
||||
format = Documenter.HTML(
|
||||
prettyurls = get(ENV, "CI", nothing) == "true",
|
||||
prettyurls = CI_FLG,
|
||||
canonical = "http://weavejl.mpastell.com/stable/",
|
||||
),
|
||||
sitename = "Weave.jl",
|
||||
|
@ -13,12 +15,13 @@ makedocs(
|
|||
"usage.md",
|
||||
"publish.md",
|
||||
"chunk_options.md",
|
||||
"header.md",
|
||||
"notebooks.md",
|
||||
"function_index.md",
|
||||
],
|
||||
)
|
||||
|
||||
include("make_examples.jl")
|
||||
CI_FLG && include("make_examples.jl")
|
||||
|
||||
deploydocs(
|
||||
repo = "github.com/JunoLab/Weave.jl.git",
|
||||
|
|
|
@ -1,28 +1,30 @@
|
|||
using Weave
|
||||
start_dir = pwd()
|
||||
cd(@__DIR__)
|
||||
|
||||
weave("../examples/FIR_design.jmd",
|
||||
informat="markdown", out_path = "build/examples", doctype = "pandoc")
|
||||
let start_dir = pwd()
|
||||
cd(@__DIR__)
|
||||
|
||||
weave("../examples/FIR_design.jmd",
|
||||
informat="markdown", out_path = "build/examples", doctype = "md2html")
|
||||
weave("../examples/FIR_design.jmd", doctype = "pandoc", out_path = "build/examples")
|
||||
weave("../examples/FIR_design.jmd", doctype = "md2html", out_path = "build/examples")
|
||||
weave("../examples/FIR_design_plots.jl", doctype = "md2html", out_path = "build/examples")
|
||||
|
||||
cp("../examples/FIR_design.jmd",
|
||||
"build/examples/FIR_design.jmd", force = true)
|
||||
# PDF outputs
|
||||
if haskey(ENV, "TRAVIS")
|
||||
# in Travis, just cp already generated PDFs
|
||||
cp("assets/FIR_design.pdf", "build/examples/FIR_design.pdf", force = true)
|
||||
cp("assets/FIR_design_plots.pdf", "build/examples/FIR_design_plots.pdf", force = true)
|
||||
else
|
||||
# otherwise try to generate them
|
||||
try
|
||||
weave("../examples/FIR_design.jmd", doctype = "md2pdf", out_path = "assets")
|
||||
weave("../examples/FIR_design_plots.jl", doctype = "md2pdf", out_path = "assets")
|
||||
catch err
|
||||
@error err
|
||||
end
|
||||
end
|
||||
|
||||
cp("build/examples/FIR_design.md",
|
||||
"build/examples/FIR_design.txt", force = true)
|
||||
cp("../examples/FIR_design.jmd", "build/examples/FIR_design.jmd", force = true)
|
||||
cp("build/examples/FIR_design.md", "build/examples/FIR_design.txt", force = true)
|
||||
cp("../examples/FIR_design_plots.jl", "build/examples/FIR_design_plots.jl", force = true)
|
||||
|
||||
weave("../examples/FIR_design_plots.jl", out_path = "build/examples")
|
||||
|
||||
cp("../examples/FIR_design_plots.jl",
|
||||
"build/examples/FIR_design_plots.jl", force = true)
|
||||
|
||||
if !haskey(ENV, "TRAVIS")
|
||||
weave("../examples/FIR_design.jmd",
|
||||
informat="markdown", out_path = "build/examples", doctype = "md2pdf")
|
||||
weave("../examples/FIR_design_plots.jl", doctype = "md2pdf", out_path = "build/examples")
|
||||
cd(start_dir)
|
||||
end
|
||||
|
||||
cd(start_dir)
|
||||
|
|
|
@ -1,55 +1,81 @@
|
|||
# Chunk options
|
||||
# [Chunk Options](@id chunk-options)
|
||||
|
||||
I've mostly followed [Knitr](http://yihui.name/knitr/options)'s naming for chunk options, but not all options are implemented.
|
||||
|
||||
Options are separated using ";" and need to be valid Julia expressions. Example: markdown code chunk that saves and displays a 12 cm wide image and hides the source code:
|
||||
|
||||
`julia; out_width="12cm"; echo=false`
|
||||
|
||||
Weave currently supports the following chunk options with the following defaults:
|
||||
|
||||
## Options for code
|
||||
|
||||
* `echo = true`. Echo the code in the output document. If `false` the source code will be hidden.
|
||||
* `results = "markup"`. The output format of the printed results. "markup" for literal block, "hidden" for hidden results or anything else for raw output (I tend to use ‘tex’ for Latex and ‘rst’ for rest. Raw output is useful if you wan’t 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`. Chunk label, will be used for figure labels in Latex as fig:label
|
||||
* `wrap = true`. Wrap long lines from output.
|
||||
* `line_width = 75`. Line width for wrapped lines.
|
||||
* `cache = false`. Cache results, depends on `cache` parameter on `weave` function.
|
||||
* `hold = false`. Hold all results until the end of the chunk.
|
||||
* `tangle = true`. Set tangle to false to exclude chunk from tangled code.
|
||||
|
||||
## Options for figures
|
||||
|
||||
* `fig_width`. Figure width passed to plotting library e.g. `800`
|
||||
* `fig_height` Figure height passed to plotting library
|
||||
* `out_width`. Width of saved figure in output markup e.g. "50%", "12cm", `0.5\linewidth`
|
||||
* `out_height`. Height of saved figure in output markup
|
||||
* `dpi`=96. Resolution of saved figures.
|
||||
* `fig_cap`. Figure caption.
|
||||
* `label`. Chunk label, will be used for figure labels in Latex as fig:label
|
||||
* `fig_ext`. File extension (format) of saved figures.
|
||||
* `fig_pos="!h"`. Figure position in Latex.
|
||||
* `fig_env="figure"`. Figure environment in Latex.
|
||||
You can use chunk options to configure how each chunk is evaluated, rendered, etc.
|
||||
Most of the ideas came from [chunk options in RMarkdown](http://yihui.name/knitr/options).
|
||||
|
||||
|
||||
## Set default chunk options
|
||||
## Syntax
|
||||
|
||||
You can set the default chunk options (and `weave` arguments) for a document using the YAML header `options` field. e.g to set the default `out_width` of all figures you can use:
|
||||
Chunk options come after [code chunk](@ref code-chunks) header.
|
||||
There are two (slightly) different syntax to write them:
|
||||
- (Julia's toplevel expression) options are separated by semicolon (`;`)
|
||||
- (RMarkdown style) options are separated by comma (`,`)
|
||||
|
||||
Let's take a look at examples. All the following code chunk header are valid,
|
||||
and so configured to hide the source code from generated output (`echo = false`)
|
||||
and displays figures with 12cm width (`out_width = "12cm"`):
|
||||
```md
|
||||
```julia; echo = false; out_width = "12cm"
|
||||
|
||||
```{julia; echo = false; out_width = "12cm"}
|
||||
|
||||
```julia, echo = false, out_width = "12cm"
|
||||
|
||||
```{julia, echo = false, out_width = "12cm"}
|
||||
```
|
||||
|
||||
|
||||
## Weave Chunk Options
|
||||
|
||||
Weave currently supports the following chunk options:
|
||||
we've mostly followed [RMarkdown's namings](http://yihui.name/knitr/options), but not all options are implemented.
|
||||
|
||||
### Evaluation
|
||||
|
||||
- `eval = true`: Evaluate the code chunk. If `false` the chunk 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.
|
||||
- `term = false`: If `true` the output emulates a REPL session. Otherwise only stdout and figures will be included in output.
|
||||
- `wrap = true`: Wrap long lines from output.
|
||||
- `line_width = 75`: Line width for wrapped lines.
|
||||
- `hold = false`: Hold all results until the end of the chunk.
|
||||
|
||||
### Figures
|
||||
|
||||
- `label = nothing`: Chunk label, will be used for figure labels in Latex as `fig:label`.
|
||||
- `fig_width = 6`: Figure width passed to plotting library.
|
||||
- `fig_height = 4`: Figure height passed to plotting library.
|
||||
- `out_width`: Width of saved figure in output markup e.g. `"50%"`, `"12cm"`, `0.5\linewidth`
|
||||
- `out_height`: Height of saved figure in output markup
|
||||
- `dpi = 96`: Resolution of saved figures.
|
||||
- `fig_cap`: Figure caption.
|
||||
- `fig_ext`: File extension (format) of saved figures.
|
||||
- `fig_pos = "!h"`: Figure position in Latex, e.g.: `"ht"`.
|
||||
- `fig_env = "figure"`: Figure environment in Latex.
|
||||
|
||||
|
||||
## Default Chunk Options
|
||||
|
||||
You can set the default chunk options (and `weave` arguments) for a document using `weave_options` key in YAML [Header Configuration](@ref).
|
||||
E.g. to set the default `out_width` of all figures you can use:
|
||||
|
||||
```yaml
|
||||
---
|
||||
options:
|
||||
out_width : 50%
|
||||
weave_options:
|
||||
out_width : 50%
|
||||
---
|
||||
```
|
||||
|
||||
You can also set or change the default chunk options for a document either before weave using the `set_chunk_defaults` function.
|
||||
|
||||
```@docs
|
||||
set_chunk_defaults
|
||||
set_chunk_defaults!
|
||||
get_chunk_defaults
|
||||
restore_chunk_defaults
|
||||
restore_chunk_defaults!
|
||||
```
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
|
||||
# Getting started
|
||||
|
||||
The best way to get started using Weave.jl is to look at the example input and
|
||||
output documents. Examples for different formats are included in the packages
|
||||
[`examples`](https://github.com/JunoLab/Weave.jl/tree/master/examples) directory.
|
||||
The best way to get started using Weave.jl is to look at the example input and output documents.
|
||||
Examples for different formats are included in the package's [`examples`](https://github.com/JunoLab/Weave.jl/tree/master/examples) directory.
|
||||
|
||||
First have a look at source document using markdown code chunks and
|
||||
[Plots.jl](https://github.com/JuliaPlots/Plots.jl) for figures:
|
||||
[FIR_design.jmd](../examples/FIR_design.jmd) and then see the
|
||||
output in different formats:
|
||||
First have a look at source document using markdown code chunks and [Plots.jl](https://github.com/JuliaPlots/Plots.jl) for figures:
|
||||
|
||||
- HTML: [FIR_design.html](../examples/FIR_design.html)
|
||||
- pdf: [FIR_design.pdf](../examples/FIR_design.pdf)
|
||||
- Pandoc markdown: [FIR_design.txt](../examples/FIR_design.txt)
|
||||
All the different format documents below are generated from a single Weave document [`FIR_design.jmd`](../examples/FIR_design.jmd):
|
||||
- HTML: [`FIR_design.html`](../examples/FIR_design.html)
|
||||
- PDF: [`FIR_design.pdf`](../examples/FIR_design.pdf)
|
||||
- Pandoc markdown: [`FIR_design.txt`](../examples/FIR_design.txt)
|
||||
|
||||
*Producing pdf output requires that you have XeLateX installed.*
|
||||
!!! note
|
||||
Producing PDF output requires that you have XeLateX installed.
|
||||
|
||||
Add dependencies for the example if needed:
|
||||
|
||||
|
@ -22,20 +20,22 @@ Add dependencies for the example if needed:
|
|||
using Pkg; Pkg.add.(["Plots", "DSP"])
|
||||
```
|
||||
|
||||
Weave the files to your working directory using:
|
||||
Weave the files to your working directory:
|
||||
|
||||
```julia
|
||||
using Weave
|
||||
#HTML
|
||||
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
|
||||
out_path=:pwd,
|
||||
doctype = "md2html")
|
||||
#pdf
|
||||
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
|
||||
out_path=:pwd,
|
||||
doctype = "md2pdf")
|
||||
#Markdown
|
||||
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"),
|
||||
doctype="pandoc",
|
||||
out_path=:pwd)
|
||||
|
||||
filename = normpath(Weave.EXAMPLE_FOLDER, "FIR_design.jmd")
|
||||
|
||||
# Julia markdown to HTML
|
||||
weave(filename; doctype = "md2html", out_path = :pwd)
|
||||
|
||||
# Julia markdown to PDF
|
||||
weave(filename; doctype = "md2pdf", out_path = :pwd)
|
||||
|
||||
# Julia markdown to Pandoc markdown
|
||||
weave(filename; doctype = "pandoc", out_path = :pwd)
|
||||
```
|
||||
|
||||
!!! tips
|
||||
`Weave.EXAMPLE_FOLDER` points to [the `examples` directory](https://github.com/JunoLab/Weave.jl/tree/master/examples).
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
# Header Configuration
|
||||
|
||||
When `weave`ing a markdown document, you use YAML header to provide additional metadata and configuration options.
|
||||
A YAML header should be in the beginning of the input document delimited with `---`.
|
||||
|
||||
|
||||
!!! warning
|
||||
YAML header configuration is only supported when `weave`ing [markdown or Noweb syntax documents](@ref document-syntax).
|
||||
|
||||
|
||||
## Document Metadata
|
||||
|
||||
You can set additional document metadata in YAML header.
|
||||
When `weave`ing to Julia markdown documents to HTML or PDF, Weave respects the following metadata specification:
|
||||
- `title`
|
||||
- `author`
|
||||
- `date`
|
||||
|
||||
An example:
|
||||
```yaml
|
||||
---
|
||||
title : Header Example
|
||||
author : Shuhei Kadowaki
|
||||
date: 16th May 2020
|
||||
---
|
||||
```
|
||||
|
||||
!!! note
|
||||
You can also have other metadata, but they won't appear in the resulting HTML and PDF.
|
||||
If you weave to Julia markdown to GitHub/Hugo markdown, all the metadata will be preserved.
|
||||
|
||||
### Dynamic Metadata
|
||||
|
||||
The metadata can be given "dynamically"; if you have [inline code](@ref) within YAML header, they will be evaluated _after_ evaluating all the chunks and replaced with the results.
|
||||
|
||||
The example document below will set `date` metadata dynamically.
|
||||
Note that `Date` is available since the chunk is evaluated first.
|
||||
```md
|
||||
---
|
||||
title : Header Example
|
||||
author : Shuhei Kadowaki
|
||||
date: `j import Dates; Dates.Date(Dates.now())`
|
||||
---
|
||||
|
||||
```julia; echo = false
|
||||
using Dates
|
||||
```
|
||||
```
|
||||
|
||||
|
||||
## Configuration Options
|
||||
|
||||
Each of keyword arguments of [`weave`](@ref) can be set in the YAML header under `options` field.
|
||||
You can also set [Chunks Options](@ref) there that will be applied globally.
|
||||
|
||||
The example below sets `out_path` and `doctype` options and overwrites `term` and `wrap` chunk options:
|
||||
```yaml
|
||||
---
|
||||
title : Header Example
|
||||
author : Shuhei Kadowaki
|
||||
date: 16th May 2020
|
||||
weave_options:
|
||||
out_path: relative/path/to/this/document
|
||||
doctype: github
|
||||
term: true
|
||||
wrap: false
|
||||
---
|
||||
```
|
||||
|
||||
!!! note
|
||||
- configurations specified within the YAML header have higher precedence than those specified via `weave` keyword arguments
|
||||
- chunk options specified within each chunk have higher precedence than the global global chunk options specified within the YAML header
|
||||
|
||||
!!! warning
|
||||
As opposed to metadata, _most_ of those configuration options can't be given dynamically (i.e. can't be via inline code),
|
||||
since they are needed for evaluation of chunks themselves.
|
||||
But some configuration options that are needed "formatting" document can still be given dynamically:
|
||||
- `template`
|
||||
- `css`
|
||||
- `highlight_theme`
|
||||
- `pandoc_options`
|
||||
- `latex_cmd`
|
||||
- `keep_unicode`
|
||||
|
||||
See also: [`weave`](@ref)
|
||||
|
||||
|
||||
## Format Specific Options
|
||||
|
||||
The header configurations can be format specific.
|
||||
Here is how to set different `out_path` for `md2html` and `md2pdf` and set `fig_ext` globally:
|
||||
```yaml
|
||||
---
|
||||
weave_options:
|
||||
md2html:
|
||||
out_path : html
|
||||
md2pdf:
|
||||
out_path : pdf
|
||||
fig_ext : .png
|
||||
---
|
||||
```
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Weave.jl - Scientific Reports Using Julia
|
||||
|
||||
This is the documentation of [Weave.jl](http://github.com/mpastell/weave.jl).
|
||||
|
@ -12,20 +11,28 @@ and [Sweave](https://stat.ethz.ch/R-manual/R-patched/library/utils/doc/Sweave.pd
|
|||
|
||||
**Current features**
|
||||
|
||||
* Markdown, script of Noweb syntax for input documents
|
||||
* Publish markdown directly to html and pdf using Julia or Pandoc markdown
|
||||
* Execute code as terminal or "script" chunks
|
||||
* Capture Plots.jl or Gadfly.jl figures
|
||||
* Supports LaTex, Pandoc, GitHub markdown, MultiMarkdown, Asciidoc and reStructuredText output
|
||||
* Simple caching of results
|
||||
* Convert to and from IJulia notebooks
|
||||
- Publish markdown directly to HTML and PDF using Julia or [Pandoc](https://pandoc.org/MANUAL.html)
|
||||
- Execute code as in terminal or in a unit of code chunk
|
||||
- Capture [Plots.jl](https://github.com/JuliaPlots/Plots.jl) or [Gadfly.jl](https://github.com/GiovineItalia/Gadfly.jl) figures
|
||||
- Supports various input format: Markdown, [Noweb](https://www.cs.tufts.edu/~nr/noweb/), [Jupyter Notebook](https://jupyter.org/), and ordinal Julia script
|
||||
- Conversions between those input formats
|
||||
- Supports various output document formats: HTML, PDF, GitHub markdown, Jupyter Notebook, MultiMarkdown, Asciidoc and reStructuredText
|
||||
- Simple caching of results
|
||||
|
||||
![Weave in Juno demo](https://user-images.githubusercontent.com/40514306/76081328-32f41900-5fec-11ea-958a-375f77f642a2.png)
|
||||
|
||||
## Contents
|
||||
|
||||
## Index
|
||||
|
||||
```@contents
|
||||
Pages = ["getting_started.md", "usage.md",
|
||||
"publish.md", "chunk_options.md", "notebooks.md",
|
||||
"function_index.md"]
|
||||
Pages = [
|
||||
"index.md",
|
||||
"getting_started.md",
|
||||
"usage.md",
|
||||
"publish.md",
|
||||
"chunk_options.md",
|
||||
"header.md",
|
||||
"notebooks.md",
|
||||
"function_index.md",
|
||||
]
|
||||
```
|
||||
|
|
|
@ -3,32 +3,34 @@
|
|||
|
||||
## Weaving from Jupyter notebooks
|
||||
|
||||
Weave supports using Jupyter notebooks as input format, this means you
|
||||
can weave notebooks to any supported formats. You can't use chunk options with notebooks.
|
||||
Weave supports using [Jupyter Notebook](https://jupyter.org/)s as input format.
|
||||
This means you can [`weave`](@ref) notebooks to any supported formats;
|
||||
by default, it will be weaved to HTML.
|
||||
|
||||
```julia
|
||||
weave("notebook.ipynb")
|
||||
weave("notebook.ipynb") # will be weaved to HTML
|
||||
```
|
||||
|
||||
!!! warning
|
||||
You can't use chunk options with notebooks.
|
||||
|
||||
## Output to Jupyter notebooks
|
||||
|
||||
As of Weave 0.5.1. there is new `notebook` method to convert Weave documents
|
||||
to Jupyter notebooks using [nbconvert](http://nbconvert.readthedocs.io/en/latest/execute_api.html). The code **is not executed by Weave**
|
||||
and the output doesn't always work properly,
|
||||
see [#116](https://github.com/mpastell/Weave.jl/issues/116).
|
||||
As of Weave 0.5.1. there is new [`notebook`](@ref) method to convert Weave documents to Jupyter notebooks using
|
||||
[nbconvert](http://nbconvert.readthedocs.io/en/latest/execute_api.html).
|
||||
|
||||
```@docs
|
||||
notebook
|
||||
```
|
||||
|
||||
You might want to use the `convert_doc` method below instead and run the code in Jupyter.
|
||||
You can specify `jupyter` used to execute the notebook with the `jupyter_path` keyword argument
|
||||
(this defaults to the `"jupyter"`, i.e. whatever you have linked to that location).
|
||||
|
||||
You can select the `jupyter` used to execute the notebook with the `jupyter_path` argument (this defaults to the string "jupyter," i.e., whatever you have linked to that location.)
|
||||
Instead, you might want to use the [`convert_doc`](@ref) method below and run the code in Jupyter.
|
||||
|
||||
## Converting between formats
|
||||
|
||||
You can convert between all supported input formats using the `convert_doc`
|
||||
function.
|
||||
You can convert between all supported input formats using the [`convert_doc`](@ref) function.
|
||||
|
||||
To convert from script to notebook:
|
||||
|
||||
|
@ -36,12 +38,12 @@ To convert from script to notebook:
|
|||
convert_doc("examples/FIR_design.jl", "FIR_design.ipynb")
|
||||
```
|
||||
|
||||
and from notebooks to markdown use:
|
||||
and from notebook to Markdown use:
|
||||
|
||||
```julia
|
||||
convert_doc("FIR_design.ipynb", "FIR_design.jmd")
|
||||
```
|
||||
|
||||
```@docs
|
||||
convert_doc(infile::String, outfile::String)
|
||||
convert_doc
|
||||
```
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
# Publishing to html and pdf
|
||||
# Publishing to HTML and PDF
|
||||
|
||||
You can also publish any supported input format using markdown for doc chunks to html and pdf documents. Producing pdf output requires that you have pdflatex installed and in your path.
|
||||
You can also publish any supported input format to HTML and PDF documents.
|
||||
|
||||
You can use a YAML header in the beginning of the input document delimited with "---"
|
||||
to set the document title, author and date e.g.
|
||||
!!! note
|
||||
Producing PDF output requires that you have XeLaTex installed and in your path.
|
||||
|
||||
You can use a YAML header in the beginning of the input document delimited with `---`
|
||||
to set the document title, author and date, e.g.:
|
||||
```
|
||||
---
|
||||
title : Weave example
|
||||
|
@ -13,37 +15,48 @@ date: 15th December 2016
|
|||
---
|
||||
```
|
||||
|
||||
Here is a a sample document and output:
|
||||
|
||||
[FIR_design_plots.jl](../examples/FIR_design_plots.jl), [FIR_design_plots.html](../examples/FIR_design_plots.html) , [FIR_design_plots.pdf](../examples/FIR_design_plots.pdf).
|
||||
Here are sample input and outputs:
|
||||
- input (Julia markdown format): [`FIR_design_plots.jl`](../examples/FIR_design_plots.jl) (its path is bound to `Weave.SAMPLE_JL_DOC`)
|
||||
- HTML output: [`FIR_design_plots.html`](../examples/FIR_design_plots.html)
|
||||
- PDF output: [`FIR_design_plots.pdf`](../examples/FIR_design_plots.pdf)
|
||||
|
||||
They are generated as follows:
|
||||
```julia
|
||||
weave("FIR_design_plots.jl")
|
||||
weave("FIR_design_plots.jl", docformat = "md2pdf")
|
||||
weave(Weave.SAMPLE_JL_DOC)) # default to md2html output format
|
||||
weave(Weave.SAMPLE_JL_DOC; doctype = "md2pdf")
|
||||
```
|
||||
|
||||
**Note:** docformats `md2pdf` and `md2html` use Julia markdown and `pandoc2pdf` and `pandoc2html`
|
||||
use Pandoc.
|
||||
!!! tips
|
||||
`Weave.SAMPLE_JL_DOC` is the path of [FIR_design.jl](../examples/FIR_design.jl).
|
||||
|
||||
!!! note
|
||||
`"md2html"` and `"md2pdf"` assume Julia markdown format as an input,
|
||||
while `pandoc2pdf` and `pandoc2html` assume Noweb input format (i.e. Pandoc markdown).
|
||||
|
||||
|
||||
## Templates
|
||||
|
||||
You can use a custom template with `md2pdf` and `md2html` formats with `template`
|
||||
argument (e.g) `weave("FIR_design_plots.jl", template = "custom.tpl"`). You can use
|
||||
the existing templates as starting point.
|
||||
You can use a custom template with `md2html` and `md2pdf` formats with `template` keyword option,
|
||||
e.g.: `weave("FIR_design_plots.jl", template = "custom.tpl"`.
|
||||
|
||||
For HTML: [julia_html.tpl](https://github.com/mpastell/Weave.jl/blob/master/templates/julia_html.tpl) and LaTex: [julia_tex.tpl](https://github.com/mpastell/Weave.jl/blob/master/templates/julia_tex.tpl)
|
||||
As starting point, you can use the existing templates:
|
||||
|
||||
- HTML (`md2html`): [`md2html.tpl`](https://github.com/JunoLab/Weave.jl/blob/master/templates/md2html.tpl)
|
||||
- LaTex (`md2pdf`): [`md2pdf.tpl`](https://github.com/JunoLab/Weave.jl/blob/master/templates/md2pdf.tpl)
|
||||
|
||||
Templates are rendered using [Mustache.jl](https://github.com/jverzani/Mustache.jl).
|
||||
|
||||
|
||||
## Supported Markdown syntax
|
||||
|
||||
The markdown variant used by Weave is [Julia markdown](https://docs.julialang.org/en/v1/stdlib/Markdown/#). In addition Weave supports few additional Markdown features:
|
||||
The markdown variant used by Weave is [Julia markdown](https://docs.julialang.org/en/v1/stdlib/Markdown/#).
|
||||
In addition Weave supports few additional Markdown features:
|
||||
|
||||
**Comments**
|
||||
### Comments
|
||||
|
||||
You can add comments using html syntax: `<!-- -->`
|
||||
|
||||
**Multiline equations**
|
||||
### Multiline equations
|
||||
|
||||
You can add multiline equations using:
|
||||
|
||||
|
|
197
doc/src/usage.md
197
doc/src/usage.md
|
@ -1,58 +1,65 @@
|
|||
# Using Weave
|
||||
|
||||
You can write your documentation and code in input document using Markdown, Noweb or script
|
||||
syntax and use `weave` function to execute to document to capture results and figures.
|
||||
syntax and use [`weave`](@ref) function to execute to document to capture results and figures.
|
||||
|
||||
## Weave
|
||||
## `weave`
|
||||
|
||||
Weave document with markup and julia code using `Plots.jl` for plots,
|
||||
`out_path = :pwd` makes the results appear in the current working directory.
|
||||
|
||||
> A prepared example: [`Weave.SAMPLE_JL_DOC`](../examples/FIR_design.jmd)
|
||||
|
||||
```julia
|
||||
#First add depencies for the example
|
||||
# First add depencies for the example
|
||||
using Pkg; Pkg.add.(["Plots", "DSP"])
|
||||
using Weave
|
||||
weave(joinpath(dirname(pathof(Weave)), "../examples", "FIR_design.jmd"), out_path=:pwd)
|
||||
weave(Weave.SAMPLE_JL_DOC; out_path=:pwd)
|
||||
```
|
||||
|
||||
```@docs
|
||||
weave(source)
|
||||
weave
|
||||
```
|
||||
|
||||
## Tangle
|
||||
## `tangle`
|
||||
|
||||
Tangling extracts the code from document:
|
||||
|
||||
```@docs
|
||||
tangle(source)
|
||||
tangle
|
||||
```
|
||||
|
||||
## Supported output formats
|
||||
## Supported Output Formats
|
||||
|
||||
Weave sets the output format based on the file extension, but you can also set
|
||||
it using `doctype` option. The rules for detecting the format are:
|
||||
Weave automatically detects the output format based on the file extension.
|
||||
The auto output format detection is handled by `detect_doctype(path::AbstractString)`:
|
||||
|
||||
```julia
|
||||
ext == ".jl" && return "md2html"
|
||||
contains(ext, ".md") && return "md2html"
|
||||
contains(ext, ".rst") && return "rst"
|
||||
contains(ext, ".tex") && return "texminted"
|
||||
contains(ext, ".txt") && return "asciidoc"
|
||||
return "pandoc"
|
||||
function detect_doctype(path::AbstractString)
|
||||
_, ext = lowercase.(splitext(path))
|
||||
|
||||
match(r"^\.(jl|.?md|ipynb)", ext) !== nothing && return "md2html"
|
||||
ext == ".rst" && return "rst"
|
||||
ext == ".tex" && return "texminted"
|
||||
ext == ".txt" && return "asciidoc"
|
||||
|
||||
return "pandoc"
|
||||
end
|
||||
```
|
||||
|
||||
You can also manually specify it using the `doctype` keyword option.
|
||||
You can get a list of supported output formats:
|
||||
|
||||
```@docs
|
||||
list_out_formats
|
||||
```
|
||||
|
||||
```@example
|
||||
using Weave # hide
|
||||
list_out_formats()
|
||||
```
|
||||
|
||||
```@docs
|
||||
list_out_formats()
|
||||
```
|
||||
|
||||
## Document syntax
|
||||
## [Document Syntax](@id document-syntax)
|
||||
|
||||
Weave uses markdown, Noweb or script syntax for defining the code chunks and
|
||||
documentation chunks. You can also weave Jupyter notebooks. The format is detected based on the file extension, but you can also set it manually using the `informat` parameter.
|
||||
|
@ -66,137 +73,109 @@ ext == ".ipynb" && return "notebook"
|
|||
return "noweb"
|
||||
```
|
||||
|
||||
## Documentation chunks
|
||||
|
||||
In Markdown and Noweb input formats documentation chunks are the parts that aren't inside code delimiters. Documentation chunks can be written with several different markup languages.
|
||||
### Documentation Chunks
|
||||
|
||||
## Code chunks
|
||||
In markdown and Noweb input formats documentation chunks are the parts that aren't inside code delimiters. Documentation chunks can be written with several different markup languages.
|
||||
|
||||
### Markdown format
|
||||
|
||||
Markdown code chunks are defined using fenced code blocks with options following on the same line. e.g. to hide code from output you can use:
|
||||
### [Code Chunks](@id code-chunks)
|
||||
|
||||
```
|
||||
```julia; echo=false
|
||||
Code chunks are written in different ways in different formats.
|
||||
|
||||
#### Markdown Format
|
||||
|
||||
Weave code chunks are defined using fenced code blocks, same as with [common markdown](https://spec.commonmark.org/0.29/#fenced-code-blocks):
|
||||
```markdown
|
||||
```julia
|
||||
code
|
||||
...
|
||||
```
|
||||
```
|
||||
|
||||
[Sample document]( https://github.com/mpastell/Weave.jl/blob/master/examples/FIR_design.jmd)
|
||||
Weave code chunks can optionally be followed by [chunk options](@ref) on the same line.
|
||||
E.g. the chunk below will hide code itself from generated output:
|
||||
```markdown
|
||||
```julia, echo = false
|
||||
code
|
||||
...
|
||||
```
|
||||
```
|
||||
|
||||
## Inline code
|
||||
#### Noweb Format
|
||||
|
||||
Code chunks start with a line marked with `<<>>=` or `<<options>>=` and end with line marked with `@`.
|
||||
The code between the start and end markers is executed and the output is captured to the output document.
|
||||
|
||||
### [Inline Code](@id inline-code)
|
||||
|
||||
You can also add inline code to your documents using
|
||||
|
||||
```
|
||||
`j juliacode`
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
! juliacode
|
||||
```
|
||||
syntax.
|
||||
|
||||
syntax. Using the `j code` syntax you can insert code anywhere in a line and with
|
||||
the `!` syntax the whole line after `!` will be executed. The code will be replaced
|
||||
with captured output in the weaved document.
|
||||
|
||||
If the code produces figures the filename or base64 encoded string will be
|
||||
added to output e.g. to include a Plots figure in markdown you can use:
|
||||
The former syntax allows you to insert code _anywhere_ in a line
|
||||
while the `!` syntax treats the whole line as code,
|
||||
and the code will be replaced with captured output in the weaved document.
|
||||
|
||||
If the code produces figures, the filename or base64 encoded string will be added to output,
|
||||
e.g. to include a Plots figure in markdown you can use:
|
||||
```
|
||||
![A plot](`j plot(1:10)`)
|
||||
```
|
||||
|
||||
or to produce any html output:
|
||||
|
||||
or to produce any HTML output:
|
||||
```
|
||||
! display("text/html", "Header from julia");
|
||||
```
|
||||
|
||||
### Script Format
|
||||
|
||||
### Noweb format
|
||||
Weave also supports script input format with a markup in comments.
|
||||
These scripts can be executed normally using Julia or published with Weave.
|
||||
|
||||
Code chunks start with a line marked with `<<>>=` or `<<options>>=` and end with line marked with `@`. The code between the start and end markers is executed and the output is captured to the output document. See [chunk options](../chunk_options/).
|
||||
Lines starting with `#'`, `#%%` or `# %%` are treated as document.
|
||||
|
||||
All non-document lines are treated as code.
|
||||
You can set chunk options using lines starting with `#+` just before code e.g:
|
||||
```julia
|
||||
#+ term=true
|
||||
hoge # some code comes here
|
||||
```
|
||||
|
||||
### Script format
|
||||
|
||||
Weave also support script input format with a markup in comments.
|
||||
These scripts can be executed normally using Julia or published with
|
||||
Weave. Documentation is in lines starting with
|
||||
`#'`, `#%%` or `# %%`, and code is executed and results are included
|
||||
in the weaved document.
|
||||
|
||||
All lines that are not documentation are treated as code. You can set chunk options
|
||||
using lines starting with `#+` just before code e.g. `#+ term=true`.
|
||||
|
||||
The format is identical to [Pweave](http://mpastell.com/pweave/pypublish.html)
|
||||
and the concept is similar to publishing documents with MATLAB or
|
||||
using Knitr's [spin](http://yihui.name/knitr/demo/stitch/).
|
||||
The format is identical to [Pweave](http://mpastell.com/pweave/pypublish.html) and the concept is similar to publishing documents with MATLAB or using Knitr's [spin](http://yihui.name/knitr/demo/stitch/).
|
||||
Weave will remove the first empty space from each line of documentation.
|
||||
|
||||
|
||||
[See sample document:](https://github.com/mpastell/Weave.jl/blob/master/examples/FIR_design.jl)
|
||||
|
||||
## Setting document options in header
|
||||
|
||||
You can use a YAML header in the beginning of the input document delimited with "---" to set the document title, author and date e.g. and default document options. Each of Weave command line arguments and chunk options can be set in header using `options` field. Below is an example that sets document `out_path` and `doctype` using the header.
|
||||
!!! tip
|
||||
- Here are sample documents:
|
||||
+ [markdown format](https://github.com/JunoLab/Weave.jl/blob/master/examples/FIR_design.jmd)
|
||||
+ [script format](https://github.com/JunoLab/Weave.jl/blob/master/examples/FIR_design.jl)
|
||||
- [Details about chunk options](@ref chunk-options)
|
||||
|
||||
|
||||
```yaml
|
||||
---
|
||||
title : Weave example
|
||||
author : Matti Pastell
|
||||
date: 15th December 2016
|
||||
options:
|
||||
out_path : reports/example.md
|
||||
doctype : github
|
||||
---
|
||||
```
|
||||
## Configuration via YAML Header
|
||||
|
||||
You can also set format specific options. Here is how to set different `out_path` for `md2html` and `md2pdf` and set `fig_ext` for both:
|
||||
When `weave`ing markdown files, you can use YAML header to provide additional metadata and configuration options.
|
||||
See [Header Configuration](@ref) section for more details.
|
||||
|
||||
```
|
||||
---
|
||||
options:
|
||||
md2html:
|
||||
out_path : html
|
||||
md2pdf:
|
||||
out_path : pdf
|
||||
fig_ext : .png
|
||||
---
|
||||
```
|
||||
|
||||
## Passing arguments to documents
|
||||
## Passing Runtime Arguments to Documents
|
||||
|
||||
You can pass arguments as dictionary to the weaved document using the `args` argument
|
||||
to `weave`. The dictionary will be available as `WEAVE_ARGS` variable in the document.
|
||||
You can pass arbitrary object to the weaved document using [`weave`](@ref)'s optional argument `args`.
|
||||
It will be available as `WEAVE_ARGS` variable in the `weave`d document.
|
||||
|
||||
This makes it possible to create the same report easily for e.g. different
|
||||
date ranges of input data from a database or from files with similar format giving the
|
||||
filename as input.
|
||||
This makes it possible to create the same report easily for e.g. different date ranges of input data from a database or from files with similar format giving the filename as input.
|
||||
|
||||
In order to pass a filename to a document you need call `weave` using:
|
||||
E.g. if you call `weave("weavefile.jmd", args = (datalocation = "somedata.h5",))`, and then you can retrieve the `datalocation` in `weavefile.jmd` as follows: `WEAVE_ARGS.datalocation`
|
||||
|
||||
```julia
|
||||
weave("mydoc.jmd", args = Dict("filename" => "somedata.h5"))
|
||||
```
|
||||
|
||||
and you can access the filename from document as follows:
|
||||
## `include_weave`
|
||||
|
||||
```
|
||||
```julia
|
||||
print(WEAVE_ARGS["filename"])
|
||||
```
|
||||
```
|
||||
|
||||
You can use the `out_path` argument to control the name of the
|
||||
output document.
|
||||
|
||||
## Include Weave document in Julia
|
||||
|
||||
You can call `include_weave` on a Weave document to run the contents
|
||||
of all code chunks in Julia.
|
||||
You can call `include_weave` on a Weave document and run all code chunks within in the current session.
|
||||
|
||||
```@docs
|
||||
include_weave
|
||||
|
|
|
@ -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
|
||||
|
@ -22,6 +22,13 @@ If you're viewing the published version have a look at the
|
|||
[source](FIR_design_plots.jl) to see the markup.
|
||||
|
||||
|
||||
<!-- this setup dependencies, but doesn't appear in the generated document -->
|
||||
```julia; echo = false; results = "hidden"
|
||||
using Pkg
|
||||
"Plots" ∉ keys(Pkg.project().dependencies) && Pkg.add("Plots")
|
||||
"DSP" ∉ keys(Pkg.project().dependencies) && Pkg.add("DSP")
|
||||
```
|
||||
|
||||
|
||||
# FIR Filter Design
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
This a sample [Julia](http://julialang.org/) noweb document that can
|
||||
be executed using Weave. Output from code chunks and PyPlot
|
||||
plots will be included in the weaved document. You also need to install Pweave from Github in order to use Weave.
|
||||
plots will be included in the weaved document. You also need to install Pweave from GitHub in order to use Weave.
|
||||
|
||||
This documented can be turned into Pandoc markdown with captured
|
||||
result from Julia prompt.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title : A minimal beamer example using Weave markdown
|
||||
author : Matti Pastell
|
||||
options :
|
||||
title: A minimal beamer example using Weave markdown
|
||||
author: Matti Pastell
|
||||
weave_options:
|
||||
doctype : md2pdf
|
||||
out_path : pdf
|
||||
template : beamer.tpl
|
||||
|
|
485
src/Weave.jl
485
src/Weave.jl
|
@ -1,254 +1,337 @@
|
|||
module Weave
|
||||
import Highlights
|
||||
using Requires
|
||||
|
||||
using Highlights, Mustache, Requires, Pkg, REPL
|
||||
|
||||
|
||||
# directories
|
||||
const PKG_DIR = normpath(@__DIR__, "..")
|
||||
const TEMPLATE_DIR = normpath(PKG_DIR, "templates")
|
||||
const STYLESHEET_DIR = normpath(PKG_DIR, "stylesheets")
|
||||
# keeps paths of sample documents for easy try
|
||||
const EXAMPLE_FOLDER = normpath(PKG_DIR, "examples")
|
||||
|
||||
# constant names
|
||||
const WEAVE_OPTION_NAME = "weave_options"
|
||||
const WEAVE_OPTION_NAME_DEPRECATED = "options" # remove this when tagging v0.11
|
||||
const WEAVE_OPTION_DEPRECATE_ID = "weave_option_duplicate_id"
|
||||
const DEFAULT_FIG_PATH = "figures"
|
||||
|
||||
const WEAVE_VERSION = try
|
||||
'v' * Pkg.TOML.parsefile(normpath(PKG_DIR, "Project.toml"))["version"]
|
||||
catch
|
||||
""
|
||||
end
|
||||
weave_info() = WEAVE_VERSION, string(Date(now()))
|
||||
|
||||
function __init__()
|
||||
@require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" Base.include(Main, joinpath(@__DIR__, "plots.jl"))
|
||||
@require Gadfly="c91e804a-d5a3-530f-b6f0-dfbca275c004" Base.include(Main, joinpath(@__DIR__, "gadfly.jl"))
|
||||
@require Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" include("plots.jl")
|
||||
@require Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004" include("gadfly.jl")
|
||||
end
|
||||
|
||||
"""
|
||||
`list_out_formats()`
|
||||
|
||||
List supported output formats
|
||||
"""
|
||||
function list_out_formats()
|
||||
for format = keys(formats)
|
||||
println(string(format,": ", formats[format].description))
|
||||
end
|
||||
end
|
||||
# utilitity functions
|
||||
take2string!(io) = String(take!(io))
|
||||
joinlines(lines) = join(lines, '\n')
|
||||
|
||||
|
||||
include("types.jl")
|
||||
include("config.jl")
|
||||
include("WeaveMarkdown/markdown.jl")
|
||||
include("display_methods.jl")
|
||||
include("reader/reader.jl")
|
||||
include("run.jl")
|
||||
include("cache.jl")
|
||||
include("rendering/rendering.jl")
|
||||
include("writer/writer.jl")
|
||||
include("converter.jl")
|
||||
|
||||
|
||||
get_format(doctype::AbstractString) = FORMATS[doctype]
|
||||
|
||||
"""
|
||||
`tangle(source ; out_path=:doc, informat="noweb")`
|
||||
list_out_formats()
|
||||
|
||||
List supported output formats with its description.
|
||||
"""
|
||||
list_out_formats() = [k => v.description for (k,v) in FORMATS]
|
||||
|
||||
"""
|
||||
tangle(source::AbstractString; kwargs...)
|
||||
|
||||
Tangle source code from input document to .jl file.
|
||||
|
||||
* `informat`: `"noweb"` of `"markdown"`
|
||||
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document, `:pwd`: Julia working directory, `"somepath"`, directory name as a string e.g `"/home/mpastell/weaveout"`
|
||||
or filename as string e.g. ~/outpath/outfile.jl.
|
||||
## Keyword options
|
||||
|
||||
- `informat::Union{Nothing,AbstractString} = nothing`: Input document format. By default (i.e. given `nothing`), Weave will set it automatically based on file extension. You can also specify either of `"script"`, `"markdown"`, `"notebook"`, or `"noweb"`
|
||||
- `out_path::Union{Symbol,AbstractString} = :doc`: Path where the output is generated can be either of:
|
||||
* `:doc`: Path of the source document (default)
|
||||
* `:pwd`: Julia working directory
|
||||
* `"somepath"`: `String` of output directory e.g. `"~/outdir"`, or of filename e.g. `"~/outdir/outfile.tex"`
|
||||
"""
|
||||
function tangle(source ; out_path=:doc, informat=:auto)
|
||||
doc = read_doc(source, informat)
|
||||
function tangle(
|
||||
source::AbstractString;
|
||||
out_path::Union{Symbol,AbstractString} = :doc,
|
||||
informat::Union{Nothing,AbstractString} = nothing,
|
||||
)
|
||||
doc = WeaveDoc(source, informat)
|
||||
doc.cwd = get_cwd(doc, out_path)
|
||||
|
||||
outname = get_outname(out_path, doc, ext = "jl")
|
||||
out_path = get_out_path(doc, out_path, "jl")
|
||||
|
||||
open(outname, "w") do io
|
||||
for chunk in doc.chunks
|
||||
if typeof(chunk) == CodeChunk
|
||||
options = merge(doc.chunk_defaults, chunk.options)
|
||||
if options[:tangle]
|
||||
write(io, chunk.content*"\n")
|
||||
end
|
||||
end
|
||||
open(out_path, "w") do io
|
||||
for chunk in doc.chunks
|
||||
if typeof(chunk) == CodeChunk
|
||||
options = merge(doc.chunk_defaults, chunk.options)
|
||||
options[:tangle] && write(io, chunk.content * "\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
doc.cwd == pwd() && (outname = basename(outname))
|
||||
@info("Writing to file $outname")
|
||||
|
||||
@info "Tangled to $(out_path)"
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
weave(source ; doctype = :auto,
|
||||
informat=:auto, out_path=:doc, args = Dict(),
|
||||
mod::Union{Module, Symbol} = Main,
|
||||
fig_path = "figures", fig_ext = nothing,
|
||||
cache_path = "cache", cache=:off,
|
||||
template = nothing, highlight_theme = nothing, css = nothing,
|
||||
pandoc_options = "",
|
||||
latex_cmd = "xelatex")
|
||||
weave(source::AbstractString; kwargs...)
|
||||
|
||||
Weave an input document to output file.
|
||||
|
||||
* `doctype`: :auto = set based on file extension or specify one of the supported formats.
|
||||
See `list_out_formats()`
|
||||
* `informat`: :auto = set based on file extension or set to `"noweb"`, `"markdown"` or `script`
|
||||
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document, `:pwd`:
|
||||
Julia working directory, `"somepath"`: output directory as a String e.g `"/home/mpastell/weaveout"` or filename as
|
||||
string e.g. ~/outpath/outfile.tex.
|
||||
* `args`: dictionary of arguments to pass to document. Available as WEAVE_ARGS
|
||||
* `mod`: Module where Weave `eval`s code. Defaults to `:sandbox`
|
||||
to create new sandbox module, you can also pass a module e.g. `Main`.
|
||||
* `fig_path`: where figures will be generated, relative to out_path
|
||||
* `fig_ext`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`.
|
||||
* `cache_path`: where of cached output will be saved.
|
||||
* `cache`: controls caching of code: `:off` = no caching, `:all` = cache everything,
|
||||
`:user` = cache based on chunk options, `:refresh`, run all code chunks and save new cache.
|
||||
* `throw_errors`: if `false` errors are included in output document and the whole document is
|
||||
executed. if `true` errors are thrown when they occur.
|
||||
* `template`: Template (file path) or MustacheTokens for md2html or md2tex formats.
|
||||
* `highlight_theme`: Theme (Highlights.AbstractTheme) for used syntax highlighting
|
||||
* `css`: CSS (file path) used for md2html format
|
||||
* `pandoc_options`: String array of options to pass to pandoc for `pandoc2html` and
|
||||
`pandoc2pdf` formats e.g. ["--toc", "-N"]
|
||||
* `latex_cmd`: the command used to make pdf from .tex
|
||||
* `latex_keep_unicode`: if set to true (default is false), do not convert unicode characters to their
|
||||
respective latex representation. This is especially useful if a font and tex-engine with support for unicode
|
||||
characters are used.
|
||||
## Keyword options
|
||||
|
||||
**Note:** Run Weave from terminal and not using IJulia, Juno or ESS, they tend to mess with capturing output.
|
||||
- `doctype::Union{Nothing,AbstractString} = nothing`: Output document format. By default (i.e. given `nothing`), Weave will set it automatically based on file extension. You can also manually specify it; see [`list_out_formats()`](@ref) for the supported formats
|
||||
- `informat::Union{Nothing,AbstractString} = nothing`: Input document format. By default (i.e. given `nothing`), Weave will set it automatically based on file extension. You can also specify either of `"script"`, `"markdown"`, `"notebook"`, or `"noweb"`
|
||||
- `out_path::Union{Symbol,AbstractString} = :doc`: Path where the output is generated can be either of:
|
||||
* `:doc`: Path of the source document (default)
|
||||
* `:pwd`: Julia working directory
|
||||
* `"somepath"`: `String` of output directory e.g. `"~/outdir"`, or of filename e.g. `"~/outdir/outfile.tex"`
|
||||
- `args::Any = Dict()`: A runtime object that is available as `WEAVE_ARGS` while `weave`ing
|
||||
- `mod::Union{Module,Nothing} = nothing`: Module where Weave `eval`s code. You can pass a `Module` object, otherwise create an new sandbox module.
|
||||
- `fig_path::Union{Nothing,AbstractString} = nothing`: Where figures will be generated, relative to `out_path`. By default (i.e. given `nothing`), Weave will automatically create `$(DEFAULT_FIG_PATH)` directory.
|
||||
- `fig_ext::Union{Nothing,AbstractString} = nothing`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`
|
||||
- `cache_path::AbstractString = "cache"`: Where of cached output will be saved
|
||||
- `cache::Symbol = :off`: Controls caching of code:
|
||||
* `:off` means no caching (default)
|
||||
* `:all` caches everything
|
||||
* `:user` caches based on chunk options
|
||||
* `:refresh` runs all code chunks and save new cache
|
||||
- `template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing`: Template (file path) or `Mustache.MustacheTokens`s for `md2html` or `md2tex` formats
|
||||
- `css::Union{Nothing,AbstractString} = nothing`: Path of a CSS file used for md2html format
|
||||
- `highlight_theme::Union{Nothing,Type{<:Highlights.AbstractTheme}} = nothing`: Theme used for syntax highlighting (defaults to `Highlights.Themes.DefaultTheme`)
|
||||
- `pandoc_options::Vector{<:AbstractString} = $(DEFAULT_PANDOC_OPTIONS)`: `String`s of options to pass to pandoc for `pandoc2html` and `pandoc2pdf` formats, e.g. `["--toc", "-N"]`
|
||||
- `latex_cmd::Vector{<:AbstractString} = $(DEFAULT_LATEX_CMD)`: The command used to make PDF file from .tex
|
||||
- `keep_unicode::Bool = false`: If `true`, do not convert unicode characters to their respective latex representation. This is especially useful if a font and tex-engine with support for unicode characters are used
|
||||
|
||||
!!! note
|
||||
Run Weave from terminal and try to avoid weaving from IJulia or ESS; they tend to mess with capturing output.
|
||||
"""
|
||||
function weave(source ; doctype = :auto,
|
||||
informat=:auto, out_path=:doc, args = Dict(),
|
||||
mod::Union{Module, Symbol} = :sandbox,
|
||||
fig_path = "figures", fig_ext = nothing,
|
||||
cache_path = "cache", cache=:off,
|
||||
throw_errors = false,
|
||||
template = nothing, highlight_theme = nothing, css = nothing,
|
||||
pandoc_options = String[]::Array{String},
|
||||
latex_cmd = "xelatex",latex_keep_unicode=false)
|
||||
function weave(
|
||||
source::AbstractString;
|
||||
doctype::Union{Nothing,AbstractString} = nothing,
|
||||
informat::Union{Nothing,AbstractString} = nothing,
|
||||
out_path::Union{Symbol,AbstractString} = :doc,
|
||||
args::Any = Dict(),
|
||||
mod::Union{Module,Nothing} = nothing,
|
||||
fig_path::Union{Nothing,AbstractString} = nothing,
|
||||
fig_ext::Union{Nothing,AbstractString} = nothing,
|
||||
cache_path::AbstractString = "cache",
|
||||
cache::Symbol = :off,
|
||||
template::Union{Nothing,AbstractString,Mustache.MustacheTokens} = nothing,
|
||||
css::Union{Nothing,AbstractString} = nothing, # TODO: rename to `stylesheet`
|
||||
highlight_theme::Union{Nothing,Type{<:Highlights.AbstractTheme}} = nothing,
|
||||
pandoc_options::Vector{<:AbstractString} = DEFAULT_PANDOC_OPTIONS,
|
||||
latex_cmd::Vector{<:AbstractString} = DEFAULT_LATEX_CMD,
|
||||
keep_unicode::Bool = false,
|
||||
)
|
||||
doc = WeaveDoc(source, informat)
|
||||
|
||||
doc = read_doc(source, informat)
|
||||
doctype == :auto && (doctype = detect_doctype(doc.source))
|
||||
doc.doctype = doctype
|
||||
# run document
|
||||
# ------------
|
||||
|
||||
|
||||
# Read args from document header, overrides command line args
|
||||
if haskey(doc.header, "options")
|
||||
(doctype, informat, out_path, args, mod, fig_path, fig_ext,
|
||||
cache_path, cache, throw_errors, template, highlight_theme, css,
|
||||
pandoc_options, latex_cmd) = header_args(doc, out_path, mod,
|
||||
fig_ext, fig_path,
|
||||
cache_path, cache, throw_errors,
|
||||
template, highlight_theme, css,
|
||||
pandoc_options, latex_cmd)
|
||||
# overwrites options with those specified in header, that are needed for running document
|
||||
# NOTE: these YAML options can NOT be given dynamically
|
||||
weave_options = get(doc.header, WEAVE_OPTION_NAME, nothing)
|
||||
if haskey(doc.header, WEAVE_OPTION_NAME_DEPRECATED)
|
||||
@warn "Weave: `options` key is deprecated. Use `weave_options` key instead." _id = WEAVE_OPTION_DEPRECATE_ID maxlog = 1
|
||||
weave_options = get(doc.header, WEAVE_OPTION_NAME_DEPRECATED, nothing)
|
||||
end
|
||||
|
||||
template != nothing && (doc.template = template)
|
||||
highlight_theme != nothing && (doc.highlight_theme = highlight_theme)
|
||||
#theme != nothing && (doc.theme = theme) #Reserved for themes
|
||||
css != nothing && (doc.css = css)
|
||||
if !isnothing(weave_options)
|
||||
doctype = get(weave_options, "doctype", doctype)
|
||||
specific_options!(weave_options, doctype)
|
||||
if haskey(weave_options, "out_path")
|
||||
out_path = let
|
||||
out_path = weave_options["out_path"]
|
||||
if out_path == ":doc" || out_path == ":pwd"
|
||||
Symbol(out_path)
|
||||
else
|
||||
normpath(dirname(source), out_path) # resolve relative to this document
|
||||
end
|
||||
end
|
||||
end
|
||||
mod = get(weave_options, "mod", mod)
|
||||
mod isa AbstractString && (mod = Main.eval(Meta.parse(mod)))
|
||||
fig_path = get(weave_options, "fig_path", fig_path)
|
||||
fig_ext = get(weave_options, "fig_ext", fig_ext)
|
||||
cache_path = get(weave_options, "cache_path", cache_path)
|
||||
cache = Symbol(get(weave_options, "cache", cache))
|
||||
end
|
||||
|
||||
try
|
||||
doc = run(doc, doctype = doctype,
|
||||
mod = mod,
|
||||
out_path=out_path, args = args,
|
||||
fig_path = fig_path, fig_ext = fig_ext, cache_path = cache_path, cache=cache,
|
||||
throw_errors = throw_errors,latex_keep_unicode=latex_keep_unicode)
|
||||
formatted = format(doc)
|
||||
doc = run_doc(
|
||||
doc;
|
||||
doctype = doctype,
|
||||
mod = mod,
|
||||
out_path = out_path,
|
||||
args = args,
|
||||
fig_path = fig_path,
|
||||
fig_ext = fig_ext,
|
||||
cache_path = cache_path,
|
||||
cache = cache,
|
||||
)
|
||||
|
||||
outname = get_outname(out_path, doc)
|
||||
# overwrites options with those specified in header, that are needed for rendering/writing document
|
||||
# NOTE: these YAML options can be given dynamically
|
||||
if !isnothing(weave_options)
|
||||
if haskey(weave_options, "template")
|
||||
template = weave_options["template"]
|
||||
# resolve relative to this document
|
||||
template isa AbstractString && (template = normpath(dirname(source), template))
|
||||
end
|
||||
if haskey(weave_options, "css")
|
||||
css = weave_options["css"]
|
||||
# resolve relative to this document
|
||||
css isa AbstractString && (css = normpath(dirname(source), css))
|
||||
end
|
||||
highlight_theme = get(weave_options, "highlight_theme", highlight_theme)
|
||||
keep_unicode = get(weave_options, "keep_unicode", keep_unicode)
|
||||
latex_cmd = get(weave_options, "latex_cmd", latex_cmd)
|
||||
pandoc_options = get(weave_options, "pandoc_options", pandoc_options)
|
||||
end
|
||||
|
||||
open(outname, "w") do io
|
||||
write(io, formatted)
|
||||
end
|
||||
set_format_options!(
|
||||
doc;
|
||||
# general
|
||||
template = template,
|
||||
highlight_theme = highlight_theme,
|
||||
css = css,
|
||||
# pandoc
|
||||
pandoc_options = pandoc_options,
|
||||
# latex
|
||||
keep_unicode = keep_unicode,
|
||||
latex_cmd = latex_cmd,
|
||||
)
|
||||
|
||||
#Special for that need external programs
|
||||
if doc.doctype == "pandoc2html"
|
||||
mdname = outname
|
||||
outname = get_outname(out_path, doc, ext = "html")
|
||||
pandoc2html(formatted, doc, outname, pandoc_options)
|
||||
rm(mdname)
|
||||
elseif doc.doctype == "pandoc2pdf"
|
||||
mdname = outname
|
||||
outname = get_outname(out_path, doc, ext = "pdf")
|
||||
pandoc2pdf(formatted, doc, outname, pandoc_options)
|
||||
rm(mdname)
|
||||
elseif doc.doctype == "md2pdf"
|
||||
success = run_latex(doc, outname, latex_cmd)
|
||||
success && rm(doc.fig_path, force = true, recursive = true)
|
||||
success || return
|
||||
outname = get_outname(out_path, doc, ext = "pdf")
|
||||
end
|
||||
# render document
|
||||
# ---------------
|
||||
rendered = render_doc(doc)
|
||||
|
||||
doc.cwd == pwd() && (outname = basename(outname))
|
||||
@info("Report weaved to $outname")
|
||||
return abspath(outname)
|
||||
#catch err
|
||||
# @warn("Something went wrong during weaving")
|
||||
# @error(sprint(showerror, err))
|
||||
# return nothing
|
||||
finally
|
||||
doctype == :auto && (doctype = detect_doctype(doc.source))
|
||||
if occursin("2pdf", doctype)
|
||||
rm(doc.fig_path, force = true, recursive = true)
|
||||
elseif occursin("2html", doctype)
|
||||
rm(doc.fig_path, force = true, recursive = true)
|
||||
# write documents
|
||||
# ---------------
|
||||
out_path = write_doc(doc, rendered, get_out_path(doc, out_path))
|
||||
|
||||
@info "Weaved to $(out_path)"
|
||||
return out_path
|
||||
end
|
||||
|
||||
weave(doc::AbstractString, doctype::Union{Symbol,AbstractString}; kwargs...) =
|
||||
weave(doc; doctype = doctype, kwargs...)
|
||||
|
||||
function specific_options!(weave_options, doctype)
|
||||
fmts = keys(FORMATS)
|
||||
for (k,v) in weave_options
|
||||
if k in fmts
|
||||
k == doctype && merge!(weave_options, v)
|
||||
delete!(weave_options, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function weave(doc::AbstractString, doctype::AbstractString)
|
||||
weave(doc, doctype=doctype)
|
||||
get_out_path(doc, out_path, ext::Nothing = nothing) = get_out_path(doc, out_path, doc.format.extension)
|
||||
get_out_path(doc, out_path, ext) = abspath(get_cwd(doc, out_path), string(doc.basename , '.', ext))
|
||||
|
||||
"""
|
||||
notebook(source::AbstractString; kwargs...)
|
||||
|
||||
Convert Weave document `source` to Jupyter Notebook and execute the code
|
||||
using [`nbconvert`](https://nbconvert.readthedocs.io/en/latest/).
|
||||
**Ignores** all chunk options.
|
||||
|
||||
## Keyword options
|
||||
|
||||
- `out_path::Union{Symbol,AbstractString} = :pwd`: Path where the output is generated can be either of:
|
||||
* `:doc`: Path of the source document
|
||||
* `:pwd`: Julia working directory (default)
|
||||
* `"somepath"`: `String` of output directory e.g. `"~/outdir"`, or of filename e.g. `"~/outdir/outfile.tex"`
|
||||
- `timeout = -1`: nbconvert cell timeout in seconds. Defaults to `-1` (no timeout)
|
||||
- `nbconvert_options::AbstractString = ""`: `String` of additional options to pass to nbconvert, such as `"--allow-errors"`
|
||||
- `jupyter_path::AbstractString = "jupyter"`: Path/command for the Jupyter you want to use. Defaults to `"jupyter"`, which runs whatever is linked/alias to that
|
||||
|
||||
!!! warning
|
||||
The code is _**not**_ executed by Weave, but by [`nbconvert`](https://nbconvert.readthedocs.io/en/latest/).
|
||||
This means that the output doesn't necessarily always work properly; see [#116](https://github.com/JunoLab/Weave.jl/issues/116).
|
||||
|
||||
!!! note
|
||||
In order to _just_ convert Weave document to Jupyter Notebook,
|
||||
use [`convert_doc`](@ref) instead.
|
||||
"""
|
||||
function notebook(
|
||||
source::AbstractString;
|
||||
out_path::Union{Symbol,AbstractString} = :pwd,
|
||||
timeout = -1,
|
||||
nbconvert_options::AbstractString = "",
|
||||
jupyter_path::AbstractString = "jupyter",
|
||||
)
|
||||
doc = WeaveDoc(source)
|
||||
converted = convert_to_notebook(doc)
|
||||
doc.cwd = get_cwd(doc, out_path)
|
||||
out_path = get_out_path(doc, out_path, "ipynb")
|
||||
|
||||
write(out_path, converted)
|
||||
|
||||
@info "Running nbconvert ..."
|
||||
return read(
|
||||
`$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $(out_path) $nbconvert_options --output $(out_path)`,
|
||||
String,
|
||||
)
|
||||
end
|
||||
|
||||
"""
|
||||
notebook(source::String; out_path=:pwd, timeout=-1, nbconvert_options="", jupyter_path = "jupyter")
|
||||
include_weave(source::AbstractString, informat::Union{Nothing,AbstractString} = nothing)
|
||||
include_weave(m::Module, source::AbstractString, informat::Union{Nothing,AbstractString} = nothing)
|
||||
|
||||
Convert Weave document `source` to Jupyter notebook and execute the code
|
||||
using nbconvert. **Ignores** all chunk options
|
||||
|
||||
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document,
|
||||
`:pwd`: Julia working directory, `"somepath"`: Path as a
|
||||
String e.g `"/home/mpastell/weaveout"`
|
||||
* `timeout`: nbconvert cell timeout in seconds. Defaults to -1 (no timeout)
|
||||
* `nbconvert_options`: string of additional options to pass to nbconvert, such as `--allow-errors`
|
||||
* `jupyter_path`: Path/command for the Jupyter you want to use. Defaults to "jupyter," which runs whatever is linked/alias to that.
|
||||
Include code from Weave document calling `include_string` on all code from doc.
|
||||
Code is run in the path of the include document.
|
||||
"""
|
||||
function notebook(source::String; out_path=:pwd, timeout=-1, nbconvert_options=[], jupyter_path = "jupyter")
|
||||
doc = read_doc(source)
|
||||
converted = convert_doc(doc, NotebookOutput())
|
||||
doc.cwd = get_cwd(doc, out_path)
|
||||
outfile = get_outname(out_path, doc, ext="ipynb")
|
||||
|
||||
open(outfile, "w") do f
|
||||
write(f, converted)
|
||||
end
|
||||
|
||||
@info("Running nbconvert")
|
||||
out = read(`$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $outfile $nbconvert_options --output $outfile`, String)
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
include_weave(doc, informat=:auto)
|
||||
include_weave(m::Module, doc, informat=:auto)
|
||||
|
||||
Include code from Weave document calling `include_string` on
|
||||
all code from doc. Code is run in the path of the include document.
|
||||
"""
|
||||
function include_weave(m::Module, source, informat=:auto)
|
||||
function include_weave(
|
||||
m::Module,
|
||||
source::AbstractString,
|
||||
informat::Union{Nothing,AbstractString} = nothing,
|
||||
)
|
||||
old_path = pwd()
|
||||
doc = read_doc(source, informat)
|
||||
cd(doc.path)
|
||||
doc = WeaveDoc(source, informat)
|
||||
cd(dirname(doc.path))
|
||||
try
|
||||
code = join([x.content for x in
|
||||
filter(x -> isa(x,Weave.CodeChunk), doc.chunks)], "\n")
|
||||
code = join(
|
||||
[x.content for x in filter(x -> isa(x, Weave.CodeChunk), doc.chunks)],
|
||||
"\n",
|
||||
)
|
||||
include_string(m, code)
|
||||
catch e
|
||||
throw(e)
|
||||
catch err
|
||||
throw(err)
|
||||
finally
|
||||
cd(old_path)
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
|
||||
include_weave(source, informat=:auto) = include_weave(Main, source, informat)
|
||||
|
||||
#Hooks to run before and after chunks, this is form IJulia,
|
||||
#but note that Weave hooks take the chunk as input
|
||||
const preexecute_hooks = Function[]
|
||||
push_preexecute_hook(f::Function) = push!(preexecute_hooks, f)
|
||||
pop_preexecute_hook(f::Function) = splice!(preexecute_hooks, findfirst(x -> x == f, preexecute_hooks))
|
||||
|
||||
const postexecute_hooks = Function[]
|
||||
push_postexecute_hook(f::Function) = push!(postexecute_hooks, f)
|
||||
pop_postexecute_hook(f::Function) = splice!(postexecute_hooks, findfirst(x -> x == f, postexecute_hooks))
|
||||
|
||||
include("chunks.jl")
|
||||
include("config.jl")
|
||||
include("WeaveMarkdown/markdown.jl")
|
||||
include("display_methods.jl")
|
||||
include("readers.jl")
|
||||
include("run.jl")
|
||||
include("cache.jl")
|
||||
include("formatters.jl")
|
||||
include("format.jl")
|
||||
include("pandoc.jl")
|
||||
include("writers.jl")
|
||||
include_weave(source, informat = nothing) = include_weave(Main, source, informat)
|
||||
|
||||
|
||||
export weave, list_out_formats, tangle, convert_doc, notebook,
|
||||
set_chunk_defaults, get_chunk_defaults, restore_chunk_defaults,
|
||||
include_weave
|
||||
export weave,
|
||||
list_out_formats,
|
||||
tangle,
|
||||
convert_doc,
|
||||
notebook,
|
||||
set_chunk_defaults!,
|
||||
get_chunk_defaults,
|
||||
restore_chunk_defaults!,
|
||||
include_weave
|
||||
|
||||
end
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
#module Markdown2HTML
|
||||
# Markdown to HTML writer, Modified from Julia Base.Markdown html writer
|
||||
using Markdown: MD, Header, Code, Paragraph, BlockQuote, Footnote, Table,
|
||||
Admonition, List, HorizontalRule, Bold, Italic, Image, Link, LineBreak,
|
||||
LaTeX, isordered
|
||||
|
||||
function tohtml(io::IO, m::MIME"text/html", x)
|
||||
show(io, m, x)
|
||||
end
|
||||
using Markdown:
|
||||
MD,
|
||||
Header,
|
||||
Code,
|
||||
Paragraph,
|
||||
BlockQuote,
|
||||
Footnote,
|
||||
Table,
|
||||
Admonition,
|
||||
List,
|
||||
HorizontalRule,
|
||||
Bold,
|
||||
Italic,
|
||||
Image,
|
||||
Link,
|
||||
LineBreak,
|
||||
LaTeX,
|
||||
isordered
|
||||
|
||||
function tohtml(io::IO, m::MIME"text/plain", x)
|
||||
htmlesc(io, sprint(show, m, x))
|
||||
end
|
||||
|
||||
tohtml(io::IO, m::MIME"text/html", x) = show(io, m, x)
|
||||
|
||||
tohtml(io::IO, m::MIME"text/plain", x) = htmlesc(io, sprint(show, m, x))
|
||||
|
||||
function tohtml(io::IO, m::MIME"image/png", img)
|
||||
print(io, """<img src="data:image/png;base64,""")
|
||||
|
@ -18,11 +30,7 @@ function tohtml(io::IO, m::MIME"image/png", img)
|
|||
print(io, "\" />")
|
||||
end
|
||||
|
||||
function tohtml(m::MIME"image/svg+xml", img)
|
||||
show(io, m, img)
|
||||
end
|
||||
|
||||
|
||||
tohtml(m::MIME"image/svg+xml", img) = show(io, m, img)
|
||||
|
||||
# AbstractDisplay infrastructure
|
||||
|
||||
|
@ -35,7 +43,6 @@ end
|
|||
|
||||
tohtml(io::IO, x) = tohtml(io, bestmime(x), x)
|
||||
|
||||
|
||||
# Utils
|
||||
|
||||
function withtag(f, io::IO, tag, attrs...)
|
||||
|
@ -56,10 +63,13 @@ end
|
|||
|
||||
tag(io::IO, tag, attrs...) = withtag(nothing, io, tag, attrs...)
|
||||
|
||||
const _htmlescape_chars = Dict('<'=>"<", '>'=>">",
|
||||
'"'=>""", '&'=>"&",
|
||||
# ' '=>" ",
|
||||
)
|
||||
const _htmlescape_chars = Dict(
|
||||
'<' => "<",
|
||||
'>' => ">",
|
||||
'"' => """,
|
||||
'&' => "&",
|
||||
# ' '=>" ",
|
||||
)
|
||||
for ch in "'`!\$%()=+{}[]"
|
||||
_htmlescape_chars[ch] = "&#$(Int(ch));"
|
||||
end
|
||||
|
@ -93,7 +103,7 @@ end
|
|||
|
||||
html(io::IO, md::MD) = html(io, md.content)
|
||||
|
||||
function html(io::IO, header::Header{l}) where l
|
||||
function html(io::IO, header::Header{l}) where {l}
|
||||
withtag(io, "h$l") do
|
||||
htmlinline(io, header.text)
|
||||
end
|
||||
|
@ -141,7 +151,7 @@ function html(io::IO, md::Admonition)
|
|||
end
|
||||
|
||||
function html(io::IO, md::List)
|
||||
maybe_attr = md.ordered > 1 ? Any[:start => string(md.ordered)] : []
|
||||
maybe_attr = md.ordered > 1 ? Any[:start=>string(md.ordered)] : []
|
||||
withtag(io, isordered(md) ? :ol : :ul, maybe_attr...) do
|
||||
for item in md.items
|
||||
println(io)
|
||||
|
@ -153,9 +163,7 @@ function html(io::IO, md::List)
|
|||
end
|
||||
end
|
||||
|
||||
function html(io::IO, md::HorizontalRule)
|
||||
tag(io, :hr)
|
||||
end
|
||||
html(io::IO, md::HorizontalRule) = tag(io, :hr)
|
||||
|
||||
function html(io::IO, tex::LaTeX)
|
||||
withtag(io, :p, :class => "math") do
|
||||
|
@ -163,9 +171,7 @@ function html(io::IO, tex::LaTeX)
|
|||
end
|
||||
end
|
||||
|
||||
function html(io::IO, comment::Comment)
|
||||
write(io, "\n<!-- $(comment.text) -->\n")
|
||||
end
|
||||
html(io::IO, comment::Comment) = write(io, "\n<!-- $(comment.text) -->\n")
|
||||
|
||||
function html(io::IO, md::Table)
|
||||
withtag(io, :table) do
|
||||
|
@ -203,9 +209,7 @@ function htmlinline(io::IO, tex::LaTeX)
|
|||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, md::Union{Symbol,AbstractString})
|
||||
htmlesc(io, md)
|
||||
end
|
||||
htmlinline(io::IO, md::Union{Symbol,AbstractString}) = htmlesc(io, md)
|
||||
|
||||
function htmlinline(io::IO, md::Bold)
|
||||
withtag(io, :strong) do
|
||||
|
@ -219,10 +223,7 @@ function htmlinline(io::IO, md::Italic)
|
|||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, md::Image)
|
||||
tag(io, :img, :src=>md.url, :alt=>md.alt)
|
||||
end
|
||||
|
||||
htmlinline(io::IO, md::Image) = tag(io, :img, :src => md.url, :alt => md.alt)
|
||||
|
||||
function htmlinline(io::IO, f::Footnote)
|
||||
withtag(io, :a, :href => "#footnote-$(f.id)", :class => "footnote") do
|
||||
|
@ -231,23 +232,17 @@ function htmlinline(io::IO, f::Footnote)
|
|||
end
|
||||
|
||||
function htmlinline(io::IO, link::Link)
|
||||
withtag(io, :a, :href=>link.url) do
|
||||
withtag(io, :a, :href => link.url) do
|
||||
htmlinline(io, link.text)
|
||||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, br::LineBreak)
|
||||
tag(io, :br)
|
||||
end
|
||||
htmlinline(io::IO, br::LineBreak) = tag(io, :br)
|
||||
|
||||
function htmlinline(io::IO, comment::Comment)
|
||||
write(io, "<!-- $(comment.text) -->")
|
||||
end
|
||||
htmlinline(io::IO, comment::Comment) = write(io, "<!-- $(comment.text) -->")
|
||||
|
||||
htmlinline(io::IO, x) = tohtml(io, x)
|
||||
|
||||
# API
|
||||
|
||||
html(md) = sprint(html, md)
|
||||
|
||||
#end
|
||||
|
|
|
@ -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,29 +1,26 @@
|
|||
# This module extends the julia markdown parser to improve compatibility with Jupyter, Pandoc etc.
|
||||
module WeaveMarkdown
|
||||
|
||||
using ..Weave: isnothing, take2string!
|
||||
using Markdown
|
||||
import Markdown: @trigger, @breaking, Code, MD, withstream, startswith, LaTeX
|
||||
|
||||
function __init__()
|
||||
# NOTE:
|
||||
# overwriting `Markdown.latex` function should be done here in order to allow
|
||||
# incremental precompilations
|
||||
Markdown.eval(quote
|
||||
function latex(io::IO, tex::Markdown.LaTeX)
|
||||
math_envs = ["align", "equation", "eqnarray"]
|
||||
use_dollars = !any([occursin("\\begin{$me", tex.formula) for me in math_envs])
|
||||
use_dollars && write(io, "\\[")
|
||||
write(io, string("\n", tex.formula, "\n"))
|
||||
use_dollars && write(io, "\\]\n")
|
||||
end
|
||||
end)
|
||||
# Note that this definition causes a "Method overwritten" warning,
|
||||
# but defining this function in __init__() is not legal in julia v1.5
|
||||
function Markdown.latex(io::IO, tex::Markdown.LaTeX)
|
||||
math_envs = ["align", "equation", "eqnarray"]
|
||||
use_dollars =
|
||||
!any([occursin("\\begin{$me", tex.formula) for me in math_envs])
|
||||
use_dollars && write(io, "\\[")
|
||||
write(io, string("\n", tex.formula, "\n"))
|
||||
use_dollars && write(io, "\\]\n")
|
||||
end
|
||||
|
||||
mutable struct Comment
|
||||
text::String
|
||||
end
|
||||
|
||||
@breaking true ->
|
||||
function dollarmath(stream::IO, block::MD)
|
||||
@breaking true -> function dollarmath(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
str = Markdown.startswith(stream, r"^\$\$$"m)
|
||||
isempty(str) && return false
|
||||
|
@ -35,29 +32,28 @@ function dollarmath(stream::IO, block::MD)
|
|||
if !isempty(estr)
|
||||
estr = Markdown.startswith(stream, r"^\$\$$"m)
|
||||
if isempty(estr)
|
||||
push!(block, LaTeX(String(take!(buffer)) |> chomp))
|
||||
push!(block, LaTeX(take2string!(buffer) |> chomp))
|
||||
end
|
||||
return true
|
||||
else
|
||||
seek(stream, line_start)
|
||||
end
|
||||
write(buffer, readline(stream, keep=true))
|
||||
write(buffer, readline(stream, keep = true))
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
@breaking true ->
|
||||
function topcomment(stream::IO, block::MD)
|
||||
@breaking true -> function topcomment(stream::IO, block::MD)
|
||||
buffer = IOBuffer()
|
||||
withstream(stream) do
|
||||
str = Markdown.startswith(stream, r"^<!--")
|
||||
isempty(str) && return false
|
||||
while !eof(stream)
|
||||
line = readline(stream, keep=true)
|
||||
line = readline(stream, keep = true)
|
||||
write(buffer, line)
|
||||
if occursin(r"-->$", line)
|
||||
s = replace(String(take!(buffer)) |> chomp, r"-->$" => "")
|
||||
s = replace(take2string!(buffer) |> chomp, r"-->$" => "")
|
||||
push!(block, Comment(s))
|
||||
return true
|
||||
end
|
||||
|
@ -66,12 +62,11 @@ function topcomment(stream::IO, block::MD)
|
|||
end
|
||||
end
|
||||
|
||||
@trigger '<' ->
|
||||
function comment(stream::IO, md::MD)
|
||||
@trigger '<' -> function comment(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
Markdown.startswith(stream, "<!--") || return
|
||||
text = Markdown.readuntil(stream, "-->")
|
||||
text ≡ nothing && return
|
||||
isnothing(text) && return
|
||||
return Comment(text)
|
||||
end
|
||||
end
|
||||
|
@ -88,6 +83,8 @@ for key in keys(Markdown.julia.inner)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
include("html.jl")
|
||||
include("latex.jl")
|
||||
end
|
||||
|
||||
end # module
|
||||
|
|
48
src/cache.jl
48
src/cache.jl
|
@ -1,9 +1,9 @@
|
|||
#Serialization is imported only if cache is used
|
||||
# Serialization is imported only if cache is used
|
||||
|
||||
function write_cache(doc::WeaveDoc, cache_path)
|
||||
cache_dir = joinpath(doc.cwd, cache_path)
|
||||
isdir(cache_dir) || mkpath(cache_dir)
|
||||
open(joinpath(cache_dir, doc.basename * ".cache"),"w") do io
|
||||
isdir(cache_dir) || mkpath(cache_dir)
|
||||
open(joinpath(cache_dir, doc.basename * ".cache"), "w") do io
|
||||
Serialization.serialize(io, doc)
|
||||
end
|
||||
return nothing
|
||||
|
@ -11,47 +11,47 @@ end
|
|||
|
||||
function read_cache(doc::WeaveDoc, cache_path)
|
||||
name = joinpath(doc.cwd, cache_path, doc.basename * ".cache")
|
||||
isfile(name) || return nothing
|
||||
open(name,"r") do io
|
||||
isfile(name) || return nothing
|
||||
open(name, "r") do io
|
||||
doc = Serialization.deserialize(io)
|
||||
end
|
||||
return doc
|
||||
end
|
||||
|
||||
function restore_chunk(chunk::CodeChunk, cached)
|
||||
chunks = filter(x -> x.number == chunk.number &&
|
||||
string(typeof(x)) == "Weave.CodeChunk", cached.chunks)
|
||||
chunks = filter(
|
||||
x -> x.number == chunk.number && string(typeof(x)) == "Weave.CodeChunk",
|
||||
cached.chunks,
|
||||
)
|
||||
|
||||
#Chunk types, don't match after loading. Fix by constructing chunks
|
||||
#from loaded content
|
||||
new_chunks = Any[]
|
||||
# Chunk types, don't match after loading. Fix by constructing chunks
|
||||
# from loaded content
|
||||
new_chunks = []
|
||||
for c in chunks
|
||||
newc = CodeChunk(c.content, c.number, c.start_line, c.optionstring, c.options)
|
||||
newc.result_no = c.result_no
|
||||
newc.figures = c.figures
|
||||
newc.result = c.result
|
||||
newc.output = c.output
|
||||
newc.rich_output = c.rich_output
|
||||
push!(new_chunks, newc)
|
||||
newc = CodeChunk(c.content, c.number, c.start_line, c.optionstring, c.options)
|
||||
newc.figures = c.figures
|
||||
newc.result = c.result
|
||||
newc.output = c.output
|
||||
newc.rich_output = c.rich_output
|
||||
push!(new_chunks, newc)
|
||||
end
|
||||
return new_chunks
|
||||
end
|
||||
|
||||
#Restore inline code
|
||||
# Restore inline code
|
||||
function restore_chunk(chunk::DocChunk, cached::WeaveDoc)
|
||||
#Get chunk from cached doc
|
||||
c_chunk = filter(x -> x.number == chunk.number &&
|
||||
isa(x, DocChunk), cached.chunks)
|
||||
# Get chunk from cached doc
|
||||
c_chunk = filter(x -> x.number == chunk.number && isa(x, DocChunk), cached.chunks)
|
||||
isempty(c_chunk) && return chunk
|
||||
c_chunk = c_chunk[1]
|
||||
|
||||
#Collect cached code
|
||||
# Collect cached code
|
||||
c_inline = filter(x -> isa(x, InlineCode), c_chunk.content)
|
||||
isempty(c_inline) && return chunk
|
||||
|
||||
#Restore cached results for Inline code
|
||||
# Restore cached results for Inline code
|
||||
n = length(chunk.content)
|
||||
for i in 1:n
|
||||
for i = 1:n
|
||||
if isa(chunk.content[i], InlineCode)
|
||||
ci = filter(x -> x.number == chunk.content[i].number, c_inline)
|
||||
isempty(ci) && continue
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
import Mustache
|
||||
|
||||
abstract type WeaveChunk end
|
||||
abstract type Inline end
|
||||
|
||||
mutable struct WeaveDoc
|
||||
source::AbstractString
|
||||
basename::AbstractString
|
||||
path::AbstractString
|
||||
chunks::Array{WeaveChunk}
|
||||
cwd::AbstractString
|
||||
format
|
||||
doctype::AbstractString
|
||||
header_script::String
|
||||
header::Dict
|
||||
template::Union{AbstractString, Mustache.MustacheTokens}
|
||||
css::AbstractString
|
||||
highlight_theme
|
||||
fig_path::AbstractString
|
||||
chunk_defaults::Dict{Symbol,Any}
|
||||
function WeaveDoc(source, chunks, header)
|
||||
path, fname = splitdir(abspath(source))
|
||||
basename = splitext(fname)[1]
|
||||
new(source, basename, path, chunks, "", nothing, "", "", header,
|
||||
"", "", Highlights.Themes.DefaultTheme, "", deepcopy(rcParams[:chunk_defaults]))
|
||||
end
|
||||
end
|
||||
|
||||
struct ChunkOutput
|
||||
code::AbstractString
|
||||
stdout::AbstractString
|
||||
displayed::AbstractString
|
||||
rich_output::AbstractString
|
||||
figures::Array{AbstractString}
|
||||
end
|
||||
|
||||
mutable struct CodeChunk <: WeaveChunk
|
||||
content::AbstractString
|
||||
number::Int
|
||||
result_no::Int
|
||||
start_line::Int
|
||||
optionstring::AbstractString
|
||||
options::Dict{Symbol, Any}
|
||||
output::AbstractString
|
||||
rich_output::AbstractString
|
||||
figures::Array{AbstractString}
|
||||
result::Array{ChunkOutput}
|
||||
function CodeChunk(content, number, start_line, optionstring, options)
|
||||
new(rstrip(content) * "\n", number, 0, start_line, optionstring, options, "","", AbstractString[], ChunkOutput[])
|
||||
end
|
||||
end
|
||||
|
||||
mutable struct DocChunk <: WeaveChunk
|
||||
content::Array{Inline}
|
||||
number::Int
|
||||
start_line::Int
|
||||
function DocChunk(text::AbstractString, number::Int, start_line::Int, inline_regex = nothing)
|
||||
chunks = parse_inline(text, inline_regex)
|
||||
new(chunks, number, start_line)
|
||||
end
|
||||
end
|
||||
|
||||
mutable struct InlineText <: Inline
|
||||
content::AbstractString
|
||||
si::Int
|
||||
ei::Int
|
||||
number::Int
|
||||
end
|
||||
|
||||
mutable struct InlineCode <: Inline
|
||||
content::AbstractString
|
||||
si::Int
|
||||
ei::Int
|
||||
number::Int
|
||||
ctype::Symbol
|
||||
output::AbstractString
|
||||
rich_output::AbstractString
|
||||
figures::Array{AbstractString}
|
||||
function InlineCode(content, si, ei, number, ctype)
|
||||
new(content, si, ei, number, ctype, "", "", AbstractString[])
|
||||
end
|
||||
end
|
||||
|
||||
struct TermResult end
|
||||
struct ScriptResult end
|
||||
struct CollectResult end
|
172
src/config.jl
172
src/config.jl
|
@ -1,143 +1,59 @@
|
|||
import Mustache
|
||||
|
||||
#Default options
|
||||
const defaultParams =
|
||||
Dict{Symbol,Any}(:storeresults => false,
|
||||
:doc_number => 0,
|
||||
:chunk_defaults =>
|
||||
Dict{Symbol,Any}(
|
||||
:echo=> true,
|
||||
:results=> "markup",
|
||||
:hold => false,
|
||||
:fig=> true,
|
||||
:include=> true,
|
||||
:eval => true,
|
||||
:tangle => true,
|
||||
:cache => false,
|
||||
:fig_cap=> nothing,
|
||||
#Size in inches
|
||||
:fig_width => 6,
|
||||
:fig_height => 4,
|
||||
:fig_path=> "figures",
|
||||
:dpi => 96,
|
||||
:term=> false,
|
||||
:display => false,
|
||||
:prompt => "\njulia> ",
|
||||
:label=> nothing,
|
||||
:wrap=> true,
|
||||
:line_width => 75,
|
||||
:engine=> "julia",
|
||||
#:option_AbstractString=> "",
|
||||
#Defined in formats
|
||||
:fig_ext => nothing,
|
||||
:fig_pos=> nothing,
|
||||
:fig_env=> nothing,
|
||||
:out_width=> nothing,
|
||||
:out_height=> nothing,
|
||||
:skip=>false,
|
||||
:print=>false
|
||||
)
|
||||
)
|
||||
#This one can be changed at runtime, initially a copy of defaults
|
||||
const rcParams = deepcopy(defaultParams)
|
||||
# TODO: follow RMarkdown convention more
|
||||
const _DEFAULT_PARAMS = Dict{Symbol,Any}(
|
||||
:echo => true,
|
||||
:results => "markup",
|
||||
:hold => false,
|
||||
:fig => true,
|
||||
:eval => true,
|
||||
:error => true,
|
||||
:tangle => true,
|
||||
:cache => false,
|
||||
:fig_cap => nothing,
|
||||
# NOTE: size in inches
|
||||
:fig_width => 6,
|
||||
:fig_height => 4,
|
||||
:fig_path => DEFAULT_FIG_PATH,
|
||||
:dpi => 96,
|
||||
:term => false,
|
||||
:prompt => "julia>",
|
||||
:label => nothing,
|
||||
:wrap => true,
|
||||
:line_width => 75,
|
||||
:fig_ext => nothing,
|
||||
:fig_pos => nothing,
|
||||
:fig_env => nothing,
|
||||
:out_width => nothing,
|
||||
:out_height => nothing,
|
||||
:print => false,
|
||||
)
|
||||
const DEFAULT_PARAMS = deepcopy(_DEFAULT_PARAMS) # might be changed at runtime
|
||||
|
||||
"""
|
||||
set_chunk_defaults(opts::Dict{Symbol, Any})
|
||||
set_chunk_defaults!(k, v)
|
||||
set_chunk_defaults!(kv::Pair...)
|
||||
set_chunk_defaults!(opts::AbstractDict)
|
||||
|
||||
Set default options for code chunks, use [`get_chunk_defaults`](@ref) to see the current values.
|
||||
|
||||
E.g.: set default `dpi` to 200 and `fig_width` to 8
|
||||
|
||||
```julia
|
||||
julia> set_chunk_defaults(Dict{Symbol, Any}(:dpi => 200, fig_width => 8))
|
||||
```
|
||||
E.g.: all the three examples below will set default `dpi` to `200` and `fig_width` to `8`:
|
||||
- `set_chunk_defaults!(:dpi, 200); set_chunk_defaults!(:fig_width, 8)`
|
||||
- `set_chunk_defaults!(:dpi => 200, :fig_width => 8)`
|
||||
- `set_chunk_defaults!(Dict(:dpi => 200, :fig_width => 8))`
|
||||
"""
|
||||
function set_chunk_defaults(opts::Dict{Symbol, Any})
|
||||
merge!(rcParams[:chunk_defaults], opts)
|
||||
return nothing
|
||||
end
|
||||
set_chunk_defaults!(k, v) = DEFAULT_PARAMS[k]= v
|
||||
set_chunk_defaults!(kv::Pair...) = for (k,v) in kv; set_chunk_defaults!(k, v); end
|
||||
set_chunk_defaults!(opts::AbstractDict) = merge!(DEFAULT_PARAMS, opts)
|
||||
|
||||
"""
|
||||
`get_chunk_defaults()`
|
||||
get_chunk_defaults()
|
||||
|
||||
Get default options used for code chunks.
|
||||
"""
|
||||
function get_chunk_defaults()
|
||||
return(rcParams[:chunk_defaults])
|
||||
end
|
||||
get_chunk_defaults() = DEFAULT_PARAMS
|
||||
|
||||
"""
|
||||
`restore_chunk_defaults()`
|
||||
restore_chunk_defaults!()
|
||||
|
||||
Restore Weave.jl default chunk options
|
||||
Restore Weave.jl default chunk options.
|
||||
"""
|
||||
function restore_chunk_defaults()
|
||||
rcParams[:chunk_defaults] = defaultParams[:chunk_defaults]
|
||||
return nothing
|
||||
end
|
||||
|
||||
"""Combine format specific and common options from document header"""
|
||||
function combine_args(args, doctype)
|
||||
common = Dict()
|
||||
specific = Dict()
|
||||
for key in keys(args)
|
||||
if key ∈ keys(Weave.formats)
|
||||
specific[key] = args[key]
|
||||
else
|
||||
common[key] = args[key]
|
||||
end
|
||||
end
|
||||
haskey(specific, doctype) && merge!(common, specific[doctype])
|
||||
common
|
||||
end
|
||||
|
||||
getvalue(d::Dict, key , default) = haskey(d, key) ? d[key] : default
|
||||
|
||||
"""
|
||||
header_args(doc::WeaveDoc)`
|
||||
|
||||
Get weave arguments from document header
|
||||
"""
|
||||
function header_args(doc::WeaveDoc, out_path, mod, fig_ext, fig_path,
|
||||
cache_path, cache, throw_errors,template,
|
||||
highlight_theme, css,
|
||||
pandoc_options, latex_cmd)
|
||||
args = getvalue(doc.header, "options", Dict())
|
||||
doctype = getvalue(args, "doctype", doc.doctype)
|
||||
args = combine_args(args, doctype)
|
||||
informat = getvalue(args, "informat", :auto)
|
||||
out_path = getvalue(args, "out_path", out_path)
|
||||
out_path == ":pwd" && (out_path = :pwd)
|
||||
isa(out_path, Symbol) || (out_path = joinpath(dirname(doc.source), out_path))
|
||||
mod = Symbol(getvalue(args, "mod", mod))
|
||||
fig_path = getvalue(args, "fig_path", fig_path)
|
||||
fig_ext = getvalue(args, "fig_ext", fig_ext)
|
||||
cache_path = getvalue(args, "cache_path", cache_path)
|
||||
cache = Symbol(getvalue(args, "cache", cache))
|
||||
throw_errors = getvalue(args, "throw_errors", throw_errors)
|
||||
template = getvalue(args, "template", template)
|
||||
if template != nothing && !isa(template, Mustache.MustacheTokens) && !isempty(template)
|
||||
template = joinpath(dirname(doc.source), template)
|
||||
end
|
||||
highlight_theme = getvalue(args, "highlight_theme", highlight_theme)
|
||||
css = getvalue(args, "css", css)
|
||||
pandoc_options = getvalue(args, "pandoc_options", pandoc_options)
|
||||
latex_cmd = getvalue(args, "latex_cmd", latex_cmd)
|
||||
|
||||
return (doctype, informat, out_path, args, mod, fig_path, fig_ext,
|
||||
cache_path, cache, throw_errors, template, highlight_theme, css,
|
||||
pandoc_options, latex_cmd)
|
||||
end
|
||||
|
||||
"""
|
||||
`header_chunk_defaults!(doc::WeaveDoc)`
|
||||
|
||||
Get chunk defaults from header and update
|
||||
"""
|
||||
function header_chunk_defaults!(doc::WeaveDoc)
|
||||
for key in keys(doc.chunk_defaults)
|
||||
if haskey(doc.header["options"], String(key))
|
||||
doc.chunk_defaults[key] = doc.header["options"][String(key)]
|
||||
end
|
||||
end
|
||||
end
|
||||
restore_chunk_defaults!() = for (k,v) in _DEFAULT_PARAMS; DEFAULT_PARAMS[k] = v; end
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
using JSON, Mustache
|
||||
|
||||
"""
|
||||
convert_doc(infile::AbstractString, outfile::AbstractString; outformat::Union{Nothing,AbstractString} = nothing)
|
||||
|
||||
Convert Weave documents between different formats
|
||||
|
||||
- `infile`: Path of the input document
|
||||
- `outfile`: Path of the output document
|
||||
- `outformat = nothing`: Output document format (optional). By default (i.e. given `nothing`) Weave will try to automatically detect it from the `outfile`'s extension. You can also specify either of `"script"`, `"markdown"`, `"notebook"`, or `"noweb"`
|
||||
"""
|
||||
function convert_doc(
|
||||
infile::AbstractString,
|
||||
outfile::AbstractString;
|
||||
outformat::Union{Nothing,AbstractString} = nothing,
|
||||
)
|
||||
doc = WeaveDoc(infile)
|
||||
|
||||
if isnothing(outformat)
|
||||
ext = lowercase(splitext(outfile)[2])
|
||||
outformat =
|
||||
ext == ".jl" ? "script" :
|
||||
ext == ".jmd" ? "markdown" :
|
||||
ext == ".ipynb" ? "notebook" :
|
||||
"noweb" # fallback
|
||||
end
|
||||
|
||||
converted = _convert_doc(doc, outformat)
|
||||
|
||||
open(outfile, "w") do f
|
||||
write(f, converted)
|
||||
end
|
||||
return outfile
|
||||
end
|
||||
|
||||
function _convert_doc(doc, outformat)
|
||||
outformat == "script" ? convert_to_script(doc) :
|
||||
outformat == "markdown" ? convert_to_markdown(doc) :
|
||||
outformat == "notebook" ? convert_to_notebook(doc) :
|
||||
convert_to_noweb(doc)
|
||||
end
|
||||
|
||||
function convert_to_script(doc)
|
||||
output = ""
|
||||
for chunk in doc.chunks
|
||||
if typeof(chunk) == Weave.DocChunk
|
||||
content = join([repr(c) for c in chunk.content], "")
|
||||
output *= join(["#' " * s for s in split(content, "\n")], "\n")
|
||||
else
|
||||
output *= "\n#+ "
|
||||
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
|
||||
output *= "\n\n" * lstrip(chunk.content)
|
||||
output *= "\n"
|
||||
end
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
function convert_to_markdown(doc)
|
||||
output = ""
|
||||
for chunk in doc.chunks
|
||||
if isa(chunk, DocChunk)
|
||||
output *= join([repr(c) for c in chunk.content], "")
|
||||
else
|
||||
output *= "\n" * "```julia"
|
||||
isempty(chunk.optionstring) || (output *= ";" * chunk.optionstring)
|
||||
output *= "\n" * lstrip(chunk.content)
|
||||
output *= "```\n"
|
||||
end
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
function convert_to_notebook(doc)
|
||||
nb = Dict()
|
||||
nb["nbformat"] = 4
|
||||
nb["nbformat_minor"] = 2
|
||||
metadata = Dict()
|
||||
kernelspec = Dict()
|
||||
kernelspec["language"] = "julia"
|
||||
kernelspec["name"] = "julia-$(VERSION.major).$(VERSION.minor)"
|
||||
kernelspec["display_name"] = "Julia $(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
|
||||
metadata["kernelspec"] = kernelspec
|
||||
language_info = Dict()
|
||||
language_info["file_extension"] = ".jl"
|
||||
language_info["mimetype"] = "application/julia"
|
||||
language_info["name"] = "julia"
|
||||
language_info["version"] = "$(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
|
||||
metadata["language_info"] = language_info
|
||||
cells = []
|
||||
ex_count = 1
|
||||
|
||||
for chunk in doc.chunks
|
||||
if isa(chunk, DocChunk)
|
||||
push!(
|
||||
cells,
|
||||
Dict(
|
||||
"cell_type" => "markdown",
|
||||
"metadata" => Dict(),
|
||||
"source" => [strip(join([repr(c) for c in chunk.content], ""))],
|
||||
),
|
||||
)
|
||||
else
|
||||
push!(
|
||||
cells,
|
||||
Dict(
|
||||
"cell_type" => "code",
|
||||
"metadata" => Dict(),
|
||||
"source" => [strip(chunk.content)],
|
||||
"execution_count" => nothing,
|
||||
"outputs" => [],
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
nb["cells"] = cells
|
||||
nb["metadata"] = metadata
|
||||
|
||||
json_nb = JSON.json(nb, 2)
|
||||
return json_nb
|
||||
end
|
||||
|
||||
function convert_to_noweb(doc)
|
||||
output = ""
|
||||
for chunk in doc.chunks
|
||||
if isa(chunk, DocChunk)
|
||||
output *= join([repr(c) for c in chunk.content], "")
|
||||
else
|
||||
output *= "\n" * "<<"
|
||||
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
|
||||
output *= ">>="
|
||||
output *= "\n" * lstrip(chunk.content)
|
||||
output *= "@\n"
|
||||
end
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
Base.repr(c::InlineText) = c.content
|
||||
Base.repr(c::InlineCode) = "`j $(c.content)`"
|
|
@ -1,51 +1,43 @@
|
|||
using Markdown
|
||||
import .WeaveMarkdown
|
||||
using Markdown, .WeaveMarkdown
|
||||
|
||||
#Contains report global properties
|
||||
# Contains report global properties
|
||||
mutable struct Report <: AbstractDisplay
|
||||
cwd::AbstractString
|
||||
basename::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
pending_code::AbstractString
|
||||
cur_result::AbstractString
|
||||
rich_output::AbstractString
|
||||
fignum::Int
|
||||
figures::Array{AbstractString}
|
||||
term_state::Symbol
|
||||
cur_chunk
|
||||
mimetypes::Array{AbstractString}
|
||||
first_plot::Bool
|
||||
header_script::String
|
||||
throw_errors::Bool
|
||||
cwd::String
|
||||
basename::String
|
||||
format::WeaveFormat
|
||||
rich_output::String
|
||||
fignum::Int
|
||||
figures::Vector{String}
|
||||
cur_chunk::Union{Nothing,CodeChunk}
|
||||
mimetypes::Vector{String}
|
||||
first_plot::Bool
|
||||
header_script::String
|
||||
end
|
||||
|
||||
function Report(cwd, basename, formatdict, mimetypes, throw_errors)
|
||||
Report(cwd, basename, formatdict, "", "", "", 1, AbstractString[], :text, nothing,
|
||||
mimetypes, true, "", throw_errors)
|
||||
end
|
||||
Report(cwd, basename, format, mimetypes) =
|
||||
Report(cwd, basename, format, "", 1, String[], nothing, mimetypes, true, "")
|
||||
|
||||
|
||||
#Default mimetypes in order, can be overridden for some inside `run method` formats
|
||||
# Default mimetypes in order, can be overridden for some inside `run method` formats
|
||||
const default_mime_types = ["image/svg+xml", "image/png", "text/html", "text/plain"]
|
||||
#const default_mime_types = ["image/png", "image/svg+xml", "text/html", "text/plain"]
|
||||
#From IJulia as a reminder
|
||||
#const supported_mime_types = [ "text/html", "text/latex", "image/svg+xml", "image/png", "image/jpeg", "text/plain", "text/markdown" ]
|
||||
# const default_mime_types = ["image/png", "image/svg+xml", "text/html", "text/plain"]
|
||||
# From IJulia as a reminder
|
||||
# const supported_mime_types = [ "text/html", "text/latex", "image/svg+xml", "image/png", "image/jpeg", "text/plain", "text/markdown" ]
|
||||
|
||||
const mimetype_ext =
|
||||
Dict(".png" => "image/png",
|
||||
".jpg" => "image/jpeg",
|
||||
".jpeg" => "image/jpeg",
|
||||
".svg" => "image/svg+xml",
|
||||
".js.svg" => "image/svg+xml",
|
||||
".pdf" => "application/pdf",
|
||||
".ps" => "application/postscript",
|
||||
".tex" => "text/latex"
|
||||
)
|
||||
const mimetype_ext = Dict(
|
||||
".png" => "image/png",
|
||||
".jpg" => "image/jpeg",
|
||||
".jpeg" => "image/jpeg",
|
||||
".svg" => "image/svg+xml",
|
||||
".js.svg" => "image/svg+xml",
|
||||
".pdf" => "application/pdf",
|
||||
".ps" => "application/postscript",
|
||||
".tex" => "text/latex",
|
||||
)
|
||||
|
||||
function Base.display(report::Report, data)
|
||||
#Set preferred mimetypes for report based on format
|
||||
# Set preferred mimetypes for report based on format
|
||||
fig_ext = report.cur_chunk.options[:fig_ext]
|
||||
for m in unique([mimetype_ext[fig_ext] ; report.mimetypes])
|
||||
for m in unique([mimetype_ext[fig_ext]; report.mimetypes])
|
||||
if Base.invokelatest(showable, m, data)
|
||||
try
|
||||
if !istextmime(m)
|
||||
|
@ -69,19 +61,13 @@ function Base.display(report::Report, data)
|
|||
end
|
||||
end
|
||||
|
||||
function Base.display(report::Report, m::MIME"image/png", data)
|
||||
figname = add_figure(report, data, m, ".png")
|
||||
end
|
||||
Base.display(report::Report, m::MIME"image/png", data) = add_figure(report, data, m, ".png")
|
||||
|
||||
function Base.display(report::Report, m::MIME"image/svg+xml", data)
|
||||
figname = add_figure(report, data, m, ".svg")
|
||||
end
|
||||
Base.display(report::Report, m::MIME"image/svg+xml", data) = add_figure(report, data, m, ".svg")
|
||||
|
||||
function Base.display(report::Report, m::MIME"application/pdf", data)
|
||||
figname = add_figure(report, data, m, ".pdf")
|
||||
end
|
||||
Base.display(report::Report, m::MIME"application/pdf", data) = add_figure(report, data, m, ".pdf")
|
||||
|
||||
#Text is written to stdout, called from "term" mode chunks
|
||||
# Text is written to stdout, called from "term" mode chunks
|
||||
function Base.display(report::Report, m::MIME"text/plain", data)
|
||||
io = PipeBuffer()
|
||||
show(IOContext(io, :limit => true), m, data)
|
||||
|
@ -100,24 +86,25 @@ function Base.display(report::Report, m::MIME"text/html", data::Exception)
|
|||
end
|
||||
|
||||
function Base.show(io, m::MIME"text/html", data::Exception)
|
||||
println(io ,"<pre class=\"julia-error\">")
|
||||
println(io, "<pre class=\"julia-error\">")
|
||||
println(io, Markdown.htmlesc("ERROR: " * sprint(showerror, data)))
|
||||
println(io ,"</pre>")
|
||||
println(io, "</pre>")
|
||||
end
|
||||
|
||||
#Catch "rich_output"
|
||||
# Catch "rich_output"
|
||||
function Base.display(report::Report, m::MIME"text/html", data)
|
||||
s = repr(m, data)
|
||||
report.rich_output *= "\n" * s
|
||||
io = IOBuffer()
|
||||
show(IOContext(io, :limit => true), m, data)
|
||||
report.rich_output *= string('\n', take2string!(io))
|
||||
end
|
||||
|
||||
#Catch "rich_output"
|
||||
# Catch "rich_output"
|
||||
function Base.display(report::Report, m::MIME"text/markdown", data)
|
||||
s = repr(m, data)
|
||||
# Convert to "richer" type of possible
|
||||
for m in report.mimetypes
|
||||
if m == "text/html" || m == "text/latex"
|
||||
display(Markdown.parse(s, flavor=WeaveMarkdown.weavemd))
|
||||
display(Markdown.parse(s, flavor = WeaveMarkdown.weavemd))
|
||||
break
|
||||
elseif m == "text/markdown"
|
||||
report.rich_output *= "\n" * s
|
||||
|
@ -128,23 +115,23 @@ end
|
|||
|
||||
function Base.display(report::Report, m::MIME"text/latex", data)
|
||||
s = repr(m, data)
|
||||
report.rich_output *= "\n" * s
|
||||
report.rich_output *= string('\n', s)
|
||||
end
|
||||
|
||||
"""Add saved figure name to results and return the name"""
|
||||
function add_figure(report::Report, data, m, ext)
|
||||
chunk = report.cur_chunk
|
||||
full_name, rel_name = get_figname(report, chunk, ext = ext)
|
||||
chunk = report.cur_chunk
|
||||
full_name, rel_name = get_figname(report, chunk, ext = ext)
|
||||
|
||||
open(full_name, "w") do io
|
||||
if ext == ".pdf"
|
||||
write(io, repr(m, data))
|
||||
else
|
||||
show(io, m, data)
|
||||
end
|
||||
end
|
||||
open(full_name, "w") do io
|
||||
if ext == ".pdf"
|
||||
write(io, repr(m, data))
|
||||
else
|
||||
show(io, m, data)
|
||||
end
|
||||
end
|
||||
|
||||
push!(report.figures, rel_name)
|
||||
report.fignum += 1
|
||||
return full_name
|
||||
push!(report.figures, rel_name)
|
||||
report.fignum += 1
|
||||
return full_name
|
||||
end
|
||||
|
|
389
src/format.jl
389
src/format.jl
|
@ -1,389 +0,0 @@
|
|||
import Mustache, Highlights
|
||||
import .WeaveMarkdown
|
||||
using Dates
|
||||
using Markdown
|
||||
using REPL.REPLCompletions: latex_symbols
|
||||
|
||||
|
||||
function format(doc::WeaveDoc)
|
||||
formatted = AbstractString[]
|
||||
docformat = doc.format
|
||||
|
||||
#Complete format dictionaries with defaults
|
||||
formatdict = docformat.formatdict
|
||||
get!(formatdict, :termstart, formatdict[:codestart])
|
||||
get!(formatdict, :termend, formatdict[:codeend])
|
||||
get!(formatdict, :out_width, nothing)
|
||||
get!(formatdict, :out_height, nothing)
|
||||
get!(formatdict, :fig_pos, nothing)
|
||||
get!(formatdict, :fig_env, nothing)
|
||||
|
||||
docformat.formatdict[:cwd] = doc.cwd #pass wd to figure formatters
|
||||
docformat.formatdict[:theme] = doc.highlight_theme
|
||||
|
||||
#strip header
|
||||
if isa(doc.chunks[1], DocChunk)
|
||||
if !occursin("pandoc", doc.doctype)
|
||||
doc.chunks[1] = strip_header(doc.chunks[1])
|
||||
end
|
||||
end
|
||||
|
||||
for chunk in copy(doc.chunks)
|
||||
result = format_chunk(chunk, formatdict, docformat)
|
||||
push!(formatted, result)
|
||||
end
|
||||
|
||||
formatted = join(formatted, "\n")
|
||||
# Render using a template if needed
|
||||
rendered = render_doc(formatted, doc, doc.format)
|
||||
|
||||
return rendered
|
||||
end
|
||||
|
||||
"""
|
||||
render_doc(formatted::AbstractString, format)
|
||||
|
||||
Render formatted document to a template
|
||||
"""
|
||||
function render_doc(formatted, doc::WeaveDoc, format)
|
||||
return formatted
|
||||
end
|
||||
|
||||
function highlight(mime::MIME, source::AbstractString, lexer, theme=Highlights.Themes.DefaultTheme)
|
||||
return sprint( (io, x) -> Highlights.highlight(io, mime, x, lexer, theme), source)
|
||||
end
|
||||
|
||||
function stylesheet(m::MIME, theme)
|
||||
return sprint( (io, x) -> Highlights.stylesheet(io, m, x), theme)
|
||||
end
|
||||
|
||||
function render_doc(formatted, doc::WeaveDoc, format::JMarkdown2HTML)
|
||||
css = stylesheet(MIME("text/html"), doc.highlight_theme)
|
||||
path, wsource = splitdir(abspath(doc.source))
|
||||
#wversion = string(Pkg.installed("Weave"))
|
||||
wversion = ""
|
||||
wtime = string(Date(now()))
|
||||
|
||||
if isempty(doc.css)
|
||||
theme_css = read(joinpath(dirname(@__FILE__), "../templates/skeleton_css.css"), String)
|
||||
else
|
||||
theme_css = read(doc.css, String)
|
||||
end
|
||||
|
||||
if isa(doc.template, Mustache.MustacheTokens)
|
||||
template = doc.template
|
||||
elseif isempty(doc.template)
|
||||
template = Mustache.template_from_file(joinpath(dirname(@__FILE__), "../templates/julia_html.tpl"))
|
||||
else
|
||||
template = Mustache.template_from_file(doc.template)
|
||||
end
|
||||
|
||||
return Mustache.render(template; themecss = theme_css,
|
||||
highlightcss = css, body = formatted, header_script = doc.header_script,
|
||||
source = wsource, wtime = wtime, wversion = wversion,
|
||||
[Pair(Symbol(k), v) for (k,v) in doc.header]...)
|
||||
end
|
||||
|
||||
function render_doc(formatted, doc::WeaveDoc, format::JMarkdown2tex)
|
||||
highlight = stylesheet(MIME("text/latex"), doc.highlight_theme)
|
||||
path, wsource = splitdir(abspath(doc.source))
|
||||
#wversion = string(Pkg.installed("Weave"))
|
||||
wversion = ""
|
||||
wtime = string(Date(now()))
|
||||
|
||||
|
||||
|
||||
if isa(doc.template, Mustache.MustacheTokens)
|
||||
template = doc.template
|
||||
elseif isempty(doc.template)
|
||||
template = Mustache.template_from_file(joinpath(dirname(@__FILE__), "../templates/julia_tex.tpl"))
|
||||
else
|
||||
template = Mustache.template_from_file(doc.template)
|
||||
end
|
||||
|
||||
return Mustache.render(template; body = formatted,
|
||||
highlight = highlight,
|
||||
[Pair(Symbol(k), v) for (k,v) in doc.header]...)
|
||||
end
|
||||
|
||||
function strip_header(chunk::DocChunk)
|
||||
if occursin(r"^---$(?<header>.+)^---$"ms, chunk.content[1].content)
|
||||
chunk.content[1].content = lstrip(replace(chunk.content[1].content, r"^---$(?<header>.+)^---$"ms => ""))
|
||||
end
|
||||
return chunk
|
||||
end
|
||||
|
||||
function format_chunk(chunk::DocChunk, formatdict, docformat)
|
||||
return join([format_inline(c) for c in chunk.content], "")
|
||||
end
|
||||
|
||||
function format_inline(inline::InlineText)
|
||||
return inline.content
|
||||
end
|
||||
|
||||
function format_inline(inline::InlineCode)
|
||||
isempty(inline.rich_output) || return inline.rich_output
|
||||
isempty(inline.figures) || return inline.figures[end]
|
||||
isempty(inline.output) || return inline.output
|
||||
end
|
||||
|
||||
function ioformat!(io::IOBuffer, out::IOBuffer, fun=WeaveMarkdown.latex)
|
||||
text = String(take!(io))
|
||||
if !isempty(text)
|
||||
m = Markdown.parse(text, flavor=WeaveMarkdown.weavemd)
|
||||
write(out, string(fun(m)))
|
||||
end
|
||||
end
|
||||
|
||||
function addspace(op, inline)
|
||||
inline.ctype == :line && (op = "\n$op\n")
|
||||
return op
|
||||
end
|
||||
|
||||
function format_chunk(chunk::DocChunk, formatdict, docformat::JMarkdown2tex)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
ioformat!(io, out)
|
||||
write(out, addspace(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end], inline)
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addspace(inline.output, inline))
|
||||
end
|
||||
end
|
||||
ioformat!(io, out)
|
||||
formatdict[:keep_unicode] || return uc2tex(String(take!(out)))
|
||||
return String(take!(out))
|
||||
end
|
||||
|
||||
function format_chunk(chunk::DocChunk, formatdict, docformat::JMarkdown2HTML)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
fun = WeaveMarkdown.html
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
ioformat!(io, out, fun)
|
||||
write(out, addspace(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end])
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addspace(inline.output, inline))
|
||||
end
|
||||
end
|
||||
ioformat!(io, out, fun)
|
||||
return String(take!(out))
|
||||
end
|
||||
|
||||
function format_chunk(chunk::CodeChunk, formatdict, docformat)
|
||||
#Fill undefined options with format specific defaults
|
||||
chunk.options[:out_width] == nothing &&
|
||||
(chunk.options[:out_width] = formatdict[:out_width])
|
||||
chunk.options[:fig_pos] == nothing &&
|
||||
(chunk.options[:fig_pos] = formatdict[:fig_pos])
|
||||
|
||||
#Only use floats if chunk has caption or sets fig_env
|
||||
if chunk.options[:fig_cap] != nothing && chunk.options[:fig_env] == nothing
|
||||
(chunk.options[:fig_env] = formatdict[:fig_env])
|
||||
end
|
||||
|
||||
if haskey(formatdict, :indent)
|
||||
chunk.content = indent(chunk.content, formatdict[:indent])
|
||||
end
|
||||
|
||||
chunk.content = format_code(chunk.content, docformat)
|
||||
|
||||
if !chunk.options[:eval]
|
||||
if chunk.options[:echo]
|
||||
result = "$(formatdict[:codestart])\n$(chunk.content)$(formatdict[:codeend])"
|
||||
return result
|
||||
else
|
||||
r = ""
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
if chunk.options[:term]
|
||||
result = format_termchunk(chunk, formatdict, docformat)
|
||||
else
|
||||
|
||||
if chunk.options[:echo]
|
||||
#Convert to output format and highlight (html, tex...) if needed
|
||||
result = "$(formatdict[:codestart])$(chunk.content)$(formatdict[:codeend])\n"
|
||||
else
|
||||
result = ""
|
||||
end
|
||||
|
||||
if (strip(chunk.output)!= "" || strip(chunk.rich_output) != "") && (chunk.options[:results] != "hidden")
|
||||
if chunk.options[:results] != "markup" && chunk.options[:results] != "hold"
|
||||
strip(chunk.output) ≠ "" && (result *= "$(chunk.output)\n")
|
||||
strip(chunk.rich_output) ≠ "" && (result *= "$(chunk.rich_output)\n")
|
||||
else
|
||||
if chunk.options[:wrap]
|
||||
chunk.output = "\n" * wraplines(chunk.output, chunk.options[:line_width])
|
||||
chunk.output = format_output(chunk.output, docformat)
|
||||
else
|
||||
chunk.output = "\n" * rstrip(chunk.output)
|
||||
chunk.output = format_output(chunk.output, docformat)
|
||||
end
|
||||
|
||||
if haskey(formatdict, :indent)
|
||||
chunk.output = indent(chunk.output, formatdict[:indent])
|
||||
end
|
||||
strip(chunk.output) ≠ "" &&
|
||||
(result *= "$(formatdict[:outputstart])$(chunk.output)\n$(formatdict[:outputend])\n")
|
||||
strip(chunk.rich_output) ≠ "" && (result *= chunk.rich_output * "\n")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#Handle figures
|
||||
if chunk.options[:fig] && length(chunk.figures) > 0
|
||||
if chunk.options[:include]
|
||||
result *= formatfigures(chunk, docformat)
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function format_output(result::AbstractString, docformat)
|
||||
return result
|
||||
end
|
||||
|
||||
function format_output(result::AbstractString, docformat::JMarkdown2HTML)
|
||||
return Markdown.htmlesc(result)
|
||||
end
|
||||
|
||||
function format_output(result::AbstractString, docformat::JMarkdown2tex)
|
||||
# Highligts has some extra escaping defined, eg of $, ", ...
|
||||
result_escaped = sprint( (io, x) -> Highlights.Format.escape(io, MIME("text/latex"), x, charescape=true), result)
|
||||
docformat.formatdict[:keep_unicode] || return uc2tex(result_escaped, true)
|
||||
return result_escaped
|
||||
end
|
||||
|
||||
function format_code(result::AbstractString, docformat)
|
||||
return result
|
||||
end
|
||||
|
||||
function format_code(result::AbstractString, docformat::JMarkdown2tex)
|
||||
highlighted = highlight(MIME("text/latex"), strip(result),
|
||||
Highlights.Lexers.JuliaLexer, docformat.formatdict[:theme])
|
||||
docformat.formatdict[:keep_unicode] || return uc2tex(highlighted)
|
||||
return highlighted
|
||||
#return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
|
||||
end
|
||||
|
||||
#Convert unicode to tex, escape listings if needed
|
||||
function uc2tex(s, escape=false)
|
||||
for key in keys(latex_symbols)
|
||||
if escape
|
||||
s = replace(s, latex_symbols[key] => "(*@\\ensuremath{$(texify(key))}@*)")
|
||||
else
|
||||
s = replace(s, latex_symbols[key] => "\\ensuremath{$(texify(key))}")
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
# Make julia symbols (\bf* etc.) valid latex
|
||||
function texify(s)
|
||||
ts = ""
|
||||
if occursin(r"^\\bf[A-Z]$", s)
|
||||
ts = replace(s, "\\bf" => "\\bm{\\mathrm{") * "}}"
|
||||
elseif startswith(s, "\\bfrak")
|
||||
ts = replace(s, "\\bfrak" => "\\bm{\\mathfrak{") * "}}"
|
||||
elseif startswith(s, "\\bf")
|
||||
ts = replace(s, "\\bf" => "\\bm{\\") * "}"
|
||||
elseif startswith(s, "\\frak")
|
||||
ts = replace(s, "\\frak" => "\\mathfrak{") * "}"
|
||||
else
|
||||
ts = s
|
||||
end
|
||||
return ts
|
||||
end
|
||||
|
||||
function format_code(result::AbstractString, docformat::JMarkdown2HTML)
|
||||
return highlight(MIME("text/html"), strip(result),
|
||||
Highlights.Lexers.JuliaLexer, docformat.formatdict[:theme])
|
||||
end
|
||||
|
||||
function format_code(result::AbstractString, docformat::Pandoc2HTML)
|
||||
return highlight(MIME("text/html"), strip(result),
|
||||
Highlights.Lexers.JuliaLexer, docformat.formatdict[:theme])
|
||||
end
|
||||
|
||||
function format_termchunk(chunk, formatdict, docformat)
|
||||
if chunk.options[:echo] && chunk.options[:results] != "hidden"
|
||||
result = "$(formatdict[:termstart])$(chunk.output)\n" * "$(formatdict[:termend])\n"
|
||||
else
|
||||
result = ""
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function format_termchunk(chunk, formatdict, docformat::JMarkdown2HTML)
|
||||
if chunk.options[:echo] && chunk.options[:results] != "hidden"
|
||||
result = highlight(MIME("text/html"), strip(chunk.output),
|
||||
Highlights.Lexers.JuliaConsoleLexer, docformat.formatdict[:theme])
|
||||
else
|
||||
result = ""
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function format_termchunk(chunk, formatdict, docformat::Pandoc2HTML)
|
||||
if chunk.options[:echo] && chunk.options[:results] != "hidden"
|
||||
result = highlight(MIME("text/html"), strip(chunk.output),
|
||||
Highlights.Lexers.JuliaConsoleLexer, docformat.formatdict[:theme])
|
||||
else
|
||||
result = ""
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function format_termchunk(chunk, formatdict, docformat::JMarkdown2tex)
|
||||
if chunk.options[:echo] && chunk.options[:results] != "hidden"
|
||||
result = highlight(MIME("text/latex"), strip(chunk.output),
|
||||
Highlights.Lexers.JuliaConsoleLexer,
|
||||
docformat.formatdict[:theme])
|
||||
#return "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}\n$result\n\\end{minted}\n"
|
||||
else
|
||||
result = ""
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function indent(text, nindent)
|
||||
return join(map(x->
|
||||
string(repeat(" ", nindent), x), split(text, "\n")), "\n")
|
||||
end
|
||||
|
||||
function wraplines(text, line_width=75)
|
||||
result = AbstractString[]
|
||||
lines = split(text, "\n")
|
||||
for line in lines
|
||||
if length(line) > line_width
|
||||
push!(result, wrapline(line, line_width))
|
||||
else
|
||||
push!(result, line)
|
||||
end
|
||||
end
|
||||
|
||||
return strip(join(result, "\n"))
|
||||
end
|
||||
|
||||
function wrapline(text, line_width=75)
|
||||
result = ""
|
||||
while length(text) > line_width
|
||||
result*= first(text, line_width) * "\n"
|
||||
text = chop(text, head=line_width, tail=0)
|
||||
end
|
||||
result *= text
|
||||
end
|
|
@ -1,482 +0,0 @@
|
|||
using Printf
|
||||
|
||||
struct Tex
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
const tex = Tex("Latex with custom code environments",
|
||||
Dict{Symbol,Any}(:codestart => "\\begin{juliacode}",
|
||||
:codeend => "\\end{juliacode}",
|
||||
:outputstart => "\\begin{juliaout}",
|
||||
:outputend => "\\end{juliaout}",
|
||||
:termstart => "\\begin{juliaterm}",
|
||||
:termend => "\\end{juliaterm}",
|
||||
:fig_ext => ".pdf",
|
||||
:extension =>"tex",
|
||||
:out_width=> "\\linewidth",
|
||||
:fig_env=> "figure",
|
||||
:fig_pos => "htpb",
|
||||
:doctype => "tex",
|
||||
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
|
||||
:keep_unicode => false,
|
||||
))
|
||||
|
||||
const texminted = Tex("Latex using minted for highlighting",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => "\\begin{minted}[mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}",
|
||||
:codeend => "\\end{minted}",
|
||||
:outputstart => "\\begin{minted}[fontsize=\\small, xleftmargin=0.5em, mathescape, frame = leftline]{text}",
|
||||
:outputend => "\\end{minted}",
|
||||
:termstart=> "\\begin{minted}[fontsize=\\footnotesize, xleftmargin=0.5em, mathescape]{jlcon}",
|
||||
:termend => "\\end{minted}",
|
||||
:fig_ext => ".pdf",
|
||||
:extension =>"tex",
|
||||
:out_width => "\\linewidth",
|
||||
:fig_env=> "figure",
|
||||
:fig_pos => "htpb",
|
||||
:doctype => "texminted",
|
||||
:mimetypes => ["application/pdf", "image/png", "text/latex", "text/plain"],
|
||||
:keep_unicode => false,
|
||||
))
|
||||
|
||||
struct Pandoc
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
|
||||
const pandoc = Pandoc("Pandoc markdown",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => "~~~~{.julia}",
|
||||
:codeend=>"~~~~~~~~~~~~~\n\n",
|
||||
:outputstart=>"~~~~",
|
||||
:outputend=>"~~~~\n\n",
|
||||
:fig_ext=>".png",
|
||||
:out_width=>nothing,
|
||||
:extension=>"md",
|
||||
#Prefer png figures for markdown conversion, svg doesn't work with latex
|
||||
:mimetypes => ["image/png", "image/jpg", "image/svg+xml", "text/markdown", "text/plain"],
|
||||
:doctype=>"pandoc"
|
||||
))
|
||||
|
||||
struct Pandoc2HTML
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
const pdoc2html = Pandoc2HTML("Markdown to HTML (requires Pandoc 2)",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => "\n",
|
||||
:codeend=> "\n",
|
||||
:outputstart=> "\n",
|
||||
:outputend=> "\n",
|
||||
:fig_ext=> ".png",
|
||||
:extension=> "md",
|
||||
:mimetypes => ["image/png", "image/svg+xml", "image/jpg",
|
||||
"text/html", "text/markdown", "text/plain"],
|
||||
:doctype=> "pandoc2html"))
|
||||
|
||||
struct GithubMarkdown
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
const github = GithubMarkdown("Github markdown",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => "````julia",
|
||||
:codeend=> "````\n\n",
|
||||
:outputstart=> "````",
|
||||
:outputend=> "````\n\n",
|
||||
:fig_ext=> ".png",
|
||||
:extension=> "md",
|
||||
:mimetypes => ["image/png", "image/svg+xml", "image/jpg", "text/markdown", "text/plain"],
|
||||
:doctype=> "github"
|
||||
))
|
||||
|
||||
"""
|
||||
Formatter for Hugo: https://gohugo.io/
|
||||
|
||||
When `uglyURLs` is `false`, prepend figure path by `..`.
|
||||
"""
|
||||
struct Hugo
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
uglyURLs::Bool
|
||||
end
|
||||
|
||||
const hugo = Hugo("Hugo markdown (using shortcodes)",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => "````julia",
|
||||
:codeend => "````\n\n",
|
||||
:outputstart => "````",
|
||||
:outputend => "````\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "md",
|
||||
:doctype => "hugo"),
|
||||
false)
|
||||
|
||||
#Julia markdown
|
||||
struct JMarkdown2HTML
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
const md2html = JMarkdown2HTML("Julia markdown to html", Dict{Symbol,Any}(
|
||||
:codestart => "\n",
|
||||
:codeend=> "\n",
|
||||
:outputstart=> "<pre class=\"output\">",
|
||||
:outputend=> "</pre>\n",
|
||||
:fig_ext=> ".png",
|
||||
:mimetypes => ["image/png", "image/jpg", "image/svg+xml",
|
||||
"text/html", "text/markdown", "text/plain"],
|
||||
:extension=> "html",
|
||||
:doctype=> "md2html"))
|
||||
|
||||
#Julia markdown
|
||||
struct JMarkdown2tex
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
const md2tex = JMarkdown2tex("Julia markdown to latex", Dict{Symbol,Any}(
|
||||
:codestart => "",
|
||||
:codeend=> "",
|
||||
:outputstart=> "\\begin{lstlisting}",
|
||||
:outputend=> "\\end{lstlisting}\n",
|
||||
:fig_ext=> ".pdf",
|
||||
:extension=> "tex",
|
||||
:out_width => "\\linewidth",
|
||||
:mimetypes => ["application/pdf", "image/png", "image/jpg", "text/latex",
|
||||
"text/markdown", "text/plain"],
|
||||
:doctype=> "md2tex",
|
||||
:keep_unicode=>false))
|
||||
|
||||
|
||||
struct MultiMarkdown
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::JMarkdown2HTML)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
#Set size
|
||||
attribs = ""
|
||||
width == nothing || (attribs = "width=\"$width\"")
|
||||
(attribs != "" && height != nothing ) && (attribs *= ",")
|
||||
height == nothing || (attribs *= " height=\"$height\" ")
|
||||
|
||||
if caption != nothing
|
||||
result *= """<figure>\n"""
|
||||
end
|
||||
|
||||
for fig = fignames
|
||||
|
||||
figstring *= """<img src="$fig" $attribs />\n"""
|
||||
end
|
||||
|
||||
result *= figstring
|
||||
|
||||
if caption != nothing
|
||||
result *= """
|
||||
<figcaption>$caption</figcaption>
|
||||
"""
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= "</figure>\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
const multimarkdown = MultiMarkdown("MultiMarkdown",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => "````julia",
|
||||
:codeend=> "````\n\n",
|
||||
:outputstart=> "````",
|
||||
:outputend=> "````\n\n",
|
||||
:fig_ext=> ".png",
|
||||
:extension=> "md",
|
||||
:doctype=> "github"
|
||||
))
|
||||
|
||||
|
||||
struct Rest
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
const rst = Rest("reStructuredText and Sphinx",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => ".. code-block:: julia\n",
|
||||
:codeend => "\n\n",
|
||||
:outputstart => "::\n",
|
||||
:outputend => "\n\n",
|
||||
:indent=> 4,
|
||||
:fig_ext => ".png",
|
||||
:extension => "rst",
|
||||
:out_width => "15 cm",
|
||||
:doctype => "rst"
|
||||
))
|
||||
|
||||
struct AsciiDoc
|
||||
description::AbstractString
|
||||
formatdict::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
#asciidoc -b html5 -a source-highlighter=pygments ...
|
||||
const adoc = AsciiDoc("AsciiDoc",
|
||||
Dict{Symbol,Any}(
|
||||
:codestart => "[source,julia]\n--------------------------------------",
|
||||
:codeend => "--------------------------------------\n\n",
|
||||
:outputstart => "--------------------------------------",
|
||||
:outputend => "--------------------------------------\n\n",
|
||||
:fig_ext => ".png",
|
||||
:extension => "txt",
|
||||
:out_width => "600",
|
||||
:doctype => "asciidoc"
|
||||
))
|
||||
|
||||
function md_length_to_latex(def,reference)
|
||||
if occursin("%",def)
|
||||
_def = tryparse(Float64,replace(def,"%"=>""))
|
||||
_def == nothing && return def
|
||||
perc = round(_def/100,digits=2)
|
||||
return "$perc$reference"
|
||||
end
|
||||
return def
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::Union{Tex,JMarkdown2tex})
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
if f_env == nothing && caption != nothing
|
||||
f_env = "figure"
|
||||
end
|
||||
|
||||
(f_pos == nothing) && (f_pos = "!h")
|
||||
#Set size
|
||||
attribs = ""
|
||||
width == nothing || (attribs = "width=$(md_length_to_latex(width,"\\linewidth"))")
|
||||
(attribs != "" && height != nothing ) && (attribs *= ",")
|
||||
height == nothing || (attribs *= "height=$(md_length_to_latex(height,"\\paperheight"))")
|
||||
|
||||
if f_env != nothing
|
||||
result *= "\\begin{$f_env}"
|
||||
(f_pos != "") && (result *= "[$f_pos]")
|
||||
result *= "\n"
|
||||
end
|
||||
|
||||
for fig = fignames
|
||||
if splitext(fig)[2] == ".tex" #Tikz figures
|
||||
figstring *= "\\resizebox{$width}{!}{\\input{$fig}}\n"
|
||||
else
|
||||
if isempty(attribs)
|
||||
figstring *= "\\includegraphics{$fig}\n"
|
||||
else
|
||||
figstring *= "\\includegraphics[$attribs]{$fig}\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Figure environment
|
||||
if caption != nothing
|
||||
result *= string("\\center\n",
|
||||
"$figstring",
|
||||
"\\caption{$caption}\n")
|
||||
else
|
||||
result *= figstring
|
||||
end
|
||||
|
||||
if chunk.options[:label] != nothing && f_env !=nothing
|
||||
label = chunk.options[:label]
|
||||
result *= "\\label{fig:$label}\n"
|
||||
end
|
||||
|
||||
|
||||
if f_env != nothing
|
||||
result *= "\\end{$f_env}\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
formatfigures(chunk, docformat::Pandoc2HTML) = formatfigures(chunk, pandoc)
|
||||
|
||||
function formatfigures(chunk, docformat::Pandoc)
|
||||
fignames = chunk.figures
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
caption = chunk.options[:fig_cap]
|
||||
label = get(chunk.options, :label, nothing)
|
||||
result = ""
|
||||
figstring = ""
|
||||
attribs = ""
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
|
||||
#Build figure attibutes
|
||||
attribs = String[]
|
||||
width == nothing || push!(attribs, "width=$width")
|
||||
height == nothing || push!(attribs, "height=$height")
|
||||
label == nothing || push!(attribs, "#fig:$label")
|
||||
attribs = isempty(attribs) ? "" : "{" * join(attribs, " ") * "}"
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption]($(fignames[1]))$attribs\n"
|
||||
for fig = fignames[2:end]
|
||||
result *= "![]($fig)$attribs\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![]($fig)$attribs\\ \n\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::GithubMarkdown)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption]($(fignames[1]))\n"
|
||||
for fig = fignames[2:end]
|
||||
result *= "![]($fig)\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![]($fig)\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::Hugo)
|
||||
relpath = docformat.uglyURLs ? "" : ".."
|
||||
function format_shortcode(index_and_fig)
|
||||
index, fig = index_and_fig
|
||||
if index > 1
|
||||
@warn("Only the first figure gets a caption.")
|
||||
title_spec = ""
|
||||
else
|
||||
caption = chunk.options[:fig_cap]
|
||||
title_spec = caption == nothing ? "" : "title=\"$(caption)\" "
|
||||
end
|
||||
"{{< figure src=\"$(joinpath(relpath, fig))\" $(title_spec) >}}"
|
||||
end
|
||||
mapreduce(format_shortcode, *, enumerate(chunk.figures), init="")
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::MultiMarkdown)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
if chunk.options[:out_width] == nothing
|
||||
width = ""
|
||||
else
|
||||
width = "width=$(chunk.options[:out_width])"
|
||||
end
|
||||
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
if caption != nothing
|
||||
result *= "![$caption][$(fignames[1])]\n\n"
|
||||
result *= "[$(fignames[1])]: $(fignames[1]) $width\n"
|
||||
for fig = fignames[2:end]
|
||||
result *= "![][$fig]\n\n"
|
||||
result *= "[$fig]: $fig $width\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![][$fig]\n\n"
|
||||
result *= "[$fig]: $fig $width\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::Rest)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
for fig=fignames
|
||||
figstring *= @sprintf(".. image:: %s\n :width: %s\n\n", fig, width)
|
||||
end
|
||||
|
||||
if caption != nothing
|
||||
result *= string(".. figure:: $(fignames[1])\n",
|
||||
" :width: $width\n\n",
|
||||
" $caption\n\n")
|
||||
else
|
||||
result *= figstring
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
function formatfigures(chunk, docformat::AsciiDoc)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
|
||||
for fig=fignames
|
||||
figstring *= @sprintf("image::%s[width=%s]\n", fig, width)
|
||||
end
|
||||
|
||||
|
||||
if caption != nothing
|
||||
result *= string("image::$(fignames[1])",
|
||||
"[width=$width,",
|
||||
"title=\"$caption\"]")
|
||||
else
|
||||
result *= figstring
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
#Add new supported formats here
|
||||
const formats = Dict{AbstractString, Any}("tex" => tex,
|
||||
"texminted" => texminted,
|
||||
"pandoc" => pandoc,
|
||||
"pandoc2html" => pdoc2html,
|
||||
"pandoc2pdf" => pandoc,
|
||||
"md2pdf" => md2tex,
|
||||
"github" => github,
|
||||
"hugo" => hugo,
|
||||
"multimarkdown" => multimarkdown,
|
||||
"rst" => rst,
|
||||
"asciidoc" => adoc,
|
||||
"md2html" => md2html,
|
||||
"md2tex" => md2tex
|
||||
)
|
|
@ -1,12 +1,7 @@
|
|||
module GadflyPlots
|
||||
|
||||
import Gadfly
|
||||
import Weave
|
||||
try
|
||||
import Cairo
|
||||
catch
|
||||
@warn("Cairo.jl is required to be installed to generate raster images")
|
||||
end
|
||||
using ..Weave, ..Gadfly
|
||||
|
||||
|
||||
Gadfly.set_default_plot_format(:svg)
|
||||
|
||||
|
@ -21,13 +16,13 @@ function Base.display(report::Weave.Report, m::MIME"image/png", p::Gadfly.Plot)
|
|||
display(report, MIME("image/svg+xml"), p)
|
||||
end
|
||||
|
||||
#Gadfly doesn't call the default display methods, this catches
|
||||
#all Gadfly plots
|
||||
# Gadfly doesn't call the default display methods, this catches
|
||||
# all Gadfly plots
|
||||
function Base.display(report::Weave.Report, m::MIME"image/svg+xml", p::Gadfly.Plot)
|
||||
chunk = report.cur_chunk
|
||||
|
||||
w = chunk.options[:fig_width]Gadfly.inch
|
||||
h = chunk.options[:fig_height]Gadfly.inch
|
||||
w = chunk.options[:fig_width] * Gadfly.inch
|
||||
h = chunk.options[:fig_height] * Gadfly.inch
|
||||
format = chunk.options[:fig_ext]
|
||||
dpi = chunk.options[:dpi]
|
||||
|
||||
|
@ -41,15 +36,16 @@ function Base.display(report::Weave.Report, m::MIME"image/svg+xml", p::Gadfly.Pl
|
|||
elseif format == ".js.svg"
|
||||
Gadfly.draw(Gadfly.SVGJS(full_name, w, h), p)
|
||||
elseif format == ".png"
|
||||
Gadfly.draw(Gadfly.PNG(full_name, w, h, dpi=dpi), p)
|
||||
Gadfly.draw(Gadfly.PNG(full_name, w, h, dpi = dpi), p)
|
||||
elseif format == ".pdf"
|
||||
Gadfly.draw(Gadfly.PDF(full_name, w, h), p)
|
||||
elseif format == ".ps"
|
||||
Gadfly.draw(Gadfly.PS(full_name, w, h), p)
|
||||
elseif format == ".tex"
|
||||
Gadfly.draw(Gadfly.PGF(full_name, w, h, true ), p)
|
||||
Gadfly.draw(Gadfly.PGF(full_name, w, h, true), p)
|
||||
else
|
||||
@warn("Can't save figure. Unsupported format, $format")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
126
src/pandoc.jl
126
src/pandoc.jl
|
@ -1,126 +0,0 @@
|
|||
|
||||
|
||||
"""
|
||||
`pandoc2html(formatted::AbstractString, doc::WeaveDoc)`
|
||||
|
||||
Convert output from pandoc markdown to html using Weave.jl template
|
||||
"""
|
||||
function pandoc2html(formatted::AbstractString, doc::WeaveDoc, outname::AbstractString, pandoc_options)
|
||||
weavedir = dirname(@__FILE__)
|
||||
html_template = joinpath(weavedir, "../templates/pandoc_skeleton.html")
|
||||
css_template = joinpath(weavedir, "../templates/pandoc_skeleton.css")
|
||||
css = stylesheet(MIME("text/html"), doc.highlight_theme)
|
||||
|
||||
path, wsource = splitdir(abspath(doc.source))
|
||||
#wversion = string(Pkg.installed("Weave"))
|
||||
wversion = ""
|
||||
wtime = string(Date(now()))
|
||||
|
||||
#Header is inserted from displayed plots
|
||||
header_script = doc.header_script
|
||||
self_contained = (header_script ≠ "") ? [] : "--self-contained"
|
||||
|
||||
if haskey(doc.header, "bibliography")
|
||||
filt = "--filter"
|
||||
citeproc = "pandoc-citeproc"
|
||||
else
|
||||
filt = []
|
||||
citeproc = []
|
||||
end
|
||||
|
||||
#Change path for pandoc
|
||||
old_wd = pwd()
|
||||
cd(doc.cwd)
|
||||
html =""
|
||||
outname = basename(outname)
|
||||
|
||||
open("temp.md", "w") do io
|
||||
println(io, formatted)
|
||||
end
|
||||
|
||||
try
|
||||
cmd = `pandoc -f markdown+raw_html -s --mathjax=""
|
||||
$filt $citeproc $pandoc_options
|
||||
--template $html_template -H $css_template $self_contained
|
||||
-V wversion=$wversion -V wtime=$wtime -V wsource=$wsource
|
||||
-V highlightcss=$css
|
||||
-V headerscript=$header_script
|
||||
-o $outname`
|
||||
proc = open(cmd, "r+")
|
||||
println(proc.in, formatted)
|
||||
close(proc.in)
|
||||
proc_output = read(proc.out, String)
|
||||
cd(old_wd)
|
||||
catch e
|
||||
cd(old_wd)
|
||||
@warn("Error converting document to HTML")
|
||||
throw(e)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
`pandoc2pdf(formatted::AbstractString, doc::WeaveDoc)`
|
||||
|
||||
Convert output from pandoc markdown to pdf using Weave.jl template
|
||||
"""
|
||||
function pandoc2pdf(formatted::AbstractString, doc::WeaveDoc, outname::AbstractString, pandoc_options)
|
||||
weavedir = dirname(@__FILE__)
|
||||
header_template = joinpath(weavedir, "../templates/pandoc_header.txt")
|
||||
|
||||
path, wsource = splitdir(abspath(doc.source))
|
||||
#wversion = string(Pkg.installed("Weave"))
|
||||
wversion = ""
|
||||
wtime = Date(now())
|
||||
outname = basename(outname)
|
||||
|
||||
#Change path for pandoc
|
||||
old_wd = pwd()
|
||||
cd(doc.cwd)
|
||||
html =""
|
||||
|
||||
if haskey(doc.header, "bibliography")
|
||||
filt = "--filter"
|
||||
citeproc = "pandoc-citeproc"
|
||||
else
|
||||
filt = []
|
||||
citeproc = []
|
||||
end
|
||||
|
||||
@info("Done executing code. Running xelatex")
|
||||
try
|
||||
cmd = `pandoc -f markdown+raw_tex -s --pdf-engine=xelatex --highlight-style=tango
|
||||
$filt $citeproc $pandoc_options
|
||||
--include-in-header=$header_template
|
||||
-V fontsize=12pt -o $outname`
|
||||
proc = open(cmd, "r+")
|
||||
println(proc.in, formatted)
|
||||
close(proc.in)
|
||||
proc_output = read(proc.out, String)
|
||||
cd(old_wd)
|
||||
catch e
|
||||
cd(old_wd)
|
||||
@warn("Error converting document to pdf")
|
||||
throw(e)
|
||||
end
|
||||
end
|
||||
|
||||
function run_latex(doc::WeaveDoc, outname, latex_cmd = "xelatex")
|
||||
old_wd = pwd()
|
||||
cd(doc.cwd)
|
||||
xname = basename(outname)
|
||||
@info("Weaved code to $outname. Running $latex_cmd")
|
||||
textmp = mktempdir(".")
|
||||
try
|
||||
out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String)
|
||||
out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String)
|
||||
rm(xname)
|
||||
rm(textmp, recursive=true)
|
||||
cd(old_wd)
|
||||
return true
|
||||
catch e
|
||||
@warn("Error converting document to pdf. Try running latex manually")
|
||||
cd(old_wd)
|
||||
rm(textmp)
|
||||
return false
|
||||
end
|
||||
end
|
126
src/plots.jl
126
src/plots.jl
|
@ -1,69 +1,81 @@
|
|||
module WeavePlots
|
||||
|
||||
using Base64
|
||||
import Plots
|
||||
import Weave
|
||||
using Base64, ..Plots, ..Weave
|
||||
|
||||
"""Pre-execute hooks to set the plot size for the chunk """
|
||||
function plots_set_size(chunk)
|
||||
w = chunk.options[:fig_width] * chunk.options[:dpi]
|
||||
h = chunk.options[:fig_height] * chunk.options[:dpi]
|
||||
Plots.default(size = (w,h))
|
||||
return chunk
|
||||
|
||||
# Pre-execute hooks to set the plot size for the chunk
|
||||
function plots_set_size!(chunk)
|
||||
w = chunk.options[:fig_width] * chunk.options[:dpi]
|
||||
h = chunk.options[:fig_height] * chunk.options[:dpi]
|
||||
Plots.default(size = (w, h))
|
||||
end
|
||||
|
||||
Weave.push_preexecute_hook(plots_set_size)
|
||||
Weave.push_preexecution_hook!(plots_set_size!)
|
||||
|
||||
#PNG or SVG is not working, output html
|
||||
function Base.display(report::Weave.Report, m::MIME"image/svg+xml", data::Plots.Plot{Plots.PlotlyBackend})#
|
||||
#Remove extra spaces from start of line for pandoc
|
||||
s = repr(MIME("text/html"), data)
|
||||
splitted = split(s, "\n")
|
||||
start = split(splitted[1], r"(?=<div)")
|
||||
#script = lstrip(start[1]) #local
|
||||
# PNG or SVG is not working, output html
|
||||
function Base.display(
|
||||
report::Weave.Report,
|
||||
m::MIME"image/svg+xml",
|
||||
data::Plots.Plot{Plots.PlotlyBackend},
|
||||
)
|
||||
# Remove extra spaces from start of line for pandoc
|
||||
s = repr(MIME("text/html"), data)
|
||||
splitted = split(s, "\n")
|
||||
start = split(splitted[1], r"(?=<div)")
|
||||
# script = lstrip(start[1]) # local
|
||||
|
||||
div = lstrip(start[2])
|
||||
plot = join(map(lstrip, splitted[2:end]), "\n")
|
||||
div = lstrip(start[2])
|
||||
plot = join(map(lstrip, splitted[2:end]), "\n")
|
||||
|
||||
if report.first_plot
|
||||
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
|
||||
report.first_plot = false
|
||||
end
|
||||
if report.first_plot
|
||||
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
|
||||
report.first_plot = false
|
||||
end
|
||||
|
||||
report.rich_output *= "\n" * div * "\n" * plot
|
||||
end
|
||||
|
||||
function Base.display(report::Weave.Report, m::MIME"image/png", data::Plots.Plot{Plots.PlotlyBackend})#
|
||||
display(report, MIME("image/svg+xml"), data)
|
||||
function Base.display(
|
||||
report::Weave.Report,
|
||||
m::MIME"image/png",
|
||||
data::Plots.Plot{Plots.PlotlyBackend},
|
||||
)
|
||||
display(report, MIME("image/svg+xml"), data)
|
||||
end
|
||||
|
||||
# PNG or SVG is not working, output html
|
||||
function Base.display(
|
||||
report::Weave.Report,
|
||||
m::MIME"image/svg+xml",
|
||||
plot::Plots.Plot{Plots.PlotlyJSBackend},
|
||||
)
|
||||
body = Plots.PlotlyJS.html_body(plot.o.plot)
|
||||
|
||||
#PNG or SVG is not working, output html
|
||||
function Base.display(report::Weave.Report, m::MIME"image/svg+xml", plot::Plots.Plot{Plots.PlotlyJSBackend})
|
||||
body = Plots.PlotlyJS.html_body(plot.o.plot)
|
||||
if report.first_plot
|
||||
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
|
||||
report.first_plot = false
|
||||
end
|
||||
|
||||
if report.first_plot
|
||||
report.header_script *= "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>"
|
||||
report.first_plot = false
|
||||
end
|
||||
|
||||
report.rich_output *= "\n" * body
|
||||
report.rich_output *= "\n" * body
|
||||
end
|
||||
|
||||
function Base.display(report::Weave.Report, m::MIME"image/png", plot::Plots.Plot{Plots.PlotlyJSBackend})
|
||||
display(report, MIME("image/svg+xml"), data)
|
||||
function Base.display(
|
||||
report::Weave.Report,
|
||||
m::MIME"image/png",
|
||||
plot::Plots.Plot{Plots.PlotlyJSBackend},
|
||||
)
|
||||
display(report, MIME("image/svg+xml"), data)
|
||||
end
|
||||
|
||||
|
||||
"""Add saved figure name to results and return the name"""
|
||||
function add_plots_figure(report::Weave.Report, plot::Plots.Plot, ext)
|
||||
chunk = report.cur_chunk
|
||||
full_name, rel_name = Weave.get_figname(report, chunk, ext = ext)
|
||||
chunk = report.cur_chunk
|
||||
full_name, rel_name = Weave.get_figname(report, chunk, ext = ext)
|
||||
|
||||
Plots.savefig(plot, full_name)
|
||||
push!(report.figures, rel_name)
|
||||
report.fignum += 1
|
||||
return full_name
|
||||
Plots.savefig(plot, full_name)
|
||||
push!(report.figures, rel_name)
|
||||
report.fignum += 1
|
||||
return full_name
|
||||
end
|
||||
|
||||
function Base.display(report::Weave.Report, m::MIME"application/pdf", plot::Plots.Plot)
|
||||
|
@ -80,21 +92,21 @@ end
|
|||
|
||||
# write out html to view Animated gif
|
||||
function Base.display(report::Weave.Report, ::MIME"text/html", agif::Plots.AnimatedGif)
|
||||
ext = agif.filename[end-2:end]
|
||||
res = ""
|
||||
if ext == "gif"
|
||||
img = stringmime(MIME("image/gif"), read(agif.filename))
|
||||
res = "<img src=\"data:image/gif;base64,$img\" />"
|
||||
elseif ext in ("mov", "mp4")
|
||||
#Uncomment to embed mp4, make global or chunk option?
|
||||
#img = stringmime(MIME("video/$ext"), read(agif.filename))
|
||||
#res = "<video controls><source src=\"data:video/$(ext);base64,$img\" type=\"video/$ext\"></video>"
|
||||
res = "<video controls><source src=\"$(relpath(agif.filename))\" type=\"video/$ext\"></video>"
|
||||
else
|
||||
error("Cannot show animation with extension $ext: $agif")
|
||||
end
|
||||
ext = agif.filename[end-2:end]
|
||||
res = ""
|
||||
if ext == "gif"
|
||||
img = stringmime(MIME("image/gif"), read(agif.filename))
|
||||
res = "<img src=\"data:image/gif;base64,$img\" />"
|
||||
elseif ext in ("mov", "mp4")
|
||||
# Uncomment to embed mp4, make global or chunk option?
|
||||
# img = stringmime(MIME("video/$ext"), read(agif.filename))
|
||||
# res = "<video controls><source src=\"data:video/$(ext);base64,$img\" type=\"video/$ext\"></video>"
|
||||
res = "<video controls><source src=\"$(relpath(agif.filename))\" type=\"video/$ext\"></video>"
|
||||
else
|
||||
error("Cannot show animation with extension $ext: $agif")
|
||||
end
|
||||
|
||||
report.rich_output *= "\n" * res * "\n"
|
||||
report.rich_output *= "\n" * res * "\n"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
function parse_markdown(document_body; is_pandoc = false)
|
||||
header_text, document_body, offset = separate_header_text(document_body)
|
||||
header = parse_header(header_text)
|
||||
code_start, code_end = if is_pandoc
|
||||
r"^<<(?<options>.*?)>>=\s*$",
|
||||
r"^@\s*$"
|
||||
else
|
||||
r"^[`~]{3}(\{?)julia\s*([;,]?)\s*(?<options>.*?)(\}|\s*)$",
|
||||
r"^[`~]{3}\s*$"
|
||||
end
|
||||
return header, parse_markdown_body(document_body, code_start, code_end, offset)
|
||||
end
|
||||
|
||||
# headers
|
||||
# -------
|
||||
|
||||
const HEADER_REGEX = r"^---$(?<header>((?!---).)+)^---$"ms
|
||||
|
||||
# TODO: non-Weave headers should keep live in a doc
|
||||
# separates header section from `text`
|
||||
function separate_header_text(text)
|
||||
m = match(HEADER_REGEX, text)
|
||||
isnothing(m) && return "", text, 0
|
||||
header_text = m[:header]
|
||||
offset = @static if VERSION ≥ v"1.4"
|
||||
count("\n", header_text)
|
||||
else
|
||||
count(c->c==='\n', header_text)
|
||||
end
|
||||
return header_text, replace(text, HEADER_REGEX => ""; count = 1), offset
|
||||
end
|
||||
|
||||
# HACK:
|
||||
# YAML.jl can't parse text including ``` characters, so first replace all the inline code
|
||||
# with these temporary code start/end string
|
||||
const HEADER_INLINE_START = "<weave_header_inline_start>"
|
||||
const HEADER_INLINE_END = "<weave_header_inline_end>"
|
||||
|
||||
function parse_header(header_text)
|
||||
isempty(header_text) && return Dict()
|
||||
pat = INLINE_REGEX => SubstitutionString("$(HEADER_INLINE_START)\\1$(HEADER_INLINE_END)")
|
||||
header_text = replace(header_text, pat)
|
||||
return YAML.load(header_text)
|
||||
end
|
||||
|
||||
# body
|
||||
# ----
|
||||
|
||||
function parse_markdown_body(document_body, code_start, code_end, offset)
|
||||
lines = split(document_body, '\n')
|
||||
|
||||
state = :doc
|
||||
doc_no = 0
|
||||
code_no = 0
|
||||
content = ""
|
||||
start_line = offset
|
||||
|
||||
options = OptionDict()
|
||||
option_string = ""
|
||||
|
||||
chunks = WeaveChunk[]
|
||||
for (line_no, line) in enumerate(lines)
|
||||
m = match(code_start, line)
|
||||
if !isnothing(m) && state === :doc
|
||||
state = :code
|
||||
|
||||
option_string = isnothing(m[:options]) ? "" : strip(m[:options])
|
||||
options = parse_options(option_string)
|
||||
haskey(options, :label) && (options[:name] = options[:label])
|
||||
haskey(options, :name) || (options[:name] = nothing)
|
||||
|
||||
isempty(strip(content)) || push!(chunks, DocChunk(content, doc_no += 1, start_line))
|
||||
|
||||
start_line = line_no + offset
|
||||
content = ""
|
||||
continue
|
||||
end
|
||||
|
||||
if occursin(code_end, line) && state === :code
|
||||
push!(chunks, CodeChunk(content, code_no += 1, start_line, option_string, options))
|
||||
|
||||
start_line = line_no + offset
|
||||
content = ""
|
||||
state = :doc
|
||||
continue
|
||||
end
|
||||
|
||||
content *= isone(line_no) ? line : string('\n', line)
|
||||
end
|
||||
|
||||
# Remember the last chunk
|
||||
isempty(strip(content)) || push!(chunks, DocChunk(content, doc_no += 1, start_line))
|
||||
|
||||
return chunks
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
using JSON
|
||||
|
||||
|
||||
function parse_notebook(document_body)
|
||||
nb = JSON.parse(document_body)
|
||||
code_no = 0
|
||||
doc_no = 0
|
||||
|
||||
# TODO: handle some of options ?
|
||||
options = Dict{Symbol,Any}()
|
||||
opt_string = ""
|
||||
|
||||
chunks = map(nb["cells"]) do cell
|
||||
text = string('\n', join(cell["source"]), '\n')
|
||||
return if cell["cell_type"] == "code"
|
||||
CodeChunk(text, code_no += 1, 0, opt_string, options)
|
||||
else
|
||||
DocChunk(text, doc_no += 1, 0; notebook = true)
|
||||
end
|
||||
end
|
||||
|
||||
return Dict(), chunks
|
||||
end
|
|
@ -0,0 +1,128 @@
|
|||
using YAML
|
||||
|
||||
|
||||
function WeaveDoc(source, informat = nothing)
|
||||
path = abspath(source)
|
||||
_, fname = splitdir(path)
|
||||
basename = splitext(fname)[1]
|
||||
|
||||
isnothing(informat) && (informat = detect_informat(source))
|
||||
header, chunks = parse_doc(read(source, String), informat)
|
||||
|
||||
# update default chunk options from header
|
||||
chunk_defaults = deepcopy(get_chunk_defaults())
|
||||
if (weave_options = get(header, WEAVE_OPTION_NAME, nothing)) !== nothing
|
||||
for key in keys(chunk_defaults)
|
||||
if (val = get(weave_options, string(key), nothing)) !== nothing
|
||||
chunk_defaults[key] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
if haskey(header, WEAVE_OPTION_NAME_DEPRECATED)
|
||||
@warn "Weave: `options` key is deprecated. Use `weave_options` key instead." _id = WEAVE_OPTION_DEPRECATE_ID maxlog = 1
|
||||
for key in keys(chunk_defaults)
|
||||
if (val = get(header[WEAVE_OPTION_NAME_DEPRECATED], string(key), nothing)) !== nothing
|
||||
chunk_defaults[key] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return WeaveDoc(
|
||||
source,
|
||||
basename,
|
||||
path,
|
||||
chunks,
|
||||
"",
|
||||
nothing,
|
||||
"",
|
||||
"",
|
||||
header,
|
||||
chunk_defaults,
|
||||
)
|
||||
end
|
||||
|
||||
"""
|
||||
detect_informat(path)
|
||||
|
||||
Detect Weave input format based on file extension of `path`.
|
||||
"""
|
||||
function detect_informat(path)
|
||||
ext = lowercase(last(splitext(path)))
|
||||
|
||||
ext == ".jl" && return "script"
|
||||
ext == ".jmd" && return "markdown"
|
||||
ext == ".ipynb" && return "notebook"
|
||||
return "noweb"
|
||||
end
|
||||
|
||||
function parse_doc(document, informat)
|
||||
document = replace(document, "\r\n" => "\n") # normalize line ending
|
||||
|
||||
return informat == "markdown" ? parse_markdown(document) :
|
||||
informat == "noweb" ? parse_markdown(document; is_pandoc = true) :
|
||||
informat == "script" ? parse_script(document) :
|
||||
informat == "notebook" ? parse_notebook(document) :
|
||||
error("unsupported input format given: $informat")
|
||||
end
|
||||
|
||||
# inline
|
||||
# ------
|
||||
|
||||
function DocChunk(text::AbstractString, number, start_line; notebook = false)
|
||||
# don't parse inline code in notebook
|
||||
content = notebook ? parse_inline(text) : parse_inlines(text)
|
||||
return DocChunk(content, number, start_line)
|
||||
end
|
||||
|
||||
const INLINE_REGEX = r"`j\s+(.*?)`"
|
||||
const INLINE_REGEXES = r"`j\s+(.*?)`|^!\s(.*)$"m
|
||||
|
||||
# handle code units correctly !
|
||||
function parse_inlines(str)
|
||||
ret = Inline[]
|
||||
s = 1
|
||||
code_no = text_no = 0
|
||||
for m in eachmatch(INLINE_REGEXES, str)
|
||||
e = m.offset
|
||||
push!(ret, InlineText((str[s:prevind(str,e)]), text_no += 1))
|
||||
i = findfirst(!isnothing, m.captures)
|
||||
push!(ret, InlineCode(m.captures[i], code_no += 1, isone(i) ? :inline : :line))
|
||||
s = e + ncodeunits(m.match)
|
||||
end
|
||||
push!(ret, InlineText(str[s:end], text_no += 1))
|
||||
return ret
|
||||
end
|
||||
|
||||
parse_inline(str) = Inline[InlineText(str, 1)]
|
||||
|
||||
# options
|
||||
# -------
|
||||
|
||||
const OptionDict = Dict{Symbol,Any}
|
||||
|
||||
function parse_options(str)::OptionDict
|
||||
str = string('(', str, ')')
|
||||
ex = Meta.parse(str)
|
||||
nt = if Meta.isexpr(ex, (
|
||||
:block, # "(k1 = v1; k2 = v2, ...)"
|
||||
:tuple, # "(k1 = v1, k2 = v2, ...)"
|
||||
))
|
||||
eval(Expr(:tuple, filter(is_valid_kv, ex.args)...))
|
||||
elseif is_valid_kv(ex) # "(k = v)"
|
||||
eval(Expr(:tuple, ex))
|
||||
else
|
||||
NamedTuple{}()
|
||||
end
|
||||
return dict(nt)
|
||||
end
|
||||
|
||||
is_valid_kv(x) = Meta.isexpr(x, :(=))
|
||||
dict(nt) = Dict((k => v for (k,v) in zip(keys(nt), values(nt)))...)
|
||||
nt(dict) = NamedTuple{(Symbol.(keys(dict))...,)}((collect(values(dict))...,))
|
||||
|
||||
# each input format
|
||||
# -----------------
|
||||
|
||||
include("markdown.jl")
|
||||
include("script.jl")
|
||||
include("notebook.jl")
|
|
@ -0,0 +1,67 @@
|
|||
function parse_script(document_body)
|
||||
lines = split(document_body, '\n')
|
||||
|
||||
doc_line = r"(^#'.*)|(^#%%.*)|(^# %%.*)"
|
||||
doc_start = r"(^#')|(^#%%)|(^# %%)"
|
||||
opt_line = r"(^#\+.*$)|(^#%%\+.*$)|(^# %%\+.*$)"
|
||||
opt_start = r"(^#\+)|(^#%%\+)|(^# %%\+)"
|
||||
|
||||
content = ""
|
||||
state = :code
|
||||
doc_no = 0
|
||||
code_no = 0
|
||||
start_line = 1
|
||||
|
||||
options = OptionDict()
|
||||
option_string = ""
|
||||
|
||||
chunks = WeaveChunk[]
|
||||
for (line_no, line) in enumerate(lines)
|
||||
if (m = match(doc_line, line)) !== nothing && (m = match(opt_line, line)) === nothing
|
||||
line = replace(line, doc_start => "", count = 1)
|
||||
startswith(line, ' ') && (line = replace(line, ' ' => "", count = 1))
|
||||
if state === :code && !isempty(strip(content))
|
||||
push!(chunks, CodeChunk(string('\n', strip(content)), code_no += 1, start_line, option_string, options))
|
||||
content = ""
|
||||
start_line = line_no
|
||||
end
|
||||
state = :doc
|
||||
elseif (m = match(opt_line, line)) !== nothing
|
||||
start_line = line_no
|
||||
if state === :code && !isempty(strip(content))
|
||||
push!(chunks, CodeChunk(string('\n', strip(content)), code_no += 1, start_line, option_string, options))
|
||||
content = ""
|
||||
end
|
||||
if state === :doc && !isempty(strip(content))
|
||||
iszero(doc_no) || (content = string('\n', content)) # Add whitespace to doc chunk. Needed for markdown output
|
||||
push!(chunks, DocChunk(content, doc_no += 1, start_line))
|
||||
content = ""
|
||||
end
|
||||
|
||||
option_string = replace(line, opt_start => "", count = 1)
|
||||
options = parse_options(option_string)
|
||||
haskey(options, :label) && (options[:name] = options[:label])
|
||||
haskey(options, :name) || (options[:name] = nothing)
|
||||
|
||||
state = :code
|
||||
continue
|
||||
elseif state === :doc # && strip(line) != "" && strip(content) != ""
|
||||
state = :code
|
||||
iszero(doc_no) || (content = string('\n', content)) # Add whitespace to doc chunk. Needed for markdown output
|
||||
push!(chunks, DocChunk(content, doc_no += 1, start_line))
|
||||
content = ""
|
||||
|
||||
options = Dict{Symbol,Any}()
|
||||
start_line = line_no
|
||||
end
|
||||
content *= string(line, '\n')
|
||||
end
|
||||
|
||||
# Handle the last chunk
|
||||
chunk = state === :code ?
|
||||
CodeChunk(string('\n', strip(content)), code_no, start_line, option_string, options) :
|
||||
DocChunk(content, doc_no, start_line)
|
||||
push!(chunks, chunk)
|
||||
|
||||
return Dict(), chunks
|
||||
end
|
315
src/readers.jl
315
src/readers.jl
|
@ -1,315 +0,0 @@
|
|||
import JSON, YAML
|
||||
|
||||
pushopt(options::Dict,expr::Expr) = Base.Meta.isexpr(expr,:(=)) && (options[expr.args[1]] = expr.args[2])
|
||||
|
||||
mutable struct MarkupInput
|
||||
codestart::Regex
|
||||
codeend::Regex
|
||||
inline::Regex
|
||||
end
|
||||
|
||||
mutable struct ScriptInput
|
||||
doc_line::Regex
|
||||
doc_start::Regex
|
||||
opt_line::Regex
|
||||
opt_start::Regex
|
||||
inline::Regex
|
||||
end
|
||||
|
||||
mutable struct NotebookInput
|
||||
inline
|
||||
end
|
||||
|
||||
const input_formats = Dict{AbstractString, Any}(
|
||||
"noweb" => MarkupInput(r"^<<(.*?)>>=\s*$",
|
||||
r"^@\s*$",
|
||||
r"`j\s+(.*?)`|^!\s(.*)$"m
|
||||
),
|
||||
"markdown" => MarkupInput(
|
||||
r"^[`~]{3,}(?:\{|\{\.|)julia(?:;|)\s*(.*?)(\}|\s*)$",
|
||||
r"^[`~]{3,}\s*$",
|
||||
r"`j\s+(.*?)`|^!\s(.*)$"m),
|
||||
"script" => ScriptInput(
|
||||
r"(^#'.*)|(^#%%.*)|(^# %%.*)",
|
||||
r"(^#')|(^#%%)|(^# %%)",
|
||||
r"(^#\+.*$)|(^#%%\+.*$)|(^# %%\+.*$)",
|
||||
r"(^#\+)|(^#%%\+)|(^# %%\+)",
|
||||
r"`j\s+(.*?)`|^!\s(.*)$"m),
|
||||
"notebook" => NotebookInput(nothing) #Don't parse inline code from notebooks
|
||||
)
|
||||
|
||||
"""Detect the input format based on file extension"""
|
||||
function detect_informat(source::AbstractString)
|
||||
ext = lowercase(splitext(source)[2])
|
||||
|
||||
ext == ".jl" && return "script"
|
||||
ext == ".jmd" && return "markdown"
|
||||
ext == ".ipynb" && return "notebook"
|
||||
return "noweb"
|
||||
end
|
||||
|
||||
"""Read and parse input document"""
|
||||
function read_doc(source::AbstractString, format=:auto)
|
||||
format == :auto && (format = detect_informat(source))
|
||||
document = read(source, String)
|
||||
document = replace(document, "\r\n" => "\n")
|
||||
parsed = parse_doc(document, format)
|
||||
header = parse_header(parsed[1])
|
||||
doc = WeaveDoc(source, parsed, header)
|
||||
haskey(header, "options") && header_chunk_defaults!(doc)
|
||||
return doc
|
||||
end
|
||||
|
||||
function parse_header(chunk::CodeChunk)
|
||||
return Dict()
|
||||
end
|
||||
|
||||
function parse_header(chunk::DocChunk)
|
||||
m = match(r"^---$(?<header>.+)^---$"ms, chunk.content[1].content)
|
||||
if m !== nothing
|
||||
header = YAML.load(string(m[:header]))
|
||||
else
|
||||
header = Dict()
|
||||
end
|
||||
return header
|
||||
end
|
||||
|
||||
function parse_doc(document::AbstractString, format="noweb"::AbstractString)
|
||||
return parse_doc(document, input_formats[format])
|
||||
end
|
||||
|
||||
"""Parse documents with Weave.jl markup"""
|
||||
function parse_doc(document::AbstractString, format::MarkupInput)
|
||||
document = replace(document, "\r\n" => "\n")
|
||||
lines = split(document, "\n")
|
||||
|
||||
codestart = format.codestart
|
||||
codeend = format.codeend
|
||||
state = "doc"
|
||||
|
||||
docno = 1
|
||||
codeno = 1
|
||||
content = ""
|
||||
start_line = 0
|
||||
|
||||
options = Dict()
|
||||
optionString = ""
|
||||
parsed = Any[]
|
||||
for lineno in 1:length(lines)
|
||||
line = lines[lineno]
|
||||
if (m = match(codestart, line)) != nothing && state=="doc"
|
||||
state = "code"
|
||||
if m.captures[1] == nothing
|
||||
optionString = ""
|
||||
else
|
||||
optionString=strip(m.captures[1])
|
||||
end
|
||||
|
||||
options = Dict{Symbol,Any}()
|
||||
if length(optionString) > 0
|
||||
expr = Meta.parse(optionString)
|
||||
Base.Meta.isexpr(expr,:(=)) && (options[expr.args[1]] = expr.args[2])
|
||||
Base.Meta.isexpr(expr,:toplevel) && map(pushopt,fill(options,length(expr.args)),expr.args)
|
||||
end
|
||||
haskey(options, :label) && (options[:name] = options[:label])
|
||||
haskey(options, :name) || (options[:name] = nothing)
|
||||
|
||||
if !isempty(strip(content))
|
||||
chunk = DocChunk(content, docno, start_line, format.inline)
|
||||
docno += 1
|
||||
push!(parsed, chunk)
|
||||
end
|
||||
|
||||
content = ""
|
||||
start_line = lineno
|
||||
|
||||
continue
|
||||
|
||||
end
|
||||
if occursin(codeend, line) && state=="code"
|
||||
|
||||
chunk = CodeChunk(content, codeno, start_line, optionString, options)
|
||||
|
||||
codeno+=1
|
||||
start_line = lineno
|
||||
content = ""
|
||||
state = "doc"
|
||||
push!(parsed, chunk)
|
||||
continue
|
||||
end
|
||||
|
||||
if lineno == 1
|
||||
content *= line
|
||||
else
|
||||
content *= "\n" * line
|
||||
end
|
||||
end
|
||||
|
||||
#Remember the last chunk
|
||||
if strip(content) != ""
|
||||
chunk = DocChunk(content, docno, start_line, format.inline)
|
||||
#chunk = Dict{Symbol,Any}(:type => "doc", :content => content,
|
||||
# :number => docno, :start_line => start_line)
|
||||
push!(parsed, chunk)
|
||||
end
|
||||
return parsed
|
||||
end
|
||||
|
||||
"""Parse .jl scripts with Weave.jl markup"""
|
||||
function parse_doc(document::AbstractString, format::ScriptInput)
|
||||
document = replace(document, "\r\n" => "\n")
|
||||
lines = split(document, "\n")
|
||||
|
||||
doc_line = format.doc_line
|
||||
doc_start = format.doc_start
|
||||
opt_line = format.opt_line
|
||||
opt_start = format.opt_start
|
||||
|
||||
read = ""
|
||||
chunks = []
|
||||
docno = 1
|
||||
codeno = 1
|
||||
content = ""
|
||||
start_line = 1
|
||||
options = Dict{Symbol,Any}()
|
||||
optionString = ""
|
||||
parsed = Any[]
|
||||
state = "code"
|
||||
lineno = 1
|
||||
n_emptylines = 0
|
||||
|
||||
|
||||
|
||||
for lineno in 1:length(lines)
|
||||
line = lines[lineno]
|
||||
if (m = match(doc_line, line)) != nothing && (m = match(opt_line, line)) == nothing
|
||||
line = replace(line, doc_start => "", count=1)
|
||||
if startswith(line, " ")
|
||||
line = replace(line, " " => "", count=1)
|
||||
end
|
||||
if state == "code" && strip(read) != ""
|
||||
chunk = CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
|
||||
push!(parsed, chunk)
|
||||
codeno +=1
|
||||
read = ""
|
||||
start_line = lineno
|
||||
end
|
||||
state = "doc"
|
||||
elseif (m = match(opt_line, line)) != nothing
|
||||
start_line = lineno
|
||||
if state == "code" && strip(read) !=""
|
||||
chunk = CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
|
||||
push!(parsed, chunk)
|
||||
read = ""
|
||||
codeno +=1
|
||||
end
|
||||
if state == "doc" && strip(read) != ""
|
||||
(docno > 1) && (read = "\n" * read) # Add whitespace to doc chunk. Needed for markdown output
|
||||
chunk = DocChunk(read, docno, start_line)
|
||||
push!(parsed, chunk)
|
||||
read = ""
|
||||
docno += 1
|
||||
end
|
||||
|
||||
optionString = replace(line, opt_start => "", count=1)
|
||||
#Get options
|
||||
options = Dict{Symbol,Any}()
|
||||
if length(optionString) > 0
|
||||
expr = Meta.parse(optionString)
|
||||
Base.Meta.isexpr(expr,:(=)) && (options[expr.args[1]] = expr.args[2])
|
||||
Base.Meta.isexpr(expr,:toplevel) && map(pushopt,fill(options,length(expr.args)),expr.args)
|
||||
end
|
||||
haskey(options, :label) && (options[:name] = options[:label])
|
||||
haskey(options, :name) || (options[:name] = nothing)
|
||||
|
||||
state = "code"
|
||||
continue
|
||||
elseif state == "doc" #&& strip(line) != "" && strip(read) != ""
|
||||
state = "code"
|
||||
(docno > 1) && (read = "\n" * read) # Add whitespace to doc chunk. Needed for markdown output
|
||||
chunk = DocChunk(read, docno, start_line, format.inline)
|
||||
push!(parsed, chunk)
|
||||
options = Dict{Symbol,Any}()
|
||||
start_line = lineno
|
||||
read = ""
|
||||
docno += 1
|
||||
end
|
||||
read *= line * "\n"
|
||||
|
||||
if strip(line) == ""
|
||||
n_emptylines += 1
|
||||
else
|
||||
n_emptylines = 0
|
||||
end
|
||||
end
|
||||
|
||||
# Handle the last chunk
|
||||
if state == "code"
|
||||
chunk = CodeChunk("\n" * strip(read), codeno, start_line, optionString, options)
|
||||
push!(parsed, chunk)
|
||||
else
|
||||
chunk = DocChunk(read, docno, start_line, format.inline)
|
||||
push!(parsed, chunk)
|
||||
end
|
||||
|
||||
return parsed
|
||||
end
|
||||
|
||||
"""Parse IJUlia notebook"""
|
||||
function parse_doc(document::String, format::NotebookInput)
|
||||
document = replace(document, "\r\n" => "\n")
|
||||
nb = JSON.parse(document)
|
||||
parsed = Any[]
|
||||
options = Dict{Symbol,Any}()
|
||||
opt_string = ""
|
||||
docno = 1
|
||||
codeno = 1
|
||||
|
||||
for cell in nb["cells"]
|
||||
srctext = "\n" * join(cell["source"], "")
|
||||
|
||||
if cell["cell_type"] == "code"
|
||||
chunk = CodeChunk(rstrip(srctext), codeno, 0, opt_string, options)
|
||||
push!(parsed, chunk)
|
||||
codeno += 1
|
||||
else
|
||||
chunk = DocChunk(srctext * "\n", docno, 0)
|
||||
push!(parsed, chunk)
|
||||
docno +=1
|
||||
end
|
||||
end
|
||||
|
||||
return parsed
|
||||
end
|
||||
|
||||
#Use this if regex is undefined
|
||||
function parse_inline(text, noex)
|
||||
return Inline[InlineText(text, 1, length(text), 1)]
|
||||
end
|
||||
|
||||
function parse_inline(text::AbstractString, inline_ex::Regex)
|
||||
occursin(inline_ex, text) || return Inline[InlineText(text, 1, length(text), 1)]
|
||||
|
||||
inline_chunks = eachmatch(inline_ex, text)
|
||||
s = 1
|
||||
e = 1
|
||||
res = Inline[]
|
||||
textno = 1
|
||||
codeno = 1
|
||||
|
||||
for ic in inline_chunks
|
||||
s = ic.offset
|
||||
doc = InlineText(text[e:(s-1)], e, s-1, textno)
|
||||
textno += 1
|
||||
push!(res, doc)
|
||||
e = s + lastindex(ic.match)
|
||||
ic.captures[1] !== nothing && (ctype = :inline)
|
||||
ic.captures[2] !== nothing && (ctype = :line)
|
||||
cap = filter(x -> x !== nothing, ic.captures)[1]
|
||||
push!(res, InlineCode(cap, s, e, codeno, ctype))
|
||||
codeno += 1
|
||||
end
|
||||
push!(res, InlineText(text[e:end], e, length(text), textno))
|
||||
|
||||
return res
|
||||
end
|
|
@ -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,160 @@
|
|||
# HTML
|
||||
# ----
|
||||
|
||||
abstract type HTMLFormat <: WeaveFormat end
|
||||
|
||||
render_code(docformat::HTMLFormat, code) =
|
||||
highlight_code(MIME("text/html"), code, docformat.highlight_theme)
|
||||
|
||||
render_termchunk(docformat::HTMLFormat, chunk) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/html"), chunk.output, docformat.highlight_theme) : ""
|
||||
|
||||
# Julia markdown
|
||||
# --------------
|
||||
|
||||
Base.@kwdef mutable struct WeaveHTML <: HTMLFormat
|
||||
description = "Weave-style HTML"
|
||||
extension = "html"
|
||||
codestart = '\n'
|
||||
codeend = '\n'
|
||||
termstart = codestart
|
||||
termend = codeend
|
||||
outputstart = "<pre class=\"output\">"
|
||||
outputend = "</pre>\n"
|
||||
mimetypes = ["image/png", "image/jpg", "image/svg+xml",
|
||||
"text/html", "text/markdown", "text/plain"]
|
||||
fig_ext = ".png"
|
||||
out_width = nothing
|
||||
out_height = nothing
|
||||
fig_pos = nothing
|
||||
fig_env = nothing
|
||||
# specials
|
||||
template = nothing
|
||||
stylesheet = nothing
|
||||
highlight_theme = nothing
|
||||
end
|
||||
register_format!("md2html", WeaveHTML())
|
||||
|
||||
function set_format_options!(docformat::WeaveHTML; template = nothing, css = nothing, highlight_theme = nothing, _kwargs...)
|
||||
template_path = isnothing(template) ? normpath(TEMPLATE_DIR, "md2html.tpl") : template
|
||||
docformat.template = get_mustache_template(template_path)
|
||||
stylesheet_path = isnothing(css) ? normpath(STYLESHEET_DIR, "skeleton.css") : css
|
||||
docformat.stylesheet = read(stylesheet_path, String)
|
||||
docformat.highlight_theme = get_highlight_theme(highlight_theme)
|
||||
end
|
||||
|
||||
# very similar to tex version of function
|
||||
function render_chunk(docformat::WeaveHTML, chunk::DocChunk)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.html)
|
||||
write(out, addlines(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end])
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addlines(inline.output, inline))
|
||||
end
|
||||
end
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.html)
|
||||
return take2string!(out)
|
||||
end
|
||||
|
||||
render_output(docformat::WeaveHTML, output) = Markdown.htmlesc(output)
|
||||
|
||||
function render_figures(docformat::WeaveHTML, chunk)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
# Set size
|
||||
attribs = ""
|
||||
isnothing(width) || (attribs = "width=\"$width\"")
|
||||
(!isempty(attribs) && !isnothing(height)) && (attribs *= ",")
|
||||
isnothing(height) || (attribs *= " height=\"$height\" ")
|
||||
|
||||
if !isnothing(caption)
|
||||
result *= """<figure>\n"""
|
||||
end
|
||||
|
||||
for fig in fignames
|
||||
figstring *= """<img src="$fig" $attribs />\n"""
|
||||
end
|
||||
|
||||
result *= figstring
|
||||
|
||||
if !isnothing(caption)
|
||||
result *= """
|
||||
<figcaption>$caption</figcaption>
|
||||
"""
|
||||
end
|
||||
|
||||
if !isnothing(caption)
|
||||
result *= "</figure>\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function render_doc(docformat::WeaveHTML, body, doc; css = nothing)
|
||||
_, weave_source = splitdir(abspath(doc.source))
|
||||
weave_version, weave_date = weave_info()
|
||||
|
||||
return Mustache.render(
|
||||
docformat.template;
|
||||
body = body,
|
||||
stylesheet = docformat.stylesheet,
|
||||
highlight_stylesheet = get_highlight_stylesheet(MIME("text/html"), docformat.highlight_theme),
|
||||
header_script = doc.header_script,
|
||||
weave_source = weave_source,
|
||||
weave_version = weave_version,
|
||||
weave_date = weave_date,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
# Pandoc
|
||||
# ------
|
||||
|
||||
Base.@kwdef mutable struct Pandoc2HTML <: HTMLFormat
|
||||
description = "HTML via intermediate Pandoc Markdown (requires Pandoc 2)"
|
||||
extension = "md"
|
||||
codestart = '\n'
|
||||
codeend = '\n'
|
||||
termstart = codestart
|
||||
termend = codeend
|
||||
outputstart = '\n'
|
||||
outputend = '\n'
|
||||
mimetypes = ["image/png", "image/svg+xml", "image/jpg", "text/html", "text/markdown", "text/plain"]
|
||||
fig_ext = ".png"
|
||||
out_width = nothing
|
||||
out_height = nothing
|
||||
fig_pos = nothing
|
||||
fig_env = nothing
|
||||
# specials
|
||||
preserve_header = true
|
||||
template_path = nothing
|
||||
stylesheet_path = nothing
|
||||
highlight_theme = nothing
|
||||
pandoc_options = String[]
|
||||
end
|
||||
register_format!("pandoc2html", Pandoc2HTML())
|
||||
|
||||
function set_format_options!(docformat::Pandoc2HTML; template = nothing, css = nothing, highlight_theme = nothing, pandoc_options = String[], _kwargs...)
|
||||
docformat.template_path =
|
||||
isnothing(template) ? normpath(TEMPLATE_DIR, "pandoc2html.html") : template
|
||||
docformat.stylesheet_path =
|
||||
isnothing(css) ? normpath(STYLESHEET_DIR, "pandoc2html_skeleton.css") : css
|
||||
docformat.highlight_theme = get_highlight_theme(highlight_theme)
|
||||
docformat.pandoc_options = pandoc_options
|
||||
end
|
||||
|
||||
render_figures(docformat::Pandoc2HTML, chunk) = render_figures(Pandoc(), chunk)
|
|
@ -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,84 @@
|
|||
abstract type PandocFormat <: WeaveFormat end
|
||||
|
||||
function render_figures(docformat::PandocFormat, chunk)
|
||||
fignames = chunk.figures
|
||||
length(fignames) > 0 || (return "")
|
||||
|
||||
caption = chunk.options[:fig_cap]
|
||||
label = get(chunk.options, :label, nothing)
|
||||
result = ""
|
||||
figstring = ""
|
||||
attribs = ""
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
|
||||
# Build figure attibutes
|
||||
attribs = String[]
|
||||
isnothing(width) || push!(attribs, "width=$width")
|
||||
isnothing(height) || push!(attribs, "height=$height")
|
||||
isnothing(label) || push!(attribs, "#fig:$label")
|
||||
attribs = isempty(attribs) ? "" : "{" * join(attribs, " ") * "}"
|
||||
|
||||
if !isnothing(caption)
|
||||
result *= "![$caption]($(fignames[1]))$attribs\n"
|
||||
for fig in fignames[2:end]
|
||||
result *= "![]($fig)$attribs\n"
|
||||
println("Warning, only the first figure gets a caption\n")
|
||||
end
|
||||
else
|
||||
for fig in fignames
|
||||
result *= "![]($fig)$attribs\\ \n\n"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
Base.@kwdef mutable struct Pandoc <: PandocFormat
|
||||
description = "Pandoc Markdown"
|
||||
extension = "md"
|
||||
codestart = "~~~~{.julia}"
|
||||
codeend = "~~~~~~~~~~~~~\n"
|
||||
termstart = codestart
|
||||
termend = codeend
|
||||
outputstart = "~~~~"
|
||||
outputend = "~~~~\n\n"
|
||||
# Prefer png figures for markdown conversion, svg doesn't work with latex
|
||||
mimetypes = ["image/png", "image/jpg", "image/svg+xml", "text/markdown", "text/plain"]
|
||||
fig_ext = ".png"
|
||||
out_width = nothing
|
||||
out_height = nothing
|
||||
fig_pos = nothing
|
||||
fig_env = nothing
|
||||
# specials
|
||||
preserve_header = true
|
||||
end
|
||||
register_format!("pandoc", Pandoc())
|
||||
|
||||
const DEFAULT_PANDOC_OPTIONS = String[]
|
||||
|
||||
Base.@kwdef mutable struct Pandoc2PDF <: PandocFormat
|
||||
description = "PDF via intermediate Pandoc Markdown"
|
||||
extension = "md"
|
||||
codestart = "~~~~{.julia}"
|
||||
codeend = "~~~~~~~~~~~~~\n"
|
||||
termstart = codestart
|
||||
termend = codeend
|
||||
outputstart = "~~~~"
|
||||
outputend = "~~~~\n\n"
|
||||
# Prefer png figures for markdown conversion, svg doesn't work with latex
|
||||
mimetypes = ["image/png", "image/jpg", "image/svg+xml", "text/markdown", "text/plain"]
|
||||
fig_ext = ".png"
|
||||
out_width = nothing
|
||||
out_height = nothing
|
||||
fig_pos = nothing
|
||||
fig_env = nothing
|
||||
# specials
|
||||
preserve_header = true
|
||||
header_template = normpath(TEMPLATE_DIR, "pandoc2pdf_header.txt")
|
||||
pandoc_options = DEFAULT_PANDOC_OPTIONS
|
||||
end
|
||||
register_format!("pandoc2pdf", Pandoc2PDF())
|
||||
|
||||
function set_format_options!(docformat::Pandoc2PDF; pandoc_options = DEFAULT_PANDOC_OPTIONS, _kwargs...)
|
||||
docformat.pandoc_options = pandoc_options
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# TODO:
|
||||
# - 1. Improve argument handling
|
||||
# - 2. Update code to use UnPack.jl to make it more readable
|
||||
# - 3. Export new interface
|
||||
# - 4. Document Interface
|
||||
|
||||
using Mustache, Highlights, .WeaveMarkdown, Markdown, Dates, Printf
|
||||
|
||||
|
||||
const FORMATS = Dict{String,WeaveFormat}()
|
||||
|
||||
# TODO: do some assertion for necessary fields of `format`
|
||||
register_format!(format_name::AbstractString, format::WeaveFormat) = push!(FORMATS, format_name => format)
|
||||
register_format!(_, format) = error("Format needs to be a subtype of WeaveFormat.")
|
||||
|
||||
set_format_options!(doc; kwargs...) = set_format_options!(doc.format; kwargs...)
|
||||
|
||||
function render_doc(doc::WeaveDoc)
|
||||
restore_header!(doc)
|
||||
|
||||
docformat = doc.format
|
||||
body = joinlines(render_chunk.(Ref(docformat), copy(doc.chunks)))
|
||||
return render_doc(docformat, body, doc)
|
||||
end
|
||||
|
||||
|
||||
include("common.jl")
|
||||
include("htmlformats.jl")
|
||||
include("texformats.jl")
|
||||
include("pandocformats.jl")
|
||||
include("miscformats.jl")
|
|
@ -0,0 +1,276 @@
|
|||
# Tex
|
||||
# ---
|
||||
|
||||
abstract type LaTeXFormat <: WeaveFormat end
|
||||
|
||||
function set_format_options!(docformat::LaTeXFormat; keep_unicode = false, template = nothing, _kwargs...)
|
||||
docformat.keep_unicode |= keep_unicode
|
||||
docformat.template =
|
||||
get_mustache_template(isnothing(template) ? normpath(TEMPLATE_DIR, "md2pdf.tpl") : template)
|
||||
end
|
||||
|
||||
# very similar to export to html
|
||||
function render_chunk(docformat::LaTeXFormat, chunk::DocChunk)
|
||||
out = IOBuffer()
|
||||
io = IOBuffer()
|
||||
for inline in chunk.content
|
||||
if isa(inline, InlineText)
|
||||
write(io, inline.content)
|
||||
elseif !isempty(inline.rich_output)
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.latex)
|
||||
write(out, addlines(inline.rich_output, inline))
|
||||
elseif !isempty(inline.figures)
|
||||
write(io, inline.figures[end], inline)
|
||||
elseif !isempty(inline.output)
|
||||
write(io, addlines(inline.output, inline))
|
||||
end
|
||||
end
|
||||
clear_buffer_and_format!(io, out, WeaveMarkdown.latex)
|
||||
out = take2string!(out)
|
||||
return unicode2latex(docformat, out)
|
||||
end
|
||||
|
||||
render_output(docformat::LaTeXFormat, output) = unicode2latex(docformat, output, true)
|
||||
|
||||
render_code(docformat::LaTeXFormat, code) = unicode2latex(docformat, code, true)
|
||||
|
||||
render_termchunk(docformat::LaTeXFormat, chunk) = string(docformat.termstart, chunk.output, docformat.termend, "\n")
|
||||
|
||||
# from julia symbols (e.g. "\bfhoge") to valid latex
|
||||
const UNICODE2LATEX = let
|
||||
function texify(s)
|
||||
return if occursin(r"^\\bf[A-Z]$", s)
|
||||
replace(s, "\\bf" => "\\bm{\\mathrm{") * "}}"
|
||||
elseif startswith(s, "\\bfrak")
|
||||
replace(s, "\\bfrak" => "\\bm{\\mathfrak{") * "}}"
|
||||
elseif startswith(s, "\\bf")
|
||||
replace(s, "\\bf" => "\\bm{\\") * "}"
|
||||
elseif startswith(s, "\\frak")
|
||||
replace(s, "\\frak" => "\\mathfrak{") * "}"
|
||||
else
|
||||
s
|
||||
end
|
||||
end
|
||||
Dict(unicode => texify(sym) for (sym, unicode) in REPL.REPLCompletions.latex_symbols)
|
||||
end
|
||||
|
||||
function unicode2latex(docformat::LaTeXFormat, s, escape = false)
|
||||
# Check whether to convert at all and return input if not
|
||||
docformat.keep_unicode && return s
|
||||
for (unicode, latex) in UNICODE2LATEX
|
||||
body = "\\ensuremath{$(latex)}"
|
||||
target = escape ? string(docformat.escape_starter, body, docformat.escape_closer) : body
|
||||
s = replace(s, unicode => target)
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function render_figures(docformat::LaTeXFormat, chunk)
|
||||
fignames = chunk.figures
|
||||
caption = chunk.options[:fig_cap]
|
||||
width = chunk.options[:out_width]
|
||||
height = chunk.options[:out_height]
|
||||
f_pos = chunk.options[:fig_pos]
|
||||
f_env = chunk.options[:fig_env]
|
||||
result = ""
|
||||
figstring = ""
|
||||
|
||||
if isnothing(f_env) && !isnothing(caption)
|
||||
f_env = "figure"
|
||||
end
|
||||
|
||||
(isnothing(f_pos)) && (f_pos = "!h")
|
||||
# Set size
|
||||
attribs = ""
|
||||
isnothing(width) || (attribs = "width=$(md_length_to_latex(width,"\\linewidth"))")
|
||||
(!isempty(attribs) && !isnothing(height)) && (attribs *= ",")
|
||||
isnothing(height) || (attribs *= "height=$(md_length_to_latex(height,"\\paperheight"))")
|
||||
|
||||
if !isnothing(f_env)
|
||||
result *= "\\begin{$f_env}"
|
||||
(!isempty(f_pos)) && (result *= "[$f_pos]")
|
||||
result *= "\n"
|
||||
end
|
||||
|
||||
for fig in fignames
|
||||
if splitext(fig)[2] == ".tex" # Tikz figures
|
||||
figstring *= "\\resizebox{$width}{!}{\\input{$fig}}\n"
|
||||
else
|
||||
if isempty(attribs)
|
||||
figstring *= "\\includegraphics{$fig}\n"
|
||||
else
|
||||
figstring *= "\\includegraphics[$attribs]{$fig}\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Figure environment
|
||||
if !isnothing(caption)
|
||||
result *= string("\\center\n", "$figstring", "\\caption{$caption}\n")
|
||||
else
|
||||
result *= figstring
|
||||
end
|
||||
|
||||
if !isnothing(chunk.options[:label]) && !isnothing(f_env)
|
||||
label = chunk.options[:label]
|
||||
result *= "\\label{fig:$label}\n"
|
||||
end
|
||||
|
||||
if !isnothing(f_env)
|
||||
result *= "\\end{$f_env}\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function md_length_to_latex(def, reference)
|
||||
if occursin("%", def)
|
||||
_def = tryparse(Float64, replace(def, "%" => ""))
|
||||
isnothing(_def) && return def
|
||||
perc = round(_def / 100, digits = 2)
|
||||
return "$perc$reference"
|
||||
end
|
||||
return def
|
||||
end
|
||||
|
||||
function render_doc(docformat::LaTeXFormat, body, doc)
|
||||
return Mustache.render(
|
||||
docformat.template;
|
||||
body = body,
|
||||
highlight = "",
|
||||
tex_deps = docformat.tex_deps,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
# minted Tex
|
||||
# ----------
|
||||
|
||||
Base.@kwdef mutable struct LaTeXMinted <: LaTeXFormat
|
||||
description = "LaTeX using minted package for code highlighting"
|
||||
extension = "tex"
|
||||
codestart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\small, xleftmargin=0.5em]{julia}"
|
||||
codeend = "\\end{minted}"
|
||||
termstart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\footnotesize, xleftmargin=0.5em]{jlcon}"
|
||||
termend = "\\end{minted}"
|
||||
outputstart = "\\begin{minted}[escapeinside=||, mathescape, fontsize=\\small, xleftmargin=0.5em, frame = leftline]{text}"
|
||||
outputend = "\\end{minted}"
|
||||
mimetypes = ["application/pdf", "image/png", "text/latex", "text/plain"]
|
||||
fig_ext = ".pdf"
|
||||
out_width = "\\linewidth"
|
||||
out_height = nothing
|
||||
fig_pos = "htpb"
|
||||
fig_env = "figure"
|
||||
# specials
|
||||
keep_unicode = false
|
||||
template = nothing
|
||||
tex_deps = "\\usepackage{minted}"
|
||||
# how to escape latex in verbatim/code environment
|
||||
escape_starter = "|\$"
|
||||
escape_closer = reverse(escape_starter)
|
||||
end
|
||||
register_format!("texminted", LaTeXMinted())
|
||||
|
||||
# Tex (directly to PDF)
|
||||
# ---------------------
|
||||
|
||||
abstract type WeaveLaTeXFormat <: LaTeXFormat end
|
||||
|
||||
function set_format_options!(docformat::WeaveLaTeXFormat; template = nothing, highlight_theme = nothing, keep_unicode = false, _kwargs...)
|
||||
docformat.template =
|
||||
get_mustache_template(isnothing(template) ? normpath(TEMPLATE_DIR, "md2pdf.tpl") : template)
|
||||
docformat.highlight_theme = get_highlight_theme(highlight_theme)
|
||||
docformat.keep_unicode |= keep_unicode
|
||||
end
|
||||
|
||||
function render_output(docformat::WeaveLaTeXFormat, output)
|
||||
# Highligts has some extra escaping defined, eg of $, ", ...
|
||||
output_escaped = sprint(
|
||||
(io, x) ->
|
||||
Highlights.Format.escape(io, MIME("text/latex"), x, charescape = true),
|
||||
output,
|
||||
)
|
||||
return unicode2latex(docformat, output_escaped, true)
|
||||
end
|
||||
|
||||
function render_code(docformat::WeaveLaTeXFormat, code)
|
||||
ret = highlight_code(MIME("text/latex"), code, docformat.highlight_theme)
|
||||
unicode2latex(docformat, ret, false)
|
||||
end
|
||||
|
||||
render_termchunk(docformat::WeaveLaTeXFormat, chunk) =
|
||||
should_render(chunk) ? highlight_term(MIME("text/latex"), chunk.output, docformat.highlight_theme) : ""
|
||||
|
||||
function render_doc(docformat::WeaveLaTeXFormat, body, doc)
|
||||
return Mustache.render(
|
||||
docformat.template;
|
||||
body = body,
|
||||
highlight = get_highlight_stylesheet(MIME("text/latex"), docformat.highlight_theme),
|
||||
tex_deps = docformat.tex_deps,
|
||||
[Pair(Symbol(k), v) for (k, v) in doc.header]...,
|
||||
)
|
||||
end
|
||||
|
||||
Base.@kwdef mutable struct WeaveLaTeX <: WeaveLaTeXFormat
|
||||
description = "Weave-styled LaTeX"
|
||||
extension = "tex"
|
||||
codestart = ""
|
||||
codeend = ""
|
||||
termstart = codestart
|
||||
termend = codeend
|
||||
outputstart = "\\begin{lstlisting}"
|
||||
outputend = "\\end{lstlisting}\n"
|
||||
mimetypes = ["application/pdf", "image/png", "image/jpg", "text/latex", "text/markdown", "text/plain"]
|
||||
fig_ext = ".pdf"
|
||||
out_width = "\\linewidth"
|
||||
out_height = nothing
|
||||
fig_pos = nothing
|
||||
fig_env = nothing
|
||||
# specials
|
||||
highlight_theme = nothing
|
||||
template = nothing
|
||||
keep_unicode = false
|
||||
tex_deps = ""
|
||||
# how to escape latex in verbatim/code environment
|
||||
escape_starter = "(*@"
|
||||
escape_closer = reverse(escape_starter)
|
||||
end
|
||||
register_format!("md2tex", WeaveLaTeX())
|
||||
|
||||
# will be used by `write_doc`
|
||||
const DEFAULT_LATEX_CMD = ["xelatex", "-shell-escape", "-halt-on-error"]
|
||||
|
||||
Base.@kwdef mutable struct WeaveLaTeX2PDF <: WeaveLaTeXFormat
|
||||
description = "PDF via Weave-styled LaTeX"
|
||||
extension = "tex"
|
||||
codestart = ""
|
||||
codeend = ""
|
||||
termstart = codestart
|
||||
termend = codeend
|
||||
outputstart = "\\begin{lstlisting}"
|
||||
outputend = "\\end{lstlisting}\n"
|
||||
mimetypes = ["application/pdf", "image/png", "image/jpg", "text/latex", "text/markdown", "text/plain"]
|
||||
fig_ext = ".pdf"
|
||||
out_width = "\\linewidth"
|
||||
out_height = nothing
|
||||
fig_pos = nothing
|
||||
fig_env = nothing
|
||||
# specials
|
||||
highlight_theme = nothing
|
||||
template = nothing
|
||||
keep_unicode = false
|
||||
tex_deps = ""
|
||||
latex_cmd = DEFAULT_LATEX_CMD
|
||||
# how to escape latex in verbatim/code environment
|
||||
escape_starter = "(*@"
|
||||
escape_closer = reverse(escape_starter)
|
||||
end
|
||||
register_format!("md2pdf", WeaveLaTeX2PDF())
|
||||
|
||||
function set_format_options!(docformat::WeaveLaTeX2PDF; template = nothing, highlight_theme = nothing, keep_unicode = false, latex_cmd = DEFAULT_LATEX_CMD, _kwargs...)
|
||||
docformat.template =
|
||||
get_mustache_template(isnothing(template) ? normpath(TEMPLATE_DIR, "md2pdf.tpl") : template)
|
||||
docformat.highlight_theme = get_highlight_theme(highlight_theme)
|
||||
docformat.keep_unicode |= keep_unicode
|
||||
docformat.latex_cmd = latex_cmd
|
||||
end
|
640
src/run.jl
640
src/run.jl
|
@ -1,190 +1,189 @@
|
|||
using Base64
|
||||
|
||||
"""
|
||||
run(doc::WeaveDoc; doctype = :auto,
|
||||
mod::Union{Module, Symbol} = :sandbox, out_path=:doc,
|
||||
args=Dict(), fig_path = "figures", fig_ext = nothing,
|
||||
cache_path = "cache", cache = :off, throw_errors=false)
|
||||
|
||||
Run code chunks and capture output from parsed document.
|
||||
const PROGRESS_ID = "weave_progress"
|
||||
|
||||
* `doctype`: :auto = set based on file extension or specify one of the supported formats.
|
||||
See `list_out_formats()`
|
||||
* `out_path`: Path where the output is generated. Can be: `:doc`: Path of the source document, `:pwd`: Julia working directory,
|
||||
`"somepath"`: Path as a AbstractString e.g `"/home/mpastell/weaveout"`
|
||||
* `args`: dictionary of arguments to pass to document. Available as WEAVE_ARGS.
|
||||
* `mod`: Module where Weave `eval`s code. Defaults to `:sandbox`
|
||||
to create new sandbox module, you can also pass a module e.g. `Main`.
|
||||
* `fig_path`: where figures will be generated, relative to out_path
|
||||
* `fig_ext`: Extension for saved figures e.g. `".pdf"`, `".png"`. Default setting depends on `doctype`.
|
||||
* `cache_path`: where of cached output will be saved.
|
||||
* `cache`: controls caching of code: `:off` = no caching, `:all` = cache everything,
|
||||
`:user` = cache based on chunk options, `:refresh`, run all code chunks and save new cache.
|
||||
function run_doc(
|
||||
doc::WeaveDoc;
|
||||
doctype::Union{Nothing,AbstractString} = nothing,
|
||||
out_path::Union{Symbol,AbstractString} = :doc,
|
||||
args::Any = Dict(),
|
||||
mod::Union{Module,Nothing} = nothing,
|
||||
fig_path::Union{Nothing,AbstractString} = nothing,
|
||||
fig_ext::Union{Nothing,AbstractString} = nothing,
|
||||
cache_path::AbstractString = "cache",
|
||||
cache::Symbol = :off,
|
||||
)
|
||||
# cache :all, :user, :off, :refresh
|
||||
|
||||
**Note:** Run command from terminal and not using IJulia, Juno or ESS, they tend to mess with capturing output.
|
||||
"""
|
||||
function Base.run(doc::WeaveDoc; doctype = :auto,
|
||||
mod::Union{Module, Symbol} = :sandbox, out_path=:doc,
|
||||
args=Dict(), fig_path = "figures", fig_ext = nothing,
|
||||
cache_path = "cache", cache = :off, throw_errors=false, latex_keep_unicode=false)
|
||||
#cache :all, :user, :off, :refresh
|
||||
doc.doctype = isnothing(doctype) ? (doctype = detect_doctype(doc.source)) : doctype
|
||||
doc.format = deepcopy(get_format(doctype))
|
||||
|
||||
doc.cwd = get_cwd(doc, out_path)
|
||||
doctype == :auto && (doctype = detect_doctype(doc.source))
|
||||
doc.doctype = doctype
|
||||
doc.format = formats[doctype]
|
||||
cwd = doc.cwd = get_cwd(doc, out_path)
|
||||
mkpath(cwd)
|
||||
|
||||
if (haskey(doc.format.formatdict, :keep_unicode))
|
||||
doc.format.formatdict[:keep_unicode] = latex_keep_unicode
|
||||
# TODO: provide a way not to create `fig_path` ?
|
||||
if isnothing(fig_path)
|
||||
fig_path = if (endswith(doctype, "2pdf") && cache === :off) || endswith(doctype, "2html")
|
||||
basename(mktempdir(abspath(cwd)))
|
||||
else
|
||||
DEFAULT_FIG_PATH
|
||||
end
|
||||
end
|
||||
|
||||
isdir(doc.cwd) || mkpath(doc.cwd)
|
||||
|
||||
if occursin("2pdf", doctype) && cache == :off
|
||||
fig_path = mktempdir(abspath(doc.cwd))
|
||||
elseif occursin("2html", doctype)
|
||||
fig_path = mktempdir(abspath(doc.cwd))
|
||||
end
|
||||
|
||||
cache == :off || @eval import Serialization
|
||||
|
||||
#This is needed for latex and should work on all output formats
|
||||
Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/"))
|
||||
|
||||
doc.fig_path = fig_path
|
||||
mkpath(normpath(cwd, fig_path))
|
||||
# This is needed for latex and should work on all output formats
|
||||
@static Sys.iswindows() && (fig_path = replace(fig_path, "\\" => "/"))
|
||||
set_rc_params(doc, fig_path, fig_ext)
|
||||
|
||||
#New sandbox for each document with args exposed
|
||||
if mod == :sandbox
|
||||
sandbox = "WeaveSandBox$(rcParams[:doc_number])"
|
||||
mod = Core.eval(Main, Meta.parse("module $sandbox\nend"))
|
||||
end
|
||||
@eval mod WEAVE_ARGS = Dict()
|
||||
merge!(mod.WEAVE_ARGS, args)
|
||||
cache === :off || @eval import Serialization # XXX: evaluate in a more sensible module
|
||||
|
||||
rcParams[:doc_number] += 1
|
||||
# New sandbox for each document with args exposed
|
||||
isnothing(mod) && (mod = sandbox = Core.eval(Main, :(module $(gensym(:WeaveSandBox)) end))::Module)
|
||||
Core.eval(mod, :(const WEAVE_ARGS = $(args)))
|
||||
|
||||
if haskey(doc.format.formatdict, :mimetypes)
|
||||
mimetypes = doc.format.formatdict[:mimetypes]
|
||||
else
|
||||
mimetypes = default_mime_types
|
||||
end
|
||||
mimetypes = doc.format.mimetypes
|
||||
|
||||
report = Report(doc.cwd, doc.basename, doc.format.formatdict, mimetypes, throw_errors)
|
||||
report = Report(cwd, doc.basename, doc.format, mimetypes)
|
||||
cd_back = let d = pwd(); () -> cd(d); end
|
||||
cd(cwd)
|
||||
pushdisplay(report)
|
||||
|
||||
if cache != :off && cache != :refresh
|
||||
cached = read_cache(doc, cache_path)
|
||||
cached == nothing && @info("No cached results found, running code")
|
||||
else
|
||||
cached = nothing
|
||||
end
|
||||
|
||||
executed = Any[]
|
||||
n = length(doc.chunks)
|
||||
|
||||
for i = 1:n
|
||||
chunk = doc.chunks[i]
|
||||
|
||||
if isa(chunk, CodeChunk)
|
||||
options = merge(doc.chunk_defaults, chunk.options)
|
||||
merge!(chunk.options, options)
|
||||
end
|
||||
|
||||
restore = (cache ==:user && typeof(chunk) == CodeChunk && chunk.options[:cache])
|
||||
|
||||
if cached != nothing && (cache == :all || restore)
|
||||
result_chunks = restore_chunk(chunk, cached)
|
||||
try
|
||||
if cache !== :off && cache !== :refresh
|
||||
cached = read_cache(doc, cache_path)
|
||||
isnothing(cached) && @info "No cached results found, running code"
|
||||
else
|
||||
result_chunks = run_chunk(chunk, doc, report, mod)
|
||||
cached = nothing
|
||||
end
|
||||
|
||||
executed = [executed; result_chunks]
|
||||
end
|
||||
executed = []
|
||||
n = length(filter(chunk->isa(chunk,CodeChunk), doc.chunks))
|
||||
i = 0
|
||||
for chunk in doc.chunks
|
||||
if chunk isa CodeChunk
|
||||
options = merge(doc.chunk_defaults, chunk.options)
|
||||
merge!(chunk.options, options)
|
||||
|
||||
doc.header_script = report.header_script
|
||||
@info "Weaving chunk $(chunk.number) from line $(chunk.start_line)" progress=(i)/n _id=PROGRESS_ID
|
||||
i+=1
|
||||
end
|
||||
|
||||
popdisplay(report)
|
||||
restore = (cache === :user && chunk isa CodeChunk && chunk.options[:cache])
|
||||
result_chunks = if cached ≠ nothing && (cache === :all || restore)
|
||||
restore_chunk(chunk, cached)
|
||||
else
|
||||
run_chunk(chunk, doc, report, mod)
|
||||
end
|
||||
executed = [executed; result_chunks]
|
||||
end
|
||||
|
||||
#Clear variables from used sandbox
|
||||
mod == :sandbox && clear_sandbox(SandBox)
|
||||
doc.chunks = executed
|
||||
replace_header_inline!(doc, report, mod) # evaluate and replace inline code in header
|
||||
|
||||
if cache != :off
|
||||
write_cache(doc, cache_path)
|
||||
doc.header_script = report.header_script
|
||||
doc.chunks = executed
|
||||
|
||||
cache !== :off && write_cache(doc, cache_path)
|
||||
|
||||
@isdefined(sandbox) && clear_module!(sandbox)
|
||||
catch err
|
||||
rethrow(err)
|
||||
finally
|
||||
@info "Weaved all chunks" progress=1 _id=PROGRESS_ID
|
||||
cd_back()
|
||||
popdisplay(report) # ensure display pops out even if internal error occurs
|
||||
end
|
||||
|
||||
return doc
|
||||
end
|
||||
|
||||
"""Detect the output format based on file extension"""
|
||||
function detect_doctype(source::AbstractString)
|
||||
ext = lowercase(splitext(source)[2])
|
||||
ext == ".jl" && return "md2html"
|
||||
occursin("md", ext) && return "md2html"
|
||||
occursin("rst", ext) && return "rst"
|
||||
occursin("tex", ext) && return "texminted"
|
||||
occursin("txt", ext) && return "asciidoc"
|
||||
run_doc(doc::WeaveDoc, doctype::Union{Nothing,AbstractString}; kwargs...) =
|
||||
run_doc(doc; doctype = doctype, kwargs...)
|
||||
|
||||
return "pandoc"
|
||||
"""
|
||||
detect_doctype(path)
|
||||
|
||||
Detect the output format based on file extension.
|
||||
"""
|
||||
function detect_doctype(path)
|
||||
_, ext = lowercase.(splitext(path))
|
||||
|
||||
match(r"^\.(jl|.?md|ipynb)", ext) !== nothing && return "md2html"
|
||||
ext == ".rst" && return "rst"
|
||||
ext == ".tex" && return "texminted"
|
||||
ext == ".txt" && return "asciidoc"
|
||||
|
||||
return "pandoc"
|
||||
end
|
||||
|
||||
|
||||
function run_chunk(chunk::CodeChunk, doc::WeaveDoc, report::Report, SandBox::Module)
|
||||
@info("Weaving chunk $(chunk.number) from line $(chunk.start_line)")
|
||||
result_chunks = eval_chunk(chunk, report, SandBox)
|
||||
occursin("2html", report.formatdict[:doctype]) && (result_chunks = embed_figures(result_chunks, report.cwd))
|
||||
return result_chunks
|
||||
end
|
||||
|
||||
function embed_figures(chunk::CodeChunk, cwd)
|
||||
chunk.figures = [img2base64(fig, cwd) for fig in chunk.figures]
|
||||
return chunk
|
||||
end
|
||||
|
||||
function embed_figures(result_chunks, cwd)
|
||||
for i in 1:length(result_chunks)
|
||||
figs = result_chunks[i].figures
|
||||
if !isempty(figs)
|
||||
result_chunks[i].figures = [img2base64(fig, cwd) for fig in figs]
|
||||
function get_cwd(doc, out_path)
|
||||
return if out_path === :doc
|
||||
dirname(doc.path)
|
||||
elseif out_path === :pwd
|
||||
pwd()
|
||||
else
|
||||
path, ext = splitext(out_path)
|
||||
if isempty(ext) # directory given
|
||||
path
|
||||
else # file given
|
||||
dirname(path)
|
||||
end
|
||||
end |> abspath
|
||||
end
|
||||
|
||||
function run_chunk(chunk::CodeChunk, doc, report, mod)
|
||||
result = eval_chunk(doc, chunk, report, mod)
|
||||
occursin("2html", doc.doctype) && (embed_figures!(result, report.cwd))
|
||||
return result
|
||||
end
|
||||
|
||||
function embed_figures!(chunk::CodeChunk, cwd)
|
||||
for (i, fig) in enumerate(chunk.figures)
|
||||
chunk.figures[i] = img2base64(fig, cwd)
|
||||
end
|
||||
end
|
||||
|
||||
function embed_figures!(chunks::Vector{CodeChunk}, cwd)
|
||||
for chunk in chunks
|
||||
embed_figures!(chunk, cwd)
|
||||
end
|
||||
return result_chunks
|
||||
end
|
||||
|
||||
function img2base64(fig, cwd)
|
||||
ext = splitext(fig)[2]
|
||||
f = open(joinpath(cwd, fig), "r")
|
||||
ext = splitext(fig)[2]
|
||||
f = open(joinpath(cwd, fig), "r")
|
||||
raw = read(f)
|
||||
close(f)
|
||||
if ext == ".png"
|
||||
return "data:image/png;base64," * stringmime(MIME("image/png"), raw)
|
||||
elseif ext == ".svg"
|
||||
return "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw)
|
||||
elseif ext == ".gif"
|
||||
return "data:image/gif;base64," * stringmime(MIME("image/gif"), raw)
|
||||
else
|
||||
return(fig)
|
||||
end
|
||||
close(f)
|
||||
if ext == ".png"
|
||||
return "data:image/png;base64," * stringmime(MIME("image/png"), raw)
|
||||
elseif ext == ".svg"
|
||||
return "data:image/svg+xml;base64," * stringmime(MIME("image/svg"), raw)
|
||||
elseif ext == ".gif"
|
||||
return "data:image/gif;base64," * stringmime(MIME("image/gif"), raw)
|
||||
else
|
||||
return (fig)
|
||||
end
|
||||
end
|
||||
|
||||
function run_chunk(chunk::DocChunk, doc::WeaveDoc, report::Report, SandBox::Module)
|
||||
chunk.content = [run_inline(c, doc, report, SandBox) for c in chunk.content]
|
||||
function run_chunk(chunk::DocChunk, doc, report, mod)
|
||||
chunk.content = [run_inline(c, doc, report, mod) for c in chunk.content]
|
||||
return chunk
|
||||
end
|
||||
|
||||
function run_inline(inline::InlineText, doc::WeaveDoc, report::Report, SandBox::Module)
|
||||
return inline
|
||||
end
|
||||
run_inline(inline::InlineText, ::WeaveDoc, ::Report, ::Module) = inline
|
||||
|
||||
function run_inline(inline::InlineCode, doc::WeaveDoc, report::Report, SandBox::Module)
|
||||
#Make a temporary CodeChunk for running code. Collect results and don't wrap
|
||||
chunk = CodeChunk(inline.content, 0, 0, "", Dict(:hold => true, :wrap => false))
|
||||
const INLINE_OPTIONS = Dict(
|
||||
:term => false,
|
||||
:hold => true,
|
||||
:wrap => false
|
||||
)
|
||||
|
||||
function run_inline(inline::InlineCode, doc::WeaveDoc, report::Report, mod::Module)
|
||||
# Make a temporary CodeChunk for running code. Collect results and don't wrap
|
||||
chunk = CodeChunk(inline.content, 0, 0, "", INLINE_OPTIONS)
|
||||
options = merge(doc.chunk_defaults, chunk.options)
|
||||
merge!(chunk.options, options)
|
||||
|
||||
chunks = eval_chunk(chunk, report, SandBox)
|
||||
occursin("2html", report.formatdict[:doctype]) && (chunks = embed_figures(chunks, report.cwd))
|
||||
chunks = eval_chunk(doc, chunk, report, mod)
|
||||
occursin("2html", doc.doctype) && (embed_figures!(chunks, report.cwd))
|
||||
|
||||
output = chunks[1].output
|
||||
endswith(output, "\n") && (output = output[1:end-1])
|
||||
|
@ -194,260 +193,269 @@ function run_inline(inline::InlineCode, doc::WeaveDoc, report::Report, SandBox::
|
|||
return inline
|
||||
end
|
||||
|
||||
function reset_report(report::Report)
|
||||
report.cur_result = ""
|
||||
report.figures = AbstractString[]
|
||||
report.term_state = :text
|
||||
function run_code(doc::WeaveDoc, chunk::CodeChunk, report::Report, mod::Module)
|
||||
code = chunk.content
|
||||
path = doc.path
|
||||
error = chunk.options[:error]
|
||||
codes = chunk.options[:term] ? split_code(code) : [code]
|
||||
capture = code -> capture_output(code, mod, path, error, report)
|
||||
return capture.(codes)
|
||||
end
|
||||
|
||||
function run_code(chunk::CodeChunk, report::Report, SandBox::Module)
|
||||
expressions = parse_input(chunk.content)
|
||||
N = length(expressions)
|
||||
#@show expressions
|
||||
result_no = 1
|
||||
results = ChunkOutput[ ]
|
||||
|
||||
for (str_expr, expr) = expressions
|
||||
reset_report(report)
|
||||
lastline = (result_no == N)
|
||||
(obj, out) = capture_output(expr, SandBox, chunk.options[:term],
|
||||
chunk.options[:display], lastline, report.throw_errors)
|
||||
figures = report.figures #Captured figures
|
||||
result = ChunkOutput(str_expr, out, report.cur_result, report.rich_output, figures)
|
||||
report.rich_output = ""
|
||||
push!(results, result)
|
||||
result_no += 1
|
||||
function split_code(code)
|
||||
res = String[]
|
||||
e = 1
|
||||
ex = :init
|
||||
while true
|
||||
s = e
|
||||
ex, e = Meta.parse(code, s)
|
||||
isnothing(ex) && break
|
||||
push!(res, strip(code[s:e-1]))
|
||||
end
|
||||
return results
|
||||
return res
|
||||
end
|
||||
|
||||
getstdout() = stdout
|
||||
function capture_output(code, mod, path, error, report)
|
||||
reset_report!(report)
|
||||
|
||||
function capture_output(expr, SandBox::Module, term, disp,
|
||||
lastline, throw_errors=false)
|
||||
#oldSTDOUT = STDOUT
|
||||
oldSTDOUT = getstdout()
|
||||
out = nothing
|
||||
obj = nothing
|
||||
old = stdout
|
||||
rw, wr = redirect_stdout()
|
||||
reader = @async read(rw, String)
|
||||
try
|
||||
obj = Core.eval(SandBox, expr)
|
||||
if (term || disp) && (typeof(expr) != Expr || expr.head != :toplevel)
|
||||
obj != nothing && display(obj)
|
||||
#This shows images and lone variables, result can
|
||||
#Handle last line sepately
|
||||
elseif lastline && obj != nothing
|
||||
(typeof(expr) != Expr || expr.head != :toplevel) && display(obj)
|
||||
|
||||
local out = nothing
|
||||
task_local_storage(:SOURCE_PATH, path) do
|
||||
try
|
||||
obj = include_string(mod, code, path) # TODO: fix line number
|
||||
!isnothing(obj) && !REPL.ends_with_semicolon(code) && display(obj)
|
||||
catch _err
|
||||
err = unwrap_load_err(_err)
|
||||
error || throw(err)
|
||||
display(err)
|
||||
@warn "ERROR: $(typeof(err)) occurred, including output in Weaved document"
|
||||
finally
|
||||
redirect_stdout(old)
|
||||
close(wr)
|
||||
out = fetch(reader)
|
||||
close(rw)
|
||||
end
|
||||
catch E
|
||||
throw_errors && throw(E)
|
||||
display(E)
|
||||
@warn("ERROR: $(typeof(E)) occurred, including output in Weaved document")
|
||||
finally
|
||||
redirect_stdout(oldSTDOUT)
|
||||
close(wr)
|
||||
out = fetch(reader)
|
||||
close(rw)
|
||||
end
|
||||
out = replace(out, r"\u001b\[.*?m" => "") #Remove ANSI color codes
|
||||
return (obj, out)
|
||||
|
||||
return ChunkOutput(code, remove_ansi_control_chars(out), report.rich_output, report.figures)
|
||||
end
|
||||
|
||||
|
||||
#Parse chunk input to array of expressions
|
||||
function parse_input(input::AbstractString)
|
||||
parsed = Tuple{AbstractString, Any}[]
|
||||
input = lstrip(input)
|
||||
n = sizeof(input)
|
||||
pos = 1 #The first character is extra line end
|
||||
while pos ≤ n
|
||||
oldpos = pos
|
||||
code, pos = Meta.parse(input, pos)
|
||||
push!(parsed, (input[oldpos:pos-1] , code ))
|
||||
end
|
||||
parsed
|
||||
function reset_report!(report)
|
||||
report.rich_output = ""
|
||||
report.figures = String[]
|
||||
end
|
||||
|
||||
unwrap_load_err(err) = return err
|
||||
unwrap_load_err(err::LoadError) = return err.error
|
||||
|
||||
function eval_chunk(chunk::CodeChunk, report::Report, SandBox::Module)
|
||||
# https://stackoverflow.com/a/33925425/12113178
|
||||
remove_ansi_control_chars(s) = replace(s, r"(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]" => "")
|
||||
|
||||
function eval_chunk(doc::WeaveDoc, chunk::CodeChunk, report::Report, mod::Module)
|
||||
if !chunk.options[:eval]
|
||||
chunk.output = ""
|
||||
chunk.options[:fig] = false
|
||||
return chunk
|
||||
end
|
||||
|
||||
#Run preexecute_hooks
|
||||
for hook in preexecute_hooks
|
||||
chunk = Base.invokelatest(hook, chunk)
|
||||
end
|
||||
execute_prehooks!(chunk)
|
||||
|
||||
report.fignum = 1
|
||||
report.cur_chunk = chunk
|
||||
|
||||
if haskey(report.formatdict, :out_width) && chunk.options[:out_width] == nothing
|
||||
chunk.options[:out_width] = report.formatdict[:out_width]
|
||||
if hasproperty(report.format, :out_width) && isnothing(chunk.options[:out_width])
|
||||
chunk.options[:out_width] = report.format.out_width
|
||||
end
|
||||
|
||||
chunk.result = run_code(chunk, report, SandBox)
|
||||
chunk.result = run_code(doc, chunk, report, mod)
|
||||
|
||||
execute_posthooks!(chunk)
|
||||
|
||||
#Run post_execute chunks
|
||||
for hook in postexecute_hooks
|
||||
chunk = Base.invokelatest(hook, chunk)
|
||||
end
|
||||
|
||||
if chunk.options[:term]
|
||||
chunks = collect_results(chunk, TermResult())
|
||||
chunks = if chunk.options[:term]
|
||||
collect_term_results(chunk)
|
||||
elseif chunk.options[:hold]
|
||||
chunks = collect_results(chunk, CollectResult())
|
||||
collect_hold_results(chunk)
|
||||
else
|
||||
chunks = collect_results(chunk, ScriptResult())
|
||||
collect_results(chunk)
|
||||
end
|
||||
|
||||
#else
|
||||
# chunk.options[:fig] && (chunk.figures = copy(report.figures))
|
||||
#end
|
||||
|
||||
chunks
|
||||
return chunks
|
||||
end
|
||||
|
||||
# Hooks to run before and after chunks, this is form IJulia,
|
||||
const preexecution_hooks = Function[]
|
||||
push_preexecution_hook!(f::Function) = push!(preexecution_hooks, f)
|
||||
function pop_preexecution_hook!(f::Function)
|
||||
i = findfirst(x -> x == f, preexecution_hooks)
|
||||
isnothing(i) && error("this function has not been registered in the pre-execution hook yet")
|
||||
return splice!(preexecution_hooks, i)
|
||||
end
|
||||
execute_prehooks!(chunk::CodeChunk) = for prehook in preexecution_hooks; Base.invokelatest(prehook, chunk); end
|
||||
|
||||
#function eval_chunk(chunk::DocChunk, report::Report, SandBox)
|
||||
# chunk
|
||||
#end
|
||||
const postexecution_hooks = Function[]
|
||||
push_postexecution_hook!(f::Function) = push!(postexecution_hooks, f)
|
||||
function pop_postexecution_hook!(f::Function)
|
||||
i = findfirst(x -> x == f, postexecution_hooks)
|
||||
isnothing(i) && error("this function has not been registered in the post-execution hook yet")
|
||||
return splice!(postexecution_hooks, i)
|
||||
end
|
||||
execute_posthooks!(chunk::CodeChunk) = for posthook in postexecution_hooks; Base.invokelatest(posthook, chunk); end
|
||||
|
||||
#Set all variables to nothing
|
||||
function clear_sandbox(SandBox::Module)
|
||||
for name = names(SandBox, all=true)
|
||||
if name != :eval && name != names(SandBox)[1]
|
||||
try eval(SandBox, Meta.parse(AbstractString(AbstractString(name), "=nothing"))) catch; end
|
||||
"""
|
||||
clear_module!(mod::Module)
|
||||
|
||||
Recursively sets variables in `mod` to `nothing` so that they're GCed.
|
||||
|
||||
!!! warning
|
||||
`const` variables can't be reassigned, as such they can't be cleared.
|
||||
"""
|
||||
function clear_module!(mod::Module)
|
||||
for name in names(mod; all = true)
|
||||
name === :eval && continue
|
||||
try
|
||||
v = getfield(mod, name)
|
||||
if v isa Module && v != mod
|
||||
clear_module!(v)
|
||||
continue
|
||||
end
|
||||
isconst(mod, name) && continue # can't clear constant
|
||||
Core.eval(mod, :($name = nothing))
|
||||
catch err
|
||||
@debug err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function get_figname(report::Report, chunk; fignum = nothing, ext = nothing)
|
||||
figpath = joinpath(report.cwd, chunk.options[:fig_path])
|
||||
isdir(figpath) || mkpath(figpath)
|
||||
ext == nothing && (ext = chunk.options[:fig_ext])
|
||||
fignum == nothing && (fignum = report.fignum)
|
||||
isnothing(ext) && (ext = chunk.options[:fig_ext])
|
||||
isnothing(fignum) && (fignum = report.fignum)
|
||||
|
||||
chunkid = (chunk.options[:label] == nothing) ? chunk.number : chunk.options[:label]
|
||||
full_name = joinpath(report.cwd, chunk.options[:fig_path],
|
||||
"$(report.basename)_$(chunkid)_$(fignum)$ext")
|
||||
rel_name = "$(chunk.options[:fig_path])/$(report.basename)_$(chunkid)_$(fignum)$ext" #Relative path is used in output
|
||||
chunkid = isnothing(chunk.options[:label]) ? chunk.number : chunk.options[:label]
|
||||
basename = string(report.basename, '_', chunkid, '_', fignum, ext)
|
||||
full_name = normpath(report.cwd, chunk.options[:fig_path], basename)
|
||||
rel_name = string(chunk.options[:fig_path], '/', basename) # Relative path is used in output
|
||||
return full_name, rel_name
|
||||
end
|
||||
|
||||
function get_cwd(doc::WeaveDoc, out_path)
|
||||
#Set the output directory
|
||||
if out_path == :doc
|
||||
cwd = doc.path
|
||||
elseif out_path == :pwd
|
||||
cwd = pwd()
|
||||
else
|
||||
#If there is no extension, use as path
|
||||
splitted = splitext(out_path)
|
||||
if splitted[2] == ""
|
||||
cwd = expanduser(out_path)
|
||||
else
|
||||
cwd = splitdir(expanduser(out_path))[1]
|
||||
end
|
||||
end
|
||||
return cwd
|
||||
end
|
||||
|
||||
|
||||
"""Get output file name based on out_path"""
|
||||
function get_outname(out_path::Symbol, doc::WeaveDoc; ext = nothing)
|
||||
ext == nothing && (ext = doc.format.formatdict[:extension])
|
||||
outname = "$(doc.cwd)/$(doc.basename).$ext"
|
||||
end
|
||||
|
||||
|
||||
"""Get output file name based on out_path"""
|
||||
function get_outname(out_path::AbstractString, doc::WeaveDoc; ext = nothing)
|
||||
ext == nothing && (ext = doc.format.formatdict[:extension])
|
||||
splitted = splitext(out_path)
|
||||
if (splitted[2]) == ""
|
||||
outname = "$(doc.cwd)/$(doc.basename).$ext"
|
||||
else
|
||||
outname = expanduser(out_path)
|
||||
end
|
||||
end
|
||||
|
||||
function set_rc_params(doc::WeaveDoc, fig_path, fig_ext)
|
||||
formatdict = doc.format.formatdict
|
||||
if fig_ext == nothing
|
||||
doc.chunk_defaults[:fig_ext] = formatdict[:fig_ext]
|
||||
if isnothing(fig_ext)
|
||||
doc.chunk_defaults[:fig_ext] = doc.format.fig_ext
|
||||
else
|
||||
doc.chunk_defaults[:fig_ext] = fig_ext
|
||||
end
|
||||
doc.chunk_defaults[:fig_path] = fig_path
|
||||
return nothing
|
||||
doc.chunk_defaults[:fig_path] = fig_path
|
||||
end
|
||||
|
||||
function collect_results(chunk::CodeChunk, fmt::ScriptResult)
|
||||
function collect_results(chunk::CodeChunk)
|
||||
content = ""
|
||||
result_no = 1
|
||||
result_chunks = CodeChunk[ ]
|
||||
for r = chunk.result
|
||||
#Check if there is any output from chunk
|
||||
if strip(r.stdout) == "" && isempty(r.figures) && strip(r.rich_output) == ""
|
||||
content *= r.code
|
||||
else
|
||||
content = "\n" * content * r.code
|
||||
rchunk = CodeChunk(content, chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
|
||||
content = ""
|
||||
rchunk.result_no = result_no
|
||||
result_no *=1
|
||||
result_chunks = CodeChunk[]
|
||||
for r in chunk.result
|
||||
content *= r.code
|
||||
# Check if there is any output from chunk
|
||||
if any(!isempty ∘ strip, (r.stdout, r.rich_output)) || !isempty(r.figures)
|
||||
rchunk = CodeChunk(
|
||||
content,
|
||||
chunk.number,
|
||||
chunk.start_line,
|
||||
chunk.optionstring,
|
||||
copy(chunk.options),
|
||||
)
|
||||
rchunk.figures = r.figures
|
||||
rchunk.output = r.stdout * r.displayed
|
||||
rchunk.output = r.stdout
|
||||
rchunk.rich_output = r.rich_output
|
||||
push!(result_chunks, rchunk)
|
||||
content = ""
|
||||
end
|
||||
end
|
||||
if content != ""
|
||||
startswith(content, "\n") || (content = "\n" * content)
|
||||
rchunk = CodeChunk(content, chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
|
||||
if !isempty(content)
|
||||
rchunk = CodeChunk(
|
||||
content,
|
||||
chunk.number,
|
||||
chunk.start_line,
|
||||
chunk.optionstring,
|
||||
copy(chunk.options),
|
||||
)
|
||||
push!(result_chunks, rchunk)
|
||||
end
|
||||
|
||||
return result_chunks
|
||||
end
|
||||
|
||||
function collect_results(chunk::CodeChunk, fmt::TermResult)
|
||||
function collect_term_results(chunk::CodeChunk)
|
||||
output = ""
|
||||
prompt = chunk.options[:prompt]
|
||||
result_no = 1
|
||||
result_chunks = CodeChunk[ ]
|
||||
for r = chunk.result
|
||||
output *= prompt * r.code
|
||||
output *= r.displayed * r.stdout
|
||||
result_chunks = CodeChunk[]
|
||||
for r in chunk.result
|
||||
output *= string('\n', indent_term_code(prompt, r.code), '\n', r.stdout)
|
||||
if !isempty(r.figures)
|
||||
rchunk = CodeChunk("", chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
|
||||
rchunk = CodeChunk(
|
||||
"",
|
||||
chunk.number,
|
||||
chunk.start_line,
|
||||
chunk.optionstring,
|
||||
copy(chunk.options),
|
||||
)
|
||||
rchunk.output = output
|
||||
output = ""
|
||||
rchunk.figures = r.figures
|
||||
push!(result_chunks, rchunk)
|
||||
end
|
||||
end
|
||||
if output != ""
|
||||
rchunk = CodeChunk("", chunk.number, chunk.start_line, chunk.optionstring, copy(chunk.options))
|
||||
rchunk.output = output
|
||||
if !isempty(output)
|
||||
rchunk = CodeChunk(
|
||||
"",
|
||||
chunk.number,
|
||||
chunk.start_line,
|
||||
chunk.optionstring,
|
||||
copy(chunk.options),
|
||||
)
|
||||
rchunk.output = output
|
||||
push!(result_chunks, rchunk)
|
||||
end
|
||||
|
||||
return result_chunks
|
||||
end
|
||||
|
||||
function collect_results(chunk::CodeChunk, fmt::CollectResult)
|
||||
result_no = 1
|
||||
for r =chunk.result
|
||||
chunk.output *= r.stdout
|
||||
function indent_term_code(prompt, code)
|
||||
prompt_with_space = string(prompt, ' ')
|
||||
n = length(prompt_with_space)
|
||||
pads = ' ' ^ n
|
||||
return map(enumerate(split(code, '\n'))) do (i,line)
|
||||
isone(i) ? string(prompt_with_space, line) : string(pads, line)
|
||||
end |> joinlines
|
||||
end
|
||||
|
||||
function collect_hold_results(chunk::CodeChunk)
|
||||
for r in chunk.result
|
||||
chunk.output *= r.stdout
|
||||
chunk.rich_output *= r.rich_output
|
||||
chunk.figures = [chunk.figures; r.figures]
|
||||
end
|
||||
return [chunk]
|
||||
end
|
||||
|
||||
const HEADER_INLINE = Regex("$(HEADER_INLINE_START)(?<code>.+)$(HEADER_INLINE_END)")
|
||||
|
||||
replace_header_inline!(doc, report, mod) = _replace_header_inline!(doc, doc.header, report, mod)
|
||||
|
||||
function _replace_header_inline!(doc, header, report, mod)
|
||||
replace!(header) do (k,v)
|
||||
return k =>
|
||||
v isa Dict ? _replace_header_inline!(doc, v, report, mod) :
|
||||
!isa(v, AbstractString) ? v :
|
||||
replace(v, HEADER_INLINE => s -> begin
|
||||
code = replace(s, HEADER_INLINE => s"\g<code>")
|
||||
run_inline_code(code, doc, report, mod)
|
||||
end)
|
||||
end
|
||||
return header
|
||||
end
|
||||
|
||||
function run_inline_code(code, doc, report, mod)
|
||||
inline = InlineCode(code, 1, :inline)
|
||||
inline = run_inline(inline, doc, report, mod)
|
||||
return strip(inline.output, '"')
|
||||
end
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
# TODO: concreate typing
|
||||
|
||||
abstract type WeaveChunk end
|
||||
abstract type Inline end
|
||||
abstract type WeaveFormat end
|
||||
|
||||
mutable struct WeaveDoc
|
||||
source::AbstractString
|
||||
basename::AbstractString
|
||||
path::AbstractString
|
||||
chunks::Vector{WeaveChunk}
|
||||
cwd::AbstractString
|
||||
format::Any
|
||||
doctype::String
|
||||
header_script::String
|
||||
header::Dict
|
||||
chunk_defaults::Dict{Symbol,Any}
|
||||
end
|
||||
|
||||
struct ChunkOutput
|
||||
code::String
|
||||
stdout::String
|
||||
rich_output::String
|
||||
figures::Vector{String}
|
||||
end
|
||||
|
||||
mutable struct CodeChunk <: WeaveChunk
|
||||
content::String
|
||||
number::Int
|
||||
start_line::Int
|
||||
optionstring::String
|
||||
options::Dict{Symbol,Any}
|
||||
output::AbstractString
|
||||
rich_output::AbstractString
|
||||
figures::Vector{String}
|
||||
result::Vector{ChunkOutput}
|
||||
end
|
||||
|
||||
function CodeChunk(content, number, start_line, optionstring, options)
|
||||
return CodeChunk(
|
||||
string(rstrip(content), '\n'), # normalize end of chunk)
|
||||
number,
|
||||
start_line,
|
||||
optionstring,
|
||||
options,
|
||||
"",
|
||||
"",
|
||||
AbstractString[],
|
||||
ChunkOutput[]
|
||||
)
|
||||
end
|
||||
|
||||
mutable struct DocChunk <: WeaveChunk
|
||||
content::Vector{Inline}
|
||||
number::Int
|
||||
start_line::Int
|
||||
end
|
||||
|
||||
struct InlineText <: Inline
|
||||
content::String
|
||||
number::Int
|
||||
end
|
||||
|
||||
mutable struct InlineCode <: Inline
|
||||
content::String
|
||||
number::Int
|
||||
ctype::Symbol
|
||||
output::String
|
||||
rich_output::String
|
||||
figures::Vector{String}
|
||||
end
|
||||
InlineCode(content, number, ctype) = InlineCode(content, number, ctype, "", "", String[])
|
|
@ -0,0 +1,19 @@
|
|||
function write_doc(docformat::WeaveLaTeX2PDF, doc, rendered, out_path)
|
||||
cd_back = let d = pwd(); () -> cd(d); end
|
||||
cd(doc.cwd)
|
||||
try
|
||||
tex_path = basename(out_path)
|
||||
write(tex_path, rendered)
|
||||
cmds = copy(docformat.latex_cmd)
|
||||
push!(cmds, tex_path)
|
||||
cmd = Cmd(cmds)
|
||||
run(cmd); run(cmd) # XXX: is twice enough for every case ?
|
||||
catch
|
||||
@warn "Error converting document to pdf. Try running latex manually"
|
||||
rethrow()
|
||||
finally
|
||||
cd_back()
|
||||
end
|
||||
|
||||
return get_out_path(doc, out_path, "pdf")
|
||||
end
|
|
@ -0,0 +1,76 @@
|
|||
function write_doc(docformat::Pandoc2HTML, doc, rendered, out_path)
|
||||
_, weave_source = splitdir(abspath(doc.source))
|
||||
weave_version, weave_date = weave_info()
|
||||
|
||||
# Header is inserted from displayed plots
|
||||
header_script = doc.header_script
|
||||
self_contained = (header_script ≠ "") ? [] : "--self-contained"
|
||||
|
||||
if haskey(doc.header, "bibliography")
|
||||
filt = "--filter"
|
||||
citeproc = "pandoc-citeproc"
|
||||
else
|
||||
filt = []
|
||||
citeproc = []
|
||||
end
|
||||
|
||||
out_path = get_out_path(doc, out_path, "html")
|
||||
cd_back = let d = pwd(); () -> cd(d); end
|
||||
cd(dirname(out_path))
|
||||
try
|
||||
out = basename(out_path)
|
||||
highlight_stylesheet = get_highlight_stylesheet(MIME("text/html"), docformat.highlight_theme)
|
||||
cmd = `pandoc -f markdown+raw_html -s --mathjax=""
|
||||
$filt $citeproc $(docformat.pandoc_options)
|
||||
--template $(docformat.template_path)
|
||||
-H $(docformat.stylesheet_path)
|
||||
$(self_contained)
|
||||
-V highlight_stylesheet=$(highlight_stylesheet)
|
||||
-V weave_version=$(weave_version)
|
||||
-V weave_date=$(weave_date)
|
||||
-V weave_source=$(weave_source)
|
||||
-V headerscript=$(header_script)
|
||||
-o $(out)`
|
||||
proc = open(cmd, "r+")
|
||||
println(proc.in, rendered)
|
||||
close(proc.in)
|
||||
proc_output = read(proc.out, String)
|
||||
catch
|
||||
rethrow() # TODO: just show error content instead of rethrow the err
|
||||
finally
|
||||
cd_back()
|
||||
end
|
||||
|
||||
return out_path
|
||||
end
|
||||
|
||||
function write_doc(docformat::Pandoc2PDF, doc, rendered, out_path)
|
||||
if haskey(doc.header, "bibliography")
|
||||
filt = "--filter"
|
||||
citeproc = "pandoc-citeproc"
|
||||
else
|
||||
filt = []
|
||||
citeproc = []
|
||||
end
|
||||
|
||||
out_path = get_out_path(doc, out_path, "pdf")
|
||||
cd_back = let d = pwd(); () -> cd(d); end
|
||||
cd(dirname(out_path))
|
||||
try
|
||||
out = basename(out_path)
|
||||
cmd = `pandoc -f markdown+raw_tex -s --pdf-engine=xelatex --highlight-style=tango
|
||||
$filt $citeproc $(docformat.pandoc_options)
|
||||
--include-in-header=$(docformat.header_template)
|
||||
-V fontsize=12pt -o $(out)`
|
||||
proc = open(cmd, "r+")
|
||||
println(proc.in, rendered)
|
||||
close(proc.in)
|
||||
proc_output = read(proc.out, String)
|
||||
catch
|
||||
rethrow()
|
||||
finally
|
||||
cd_back()
|
||||
end
|
||||
|
||||
return out_path
|
||||
end
|
|
@ -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")
|
179
src/writers.jl
179
src/writers.jl
|
@ -1,179 +0,0 @@
|
|||
import JSON
|
||||
import Mustache
|
||||
|
||||
mutable struct NotebookOutput
|
||||
end
|
||||
|
||||
mutable struct MarkdownOutput
|
||||
end
|
||||
|
||||
mutable struct NowebOutput
|
||||
end
|
||||
|
||||
mutable struct ScriptOutput
|
||||
end
|
||||
|
||||
const output_formats = Dict{String, Any}(
|
||||
"noweb" => NowebOutput(),
|
||||
"notebook" => NotebookOutput(),
|
||||
"markdown" => MarkdownOutput(),
|
||||
"script" => ScriptOutput()
|
||||
)
|
||||
|
||||
"""Autodetect format for converter"""
|
||||
function detect_outformat(outfile::String)
|
||||
ext = lowercase(splitext(outfile)[2])
|
||||
|
||||
ext == ".jl" && return "script"
|
||||
ext == ".jmd" && return "markdown"
|
||||
ext == ".ipynb" && return "notebook"
|
||||
return "noweb"
|
||||
end
|
||||
|
||||
"""
|
||||
`convert_doc(infile::AbstractString, outfile::AbstractString; format = nothing)`
|
||||
|
||||
Convert Weave documents between different formats
|
||||
|
||||
* `infile` = Name of the input document
|
||||
* `outfile` = Name of the output document
|
||||
* `format` = Output format (optional). Detected from outfile extension, but can
|
||||
be set to `"script"`, `"markdown"`, `"notebook"` or `"noweb"`.
|
||||
"""
|
||||
function convert_doc(infile::AbstractString, outfile::AbstractString; format = nothing)
|
||||
doc = read_doc(infile)
|
||||
|
||||
if format == nothing
|
||||
format = detect_outformat(outfile)
|
||||
end
|
||||
|
||||
converted = convert_doc(doc, output_formats[format])
|
||||
|
||||
open(outfile, "w") do f
|
||||
write(f, converted)
|
||||
end
|
||||
|
||||
return nothing
|
||||
end
|
||||
|
||||
"""Convert Weave document to Jupyter notebook format"""
|
||||
function convert_doc(doc::WeaveDoc, format::NotebookOutput)
|
||||
nb = Dict()
|
||||
nb["nbformat"] = 4
|
||||
nb["nbformat_minor"] = 2
|
||||
metadata = Dict()
|
||||
kernelspec = Dict()
|
||||
kernelspec["language"] = "julia"
|
||||
kernelspec["name"] = "julia-$(VERSION.major).$(VERSION.minor)"
|
||||
kernelspec["display_name"] = "Julia $(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
|
||||
metadata["kernelspec"] = kernelspec
|
||||
language_info = Dict()
|
||||
language_info["file_extension"] = ".jl"
|
||||
language_info["mimetype"] = "application/julia"
|
||||
language_info["name"]= "julia"
|
||||
language_info["version"] = "$(VERSION.major).$(VERSION.minor).$(VERSION.patch)"
|
||||
metadata["language_info"] = language_info
|
||||
cells = []
|
||||
ex_count = 1
|
||||
|
||||
# Handle header
|
||||
head_tpl = """
|
||||
{{#:title}}# {{:title}}{{/:title}}
|
||||
{{#:author}}### {{{:author}}}{{/:author}}
|
||||
{{#:date}}### {{{:date}}}{{/:date}}
|
||||
"""
|
||||
|
||||
if isa(doc.chunks[1], DocChunk)
|
||||
doc.chunks[1] = strip_header(doc.chunks[1])
|
||||
doc.chunks[1].content[1].content = Mustache.render(head_tpl;
|
||||
[Pair(Symbol(k), v) for (k,v) in doc.header]...) * doc.chunks[1].content[1].content
|
||||
end
|
||||
|
||||
for chunk in doc.chunks
|
||||
|
||||
if isa(chunk, DocChunk)
|
||||
push!(cells,
|
||||
Dict("cell_type" => "markdown",
|
||||
"metadata" => Dict(),
|
||||
"source" => [strip(join([repr(c) for c in chunk.content], ""))])
|
||||
)
|
||||
elseif haskey(chunk.options, :skip) && chunk.options[:skip] == "notebook"
|
||||
continue
|
||||
else
|
||||
push!(cells,
|
||||
Dict("cell_type" => "code",
|
||||
"metadata" => Dict(),
|
||||
"source" => [strip(chunk.content)],
|
||||
"execution_count" => nothing,
|
||||
"outputs" => []
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
nb["cells"] = cells
|
||||
nb["metadata"] = metadata
|
||||
|
||||
json_nb = JSON.json(nb, 2)
|
||||
return json_nb
|
||||
end
|
||||
|
||||
"""Convert Weave document to Jupyter notebook format"""
|
||||
function convert_doc(doc::WeaveDoc, format::MarkdownOutput)
|
||||
output = ""
|
||||
for chunk in doc.chunks
|
||||
if isa(chunk, DocChunk)
|
||||
output *= join([repr(c) for c in chunk.content], "")
|
||||
else
|
||||
output *= "\n" * "```julia"
|
||||
isempty(chunk.optionstring) || (output *= ";" * chunk.optionstring)
|
||||
output *= "\n" * lstrip(chunk.content)
|
||||
output *= "```\n"
|
||||
end
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
"""Convert Weave document to noweb format"""
|
||||
function convert_doc(doc::WeaveDoc, format::NowebOutput)
|
||||
output = ""
|
||||
for chunk in doc.chunks
|
||||
if isa(chunk, DocChunk)
|
||||
output *= join([repr(c) for c in chunk.content], "")
|
||||
else
|
||||
output *= "\n" * "<<"
|
||||
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
|
||||
output *= ">>="
|
||||
output *= "\n" * lstrip(chunk.content)
|
||||
output *= "@\n"
|
||||
end
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
"""Convert Weave document to script format"""
|
||||
function convert_doc(doc::WeaveDoc, format::ScriptOutput)
|
||||
output = ""
|
||||
for chunk in doc.chunks
|
||||
if typeof(chunk) == Weave.DocChunk
|
||||
content = join([repr(c) for c in chunk.content], "")
|
||||
output *= join(["#' " * s for s in split(content, "\n")], "\n")
|
||||
else
|
||||
output *= "\n#+ "
|
||||
isempty(chunk.optionstring) || (output *= strip(chunk.optionstring))
|
||||
output *= "\n\n" * lstrip(chunk.content)
|
||||
output *= "\n"
|
||||
end
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
function Base.repr(c::InlineText)
|
||||
return c.content
|
||||
end
|
||||
|
||||
function Base.repr(c::InlineCode)
|
||||
return "`j $(c.content)`"
|
||||
end
|
|
@ -1,54 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<HTML lang = "en">
|
||||
<HEAD>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
{{#:title}}<title>{{:title}}</title>{{/:title}}
|
||||
{{{ :header_script }}}
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]},
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" } }
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
{{{ :highlightcss }}}
|
||||
|
||||
<style type="text/css">
|
||||
{{{ :themecss }}}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<div class ="container">
|
||||
<div class = "row">
|
||||
<div class = "col-md-12 twelve columns">
|
||||
|
||||
<div class="title">
|
||||
{{#:title}}<h1 class="title">{{:title}}</h1>{{/:title}}
|
||||
{{#:author}}<h5>{{{:author}}}</h5>{{/:author}}
|
||||
{{#:date}}<h5>{{{:date}}}</h5>{{/:date}}
|
||||
</div>
|
||||
|
||||
{{{ :body }}}
|
||||
|
||||
|
||||
<HR/>
|
||||
<div class="footer"><p>
|
||||
Published from <a href="{{{:source}}}">{{{:source}}}</a> using
|
||||
<a href="http://github.com/mpastell/Weave.jl">Weave.jl</a>
|
||||
{{:wversion}} on {{:wtime}}.
|
||||
<p></div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<HTML lang = "en">
|
||||
<HEAD>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
{{#:title}}<title>{{:title}}</title>{{/:title}}
|
||||
{{{ :header_script }}}
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]},
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" } }
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
{{{ :highlight_stylesheet }}}
|
||||
|
||||
<style type="text/css">
|
||||
{{{ :stylesheet }}}
|
||||
</style>
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
<div class ="container">
|
||||
<div class = "row">
|
||||
<div class = "col-md-12 twelve columns">
|
||||
<div class="title">
|
||||
{{#:title}}<h1 class="title">{{:title}}</h1>{{/:title}}
|
||||
{{#:author}}<h5>{{{:author}}}</h5>{{/:author}}
|
||||
{{#:date}}<h5>{{{:date}}}</h5>{{/:date}}
|
||||
</div>
|
||||
|
||||
{{{ :body }}}
|
||||
|
||||
<HR/>
|
||||
<div class="footer">
|
||||
<p>
|
||||
Published from <a href="{{{:weave_source}}}">{{{:weave_source}}}</a>
|
||||
using <a href="http://github.com/JunoLab/Weave.jl">Weave.jl</a> {{:weave_version}} on {{:weave_date}}.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
|
@ -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 $wtime$.
|
||||
Published from <a href="$source$">$source$</a> using
|
||||
<a href="http://github.com/mpastell/Weave.jl">Weave.jl</a> $weave_version$ on $weave_date$.
|
||||
<p></div>
|
||||
|
||||
</div>
|
|
@ -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,18 +0,0 @@
|
|||
using Weave
|
||||
using Test
|
||||
|
||||
cleanup = true
|
||||
|
||||
#Test hold and term options
|
||||
weave("documents/test_hold.mdw", doctype="pandoc", plotlib="Gadfly")
|
||||
result = read("documents/test_hold.md", String)
|
||||
ref = read("documents/test_hold_ref.md", String)
|
||||
@test result == ref
|
||||
cleanup && rm("documents/test_hold.md")
|
||||
|
||||
#Test setting and restoring chunk options
|
||||
Weave.weave("documents/default_opts.noweb", doctype = "tex")
|
||||
result = read("documents/default_opts.tex", String)
|
||||
ref = read("documents/default_opts_ref.tex", String)
|
||||
@test result == ref
|
||||
cleanup && rm("documents/default_opts.tex")
|
|
@ -1,80 +0,0 @@
|
|||
#' % FIR filter design with Julia
|
||||
#' % Matti Pastell
|
||||
#' % 21th April 2016
|
||||
|
||||
#' # Introduction
|
||||
|
||||
#' This an example of a julia script that can be published using
|
||||
#' [Weave](http://mpastell.github.io/Weave.jl/latest/usage/).
|
||||
#' The script can be executed normally using Julia
|
||||
#' or published to HTML or pdf with Weave.
|
||||
#' Text is written in markdown in lines starting with "`#'` " and code
|
||||
#' is executed and results are included in the published document.
|
||||
|
||||
#' Notice that you don't need to define chunk options, but you can using
|
||||
#' `#+`. just before code e.g. `#+ term=True, caption='Fancy plots.'`.
|
||||
#' If you're viewing the published version have a look at the
|
||||
#' [source](FIR_design.jl) to see the markup.
|
||||
|
||||
|
||||
#' # FIR Filter Design
|
||||
|
||||
#' We'll implement lowpass, highpass and ' bandpass FIR filters. If
|
||||
#' you want to read more about DSP I highly recommend [The Scientist
|
||||
#' and Engineer's Guide to Digital Signal
|
||||
#' Processing](http://www.dspguide.com/) which is freely available
|
||||
#' online.
|
||||
|
||||
#' ## Calculating frequency response
|
||||
|
||||
#' DSP.jl package doesn't (yet) have a method to calculate the
|
||||
#' the frequency response of a FIR filter so we define it:
|
||||
|
||||
using Gadfly, DSP
|
||||
|
||||
function FIRfreqz(b::Array, w = range(0, stop=π, length=1024))
|
||||
n = length(w)
|
||||
h = Array{ComplexF32}(n)
|
||||
sw = 0
|
||||
for i = 1:n
|
||||
for j = 1:length(b)
|
||||
sw += b[j]*exp(-im*w[i])^-j
|
||||
end
|
||||
h[i] = sw
|
||||
sw = 0
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
|
||||
#' ## Design Lowpass FIR filter
|
||||
|
||||
#' Designing a lowpass FIR filter is very simple to do with DSP.jl, all you
|
||||
#' need to do is to define the window length, cut off frequency and the
|
||||
#' window. We will define a lowpass filter with cut off frequency at 5Hz for a signal
|
||||
#' sampled at 20 Hz.
|
||||
#' We will use the Hamming window, which is defined as:
|
||||
#' $w(n) = \alpha - \beta\cos\frac{2\pi n}{N-1}$, where $\alpha=0.54$ and $\beta=0.46$
|
||||
|
||||
|
||||
fs = 20
|
||||
f = digitalfilter(Lowpass(5, fs = fs), FIRWindow(hamming(61)))
|
||||
w = range(0, stop=pi, length=1024)
|
||||
h = FIRfreqz(f, w)
|
||||
|
||||
#' ## Plot the frequency and impulse response
|
||||
|
||||
h_db = log10(abs(h))
|
||||
ws = w/pi*(fs/2)
|
||||
|
||||
#' The next code chunk is executed in term mode, see the [script](FIR_design.jl) for syntax.
|
||||
#+ term=true
|
||||
|
||||
plot(y = h_db, x = ws, Geom.line,
|
||||
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Magnitude (db)"))
|
||||
|
||||
#' And again with default options
|
||||
|
||||
h_phase = unwrap(-atan(imag(h),real(h)))
|
||||
plot(y = h_phase, x = ws, Geom.line,
|
||||
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Phase (radians)"))
|
|
@ -1,112 +0,0 @@
|
|||
% FIR filter design with Julia
|
||||
% Matti Pastell
|
||||
% 21th April 2016
|
||||
|
||||
# Introduction
|
||||
|
||||
This an example of a julia script that can be published using
|
||||
[Weave](http://mpastell.github.io/Weave.jl/latest/usage/).
|
||||
The script can be executed normally using Julia
|
||||
or published to HTML or pdf with Weave.
|
||||
Text is written in markdown in lines starting with "`#'` " and code
|
||||
is executed and results are included in the published document.
|
||||
|
||||
Notice that you don't need to define chunk options, but you can using
|
||||
`#+`. just before code e.g. `#+ term=True, caption='Fancy plots.'`.
|
||||
If you're viewing the published version have a look at the
|
||||
[source](FIR_design.jl) to see the markup.
|
||||
|
||||
|
||||
# FIR Filter Design
|
||||
|
||||
We'll implement lowpass, highpass and ' bandpass FIR filters. If
|
||||
you want to read more about DSP I highly recommend [The Scientist
|
||||
and Engineer's Guide to Digital Signal
|
||||
Processing](http://www.dspguide.com/) which is freely available
|
||||
online.
|
||||
|
||||
## Calculating frequency response
|
||||
|
||||
DSP.jl package doesn't (yet) have a method to calculate the
|
||||
the frequency response of a FIR filter so we define it:
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
using Gadfly, DSP
|
||||
|
||||
function FIRfreqz(b::Array, w = linspace(0, π, 1024))
|
||||
n = length(w)
|
||||
h = Array{Complex64}(n)
|
||||
sw = 0
|
||||
for i = 1:n
|
||||
for j = 1:length(b)
|
||||
sw += b[j]*exp(-im*w[i])^-j
|
||||
end
|
||||
h[i] = sw
|
||||
sw = 0
|
||||
end
|
||||
return h
|
||||
end
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
|
||||
## Design Lowpass FIR filter
|
||||
|
||||
Designing a lowpass FIR filter is very simple to do with DSP.jl, all you
|
||||
need to do is to define the window length, cut off frequency and the
|
||||
window. We will define a lowpass filter with cut off frequency at 5Hz for a signal
|
||||
sampled at 20 Hz.
|
||||
We will use the Hamming window, which is defined as:
|
||||
$w(n) = \alpha - \beta\cos\frac{2\pi n}{N-1}$, where $\alpha=0.54$ and $\beta=0.46$
|
||||
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
fs = 20
|
||||
f = digitalfilter(Lowpass(5, fs = fs), FIRWindow(hamming(61)))
|
||||
w = linspace(0, pi, 1024)
|
||||
h = FIRfreqz(f, w)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
|
||||
## Plot the frequency and impulse response
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
h_db = log10(abs(h))
|
||||
ws = w/pi*(fs/2)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
|
||||
The next code chunk is executed in term mode, see the [script](FIR_design.jl) for syntax.
|
||||
|
||||
~~~~{.julia}
|
||||
julia> plot(y = h_db, x = ws, Geom.line,
|
||||
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Magnitude (db)"))
|
||||
Plot(...)
|
||||
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/FIR_design_4_1.png)\
|
||||
|
||||
|
||||
|
||||
And again with default options
|
||||
|
||||
|
||||
~~~~{.julia}
|
||||
h_phase = unwrap(-atan2(imag(h),real(h)))
|
||||
plot(y = h_phase, x = ws, Geom.line,
|
||||
Guide.xlabel("Frequency (Hz)"), Guide.ylabel("Phase (radians)"))
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/FIR_design_5_1.png)\
|
||||
|
|
@ -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,30 +0,0 @@
|
|||
|
||||
|
||||
<<>>=
|
||||
using Gadfly
|
||||
print(1:10)
|
||||
plot(x = 1:10)
|
||||
@
|
||||
|
||||
<<>>=
|
||||
import Weave
|
||||
Weave.set_chunk_defaults(Dict{Symbol, Any}(
|
||||
:out_width => "\\0.5linewidth",
|
||||
:results => "tex"
|
||||
))
|
||||
@
|
||||
|
||||
<<>>=
|
||||
print(1:10)
|
||||
plot(x = 1:10)
|
||||
@
|
||||
|
||||
|
||||
<<echo = false>>=
|
||||
Weave.restore_chunk_defaults()
|
||||
@
|
||||
|
||||
<<>>=
|
||||
print(1:10)
|
||||
plot(x = 1:10)
|
||||
@
|
|
@ -1,43 +0,0 @@
|
|||
\begin{juliacode}
|
||||
using Gadfly
|
||||
print(1:10)
|
||||
\end{juliacode}
|
||||
\begin{juliaout}
|
||||
1:10
|
||||
\end{juliaout}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x = 1:10)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=\linewidth]{figures/default_opts_1_1.pdf}
|
||||
|
||||
\begin{juliacode}
|
||||
import Weave
|
||||
Weave.set_chunk_defaults(Dict{Symbol, Any}(
|
||||
:out_width => "\\0.5linewidth",
|
||||
:results => "tex"
|
||||
))
|
||||
\end{juliacode}
|
||||
|
||||
\begin{juliacode}
|
||||
print(1:10)
|
||||
\end{juliacode}
|
||||
1:10
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x = 1:10)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=\0.5linewidth]{figures/default_opts_3_1.pdf}
|
||||
|
||||
|
||||
\begin{juliacode}
|
||||
print(1:10)
|
||||
\end{juliacode}
|
||||
\begin{juliaout}
|
||||
1:10
|
||||
\end{juliaout}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x = 1:10)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=\linewidth]{figures/default_opts_5_1.pdf}
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
options :
|
||||
out_path : gadfly
|
||||
---
|
||||
|
||||
~~~~{.julia}
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.js.svg){#fig:sin_fun}
|
||||
|
||||
![cos(x) function.](figures/gadfly_formats_test_2_1.js.svg)
|
||||
|
||||
~~~~{.julia}
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/gadfly_formats_test_cos2_fun_1.js.svg){width=15cm #fig:cos2_fun}\
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
````julia
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
````
|
||||
|
||||
|
||||
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.pdf)
|
||||
|
||||
![cos(x) function.](figures/gadfly_formats_test_2_1.pdf)
|
||||
|
||||
````julia
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
````
|
||||
|
||||
|
||||
![](figures/gadfly_formats_test_cos2_fun_1.pdf)
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
````julia
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
````
|
||||
|
||||
|
||||
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.png)
|
||||
|
||||
![cos(x) function.](figures/gadfly_formats_test_2_1.png)
|
||||
|
||||
````julia
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
````
|
||||
|
||||
|
||||
![](figures/gadfly_formats_test_cos2_fun_1.png)
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
options :
|
||||
out_path : gadfly
|
||||
---
|
||||
|
||||
~~~~{.julia}
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.png){#fig:sin_fun}
|
||||
|
||||
![cos(x) function.](figures/gadfly_formats_test_2_1.png)
|
||||
|
||||
~~~~{.julia}
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
![](figures/gadfly_formats_test_cos2_fun_1.png){width=15cm #fig:cos2_fun}\
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
````julia
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
````
|
||||
|
||||
|
||||
![sin(x) function.](figures/gadfly_formats_test_sin_fun_1.svg)
|
||||
|
||||
![cos(x) function.](figures/gadfly_formats_test_2_1.svg)
|
||||
|
||||
````julia
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
````
|
||||
|
||||
|
||||
![](figures/gadfly_formats_test_cos2_fun_1.svg)
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
\begin{juliacode}
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
\end{juliacode}
|
||||
\begin{figure}[ht]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_sin_fun_1.pdf}
|
||||
\caption{sin(x) function.}
|
||||
\label{fig:sin_fun}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[htpb]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_2_1.pdf}
|
||||
\caption{cos(x) function.}
|
||||
\end{figure}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=15cm]{figures/gadfly_formats_test_cos2_fun_1.pdf}
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
\begin{juliacode}
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
\end{juliacode}
|
||||
\begin{figure}[ht]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_sin_fun_1.png}
|
||||
\caption{sin(x) function.}
|
||||
\label{fig:sin_fun}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[htpb]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_2_1.png}
|
||||
\caption{cos(x) function.}
|
||||
\end{figure}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=15cm]{figures/gadfly_formats_test_cos2_fun_1.png}
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
\begin{juliacode}
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
\end{juliacode}
|
||||
\begin{figure}[ht]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_sin_fun_1.ps}
|
||||
\caption{sin(x) function.}
|
||||
\label{fig:sin_fun}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[htpb]
|
||||
\center
|
||||
\includegraphics[width=\linewidth]{figures/gadfly_formats_test_2_1.ps}
|
||||
\caption{cos(x) function.}
|
||||
\end{figure}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
\end{juliacode}
|
||||
\includegraphics[width=15cm]{figures/gadfly_formats_test_cos2_fun_1.ps}
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
\begin{juliacode}
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
\end{juliacode}
|
||||
\begin{figure}[ht]
|
||||
\center
|
||||
\resizebox{\linewidth}{!}{\input{figures/gadfly_formats_test_sin_fun_1.tex}}
|
||||
\caption{sin(x) function.}
|
||||
\label{fig:sin_fun}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[htpb]
|
||||
\center
|
||||
\resizebox{\linewidth}{!}{\input{figures/gadfly_formats_test_2_1.tex}}
|
||||
\caption{cos(x) function.}
|
||||
\end{figure}
|
||||
|
||||
\begin{juliacode}
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
\end{juliacode}
|
||||
\resizebox{15cm}{!}{\input{figures/gadfly_formats_test_cos2_fun_1.tex}}
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
options :
|
||||
out_path : gadfly
|
||||
---
|
||||
|
||||
<<fig_cap="sin(x) function."; label="sin_fun"; fig_pos="ht">>=
|
||||
using Gadfly
|
||||
x = range(0, stop =2π, step=0.05)
|
||||
plot(x=x, y = sin.(x), Geom.line)
|
||||
@
|
||||
|
||||
|
||||
<<echo=false; fig_cap="cos(x) function."; dpi=200>>=
|
||||
plot(x=x, y = cos.(x), Geom.line)
|
||||
@
|
||||
|
||||
<<label="cos2_fun"; out_width="15cm">>=
|
||||
plot(x=x, y = cos.(2x), Geom.line)
|
||||
@
|
|
@ -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,12 +0,0 @@
|
|||
---
|
||||
options:
|
||||
md2html :
|
||||
out_path : html
|
||||
echo : false
|
||||
out_width : 30%
|
||||
---
|
||||
|
||||
|
||||
```julia
|
||||
repeat("🐐", 10)
|
||||
```
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
title : Someheader
|
||||
---
|
||||
|
||||
```julia
|
||||
module Test1
|
||||
|
||||
x = 10
|
||||
y = 20
|
||||
|
||||
function testing(x)
|
||||
return x
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
Some random text in between
|
||||
|
||||
```julia
|
||||
module Test2
|
||||
|
||||
d = Dict("a" => "α")
|
||||
doc = read("header_test.jmd", String)
|
||||
|
||||
end
|
||||
```
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
<div class="Random plot">
|
||||
|
||||
<p>Some inline output</p>
|
||||
|
||||
|
||||
<pre class='hljl'>
|
||||
<span class='hljl-nf'>println</span><span class='hljl-p'>(</span><span class='hljl-s'>"Testing output"</span><span class='hljl-p'>)</span>
|
||||
</pre>
|
||||
|
||||
|
||||
<pre class="output">
|
||||
Testing output
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
\begin{frame}[fragile]
|
||||
\frametitle{Random plot}
|
||||
|
||||
Some inline output
|
||||
|
||||
|
||||
\begin{lstlisting}
|
||||
(*@\HLJLnf{println}@*)(*@\HLJLp{(}@*)(*@\HLJLs{"{}Testing}@*) (*@\HLJLs{output"{}}@*)(*@\HLJLp{)}@*)
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{lstlisting}
|
||||
Testing output
|
||||
\end{lstlisting}
|
||||
|
||||
|
||||
|
||||
|
||||
\end{frame}
|
||||
|
|
@ -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
|
||||
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,56 +0,0 @@
|
|||
[source,julia]
|
||||
--------------------------------------
|
||||
using Gadfly
|
||||
x = linspace(0, 2π, 200)
|
||||
plot(x=x, y = sin(x), Geom.line)
|
||||
--------------------------------------
|
||||
|
||||
|
||||
image::figures/gadfly_formats_test_sin_fun_1.png[width=600,title="sin(x) function."]
|
||||
image::figures/gadfly_formats_test_2_1.png[width=600,title="cos(x) function."]
|
||||
image::figures/gadfly_formats_test_cos2_fun_1.png[width=600]
|
||||
|
||||
[source,julia]
|
||||
--------------------------------------
|
||||
julia> x = linspace(0, 2π, 200)
|
||||
200-element LinSpace{Float64}:
|
||||
0.0,0.0315738,0.0631476,0.0947214,0.126295,…,6.18846,6.22004,6.25161,6.28319
|
||||
|
||||
julia> plot(x=x, y = sin(x), Geom.line)
|
||||
Plot(...)
|
||||
|
||||
--------------------------------------
|
||||
|
||||
|
||||
image::figures/gadfly_formats_test_4_1.png[width=600]
|
||||
|
||||
[source,julia]
|
||||
--------------------------------------
|
||||
julia> y = 20
|
||||
20
|
||||
|
||||
julia> plot(x=x, y = cos(x), Geom.line)
|
||||
Plot(...)
|
||||
|
||||
--------------------------------------
|
||||
|
||||
|
||||
image::figures/gadfly_formats_test_4_2.png[width=600]
|
||||
|
||||
[source,julia]
|
||||
--------------------------------------
|
||||
x = linspace(0, 2π, 200)
|
||||
plot(x=x, y = sin(x), Geom.line)
|
||||
--------------------------------------
|
||||
|
||||
|
||||
image::figures/gadfly_formats_test_5_1.png[width=15cm]
|
||||
|
||||
[source,julia]
|
||||
--------------------------------------
|
||||
y = 20
|
||||
plot(x=x, y = cos(x), Geom.line)
|
||||
--------------------------------------
|
||||
|
||||
|
||||
image::figures/gadfly_formats_test_5_2.png[width=15cm]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue