packages feed

pandoc-plot 1.7.0 → 1.8.0

raw patch · 47 files changed

+7336/−7228 lines, 47 filessetup-changedPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Text.Pandoc.Filter.Plot: Asymptote :: Toolkit
+ Text.Pandoc.Filter.Plot: [asyCmdArgs] :: Configuration -> !Text
+ Text.Pandoc.Filter.Plot: [asyExe] :: Configuration -> !FilePath
+ Text.Pandoc.Filter.Plot: [asyPreamble] :: Configuration -> !Script
+ Text.Pandoc.Filter.Plot.Internal: Asymptote :: Toolkit
+ Text.Pandoc.Filter.Plot.Internal: [asyCmdArgs] :: Configuration -> !Text
+ Text.Pandoc.Filter.Plot.Internal: [asyExe] :: Configuration -> !FilePath
+ Text.Pandoc.Filter.Plot.Internal: [asyPreamble] :: Configuration -> !Script
- Text.Pandoc.Filter.Plot: Configuration :: !FilePath -> !Bool -> !Int -> !SaveFormat -> ![FilePath] -> !Format -> !Text -> !Bool -> !Verbosity -> !LogSink -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Bool -> !Bool -> Configuration
+ Text.Pandoc.Filter.Plot: Configuration :: !FilePath -> !Bool -> !Int -> !SaveFormat -> ![FilePath] -> !Format -> !Text -> !Bool -> !Verbosity -> !LogSink -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Bool -> !Bool -> Configuration
- Text.Pandoc.Filter.Plot.Internal: Configuration :: !FilePath -> !Bool -> !Int -> !SaveFormat -> ![FilePath] -> !Format -> !Text -> !Bool -> !Verbosity -> !LogSink -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Bool -> !Bool -> Configuration
+ Text.Pandoc.Filter.Plot.Internal: Configuration :: !FilePath -> !Bool -> !Int -> !SaveFormat -> ![FilePath] -> !Format -> !Text -> !Bool -> !Verbosity -> !LogSink -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !Script -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !FilePath -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Text -> !Bool -> !Bool -> Configuration

Files

CHANGELOG.md view
@@ -1,346 +1,350 @@-# Change log--pandoc-plot uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html)--## Release 1.7.0--* Added support for the declarative diagram language [D2](https://d2lang.com/), thanks to a contribution by Sanchayan Maity (#60).-* Added support for `optparse-applicative` v0.18.--## Release 1.6.2--* Fixed some imports which were removed in `mtl-2.3`.--## Release 1.6.1--* Fixed an issue where figure attributes were lost, which prevent other filters (e.g. pandoc-crossref) from working in conjunction with pandoc-plot.--## Release 1.6.0--* Support for pandoc 3. Support for older pandoc version has also been dropped (pandoc 2.19 and earlier).--## Release 1.5.5--* Fixed an issue where there was a race condition when rendering multiple identical figures (#53).--## Release 1.5.4--* Fixed an issue where graphviz plots in vector format were cropped when a DPI was specified (#40).--## Release 1.5.3--* Fixed an issue where the `tight_bbox` option for Matplotlib plots was ignored (#48).--## Release 1.5.2--* Overhauled the way executables are handled. This fixes an issue where executables specified in documents (rather than configuration) were ignored (#46).--## Release 1.5.1--* Figures with no captions (and no link to the source script), will now be shown as an image, without figure numbering (#37).--## Release 1.5.0--* Added support for [Sage](https://www.sagemath.org/) (#44).-* Fixed an issue where the parsing of default save format from configuration was overly restrictive (#42).-* Linux and Windows executables now built with GHC 9.2.--## Release 1.4.1--* Don't automatically defer javascript scripts when creating interactive figures (#39).--## Release 1.4.0--* The executable `pandoc-plot` now uses pandoc 2.17. Pandoc 2.11+ are still supported.-* Added support for `aeson` 2+.--## Release 1.3.0--* The executable `pandoc-plot` is now aware of final conversion format.-* Added a new function, `plotFilter`, which is aware of the pandoc's final conversion format. This allows for better defaults and error messages.-* Deprecated `plotTransform` in favour of `plotFilter`. `plotTransform` will be removed in the next major update (v2+).-* Save formats incompatible with toolkits will now show an appropriate error.-* The build system is now based on `cabal-install` rather than `stack`.-* Fixed an issue where some types of PlantUML diagrams (e.g. Gantt charts) would not be exported correctly (#30).--## Release 1.2.3--* Fixed an issue where MATLAB figures were not being saved in the right location (#27).-* Releases are now completely taken care of via Github actions.--## Release 1.2.2--* Executables are now built using GHC 9.0.1-* The executables are now built with Pandoc 2.14. Pandoc 2.11, 2.12, and 2.13 are still supported.--## Release 1.2.1--* Added the ability to save plots as LaTeX directly from the GNUplot toolkit. To do this, simply set the output format to `latex`. The figure content will be embedded in the output document, which only makes sense for final conversion to LaTeX. For example:--  ````markdown-    ```{.gnuplot format=latex caption="This is a test."}-    ...-    ```-  ````-  This patch was contributed by Saku Laesvuori.--## Release 1.2.0--* Fixed an issue where code blocks nested in other structures were detected properly. For example, in the following LaTeX snippet, plots would not be detected properly:-```latex-\begin{column}-  \begin{minted}[]{matplotlib}-  ...-  \end{minted}-\end{column}-```-Nested figures are not correctly identified.--* The executables are now built with Pandoc 2.13. Pandoc 2.11 and Pandoc 2.12 are still supported.--## Release 1.1.1--* Error messages now include the source script and line numbers.-* The executables are now built with Pandoc 2.12. Pandoc 2.11 is still supported.--## Release 1.1.0--* Added the [PlantUML](https://plantuml.com) toolkit (#18). Diagrams can be generated like so:--  ````markdown--  ```{.plantuml}-  @startuml-  Bob->Alice : hello-  @enduml-  ```--  ````-* Changed versioning scheme to match more common Major.Minor.Bugfix.--## Release 1.0.2.1--* `pandoc-plot` will now only render at most `N` figures in parallel, where `N` is the number of available CPU cores.-* Fixed an issue where error message would get mangled in strict-mode.--## Release 1.0.2.0--* Added the ability to run `pandoc-plot` in **strict mode**. By default, `pandoc-plot` leaves code blocks unchanged if a figure fails to be rendered.  In strict mode, `pandoc-plot` will immediately halt if it encounters a problem, such as a missing toolkit. You can activate strict mode via configuration:--```yaml-strict: true-```--* Added the ability to set command-line arguments for interpreters via configuration. For example, if you want to run the Matplotlib toolkit with all warnings shown:--```yaml-# Possible parameters for the Matplotlib toolkit-matplotlib:-  executable: python-  command_line_arguments: -Wa-```--Or if you want `julia` to use more than one thread:--```yaml-# Possible parameters for the Plotsjl toolkit-plotsjl:-  executable: julia-  command_line_arguments: --threads auto --optimize=0-```--* Fixed an issue where invoking the `plotsjl` toolkit on Windows would sometimes fail with the error: Unknown system error 50.-* Fixed an issue with R-based toolkits on Windows not being detected properly.--## Release 1.0.1.0--* Added the ability to change the "Source code" label to other languages via configuration.-* Added syntax highlighting to the linked source code.-* Fixed an issue where code blocks with unicode symbols (e.g. greek letters) would trip up pandoc-plot (#16).--## Release 1.0.0.0--* Added support for Pandoc 2.11. Unfortunately, there is no way to support prior versions of Pandoc at the same time.-* With release 1.0.0.0, `pandoc-plot` has stabilized. The Haskell library API will not change until version 2+. --## Release 0.9.4.0--* Fixed an issue where the current working directory was changed. This prevented users from referring to files in scripts with relative paths (#2).--## Release 0.9.3.0--* Added executable caching: repeated usage of a particular toolkit will be faster because executables are only looked-for once.-* Reverting the change from 0.8.1.0: internal machinery of `pandoc-plot` has been moved to the `Text.Pandoc.Filter.Plot.Internal` module, where there is no guarantee of backwards-compatibility after 1.0.0.-* Removed the `makePlot` function, which could not take advantage of multithreading and other key features of `pandoc-plot`.-* Fixed an issue where files required for tests were missing from source tarballs (#13).--## Release 0.9.2.0--* Fixed an issue where executables located on paths with spaces would not be invoked correctly (#12).-* Fixed an issue where R-paths were not normalized correctly.-* Fixed an issue where executables specified in configuration that did not exist would crash `pandoc-plot`.-* Fixed an issue where some R-based toolkits appeared to be available, but were not.--## Release 0.9.1.0--* Added the `file` parameter, which allows the user to read figure content from a file instead of using the code block content in documents. This is especially useful for complex figures, where you might want to have the help of your tooling in an IDE, for instance. Here's an example:--````markdown--```{.matplotlib file=myplot.py}-```--````-* Better error messages when specifying logger verbosity.-* Cleaning output directories with `pandoc-plot clean` now follows configuration values for logging. -* Fixed an issue where configuration in metadata did not get parsed properly.--## Release 0.9.0.0--* The `bokeh` toolkit now supports exporting plots as SVGs (#8).-* Interactive plots relying on javascript scripts will now defer loading the scripts (#9). -* Added the `dependencies` argument, which tells `pandoc-plot` what files are important to a particular figure (#10). If a file listed in `dependencies` changes (for example, a data file), `pandoc-plot` will re-render the associated figure.-* Better heuristic to determine what `bokeh` plot to save. This allows the user to export plots like the [`bokeh.layouts` module](https://docs.bokeh.org/en/latest/docs/user_guide/layout.html#creating-layouts).-* Added support for the `dpi` parameter in `graphviz` and `mathematica`.-* Added support for MATLAB's new `exportgraphics` function introduced in MATLAB 2020a. Older versions fallback to using `saveas`.--## Release 0.8.1.0--* The module `Text.Pandoc.Filter.Plot.Internal` is no longer exposed; instead, everything relevant is exposed by the `Text.Pandoc.Filter.Plot` module.-* Fixed an issue where script errors would be logged as debug messages.-* Interactive plots are now embedded directly in output (#7).--## Release 0.8.0.0--* Added a new output format, HTML, to produce interactive plots. Not all renderers support it. You can try with Plotly/Python and Plotly/R as follows:--````markdown--```{.plotly_python format=html}-import plotly.express as px-df = px.data.election()-fig = px.scatter_ternary(df, a="Joly", b="Coderre", c="Bergeron")-```--````--* Added a new toolkit, [`bokeh`](https://bokeh.org/). This toolkit can take advantage of the new HTML interactive output.-* Added a new toolkit, [`plotsjl`](http://docs.juliaplots.org/latest/).-* Separated the detailed information from `README.md` and into a proper `MANUAL.md`. This is now the information which will be shown with `pandoc-plot --manual`.-* Exposed the `pandoc-plot` version via `Text.Pandoc.Filter.Plot.pandocPlotVersion`.--## Release 0.7.2.1--* Fixed an issue where the `pandoc` version was not parsed properly, giving rise to errors when running `pandoc-plot`.-* Fixed an issue where logging errors were not always displayed.--## Release 0.7.2.0--* Removed dependency on `open-browser` package.-* Starting with this version, `pandoc` 2.8 and 2.9 are **no longer supported** due to a breaking API change in `pandoc` 2.10.-* Executables are now built with GHC 8.10.1.--## Release 0.7.1.0--* Better multi-threaded logging. Only one thread (the logging thread) performs IO on the log file. This prevents hang-ups when working on large documents. --## Release 0.7.0.0--* Added documentation on using `pandoc-plot` with LaTeX documents as well.-* Added preliminary support for logging to `pandoc-plot`. You can turn on this feature in the configuration as follows:--````yaml-logging:-    # Possible verbosity values: debug, error, warning, info, silent-    # debug level shows all messages-    # error level shows all but debug messages, etc.-    verbosity: info-    -    # OPTIONAL: log to file-    # Remove line below to log to stderr-    filepath: log.txt-````--* Removed dependencies `turtle`, `temporary`, `deepseq`, and `data-default-class`, resulting in improved build times by ~10%, and makes the executable smaller by 15-20%!--## Release 0.6.1.0--* Made the functions `availableToolkits` and `unavailableToolkits` public.-* Minor documentation fixes.-* Executables are now built with GHC 8.8.3.--## Release 0.6.0.0--New toolkits:-* Added support for the Plotly/R plotting library.-* Added support for Graphviz.--Other changes:-* The determination of which figures to re-render or not has been improved. For example, changing the caption will not trigger a re-render of a figure anymore.-* `pandoc-plot` will look for executables more thoroughly.-* `pandoc-plot toolkits` will now show the exact executable that is being used, if possible.-* Added a check when running the filter that the Pandoc version is at least 2.8. This is easier to understand that the default Pandoc warning on API incompatibility.-* Added the ability to write the example configuration to an arbitrary file using `pandoc-plot write-example-config`.-* Added the possibility to specify the configuration file via metadata. For example, in Markdown:--    ```markdown-    ----    title: My document-    author: John Doe-    plot-configuration: /path/to/file.yml-    ---     -    ```--or on the command line:--```bash-pandoc --filter pandoc-plot -M plot-configuration=/path/to/file.yml ...-```-* Added the ability to specify configuration file to the `pandoc-plot clean` and `pandoc-plot toolkits` commands.--## Release 0.5.0.0--* The `pandoc-plot` executable will now process documents in parallel. This should dramatically speed up processing of large documents with lots of figures. -This happens automatically through the function `plotTransform`.-* Added a benchmarking suite.-* Added `defaultConfiguration` so that people don't have to install the `data-default` package to get access to default configuration values. -* Added a check for the `matplotlib` toolkit, preventing users from using `matplotlib.pyplot.show` in figures. This would halt `pandoc-plot`.--## Release 0.4.0.1--* Fixed an issue where the `pandoc-plot` executable could not be built outside of its git repository.--## Release 0.4.0.0--* Updated documentation.-* Added a `--full-version` flag to the executable, which includes which version of pandoc/pandoc-types was used, as well as the git revision.-* Added the `clean` command to the executable. This can be used to clean-up output files produced by pandoc-plot.-* Changed the flag `--write-example-config` to the command `write-example-config`.-* Added the top-level function `cleanOutputDir` to clean output of pandoc-plot. This is only accessible if `pandoc-plot` is used as a library.-* Added a distinction between failure to render a figure because of a mistake, and failing to render a figure because the toolkit is not installed. `pandoc-plot` will give better error messages in the latter case.--## Release 0.3.0.0--* Added more examples.-* Added MacOS binaries built via Azure pipelines.-* BREAKING CHANGE: Parsing captions based on source file was not working. Captions format can be specified in the configuration file. This unfortunately changes the type signature of a few high-level functions.--## Release 0.2.2.0--* Fixed an issue where paths with spaces would not work (issue #2).-* Added Linux binaries built via Azure pipelines.--## Release 0.2.1.0--* Improved documentation.--## Release 0.2.0.0--* Added support for gnuplot.-* Added more tests for all toolkits.--* Fixed an issue where the package could not be installed because a source file was not included in the cabal file.--## Release 0.1.0.0--* Initial release+# Change log
+
+pandoc-plot uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
+
+## Release 1.8.0
+
+* Added support for [Asymptote](https://asymptote.sourceforge.io/), thanks to a contribution by Michał J. Gajda (#61).
+
+## Release 1.7.0
+
+* Added support for the declarative diagram language [D2](https://d2lang.com/), thanks to a contribution by Sanchayan Maity (#60).
+* Added support for `optparse-applicative` v0.18.
+
+## Release 1.6.2
+
+* Fixed some imports which were removed in `mtl-2.3`.
+
+## Release 1.6.1
+
+* Fixed an issue where figure attributes were lost, which prevent other filters (e.g. pandoc-crossref) from working in conjunction with pandoc-plot.
+
+## Release 1.6.0
+
+* Support for pandoc 3. Support for older pandoc version has also been dropped (pandoc 2.19 and earlier).
+
+## Release 1.5.5
+
+* Fixed an issue where there was a race condition when rendering multiple identical figures (#53).
+
+## Release 1.5.4
+
+* Fixed an issue where graphviz plots in vector format were cropped when a DPI was specified (#40).
+
+## Release 1.5.3
+
+* Fixed an issue where the `tight_bbox` option for Matplotlib plots was ignored (#48).
+
+## Release 1.5.2
+
+* Overhauled the way executables are handled. This fixes an issue where executables specified in documents (rather than configuration) were ignored (#46).
+
+## Release 1.5.1
+
+* Figures with no captions (and no link to the source script), will now be shown as an image, without figure numbering (#37).
+
+## Release 1.5.0
+
+* Added support for [Sage](https://www.sagemath.org/) (#44).
+* Fixed an issue where the parsing of default save format from configuration was overly restrictive (#42).
+* Linux and Windows executables now built with GHC 9.2.
+
+## Release 1.4.1
+
+* Don't automatically defer javascript scripts when creating interactive figures (#39).
+
+## Release 1.4.0
+
+* The executable `pandoc-plot` now uses pandoc 2.17. Pandoc 2.11+ are still supported.
+* Added support for `aeson` 2+.
+
+## Release 1.3.0
+
+* The executable `pandoc-plot` is now aware of final conversion format.
+* Added a new function, `plotFilter`, which is aware of the pandoc's final conversion format. This allows for better defaults and error messages.
+* Deprecated `plotTransform` in favour of `plotFilter`. `plotTransform` will be removed in the next major update (v2+).
+* Save formats incompatible with toolkits will now show an appropriate error.
+* The build system is now based on `cabal-install` rather than `stack`.
+* Fixed an issue where some types of PlantUML diagrams (e.g. Gantt charts) would not be exported correctly (#30).
+
+## Release 1.2.3
+
+* Fixed an issue where MATLAB figures were not being saved in the right location (#27).
+* Releases are now completely taken care of via Github actions.
+
+## Release 1.2.2
+
+* Executables are now built using GHC 9.0.1
+* The executables are now built with Pandoc 2.14. Pandoc 2.11, 2.12, and 2.13 are still supported.
+
+## Release 1.2.1
+
+* Added the ability to save plots as LaTeX directly from the GNUplot toolkit. To do this, simply set the output format to `latex`. The figure content will be embedded in the output document, which only makes sense for final conversion to LaTeX. For example:
+
+  ````markdown
+    ```{.gnuplot format=latex caption="This is a test."}
+    ...
+    ```
+  ````
+  This patch was contributed by Saku Laesvuori.
+
+## Release 1.2.0
+
+* Fixed an issue where code blocks nested in other structures were detected properly. For example, in the following LaTeX snippet, plots would not be detected properly:
+```latex
+\begin{column}
+  \begin{minted}[]{matplotlib}
+  ...
+  \end{minted}
+\end{column}
+```
+Nested figures are not correctly identified.
+
+* The executables are now built with Pandoc 2.13. Pandoc 2.11 and Pandoc 2.12 are still supported.
+
+## Release 1.1.1
+
+* Error messages now include the source script and line numbers.
+* The executables are now built with Pandoc 2.12. Pandoc 2.11 is still supported.
+
+## Release 1.1.0
+
+* Added the [PlantUML](https://plantuml.com) toolkit (#18). Diagrams can be generated like so:
+
+  ````markdown
+
+  ```{.plantuml}
+  @startuml
+  Bob->Alice : hello
+  @enduml
+  ```
+
+  ````
+* Changed versioning scheme to match more common Major.Minor.Bugfix.
+
+## Release 1.0.2.1
+
+* `pandoc-plot` will now only render at most `N` figures in parallel, where `N` is the number of available CPU cores.
+* Fixed an issue where error message would get mangled in strict-mode.
+
+## Release 1.0.2.0
+
+* Added the ability to run `pandoc-plot` in **strict mode**. By default, `pandoc-plot` leaves code blocks unchanged if a figure fails to be rendered.  In strict mode, `pandoc-plot` will immediately halt if it encounters a problem, such as a missing toolkit. You can activate strict mode via configuration:
+
+```yaml
+strict: true
+```
+
+* Added the ability to set command-line arguments for interpreters via configuration. For example, if you want to run the Matplotlib toolkit with all warnings shown:
+
+```yaml
+# Possible parameters for the Matplotlib toolkit
+matplotlib:
+  executable: python
+  command_line_arguments: -Wa
+```
+
+Or if you want `julia` to use more than one thread:
+
+```yaml
+# Possible parameters for the Plotsjl toolkit
+plotsjl:
+  executable: julia
+  command_line_arguments: --threads auto --optimize=0
+```
+
+* Fixed an issue where invoking the `plotsjl` toolkit on Windows would sometimes fail with the error: Unknown system error 50.
+* Fixed an issue with R-based toolkits on Windows not being detected properly.
+
+## Release 1.0.1.0
+
+* Added the ability to change the "Source code" label to other languages via configuration.
+* Added syntax highlighting to the linked source code.
+* Fixed an issue where code blocks with unicode symbols (e.g. greek letters) would trip up pandoc-plot (#16).
+
+## Release 1.0.0.0
+
+* Added support for Pandoc 2.11. Unfortunately, there is no way to support prior versions of Pandoc at the same time.
+* With release 1.0.0.0, `pandoc-plot` has stabilized. The Haskell library API will not change until version 2+. 
+
+## Release 0.9.4.0
+
+* Fixed an issue where the current working directory was changed. This prevented users from referring to files in scripts with relative paths (#2).
+
+## Release 0.9.3.0
+
+* Added executable caching: repeated usage of a particular toolkit will be faster because executables are only looked-for once.
+* Reverting the change from 0.8.1.0: internal machinery of `pandoc-plot` has been moved to the `Text.Pandoc.Filter.Plot.Internal` module, where there is no guarantee of backwards-compatibility after 1.0.0.
+* Removed the `makePlot` function, which could not take advantage of multithreading and other key features of `pandoc-plot`.
+* Fixed an issue where files required for tests were missing from source tarballs (#13).
+
+## Release 0.9.2.0
+
+* Fixed an issue where executables located on paths with spaces would not be invoked correctly (#12).
+* Fixed an issue where R-paths were not normalized correctly.
+* Fixed an issue where executables specified in configuration that did not exist would crash `pandoc-plot`.
+* Fixed an issue where some R-based toolkits appeared to be available, but were not.
+
+## Release 0.9.1.0
+
+* Added the `file` parameter, which allows the user to read figure content from a file instead of using the code block content in documents. This is especially useful for complex figures, where you might want to have the help of your tooling in an IDE, for instance. Here's an example:
+
+````markdown
+
+```{.matplotlib file=myplot.py}
+```
+
+````
+* Better error messages when specifying logger verbosity.
+* Cleaning output directories with `pandoc-plot clean` now follows configuration values for logging. 
+* Fixed an issue where configuration in metadata did not get parsed properly.
+
+## Release 0.9.0.0
+
+* The `bokeh` toolkit now supports exporting plots as SVGs (#8).
+* Interactive plots relying on javascript scripts will now defer loading the scripts (#9). 
+* Added the `dependencies` argument, which tells `pandoc-plot` what files are important to a particular figure (#10). If a file listed in `dependencies` changes (for example, a data file), `pandoc-plot` will re-render the associated figure.
+* Better heuristic to determine what `bokeh` plot to save. This allows the user to export plots like the [`bokeh.layouts` module](https://docs.bokeh.org/en/latest/docs/user_guide/layout.html#creating-layouts).
+* Added support for the `dpi` parameter in `graphviz` and `mathematica`.
+* Added support for MATLAB's new `exportgraphics` function introduced in MATLAB 2020a. Older versions fallback to using `saveas`.
+
+## Release 0.8.1.0
+
+* The module `Text.Pandoc.Filter.Plot.Internal` is no longer exposed; instead, everything relevant is exposed by the `Text.Pandoc.Filter.Plot` module.
+* Fixed an issue where script errors would be logged as debug messages.
+* Interactive plots are now embedded directly in output (#7).
+
+## Release 0.8.0.0
+
+* Added a new output format, HTML, to produce interactive plots. Not all renderers support it. You can try with Plotly/Python and Plotly/R as follows:
+
+````markdown
+
+```{.plotly_python format=html}
+import plotly.express as px
+df = px.data.election()
+fig = px.scatter_ternary(df, a="Joly", b="Coderre", c="Bergeron")
+```
+
+````
+
+* Added a new toolkit, [`bokeh`](https://bokeh.org/). This toolkit can take advantage of the new HTML interactive output.
+* Added a new toolkit, [`plotsjl`](http://docs.juliaplots.org/latest/).
+* Separated the detailed information from `README.md` and into a proper `MANUAL.md`. This is now the information which will be shown with `pandoc-plot --manual`.
+* Exposed the `pandoc-plot` version via `Text.Pandoc.Filter.Plot.pandocPlotVersion`.
+
+## Release 0.7.2.1
+
+* Fixed an issue where the `pandoc` version was not parsed properly, giving rise to errors when running `pandoc-plot`.
+* Fixed an issue where logging errors were not always displayed.
+
+## Release 0.7.2.0
+
+* Removed dependency on `open-browser` package.
+* Starting with this version, `pandoc` 2.8 and 2.9 are **no longer supported** due to a breaking API change in `pandoc` 2.10.
+* Executables are now built with GHC 8.10.1.
+
+## Release 0.7.1.0
+
+* Better multi-threaded logging. Only one thread (the logging thread) performs IO on the log file. This prevents hang-ups when working on large documents. 
+
+## Release 0.7.0.0
+
+* Added documentation on using `pandoc-plot` with LaTeX documents as well.
+* Added preliminary support for logging to `pandoc-plot`. You can turn on this feature in the configuration as follows:
+
+````yaml
+logging:
+    # Possible verbosity values: debug, error, warning, info, silent
+    # debug level shows all messages
+    # error level shows all but debug messages, etc.
+    verbosity: info
+    
+    # OPTIONAL: log to file
+    # Remove line below to log to stderr
+    filepath: log.txt
+````
+
+* Removed dependencies `turtle`, `temporary`, `deepseq`, and `data-default-class`, resulting in improved build times by ~10%, and makes the executable smaller by 15-20%!
+
+## Release 0.6.1.0
+
+* Made the functions `availableToolkits` and `unavailableToolkits` public.
+* Minor documentation fixes.
+* Executables are now built with GHC 8.8.3.
+
+## Release 0.6.0.0
+
+New toolkits:
+* Added support for the Plotly/R plotting library.
+* Added support for Graphviz.
+
+Other changes:
+* The determination of which figures to re-render or not has been improved. For example, changing the caption will not trigger a re-render of a figure anymore.
+* `pandoc-plot` will look for executables more thoroughly.
+* `pandoc-plot toolkits` will now show the exact executable that is being used, if possible.
+* Added a check when running the filter that the Pandoc version is at least 2.8. This is easier to understand that the default Pandoc warning on API incompatibility.
+* Added the ability to write the example configuration to an arbitrary file using `pandoc-plot write-example-config`.
+* Added the possibility to specify the configuration file via metadata. For example, in Markdown:
+
+    ```markdown
+    ---
+    title: My document
+    author: John Doe
+    plot-configuration: /path/to/file.yml
+    ---     
+    ```
+
+or on the command line:
+
+```bash
+pandoc --filter pandoc-plot -M plot-configuration=/path/to/file.yml ...
+```
+* Added the ability to specify configuration file to the `pandoc-plot clean` and `pandoc-plot toolkits` commands.
+
+## Release 0.5.0.0
+
+* The `pandoc-plot` executable will now process documents in parallel. This should dramatically speed up processing of large documents with lots of figures. 
+This happens automatically through the function `plotTransform`.
+* Added a benchmarking suite.
+* Added `defaultConfiguration` so that people don't have to install the `data-default` package to get access to default configuration values. 
+* Added a check for the `matplotlib` toolkit, preventing users from using `matplotlib.pyplot.show` in figures. This would halt `pandoc-plot`.
+
+## Release 0.4.0.1
+
+* Fixed an issue where the `pandoc-plot` executable could not be built outside of its git repository.
+
+## Release 0.4.0.0
+
+* Updated documentation.
+* Added a `--full-version` flag to the executable, which includes which version of pandoc/pandoc-types was used, as well as the git revision.
+* Added the `clean` command to the executable. This can be used to clean-up output files produced by pandoc-plot.
+* Changed the flag `--write-example-config` to the command `write-example-config`.
+* Added the top-level function `cleanOutputDir` to clean output of pandoc-plot. This is only accessible if `pandoc-plot` is used as a library.
+* Added a distinction between failure to render a figure because of a mistake, and failing to render a figure because the toolkit is not installed. `pandoc-plot` will give better error messages in the latter case.
+
+## Release 0.3.0.0
+
+* Added more examples.
+* Added MacOS binaries built via Azure pipelines.
+* BREAKING CHANGE: Parsing captions based on source file was not working. Captions format can be specified in the configuration file. This unfortunately changes the type signature of a few high-level functions.
+
+## Release 0.2.2.0
+
+* Fixed an issue where paths with spaces would not work (issue #2).
+* Added Linux binaries built via Azure pipelines.
+
+## Release 0.2.1.0
+
+* Improved documentation.
+
+## Release 0.2.0.0
+
+* Added support for gnuplot.
+* Added more tests for all toolkits.
+
+* Fixed an issue where the package could not be installed because a source file was not included in the cabal file.
+
+## Release 0.1.0.0
+
+* Initial release
LICENSE view
@@ -1,339 +1,339 @@-                    GNU GENERAL PUBLIC LICENSE-                       Version 2, June 1991-- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA- Everyone is permitted to copy and distribute verbatim copies- of this license document, but changing it is not allowed.--                            Preamble--  The licenses for most software are designed to take away your-freedom to share and change it.  By contrast, the GNU General Public-License is intended to guarantee your freedom to share and change free-software--to make sure the software is free for all its users.  This-General Public License applies to most of the Free Software-Foundation's software and to any other program whose authors commit to-using it.  (Some other Free Software Foundation software is covered by-the GNU Lesser General Public License instead.)  You can apply it to-your programs, too.--  When we speak of free software, we are referring to freedom, not-price.  Our General Public Licenses are designed to make sure that you-have the freedom to distribute copies of free software (and charge for-this service if you wish), that you receive source code or can get it-if you want it, that you can change the software or use pieces of it-in new free programs; and that you know you can do these things.--  To protect your rights, we need to make restrictions that forbid-anyone to deny you these rights or to ask you to surrender the rights.-These restrictions translate to certain responsibilities for you if you-distribute copies of the software, or if you modify it.--  For example, if you distribute copies of such a program, whether-gratis or for a fee, you must give the recipients all the rights that-you have.  You must make sure that they, too, receive or can get the-source code.  And you must show them these terms so they know their-rights.--  We protect your rights with two steps: (1) copyright the software, and-(2) offer you this license which gives you legal permission to copy,-distribute and/or modify the software.--  Also, for each author's protection and ours, we want to make certain-that everyone understands that there is no warranty for this free-software.  If the software is modified by someone else and passed on, we-want its recipients to know that what they have is not the original, so-that any problems introduced by others will not reflect on the original-authors' reputations.--  Finally, any free program is threatened constantly by software-patents.  We wish to avoid the danger that redistributors of a free-program will individually obtain patent licenses, in effect making the-program proprietary.  To prevent this, we have made it clear that any-patent must be licensed for everyone's free use or not licensed at all.--  The precise terms and conditions for copying, distribution and-modification follow.--                    GNU GENERAL PUBLIC LICENSE-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION--  0. This License applies to any program or other work which contains-a notice placed by the copyright holder saying it may be distributed-under the terms of this General Public License.  The "Program", below,-refers to any such program or work, and a "work based on the Program"-means either the Program or any derivative work under copyright law:-that is to say, a work containing the Program or a portion of it,-either verbatim or with modifications and/or translated into another-language.  (Hereinafter, translation is included without limitation in-the term "modification".)  Each licensee is addressed as "you".--Activities other than copying, distribution and modification are not-covered by this License; they are outside its scope.  The act of-running the Program is not restricted, and the output from the Program-is covered only if its contents constitute a work based on the-Program (independent of having been made by running the Program).-Whether that is true depends on what the Program does.--  1. You may copy and distribute verbatim copies of the Program's-source code as you receive it, in any medium, provided that you-conspicuously and appropriately publish on each copy an appropriate-copyright notice and disclaimer of warranty; keep intact all the-notices that refer to this License and to the absence of any warranty;-and give any other recipients of the Program a copy of this License-along with the Program.--You may charge a fee for the physical act of transferring a copy, and-you may at your option offer warranty protection in exchange for a fee.--  2. You may modify your copy or copies of the Program or any portion-of it, thus forming a work based on the Program, and copy and-distribute such modifications or work under the terms of Section 1-above, provided that you also meet all of these conditions:--    a) You must cause the modified files to carry prominent notices-    stating that you changed the files and the date of any change.--    b) You must cause any work that you distribute or publish, that in-    whole or in part contains or is derived from the Program or any-    part thereof, to be licensed as a whole at no charge to all third-    parties under the terms of this License.--    c) If the modified program normally reads commands interactively-    when run, you must cause it, when started running for such-    interactive use in the most ordinary way, to print or display an-    announcement including an appropriate copyright notice and a-    notice that there is no warranty (or else, saying that you provide-    a warranty) and that users may redistribute the program under-    these conditions, and telling the user how to view a copy of this-    License.  (Exception: if the Program itself is interactive but-    does not normally print such an announcement, your work based on-    the Program is not required to print an announcement.)--These requirements apply to the modified work as a whole.  If-identifiable sections of that work are not derived from the Program,-and can be reasonably considered independent and separate works in-themselves, then this License, and its terms, do not apply to those-sections when you distribute them as separate works.  But when you-distribute the same sections as part of a whole which is a work based-on the Program, the distribution of the whole must be on the terms of-this License, whose permissions for other licensees extend to the-entire whole, and thus to each and every part regardless of who wrote it.--Thus, it is not the intent of this section to claim rights or contest-your rights to work written entirely by you; rather, the intent is to-exercise the right to control the distribution of derivative or-collective works based on the Program.--In addition, mere aggregation of another work not based on the Program-with the Program (or with a work based on the Program) on a volume of-a storage or distribution medium does not bring the other work under-the scope of this License.--  3. You may copy and distribute the Program (or a work based on it,-under Section 2) in object code or executable form under the terms of-Sections 1 and 2 above provided that you also do one of the following:--    a) Accompany it with the complete corresponding machine-readable-    source code, which must be distributed under the terms of Sections-    1 and 2 above on a medium customarily used for software interchange; or,--    b) Accompany it with a written offer, valid for at least three-    years, to give any third party, for a charge no more than your-    cost of physically performing source distribution, a complete-    machine-readable copy of the corresponding source code, to be-    distributed under the terms of Sections 1 and 2 above on a medium-    customarily used for software interchange; or,--    c) Accompany it with the information you received as to the offer-    to distribute corresponding source code.  (This alternative is-    allowed only for noncommercial distribution and only if you-    received the program in object code or executable form with such-    an offer, in accord with Subsection b above.)--The source code for a work means the preferred form of the work for-making modifications to it.  For an executable work, complete source-code means all the source code for all modules it contains, plus any-associated interface definition files, plus the scripts used to-control compilation and installation of the executable.  However, as a-special exception, the source code distributed need not include-anything that is normally distributed (in either source or binary-form) with the major components (compiler, kernel, and so on) of the-operating system on which the executable runs, unless that component-itself accompanies the executable.--If distribution of executable or object code is made by offering-access to copy from a designated place, then offering equivalent-access to copy the source code from the same place counts as-distribution of the source code, even though third parties are not-compelled to copy the source along with the object code.--  4. You may not copy, modify, sublicense, or distribute the Program-except as expressly provided under this License.  Any attempt-otherwise to copy, modify, sublicense or distribute the Program is-void, and will automatically terminate your rights under this License.-However, parties who have received copies, or rights, from you under-this License will not have their licenses terminated so long as such-parties remain in full compliance.--  5. You are not required to accept this License, since you have not-signed it.  However, nothing else grants you permission to modify or-distribute the Program or its derivative works.  These actions are-prohibited by law if you do not accept this License.  Therefore, by-modifying or distributing the Program (or any work based on the-Program), you indicate your acceptance of this License to do so, and-all its terms and conditions for copying, distributing or modifying-the Program or works based on it.--  6. Each time you redistribute the Program (or any work based on the-Program), the recipient automatically receives a license from the-original licensor to copy, distribute or modify the Program subject to-these terms and conditions.  You may not impose any further-restrictions on the recipients' exercise of the rights granted herein.-You are not responsible for enforcing compliance by third parties to-this License.--  7. If, as a consequence of a court judgment or allegation of patent-infringement or for any other reason (not limited to patent issues),-conditions are imposed on you (whether by court order, agreement or-otherwise) that contradict the conditions of this License, they do not-excuse you from the conditions of this License.  If you cannot-distribute so as to satisfy simultaneously your obligations under this-License and any other pertinent obligations, then as a consequence you-may not distribute the Program at all.  For example, if a patent-license would not permit royalty-free redistribution of the Program by-all those who receive copies directly or indirectly through you, then-the only way you could satisfy both it and this License would be to-refrain entirely from distribution of the Program.--If any portion of this section is held invalid or unenforceable under-any particular circumstance, the balance of the section is intended to-apply and the section as a whole is intended to apply in other-circumstances.--It is not the purpose of this section to induce you to infringe any-patents or other property right claims or to contest validity of any-such claims; this section has the sole purpose of protecting the-integrity of the free software distribution system, which is-implemented by public license practices.  Many people have made-generous contributions to the wide range of software distributed-through that system in reliance on consistent application of that-system; it is up to the author/donor to decide if he or she is willing-to distribute software through any other system and a licensee cannot-impose that choice.--This section is intended to make thoroughly clear what is believed to-be a consequence of the rest of this License.--  8. If the distribution and/or use of the Program is restricted in-certain countries either by patents or by copyrighted interfaces, the-original copyright holder who places the Program under this License-may add an explicit geographical distribution limitation excluding-those countries, so that distribution is permitted only in or among-countries not thus excluded.  In such case, this License incorporates-the limitation as if written in the body of this License.--  9. The Free Software Foundation may publish revised and/or new versions-of the General Public License from time to time.  Such new versions will-be similar in spirit to the present version, but may differ in detail to-address new problems or concerns.--Each version is given a distinguishing version number.  If the Program-specifies a version number of this License which applies to it and "any-later version", you have the option of following the terms and conditions-either of that version or of any later version published by the Free-Software Foundation.  If the Program does not specify a version number of-this License, you may choose any version ever published by the Free Software-Foundation.--  10. If you wish to incorporate parts of the Program into other free-programs whose distribution conditions are different, write to the author-to ask for permission.  For software which is copyrighted by the Free-Software Foundation, write to the Free Software Foundation; we sometimes-make exceptions for this.  Our decision will be guided by the two goals-of preserving the free status of all derivatives of our free software and-of promoting the sharing and reuse of software generally.--                            NO WARRANTY--  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,-REPAIR OR CORRECTION.--  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE-POSSIBILITY OF SUCH DAMAGES.--                     END OF TERMS AND CONDITIONS--            How to Apply These Terms to Your New Programs--  If you develop a new program, and you want it to be of the greatest-possible use to the public, the best way to achieve this is to make it-free software which everyone can redistribute and change under these terms.--  To do so, attach the following notices to the program.  It is safest-to attach them to the start of each source file to most effectively-convey the exclusion of warranty; and each file should have at least-the "copyright" line and a pointer to where the full notice is found.--    <one line to give the program's name and a brief idea of what it does.>-    Copyright (C) <year>  <name of author>--    This program is free software; you can redistribute it and/or modify-    it under the terms of the GNU General Public License as published by-    the Free Software Foundation; either version 2 of the License, or-    (at your option) any later version.--    This program is distributed in the hope that it will be useful,-    but WITHOUT ANY WARRANTY; without even the implied warranty of-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-    GNU General Public License for more details.--    You should have received a copy of the GNU General Public License along-    with this program; if not, write to the Free Software Foundation, Inc.,-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.--Also add information on how to contact you by electronic and paper mail.--If the program is interactive, make it output a short notice like this-when it starts in an interactive mode:--    Gnomovision version 69, Copyright (C) year name of author-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.-    This is free software, and you are welcome to redistribute it-    under certain conditions; type `show c' for details.--The hypothetical commands `show w' and `show c' should show the appropriate-parts of the General Public License.  Of course, the commands you use may-be called something other than `show w' and `show c'; they could even be-mouse-clicks or menu items--whatever suits your program.--You should also get your employer (if you work as a programmer) or your-school, if any, to sign a "copyright disclaimer" for the program, if-necessary.  Here is a sample; alter the names:--  Yoyodyne, Inc., hereby disclaims all copyright interest in the program-  `Gnomovision' (which makes passes at compilers) written by James Hacker.--  <signature of Ty Coon>, 1 April 1989-  Ty Coon, President of Vice--This General Public License does not permit incorporating your program into-proprietary programs.  If your program is a subroutine library, you may-consider it more useful to permit linking proprietary applications with the-library.  If this is what you want to do, use the GNU Lesser General-Public License instead of this License.+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
MANUAL.md view
@@ -1,663 +1,663 @@-<!---The file MANUAL.md is automatically generated by the tools/mkmanual.ps1 script. Do not edit manually.--->--## A Pandoc filter to generate figures from code blocks in documents--`pandoc-plot` turns code blocks present in your documents (Markdown, LaTeX, etc.) into embedded figures, using your plotting toolkit of choice, including Matplotlib, ggplot2, MATLAB, Mathematica, and more.---   [Features Overview](#features-overview)-    -   [Captions](#captions)-    -   [Link to source code](#link-to-source-code)-    -   [Preamble scripts](#preamble-scripts)-    -   [Support for interactive plots](#support-for-interactive-plots)-    -   [Performance](#performance)-    -   [Compatibility with pandoc-crossref](#compatibility-with-pandoc-crossref)--   [Detailed usage](#detailed-usage)-    -   [As a filter](#as-a-filter)-    -   [Syntax](#syntax)-        -   [Markdown](#markdown)-        -   [LaTeX](#latex)-    -   [Parameters and options](#parameters-and-options)-        -   [Code highlighting](#code-highlighting)-    -   [Interactive HTML figures](#interactive-html-figures)-    -   [Configuration](#configuration)-        -   [Executables](#executables)-        -   [Command-line arguments](#command-line-arguments)-        -   [Toolkit-specific options](#toolkit-specific-options)-        -   [Logging](#logging)-        -   [Strict mode](#strict-mode)-    -   [Other commands](#other-commands)-        -   [Finding installed toolkits](#finding-installed-toolkits)-        -   [Cleaning output](#cleaning-output)-        -   [Configuration template](#configuration-template)-    -   [As a Haskell library](#as-a-haskell-library)-        -   [Usage with Hakyll](#usage-with-hakyll)--   [Warning](#warning)--## Features Overview--### Captions--You can also specify a caption for your image. This is done using the optional `caption` parameter.--**Markdown**:--```` markdown-```{.matlabplot caption="This is a simple figure with a **Markdown** caption"}-x  = 0: .1 : 2*pi;-y1 = cos(x);-y2 = sin(x);--figure-plot(x, y1, 'b', x, y2, 'r-.', 'LineWidth', 2)-```-````--**LaTex**:--``` latex-\begin{minted}[caption=This is a simple figure with a caption]{matlabplot}-x  = 0: .1 : 2*pi;-y1 = cos(x);-y2 = sin(x);--figure-plot(x, y1, 'b', x, y2, 'r-.', 'LineWidth', 2)-\end{minted}-```--Caption formatting unfortunately cannot be determined automatically. To specify a caption format (e.g. “markdown”, “LaTeX”, etc.), see [Configuration](#configuration).--### Link to source code--In case of an output format that supports links (e.g. HTML), the embedded image generated by `pandoc-plot` can show a link to the source code which was used to generate the file. Therefore, other people can see what code was used to create your figures.--You can turn this on via the `source=true` key:--**Markdown**:--```` markdown-```{.mathplot source=true}-...-```-````--**LaTex**:--``` latex-\begin{minted}[source=true]{mathplot}-...-\end{minted}-```--or via a [configuration file](#Configuration).--### Preamble scripts--If you find yourself always repeating some steps, inclusion of scripts is possible using the `preamble` parameter. For example, if you want all Matplotlib plots to have the [`ggplot`](https://matplotlib.org/tutorials/introductory/customizing.html#sphx-glr-tutorials-introductory-customizing-py) style, you can write a very short preamble `style.py` like so:--``` python-import matplotlib.pyplot as plt-plt.style.use('ggplot')-```--and include it in your document as follows:--```` markdown-```{.matplotlib preamble=style.py}-plt.figure()-plt.plot([0,1,2,3,4], [1,2,3,4,5])-plt.title('This is an example figure')-```-````--Which is equivalent to writing the following markdown:--```` markdown-```{.matplotlib}-import matplotlib.pyplot as plt-plt.style.use('ggplot')--plt.figure()-plt.plot([0,1,2,3,4], [1,2,3,4,5])-plt.title('This is an example figure')-```-````--The equivalent LaTeX usage is as follows:--``` latex-\begin{minted}[include=style.py]{matplotlib}--\end{minted}-```--This `preamble` parameter is perfect for longer documents with many plots. Simply define the style you want in a separate script! You can also import packages this way, or define functions you often use.--### Support for interactive plots--Starting with version 0.8.0.0, `pandoc-plot` supports the creation of interactive plots (if a toolkit supports it). All you need to do is set the save format to `html`. The resulting plot is fully self-contained, so it can be displayed offline.--### Performance--`pandoc-plot` minimizes work, only generating figures if it absolutely must, i.e. if the content has changed. `pandoc-plot` will save the hash of the source code used to generate a figure in its filename. Before generating a figure, `pandoc-plot` will check it this figure already exists based on the hash of its source! This also means that there is no way to directly name figures.--Moreover, starting with version 0.5.0.0, `pandoc-plot` takes advantage of multicore CPUs, rendering figures **in parallel**.--Therefore, you can confidently run the filter on very large documents containing hundreds of figures, like a book or a thesis.--### Compatibility with pandoc-crossref--[`pandoc-crossref`](https://github.com/lierdakil/pandoc-crossref) is a pandoc filter that makes it effortless to cross-reference objects in Markdown documents.--You can use `pandoc-crossref` in conjunction with `pandoc-plot` for the ultimate figure-making pipeline. You can combine both in a figure like so:--```` markdown-```{#fig:myexample .plotly_python caption="This is a caption"}-# Insert figure script here-```--As you can see in @fig:myexample, ...-````--If the above source is located in file `myfile.md`, you can render the figure and references by applying `pandoc-plot` **first**, and then `pandoc-crossref`. For example:--``` bash-pandoc --filter pandoc-plot --filter pandoc-crossref -i myfile.md -o myfile.html-```--## Detailed usage--`pandoc-plot` is a command line executable with a few functions. You can take a look at the help using the `-h`/`--help` flag:--``` bash-pandoc-plot 1.3.0 - generate figures directly in documents--Usage: pandoc-plot.EXE [(-v|--version) | --full-version | (-m|--manual)] -                       [COMMAND] [AST]-  This pandoc filter generates plots from code blocks using a multitude of-  possible renderers. This allows to keep documentation and figures in perfect-  synchronicity.--Available options:-  -v,--version             Show version number and exit.-  --full-version           Show full version information and exit.-  -m,--manual              Open the manual page in the default web browser and-                           exit.-  -h,--help                Show this help text--Available commands:-  toolkits                 Show information on toolkits and exit.-  clean                    Clean output directories where figures from FILE and-                           log files might be stored. WARNING: All files in-                           those directories will be deleted.-  write-example-config     Write example configuration to a file and exit.--More information can be found via the manual (pandoc-plot --manual) or the-repository README, located at https://github.com/LaurentRDC/pandoc-plot-```--### As a filter--The most common use for `pandoc-plot` is as a pandoc filter, in which case it should be called without arguments. For example:--``` bash-pandoc --filter pandoc-plot -i input.md -o output.html-```--If `pandoc-plot` fails to render a code block into a figure, the filtering will not stop. Your code blocks will stay unchanged, unless you activate [strict mode](#strict-mode).--You can chain other filters with it (e.g., [`pandoc-crossref`](https://github.com/lierdakil/pandoc-crossref)) like so:--``` bash-pandoc --filter pandoc-plot --filter pandoc-crossref -i input.md -o output.html-```--### Syntax--The syntax for code blocks in documents is shown below. `pandoc-plot` looks for code blocks with a specific class, depending on the toolkit you want to use. `pandoc-plot` will run the code and capture the figure output. There can only be **one** figure per code block.--The possible parameters and options are described in [further below](#parameters-and-options).--#### Markdown--```` markdown-  ```{.cls param1=value1 param2=value2 ...}-  # script content-  ```-````--#### LaTeX--Note that the `minted` LaTeX package need not be installed.--``` latex-\begin{minted}[param1=value1, param2=value2, ...]{cls}-...-\end{minted}-```--### Parameters and options--There are parameters that affect the figure that will be included in your document. Here are all the possible general parameters, in Markdown syntax:--```` markdown-  ```{.cls -      .language-      directory=(path) -      caption=(text) -      format=(PNG|PDF|SVG|JPG|EPS|GIF|TIF|WEBP|HTML|LATEX) -      source=(true|True|false|False) -      source_label=(text)-      preamble=(path) -      dpi=(integer)-      dependencies=[...]-      file=(path)-      executable=(path) -      caption_format=(text)-      }-  # script content-  ```-````---   `cls` must be one of the following: `matplotlib`, `matlabplot`, `plotly_python`, `plotly_r`, `mathplot`, `octaveplot`, `ggplot2`, `gnuplot`, `graphviz`, `bokeh`, `plotsjl`, `plantuml` (*new in version 1.1.0*).--All following parameters are optional, with their default values controlled by the [configuration](#configuration).---   `language` specifies the programming language used in this block. This parameter is ignored by `pandoc-plot`, but your text editor may use it to highlight code. See [Code highlighting](#code-highlighting) below.--   `directory` is a path to the directory where the figure and source code will be saved. You cannot control the file name. This path is either absolute, or relative from the working directory where you call `pandoc-plot`.--   `caption` is the caption text. The format of the caption is specified in the `caption_format` parameter, described below.--   `format` is the desired filetype for the resulting figure. Possible values for `format` are \[`PNG`, `PDF`, `SVG`, `JPG`, `EPS`, `GIF`, `TIF`, `WEBP`, `HTML`, `LATEX`\]. Not all toolkits support all formats. See `pandoc-plot toolkits` for toolkit-specific information regarding save formats. The `HTML` format is special; it can produce standalone, offline, interactive plots. As such, it only makes sense to use this format when creating HTML documents. Similarly, the `LATEX` format is special; plots in the LaTeX format will be embedded in the document. Therefore, it only makes sense to use this format when creating LaTeX documents.--   `source` is a boolean toggle that determines whether the source code should be linked in the caption or not. Possible values are \[`true`, `True`, `false`, `False`\].--   `source_label` is the text that links to source code (if `source=true`). This is useful if you are writing text in a different language. The default is `source_label="Source Code"`. You might want to set this via the [configuration](#configuration) instead.--   `preamble` is a path to a script that will be included as a preamble to the content of the code block. This path is either absolute, or relative from the working directory where you call `pandoc-plot`.--   `dpi` is the pixel density of the figure in dots-per-inch. Possible values are positive integers. Not all toolkits respect this.--   `dependencies` is a list of files/directories that affect the figure, for example data files. If one of those files/directories changes, `pandoc-plot` will re-render the associated figure. Format is a comma-separated list, e.g. `dependencies=[data.txt, foo.bar, ~/wtv]`. Values for `dependencies` in the configuration file will be appended to the values in a code block.--   `file` is a path to a file from which to read the figure content. If this parameter is used, the content of the code block is ignored. By using this parameter, you can use all the standard tooling of your plotting toolkit of choice, which is especially useful for complex figures.--   `executable` is a path to the executable to use (e.g. `C:\\python3.exe`) or the name of the executable (e.g. `python3`).--   `caption_format` is the text format of the caption. Possible values are exactly the same as `pandoc`’s format specification, usually `FORMAT+EXTENSION-EXTENSION`. For example, captions in Markdown with raw LaTeX would be parsed correctly provided that `caption_format=markdown+raw_tex`. See Pandoc’s guide on [Specifying formats](https://pandoc.org/MANUAL.html#specifying-formats).--#### Code highlighting--If your editor supports code highlighting in code blocks, you can also include the programming language. In Markdown:--```` markdown-  ```{.language .cls (options)}-  # script content-  ```-````--or Latex:--``` latex-  \begin{minted}[(options)]{language, cls}-  # script content-  \end{minted}-```--For example, for GGPlot2 figures:--```` markdown-  ```{.r .ggplot2 caption=Highlighted code block}-  # script content-  ```-````--or (Latex):--``` latex-  \begin{minted}[caption=Highlighted code block]{r, ggplot2}-  # script content-  \end{minted}-```--This way, you benefit from code highlighting *and* `pandoc-plot`.--### Interactive HTML figures--Interactive HTML figures are available for a few toolkits, e.g. `bokeh`. To make a figure interactive, use the output format `format=html`. This only makes sense if your output file is also HTML.--You can take a look at the [demonstration page](https://laurentrdc.github.io/pandoc-plot/) for an example result.--Many interactive plots rely on javascript scripts stored on the internet. If you want to have a self-contained document that can be viewed offline – or you want your document to work for the next 10 years –, you can use pandoc’s `--self-contained` flag:--``` bash-pandoc --self-contained --filter pandoc-plot -i mydoc.md -o webpage.html -```--The resulting output `webpage.html` will contain everything, at the cost of size.--### Configuration--To avoid repetition, `pandoc-plot` can be configured using simple YAML-files. Here are **all** the possible parameters:--``` yaml-# This is an example configuration. Everything in this file is optional.-# Please refer to the documentation to know about the parameters herein.-#-# The `executable` parameter for all toolkits can be either the-# executable name (if it is present on the PATH), or-# the full path to the executable.-# E.g.:-#  executable: python3-#  executable: "C:\Python37\Scripts\python.exe"--# The following parameters affect all toolkits-# Directory where to save the plots. The path can be relative to pandoc-plot's-# current working directory, or absolute.-directory: plots/--# Whether or not to include a link to the source script in the caption. -# Particularly useful for HTML output.-source: false--# When `strict: false`, pandoc-plot will leave code blocks untouched if a plot-# could not be generated. This could happen if, for example, a toolkit is not-# installed. If you want pandoc-plot to fail instead, use `strict: true`.-strict: false--# Text label for links to source code.-# You can change this label if you are writing a document in a non-English language. -# This only matters if `source` is set to `true`.-source_label: Source code--# Default density of figures in dots per inches (DPI). -# This can be changed in the document specifically as well.-dpi: 80--# Default format in which to save the figures. This can be specified -# individually as well.-format: PNG--# Default files/directories on which all figures depend. If any of these files/directories-# changes, all figures will be re-rendered.-# Dependencies specified in code blocks will be appended to this list.-dependencies:-  - file1.txt-  - file2.txt--# Text format for the captions. Unfortunately, there is no way to detect-# this automatically. You can use the same notation as Pandoc's --from -# parameter, specified here: -#     https://pandoc.org/MANUAL.html#option--from-# Example: markdown, rst+raw_tex-caption_format: markdown+tex_math_dollars---# Logging configuration-logging:-  # Possible verbosity values: debug, error, warning, info, silent-  verbosity: warning-  # If the filepath below is not present, then pandoc-plot will log to stderr-  # Otherwise, log messages will be appended to the filepath.-  # filepath: path/to/file.txt--# The possible parameters for the Matplotlib toolkit-matplotlib:-  # preamble: matplotlib.py-  tight_bbox: false-  transparent: false-  executable: python-  command_line_arguments:--# The possible parameters for the MATLAB toolkit-matlabplot:-  # preamble: matlab.m-  executable: matlab-  command_line_arguments:--# The possible parameters for the Plotly/Python toolkit-plotly_python:-  # preamble: plotly-python.py-  executable: python-  command_line_arguments:--# The possible parameters for the Plotly/R toolkit-plotly_r:-  # preamble: plotly-r.r-  executable: Rscript-  command_line_arguments:--# The possible parameters for the Mathematica toolkit-mathplot:-  # preamble: mathematica.m-  executable: math-  command_line_arguments:--# The possible parameters for the GNU Octave toolkit-octaveplot:-  # preamble: octave.m-  executable: octave-  command_line_arguments:--# The possible parameters for the ggplot2 toolkit-ggplot2:-  # preamble: ggplot2.r-  executable: Rscript-  command_line_arguments:--# The possible parameters for the gnuplot toolkit-gnuplot:-  # preamble: gnuplot.gp-  executable: gnuplot-  command_line_arguments:--# The possible parameters for the graphviz toolkit-graphviz:-  # preamble: graphviz.dot-  executable: dot-  command_line_arguments:--bokeh:-  # preamble: bokeh.py-  executable: python-  command_line_arguments:--plotsjl:-  # preamble: plotsjl.jl-  executable: julia-  command_line_arguments:--plantuml:-  # preamble: plantuml.txt-  executable: java-  command_line_arguments: -jar plantuml.jar-  # On Linux, if you have `plantuml.jar` as an executable, you can also-  # use the following configuration instead:-  # plantuml:-  #   executable: plantuml-  #   command_line_arguments:-```--A file like the above sets the **default** values; you can still override them in documents directly.--The easiest way to specify configuration for `pandoc-plot` is to place a `.pandoc-plot.yml` file in the current working directory. You can also specify a configuration file in document metadata, under the `plot-configuration` key. For example, in Markdown:--``` markdown-----title: My document-author: John Doe-plot-configuration: /path/to/file.yml-----```--or on the command line, using the pandoc `-M/--metadata` flag:--``` bash-pandoc --filter pandoc-plot -M plot-configuration=/path/to/file.yml ...-```--The hierarchy of configuration files is as follows:--1.  A configuration file specified in the metadata under the `plot-configuration` key;-2.  Otherwise, a file in the current working directory named `.pandoc-plot.yml`;-3.  Finally, the default configuration is used.--#### Executables--The `executable` parameter for all toolkits can be either the executable name (if it is present on the PATH), or the full path to the executable.--Examples:--``` yaml-matplotlib:-  executable: python3-```--``` yaml-matlabplot:-  executable: "C:\Program Files\Matlab\R2019b\bin\matlab.exe"-```--#### Command-line arguments--*New in version 1.0.2.0*--The `command_line_arguments` parameter available for all toolkits provides a way to customize the way interpreters are run. For example, if you want to run the `matplotlib` toolkit with all warnings shown:--``` yaml-# The possible parameters for the Matplotlib toolkit-matplotlib:-  executable: python-  command_line_arguments: -Wa-```--Or if you want `julia` to use more than one thread:--``` yaml-# The possible parameters for the Matplotlib toolkit-plotsjl:-  executable: julia-  command_line_arguments: --threads auto-```--#### Toolkit-specific options--##### Matplotlib---   `tight_bbox` is a boolean that determines whether to use `bbox_inches="tight"` or not when saving Matplotlib figures. For example, `tight_bbox: true`. See [here](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.savefig.html) for details.--   `transparent` is a boolean that determines whether to make Matplotlib figure background transparent or not. This is useful, for example, for displaying a plot on top of a colored background on a web page. High-resolution figures are not affected. For example, `transparent: true`.--#### Logging--If you are running `pandoc-plot` on a large document, you might want to turn on logging. You can do so via the configuration file as follows:--``` yaml-logging:-    # Possible verbosity values: debug, error, warning, info, silent-    # debug level shows all messages-    # error level shows all but debug messages, etc.-    verbosity: info-    -    # OPTIONAL: log to file-    # Remove line below to log to stderr-    filepath: log.txt-```--By default, `pandoc-plot` logs warnings and errors to the standard error stream only.--#### Strict mode--*New in version 1.0.2.0*--By default, `pandoc-plot` leaves code blocks unchanged if a figure fails to be rendered. This might be the case if a plotting toolkit is not installed, or if running the code to render a figure returns an error. In **strict mode**, `pandoc-plot` will immediately halt if it encounters a problem. You can activate strict mode via configuration:--``` yaml-strict: true-```--Strict mode is ideal if you want to ensure that the figures are correctly rendered in the document.--### Other commands--#### Finding installed toolkits--You can determine which toolkits are available on your current machine using the `pandoc-plot toolkits` command. Here is the full help text:--``` bash-Usage: pandoc-plot.EXE toolkits [--config PATH]-  Show information on toolkits and exit.--Available options:-  --config PATH            Path to optional configuration file.-  -h,--help                Show this help text-```--#### Cleaning output--Figures produced by `pandoc-plot` can be placed in a few different locations. You can set a default location in the [Configuration](#configuration), but you can also re-direct specific figures in other directories if you use the `directory=...` argument in code blocks. These figures will build up over time. You can use the `clean` command to scan documents and delete the associated `pandoc-plot` output files. For example, to delete the figures generated from the `input.md` file:--``` bash-pandoc-plot clean input.md-```--This sill remove all directories where a figure *could* have been placed. **WARNING**: all files will be removed.--Here is the full help text for the `clean` command:--``` bash-Usage: pandoc-plot.EXE clean [--config PATH] FILE-  Clean output directories where figures from FILE and log files might be-  stored. WARNING: All files in those directories will be deleted.--Available options:-  --config PATH            Path to optional configuration file.-  -h,--help                Show this help text-```--#### Configuration template--Because `pandoc-plot` supports a few toolkits, there are a lot of configuration options. Don’t start from scratch! The `write-example-config` command will create a file for you, which you can then modify:--``` bash-pandoc-plot write-example-config-```--You will need to re-name the file to `.pandoc-ploy.yml` to be able to use it, so don’t worry about overwriting your own configuration.--Here is the full help text for the `write-example-config` command:--``` bash-Usage: pandoc-plot.EXE write-example-config [--path FILE]-  Write example configuration to a file and exit.--Available options:-  --path FILE              Target location of the configuration file. Default is-                           ".example-pandoc-plot.yml"-  -h,--help                Show this help text-```--### As a Haskell library--To include the functionality of `pandoc-plot` in a Haskell package, you can use the `make` function (for single blocks) or `plotFilter` function (for entire documents). [Take a look at the documentation on Hackage](https://hackage.haskell.org/package/pandoc-plot).--#### Usage with Hakyll--In case you want to use the filter with your own Hakyll setup, you can use a transform function that works on entire documents:--``` haskell-import Text.Pandoc.Filter.Plot (plotFilter, defaultConfiguration)-import Text.Pandoc.Definition (Pandoc, Format(..)) -- from pandoc-types-import Hakyll--plotFilter' :: Pandoc -> IO Pandoc-plotFilter' = -  -- Notify pandoc-plot that the final conversion will be to HTML-  -- This helps give better error messages and adjust default values-  plotFilter defaultConfiguration (Just $ Format "html5") ---- Unsafe compiler is required because of the interaction--- in IO (i.e. running an external script).-makePlotPandocCompiler :: Compiler (Item String)-makePlotPandocCompiler = -  pandocCompilerWithTransformM-    defaultHakyllReaderOptions-    defaultHakyllWriterOptions-    (unsafeCompiler . plotFilter')-```--## Warning--Do not run this filter on unknown documents. There is nothing in `pandoc-plot` that can stop a script from performing **evil actions**.+<!--
+The file MANUAL.md is automatically generated by the tools/mkmanual.ps1 script. Do not edit manually.
+-->
+
+## A Pandoc filter to generate figures from code blocks in documents
+
+`pandoc-plot` turns code blocks present in your documents (Markdown, LaTeX, etc.) into embedded figures, using your plotting toolkit of choice, including Matplotlib, ggplot2, MATLAB, Mathematica, and more.
+
+-   [Features Overview](#features-overview)
+    -   [Captions](#captions)
+    -   [Link to source code](#link-to-source-code)
+    -   [Preamble scripts](#preamble-scripts)
+    -   [Support for interactive plots](#support-for-interactive-plots)
+    -   [Performance](#performance)
+    -   [Compatibility with pandoc-crossref](#compatibility-with-pandoc-crossref)
+-   [Detailed usage](#detailed-usage)
+    -   [As a filter](#as-a-filter)
+    -   [Syntax](#syntax)
+        -   [Markdown](#markdown)
+        -   [LaTeX](#latex)
+    -   [Parameters and options](#parameters-and-options)
+        -   [Code highlighting](#code-highlighting)
+    -   [Interactive HTML figures](#interactive-html-figures)
+    -   [Configuration](#configuration)
+        -   [Executables](#executables)
+        -   [Command-line arguments](#command-line-arguments)
+        -   [Toolkit-specific options](#toolkit-specific-options)
+        -   [Logging](#logging)
+        -   [Strict mode](#strict-mode)
+    -   [Other commands](#other-commands)
+        -   [Finding installed toolkits](#finding-installed-toolkits)
+        -   [Cleaning output](#cleaning-output)
+        -   [Configuration template](#configuration-template)
+    -   [As a Haskell library](#as-a-haskell-library)
+        -   [Usage with Hakyll](#usage-with-hakyll)
+-   [Warning](#warning)
+
+## Features Overview
+
+### Captions
+
+You can also specify a caption for your image. This is done using the optional `caption` parameter.
+
+**Markdown**:
+
+```` markdown
+```{.matlabplot caption="This is a simple figure with a **Markdown** caption"}
+x  = 0: .1 : 2*pi;
+y1 = cos(x);
+y2 = sin(x);
+
+figure
+plot(x, y1, 'b', x, y2, 'r-.', 'LineWidth', 2)
+```
+````
+
+**LaTex**:
+
+``` latex
+\begin{minted}[caption=This is a simple figure with a caption]{matlabplot}
+x  = 0: .1 : 2*pi;
+y1 = cos(x);
+y2 = sin(x);
+
+figure
+plot(x, y1, 'b', x, y2, 'r-.', 'LineWidth', 2)
+\end{minted}
+```
+
+Caption formatting unfortunately cannot be determined automatically. To specify a caption format (e.g. “markdown”, “LaTeX”, etc.), see [Configuration](#configuration).
+
+### Link to source code
+
+In case of an output format that supports links (e.g. HTML), the embedded image generated by `pandoc-plot` can show a link to the source code which was used to generate the file. Therefore, other people can see what code was used to create your figures.
+
+You can turn this on via the `source=true` key:
+
+**Markdown**:
+
+```` markdown
+```{.mathplot source=true}
+...
+```
+````
+
+**LaTex**:
+
+``` latex
+\begin{minted}[source=true]{mathplot}
+...
+\end{minted}
+```
+
+or via a [configuration file](#Configuration).
+
+### Preamble scripts
+
+If you find yourself always repeating some steps, inclusion of scripts is possible using the `preamble` parameter. For example, if you want all Matplotlib plots to have the [`ggplot`](https://matplotlib.org/tutorials/introductory/customizing.html#sphx-glr-tutorials-introductory-customizing-py) style, you can write a very short preamble `style.py` like so:
+
+``` python
+import matplotlib.pyplot as plt
+plt.style.use('ggplot')
+```
+
+and include it in your document as follows:
+
+```` markdown
+```{.matplotlib preamble=style.py}
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
+```
+````
+
+Which is equivalent to writing the following markdown:
+
+```` markdown
+```{.matplotlib}
+import matplotlib.pyplot as plt
+plt.style.use('ggplot')
+
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
+```
+````
+
+The equivalent LaTeX usage is as follows:
+
+``` latex
+\begin{minted}[include=style.py]{matplotlib}
+
+\end{minted}
+```
+
+This `preamble` parameter is perfect for longer documents with many plots. Simply define the style you want in a separate script! You can also import packages this way, or define functions you often use.
+
+### Support for interactive plots
+
+Starting with version 0.8.0.0, `pandoc-plot` supports the creation of interactive plots (if a toolkit supports it). All you need to do is set the save format to `html`. The resulting plot is fully self-contained, so it can be displayed offline.
+
+### Performance
+
+`pandoc-plot` minimizes work, only generating figures if it absolutely must, i.e. if the content has changed. `pandoc-plot` will save the hash of the source code used to generate a figure in its filename. Before generating a figure, `pandoc-plot` will check it this figure already exists based on the hash of its source! This also means that there is no way to directly name figures.
+
+Moreover, starting with version 0.5.0.0, `pandoc-plot` takes advantage of multicore CPUs, rendering figures **in parallel**.
+
+Therefore, you can confidently run the filter on very large documents containing hundreds of figures, like a book or a thesis.
+
+### Compatibility with pandoc-crossref
+
+[`pandoc-crossref`](https://github.com/lierdakil/pandoc-crossref) is a pandoc filter that makes it effortless to cross-reference objects in Markdown documents.
+
+You can use `pandoc-crossref` in conjunction with `pandoc-plot` for the ultimate figure-making pipeline. You can combine both in a figure like so:
+
+```` markdown
+```{#fig:myexample .plotly_python caption="This is a caption"}
+# Insert figure script here
+```
+
+As you can see in @fig:myexample, ...
+````
+
+If the above source is located in file `myfile.md`, you can render the figure and references by applying `pandoc-plot` **first**, and then `pandoc-crossref`. For example:
+
+``` bash
+pandoc --filter pandoc-plot --filter pandoc-crossref -i myfile.md -o myfile.html
+```
+
+## Detailed usage
+
+`pandoc-plot` is a command line executable with a few functions. You can take a look at the help using the `-h`/`--help` flag:
+
+``` bash
+pandoc-plot 1.3.0 - generate figures directly in documents
+
+Usage: pandoc-plot.EXE [(-v|--version) | --full-version | (-m|--manual)] 
+                       [COMMAND] [AST]
+  This pandoc filter generates plots from code blocks using a multitude of
+  possible renderers. This allows to keep documentation and figures in perfect
+  synchronicity.
+
+Available options:
+  -v,--version             Show version number and exit.
+  --full-version           Show full version information and exit.
+  -m,--manual              Open the manual page in the default web browser and
+                           exit.
+  -h,--help                Show this help text
+
+Available commands:
+  toolkits                 Show information on toolkits and exit.
+  clean                    Clean output directories where figures from FILE and
+                           log files might be stored. WARNING: All files in
+                           those directories will be deleted.
+  write-example-config     Write example configuration to a file and exit.
+
+More information can be found via the manual (pandoc-plot --manual) or the
+repository README, located at https://github.com/LaurentRDC/pandoc-plot
+```
+
+### As a filter
+
+The most common use for `pandoc-plot` is as a pandoc filter, in which case it should be called without arguments. For example:
+
+``` bash
+pandoc --filter pandoc-plot -i input.md -o output.html
+```
+
+If `pandoc-plot` fails to render a code block into a figure, the filtering will not stop. Your code blocks will stay unchanged, unless you activate [strict mode](#strict-mode).
+
+You can chain other filters with it (e.g., [`pandoc-crossref`](https://github.com/lierdakil/pandoc-crossref)) like so:
+
+``` bash
+pandoc --filter pandoc-plot --filter pandoc-crossref -i input.md -o output.html
+```
+
+### Syntax
+
+The syntax for code blocks in documents is shown below. `pandoc-plot` looks for code blocks with a specific class, depending on the toolkit you want to use. `pandoc-plot` will run the code and capture the figure output. There can only be **one** figure per code block.
+
+The possible parameters and options are described in [further below](#parameters-and-options).
+
+#### Markdown
+
+```` markdown
+  ```{.cls param1=value1 param2=value2 ...}
+  # script content
+  ```
+````
+
+#### LaTeX
+
+Note that the `minted` LaTeX package need not be installed.
+
+``` latex
+\begin{minted}[param1=value1, param2=value2, ...]{cls}
+...
+\end{minted}
+```
+
+### Parameters and options
+
+There are parameters that affect the figure that will be included in your document. Here are all the possible general parameters, in Markdown syntax:
+
+```` markdown
+  ```{.cls 
+      .language
+      directory=(path) 
+      caption=(text) 
+      format=(PNG|PDF|SVG|JPG|EPS|GIF|TIF|WEBP|HTML|LATEX) 
+      source=(true|True|false|False) 
+      source_label=(text)
+      preamble=(path) 
+      dpi=(integer)
+      dependencies=[...]
+      file=(path)
+      executable=(path) 
+      caption_format=(text)
+      }
+  # script content
+  ```
+````
+
+-   `cls` must be one of the following: `matplotlib`, `matlabplot`, `plotly_python`, `plotly_r`, `mathplot`, `octaveplot`, `ggplot2`, `gnuplot`, `graphviz`, `bokeh`, `plotsjl`, `plantuml` (*new in version 1.1.0*).
+
+All following parameters are optional, with their default values controlled by the [configuration](#configuration).
+
+-   `language` specifies the programming language used in this block. This parameter is ignored by `pandoc-plot`, but your text editor may use it to highlight code. See [Code highlighting](#code-highlighting) below.
+-   `directory` is a path to the directory where the figure and source code will be saved. You cannot control the file name. This path is either absolute, or relative from the working directory where you call `pandoc-plot`.
+-   `caption` is the caption text. The format of the caption is specified in the `caption_format` parameter, described below.
+-   `format` is the desired filetype for the resulting figure. Possible values for `format` are \[`PNG`, `PDF`, `SVG`, `JPG`, `EPS`, `GIF`, `TIF`, `WEBP`, `HTML`, `LATEX`\]. Not all toolkits support all formats. See `pandoc-plot toolkits` for toolkit-specific information regarding save formats. The `HTML` format is special; it can produce standalone, offline, interactive plots. As such, it only makes sense to use this format when creating HTML documents. Similarly, the `LATEX` format is special; plots in the LaTeX format will be embedded in the document. Therefore, it only makes sense to use this format when creating LaTeX documents.
+-   `source` is a boolean toggle that determines whether the source code should be linked in the caption or not. Possible values are \[`true`, `True`, `false`, `False`\].
+-   `source_label` is the text that links to source code (if `source=true`). This is useful if you are writing text in a different language. The default is `source_label="Source Code"`. You might want to set this via the [configuration](#configuration) instead.
+-   `preamble` is a path to a script that will be included as a preamble to the content of the code block. This path is either absolute, or relative from the working directory where you call `pandoc-plot`.
+-   `dpi` is the pixel density of the figure in dots-per-inch. Possible values are positive integers. Not all toolkits respect this.
+-   `dependencies` is a list of files/directories that affect the figure, for example data files. If one of those files/directories changes, `pandoc-plot` will re-render the associated figure. Format is a comma-separated list, e.g. `dependencies=[data.txt, foo.bar, ~/wtv]`. Values for `dependencies` in the configuration file will be appended to the values in a code block.
+-   `file` is a path to a file from which to read the figure content. If this parameter is used, the content of the code block is ignored. By using this parameter, you can use all the standard tooling of your plotting toolkit of choice, which is especially useful for complex figures.
+-   `executable` is a path to the executable to use (e.g. `C:\\python3.exe`) or the name of the executable (e.g. `python3`).
+-   `caption_format` is the text format of the caption. Possible values are exactly the same as `pandoc`’s format specification, usually `FORMAT+EXTENSION-EXTENSION`. For example, captions in Markdown with raw LaTeX would be parsed correctly provided that `caption_format=markdown+raw_tex`. See Pandoc’s guide on [Specifying formats](https://pandoc.org/MANUAL.html#specifying-formats).
+
+#### Code highlighting
+
+If your editor supports code highlighting in code blocks, you can also include the programming language. In Markdown:
+
+```` markdown
+  ```{.language .cls (options)}
+  # script content
+  ```
+````
+
+or Latex:
+
+``` latex
+  \begin{minted}[(options)]{language, cls}
+  # script content
+  \end{minted}
+```
+
+For example, for GGPlot2 figures:
+
+```` markdown
+  ```{.r .ggplot2 caption=Highlighted code block}
+  # script content
+  ```
+````
+
+or (Latex):
+
+``` latex
+  \begin{minted}[caption=Highlighted code block]{r, ggplot2}
+  # script content
+  \end{minted}
+```
+
+This way, you benefit from code highlighting *and* `pandoc-plot`.
+
+### Interactive HTML figures
+
+Interactive HTML figures are available for a few toolkits, e.g. `bokeh`. To make a figure interactive, use the output format `format=html`. This only makes sense if your output file is also HTML.
+
+You can take a look at the [demonstration page](https://laurentrdc.github.io/pandoc-plot/) for an example result.
+
+Many interactive plots rely on javascript scripts stored on the internet. If you want to have a self-contained document that can be viewed offline – or you want your document to work for the next 10 years –, you can use pandoc’s `--self-contained` flag:
+
+``` bash
+pandoc --self-contained --filter pandoc-plot -i mydoc.md -o webpage.html 
+```
+
+The resulting output `webpage.html` will contain everything, at the cost of size.
+
+### Configuration
+
+To avoid repetition, `pandoc-plot` can be configured using simple YAML
+files. Here are **all** the possible parameters:
+
+``` yaml
+# This is an example configuration. Everything in this file is optional.
+# Please refer to the documentation to know about the parameters herein.
+#
+# The `executable` parameter for all toolkits can be either the
+# executable name (if it is present on the PATH), or
+# the full path to the executable.
+# E.g.:
+#  executable: python3
+#  executable: "C:\Python37\Scripts\python.exe"
+
+# The following parameters affect all toolkits
+# Directory where to save the plots. The path can be relative to pandoc-plot's
+# current working directory, or absolute.
+directory: plots/
+
+# Whether or not to include a link to the source script in the caption. 
+# Particularly useful for HTML output.
+source: false
+
+# When `strict: false`, pandoc-plot will leave code blocks untouched if a plot
+# could not be generated. This could happen if, for example, a toolkit is not
+# installed. If you want pandoc-plot to fail instead, use `strict: true`.
+strict: false
+
+# Text label for links to source code.
+# You can change this label if you are writing a document in a non-English language. 
+# This only matters if `source` is set to `true`.
+source_label: Source code
+
+# Default density of figures in dots per inches (DPI). 
+# This can be changed in the document specifically as well.
+dpi: 80
+
+# Default format in which to save the figures. This can be specified 
+# individually as well.
+format: PNG
+
+# Default files/directories on which all figures depend. If any of these files/directories
+# changes, all figures will be re-rendered.
+# Dependencies specified in code blocks will be appended to this list.
+dependencies:
+  - file1.txt
+  - file2.txt
+
+# Text format for the captions. Unfortunately, there is no way to detect
+# this automatically. You can use the same notation as Pandoc's --from 
+# parameter, specified here: 
+#     https://pandoc.org/MANUAL.html#option--from
+# Example: markdown, rst+raw_tex
+caption_format: markdown+tex_math_dollars
+
+
+# Logging configuration
+logging:
+  # Possible verbosity values: debug, error, warning, info, silent
+  verbosity: warning
+  # If the filepath below is not present, then pandoc-plot will log to stderr
+  # Otherwise, log messages will be appended to the filepath.
+  # filepath: path/to/file.txt
+
+# The possible parameters for the Matplotlib toolkit
+matplotlib:
+  # preamble: matplotlib.py
+  tight_bbox: false
+  transparent: false
+  executable: python
+  command_line_arguments:
+
+# The possible parameters for the MATLAB toolkit
+matlabplot:
+  # preamble: matlab.m
+  executable: matlab
+  command_line_arguments:
+
+# The possible parameters for the Plotly/Python toolkit
+plotly_python:
+  # preamble: plotly-python.py
+  executable: python
+  command_line_arguments:
+
+# The possible parameters for the Plotly/R toolkit
+plotly_r:
+  # preamble: plotly-r.r
+  executable: Rscript
+  command_line_arguments:
+
+# The possible parameters for the Mathematica toolkit
+mathplot:
+  # preamble: mathematica.m
+  executable: math
+  command_line_arguments:
+
+# The possible parameters for the GNU Octave toolkit
+octaveplot:
+  # preamble: octave.m
+  executable: octave
+  command_line_arguments:
+
+# The possible parameters for the ggplot2 toolkit
+ggplot2:
+  # preamble: ggplot2.r
+  executable: Rscript
+  command_line_arguments:
+
+# The possible parameters for the gnuplot toolkit
+gnuplot:
+  # preamble: gnuplot.gp
+  executable: gnuplot
+  command_line_arguments:
+
+# The possible parameters for the graphviz toolkit
+graphviz:
+  # preamble: graphviz.dot
+  executable: dot
+  command_line_arguments:
+
+bokeh:
+  # preamble: bokeh.py
+  executable: python
+  command_line_arguments:
+
+plotsjl:
+  # preamble: plotsjl.jl
+  executable: julia
+  command_line_arguments:
+
+plantuml:
+  # preamble: plantuml.txt
+  executable: java
+  command_line_arguments: -jar plantuml.jar
+  # On Linux, if you have `plantuml.jar` as an executable, you can also
+  # use the following configuration instead:
+  # plantuml:
+  #   executable: plantuml
+  #   command_line_arguments:
+```
+
+A file like the above sets the **default** values; you can still override them in documents directly.
+
+The easiest way to specify configuration for `pandoc-plot` is to place a `.pandoc-plot.yml` file in the current working directory. You can also specify a configuration file in document metadata, under the `plot-configuration` key. For example, in Markdown:
+
+``` markdown
+---
+title: My document
+author: John Doe
+plot-configuration: /path/to/file.yml
+---
+```
+
+or on the command line, using the pandoc `-M/--metadata` flag:
+
+``` bash
+pandoc --filter pandoc-plot -M plot-configuration=/path/to/file.yml ...
+```
+
+The hierarchy of configuration files is as follows:
+
+1.  A configuration file specified in the metadata under the `plot-configuration` key;
+2.  Otherwise, a file in the current working directory named `.pandoc-plot.yml`;
+3.  Finally, the default configuration is used.
+
+#### Executables
+
+The `executable` parameter for all toolkits can be either the executable name (if it is present on the PATH), or the full path to the executable.
+
+Examples:
+
+``` yaml
+matplotlib:
+  executable: python3
+```
+
+``` yaml
+matlabplot:
+  executable: "C:\Program Files\Matlab\R2019b\bin\matlab.exe"
+```
+
+#### Command-line arguments
+
+*New in version 1.0.2.0*
+
+The `command_line_arguments` parameter available for all toolkits provides a way to customize the way interpreters are run. For example, if you want to run the `matplotlib` toolkit with all warnings shown:
+
+``` yaml
+# The possible parameters for the Matplotlib toolkit
+matplotlib:
+  executable: python
+  command_line_arguments: -Wa
+```
+
+Or if you want `julia` to use more than one thread:
+
+``` yaml
+# The possible parameters for the Matplotlib toolkit
+plotsjl:
+  executable: julia
+  command_line_arguments: --threads auto
+```
+
+#### Toolkit-specific options
+
+##### Matplotlib
+
+-   `tight_bbox` is a boolean that determines whether to use `bbox_inches="tight"` or not when saving Matplotlib figures. For example, `tight_bbox: true`. See [here](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.savefig.html) for details.
+-   `transparent` is a boolean that determines whether to make Matplotlib figure background transparent or not. This is useful, for example, for displaying a plot on top of a colored background on a web page. High-resolution figures are not affected. For example, `transparent: true`.
+
+#### Logging
+
+If you are running `pandoc-plot` on a large document, you might want to turn on logging. You can do so via the configuration file as follows:
+
+``` yaml
+logging:
+    # Possible verbosity values: debug, error, warning, info, silent
+    # debug level shows all messages
+    # error level shows all but debug messages, etc.
+    verbosity: info
+    
+    # OPTIONAL: log to file
+    # Remove line below to log to stderr
+    filepath: log.txt
+```
+
+By default, `pandoc-plot` logs warnings and errors to the standard error stream only.
+
+#### Strict mode
+
+*New in version 1.0.2.0*
+
+By default, `pandoc-plot` leaves code blocks unchanged if a figure fails to be rendered. This might be the case if a plotting toolkit is not installed, or if running the code to render a figure returns an error. In **strict mode**, `pandoc-plot` will immediately halt if it encounters a problem. You can activate strict mode via configuration:
+
+``` yaml
+strict: true
+```
+
+Strict mode is ideal if you want to ensure that the figures are correctly rendered in the document.
+
+### Other commands
+
+#### Finding installed toolkits
+
+You can determine which toolkits are available on your current machine using the `pandoc-plot toolkits` command. Here is the full help text:
+
+``` bash
+Usage: pandoc-plot.EXE toolkits [--config PATH]
+  Show information on toolkits and exit.
+
+Available options:
+  --config PATH            Path to optional configuration file.
+  -h,--help                Show this help text
+```
+
+#### Cleaning output
+
+Figures produced by `pandoc-plot` can be placed in a few different locations. You can set a default location in the [Configuration](#configuration), but you can also re-direct specific figures in other directories if you use the `directory=...` argument in code blocks. These figures will build up over time. You can use the `clean` command to scan documents and delete the associated `pandoc-plot` output files. For example, to delete the figures generated from the `input.md` file:
+
+``` bash
+pandoc-plot clean input.md
+```
+
+This sill remove all directories where a figure *could* have been placed. **WARNING**: all files will be removed.
+
+Here is the full help text for the `clean` command:
+
+``` bash
+Usage: pandoc-plot.EXE clean [--config PATH] FILE
+  Clean output directories where figures from FILE and log files might be
+  stored. WARNING: All files in those directories will be deleted.
+
+Available options:
+  --config PATH            Path to optional configuration file.
+  -h,--help                Show this help text
+```
+
+#### Configuration template
+
+Because `pandoc-plot` supports a few toolkits, there are a lot of configuration options. Don’t start from scratch! The `write-example-config` command will create a file for you, which you can then modify:
+
+``` bash
+pandoc-plot write-example-config
+```
+
+You will need to re-name the file to `.pandoc-ploy.yml` to be able to use it, so don’t worry about overwriting your own configuration.
+
+Here is the full help text for the `write-example-config` command:
+
+``` bash
+Usage: pandoc-plot.EXE write-example-config [--path FILE]
+  Write example configuration to a file and exit.
+
+Available options:
+  --path FILE              Target location of the configuration file. Default is
+                           ".example-pandoc-plot.yml"
+  -h,--help                Show this help text
+```
+
+### As a Haskell library
+
+To include the functionality of `pandoc-plot` in a Haskell package, you can use the `make` function (for single blocks) or `plotFilter` function (for entire documents). [Take a look at the documentation on Hackage](https://hackage.haskell.org/package/pandoc-plot).
+
+#### Usage with Hakyll
+
+In case you want to use the filter with your own Hakyll setup, you can use a transform function that works on entire documents:
+
+``` haskell
+import Text.Pandoc.Filter.Plot (plotFilter, defaultConfiguration)
+import Text.Pandoc.Definition (Pandoc, Format(..)) -- from pandoc-types
+import Hakyll
+
+plotFilter' :: Pandoc -> IO Pandoc
+plotFilter' = 
+  -- Notify pandoc-plot that the final conversion will be to HTML
+  -- This helps give better error messages and adjust default values
+  plotFilter defaultConfiguration (Just $ Format "html5") 
+
+-- Unsafe compiler is required because of the interaction
+-- in IO (i.e. running an external script).
+makePlotPandocCompiler :: Compiler (Item String)
+makePlotPandocCompiler = 
+  pandocCompilerWithTransformM
+    defaultHakyllReaderOptions
+    defaultHakyllWriterOptions
+    (unsafeCompiler . plotFilter')
+```
+
+## Warning
+
+Do not run this filter on unknown documents. There is nothing in `pandoc-plot` that can stop a script from performing **evil actions**.
README.md view
@@ -1,169 +1,170 @@-# pandoc-plot --## A Pandoc filter to generate figures from code blocks in documents--[![license](https://img.shields.io/badge/license-GPLv2+-lightgray.svg)](https://www.gnu.org/licenses/gpl.html) --`pandoc-plot` turns code blocks present in your documents (Markdown, LaTeX, etc.) into embedded figures, using your plotting toolkit of choice, including Matplotlib, ggplot2, MATLAB, Mathematica, and more.--## Overview--This program is a [Pandoc](https://pandoc.org/) filter. It can therefore-be used in the middle of conversion from input format to output format,-replacing code blocks with figures.--The filter recognizes code blocks with classes that match plotting-toolkits. For example, using the `matplotlib` toolkit:--```` markdown-# My document--This is a paragraph.--```{.matplotlib}-import matplotlib.pyplot as plt--plt.figure()-plt.plot([0,1,2,3,4], [1,2,3,4,5])-plt.title('This is an example figure')-```-````--Putting the above in `input.md`, we can then generate the plot and embed-it in an HTML page:--``` bash-pandoc --filter pandoc-plot input.md --output output.html-```--The resulting `output.html` looks like this:--```html-<h1 id="my-document">My document</h1>--<p>This is a paragraph.</p>--<figure>-<img src="plots\9671478262050082276.png" />-</figure>-```--## Supported toolkits--`pandoc-plot` currently supports the following plotting toolkits-(**installed separately**):--  - `matplotlib`: plots using the [matplotlib](https://matplotlib.org/)-    Python library;-  - `plotly_python` : plots using the-    [plotly](https://plotly.com/python/) Python library;-  - `plotly_r`: plots using the [plotly](https://plotly.com/r/) R-    library-  - `matlabplot`: plots using [MATLAB](https://www.mathworks.com/);-  - `mathplot` : plots using-    [Mathematica](https://www.wolfram.com/mathematica/);-  - `octaveplot`: plots using [GNU-    Octave](https://www.gnu.org/software/octave/);-  - `ggplot2`: plots using [ggplot2](https://ggplot2.tidyverse.org/);-  - `gnuplot`: plots using [gnuplot](http://www.gnuplot.info/);-  - `graphviz`: graphs using [Graphviz](http://graphviz.org/);-  - `bokeh`: plots using the [Bokeh](https://bokeh.org/) visualization library;-  - `plotsjl`: plots using the [Julia `Plots.jl`](https://docs.juliaplots.org/latest/) package;-  - `plantuml`: diagrams using the [PlantUML](https://plantuml.com/) software suite;-  - `sageplot`: plots using the [Sage](https://www.sagemath.org/) software system.-  - `d2`: plots using [D2](https://d2lang.com/). --To know which toolkits are useable on *your machine* (and which ones are-not available), you can check with the `toolkits` command:--``` bash-pandoc-plot toolkits-```--**Wish your plotting toolkit of choice was available? Please [raise an-issue](https://github.com/LaurentRDC/pandoc-plot/issues)\!**--## Documentation--You can find more information in the documentation, available either in the-source repository file `MANUAL.md`, on the [webpage](https://laurentrdc.github.io/pandoc-plot/MANUAL.html), or via the command `pandoc-plot --manual`.--## Installation--### Binaries and Installers--[![Latest release](https://img.shields.io/github/v/release/LaurentRDC/pandoc-plot)](https://github.com/LaurentRDC/pandoc-plot/releases)--Windows, Linux, and Mac OS binaries are available on the [GitHub release-page](https://github.com/LaurentRDC/pandoc-plot/releases). There are-also Windows installers.--### conda--[![Conda Version](https://anaconda.org/conda-forge/pandoc-plot/badges/version.svg)](https://anaconda.org/conda-forge/pandoc-plot)--Like `pandoc`, `pandoc-plot` is available as a package installable with-[`conda`](https://docs.conda.io/en/latest/). [Click here to see the-package page](https://anaconda.org/conda-forge/pandoc-plot).--To install in the current environment:--``` sh-conda install -c conda-forge pandoc-plot-```--### Homebrew --[![homebrew version](https://img.shields.io/homebrew/v/pandoc-plot)](https://formulae.brew.sh/formula/pandoc-plot)--`pandoc-plot` is available as a package via [`Homebrew`](https://brew.sh/). [Click here to see the package page](https://formulae.brew.sh/formula/pandoc-plot#default). --To install:--```sh-brew install pandoc-plot-```--### winget--You can install `pandoc-plot` from the [Windows Package-Manager](https://github.com/microsoft/winget-cli) `winget` (just like-`pandoc`). To install:--``` sh-winget install pandoc-plot-```--### Arch Linux--[![AUR version](https://img.shields.io/aur/version/pandoc-plot-bin)](https://aur.archlinux.org/packages/pandoc-plot-bin/)--You can install `pandoc-plot` from the [archlinux user repository](https://aur.archlinux.org/packages/pandoc-plot-bin/) as `pandoc-plot-bin`. You can install using e.g. `yay`:--```sh-yay -S pandoc-plot-bin-```--### From Hackage/Stackage--[![Hackage version](https://img.shields.io/hackage/v/pandoc-plot.svg)](http://hackage.haskell.org/package/pandoc-plot)--`pandoc-plot` is available on-[Hackage](http://hackage.haskell.org/package/pandoc-plot) and-[Stackage](https://www.stackage.org/nightly/package/pandoc-plot). Using-the [`cabal-install`](https://www.haskell.org/cabal/) tool:--``` bash-cabal update-cabal install-```--### From source--Building from source can be done using [`cabal`](https://www.haskell.org/cabal/):--``` bash-git clone https://github.com/LaurentRDC/pandoc-plot-cd pandoc-plot-cabal install # Alternatively, `stack install`-```+# pandoc-plot 
+
+## A Pandoc filter to generate figures from code blocks in documents
+
+[![license](https://img.shields.io/badge/license-GPLv2+-lightgray.svg)](https://www.gnu.org/licenses/gpl.html) 
+
+`pandoc-plot` turns code blocks present in your documents (Markdown, LaTeX, etc.) into embedded figures, using your plotting toolkit of choice, including Matplotlib, ggplot2, MATLAB, Mathematica, and more.
+
+## Overview
+
+This program is a [Pandoc](https://pandoc.org/) filter. It can therefore
+be used in the middle of conversion from input format to output format,
+replacing code blocks with figures.
+
+The filter recognizes code blocks with classes that match plotting
+toolkits. For example, using the `matplotlib` toolkit:
+
+```` markdown
+# My document
+
+This is a paragraph.
+
+```{.matplotlib}
+import matplotlib.pyplot as plt
+
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
+```
+````
+
+Putting the above in `input.md`, we can then generate the plot and embed
+it in an HTML page:
+
+``` bash
+pandoc --filter pandoc-plot input.md --output output.html
+```
+
+The resulting `output.html` looks like this:
+
+```html
+<h1 id="my-document">My document</h1>
+
+<p>This is a paragraph.</p>
+
+<figure>
+<img src="plots\9671478262050082276.png" />
+</figure>
+```
+
+## Supported toolkits
+
+`pandoc-plot` currently supports the following plotting toolkits
+(**installed separately**):
+
+  - `matplotlib`: plots using the [matplotlib](https://matplotlib.org/)
+    Python library;
+  - `plotly_python` : plots using the
+    [plotly](https://plotly.com/python/) Python library;
+  - `plotly_r`: plots using the [plotly](https://plotly.com/r/) R
+    library
+  - `matlabplot`: plots using [MATLAB](https://www.mathworks.com/);
+  - `mathplot` : plots using
+    [Mathematica](https://www.wolfram.com/mathematica/);
+  - `octaveplot`: plots using [GNU
+    Octave](https://www.gnu.org/software/octave/);
+  - `ggplot2`: plots using [ggplot2](https://ggplot2.tidyverse.org/);
+  - `gnuplot`: plots using [gnuplot](http://www.gnuplot.info/);
+  - `graphviz`: graphs using [Graphviz](http://graphviz.org/);
+  - `bokeh`: plots using the [Bokeh](https://bokeh.org/) visualization library;
+  - `plotsjl`: plots using the [Julia `Plots.jl`](https://docs.juliaplots.org/latest/) package;
+  - `plantuml`: diagrams using the [PlantUML](https://plantuml.com/) software suite;
+  - `sageplot`: plots using the [Sage](https://www.sagemath.org/) software system;
+  - `d2`: plots using [D2](https://d2lang.com/);
+  - `asymptote`: plots using [Asymptote](https://asymptote.sourceforge.io/).
+
+To know which toolkits are useable on *your machine* (and which ones are
+not available), you can check with the `toolkits` command:
+
+``` bash
+pandoc-plot toolkits
+```
+
+**Wish your plotting toolkit of choice was available? Please [raise an
+issue](https://github.com/LaurentRDC/pandoc-plot/issues)\!**
+
+## Documentation
+
+You can find more information in the documentation, available either in the
+source repository file `MANUAL.md`, on the [webpage](https://laurentrdc.github.io/pandoc-plot/MANUAL.html), or via the command `pandoc-plot --manual`.
+
+## Installation
+
+### Binaries and Installers
+
+[![Latest release](https://img.shields.io/github/v/release/LaurentRDC/pandoc-plot)](https://github.com/LaurentRDC/pandoc-plot/releases)
+
+Windows, Linux, and Mac OS binaries are available on the [GitHub release
+page](https://github.com/LaurentRDC/pandoc-plot/releases). There are
+also Windows installers.
+
+### conda
+
+[![Conda Version](https://anaconda.org/conda-forge/pandoc-plot/badges/version.svg)](https://anaconda.org/conda-forge/pandoc-plot)
+
+Like `pandoc`, `pandoc-plot` is available as a package installable with
+[`conda`](https://docs.conda.io/en/latest/). [Click here to see the
+package page](https://anaconda.org/conda-forge/pandoc-plot).
+
+To install in the current environment:
+
+``` sh
+conda install -c conda-forge pandoc-plot
+```
+
+### Homebrew 
+
+[![homebrew version](https://img.shields.io/homebrew/v/pandoc-plot)](https://formulae.brew.sh/formula/pandoc-plot)
+
+`pandoc-plot` is available as a package via [`Homebrew`](https://brew.sh/). [Click here to see the package page](https://formulae.brew.sh/formula/pandoc-plot#default). 
+
+To install:
+
+```sh
+brew install pandoc-plot
+```
+
+### winget
+
+You can install `pandoc-plot` from the [Windows Package
+Manager](https://github.com/microsoft/winget-cli) `winget` (just like
+`pandoc`). To install:
+
+``` sh
+winget install pandoc-plot
+```
+
+### Arch Linux
+
+[![AUR version](https://img.shields.io/aur/version/pandoc-plot-bin)](https://aur.archlinux.org/packages/pandoc-plot-bin/)
+
+You can install `pandoc-plot` from the [archlinux user repository](https://aur.archlinux.org/packages/pandoc-plot-bin/) as `pandoc-plot-bin`. You can install using e.g. `yay`:
+
+```sh
+yay -S pandoc-plot-bin
+```
+
+### From Hackage/Stackage
+
+[![Hackage version](https://img.shields.io/hackage/v/pandoc-plot.svg)](http://hackage.haskell.org/package/pandoc-plot)
+
+`pandoc-plot` is available on
+[Hackage](http://hackage.haskell.org/package/pandoc-plot) and
+[Stackage](https://www.stackage.org/nightly/package/pandoc-plot). Using
+the [`cabal-install`](https://www.haskell.org/cabal/) tool:
+
+``` bash
+cabal update
+cabal install
+```
+
+### From source
+
+Building from source can be done using [`cabal`](https://www.haskell.org/cabal/):
+
+``` bash
+git clone https://github.com/LaurentRDC/pandoc-plot
+cd pandoc-plot
+cabal install # Alternatively, `stack install`
+```
Setup.hs view
@@ -1,7 +1,7 @@--- This script is used to build and install your package. Typically you don't--- need to change it. The Cabal documentation has more information about this--- file: <https://www.haskell.org/cabal/users-guide/installing-packages.html>.-import qualified Distribution.Simple--main :: IO ()-main = Distribution.Simple.defaultMain+-- This script is used to build and install your package. Typically you don't
+-- need to change it. The Cabal documentation has more information about this
+-- file: <https://www.haskell.org/cabal/users-guide/installing-packages.html>.
+import qualified Distribution.Simple
+
+main :: IO ()
+main = Distribution.Simple.defaultMain
data/srctemplate.html view
@@ -1,241 +1,241 @@-<!DOCTYPE html>-<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>-<head>-  <meta charset="utf-8" />-  <meta name="generator" content="pandoc-plot" />-  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />-$for(author-meta)$-  <meta name="author" content="$author-meta$" />-$endfor$-$if(date-meta)$-  <meta name="dcterms.date" content="$date-meta$" />-$endif$-$if(keywords)$-  <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />-$endif$-  <title>Generated figure</title>-  <style>-$if(document-css)$-html {-  line-height: $if(linestretch)$$linestretch$$else$1.5$endif$;-  font-family: $if(mainfont)$$mainfont$$else$Georgia, serif$endif$;-  font-size: $if(fontsize)$$fontsize$$else$20px$endif$;-  color: $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;-  background-color: $if(backgroundcolor)$$backgroundcolor$$else$#fdfdfd$endif$;-}-body {-  margin: 0 auto;-  max-width: 36em;-  padding-left: $if(margin-left)$$margin-left$$else$50px$endif$;-  padding-right: $if(margin-right)$$margin-right$$else$50px$endif$;-  padding-top: $if(margin-top)$$margin-top$$else$50px$endif$;-  padding-bottom: $if(margin-bottom)$$margin-bottom$$else$50px$endif$;-  hyphens: auto;-  word-wrap: break-word;-  text-rendering: optimizeLegibility;-  font-kerning: normal;-}-@media (max-width: 600px) {-  body {-    font-size: 0.9em;-    padding: 1em;-  }-}-@media print {-  body {-    background-color: transparent;-    color: black;-    font-size: 12pt;-  }-  p, h2, h3 {-    orphans: 3;-    widows: 3;-  }-  h2, h3, h4 {-    page-break-after: avoid;-  }-}-p {-  margin: 1em 0;-}-a {-  color: $if(linkcolor)$$linkcolor$$else$#1a1a1a$endif$;-}-a:visited {-  color: $if(linkcolor)$$linkcolor$$else$#1a1a1a$endif$;-}-img {-  max-width: 100%;-}-h1, h2, h3, h4, h5, h6 {-  margin-top: 1.4em;-}-h5, h6 {-  font-size: 1em;-  font-style: italic;-}-h6 {-  font-weight: normal;-}-ol, ul {-  padding-left: 1.7em;-  margin-top: 1em;-}-li > ol, li > ul {-  margin-top: 0;-}-blockquote {-  margin: 1em 0 1em 1.7em;-  padding-left: 1em;-  border-left: 2px solid #e6e6e6;-  color: #606060;-}-code {-  font-family: $if(monofont)$$monofont$$else$Menlo, Monaco, 'Lucida Console', Consolas, monospace$endif$;-$if(monobackgroundcolor)$-  background-color: $monobackgroundcolor$;-  padding: .2em .4em;-$endif$-  font-size: 85%;-  margin: 0;-}-pre {-  margin: 1em 0;-$if(monobackgroundcolor)$-  background-color: $monobackgroundcolor$;-  padding: 1em;-$endif$-  overflow: auto;-}-pre code {-  padding: 0;-  overflow: visible;-}-.sourceCode {- background-color: transparent;- overflow: visible;-}-hr {-  background-color: #1a1a1a;-  border: none;-  height: 1px;-  margin: 1em 0;-}-table {-  margin: 1em 0;-  border-collapse: collapse;-  width: 100%;-  overflow-x: auto;-  display: block;-  font-variant-numeric: lining-nums tabular-nums;-}-table caption {-  margin-bottom: 0.75em;-}-tbody {-  margin-top: 0.5em;-  border-top: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;-  border-bottom: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;-}-th {-  border-top: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;-  padding: 0.25em 0.5em 0.25em 0.5em;-}-td {-  padding: 0.125em 0.5em 0.25em 0.5em;-}-header {-  margin-bottom: 4em;-  text-align: center;-}-#TOC li {-  list-style: none;-}-#TOC a:not(:hover) {-  text-decoration: none;-}-$endif$-code{white-space: pre-wrap;}-span.smallcaps{font-variant: small-caps;}-span.underline{text-decoration: underline;}-div.column{display: inline-block; vertical-align: top; width: 50%;}-div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}-ul.task-list{list-style: none;}-$if(quotes)$-q { quotes: "“" "”" "‘" "’"; }-$endif$-$if(highlighting-css)$-$highlighting-css$-$endif$-$if(displaymath-css)$-.display.math{display: block; text-align: center; margin: 0.5rem auto;}-$endif$-$if(csl-css)$-div.csl-bib-body { }-div.csl-entry {-  clear: both;-$if(csl-entry-spacing)$-  margin-bottom: $csl-entry-spacing$;-$endif$-}-.hanging div.csl-entry {-  margin-left:2em;-  text-indent:-2em;-}-div.csl-left-margin {-  min-width:2em;-  float:left;-}-div.csl-right-inline {-  margin-left:2em;-  padding-left:1em;-}-div.csl-indent {-  margin-left: 2em;-}-$endif$-  </style>-$for(css)$-  <link rel="stylesheet" href="$css$" />-$endfor$-$if(math)$-  $math$-$endif$--$for(header-includes)$-  $header-includes$-$endfor$-</head>-<body>-$for(include-before)$-$include-before$-$endfor$-$if(title)$-<header id="title-block-header">-<h1 class="title">$title$</h1>-$if(subtitle)$-<p class="subtitle">$subtitle$</p>-$endif$-$for(author)$-<p class="author">$author$</p>-$endfor$-$if(date)$-<p class="date">$date$</p>-$endif$-</header>-$endif$-$if(toc)$-<nav id="$idprefix$TOC" role="doc-toc">-$if(toc-title)$-<h2 id="$idprefix$toc-title">$toc-title$</h2>-$endif$-$table-of-contents$-</nav>-$endif$-$body$-$for(include-after)$-$include-after$-$endfor$-<a href="https://github.com/LaurentRDC/pandoc-plot">Click here to see how this plot was generated.</a>-</body>+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
+<head>
+  <meta charset="utf-8" />
+  <meta name="generator" content="pandoc-plot" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+$for(author-meta)$
+  <meta name="author" content="$author-meta$" />
+$endfor$
+$if(date-meta)$
+  <meta name="dcterms.date" content="$date-meta$" />
+$endif$
+$if(keywords)$
+  <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
+$endif$
+  <title>Generated figure</title>
+  <style>
+$if(document-css)$
+html {
+  line-height: $if(linestretch)$$linestretch$$else$1.5$endif$;
+  font-family: $if(mainfont)$$mainfont$$else$Georgia, serif$endif$;
+  font-size: $if(fontsize)$$fontsize$$else$20px$endif$;
+  color: $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
+  background-color: $if(backgroundcolor)$$backgroundcolor$$else$#fdfdfd$endif$;
+}
+body {
+  margin: 0 auto;
+  max-width: 36em;
+  padding-left: $if(margin-left)$$margin-left$$else$50px$endif$;
+  padding-right: $if(margin-right)$$margin-right$$else$50px$endif$;
+  padding-top: $if(margin-top)$$margin-top$$else$50px$endif$;
+  padding-bottom: $if(margin-bottom)$$margin-bottom$$else$50px$endif$;
+  hyphens: auto;
+  word-wrap: break-word;
+  text-rendering: optimizeLegibility;
+  font-kerning: normal;
+}
+@media (max-width: 600px) {
+  body {
+    font-size: 0.9em;
+    padding: 1em;
+  }
+}
+@media print {
+  body {
+    background-color: transparent;
+    color: black;
+    font-size: 12pt;
+  }
+  p, h2, h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2, h3, h4 {
+    page-break-after: avoid;
+  }
+}
+p {
+  margin: 1em 0;
+}
+a {
+  color: $if(linkcolor)$$linkcolor$$else$#1a1a1a$endif$;
+}
+a:visited {
+  color: $if(linkcolor)$$linkcolor$$else$#1a1a1a$endif$;
+}
+img {
+  max-width: 100%;
+}
+h1, h2, h3, h4, h5, h6 {
+  margin-top: 1.4em;
+}
+h5, h6 {
+  font-size: 1em;
+  font-style: italic;
+}
+h6 {
+  font-weight: normal;
+}
+ol, ul {
+  padding-left: 1.7em;
+  margin-top: 1em;
+}
+li > ol, li > ul {
+  margin-top: 0;
+}
+blockquote {
+  margin: 1em 0 1em 1.7em;
+  padding-left: 1em;
+  border-left: 2px solid #e6e6e6;
+  color: #606060;
+}
+code {
+  font-family: $if(monofont)$$monofont$$else$Menlo, Monaco, 'Lucida Console', Consolas, monospace$endif$;
+$if(monobackgroundcolor)$
+  background-color: $monobackgroundcolor$;
+  padding: .2em .4em;
+$endif$
+  font-size: 85%;
+  margin: 0;
+}
+pre {
+  margin: 1em 0;
+$if(monobackgroundcolor)$
+  background-color: $monobackgroundcolor$;
+  padding: 1em;
+$endif$
+  overflow: auto;
+}
+pre code {
+  padding: 0;
+  overflow: visible;
+}
+.sourceCode {
+ background-color: transparent;
+ overflow: visible;
+}
+hr {
+  background-color: #1a1a1a;
+  border: none;
+  height: 1px;
+  margin: 1em 0;
+}
+table {
+  margin: 1em 0;
+  border-collapse: collapse;
+  width: 100%;
+  overflow-x: auto;
+  display: block;
+  font-variant-numeric: lining-nums tabular-nums;
+}
+table caption {
+  margin-bottom: 0.75em;
+}
+tbody {
+  margin-top: 0.5em;
+  border-top: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
+  border-bottom: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
+}
+th {
+  border-top: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
+  padding: 0.25em 0.5em 0.25em 0.5em;
+}
+td {
+  padding: 0.125em 0.5em 0.25em 0.5em;
+}
+header {
+  margin-bottom: 4em;
+  text-align: center;
+}
+#TOC li {
+  list-style: none;
+}
+#TOC a:not(:hover) {
+  text-decoration: none;
+}
+$endif$
+code{white-space: pre-wrap;}
+span.smallcaps{font-variant: small-caps;}
+span.underline{text-decoration: underline;}
+div.column{display: inline-block; vertical-align: top; width: 50%;}
+div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
+ul.task-list{list-style: none;}
+$if(quotes)$
+q { quotes: "“" "”" "‘" "’"; }
+$endif$
+$if(highlighting-css)$
+$highlighting-css$
+$endif$
+$if(displaymath-css)$
+.display.math{display: block; text-align: center; margin: 0.5rem auto;}
+$endif$
+$if(csl-css)$
+div.csl-bib-body { }
+div.csl-entry {
+  clear: both;
+$if(csl-entry-spacing)$
+  margin-bottom: $csl-entry-spacing$;
+$endif$
+}
+.hanging div.csl-entry {
+  margin-left:2em;
+  text-indent:-2em;
+}
+div.csl-left-margin {
+  min-width:2em;
+  float:left;
+}
+div.csl-right-inline {
+  margin-left:2em;
+  padding-left:1em;
+}
+div.csl-indent {
+  margin-left: 2em;
+}
+$endif$
+  </style>
+$for(css)$
+  <link rel="stylesheet" href="$css$" />
+$endfor$
+$if(math)$
+  $math$
+$endif$
+
+$for(header-includes)$
+  $header-includes$
+$endfor$
+</head>
+<body>
+$for(include-before)$
+$include-before$
+$endfor$
+$if(title)$
+<header id="title-block-header">
+<h1 class="title">$title$</h1>
+$if(subtitle)$
+<p class="subtitle">$subtitle$</p>
+$endif$
+$for(author)$
+<p class="author">$author$</p>
+$endfor$
+$if(date)$
+<p class="date">$date$</p>
+$endif$
+</header>
+$endif$
+$if(toc)$
+<nav id="$idprefix$TOC" role="doc-toc">
+$if(toc-title)$
+<h2 id="$idprefix$toc-title">$toc-title$</h2>
+$endif$
+$table-of-contents$
+</nav>
+$endif$
+$body$
+$for(include-after)$
+$include-after$
+$endfor$
+<a href="https://github.com/LaurentRDC/pandoc-plot">Click here to see how this plot was generated.</a>
+</body>
 </html>
docs/MANUAL.html view
@@ -1,569 +1,569 @@-<!DOCTYPE html>-<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>-<head>-  <meta charset="utf-8" />-  <meta name="generator" content="pandoc" />-  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />-  <title>pandoc-plot 1.3.0 manual</title>-  <style>-    code{white-space: pre-wrap;}-    span.smallcaps{font-variant: small-caps;}-    span.underline{text-decoration: underline;}-    div.column{display: inline-block; vertical-align: top; width: 50%;}-    div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}-    ul.task-list{list-style: none;}-    pre > code.sourceCode { white-space: pre; position: relative; }-    pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }-    pre > code.sourceCode > span:empty { height: 1.2em; }-    .sourceCode { overflow: visible; }-    code.sourceCode > span { color: inherit; text-decoration: inherit; }-    div.sourceCode { margin: 1em 0; }-    pre.sourceCode { margin: 0; }-    @media screen {-    div.sourceCode { overflow: auto; }-    }-    @media print {-    pre > code.sourceCode { white-space: pre-wrap; }-    pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }-    }-    pre.numberSource code-      { counter-reset: source-line 0; }-    pre.numberSource code > span-      { position: relative; left: -4em; counter-increment: source-line; }-    pre.numberSource code > span > a:first-child::before-      { content: counter(source-line);-        position: relative; left: -1em; text-align: right; vertical-align: baseline;-        border: none; display: inline-block;-        -webkit-touch-callout: none; -webkit-user-select: none;-        -khtml-user-select: none; -moz-user-select: none;-        -ms-user-select: none; user-select: none;-        padding: 0 4px; width: 4em;-        color: #aaaaaa;-      }-    pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }-    div.sourceCode-      {   }-    @media screen {-    pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }-    }-    code span.al { color: #ff0000; font-weight: bold; } /* Alert */-    code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */-    code span.at { color: #7d9029; } /* Attribute */-    code span.bn { color: #40a070; } /* BaseN */-    code span.bu { } /* BuiltIn */-    code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */-    code span.ch { color: #4070a0; } /* Char */-    code span.cn { color: #880000; } /* Constant */-    code span.co { color: #60a0b0; font-style: italic; } /* Comment */-    code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */-    code span.do { color: #ba2121; font-style: italic; } /* Documentation */-    code span.dt { color: #902000; } /* DataType */-    code span.dv { color: #40a070; } /* DecVal */-    code span.er { color: #ff0000; font-weight: bold; } /* Error */-    code span.ex { } /* Extension */-    code span.fl { color: #40a070; } /* Float */-    code span.fu { color: #06287e; } /* Function */-    code span.im { } /* Import */-    code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */-    code span.kw { color: #007020; font-weight: bold; } /* Keyword */-    code span.op { color: #666666; } /* Operator */-    code span.ot { color: #007020; } /* Other */-    code span.pp { color: #bc7a00; } /* Preprocessor */-    code span.sc { color: #4070a0; } /* SpecialChar */-    code span.ss { color: #bb6688; } /* SpecialString */-    code span.st { color: #4070a0; } /* String */-    code span.va { color: #19177c; } /* Variable */-    code span.vs { color: #4070a0; } /* VerbatimString */-    code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */-    .display.math{display: block; text-align: center; margin: 0.5rem auto;}-  </style>-  <link rel="stylesheet" href="data:text/css,html%20%7B%20font%2Dsize%3A%20100%25%3B%20overflow%2Dy%3A%20scroll%3B%20%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%20%2Dms%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%20%7Dbody%7Bcolor%3A%23444%3Bfont%2Dfamily%3AGeorgia%2C%20Palatino%2C%20%27Palatino%20Linotype%27%2C%20Times%2C%20%27Times%20New%20Roman%27%2C%20serif%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5em%3Bpadding%3A1em%3Bmargin%3Aauto%3Bmax%2Dwidth%3A42em%3Bbackground%3A%23fefefe%3B%7Da%7B%20color%3A%20%230645ad%3B%20text%2Ddecoration%3Anone%3B%7Da%3Avisited%7B%20color%3A%20%230b0080%3B%20%7Da%3Ahover%7B%20color%3A%20%2306e%3B%20%7Da%3Aactive%7B%20color%3A%23faa700%3B%20%7Da%3Afocus%7B%20outline%3A%20thin%20dotted%3B%20%7Da%3Ahover%2C%20a%3Aactive%7B%20outline%3A%200%3B%20%7D%3A%3A%2Dmoz%2Dselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%23000%7D%3A%3Aselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%23000%7Da%3A%3A%2Dmoz%2Dselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%230645ad%7Da%3A%3Aselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%230645ad%7Dp%7Bmargin%3A1em%200%3B%7Dimg%7Bmax%2Dwidth%3A100%25%3B%7Dh1%2Ch2%2Ch3%2Ch4%2Ch5%2Ch6%7Bfont%2Dweight%3Anormal%3Bcolor%3A%23111%3Bline%2Dheight%3A1em%3B%7Dh4%2Ch5%2Ch6%7B%20font%2Dweight%3A%20bold%3B%20%7Dh1%7B%20font%2Dsize%3A2%2E5em%3B%20%7Dh2%7B%20font%2Dsize%3A2em%3B%20%7Dh3%7B%20font%2Dsize%3A1%2E5em%3B%20%7Dh4%7B%20font%2Dsize%3A1%2E2em%3B%20%7Dh5%7B%20font%2Dsize%3A1em%3B%20%7Dh6%7B%20font%2Dsize%3A0%2E9em%3B%20%7Dblockquote%7Bcolor%3A%23666666%3Bmargin%3A0%3Bpadding%2Dleft%3A%203em%3Bborder%2Dleft%3A%200%2E5em%20%23EEE%20solid%3B%7Dhr%20%7B%20display%3A%20block%3B%20height%3A%202px%3B%20border%3A%200%3B%20border%2Dtop%3A%201px%20solid%20%23aaa%3Bborder%2Dbottom%3A%201px%20solid%20%23eee%3B%20margin%3A%201em%200%3B%20padding%3A%200%3B%20%7Dpre%2C%20code%2C%20kbd%2C%20samp%20%7B%20color%3A%20%23000%3B%20font%2Dfamily%3A%20monospace%2C%20monospace%3B%20%5Ffont%2Dfamily%3A%20%27courier%20new%27%2C%20monospace%3B%20font%2Dsize%3A%200%2E98em%3B%20%7Dpre%20%7B%20white%2Dspace%3A%20pre%3B%20white%2Dspace%3A%20pre%2Dwrap%3B%20word%2Dwrap%3A%20break%2Dword%3B%20%7Db%2C%20strong%20%7B%20font%2Dweight%3A%20bold%3B%20%7Ddfn%20%7B%20font%2Dstyle%3A%20italic%3B%20%7Dins%20%7B%20background%3A%20%23ff9%3B%20color%3A%20%23000%3B%20text%2Ddecoration%3A%20none%3B%20%7Dmark%20%7B%20background%3A%20%23ff0%3B%20color%3A%20%23000%3B%20font%2Dstyle%3A%20italic%3B%20font%2Dweight%3A%20bold%3B%20%7Dsub%2C%20sup%20%7B%20font%2Dsize%3A%2075%25%3B%20line%2Dheight%3A%200%3B%20position%3A%20relative%3B%20vertical%2Dalign%3A%20baseline%3B%20%7Dsup%20%7B%20top%3A%20%2D0%2E5em%3B%20%7Dsub%20%7B%20bottom%3A%20%2D0%2E25em%3B%20%7Dul%2C%20ol%20%7B%20margin%3A%201em%200%3B%20padding%3A%200%200%200%202em%3B%20%7Dli%20p%3Alast%2Dchild%20%7B%20margin%3A0%20%7Ddd%20%7B%20margin%3A%200%200%200%202em%3B%20%7Dimg%20%7B%20border%3A%200%3B%20%2Dms%2Dinterpolation%2Dmode%3A%20bicubic%3B%20vertical%2Dalign%3A%20middle%3B%20%7Dtable%20%7Bborder%2Dcollapse%3A%20collapse%3Bborder%2Dspacing%3A%200%3Bwidth%3A%20100%25%3B%7Dth%20%7B%20border%2Dbottom%3A%201px%20solid%20black%3B%20%7Dtd%20%7B%20vertical%2Dalign%3A%20top%3B%20%7D%40media%20only%20screen%20and%20%28min%2Dwidth%3A%20480px%29%20%7Bbody%7Bfont%2Dsize%3A14px%3B%7D%7D%40media%20only%20screen%20and%20%28min%2Dwidth%3A%20768px%29%20%7Bbody%7Bfont%2Dsize%3A16px%3B%7D%7D%40media%20print%20%7B%2A%20%7B%20background%3A%20transparent%20%21important%3B%20color%3A%20black%20%21important%3B%20filter%3Anone%20%21important%3B%20%2Dms%2Dfilter%3A%20none%20%21important%3B%20%7Dbody%7Bfont%2Dsize%3A12pt%3B%20max%2Dwidth%3A100%25%3B%7Da%2C%20a%3Avisited%20%7B%20text%2Ddecoration%3A%20underline%3B%20%7Dhr%20%7B%20height%3A%201px%3B%20border%3A0%3B%20border%2Dbottom%3A1px%20solid%20black%3B%20%7Da%5Bhref%5D%3Aafter%20%7B%20content%3A%20%22%20%28%22%20attr%28href%29%20%22%29%22%3B%20%7Dabbr%5Btitle%5D%3Aafter%20%7B%20content%3A%20%22%20%28%22%20attr%28title%29%20%22%29%22%3B%20%7D%2Eir%20a%3Aafter%2C%20a%5Bhref%5E%3D%22javascript%3A%22%5D%3Aafter%2C%20a%5Bhref%5E%3D%22%23%22%5D%3Aafter%20%7B%20content%3A%20%22%22%3B%20%7Dpre%2C%20blockquote%20%7B%20border%3A%201px%20solid%20%23999%3B%20padding%2Dright%3A%201em%3B%20page%2Dbreak%2Dinside%3A%20avoid%3B%20%7Dtr%2C%20img%20%7B%20page%2Dbreak%2Dinside%3A%20avoid%3B%20%7Dimg%20%7B%20max%2Dwidth%3A%20100%25%20%21important%3B%20%7D%40page%20%3Aleft%20%7B%20margin%3A%2015mm%2020mm%2015mm%2010mm%3B%20%7D%40page%20%3Aright%20%7B%20margin%3A%2015mm%2010mm%2015mm%2020mm%3B%20%7Dp%2C%20h2%2C%20h3%20%7B%20orphans%3A%203%3B%20widows%3A%203%3B%20%7Dh2%2C%20h3%20%7B%20page%2Dbreak%2Dafter%3A%20avoid%3B%20%7D%7D" />-  <!--[if lt IE 9]>-    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>-  <![endif]-->-</head>-<body>-<header id="title-block-header">-<h1 class="title">pandoc-plot 1.3.0 manual</h1>-</header>-<!---The file MANUAL.md is automatically generated by the tools/mkmanual.ps1 script. Do not edit manually.--->-<h2 id="a-pandoc-filter-to-generate-figures-from-code-blocks-in-documents">A Pandoc filter to generate figures from code blocks in documents</h2>-<p><code>pandoc-plot</code> turns code blocks present in your documents (Markdown, LaTeX, etc.) into embedded figures, using your plotting toolkit of choice, including Matplotlib, ggplot2, MATLAB, Mathematica, and more.</p>-<ul>-<li><a href="#features-overview">Features Overview</a>-<ul>-<li><a href="#captions">Captions</a></li>-<li><a href="#link-to-source-code">Link to source code</a></li>-<li><a href="#preamble-scripts">Preamble scripts</a></li>-<li><a href="#support-for-interactive-plots">Support for interactive plots</a></li>-<li><a href="#performance">Performance</a></li>-<li><a href="#compatibility-with-pandoc-crossref">Compatibility with pandoc-crossref</a></li>-</ul></li>-<li><a href="#detailed-usage">Detailed usage</a>-<ul>-<li><a href="#as-a-filter">As a filter</a></li>-<li><a href="#syntax">Syntax</a>-<ul>-<li><a href="#markdown">Markdown</a></li>-<li><a href="#latex">LaTeX</a></li>-</ul></li>-<li><a href="#parameters-and-options">Parameters and options</a>-<ul>-<li><a href="#code-highlighting">Code highlighting</a></li>-</ul></li>-<li><a href="#interactive-html-figures">Interactive HTML figures</a></li>-<li><a href="#configuration">Configuration</a>-<ul>-<li><a href="#executables">Executables</a></li>-<li><a href="#command-line-arguments">Command-line arguments</a></li>-<li><a href="#toolkit-specific-options">Toolkit-specific options</a></li>-<li><a href="#logging">Logging</a></li>-<li><a href="#strict-mode">Strict mode</a></li>-</ul></li>-<li><a href="#other-commands">Other commands</a>-<ul>-<li><a href="#finding-installed-toolkits">Finding installed toolkits</a></li>-<li><a href="#cleaning-output">Cleaning output</a></li>-<li><a href="#configuration-template">Configuration template</a></li>-</ul></li>-<li><a href="#as-a-haskell-library">As a Haskell library</a>-<ul>-<li><a href="#usage-with-hakyll">Usage with Hakyll</a></li>-</ul></li>-</ul></li>-<li><a href="#warning">Warning</a></li>-</ul>-<h2 id="features-overview">Features Overview</h2>-<h3 id="captions">Captions</h3>-<p>You can also specify a caption for your image. This is done using the optional <code>caption</code> parameter.</p>-<p><strong>Markdown</strong>:</p>-<div class="sourceCode" id="cb1"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.matlabplot caption=&quot;This is a simple figure with a **Markdown** caption&quot;}</span></span>-<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="in">x  = 0: .1 : 2*pi;</span></span>-<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="in">y1 = cos(x);</span></span>-<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="in">y2 = sin(x);</span></span>-<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="in">figure</span></span>-<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="in">plot(x, y1, &#39;b&#39;, x, y2, &#39;r-.&#39;, &#39;LineWidth&#39;, 2)</span></span>-<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>-<p><strong>LaTex</strong>:</p>-<div class="sourceCode" id="cb2"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[caption=This is a simple figure with a caption]{matlabplot}</span>-<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="vs">x  = 0: .1 : 2*pi;</span></span>-<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="vs">y1 = cos(x);</span></span>-<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="vs">y2 = sin(x);</span></span>-<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="vs">figure</span></span>-<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="vs">plot(x, y1, &#39;b&#39;, x, y2, &#39;r-.&#39;, &#39;LineWidth&#39;, 2)</span></span>-<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>-<p>Caption formatting unfortunately cannot be determined automatically. To specify a caption format (e.g. “markdown”, “LaTeX”, etc.), see <a href="#configuration">Configuration</a>.</p>-<h3 id="link-to-source-code">Link to source code</h3>-<p>In case of an output format that supports links (e.g. HTML), the embedded image generated by <code>pandoc-plot</code> can show a link to the source code which was used to generate the file. Therefore, other people can see what code was used to create your figures.</p>-<p>You can turn this on via the <code>source=true</code> key:</p>-<p><strong>Markdown</strong>:</p>-<div class="sourceCode" id="cb3"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.mathplot source=true}</span></span>-<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="in">...</span></span>-<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>-<p><strong>LaTex</strong>:</p>-<div class="sourceCode" id="cb4"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[source=true]{mathplot}</span>-<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="vs">...</span></span>-<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>-<p>or via a <a href="#Configuration">configuration file</a>.</p>-<h3 id="preamble-scripts">Preamble scripts</h3>-<p>If you find yourself always repeating some steps, inclusion of scripts is possible using the <code>preamble</code> parameter. For example, if you want all Matplotlib plots to have the <a href="https://matplotlib.org/tutorials/introductory/customizing.html#sphx-glr-tutorials-introductory-customizing-py"><code>ggplot</code></a> style, you can write a very short preamble <code>style.py</code> like so:</p>-<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> matplotlib.pyplot <span class="im">as</span> plt</span>-<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>plt.style.use(<span class="st">&#39;ggplot&#39;</span>)</span></code></pre></div>-<p>and include it in your document as follows:</p>-<div class="sourceCode" id="cb6"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.matplotlib preamble=style.py}</span></span>-<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="in">plt.figure()</span></span>-<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="in">plt.plot([0,1,2,3,4], [1,2,3,4,5])</span></span>-<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="in">plt.title(&#39;This is an example figure&#39;)</span></span>-<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>-<p>Which is equivalent to writing the following markdown:</p>-<div class="sourceCode" id="cb7"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.matplotlib}</span></span>-<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="in">import matplotlib.pyplot as plt</span></span>-<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="in">plt.style.use(&#39;ggplot&#39;)</span></span>-<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="in">plt.figure()</span></span>-<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="in">plt.plot([0,1,2,3,4], [1,2,3,4,5])</span></span>-<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="in">plt.title(&#39;This is an example figure&#39;)</span></span>-<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>-<p>The equivalent LaTeX usage is as follows:</p>-<div class="sourceCode" id="cb8"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[include=style.py]{matplotlib}</span>-<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>-<p>This <code>preamble</code> parameter is perfect for longer documents with many plots. Simply define the style you want in a separate script! You can also import packages this way, or define functions you often use.</p>-<h3 id="support-for-interactive-plots">Support for interactive plots</h3>-<p>Starting with version 0.8.0.0, <code>pandoc-plot</code> supports the creation of interactive plots (if a toolkit supports it). All you need to do is set the save format to <code>html</code>. The resulting plot is fully self-contained, so it can be displayed offline.</p>-<h3 id="performance">Performance</h3>-<p><code>pandoc-plot</code> minimizes work, only generating figures if it absolutely must, i.e. if the content has changed. <code>pandoc-plot</code> will save the hash of the source code used to generate a figure in its filename. Before generating a figure, <code>pandoc-plot</code> will check it this figure already exists based on the hash of its source! This also means that there is no way to directly name figures.</p>-<p>Moreover, starting with version 0.5.0.0, <code>pandoc-plot</code> takes advantage of multicore CPUs, rendering figures <strong>in parallel</strong>.</p>-<p>Therefore, you can confidently run the filter on very large documents containing hundreds of figures, like a book or a thesis.</p>-<h3 id="compatibility-with-pandoc-crossref">Compatibility with pandoc-crossref</h3>-<p><a href="https://github.com/lierdakil/pandoc-crossref"><code>pandoc-crossref</code></a> is a pandoc filter that makes it effortless to cross-reference objects in Markdown documents.</p>-<p>You can use <code>pandoc-crossref</code> in conjunction with <code>pandoc-plot</code> for the ultimate figure-making pipeline. You can combine both in a figure like so:</p>-<div class="sourceCode" id="cb9"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{#fig:myexample .plotly_python caption=&quot;This is a caption&quot;}</span></span>-<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="in"># Insert figure script here</span></span>-<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span>-<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>As you can see in @fig:myexample, ...</span></code></pre></div>-<p>If the above source is located in file <code>myfile.md</code>, you can render the figure and references by applying <code>pandoc-plot</code> <strong>first</strong>, and then <code>pandoc-crossref</code>. For example:</p>-<div class="sourceCode" id="cb10"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">--filter</span> pandoc-crossref <span class="at">-i</span> myfile.md <span class="at">-o</span> myfile.html</span></code></pre></div>-<h2 id="detailed-usage">Detailed usage</h2>-<p><code>pandoc-plot</code> is a command line executable with a few functions. You can take a look at the help using the <code>-h</code>/<code>--help</code> flag:</p>-<div class="sourceCode" id="cb11"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc-plot</span> 1.3.0 <span class="at">-</span> generate figures directly in documents</span>-<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE [<span class="er">(</span><span class="ex">-v</span><span class="kw">|</span><span class="ex">--version</span><span class="kw">)</span> <span class="kw">|</span> <span class="ex">--full-version</span> <span class="kw">|</span> <span class="kw">(</span><span class="ex">-m</span><span class="kw">|</span><span class="ex">--manual</span><span class="kw">)</span><span class="ex">]</span> </span>-<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>                       <span class="ex">[COMMAND]</span> [AST]</span>-<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">This</span> pandoc filter generates plots from code blocks using a multitude of</span>-<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">possible</span> renderers. This allows to keep documentation and figures in perfect</span>-<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">synchronicity.</span></span>-<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>-<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-v,--version</span>             Show version number and exit.</span>-<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--full-version</span>           Show full version information and exit.</span>-<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-m,--manual</span>              Open the manual page in the default web browser and</span>-<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>                           <span class="ex">exit.</span></span>-<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span>-<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> commands:</span>-<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>  <span class="ex">toolkits</span>                 Show information on toolkits and exit.</span>-<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>  <span class="ex">clean</span>                    Clean output directories where figures from FILE and</span>-<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>                           <span class="ex">log</span> files might be stored. WARNING: All files in</span>-<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>                           <span class="ex">those</span> directories will be deleted.</span>-<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>  <span class="ex">write-example-config</span>     Write example configuration to a file and exit.</span>-<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a><span class="ex">More</span> information can be found via the manual <span class="er">(</span><span class="ex">pandoc-plot</span> <span class="at">--manual</span><span class="kw">)</span> <span class="ex">or</span> the</span>-<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a><span class="ex">repository</span> README, located at https://github.com/LaurentRDC/pandoc-plot</span></code></pre></div>-<h3 id="as-a-filter">As a filter</h3>-<p>The most common use for <code>pandoc-plot</code> is as a pandoc filter, in which case it should be called without arguments. For example:</p>-<div class="sourceCode" id="cb12"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">-i</span> input.md <span class="at">-o</span> output.html</span></code></pre></div>-<p>If <code>pandoc-plot</code> fails to render a code block into a figure, the filtering will not stop. Your code blocks will stay unchanged, unless you activate <a href="#strict-mode">strict mode</a>.</p>-<p>You can chain other filters with it (e.g., <a href="https://github.com/lierdakil/pandoc-crossref"><code>pandoc-crossref</code></a>) like so:</p>-<div class="sourceCode" id="cb13"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">--filter</span> pandoc-crossref <span class="at">-i</span> input.md <span class="at">-o</span> output.html</span></code></pre></div>-<h3 id="syntax">Syntax</h3>-<p>The syntax for code blocks in documents is shown below. <code>pandoc-plot</code> looks for code blocks with a specific class, depending on the toolkit you want to use. <code>pandoc-plot</code> will run the code and capture the figure output. There can only be <strong>one</strong> figure per code block.</p>-<p>The possible parameters and options are described in <a href="#parameters-and-options">further below</a>.</p>-<h4 id="markdown">Markdown</h4>-<div class="sourceCode" id="cb14"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.cls param1=value1 param2=value2 ...}</span></span>-<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>-<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>-<h4 id="latex">LaTeX</h4>-<p>Note that the <code>minted</code> LaTeX package need not be installed.</p>-<div class="sourceCode" id="cb15"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[param1=value1, param2=value2, ...]{cls}</span>-<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="vs">...</span></span>-<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>-<h3 id="parameters-and-options">Parameters and options</h3>-<p>There are parameters that affect the figure that will be included in your document. Here are all the possible general parameters, in Markdown syntax:</p>-<div class="sourceCode" id="cb16"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.cls </span></span>-<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="in">      .language</span></span>-<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="in">      directory=(path) </span></span>-<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="in">      caption=(text) </span></span>-<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="in">      format=(PNG|PDF|SVG|JPG|EPS|GIF|TIF|WEBP|HTML|LATEX) </span></span>-<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="in">      source=(true|True|false|False) </span></span>-<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="in">      source_label=(text)</span></span>-<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a><span class="in">      preamble=(path) </span></span>-<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="in">      dpi=(integer)</span></span>-<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a><span class="in">      dependencies=[...]</span></span>-<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a><span class="in">      file=(path)</span></span>-<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a><span class="in">      executable=(path) </span></span>-<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a><span class="in">      caption_format=(text)</span></span>-<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a><span class="in">      }</span></span>-<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>-<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>-<ul>-<li><code>cls</code> must be one of the following: <code>matplotlib</code>, <code>matlabplot</code>, <code>plotly_python</code>, <code>plotly_r</code>, <code>mathplot</code>, <code>octaveplot</code>, <code>ggplot2</code>, <code>gnuplot</code>, <code>graphviz</code>, <code>bokeh</code>, <code>plotsjl</code>, <code>plantuml</code> (<em>new in version 1.1.0</em>).</li>-</ul>-<p>All following parameters are optional, with their default values controlled by the <a href="#configuration">configuration</a>.</p>-<ul>-<li><code>language</code> specifies the programming language used in this block. This parameter is ignored by <code>pandoc-plot</code>, but your text editor may use it to highlight code. See <a href="#code-highlighting">Code highlighting</a> below.</li>-<li><code>directory</code> is a path to the directory where the figure and source code will be saved. You cannot control the file name. This path is either absolute, or relative from the working directory where you call <code>pandoc-plot</code>.</li>-<li><code>caption</code> is the caption text. The format of the caption is specified in the <code>caption_format</code> parameter, described below.</li>-<li><code>format</code> is the desired filetype for the resulting figure. Possible values for <code>format</code> are [<code>PNG</code>, <code>PDF</code>, <code>SVG</code>, <code>JPG</code>, <code>EPS</code>, <code>GIF</code>, <code>TIF</code>, <code>WEBP</code>, <code>HTML</code>, <code>LATEX</code>]. Not all toolkits support all formats. See <code>pandoc-plot toolkits</code> for toolkit-specific information regarding save formats. The <code>HTML</code> format is special; it can produce standalone, offline, interactive plots. As such, it only makes sense to use this format when creating HTML documents. Similarly, the <code>LATEX</code> format is special; plots in the LaTeX format will be embedded in the document. Therefore, it only makes sense to use this format when creating LaTeX documents.</li>-<li><code>source</code> is a boolean toggle that determines whether the source code should be linked in the caption or not. Possible values are [<code>true</code>, <code>True</code>, <code>false</code>, <code>False</code>].</li>-<li><code>source_label</code> is the text that links to source code (if <code>source=true</code>). This is useful if you are writing text in a different language. The default is <code>source_label=&quot;Source Code&quot;</code>. You might want to set this via the <a href="#configuration">configuration</a> instead.</li>-<li><code>preamble</code> is a path to a script that will be included as a preamble to the content of the code block. This path is either absolute, or relative from the working directory where you call <code>pandoc-plot</code>.</li>-<li><code>dpi</code> is the pixel density of the figure in dots-per-inch. Possible values are positive integers. Not all toolkits respect this.</li>-<li><code>dependencies</code> is a list of files/directories that affect the figure, for example data files. If one of those files/directories changes, <code>pandoc-plot</code> will re-render the associated figure. Format is a comma-separated list, e.g. <code>dependencies=[data.txt, foo.bar, ~/wtv]</code>. Values for <code>dependencies</code> in the configuration file will be appended to the values in a code block.</li>-<li><code>file</code> is a path to a file from which to read the figure content. If this parameter is used, the content of the code block is ignored. By using this parameter, you can use all the standard tooling of your plotting toolkit of choice, which is especially useful for complex figures.</li>-<li><code>executable</code> is a path to the executable to use (e.g. <code>C:\\python3.exe</code>) or the name of the executable (e.g. <code>python3</code>).</li>-<li><code>caption_format</code> is the text format of the caption. Possible values are exactly the same as <code>pandoc</code>’s format specification, usually <code>FORMAT+EXTENSION-EXTENSION</code>. For example, captions in Markdown with raw LaTeX would be parsed correctly provided that <code>caption_format=markdown+raw_tex</code>. See Pandoc’s guide on <a href="https://pandoc.org/MANUAL.html#specifying-formats">Specifying formats</a>.</li>-</ul>-<h4 id="code-highlighting">Code highlighting</h4>-<p>If your editor supports code highlighting in code blocks, you can also include the programming language. In Markdown:</p>-<div class="sourceCode" id="cb17"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.language .cls (options)}</span></span>-<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>-<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>-<p>or Latex:</p>-<div class="sourceCode" id="cb18"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">\begin</span>{<span class="ex">minted</span>}[(options)]{language, cls}</span>-<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="vs">  # script content</span></span>-<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="vs">  </span><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>-<p>For example, for GGPlot2 figures:</p>-<div class="sourceCode" id="cb19"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.r .ggplot2 caption=Highlighted code block}</span></span>-<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>-<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>-<p>or (Latex):</p>-<div class="sourceCode" id="cb20"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">\begin</span>{<span class="ex">minted</span>}[caption=Highlighted code block]{r, ggplot2}</span>-<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="vs">  # script content</span></span>-<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="vs">  </span><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>-<p>This way, you benefit from code highlighting <em>and</em> <code>pandoc-plot</code>.</p>-<h3 id="interactive-html-figures">Interactive HTML figures</h3>-<p>Interactive HTML figures are available for a few toolkits, e.g. <code>bokeh</code>. To make a figure interactive, use the output format <code>format=html</code>. This only makes sense if your output file is also HTML.</p>-<p>You can take a look at the <a href="https://laurentrdc.github.io/pandoc-plot/">demonstration page</a> for an example result.</p>-<p>Many interactive plots rely on javascript scripts stored on the internet. If you want to have a self-contained document that can be viewed offline – or you want your document to work for the next 10 years –, you can use pandoc’s <code>--self-contained</code> flag:</p>-<div class="sourceCode" id="cb21"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--self-contained</span> <span class="at">--filter</span> pandoc-plot <span class="at">-i</span> mydoc.md <span class="at">-o</span> webpage.html </span></code></pre></div>-<p>The resulting output <code>webpage.html</code> will contain everything, at the cost of size.</p>-<h3 id="configuration">Configuration</h3>-<p>To avoid repetition, <code>pandoc-plot</code> can be configured using simple YAML-files. Here are <strong>all</strong> the possible parameters:</p>-<div class="sourceCode" id="cb22"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co"># This is an example configuration. Everything in this file is optional.</span></span>-<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Please refer to the documentation to know about the parameters herein.</span></span>-<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>-<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="co"># The `executable` parameter for all toolkits can be either the</span></span>-<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a><span class="co"># executable name (if it is present on the PATH), or</span></span>-<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a><span class="co"># the full path to the executable.</span></span>-<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a><span class="co"># E.g.:</span></span>-<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a><span class="co">#  executable: python3</span></span>-<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="co">#  executable: &quot;C:\Python37\Scripts\python.exe&quot;</span></span>-<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="co"># The following parameters affect all toolkits</span></span>-<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a><span class="co"># Directory where to save the plots. The path can be relative to pandoc-plot&#39;s</span></span>-<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a><span class="co"># current working directory, or absolute.</span></span>-<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a><span class="fu">directory</span><span class="kw">:</span><span class="at"> plots/</span></span>-<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a><span class="co"># Whether or not to include a link to the source script in the caption. </span></span>-<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a><span class="co"># Particularly useful for HTML output.</span></span>-<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a><span class="fu">source</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>-<span id="cb22-19"><a href="#cb22-19" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-20"><a href="#cb22-20" aria-hidden="true" tabindex="-1"></a><span class="co"># When `strict: false`, pandoc-plot will leave code blocks untouched if a plot</span></span>-<span id="cb22-21"><a href="#cb22-21" aria-hidden="true" tabindex="-1"></a><span class="co"># could not be generated. This could happen if, for example, a toolkit is not</span></span>-<span id="cb22-22"><a href="#cb22-22" aria-hidden="true" tabindex="-1"></a><span class="co"># installed. If you want pandoc-plot to fail instead, use `strict: true`.</span></span>-<span id="cb22-23"><a href="#cb22-23" aria-hidden="true" tabindex="-1"></a><span class="fu">strict</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>-<span id="cb22-24"><a href="#cb22-24" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-25"><a href="#cb22-25" aria-hidden="true" tabindex="-1"></a><span class="co"># Text label for links to source code.</span></span>-<span id="cb22-26"><a href="#cb22-26" aria-hidden="true" tabindex="-1"></a><span class="co"># You can change this label if you are writing a document in a non-English language. </span></span>-<span id="cb22-27"><a href="#cb22-27" aria-hidden="true" tabindex="-1"></a><span class="co"># This only matters if `source` is set to `true`.</span></span>-<span id="cb22-28"><a href="#cb22-28" aria-hidden="true" tabindex="-1"></a><span class="fu">source_label</span><span class="kw">:</span><span class="at"> Source code</span></span>-<span id="cb22-29"><a href="#cb22-29" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-30"><a href="#cb22-30" aria-hidden="true" tabindex="-1"></a><span class="co"># Default density of figures in dots per inches (DPI). </span></span>-<span id="cb22-31"><a href="#cb22-31" aria-hidden="true" tabindex="-1"></a><span class="co"># This can be changed in the document specifically as well.</span></span>-<span id="cb22-32"><a href="#cb22-32" aria-hidden="true" tabindex="-1"></a><span class="fu">dpi</span><span class="kw">:</span><span class="at"> </span><span class="dv">80</span></span>-<span id="cb22-33"><a href="#cb22-33" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-34"><a href="#cb22-34" aria-hidden="true" tabindex="-1"></a><span class="co"># Default format in which to save the figures. This can be specified </span></span>-<span id="cb22-35"><a href="#cb22-35" aria-hidden="true" tabindex="-1"></a><span class="co"># individually as well.</span></span>-<span id="cb22-36"><a href="#cb22-36" aria-hidden="true" tabindex="-1"></a><span class="fu">format</span><span class="kw">:</span><span class="at"> PNG</span></span>-<span id="cb22-37"><a href="#cb22-37" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-38"><a href="#cb22-38" aria-hidden="true" tabindex="-1"></a><span class="co"># Default files/directories on which all figures depend. If any of these files/directories</span></span>-<span id="cb22-39"><a href="#cb22-39" aria-hidden="true" tabindex="-1"></a><span class="co"># changes, all figures will be re-rendered.</span></span>-<span id="cb22-40"><a href="#cb22-40" aria-hidden="true" tabindex="-1"></a><span class="co"># Dependencies specified in code blocks will be appended to this list.</span></span>-<span id="cb22-41"><a href="#cb22-41" aria-hidden="true" tabindex="-1"></a><span class="fu">dependencies</span><span class="kw">:</span></span>-<span id="cb22-42"><a href="#cb22-42" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span><span class="at"> file1.txt</span></span>-<span id="cb22-43"><a href="#cb22-43" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span><span class="at"> file2.txt</span></span>-<span id="cb22-44"><a href="#cb22-44" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-45"><a href="#cb22-45" aria-hidden="true" tabindex="-1"></a><span class="co"># Text format for the captions. Unfortunately, there is no way to detect</span></span>-<span id="cb22-46"><a href="#cb22-46" aria-hidden="true" tabindex="-1"></a><span class="co"># this automatically. You can use the same notation as Pandoc&#39;s --from </span></span>-<span id="cb22-47"><a href="#cb22-47" aria-hidden="true" tabindex="-1"></a><span class="co"># parameter, specified here: </span></span>-<span id="cb22-48"><a href="#cb22-48" aria-hidden="true" tabindex="-1"></a><span class="co">#     https://pandoc.org/MANUAL.html#option--from</span></span>-<span id="cb22-49"><a href="#cb22-49" aria-hidden="true" tabindex="-1"></a><span class="co"># Example: markdown, rst+raw_tex</span></span>-<span id="cb22-50"><a href="#cb22-50" aria-hidden="true" tabindex="-1"></a><span class="fu">caption_format</span><span class="kw">:</span><span class="at"> markdown+tex_math_dollars</span></span>-<span id="cb22-51"><a href="#cb22-51" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-52"><a href="#cb22-52" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-53"><a href="#cb22-53" aria-hidden="true" tabindex="-1"></a><span class="co"># Logging configuration</span></span>-<span id="cb22-54"><a href="#cb22-54" aria-hidden="true" tabindex="-1"></a><span class="fu">logging</span><span class="kw">:</span></span>-<span id="cb22-55"><a href="#cb22-55" aria-hidden="true" tabindex="-1"></a><span class="co">  # Possible verbosity values: debug, error, warning, info, silent</span></span>-<span id="cb22-56"><a href="#cb22-56" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">verbosity</span><span class="kw">:</span><span class="at"> warning</span></span>-<span id="cb22-57"><a href="#cb22-57" aria-hidden="true" tabindex="-1"></a><span class="co">  # If the filepath below is not present, then pandoc-plot will log to stderr</span></span>-<span id="cb22-58"><a href="#cb22-58" aria-hidden="true" tabindex="-1"></a><span class="co">  # Otherwise, log messages will be appended to the filepath.</span></span>-<span id="cb22-59"><a href="#cb22-59" aria-hidden="true" tabindex="-1"></a><span class="co">  # filepath: path/to/file.txt</span></span>-<span id="cb22-60"><a href="#cb22-60" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-61"><a href="#cb22-61" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Matplotlib toolkit</span></span>-<span id="cb22-62"><a href="#cb22-62" aria-hidden="true" tabindex="-1"></a><span class="fu">matplotlib</span><span class="kw">:</span></span>-<span id="cb22-63"><a href="#cb22-63" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: matplotlib.py</span></span>-<span id="cb22-64"><a href="#cb22-64" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">tight_bbox</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>-<span id="cb22-65"><a href="#cb22-65" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">transparent</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>-<span id="cb22-66"><a href="#cb22-66" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>-<span id="cb22-67"><a href="#cb22-67" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-68"><a href="#cb22-68" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-69"><a href="#cb22-69" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the MATLAB toolkit</span></span>-<span id="cb22-70"><a href="#cb22-70" aria-hidden="true" tabindex="-1"></a><span class="fu">matlabplot</span><span class="kw">:</span></span>-<span id="cb22-71"><a href="#cb22-71" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: matlab.m</span></span>-<span id="cb22-72"><a href="#cb22-72" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> matlab</span></span>-<span id="cb22-73"><a href="#cb22-73" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-74"><a href="#cb22-74" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-75"><a href="#cb22-75" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Plotly/Python toolkit</span></span>-<span id="cb22-76"><a href="#cb22-76" aria-hidden="true" tabindex="-1"></a><span class="fu">plotly_python</span><span class="kw">:</span></span>-<span id="cb22-77"><a href="#cb22-77" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plotly-python.py</span></span>-<span id="cb22-78"><a href="#cb22-78" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>-<span id="cb22-79"><a href="#cb22-79" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-80"><a href="#cb22-80" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-81"><a href="#cb22-81" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Plotly/R toolkit</span></span>-<span id="cb22-82"><a href="#cb22-82" aria-hidden="true" tabindex="-1"></a><span class="fu">plotly_r</span><span class="kw">:</span></span>-<span id="cb22-83"><a href="#cb22-83" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plotly-r.r</span></span>-<span id="cb22-84"><a href="#cb22-84" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> Rscript</span></span>-<span id="cb22-85"><a href="#cb22-85" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-86"><a href="#cb22-86" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-87"><a href="#cb22-87" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Mathematica toolkit</span></span>-<span id="cb22-88"><a href="#cb22-88" aria-hidden="true" tabindex="-1"></a><span class="fu">mathplot</span><span class="kw">:</span></span>-<span id="cb22-89"><a href="#cb22-89" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: mathematica.m</span></span>-<span id="cb22-90"><a href="#cb22-90" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> math</span></span>-<span id="cb22-91"><a href="#cb22-91" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-92"><a href="#cb22-92" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-93"><a href="#cb22-93" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the GNU Octave toolkit</span></span>-<span id="cb22-94"><a href="#cb22-94" aria-hidden="true" tabindex="-1"></a><span class="fu">octaveplot</span><span class="kw">:</span></span>-<span id="cb22-95"><a href="#cb22-95" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: octave.m</span></span>-<span id="cb22-96"><a href="#cb22-96" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> octave</span></span>-<span id="cb22-97"><a href="#cb22-97" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-98"><a href="#cb22-98" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-99"><a href="#cb22-99" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the ggplot2 toolkit</span></span>-<span id="cb22-100"><a href="#cb22-100" aria-hidden="true" tabindex="-1"></a><span class="fu">ggplot2</span><span class="kw">:</span></span>-<span id="cb22-101"><a href="#cb22-101" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: ggplot2.r</span></span>-<span id="cb22-102"><a href="#cb22-102" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> Rscript</span></span>-<span id="cb22-103"><a href="#cb22-103" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-104"><a href="#cb22-104" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-105"><a href="#cb22-105" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the gnuplot toolkit</span></span>-<span id="cb22-106"><a href="#cb22-106" aria-hidden="true" tabindex="-1"></a><span class="fu">gnuplot</span><span class="kw">:</span></span>-<span id="cb22-107"><a href="#cb22-107" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: gnuplot.gp</span></span>-<span id="cb22-108"><a href="#cb22-108" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> gnuplot</span></span>-<span id="cb22-109"><a href="#cb22-109" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-110"><a href="#cb22-110" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-111"><a href="#cb22-111" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the graphviz toolkit</span></span>-<span id="cb22-112"><a href="#cb22-112" aria-hidden="true" tabindex="-1"></a><span class="fu">graphviz</span><span class="kw">:</span></span>-<span id="cb22-113"><a href="#cb22-113" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: graphviz.dot</span></span>-<span id="cb22-114"><a href="#cb22-114" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> dot</span></span>-<span id="cb22-115"><a href="#cb22-115" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-116"><a href="#cb22-116" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-117"><a href="#cb22-117" aria-hidden="true" tabindex="-1"></a><span class="fu">bokeh</span><span class="kw">:</span></span>-<span id="cb22-118"><a href="#cb22-118" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: bokeh.py</span></span>-<span id="cb22-119"><a href="#cb22-119" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>-<span id="cb22-120"><a href="#cb22-120" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-121"><a href="#cb22-121" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-122"><a href="#cb22-122" aria-hidden="true" tabindex="-1"></a><span class="fu">plotsjl</span><span class="kw">:</span></span>-<span id="cb22-123"><a href="#cb22-123" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plotsjl.jl</span></span>-<span id="cb22-124"><a href="#cb22-124" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> julia</span></span>-<span id="cb22-125"><a href="#cb22-125" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>-<span id="cb22-126"><a href="#cb22-126" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb22-127"><a href="#cb22-127" aria-hidden="true" tabindex="-1"></a><span class="fu">plantuml</span><span class="kw">:</span></span>-<span id="cb22-128"><a href="#cb22-128" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plantuml.txt</span></span>-<span id="cb22-129"><a href="#cb22-129" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> java</span></span>-<span id="cb22-130"><a href="#cb22-130" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span><span class="at"> -jar plantuml.jar</span></span>-<span id="cb22-131"><a href="#cb22-131" aria-hidden="true" tabindex="-1"></a><span class="co">  # On Linux, if you have `plantuml.jar` as an executable, you can also</span></span>-<span id="cb22-132"><a href="#cb22-132" aria-hidden="true" tabindex="-1"></a><span class="co">  # use the following configuration instead:</span></span>-<span id="cb22-133"><a href="#cb22-133" aria-hidden="true" tabindex="-1"></a><span class="co">  # plantuml:</span></span>-<span id="cb22-134"><a href="#cb22-134" aria-hidden="true" tabindex="-1"></a><span class="co">  #   executable: plantuml</span></span>-<span id="cb22-135"><a href="#cb22-135" aria-hidden="true" tabindex="-1"></a><span class="co">  #   command_line_arguments:</span></span></code></pre></div>-<p>A file like the above sets the <strong>default</strong> values; you can still override them in documents directly.</p>-<p>The easiest way to specify configuration for <code>pandoc-plot</code> is to place a <code>.pandoc-plot.yml</code> file in the current working directory. You can also specify a configuration file in document metadata, under the <code>plot-configuration</code> key. For example, in Markdown:</p>-<div class="sourceCode" id="cb23"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span>-<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="an">title:</span><span class="co"> My document</span></span>-<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="an">author:</span><span class="co"> John Doe</span></span>-<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="an">plot-configuration:</span><span class="co"> /path/to/file.yml</span></span>-<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span></code></pre></div>-<p>or on the command line, using the pandoc <code>-M/--metadata</code> flag:</p>-<div class="sourceCode" id="cb24"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">-M</span> plot-configuration=/path/to/file.yml ...</span></code></pre></div>-<p>The hierarchy of configuration files is as follows:</p>-<ol type="1">-<li>A configuration file specified in the metadata under the <code>plot-configuration</code> key;</li>-<li>Otherwise, a file in the current working directory named <code>.pandoc-plot.yml</code>;</li>-<li>Finally, the default configuration is used.</li>-</ol>-<h4 id="executables">Executables</h4>-<p>The <code>executable</code> parameter for all toolkits can be either the executable name (if it is present on the PATH), or the full path to the executable.</p>-<p>Examples:</p>-<div class="sourceCode" id="cb25"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="fu">matplotlib</span><span class="kw">:</span></span>-<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python3</span></span></code></pre></div>-<div class="sourceCode" id="cb26"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="fu">matlabplot</span><span class="kw">:</span></span>-<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> </span><span class="st">&quot;C:\Program Files\Matlab\R2019b</span><span class="sc">\b</span><span class="st">in\matlab.exe&quot;</span></span></code></pre></div>-<h4 id="command-line-arguments">Command-line arguments</h4>-<p><em>New in version 1.0.2.0</em></p>-<p>The <code>command_line_arguments</code> parameter available for all toolkits provides a way to customize the way interpreters are run. For example, if you want to run the <code>matplotlib</code> toolkit with all warnings shown:</p>-<div class="sourceCode" id="cb27"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Matplotlib toolkit</span></span>-<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="fu">matplotlib</span><span class="kw">:</span></span>-<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>-<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span><span class="at"> -Wa</span></span></code></pre></div>-<p>Or if you want <code>julia</code> to use more than one thread:</p>-<div class="sourceCode" id="cb28"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Matplotlib toolkit</span></span>-<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="fu">plotsjl</span><span class="kw">:</span></span>-<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> julia</span></span>-<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span><span class="at"> --threads auto</span></span></code></pre></div>-<h4 id="toolkit-specific-options">Toolkit-specific options</h4>-<h5 id="matplotlib">Matplotlib</h5>-<ul>-<li><code>tight_bbox</code> is a boolean that determines whether to use <code>bbox_inches=&quot;tight&quot;</code> or not when saving Matplotlib figures. For example, <code>tight_bbox: true</code>. See <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.savefig.html">here</a> for details.</li>-<li><code>transparent</code> is a boolean that determines whether to make Matplotlib figure background transparent or not. This is useful, for example, for displaying a plot on top of a colored background on a web page. High-resolution figures are not affected. For example, <code>transparent: true</code>.</li>-</ul>-<h4 id="logging">Logging</h4>-<p>If you are running <code>pandoc-plot</code> on a large document, you might want to turn on logging. You can do so via the configuration file as follows:</p>-<div class="sourceCode" id="cb29"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="fu">logging</span><span class="kw">:</span></span>-<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="co">    # Possible verbosity values: debug, error, warning, info, silent</span></span>-<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="co">    # debug level shows all messages</span></span>-<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="co">    # error level shows all but debug messages, etc.</span></span>-<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">verbosity</span><span class="kw">:</span><span class="at"> info</span></span>-<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a><span class="at">    </span></span>-<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a><span class="co">    # OPTIONAL: log to file</span></span>-<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a><span class="co">    # Remove line below to log to stderr</span></span>-<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">filepath</span><span class="kw">:</span><span class="at"> log.txt</span></span></code></pre></div>-<p>By default, <code>pandoc-plot</code> logs warnings and errors to the standard error stream only.</p>-<h4 id="strict-mode">Strict mode</h4>-<p><em>New in version 1.0.2.0</em></p>-<p>By default, <code>pandoc-plot</code> leaves code blocks unchanged if a figure fails to be rendered. This might be the case if a plotting toolkit is not installed, or if running the code to render a figure returns an error. In <strong>strict mode</strong>, <code>pandoc-plot</code> will immediately halt if it encounters a problem. You can activate strict mode via configuration:</p>-<div class="sourceCode" id="cb30"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="fu">strict</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span></code></pre></div>-<p>Strict mode is ideal if you want to ensure that the figures are correctly rendered in the document.</p>-<h3 id="other-commands">Other commands</h3>-<h4 id="finding-installed-toolkits">Finding installed toolkits</h4>-<p>You can determine which toolkits are available on your current machine using the <code>pandoc-plot toolkits</code> command. Here is the full help text:</p>-<div class="sourceCode" id="cb31"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE toolkits [--config PATH]</span>-<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">Show</span> information on toolkits and exit.</span>-<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>-<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--config</span> PATH            Path to optional configuration file.</span>-<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span></code></pre></div>-<h4 id="cleaning-output">Cleaning output</h4>-<p>Figures produced by <code>pandoc-plot</code> can be placed in a few different locations. You can set a default location in the <a href="#configuration">Configuration</a>, but you can also re-direct specific figures in other directories if you use the <code>directory=...</code> argument in code blocks. These figures will build up over time. You can use the <code>clean</code> command to scan documents and delete the associated <code>pandoc-plot</code> output files. For example, to delete the figures generated from the <code>input.md</code> file:</p>-<div class="sourceCode" id="cb32"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc-plot</span> clean input.md</span></code></pre></div>-<p>This sill remove all directories where a figure <em>could</em> have been placed. <strong>WARNING</strong>: all files will be removed.</p>-<p>Here is the full help text for the <code>clean</code> command:</p>-<div class="sourceCode" id="cb33"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE clean [--config PATH] FILE</span>-<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">Clean</span> output directories where figures from FILE and log files might be</span>-<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">stored.</span> WARNING: All files in those directories will be deleted.</span>-<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>-<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--config</span> PATH            Path to optional configuration file.</span>-<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span></code></pre></div>-<h4 id="configuration-template">Configuration template</h4>-<p>Because <code>pandoc-plot</code> supports a few toolkits, there are a lot of configuration options. Don’t start from scratch! The <code>write-example-config</code> command will create a file for you, which you can then modify:</p>-<div class="sourceCode" id="cb34"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc-plot</span> write-example-config</span></code></pre></div>-<p>You will need to re-name the file to <code>.pandoc-ploy.yml</code> to be able to use it, so don’t worry about overwriting your own configuration.</p>-<p>Here is the full help text for the <code>write-example-config</code> command:</p>-<div class="sourceCode" id="cb35"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE write-example-config [--path FILE]</span>-<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">Write</span> example configuration to a file and exit.</span>-<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>-<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--path</span> FILE              Target location of the configuration file. Default is</span>-<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a>                           <span class="st">&quot;.example-pandoc-plot.yml&quot;</span></span>-<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span></code></pre></div>-<h3 id="as-a-haskell-library">As a Haskell library</h3>-<p>To include the functionality of <code>pandoc-plot</code> in a Haskell package, you can use the <code>make</code> function (for single blocks) or <code>plotFilter</code> function (for entire documents). <a href="https://hackage.haskell.org/package/pandoc-plot">Take a look at the documentation on Hackage</a>.</p>-<h4 id="usage-with-hakyll">Usage with Hakyll</h4>-<p>In case you want to use the filter with your own Hakyll setup, you can use a transform function that works on entire documents:</p>-<div class="sourceCode" id="cb36"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Text.Pandoc.Filter.Plot</span> (plotFilter, defaultConfiguration)</span>-<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Text.Pandoc.Definition</span> (<span class="dt">Pandoc</span>, <span class="dt">Format</span>(..)) <span class="co">-- from pandoc-types</span></span>-<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Hakyll</span></span>-<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a><span class="ot">plotFilter&#39; ::</span> <span class="dt">Pandoc</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Pandoc</span></span>-<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a>plotFilter&#39; <span class="ot">=</span> </span>-<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Notify pandoc-plot that the final conversion will be to HTML</span></span>-<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- This helps give better error messages and adjust default values</span></span>-<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a>  plotFilter defaultConfiguration (<span class="dt">Just</span> <span class="op">$</span> <span class="dt">Format</span> <span class="st">&quot;html5&quot;</span>) </span>-<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a></span>-<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- Unsafe compiler is required because of the interaction</span></span>-<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- in IO (i.e. running an external script).</span></span>-<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a><span class="ot">makePlotPandocCompiler ::</span> <span class="dt">Compiler</span> (<span class="dt">Item</span> <span class="dt">String</span>)</span>-<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a>makePlotPandocCompiler <span class="ot">=</span> </span>-<span id="cb36-15"><a href="#cb36-15" aria-hidden="true" tabindex="-1"></a>  pandocCompilerWithTransformM</span>-<span id="cb36-16"><a href="#cb36-16" aria-hidden="true" tabindex="-1"></a>    defaultHakyllReaderOptions</span>-<span id="cb36-17"><a href="#cb36-17" aria-hidden="true" tabindex="-1"></a>    defaultHakyllWriterOptions</span>-<span id="cb36-18"><a href="#cb36-18" aria-hidden="true" tabindex="-1"></a>    (unsafeCompiler <span class="op">.</span> plotFilter&#39;)</span></code></pre></div>-<h2 id="warning">Warning</h2>-<p>Do not run this filter on unknown documents. There is nothing in <code>pandoc-plot</code> that can stop a script from performing <strong>evil actions</strong>.</p>-</body>-</html>+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
+<head>
+  <meta charset="utf-8" />
+  <meta name="generator" content="pandoc" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+  <title>pandoc-plot 1.3.0 manual</title>
+  <style>
+    code{white-space: pre-wrap;}
+    span.smallcaps{font-variant: small-caps;}
+    span.underline{text-decoration: underline;}
+    div.column{display: inline-block; vertical-align: top; width: 50%;}
+    div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
+    ul.task-list{list-style: none;}
+    pre > code.sourceCode { white-space: pre; position: relative; }
+    pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
+    pre > code.sourceCode > span:empty { height: 1.2em; }
+    .sourceCode { overflow: visible; }
+    code.sourceCode > span { color: inherit; text-decoration: inherit; }
+    div.sourceCode { margin: 1em 0; }
+    pre.sourceCode { margin: 0; }
+    @media screen {
+    div.sourceCode { overflow: auto; }
+    }
+    @media print {
+    pre > code.sourceCode { white-space: pre-wrap; }
+    pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
+    }
+    pre.numberSource code
+      { counter-reset: source-line 0; }
+    pre.numberSource code > span
+      { position: relative; left: -4em; counter-increment: source-line; }
+    pre.numberSource code > span > a:first-child::before
+      { content: counter(source-line);
+        position: relative; left: -1em; text-align: right; vertical-align: baseline;
+        border: none; display: inline-block;
+        -webkit-touch-callout: none; -webkit-user-select: none;
+        -khtml-user-select: none; -moz-user-select: none;
+        -ms-user-select: none; user-select: none;
+        padding: 0 4px; width: 4em;
+        color: #aaaaaa;
+      }
+    pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
+    div.sourceCode
+      {   }
+    @media screen {
+    pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
+    }
+    code span.al { color: #ff0000; font-weight: bold; } /* Alert */
+    code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+    code span.at { color: #7d9029; } /* Attribute */
+    code span.bn { color: #40a070; } /* BaseN */
+    code span.bu { } /* BuiltIn */
+    code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+    code span.ch { color: #4070a0; } /* Char */
+    code span.cn { color: #880000; } /* Constant */
+    code span.co { color: #60a0b0; font-style: italic; } /* Comment */
+    code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+    code span.do { color: #ba2121; font-style: italic; } /* Documentation */
+    code span.dt { color: #902000; } /* DataType */
+    code span.dv { color: #40a070; } /* DecVal */
+    code span.er { color: #ff0000; font-weight: bold; } /* Error */
+    code span.ex { } /* Extension */
+    code span.fl { color: #40a070; } /* Float */
+    code span.fu { color: #06287e; } /* Function */
+    code span.im { } /* Import */
+    code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+    code span.kw { color: #007020; font-weight: bold; } /* Keyword */
+    code span.op { color: #666666; } /* Operator */
+    code span.ot { color: #007020; } /* Other */
+    code span.pp { color: #bc7a00; } /* Preprocessor */
+    code span.sc { color: #4070a0; } /* SpecialChar */
+    code span.ss { color: #bb6688; } /* SpecialString */
+    code span.st { color: #4070a0; } /* String */
+    code span.va { color: #19177c; } /* Variable */
+    code span.vs { color: #4070a0; } /* VerbatimString */
+    code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
+  </style>
+  <link rel="stylesheet" href="data:text/css,html%20%7B%20font%2Dsize%3A%20100%25%3B%20overflow%2Dy%3A%20scroll%3B%20%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%20%2Dms%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%20%7Dbody%7Bcolor%3A%23444%3Bfont%2Dfamily%3AGeorgia%2C%20Palatino%2C%20%27Palatino%20Linotype%27%2C%20Times%2C%20%27Times%20New%20Roman%27%2C%20serif%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5em%3Bpadding%3A1em%3Bmargin%3Aauto%3Bmax%2Dwidth%3A42em%3Bbackground%3A%23fefefe%3B%7Da%7B%20color%3A%20%230645ad%3B%20text%2Ddecoration%3Anone%3B%7Da%3Avisited%7B%20color%3A%20%230b0080%3B%20%7Da%3Ahover%7B%20color%3A%20%2306e%3B%20%7Da%3Aactive%7B%20color%3A%23faa700%3B%20%7Da%3Afocus%7B%20outline%3A%20thin%20dotted%3B%20%7Da%3Ahover%2C%20a%3Aactive%7B%20outline%3A%200%3B%20%7D%3A%3A%2Dmoz%2Dselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%23000%7D%3A%3Aselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%23000%7Da%3A%3A%2Dmoz%2Dselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%230645ad%7Da%3A%3Aselection%7Bbackground%3Argba%28255%2C255%2C0%2C0%2E3%29%3Bcolor%3A%230645ad%7Dp%7Bmargin%3A1em%200%3B%7Dimg%7Bmax%2Dwidth%3A100%25%3B%7Dh1%2Ch2%2Ch3%2Ch4%2Ch5%2Ch6%7Bfont%2Dweight%3Anormal%3Bcolor%3A%23111%3Bline%2Dheight%3A1em%3B%7Dh4%2Ch5%2Ch6%7B%20font%2Dweight%3A%20bold%3B%20%7Dh1%7B%20font%2Dsize%3A2%2E5em%3B%20%7Dh2%7B%20font%2Dsize%3A2em%3B%20%7Dh3%7B%20font%2Dsize%3A1%2E5em%3B%20%7Dh4%7B%20font%2Dsize%3A1%2E2em%3B%20%7Dh5%7B%20font%2Dsize%3A1em%3B%20%7Dh6%7B%20font%2Dsize%3A0%2E9em%3B%20%7Dblockquote%7Bcolor%3A%23666666%3Bmargin%3A0%3Bpadding%2Dleft%3A%203em%3Bborder%2Dleft%3A%200%2E5em%20%23EEE%20solid%3B%7Dhr%20%7B%20display%3A%20block%3B%20height%3A%202px%3B%20border%3A%200%3B%20border%2Dtop%3A%201px%20solid%20%23aaa%3Bborder%2Dbottom%3A%201px%20solid%20%23eee%3B%20margin%3A%201em%200%3B%20padding%3A%200%3B%20%7Dpre%2C%20code%2C%20kbd%2C%20samp%20%7B%20color%3A%20%23000%3B%20font%2Dfamily%3A%20monospace%2C%20monospace%3B%20%5Ffont%2Dfamily%3A%20%27courier%20new%27%2C%20monospace%3B%20font%2Dsize%3A%200%2E98em%3B%20%7Dpre%20%7B%20white%2Dspace%3A%20pre%3B%20white%2Dspace%3A%20pre%2Dwrap%3B%20word%2Dwrap%3A%20break%2Dword%3B%20%7Db%2C%20strong%20%7B%20font%2Dweight%3A%20bold%3B%20%7Ddfn%20%7B%20font%2Dstyle%3A%20italic%3B%20%7Dins%20%7B%20background%3A%20%23ff9%3B%20color%3A%20%23000%3B%20text%2Ddecoration%3A%20none%3B%20%7Dmark%20%7B%20background%3A%20%23ff0%3B%20color%3A%20%23000%3B%20font%2Dstyle%3A%20italic%3B%20font%2Dweight%3A%20bold%3B%20%7Dsub%2C%20sup%20%7B%20font%2Dsize%3A%2075%25%3B%20line%2Dheight%3A%200%3B%20position%3A%20relative%3B%20vertical%2Dalign%3A%20baseline%3B%20%7Dsup%20%7B%20top%3A%20%2D0%2E5em%3B%20%7Dsub%20%7B%20bottom%3A%20%2D0%2E25em%3B%20%7Dul%2C%20ol%20%7B%20margin%3A%201em%200%3B%20padding%3A%200%200%200%202em%3B%20%7Dli%20p%3Alast%2Dchild%20%7B%20margin%3A0%20%7Ddd%20%7B%20margin%3A%200%200%200%202em%3B%20%7Dimg%20%7B%20border%3A%200%3B%20%2Dms%2Dinterpolation%2Dmode%3A%20bicubic%3B%20vertical%2Dalign%3A%20middle%3B%20%7Dtable%20%7Bborder%2Dcollapse%3A%20collapse%3Bborder%2Dspacing%3A%200%3Bwidth%3A%20100%25%3B%7Dth%20%7B%20border%2Dbottom%3A%201px%20solid%20black%3B%20%7Dtd%20%7B%20vertical%2Dalign%3A%20top%3B%20%7D%40media%20only%20screen%20and%20%28min%2Dwidth%3A%20480px%29%20%7Bbody%7Bfont%2Dsize%3A14px%3B%7D%7D%40media%20only%20screen%20and%20%28min%2Dwidth%3A%20768px%29%20%7Bbody%7Bfont%2Dsize%3A16px%3B%7D%7D%40media%20print%20%7B%2A%20%7B%20background%3A%20transparent%20%21important%3B%20color%3A%20black%20%21important%3B%20filter%3Anone%20%21important%3B%20%2Dms%2Dfilter%3A%20none%20%21important%3B%20%7Dbody%7Bfont%2Dsize%3A12pt%3B%20max%2Dwidth%3A100%25%3B%7Da%2C%20a%3Avisited%20%7B%20text%2Ddecoration%3A%20underline%3B%20%7Dhr%20%7B%20height%3A%201px%3B%20border%3A0%3B%20border%2Dbottom%3A1px%20solid%20black%3B%20%7Da%5Bhref%5D%3Aafter%20%7B%20content%3A%20%22%20%28%22%20attr%28href%29%20%22%29%22%3B%20%7Dabbr%5Btitle%5D%3Aafter%20%7B%20content%3A%20%22%20%28%22%20attr%28title%29%20%22%29%22%3B%20%7D%2Eir%20a%3Aafter%2C%20a%5Bhref%5E%3D%22javascript%3A%22%5D%3Aafter%2C%20a%5Bhref%5E%3D%22%23%22%5D%3Aafter%20%7B%20content%3A%20%22%22%3B%20%7Dpre%2C%20blockquote%20%7B%20border%3A%201px%20solid%20%23999%3B%20padding%2Dright%3A%201em%3B%20page%2Dbreak%2Dinside%3A%20avoid%3B%20%7Dtr%2C%20img%20%7B%20page%2Dbreak%2Dinside%3A%20avoid%3B%20%7Dimg%20%7B%20max%2Dwidth%3A%20100%25%20%21important%3B%20%7D%40page%20%3Aleft%20%7B%20margin%3A%2015mm%2020mm%2015mm%2010mm%3B%20%7D%40page%20%3Aright%20%7B%20margin%3A%2015mm%2010mm%2015mm%2020mm%3B%20%7Dp%2C%20h2%2C%20h3%20%7B%20orphans%3A%203%3B%20widows%3A%203%3B%20%7Dh2%2C%20h3%20%7B%20page%2Dbreak%2Dafter%3A%20avoid%3B%20%7D%7D" />
+  <!--[if lt IE 9]>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+  <![endif]-->
+</head>
+<body>
+<header id="title-block-header">
+<h1 class="title">pandoc-plot 1.3.0 manual</h1>
+</header>
+<!--
+The file MANUAL.md is automatically generated by the tools/mkmanual.ps1 script. Do not edit manually.
+-->
+<h2 id="a-pandoc-filter-to-generate-figures-from-code-blocks-in-documents">A Pandoc filter to generate figures from code blocks in documents</h2>
+<p><code>pandoc-plot</code> turns code blocks present in your documents (Markdown, LaTeX, etc.) into embedded figures, using your plotting toolkit of choice, including Matplotlib, ggplot2, MATLAB, Mathematica, and more.</p>
+<ul>
+<li><a href="#features-overview">Features Overview</a>
+<ul>
+<li><a href="#captions">Captions</a></li>
+<li><a href="#link-to-source-code">Link to source code</a></li>
+<li><a href="#preamble-scripts">Preamble scripts</a></li>
+<li><a href="#support-for-interactive-plots">Support for interactive plots</a></li>
+<li><a href="#performance">Performance</a></li>
+<li><a href="#compatibility-with-pandoc-crossref">Compatibility with pandoc-crossref</a></li>
+</ul></li>
+<li><a href="#detailed-usage">Detailed usage</a>
+<ul>
+<li><a href="#as-a-filter">As a filter</a></li>
+<li><a href="#syntax">Syntax</a>
+<ul>
+<li><a href="#markdown">Markdown</a></li>
+<li><a href="#latex">LaTeX</a></li>
+</ul></li>
+<li><a href="#parameters-and-options">Parameters and options</a>
+<ul>
+<li><a href="#code-highlighting">Code highlighting</a></li>
+</ul></li>
+<li><a href="#interactive-html-figures">Interactive HTML figures</a></li>
+<li><a href="#configuration">Configuration</a>
+<ul>
+<li><a href="#executables">Executables</a></li>
+<li><a href="#command-line-arguments">Command-line arguments</a></li>
+<li><a href="#toolkit-specific-options">Toolkit-specific options</a></li>
+<li><a href="#logging">Logging</a></li>
+<li><a href="#strict-mode">Strict mode</a></li>
+</ul></li>
+<li><a href="#other-commands">Other commands</a>
+<ul>
+<li><a href="#finding-installed-toolkits">Finding installed toolkits</a></li>
+<li><a href="#cleaning-output">Cleaning output</a></li>
+<li><a href="#configuration-template">Configuration template</a></li>
+</ul></li>
+<li><a href="#as-a-haskell-library">As a Haskell library</a>
+<ul>
+<li><a href="#usage-with-hakyll">Usage with Hakyll</a></li>
+</ul></li>
+</ul></li>
+<li><a href="#warning">Warning</a></li>
+</ul>
+<h2 id="features-overview">Features Overview</h2>
+<h3 id="captions">Captions</h3>
+<p>You can also specify a caption for your image. This is done using the optional <code>caption</code> parameter.</p>
+<p><strong>Markdown</strong>:</p>
+<div class="sourceCode" id="cb1"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.matlabplot caption=&quot;This is a simple figure with a **Markdown** caption&quot;}</span></span>
+<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="in">x  = 0: .1 : 2*pi;</span></span>
+<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="in">y1 = cos(x);</span></span>
+<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="in">y2 = sin(x);</span></span>
+<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="in">figure</span></span>
+<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="in">plot(x, y1, &#39;b&#39;, x, y2, &#39;r-.&#39;, &#39;LineWidth&#39;, 2)</span></span>
+<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>
+<p><strong>LaTex</strong>:</p>
+<div class="sourceCode" id="cb2"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[caption=This is a simple figure with a caption]{matlabplot}</span>
+<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="vs">x  = 0: .1 : 2*pi;</span></span>
+<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="vs">y1 = cos(x);</span></span>
+<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="vs">y2 = sin(x);</span></span>
+<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="vs">figure</span></span>
+<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="vs">plot(x, y1, &#39;b&#39;, x, y2, &#39;r-.&#39;, &#39;LineWidth&#39;, 2)</span></span>
+<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>
+<p>Caption formatting unfortunately cannot be determined automatically. To specify a caption format (e.g. “markdown”, “LaTeX”, etc.), see <a href="#configuration">Configuration</a>.</p>
+<h3 id="link-to-source-code">Link to source code</h3>
+<p>In case of an output format that supports links (e.g. HTML), the embedded image generated by <code>pandoc-plot</code> can show a link to the source code which was used to generate the file. Therefore, other people can see what code was used to create your figures.</p>
+<p>You can turn this on via the <code>source=true</code> key:</p>
+<p><strong>Markdown</strong>:</p>
+<div class="sourceCode" id="cb3"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.mathplot source=true}</span></span>
+<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="in">...</span></span>
+<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>
+<p><strong>LaTex</strong>:</p>
+<div class="sourceCode" id="cb4"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[source=true]{mathplot}</span>
+<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="vs">...</span></span>
+<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>
+<p>or via a <a href="#Configuration">configuration file</a>.</p>
+<h3 id="preamble-scripts">Preamble scripts</h3>
+<p>If you find yourself always repeating some steps, inclusion of scripts is possible using the <code>preamble</code> parameter. For example, if you want all Matplotlib plots to have the <a href="https://matplotlib.org/tutorials/introductory/customizing.html#sphx-glr-tutorials-introductory-customizing-py"><code>ggplot</code></a> style, you can write a very short preamble <code>style.py</code> like so:</p>
+<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> matplotlib.pyplot <span class="im">as</span> plt</span>
+<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>plt.style.use(<span class="st">&#39;ggplot&#39;</span>)</span></code></pre></div>
+<p>and include it in your document as follows:</p>
+<div class="sourceCode" id="cb6"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.matplotlib preamble=style.py}</span></span>
+<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="in">plt.figure()</span></span>
+<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="in">plt.plot([0,1,2,3,4], [1,2,3,4,5])</span></span>
+<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="in">plt.title(&#39;This is an example figure&#39;)</span></span>
+<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>
+<p>Which is equivalent to writing the following markdown:</p>
+<div class="sourceCode" id="cb7"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{.matplotlib}</span></span>
+<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="in">import matplotlib.pyplot as plt</span></span>
+<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="in">plt.style.use(&#39;ggplot&#39;)</span></span>
+<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="in">plt.figure()</span></span>
+<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="in">plt.plot([0,1,2,3,4], [1,2,3,4,5])</span></span>
+<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="in">plt.title(&#39;This is an example figure&#39;)</span></span>
+<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span></code></pre></div>
+<p>The equivalent LaTeX usage is as follows:</p>
+<div class="sourceCode" id="cb8"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[include=style.py]{matplotlib}</span>
+<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>
+<p>This <code>preamble</code> parameter is perfect for longer documents with many plots. Simply define the style you want in a separate script! You can also import packages this way, or define functions you often use.</p>
+<h3 id="support-for-interactive-plots">Support for interactive plots</h3>
+<p>Starting with version 0.8.0.0, <code>pandoc-plot</code> supports the creation of interactive plots (if a toolkit supports it). All you need to do is set the save format to <code>html</code>. The resulting plot is fully self-contained, so it can be displayed offline.</p>
+<h3 id="performance">Performance</h3>
+<p><code>pandoc-plot</code> minimizes work, only generating figures if it absolutely must, i.e. if the content has changed. <code>pandoc-plot</code> will save the hash of the source code used to generate a figure in its filename. Before generating a figure, <code>pandoc-plot</code> will check it this figure already exists based on the hash of its source! This also means that there is no way to directly name figures.</p>
+<p>Moreover, starting with version 0.5.0.0, <code>pandoc-plot</code> takes advantage of multicore CPUs, rendering figures <strong>in parallel</strong>.</p>
+<p>Therefore, you can confidently run the filter on very large documents containing hundreds of figures, like a book or a thesis.</p>
+<h3 id="compatibility-with-pandoc-crossref">Compatibility with pandoc-crossref</h3>
+<p><a href="https://github.com/lierdakil/pandoc-crossref"><code>pandoc-crossref</code></a> is a pandoc filter that makes it effortless to cross-reference objects in Markdown documents.</p>
+<p>You can use <code>pandoc-crossref</code> in conjunction with <code>pandoc-plot</code> for the ultimate figure-making pipeline. You can combine both in a figure like so:</p>
+<div class="sourceCode" id="cb9"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="in">```{#fig:myexample .plotly_python caption=&quot;This is a caption&quot;}</span></span>
+<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="in"># Insert figure script here</span></span>
+<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="in">```</span></span>
+<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>As you can see in @fig:myexample, ...</span></code></pre></div>
+<p>If the above source is located in file <code>myfile.md</code>, you can render the figure and references by applying <code>pandoc-plot</code> <strong>first</strong>, and then <code>pandoc-crossref</code>. For example:</p>
+<div class="sourceCode" id="cb10"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">--filter</span> pandoc-crossref <span class="at">-i</span> myfile.md <span class="at">-o</span> myfile.html</span></code></pre></div>
+<h2 id="detailed-usage">Detailed usage</h2>
+<p><code>pandoc-plot</code> is a command line executable with a few functions. You can take a look at the help using the <code>-h</code>/<code>--help</code> flag:</p>
+<div class="sourceCode" id="cb11"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc-plot</span> 1.3.0 <span class="at">-</span> generate figures directly in documents</span>
+<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE [<span class="er">(</span><span class="ex">-v</span><span class="kw">|</span><span class="ex">--version</span><span class="kw">)</span> <span class="kw">|</span> <span class="ex">--full-version</span> <span class="kw">|</span> <span class="kw">(</span><span class="ex">-m</span><span class="kw">|</span><span class="ex">--manual</span><span class="kw">)</span><span class="ex">]</span> </span>
+<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>                       <span class="ex">[COMMAND]</span> [AST]</span>
+<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">This</span> pandoc filter generates plots from code blocks using a multitude of</span>
+<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">possible</span> renderers. This allows to keep documentation and figures in perfect</span>
+<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">synchronicity.</span></span>
+<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>
+<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-v,--version</span>             Show version number and exit.</span>
+<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--full-version</span>           Show full version information and exit.</span>
+<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-m,--manual</span>              Open the manual page in the default web browser and</span>
+<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>                           <span class="ex">exit.</span></span>
+<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span>
+<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> commands:</span>
+<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>  <span class="ex">toolkits</span>                 Show information on toolkits and exit.</span>
+<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>  <span class="ex">clean</span>                    Clean output directories where figures from FILE and</span>
+<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>                           <span class="ex">log</span> files might be stored. WARNING: All files in</span>
+<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>                           <span class="ex">those</span> directories will be deleted.</span>
+<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>  <span class="ex">write-example-config</span>     Write example configuration to a file and exit.</span>
+<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a><span class="ex">More</span> information can be found via the manual <span class="er">(</span><span class="ex">pandoc-plot</span> <span class="at">--manual</span><span class="kw">)</span> <span class="ex">or</span> the</span>
+<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a><span class="ex">repository</span> README, located at https://github.com/LaurentRDC/pandoc-plot</span></code></pre></div>
+<h3 id="as-a-filter">As a filter</h3>
+<p>The most common use for <code>pandoc-plot</code> is as a pandoc filter, in which case it should be called without arguments. For example:</p>
+<div class="sourceCode" id="cb12"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">-i</span> input.md <span class="at">-o</span> output.html</span></code></pre></div>
+<p>If <code>pandoc-plot</code> fails to render a code block into a figure, the filtering will not stop. Your code blocks will stay unchanged, unless you activate <a href="#strict-mode">strict mode</a>.</p>
+<p>You can chain other filters with it (e.g., <a href="https://github.com/lierdakil/pandoc-crossref"><code>pandoc-crossref</code></a>) like so:</p>
+<div class="sourceCode" id="cb13"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">--filter</span> pandoc-crossref <span class="at">-i</span> input.md <span class="at">-o</span> output.html</span></code></pre></div>
+<h3 id="syntax">Syntax</h3>
+<p>The syntax for code blocks in documents is shown below. <code>pandoc-plot</code> looks for code blocks with a specific class, depending on the toolkit you want to use. <code>pandoc-plot</code> will run the code and capture the figure output. There can only be <strong>one</strong> figure per code block.</p>
+<p>The possible parameters and options are described in <a href="#parameters-and-options">further below</a>.</p>
+<h4 id="markdown">Markdown</h4>
+<div class="sourceCode" id="cb14"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.cls param1=value1 param2=value2 ...}</span></span>
+<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>
+<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>
+<h4 id="latex">LaTeX</h4>
+<p>Note that the <code>minted</code> LaTeX package need not be installed.</p>
+<div class="sourceCode" id="cb15"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">minted</span>}[param1=value1, param2=value2, ...]{cls}</span>
+<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="vs">...</span></span>
+<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>
+<h3 id="parameters-and-options">Parameters and options</h3>
+<p>There are parameters that affect the figure that will be included in your document. Here are all the possible general parameters, in Markdown syntax:</p>
+<div class="sourceCode" id="cb16"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.cls </span></span>
+<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="in">      .language</span></span>
+<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="in">      directory=(path) </span></span>
+<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="in">      caption=(text) </span></span>
+<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="in">      format=(PNG|PDF|SVG|JPG|EPS|GIF|TIF|WEBP|HTML|LATEX) </span></span>
+<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="in">      source=(true|True|false|False) </span></span>
+<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="in">      source_label=(text)</span></span>
+<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a><span class="in">      preamble=(path) </span></span>
+<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="in">      dpi=(integer)</span></span>
+<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a><span class="in">      dependencies=[...]</span></span>
+<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a><span class="in">      file=(path)</span></span>
+<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a><span class="in">      executable=(path) </span></span>
+<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a><span class="in">      caption_format=(text)</span></span>
+<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a><span class="in">      }</span></span>
+<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>
+<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>
+<ul>
+<li><code>cls</code> must be one of the following: <code>matplotlib</code>, <code>matlabplot</code>, <code>plotly_python</code>, <code>plotly_r</code>, <code>mathplot</code>, <code>octaveplot</code>, <code>ggplot2</code>, <code>gnuplot</code>, <code>graphviz</code>, <code>bokeh</code>, <code>plotsjl</code>, <code>plantuml</code> (<em>new in version 1.1.0</em>).</li>
+</ul>
+<p>All following parameters are optional, with their default values controlled by the <a href="#configuration">configuration</a>.</p>
+<ul>
+<li><code>language</code> specifies the programming language used in this block. This parameter is ignored by <code>pandoc-plot</code>, but your text editor may use it to highlight code. See <a href="#code-highlighting">Code highlighting</a> below.</li>
+<li><code>directory</code> is a path to the directory where the figure and source code will be saved. You cannot control the file name. This path is either absolute, or relative from the working directory where you call <code>pandoc-plot</code>.</li>
+<li><code>caption</code> is the caption text. The format of the caption is specified in the <code>caption_format</code> parameter, described below.</li>
+<li><code>format</code> is the desired filetype for the resulting figure. Possible values for <code>format</code> are [<code>PNG</code>, <code>PDF</code>, <code>SVG</code>, <code>JPG</code>, <code>EPS</code>, <code>GIF</code>, <code>TIF</code>, <code>WEBP</code>, <code>HTML</code>, <code>LATEX</code>]. Not all toolkits support all formats. See <code>pandoc-plot toolkits</code> for toolkit-specific information regarding save formats. The <code>HTML</code> format is special; it can produce standalone, offline, interactive plots. As such, it only makes sense to use this format when creating HTML documents. Similarly, the <code>LATEX</code> format is special; plots in the LaTeX format will be embedded in the document. Therefore, it only makes sense to use this format when creating LaTeX documents.</li>
+<li><code>source</code> is a boolean toggle that determines whether the source code should be linked in the caption or not. Possible values are [<code>true</code>, <code>True</code>, <code>false</code>, <code>False</code>].</li>
+<li><code>source_label</code> is the text that links to source code (if <code>source=true</code>). This is useful if you are writing text in a different language. The default is <code>source_label=&quot;Source Code&quot;</code>. You might want to set this via the <a href="#configuration">configuration</a> instead.</li>
+<li><code>preamble</code> is a path to a script that will be included as a preamble to the content of the code block. This path is either absolute, or relative from the working directory where you call <code>pandoc-plot</code>.</li>
+<li><code>dpi</code> is the pixel density of the figure in dots-per-inch. Possible values are positive integers. Not all toolkits respect this.</li>
+<li><code>dependencies</code> is a list of files/directories that affect the figure, for example data files. If one of those files/directories changes, <code>pandoc-plot</code> will re-render the associated figure. Format is a comma-separated list, e.g. <code>dependencies=[data.txt, foo.bar, ~/wtv]</code>. Values for <code>dependencies</code> in the configuration file will be appended to the values in a code block.</li>
+<li><code>file</code> is a path to a file from which to read the figure content. If this parameter is used, the content of the code block is ignored. By using this parameter, you can use all the standard tooling of your plotting toolkit of choice, which is especially useful for complex figures.</li>
+<li><code>executable</code> is a path to the executable to use (e.g. <code>C:\\python3.exe</code>) or the name of the executable (e.g. <code>python3</code>).</li>
+<li><code>caption_format</code> is the text format of the caption. Possible values are exactly the same as <code>pandoc</code>’s format specification, usually <code>FORMAT+EXTENSION-EXTENSION</code>. For example, captions in Markdown with raw LaTeX would be parsed correctly provided that <code>caption_format=markdown+raw_tex</code>. See Pandoc’s guide on <a href="https://pandoc.org/MANUAL.html#specifying-formats">Specifying formats</a>.</li>
+</ul>
+<h4 id="code-highlighting">Code highlighting</h4>
+<p>If your editor supports code highlighting in code blocks, you can also include the programming language. In Markdown:</p>
+<div class="sourceCode" id="cb17"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.language .cls (options)}</span></span>
+<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>
+<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>
+<p>or Latex:</p>
+<div class="sourceCode" id="cb18"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">\begin</span>{<span class="ex">minted</span>}[(options)]{language, cls}</span>
+<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="vs">  # script content</span></span>
+<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="vs">  </span><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>
+<p>For example, for GGPlot2 figures:</p>
+<div class="sourceCode" id="cb19"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>  <span class="in">```{.r .ggplot2 caption=Highlighted code block}</span></span>
+<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="in">  # script content</span></span>
+<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="in">  ```</span></span></code></pre></div>
+<p>or (Latex):</p>
+<div class="sourceCode" id="cb20"><pre class="sourceCode latex"><code class="sourceCode latex"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">\begin</span>{<span class="ex">minted</span>}[caption=Highlighted code block]{r, ggplot2}</span>
+<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="vs">  # script content</span></span>
+<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="vs">  </span><span class="kw">\end</span>{<span class="ex">minted</span>}</span></code></pre></div>
+<p>This way, you benefit from code highlighting <em>and</em> <code>pandoc-plot</code>.</p>
+<h3 id="interactive-html-figures">Interactive HTML figures</h3>
+<p>Interactive HTML figures are available for a few toolkits, e.g. <code>bokeh</code>. To make a figure interactive, use the output format <code>format=html</code>. This only makes sense if your output file is also HTML.</p>
+<p>You can take a look at the <a href="https://laurentrdc.github.io/pandoc-plot/">demonstration page</a> for an example result.</p>
+<p>Many interactive plots rely on javascript scripts stored on the internet. If you want to have a self-contained document that can be viewed offline – or you want your document to work for the next 10 years –, you can use pandoc’s <code>--self-contained</code> flag:</p>
+<div class="sourceCode" id="cb21"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--self-contained</span> <span class="at">--filter</span> pandoc-plot <span class="at">-i</span> mydoc.md <span class="at">-o</span> webpage.html </span></code></pre></div>
+<p>The resulting output <code>webpage.html</code> will contain everything, at the cost of size.</p>
+<h3 id="configuration">Configuration</h3>
+<p>To avoid repetition, <code>pandoc-plot</code> can be configured using simple YAML
+files. Here are <strong>all</strong> the possible parameters:</p>
+<div class="sourceCode" id="cb22"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co"># This is an example configuration. Everything in this file is optional.</span></span>
+<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Please refer to the documentation to know about the parameters herein.</span></span>
+<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
+<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="co"># The `executable` parameter for all toolkits can be either the</span></span>
+<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a><span class="co"># executable name (if it is present on the PATH), or</span></span>
+<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a><span class="co"># the full path to the executable.</span></span>
+<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a><span class="co"># E.g.:</span></span>
+<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a><span class="co">#  executable: python3</span></span>
+<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="co">#  executable: &quot;C:\Python37\Scripts\python.exe&quot;</span></span>
+<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="co"># The following parameters affect all toolkits</span></span>
+<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a><span class="co"># Directory where to save the plots. The path can be relative to pandoc-plot&#39;s</span></span>
+<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a><span class="co"># current working directory, or absolute.</span></span>
+<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a><span class="fu">directory</span><span class="kw">:</span><span class="at"> plots/</span></span>
+<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a><span class="co"># Whether or not to include a link to the source script in the caption. </span></span>
+<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a><span class="co"># Particularly useful for HTML output.</span></span>
+<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a><span class="fu">source</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
+<span id="cb22-19"><a href="#cb22-19" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-20"><a href="#cb22-20" aria-hidden="true" tabindex="-1"></a><span class="co"># When `strict: false`, pandoc-plot will leave code blocks untouched if a plot</span></span>
+<span id="cb22-21"><a href="#cb22-21" aria-hidden="true" tabindex="-1"></a><span class="co"># could not be generated. This could happen if, for example, a toolkit is not</span></span>
+<span id="cb22-22"><a href="#cb22-22" aria-hidden="true" tabindex="-1"></a><span class="co"># installed. If you want pandoc-plot to fail instead, use `strict: true`.</span></span>
+<span id="cb22-23"><a href="#cb22-23" aria-hidden="true" tabindex="-1"></a><span class="fu">strict</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
+<span id="cb22-24"><a href="#cb22-24" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-25"><a href="#cb22-25" aria-hidden="true" tabindex="-1"></a><span class="co"># Text label for links to source code.</span></span>
+<span id="cb22-26"><a href="#cb22-26" aria-hidden="true" tabindex="-1"></a><span class="co"># You can change this label if you are writing a document in a non-English language. </span></span>
+<span id="cb22-27"><a href="#cb22-27" aria-hidden="true" tabindex="-1"></a><span class="co"># This only matters if `source` is set to `true`.</span></span>
+<span id="cb22-28"><a href="#cb22-28" aria-hidden="true" tabindex="-1"></a><span class="fu">source_label</span><span class="kw">:</span><span class="at"> Source code</span></span>
+<span id="cb22-29"><a href="#cb22-29" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-30"><a href="#cb22-30" aria-hidden="true" tabindex="-1"></a><span class="co"># Default density of figures in dots per inches (DPI). </span></span>
+<span id="cb22-31"><a href="#cb22-31" aria-hidden="true" tabindex="-1"></a><span class="co"># This can be changed in the document specifically as well.</span></span>
+<span id="cb22-32"><a href="#cb22-32" aria-hidden="true" tabindex="-1"></a><span class="fu">dpi</span><span class="kw">:</span><span class="at"> </span><span class="dv">80</span></span>
+<span id="cb22-33"><a href="#cb22-33" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-34"><a href="#cb22-34" aria-hidden="true" tabindex="-1"></a><span class="co"># Default format in which to save the figures. This can be specified </span></span>
+<span id="cb22-35"><a href="#cb22-35" aria-hidden="true" tabindex="-1"></a><span class="co"># individually as well.</span></span>
+<span id="cb22-36"><a href="#cb22-36" aria-hidden="true" tabindex="-1"></a><span class="fu">format</span><span class="kw">:</span><span class="at"> PNG</span></span>
+<span id="cb22-37"><a href="#cb22-37" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-38"><a href="#cb22-38" aria-hidden="true" tabindex="-1"></a><span class="co"># Default files/directories on which all figures depend. If any of these files/directories</span></span>
+<span id="cb22-39"><a href="#cb22-39" aria-hidden="true" tabindex="-1"></a><span class="co"># changes, all figures will be re-rendered.</span></span>
+<span id="cb22-40"><a href="#cb22-40" aria-hidden="true" tabindex="-1"></a><span class="co"># Dependencies specified in code blocks will be appended to this list.</span></span>
+<span id="cb22-41"><a href="#cb22-41" aria-hidden="true" tabindex="-1"></a><span class="fu">dependencies</span><span class="kw">:</span></span>
+<span id="cb22-42"><a href="#cb22-42" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span><span class="at"> file1.txt</span></span>
+<span id="cb22-43"><a href="#cb22-43" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span><span class="at"> file2.txt</span></span>
+<span id="cb22-44"><a href="#cb22-44" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-45"><a href="#cb22-45" aria-hidden="true" tabindex="-1"></a><span class="co"># Text format for the captions. Unfortunately, there is no way to detect</span></span>
+<span id="cb22-46"><a href="#cb22-46" aria-hidden="true" tabindex="-1"></a><span class="co"># this automatically. You can use the same notation as Pandoc&#39;s --from </span></span>
+<span id="cb22-47"><a href="#cb22-47" aria-hidden="true" tabindex="-1"></a><span class="co"># parameter, specified here: </span></span>
+<span id="cb22-48"><a href="#cb22-48" aria-hidden="true" tabindex="-1"></a><span class="co">#     https://pandoc.org/MANUAL.html#option--from</span></span>
+<span id="cb22-49"><a href="#cb22-49" aria-hidden="true" tabindex="-1"></a><span class="co"># Example: markdown, rst+raw_tex</span></span>
+<span id="cb22-50"><a href="#cb22-50" aria-hidden="true" tabindex="-1"></a><span class="fu">caption_format</span><span class="kw">:</span><span class="at"> markdown+tex_math_dollars</span></span>
+<span id="cb22-51"><a href="#cb22-51" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-52"><a href="#cb22-52" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-53"><a href="#cb22-53" aria-hidden="true" tabindex="-1"></a><span class="co"># Logging configuration</span></span>
+<span id="cb22-54"><a href="#cb22-54" aria-hidden="true" tabindex="-1"></a><span class="fu">logging</span><span class="kw">:</span></span>
+<span id="cb22-55"><a href="#cb22-55" aria-hidden="true" tabindex="-1"></a><span class="co">  # Possible verbosity values: debug, error, warning, info, silent</span></span>
+<span id="cb22-56"><a href="#cb22-56" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">verbosity</span><span class="kw">:</span><span class="at"> warning</span></span>
+<span id="cb22-57"><a href="#cb22-57" aria-hidden="true" tabindex="-1"></a><span class="co">  # If the filepath below is not present, then pandoc-plot will log to stderr</span></span>
+<span id="cb22-58"><a href="#cb22-58" aria-hidden="true" tabindex="-1"></a><span class="co">  # Otherwise, log messages will be appended to the filepath.</span></span>
+<span id="cb22-59"><a href="#cb22-59" aria-hidden="true" tabindex="-1"></a><span class="co">  # filepath: path/to/file.txt</span></span>
+<span id="cb22-60"><a href="#cb22-60" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-61"><a href="#cb22-61" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Matplotlib toolkit</span></span>
+<span id="cb22-62"><a href="#cb22-62" aria-hidden="true" tabindex="-1"></a><span class="fu">matplotlib</span><span class="kw">:</span></span>
+<span id="cb22-63"><a href="#cb22-63" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: matplotlib.py</span></span>
+<span id="cb22-64"><a href="#cb22-64" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">tight_bbox</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
+<span id="cb22-65"><a href="#cb22-65" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">transparent</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
+<span id="cb22-66"><a href="#cb22-66" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>
+<span id="cb22-67"><a href="#cb22-67" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-68"><a href="#cb22-68" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-69"><a href="#cb22-69" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the MATLAB toolkit</span></span>
+<span id="cb22-70"><a href="#cb22-70" aria-hidden="true" tabindex="-1"></a><span class="fu">matlabplot</span><span class="kw">:</span></span>
+<span id="cb22-71"><a href="#cb22-71" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: matlab.m</span></span>
+<span id="cb22-72"><a href="#cb22-72" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> matlab</span></span>
+<span id="cb22-73"><a href="#cb22-73" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-74"><a href="#cb22-74" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-75"><a href="#cb22-75" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Plotly/Python toolkit</span></span>
+<span id="cb22-76"><a href="#cb22-76" aria-hidden="true" tabindex="-1"></a><span class="fu">plotly_python</span><span class="kw">:</span></span>
+<span id="cb22-77"><a href="#cb22-77" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plotly-python.py</span></span>
+<span id="cb22-78"><a href="#cb22-78" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>
+<span id="cb22-79"><a href="#cb22-79" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-80"><a href="#cb22-80" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-81"><a href="#cb22-81" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Plotly/R toolkit</span></span>
+<span id="cb22-82"><a href="#cb22-82" aria-hidden="true" tabindex="-1"></a><span class="fu">plotly_r</span><span class="kw">:</span></span>
+<span id="cb22-83"><a href="#cb22-83" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plotly-r.r</span></span>
+<span id="cb22-84"><a href="#cb22-84" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> Rscript</span></span>
+<span id="cb22-85"><a href="#cb22-85" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-86"><a href="#cb22-86" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-87"><a href="#cb22-87" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Mathematica toolkit</span></span>
+<span id="cb22-88"><a href="#cb22-88" aria-hidden="true" tabindex="-1"></a><span class="fu">mathplot</span><span class="kw">:</span></span>
+<span id="cb22-89"><a href="#cb22-89" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: mathematica.m</span></span>
+<span id="cb22-90"><a href="#cb22-90" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> math</span></span>
+<span id="cb22-91"><a href="#cb22-91" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-92"><a href="#cb22-92" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-93"><a href="#cb22-93" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the GNU Octave toolkit</span></span>
+<span id="cb22-94"><a href="#cb22-94" aria-hidden="true" tabindex="-1"></a><span class="fu">octaveplot</span><span class="kw">:</span></span>
+<span id="cb22-95"><a href="#cb22-95" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: octave.m</span></span>
+<span id="cb22-96"><a href="#cb22-96" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> octave</span></span>
+<span id="cb22-97"><a href="#cb22-97" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-98"><a href="#cb22-98" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-99"><a href="#cb22-99" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the ggplot2 toolkit</span></span>
+<span id="cb22-100"><a href="#cb22-100" aria-hidden="true" tabindex="-1"></a><span class="fu">ggplot2</span><span class="kw">:</span></span>
+<span id="cb22-101"><a href="#cb22-101" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: ggplot2.r</span></span>
+<span id="cb22-102"><a href="#cb22-102" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> Rscript</span></span>
+<span id="cb22-103"><a href="#cb22-103" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-104"><a href="#cb22-104" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-105"><a href="#cb22-105" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the gnuplot toolkit</span></span>
+<span id="cb22-106"><a href="#cb22-106" aria-hidden="true" tabindex="-1"></a><span class="fu">gnuplot</span><span class="kw">:</span></span>
+<span id="cb22-107"><a href="#cb22-107" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: gnuplot.gp</span></span>
+<span id="cb22-108"><a href="#cb22-108" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> gnuplot</span></span>
+<span id="cb22-109"><a href="#cb22-109" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-110"><a href="#cb22-110" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-111"><a href="#cb22-111" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the graphviz toolkit</span></span>
+<span id="cb22-112"><a href="#cb22-112" aria-hidden="true" tabindex="-1"></a><span class="fu">graphviz</span><span class="kw">:</span></span>
+<span id="cb22-113"><a href="#cb22-113" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: graphviz.dot</span></span>
+<span id="cb22-114"><a href="#cb22-114" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> dot</span></span>
+<span id="cb22-115"><a href="#cb22-115" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-116"><a href="#cb22-116" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-117"><a href="#cb22-117" aria-hidden="true" tabindex="-1"></a><span class="fu">bokeh</span><span class="kw">:</span></span>
+<span id="cb22-118"><a href="#cb22-118" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: bokeh.py</span></span>
+<span id="cb22-119"><a href="#cb22-119" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>
+<span id="cb22-120"><a href="#cb22-120" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-121"><a href="#cb22-121" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-122"><a href="#cb22-122" aria-hidden="true" tabindex="-1"></a><span class="fu">plotsjl</span><span class="kw">:</span></span>
+<span id="cb22-123"><a href="#cb22-123" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plotsjl.jl</span></span>
+<span id="cb22-124"><a href="#cb22-124" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> julia</span></span>
+<span id="cb22-125"><a href="#cb22-125" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span></span>
+<span id="cb22-126"><a href="#cb22-126" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb22-127"><a href="#cb22-127" aria-hidden="true" tabindex="-1"></a><span class="fu">plantuml</span><span class="kw">:</span></span>
+<span id="cb22-128"><a href="#cb22-128" aria-hidden="true" tabindex="-1"></a><span class="co">  # preamble: plantuml.txt</span></span>
+<span id="cb22-129"><a href="#cb22-129" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> java</span></span>
+<span id="cb22-130"><a href="#cb22-130" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span><span class="at"> -jar plantuml.jar</span></span>
+<span id="cb22-131"><a href="#cb22-131" aria-hidden="true" tabindex="-1"></a><span class="co">  # On Linux, if you have `plantuml.jar` as an executable, you can also</span></span>
+<span id="cb22-132"><a href="#cb22-132" aria-hidden="true" tabindex="-1"></a><span class="co">  # use the following configuration instead:</span></span>
+<span id="cb22-133"><a href="#cb22-133" aria-hidden="true" tabindex="-1"></a><span class="co">  # plantuml:</span></span>
+<span id="cb22-134"><a href="#cb22-134" aria-hidden="true" tabindex="-1"></a><span class="co">  #   executable: plantuml</span></span>
+<span id="cb22-135"><a href="#cb22-135" aria-hidden="true" tabindex="-1"></a><span class="co">  #   command_line_arguments:</span></span></code></pre></div>
+<p>A file like the above sets the <strong>default</strong> values; you can still override them in documents directly.</p>
+<p>The easiest way to specify configuration for <code>pandoc-plot</code> is to place a <code>.pandoc-plot.yml</code> file in the current working directory. You can also specify a configuration file in document metadata, under the <code>plot-configuration</code> key. For example, in Markdown:</p>
+<div class="sourceCode" id="cb23"><pre class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span>
+<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="an">title:</span><span class="co"> My document</span></span>
+<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="an">author:</span><span class="co"> John Doe</span></span>
+<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="an">plot-configuration:</span><span class="co"> /path/to/file.yml</span></span>
+<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span></code></pre></div>
+<p>or on the command line, using the pandoc <code>-M/--metadata</code> flag:</p>
+<div class="sourceCode" id="cb24"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc</span> <span class="at">--filter</span> pandoc-plot <span class="at">-M</span> plot-configuration=/path/to/file.yml ...</span></code></pre></div>
+<p>The hierarchy of configuration files is as follows:</p>
+<ol type="1">
+<li>A configuration file specified in the metadata under the <code>plot-configuration</code> key;</li>
+<li>Otherwise, a file in the current working directory named <code>.pandoc-plot.yml</code>;</li>
+<li>Finally, the default configuration is used.</li>
+</ol>
+<h4 id="executables">Executables</h4>
+<p>The <code>executable</code> parameter for all toolkits can be either the executable name (if it is present on the PATH), or the full path to the executable.</p>
+<p>Examples:</p>
+<div class="sourceCode" id="cb25"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="fu">matplotlib</span><span class="kw">:</span></span>
+<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python3</span></span></code></pre></div>
+<div class="sourceCode" id="cb26"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="fu">matlabplot</span><span class="kw">:</span></span>
+<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> </span><span class="st">&quot;C:\Program Files\Matlab\R2019b</span><span class="sc">\b</span><span class="st">in\matlab.exe&quot;</span></span></code></pre></div>
+<h4 id="command-line-arguments">Command-line arguments</h4>
+<p><em>New in version 1.0.2.0</em></p>
+<p>The <code>command_line_arguments</code> parameter available for all toolkits provides a way to customize the way interpreters are run. For example, if you want to run the <code>matplotlib</code> toolkit with all warnings shown:</p>
+<div class="sourceCode" id="cb27"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Matplotlib toolkit</span></span>
+<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="fu">matplotlib</span><span class="kw">:</span></span>
+<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> python</span></span>
+<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span><span class="at"> -Wa</span></span></code></pre></div>
+<p>Or if you want <code>julia</code> to use more than one thread:</p>
+<div class="sourceCode" id="cb28"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co"># The possible parameters for the Matplotlib toolkit</span></span>
+<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="fu">plotsjl</span><span class="kw">:</span></span>
+<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">executable</span><span class="kw">:</span><span class="at"> julia</span></span>
+<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">command_line_arguments</span><span class="kw">:</span><span class="at"> --threads auto</span></span></code></pre></div>
+<h4 id="toolkit-specific-options">Toolkit-specific options</h4>
+<h5 id="matplotlib">Matplotlib</h5>
+<ul>
+<li><code>tight_bbox</code> is a boolean that determines whether to use <code>bbox_inches=&quot;tight&quot;</code> or not when saving Matplotlib figures. For example, <code>tight_bbox: true</code>. See <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.savefig.html">here</a> for details.</li>
+<li><code>transparent</code> is a boolean that determines whether to make Matplotlib figure background transparent or not. This is useful, for example, for displaying a plot on top of a colored background on a web page. High-resolution figures are not affected. For example, <code>transparent: true</code>.</li>
+</ul>
+<h4 id="logging">Logging</h4>
+<p>If you are running <code>pandoc-plot</code> on a large document, you might want to turn on logging. You can do so via the configuration file as follows:</p>
+<div class="sourceCode" id="cb29"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="fu">logging</span><span class="kw">:</span></span>
+<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="co">    # Possible verbosity values: debug, error, warning, info, silent</span></span>
+<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="co">    # debug level shows all messages</span></span>
+<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="co">    # error level shows all but debug messages, etc.</span></span>
+<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">verbosity</span><span class="kw">:</span><span class="at"> info</span></span>
+<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a><span class="at">    </span></span>
+<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a><span class="co">    # OPTIONAL: log to file</span></span>
+<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a><span class="co">    # Remove line below to log to stderr</span></span>
+<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">filepath</span><span class="kw">:</span><span class="at"> log.txt</span></span></code></pre></div>
+<p>By default, <code>pandoc-plot</code> logs warnings and errors to the standard error stream only.</p>
+<h4 id="strict-mode">Strict mode</h4>
+<p><em>New in version 1.0.2.0</em></p>
+<p>By default, <code>pandoc-plot</code> leaves code blocks unchanged if a figure fails to be rendered. This might be the case if a plotting toolkit is not installed, or if running the code to render a figure returns an error. In <strong>strict mode</strong>, <code>pandoc-plot</code> will immediately halt if it encounters a problem. You can activate strict mode via configuration:</p>
+<div class="sourceCode" id="cb30"><pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="fu">strict</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span></code></pre></div>
+<p>Strict mode is ideal if you want to ensure that the figures are correctly rendered in the document.</p>
+<h3 id="other-commands">Other commands</h3>
+<h4 id="finding-installed-toolkits">Finding installed toolkits</h4>
+<p>You can determine which toolkits are available on your current machine using the <code>pandoc-plot toolkits</code> command. Here is the full help text:</p>
+<div class="sourceCode" id="cb31"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE toolkits [--config PATH]</span>
+<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">Show</span> information on toolkits and exit.</span>
+<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>
+<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--config</span> PATH            Path to optional configuration file.</span>
+<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span></code></pre></div>
+<h4 id="cleaning-output">Cleaning output</h4>
+<p>Figures produced by <code>pandoc-plot</code> can be placed in a few different locations. You can set a default location in the <a href="#configuration">Configuration</a>, but you can also re-direct specific figures in other directories if you use the <code>directory=...</code> argument in code blocks. These figures will build up over time. You can use the <code>clean</code> command to scan documents and delete the associated <code>pandoc-plot</code> output files. For example, to delete the figures generated from the <code>input.md</code> file:</p>
+<div class="sourceCode" id="cb32"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc-plot</span> clean input.md</span></code></pre></div>
+<p>This sill remove all directories where a figure <em>could</em> have been placed. <strong>WARNING</strong>: all files will be removed.</p>
+<p>Here is the full help text for the <code>clean</code> command:</p>
+<div class="sourceCode" id="cb33"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE clean [--config PATH] FILE</span>
+<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">Clean</span> output directories where figures from FILE and log files might be</span>
+<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">stored.</span> WARNING: All files in those directories will be deleted.</span>
+<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>
+<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--config</span> PATH            Path to optional configuration file.</span>
+<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span></code></pre></div>
+<h4 id="configuration-template">Configuration template</h4>
+<p>Because <code>pandoc-plot</code> supports a few toolkits, there are a lot of configuration options. Don’t start from scratch! The <code>write-example-config</code> command will create a file for you, which you can then modify:</p>
+<div class="sourceCode" id="cb34"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pandoc-plot</span> write-example-config</span></code></pre></div>
+<p>You will need to re-name the file to <code>.pandoc-ploy.yml</code> to be able to use it, so don’t worry about overwriting your own configuration.</p>
+<p>Here is the full help text for the <code>write-example-config</code> command:</p>
+<div class="sourceCode" id="cb35"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Usage:</span> pandoc-plot.EXE write-example-config [--path FILE]</span>
+<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">Write</span> example configuration to a file and exit.</span>
+<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a><span class="ex">Available</span> options:</span>
+<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">--path</span> FILE              Target location of the configuration file. Default is</span>
+<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a>                           <span class="st">&quot;.example-pandoc-plot.yml&quot;</span></span>
+<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">-h,--help</span>                Show this help text</span></code></pre></div>
+<h3 id="as-a-haskell-library">As a Haskell library</h3>
+<p>To include the functionality of <code>pandoc-plot</code> in a Haskell package, you can use the <code>make</code> function (for single blocks) or <code>plotFilter</code> function (for entire documents). <a href="https://hackage.haskell.org/package/pandoc-plot">Take a look at the documentation on Hackage</a>.</p>
+<h4 id="usage-with-hakyll">Usage with Hakyll</h4>
+<p>In case you want to use the filter with your own Hakyll setup, you can use a transform function that works on entire documents:</p>
+<div class="sourceCode" id="cb36"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Text.Pandoc.Filter.Plot</span> (plotFilter, defaultConfiguration)</span>
+<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Text.Pandoc.Definition</span> (<span class="dt">Pandoc</span>, <span class="dt">Format</span>(..)) <span class="co">-- from pandoc-types</span></span>
+<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Hakyll</span></span>
+<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a><span class="ot">plotFilter&#39; ::</span> <span class="dt">Pandoc</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Pandoc</span></span>
+<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a>plotFilter&#39; <span class="ot">=</span> </span>
+<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Notify pandoc-plot that the final conversion will be to HTML</span></span>
+<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- This helps give better error messages and adjust default values</span></span>
+<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a>  plotFilter defaultConfiguration (<span class="dt">Just</span> <span class="op">$</span> <span class="dt">Format</span> <span class="st">&quot;html5&quot;</span>) </span>
+<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a></span>
+<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- Unsafe compiler is required because of the interaction</span></span>
+<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- in IO (i.e. running an external script).</span></span>
+<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a><span class="ot">makePlotPandocCompiler ::</span> <span class="dt">Compiler</span> (<span class="dt">Item</span> <span class="dt">String</span>)</span>
+<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a>makePlotPandocCompiler <span class="ot">=</span> </span>
+<span id="cb36-15"><a href="#cb36-15" aria-hidden="true" tabindex="-1"></a>  pandocCompilerWithTransformM</span>
+<span id="cb36-16"><a href="#cb36-16" aria-hidden="true" tabindex="-1"></a>    defaultHakyllReaderOptions</span>
+<span id="cb36-17"><a href="#cb36-17" aria-hidden="true" tabindex="-1"></a>    defaultHakyllWriterOptions</span>
+<span id="cb36-18"><a href="#cb36-18" aria-hidden="true" tabindex="-1"></a>    (unsafeCompiler <span class="op">.</span> plotFilter&#39;)</span></code></pre></div>
+<h2 id="warning">Warning</h2>
+<p>Do not run this filter on unknown documents. There is nothing in <code>pandoc-plot</code> that can stop a script from performing <strong>evil actions</strong>.</p>
+</body>
+</html>
example-config.yml view
@@ -1,148 +1,148 @@--# This is an example configuration. Everything in this file is optional.-# Please refer to the documentation to know about the parameters herein.-#-# The `executable` parameter for all toolkits can be either the-# executable name (if it is present on the PATH), or-# the full path to the executable.-# E.g.:-#  executable: python3-#  executable: "C:\Python37\Scripts\python.exe"--# The following parameters affect all toolkits-# Directory where to save the plots. The path can be relative to pandoc-plot's-# current working directory, or absolute.-directory: plots/--# Whether or not to include a link to the source script in the caption. -# Particularly useful for HTML output.-source: false--# When `strict: false`, pandoc-plot will leave code blocks untouched if a plot-# could not be generated. This could happen if, for example, a toolkit is not-# installed. If you want pandoc-plot to fail instead, use `strict: true`.-strict: false--# Text label for links to source code.-# You can change this label if you are writing a document in a non-English language. -# This only matters if `source` is set to `true`.-source_label: Source code--# Default density of figures in dots per inches (DPI). -# This can be changed in the document specifically as well.-dpi: 80--# Default format in which to save the figures. This can be specified -# individually as well.-format: PNG--# Default files/directories on which all figures depend. If any of these files/directories-# changes, all figures will be re-rendered.-# Dependencies specified in code blocks will be appended to this list.-dependencies:-  - file1.txt-  - file2.txt--# Text format for the captions. Unfortunately, there is no way to detect-# this automatically. You can use the same notation as Pandoc's --from -# parameter, specified here: -#     https://pandoc.org/MANUAL.html#option--from-# Example: markdown, rst+raw_tex-caption_format: markdown+tex_math_dollars---# Logging configuration-logging:-  # Possible verbosity values: debug, error, warning, info, silent-  verbosity: warning-  # If the filepath below is not present, then pandoc-plot will log to stderr-  # Otherwise, log messages will be appended to the filepath.-  # filepath: path/to/file.txt--# The possible parameters for the Matplotlib toolkit-matplotlib:-  # preamble: matplotlib.py-  tight_bbox: false-  transparent: false-  executable: python-  command_line_arguments:--# The possible parameters for the MATLAB toolkit-matlabplot:-  # preamble: matlab.m-  executable: matlab-  command_line_arguments:--# The possible parameters for the Plotly/Python toolkit-plotly_python:-  # preamble: plotly-python.py-  executable: python-  command_line_arguments:--# The possible parameters for the Plotly/R toolkit-plotly_r:-  # preamble: plotly-r.r-  executable: Rscript-  command_line_arguments:--# The possible parameters for the Mathematica toolkit-mathplot:-  # preamble: mathematica.m-  executable: math-  command_line_arguments:--# The possible parameters for the GNU Octave toolkit-octaveplot:-  # preamble: octave.m-  executable: octave-  command_line_arguments:--# The possible parameters for the ggplot2 toolkit-ggplot2:-  # preamble: ggplot2.r-  executable: Rscript-  command_line_arguments:--# The possible parameters for the gnuplot toolkit-gnuplot:-  # preamble: gnuplot.gp-  executable: gnuplot-  command_line_arguments:--# The possible parameters for the graphviz toolkit-graphviz:-  # preamble: graphviz.dot-  executable: dot-  command_line_arguments:--# The possible parameters for the Bokeh toolkit using Python-bokeh:-  # preamble: bokeh.py-  executable: python-  command_line_arguments:--# The possible parameters for the Plots.jl toolkit using Julia-plotsjl:-  # preamble: plotsjl.jl-  executable: julia-  command_line_arguments:--# The possible parameters for the PlantUML toolkit-plantuml:-  # preamble: plantuml.txt-  executable: java-  command_line_arguments: -jar plantuml.jar-  # On Linux, if you have `plantuml.jar` as an executable, you can also-  # use the following configuration instead:-  # plantuml:-  #   executable: plantuml-  #   command_line_arguments:--sageplot:-  # preamble: sageplot.sage-  executable: sage-  command_line_arguments:--d2:-  executable: d2-  command_line_arguments:+
+# This is an example configuration. Everything in this file is optional.
+# Please refer to the documentation to know about the parameters herein.
+#
+# The `executable` parameter for all toolkits can be either the
+# executable name (if it is present on the PATH), or
+# the full path to the executable.
+# E.g.:
+#  executable: python3
+#  executable: "C:\Python37\Scripts\python.exe"
+
+# The following parameters affect all toolkits
+# Directory where to save the plots. The path can be relative to pandoc-plot's
+# current working directory, or absolute.
+directory: plots/
+
+# Whether or not to include a link to the source script in the caption. 
+# Particularly useful for HTML output.
+source: false
+
+# When `strict: false`, pandoc-plot will leave code blocks untouched if a plot
+# could not be generated. This could happen if, for example, a toolkit is not
+# installed. If you want pandoc-plot to fail instead, use `strict: true`.
+strict: false
+
+# Text label for links to source code.
+# You can change this label if you are writing a document in a non-English language. 
+# This only matters if `source` is set to `true`.
+source_label: Source code
+
+# Default density of figures in dots per inches (DPI). 
+# This can be changed in the document specifically as well.
+dpi: 80
+
+# Default format in which to save the figures. This can be specified 
+# individually as well.
+format: PNG
+
+# Default files/directories on which all figures depend. If any of these files/directories
+# changes, all figures will be re-rendered.
+# Dependencies specified in code blocks will be appended to this list.
+dependencies:
+  - file1.txt
+  - file2.txt
+
+# Text format for the captions. Unfortunately, there is no way to detect
+# this automatically. You can use the same notation as Pandoc's --from 
+# parameter, specified here: 
+#     https://pandoc.org/MANUAL.html#option--from
+# Example: markdown, rst+raw_tex
+caption_format: markdown+tex_math_dollars
+
+
+# Logging configuration
+logging:
+  # Possible verbosity values: debug, error, warning, info, silent
+  verbosity: warning
+  # If the filepath below is not present, then pandoc-plot will log to stderr
+  # Otherwise, log messages will be appended to the filepath.
+  # filepath: path/to/file.txt
+
+# The possible parameters for the Matplotlib toolkit
+matplotlib:
+  # preamble: matplotlib.py
+  tight_bbox: false
+  transparent: false
+  executable: python
+  command_line_arguments:
+
+# The possible parameters for the MATLAB toolkit
+matlabplot:
+  # preamble: matlab.m
+  executable: matlab
+  command_line_arguments:
+
+# The possible parameters for the Plotly/Python toolkit
+plotly_python:
+  # preamble: plotly-python.py
+  executable: python
+  command_line_arguments:
+
+# The possible parameters for the Plotly/R toolkit
+plotly_r:
+  # preamble: plotly-r.r
+  executable: Rscript
+  command_line_arguments:
+
+# The possible parameters for the Mathematica toolkit
+mathplot:
+  # preamble: mathematica.m
+  executable: math
+  command_line_arguments:
+
+# The possible parameters for the GNU Octave toolkit
+octaveplot:
+  # preamble: octave.m
+  executable: octave
+  command_line_arguments:
+
+# The possible parameters for the ggplot2 toolkit
+ggplot2:
+  # preamble: ggplot2.r
+  executable: Rscript
+  command_line_arguments:
+
+# The possible parameters for the gnuplot toolkit
+gnuplot:
+  # preamble: gnuplot.gp
+  executable: gnuplot
+  command_line_arguments:
+
+# The possible parameters for the graphviz toolkit
+graphviz:
+  # preamble: graphviz.dot
+  executable: dot
+  command_line_arguments:
+
+# The possible parameters for the Bokeh toolkit using Python
+bokeh:
+  # preamble: bokeh.py
+  executable: python
+  command_line_arguments:
+
+# The possible parameters for the Plots.jl toolkit using Julia
+plotsjl:
+  # preamble: plotsjl.jl
+  executable: julia
+  command_line_arguments:
+
+# The possible parameters for the PlantUML toolkit
+plantuml:
+  # preamble: plantuml.txt
+  executable: java
+  command_line_arguments: -jar plantuml.jar
+  # On Linux, if you have `plantuml.jar` as an executable, you can also
+  # use the following configuration instead:
+  # plantuml:
+  #   executable: plantuml
+  #   command_line_arguments:
+
+sageplot:
+  # preamble: sageplot.sage
+  executable: sage
+  command_line_arguments:
+
+d2:
+  executable: d2
+  command_line_arguments:
executable/ExampleConfig.hs view
@@ -1,30 +1,30 @@-{-# LANGUAGE TemplateHaskellQuotes #-}--module ExampleConfig (embedExampleConfig) where--import Data.Functor ((<&>))-import Data.String (IsString (fromString))-import Data.Text (unpack)-import qualified Data.Text.IO as TIO-import Language.Haskell.TH.Syntax-  ( Exp (AppE, LitE, VarE),-    Lit (StringL),-    Q,-    Quasi (qAddDependentFile),-    runIO,-  )--docFile :: FilePath-docFile = "example-config.yml"--readDocFile :: IO String-readDocFile = TIO.readFile docFile <&> unpack--embedExampleConfig :: Q Exp-embedExampleConfig = do-  qAddDependentFile docFile-  s <- runIO readDocFile-  strToExp s-  where-    strToExp :: String -> Q Exp-    strToExp s = return $ VarE 'fromString `AppE` LitE (StringL s)+{-# LANGUAGE TemplateHaskellQuotes #-}
+
+module ExampleConfig (embedExampleConfig) where
+
+import Data.Functor ((<&>))
+import Data.String (IsString (fromString))
+import Data.Text (unpack)
+import qualified Data.Text.IO as TIO
+import Language.Haskell.TH.Syntax
+  ( Exp (AppE, LitE, VarE),
+    Lit (StringL),
+    Q,
+    Quasi (qAddDependentFile),
+    runIO,
+  )
+
+docFile :: FilePath
+docFile = "example-config.yml"
+
+readDocFile :: IO String
+readDocFile = TIO.readFile docFile <&> unpack
+
+embedExampleConfig :: Q Exp
+embedExampleConfig = do
+  qAddDependentFile docFile
+  s <- runIO readDocFile
+  strToExp s
+  where
+    strToExp :: String -> Q Exp
+    strToExp s = return $ VarE 'fromString `AppE` LitE (StringL s)
executable/Main.hs view
@@ -1,326 +1,326 @@-{-# LANGUAGE ApplicativeDo #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TemplateHaskell #-}--module Main where--import Control.Monad (join, msum, void, when)-import Data.List (intersperse, (\\))-import Data.Text (unpack)-import qualified Data.Text.IO as TIO-import Data.Version (parseVersion, showVersion)-import qualified Data.Version as V-import Development.GitRev (gitHash)-import ExampleConfig (embedExampleConfig)-import GHC.IO.Encoding (setLocaleEncoding, utf8)-import ManPage (embedManualHtml)-import OpenFile (openFile)-import Options.Applicative-  ( Alternative ((<|>)),-    Parser,-    command,-    execParser,-    flag,-    footerDoc,-    fullDesc,-    header,-    help,-    helper,-    info,-    long,-    metavar,-    optional,-    progDesc,-    short,-    strArgument,-    strOption,-    subparser,-    value,-    (<**>),-  )-import qualified Options.Applicative.Help.Pretty as P-import System.Directory (doesFileExist, getTemporaryDirectory)-import System.Environment (lookupEnv)-import System.FilePath ((</>))-import System.IO (hPutStrLn, stderr)-import Text.Pandoc (pandocVersion)-import Text.Pandoc.Definition (pandocTypesVersion)-import Text.Pandoc.Filter.Plot-  ( Configuration (..),-    availableToolkits,-    configuration,-    defaultConfiguration,-    pandocPlotVersion,-    plotFilter,-  )-import Text.Pandoc.Filter.Plot.Internal-  ( cleanOutputDirs,-    cls,-    configurationPathMeta,-    executable,-    pathToExe,-    readDoc,-    runPlotM,-    supportedSaveFormats,-    toolkits,-  )-import Text.Pandoc.JSON (toJSONFilter)-import Text.ParserCombinators.ReadP (readP_to_S)---- The difference between commands and flags is that commands require knowledge of--- the configuration, while flags only display static information.---- Please note that for some reason, makeVersion [2, 11, 0, 0] > makeVersion [2, 11]-minimumPandocVersion :: V.Version-minimumPandocVersion = V.makeVersion [2, 11]--data Command-  = Clean (Maybe FilePath) FilePath-  | WriteConfig FilePath-  | Toolkits (Maybe FilePath)--data Flag-  = Version-  | FullVersion-  | Manual-  deriving (Eq)--main :: IO ()-main = do-  setLocaleEncoding utf8-  join $ execParser opts-  where-    opts =-      info-        (optparse <**> helper)-        ( fullDesc-            <> progDesc-              ( unlines-                  [ "This pandoc filter generates plots from code blocks using a multitude of ",-                    "possible renderers. This allows to keep documentation and figures in",-                    "perfect synchronicity."-                  ]-              )-            <> header (mconcat ["pandoc-plot ", V.showVersion pandocPlotVersion, " - generate figures directly in documents"])-            <> footerDoc-              ( Just $-                  P.vsep-                    [ "More information can be found via the manual (pandoc-plot --manual) or the",-                      "repository README, located at https://github.com/LaurentRDC/pandoc-plot"-                    ]-              )-        )--    optparse = do-      flag_ <- flagParser-      command_ <- commandParser-      -- The extra optional input below only serves to show-      -- to the user that the last argument is the AST from pandoc-      -- The parsed input is never used-      input <- optional $ strArgument (metavar "AST")-      return $ go flag_ command_ input--    go :: Maybe Flag -> Maybe Command -> Maybe String -> IO ()-    go (Just Version) _ _ = putStrLn (V.showVersion pandocPlotVersion)-    go (Just FullVersion) _ _ = showFullVersion-    go (Just Manual) _ _ = showManPage-    go _ (Just (Toolkits mfp)) _ = showAvailableToolkits mfp-    go _ (Just (Clean mfp fp)) _ = clean mfp fp-    go _ (Just (WriteConfig fp)) _ = writeFile fp $(embedExampleConfig)-    go Nothing Nothing _ = toJSONFilterWithConfig--flagParser :: Parser (Maybe Flag)-flagParser = versionP <|> fullVersionP <|> manualP-  where-    versionP =-      flag-        Nothing-        (Just Version)-        ( mconcat-            [ long "version",-              short 'v',-              help "Show version number and exit."-            ]-        )--    fullVersionP =-      flag-        Nothing-        (Just FullVersion)-        ( mconcat-            [ long "full-version",-              help "Show full version information and exit."-            ]-        )--    manualP =-      flag-        Nothing-        (Just Manual)-        ( mconcat-            [ long "manual",-              short 'm',-              help "Open the manual page in the default web browser and exit."-            ]-        )--commandParser :: Parser (Maybe Command)-commandParser =-  optional $-    subparser $-      mconcat-        [ command-            "toolkits"-            ( info (toolkitsP <**> helper) (progDesc "Show information on toolkits and exit.")-            ),-          command-            "clean"-            ( info-                (cleanP <**> helper)-                ( progDesc-                    ( unlines-                        [ "Clean output directories where figures from FILE and log files might be stored.",-                          "WARNING: All files in those directories will be deleted."-                        ]-                    )-                )-            ),-          command-            "write-example-config"-            ( info (writeConfigP <**> helper) (progDesc "Write example configuration to a file and exit.")-            )-        ]-  where-    configP = optional $ strOption (mconcat [long "config", metavar "PATH", help "Path to optional configuration file."])-    toolkitsP = Toolkits <$> configP-    cleanP = Clean <$> configP <*> strArgument (metavar "FILE")-    writeConfigP =-      WriteConfig-        <$> strOption-          ( mconcat-              [ long "path",-                metavar "FILE",-                value ".example-pandoc-plot.yml",-                help "Target location of the configuration file. Default is \".example-pandoc-plot.yml\""-              ]-          )---- | Determine configuration and run filter.------ Priority for configuration:------     (1) Loaded from filepath stored in document metadata, under the key @plot-configuration@;------     (2) Loaded from file @.pandoc-plot.yml@ in current work directory;------     (3) Default configuration-toJSONFilterWithConfig :: IO ()-toJSONFilterWithConfig = do-  upToDatePandoc <- checkRuntimePandocVersion-  when upToDatePandoc $-    toJSONFilter $ \mfmt doc -> do-      c <- maybe localConfig configuration (configurationPathMeta doc)-      plotFilter c mfmt doc---- | Check that the runtime version of Pandoc is at least 2.11. The return value--- indicates whether the Pandoc version is new enough or not.-checkRuntimePandocVersion :: IO Bool-checkRuntimePandocVersion = do-  -- Pandoc runs filters in an environment with two variables:-  -- PANDOV_VERSION and PANDOC_READER_OPTS-  -- We can use the former to ensure that people are not-  -- using an old version of pandoc-  pandocV <- lookupEnv "PANDOC_VERSION"-  case pandocV >>= readVersion of-    Nothing -> return True-    Just v ->-      if v < minimumPandocVersion-        then do-          hPutStrLn stderr $-            mconcat-              [ "ERROR (pandoc-plot) The pandoc-plot filter only ",-                "supports Pandoc 2.11 and newer. ",-                "but you are using Pandoc ",-                showVersion v-              ]-          return False-        else return True-  where-    readVersion = fmap fst . lastMaybe . readP_to_S parseVersion-    lastMaybe xs = if length xs > 1 then Just (last xs) else Nothing---- | Load configuration from local file @.pandoc-plot.yml@.--- If the file does not exist, the default configuration will be used.-localConfig :: IO Configuration-localConfig = do-  configExists <- doesFileExist ".pandoc-plot.yml"-  if configExists-    then configuration ".pandoc-plot.yml"-    else return defaultConfiguration--showFullVersion :: IO ()-showFullVersion = do-  putStrLn $ "pandoc-plot " <> V.showVersion pandocPlotVersion-  putStrLn $ "Git revision " <> $gitHash-  putStrLn $-    mconcat-      [ "Compiled with pandoc ",-        V.showVersion pandocVersion,-        " and pandoc-types ",-        V.showVersion pandocTypesVersion,-        " using GHC ",-        TOOL_VERSION_ghc -- Constant defined by CPP-      ]--showAvailableToolkits :: Maybe FilePath -> IO ()-showAvailableToolkits mfp = do-  c <- maybe localConfig configuration mfp--  putStrLn "\nAVAILABLE TOOLKITS\n"-  available <- availableToolkits c-  mapM_ (availToolkitInfo c) available-  putStrLn "\nUNAVAILABLE TOOLKITS\n"-  -- We don't use unavailableToolkits because this would force-  -- more IO actions-  let unavailable = toolkits \\ available-  mapM_ (unavailToolkitInfo c) unavailable-  where-    toolkitInfo avail conf tk = do-      putStrLn $ "Toolkit: " <> show tk-      when avail $ do-        exe <- runPlotM Nothing conf $ executable tk-        putStrLn $ "    Executable: " <> pathToExe exe-      putStrLn $ "    Code block trigger: " <> (unpack . cls $ tk)-      putStrLn $ "    Supported save formats: " <> (mconcat . intersperse ", " . fmap show $ supportedSaveFormats tk)-      putStrLn mempty-    availToolkitInfo = toolkitInfo True-    unavailToolkitInfo = toolkitInfo False---- | Clean output directories associated with a file------ Priority for configuration are the same as @toJSONFilterWithConfig@.-clean ::-  Maybe FilePath -> -- Use configuration file?-  FilePath -> -- Document to clean-  IO ()-clean mfp fp = do-  doc <- readDoc fp-  -- Note the priority for configuration:-  --   (1) path of argument --config-  --   (2) document metadata-  --   (3) local .pandoc-plot.yml-  --   (4) default config-  conf <- maybe localConfig configuration $ firstJusts [configurationPathMeta doc, mfp]-  void (cleanOutputDirs conf doc)-  where-    firstJusts :: [Maybe a] -> Maybe a-    firstJusts = msum--showManPage :: IO ()-showManPage = do-  manualPath <- (</> "pandoc-plot-manual.html") <$> getTemporaryDirectory-  TIO.writeFile manualPath $(embedManualHtml)-  openFile ("file:///" <> manualPath)+{-# LANGUAGE ApplicativeDo #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Main where
+
+import Control.Monad (join, msum, void, when)
+import Data.List (intersperse, (\\))
+import Data.Text (unpack)
+import qualified Data.Text.IO as TIO
+import Data.Version (parseVersion, showVersion)
+import qualified Data.Version as V
+import Development.GitRev (gitHash)
+import ExampleConfig (embedExampleConfig)
+import GHC.IO.Encoding (setLocaleEncoding, utf8)
+import ManPage (embedManualHtml)
+import OpenFile (openFile)
+import Options.Applicative
+  ( Alternative ((<|>)),
+    Parser,
+    command,
+    execParser,
+    flag,
+    footerDoc,
+    fullDesc,
+    header,
+    help,
+    helper,
+    info,
+    long,
+    metavar,
+    optional,
+    progDesc,
+    short,
+    strArgument,
+    strOption,
+    subparser,
+    value,
+    (<**>),
+  )
+import qualified Options.Applicative.Help.Pretty as P
+import System.Directory (doesFileExist, getTemporaryDirectory)
+import System.Environment (lookupEnv)
+import System.FilePath ((</>))
+import System.IO (hPutStrLn, stderr)
+import Text.Pandoc (pandocVersion)
+import Text.Pandoc.Definition (pandocTypesVersion)
+import Text.Pandoc.Filter.Plot
+  ( Configuration (..),
+    availableToolkits,
+    configuration,
+    defaultConfiguration,
+    pandocPlotVersion,
+    plotFilter,
+  )
+import Text.Pandoc.Filter.Plot.Internal
+  ( cleanOutputDirs,
+    cls,
+    configurationPathMeta,
+    executable,
+    pathToExe,
+    readDoc,
+    runPlotM,
+    supportedSaveFormats,
+    toolkits,
+  )
+import Text.Pandoc.JSON (toJSONFilter)
+import Text.ParserCombinators.ReadP (readP_to_S)
+
+-- The difference between commands and flags is that commands require knowledge of
+-- the configuration, while flags only display static information.
+
+-- Please note that for some reason, makeVersion [2, 11, 0, 0] > makeVersion [2, 11]
+minimumPandocVersion :: V.Version
+minimumPandocVersion = V.makeVersion [2, 11]
+
+data Command
+  = Clean (Maybe FilePath) FilePath
+  | WriteConfig FilePath
+  | Toolkits (Maybe FilePath)
+
+data Flag
+  = Version
+  | FullVersion
+  | Manual
+  deriving (Eq)
+
+main :: IO ()
+main = do
+  setLocaleEncoding utf8
+  join $ execParser opts
+  where
+    opts =
+      info
+        (optparse <**> helper)
+        ( fullDesc
+            <> progDesc
+              ( unlines
+                  [ "This pandoc filter generates plots from code blocks using a multitude of ",
+                    "possible renderers. This allows to keep documentation and figures in",
+                    "perfect synchronicity."
+                  ]
+              )
+            <> header (mconcat ["pandoc-plot ", V.showVersion pandocPlotVersion, " - generate figures directly in documents"])
+            <> footerDoc
+              ( Just $
+                  P.vsep
+                    [ "More information can be found via the manual (pandoc-plot --manual) or the",
+                      "repository README, located at https://github.com/LaurentRDC/pandoc-plot"
+                    ]
+              )
+        )
+
+    optparse = do
+      flag_ <- flagParser
+      command_ <- commandParser
+      -- The extra optional input below only serves to show
+      -- to the user that the last argument is the AST from pandoc
+      -- The parsed input is never used
+      input <- optional $ strArgument (metavar "AST")
+      return $ go flag_ command_ input
+
+    go :: Maybe Flag -> Maybe Command -> Maybe String -> IO ()
+    go (Just Version) _ _ = putStrLn (V.showVersion pandocPlotVersion)
+    go (Just FullVersion) _ _ = showFullVersion
+    go (Just Manual) _ _ = showManPage
+    go _ (Just (Toolkits mfp)) _ = showAvailableToolkits mfp
+    go _ (Just (Clean mfp fp)) _ = clean mfp fp
+    go _ (Just (WriteConfig fp)) _ = writeFile fp $(embedExampleConfig)
+    go Nothing Nothing _ = toJSONFilterWithConfig
+
+flagParser :: Parser (Maybe Flag)
+flagParser = versionP <|> fullVersionP <|> manualP
+  where
+    versionP =
+      flag
+        Nothing
+        (Just Version)
+        ( mconcat
+            [ long "version",
+              short 'v',
+              help "Show version number and exit."
+            ]
+        )
+
+    fullVersionP =
+      flag
+        Nothing
+        (Just FullVersion)
+        ( mconcat
+            [ long "full-version",
+              help "Show full version information and exit."
+            ]
+        )
+
+    manualP =
+      flag
+        Nothing
+        (Just Manual)
+        ( mconcat
+            [ long "manual",
+              short 'm',
+              help "Open the manual page in the default web browser and exit."
+            ]
+        )
+
+commandParser :: Parser (Maybe Command)
+commandParser =
+  optional $
+    subparser $
+      mconcat
+        [ command
+            "toolkits"
+            ( info (toolkitsP <**> helper) (progDesc "Show information on toolkits and exit.")
+            ),
+          command
+            "clean"
+            ( info
+                (cleanP <**> helper)
+                ( progDesc
+                    ( unlines
+                        [ "Clean output directories where figures from FILE and log files might be stored.",
+                          "WARNING: All files in those directories will be deleted."
+                        ]
+                    )
+                )
+            ),
+          command
+            "write-example-config"
+            ( info (writeConfigP <**> helper) (progDesc "Write example configuration to a file and exit.")
+            )
+        ]
+  where
+    configP = optional $ strOption (mconcat [long "config", metavar "PATH", help "Path to optional configuration file."])
+    toolkitsP = Toolkits <$> configP
+    cleanP = Clean <$> configP <*> strArgument (metavar "FILE")
+    writeConfigP =
+      WriteConfig
+        <$> strOption
+          ( mconcat
+              [ long "path",
+                metavar "FILE",
+                value ".example-pandoc-plot.yml",
+                help "Target location of the configuration file. Default is \".example-pandoc-plot.yml\""
+              ]
+          )
+
+-- | Determine configuration and run filter.
+--
+-- Priority for configuration:
+--
+--     (1) Loaded from filepath stored in document metadata, under the key @plot-configuration@;
+--
+--     (2) Loaded from file @.pandoc-plot.yml@ in current work directory;
+--
+--     (3) Default configuration
+toJSONFilterWithConfig :: IO ()
+toJSONFilterWithConfig = do
+  upToDatePandoc <- checkRuntimePandocVersion
+  when upToDatePandoc $
+    toJSONFilter $ \mfmt doc -> do
+      c <- maybe localConfig configuration (configurationPathMeta doc)
+      plotFilter c mfmt doc
+
+-- | Check that the runtime version of Pandoc is at least 2.11. The return value
+-- indicates whether the Pandoc version is new enough or not.
+checkRuntimePandocVersion :: IO Bool
+checkRuntimePandocVersion = do
+  -- Pandoc runs filters in an environment with two variables:
+  -- PANDOV_VERSION and PANDOC_READER_OPTS
+  -- We can use the former to ensure that people are not
+  -- using an old version of pandoc
+  pandocV <- lookupEnv "PANDOC_VERSION"
+  case pandocV >>= readVersion of
+    Nothing -> return True
+    Just v ->
+      if v < minimumPandocVersion
+        then do
+          hPutStrLn stderr $
+            mconcat
+              [ "ERROR (pandoc-plot) The pandoc-plot filter only ",
+                "supports Pandoc 2.11 and newer. ",
+                "but you are using Pandoc ",
+                showVersion v
+              ]
+          return False
+        else return True
+  where
+    readVersion = fmap fst . lastMaybe . readP_to_S parseVersion
+    lastMaybe xs = if length xs > 1 then Just (last xs) else Nothing
+
+-- | Load configuration from local file @.pandoc-plot.yml@.
+-- If the file does not exist, the default configuration will be used.
+localConfig :: IO Configuration
+localConfig = do
+  configExists <- doesFileExist ".pandoc-plot.yml"
+  if configExists
+    then configuration ".pandoc-plot.yml"
+    else return defaultConfiguration
+
+showFullVersion :: IO ()
+showFullVersion = do
+  putStrLn $ "pandoc-plot " <> V.showVersion pandocPlotVersion
+  putStrLn $ "Git revision " <> $gitHash
+  putStrLn $
+    mconcat
+      [ "Compiled with pandoc ",
+        V.showVersion pandocVersion,
+        " and pandoc-types ",
+        V.showVersion pandocTypesVersion,
+        " using GHC ",
+        TOOL_VERSION_ghc -- Constant defined by CPP
+      ]
+
+showAvailableToolkits :: Maybe FilePath -> IO ()
+showAvailableToolkits mfp = do
+  c <- maybe localConfig configuration mfp
+
+  putStrLn "\nAVAILABLE TOOLKITS\n"
+  available <- availableToolkits c
+  mapM_ (availToolkitInfo c) available
+  putStrLn "\nUNAVAILABLE TOOLKITS\n"
+  -- We don't use unavailableToolkits because this would force
+  -- more IO actions
+  let unavailable = toolkits \\ available
+  mapM_ (unavailToolkitInfo c) unavailable
+  where
+    toolkitInfo avail conf tk = do
+      putStrLn $ "Toolkit: " <> show tk
+      when avail $ do
+        exe <- runPlotM Nothing conf $ executable tk
+        putStrLn $ "    Executable: " <> pathToExe exe
+      putStrLn $ "    Code block trigger: " <> (unpack . cls $ tk)
+      putStrLn $ "    Supported save formats: " <> (mconcat . intersperse ", " . fmap show $ supportedSaveFormats tk)
+      putStrLn mempty
+    availToolkitInfo = toolkitInfo True
+    unavailToolkitInfo = toolkitInfo False
+
+-- | Clean output directories associated with a file
+--
+-- Priority for configuration are the same as @toJSONFilterWithConfig@.
+clean ::
+  Maybe FilePath -> -- Use configuration file?
+  FilePath -> -- Document to clean
+  IO ()
+clean mfp fp = do
+  doc <- readDoc fp
+  -- Note the priority for configuration:
+  --   (1) path of argument --config
+  --   (2) document metadata
+  --   (3) local .pandoc-plot.yml
+  --   (4) default config
+  conf <- maybe localConfig configuration $ firstJusts [configurationPathMeta doc, mfp]
+  void (cleanOutputDirs conf doc)
+  where
+    firstJusts :: [Maybe a] -> Maybe a
+    firstJusts = msum
+
+showManPage :: IO ()
+showManPage = do
+  manualPath <- (</> "pandoc-plot-manual.html") <$> getTemporaryDirectory
+  TIO.writeFile manualPath $(embedManualHtml)
+  openFile ("file:///" <> manualPath)
executable/ManPage.hs view
@@ -1,41 +1,41 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}---- |--- This module was inspired by pandoc-crossref--- |-module ManPage (embedManualHtml) where--import Control.Monad (unless)-import Data.String (fromString)-import Data.Text (unpack)-import qualified Data.Text.IO as TIO-import Language.Haskell.TH.Syntax-  ( Exp (AppE, LitE, VarE),-    Lit (StringL),-    Q,-    Quasi (qAddDependentFile),-    runIO,-  )-import System.Directory (doesFileExist)-import System.FilePath ((</>))--docFile :: FilePath-docFile = "docs" </> "MANUAL.html"--readDocFile :: IO String-readDocFile = TIO.readFile docFile >>= return . unpack--embedManualHtml :: Q Exp-embedManualHtml = do-  -- Ensure that the manual file exists-  -- even if it is empty-  manualExists <- runIO $ doesFileExist docFile-  unless manualExists (runIO $ TIO.writeFile docFile mempty)--  qAddDependentFile docFile-  d <- runIO readDocFile-  strToExp d-  where-    strToExp :: String -> Q Exp-    strToExp s = return $ VarE 'fromString `AppE` LitE (StringL s)+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+-- |
+-- This module was inspired by pandoc-crossref
+-- |
+module ManPage (embedManualHtml) where
+
+import Control.Monad (unless)
+import Data.String (fromString)
+import Data.Text (unpack)
+import qualified Data.Text.IO as TIO
+import Language.Haskell.TH.Syntax
+  ( Exp (AppE, LitE, VarE),
+    Lit (StringL),
+    Q,
+    Quasi (qAddDependentFile),
+    runIO,
+  )
+import System.Directory (doesFileExist)
+import System.FilePath ((</>))
+
+docFile :: FilePath
+docFile = "docs" </> "MANUAL.html"
+
+readDocFile :: IO String
+readDocFile = TIO.readFile docFile >>= return . unpack
+
+embedManualHtml :: Q Exp
+embedManualHtml = do
+  -- Ensure that the manual file exists
+  -- even if it is empty
+  manualExists <- runIO $ doesFileExist docFile
+  unless manualExists (runIO $ TIO.writeFile docFile mempty)
+
+  qAddDependentFile docFile
+  d <- runIO readDocFile
+  strToExp d
+  where
+    strToExp :: String -> Q Exp
+    strToExp s = return $ VarE 'fromString `AppE` LitE (StringL s)
executable/OpenFile.hs view
@@ -1,37 +1,37 @@--- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Open a file in its default program.-module OpenFile (openFile) where--import Data.List (isInfixOf)-import System.Info (os)-import System.Process.Typed (proc, runProcess_, shell)--openFile :: FilePath -> IO ()-openFile-  -- Aliases taken from cabal's Distribution.System module-  | os `elem` ["mingw32", "win32", "cygwin32"] = openFileWindows-  | any (`isInfixOf` os) ["linux", "bsd"] = openFileLinux-  | os `elem` ["darwin"] = openFileMacOS-  | otherwise = error $ "Unsupported OS: " <> os--openFileWindows :: FilePath -> IO ()-openFileWindows fp =-  -- Call looks like: cmd /c 'start "" "my_filepath.html"'-  runProcess_ $ shell $ mconcat ["cmd /c start ", quoted mempty, " ", quoted fp]-  where-    quoted f = mconcat ["\"", f, "\""]--openFileLinux :: FilePath -> IO ()-openFileLinux fp =-  runProcess_ (proc "sh" ["-c", "xdg-open \"$0\" 2>&1 > /dev/null", fp])--openFileMacOS :: FilePath -> IO ()-openFileMacOS fp =-  runProcess_ (proc "open" [fp])+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Open a file in its default program.
+module OpenFile (openFile) where
+
+import Data.List (isInfixOf)
+import System.Info (os)
+import System.Process.Typed (proc, runProcess_, shell)
+
+openFile :: FilePath -> IO ()
+openFile
+  -- Aliases taken from cabal's Distribution.System module
+  | os `elem` ["mingw32", "win32", "cygwin32"] = openFileWindows
+  | any (`isInfixOf` os) ["linux", "bsd"] = openFileLinux
+  | os `elem` ["darwin"] = openFileMacOS
+  | otherwise = error $ "Unsupported OS: " <> os
+
+openFileWindows :: FilePath -> IO ()
+openFileWindows fp =
+  -- Call looks like: cmd /c 'start "" "my_filepath.html"'
+  runProcess_ $ shell $ mconcat ["cmd /c start ", quoted mempty, " ", quoted fp]
+  where
+    quoted f = mconcat ["\"", f, "\""]
+
+openFileLinux :: FilePath -> IO ()
+openFileLinux fp =
+  runProcess_ (proc "sh" ["-c", "xdg-open \"$0\" 2>&1 > /dev/null", fp])
+
+openFileMacOS :: FilePath -> IO ()
+openFileMacOS fp =
+  runProcess_ (proc "open" [fp])
pandoc-plot.cabal view
@@ -1,168 +1,170 @@-cabal-version:  2.2-name:           pandoc-plot-version:        1.7.0-synopsis:       A Pandoc filter to include figures generated from code blocks using your plotting toolkit of choice.-description:    A Pandoc filter to include figures generated from code blocks. -                Keep the document and code in the same location. Output is -                captured and included as a figure.-category:       Text-copyright:      (c) 2019-present Laurent P. René de Cotret-homepage:       https://github.com/LaurentRDC/pandoc-plot#readme-bug-reports:    https://github.com/LaurentRDC/pandoc-plot/issues-author:         Laurent P. René de Cotret-maintainer:     Laurent P. René de Cotret-license:        GPL-2.0-or-later-license-file:   LICENSE-build-type:     Simple-tested-with:    GHC == 8.10.4, -                GHC == 9.0.1, -                GHC == 9.2.1, -                GHC == 9.2.2,-                GHC == 9.4.4,-                GHC == 9.6.1-extra-source-files:-    CHANGELOG.md-    LICENSE-    README.md-    MANUAL.md-    docs/MANUAL.html-    example-config.yml--    data/srctemplate.html--    tests/fixtures/.config-meta.yml-    tests/fixtures/.empty-config.yml-    tests/fixtures/.verbose-config.yml-    tests/fixtures/plotfile.py-    tests/fixtures/data.csv-    -    tests/includes/bokeh.py-    tests/includes/ggplot2.r-    tests/includes/gnuplot.gp-    tests/includes/graphviz.dot-    tests/includes/mathplot.m-    tests/includes/matlabplot.m-    tests/includes/matplotlib.py-    tests/includes/octave.m-    tests/includes/plotly-python.py-    tests/includes/plotly-r.r-    tests/includes/plotsjl.jl-    tests/includes/plantuml.txt-    tests/includes/sagemath.sage-    tests/includes/d2-dd.d2--source-repository head-    type: git-    location: https://github.com/LaurentRDC/pandoc-plot--library-    exposed-modules:-        Text.Pandoc.Filter.Plot-        Text.Pandoc.Filter.Plot.Internal-    other-modules:-        Paths_pandoc_plot-        Text.Pandoc.Filter.Plot.Clean-        Text.Pandoc.Filter.Plot.Configuration-        Text.Pandoc.Filter.Plot.Parse-        Text.Pandoc.Filter.Plot.Scripting-        Text.Pandoc.Filter.Plot.Scripting.Template-        Text.Pandoc.Filter.Plot.Renderers-        Text.Pandoc.Filter.Plot.Renderers.Prelude-        Text.Pandoc.Filter.Plot.Renderers.Matplotlib-        Text.Pandoc.Filter.Plot.Renderers.PlotlyPython-        Text.Pandoc.Filter.Plot.Renderers.PlotlyR-        Text.Pandoc.Filter.Plot.Renderers.Matlab-        Text.Pandoc.Filter.Plot.Renderers.Mathematica-        Text.Pandoc.Filter.Plot.Renderers.Octave-        Text.Pandoc.Filter.Plot.Renderers.GGPlot2-        Text.Pandoc.Filter.Plot.Renderers.GNUPlot-        Text.Pandoc.Filter.Plot.Renderers.Graphviz-        Text.Pandoc.Filter.Plot.Renderers.Bokeh-        Text.Pandoc.Filter.Plot.Renderers.Plotsjl-        Text.Pandoc.Filter.Plot.Renderers.PlantUML-        Text.Pandoc.Filter.Plot.Renderers.SageMath-        Text.Pandoc.Filter.Plot.Renderers.D2-        Text.Pandoc.Filter.Plot.Monad-        Text.Pandoc.Filter.Plot.Monad.Logging-        Text.Pandoc.Filter.Plot.Monad.Types-        Text.Pandoc.Filter.Plot.Embed-    autogen-modules:-        Paths_pandoc_plot-    hs-source-dirs:-        src-    ghc-options: -        -Wall -        -Wcompat-        -Widentities-        -Wincomplete-uni-patterns-        -Wincomplete-record-updates-        -Wredundant-constraints-        -fhide-source-paths-        -Wmissing-export-lists-        -Wpartial-fields-    build-depends:-          aeson              >= 2     && < 3-        , base               >= 4.11  && < 5-        , bytestring-        , containers-        , data-default  -        , directory          >= 1.2.7 && < 2-        , filepath           >= 1.4   && < 2-        , hashable           >= 1     && < 2-        , pandoc             >= 3     && < 4-        , pandoc-types       >= 1.23  && < 1.24-        , lifted-async       >= 0.10  && < 1-        , lifted-base        >= 0.2   && < 1-        , shakespeare        >= 2.0   && < 3-        , tagsoup            >= 0.14  && < 1-        , template-haskell   >  2.7   && < 3-        , text               >= 1     && < 3-        , typed-process      >= 0.2.1 && < 1-        , yaml               >= 0.8   && < 1-        , mtl                >= 2.2   && < 3-    if !os(windows)-        build-depends:  unix >= 2.4 && < 2.9-    default-language: Haskell2010--executable pandoc-plot-    main-is: Main.hs-    other-modules:-        ManPage-        ExampleConfig-        OpenFile-        Paths_pandoc_plot-    hs-source-dirs:-        executable-    ghc-options: -Wall -Wcompat -threaded -rtsopts -with-rtsopts=-N-    build-depends:-          base                  >= 4.11 && <5-        , containers-        , directory-        , filepath-        , gitrev                >= 1    && < 2-        , optparse-applicative  >= 0.14 && < 0.19-        , pandoc-        , pandoc-plot-        , pandoc-types          >= 1.21 && < 2-        , template-haskell      >  2.7  && < 3-        , typed-process-        , text-    default-language: Haskell2010--test-suite tests-    type: exitcode-stdio-1.0-    hs-source-dirs:  tests-    main-is:         Main.hs-    other-modules:   Common-    build-depends:   base-                   , containers-                   , directory-                   , filepath-                   , hspec-expectations-                   , pandoc-types-                   , pandoc-plot-                   , tasty-                   , tasty-hunit-                   , tasty-hspec-                   , text-    default-language: Haskell2010+cabal-version:  2.2
+name:           pandoc-plot
+version:        1.8.0
+synopsis:       A Pandoc filter to include figures generated from code blocks using your plotting toolkit of choice.
+description:    A Pandoc filter to include figures generated from code blocks. 
+                Keep the document and code in the same location. Output is 
+                captured and included as a figure.
+category:       Text
+copyright:      (c) 2019-present Laurent P. René de Cotret
+homepage:       https://github.com/LaurentRDC/pandoc-plot#readme
+bug-reports:    https://github.com/LaurentRDC/pandoc-plot/issues
+author:         Laurent P. René de Cotret
+maintainer:     Laurent P. René de Cotret
+license:        GPL-2.0-or-later
+license-file:   LICENSE
+build-type:     Simple
+tested-with:    GHC == 8.10.4, 
+                GHC == 9.0.1, 
+                GHC == 9.2.1, 
+                GHC == 9.2.2,
+                GHC == 9.4.4,
+                GHC == 9.6.1,
+                GHC == 9.6.3
+extra-source-files:
+    CHANGELOG.md
+    LICENSE
+    README.md
+    MANUAL.md
+    docs/MANUAL.html
+    example-config.yml
+
+    data/srctemplate.html
+
+    tests/fixtures/.config-meta.yml
+    tests/fixtures/.empty-config.yml
+    tests/fixtures/.verbose-config.yml
+    tests/fixtures/plotfile.py
+    tests/fixtures/data.csv
+    
+    tests/includes/bokeh.py
+    tests/includes/ggplot2.r
+    tests/includes/gnuplot.gp
+    tests/includes/graphviz.dot
+    tests/includes/mathplot.m
+    tests/includes/matlabplot.m
+    tests/includes/matplotlib.py
+    tests/includes/octave.m
+    tests/includes/plotly-python.py
+    tests/includes/plotly-r.r
+    tests/includes/plotsjl.jl
+    tests/includes/plantuml.txt
+    tests/includes/sagemath.sage
+    tests/includes/d2-dd.d2
+
+source-repository head
+    type: git
+    location: https://github.com/LaurentRDC/pandoc-plot
+
+library
+    exposed-modules:
+        Text.Pandoc.Filter.Plot
+        Text.Pandoc.Filter.Plot.Internal
+    other-modules:
+        Paths_pandoc_plot
+        Text.Pandoc.Filter.Plot.Clean
+        Text.Pandoc.Filter.Plot.Configuration
+        Text.Pandoc.Filter.Plot.Parse
+        Text.Pandoc.Filter.Plot.Scripting
+        Text.Pandoc.Filter.Plot.Scripting.Template
+        Text.Pandoc.Filter.Plot.Renderers
+        Text.Pandoc.Filter.Plot.Renderers.Prelude
+        Text.Pandoc.Filter.Plot.Renderers.Matplotlib
+        Text.Pandoc.Filter.Plot.Renderers.PlotlyPython
+        Text.Pandoc.Filter.Plot.Renderers.PlotlyR
+        Text.Pandoc.Filter.Plot.Renderers.Matlab
+        Text.Pandoc.Filter.Plot.Renderers.Mathematica
+        Text.Pandoc.Filter.Plot.Renderers.Octave
+        Text.Pandoc.Filter.Plot.Renderers.GGPlot2
+        Text.Pandoc.Filter.Plot.Renderers.GNUPlot
+        Text.Pandoc.Filter.Plot.Renderers.Graphviz
+        Text.Pandoc.Filter.Plot.Renderers.Bokeh
+        Text.Pandoc.Filter.Plot.Renderers.Plotsjl
+        Text.Pandoc.Filter.Plot.Renderers.PlantUML
+        Text.Pandoc.Filter.Plot.Renderers.SageMath
+        Text.Pandoc.Filter.Plot.Renderers.D2
+        Text.Pandoc.Filter.Plot.Renderers.Asymptote
+        Text.Pandoc.Filter.Plot.Monad
+        Text.Pandoc.Filter.Plot.Monad.Logging
+        Text.Pandoc.Filter.Plot.Monad.Types
+        Text.Pandoc.Filter.Plot.Embed
+    autogen-modules:
+        Paths_pandoc_plot
+    hs-source-dirs:
+        src
+    ghc-options: 
+        -Wall 
+        -Wcompat
+        -Widentities
+        -Wincomplete-uni-patterns
+        -Wincomplete-record-updates
+        -Wredundant-constraints
+        -fhide-source-paths
+        -Wmissing-export-lists
+        -Wpartial-fields
+    build-depends:
+          aeson              >= 2     && < 3
+        , base               >= 4.11  && < 5
+        , bytestring
+        , containers
+        , data-default  
+        , directory          >= 1.2.7 && < 2
+        , filepath           >= 1.4   && < 2
+        , hashable           >= 1     && < 2
+        , pandoc             >= 3     && < 4
+        , pandoc-types       >= 1.23  && < 1.24
+        , lifted-async       >= 0.10  && < 1
+        , lifted-base        >= 0.2   && < 1
+        , shakespeare        >= 2.0   && < 3
+        , tagsoup            >= 0.14  && < 1
+        , template-haskell   >  2.7   && < 3
+        , text               >= 1     && < 3
+        , typed-process      >= 0.2.1 && < 1
+        , yaml               >= 0.8   && < 1
+        , mtl                >= 2.2   && < 3
+    if !os(windows)
+        build-depends:  unix >= 2.4 && < 2.9
+    default-language: Haskell2010
+
+executable pandoc-plot
+    main-is: Main.hs
+    other-modules:
+        ManPage
+        ExampleConfig
+        OpenFile
+        Paths_pandoc_plot
+    hs-source-dirs:
+        executable
+    ghc-options: -Wall -Wcompat -threaded -rtsopts -with-rtsopts=-N
+    build-depends:
+          base                  >= 4.11 && <5
+        , containers
+        , directory
+        , filepath
+        , gitrev                >= 1    && < 2
+        , optparse-applicative  >= 0.14 && < 0.19
+        , pandoc
+        , pandoc-plot
+        , pandoc-types          >= 1.21 && < 2
+        , template-haskell      >  2.7  && < 3
+        , typed-process
+        , text
+    default-language: Haskell2010
+
+test-suite tests
+    type: exitcode-stdio-1.0
+    hs-source-dirs:  tests
+    main-is:         Main.hs
+    other-modules:   Common
+    build-depends:   base
+                   , containers
+                   , directory
+                   , filepath
+                   , hspec-expectations
+                   , pandoc-types
+                   , pandoc-plot
+                   , tasty
+                   , tasty-hunit
+                   , tasty-hspec
+                   , text
+    default-language: Haskell2010
src/Text/Pandoc/Filter/Plot.hs view
@@ -1,242 +1,242 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : $header$--- Description : Pandoc filter to create figures from code blocks using your plotting toolkit of choice--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : unstable--- Portability : portable------ This module defines a Pandoc filter @plotFilter@ and related functions--- that can be used to walk over a Pandoc document and generate figures from--- code blocks, using a multitude of plotting toolkits.------ The syntax for code blocks is simple. Code blocks with the appropriate class--- attribute will trigger the filter, e.g. @matplotlib@ for matplotlib-based Python plots.------ Here is an example, in Markdown, for a plot in MATLAB:------ @--- This is a paragraph.------ ```{.matlabplot}--- figure()--- plot([1,2,3,4,5], [1,2,3,4,5], '-k')--- ```--- @------ or a using GNUPlot:------ @--- ```{.gnuplot format=png caption="Sinusoidal function" source=true}--- sin(x)------ set xlabel "x"--- set ylabel "y"--- ```--- @------ The code block will be reworked into a script and the output figure will be captured. Optionally, the source code---  used to generate the figure will be linked in the caption.------ Here are /some/ of the possible attributes what pandoc-plot understands for ALL toolkits:------     * @directory=...@ : Directory where to save the figure. This path should be specified with---       respect to the current working directory, and not with respect to the document.---     * @source=true|false@ : Whether or not to link the source code of this figure in the caption.---       Ideal for web pages, for example. Default is false.---     * @format=...@: Format of the generated figure. This can be an extension or an acronym,---       e.g. @format=PNG@.---     * @caption="..."@: Specify a plot caption (or alternate text). Format---       for captions is specified in the documentation for the @Configuration@ type.---     * @dpi=...@: Specify a value for figure resolution, or dots-per-inch. Certain toolkits ignore this.---     * @dependencies=[...]@: Specify files/directories on which a figure depends, e.g. data file.---       Figures will be re-rendered if one of those file/directory changes. These paths should---       be specified with respect to the current working directory, and not with respect to the document.---     * @preamble=...@: Path to a file to include before the code block. Ideal to avoid repetition over---       many figures.---     * @file=...@: Path to a file from which to read the content of the figure. The content of the---       code block will be ignored. This path should be specified with respect to the current working---       directory, and not with respect to the document.------ All attributes are described in the online documentation, linked on the home page.-module Text.Pandoc.Filter.Plot-  ( -- * Operating on whole Pandoc documents-    plotFilter,-    plotTransform,--    -- * Cleaning output directories-    cleanOutputDirs,--    -- * Runtime configuration-    configuration,-    defaultConfiguration,-    Configuration (..),-    Verbosity (..),-    LogSink (..),-    SaveFormat (..),-    Script,--    -- * Determining available plotting toolkits-    Toolkit (..),-    availableToolkits,-    unavailableToolkits,-    toolkits,-    supportedSaveFormats,--    -- * Version information-    pandocPlotVersion,--    -- * For embedding, testing and internal purposes ONLY. Might change without notice.-    make,-    makeEither,-    PandocPlotError (..),-  )-where--import Control.Concurrent (getNumCapabilities)-import Control.Monad (when)-import Data.Functor ((<&>))-import Data.Map (singleton)-import Data.Text (Text, pack, unpack)-import Data.Version (Version)-import Paths_pandoc_plot (version)-import Text.Pandoc.Definition (Block, Format, Meta (..), MetaValue (..), Pandoc (..))-import Text.Pandoc.Filter.Plot.Internal-  ( Configuration (..),-    FigureSpec,-    LogSink (..),-    ParseFigureResult (..),-    PlotM,-    RuntimeEnv (envConfig),-    SaveFormat (..),-    Script,-    ScriptResult (..),-    Toolkit (..),-    Verbosity (..),-    asks,-    asksConfig,-    availableToolkits,-    cleanOutputDirs,-    configuration,-    debug,-    defaultConfiguration,-    mapConcurrentlyN,-    parseFigureSpec,-    runPlotM,-    runScriptIfNecessary,-    supportedSaveFormats,-    throwStrictError,-    toFigure,-    toolkits,-    unavailableToolkits,-  )-import Text.Pandoc.Walk (walkM)---- | Walk over an entire Pandoc document, transforming appropriate code blocks--- into figures. This function will operate on blocks in parallel if possible.------ If the target conversion format is known, then this function can provide better--- defaults and error messages. For example, hyperlinks to source code will only be created--- if the final target format supports it (e.g. HTML).------ Failing to render a figure does not stop the filter, so that you may run the filter--- on documents without having all necessary toolkits installed. In this case, error--- messages are printed to stderr, and blocks are left unchanged.------ @since 1.3.0-plotFilter ::-  -- | Configuration for default values-  Configuration ->-  -- | Final converted format, if known-  Maybe Format ->-  -- | Input document-  Pandoc ->-  IO Pandoc-plotFilter conf mfmt (Pandoc meta blocks) = do-  maxproc <- getNumCapabilities-  runPlotM mfmt conf $ do-    debug $ mconcat ["Starting a new run, utilizing at most ", pack . show $ maxproc, " processes."]-    mapConcurrentlyN maxproc make blocks <&> Pandoc newMeta-  where-    -- This variable is needed for pandoc's default LaTeX template,-    -- so that graphicx gets used.-    newMeta = meta <> Meta (singleton "graphics" $ MetaBool True)---- | Walk over an entire Pandoc document, transforming appropriate code blocks--- into figures. This function will operate on blocks in parallel if possible.------ Failing to render a figure does not stop the filter, so that you may run the filter--- on documents without having all necessary toolkits installed. In this case, error--- messages are printed to stderr, and blocks are left unchanged.------ __Note that this function is DEPRECATED in favour of @plotFilter@. It will be--- removed in the next major update (v2+).__-plotTransform ::-  -- | Configuration for default values-  Configuration ->-  -- | Input document-  Pandoc ->-  IO Pandoc-{-# DEPRECATED-  plotTransform-  [ "plotTransform has been deprecated in favour of plotFilter, which is aware of conversion format.",-    "plotTransform will be removed in an upcoming major update."-  ]-  #-}-plotTransform conf = plotFilter conf Nothing---- | The version of the pandoc-plot package.------ @since 0.8.0.0-pandocPlotVersion :: Version-pandocPlotVersion = version---- | Try to process the block with `pandoc-plot`. If a failure happens (or the block)--- was not meant to become a figure, return the block as-is unless running in strict mode.--- In strict mode, any failure (for example, due to a missing plotting toolkit) will halt execution.------ New in version 1.2.0: this function will detect nested code blocks, for example in @Div@ blocks.-make :: Block -> PlotM Block-make = walkM $ \blk -> either (onError blk) return =<< makeEither blk-  where-    onError :: Block -> PandocPlotError -> PlotM Block-    onError b e = do-      whenStrict $ throwStrictError (pack . show $ e)-      return b--    whenStrict f = asksConfig strictMode >>= \s -> when s f---- | Try to process the block with `pandoc-plot`, documenting the error.--- This function does not transform code blocks nested in--- other blocks (e.g. @Divs@)-makeEither :: Block -> PlotM (Either PandocPlotError Block)-makeEither block =-  parseFigureSpec block-    >>= \case-      NotAFigure -> return $ Right block-      PFigure fs -> runScriptIfNecessary fs >>= handleResult fs-      MissingToolkit tk -> return $ Left $ ToolkitNotInstalledError tk-      UnsupportedSaveFormat tk sv -> return $ Left $ IncompatibleSaveFormatError sv tk-  where-    -- Logging of errors has been taken care of in @runScriptIfNecessary@-    handleResult :: FigureSpec -> ScriptResult -> PlotM (Either PandocPlotError Block)-    handleResult _ (ScriptFailure cmd code _) = return $ Left (ScriptRuntimeError cmd code)-    handleResult _ (ScriptChecksFailed msg) = return $ Left (ScriptChecksFailedError msg)-    handleResult spec ScriptSuccess = asks envConfig >>= \c -> Right <$> toFigure (captionFormat c) spec--data PandocPlotError-  = ScriptRuntimeError Text Int-  | ScriptChecksFailedError Text-  | ToolkitNotInstalledError Toolkit-  | IncompatibleSaveFormatError SaveFormat Toolkit--instance Show PandocPlotError where-  show (ScriptRuntimeError _ exitcode) = "ERROR (pandoc-plot) The script failed with exit code " <> show exitcode <> "."-  show (ScriptChecksFailedError msg) = "ERROR (pandoc-plot) A script check failed with message: " <> unpack msg <> "."-  show (ToolkitNotInstalledError tk) = "ERROR (pandoc-plot) The " <> show tk <> " toolkit is required but not installed."-  show (IncompatibleSaveFormatError tk sv) = "ERROR (pandoc-plot) Save format " <> show sv <> " not supported by the " <> show tk <> " toolkit."+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : $header$
+-- Description : Pandoc filter to create figures from code blocks using your plotting toolkit of choice
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : unstable
+-- Portability : portable
+--
+-- This module defines a Pandoc filter @plotFilter@ and related functions
+-- that can be used to walk over a Pandoc document and generate figures from
+-- code blocks, using a multitude of plotting toolkits.
+--
+-- The syntax for code blocks is simple. Code blocks with the appropriate class
+-- attribute will trigger the filter, e.g. @matplotlib@ for matplotlib-based Python plots.
+--
+-- Here is an example, in Markdown, for a plot in MATLAB:
+--
+-- @
+-- This is a paragraph.
+--
+-- ```{.matlabplot}
+-- figure()
+-- plot([1,2,3,4,5], [1,2,3,4,5], '-k')
+-- ```
+-- @
+--
+-- or a using GNUPlot:
+--
+-- @
+-- ```{.gnuplot format=png caption="Sinusoidal function" source=true}
+-- sin(x)
+--
+-- set xlabel "x"
+-- set ylabel "y"
+-- ```
+-- @
+--
+-- The code block will be reworked into a script and the output figure will be captured. Optionally, the source code
+--  used to generate the figure will be linked in the caption.
+--
+-- Here are /some/ of the possible attributes what pandoc-plot understands for ALL toolkits:
+--
+--     * @directory=...@ : Directory where to save the figure. This path should be specified with
+--       respect to the current working directory, and not with respect to the document.
+--     * @source=true|false@ : Whether or not to link the source code of this figure in the caption.
+--       Ideal for web pages, for example. Default is false.
+--     * @format=...@: Format of the generated figure. This can be an extension or an acronym,
+--       e.g. @format=PNG@.
+--     * @caption="..."@: Specify a plot caption (or alternate text). Format
+--       for captions is specified in the documentation for the @Configuration@ type.
+--     * @dpi=...@: Specify a value for figure resolution, or dots-per-inch. Certain toolkits ignore this.
+--     * @dependencies=[...]@: Specify files/directories on which a figure depends, e.g. data file.
+--       Figures will be re-rendered if one of those file/directory changes. These paths should
+--       be specified with respect to the current working directory, and not with respect to the document.
+--     * @preamble=...@: Path to a file to include before the code block. Ideal to avoid repetition over
+--       many figures.
+--     * @file=...@: Path to a file from which to read the content of the figure. The content of the
+--       code block will be ignored. This path should be specified with respect to the current working
+--       directory, and not with respect to the document.
+--
+-- All attributes are described in the online documentation, linked on the home page.
+module Text.Pandoc.Filter.Plot
+  ( -- * Operating on whole Pandoc documents
+    plotFilter,
+    plotTransform,
+
+    -- * Cleaning output directories
+    cleanOutputDirs,
+
+    -- * Runtime configuration
+    configuration,
+    defaultConfiguration,
+    Configuration (..),
+    Verbosity (..),
+    LogSink (..),
+    SaveFormat (..),
+    Script,
+
+    -- * Determining available plotting toolkits
+    Toolkit (..),
+    availableToolkits,
+    unavailableToolkits,
+    toolkits,
+    supportedSaveFormats,
+
+    -- * Version information
+    pandocPlotVersion,
+
+    -- * For embedding, testing and internal purposes ONLY. Might change without notice.
+    make,
+    makeEither,
+    PandocPlotError (..),
+  )
+where
+
+import Control.Concurrent (getNumCapabilities)
+import Control.Monad (when)
+import Data.Functor ((<&>))
+import Data.Map (singleton)
+import Data.Text (Text, pack, unpack)
+import Data.Version (Version)
+import Paths_pandoc_plot (version)
+import Text.Pandoc.Definition (Block, Format, Meta (..), MetaValue (..), Pandoc (..))
+import Text.Pandoc.Filter.Plot.Internal
+  ( Configuration (..),
+    FigureSpec,
+    LogSink (..),
+    ParseFigureResult (..),
+    PlotM,
+    RuntimeEnv (envConfig),
+    SaveFormat (..),
+    Script,
+    ScriptResult (..),
+    Toolkit (..),
+    Verbosity (..),
+    asks,
+    asksConfig,
+    availableToolkits,
+    cleanOutputDirs,
+    configuration,
+    debug,
+    defaultConfiguration,
+    mapConcurrentlyN,
+    parseFigureSpec,
+    runPlotM,
+    runScriptIfNecessary,
+    supportedSaveFormats,
+    throwStrictError,
+    toFigure,
+    toolkits,
+    unavailableToolkits,
+  )
+import Text.Pandoc.Walk (walkM)
+
+-- | Walk over an entire Pandoc document, transforming appropriate code blocks
+-- into figures. This function will operate on blocks in parallel if possible.
+--
+-- If the target conversion format is known, then this function can provide better
+-- defaults and error messages. For example, hyperlinks to source code will only be created
+-- if the final target format supports it (e.g. HTML).
+--
+-- Failing to render a figure does not stop the filter, so that you may run the filter
+-- on documents without having all necessary toolkits installed. In this case, error
+-- messages are printed to stderr, and blocks are left unchanged.
+--
+-- @since 1.3.0
+plotFilter ::
+  -- | Configuration for default values
+  Configuration ->
+  -- | Final converted format, if known
+  Maybe Format ->
+  -- | Input document
+  Pandoc ->
+  IO Pandoc
+plotFilter conf mfmt (Pandoc meta blocks) = do
+  maxproc <- getNumCapabilities
+  runPlotM mfmt conf $ do
+    debug $ mconcat ["Starting a new run, utilizing at most ", pack . show $ maxproc, " processes."]
+    mapConcurrentlyN maxproc make blocks <&> Pandoc newMeta
+  where
+    -- This variable is needed for pandoc's default LaTeX template,
+    -- so that graphicx gets used.
+    newMeta = meta <> Meta (singleton "graphics" $ MetaBool True)
+
+-- | Walk over an entire Pandoc document, transforming appropriate code blocks
+-- into figures. This function will operate on blocks in parallel if possible.
+--
+-- Failing to render a figure does not stop the filter, so that you may run the filter
+-- on documents without having all necessary toolkits installed. In this case, error
+-- messages are printed to stderr, and blocks are left unchanged.
+--
+-- __Note that this function is DEPRECATED in favour of @plotFilter@. It will be
+-- removed in the next major update (v2+).__
+plotTransform ::
+  -- | Configuration for default values
+  Configuration ->
+  -- | Input document
+  Pandoc ->
+  IO Pandoc
+{-# DEPRECATED
+  plotTransform
+  [ "plotTransform has been deprecated in favour of plotFilter, which is aware of conversion format.",
+    "plotTransform will be removed in an upcoming major update."
+  ]
+  #-}
+plotTransform conf = plotFilter conf Nothing
+
+-- | The version of the pandoc-plot package.
+--
+-- @since 0.8.0.0
+pandocPlotVersion :: Version
+pandocPlotVersion = version
+
+-- | Try to process the block with `pandoc-plot`. If a failure happens (or the block)
+-- was not meant to become a figure, return the block as-is unless running in strict mode.
+-- In strict mode, any failure (for example, due to a missing plotting toolkit) will halt execution.
+--
+-- New in version 1.2.0: this function will detect nested code blocks, for example in @Div@ blocks.
+make :: Block -> PlotM Block
+make = walkM $ \blk -> either (onError blk) return =<< makeEither blk
+  where
+    onError :: Block -> PandocPlotError -> PlotM Block
+    onError b e = do
+      whenStrict $ throwStrictError (pack . show $ e)
+      return b
+
+    whenStrict f = asksConfig strictMode >>= \s -> when s f
+
+-- | Try to process the block with `pandoc-plot`, documenting the error.
+-- This function does not transform code blocks nested in
+-- other blocks (e.g. @Divs@)
+makeEither :: Block -> PlotM (Either PandocPlotError Block)
+makeEither block =
+  parseFigureSpec block
+    >>= \case
+      NotAFigure -> return $ Right block
+      PFigure fs -> runScriptIfNecessary fs >>= handleResult fs
+      MissingToolkit tk -> return $ Left $ ToolkitNotInstalledError tk
+      UnsupportedSaveFormat tk sv -> return $ Left $ IncompatibleSaveFormatError sv tk
+  where
+    -- Logging of errors has been taken care of in @runScriptIfNecessary@
+    handleResult :: FigureSpec -> ScriptResult -> PlotM (Either PandocPlotError Block)
+    handleResult _ (ScriptFailure cmd code _) = return $ Left (ScriptRuntimeError cmd code)
+    handleResult _ (ScriptChecksFailed msg) = return $ Left (ScriptChecksFailedError msg)
+    handleResult spec ScriptSuccess = asks envConfig >>= \c -> Right <$> toFigure (captionFormat c) spec
+
+data PandocPlotError
+  = ScriptRuntimeError Text Int
+  | ScriptChecksFailedError Text
+  | ToolkitNotInstalledError Toolkit
+  | IncompatibleSaveFormatError SaveFormat Toolkit
+
+instance Show PandocPlotError where
+  show (ScriptRuntimeError _ exitcode) = "ERROR (pandoc-plot) The script failed with exit code " <> show exitcode <> "."
+  show (ScriptChecksFailedError msg) = "ERROR (pandoc-plot) A script check failed with message: " <> unpack msg <> "."
+  show (ToolkitNotInstalledError tk) = "ERROR (pandoc-plot) The " <> show tk <> " toolkit is required but not installed."
+  show (IncompatibleSaveFormatError tk sv) = "ERROR (pandoc-plot) Save format " <> show sv <> " not supported by the " <> show tk <> " toolkit."
src/Text/Pandoc/Filter/Plot/Clean.hs view
@@ -1,165 +1,165 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Utilities to clean pandoc-plot output directories.-module Text.Pandoc.Filter.Plot.Clean-  ( cleanOutputDirs,-    outputDirs,-    readDoc,-  )-where---- TODO: forConcurrently-import Control.Monad (forM)-import qualified Data.ByteString.Lazy as B-import Data.Char (toLower)-import Data.Default (def)-import Data.List (nub)-import Data.Maybe (catMaybes, fromMaybe)-import Data.Text (Text, pack)-import qualified Data.Text.IO as Text-import System.Directory (removePathForcibly)-import System.FilePath (takeExtension)-import Text.Pandoc.Class (runIO)-import Text.Pandoc.Definition (Block, Pandoc)-import Text.Pandoc.Error (handleError)-import Text.Pandoc.Filter.Plot.Monad-import Text.Pandoc.Filter.Plot.Parse-import Text.Pandoc.Format (FlavoredFormat (..))-import qualified Text.Pandoc.Options as P-import qualified Text.Pandoc.Readers as P-import Text.Pandoc.Walk (Walkable, query)---- | Clean all output related to pandoc-plot. This includes output directories specified--- in the configuration and in the document/block, as well as log files.--- Note that *all* files in pandoc-plot output directories will be removed.------ The cleaned directories are returned.-cleanOutputDirs ::-  (Walkable Block b) =>-  Configuration ->-  b ->-  IO [FilePath]-cleanOutputDirs conf doc = do-  dirs <- runPlotM Nothing conf . cleanOutputDirsM $ doc-  -- Deletion of the log file must be done outside of PlotM-  -- to ensure the log file has been closed.-  case logSink conf of-    LogFile path -> removePathForcibly path-    _ -> return ()-  return dirs---- | Analyze a document to determine where would the pandoc-plot output directories be.-outputDirs ::-  (Walkable Block b) =>-  b ->-  PlotM [FilePath]-outputDirs = fmap (nub . catMaybes) . sequence . query (\b -> [hasDirectory <$> parseFigureSpec b])-  where-    hasDirectory :: ParseFigureResult -> Maybe FilePath-    hasDirectory (PFigure fs) = Just $ directory fs-    hasDirectory _ = Nothing---- | PlotM version of @cleanOutputDirs@-cleanOutputDirsM ::-  (Walkable Block b) =>-  b ->-  PlotM [FilePath]-cleanOutputDirsM doc = do-  directories <- outputDirs doc-  forM directories $ \fp -> do-    info $ "Removing directory " <> pack fp-    -- It is important to use `removePathForcibly` here, because it does-    -- not throw exceptions if the directory doesn't exist. This means-    -- we do not have to check in advance if directories are nested in our-    -- list of directories.-    liftIO $ removePathForcibly fp-    return fp---- | Read a document, guessing what extensions and reader options are appropriate. If--- the file cannot be read for any reason, an error is thrown.-readDoc :: FilePath -> IO Pandoc-readDoc fp =-  handleError-    =<< runIO-      ( do-          let fmt = fromMaybe mempty (formatFromFilePath fp)-          (reader, exts) <- P.getReader $ FlavoredFormat fmt mempty-          let readerOpts = def {P.readerExtensions = exts}-          case reader of-            P.TextReader fct -> do-              t <- liftIO $ Text.readFile fp-              fct readerOpts t-            P.ByteStringReader bst -> do-              b <- liftIO $ B.readFile fp-              bst readerOpts b-      )---- | Determine format based on file extension--- Note : this is exactly the heuristic used by pandoc here:--- https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/App/FormatHeuristics.hs------ However, this is not exported, so it must be re-defined here.-formatFromFilePath :: FilePath -> Maybe Text-formatFromFilePath x =-  case takeExtension (map toLower x) of-    ".adoc" -> Just "asciidoc"-    ".asciidoc" -> Just "asciidoc"-    ".context" -> Just "context"-    ".ctx" -> Just "context"-    ".db" -> Just "docbook"-    ".doc" -> Just "doc" -- so we get an "unknown reader" error-    ".docx" -> Just "docx"-    ".dokuwiki" -> Just "dokuwiki"-    ".epub" -> Just "epub"-    ".fb2" -> Just "fb2"-    ".htm" -> Just "html"-    ".html" -> Just "html"-    ".icml" -> Just "icml"-    ".json" -> Just "json"-    ".latex" -> Just "latex"-    ".lhs" -> Just "markdown+lhs"-    ".ltx" -> Just "latex"-    ".markdown" -> Just "markdown"-    ".mkdn" -> Just "markdown"-    ".mkd" -> Just "markdown"-    ".mdwn" -> Just "markdown"-    ".mdown" -> Just "markdown"-    ".Rmd" -> Just "markdown"-    ".md" -> Just "markdown"-    ".ms" -> Just "ms"-    ".muse" -> Just "muse"-    ".native" -> Just "native"-    ".odt" -> Just "odt"-    ".opml" -> Just "opml"-    ".org" -> Just "org"-    ".pdf" -> Just "pdf" -- so we get an "unknown reader" error-    ".pptx" -> Just "pptx"-    ".roff" -> Just "ms"-    ".rst" -> Just "rst"-    ".rtf" -> Just "rtf"-    ".s5" -> Just "s5"-    ".t2t" -> Just "t2t"-    ".tei" -> Just "tei"-    ".tei.xml" -> Just "tei"-    ".tex" -> Just "latex"-    ".texi" -> Just "texinfo"-    ".texinfo" -> Just "texinfo"-    ".text" -> Just "markdown"-    ".textile" -> Just "textile"-    ".txt" -> Just "markdown"-    ".wiki" -> Just "mediawiki"-    ".xhtml" -> Just "html"-    ".ipynb" -> Just "ipynb"-    ".csv" -> Just "csv"-    ".bib" -> Just "biblatex"-    ['.', y] | y `elem` ['1' .. '9'] -> Just "man"-    _ -> Nothing+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Utilities to clean pandoc-plot output directories.
+module Text.Pandoc.Filter.Plot.Clean
+  ( cleanOutputDirs,
+    outputDirs,
+    readDoc,
+  )
+where
+
+-- TODO: forConcurrently
+import Control.Monad (forM)
+import qualified Data.ByteString.Lazy as B
+import Data.Char (toLower)
+import Data.Default (def)
+import Data.List (nub)
+import Data.Maybe (catMaybes, fromMaybe)
+import Data.Text (Text, pack)
+import qualified Data.Text.IO as Text
+import System.Directory (removePathForcibly)
+import System.FilePath (takeExtension)
+import Text.Pandoc.Class (runIO)
+import Text.Pandoc.Definition (Block, Pandoc)
+import Text.Pandoc.Error (handleError)
+import Text.Pandoc.Filter.Plot.Monad
+import Text.Pandoc.Filter.Plot.Parse
+import Text.Pandoc.Format (FlavoredFormat (..))
+import qualified Text.Pandoc.Options as P
+import qualified Text.Pandoc.Readers as P
+import Text.Pandoc.Walk (Walkable, query)
+
+-- | Clean all output related to pandoc-plot. This includes output directories specified
+-- in the configuration and in the document/block, as well as log files.
+-- Note that *all* files in pandoc-plot output directories will be removed.
+--
+-- The cleaned directories are returned.
+cleanOutputDirs ::
+  (Walkable Block b) =>
+  Configuration ->
+  b ->
+  IO [FilePath]
+cleanOutputDirs conf doc = do
+  dirs <- runPlotM Nothing conf . cleanOutputDirsM $ doc
+  -- Deletion of the log file must be done outside of PlotM
+  -- to ensure the log file has been closed.
+  case logSink conf of
+    LogFile path -> removePathForcibly path
+    _ -> return ()
+  return dirs
+
+-- | Analyze a document to determine where would the pandoc-plot output directories be.
+outputDirs ::
+  (Walkable Block b) =>
+  b ->
+  PlotM [FilePath]
+outputDirs = fmap (nub . catMaybes) . sequence . query (\b -> [hasDirectory <$> parseFigureSpec b])
+  where
+    hasDirectory :: ParseFigureResult -> Maybe FilePath
+    hasDirectory (PFigure fs) = Just $ directory fs
+    hasDirectory _ = Nothing
+
+-- | PlotM version of @cleanOutputDirs@
+cleanOutputDirsM ::
+  (Walkable Block b) =>
+  b ->
+  PlotM [FilePath]
+cleanOutputDirsM doc = do
+  directories <- outputDirs doc
+  forM directories $ \fp -> do
+    info $ "Removing directory " <> pack fp
+    -- It is important to use `removePathForcibly` here, because it does
+    -- not throw exceptions if the directory doesn't exist. This means
+    -- we do not have to check in advance if directories are nested in our
+    -- list of directories.
+    liftIO $ removePathForcibly fp
+    return fp
+
+-- | Read a document, guessing what extensions and reader options are appropriate. If
+-- the file cannot be read for any reason, an error is thrown.
+readDoc :: FilePath -> IO Pandoc
+readDoc fp =
+  handleError
+    =<< runIO
+      ( do
+          let fmt = fromMaybe mempty (formatFromFilePath fp)
+          (reader, exts) <- P.getReader $ FlavoredFormat fmt mempty
+          let readerOpts = def {P.readerExtensions = exts}
+          case reader of
+            P.TextReader fct -> do
+              t <- liftIO $ Text.readFile fp
+              fct readerOpts t
+            P.ByteStringReader bst -> do
+              b <- liftIO $ B.readFile fp
+              bst readerOpts b
+      )
+
+-- | Determine format based on file extension
+-- Note : this is exactly the heuristic used by pandoc here:
+-- https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/App/FormatHeuristics.hs
+--
+-- However, this is not exported, so it must be re-defined here.
+formatFromFilePath :: FilePath -> Maybe Text
+formatFromFilePath x =
+  case takeExtension (map toLower x) of
+    ".adoc" -> Just "asciidoc"
+    ".asciidoc" -> Just "asciidoc"
+    ".context" -> Just "context"
+    ".ctx" -> Just "context"
+    ".db" -> Just "docbook"
+    ".doc" -> Just "doc" -- so we get an "unknown reader" error
+    ".docx" -> Just "docx"
+    ".dokuwiki" -> Just "dokuwiki"
+    ".epub" -> Just "epub"
+    ".fb2" -> Just "fb2"
+    ".htm" -> Just "html"
+    ".html" -> Just "html"
+    ".icml" -> Just "icml"
+    ".json" -> Just "json"
+    ".latex" -> Just "latex"
+    ".lhs" -> Just "markdown+lhs"
+    ".ltx" -> Just "latex"
+    ".markdown" -> Just "markdown"
+    ".mkdn" -> Just "markdown"
+    ".mkd" -> Just "markdown"
+    ".mdwn" -> Just "markdown"
+    ".mdown" -> Just "markdown"
+    ".Rmd" -> Just "markdown"
+    ".md" -> Just "markdown"
+    ".ms" -> Just "ms"
+    ".muse" -> Just "muse"
+    ".native" -> Just "native"
+    ".odt" -> Just "odt"
+    ".opml" -> Just "opml"
+    ".org" -> Just "org"
+    ".pdf" -> Just "pdf" -- so we get an "unknown reader" error
+    ".pptx" -> Just "pptx"
+    ".roff" -> Just "ms"
+    ".rst" -> Just "rst"
+    ".rtf" -> Just "rtf"
+    ".s5" -> Just "s5"
+    ".t2t" -> Just "t2t"
+    ".tei" -> Just "tei"
+    ".tei.xml" -> Just "tei"
+    ".tex" -> Just "latex"
+    ".texi" -> Just "texinfo"
+    ".texinfo" -> Just "texinfo"
+    ".text" -> Just "markdown"
+    ".textile" -> Just "textile"
+    ".txt" -> Just "markdown"
+    ".wiki" -> Just "mediawiki"
+    ".xhtml" -> Just "html"
+    ".ipynb" -> Just "ipynb"
+    ".csv" -> Just "csv"
+    ".bib" -> Just "biblatex"
+    ['.', y] | y `elem` ['1' .. '9'] -> Just "man"
+    _ -> Nothing
src/Text/Pandoc/Filter/Plot/Configuration.hs view
@@ -1,399 +1,414 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Reading configuration from file-module Text.Pandoc.Filter.Plot.Configuration-  ( configuration,-    configurationPathMeta,-    defaultConfiguration,-  )-where--import Data.Aeson (FromJSON (parseJSON), Key, Value (Null, Object), (.!=), (.:?))-import Data.String (IsString (..))-import Data.Text (Text, unpack)-import qualified Data.Text.IO as TIO-import Data.Yaml.Config (ignoreEnv, loadYamlSettings)-import System.FilePath (normalise)-import Text.Pandoc.Definition (Format (..), Inline (..), MetaValue (..), Pandoc (..), lookupMeta)-import Text.Pandoc.Filter.Plot.Monad---- | Read configuration from a YAML file. The--- keys are exactly the same as for code blocks.------ If a key is not present, its value will be set--- to the default value. Parsing errors result in thrown exceptions.-configuration :: FilePath -> IO Configuration-configuration fp = loadYamlSettings [normalise fp] [] ignoreEnv >>= renderConfig---- | Default configuration values.------ @since 0.5.0.0-defaultConfiguration :: Configuration-defaultConfiguration =-  Configuration-    { defaultDirectory = "plots/",-      defaultWithSource = False,-      defaultDPI = 80,-      defaultSaveFormat = PNG,-      defaultDependencies = mempty,-      captionFormat = Format "markdown+tex_math_dollars",-      sourceCodeLabel = "Source code",-      strictMode = False,-      logVerbosity = Warning,-      logSink = StdErr,-      -- Preambles-      matplotlibPreamble = mempty,-      plotlyPythonPreamble = mempty,-      plotlyRPreamble = mempty,-      matlabPreamble = mempty,-      mathematicaPreamble = mempty,-      octavePreamble = mempty,-      ggplot2Preamble = mempty,-      gnuplotPreamble = mempty,-      graphvizPreamble = mempty,-      bokehPreamble = mempty,-      plotsjlPreamble = mempty,-      plantumlPreamble = mempty,-      sagemathPreamble = mempty,-      d2Preamble = mempty,-      -- Executables-      matplotlibExe = python,-      matlabExe = "matlab",-      plotlyPythonExe = python,-      plotlyRExe = "Rscript",-      mathematicaExe = "math",-      octaveExe = "octave",-      ggplot2Exe = "Rscript",-      gnuplotExe = "gnuplot",-      graphvizExe = "dot",-      bokehExe = python,-      plotsjlExe = "julia",-      plantumlExe = "java",-      sagemathExe = "sage",-      d2Exe = "d2",-      -- Command line arguments-      matplotlibCmdArgs = mempty,-      matlabCmdArgs = mempty,-      plotlyPythonCmdArgs = mempty,-      plotlyRCmdArgs = mempty,-      mathematicaCmdArgs = mempty,-      octaveCmdArgs = mempty,-      ggplot2CmdArgs = mempty,-      gnuplotCmdArgs = mempty,-      graphvizCmdArgs = mempty,-      bokehCmdArgs = mempty,-      plotsjlCmdArgs = mempty,-      plantumlCmdArgs = "-jar plantuml.jar",-      sagemathCmdArgs = mempty,-      d2CmdArgs = mempty,-      -- Extras-      matplotlibTightBBox = False,-      matplotlibTransparent = False-    }-  where-    python = if isWindows then "python" else "python3"---- | Extact path to configuration from the metadata in a Pandoc document.--- The path to the configuration file should be under the @plot-configuration@ key.--- In case there is no such metadata, return the default configuration.------ For example, at the top of a markdown file:------ @--- ------ title: My document--- author: John Doe--- plot-configuration: /path/to/file.yml--- ------ @------ The same can be specified via the command line using Pandoc's @-M@ flag:------ > pandoc --filter pandoc-plot -M plot-configuration="path/to/file.yml" ...------ @since 0.6.0.0-configurationPathMeta :: Pandoc -> Maybe FilePath-configurationPathMeta (Pandoc meta _) =-  lookupMeta "plot-configuration" meta >>= getPath-  where-    getPath (MetaString t) = Just (unpack t)-    getPath (MetaInlines [Str s]) = Just (unpack s)-    getPath _ = Nothing---- We define a precursor type because preambles are best specified as file paths,--- but we want to read those files before building a full--- @Configuration@ value.-data ConfigPrecursor = ConfigPrecursor-  { _defaultDirectory :: !FilePath,-    _defaultWithSource :: !Bool,-    _defaultDPI :: !Int,-    _defaultSaveFormat :: !SaveFormat,-    _defaultDependencies :: ![FilePath],-    _captionFormat :: !Format,-    _sourceCodeLabel :: !Text,-    _strictMode :: !Bool,-    _logPrec :: !LoggingPrecursor,-    _matplotlibPrec :: !MatplotlibPrecursor,-    _matlabPrec :: !MatlabPrecursor,-    _plotlyPythonPrec :: !PlotlyPythonPrecursor,-    _plotlyRPrec :: !PlotlyRPrecursor,-    _mathematicaPrec :: !MathematicaPrecursor,-    _octavePrec :: !OctavePrecursor,-    _ggplot2Prec :: !GGPlot2Precursor,-    _gnuplotPrec :: !GNUPlotPrecursor,-    _graphvizPrec :: !GraphvizPrecursor,-    _bokehPrec :: !BokehPrecursor,-    _plotsjlPrec :: !PlotsjlPrecursor,-    _plantumlPrec :: !PlantUMLPrecursor,-    _sagemathPrec :: !SageMathPrecursor,-    _d2Prec :: !D2Precursor-  }--defaultConfigPrecursor :: ConfigPrecursor-defaultConfigPrecursor =-  ConfigPrecursor-    { _defaultDirectory = defaultDirectory defaultConfiguration,-      _defaultWithSource = defaultWithSource defaultConfiguration,-      _defaultDPI = defaultDPI defaultConfiguration,-      _defaultSaveFormat = defaultSaveFormat defaultConfiguration,-      _defaultDependencies = defaultDependencies defaultConfiguration,-      _captionFormat = captionFormat defaultConfiguration,-      _sourceCodeLabel = sourceCodeLabel defaultConfiguration,-      _strictMode = strictMode defaultConfiguration,-      _logPrec = LoggingPrecursor (logVerbosity defaultConfiguration) Nothing, -- _logFilePath=Nothing implies log to stderr-      _matplotlibPrec = MatplotlibPrecursor Nothing (matplotlibTightBBox defaultConfiguration) (matplotlibTransparent defaultConfiguration) (matplotlibExe defaultConfiguration) (matplotlibCmdArgs defaultConfiguration),-      _matlabPrec = MatlabPrecursor Nothing (matlabExe defaultConfiguration) (matlabCmdArgs defaultConfiguration),-      _plotlyPythonPrec = PlotlyPythonPrecursor Nothing (plotlyPythonExe defaultConfiguration) (plotlyPythonCmdArgs defaultConfiguration),-      _plotlyRPrec = PlotlyRPrecursor Nothing (plotlyRExe defaultConfiguration) (plotlyRCmdArgs defaultConfiguration),-      _mathematicaPrec = MathematicaPrecursor Nothing (mathematicaExe defaultConfiguration) (mathematicaCmdArgs defaultConfiguration),-      _octavePrec = OctavePrecursor Nothing (octaveExe defaultConfiguration) (octaveCmdArgs defaultConfiguration),-      _ggplot2Prec = GGPlot2Precursor Nothing (ggplot2Exe defaultConfiguration) (ggplot2CmdArgs defaultConfiguration),-      _gnuplotPrec = GNUPlotPrecursor Nothing (gnuplotExe defaultConfiguration) (gnuplotCmdArgs defaultConfiguration),-      _graphvizPrec = GraphvizPrecursor Nothing (graphvizExe defaultConfiguration) (graphvizCmdArgs defaultConfiguration),-      _bokehPrec = BokehPrecursor Nothing (bokehExe defaultConfiguration) (bokehCmdArgs defaultConfiguration),-      _plotsjlPrec = PlotsjlPrecursor Nothing (plotsjlExe defaultConfiguration) (plotsjlCmdArgs defaultConfiguration),-      _plantumlPrec = PlantUMLPrecursor Nothing (plantumlExe defaultConfiguration) (plantumlCmdArgs defaultConfiguration),-      _sagemathPrec = SageMathPrecursor Nothing (sagemathExe defaultConfiguration) (sagemathCmdArgs defaultConfiguration),-      _d2Prec = D2Precursor Nothing (d2Exe defaultConfiguration) (d2CmdArgs defaultConfiguration)-    }--data LoggingPrecursor = LoggingPrecursor-  { _logVerbosity :: !Verbosity,-    _logFilePath :: !(Maybe FilePath)-  }---- Separate YAML clauses have their own types.-data MatplotlibPrecursor = MatplotlibPrecursor-  { _matplotlibPreamble :: !(Maybe FilePath),-    _matplotlibTightBBox :: !Bool,-    _matplotlibTransparent :: !Bool,-    _matplotlibExe :: !FilePath,-    _matplotlibCmdArgs :: !Text-  }--data MatlabPrecursor = MatlabPrecursor {_matlabPreamble :: !(Maybe FilePath), _matlabExe :: !FilePath, _matlabCmdArgs :: !Text}--data PlotlyPythonPrecursor = PlotlyPythonPrecursor {_plotlyPythonPreamble :: !(Maybe FilePath), _plotlyPythonExe :: !FilePath, _plotlyPythonCmdArgs :: !Text}--data PlotlyRPrecursor = PlotlyRPrecursor {_plotlyRPreamble :: !(Maybe FilePath), _plotlyRExe :: !FilePath, _plotlyRCmdArgs :: !Text}--data MathematicaPrecursor = MathematicaPrecursor {_mathematicaPreamble :: !(Maybe FilePath), _mathematicaExe :: !FilePath, _mathematicaCmdArgs :: !Text}--data OctavePrecursor = OctavePrecursor {_octavePreamble :: !(Maybe FilePath), _octaveExe :: !FilePath, _octaveCmdArgs :: !Text}--data GGPlot2Precursor = GGPlot2Precursor {_ggplot2Preamble :: !(Maybe FilePath), _ggplot2Exe :: !FilePath, _ggplot2CmdArgs :: !Text}--data GNUPlotPrecursor = GNUPlotPrecursor {_gnuplotPreamble :: !(Maybe FilePath), _gnuplotExe :: !FilePath, _gnuplotCmdArgs :: !Text}--data GraphvizPrecursor = GraphvizPrecursor {_graphvizPreamble :: !(Maybe FilePath), _graphvizExe :: !FilePath, _graphvizCmdArgs :: !Text}--data BokehPrecursor = BokehPrecursor {_bokehPreamble :: !(Maybe FilePath), _bokehExe :: !FilePath, _bokehCmdArgs :: !Text}--data PlotsjlPrecursor = PlotsjlPrecursor {_plotsjlPreamble :: !(Maybe FilePath), _plotsjlExe :: !FilePath, _plotsjlCmdArgs :: !Text}--data PlantUMLPrecursor = PlantUMLPrecursor {_plantumlPreamble :: !(Maybe FilePath), _plantumlExe :: !FilePath, _plantumlCmdArgs :: !Text}--data SageMathPrecursor = SageMathPrecursor {_sagemathPreamble :: !(Maybe FilePath), _sagemathExe :: !FilePath, _sagemathCmdArgs :: !Text}--data D2Precursor = D2Precursor {_d2Preamble :: !(Maybe FilePath), _d2Exe :: !FilePath, _d2CmdArgs :: !Text}--instance FromJSON LoggingPrecursor where-  parseJSON (Object v) =-    LoggingPrecursor-      <$> v .:? "verbosity" .!= logVerbosity defaultConfiguration-      <*> v .:? "filepath"-  parseJSON _ = fail $ mconcat ["Could not parse logging configuration. "]--asKey :: InclusionKey -> Key-asKey = fromString . show--instance FromJSON MatplotlibPrecursor where-  parseJSON (Object v) =-    MatplotlibPrecursor-      <$> v .:? asKey PreambleK-      <*> v .:? asKey MatplotlibTightBBoxK .!= matplotlibTightBBox defaultConfiguration-      <*> v .:? asKey MatplotlibTransparentK .!= matplotlibTransparent defaultConfiguration-      <*> v .:? asKey ExecutableK .!= matplotlibExe defaultConfiguration-      <*> v .:? asKey CommandLineArgsK .!= matplotlibCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show Matplotlib, " configuration."]--instance FromJSON MatlabPrecursor where-  parseJSON (Object v) = MatlabPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= matlabExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= matlabCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show Matlab, " configuration."]--instance FromJSON PlotlyPythonPrecursor where-  parseJSON (Object v) = PlotlyPythonPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plotlyPythonExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plotlyPythonCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show PlotlyPython, " configuration."]--instance FromJSON PlotlyRPrecursor where-  parseJSON (Object v) = PlotlyRPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plotlyRExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plotlyRCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show PlotlyR, " configuration."]--instance FromJSON MathematicaPrecursor where-  parseJSON (Object v) = MathematicaPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= mathematicaExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= mathematicaCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show Mathematica, " configuration."]--instance FromJSON OctavePrecursor where-  parseJSON (Object v) = OctavePrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= octaveExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= octaveCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show Octave, " configuration."]--instance FromJSON GGPlot2Precursor where-  parseJSON (Object v) = GGPlot2Precursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= ggplot2Exe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= ggplot2CmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show GGPlot2, " configuration."]--instance FromJSON GNUPlotPrecursor where-  parseJSON (Object v) = GNUPlotPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= gnuplotExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= gnuplotCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show GNUPlot, " configuration."]--instance FromJSON GraphvizPrecursor where-  parseJSON (Object v) = GraphvizPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= graphvizExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= graphvizCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show Graphviz, " configuration."]--instance FromJSON BokehPrecursor where-  parseJSON (Object v) = BokehPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= bokehExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= bokehCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show Bokeh, " configuration."]--instance FromJSON PlotsjlPrecursor where-  parseJSON (Object v) = PlotsjlPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plotsjlExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plotsjlCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show Plotsjl, " configuration."]--instance FromJSON PlantUMLPrecursor where-  parseJSON (Object v) = PlantUMLPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plantumlExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plantumlCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show PlantUML, " configuration."]--instance FromJSON SageMathPrecursor where-  parseJSON (Object v) = SageMathPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= sagemathExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= sagemathCmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show SageMath, " configuration."]--instance FromJSON D2Precursor where-  parseJSON (Object v) = D2Precursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= d2Exe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= d2CmdArgs defaultConfiguration-  parseJSON _ = fail $ mconcat ["Could not parse ", show SageMath, " configuration."]--toolkitAsKey :: Toolkit -> Key-toolkitAsKey = fromString . unpack . cls--instance FromJSON ConfigPrecursor where-  parseJSON Null = return defaultConfigPrecursor -- In case of empty file-  parseJSON (Object v) = do-    _defaultDirectory <- v .:? asKey DirectoryK .!= _defaultDirectory defaultConfigPrecursor-    _defaultWithSource <- v .:? asKey WithSourceK .!= _defaultWithSource defaultConfigPrecursor-    _defaultDPI <- v .:? asKey DpiK .!= _defaultDPI defaultConfigPrecursor-    _defaultSaveFormat <- v .:? asKey SaveFormatK .!= _defaultSaveFormat defaultConfigPrecursor-    _defaultDependencies <- v .:? asKey DependenciesK .!= _defaultDependencies defaultConfigPrecursor-    _captionFormat <- v .:? asKey CaptionFormatK .!= _captionFormat defaultConfigPrecursor-    _sourceCodeLabel <- v .:? asKey SourceCodeLabelK .!= _sourceCodeLabel defaultConfigPrecursor-    _strictMode <- v .:? asKey StrictModeK .!= _strictMode defaultConfigPrecursor-    _logPrec <- v .:? "logging" .!= _logPrec defaultConfigPrecursor--    _matplotlibPrec <- v .:? toolkitAsKey Matplotlib .!= _matplotlibPrec defaultConfigPrecursor-    _matlabPrec <- v .:? toolkitAsKey Matlab .!= _matlabPrec defaultConfigPrecursor-    _plotlyPythonPrec <- v .:? toolkitAsKey PlotlyPython .!= _plotlyPythonPrec defaultConfigPrecursor-    _plotlyRPrec <- v .:? toolkitAsKey PlotlyR .!= _plotlyRPrec defaultConfigPrecursor-    _mathematicaPrec <- v .:? toolkitAsKey Mathematica .!= _mathematicaPrec defaultConfigPrecursor-    _octavePrec <- v .:? toolkitAsKey Octave .!= _octavePrec defaultConfigPrecursor-    _ggplot2Prec <- v .:? toolkitAsKey GGPlot2 .!= _ggplot2Prec defaultConfigPrecursor-    _gnuplotPrec <- v .:? toolkitAsKey GNUPlot .!= _gnuplotPrec defaultConfigPrecursor-    _graphvizPrec <- v .:? toolkitAsKey Graphviz .!= _graphvizPrec defaultConfigPrecursor-    _bokehPrec <- v .:? toolkitAsKey Bokeh .!= _bokehPrec defaultConfigPrecursor-    _plotsjlPrec <- v .:? toolkitAsKey Plotsjl .!= _plotsjlPrec defaultConfigPrecursor-    _plantumlPrec <- v .:? toolkitAsKey PlantUML .!= _plantumlPrec defaultConfigPrecursor-    _sagemathPrec <- v .:? toolkitAsKey SageMath .!= _sagemathPrec defaultConfigPrecursor-    _d2Prec <- v .:? toolkitAsKey D2 .!= _d2Prec defaultConfigPrecursor--    return $ ConfigPrecursor {..}-  parseJSON _ = fail "Could not parse configuration."--renderConfig :: ConfigPrecursor -> IO Configuration-renderConfig ConfigPrecursor {..} = do-  let defaultDirectory = _defaultDirectory-      defaultWithSource = _defaultWithSource-      defaultDPI = _defaultDPI-      defaultSaveFormat = _defaultSaveFormat-      defaultDependencies = _defaultDependencies-      captionFormat = _captionFormat-      sourceCodeLabel = _sourceCodeLabel-      strictMode = _strictMode--      logVerbosity = _logVerbosity _logPrec-      logSink = maybe StdErr LogFile (_logFilePath _logPrec)--      matplotlibTightBBox = _matplotlibTightBBox _matplotlibPrec-      matplotlibTransparent = _matplotlibTransparent _matplotlibPrec--      matplotlibExe = _matplotlibExe _matplotlibPrec-      matlabExe = _matlabExe _matlabPrec-      plotlyPythonExe = _plotlyPythonExe _plotlyPythonPrec-      plotlyRExe = _plotlyRExe _plotlyRPrec-      mathematicaExe = _mathematicaExe _mathematicaPrec-      octaveExe = _octaveExe _octavePrec-      ggplot2Exe = _ggplot2Exe _ggplot2Prec-      gnuplotExe = _gnuplotExe _gnuplotPrec-      graphvizExe = _graphvizExe _graphvizPrec-      bokehExe = _bokehExe _bokehPrec-      plotsjlExe = _plotsjlExe _plotsjlPrec-      plantumlExe = _plantumlExe _plantumlPrec-      sagemathExe = _sagemathExe _sagemathPrec-      d2Exe = _d2Exe _d2Prec--      matplotlibCmdArgs = _matplotlibCmdArgs _matplotlibPrec-      matlabCmdArgs = _matlabCmdArgs _matlabPrec-      plotlyPythonCmdArgs = _plotlyPythonCmdArgs _plotlyPythonPrec-      plotlyRCmdArgs = _plotlyRCmdArgs _plotlyRPrec-      mathematicaCmdArgs = _mathematicaCmdArgs _mathematicaPrec-      octaveCmdArgs = _octaveCmdArgs _octavePrec-      ggplot2CmdArgs = _ggplot2CmdArgs _ggplot2Prec-      gnuplotCmdArgs = _gnuplotCmdArgs _gnuplotPrec-      graphvizCmdArgs = _graphvizCmdArgs _graphvizPrec-      bokehCmdArgs = _bokehCmdArgs _bokehPrec-      plotsjlCmdArgs = _plotsjlCmdArgs _plotsjlPrec-      plantumlCmdArgs = _plantumlCmdArgs _plantumlPrec-      sagemathCmdArgs = _sagemathCmdArgs _sagemathPrec-      d2CmdArgs = _d2CmdArgs _d2Prec--  matplotlibPreamble <- readPreamble (_matplotlibPreamble _matplotlibPrec)-  matlabPreamble <- readPreamble (_matlabPreamble _matlabPrec)-  plotlyPythonPreamble <- readPreamble (_plotlyPythonPreamble _plotlyPythonPrec)-  plotlyRPreamble <- readPreamble (_plotlyRPreamble _plotlyRPrec)-  mathematicaPreamble <- readPreamble (_mathematicaPreamble _mathematicaPrec)-  octavePreamble <- readPreamble (_octavePreamble _octavePrec)-  ggplot2Preamble <- readPreamble (_ggplot2Preamble _ggplot2Prec)-  gnuplotPreamble <- readPreamble (_gnuplotPreamble _gnuplotPrec)-  graphvizPreamble <- readPreamble (_graphvizPreamble _graphvizPrec)-  bokehPreamble <- readPreamble (_bokehPreamble _bokehPrec)-  plotsjlPreamble <- readPreamble (_plotsjlPreamble _plotsjlPrec)-  plantumlPreamble <- readPreamble (_plantumlPreamble _plantumlPrec)-  sagemathPreamble <- readPreamble (_sagemathPreamble _sagemathPrec)-  d2Preamble <- readPreamble (_d2Preamble _d2Prec)--  return Configuration {..}-  where-    readPreamble = maybe mempty TIO.readFile+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Reading configuration from file
+module Text.Pandoc.Filter.Plot.Configuration
+  ( configuration,
+    configurationPathMeta,
+    defaultConfiguration,
+  )
+where
+
+import Data.Aeson (FromJSON (parseJSON), Key, Value (Null, Object), (.!=), (.:?))
+import Data.String (IsString (..))
+import Data.Text (Text, unpack)
+import qualified Data.Text.IO as TIO
+import Data.Yaml.Config (ignoreEnv, loadYamlSettings)
+import System.FilePath (normalise)
+import Text.Pandoc.Definition (Format (..), Inline (..), MetaValue (..), Pandoc (..), lookupMeta)
+import Text.Pandoc.Filter.Plot.Monad
+
+-- | Read configuration from a YAML file. The
+-- keys are exactly the same as for code blocks.
+--
+-- If a key is not present, its value will be set
+-- to the default value. Parsing errors result in thrown exceptions.
+configuration :: FilePath -> IO Configuration
+configuration fp = loadYamlSettings [normalise fp] [] ignoreEnv >>= renderConfig
+
+-- | Default configuration values.
+--
+-- @since 0.5.0.0
+defaultConfiguration :: Configuration
+defaultConfiguration =
+  Configuration
+    { defaultDirectory = "plots/",
+      defaultWithSource = False,
+      defaultDPI = 80,
+      defaultSaveFormat = PNG,
+      defaultDependencies = mempty,
+      captionFormat = Format "markdown+tex_math_dollars",
+      sourceCodeLabel = "Source code",
+      strictMode = False,
+      logVerbosity = Warning,
+      logSink = StdErr,
+      -- Preambles
+      matplotlibPreamble = mempty,
+      plotlyPythonPreamble = mempty,
+      plotlyRPreamble = mempty,
+      matlabPreamble = mempty,
+      mathematicaPreamble = mempty,
+      octavePreamble = mempty,
+      ggplot2Preamble = mempty,
+      gnuplotPreamble = mempty,
+      graphvizPreamble = mempty,
+      bokehPreamble = mempty,
+      plotsjlPreamble = mempty,
+      plantumlPreamble = mempty,
+      sagemathPreamble = mempty,
+      d2Preamble = mempty,
+      asyPreamble = mempty,
+      -- Executables
+      matplotlibExe = python,
+      matlabExe = "matlab",
+      plotlyPythonExe = python,
+      plotlyRExe = "Rscript",
+      mathematicaExe = "math",
+      octaveExe = "octave",
+      ggplot2Exe = "Rscript",
+      gnuplotExe = "gnuplot",
+      graphvizExe = "dot",
+      bokehExe = python,
+      plotsjlExe = "julia",
+      plantumlExe = "java",
+      sagemathExe = "sage",
+      d2Exe = "d2",
+      asyExe = "asy",
+      -- Command line arguments
+      matplotlibCmdArgs = mempty,
+      matlabCmdArgs = mempty,
+      plotlyPythonCmdArgs = mempty,
+      plotlyRCmdArgs = mempty,
+      mathematicaCmdArgs = mempty,
+      octaveCmdArgs = mempty,
+      ggplot2CmdArgs = mempty,
+      gnuplotCmdArgs = mempty,
+      graphvizCmdArgs = mempty,
+      bokehCmdArgs = mempty,
+      plotsjlCmdArgs = mempty,
+      plantumlCmdArgs = "-jar plantuml.jar",
+      sagemathCmdArgs = mempty,
+      d2CmdArgs = mempty,
+      asyCmdArgs = mempty,
+      -- Extras
+      matplotlibTightBBox = False,
+      matplotlibTransparent = False
+    }
+  where
+    python = if isWindows then "python" else "python3"
+
+-- | Extact path to configuration from the metadata in a Pandoc document.
+-- The path to the configuration file should be under the @plot-configuration@ key.
+-- In case there is no such metadata, return the default configuration.
+--
+-- For example, at the top of a markdown file:
+--
+-- @
+-- ---
+-- title: My document
+-- author: John Doe
+-- plot-configuration: /path/to/file.yml
+-- ---
+-- @
+--
+-- The same can be specified via the command line using Pandoc's @-M@ flag:
+--
+-- > pandoc --filter pandoc-plot -M plot-configuration="path/to/file.yml" ...
+--
+-- @since 0.6.0.0
+configurationPathMeta :: Pandoc -> Maybe FilePath
+configurationPathMeta (Pandoc meta _) =
+  lookupMeta "plot-configuration" meta >>= getPath
+  where
+    getPath (MetaString t) = Just (unpack t)
+    getPath (MetaInlines [Str s]) = Just (unpack s)
+    getPath _ = Nothing
+
+-- We define a precursor type because preambles are best specified as file paths,
+-- but we want to read those files before building a full
+-- @Configuration@ value.
+data ConfigPrecursor = ConfigPrecursor
+  { _defaultDirectory :: !FilePath,
+    _defaultWithSource :: !Bool,
+    _defaultDPI :: !Int,
+    _defaultSaveFormat :: !SaveFormat,
+    _defaultDependencies :: ![FilePath],
+    _captionFormat :: !Format,
+    _sourceCodeLabel :: !Text,
+    _strictMode :: !Bool,
+    _logPrec :: !LoggingPrecursor,
+    _matplotlibPrec :: !MatplotlibPrecursor,
+    _matlabPrec :: !MatlabPrecursor,
+    _plotlyPythonPrec :: !PlotlyPythonPrecursor,
+    _plotlyRPrec :: !PlotlyRPrecursor,
+    _mathematicaPrec :: !MathematicaPrecursor,
+    _octavePrec :: !OctavePrecursor,
+    _ggplot2Prec :: !GGPlot2Precursor,
+    _gnuplotPrec :: !GNUPlotPrecursor,
+    _graphvizPrec :: !GraphvizPrecursor,
+    _bokehPrec :: !BokehPrecursor,
+    _plotsjlPrec :: !PlotsjlPrecursor,
+    _plantumlPrec :: !PlantUMLPrecursor,
+    _sagemathPrec :: !SageMathPrecursor,
+    _d2Prec :: !D2Precursor,
+    _asyPrec :: !AsyPrecursor
+  }
+
+defaultConfigPrecursor :: ConfigPrecursor
+defaultConfigPrecursor =
+  ConfigPrecursor
+    { _defaultDirectory = defaultDirectory defaultConfiguration,
+      _defaultWithSource = defaultWithSource defaultConfiguration,
+      _defaultDPI = defaultDPI defaultConfiguration,
+      _defaultSaveFormat = defaultSaveFormat defaultConfiguration,
+      _defaultDependencies = defaultDependencies defaultConfiguration,
+      _captionFormat = captionFormat defaultConfiguration,
+      _sourceCodeLabel = sourceCodeLabel defaultConfiguration,
+      _strictMode = strictMode defaultConfiguration,
+      _logPrec = LoggingPrecursor (logVerbosity defaultConfiguration) Nothing, -- _logFilePath=Nothing implies log to stderr
+      _matplotlibPrec = MatplotlibPrecursor Nothing (matplotlibTightBBox defaultConfiguration) (matplotlibTransparent defaultConfiguration) (matplotlibExe defaultConfiguration) (matplotlibCmdArgs defaultConfiguration),
+      _matlabPrec = MatlabPrecursor Nothing (matlabExe defaultConfiguration) (matlabCmdArgs defaultConfiguration),
+      _plotlyPythonPrec = PlotlyPythonPrecursor Nothing (plotlyPythonExe defaultConfiguration) (plotlyPythonCmdArgs defaultConfiguration),
+      _plotlyRPrec = PlotlyRPrecursor Nothing (plotlyRExe defaultConfiguration) (plotlyRCmdArgs defaultConfiguration),
+      _mathematicaPrec = MathematicaPrecursor Nothing (mathematicaExe defaultConfiguration) (mathematicaCmdArgs defaultConfiguration),
+      _octavePrec = OctavePrecursor Nothing (octaveExe defaultConfiguration) (octaveCmdArgs defaultConfiguration),
+      _ggplot2Prec = GGPlot2Precursor Nothing (ggplot2Exe defaultConfiguration) (ggplot2CmdArgs defaultConfiguration),
+      _gnuplotPrec = GNUPlotPrecursor Nothing (gnuplotExe defaultConfiguration) (gnuplotCmdArgs defaultConfiguration),
+      _graphvizPrec = GraphvizPrecursor Nothing (graphvizExe defaultConfiguration) (graphvizCmdArgs defaultConfiguration),
+      _bokehPrec = BokehPrecursor Nothing (bokehExe defaultConfiguration) (bokehCmdArgs defaultConfiguration),
+      _plotsjlPrec = PlotsjlPrecursor Nothing (plotsjlExe defaultConfiguration) (plotsjlCmdArgs defaultConfiguration),
+      _plantumlPrec = PlantUMLPrecursor Nothing (plantumlExe defaultConfiguration) (plantumlCmdArgs defaultConfiguration),
+      _sagemathPrec = SageMathPrecursor Nothing (sagemathExe defaultConfiguration) (sagemathCmdArgs defaultConfiguration),
+      _d2Prec = D2Precursor Nothing (d2Exe defaultConfiguration) (d2CmdArgs defaultConfiguration),
+      _asyPrec = AsyPrecursor Nothing (asyExe defaultConfiguration) (asyCmdArgs defaultConfiguration)
+    }
+
+data LoggingPrecursor = LoggingPrecursor
+  { _logVerbosity :: !Verbosity,
+    _logFilePath :: !(Maybe FilePath)
+  }
+
+-- Separate YAML clauses have their own types.
+data MatplotlibPrecursor = MatplotlibPrecursor
+  { _matplotlibPreamble :: !(Maybe FilePath),
+    _matplotlibTightBBox :: !Bool,
+    _matplotlibTransparent :: !Bool,
+    _matplotlibExe :: !FilePath,
+    _matplotlibCmdArgs :: !Text
+  }
+
+data MatlabPrecursor = MatlabPrecursor {_matlabPreamble :: !(Maybe FilePath), _matlabExe :: !FilePath, _matlabCmdArgs :: !Text}
+
+data PlotlyPythonPrecursor = PlotlyPythonPrecursor {_plotlyPythonPreamble :: !(Maybe FilePath), _plotlyPythonExe :: !FilePath, _plotlyPythonCmdArgs :: !Text}
+
+data PlotlyRPrecursor = PlotlyRPrecursor {_plotlyRPreamble :: !(Maybe FilePath), _plotlyRExe :: !FilePath, _plotlyRCmdArgs :: !Text}
+
+data MathematicaPrecursor = MathematicaPrecursor {_mathematicaPreamble :: !(Maybe FilePath), _mathematicaExe :: !FilePath, _mathematicaCmdArgs :: !Text}
+
+data OctavePrecursor = OctavePrecursor {_octavePreamble :: !(Maybe FilePath), _octaveExe :: !FilePath, _octaveCmdArgs :: !Text}
+
+data GGPlot2Precursor = GGPlot2Precursor {_ggplot2Preamble :: !(Maybe FilePath), _ggplot2Exe :: !FilePath, _ggplot2CmdArgs :: !Text}
+
+data GNUPlotPrecursor = GNUPlotPrecursor {_gnuplotPreamble :: !(Maybe FilePath), _gnuplotExe :: !FilePath, _gnuplotCmdArgs :: !Text}
+
+data GraphvizPrecursor = GraphvizPrecursor {_graphvizPreamble :: !(Maybe FilePath), _graphvizExe :: !FilePath, _graphvizCmdArgs :: !Text}
+
+data BokehPrecursor = BokehPrecursor {_bokehPreamble :: !(Maybe FilePath), _bokehExe :: !FilePath, _bokehCmdArgs :: !Text}
+
+data PlotsjlPrecursor = PlotsjlPrecursor {_plotsjlPreamble :: !(Maybe FilePath), _plotsjlExe :: !FilePath, _plotsjlCmdArgs :: !Text}
+
+data PlantUMLPrecursor = PlantUMLPrecursor {_plantumlPreamble :: !(Maybe FilePath), _plantumlExe :: !FilePath, _plantumlCmdArgs :: !Text}
+
+data SageMathPrecursor = SageMathPrecursor {_sagemathPreamble :: !(Maybe FilePath), _sagemathExe :: !FilePath, _sagemathCmdArgs :: !Text}
+
+data D2Precursor = D2Precursor {_d2Preamble :: !(Maybe FilePath), _d2Exe :: !FilePath, _d2CmdArgs :: !Text}
+
+data AsyPrecursor = AsyPrecursor {_asyPreamble :: !(Maybe FilePath), _asyExe :: !FilePath, _asyCmdArgs :: !Text}
+
+instance FromJSON LoggingPrecursor where
+  parseJSON (Object v) =
+    LoggingPrecursor
+      <$> v .:? "verbosity" .!= logVerbosity defaultConfiguration
+      <*> v .:? "filepath"
+  parseJSON _ = fail $ mconcat ["Could not parse logging configuration. "]
+
+asKey :: InclusionKey -> Key
+asKey = fromString . show
+
+instance FromJSON MatplotlibPrecursor where
+  parseJSON (Object v) =
+    MatplotlibPrecursor
+      <$> v .:? asKey PreambleK
+      <*> v .:? asKey MatplotlibTightBBoxK .!= matplotlibTightBBox defaultConfiguration
+      <*> v .:? asKey MatplotlibTransparentK .!= matplotlibTransparent defaultConfiguration
+      <*> v .:? asKey ExecutableK .!= matplotlibExe defaultConfiguration
+      <*> v .:? asKey CommandLineArgsK .!= matplotlibCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Matplotlib, " configuration."]
+
+instance FromJSON MatlabPrecursor where
+  parseJSON (Object v) = MatlabPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= matlabExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= matlabCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Matlab, " configuration."]
+
+instance FromJSON PlotlyPythonPrecursor where
+  parseJSON (Object v) = PlotlyPythonPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plotlyPythonExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plotlyPythonCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show PlotlyPython, " configuration."]
+
+instance FromJSON PlotlyRPrecursor where
+  parseJSON (Object v) = PlotlyRPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plotlyRExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plotlyRCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show PlotlyR, " configuration."]
+
+instance FromJSON MathematicaPrecursor where
+  parseJSON (Object v) = MathematicaPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= mathematicaExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= mathematicaCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Mathematica, " configuration."]
+
+instance FromJSON OctavePrecursor where
+  parseJSON (Object v) = OctavePrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= octaveExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= octaveCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Octave, " configuration."]
+
+instance FromJSON GGPlot2Precursor where
+  parseJSON (Object v) = GGPlot2Precursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= ggplot2Exe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= ggplot2CmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show GGPlot2, " configuration."]
+
+instance FromJSON GNUPlotPrecursor where
+  parseJSON (Object v) = GNUPlotPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= gnuplotExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= gnuplotCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show GNUPlot, " configuration."]
+
+instance FromJSON GraphvizPrecursor where
+  parseJSON (Object v) = GraphvizPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= graphvizExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= graphvizCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Graphviz, " configuration."]
+
+instance FromJSON BokehPrecursor where
+  parseJSON (Object v) = BokehPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= bokehExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= bokehCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Bokeh, " configuration."]
+
+instance FromJSON PlotsjlPrecursor where
+  parseJSON (Object v) = PlotsjlPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plotsjlExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plotsjlCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Plotsjl, " configuration."]
+
+instance FromJSON PlantUMLPrecursor where
+  parseJSON (Object v) = PlantUMLPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plantumlExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plantumlCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show PlantUML, " configuration."]
+
+instance FromJSON SageMathPrecursor where
+  parseJSON (Object v) = SageMathPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= sagemathExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= sagemathCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show SageMath, " configuration."]
+
+instance FromJSON D2Precursor where
+  parseJSON (Object v) = D2Precursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= d2Exe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= d2CmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show SageMath, " configuration."]
+
+instance FromJSON AsyPrecursor where
+  parseJSON (Object v) = AsyPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= asyExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= asyCmdArgs defaultConfiguration
+  parseJSON _ = fail $ mconcat ["Could not parse ", show Asymptote, " configuration."]
+
+toolkitAsKey :: Toolkit -> Key
+toolkitAsKey = fromString . unpack . cls
+
+instance FromJSON ConfigPrecursor where
+  parseJSON Null = return defaultConfigPrecursor -- In case of empty file
+  parseJSON (Object v) = do
+    _defaultDirectory <- v .:? asKey DirectoryK .!= _defaultDirectory defaultConfigPrecursor
+    _defaultWithSource <- v .:? asKey WithSourceK .!= _defaultWithSource defaultConfigPrecursor
+    _defaultDPI <- v .:? asKey DpiK .!= _defaultDPI defaultConfigPrecursor
+    _defaultSaveFormat <- v .:? asKey SaveFormatK .!= _defaultSaveFormat defaultConfigPrecursor
+    _defaultDependencies <- v .:? asKey DependenciesK .!= _defaultDependencies defaultConfigPrecursor
+    _captionFormat <- v .:? asKey CaptionFormatK .!= _captionFormat defaultConfigPrecursor
+    _sourceCodeLabel <- v .:? asKey SourceCodeLabelK .!= _sourceCodeLabel defaultConfigPrecursor
+    _strictMode <- v .:? asKey StrictModeK .!= _strictMode defaultConfigPrecursor
+    _logPrec <- v .:? "logging" .!= _logPrec defaultConfigPrecursor
+
+    _matplotlibPrec <- v .:? toolkitAsKey Matplotlib .!= _matplotlibPrec defaultConfigPrecursor
+    _matlabPrec <- v .:? toolkitAsKey Matlab .!= _matlabPrec defaultConfigPrecursor
+    _plotlyPythonPrec <- v .:? toolkitAsKey PlotlyPython .!= _plotlyPythonPrec defaultConfigPrecursor
+    _plotlyRPrec <- v .:? toolkitAsKey PlotlyR .!= _plotlyRPrec defaultConfigPrecursor
+    _mathematicaPrec <- v .:? toolkitAsKey Mathematica .!= _mathematicaPrec defaultConfigPrecursor
+    _octavePrec <- v .:? toolkitAsKey Octave .!= _octavePrec defaultConfigPrecursor
+    _ggplot2Prec <- v .:? toolkitAsKey GGPlot2 .!= _ggplot2Prec defaultConfigPrecursor
+    _gnuplotPrec <- v .:? toolkitAsKey GNUPlot .!= _gnuplotPrec defaultConfigPrecursor
+    _graphvizPrec <- v .:? toolkitAsKey Graphviz .!= _graphvizPrec defaultConfigPrecursor
+    _bokehPrec <- v .:? toolkitAsKey Bokeh .!= _bokehPrec defaultConfigPrecursor
+    _plotsjlPrec <- v .:? toolkitAsKey Plotsjl .!= _plotsjlPrec defaultConfigPrecursor
+    _plantumlPrec <- v .:? toolkitAsKey PlantUML .!= _plantumlPrec defaultConfigPrecursor
+    _sagemathPrec <- v .:? toolkitAsKey SageMath .!= _sagemathPrec defaultConfigPrecursor
+    _d2Prec <- v .:? toolkitAsKey D2 .!= _d2Prec defaultConfigPrecursor
+    _asyPrec <- v .:? toolkitAsKey Asymptote .!= _asyPrec defaultConfigPrecursor
+
+    return $ ConfigPrecursor {..}
+  parseJSON _ = fail "Could not parse configuration."
+
+renderConfig :: ConfigPrecursor -> IO Configuration
+renderConfig ConfigPrecursor {..} = do
+  let defaultDirectory = _defaultDirectory
+      defaultWithSource = _defaultWithSource
+      defaultDPI = _defaultDPI
+      defaultSaveFormat = _defaultSaveFormat
+      defaultDependencies = _defaultDependencies
+      captionFormat = _captionFormat
+      sourceCodeLabel = _sourceCodeLabel
+      strictMode = _strictMode
+
+      logVerbosity = _logVerbosity _logPrec
+      logSink = maybe StdErr LogFile (_logFilePath _logPrec)
+
+      matplotlibTightBBox = _matplotlibTightBBox _matplotlibPrec
+      matplotlibTransparent = _matplotlibTransparent _matplotlibPrec
+
+      matplotlibExe = _matplotlibExe _matplotlibPrec
+      matlabExe = _matlabExe _matlabPrec
+      plotlyPythonExe = _plotlyPythonExe _plotlyPythonPrec
+      plotlyRExe = _plotlyRExe _plotlyRPrec
+      mathematicaExe = _mathematicaExe _mathematicaPrec
+      octaveExe = _octaveExe _octavePrec
+      ggplot2Exe = _ggplot2Exe _ggplot2Prec
+      gnuplotExe = _gnuplotExe _gnuplotPrec
+      graphvizExe = _graphvizExe _graphvizPrec
+      bokehExe = _bokehExe _bokehPrec
+      plotsjlExe = _plotsjlExe _plotsjlPrec
+      plantumlExe = _plantumlExe _plantumlPrec
+      sagemathExe = _sagemathExe _sagemathPrec
+      d2Exe = _d2Exe _d2Prec
+      asyExe = _asyExe _asyPrec
+
+      matplotlibCmdArgs = _matplotlibCmdArgs _matplotlibPrec
+      matlabCmdArgs = _matlabCmdArgs _matlabPrec
+      plotlyPythonCmdArgs = _plotlyPythonCmdArgs _plotlyPythonPrec
+      plotlyRCmdArgs = _plotlyRCmdArgs _plotlyRPrec
+      mathematicaCmdArgs = _mathematicaCmdArgs _mathematicaPrec
+      octaveCmdArgs = _octaveCmdArgs _octavePrec
+      ggplot2CmdArgs = _ggplot2CmdArgs _ggplot2Prec
+      gnuplotCmdArgs = _gnuplotCmdArgs _gnuplotPrec
+      graphvizCmdArgs = _graphvizCmdArgs _graphvizPrec
+      bokehCmdArgs = _bokehCmdArgs _bokehPrec
+      plotsjlCmdArgs = _plotsjlCmdArgs _plotsjlPrec
+      plantumlCmdArgs = _plantumlCmdArgs _plantumlPrec
+      sagemathCmdArgs = _sagemathCmdArgs _sagemathPrec
+      d2CmdArgs = _d2CmdArgs _d2Prec
+      asyCmdArgs = _asyCmdArgs _asyPrec
+
+  matplotlibPreamble <- readPreamble (_matplotlibPreamble _matplotlibPrec)
+  matlabPreamble <- readPreamble (_matlabPreamble _matlabPrec)
+  plotlyPythonPreamble <- readPreamble (_plotlyPythonPreamble _plotlyPythonPrec)
+  plotlyRPreamble <- readPreamble (_plotlyRPreamble _plotlyRPrec)
+  mathematicaPreamble <- readPreamble (_mathematicaPreamble _mathematicaPrec)
+  octavePreamble <- readPreamble (_octavePreamble _octavePrec)
+  ggplot2Preamble <- readPreamble (_ggplot2Preamble _ggplot2Prec)
+  gnuplotPreamble <- readPreamble (_gnuplotPreamble _gnuplotPrec)
+  graphvizPreamble <- readPreamble (_graphvizPreamble _graphvizPrec)
+  bokehPreamble <- readPreamble (_bokehPreamble _bokehPrec)
+  plotsjlPreamble <- readPreamble (_plotsjlPreamble _plotsjlPrec)
+  plantumlPreamble <- readPreamble (_plantumlPreamble _plantumlPrec)
+  sagemathPreamble <- readPreamble (_sagemathPreamble _sagemathPrec)
+  d2Preamble <- readPreamble (_d2Preamble _d2Prec)
+  asyPreamble <- readPreamble (_asyPreamble _asyPrec)
+
+  return Configuration {..}
+  where
+    readPreamble = maybe mempty TIO.readFile
src/Text/Pandoc/Filter/Plot/Embed.hs view
@@ -1,190 +1,190 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Embedding HTML and LaTeX content-module Text.Pandoc.Filter.Plot.Embed-  ( extractPlot,-    toFigure,-  )-where--import Data.Default (def)-import Data.Maybe (fromMaybe)-import Data.Text (Text, pack)-import qualified Data.Text.IO as T-import Text.HTML.TagSoup-  ( Tag (TagClose, TagOpen),-    canonicalizeTags,-    parseOptionsFast,-    parseTagsOptions,-    partitions,-    renderTags,-    (~/=),-    (~==),-  )-import Text.Pandoc.Builder as Builder-  ( Inlines,-    figureWith,-    fromList,-    imageWith,-    link,-    plain,-    simpleCaption,-    str,-    toList,-  )-import Text.Pandoc.Class (runPure)-import Text.Pandoc.Definition (Attr, Block (..), Format, Pandoc (..))-import Text.Pandoc.Error (handleError)-import Text.Pandoc.Filter.Plot.Monad-import Text.Pandoc.Filter.Plot.Parse (captionReader)-import Text.Pandoc.Filter.Plot.Scripting (figurePath, sourceCodePath)-import Text.Pandoc.Writers.HTML (writeHtml5String)-import Text.Pandoc.Writers.LaTeX (writeLaTeX)-import Text.Shakespeare.Text (st)---- | Convert a @FigureSpec@ to a Pandoc figure component.--- Note that the script to generate figure files must still--- be run in another function.-toFigure ::-  -- | text format of the caption-  Format ->-  FigureSpec ->-  PlotM Block-toFigure fmt spec = do-  target <- figurePath spec-  scp <- pack <$> sourceCodePath spec-  sourceLabel <- asksConfig sourceCodeLabel -- Allow the possibility for non-english labels-  let srcLink = link scp mempty (str sourceLabel)-      attrs' = blockAttrs spec-      captionText = fromList $ fromMaybe mempty (captionReader fmt $ caption spec)-      captionLinks = mconcat [" (", srcLink, ")"]-      caption' = if withSource spec then captionText <> captionLinks else captionText-  builder attrs' target caption'-  where-    builder = case saveFormat spec of-      HTML -> interactiveBlock-      LaTeX -> latexInput-      _ -> figure--figure ::-  Attr ->-  FilePath ->-  Inlines ->-  PlotM Block-figure as fp caption' =-  return . head . toList $-    -- We want the attributes both on the Figure element and the contained Image element-    -- so that pandoc-plot plays nice with pandoc-crossref and other filters-    figureWith as (simpleCaption (plain caption')) $-      plain $-        imageWith mempty (pack fp) mempty caption'---- TODO: also add the case where SVG plots can be---       embedded in HTML output--- embeddedSVGBlock ::---   Attr ->---   FilePath ->---   Inlines ->---   PlotM Block--- embeddedSVGBlock _ fp caption' = do---   svgsource <- liftIO $ T.readFile fp---   renderedCaption <- writeHtml caption'---   return $---     RawBlock---       "html5"---       [st|--- <figure>---     <svg>---     #{svgsource}---     </svg>---     <figcaption>#{renderedCaption}</figcaption>--- </figure>---     |]--latexInput :: Attr -> FilePath -> Inlines -> PlotM Block-latexInput _ fp caption' = do-  renderedCaption' <- writeLatex caption'-  let renderedCaption =-        if renderedCaption' /= ""-          then [st|\caption{#{renderedCaption'}}|]-          else ""-  return $-    RawBlock-      "latex"-      [st|-    \begin{figure}-        \centering-        \input{#{pack $ normalizePath $ fp}}-        #{renderedCaption}-    \end{figure}-        |]-  where-    normalizePath = map f-      where-        f '\\' = '/'-        f x = x--interactiveBlock ::-  Attr ->-  FilePath ->-  Inlines ->-  PlotM Block-interactiveBlock _ fp caption' = do-  -- TODO: should we instead include the scripts in the "include-after"-  --       template variable?-  --       See https://github.com/jgm/pandoc/issues/6582-  htmlpage <- liftIO $ T.readFile fp-  renderedCaption <- writeHtml caption'-  return $-    RawBlock-      "html5"-      [st|-<figure>-    <div>-    #{extractPlot htmlpage}-    </div>-    <figcaption>#{renderedCaption}</figcaption>-</figure>-    |]---- | Convert Pandoc inlines to html-writeHtml :: Inlines -> PlotM Text-writeHtml is = liftIO $ handleError $ runPure $ writeHtml5String def document-  where-    document = Pandoc mempty [Para . toList $ is]--writeLatex :: Inlines -> PlotM Text-writeLatex is = liftIO $ handleError $ runPure $ writeLaTeX def document-  where-    document = Pandoc mempty [Para . toList $ is]---- | Extract the plot-relevant content from inside of a full HTML document.--- Scripts contained in the <head> tag are extracted, as well as the entirety of the--- <body> tag.-extractPlot :: Text -> Text-extractPlot t =-  let tags = canonicalizeTags $ parseTagsOptions parseOptionsFast t-      extracted = headScripts tags <> [inside "body" tags]-   in -- In the past (e.g. commit 8417b011ccb20263427822c7447840ab4a30a41e), we used to-      -- make all JS scripts 'deferred'. This turned out to be problematic for plotly-      -- specifically (see issue #39). In the future, we may want to defer scripts for-      -- certain toolkits, but that's a testing nightmare...-      mconcat $ renderTags <$> extracted-  where-    headScripts = partitions (~== ("<script>" :: String)) . inside "head"---- | Get content inside a tag, e.g. /inside "body"/ returns all tags--- between /<body>/ and /</body>/-inside :: Text -> [Tag Text] -> [Tag Text]-inside t = init . tail . tgs-  where-    tgs = takeWhile (~/= TagClose t) . dropWhile (~/= TagOpen t [])+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Embedding HTML and LaTeX content
+module Text.Pandoc.Filter.Plot.Embed
+  ( extractPlot,
+    toFigure,
+  )
+where
+
+import Data.Default (def)
+import Data.Maybe (fromMaybe)
+import Data.Text (Text, pack)
+import qualified Data.Text.IO as T
+import Text.HTML.TagSoup
+  ( Tag (TagClose, TagOpen),
+    canonicalizeTags,
+    parseOptionsFast,
+    parseTagsOptions,
+    partitions,
+    renderTags,
+    (~/=),
+    (~==),
+  )
+import Text.Pandoc.Builder as Builder
+  ( Inlines,
+    figureWith,
+    fromList,
+    imageWith,
+    link,
+    plain,
+    simpleCaption,
+    str,
+    toList,
+  )
+import Text.Pandoc.Class (runPure)
+import Text.Pandoc.Definition (Attr, Block (..), Format, Pandoc (..))
+import Text.Pandoc.Error (handleError)
+import Text.Pandoc.Filter.Plot.Monad
+import Text.Pandoc.Filter.Plot.Parse (captionReader)
+import Text.Pandoc.Filter.Plot.Scripting (figurePath, sourceCodePath)
+import Text.Pandoc.Writers.HTML (writeHtml5String)
+import Text.Pandoc.Writers.LaTeX (writeLaTeX)
+import Text.Shakespeare.Text (st)
+
+-- | Convert a @FigureSpec@ to a Pandoc figure component.
+-- Note that the script to generate figure files must still
+-- be run in another function.
+toFigure ::
+  -- | text format of the caption
+  Format ->
+  FigureSpec ->
+  PlotM Block
+toFigure fmt spec = do
+  target <- figurePath spec
+  scp <- pack <$> sourceCodePath spec
+  sourceLabel <- asksConfig sourceCodeLabel -- Allow the possibility for non-english labels
+  let srcLink = link scp mempty (str sourceLabel)
+      attrs' = blockAttrs spec
+      captionText = fromList $ fromMaybe mempty (captionReader fmt $ caption spec)
+      captionLinks = mconcat [" (", srcLink, ")"]
+      caption' = if withSource spec then captionText <> captionLinks else captionText
+  builder attrs' target caption'
+  where
+    builder = case saveFormat spec of
+      HTML -> interactiveBlock
+      LaTeX -> latexInput
+      _ -> figure
+
+figure ::
+  Attr ->
+  FilePath ->
+  Inlines ->
+  PlotM Block
+figure as fp caption' =
+  return . head . toList $
+    -- We want the attributes both on the Figure element and the contained Image element
+    -- so that pandoc-plot plays nice with pandoc-crossref and other filters
+    figureWith as (simpleCaption (plain caption')) $
+      plain $
+        imageWith mempty (pack fp) mempty caption'
+
+-- TODO: also add the case where SVG plots can be
+--       embedded in HTML output
+-- embeddedSVGBlock ::
+--   Attr ->
+--   FilePath ->
+--   Inlines ->
+--   PlotM Block
+-- embeddedSVGBlock _ fp caption' = do
+--   svgsource <- liftIO $ T.readFile fp
+--   renderedCaption <- writeHtml caption'
+--   return $
+--     RawBlock
+--       "html5"
+--       [st|
+-- <figure>
+--     <svg>
+--     #{svgsource}
+--     </svg>
+--     <figcaption>#{renderedCaption}</figcaption>
+-- </figure>
+--     |]
+
+latexInput :: Attr -> FilePath -> Inlines -> PlotM Block
+latexInput _ fp caption' = do
+  renderedCaption' <- writeLatex caption'
+  let renderedCaption =
+        if renderedCaption' /= ""
+          then [st|\caption{#{renderedCaption'}}|]
+          else ""
+  return $
+    RawBlock
+      "latex"
+      [st|
+    \begin{figure}
+        \centering
+        \input{#{pack $ normalizePath $ fp}}
+        #{renderedCaption}
+    \end{figure}
+        |]
+  where
+    normalizePath = map f
+      where
+        f '\\' = '/'
+        f x = x
+
+interactiveBlock ::
+  Attr ->
+  FilePath ->
+  Inlines ->
+  PlotM Block
+interactiveBlock _ fp caption' = do
+  -- TODO: should we instead include the scripts in the "include-after"
+  --       template variable?
+  --       See https://github.com/jgm/pandoc/issues/6582
+  htmlpage <- liftIO $ T.readFile fp
+  renderedCaption <- writeHtml caption'
+  return $
+    RawBlock
+      "html5"
+      [st|
+<figure>
+    <div>
+    #{extractPlot htmlpage}
+    </div>
+    <figcaption>#{renderedCaption}</figcaption>
+</figure>
+    |]
+
+-- | Convert Pandoc inlines to html
+writeHtml :: Inlines -> PlotM Text
+writeHtml is = liftIO $ handleError $ runPure $ writeHtml5String def document
+  where
+    document = Pandoc mempty [Para . toList $ is]
+
+writeLatex :: Inlines -> PlotM Text
+writeLatex is = liftIO $ handleError $ runPure $ writeLaTeX def document
+  where
+    document = Pandoc mempty [Para . toList $ is]
+
+-- | Extract the plot-relevant content from inside of a full HTML document.
+-- Scripts contained in the <head> tag are extracted, as well as the entirety of the
+-- <body> tag.
+extractPlot :: Text -> Text
+extractPlot t =
+  let tags = canonicalizeTags $ parseTagsOptions parseOptionsFast t
+      extracted = headScripts tags <> [inside "body" tags]
+   in -- In the past (e.g. commit 8417b011ccb20263427822c7447840ab4a30a41e), we used to
+      -- make all JS scripts 'deferred'. This turned out to be problematic for plotly
+      -- specifically (see issue #39). In the future, we may want to defer scripts for
+      -- certain toolkits, but that's a testing nightmare...
+      mconcat $ renderTags <$> extracted
+  where
+    headScripts = partitions (~== ("<script>" :: String)) . inside "head"
+
+-- | Get content inside a tag, e.g. /inside "body"/ returns all tags
+-- between /<body>/ and /</body>/
+inside :: Text -> [Tag Text] -> [Tag Text]
+inside t = init . tail . tgs
+  where
+    tgs = takeWhile (~/= TagClose t) . dropWhile (~/= TagOpen t [])
src/Text/Pandoc/Filter/Plot/Internal.hs view
@@ -1,28 +1,28 @@--- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ This module re-exports internal pandoc-plot functionality.--- The external use of content from this module is discouraged.-module Text.Pandoc.Filter.Plot.Internal-  ( module Text.Pandoc.Filter.Plot.Renderers,-    module Text.Pandoc.Filter.Plot.Scripting,-    module Text.Pandoc.Filter.Plot.Parse,-    module Text.Pandoc.Filter.Plot.Configuration,-    module Text.Pandoc.Filter.Plot.Clean,-    module Text.Pandoc.Filter.Plot.Monad,-    module Text.Pandoc.Filter.Plot.Embed,-  )-where--import Text.Pandoc.Filter.Plot.Clean-import Text.Pandoc.Filter.Plot.Configuration-import Text.Pandoc.Filter.Plot.Embed-import Text.Pandoc.Filter.Plot.Monad-import Text.Pandoc.Filter.Plot.Parse-import Text.Pandoc.Filter.Plot.Renderers-import Text.Pandoc.Filter.Plot.Scripting+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- This module re-exports internal pandoc-plot functionality.
+-- The external use of content from this module is discouraged.
+module Text.Pandoc.Filter.Plot.Internal
+  ( module Text.Pandoc.Filter.Plot.Renderers,
+    module Text.Pandoc.Filter.Plot.Scripting,
+    module Text.Pandoc.Filter.Plot.Parse,
+    module Text.Pandoc.Filter.Plot.Configuration,
+    module Text.Pandoc.Filter.Plot.Clean,
+    module Text.Pandoc.Filter.Plot.Monad,
+    module Text.Pandoc.Filter.Plot.Embed,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Clean
+import Text.Pandoc.Filter.Plot.Configuration
+import Text.Pandoc.Filter.Plot.Embed
+import Text.Pandoc.Filter.Plot.Monad
+import Text.Pandoc.Filter.Plot.Parse
+import Text.Pandoc.Filter.Plot.Renderers
+import Text.Pandoc.Filter.Plot.Scripting
src/Text/Pandoc/Filter/Plot/Monad.hs view
@@ -1,417 +1,424 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ This module defines the @PlotM@ monad and related capabilities.-module Text.Pandoc.Filter.Plot.Monad-  ( Configuration (..),-    PlotM,-    RuntimeEnv (..),-    PlotState (..),-    runPlotM,--    -- * Concurrent execution-    mapConcurrentlyN,--    -- * Running external commands-    runCommand,-    withPrependedPath,--    -- * Halting pandoc-plot-    throwStrictError,--    -- * Getting file hashes-    fileHash,--    -- * Getting executables-    executable,--    -- * Logging-    Verbosity (..),-    LogSink (..),-    debug,-    err,-    warning,-    info,--    -- * Lifting and other monadic operations-    liftIO,-    ask,-    asks,-    asksConfig,--    -- * Base types-    module Text.Pandoc.Filter.Plot.Monad.Types,-  )-where--import Control.Concurrent.Async.Lifted (mapConcurrently)-import Control.Concurrent.MVar (MVar, newMVar, putMVar, takeMVar)-import Control.Concurrent.QSemN-  ( QSemN,-    newQSemN,-    signalQSemN,-    waitQSemN,-  )-import Control.Exception.Lifted (bracket, bracket_)-import Control.Monad.Reader-  ( MonadIO (liftIO),-    MonadReader (ask),-    ReaderT (runReaderT),-    asks,-  )-import Control.Monad.State.Strict-  ( MonadState (get, put),-    StateT,-    evalStateT,-  )-import Data.ByteString.Lazy (toStrict)-import Data.Functor ((<&>))-import Data.Hashable (hash)-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as M-import Data.Text (Text, pack, unpack)-import qualified Data.Text as T-import Data.Text.Encoding (decodeUtf8With)-import Data.Text.Encoding.Error (lenientDecode)-import System.Directory-  ( doesFileExist,-    getCurrentDirectory,-    getModificationTime,-  )-import System.Environment (getEnv, setEnv)-import System.Exit (ExitCode (..), exitFailure)-import System.Process.Typed-  ( byteStringInput,-    byteStringOutput,-    nullStream,-    readProcessStderr,-    setStderr,-    setStdin,-    setStdout,-    setWorkingDir,-    shell,-  )-import Text.Pandoc.Definition (Format (..))-import Text.Pandoc.Filter.Plot.Monad.Logging-  ( LogSink (..),-    Logger,-    MonadLogger (..),-    Verbosity (..),-    debug,-    err,-    info,-    strict,-    terminateLogging,-    warning,-    withLogger,-  )-import Text.Pandoc.Filter.Plot.Monad.Types-import Prelude hiding (fst, log, snd)---- | pandoc-plot monad-type PlotM = StateT PlotState (ReaderT RuntimeEnv IO)--instance MonadLogger PlotM where-  askLogger = asks envLogger--data RuntimeEnv = RuntimeEnv-  { envFormat :: Maybe Format, -- pandoc output format-    envConfig :: Configuration,-    envLogger :: Logger,-    envCWD :: FilePath,-    -- The following lock prevents from writing to the same file multiple times.-    -- This is a rather crude fix for issue #53.-    envIOLock :: MVar ()-  }---- | Get access to configuration within the @PlotM@ monad.-asksConfig :: (Configuration -> a) -> PlotM a-asksConfig f = asks (f . envConfig)---- | Evaluate a @PlotM@ action.-runPlotM :: Maybe Format -> Configuration -> PlotM a -> IO a-runPlotM fmt conf v = do-  cwd <- getCurrentDirectory-  sem <- newMVar ()-  st <--    PlotState <$> newMVar mempty-  let verbosity = logVerbosity conf-      sink = logSink conf-  withLogger verbosity sink $-    \logger -> runReaderT (evalStateT v st) (RuntimeEnv fmt conf logger cwd sem)---- | maps a function, performing at most @N@ actions concurrently.-mapConcurrentlyN :: (Traversable t) => Int -> (a -> PlotM b) -> t a -> PlotM (t b)-mapConcurrentlyN n f xs = do-  -- Emulating a pool of processes with locked access-  sem <- liftIO $ newQSemN n-  mapConcurrently (with sem . f) xs-  where-    with :: QSemN -> PlotM a -> PlotM a-    with s = bracket_ (liftIO $ waitQSemN s 1) (liftIO $ signalQSemN s 1)---- | Run a command within the @PlotM@ monad. Stderr stream--- is read and decoded, while Stdout is ignored.--- Logging happens at the debug level if the command succeeds, or at--- the error level if it does not succeed.-runCommand ::-  FilePath -> -- Directory from which to run the command-  Text -> -- Command to run, including executable-  PlotM (ExitCode, Text)-runCommand wordir command = do-  (ec, processOutput') <--    liftIO $-      readProcessStderr $-        -- For Julia specifically, if the line below is not there (`setStdin (byteStringInput "")`),-        -- the following error is thrown on Windows:-        --    ERROR: error initializing stdin in uv_dup:-        --           Unknown system error 50 (Unknown system error 50 50)-        setStdin (byteStringInput "") $-          setStdout nullStream $-            setStderr byteStringOutput $-              setWorkingDir wordir $-                shell (unpack command)-  let processOutput = decodeUtf8With lenientDecode $ toStrict processOutput'-      logFunc =-        if ec == ExitSuccess-          then debug-          else err-      message =-        T.unlines-          [ "Running command",-            "    " <> command,-            "ended with exit code " <> (pack . show $ ec)-          ]-      errorMessage =-        if processOutput == mempty-          then mempty-          else-            T.unlines-              [ "*******",-                processOutput,-                "*******"-              ]--  logFunc $ message <> errorMessage-  return (ec, processOutput)---- | Prepend a directory to the PATH environment variable for the duration--- of a computation.------ This function is exception-safe; even if an exception happens during the--- computation, the PATH environment variable will be reverted back to--- its initial value.-withPrependedPath :: FilePath -> PlotM a -> PlotM a-withPrependedPath dir f = do-  pathVar <- liftIO $ getEnv "PATH"-  let pathVarPrepended = mconcat [dir, ";", pathVar]-  bracket-    (liftIO $ setEnv "PATH" pathVarPrepended)-    (\_ -> liftIO $ setEnv "PATH" pathVar)-    (const f)---- | Throw an error that halts the execution of pandoc-plot due to a strict-mode.-throwStrictError :: Text -> PlotM ()-throwStrictError msg = do-  strict msg-  logger <- askLogger-  liftIO $ terminateLogging logger >> exitFailure---- Plot state is used for caching a map of filepaths to hashes--- This allows multiple plots to depend on the same file/directory, and the file hashes--- will only be calculated once. This is OK because pandoc-plot will not run for long.--- We note that because figures are rendered possibly in parallel, access to--- the state must be synchronized; otherwise, each thread might compute its own--- hashes.-type FileHash = Word--newtype PlotState-  = PlotState-      (MVar (Map FilePath FileHash))---- | Get a filehash. If the file hash has been computed before,--- it is reused. Otherwise, the filehash is calculated and stored.-fileHash :: FilePath -> PlotM FileHash-fileHash path = do-  PlotState varHashes <- get-  hashes <- liftIO $ takeMVar varHashes-  (fh, hashes') <- case M.lookup path hashes of-    Nothing -> do-      debug $ mconcat ["Calculating hash of dependency ", pack path]-      fh <- fileHash' path-      let hashes' = M.insert path fh hashes-      return (fh, hashes')-    Just h -> do-      debug $ mconcat ["Hash of dependency ", pack path, " already calculated."]-      return (h, hashes)-  liftIO $ putMVar varHashes hashes'-  put $ PlotState varHashes-  return fh-  where-    -- As a proxy for the state of a file dependency, we use the modification time-    -- This is much faster than actual file hashing-    fileHash' :: FilePath -> PlotM FileHash-    fileHash' fp = do-      fileExists <- liftIO $ doesFileExist fp-      if fileExists-        then liftIO . fmap (fromIntegral . hash . show) . getModificationTime $ fp-        else err (mconcat ["Dependency ", pack fp, " does not exist."]) >> return 0---- | Find an executable.-executable :: Toolkit -> PlotM Executable-executable tk = exeSelector tk <&> exeFromPath-  where-    exeSelector Matplotlib = asksConfig matplotlibExe-    exeSelector PlotlyPython = asksConfig plotlyPythonExe-    exeSelector PlotlyR = asksConfig plotlyRExe-    exeSelector Matlab = asksConfig matlabExe-    exeSelector Mathematica = asksConfig mathematicaExe-    exeSelector Octave = asksConfig octaveExe-    exeSelector GGPlot2 = asksConfig ggplot2Exe-    exeSelector GNUPlot = asksConfig gnuplotExe-    exeSelector Graphviz = asksConfig graphvizExe-    exeSelector Bokeh = asksConfig bokehExe-    exeSelector Plotsjl = asksConfig plotsjlExe-    exeSelector PlantUML = asksConfig plantumlExe-    exeSelector SageMath = asksConfig sagemathExe-    exeSelector D2 = asksConfig d2Exe---- | The @Configuration@ type holds the default values to use--- when running pandoc-plot. These values can be overridden in code blocks.------ You can create an instance of the @Configuration@ type from file using the @configuration@ function.------ You can store the path to a configuration file in metadata under the key @plot-configuration@. For example, in Markdown:------ @---     ------     title: My document---     author: John Doe---     plot-configuration: path\to\file.yml---     ------ @------ The same can be specified via the command line using Pandoc's @-M@ flag:------ > pandoc --filter pandoc-plot -M plot-configuration="path/to/file.yml" ...------ In this case, use @configurationPathMeta@ to extact the path from @Pandoc@ documents.-data Configuration = Configuration-  { -- | The default directory where figures will be saved.-    defaultDirectory :: !FilePath,-    -- | The default behavior of whether or not to include links to source code and high-res-    defaultWithSource :: !Bool,-    -- | The default dots-per-inch value for generated figures. Renderers might ignore this.-    defaultDPI :: !Int,-    -- | The default save format of generated figures.-    defaultSaveFormat :: !SaveFormat,-    -- | List of files/directories on which all figures depend.-    defaultDependencies :: ![FilePath],-    -- | Caption format, in the same notation as Pandoc format, e.g. "markdown+tex_math_dollars"-    captionFormat :: !Format,-    -- | The text label to which the source code is linked. Change this if you are writing non-english documents.-    sourceCodeLabel :: !Text,-    -- | Whether to halt pandoc-plot when an error is encountered or not.-    strictMode :: !Bool,-    -- | Level of logging verbosity.-    logVerbosity :: !Verbosity,-    -- | Method of logging, i.e. printing to stderr or file.-    logSink :: !LogSink,-    -- | The default preamble script for the matplotlib toolkit.-    matplotlibPreamble :: !Script,-    -- | The default preamble script for the Plotly/Python toolkit.-    plotlyPythonPreamble :: !Script,-    -- | The default preamble script for the Plotly/R toolkit.-    plotlyRPreamble :: !Script,-    -- | The default preamble script for the MATLAB toolkit.-    matlabPreamble :: !Script,-    -- | The default preamble script for the Mathematica toolkit.-    mathematicaPreamble :: !Script,-    -- | The default preamble script for the GNU Octave toolkit.-    octavePreamble :: !Script,-    -- | The default preamble script for the GGPlot2 toolkit.-    ggplot2Preamble :: !Script,-    -- | The default preamble script for the gnuplot toolkit.-    gnuplotPreamble :: !Script,-    -- | The default preamble script for the Graphviz toolkit.-    graphvizPreamble :: !Script,-    -- | The default preamble script for the Python/Bokeh toolkit.-    bokehPreamble :: !Script,-    -- | The default preamble script for the Julia/Plots.jl toolkit.-    plotsjlPreamble :: !Script,-    -- | The default preamble script for the PlantUML toolkit.-    plantumlPreamble :: !Script,-    -- | The default preamble script for the SageMath toolkit.-    sagemathPreamble :: !Script,-    -- | The default preamble script for the d2 toolkit.-    d2Preamble :: !Script,-    -- | The executable to use to generate figures using the matplotlib toolkit.-    matplotlibExe :: !FilePath,-    -- | The executable to use to generate figures using the MATLAB toolkit.-    matlabExe :: !FilePath,-    -- | The executable to use to generate figures using the Plotly/Python toolkit.-    plotlyPythonExe :: !FilePath,-    -- | The executable to use to generate figures using the Plotly/R toolkit.-    plotlyRExe :: !FilePath,-    -- | The executable to use to generate figures using the Mathematica toolkit.-    mathematicaExe :: !FilePath,-    -- | The executable to use to generate figures using the GNU Octave toolkit.-    octaveExe :: !FilePath,-    -- | The executable to use to generate figures using the GGPlot2 toolkit.-    ggplot2Exe :: !FilePath,-    -- | The executable to use to generate figures using the gnuplot toolkit.-    gnuplotExe :: !FilePath,-    -- | The executable to use to generate figures using the Graphviz toolkit.-    graphvizExe :: !FilePath,-    -- | The executable to use to generate figures using the Python/Bokeh toolkit.-    bokehExe :: !FilePath,-    -- | The executable to use to generate figures using the Julia/Plots.jl toolkit.-    plotsjlExe :: !FilePath,-    -- | The executable to use to generate figures using the PlantUML toolkit.-    plantumlExe :: !FilePath,-    -- | The executable to use to generate figures using SageMath.-    sagemathExe :: !FilePath,-    -- | The executable to use to generate figures using d2.-    d2Exe :: !FilePath,-    -- | Command-line arguments to pass to the Python interpreter for the Matplotlib toolkit-    matplotlibCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the MATLAB toolkit.-    matlabCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the Plotly/Python toolkit.-    plotlyPythonCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the Plotly/R toolkit.-    plotlyRCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the Mathematica toolkit.-    mathematicaCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the GNU Octave toolkit.-    octaveCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the GGPlot2 toolkit.-    ggplot2CmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the gnuplot toolkit.-    gnuplotCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the Graphviz toolkit.-    graphvizCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the Python/Bokeh toolkit.-    bokehCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the Julia/Plots.jl toolkit.-    plotsjlCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the plantUML toolkit.-    plantumlCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the SageMath toolkit.-    sagemathCmdArgs :: !Text,-    -- | Command-line arguments to pass to the interpreter for the d2 toolkit.-    d2CmdArgs :: !Text,-    -- | Whether or not to make Matplotlib figures tight by default.-    matplotlibTightBBox :: !Bool,-    -- | Whether or not to make Matplotlib figures transparent by default.-    matplotlibTransparent :: !Bool-  }-  deriving (Eq, Show)+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- This module defines the @PlotM@ monad and related capabilities.
+module Text.Pandoc.Filter.Plot.Monad
+  ( Configuration (..),
+    PlotM,
+    RuntimeEnv (..),
+    PlotState (..),
+    runPlotM,
+
+    -- * Concurrent execution
+    mapConcurrentlyN,
+
+    -- * Running external commands
+    runCommand,
+    withPrependedPath,
+
+    -- * Halting pandoc-plot
+    throwStrictError,
+
+    -- * Getting file hashes
+    fileHash,
+
+    -- * Getting executables
+    executable,
+
+    -- * Logging
+    Verbosity (..),
+    LogSink (..),
+    debug,
+    err,
+    warning,
+    info,
+
+    -- * Lifting and other monadic operations
+    liftIO,
+    ask,
+    asks,
+    asksConfig,
+
+    -- * Base types
+    module Text.Pandoc.Filter.Plot.Monad.Types,
+  )
+where
+
+import Control.Concurrent.Async.Lifted (mapConcurrently)
+import Control.Concurrent.MVar (MVar, newMVar, putMVar, takeMVar)
+import Control.Concurrent.QSemN
+  ( QSemN,
+    newQSemN,
+    signalQSemN,
+    waitQSemN,
+  )
+import Control.Exception.Lifted (bracket, bracket_)
+import Control.Monad.Reader
+  ( MonadIO (liftIO),
+    MonadReader (ask),
+    ReaderT (runReaderT),
+    asks,
+  )
+import Control.Monad.State.Strict
+  ( MonadState (get, put),
+    StateT,
+    evalStateT,
+  )
+import Data.ByteString.Lazy (toStrict)
+import Data.Functor ((<&>))
+import Data.Hashable (hash)
+import Data.Map.Strict (Map)
+import qualified Data.Map.Strict as M
+import Data.Text (Text, pack, unpack)
+import qualified Data.Text as T
+import Data.Text.Encoding (decodeUtf8With)
+import Data.Text.Encoding.Error (lenientDecode)
+import System.Directory
+  ( doesFileExist,
+    getCurrentDirectory,
+    getModificationTime,
+  )
+import System.Environment (getEnv, setEnv)
+import System.Exit (ExitCode (..), exitFailure)
+import System.Process.Typed
+  ( byteStringInput,
+    byteStringOutput,
+    nullStream,
+    readProcessStderr,
+    setStderr,
+    setStdin,
+    setStdout,
+    setWorkingDir,
+    shell,
+  )
+import Text.Pandoc.Definition (Format (..))
+import Text.Pandoc.Filter.Plot.Monad.Logging
+  ( LogSink (..),
+    Logger,
+    MonadLogger (..),
+    Verbosity (..),
+    debug,
+    err,
+    info,
+    strict,
+    terminateLogging,
+    warning,
+    withLogger,
+  )
+import Text.Pandoc.Filter.Plot.Monad.Types
+import Prelude hiding (fst, log, snd)
+
+-- | pandoc-plot monad
+type PlotM = StateT PlotState (ReaderT RuntimeEnv IO)
+
+instance MonadLogger PlotM where
+  askLogger = asks envLogger
+
+data RuntimeEnv = RuntimeEnv
+  { envFormat :: Maybe Format, -- pandoc output format
+    envConfig :: Configuration,
+    envLogger :: Logger,
+    envCWD :: FilePath,
+    -- The following lock prevents from writing to the same file multiple times.
+    -- This is a rather crude fix for issue #53.
+    envIOLock :: MVar ()
+  }
+
+-- | Get access to configuration within the @PlotM@ monad.
+asksConfig :: (Configuration -> a) -> PlotM a
+asksConfig f = asks (f . envConfig)
+
+-- | Evaluate a @PlotM@ action.
+runPlotM :: Maybe Format -> Configuration -> PlotM a -> IO a
+runPlotM fmt conf v = do
+  cwd <- getCurrentDirectory
+  sem <- newMVar ()
+  st <-
+    PlotState <$> newMVar mempty
+  let verbosity = logVerbosity conf
+      sink = logSink conf
+  withLogger verbosity sink $
+    \logger -> runReaderT (evalStateT v st) (RuntimeEnv fmt conf logger cwd sem)
+
+-- | maps a function, performing at most @N@ actions concurrently.
+mapConcurrentlyN :: (Traversable t) => Int -> (a -> PlotM b) -> t a -> PlotM (t b)
+mapConcurrentlyN n f xs = do
+  -- Emulating a pool of processes with locked access
+  sem <- liftIO $ newQSemN n
+  mapConcurrently (with sem . f) xs
+  where
+    with :: QSemN -> PlotM a -> PlotM a
+    with s = bracket_ (liftIO $ waitQSemN s 1) (liftIO $ signalQSemN s 1)
+
+-- | Run a command within the @PlotM@ monad. Stderr stream
+-- is read and decoded, while Stdout is ignored.
+-- Logging happens at the debug level if the command succeeds, or at
+-- the error level if it does not succeed.
+runCommand ::
+  FilePath -> -- Directory from which to run the command
+  Text -> -- Command to run, including executable
+  PlotM (ExitCode, Text)
+runCommand wordir command = do
+  (ec, processOutput') <-
+    liftIO $
+      readProcessStderr $
+        -- For Julia specifically, if the line below is not there (`setStdin (byteStringInput "")`),
+        -- the following error is thrown on Windows:
+        --    ERROR: error initializing stdin in uv_dup:
+        --           Unknown system error 50 (Unknown system error 50 50)
+        setStdin (byteStringInput "") $
+          setStdout nullStream $
+            setStderr byteStringOutput $
+              setWorkingDir wordir $
+                shell (unpack command)
+  let processOutput = decodeUtf8With lenientDecode $ toStrict processOutput'
+      logFunc =
+        if ec == ExitSuccess
+          then debug
+          else err
+      message =
+        T.unlines
+          [ "Running command",
+            "    " <> command,
+            "ended with exit code " <> (pack . show $ ec)
+          ]
+      errorMessage =
+        if processOutput == mempty
+          then mempty
+          else
+            T.unlines
+              [ "*******",
+                processOutput,
+                "*******"
+              ]
+
+  logFunc $ message <> errorMessage
+  return (ec, processOutput)
+
+-- | Prepend a directory to the PATH environment variable for the duration
+-- of a computation.
+--
+-- This function is exception-safe; even if an exception happens during the
+-- computation, the PATH environment variable will be reverted back to
+-- its initial value.
+withPrependedPath :: FilePath -> PlotM a -> PlotM a
+withPrependedPath dir f = do
+  pathVar <- liftIO $ getEnv "PATH"
+  let pathVarPrepended = mconcat [dir, ";", pathVar]
+  bracket
+    (liftIO $ setEnv "PATH" pathVarPrepended)
+    (\_ -> liftIO $ setEnv "PATH" pathVar)
+    (const f)
+
+-- | Throw an error that halts the execution of pandoc-plot due to a strict-mode.
+throwStrictError :: Text -> PlotM ()
+throwStrictError msg = do
+  strict msg
+  logger <- askLogger
+  liftIO $ terminateLogging logger >> exitFailure
+
+-- Plot state is used for caching a map of filepaths to hashes
+-- This allows multiple plots to depend on the same file/directory, and the file hashes
+-- will only be calculated once. This is OK because pandoc-plot will not run for long.
+-- We note that because figures are rendered possibly in parallel, access to
+-- the state must be synchronized; otherwise, each thread might compute its own
+-- hashes.
+type FileHash = Word
+
+newtype PlotState
+  = PlotState
+      (MVar (Map FilePath FileHash))
+
+-- | Get a filehash. If the file hash has been computed before,
+-- it is reused. Otherwise, the filehash is calculated and stored.
+fileHash :: FilePath -> PlotM FileHash
+fileHash path = do
+  PlotState varHashes <- get
+  hashes <- liftIO $ takeMVar varHashes
+  (fh, hashes') <- case M.lookup path hashes of
+    Nothing -> do
+      debug $ mconcat ["Calculating hash of dependency ", pack path]
+      fh <- fileHash' path
+      let hashes' = M.insert path fh hashes
+      return (fh, hashes')
+    Just h -> do
+      debug $ mconcat ["Hash of dependency ", pack path, " already calculated."]
+      return (h, hashes)
+  liftIO $ putMVar varHashes hashes'
+  put $ PlotState varHashes
+  return fh
+  where
+    -- As a proxy for the state of a file dependency, we use the modification time
+    -- This is much faster than actual file hashing
+    fileHash' :: FilePath -> PlotM FileHash
+    fileHash' fp = do
+      fileExists <- liftIO $ doesFileExist fp
+      if fileExists
+        then liftIO . fmap (fromIntegral . hash . show) . getModificationTime $ fp
+        else err (mconcat ["Dependency ", pack fp, " does not exist."]) >> return 0
+
+-- | Find an executable.
+executable :: Toolkit -> PlotM Executable
+executable tk = exeSelector tk <&> exeFromPath
+  where
+    exeSelector Matplotlib = asksConfig matplotlibExe
+    exeSelector PlotlyPython = asksConfig plotlyPythonExe
+    exeSelector PlotlyR = asksConfig plotlyRExe
+    exeSelector Matlab = asksConfig matlabExe
+    exeSelector Mathematica = asksConfig mathematicaExe
+    exeSelector Octave = asksConfig octaveExe
+    exeSelector GGPlot2 = asksConfig ggplot2Exe
+    exeSelector GNUPlot = asksConfig gnuplotExe
+    exeSelector Graphviz = asksConfig graphvizExe
+    exeSelector Bokeh = asksConfig bokehExe
+    exeSelector Plotsjl = asksConfig plotsjlExe
+    exeSelector PlantUML = asksConfig plantumlExe
+    exeSelector SageMath = asksConfig sagemathExe
+    exeSelector D2 = asksConfig d2Exe
+    exeSelector Asymptote = asksConfig asyExe
+
+-- | The @Configuration@ type holds the default values to use
+-- when running pandoc-plot. These values can be overridden in code blocks.
+--
+-- You can create an instance of the @Configuration@ type from file using the @configuration@ function.
+--
+-- You can store the path to a configuration file in metadata under the key @plot-configuration@. For example, in Markdown:
+--
+-- @
+--     ---
+--     title: My document
+--     author: John Doe
+--     plot-configuration: path\to\file.yml
+--     ---
+-- @
+--
+-- The same can be specified via the command line using Pandoc's @-M@ flag:
+--
+-- > pandoc --filter pandoc-plot -M plot-configuration="path/to/file.yml" ...
+--
+-- In this case, use @configurationPathMeta@ to extact the path from @Pandoc@ documents.
+data Configuration = Configuration
+  { -- | The default directory where figures will be saved.
+    defaultDirectory :: !FilePath,
+    -- | The default behavior of whether or not to include links to source code and high-res
+    defaultWithSource :: !Bool,
+    -- | The default dots-per-inch value for generated figures. Renderers might ignore this.
+    defaultDPI :: !Int,
+    -- | The default save format of generated figures.
+    defaultSaveFormat :: !SaveFormat,
+    -- | List of files/directories on which all figures depend.
+    defaultDependencies :: ![FilePath],
+    -- | Caption format, in the same notation as Pandoc format, e.g. "markdown+tex_math_dollars"
+    captionFormat :: !Format,
+    -- | The text label to which the source code is linked. Change this if you are writing non-english documents.
+    sourceCodeLabel :: !Text,
+    -- | Whether to halt pandoc-plot when an error is encountered or not.
+    strictMode :: !Bool,
+    -- | Level of logging verbosity.
+    logVerbosity :: !Verbosity,
+    -- | Method of logging, i.e. printing to stderr or file.
+    logSink :: !LogSink,
+    -- | The default preamble script for the matplotlib toolkit.
+    matplotlibPreamble :: !Script,
+    -- | The default preamble script for the Plotly/Python toolkit.
+    plotlyPythonPreamble :: !Script,
+    -- | The default preamble script for the Plotly/R toolkit.
+    plotlyRPreamble :: !Script,
+    -- | The default preamble script for the MATLAB toolkit.
+    matlabPreamble :: !Script,
+    -- | The default preamble script for the Mathematica toolkit.
+    mathematicaPreamble :: !Script,
+    -- | The default preamble script for the GNU Octave toolkit.
+    octavePreamble :: !Script,
+    -- | The default preamble script for the GGPlot2 toolkit.
+    ggplot2Preamble :: !Script,
+    -- | The default preamble script for the gnuplot toolkit.
+    gnuplotPreamble :: !Script,
+    -- | The default preamble script for the Graphviz toolkit.
+    graphvizPreamble :: !Script,
+    -- | The default preamble script for the Python/Bokeh toolkit.
+    bokehPreamble :: !Script,
+    -- | The default preamble script for the Julia/Plots.jl toolkit.
+    plotsjlPreamble :: !Script,
+    -- | The default preamble script for the PlantUML toolkit.
+    plantumlPreamble :: !Script,
+    -- | The default preamble script for the SageMath toolkit.
+    sagemathPreamble :: !Script,
+    -- | The default preamble script for the d2 toolkit.
+    d2Preamble :: !Script,
+    -- | The default preamble script for the Asymptote toolkit.
+    asyPreamble :: !Script,
+    -- | The executable to use to generate figures using the matplotlib toolkit.
+    matplotlibExe :: !FilePath,
+    -- | The executable to use to generate figures using the MATLAB toolkit.
+    matlabExe :: !FilePath,
+    -- | The executable to use to generate figures using the Plotly/Python toolkit.
+    plotlyPythonExe :: !FilePath,
+    -- | The executable to use to generate figures using the Plotly/R toolkit.
+    plotlyRExe :: !FilePath,
+    -- | The executable to use to generate figures using the Mathematica toolkit.
+    mathematicaExe :: !FilePath,
+    -- | The executable to use to generate figures using the GNU Octave toolkit.
+    octaveExe :: !FilePath,
+    -- | The executable to use to generate figures using the GGPlot2 toolkit.
+    ggplot2Exe :: !FilePath,
+    -- | The executable to use to generate figures using the gnuplot toolkit.
+    gnuplotExe :: !FilePath,
+    -- | The executable to use to generate figures using the Graphviz toolkit.
+    graphvizExe :: !FilePath,
+    -- | The executable to use to generate figures using the Python/Bokeh toolkit.
+    bokehExe :: !FilePath,
+    -- | The executable to use to generate figures using the Julia/Plots.jl toolkit.
+    plotsjlExe :: !FilePath,
+    -- | The executable to use to generate figures using the PlantUML toolkit.
+    plantumlExe :: !FilePath,
+    -- | The executable to use to generate figures using SageMath.
+    sagemathExe :: !FilePath,
+    -- | The executable to use to generate figures using d2.
+    d2Exe :: !FilePath,
+    -- | The executable to use to generate figures using Asymptote
+    asyExe :: !FilePath,
+    -- | Command-line arguments to pass to the Python interpreter for the Matplotlib toolkit
+    matplotlibCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the MATLAB toolkit.
+    matlabCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the Plotly/Python toolkit.
+    plotlyPythonCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the Plotly/R toolkit.
+    plotlyRCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the Mathematica toolkit.
+    mathematicaCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the GNU Octave toolkit.
+    octaveCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the GGPlot2 toolkit.
+    ggplot2CmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the gnuplot toolkit.
+    gnuplotCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the Graphviz toolkit.
+    graphvizCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the Python/Bokeh toolkit.
+    bokehCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the Julia/Plots.jl toolkit.
+    plotsjlCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the plantUML toolkit.
+    plantumlCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the SageMath toolkit.
+    sagemathCmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the d2 toolkit.
+    d2CmdArgs :: !Text,
+    -- | Command-line arguments to pass to the interpreter for the Asymptote toolkit.
+    asyCmdArgs :: !Text,
+    -- | Whether or not to make Matplotlib figures tight by default.
+    matplotlibTightBBox :: !Bool,
+    -- | Whether or not to make Matplotlib figures transparent by default.
+    matplotlibTransparent :: !Bool
+  }
+  deriving (Eq, Show)
src/Text/Pandoc/Filter/Plot/Monad/Logging.hs view
@@ -1,161 +1,161 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Logging primitives.-module Text.Pandoc.Filter.Plot.Monad.Logging-  ( MonadLogger (..),-    Verbosity (..),-    LogSink (..),-    Logger (..),-    withLogger,-    terminateLogging,--    -- * Logging messages-    debug,-    err,-    warning,-    info,-    strict,-  )-where--import Control.Concurrent (forkIO)-import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)-import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)-import Control.Monad (forM_, forever, void, when)-import Control.Monad.IO.Class (MonadIO (..))-import Data.Char (toLower)-import Data.List (intercalate)-import Data.String (IsString (..))-import Data.Text (Text, unpack)-import qualified Data.Text as T-import Data.Text.IO as TIO (appendFile, hPutStr)-import Data.Yaml (FromJSON (parseJSON), Value (String))-import System.IO (stderr)-import Prelude hiding (log)---- | Verbosity of the logger.-data Verbosity-  = -- | Log all messages, including debug messages.-    Debug-  | -- | Log information, warning, and error messages.-    Info-  | -- | Log warning and error messages.-    Warning-  | -- | Only log errors.-    Error-  | -- | Don't log anything.-    Silent-  deriving (Eq, Ord, Show, Enum, Bounded)---- | Description of the possible ways to sink log messages.-data LogSink-  = -- | Standard error stream.-    StdErr-  | -- | Appended to file.-    LogFile FilePath-  deriving (Eq, Show)---- | The logging implementation is very similar to Hakyll's.-data Logger = Logger-  { lVerbosity :: Verbosity, -- Verbosity level below which to ignore messages-    lChannel :: Chan Command, -- Queue of logging commands-    lSink :: Text -> IO (), -- Action to perform with log messages-    lSync :: MVar () -- Synchronization variable-  }--data Command-  = LogMessage Text-  | EndLogging--class (Monad m) => MonadLogger m where-  askLogger :: m Logger---- | Ensure that all log messages are flushed, and stop logging-terminateLogging :: Logger -> IO ()-terminateLogging logger = do-  -- Flushing the logger-  -- To signal to the logger that logging duties are over,-  -- we append Nothing to the channel, and wait for it to finish-  -- dealing with all items in the channel.-  writeChan (lChannel logger) EndLogging-  void $ takeMVar (lSync logger)---- | Perform an IO action with a logger. Using this function--- ensures that logging will be gracefully shut down.-withLogger :: Verbosity -> LogSink -> (Logger -> IO a) -> IO a-withLogger v s f = do-  logger <--    Logger v-      <$> newChan-      <*> pure (sink s)-      <*> newEmptyMVar--  -- The logger either logs messages (if Just "message"),-  -- or stops working on Nothing.-  _ <--    forkIO $-      forever $-        readChan (lChannel logger)-          >>= \case-            EndLogging -> putMVar (lSync logger) ()-            LogMessage t -> lSink logger t--  result <- f logger--  terminateLogging logger--  return result-  where-    sink :: LogSink -> Text -> IO ()-    sink StdErr = TIO.hPutStr stderr-    sink (LogFile fp) = TIO.appendFile fp---- | General purpose logging function.-log ::-  (MonadLogger m, MonadIO m) =>-  Text -> -- Header-  Verbosity ->-  Text ->-  m ()-log h v t = do-  logger <- askLogger-  when (v >= lVerbosity logger) $-    liftIO $ do-      forM_ (T.lines t) $ \l -> writeChan (lChannel logger) (LogMessage (h <> l <> "\n"))--debug, err, strict, warning, info :: (MonadLogger m, MonadIO m) => Text -> m ()-debug = log "[pandoc-plot] DEBUG | " Debug-err = log "[pandoc-plot] ERROR | " Error-strict = log "[pandoc-plot] STRICT MODE | " Error-warning = log "[pandoc-plot] WARN  | " Warning-info = log "[pandoc-plot] INFO  | " Info--instance IsString Verbosity where-  fromString s-    | ls == "silent" = Silent-    | ls == "info" = Info-    | ls == "warning" = Warning-    | ls == "error" = Error-    | ls == "debug" = Debug-    | otherwise = errorWithoutStackTrace $ mconcat ["Unrecognized verbosity '", s, "'. Valid choices are: "] <> choices-    where-      ls = toLower <$> s-      choices =-        intercalate-          ", "-          ( fmap toLower . show-              <$> enumFromTo minBound (maxBound :: Verbosity)-          )--instance FromJSON Verbosity where-  parseJSON (String t) = pure $ fromString . unpack $ t-  parseJSON _ = fail "Could not parse the logging verbosity."+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Logging primitives.
+module Text.Pandoc.Filter.Plot.Monad.Logging
+  ( MonadLogger (..),
+    Verbosity (..),
+    LogSink (..),
+    Logger (..),
+    withLogger,
+    terminateLogging,
+
+    -- * Logging messages
+    debug,
+    err,
+    warning,
+    info,
+    strict,
+  )
+where
+
+import Control.Concurrent (forkIO)
+import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
+import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)
+import Control.Monad (forM_, forever, void, when)
+import Control.Monad.IO.Class (MonadIO (..))
+import Data.Char (toLower)
+import Data.List (intercalate)
+import Data.String (IsString (..))
+import Data.Text (Text, unpack)
+import qualified Data.Text as T
+import Data.Text.IO as TIO (appendFile, hPutStr)
+import Data.Yaml (FromJSON (parseJSON), Value (String))
+import System.IO (stderr)
+import Prelude hiding (log)
+
+-- | Verbosity of the logger.
+data Verbosity
+  = -- | Log all messages, including debug messages.
+    Debug
+  | -- | Log information, warning, and error messages.
+    Info
+  | -- | Log warning and error messages.
+    Warning
+  | -- | Only log errors.
+    Error
+  | -- | Don't log anything.
+    Silent
+  deriving (Eq, Ord, Show, Enum, Bounded)
+
+-- | Description of the possible ways to sink log messages.
+data LogSink
+  = -- | Standard error stream.
+    StdErr
+  | -- | Appended to file.
+    LogFile FilePath
+  deriving (Eq, Show)
+
+-- | The logging implementation is very similar to Hakyll's.
+data Logger = Logger
+  { lVerbosity :: Verbosity, -- Verbosity level below which to ignore messages
+    lChannel :: Chan Command, -- Queue of logging commands
+    lSink :: Text -> IO (), -- Action to perform with log messages
+    lSync :: MVar () -- Synchronization variable
+  }
+
+data Command
+  = LogMessage Text
+  | EndLogging
+
+class (Monad m) => MonadLogger m where
+  askLogger :: m Logger
+
+-- | Ensure that all log messages are flushed, and stop logging
+terminateLogging :: Logger -> IO ()
+terminateLogging logger = do
+  -- Flushing the logger
+  -- To signal to the logger that logging duties are over,
+  -- we append Nothing to the channel, and wait for it to finish
+  -- dealing with all items in the channel.
+  writeChan (lChannel logger) EndLogging
+  void $ takeMVar (lSync logger)
+
+-- | Perform an IO action with a logger. Using this function
+-- ensures that logging will be gracefully shut down.
+withLogger :: Verbosity -> LogSink -> (Logger -> IO a) -> IO a
+withLogger v s f = do
+  logger <-
+    Logger v
+      <$> newChan
+      <*> pure (sink s)
+      <*> newEmptyMVar
+
+  -- The logger either logs messages (if Just "message"),
+  -- or stops working on Nothing.
+  _ <-
+    forkIO $
+      forever $
+        readChan (lChannel logger)
+          >>= \case
+            EndLogging -> putMVar (lSync logger) ()
+            LogMessage t -> lSink logger t
+
+  result <- f logger
+
+  terminateLogging logger
+
+  return result
+  where
+    sink :: LogSink -> Text -> IO ()
+    sink StdErr = TIO.hPutStr stderr
+    sink (LogFile fp) = TIO.appendFile fp
+
+-- | General purpose logging function.
+log ::
+  (MonadLogger m, MonadIO m) =>
+  Text -> -- Header
+  Verbosity ->
+  Text ->
+  m ()
+log h v t = do
+  logger <- askLogger
+  when (v >= lVerbosity logger) $
+    liftIO $ do
+      forM_ (T.lines t) $ \l -> writeChan (lChannel logger) (LogMessage (h <> l <> "\n"))
+
+debug, err, strict, warning, info :: (MonadLogger m, MonadIO m) => Text -> m ()
+debug = log "[pandoc-plot] DEBUG | " Debug
+err = log "[pandoc-plot] ERROR | " Error
+strict = log "[pandoc-plot] STRICT MODE | " Error
+warning = log "[pandoc-plot] WARN  | " Warning
+info = log "[pandoc-plot] INFO  | " Info
+
+instance IsString Verbosity where
+  fromString s
+    | ls == "silent" = Silent
+    | ls == "info" = Info
+    | ls == "warning" = Warning
+    | ls == "error" = Error
+    | ls == "debug" = Debug
+    | otherwise = errorWithoutStackTrace $ mconcat ["Unrecognized verbosity '", s, "'. Valid choices are: "] <> choices
+    where
+      ls = toLower <$> s
+      choices =
+        intercalate
+          ", "
+          ( fmap toLower . show
+              <$> enumFromTo minBound (maxBound :: Verbosity)
+          )
+
+instance FromJSON Verbosity where
+  parseJSON (String t) = pure $ fromString . unpack $ t
+  parseJSON _ = fail "Could not parse the logging verbosity."
src/Text/Pandoc/Filter/Plot/Monad/Types.hs view
@@ -1,300 +1,303 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ This module defines base types in use in pandoc-plot-module Text.Pandoc.Filter.Plot.Monad.Types-  ( Toolkit (..),-    Renderer (..),-    AvailabilityCheck (..),-    Script,-    CheckResult (..),-    InclusionKey (..),-    FigureSpec (..),-    OutputSpec (..),-    SaveFormat (..),-    cls,-    extension,-    toolkits,-    inclusionKeys,-    Executable (..),-    exeFromPath,-    pathToExe,-    -- Utilities-    isWindows,-  )-where--import Data.Char (toLower)-import Data.List (intersperse)-import Data.String (IsString (..))-import Data.Text (Text, pack, unpack)-import Data.Yaml (FromJSON (..), ToJSON (toJSON), withText)-import GHC.Generics (Generic)-import System.FilePath (isAbsolute, splitFileName, (</>))-import System.Info (os)-import Text.Pandoc.Definition (Attr)---- | List of supported toolkits.-toolkits :: [Toolkit]-toolkits = enumFromTo minBound maxBound---- | Enumeration of supported toolkits-data Toolkit-  = Matplotlib-  | Matlab-  | PlotlyPython-  | PlotlyR-  | Mathematica-  | Octave-  | GGPlot2-  | GNUPlot-  | Graphviz-  | Bokeh-  | Plotsjl-  | PlantUML-  | SageMath-  | D2-  deriving (Bounded, Eq, Enum, Generic, Ord)---- | This instance should only be used to display toolkit names-instance Show Toolkit where-  show Matplotlib = "Python/Matplotlib"-  show Matlab = "MATLAB"-  show PlotlyPython = "Python/Plotly"-  show PlotlyR = "R/Plotly"-  show Mathematica = "Mathematica"-  show Octave = "GNU Octave"-  show GGPlot2 = "ggplot2"-  show GNUPlot = "gnuplot"-  show Graphviz = "graphviz"-  show Bokeh = "Python/Bokeh"-  show Plotsjl = "Julia/Plots.jl"-  show PlantUML = "PlantUML"-  show SageMath = "SageMath"-  show D2 = "D2"---- | Class name which will trigger the filter-cls :: Toolkit -> Text-cls Matplotlib = "matplotlib"-cls Matlab = "matlabplot"-cls PlotlyPython = "plotly_python"-cls PlotlyR = "plotly_r"-cls Mathematica = "mathplot"-cls Octave = "octaveplot"-cls GGPlot2 = "ggplot2"-cls GNUPlot = "gnuplot"-cls Graphviz = "graphviz"-cls Bokeh = "bokeh"-cls Plotsjl = "plotsjl"-cls PlantUML = "plantuml"-cls SageMath = "sageplot"-cls D2 = "d2"---- | Executable program, and sometimes the directory where it can be found.-data Executable-  = AbsExe FilePath Text-  | RelExe Text--exeFromPath :: FilePath -> Executable-exeFromPath fp-  | isAbsolute fp =-      let (dir, name) = splitFileName fp-       in AbsExe dir (pack name)-  | otherwise = RelExe (pack fp)--pathToExe :: Executable -> FilePath-pathToExe (AbsExe dir name) = dir </> unpack name-pathToExe (RelExe name) = unpack name---- | Source context for plotting scripts-type Script = Text---- | Result of checking scripts for problems-data CheckResult-  = CheckPassed-  | CheckFailed Text-  deriving (Eq)--instance Semigroup CheckResult where-  (<>) CheckPassed a = a-  (<>) a CheckPassed = a-  (<>) (CheckFailed msg1) (CheckFailed msg2) = CheckFailed (msg1 <> msg2)--instance Monoid CheckResult where-  mempty = CheckPassed---- | Description of any possible inclusion key, both in documents--- and in configuration files.-data InclusionKey-  = DirectoryK-  | CaptionK-  | SaveFormatK-  | WithSourceK-  | CaptionFormatK-  | PreambleK-  | DpiK-  | SourceCodeLabelK-  | StrictModeK-  | ExecutableK-  | CommandLineArgsK-  | DependenciesK-  | FileK-  | MatplotlibTightBBoxK-  | MatplotlibTransparentK-  deriving (Bounded, Eq, Enum)---- | Keys that pandoc-plot will look for in code blocks.--- These are only exported for testing purposes.-instance Show InclusionKey where-  show DirectoryK = "directory"-  show CaptionK = "caption"-  show SaveFormatK = "format"-  show WithSourceK = "source"-  show CaptionFormatK = "caption_format"-  show PreambleK = "preamble"-  show DpiK = "dpi"-  show SourceCodeLabelK = "source_label"-  show StrictModeK = "strict"-  show ExecutableK = "executable"-  show CommandLineArgsK = "command_line_arguments"-  show DependenciesK = "dependencies"-  show FileK = "file"-  show MatplotlibTightBBoxK = "tight_bbox"-  show MatplotlibTransparentK = "transparent"---- | List of all keys related to pandoc-plot that--- can be specified in source material.-inclusionKeys :: [InclusionKey]-inclusionKeys = enumFromTo (minBound :: InclusionKey) maxBound---- | Datatype containing all parameters required to specify a figure.------ It is assumed that once a @FigureSpec@ has been created, no configuration--- can overload it; hence, a @FigureSpec@ completely encodes a particular figure.-data FigureSpec = FigureSpec-  { -- | Renderer to use for this figure.-    renderer_ :: !Renderer,-    -- | Executable to use in rendering this figure.-    fsExecutable :: Executable,-    -- | Figure caption.-    caption :: !Text,-    -- | Append link to source code in caption.-    withSource :: !Bool,-    -- | Source code for the figure.-    script :: !Script,-    -- | Save format of the figure.-    saveFormat :: !SaveFormat,-    -- | Directory where to save the file.-    directory :: !FilePath,-    -- | Dots-per-inch of figure.-    dpi :: !Int,-    -- | Files/directories on which this figure depends, e.g. data files.-    dependencies :: ![FilePath],-    -- | Renderer-specific extra attributes.-    extraAttrs :: ![(Text, Text)],-    -- | Attributes not related to @pandoc-plot@ will be propagated.-    blockAttrs :: !Attr-  }---- | Generated figure file format supported by pandoc-plot.--- Note that not all formats are supported by all toolkits.-data SaveFormat-  = -- | Portable network graphics-    PNG-  | -- | Portable document format-    PDF-  | -- | Scalable vector graphics-    SVG-  | -- | JPEG/JPG compressed image-    JPG-  | -- | Encapsulated postscript-    EPS-  | -- | GIF format-    GIF-  | -- | Tagged image format-    TIF-  | -- | WebP image format-    WEBP-  | -- | HTML for interactive plots.-    HTML-  | -- | LaTeX text and pdf graphics-    LaTeX-  deriving (Bounded, Enum, Ord, Eq, Show, Generic)--instance IsString SaveFormat where-  fromString s-    | s `elem` ["png", "PNG", ".png"] = PNG-    | s `elem` ["pdf", "PDF", ".pdf"] = PDF-    | s `elem` ["svg", "SVG", ".svg"] = SVG-    | s `elem` ["eps", "EPS", ".eps"] = EPS-    | s `elem` ["gif", "GIF", ".gif"] = GIF-    | s `elem` ["jpg", "jpeg", "JPG", "JPEG", ".jpg", ".jpeg"] = JPG-    | s `elem` ["tif", "tiff", "TIF", "TIFF", ".tif", ".tiff"] = TIF-    | s `elem` ["webp", "WEBP", ".webp"] = WEBP-    | s `elem` ["html", "HTML", ".html"] = HTML-    | s `elem` ["latex", "LaTeX", ".tex"] = LaTeX-    | otherwise =-        errorWithoutStackTrace $-          mconcat-            [ s,-              " is not one of the valid save formats : ",-              mconcat $ intersperse ", " $ show <$> saveFormats,-              " (and lowercase variations). "-            ]-    where-      saveFormats = enumFromTo minBound maxBound :: [SaveFormat]---- | Use the IsString instance to parse JSON so that the parsing is flexible--- with respect to uppercase/lowercase (#42)-instance FromJSON SaveFormat where-  parseJSON = withText "SaveFormat" (pure . fromString . unpack)--instance ToJSON SaveFormat where-  toJSON = toJSON . extension---- | Save format file extension-extension :: SaveFormat -> String-extension LaTeX = ".tex"-extension fmt = mconcat [".", fmap toLower . show $ fmt]--isWindows :: Bool-isWindows = os `elem` ["mingw32", "win32", "cygwin32"] -- Aliases taken from cabal's Distribution.System module---- | Internal description of all information--- needed to output a figure.-data OutputSpec = OutputSpec-  { -- | Figure spec-    oFigureSpec :: FigureSpec,-    -- | Path to the script to render-    oScriptPath :: FilePath,-    -- | Figure output path-    oFigurePath :: FilePath,-    -- | Executable to use during rendering-    oExecutable :: Executable,-    -- | Current working directory-    oCWD :: FilePath-  }--data AvailabilityCheck-  = CommandSuccess (Executable -> Text)-  | ExecutableExists--data Renderer = Renderer-  { rendererToolkit :: Toolkit,-    rendererCapture :: FigureSpec -> FilePath -> Script,-    rendererCommand :: OutputSpec -> Text,-    rendererAvailability :: AvailabilityCheck,-    rendererSupportedSaveFormats :: [SaveFormat],-    rendererChecks :: [Script -> CheckResult],-    rendererLanguage :: Text,-    rendererComment :: Text -> Text,-    rendererScriptExtension :: String-  }+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- This module defines base types in use in pandoc-plot
+module Text.Pandoc.Filter.Plot.Monad.Types
+  ( Toolkit (..),
+    Renderer (..),
+    AvailabilityCheck (..),
+    Script,
+    CheckResult (..),
+    InclusionKey (..),
+    FigureSpec (..),
+    OutputSpec (..),
+    SaveFormat (..),
+    cls,
+    extension,
+    toolkits,
+    inclusionKeys,
+    Executable (..),
+    exeFromPath,
+    pathToExe,
+    -- Utilities
+    isWindows,
+  )
+where
+
+import Data.Char (toLower)
+import Data.List (intersperse)
+import Data.String (IsString (..))
+import Data.Text (Text, pack, unpack)
+import Data.Yaml (FromJSON (..), ToJSON (toJSON), withText)
+import GHC.Generics (Generic)
+import System.FilePath (isAbsolute, splitFileName, (</>))
+import System.Info (os)
+import Text.Pandoc.Definition (Attr)
+
+-- | List of supported toolkits.
+toolkits :: [Toolkit]
+toolkits = enumFromTo minBound maxBound
+
+-- | Enumeration of supported toolkits
+data Toolkit
+  = Matplotlib
+  | Matlab
+  | PlotlyPython
+  | PlotlyR
+  | Mathematica
+  | Octave
+  | GGPlot2
+  | GNUPlot
+  | Graphviz
+  | Bokeh
+  | Plotsjl
+  | PlantUML
+  | SageMath
+  | D2
+  | Asymptote
+  deriving (Bounded, Eq, Enum, Generic, Ord)
+
+-- | This instance should only be used to display toolkit names
+instance Show Toolkit where
+  show Matplotlib = "Python/Matplotlib"
+  show Matlab = "MATLAB"
+  show PlotlyPython = "Python/Plotly"
+  show PlotlyR = "R/Plotly"
+  show Mathematica = "Mathematica"
+  show Octave = "GNU Octave"
+  show GGPlot2 = "ggplot2"
+  show GNUPlot = "gnuplot"
+  show Graphviz = "graphviz"
+  show Bokeh = "Python/Bokeh"
+  show Plotsjl = "Julia/Plots.jl"
+  show PlantUML = "PlantUML"
+  show SageMath = "SageMath"
+  show D2 = "D2"
+  show Asymptote = "Asymptote"
+
+-- | Class name which will trigger the filter
+cls :: Toolkit -> Text
+cls Matplotlib = "matplotlib"
+cls Matlab = "matlabplot"
+cls PlotlyPython = "plotly_python"
+cls PlotlyR = "plotly_r"
+cls Mathematica = "mathplot"
+cls Octave = "octaveplot"
+cls GGPlot2 = "ggplot2"
+cls GNUPlot = "gnuplot"
+cls Graphviz = "graphviz"
+cls Bokeh = "bokeh"
+cls Plotsjl = "plotsjl"
+cls PlantUML = "plantuml"
+cls SageMath = "sageplot"
+cls D2 = "d2"
+cls Asymptote = "asy"
+
+-- | Executable program, and sometimes the directory where it can be found.
+data Executable
+  = AbsExe FilePath Text
+  | RelExe Text
+
+exeFromPath :: FilePath -> Executable
+exeFromPath fp
+  | isAbsolute fp =
+      let (dir, name) = splitFileName fp
+       in AbsExe dir (pack name)
+  | otherwise = RelExe (pack fp)
+
+pathToExe :: Executable -> FilePath
+pathToExe (AbsExe dir name) = dir </> unpack name
+pathToExe (RelExe name) = unpack name
+
+-- | Source context for plotting scripts
+type Script = Text
+
+-- | Result of checking scripts for problems
+data CheckResult
+  = CheckPassed
+  | CheckFailed Text
+  deriving (Eq)
+
+instance Semigroup CheckResult where
+  (<>) CheckPassed a = a
+  (<>) a CheckPassed = a
+  (<>) (CheckFailed msg1) (CheckFailed msg2) = CheckFailed (msg1 <> msg2)
+
+instance Monoid CheckResult where
+  mempty = CheckPassed
+
+-- | Description of any possible inclusion key, both in documents
+-- and in configuration files.
+data InclusionKey
+  = DirectoryK
+  | CaptionK
+  | SaveFormatK
+  | WithSourceK
+  | CaptionFormatK
+  | PreambleK
+  | DpiK
+  | SourceCodeLabelK
+  | StrictModeK
+  | ExecutableK
+  | CommandLineArgsK
+  | DependenciesK
+  | FileK
+  | MatplotlibTightBBoxK
+  | MatplotlibTransparentK
+  deriving (Bounded, Eq, Enum)
+
+-- | Keys that pandoc-plot will look for in code blocks.
+-- These are only exported for testing purposes.
+instance Show InclusionKey where
+  show DirectoryK = "directory"
+  show CaptionK = "caption"
+  show SaveFormatK = "format"
+  show WithSourceK = "source"
+  show CaptionFormatK = "caption_format"
+  show PreambleK = "preamble"
+  show DpiK = "dpi"
+  show SourceCodeLabelK = "source_label"
+  show StrictModeK = "strict"
+  show ExecutableK = "executable"
+  show CommandLineArgsK = "command_line_arguments"
+  show DependenciesK = "dependencies"
+  show FileK = "file"
+  show MatplotlibTightBBoxK = "tight_bbox"
+  show MatplotlibTransparentK = "transparent"
+
+-- | List of all keys related to pandoc-plot that
+-- can be specified in source material.
+inclusionKeys :: [InclusionKey]
+inclusionKeys = enumFromTo (minBound :: InclusionKey) maxBound
+
+-- | Datatype containing all parameters required to specify a figure.
+--
+-- It is assumed that once a @FigureSpec@ has been created, no configuration
+-- can overload it; hence, a @FigureSpec@ completely encodes a particular figure.
+data FigureSpec = FigureSpec
+  { -- | Renderer to use for this figure.
+    renderer_ :: !Renderer,
+    -- | Executable to use in rendering this figure.
+    fsExecutable :: Executable,
+    -- | Figure caption.
+    caption :: !Text,
+    -- | Append link to source code in caption.
+    withSource :: !Bool,
+    -- | Source code for the figure.
+    script :: !Script,
+    -- | Save format of the figure.
+    saveFormat :: !SaveFormat,
+    -- | Directory where to save the file.
+    directory :: !FilePath,
+    -- | Dots-per-inch of figure.
+    dpi :: !Int,
+    -- | Files/directories on which this figure depends, e.g. data files.
+    dependencies :: ![FilePath],
+    -- | Renderer-specific extra attributes.
+    extraAttrs :: ![(Text, Text)],
+    -- | Attributes not related to @pandoc-plot@ will be propagated.
+    blockAttrs :: !Attr
+  }
+
+-- | Generated figure file format supported by pandoc-plot.
+-- Note that not all formats are supported by all toolkits.
+data SaveFormat
+  = -- | Portable network graphics
+    PNG
+  | -- | Portable document format
+    PDF
+  | -- | Scalable vector graphics
+    SVG
+  | -- | JPEG/JPG compressed image
+    JPG
+  | -- | Encapsulated postscript
+    EPS
+  | -- | GIF format
+    GIF
+  | -- | Tagged image format
+    TIF
+  | -- | WebP image format
+    WEBP
+  | -- | HTML for interactive plots.
+    HTML
+  | -- | LaTeX text and pdf graphics
+    LaTeX
+  deriving (Bounded, Enum, Ord, Eq, Show, Generic)
+
+instance IsString SaveFormat where
+  fromString s
+    | s `elem` ["png", "PNG", ".png"] = PNG
+    | s `elem` ["pdf", "PDF", ".pdf"] = PDF
+    | s `elem` ["svg", "SVG", ".svg"] = SVG
+    | s `elem` ["eps", "EPS", ".eps"] = EPS
+    | s `elem` ["gif", "GIF", ".gif"] = GIF
+    | s `elem` ["jpg", "jpeg", "JPG", "JPEG", ".jpg", ".jpeg"] = JPG
+    | s `elem` ["tif", "tiff", "TIF", "TIFF", ".tif", ".tiff"] = TIF
+    | s `elem` ["webp", "WEBP", ".webp"] = WEBP
+    | s `elem` ["html", "HTML", ".html"] = HTML
+    | s `elem` ["latex", "LaTeX", ".tex"] = LaTeX
+    | otherwise =
+        errorWithoutStackTrace $
+          mconcat
+            [ s,
+              " is not one of the valid save formats : ",
+              mconcat $ intersperse ", " $ show <$> saveFormats,
+              " (and lowercase variations). "
+            ]
+    where
+      saveFormats = enumFromTo minBound maxBound :: [SaveFormat]
+
+-- | Use the IsString instance to parse JSON so that the parsing is flexible
+-- with respect to uppercase/lowercase (#42)
+instance FromJSON SaveFormat where
+  parseJSON = withText "SaveFormat" (pure . fromString . unpack)
+
+instance ToJSON SaveFormat where
+  toJSON = toJSON . extension
+
+-- | Save format file extension
+extension :: SaveFormat -> String
+extension LaTeX = ".tex"
+extension fmt = mconcat [".", fmap toLower . show $ fmt]
+
+isWindows :: Bool
+isWindows = os `elem` ["mingw32", "win32", "cygwin32"] -- Aliases taken from cabal's Distribution.System module
+
+-- | Internal description of all information
+-- needed to output a figure.
+data OutputSpec = OutputSpec
+  { -- | Figure spec
+    oFigureSpec :: FigureSpec,
+    -- | Path to the script to render
+    oScriptPath :: FilePath,
+    -- | Figure output path
+    oFigurePath :: FilePath,
+    -- | Executable to use during rendering
+    oExecutable :: Executable,
+    -- | Current working directory
+    oCWD :: FilePath
+  }
+
+data AvailabilityCheck
+  = CommandSuccess (Executable -> Text)
+  | ExecutableExists
+
+data Renderer = Renderer
+  { rendererToolkit :: Toolkit,
+    rendererCapture :: FigureSpec -> FilePath -> Script,
+    rendererCommand :: OutputSpec -> Text,
+    rendererAvailability :: AvailabilityCheck,
+    rendererSupportedSaveFormats :: [SaveFormat],
+    rendererChecks :: [Script -> CheckResult],
+    rendererLanguage :: Text,
+    rendererComment :: Text -> Text,
+    rendererScriptExtension :: String
+  }
src/Text/Pandoc/Filter/Plot/Parse.hs view
@@ -1,196 +1,196 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ This module defines types and functions that help--- with keeping track of figure specifications-module Text.Pandoc.Filter.Plot.Parse-  ( plotToolkit,-    parseFigureSpec,-    ParseFigureResult (..),-    captionReader,-  )-where--import Control.Monad (join, unless, when)-import Data.Char (isSpace)-import Data.Default (def)-import Data.List (find, intersperse)-import qualified Data.Map.Strict as Map-import Data.Maybe (fromJust, fromMaybe, isJust)-import Data.String (fromString)-import Data.Text (Text, pack, unpack)-import qualified Data.Text as T-import qualified Data.Text.IO as TIO-import Data.Version (showVersion)-import Paths_pandoc_plot (version)-import System.FilePath (makeValid, normalise)-import Text.Pandoc.Class (runPure)-import Text.Pandoc.Definition-  ( Block (..),-    Format (..),-    Inline,-    Pandoc (..),-  )-import Text.Pandoc.Filter.Plot.Monad-import Text.Pandoc.Filter.Plot.Renderers-import Text.Pandoc.Format (parseFlavoredFormat)-import Text.Pandoc.Options (ReaderOptions (..))-import Text.Pandoc.Readers (Reader (..), getReader)--tshow :: (Show a) => a -> Text-tshow = pack . show--data ParseFigureResult-  = -- | The block is not meant to become a figure-    NotAFigure-  | -- | The block is meant to become a figure-    PFigure FigureSpec-  | -- | The block is meant to become a figure, but the plotting toolkit is missing-    MissingToolkit Toolkit-  | -- | The block is meant to become a figure, but the figure format is incompatible-    --   with the plotting toolkit-    UnsupportedSaveFormat Toolkit SaveFormat---- | Determine inclusion specifications from @Block@ attributes.--- If an environment is detected, but the save format is incompatible,--- an error will be thrown.-parseFigureSpec :: Block -> PlotM ParseFigureResult-parseFigureSpec block@(CodeBlock (id', classes, attrs) _) = do-  -- The following would be a good case for the use of MaybeT-  -- but I don't want to bring in another dependency-  let mtk = plotToolkit block-  case mtk of-    Nothing -> return NotAFigure-    Just tk -> do-      r <- renderer tk-      figureSpec r-  where-    attrs' = Map.fromList attrs-    preamblePath = unpack <$> Map.lookup (tshow PreambleK) attrs'--    figureSpec :: Renderer -> PlotM ParseFigureResult-    figureSpec renderer_@Renderer {..} = do-      conf <- asks envConfig-      let toolkit = rendererToolkit-          saveFormat = maybe (defaultSaveFormat conf) (fromString . unpack) (Map.lookup (tshow SaveFormatK) attrs')--      -- Check if the saveformat is compatible with the toolkit-      if saveFormat `notElem` rendererSupportedSaveFormats-        then do-          err $ pack $ mconcat ["Save format ", show saveFormat, " not supported by ", show toolkit]-          return $ UnsupportedSaveFormat toolkit saveFormat-        else do-          let extraAttrs' = parseExtraAttrs toolkit attrs'-              header = rendererComment $ "Generated by pandoc-plot " <> (pack . showVersion) version-              defaultPreamble = preambleSelector toolkit conf--          includeScript <--            maybe-              (return defaultPreamble)-              (liftIO . TIO.readFile)-              preamblePath-          let -- Filter attributes that are not relevant to pandoc-plot-              -- This presumes that inclusionKeys includes ALL possible keys, for all toolkits-              filteredAttrs = filter (\(k, _) -> k `notElem` (tshow <$> inclusionKeys)) attrs-              defWithSource = defaultWithSource conf-              defDPI = defaultDPI conf--          -- Decide between reading from file or using document content-          content <- parseContent block--          defaultExe <- executable rendererToolkit--          let caption = Map.findWithDefault mempty (tshow CaptionK) attrs'-              fsExecutable = maybe defaultExe (exeFromPath . unpack) $ Map.lookup (tshow ExecutableK) attrs'-              withSource = maybe defWithSource readBool (Map.lookup (tshow WithSourceK) attrs')-              script = mconcat $ intersperse "\n" [header, includeScript, content]-              directory = makeValid $ unpack $ Map.findWithDefault (pack $ defaultDirectory conf) (tshow DirectoryK) attrs'-              dpi = maybe defDPI (read . unpack) (Map.lookup (tshow DpiK) attrs')-              extraAttrs = Map.toList extraAttrs'-              blockAttrs = (id', filter (/= cls toolkit) classes, filteredAttrs)--          let blockDependencies = parseFileDependencies $ fromMaybe mempty $ Map.lookup (tshow DependenciesK) attrs'-              dependencies = defaultDependencies conf <> blockDependencies--          -- This is the first opportunity to check save format compatibility-          _' <--            unless (saveFormat `elem` rendererSupportedSaveFormats) $-              let msg = pack $ mconcat ["Save format ", show saveFormat, " not supported by ", show toolkit]-               in err msg--          -- Ensure that the save format makes sense given the final conversion format, if known-          return $ PFigure (FigureSpec {..})--- Base case: block is not a CodeBlock-parseFigureSpec _ = return NotAFigure---- | Parse script content from a block, if possible.--- The script content can either come from a file--- or from the code block itself. If both are present,--- the file is preferred.-parseContent :: Block -> PlotM Script-parseContent (CodeBlock (_, _, attrs) content) = do-  let attrs' = Map.fromList attrs-      mfile = normalise . unpack <$> Map.lookup (tshow FileK) attrs'-  when (content /= mempty && isJust mfile) $ do-    warning $-      mconcat-        [ "Figure refers to a file (",-          pack $ fromJust mfile,-          ") but also has content in the document.\nThe file content will be preferred."-        ]-  let loadFromFile fp = do-        info $ "Loading figure content from " <> pack fp-        liftIO $ TIO.readFile fp-  maybe (return content) loadFromFile mfile-parseContent _ = return mempty---- | Determine which toolkit should be used to render the plot--- from a code block, if any.-plotToolkit :: Block -> Maybe Toolkit-plotToolkit (CodeBlock (_, classes, _) _) =-  find (\tk -> cls tk `elem` classes) toolkits-plotToolkit _ = Nothing---- | Reader a caption, based on input document format-captionReader :: Format -> Text -> Maybe [Inline]-captionReader (Format f) t = either (const Nothing) (Just . extractFromBlocks) $-  runPure $ do-    fmt <- parseFlavoredFormat f-    (reader, exts) <- getReader fmt-    let readerOpts = def {readerExtensions = exts}-    -- Assuming no ByteString readers...-    case reader of-      TextReader fct -> fct readerOpts t-      _ -> return mempty-  where-    extractFromBlocks (Pandoc _ blocks) = mconcat $ extractInlines <$> blocks--    extractInlines (Plain inlines) = inlines-    extractInlines (Para inlines) = inlines-    extractInlines (LineBlock multiinlines) = join multiinlines-    extractInlines _ = []---- | Flexible boolean parsing-readBool :: Text -> Bool-readBool s-  | s `elem` ["True", "true", "'True'", "'true'", "1"] = True-  | s `elem` ["False", "false", "'False'", "'false'", "0"] = False-  | otherwise = errorWithoutStackTrace $ unpack $ mconcat ["Could not parse '", s, "' into a boolean. Please use 'True' or 'False'"]---- | Parse a list of file dependencies such as /[foo.bar, hello.txt]/.-parseFileDependencies :: Text -> [FilePath]-parseFileDependencies t-  | t == mempty = mempty-  | otherwise =-      fmap (normalise . unpack . T.dropAround isSpace)-        . T.splitOn ","-        . T.dropAround (\c -> c `elem` ['[', ']'])-        $ t+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- This module defines types and functions that help
+-- with keeping track of figure specifications
+module Text.Pandoc.Filter.Plot.Parse
+  ( plotToolkit,
+    parseFigureSpec,
+    ParseFigureResult (..),
+    captionReader,
+  )
+where
+
+import Control.Monad (join, unless, when)
+import Data.Char (isSpace)
+import Data.Default (def)
+import Data.List (find, intersperse)
+import qualified Data.Map.Strict as Map
+import Data.Maybe (fromJust, fromMaybe, isJust)
+import Data.String (fromString)
+import Data.Text (Text, pack, unpack)
+import qualified Data.Text as T
+import qualified Data.Text.IO as TIO
+import Data.Version (showVersion)
+import Paths_pandoc_plot (version)
+import System.FilePath (makeValid, normalise)
+import Text.Pandoc.Class (runPure)
+import Text.Pandoc.Definition
+  ( Block (..),
+    Format (..),
+    Inline,
+    Pandoc (..),
+  )
+import Text.Pandoc.Filter.Plot.Monad
+import Text.Pandoc.Filter.Plot.Renderers
+import Text.Pandoc.Format (parseFlavoredFormat)
+import Text.Pandoc.Options (ReaderOptions (..))
+import Text.Pandoc.Readers (Reader (..), getReader)
+
+tshow :: (Show a) => a -> Text
+tshow = pack . show
+
+data ParseFigureResult
+  = -- | The block is not meant to become a figure
+    NotAFigure
+  | -- | The block is meant to become a figure
+    PFigure FigureSpec
+  | -- | The block is meant to become a figure, but the plotting toolkit is missing
+    MissingToolkit Toolkit
+  | -- | The block is meant to become a figure, but the figure format is incompatible
+    --   with the plotting toolkit
+    UnsupportedSaveFormat Toolkit SaveFormat
+
+-- | Determine inclusion specifications from @Block@ attributes.
+-- If an environment is detected, but the save format is incompatible,
+-- an error will be thrown.
+parseFigureSpec :: Block -> PlotM ParseFigureResult
+parseFigureSpec block@(CodeBlock (id', classes, attrs) _) = do
+  -- The following would be a good case for the use of MaybeT
+  -- but I don't want to bring in another dependency
+  let mtk = plotToolkit block
+  case mtk of
+    Nothing -> return NotAFigure
+    Just tk -> do
+      r <- renderer tk
+      figureSpec r
+  where
+    attrs' = Map.fromList attrs
+    preamblePath = unpack <$> Map.lookup (tshow PreambleK) attrs'
+
+    figureSpec :: Renderer -> PlotM ParseFigureResult
+    figureSpec renderer_@Renderer {..} = do
+      conf <- asks envConfig
+      let toolkit = rendererToolkit
+          saveFormat = maybe (defaultSaveFormat conf) (fromString . unpack) (Map.lookup (tshow SaveFormatK) attrs')
+
+      -- Check if the saveformat is compatible with the toolkit
+      if saveFormat `notElem` rendererSupportedSaveFormats
+        then do
+          err $ pack $ mconcat ["Save format ", show saveFormat, " not supported by ", show toolkit]
+          return $ UnsupportedSaveFormat toolkit saveFormat
+        else do
+          let extraAttrs' = parseExtraAttrs toolkit attrs'
+              header = rendererComment $ "Generated by pandoc-plot " <> (pack . showVersion) version
+              defaultPreamble = preambleSelector toolkit conf
+
+          includeScript <-
+            maybe
+              (return defaultPreamble)
+              (liftIO . TIO.readFile)
+              preamblePath
+          let -- Filter attributes that are not relevant to pandoc-plot
+              -- This presumes that inclusionKeys includes ALL possible keys, for all toolkits
+              filteredAttrs = filter (\(k, _) -> k `notElem` (tshow <$> inclusionKeys)) attrs
+              defWithSource = defaultWithSource conf
+              defDPI = defaultDPI conf
+
+          -- Decide between reading from file or using document content
+          content <- parseContent block
+
+          defaultExe <- executable rendererToolkit
+
+          let caption = Map.findWithDefault mempty (tshow CaptionK) attrs'
+              fsExecutable = maybe defaultExe (exeFromPath . unpack) $ Map.lookup (tshow ExecutableK) attrs'
+              withSource = maybe defWithSource readBool (Map.lookup (tshow WithSourceK) attrs')
+              script = mconcat $ intersperse "\n" [header, includeScript, content]
+              directory = makeValid $ unpack $ Map.findWithDefault (pack $ defaultDirectory conf) (tshow DirectoryK) attrs'
+              dpi = maybe defDPI (read . unpack) (Map.lookup (tshow DpiK) attrs')
+              extraAttrs = Map.toList extraAttrs'
+              blockAttrs = (id', filter (/= cls toolkit) classes, filteredAttrs)
+
+          let blockDependencies = parseFileDependencies $ fromMaybe mempty $ Map.lookup (tshow DependenciesK) attrs'
+              dependencies = defaultDependencies conf <> blockDependencies
+
+          -- This is the first opportunity to check save format compatibility
+          _' <-
+            unless (saveFormat `elem` rendererSupportedSaveFormats) $
+              let msg = pack $ mconcat ["Save format ", show saveFormat, " not supported by ", show toolkit]
+               in err msg
+
+          -- Ensure that the save format makes sense given the final conversion format, if known
+          return $ PFigure (FigureSpec {..})
+-- Base case: block is not a CodeBlock
+parseFigureSpec _ = return NotAFigure
+
+-- | Parse script content from a block, if possible.
+-- The script content can either come from a file
+-- or from the code block itself. If both are present,
+-- the file is preferred.
+parseContent :: Block -> PlotM Script
+parseContent (CodeBlock (_, _, attrs) content) = do
+  let attrs' = Map.fromList attrs
+      mfile = normalise . unpack <$> Map.lookup (tshow FileK) attrs'
+  when (content /= mempty && isJust mfile) $ do
+    warning $
+      mconcat
+        [ "Figure refers to a file (",
+          pack $ fromJust mfile,
+          ") but also has content in the document.\nThe file content will be preferred."
+        ]
+  let loadFromFile fp = do
+        info $ "Loading figure content from " <> pack fp
+        liftIO $ TIO.readFile fp
+  maybe (return content) loadFromFile mfile
+parseContent _ = return mempty
+
+-- | Determine which toolkit should be used to render the plot
+-- from a code block, if any.
+plotToolkit :: Block -> Maybe Toolkit
+plotToolkit (CodeBlock (_, classes, _) _) =
+  find (\tk -> cls tk `elem` classes) toolkits
+plotToolkit _ = Nothing
+
+-- | Reader a caption, based on input document format
+captionReader :: Format -> Text -> Maybe [Inline]
+captionReader (Format f) t = either (const Nothing) (Just . extractFromBlocks) $
+  runPure $ do
+    fmt <- parseFlavoredFormat f
+    (reader, exts) <- getReader fmt
+    let readerOpts = def {readerExtensions = exts}
+    -- Assuming no ByteString readers...
+    case reader of
+      TextReader fct -> fct readerOpts t
+      _ -> return mempty
+  where
+    extractFromBlocks (Pandoc _ blocks) = mconcat $ extractInlines <$> blocks
+
+    extractInlines (Plain inlines) = inlines
+    extractInlines (Para inlines) = inlines
+    extractInlines (LineBlock multiinlines) = join multiinlines
+    extractInlines _ = []
+
+-- | Flexible boolean parsing
+readBool :: Text -> Bool
+readBool s
+  | s `elem` ["True", "true", "'True'", "'true'", "1"] = True
+  | s `elem` ["False", "false", "'False'", "'false'", "0"] = False
+  | otherwise = errorWithoutStackTrace $ unpack $ mconcat ["Could not parse '", s, "' into a boolean. Please use 'True' or 'False'"]
+
+-- | Parse a list of file dependencies such as /[foo.bar, hello.txt]/.
+parseFileDependencies :: Text -> [FilePath]
+parseFileDependencies t
+  | t == mempty = mempty
+  | otherwise =
+      fmap (normalise . unpack . T.dropAround isSpace)
+        . T.splitOn ","
+        . T.dropAround (\c -> c `elem` ['[', ']'])
+        $ t
src/Text/Pandoc/Filter/Plot/Renderers.hs view
@@ -1,206 +1,212 @@-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Specification of renderers.-module Text.Pandoc.Filter.Plot.Renderers-  ( renderer,-    preambleSelector,-    parseExtraAttrs,-    executable,-    availableToolkits,-    availableToolkitsM,-    unavailableToolkits,-    unavailableToolkitsM,-    supportedSaveFormats,-    OutputSpec (..),-    Executable (..),-    Renderer (..),-  )-where--import Control.Concurrent.Async.Lifted (forConcurrently)-import Control.Monad.Reader (local)-import Data.Functor ((<&>))-import Data.List ((\\))-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as M-import Data.Maybe (catMaybes, isJust)-import Data.Text (Text, pack)-import System.Directory (findExecutable)-import System.Exit (ExitCode (..))-import Text.Pandoc.Filter.Plot.Monad-import Text.Pandoc.Filter.Plot.Monad.Logging-  ( Logger (lVerbosity),-  )-import Text.Pandoc.Filter.Plot.Renderers.Bokeh-  ( bokeh,-    bokehSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.D2-  ( d2,-    d2SupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.GGPlot2-  ( ggplot2,-    ggplot2SupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.GNUPlot-  ( gnuplot,-    gnuplotSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.Graphviz-  ( graphviz,-    graphvizSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.Mathematica-  ( mathematica,-    mathematicaSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.Matlab-  ( matlab,-    matlabSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.Matplotlib-  ( matplotlib,-    matplotlibSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.Octave-  ( octave,-    octaveSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.PlantUML-  ( plantuml,-    plantumlSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.PlotlyPython-  ( plotlyPython,-    plotlyPythonSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.PlotlyR-  ( plotlyR,-    plotlyRSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.Plotsjl-  ( plotsjl,-    plotsjlSupportedSaveFormats,-  )-import Text.Pandoc.Filter.Plot.Renderers.SageMath-  ( sagemath,-    sagemathSupportedSaveFormats,-  )---- | Get the renderer associated with a toolkit.--- If the renderer has not been used before,--- initialize it and store where it is. It will be re-used.-renderer :: Toolkit -> PlotM Renderer-renderer Matplotlib = matplotlib-renderer PlotlyPython = plotlyPython-renderer PlotlyR = plotlyR-renderer Matlab = matlab-renderer Mathematica = mathematica-renderer Octave = octave-renderer GGPlot2 = ggplot2-renderer GNUPlot = gnuplot-renderer Graphviz = graphviz-renderer Bokeh = bokeh-renderer Plotsjl = plotsjl-renderer PlantUML = plantuml-renderer SageMath = sagemath-renderer D2 = d2---- | Save formats supported by this renderer.-supportedSaveFormats :: Toolkit -> [SaveFormat]-supportedSaveFormats Matplotlib = matplotlibSupportedSaveFormats-supportedSaveFormats PlotlyPython = plotlyPythonSupportedSaveFormats-supportedSaveFormats PlotlyR = plotlyRSupportedSaveFormats-supportedSaveFormats Matlab = matlabSupportedSaveFormats-supportedSaveFormats Mathematica = mathematicaSupportedSaveFormats-supportedSaveFormats Octave = octaveSupportedSaveFormats-supportedSaveFormats GGPlot2 = ggplot2SupportedSaveFormats-supportedSaveFormats GNUPlot = gnuplotSupportedSaveFormats-supportedSaveFormats Graphviz = graphvizSupportedSaveFormats-supportedSaveFormats Bokeh = bokehSupportedSaveFormats-supportedSaveFormats Plotsjl = plotsjlSupportedSaveFormats-supportedSaveFormats PlantUML = plantumlSupportedSaveFormats-supportedSaveFormats SageMath = sagemathSupportedSaveFormats-supportedSaveFormats D2 = d2SupportedSaveFormats---- | The function that maps from configuration to the preamble.-preambleSelector :: Toolkit -> (Configuration -> Script)-preambleSelector Matplotlib = matplotlibPreamble-preambleSelector PlotlyPython = plotlyPythonPreamble-preambleSelector PlotlyR = plotlyRPreamble-preambleSelector Matlab = matlabPreamble-preambleSelector Mathematica = mathematicaPreamble-preambleSelector Octave = octavePreamble-preambleSelector GGPlot2 = ggplot2Preamble-preambleSelector GNUPlot = gnuplotPreamble-preambleSelector Graphviz = graphvizPreamble-preambleSelector Bokeh = bokehPreamble-preambleSelector Plotsjl = plotsjlPreamble-preambleSelector PlantUML = plantumlPreamble-preambleSelector SageMath = sagemathPreamble-preambleSelector D2 = d2Preamble---- | Parse code block headers for extra attributes that are specific--- to this renderer. By default, no extra attributes are parsed.-parseExtraAttrs :: Toolkit -> Map Text Text -> Map Text Text-parseExtraAttrs Matplotlib =-  M.filterWithKey-    ( \k _ ->-        k-          `elem` [ pack $ show MatplotlibTightBBoxK,-                   pack $ show MatplotlibTransparentK-                 ]-    )-parseExtraAttrs _ = return mempty---- | List of toolkits available on this machine.--- The executables to look for are taken from the configuration.-availableToolkits :: Configuration -> IO [Toolkit]-availableToolkits conf = runPlotM Nothing conf availableToolkitsM---- | List of toolkits not available on this machine.--- The executables to look for are taken from the configur-unavailableToolkits :: Configuration -> IO [Toolkit]-unavailableToolkits conf = runPlotM Nothing conf unavailableToolkitsM---- | Monadic version of @availableToolkits@.------ Note that logging is disabled-availableToolkitsM :: PlotM [Toolkit]-availableToolkitsM = asNonStrictAndSilent $ do-  mtks <- forConcurrently toolkits $ \tk -> do-    r <- renderer tk-    exe <- executable tk-    a <- isAvailable exe (rendererAvailability r)-    if a-      then return $ Just tk-      else return Nothing-  return $ catMaybes mtks-  where-    asNonStrictAndSilent = local (\(RuntimeEnv f c l d s) -> RuntimeEnv f (c {strictMode = False}) (l {lVerbosity = Silent}) d s)--    -- \| Check that the supplied command results in-    -- an exit code of 0 (i.e. no errors)-    commandSuccess :: Text -> PlotM Bool-    commandSuccess s = do-      cwd <- asks envCWD-      (ec, _) <- runCommand cwd s-      debug $ mconcat ["Command ", s, " resulted in ", pack $ show ec]-      return $ ec == ExitSuccess--    isAvailable :: Executable -> AvailabilityCheck -> PlotM Bool-    isAvailable exe (CommandSuccess f) = commandSuccess (f exe)-    isAvailable exe ExecutableExists = liftIO $ findExecutable (pathToExe exe) <&> isJust---- | Monadic version of @unavailableToolkits@-unavailableToolkitsM :: PlotM [Toolkit]-unavailableToolkitsM = (\\) toolkits <$> availableToolkitsM+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Specification of renderers.
+module Text.Pandoc.Filter.Plot.Renderers
+  ( renderer,
+    preambleSelector,
+    parseExtraAttrs,
+    executable,
+    availableToolkits,
+    availableToolkitsM,
+    unavailableToolkits,
+    unavailableToolkitsM,
+    supportedSaveFormats,
+    OutputSpec (..),
+    Executable (..),
+    Renderer (..),
+  )
+where
+
+import Control.Concurrent.Async.Lifted (forConcurrently)
+import Control.Monad.Reader (local)
+import Data.Functor ((<&>))
+import Data.List ((\\))
+import Data.Map.Strict (Map)
+import qualified Data.Map.Strict as M
+import Data.Maybe (catMaybes, isJust)
+import Data.Text (Text, pack)
+import System.Directory (findExecutable)
+import System.Exit (ExitCode (..))
+import Text.Pandoc.Filter.Plot.Monad
+import Text.Pandoc.Filter.Plot.Monad.Logging
+  ( Logger (lVerbosity),
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Bokeh
+  ( bokeh,
+    bokehSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.D2
+  ( d2,
+    d2SupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.GGPlot2
+  ( ggplot2,
+    ggplot2SupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.GNUPlot
+  ( gnuplot,
+    gnuplotSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Graphviz
+  ( graphviz,
+    graphvizSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Mathematica
+  ( mathematica,
+    mathematicaSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Matlab
+  ( matlab,
+    matlabSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Matplotlib
+  ( matplotlib,
+    matplotlibSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Octave
+  ( octave,
+    octaveSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.PlantUML
+  ( plantuml,
+    plantumlSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.PlotlyPython
+  ( plotlyPython,
+    plotlyPythonSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.PlotlyR
+  ( plotlyR,
+    plotlyRSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Plotsjl
+  ( plotsjl,
+    plotsjlSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.SageMath
+  ( sagemath,
+    sagemathSupportedSaveFormats,
+  )
+import Text.Pandoc.Filter.Plot.Renderers.Asymptote
+  ( asymptote,
+    asymptoteSupportedSaveFormats,
+  )
+-- | Get the renderer associated with a toolkit.
+-- If the renderer has not been used before,
+-- initialize it and store where it is. It will be re-used.
+renderer :: Toolkit -> PlotM Renderer
+renderer Matplotlib = matplotlib
+renderer PlotlyPython = plotlyPython
+renderer PlotlyR = plotlyR
+renderer Matlab = matlab
+renderer Mathematica = mathematica
+renderer Octave = octave
+renderer GGPlot2 = ggplot2
+renderer GNUPlot = gnuplot
+renderer Graphviz = graphviz
+renderer Bokeh = bokeh
+renderer Plotsjl = plotsjl
+renderer PlantUML = plantuml
+renderer SageMath = sagemath
+renderer D2 = d2
+renderer Asymptote = asymptote
+
+-- | Save formats supported by this renderer.
+supportedSaveFormats :: Toolkit -> [SaveFormat]
+supportedSaveFormats Matplotlib = matplotlibSupportedSaveFormats
+supportedSaveFormats PlotlyPython = plotlyPythonSupportedSaveFormats
+supportedSaveFormats PlotlyR = plotlyRSupportedSaveFormats
+supportedSaveFormats Matlab = matlabSupportedSaveFormats
+supportedSaveFormats Mathematica = mathematicaSupportedSaveFormats
+supportedSaveFormats Octave = octaveSupportedSaveFormats
+supportedSaveFormats GGPlot2 = ggplot2SupportedSaveFormats
+supportedSaveFormats GNUPlot = gnuplotSupportedSaveFormats
+supportedSaveFormats Graphviz = graphvizSupportedSaveFormats
+supportedSaveFormats Bokeh = bokehSupportedSaveFormats
+supportedSaveFormats Plotsjl = plotsjlSupportedSaveFormats
+supportedSaveFormats PlantUML = plantumlSupportedSaveFormats
+supportedSaveFormats SageMath = sagemathSupportedSaveFormats
+supportedSaveFormats D2 = d2SupportedSaveFormats
+supportedSaveFormats Asymptote = asymptoteSupportedSaveFormats
+
+-- | The function that maps from configuration to the preamble.
+preambleSelector :: Toolkit -> (Configuration -> Script)
+preambleSelector Matplotlib = matplotlibPreamble
+preambleSelector PlotlyPython = plotlyPythonPreamble
+preambleSelector PlotlyR = plotlyRPreamble
+preambleSelector Matlab = matlabPreamble
+preambleSelector Mathematica = mathematicaPreamble
+preambleSelector Octave = octavePreamble
+preambleSelector GGPlot2 = ggplot2Preamble
+preambleSelector GNUPlot = gnuplotPreamble
+preambleSelector Graphviz = graphvizPreamble
+preambleSelector Bokeh = bokehPreamble
+preambleSelector Plotsjl = plotsjlPreamble
+preambleSelector PlantUML = plantumlPreamble
+preambleSelector SageMath = sagemathPreamble
+preambleSelector D2 = d2Preamble
+preambleSelector Asymptote = asyPreamble
+
+-- | Parse code block headers for extra attributes that are specific
+-- to this renderer. By default, no extra attributes are parsed.
+parseExtraAttrs :: Toolkit -> Map Text Text -> Map Text Text
+parseExtraAttrs Matplotlib =
+  M.filterWithKey
+    ( \k _ ->
+        k
+          `elem` [ pack $ show MatplotlibTightBBoxK,
+                   pack $ show MatplotlibTransparentK
+                 ]
+    )
+parseExtraAttrs _ = return mempty
+
+-- | List of toolkits available on this machine.
+-- The executables to look for are taken from the configuration.
+availableToolkits :: Configuration -> IO [Toolkit]
+availableToolkits conf = runPlotM Nothing conf availableToolkitsM
+
+-- | List of toolkits not available on this machine.
+-- The executables to look for are taken from the configur
+unavailableToolkits :: Configuration -> IO [Toolkit]
+unavailableToolkits conf = runPlotM Nothing conf unavailableToolkitsM
+
+-- | Monadic version of @availableToolkits@.
+--
+-- Note that logging is disabled
+availableToolkitsM :: PlotM [Toolkit]
+availableToolkitsM = asNonStrictAndSilent $ do
+  mtks <- forConcurrently toolkits $ \tk -> do
+    r <- renderer tk
+    exe <- executable tk
+    a <- isAvailable exe (rendererAvailability r)
+    if a
+      then return $ Just tk
+      else return Nothing
+  return $ catMaybes mtks
+  where
+    asNonStrictAndSilent = local (\(RuntimeEnv f c l d s) -> RuntimeEnv f (c {strictMode = False}) (l {lVerbosity = Silent}) d s)
+
+    -- \| Check that the supplied command results in
+    -- an exit code of 0 (i.e. no errors)
+    commandSuccess :: Text -> PlotM Bool
+    commandSuccess s = do
+      cwd <- asks envCWD
+      (ec, _) <- runCommand cwd s
+      debug $ mconcat ["Command ", s, " resulted in ", pack $ show ec]
+      return $ ec == ExitSuccess
+
+    isAvailable :: Executable -> AvailabilityCheck -> PlotM Bool
+    isAvailable exe (CommandSuccess f) = commandSuccess (f exe)
+    isAvailable exe ExecutableExists = liftIO $ findExecutable (pathToExe exe) <&> isJust
+
+-- | Monadic version of @unavailableToolkits@
+unavailableToolkitsM :: PlotM [Toolkit]
+unavailableToolkitsM = (\\) toolkits <$> availableToolkitsM
+ src/Text/Pandoc/Filter/Plot/Renderers/Asymptote.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Asymptote plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Asymptote
+  ( asymptote,
+    asymptoteSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+import Data.Char(toLower)
+
+asymptote :: PlotM Renderer
+asymptote = do
+  cmdargs <- asksConfig asyCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Asymptote,
+        rendererCapture = asymptoteCapture,
+        rendererCommand = asymptoteCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -environment|],
+        rendererSupportedSaveFormats = asymptoteSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "asy",
+        rendererComment = mappend "// ",
+        rendererScriptExtension = ".asy"
+      }
+
+asymptoteSupportedSaveFormats :: [SaveFormat]
+asymptoteSupportedSaveFormats = [PDF, EPS, PNG]
+
+asymptoteCommand :: Text -> OutputSpec -> Text
+asymptoteCommand cmdArgs OutputSpec {..} =
+  [st|#{pathToExe oExecutable} #{cmdArgs} -f #{toLower <$> show (saveFormat oFigureSpec)} -o "#{oFigurePath}" "#{oScriptPath}"|]
+
+-- Asymptote export is entirely based on command-line arguments
+-- so there is no need to modify the script itself.
+asymptoteCapture :: FigureSpec -> FilePath -> Script
+asymptoteCapture FigureSpec {..} _ = script
src/Text/Pandoc/Filter/Plot/Renderers/Bokeh.hs view
@@ -1,80 +1,80 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Bokeh code blocks-module Text.Pandoc.Filter.Plot.Renderers.Bokeh-  ( bokeh,-    bokehSupportedSaveFormats,-  )-where--import Data.Monoid (Any (..))-import qualified Data.Text as T-import Text.Pandoc.Filter.Plot.Renderers.Prelude--bokeh :: PlotM Renderer-bokeh = do-  cmdargs <- asksConfig bokehCmdArgs-  return-    $ Renderer-      { rendererToolkit = Bokeh,-        rendererCapture = appendCapture bokehCaptureFragment,-        rendererCommand = bokehCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -c "import bokeh; import selenium"|],-        rendererSupportedSaveFormats = bokehSupportedSaveFormats,-        rendererChecks = [bokehCheckIfShow],-        rendererLanguage = "python",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".py"-      }--bokehSupportedSaveFormats :: [SaveFormat]-bokehSupportedSaveFormats = [PNG, SVG, HTML]--bokehCommand :: Text -> OutputSpec -> Text-bokehCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]---- | Check if `bokeh.io.show()` calls are present in the script,--- which would halt pandoc-plot-bokehCheckIfShow :: Script -> CheckResult-bokehCheckIfShow s =-  if getAny $ mconcat showPresent-    then CheckFailed "encountered a call to `bokeh.io.show`."-    else CheckPassed-  where-    showPresent =-      (\n -> Any (T.isInfixOf n s))-        <$> [ "bokeh.io.show(",-              "show("-            ]--bokehCaptureFragment :: FigureSpec -> FilePath -> Script-bokehCaptureFragment FigureSpec {..} fname =-  [st|-from bokeh.io import export_png, export_svgs, save-from bokeh.models import Model-from bokeh.resources import CDN--# The heuristic to determine the current Model is to find all objects which are-# at least subclasses of bokeh.models.Model, and then find the one which was-# created last. This is a dirty hack, so if you're reading this, don't hesitate to-# suggest something else.-__current_model = [obj for obj in globals().values() if isinstance(obj, Model)][-1]-#{write}-|]-  where-    write = case saveFormat of-      HTML -> [st|save(__current_model, filename=r"#{fname}", resources=CDN)|]-      SVG -> [st|__current_model.output_backend="svg"; export_svgs(__current_model, filename=r"#{fname}")|]-      PNG -> [st|export_png(obj = __current_model, filename=r"#{fname}")|]-      fmt -> errorWithoutStackTrace $ "Save format not supported: " <> show fmt+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Bokeh code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Bokeh
+  ( bokeh,
+    bokehSupportedSaveFormats,
+  )
+where
+
+import Data.Monoid (Any (..))
+import qualified Data.Text as T
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+bokeh :: PlotM Renderer
+bokeh = do
+  cmdargs <- asksConfig bokehCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Bokeh,
+        rendererCapture = appendCapture bokehCaptureFragment,
+        rendererCommand = bokehCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -c "import bokeh; import selenium"|],
+        rendererSupportedSaveFormats = bokehSupportedSaveFormats,
+        rendererChecks = [bokehCheckIfShow],
+        rendererLanguage = "python",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".py"
+      }
+
+bokehSupportedSaveFormats :: [SaveFormat]
+bokehSupportedSaveFormats = [PNG, SVG, HTML]
+
+bokehCommand :: Text -> OutputSpec -> Text
+bokehCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
+
+-- | Check if `bokeh.io.show()` calls are present in the script,
+-- which would halt pandoc-plot
+bokehCheckIfShow :: Script -> CheckResult
+bokehCheckIfShow s =
+  if getAny $ mconcat showPresent
+    then CheckFailed "encountered a call to `bokeh.io.show`."
+    else CheckPassed
+  where
+    showPresent =
+      (\n -> Any (T.isInfixOf n s))
+        <$> [ "bokeh.io.show(",
+              "show("
+            ]
+
+bokehCaptureFragment :: FigureSpec -> FilePath -> Script
+bokehCaptureFragment FigureSpec {..} fname =
+  [st|
+from bokeh.io import export_png, export_svgs, save
+from bokeh.models import Model
+from bokeh.resources import CDN
+
+# The heuristic to determine the current Model is to find all objects which are
+# at least subclasses of bokeh.models.Model, and then find the one which was
+# created last. This is a dirty hack, so if you're reading this, don't hesitate to
+# suggest something else.
+__current_model = [obj for obj in globals().values() if isinstance(obj, Model)][-1]
+#{write}
+|]
+  where
+    write = case saveFormat of
+      HTML -> [st|save(__current_model, filename=r"#{fname}", resources=CDN)|]
+      SVG -> [st|__current_model.output_backend="svg"; export_svgs(__current_model, filename=r"#{fname}")|]
+      PNG -> [st|export_png(obj = __current_model, filename=r"#{fname}")|]
+      fmt -> errorWithoutStackTrace $ "Save format not supported: " <> show fmt
src/Text/Pandoc/Filter/Plot/Renderers/D2.hs view
@@ -1,48 +1,48 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Sanchayan Maity, 2023 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : sanchayan@sanchayanmaity.net--- Stability   : internal--- Portability : portable------ Rendering D2 plots code blocks-module Text.Pandoc.Filter.Plot.Renderers.D2-  ( d2,-    d2SupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--d2 :: PlotM Renderer-d2 = do-  cmdargs <- asksConfig d2CmdArgs-  return-    $ Renderer-      { rendererToolkit = D2,-        rendererCapture = d2Capture,-        rendererCommand = d2Command cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -v|],-        rendererSupportedSaveFormats = d2SupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "d2",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".d2"-      }--d2SupportedSaveFormats :: [SaveFormat]-d2SupportedSaveFormats = [PNG, PDF, SVG]--d2Command :: Text -> OutputSpec -> Text-d2Command cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}" "#{oFigurePath}"|]---- d2 export is entirely based on command-line arguments--- so there is no need to modify the script itself.-d2Capture :: FigureSpec -> FilePath -> Script-d2Capture FigureSpec {..} _ = script+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Sanchayan Maity, 2023 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : sanchayan@sanchayanmaity.net
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering D2 plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.D2
+  ( d2,
+    d2SupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+d2 :: PlotM Renderer
+d2 = do
+  cmdargs <- asksConfig d2CmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = D2,
+        rendererCapture = d2Capture,
+        rendererCommand = d2Command cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -v|],
+        rendererSupportedSaveFormats = d2SupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "d2",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".d2"
+      }
+
+d2SupportedSaveFormats :: [SaveFormat]
+d2SupportedSaveFormats = [PNG, PDF, SVG]
+
+d2Command :: Text -> OutputSpec -> Text
+d2Command cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}" "#{oFigurePath}"|]
+
+-- d2 export is entirely based on command-line arguments
+-- so there is no need to modify the script itself.
+d2Capture :: FigureSpec -> FilePath -> Script
+d2Capture FigureSpec {..} _ = script
src/Text/Pandoc/Filter/Plot/Renderers/GGPlot2.hs view
@@ -1,59 +1,59 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering GGPlot2 plots code blocks-module Text.Pandoc.Filter.Plot.Renderers.GGPlot2-  ( ggplot2,-    ggplot2SupportedSaveFormats,-  )-where--import qualified Data.Text as T-import Text.Pandoc.Filter.Plot.Renderers.Prelude--ggplot2 :: PlotM Renderer-ggplot2 = do-  cmdargs <- asksConfig ggplot2CmdArgs-  return-    $ Renderer-      { rendererToolkit = GGPlot2,-        rendererCapture = ggplot2Capture,-        rendererCommand = ggplot2Command cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -e "if(!require('ggplot2')) {quit(status=1)}"|],-        rendererSupportedSaveFormats = ggplot2SupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "r",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".r"-      }--ggplot2SupportedSaveFormats :: [SaveFormat]-ggplot2SupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, TIF]--ggplot2Command :: Text -> OutputSpec -> Text-ggplot2Command cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]--ggplot2Capture :: FigureSpec -> FilePath -> Script-ggplot2Capture fs fp =-  T.unlines-    [ "pdf(NULL)", -- Prevent the creation of empty Rplots.pdf-      script fs,-      ggplot2CaptureFragment fs fp-    ]--ggplot2CaptureFragment :: FigureSpec -> FilePath -> Script-ggplot2CaptureFragment FigureSpec {..} fname =-  [st|-library(ggplot2) # just in case-ggsave("#{toRPath fname}", plot = last_plot(), dpi = #{dpi})-|]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering GGPlot2 plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.GGPlot2
+  ( ggplot2,
+    ggplot2SupportedSaveFormats,
+  )
+where
+
+import qualified Data.Text as T
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+ggplot2 :: PlotM Renderer
+ggplot2 = do
+  cmdargs <- asksConfig ggplot2CmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = GGPlot2,
+        rendererCapture = ggplot2Capture,
+        rendererCommand = ggplot2Command cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -e "if(!require('ggplot2')) {quit(status=1)}"|],
+        rendererSupportedSaveFormats = ggplot2SupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "r",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".r"
+      }
+
+ggplot2SupportedSaveFormats :: [SaveFormat]
+ggplot2SupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS]
+
+ggplot2Command :: Text -> OutputSpec -> Text
+ggplot2Command cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
+
+ggplot2Capture :: FigureSpec -> FilePath -> Script
+ggplot2Capture fs fp =
+  T.unlines
+    [ "pdf(NULL)", -- Prevent the creation of empty Rplots.pdf
+      script fs,
+      ggplot2CaptureFragment fs fp
+    ]
+
+ggplot2CaptureFragment :: FigureSpec -> FilePath -> Script
+ggplot2CaptureFragment FigureSpec {..} fname =
+  [st|
+library(ggplot2) # just in case
+ggsave("#{toRPath fname}", plot = last_plot(), dpi = #{dpi})
+|]
src/Text/Pandoc/Filter/Plot/Renderers/GNUPlot.hs view
@@ -1,71 +1,71 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering gnuplot plots code blocks-module Text.Pandoc.Filter.Plot.Renderers.GNUPlot-  ( gnuplot,-    gnuplotSupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--gnuplot :: PlotM Renderer-gnuplot = do-  cmdargs <- asksConfig gnuplotCmdArgs-  return-    $ Renderer-      { rendererToolkit = GNUPlot,-        rendererCapture = gnuplotCapture,-        rendererCommand = gnuplotCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -h|],-        rendererSupportedSaveFormats = gnuplotSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "gnuplot",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".gp"-      }--gnuplotSupportedSaveFormats :: [SaveFormat]-gnuplotSupportedSaveFormats = [LaTeX, PNG, SVG, EPS, GIF, JPG, PDF]--gnuplotCommand :: Text -> OutputSpec -> Text-gnuplotCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} -c "#{oScriptPath}"|]--gnuplotCapture :: FigureSpec -> FilePath -> Script-gnuplotCapture = prependCapture gnuplotCaptureFragment-  where-    prependCapture f s fp = mconcat [f s fp, "\n", script s]--gnuplotCaptureFragment :: FigureSpec -> FilePath -> Script-gnuplotCaptureFragment FigureSpec {..} fname =-  [st|-set terminal #{terminalString saveFormat}-set output '#{normalizePath fname}'-|]-  where-    normalizePath = map f-      where-        f '\\' = '/'-        f x = x---- | Terminal name for supported save formats-terminalString :: SaveFormat -> Text-terminalString PNG = "pngcairo"-terminalString SVG = "svg"-terminalString EPS = "postscript eps"-terminalString GIF = "gif"-terminalString JPG = "jpeg"-terminalString PDF = "pdfcairo"-terminalString LaTeX = "cairolatex"-terminalString fmt = errorWithoutStackTrace $ "gnuplot: unsupported save format" <> show fmt+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering gnuplot plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.GNUPlot
+  ( gnuplot,
+    gnuplotSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+gnuplot :: PlotM Renderer
+gnuplot = do
+  cmdargs <- asksConfig gnuplotCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = GNUPlot,
+        rendererCapture = gnuplotCapture,
+        rendererCommand = gnuplotCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -h|],
+        rendererSupportedSaveFormats = gnuplotSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "gnuplot",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".gp"
+      }
+
+gnuplotSupportedSaveFormats :: [SaveFormat]
+gnuplotSupportedSaveFormats = [LaTeX, PNG, SVG, EPS, GIF, JPG, PDF]
+
+gnuplotCommand :: Text -> OutputSpec -> Text
+gnuplotCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} -c "#{oScriptPath}"|]
+
+gnuplotCapture :: FigureSpec -> FilePath -> Script
+gnuplotCapture = prependCapture gnuplotCaptureFragment
+  where
+    prependCapture f s fp = mconcat [f s fp, "\n", script s]
+
+gnuplotCaptureFragment :: FigureSpec -> FilePath -> Script
+gnuplotCaptureFragment FigureSpec {..} fname =
+  [st|
+set terminal #{terminalString saveFormat}
+set output '#{normalizePath fname}'
+|]
+  where
+    normalizePath = map f
+      where
+        f '\\' = '/'
+        f x = x
+
+-- | Terminal name for supported save formats
+terminalString :: SaveFormat -> Text
+terminalString PNG = "pngcairo"
+terminalString SVG = "svg"
+terminalString EPS = "postscript eps"
+terminalString GIF = "gif"
+terminalString JPG = "jpeg"
+terminalString PDF = "pdfcairo"
+terminalString LaTeX = "cairolatex"
+terminalString fmt = errorWithoutStackTrace $ "gnuplot: unsupported save format" <> show fmt
src/Text/Pandoc/Filter/Plot/Renderers/Graphviz.hs view
@@ -1,55 +1,55 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Graphviz plots code blocks-module Text.Pandoc.Filter.Plot.Renderers.Graphviz-  ( graphviz,-    graphvizSupportedSaveFormats,-  )-where--import Data.Char-import Text.Pandoc.Filter.Plot.Renderers.Prelude--graphviz :: PlotM Renderer-graphviz = do-  cmdargs <- asksConfig graphvizCmdArgs-  return-    $ Renderer-      { rendererToolkit = Graphviz,-        rendererCapture = graphvizCapture,-        rendererCommand = graphvizCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -?|],-        rendererSupportedSaveFormats = graphvizSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "dot",-        rendererComment = mappend "// ",-        rendererScriptExtension = ".dot"-      }--graphvizSupportedSaveFormats :: [SaveFormat]-graphvizSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, WEBP, GIF]--graphvizCommand :: Text -> OutputSpec -> Text-graphvizCommand cmdargs OutputSpec {..} =-  let fmt = fmap toLower . show . saveFormat $ oFigureSpec-      -- Specifying a DPI when the output format is SVG crops the final figure-      -- See issue #40-      -- TODO: does this also affect other vector formats like EPS?-      dpi' = if saveFormat oFigureSpec == SVG then mempty else [st|-Gdpi=#{dpi oFigureSpec}|]-   in [st|#{pathToExe oExecutable} #{cmdargs} -T#{fmt} #{dpi'} -o "#{oFigurePath}" "#{oScriptPath}"|]---- Graphviz export is entirely based on command-line arguments--- so there is no need to modify the script itself.-graphvizCapture :: FigureSpec -> FilePath -> Script-graphvizCapture FigureSpec {..} _ = script+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Graphviz plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Graphviz
+  ( graphviz,
+    graphvizSupportedSaveFormats,
+  )
+where
+
+import Data.Char
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+graphviz :: PlotM Renderer
+graphviz = do
+  cmdargs <- asksConfig graphvizCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Graphviz,
+        rendererCapture = graphvizCapture,
+        rendererCommand = graphvizCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -?|],
+        rendererSupportedSaveFormats = graphvizSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "dot",
+        rendererComment = mappend "// ",
+        rendererScriptExtension = ".dot"
+      }
+
+graphvizSupportedSaveFormats :: [SaveFormat]
+graphvizSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, WEBP, GIF]
+
+graphvizCommand :: Text -> OutputSpec -> Text
+graphvizCommand cmdargs OutputSpec {..} =
+  let fmt = fmap toLower . show . saveFormat $ oFigureSpec
+      -- Specifying a DPI when the output format is SVG crops the final figure
+      -- See issue #40
+      -- TODO: does this also affect other vector formats like EPS?
+      dpi' = if saveFormat oFigureSpec == SVG then mempty else [st|-Gdpi=#{dpi oFigureSpec}|]
+   in [st|#{pathToExe oExecutable} #{cmdargs} -T#{fmt} #{dpi'} -o "#{oFigurePath}" "#{oScriptPath}"|]
+
+-- Graphviz export is entirely based on command-line arguments
+-- so there is no need to modify the script itself.
+graphvizCapture :: FigureSpec -> FilePath -> Script
+graphvizCapture FigureSpec {..} _ = script
src/Text/Pandoc/Filter/Plot/Renderers/Mathematica.hs view
@@ -1,53 +1,53 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Mathematica plots code blocks-module Text.Pandoc.Filter.Plot.Renderers.Mathematica-  ( mathematica,-    mathematicaSupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--mathematica :: PlotM Renderer-mathematica = do-  cmdargs <- asksConfig mathematicaCmdArgs-  return-    $ Renderer-      { rendererToolkit = Mathematica,-        rendererCapture = mathematicaCapture,-        rendererCommand = mathematicaCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -h|],-        -- TODO: test this-        rendererSupportedSaveFormats = mathematicaSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "mathematica",-        rendererComment = \t -> mconcat ["(*", t, "*)"],-        rendererScriptExtension = ".m"-      }--mathematicaSupportedSaveFormats :: [SaveFormat]-mathematicaSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]--mathematicaCommand :: Text -> OutputSpec -> Text-mathematicaCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} -script "#{oScriptPath}"|]--mathematicaCapture :: FigureSpec -> FilePath -> Script-mathematicaCapture = appendCapture mathematicaCaptureFragment--mathematicaCaptureFragment :: FigureSpec -> FilePath -> Script-mathematicaCaptureFragment FigureSpec {..} fname =-  [st|-Export["#{fname}", %, #{show saveFormat}, ImageResolution -> #{dpi}]-|]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Mathematica plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Mathematica
+  ( mathematica,
+    mathematicaSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+mathematica :: PlotM Renderer
+mathematica = do
+  cmdargs <- asksConfig mathematicaCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Mathematica,
+        rendererCapture = mathematicaCapture,
+        rendererCommand = mathematicaCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -h|],
+        -- TODO: test this
+        rendererSupportedSaveFormats = mathematicaSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "mathematica",
+        rendererComment = \t -> mconcat ["(*", t, "*)"],
+        rendererScriptExtension = ".m"
+      }
+
+mathematicaSupportedSaveFormats :: [SaveFormat]
+mathematicaSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]
+
+mathematicaCommand :: Text -> OutputSpec -> Text
+mathematicaCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} -script "#{oScriptPath}"|]
+
+mathematicaCapture :: FigureSpec -> FilePath -> Script
+mathematicaCapture = appendCapture mathematicaCaptureFragment
+
+mathematicaCaptureFragment :: FigureSpec -> FilePath -> Script
+mathematicaCaptureFragment FigureSpec {..} fname =
+  [st|
+Export["#{fname}", %, #{show saveFormat}, ImageResolution -> #{dpi}]
+|]
src/Text/Pandoc/Filter/Plot/Renderers/Matlab.hs view
@@ -1,71 +1,71 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Matlab code blocks-module Text.Pandoc.Filter.Plot.Renderers.Matlab-  ( matlab,-    matlabSupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--matlab :: PlotM Renderer-matlab = do-  cmdargs <- asksConfig matlabCmdArgs-  return-    $ Renderer-      { rendererToolkit = Matlab,-        rendererCapture = matlabCapture,-        rendererCommand = matlabCommand cmdargs,-        -- On Windows at least, "matlab -help"  actually returns -1, even though the-        -- help text is shown successfully!-        -- Therefore, we cannot rely on this behavior to know if matlab is present,-        -- like other toolkits.-        rendererAvailability = ExecutableExists,-        rendererSupportedSaveFormats = matlabSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "matlab",-        rendererComment = mappend "% ",-        rendererScriptExtension = ".m"-      }--matlabSupportedSaveFormats :: [SaveFormat]-matlabSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]--matlabCommand :: Text -> OutputSpec -> Text-matlabCommand cmdargs OutputSpec {..} =-  -- The MATLAB 'run' function will switch to the directory where the script-  -- is located before executing the script. Therefore, we first save the current-  -- working directory in the variable 'pandoc_plot_cwd' so that we can use it-  -- when exporting the figure-  [st|#{pathToExe oExecutable} #{cmdargs} -sd '#{oCWD}' -noFigureWindows -batch "pandoc_plot_cwd=pwd; run('#{oScriptPath}')"|]--matlabCapture :: FigureSpec -> FilePath -> Script-matlabCapture = appendCapture matlabCaptureFragment--matlabCaptureFragment :: FigureSpec -> FilePath -> Script-matlabCaptureFragment FigureSpec {..} fname =-  [st|-if java.io.File('#{fname}').isAbsolute() > 0-  exportpath = '#{fname}';-else-  exportpath = fullfile(pandoc_plot_cwd, '#{fname}');-end--if exist("exportgraphics")>0-    exportgraphics(gcf, exportpath, 'Resolution', #{dpi});-else-    saveas(gcf, exportpath);-end-|]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Matlab code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Matlab
+  ( matlab,
+    matlabSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+matlab :: PlotM Renderer
+matlab = do
+  cmdargs <- asksConfig matlabCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Matlab,
+        rendererCapture = matlabCapture,
+        rendererCommand = matlabCommand cmdargs,
+        -- On Windows at least, "matlab -help"  actually returns -1, even though the
+        -- help text is shown successfully!
+        -- Therefore, we cannot rely on this behavior to know if matlab is present,
+        -- like other toolkits.
+        rendererAvailability = ExecutableExists,
+        rendererSupportedSaveFormats = matlabSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "matlab",
+        rendererComment = mappend "% ",
+        rendererScriptExtension = ".m"
+      }
+
+matlabSupportedSaveFormats :: [SaveFormat]
+matlabSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]
+
+matlabCommand :: Text -> OutputSpec -> Text
+matlabCommand cmdargs OutputSpec {..} =
+  -- The MATLAB 'run' function will switch to the directory where the script
+  -- is located before executing the script. Therefore, we first save the current
+  -- working directory in the variable 'pandoc_plot_cwd' so that we can use it
+  -- when exporting the figure
+  [st|#{pathToExe oExecutable} #{cmdargs} -sd '#{oCWD}' -noFigureWindows -batch "pandoc_plot_cwd=pwd; run('#{oScriptPath}')"|]
+
+matlabCapture :: FigureSpec -> FilePath -> Script
+matlabCapture = appendCapture matlabCaptureFragment
+
+matlabCaptureFragment :: FigureSpec -> FilePath -> Script
+matlabCaptureFragment FigureSpec {..} fname =
+  [st|
+if java.io.File('#{fname}').isAbsolute() > 0
+  exportpath = '#{fname}';
+else
+  exportpath = fullfile(pandoc_plot_cwd, '#{fname}');
+end
+
+if exist("exportgraphics")>0
+    exportgraphics(gcf, exportpath, 'Resolution', #{dpi});
+else
+    saveas(gcf, exportpath);
+end
+|]
src/Text/Pandoc/Filter/Plot/Renderers/Matplotlib.hs view
@@ -1,88 +1,88 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Matplotlib code blocks.------ Note that the MatplotlibM renderer supports two extra arguments:---     * @tight_bbox=True|False@ : Make plot bounding box tight. Default is False---     * @transparent=True|False@ : Make plot background transparent (perfect for web pages). Default is False.-module Text.Pandoc.Filter.Plot.Renderers.Matplotlib-  ( matplotlib,-    matplotlibSupportedSaveFormats,-  )-where--import qualified Data.Map.Strict as M-import Data.Monoid (Any (..))-import qualified Data.Text as T-import Text.Pandoc.Filter.Plot.Renderers.Prelude--matplotlib :: PlotM Renderer-matplotlib = do-  cmdargs <- asksConfig matplotlibCmdArgs-  return-    $ Renderer-      { rendererToolkit = Matplotlib,-        rendererCapture = matplotlibCapture,-        rendererCommand = matplotlibCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -c "import matplotlib"|],-        rendererSupportedSaveFormats = matplotlibSupportedSaveFormats,-        rendererChecks = [matplotlibCheckIfShow],-        rendererLanguage = "python",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".py"-      }--matplotlibSupportedSaveFormats :: [SaveFormat]-matplotlibSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]--matplotlibCommand :: Text -> OutputSpec -> Text-matplotlibCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]--matplotlibCapture :: FigureSpec -> FilePath -> Script-matplotlibCapture = appendCapture matplotlibCaptureFragment--matplotlibCaptureFragment :: FigureSpec -> FilePath -> Script-matplotlibCaptureFragment FigureSpec {..} fname =-  [st|-import matplotlib.pyplot as plt-plt.savefig(r"#{fname}", dpi=#{dpi}, transparent=#{transparent}, bbox_inches=#{tightBox})-|]-  where-    attrs = M.fromList extraAttrs-    tight_ = readBool $ M.findWithDefault "False" (T.pack $ show MatplotlibTightBBoxK) attrs-    transparent_ = readBool $ M.findWithDefault "False" (T.pack $ show MatplotlibTransparentK) attrs-    tightBox = if tight_ then ("'tight'" :: Text) else ("None" :: Text)-    transparent = if transparent_ then ("True" :: Text) else ("False" :: Text)---- | Check if `matplotlib.pyplot.show()` calls are present in the script,--- which would halt pandoc-plot-matplotlibCheckIfShow :: Script -> CheckResult-matplotlibCheckIfShow s =-  if getAny $ mconcat showPresent-    then CheckFailed "encountered a call to `matplotlib.pyplot.show` or `plt.show`, which would stall `pandoc-plot"-    else CheckPassed-  where-    showPresent =-      (\n -> Any (T.isInfixOf n s))-        <$> [ "matplotlib.pyplot.show()",-              "pyplot.show()",-              "plt.show()"-            ]---- | Flexible boolean parsing-readBool :: Text -> Bool-readBool s-  | s `elem` ["True", "true", "'True'", "'true'", "1"] = True-  | s `elem` ["False", "false", "'False'", "'false'", "0"] = False-  | otherwise = errorWithoutStackTrace $ unpack $ mconcat ["Could not parse '", s, "' into a boolean. Please use 'True' or 'False'"]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Matplotlib code blocks.
+--
+-- Note that the MatplotlibM renderer supports two extra arguments:
+--     * @tight_bbox=True|False@ : Make plot bounding box tight. Default is False
+--     * @transparent=True|False@ : Make plot background transparent (perfect for web pages). Default is False.
+module Text.Pandoc.Filter.Plot.Renderers.Matplotlib
+  ( matplotlib,
+    matplotlibSupportedSaveFormats,
+  )
+where
+
+import qualified Data.Map.Strict as M
+import Data.Monoid (Any (..))
+import qualified Data.Text as T
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+matplotlib :: PlotM Renderer
+matplotlib = do
+  cmdargs <- asksConfig matplotlibCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Matplotlib,
+        rendererCapture = matplotlibCapture,
+        rendererCommand = matplotlibCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -c "import matplotlib"|],
+        rendererSupportedSaveFormats = matplotlibSupportedSaveFormats,
+        rendererChecks = [matplotlibCheckIfShow],
+        rendererLanguage = "python",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".py"
+      }
+
+matplotlibSupportedSaveFormats :: [SaveFormat]
+matplotlibSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, TIF]
+
+matplotlibCommand :: Text -> OutputSpec -> Text
+matplotlibCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
+
+matplotlibCapture :: FigureSpec -> FilePath -> Script
+matplotlibCapture = appendCapture matplotlibCaptureFragment
+
+matplotlibCaptureFragment :: FigureSpec -> FilePath -> Script
+matplotlibCaptureFragment FigureSpec {..} fname =
+  [st|
+import matplotlib.pyplot as plt
+plt.savefig(r"#{fname}", dpi=#{dpi}, transparent=#{transparent}, bbox_inches=#{tightBox})
+|]
+  where
+    attrs = M.fromList extraAttrs
+    tight_ = readBool $ M.findWithDefault "False" (T.pack $ show MatplotlibTightBBoxK) attrs
+    transparent_ = readBool $ M.findWithDefault "False" (T.pack $ show MatplotlibTransparentK) attrs
+    tightBox = if tight_ then ("'tight'" :: Text) else ("None" :: Text)
+    transparent = if transparent_ then ("True" :: Text) else ("False" :: Text)
+
+-- | Check if `matplotlib.pyplot.show()` calls are present in the script,
+-- which would halt pandoc-plot
+matplotlibCheckIfShow :: Script -> CheckResult
+matplotlibCheckIfShow s =
+  if getAny $ mconcat showPresent
+    then CheckFailed "encountered a call to `matplotlib.pyplot.show` or `plt.show`, which would stall `pandoc-plot"
+    else CheckPassed
+  where
+    showPresent =
+      (\n -> Any (T.isInfixOf n s))
+        <$> [ "matplotlib.pyplot.show()",
+              "pyplot.show()",
+              "plt.show()"
+            ]
+
+-- | Flexible boolean parsing
+readBool :: Text -> Bool
+readBool s
+  | s `elem` ["True", "true", "'True'", "'true'", "1"] = True
+  | s `elem` ["False", "false", "'False'", "'false'", "0"] = False
+  | otherwise = errorWithoutStackTrace $ unpack $ mconcat ["Could not parse '", s, "' into a boolean. Please use 'True' or 'False'"]
src/Text/Pandoc/Filter/Plot/Renderers/Octave.hs view
@@ -1,52 +1,52 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Octave plots code blocks-module Text.Pandoc.Filter.Plot.Renderers.Octave-  ( octave,-    octaveSupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--octave :: PlotM Renderer-octave = do-  cmdargs <- asksConfig octaveCmdArgs-  return-    $ Renderer-      { rendererToolkit = Octave,-        rendererCapture = octaveCapture,-        rendererCommand = octaveCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -h|],-        rendererSupportedSaveFormats = octaveSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "matlab",-        rendererComment = mappend "% ",-        rendererScriptExtension = ".m"-      }--octaveSupportedSaveFormats :: [SaveFormat]-octaveSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]--octaveCommand :: Text -> OutputSpec -> Text-octaveCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} --no-gui --no-window-system "#{oScriptPath}"|]--octaveCapture :: FigureSpec -> FilePath -> Script-octaveCapture = appendCapture octaveCaptureFragment--octaveCaptureFragment :: FigureSpec -> FilePath -> Script-octaveCaptureFragment _ fname =-  [st|-saveas(gcf, '#{fname}')-|]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Octave plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Octave
+  ( octave,
+    octaveSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+octave :: PlotM Renderer
+octave = do
+  cmdargs <- asksConfig octaveCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Octave,
+        rendererCapture = octaveCapture,
+        rendererCommand = octaveCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -h|],
+        rendererSupportedSaveFormats = octaveSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "matlab",
+        rendererComment = mappend "% ",
+        rendererScriptExtension = ".m"
+      }
+
+octaveSupportedSaveFormats :: [SaveFormat]
+octaveSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]
+
+octaveCommand :: Text -> OutputSpec -> Text
+octaveCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} --no-gui --no-window-system "#{oScriptPath}"|]
+
+octaveCapture :: FigureSpec -> FilePath -> Script
+octaveCapture = appendCapture octaveCaptureFragment
+
+octaveCaptureFragment :: FigureSpec -> FilePath -> Script
+octaveCaptureFragment _ fname =
+  [st|
+saveas(gcf, '#{fname}')
+|]
src/Text/Pandoc/Filter/Plot/Renderers/PlantUML.hs view
@@ -1,62 +1,62 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering PlantUML markup-module Text.Pandoc.Filter.Plot.Renderers.PlantUML-  ( plantuml,-    plantumlSupportedSaveFormats,-  )-where--import Data.Char-import System.FilePath (takeDirectory, (</>))-import Text.Pandoc.Filter.Plot.Renderers.Prelude--plantuml :: PlotM Renderer-plantuml = do-  cmdargs <- asksConfig plantumlCmdArgs-  return-    $ Renderer-      { rendererToolkit = PlantUML,-        rendererCapture = plantumlCapture,-        rendererCommand = plantumlCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} #{cmdargs} -h|],-        rendererSupportedSaveFormats = plantumlSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "plantuml",-        rendererComment = mappend "' ",-        rendererScriptExtension = ".txt"-      }--plantumlSupportedSaveFormats :: [SaveFormat]-plantumlSupportedSaveFormats = [PNG, PDF, SVG]--plantumlCommand :: Text -> OutputSpec -> Text-plantumlCommand cmdargs OutputSpec {..} =-  let fmt = fmap toLower . show . saveFormat $ oFigureSpec-      dir = takeDirectory oFigurePath-   in -- the command below works as long as the script name is the same basename-      -- as the target figure path. E.g.: script basename of pandocplot123456789.txt-      -- will result in pandocplot123456789.(extension)-      [st|#{pathToExe oExecutable} #{cmdargs} -t#{fmt} -output "#{oCWD </> dir}" "#{normalizePath oScriptPath}"|]--normalizePath :: String -> String-normalizePath = map f-  where-    f '\\' = '/'-    f x = x---- PlantUML export is entirely based on command-line arguments--- so there is no need to modify the script itself.-plantumlCapture :: FigureSpec -> FilePath -> Script-plantumlCapture FigureSpec {..} _ = script+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering PlantUML markup
+module Text.Pandoc.Filter.Plot.Renderers.PlantUML
+  ( plantuml,
+    plantumlSupportedSaveFormats,
+  )
+where
+
+import Data.Char
+import System.FilePath (takeDirectory, (</>))
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+plantuml :: PlotM Renderer
+plantuml = do
+  cmdargs <- asksConfig plantumlCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = PlantUML,
+        rendererCapture = plantumlCapture,
+        rendererCommand = plantumlCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} #{cmdargs} -h|],
+        rendererSupportedSaveFormats = plantumlSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "plantuml",
+        rendererComment = mappend "' ",
+        rendererScriptExtension = ".txt"
+      }
+
+plantumlSupportedSaveFormats :: [SaveFormat]
+plantumlSupportedSaveFormats = [PNG, PDF, SVG]
+
+plantumlCommand :: Text -> OutputSpec -> Text
+plantumlCommand cmdargs OutputSpec {..} =
+  let fmt = fmap toLower . show . saveFormat $ oFigureSpec
+      dir = takeDirectory oFigurePath
+   in -- the command below works as long as the script name is the same basename
+      -- as the target figure path. E.g.: script basename of pandocplot123456789.txt
+      -- will result in pandocplot123456789.(extension)
+      [st|#{pathToExe oExecutable} #{cmdargs} -t#{fmt} -output "#{oCWD </> dir}" "#{normalizePath oScriptPath}"|]
+
+normalizePath :: String -> String
+normalizePath = map f
+  where
+    f '\\' = '/'
+    f x = x
+
+-- PlantUML export is entirely based on command-line arguments
+-- so there is no need to modify the script itself.
+plantumlCapture :: FigureSpec -> FilePath -> Script
+plantumlCapture FigureSpec {..} _ = script
src/Text/Pandoc/Filter/Plot/Renderers/PlotlyPython.hs view
@@ -1,64 +1,64 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Plotly-python code blocks-module Text.Pandoc.Filter.Plot.Renderers.PlotlyPython-  ( plotlyPython,-    plotlyPythonSupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--plotlyPython :: PlotM Renderer-plotlyPython = do-  cmdargs <- asksConfig plotlyPythonCmdArgs-  return-    $ Renderer-      { rendererToolkit = PlotlyPython,-        rendererCapture = plotlyPythonCapture,-        rendererCommand = plotlyPythonCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -c "import plotly.graph_objects"|],-        rendererSupportedSaveFormats = plotlyPythonSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "python",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".py"-      }--plotlyPythonSupportedSaveFormats :: [SaveFormat]-plotlyPythonSupportedSaveFormats = [PNG, JPG, WEBP, PDF, SVG, EPS, HTML]--plotlyPythonCommand :: Text -> OutputSpec -> Text-plotlyPythonCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]--plotlyPythonCapture :: FigureSpec -> FilePath -> Script-plotlyPythonCapture = appendCapture plotlyPythonCaptureFragment--plotlyPythonCaptureFragment :: FigureSpec -> FilePath -> Script-plotlyPythonCaptureFragment FigureSpec {..} fname =-  [st|-import plotly.graph_objects as go-__current_plotly_figure = next(obj for obj in globals().values() if type(obj) == go.Figure)-__current_plotly_figure.#{write_method}(r"#{fname}"#{extra_args})-|]-  where-    -- Note: the default behaviour for HTML export is-    --       to embed the entire Plotly.js content. This means-    --       that the resulting file can be used completely offline-    write_method = case saveFormat of-      HTML -> "write_html" :: Text-      _ -> "write_image"-    extra_args = case saveFormat of-      HTML -> ", include_plotlyjs='cdn'" :: Text-      _ -> mempty+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Plotly-python code blocks
+module Text.Pandoc.Filter.Plot.Renderers.PlotlyPython
+  ( plotlyPython,
+    plotlyPythonSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+plotlyPython :: PlotM Renderer
+plotlyPython = do
+  cmdargs <- asksConfig plotlyPythonCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = PlotlyPython,
+        rendererCapture = plotlyPythonCapture,
+        rendererCommand = plotlyPythonCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -c "import plotly.graph_objects"|],
+        rendererSupportedSaveFormats = plotlyPythonSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "python",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".py"
+      }
+
+plotlyPythonSupportedSaveFormats :: [SaveFormat]
+plotlyPythonSupportedSaveFormats = [PNG, JPG, WEBP, PDF, SVG, EPS, HTML]
+
+plotlyPythonCommand :: Text -> OutputSpec -> Text
+plotlyPythonCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
+
+plotlyPythonCapture :: FigureSpec -> FilePath -> Script
+plotlyPythonCapture = appendCapture plotlyPythonCaptureFragment
+
+plotlyPythonCaptureFragment :: FigureSpec -> FilePath -> Script
+plotlyPythonCaptureFragment FigureSpec {..} fname =
+  [st|
+import plotly.graph_objects as go
+__current_plotly_figure = next(obj for obj in globals().values() if type(obj) == go.Figure)
+__current_plotly_figure.#{write_method}(r"#{fname}"#{extra_args})
+|]
+  where
+    -- Note: the default behaviour for HTML export is
+    --       to embed the entire Plotly.js content. This means
+    --       that the resulting file can be used completely offline
+    write_method = case saveFormat of
+      HTML -> "write_html" :: Text
+      _ -> "write_image"
+    extra_args = case saveFormat of
+      HTML -> ", include_plotlyjs='cdn'" :: Text
+      _ -> mempty
src/Text/Pandoc/Filter/Plot/Renderers/PlotlyR.hs view
@@ -1,79 +1,79 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Plotly/R plots code blocks-module Text.Pandoc.Filter.Plot.Renderers.PlotlyR-  ( plotlyR,-    plotlyRSupportedSaveFormats,-  )-where--import qualified Data.Text as T-import Text.Pandoc.Filter.Plot.Renderers.Prelude--plotlyR :: PlotM Renderer-plotlyR = do-  cmdargs <- asksConfig plotlyRCmdArgs-  return-    $ Renderer-      { rendererToolkit = PlotlyR,-        rendererCapture = plotlyRCapture,-        rendererCommand = plotlyRCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -e "if(!require('plotly')) {quit(status=1)}"|],-        rendererSupportedSaveFormats = plotlyRSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "r",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".r"-      }--plotlyRSupportedSaveFormats :: [SaveFormat]-plotlyRSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, HTML]--plotlyRCommand :: Text -> OutputSpec -> Text-plotlyRCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]--plotlyRCapture :: FigureSpec -> FilePath -> Script-plotlyRCapture fs fp =-  T.unlines-    [ "pdf(NULL)", -- Prevent the creation of empty Rplots.pdf-      script fs,-      plotlyRCaptureFragment fs fp-    ]--plotlyRCaptureFragment :: FigureSpec -> FilePath -> Script-plotlyRCaptureFragment spec@FigureSpec {..} fname = case saveFormat of-  HTML -> plotlyRCaptureHtml spec fname-  _ -> plotlyRCaptureStatic spec fname---- Based on the following discussion:---    https://stackoverflow.com/q/34580095-plotlyRCaptureHtml :: FigureSpec -> FilePath -> Script-plotlyRCaptureHtml _ fname =-  [st|-library(plotly) # just in case-library(htmlwidgets)-p <- last_plot()-htmlwidgets::saveWidget(as_widget(p), "#{toRPath fname}")-|]---- Based on the following documentation:---    https://plotly.com/r/static-image-export/-plotlyRCaptureStatic :: FigureSpec -> FilePath -> Script-plotlyRCaptureStatic _ fname =-  [st|-library(plotly) # just in case-if (!require("processx")) install.packages("processx")-pdf(NULL)-orca(last_plot(), file = "#{toRPath fname}")-|]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Plotly/R plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.PlotlyR
+  ( plotlyR,
+    plotlyRSupportedSaveFormats,
+  )
+where
+
+import qualified Data.Text as T
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+plotlyR :: PlotM Renderer
+plotlyR = do
+  cmdargs <- asksConfig plotlyRCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = PlotlyR,
+        rendererCapture = plotlyRCapture,
+        rendererCommand = plotlyRCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -e "if(!require('plotly')) {quit(status=1)}"|],
+        rendererSupportedSaveFormats = plotlyRSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "r",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".r"
+      }
+
+plotlyRSupportedSaveFormats :: [SaveFormat]
+plotlyRSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, HTML]
+
+plotlyRCommand :: Text -> OutputSpec -> Text
+plotlyRCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
+
+plotlyRCapture :: FigureSpec -> FilePath -> Script
+plotlyRCapture fs fp =
+  T.unlines
+    [ "pdf(NULL)", -- Prevent the creation of empty Rplots.pdf
+      script fs,
+      plotlyRCaptureFragment fs fp
+    ]
+
+plotlyRCaptureFragment :: FigureSpec -> FilePath -> Script
+plotlyRCaptureFragment spec@FigureSpec {..} fname = case saveFormat of
+  HTML -> plotlyRCaptureHtml spec fname
+  _ -> plotlyRCaptureStatic spec fname
+
+-- Based on the following discussion:
+--    https://stackoverflow.com/q/34580095
+plotlyRCaptureHtml :: FigureSpec -> FilePath -> Script
+plotlyRCaptureHtml _ fname =
+  [st|
+library(plotly) # just in case
+library(htmlwidgets)
+p <- last_plot()
+htmlwidgets::saveWidget(as_widget(p), "#{toRPath fname}")
+|]
+
+-- Based on the following documentation:
+--    https://plotly.com/r/static-image-export/
+plotlyRCaptureStatic :: FigureSpec -> FilePath -> Script
+plotlyRCaptureStatic _ fname =
+  [st|
+library(plotly) # just in case
+if (!require("processx")) install.packages("processx")
+pdf(NULL)
+orca(last_plot(), file = "#{toRPath fname}")
+|]
src/Text/Pandoc/Filter/Plot/Renderers/Plotsjl.hs view
@@ -1,54 +1,54 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering Julia/Plots.jl code blocks-module Text.Pandoc.Filter.Plot.Renderers.Plotsjl-  ( plotsjl,-    plotsjlSupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--plotsjl :: PlotM Renderer-plotsjl = do-  cmdargs <- asksConfig plotsjlCmdArgs-  return-    $ Renderer-      { rendererToolkit = Plotsjl,-        rendererCapture = plotsjlCapture,-        rendererCommand = plotsjlCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -e "using Plots"|],-        rendererSupportedSaveFormats = plotsjlSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "julia",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".jl"-      }---- Save formats support by most backends--- https://docs.plotsjl.org/latest/output/#Supported-output-file-formats-1-plotsjlSupportedSaveFormats :: [SaveFormat]-plotsjlSupportedSaveFormats = [PNG, SVG, PDF]--plotsjlCommand :: Text -> OutputSpec -> Text-plotsjlCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} -- "#{oScriptPath}"|]--plotsjlCapture :: FigureSpec -> FilePath -> Script-plotsjlCapture = appendCapture plotsjlCaptureFragment--plotsjlCaptureFragment :: FigureSpec -> FilePath -> Script-plotsjlCaptureFragment _ fname =-  [st|-savefig(raw"#{fname}")-|]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering Julia/Plots.jl code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Plotsjl
+  ( plotsjl,
+    plotsjlSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+plotsjl :: PlotM Renderer
+plotsjl = do
+  cmdargs <- asksConfig plotsjlCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = Plotsjl,
+        rendererCapture = plotsjlCapture,
+        rendererCommand = plotsjlCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -e "using Plots"|],
+        rendererSupportedSaveFormats = plotsjlSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "julia",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".jl"
+      }
+
+-- Save formats support by most backends
+-- https://docs.plotsjl.org/latest/output/#Supported-output-file-formats-1
+plotsjlSupportedSaveFormats :: [SaveFormat]
+plotsjlSupportedSaveFormats = [PNG, SVG, PDF]
+
+plotsjlCommand :: Text -> OutputSpec -> Text
+plotsjlCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} -- "#{oScriptPath}"|]
+
+plotsjlCapture :: FigureSpec -> FilePath -> Script
+plotsjlCapture = appendCapture plotsjlCaptureFragment
+
+plotsjlCaptureFragment :: FigureSpec -> FilePath -> Script
+plotsjlCaptureFragment _ fname =
+  [st|
+savefig(raw"#{fname}")
+|]
src/Text/Pandoc/Filter/Plot/Renderers/Prelude.hs view
@@ -1,40 +1,40 @@-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Prelude for renderers, containing some helpful utilities.-module Text.Pandoc.Filter.Plot.Renderers.Prelude-  ( module Prelude,-    module Text.Pandoc.Filter.Plot.Monad,-    Text,-    st,-    unpack,-    findExecutable,-    appendCapture,-    toRPath,-  )-where--import Data.Text (Text, unpack)-import System.Directory (findExecutable)-import System.FilePath (isPathSeparator)-import Text.Pandoc.Filter.Plot.Monad-import Text.Shakespeare.Text (st)---- | A shortcut to append capture script fragments to scripts-appendCapture ::-  (FigureSpec -> FilePath -> Script) ->-  FigureSpec ->-  FilePath ->-  Script-appendCapture f s fp = mconcat [script s, "\n", f s fp]---- | R paths use the '/' path separator-toRPath :: FilePath -> FilePath-toRPath = fmap (\c -> if isPathSeparator c then '/' else c)+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Prelude for renderers, containing some helpful utilities.
+module Text.Pandoc.Filter.Plot.Renderers.Prelude
+  ( module Prelude,
+    module Text.Pandoc.Filter.Plot.Monad,
+    Text,
+    st,
+    unpack,
+    findExecutable,
+    appendCapture,
+    toRPath,
+  )
+where
+
+import Data.Text (Text, unpack)
+import System.Directory (findExecutable)
+import System.FilePath (isPathSeparator)
+import Text.Pandoc.Filter.Plot.Monad
+import Text.Shakespeare.Text (st)
+
+-- | A shortcut to append capture script fragments to scripts
+appendCapture ::
+  (FigureSpec -> FilePath -> Script) ->
+  FigureSpec ->
+  FilePath ->
+  Script
+appendCapture f s fp = mconcat [script s, "\n", f s fp]
+
+-- | R paths use the '/' path separator
+toRPath :: FilePath -> FilePath
+toRPath = fmap (\c -> if isPathSeparator c then '/' else c)
src/Text/Pandoc/Filter/Plot/Renderers/SageMath.hs view
@@ -1,71 +1,71 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NoImplicitPrelude #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Rendering SageMath figures-module Text.Pandoc.Filter.Plot.Renderers.SageMath-  ( sagemath,-    sagemathSupportedSaveFormats,-  )-where--import Text.Pandoc.Filter.Plot.Renderers.Prelude--sagemath :: PlotM Renderer-sagemath = do-  cmdargs <- asksConfig sagemathCmdArgs-  return-    $ Renderer-      { rendererToolkit = SageMath,-        rendererCapture = sagemathCapture,-        rendererCommand = sagemathCommand cmdargs,-        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -v|],-        rendererSupportedSaveFormats = sagemathSupportedSaveFormats,-        rendererChecks = mempty,-        rendererLanguage = "sagemath",-        rendererComment = mappend "# ",-        rendererScriptExtension = ".sage"-      }---- See here:--- https://doc.sagemath.org/html/en/reference/plotting/sage/plot/graphics.html#sage.plot.graphics.Graphics.save-sagemathSupportedSaveFormats :: [SaveFormat]-sagemathSupportedSaveFormats = [EPS, PDF, PNG, SVG]--sagemathCommand :: Text -> OutputSpec -> Text-sagemathCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]--sagemathCapture :: FigureSpec -> FilePath -> Script-sagemathCapture = appendCapture sagemathCaptureFragment---- This capture fragment is a bit ugly because sage does not have the--- equivalent of matplotlib's `plt.gca()` to get a pointer to the most--- recent graphical object. We must search for it-sagemathCaptureFragment :: FigureSpec -> FilePath -> Script-sagemathCaptureFragment FigureSpec {..} fname =-  [st|-import sage.plot.graphics as go-import sage.plot.plot3d.base as go3d-import builtins-# Try to concatenate 3D graphics objects first; if this doesn't work, then -# concatenate all 2D graphic objects.-__all_graphics = builtins.sum( (obj for obj in globals().values() if isinstance(obj, go3d.Graphics3d)))-if not __all_graphics:-    __all_graphics = builtins.sum( (obj for obj in globals().values() if isinstance(obj, go.Graphics)))-if not __all_graphics:-    raise RuntimeError(''.join([-        "No plotting objects detected. ",-        "Make sure that all of your plotting objects are named, e.g. `G = plot(...)` rather than just `plot(...)`. ",-        "This is a limitation specific to the interaction between sage and pandoc-plot."-    ]))-__all_graphics.save_image(r"#{fname}", dpi=#{dpi})-|]+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Rendering SageMath figures
+module Text.Pandoc.Filter.Plot.Renderers.SageMath
+  ( sagemath,
+    sagemathSupportedSaveFormats,
+  )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+
+sagemath :: PlotM Renderer
+sagemath = do
+  cmdargs <- asksConfig sagemathCmdArgs
+  return
+    $ Renderer
+      { rendererToolkit = SageMath,
+        rendererCapture = sagemathCapture,
+        rendererCommand = sagemathCommand cmdargs,
+        rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -v|],
+        rendererSupportedSaveFormats = sagemathSupportedSaveFormats,
+        rendererChecks = mempty,
+        rendererLanguage = "sagemath",
+        rendererComment = mappend "# ",
+        rendererScriptExtension = ".sage"
+      }
+
+-- See here:
+-- https://doc.sagemath.org/html/en/reference/plotting/sage/plot/graphics.html#sage.plot.graphics.Graphics.save
+sagemathSupportedSaveFormats :: [SaveFormat]
+sagemathSupportedSaveFormats = [EPS, PDF, PNG, SVG]
+
+sagemathCommand :: Text -> OutputSpec -> Text
+sagemathCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
+
+sagemathCapture :: FigureSpec -> FilePath -> Script
+sagemathCapture = appendCapture sagemathCaptureFragment
+
+-- This capture fragment is a bit ugly because sage does not have the
+-- equivalent of matplotlib's `plt.gca()` to get a pointer to the most
+-- recent graphical object. We must search for it
+sagemathCaptureFragment :: FigureSpec -> FilePath -> Script
+sagemathCaptureFragment FigureSpec {..} fname =
+  [st|
+import sage.plot.graphics as go
+import sage.plot.plot3d.base as go3d
+import builtins
+# Try to concatenate 3D graphics objects first; if this doesn't work, then 
+# concatenate all 2D graphic objects.
+__all_graphics = builtins.sum( (obj for obj in globals().values() if isinstance(obj, go3d.Graphics3d)))
+if not __all_graphics:
+    __all_graphics = builtins.sum( (obj for obj in globals().values() if isinstance(obj, go.Graphics)))
+if not __all_graphics:
+    raise RuntimeError(''.join([
+        "No plotting objects detected. ",
+        "Make sure that all of your plotting objects are named, e.g. `G = plot(...)` rather than just `plot(...)`. ",
+        "This is a limitation specific to the interaction between sage and pandoc-plot."
+    ]))
+__all_graphics.save_image(r"#{fname}", dpi=#{dpi})
+|]
src/Text/Pandoc/Filter/Plot/Scripting.hs view
@@ -1,218 +1,218 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TemplateHaskell #-}---- |--- Module      : $header$--- Copyright   : (c) Laurent P René de Cotret, 2019 - present--- License     : GNU GPL, version 2 or above--- Maintainer  : laurent.decotret@outlook.com--- Stability   : internal--- Portability : portable------ Scripting-module Text.Pandoc.Filter.Plot.Scripting-  ( ScriptResult (..),-    runTempScript,-    runScriptIfNecessary,-    figurePath,-    sourceCodePath,-  )-where--import Control.Concurrent.MVar (withMVar)-import Data.Default (def)-import Data.Functor.Identity (Identity (..))-import Data.Hashable (hash)-import Data.Text (Text, pack, unpack)-import qualified Data.Text as T-import qualified Data.Text.IO as T-import Paths_pandoc_plot (version)-import System.Directory-  ( createDirectoryIfMissing,-    doesFileExist,-    getTemporaryDirectory,-  )-import System.Exit (ExitCode (..))-import System.FilePath-  ( addExtension,-    normalise,-    replaceExtension,-    takeBaseName,-    takeDirectory,-    (</>),-  )-import Text.Pandoc.Class (runPure)-import Text.Pandoc.Definition (Block (CodeBlock), Pandoc (Pandoc))-import Text.Pandoc.Filter.Plot.Monad-import Text.Pandoc.Filter.Plot.Scripting.Template-import Text.Pandoc.Options (WriterOptions (..))-import Text.Pandoc.SelfContained (makeSelfContained)-import Text.Pandoc.Templates-import Text.Pandoc.Writers (writeHtml5String)-import Text.Printf (printf)---- Run script as described by the spec, only if necessary-runScriptIfNecessary :: FigureSpec -> PlotM ScriptResult-runScriptIfNecessary spec = do-  target <- figurePath spec-  liftIO $ createDirectoryIfMissing True . takeDirectory $ target--  fileAlreadyExists <- liftIO . doesFileExist $ target-  result <--    if fileAlreadyExists-      then return ScriptSuccess-      else runTempScript spec--  logScriptResult result--  case result of-    ScriptSuccess -> writeSource spec >> return ScriptSuccess-    other -> return other-  where-    logScriptResult ScriptSuccess = return ()-    logScriptResult r = err . pack . show $ r---- | Possible result of running a script-data ScriptResult-  = ScriptSuccess-  | ScriptChecksFailed Text -- Message-  | ScriptFailure Text Int Script -- Command, exit code, and source script--instance Show ScriptResult where-  show ScriptSuccess = "Script success."-  show (ScriptChecksFailed msg) = unpack $ "Script checks failed: " <> msg-  show (ScriptFailure cmd ec s) = mconcat ["Command \"", unpack cmd, "\" failed with exit code ", show ec, ". The script source was: \n\n", unpack . formatScript $ s, "\n"]---- | Format a script to show in error messages-formatScript :: Script -> Text-formatScript s = T.unlines . fmap (uncurry formatLine) $ zip linenos (T.lines s)-  where-    nlines = length (T.lines s)-    linenos = [1 .. nlines]--    -- No version of ceil in Prelude, so 1 + floor will have to do-    maxdigits :: Int-    maxdigits = 1 + floor (logBase 10 (fromIntegral nlines :: Double))--    formatLine :: Int -> Text -> Text-    formatLine n l = pack (printf ("%" <> show maxdigits <> "d") n) <> " > " <> l---- Run script as described by the spec--- Checks are performed, according to the renderer--- Note that stdout from the script is suppressed, but not--- stderr.-runTempScript :: FigureSpec -> PlotM ScriptResult-runTempScript spec@FigureSpec {..} = do-  let checks = rendererChecks renderer_-      checkResult = mconcat $ checks <*> [script]-  case checkResult of-    CheckFailed msg -> return $ ScriptChecksFailed msg-    CheckPassed -> do-      scriptPath <- tempScriptPath spec-      target <- figurePath spec-      cwd <- asks envCWD--      let scriptWithCapture = rendererCapture renderer_ spec target--      -- Note the use of a lock. This is a crude solution for issue #53, where-      -- multiple identical figures can cause a race condition to write to the-      -- same output file.-      sem <- asks envIOLock-      liftIO $ withMVar sem $ \_ -> T.writeFile scriptPath scriptWithCapture-      let outputSpec =-            OutputSpec-              { oFigureSpec = spec,-                oScriptPath = scriptPath,-                oFigurePath = target,-                oExecutable = fsExecutable,-                oCWD = cwd-              }-      let command_ = rendererCommand renderer_ outputSpec--      -- It is important that the CWD be inherited from the-      -- parent process. See #2.-      (ec, _) <- runCommand cwd command_-      case ec of-        ExitSuccess -> return ScriptSuccess-        ExitFailure code -> return $ ScriptFailure command_ code script---- | Determine the temp script path from Figure specifications--- Note that for certain renderers, the appropriate file extension--- is important.-tempScriptPath :: FigureSpec -> PlotM FilePath-tempScriptPath fs@FigureSpec {..} = do-  let ext = rendererScriptExtension renderer_-  -- Note that this hash is only so that we are running scripts from unique-  -- file names; it does NOT determine whether this figure should-  -- be rendered or not.-  fp <- figurePath fs-  let hashedPath = takeBaseName fp <> ext-  liftIO $ (</> hashedPath) <$> getTemporaryDirectory---- | Determine the path to the source code that generated the figure.--- To ensure that the source code path is distinguished from HTML figures, we use the extension .src.html.-sourceCodePath :: FigureSpec -> PlotM FilePath-sourceCodePath = fmap (normalise . flip replaceExtension ".src.html") . figurePath---- | Hash of the content of a @FigureSpec@. Note that unlike usual hashes,--- two @FigureSpec@ with the same @figureContentHash@ does not mean that they are equal!------ Not all parts of a FigureSpec are related to running code.--- For example, changing the caption should not require running the figure again.-figureContentHash :: FigureSpec -> PlotM Word-figureContentHash FigureSpec {..} = do-  dependenciesHash <- mapM fileHash dependencies-  -- hash looks strange because instances only exist for 7-tuples or less-  return $-    fromIntegral $-      hash-        ( ( fromEnum (rendererToolkit renderer_),-            script,-            fromEnum saveFormat,-            directory-          ),-          ( dpi,-            dependenciesHash,-            extraAttrs,-            show version -- Included version because capture scripts may change between releases-          )-        )---- | Determine the path a figure should have.--- The path for this file is unique to the content of the figure,--- so that @figurePath@ can be used to determine whether a figure should--- be rendered again or not.-figurePath :: FigureSpec -> PlotM FilePath-figurePath spec = do-  fh <- figureContentHash spec-  let ext = extension . saveFormat $ spec-      -- MATLAB will refuse to process files that don't start with-      -- a letter so it is simplest to use filenames that start-      -- with "pandocplot" throughout-      stem = flip addExtension ext . mappend "pandocplot" . show $ fh-  return $ normalise $ directory spec </> stem---- | Write the source code of a figure to an HTML file with appropriate syntax highlighting.-writeSource :: FigureSpec -> PlotM ()-writeSource spec = do-  let rdr = renderer_ spec-      language = rendererLanguage rdr-  scp <- sourceCodePath spec-  let doc = Pandoc mempty [CodeBlock (mempty, [language], mempty) (script spec)]-      renderSource = \template -> do-        let opts = def {writerTemplate = Just template}-            -- Note that making the document self-contained is absolutely required so that the CSS for-            -- syntax highlighting is included directly in the document.-            t = either (const mempty) id $ runPure (writeHtml5String opts doc >>= makeSelfContained)--        -- Note the use of a lock. This is a crude solution for issue #53, where-        -- multiple identical figures can cause a race condition to write to the-        -- same output file.-        sem <- asks envIOLock-        liftIO $ withMVar sem $ \_ -> T.writeFile scp t--  either (err . pack) renderSource $ runIdentity $ compileTemplate mempty sourceTemplate--sourceTemplate :: Text-sourceTemplate = pack $(sourceTemplate_)+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+-- |
+-- Module      : $header$
+-- Copyright   : (c) Laurent P René de Cotret, 2019 - present
+-- License     : GNU GPL, version 2 or above
+-- Maintainer  : laurent.decotret@outlook.com
+-- Stability   : internal
+-- Portability : portable
+--
+-- Scripting
+module Text.Pandoc.Filter.Plot.Scripting
+  ( ScriptResult (..),
+    runTempScript,
+    runScriptIfNecessary,
+    figurePath,
+    sourceCodePath,
+  )
+where
+
+import Control.Concurrent.MVar (withMVar)
+import Data.Default (def)
+import Data.Functor.Identity (Identity (..))
+import Data.Hashable (hash)
+import Data.Text (Text, pack, unpack)
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import Paths_pandoc_plot (version)
+import System.Directory
+  ( createDirectoryIfMissing,
+    doesFileExist,
+    getTemporaryDirectory,
+  )
+import System.Exit (ExitCode (..))
+import System.FilePath
+  ( addExtension,
+    normalise,
+    replaceExtension,
+    takeBaseName,
+    takeDirectory,
+    (</>),
+  )
+import Text.Pandoc.Class (runPure)
+import Text.Pandoc.Definition (Block (CodeBlock), Pandoc (Pandoc))
+import Text.Pandoc.Filter.Plot.Monad
+import Text.Pandoc.Filter.Plot.Scripting.Template
+import Text.Pandoc.Options (WriterOptions (..))
+import Text.Pandoc.SelfContained (makeSelfContained)
+import Text.Pandoc.Templates
+import Text.Pandoc.Writers (writeHtml5String)
+import Text.Printf (printf)
+
+-- Run script as described by the spec, only if necessary
+runScriptIfNecessary :: FigureSpec -> PlotM ScriptResult
+runScriptIfNecessary spec = do
+  target <- figurePath spec
+  liftIO $ createDirectoryIfMissing True . takeDirectory $ target
+
+  fileAlreadyExists <- liftIO . doesFileExist $ target
+  result <-
+    if fileAlreadyExists
+      then return ScriptSuccess
+      else runTempScript spec
+
+  logScriptResult result
+
+  case result of
+    ScriptSuccess -> writeSource spec >> return ScriptSuccess
+    other -> return other
+  where
+    logScriptResult ScriptSuccess = return ()
+    logScriptResult r = err . pack . show $ r
+
+-- | Possible result of running a script
+data ScriptResult
+  = ScriptSuccess
+  | ScriptChecksFailed Text -- Message
+  | ScriptFailure Text Int Script -- Command, exit code, and source script
+
+instance Show ScriptResult where
+  show ScriptSuccess = "Script success."
+  show (ScriptChecksFailed msg) = unpack $ "Script checks failed: " <> msg
+  show (ScriptFailure cmd ec s) = mconcat ["Command \"", unpack cmd, "\" failed with exit code ", show ec, ". The script source was: \n\n", unpack . formatScript $ s, "\n"]
+
+-- | Format a script to show in error messages
+formatScript :: Script -> Text
+formatScript s = T.unlines . fmap (uncurry formatLine) $ zip linenos (T.lines s)
+  where
+    nlines = length (T.lines s)
+    linenos = [1 .. nlines]
+
+    -- No version of ceil in Prelude, so 1 + floor will have to do
+    maxdigits :: Int
+    maxdigits = 1 + floor (logBase 10 (fromIntegral nlines :: Double))
+
+    formatLine :: Int -> Text -> Text
+    formatLine n l = pack (printf ("%" <> show maxdigits <> "d") n) <> " > " <> l
+
+-- Run script as described by the spec
+-- Checks are performed, according to the renderer
+-- Note that stdout from the script is suppressed, but not
+-- stderr.
+runTempScript :: FigureSpec -> PlotM ScriptResult
+runTempScript spec@FigureSpec {..} = do
+  let checks = rendererChecks renderer_
+      checkResult = mconcat $ checks <*> [script]
+  case checkResult of
+    CheckFailed msg -> return $ ScriptChecksFailed msg
+    CheckPassed -> do
+      scriptPath <- tempScriptPath spec
+      target <- figurePath spec
+      cwd <- asks envCWD
+
+      let scriptWithCapture = rendererCapture renderer_ spec target
+
+      -- Note the use of a lock. This is a crude solution for issue #53, where
+      -- multiple identical figures can cause a race condition to write to the
+      -- same output file.
+      sem <- asks envIOLock
+      liftIO $ withMVar sem $ \_ -> T.writeFile scriptPath scriptWithCapture
+      let outputSpec =
+            OutputSpec
+              { oFigureSpec = spec,
+                oScriptPath = scriptPath,
+                oFigurePath = target,
+                oExecutable = fsExecutable,
+                oCWD = cwd
+              }
+      let command_ = rendererCommand renderer_ outputSpec
+
+      -- It is important that the CWD be inherited from the
+      -- parent process. See #2.
+      (ec, _) <- runCommand cwd command_
+      case ec of
+        ExitSuccess -> return ScriptSuccess
+        ExitFailure code -> return $ ScriptFailure command_ code script
+
+-- | Determine the temp script path from Figure specifications
+-- Note that for certain renderers, the appropriate file extension
+-- is important.
+tempScriptPath :: FigureSpec -> PlotM FilePath
+tempScriptPath fs@FigureSpec {..} = do
+  let ext = rendererScriptExtension renderer_
+  -- Note that this hash is only so that we are running scripts from unique
+  -- file names; it does NOT determine whether this figure should
+  -- be rendered or not.
+  fp <- figurePath fs
+  let hashedPath = takeBaseName fp <> ext
+  liftIO $ (</> hashedPath) <$> getTemporaryDirectory
+
+-- | Determine the path to the source code that generated the figure.
+-- To ensure that the source code path is distinguished from HTML figures, we use the extension .src.html.
+sourceCodePath :: FigureSpec -> PlotM FilePath
+sourceCodePath = fmap (normalise . flip replaceExtension ".src.html") . figurePath
+
+-- | Hash of the content of a @FigureSpec@. Note that unlike usual hashes,
+-- two @FigureSpec@ with the same @figureContentHash@ does not mean that they are equal!
+--
+-- Not all parts of a FigureSpec are related to running code.
+-- For example, changing the caption should not require running the figure again.
+figureContentHash :: FigureSpec -> PlotM Word
+figureContentHash FigureSpec {..} = do
+  dependenciesHash <- mapM fileHash dependencies
+  -- hash looks strange because instances only exist for 7-tuples or less
+  return $
+    fromIntegral $
+      hash
+        ( ( fromEnum (rendererToolkit renderer_),
+            script,
+            fromEnum saveFormat,
+            directory
+          ),
+          ( dpi,
+            dependenciesHash,
+            extraAttrs,
+            show version -- Included version because capture scripts may change between releases
+          )
+        )
+
+-- | Determine the path a figure should have.
+-- The path for this file is unique to the content of the figure,
+-- so that @figurePath@ can be used to determine whether a figure should
+-- be rendered again or not.
+figurePath :: FigureSpec -> PlotM FilePath
+figurePath spec = do
+  fh <- figureContentHash spec
+  let ext = extension . saveFormat $ spec
+      -- MATLAB will refuse to process files that don't start with
+      -- a letter so it is simplest to use filenames that start
+      -- with "pandocplot" throughout
+      stem = flip addExtension ext . mappend "pandocplot" . show $ fh
+  return $ normalise $ directory spec </> stem
+
+-- | Write the source code of a figure to an HTML file with appropriate syntax highlighting.
+writeSource :: FigureSpec -> PlotM ()
+writeSource spec = do
+  let rdr = renderer_ spec
+      language = rendererLanguage rdr
+  scp <- sourceCodePath spec
+  let doc = Pandoc mempty [CodeBlock (mempty, [language], mempty) (script spec)]
+      renderSource = \template -> do
+        let opts = def {writerTemplate = Just template}
+            -- Note that making the document self-contained is absolutely required so that the CSS for
+            -- syntax highlighting is included directly in the document.
+            t = either (const mempty) id $ runPure (writeHtml5String opts doc >>= makeSelfContained)
+
+        -- Note the use of a lock. This is a crude solution for issue #53, where
+        -- multiple identical figures can cause a race condition to write to the
+        -- same output file.
+        sem <- asks envIOLock
+        liftIO $ withMVar sem $ \_ -> T.writeFile scp t
+
+  either (err . pack) renderSource $ runIdentity $ compileTemplate mempty sourceTemplate
+
+sourceTemplate :: Text
+sourceTemplate = pack $(sourceTemplate_)
src/Text/Pandoc/Filter/Plot/Scripting/Template.hs view
@@ -1,23 +1,23 @@-{-# LANGUAGE TemplateHaskell #-}--module Text.Pandoc.Filter.Plot.Scripting.Template (sourceTemplate_) where--import Data.String (fromString)-import Language.Haskell.TH.Syntax-  ( Exp (AppE, LitE, VarE),-    Lit (StringL),-    Q,-    Quasi (qAddDependentFile),-    runIO,-  )-import System.FilePath ((</>))--sourceTemplate_ :: Q Exp-sourceTemplate_ = do-  let fp = "data" </> "srctemplate.html"-  qAddDependentFile fp-  d <- runIO $ readFile fp-  strToExp d-  where-    strToExp :: String -> Q Exp-    strToExp s = return $ VarE 'fromString `AppE` LitE (StringL s)+{-# LANGUAGE TemplateHaskell #-}
+
+module Text.Pandoc.Filter.Plot.Scripting.Template (sourceTemplate_) where
+
+import Data.String (fromString)
+import Language.Haskell.TH.Syntax
+  ( Exp (AppE, LitE, VarE),
+    Lit (StringL),
+    Q,
+    Quasi (qAddDependentFile),
+    runIO,
+  )
+import System.FilePath ((</>))
+
+sourceTemplate_ :: Q Exp
+sourceTemplate_ = do
+  let fp = "data" </> "srctemplate.html"
+  qAddDependentFile fp
+  d <- runIO $ readFile fp
+  strToExp d
+  where
+    strToExp :: String -> Q Exp
+    strToExp s = return $ VarE 'fromString `AppE` LitE (StringL s)
tests/Common.hs view
@@ -1,473 +1,493 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}--module Common where--import Control.Monad (unless, when)-import Data.List (isInfixOf, isSuffixOf, (!!))-import Data.Monoid ((<>))-import qualified Data.Set as S-import Data.String (fromString)-import Data.Text (Text, pack, unpack)-import qualified Data.Text as T-import System.Directory-  ( createDirectory,-    createDirectoryIfMissing,-    doesDirectoryExist,-    doesFileExist,-    getTemporaryDirectory,-    listDirectory,-    removeDirectoryRecursive,-    removePathForcibly,-  )-import System.FilePath (takeExtensions, (</>))-import Test.Tasty-import Test.Tasty.HUnit-import qualified Text.Pandoc.Builder as B-import qualified Text.Pandoc.Definition as B-import Text.Pandoc.Filter.Plot-import Text.Pandoc.Filter.Plot.Internal-import Text.Pandoc.JSON--defaultTestConfig :: Configuration-defaultTestConfig =-  defaultConfiguration-    { logVerbosity = Silent,-      logSink = StdErr-    }------------------------------------------------------------------------------------ Test that plot files and source files are created when the filter is run-testFileCreation :: Toolkit -> TestTree-testFileCreation tk =-  testCase "writes output files in appropriate directory" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-file-creation-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    let cb = (addDirectory tempDir $ codeBlock tk (trivialContent tk))-    _ <- runPlotM Nothing defaultTestConfig $ make cb-    filesCreated <- length <$> listDirectory tempDir-    assertEqual "" 2 filesCreated------------------------------------------------------------------------------------ Test that plot files and source files are created when the filter is run--- and the path of the files involves spaces. See Issue #2-testFileCreationPathWithSpaces :: Toolkit -> TestTree-testFileCreationPathWithSpaces tk =-  testCase "writes output files in appropriate directory (with spaces)" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-file-creation-with-spaces-   -" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    let cb = (addDirectory tempDir $ codeBlock tk (trivialContent tk))-    _ <- runPlotM Nothing defaultTestConfig $ make cb-    filesCreated <- length <$> listDirectory tempDir-    assertEqual "" 2 filesCreated------------------------------------------------------------------------------------ Test that pandoc-plot appropriately transforms code blocks that are--- nested in other blocks (e.g. Divs)-testNestedCodeBlocks :: Toolkit -> TestTree-testNestedCodeBlocks tk =-  testCase "transforms code blocks nested in other blocks" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-nester-blocks-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    let block =-          Div mempty $-            singleton $-              addDirectory tempDir $-                codeBlock tk (trivialContent tk)-    _ <- runPlotM Nothing defaultTestConfig $ make block-    filesCreated <- length <$> listDirectory tempDir-    assertEqual "" 2 filesCreated-  where-    singleton :: a -> [a]-    singleton = return------------------------------------------------------------------------------------ Test that included files are found within the source-testFileInclusion :: Toolkit -> TestTree-testFileInclusion tk =-  testCase "includes plot inclusions" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-file-inclusion-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    let cb =-          ( addPreamble (include tk) $-              addDirectory tempDir $-                codeBlock tk (trivialContent tk)-          )-    _ <- runPlotM Nothing defaultTestConfig $ make cb-    inclusion <- readFile (include tk)-    sourcePath <- head . filter (isExtensionOf ".src.html") <$> listDirectory tempDir-    src <- readFile (tempDir </> sourcePath)-    assertIsInfix inclusion src-  where-    include Matplotlib = "tests/includes/matplotlib.py"-    include PlotlyPython = "tests/includes/plotly-python.py"-    include PlotlyR = "tests/includes/plotly-r.r"-    include Matlab = "tests/includes/matlabplot.m"-    include Mathematica = "tests/includes/mathplot.m"-    include Octave = "tests/includes/octave.m"-    include GGPlot2 = "tests/includes/ggplot2.r"-    include GNUPlot = "tests/includes/gnuplot.gp"-    include Graphviz = "tests/includes/graphviz.dot"-    include Bokeh = "tests/includes/bokeh.py"-    include Plotsjl = "tests/includes/plotsjl.jl"-    include PlantUML = "tests/includes/plantuml.txt"-    include SageMath = "tests/includes/sagemath.sage"-    include D2 = "tests/includes/d2-dd.d2"------------------------------------------------------------------------------------ Test that the files are saved in the appropriate format-testSaveFormat :: Toolkit -> TestTree-testSaveFormat tk =-  testCase "saves in the appropriate format" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-safe-format-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir-    let fmt = head (supportedSaveFormats tk)-        cb =-          ( addSaveFormat fmt $-              addDirectory tempDir $-                codeBlock tk (trivialContent tk)-          )-    _ <- runPlotM Nothing defaultTestConfig $ make cb-    numberjpgFiles <--      length-        <$> filter (isExtensionOf (extension fmt))-        <$> listDirectory tempDir-    assertEqual "" numberjpgFiles 1------------------------------------------------------------------------------------ Test that the appropriate error is raised when trying to save figures--- in an incompatible format-testSaveFormatIncompatibility :: Toolkit -> TestTree-testSaveFormatIncompatibility tk =-  testCase "raises the appropriate error on save format incompatibility" $ do-    let allSaveFormats = enumFromTo minBound maxBound :: [SaveFormat]-        incompatibleFormats = S.toList $ S.difference (S.fromList allSaveFormats) (S.fromList $ supportedSaveFormats tk)-    if null incompatibleFormats-      then return ()-      else do-        let fmt = head incompatibleFormats-            cb = addSaveFormat fmt $ codeBlock tk (trivialContent tk)--        result <- runPlotM Nothing defaultTestConfig $ makeEither cb-        let expectedCheck :: Either PandocPlotError a -> Bool-            expectedCheck (Left (IncompatibleSaveFormatError fmt' tk')) = (fmt' == fmt) && (tk' == tk)-            expectedCheck _ = False-        assertBool "" (expectedCheck result)------------------------------------------------------------------------------------ Test that it is possible to not render source links in captions-testWithSource :: Toolkit -> TestTree-testWithSource tk =-  testCase "appropriately omits links to source code" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-caption-links-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    let expected = "caption content"-        noSource =-          addWithSource False $-            addDirectory tempDir $-              addCaption expected $-                codeBlock tk (trivialContent tk)-        withSource =-          addWithSource True $-            addDirectory tempDir $-              addCaption expected $-                codeBlock tk (trivialContent tk)-    blockNoSource <- runPlotM Nothing defaultTestConfig $ make noSource-    blockWithSource <- runPlotM Nothing defaultTestConfig $ make withSource--    -- In the case where source=false, the caption is used verbatim.-    -- Otherwise, links will be appended to the caption; hence, the caption-    -- is no longer equal to the initial value-    assertEqual "" [B.Plain $ B.toList (fromString expected)] (extractCaption blockNoSource)-    assertNotEqual "" [B.Plain $ B.toList (fromString expected)] (extractCaption blockWithSource)-  where-    extractCaption (B.Figure _ (Caption _ caption) _) = caption------------------------------------------------------------------------------------ Test that it is possible to change the source code label in captions-testSourceLabel :: Toolkit -> TestTree-testSourceLabel tk =-  testCase "appropriately changes the source code label" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-source-label-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    -- Note that this test requires that the actual caption be empty-    -- so that the caption is only the source code label-    let withSource =-          addWithSource True $-            addDirectory tempDir $-              addCaption mempty $ -- This test requires that the actual caption be empty-                codeBlock tk (trivialContent tk)-    blockWithSource <- runPlotM Nothing defaultTestConfig {sourceCodeLabel = "Test label"} $ make withSource--    let [Plain [Space, _, B.Link _ ils _, _]] = extractCaption blockWithSource-    assertEqual "" (B.toList $ B.str "Test label") ils-  where-    extractCaption (B.Figure _ (Caption _ caption) _) = caption--    linkLabel (B.Plain [B.Link _ ils _]) = B.fromList ils-    linkLabel _ = mempty------------------------------------------------------------------------------------ Test that parameters in code blocks will override the defaults in configuration-testOverrideConfiguration :: Toolkit -> TestTree-testOverrideConfiguration tk =-  -- We set the default save format to JPG via the configuration,-  -- but set the code block parameter to PNG.-  -- Therefore, after the filter has been used, there should be one PNG file and-  -- no JPG files.-  testCase "code block attributes override configuration defaults" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-caption-links-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    let config =-          defaultTestConfig-            { defaultDirectory = tempDir,-              defaultSaveFormat = JPG-            }--    -- Not all toolkits support both save formats-    when-      ( JPG `elem` supportedSaveFormats tk-          && PNG `elem` supportedSaveFormats tk-      )-      $ do-        let cb =-              addDirectory tempDir $-                addSaveFormat PNG $-                  codeBlock tk (trivialContent tk)-        _ <- runPlotM Nothing config $ make cb--        numberPngFiles <--          length-            <$> filter (isExtensionOf (extension PNG))-            <$> listDirectory (defaultDirectory config)-        numberJpgFiles <--          length-            <$> filter (isExtensionOf (extension JPG))-            <$> listDirectory (defaultDirectory config)-        assertEqual "" numberPngFiles 1-        assertEqual "" numberJpgFiles 0------------------------------------------------------------------------------------ Test that Markdown bold formatting in captions is correctly rendered-testMarkdownFormattingCaption1 :: Toolkit -> TestTree-testMarkdownFormattingCaption1 tk =-  testCase "appropriately parses captions 1" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-caption-parsing1-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    -- Note that this test is fragile, in the sense that the expected result must be carefully-    -- constructed-    let expected = [B.Plain [B.Strong [B.Str "caption"]]]-        cb =-          addDirectory tempDir $-            addCaption "**caption**" $-              codeBlock tk (trivialContent tk)-        fmt = B.Format "markdown"-    result <- runPlotM Nothing (defaultTestConfig {captionFormat = fmt}) $ make cb-    assertIsInfix expected (extractCaption result)-  where-    extractCaption (B.Figure _ (Caption _ caption) _) = caption------------------------------------------------------------------------------------ Test that Markdown bold formatting in captions is correctly rendered-testMarkdownFormattingCaption2 :: Toolkit -> TestTree-testMarkdownFormattingCaption2 tk =-  testCase "appropriately parses captions 2" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-caption-parsing2-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    -- Note that this test is fragile, in the sense that the expected result must be carefully-    -- constructed-    let expected = [B.Plain [Link ("", [], []) [Str "title"] ("https://google.com", "")]]-        cb =-          addDirectory tempDir $-            addCaption "[title](https://google.com)" $-              codeBlock tk (trivialContent tk)-        fmt = B.Format "markdown"-    result <- runPlotM Nothing (defaultTestConfig {captionFormat = fmt}) $ make cb-    assertIsInfix expected (extractCaption result)-  where-    extractCaption (B.Figure _ (Caption _ caption) _) = caption------------------------------------------------------------------------------------ Test that cleanOutpuDirs correctly cleans the output directory specified in a block.-testCleanOutputDirs :: Toolkit -> TestTree-testCleanOutputDirs tk =-  testCase "correctly cleans output directories" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-clean-output-dir" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    let cb =-          addDirectory tempDir $-            codeBlock tk (trivialContent tk)--    result <- runPlotM Nothing defaultTestConfig $ make cb-    cleanedDirs <- cleanOutputDirs defaultTestConfig cb--    assertEqual "" [tempDir] cleanedDirs--    outputDirExists <- doesDirectoryExist tempDir-    assertEqual "" outputDirExists False------------------------------------------------------------------------------------ Test that toolkit checks failed when appropriate.-testChecksFail :: Toolkit -> TestTree-testChecksFail tk =-  testCase "script checks fail when appropriate" $ do-    assertChecksFail tk-  where-    assertChecksFail Matplotlib = do-      let postfix = unpack . cls $ tk-      tempDir <- (</> "test-checks" <> postfix) <$> getTemporaryDirectory-      ensureDirectoryExistsAndEmpty tempDir--      let cb = addDirectory tempDir $ codeBlock Matplotlib "plt.show()"-      result <- runPlotM Nothing defaultTestConfig $ makeEither cb-      let expectedCheck :: Either PandocPlotError a -> Bool-          expectedCheck (Left (ScriptChecksFailedError _)) = True-          expectedCheck _ = False-      assertBool "" (expectedCheck result)-    assertChecksFail _ = assertEqual "Test skipped" True True------------------------------------------------------------------------------------ Test that Markdown bold formatting in captions is correctly rendered-testAttributesPreservedOnFigure :: Toolkit -> TestTree-testAttributesPreservedOnFigure tk =-  testCase "preserves code block attributes and sets them on the Figure element" $ do-    let postfix = unpack . cls $ tk-    tempDir <- (</> "test-preserved-attrs-" <> postfix) <$> getTemporaryDirectory-    ensureDirectoryExistsAndEmpty tempDir--    -- Note that this test is fragile, in the sense that the expected result must be carefully-    -- constructed-    let expectedAttrs = ("hello", [cls tk], [("key1", "val1"), ("key2", "val2")])-        cb =-          setAttrs expectedAttrs $-            addDirectory tempDir $-              addCaption "[title](https://google.com)" $-                codeBlock tk (trivialContent tk)-        fmt = B.Format "markdown"-    Figure (id', _, keyvals) _ _ <--      runPlotM-        Nothing-        ( defaultTestConfig-            { captionFormat = fmt,-              defaultDirectory = tempDir-            }-        )-        $ make cb-    let (expectedId, _, expectedKeyVals) = expectedAttrs-    assertEqual "identifier" expectedId id'-    assertEqual "key-value pairs" expectedKeyVals keyvals-  where-    extractCaption (B.Figure _ (Caption _ caption) _) = caption--codeBlock :: Toolkit -> Script -> Block-codeBlock tk script = CodeBlock (mempty, [cls tk], mempty) script--trivialContent :: Toolkit -> Script-trivialContent Matplotlib = "import matplotlib.pyplot as plt\n"-trivialContent PlotlyPython = "import plotly.graph_objects as go; fit = go.Figure()\n"-trivialContent PlotlyR = "library(plotly)\nfig <- plot_ly(midwest, x = ~percollege, color = ~state, type = \"box\")"-trivialContent Matlab = "figure('visible', 'off')\n"-trivialContent Mathematica = "\n"-trivialContent Octave = "figure('visible', 'off')\nplot (-10:0.1:10);"-trivialContent GGPlot2 = "library(ggplot2)\nggplot()\n"-trivialContent GNUPlot = "plot sin(x)"-trivialContent Graphviz = "digraph {A -> B [label=\"test\"];}"-trivialContent Bokeh =-  T.unlines-    [ "from bokeh.plotting import figure",-      "p = figure(title='simple line example')",-      "p.line([1,2,3,4], [5,6,7,8])"-    ]-trivialContent Plotsjl = "using Plots; x = 1:10; y = rand(10); plot(x, y);"-trivialContent PlantUML = "@startuml\nAlice -> Bob: test\n@enduml"-trivialContent SageMath = "G = plot(sin, 1, 10)"-trivialContent D2 = "x -> y -> z"--addCaption :: String -> Block -> Block-addCaption caption (CodeBlock (id', cls, attrs) script) =-  CodeBlock (id', cls, attrs ++ [(tshow CaptionK, pack caption)]) script--addDirectory :: FilePath -> Block -> Block-addDirectory dir (CodeBlock (id', cls, attrs) script) =-  CodeBlock (id', cls, attrs ++ [(tshow DirectoryK, pack dir)]) script--addPreamble :: FilePath -> Block -> Block-addPreamble inclusionPath (CodeBlock (id', cls, attrs) script) =-  CodeBlock (id', cls, attrs ++ [(tshow PreambleK, pack inclusionPath)]) script--addSaveFormat :: SaveFormat -> Block -> Block-addSaveFormat saveFormat (CodeBlock (id', cls, attrs) script) =-  CodeBlock (id', cls, attrs ++ [(tshow SaveFormatK, pack . extension $ saveFormat)]) script--addDPI :: Int -> Block -> Block-addDPI dpi (CodeBlock (id', cls, attrs) script) =-  CodeBlock (id', cls, attrs ++ [(tshow DpiK, pack . show $ dpi)]) script--addWithSource :: Bool -> Block -> Block-addWithSource yn (CodeBlock (id', cls, attrs) script) =-  CodeBlock (id', cls, attrs ++ [(tshow WithSourceK, pack . show $ yn)]) script--setAttrs :: Attr -> Block -> Block-setAttrs attrs (CodeBlock _ script) = CodeBlock attrs script---- | Assert that a file exists-assertFileExists :: (HasCallStack) => FilePath -> Assertion-assertFileExists filepath = do-  fileExists <- doesFileExist filepath-  unless fileExists (assertFailure msg)-  where-    msg = mconcat ["File ", filepath, " does not exist."]---- | Assert not equal-assertNotEqual :: (HasCallStack, Eq a, Show a) => String -> a -> a -> Assertion-assertNotEqual msg expected actual =-  unless-    (expected /= actual)-    (assertFailure $ mconcat [msg, ": expected ", show expected, " but got ", show actual])---- | Not available with GHC < 8.4--- since this function was added in filepath-1.4.2--- but GHC 8.2.2 comes with filepath-1.4.1.2-isExtensionOf :: String -> FilePath -> Bool-isExtensionOf ext@('.' : _) = isSuffixOf ext . takeExtensions-isExtensionOf ext = isSuffixOf ('.' : ext) . takeExtensions---- | Assert that the first list is contained,--- wholly and intact, anywhere within the second.-assertIsInfix :: (Eq a, Show a, HasCallStack) => [a] -> [a] -> Assertion-assertIsInfix xs ys = unless (xs `isInfixOf` ys) (assertFailure msg)-  where-    msg = mconcat ["Expected ", show xs, " to be an infix of ", show ys]---- Ensure a directory is empty but exists.-ensureDirectoryExistsAndEmpty :: FilePath -> IO ()-ensureDirectoryExistsAndEmpty dir = do-  exists <- doesDirectoryExist dir-  if exists-    then removePathForcibly dir-    else return ()-  createDirectory dir--tshow :: (Show a) => a -> Text-tshow = pack . show+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Common where
+
+import Control.Monad (unless, when, forM)
+import Data.List (isInfixOf, isSuffixOf, (!!), (\\))
+import Data.Monoid ((<>))
+import qualified Data.Set as S
+import Data.String (fromString)
+import Data.Text (Text, pack, unpack)
+import qualified Data.Text as T
+import System.Directory
+  ( createDirectory,
+    createDirectoryIfMissing,
+    doesDirectoryExist,
+    doesFileExist,
+    getTemporaryDirectory,
+    listDirectory,
+    removeDirectoryRecursive,
+    removePathForcibly,
+  )
+import System.FilePath (takeExtensions, (</>))
+import Test.Tasty
+import Test.Tasty.HUnit
+import qualified Text.Pandoc.Builder as B
+import qualified Text.Pandoc.Definition as B
+import Text.Pandoc.Filter.Plot
+import Text.Pandoc.Filter.Plot.Internal
+import Text.Pandoc.JSON
+
+defaultTestConfig :: Configuration
+defaultTestConfig =
+  defaultConfiguration
+    { logVerbosity = Silent,
+      logSink = StdErr,
+      defaultSaveFormat = PNG
+    }
+
+-------------------------------------------------------------------------------
+-- Test that plot files and source files are created when the filter is run
+testFileCreation :: Toolkit -> TestTree
+testFileCreation tk =
+  testCase "writes output files in appropriate directory" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-file-creation-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    let cb = (addDirectory tempDir $ codeBlock tk (trivialContent tk))
+    _ <- runPlotM Nothing defaultTestConfig $ make cb
+    filesCreated <- length <$> listDirectory tempDir
+    assertEqual "" 2 filesCreated
+
+-------------------------------------------------------------------------------
+-- Test that plot files and source files are created when the filter is run
+-- and the path of the files involves spaces. See Issue #2
+testFileCreationPathWithSpaces :: Toolkit -> TestTree
+testFileCreationPathWithSpaces tk =
+  testCase "writes output files in appropriate directory (with spaces)" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-file-creation-with-spaces-   -" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    let cb = (addDirectory tempDir $ codeBlock tk (trivialContent tk))
+    _ <- runPlotM Nothing defaultTestConfig $ make cb
+    filesCreated <- length <$> listDirectory tempDir
+    assertEqual "" 2 filesCreated
+
+-------------------------------------------------------------------------------
+-- Test that pandoc-plot appropriately transforms code blocks that are
+-- nested in other blocks (e.g. Divs)
+testNestedCodeBlocks :: Toolkit -> TestTree
+testNestedCodeBlocks tk =
+  testCase "transforms code blocks nested in other blocks" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-nester-blocks-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    let block =
+          Div mempty $
+            singleton $
+              addDirectory tempDir $
+                codeBlock tk (trivialContent tk)
+    _ <- runPlotM Nothing defaultTestConfig $ make block
+    filesCreated <- length <$> listDirectory tempDir
+    assertEqual "" 2 filesCreated
+  where
+    singleton :: a -> [a]
+    singleton = return
+
+-------------------------------------------------------------------------------
+-- Test that included files are found within the source
+testFileInclusion :: Toolkit -> TestTree
+testFileInclusion tk =
+  testCase "includes plot inclusions" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-file-inclusion-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    let cb =
+          ( addPreamble (include tk) $
+              addDirectory tempDir $
+                codeBlock tk (trivialContent tk)
+          )
+    _ <- runPlotM Nothing defaultTestConfig $ make cb
+    inclusion <- readFile (include tk)
+    sourcePath <- head . filter (isExtensionOf ".src.html") <$> listDirectory tempDir
+    src <- readFile (tempDir </> sourcePath)
+    assertIsInfix inclusion src
+  where
+    include Matplotlib = "tests/includes/matplotlib.py"
+    include PlotlyPython = "tests/includes/plotly-python.py"
+    include PlotlyR = "tests/includes/plotly-r.r"
+    include Matlab = "tests/includes/matlabplot.m"
+    include Mathematica = "tests/includes/mathplot.m"
+    include Octave = "tests/includes/octave.m"
+    include GGPlot2 = "tests/includes/ggplot2.r"
+    include GNUPlot = "tests/includes/gnuplot.gp"
+    include Graphviz = "tests/includes/graphviz.dot"
+    include Bokeh = "tests/includes/bokeh.py"
+    include Plotsjl = "tests/includes/plotsjl.jl"
+    include PlantUML = "tests/includes/plantuml.txt"
+    include SageMath = "tests/includes/sagemath.sage"
+    include D2 = "tests/includes/d2-dd.d2"
+    include Asymptote = "tests/includes/asymptote.asy"
+
+-------------------------------------------------------------------------------
+-- Tests that the files are saved in all the advertised formats
+testAllSaveFormats :: Toolkit -> TestTree
+-- Correct formats unsupported on CI.
+-- TODO: change when CI support improves
+testAllSaveFormats tk@Graphviz =
+   testGroup "advertised save formats that work on CI"
+      (testSaveFormat tk <$> (supportedSaveFormats tk \\ [WEBP]))
+testAllSaveFormats tk@Matlab =
+   testGroup "advertised save formats that work on CI"
+      (testSaveFormat tk <$> (supportedSaveFormats tk \\ [SVG]))
+testAllSaveFormats tk@GGPlot2 =
+   testGroup "advertised save formats that work on CI"
+      (testSaveFormat tk <$> (supportedSaveFormats tk \\ [SVG]))
+-- All other formats:
+testAllSaveFormats tk =
+   testGroup "advertised output formats" (testSaveFormat tk <$> supportedSaveFormats tk)
+
+-------------------------------------------------------------------------------
+-- Test that the files are saved in the appropriate format
+testSaveFormat :: Toolkit -> SaveFormat -> TestTree
+testSaveFormat tk fmt =
+  testCase ("saves in the appropriate format (" <> show fmt <> ")") $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-safe-format-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+    let cb =
+          ( addSaveFormat fmt $
+              addDirectory tempDir $
+                codeBlock tk (trivialContent tk)
+          )
+    _ <- runPlotM Nothing defaultTestConfig $ make cb
+    numberjpgFiles <-
+      length
+        <$> filter (isExtensionOf (extension fmt))
+        <$> listDirectory tempDir
+    assertEqual "" numberjpgFiles 1
+
+-------------------------------------------------------------------------------
+-- Test that the appropriate error is raised when trying to save figures
+-- in an incompatible format
+testSaveFormatIncompatibility :: Toolkit -> TestTree
+testSaveFormatIncompatibility tk =
+  testCase "raises the appropriate error on save format incompatibility" $ do
+    let allSaveFormats = enumFromTo minBound maxBound :: [SaveFormat]
+        incompatibleFormats = S.toList $ S.difference (S.fromList allSaveFormats) (S.fromList $ supportedSaveFormats tk)
+    if null incompatibleFormats
+      then return ()
+      else do
+        let fmt = head incompatibleFormats
+            cb = addSaveFormat fmt $ codeBlock tk (trivialContent tk)
+
+        result <- runPlotM Nothing defaultTestConfig $ makeEither cb
+        let expectedCheck :: Either PandocPlotError a -> Bool
+            expectedCheck (Left (IncompatibleSaveFormatError fmt' tk')) = (fmt' == fmt) && (tk' == tk)
+            expectedCheck _ = False
+        assertBool "" (expectedCheck result)
+
+-------------------------------------------------------------------------------
+-- Test that it is possible to not render source links in captions
+testWithSource :: Toolkit -> TestTree
+testWithSource tk =
+  testCase "appropriately omits links to source code" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-caption-links-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    let expected = "caption content"
+        noSource =
+          addWithSource False $
+            addDirectory tempDir $
+              addCaption expected $
+                codeBlock tk (trivialContent tk)
+        withSource =
+          addWithSource True $
+            addDirectory tempDir $
+              addCaption expected $
+                codeBlock tk (trivialContent tk)
+    blockNoSource <- runPlotM Nothing defaultTestConfig $ make noSource
+    blockWithSource <- runPlotM Nothing defaultTestConfig $ make withSource
+
+    -- In the case where source=false, the caption is used verbatim.
+    -- Otherwise, links will be appended to the caption; hence, the caption
+    -- is no longer equal to the initial value
+    assertEqual "" [B.Plain $ B.toList (fromString expected)] (extractCaption blockNoSource)
+    assertNotEqual "" [B.Plain $ B.toList (fromString expected)] (extractCaption blockWithSource)
+  where
+    extractCaption (B.Figure _ (Caption _ caption) _) = caption
+
+-------------------------------------------------------------------------------
+-- Test that it is possible to change the source code label in captions
+testSourceLabel :: Toolkit -> TestTree
+testSourceLabel tk =
+  testCase "appropriately changes the source code label" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-source-label-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    -- Note that this test requires that the actual caption be empty
+    -- so that the caption is only the source code label
+    let withSource =
+          addWithSource True $
+            addDirectory tempDir $
+              addCaption mempty $ -- This test requires that the actual caption be empty
+                codeBlock tk (trivialContent tk)
+    blockWithSource <- runPlotM Nothing defaultTestConfig {sourceCodeLabel = "Test label"} $ make withSource
+
+    let [Plain [Space, _, B.Link _ ils _, _]] = extractCaption blockWithSource
+    assertEqual "" (B.toList $ B.str "Test label") ils
+  where
+    extractCaption (B.Figure _ (Caption _ caption) _) = caption
+
+    linkLabel (B.Plain [B.Link _ ils _]) = B.fromList ils
+    linkLabel _ = mempty
+
+-------------------------------------------------------------------------------
+-- Test that parameters in code blocks will override the defaults in configuration
+testOverrideConfiguration :: Toolkit -> TestTree
+testOverrideConfiguration tk =
+  -- We set the default save format to JPG via the configuration,
+  -- but set the code block parameter to PNG.
+  -- Therefore, after the filter has been used, there should be one PNG file and
+  -- no JPG files.
+  testCase "code block attributes override configuration defaults" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-caption-links-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    let config =
+          defaultTestConfig
+            { defaultDirectory = tempDir,
+              defaultSaveFormat = JPG
+            }
+
+    -- Not all toolkits support both save formats
+    when
+      ( JPG `elem` supportedSaveFormats tk
+          && PNG `elem` supportedSaveFormats tk
+      )
+      $ do
+        let cb =
+              addDirectory tempDir $
+                addSaveFormat PNG $
+                  codeBlock tk (trivialContent tk)
+        _ <- runPlotM Nothing config $ make cb
+
+        numberPngFiles <-
+          length
+            <$> filter (isExtensionOf (extension PNG))
+            <$> listDirectory (defaultDirectory config)
+        numberJpgFiles <-
+          length
+            <$> filter (isExtensionOf (extension JPG))
+            <$> listDirectory (defaultDirectory config)
+        assertEqual "" numberPngFiles 1
+        assertEqual "" numberJpgFiles 0
+
+-------------------------------------------------------------------------------
+-- Test that Markdown bold formatting in captions is correctly rendered
+testMarkdownFormattingCaption1 :: Toolkit -> TestTree
+testMarkdownFormattingCaption1 tk =
+  testCase "appropriately parses captions 1" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-caption-parsing1-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    -- Note that this test is fragile, in the sense that the expected result must be carefully
+    -- constructed
+    let expected = [B.Plain [B.Strong [B.Str "caption"]]]
+        cb =
+          addDirectory tempDir $
+            addCaption "**caption**" $
+              codeBlock tk (trivialContent tk)
+        fmt = B.Format "markdown"
+    result <- runPlotM Nothing (defaultTestConfig {captionFormat = fmt}) $ make cb
+    assertIsInfix expected (extractCaption result)
+  where
+    extractCaption (B.Figure _ (Caption _ caption) _) = caption
+
+-------------------------------------------------------------------------------
+-- Test that Markdown bold formatting in captions is correctly rendered
+testMarkdownFormattingCaption2 :: Toolkit -> TestTree
+testMarkdownFormattingCaption2 tk =
+  testCase "appropriately parses captions 2" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-caption-parsing2-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    -- Note that this test is fragile, in the sense that the expected result must be carefully
+    -- constructed
+    let expected = [B.Plain [Link ("", [], []) [Str "title"] ("https://google.com", "")]]
+        cb =
+          addDirectory tempDir $
+            addCaption "[title](https://google.com)" $
+              codeBlock tk (trivialContent tk)
+        fmt = B.Format "markdown"
+    result <- runPlotM Nothing (defaultTestConfig {captionFormat = fmt}) $ make cb
+    assertIsInfix expected (extractCaption result)
+  where
+    extractCaption (B.Figure _ (Caption _ caption) _) = caption
+
+-------------------------------------------------------------------------------
+-- Test that cleanOutpuDirs correctly cleans the output directory specified in a block.
+testCleanOutputDirs :: Toolkit -> TestTree
+testCleanOutputDirs tk =
+  testCase "correctly cleans output directories" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-clean-output-dir" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    let cb =
+          addDirectory tempDir $
+            codeBlock tk (trivialContent tk)
+
+    result <- runPlotM Nothing defaultTestConfig $ make cb
+    cleanedDirs <- cleanOutputDirs defaultTestConfig cb
+
+    assertEqual "" [tempDir] cleanedDirs
+
+    outputDirExists <- doesDirectoryExist tempDir
+    assertEqual "" outputDirExists False
+
+-------------------------------------------------------------------------------
+-- Test that toolkit checks failed when appropriate.
+testChecksFail :: Toolkit -> TestTree
+testChecksFail tk =
+  testCase "script checks fail when appropriate" $ do
+    assertChecksFail tk
+  where
+    assertChecksFail Matplotlib = do
+      let postfix = unpack . cls $ tk
+      tempDir <- (</> "test-checks" <> postfix) <$> getTemporaryDirectory
+      ensureDirectoryExistsAndEmpty tempDir
+
+      let cb = addDirectory tempDir $ codeBlock Matplotlib "plt.show()"
+      result <- runPlotM Nothing defaultTestConfig $ makeEither cb
+      let expectedCheck :: Either PandocPlotError a -> Bool
+          expectedCheck (Left (ScriptChecksFailedError _)) = True
+          expectedCheck _ = False
+      assertBool "" (expectedCheck result)
+    assertChecksFail _ = assertEqual "Test skipped" True True
+
+-------------------------------------------------------------------------------
+-- Test that Markdown bold formatting in captions is correctly rendered
+testAttributesPreservedOnFigure :: Toolkit -> TestTree
+testAttributesPreservedOnFigure tk =
+  testCase "preserves code block attributes and sets them on the Figure element" $ do
+    let postfix = unpack . cls $ tk
+    tempDir <- (</> "test-preserved-attrs-" <> postfix) <$> getTemporaryDirectory
+    ensureDirectoryExistsAndEmpty tempDir
+
+    -- Note that this test is fragile, in the sense that the expected result must be carefully
+    -- constructed
+    let expectedAttrs = ("hello", [cls tk], [("key1", "val1"), ("key2", "val2")])
+        cb =
+          setAttrs expectedAttrs $
+            addDirectory tempDir $
+              addCaption "[title](https://google.com)" $
+                codeBlock tk (trivialContent tk)
+        fmt = B.Format "markdown"
+    Figure (id', _, keyvals) _ _ <-
+      runPlotM
+        Nothing
+        ( defaultTestConfig
+            { captionFormat = fmt,
+              defaultDirectory = tempDir
+            }
+        )
+        $ make cb
+    let (expectedId, _, expectedKeyVals) = expectedAttrs
+    assertEqual "identifier" expectedId id'
+    assertEqual "key-value pairs" expectedKeyVals keyvals
+  where
+    extractCaption (B.Figure _ (Caption _ caption) _) = caption
+
+codeBlock :: Toolkit -> Script -> Block
+codeBlock tk script = CodeBlock (mempty, [cls tk], mempty) script
+
+trivialContent :: Toolkit -> Script
+trivialContent Matplotlib = "import matplotlib.pyplot as plt\n"
+trivialContent PlotlyPython = "import plotly.graph_objects as go; fit = go.Figure()\n"
+trivialContent PlotlyR = "library(plotly)\nfig <- plot_ly(midwest, x = ~percollege, color = ~state, type = \"box\")"
+trivialContent Matlab = "figure('visible', 'off')\n"
+trivialContent Mathematica = "\n"
+trivialContent Octave = "figure('visible', 'off')\nplot (-10:0.1:10);"
+trivialContent GGPlot2 = "library(ggplot2)\nggplot()\n"
+trivialContent GNUPlot = "plot sin(x)"
+trivialContent Graphviz = "digraph {A -> B [label=\"test\"];}"
+trivialContent Bokeh =
+  T.unlines
+    [ "from bokeh.plotting import figure",
+      "p = figure(title='simple line example')",
+      "p.line([1,2,3,4], [5,6,7,8])"
+    ]
+trivialContent Plotsjl = "using Plots; x = 1:10; y = rand(10); plot(x, y);"
+trivialContent PlantUML = "@startuml\nAlice -> Bob: test\n@enduml"
+trivialContent SageMath = "G = plot(sin, 1, 10)"
+trivialContent D2 = "x -> y -> z"
+trivialContent Asymptote = "draw((0,0)--(1,0));"
+
+addCaption :: String -> Block -> Block
+addCaption caption (CodeBlock (id', cls, attrs) script) =
+  CodeBlock (id', cls, attrs ++ [(tshow CaptionK, pack caption)]) script
+
+addDirectory :: FilePath -> Block -> Block
+addDirectory dir (CodeBlock (id', cls, attrs) script) =
+  CodeBlock (id', cls, attrs ++ [(tshow DirectoryK, pack dir)]) script
+
+addPreamble :: FilePath -> Block -> Block
+addPreamble inclusionPath (CodeBlock (id', cls, attrs) script) =
+  CodeBlock (id', cls, attrs ++ [(tshow PreambleK, pack inclusionPath)]) script
+
+addSaveFormat :: SaveFormat -> Block -> Block
+addSaveFormat saveFormat (CodeBlock (id', cls, attrs) script) =
+  CodeBlock (id', cls, attrs ++ [(tshow SaveFormatK, pack . extension $ saveFormat)]) script
+
+addDPI :: Int -> Block -> Block
+addDPI dpi (CodeBlock (id', cls, attrs) script) =
+  CodeBlock (id', cls, attrs ++ [(tshow DpiK, pack . show $ dpi)]) script
+
+addWithSource :: Bool -> Block -> Block
+addWithSource yn (CodeBlock (id', cls, attrs) script) =
+  CodeBlock (id', cls, attrs ++ [(tshow WithSourceK, pack . show $ yn)]) script
+
+setAttrs :: Attr -> Block -> Block
+setAttrs attrs (CodeBlock _ script) = CodeBlock attrs script
+
+-- | Assert that a file exists
+assertFileExists :: (HasCallStack) => FilePath -> Assertion
+assertFileExists filepath = do
+  fileExists <- doesFileExist filepath
+  unless fileExists (assertFailure msg)
+  where
+    msg = mconcat ["File ", filepath, " does not exist."]
+
+-- | Assert not equal
+assertNotEqual :: (HasCallStack, Eq a, Show a) => String -> a -> a -> Assertion
+assertNotEqual msg expected actual =
+  unless
+    (expected /= actual)
+    (assertFailure $ mconcat [msg, ": expected ", show expected, " but got ", show actual])
+
+-- | Not available with GHC < 8.4
+-- since this function was added in filepath-1.4.2
+-- but GHC 8.2.2 comes with filepath-1.4.1.2
+isExtensionOf :: String -> FilePath -> Bool
+isExtensionOf ext@('.' : _) = isSuffixOf ext . takeExtensions
+isExtensionOf ext = isSuffixOf ('.' : ext) . takeExtensions
+
+-- | Assert that the first list is contained,
+-- wholly and intact, anywhere within the second.
+assertIsInfix :: (Eq a, Show a, HasCallStack) => [a] -> [a] -> Assertion
+assertIsInfix xs ys = unless (xs `isInfixOf` ys) (assertFailure msg)
+  where
+    msg = mconcat ["Expected ", show xs, " to be an infix of ", show ys]
+
+-- Ensure a directory is empty but exists.
+ensureDirectoryExistsAndEmpty :: FilePath -> IO ()
+ensureDirectoryExistsAndEmpty dir = do
+  exists <- doesDirectoryExist dir
+  if exists
+    then removePathForcibly dir
+    else return ()
+  createDirectory dir
+
+tshow :: (Show a) => a -> Text
+tshow = pack . show
tests/Main.hs view
@@ -1,161 +1,161 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}--import Common-import Control.Monad (forM_)-import qualified Data.Map.Strict as Map-import Data.Text (Text, unpack)-import qualified Data.Text as T-import Test.Tasty-import Test.Tasty.HUnit-import qualified Text.Pandoc.Builder as B-import qualified Text.Pandoc.Definition as B-import Text.Pandoc.Filter.Plot-import Text.Pandoc.Filter.Plot.Internal-import Text.Pandoc.JSON--main :: IO ()-main = do-  available <- availableToolkits defaultTestConfig-  unavailable <- unavailableToolkits defaultTestConfig-  forM_ unavailable $ \tk -> do-    putStrLn $ show tk <> " is not available. Its tests will be skipped."--  defaultMain $-    testGroup-      "All tests"-      [ testGroup-          "Configuration tests"-          [ testEmptyConfiguration,-            testExampleConfiguration,-            testConfigurationPathMeta-          ],-        testGroup-          "Parsing tests"-          [testCaptionReader],-        testGroup-          "HTML embedding tests"-          [ testHtmlBodyEmbedding,-            testHtmlEmbedding-          ],-        testGroup-          "Toolkit tests"-          (toolkitSuite <$> available)-      ]---- | Suite of tests that every renderer should pass-toolkitSuite :: Toolkit -> TestTree-toolkitSuite tk =-  testGroup (show tk) $-    [ testFileCreation,-      testFileCreationPathWithSpaces,-      testNestedCodeBlocks,-      testFileInclusion,-      testSaveFormat,-      testSaveFormatIncompatibility,-      testWithSource,-      testSourceLabel,-      testOverrideConfiguration,-      testMarkdownFormattingCaption1,-      testMarkdownFormattingCaption2,-      testAttributesPreservedOnFigure,-      testCleanOutputDirs,-      testChecksFail-    ]-      <*> [tk]--testEmptyConfiguration :: TestTree-testEmptyConfiguration =-  testCase "empty configuration is correctly parsed to default values" $ do-    let config = defaultConfiguration--    parsedConfig <- configuration "tests/fixtures/.empty-config.yml"-    assertEqual "" config parsedConfig---- The example configuration is build by hand (to add comments)--- and it is embedded into the executable. Therefore, we must make sure it--- is correctly parsed (and is hence valid.)-testExampleConfiguration :: TestTree-testExampleConfiguration =-  testCase "example configuration is correctly parsed" $ do-    -- The example config reflects the Windows default-    -- Therefore, we need to test against the Windows default,-    -- even on other OSes-    let config =-          defaultConfiguration-            { matplotlibExe = "python",-              plotlyPythonExe = "python",-              bokehExe = "python",-              defaultDependencies = ["file1.txt", "file2.txt"]-            }--    parsedConfig <- configuration "example-config.yml"-    assertEqual "" config parsedConfig---- Test that the path to configuration in metadata is found correctly-testConfigurationPathMeta :: TestTree-testConfigurationPathMeta =-  testCase "Configuration path stored in metadata is correctly parsed" $ do-    let configPath = "tests/fixtures/.config-meta.yml"-        meta = B.Meta $ Map.fromList [("plot-configuration", B.MetaString configPath)]--    parsedConfig <- maybe (return defaultConfiguration) configuration $ configurationPathMeta (B.Pandoc meta mempty)-    expected <- configuration (unpack configPath)-    assertEqual "" expected parsedConfig--testCaptionReader :: TestTree-testCaptionReader =-  testCase "caption is parsed in the same way as input document format" $ do-    -- Note that this test is fragile, in the sense that the expected result must be carefully-    -- constructed-    let caption = "Here is a [link](https://www.google.com) in a caption."-        expected = Just [Str "Here", Space, Str "is", Space, Str "a", Space, Link ("", [], []) [Str "link"] ("https://www.google.com", ""), Space, Str "in", Space, Str "a", Space, Str "caption."]-        fmt = B.Format "markdown+tex_math_dollars"-        parsed = captionReader fmt caption--    assertEqual "" expected parsed--testHtmlBodyEmbedding :: TestTree-testHtmlBodyEmbedding =-  testCase "HTML body can be extracted from file" $ do-    let html =-          T.unlines-            [ "<!DOCTYPE html>",-              "<html lang=\"en\">",-              "  <head>",-              "    <meta charset=\"utf-8\">",-              "    <title>title</title>",-              "    <link rel=\"stylesheet\" href=\"style.css\">",-              "  </head>",-              "  <body>",-              "    <p>Hello</p>",-              "  </body>",-              "</html>"-            ]-        extracted = extractPlot html-        expected = "\n    <p>Hello</p>"--    assertEqual "" expected extracted--testHtmlEmbedding :: TestTree-testHtmlEmbedding =-  testCase "HTML body and head scripts can be extracted from file" $ do-    let html =-          T.unlines-            [ "<!DOCTYPE html>",-              "<html lang=\"en\">",-              "  <head>",-              "    <meta charset=\"utf-8\">",-              "    <title>title</title>",-              "    <link rel=\"stylesheet\" href=\"style.css\">",-              "    <script src=\"script.js\"></script>",-              "  </head>",-              "  <body>",-              "    <p>Hello</p>",-              "  </body>",-              "</html>"-            ]-        extracted = extractPlot html-        expected = "<script src=\"script.js\"></script>\n    <p>Hello</p>"--    assertEqual "" expected extracted+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Common
+import Control.Monad (forM_)
+import qualified Data.Map.Strict as Map
+import Data.Text (Text, unpack)
+import qualified Data.Text as T
+import Test.Tasty
+import Test.Tasty.HUnit
+import qualified Text.Pandoc.Builder as B
+import qualified Text.Pandoc.Definition as B
+import Text.Pandoc.Filter.Plot
+import Text.Pandoc.Filter.Plot.Internal
+import Text.Pandoc.JSON
+
+main :: IO ()
+main = do
+  available <- availableToolkits defaultTestConfig
+  unavailable <- unavailableToolkits defaultTestConfig
+  forM_ unavailable $ \tk -> do
+    putStrLn $ show tk <> " is not available. Its tests will be skipped."
+
+  defaultMain $
+    testGroup
+      "All tests"
+      [ testGroup
+          "Configuration tests"
+          [ testEmptyConfiguration,
+            testExampleConfiguration,
+            testConfigurationPathMeta
+          ],
+        testGroup
+          "Parsing tests"
+          [testCaptionReader],
+        testGroup
+          "HTML embedding tests"
+          [ testHtmlBodyEmbedding,
+            testHtmlEmbedding
+          ],
+        testGroup
+          "Toolkit tests"
+          (toolkitSuite <$> available)
+      ]
+
+-- | Suite of tests that every renderer should pass
+toolkitSuite :: Toolkit -> TestTree
+toolkitSuite tk =
+  testGroup (show tk) $
+    [ testFileCreation,
+      testFileCreationPathWithSpaces,
+      testNestedCodeBlocks,
+      testFileInclusion,
+      testAllSaveFormats,
+      testSaveFormatIncompatibility,
+      testWithSource,
+      testSourceLabel,
+      testOverrideConfiguration,
+      testMarkdownFormattingCaption1,
+      testMarkdownFormattingCaption2,
+      testAttributesPreservedOnFigure,
+      testCleanOutputDirs,
+      testChecksFail
+    ]
+      <*> [tk]
+
+testEmptyConfiguration :: TestTree
+testEmptyConfiguration =
+  testCase "empty configuration is correctly parsed to default values" $ do
+    let config = defaultConfiguration
+
+    parsedConfig <- configuration "tests/fixtures/.empty-config.yml"
+    assertEqual "" config parsedConfig
+
+-- The example configuration is build by hand (to add comments)
+-- and it is embedded into the executable. Therefore, we must make sure it
+-- is correctly parsed (and is hence valid.)
+testExampleConfiguration :: TestTree
+testExampleConfiguration =
+  testCase "example configuration is correctly parsed" $ do
+    -- The example config reflects the Windows default
+    -- Therefore, we need to test against the Windows default,
+    -- even on other OSes
+    let config =
+          defaultConfiguration
+            { matplotlibExe = "python",
+              plotlyPythonExe = "python",
+              bokehExe = "python",
+              defaultDependencies = ["file1.txt", "file2.txt"]
+            }
+
+    parsedConfig <- configuration "example-config.yml"
+    assertEqual "" config parsedConfig
+
+-- Test that the path to configuration in metadata is found correctly
+testConfigurationPathMeta :: TestTree
+testConfigurationPathMeta =
+  testCase "Configuration path stored in metadata is correctly parsed" $ do
+    let configPath = "tests/fixtures/.config-meta.yml"
+        meta = B.Meta $ Map.fromList [("plot-configuration", B.MetaString configPath)]
+
+    parsedConfig <- maybe (return defaultConfiguration) configuration $ configurationPathMeta (B.Pandoc meta mempty)
+    expected <- configuration (unpack configPath)
+    assertEqual "" expected parsedConfig
+
+testCaptionReader :: TestTree
+testCaptionReader =
+  testCase "caption is parsed in the same way as input document format" $ do
+    -- Note that this test is fragile, in the sense that the expected result must be carefully
+    -- constructed
+    let caption = "Here is a [link](https://www.google.com) in a caption."
+        expected = Just [Str "Here", Space, Str "is", Space, Str "a", Space, Link ("", [], []) [Str "link"] ("https://www.google.com", ""), Space, Str "in", Space, Str "a", Space, Str "caption."]
+        fmt = B.Format "markdown+tex_math_dollars"
+        parsed = captionReader fmt caption
+
+    assertEqual "" expected parsed
+
+testHtmlBodyEmbedding :: TestTree
+testHtmlBodyEmbedding =
+  testCase "HTML body can be extracted from file" $ do
+    let html =
+          T.unlines
+            [ "<!DOCTYPE html>",
+              "<html lang=\"en\">",
+              "  <head>",
+              "    <meta charset=\"utf-8\">",
+              "    <title>title</title>",
+              "    <link rel=\"stylesheet\" href=\"style.css\">",
+              "  </head>",
+              "  <body>",
+              "    <p>Hello</p>",
+              "  </body>",
+              "</html>"
+            ]
+        extracted = extractPlot html
+        expected = "\n    <p>Hello</p>"
+
+    assertEqual "" expected extracted
+
+testHtmlEmbedding :: TestTree
+testHtmlEmbedding =
+  testCase "HTML body and head scripts can be extracted from file" $ do
+    let html =
+          T.unlines
+            [ "<!DOCTYPE html>",
+              "<html lang=\"en\">",
+              "  <head>",
+              "    <meta charset=\"utf-8\">",
+              "    <title>title</title>",
+              "    <link rel=\"stylesheet\" href=\"style.css\">",
+              "    <script src=\"script.js\"></script>",
+              "  </head>",
+              "  <body>",
+              "    <p>Hello</p>",
+              "  </body>",
+              "</html>"
+            ]
+        extracted = extractPlot html
+        expected = "<script src=\"script.js\"></script>\n    <p>Hello</p>"
+
+    assertEqual "" expected extracted
tests/fixtures/.config-meta.yml view
@@ -1,3 +1,3 @@-# Just not default values-dpi: 1000-directory: ".."+# Just not default values
+dpi: 1000
+directory: ".."
tests/fixtures/.verbose-config.yml view
@@ -1,11 +1,11 @@-strict: true--logging:-  verbosity: debug--matplotlib:-  executable: "python"-  command_line_arguments: -Wa--plotsjl:+strict: true
+
+logging:
+  verbosity: debug
+
+matplotlib:
+  executable: "python"
+  command_line_arguments: -Wa
+
+plotsjl:
   command_line_arguments: --optimize=0
tests/fixtures/data.csv view
@@ -1,5 +1,5 @@-0,0-1,1-2,2-3,3+0,0
+1,1
+2,2
+3,3
 4,4
tests/fixtures/plotfile.py view
@@ -1,3 +1,3 @@-import matplotlib.pyplot as plt-+import matplotlib.pyplot as plt
+
 plt.plot([1,2,3,4,5], [5,6,7,8,9])