pax_global_header00006660000000000000000000000064141200143050014500gustar00rootroot0000000000000052 comment=1beda668a764c8aa8e1c4e0cebce4323d4181f92 pandocfilters-1.5.0/000077500000000000000000000000001412001430500143405ustar00rootroot00000000000000pandocfilters-1.5.0/.github/000077500000000000000000000000001412001430500157005ustar00rootroot00000000000000pandocfilters-1.5.0/.github/workflows/000077500000000000000000000000001412001430500177355ustar00rootroot00000000000000pandocfilters-1.5.0/.github/workflows/pythonpackage.yml000066400000000000000000000044341412001430500233220ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Python package on: push: pull_request: jobs: test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: # see setup.py for supported versions python-version: - 2.7 - 3.5 - 3.6 - 3.7 - 3.8 - 3.9 - pypy2 - pypy3 # should test sparingly across API breaking boundaries pandoc-version: # - 2.0.6 # - 2.1.3 # - 2.2.3.2 # - 2.3.1 # - 2.4 # - 2.5 # - 2.6 # panflute only support at or above this # - 2.7.3 # no major API change between 2.7 to 2.9 # - 2.8.1 # - 2.9.2.1 # as of writing, panflute only support pandoc<= 2.9. But GitHub workflow does not support "allow failure" yet. See https://github.com/actions/toolkit/issues/399 # 2.10 has breaking change # - 2.10.1 # 2.11 has minor breaking change, fixing some quirks in 2.10 # - 2.11.0.4 - 2.11.4 # - 2.12 - latest steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install examples' dependencies run: sudo apt install abcm2ps graphviz graphviz-dev texlive-full - name: Install dependencies—pip # pygraphviz for graphviz.py run: | python -m pip install -U setuptools pygraphviz python -m pip install . - name: Install dependencies—pandoc run: | # pandoc [[ ${{ matrix.pandoc-version }} == "latest" ]] && url="https://github.com/jgm/pandoc/releases/latest" || url="https://github.com/jgm/pandoc/releases/tag/${{ matrix.pandoc-version }}" downloadUrl="https://github.com$(curl -L $url | grep -o '/jgm/pandoc/releases/download/.*-amd64\.deb')" wget --quiet "$downloadUrl" sudo dpkg -i "${downloadUrl##*/}" - name: Tests run: cd examples; make -j4 pandocfilters-1.5.0/.gitignore000066400000000000000000000002401412001430500163240ustar00rootroot00000000000000build/ dist/ MANIFEST *~ *.pyc __pycache__/ *-images/ tmp_ly/ *-sample.pdf .idea/ *.egg-info/ examples/lyluatex.lua examples/lyluatex.sty examples/plantuml.jar pandocfilters-1.5.0/CHANGELOG.md000066400000000000000000000011171412001430500161510ustar00rootroot00000000000000# Revision history for `pandocfilters` - v1.5.0: Last release supporting Python 2. - Added an environment variable `PANDOCFILTER_CLEANUP` that when `get_filename4code` is used, temporary directory will be cleaned up automatically. See #88. - `examples/` is no longer included in the distribution (i.e. source distribution or binary wheels found on PyPI.) This should be a backward incompatible change as `examples/` is never exposed as a Python module, nor entry points. - Added a couple of examples. - See more in . pandocfilters-1.5.0/LICENSE000066400000000000000000000027301412001430500153470ustar00rootroot00000000000000Copyright (c) 2013, John MacFarlane All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of John Macfarlane nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pandocfilters-1.5.0/MANIFEST.in000066400000000000000000000000701412001430500160730ustar00rootroot00000000000000include README.rst include CHANGELOG.md include LICENSE pandocfilters-1.5.0/PACKAGING000066400000000000000000000002561412001430500155520ustar00rootroot00000000000000Notes on uploading this package to PyPI python setup.py sdist bdist_wheel twine upload dist/* See https://packaging.python.org/distributing/#uploading-your-project-to-pypi pandocfilters-1.5.0/README.rst000066400000000000000000000172231412001430500160340ustar00rootroot00000000000000pandocfilters ============= A python module for writing `pandoc `_ filters What are pandoc filters? -------------------------- Pandoc filters are pipes that read a JSON serialization of the Pandoc AST from stdin, transform it in some way, and write it to stdout. They can be used with pandoc (>= 1.12) either using pipes :: pandoc -t json -s | ./caps.py | pandoc -f json or using the ``--filter`` (or ``-F``) command-line option. :: pandoc --filter ./caps.py -s For more on pandoc filters, see the pandoc documentation under ``--filter`` and `the tutorial on writing filters`__. __ http://johnmacfarlane.net/pandoc/scripting.html For an alternative library for writing pandoc filters, with a more "Pythonic" design, see `panflute`__. __ https://github.com/sergiocorreia/panflute Compatibility ---------------- Pandoc 1.16 introduced link and image `attributes` to the existing `caption` and `target` arguments, requiring a change in pandocfilters that breaks backwards compatibility. Consequently, you should use: - pandocfilters version <= 1.2.4 for pandoc versions 1.12--1.15, and - pandocfilters version >= 1.3.0 for pandoc versions >= 1.16. Pandoc 1.17.3 (pandoc-types 1.17.*) introduced a new JSON format. pandocfilters 1.4.0 should work with both the old and the new format. Installing -------------- Run this inside the present directory:: python setup.py install Or install from PyPI:: pip install pandocfilters Available functions ---------------------- The main functions ``pandocfilters`` exports are - ``walk(x, action, format, meta)`` Walk a tree, applying an action to every object. Returns a modified tree. An action is a function of the form ``action(key, value, format, meta)``, where: - ``key`` is the type of the pandoc object (e.g. 'Str', 'Para') - ``value`` is the contents of the object (e.g. a string for 'Str', a list of inline elements for 'Para') - ``format`` is the target output format (as supplied by the ``format`` argument of ``walk``) - ``meta`` is the document's metadata The return of an action is either: - ``None``: this means that the object should remain unchanged - a pandoc object: this will replace the original object - a list of pandoc objects: these will replace the original object; the list is merged with the neighbors of the original objects (spliced into the list the original object belongs to); returning an empty list deletes the object - ``toJSONFilter(action)`` Like ``toJSONFilters``, but takes a single action as argument. - ``toJSONFilters(actions)`` Generate a JSON-to-JSON filter from stdin to stdout The filter: - reads a JSON-formatted pandoc document from stdin - transforms it by walking the tree and performing the actions - returns a new JSON-formatted pandoc document to stdout The argument ``actions`` is a list of functions of the form ``action(key, value, format, meta)``, as described in more detail under ``walk``. This function calls ``applyJSONFilters``, with the ``format`` argument provided by the first command-line argument, if present. (Pandoc sets this by default when calling filters.) - ``applyJSONFilters(actions, source, format="")`` Walk through JSON structure and apply filters This: - reads a JSON-formatted pandoc document from a source string - transforms it by walking the tree and performing the actions - returns a new JSON-formatted pandoc document as a string The ``actions`` argument is a list of functions (see ``walk`` for a full description). The argument ``source`` is a string encoded JSON object. The argument ``format`` is a string describing the output format. Returns a new JSON-formatted pandoc document. - ``stringify(x)`` Walks the tree x and returns concatenated string content, leaving out all formatting. - ``attributes(attrs)`` Returns an attribute list, constructed from the dictionary attrs. How to use ---------- Most users will only need ``toJSONFilter``. Here is a simple example of its use:: #!/usr/bin/env python """ Pandoc filter to convert all regular text to uppercase. Code, link URLs, etc. are not affected. """ from pandocfilters import toJSONFilter, Str def caps(key, value, format, meta): if key == 'Str': return Str(value.upper()) if __name__ == "__main__": toJSONFilter(caps) Examples -------- The examples subdirectory in the source repository contains the following filters. These filters should provide a useful starting point for developing your own pandocfilters. ``abc.py`` Pandoc filter to process code blocks with class ``abc`` containing ABC notation into images. Assumes that abcm2ps and ImageMagick's convert are in the path. Images are put in the abc-images directory. ``caps.py`` Pandoc filter to convert all regular text to uppercase. Code, link URLs, etc. are not affected. ``blockdiag.py`` Pandoc filter to process code blocks with class "blockdiag" into generated images. Needs utils from http://blockdiag.com. ``comments.py`` Pandoc filter that causes everything between ```` and ```` to be ignored. The comment lines must appear on lines by themselves, with blank lines surrounding ``deemph.py`` Pandoc filter that causes emphasized text to be displayed in ALL CAPS. ``deflists.py`` Pandoc filter to convert definition lists to bullet lists with the defined terms in strong emphasis (for compatibility with standard markdown). ``gabc.py`` Pandoc filter to convert code blocks with class "gabc" to LaTeX \\gabcsnippet commands in LaTeX output, and to images in HTML output. ``graphviz.py`` Pandoc filter to process code blocks with class ``graphviz`` into graphviz-generated images. ``lilypond.py`` Pandoc filter to process code blocks with class "ly" containing Lilypond notation. ``metavars.py`` Pandoc filter to allow interpolation of metadata fields into a document. ``%{fields}`` will be replaced by the field's value, assuming it is of the type ``MetaInlines`` or ``MetaString``. ``myemph.py`` Pandoc filter that causes emphasis to be rendered using the custom macro ``\myemph{...}`` rather than ``\emph{...}`` in latex. Other output formats are unaffected. ``plantuml.py`` Pandoc filter to process code blocks with class ``plantuml`` to images. Needs `plantuml.jar` from http://plantuml.com/. ``ditaa.py`` Pandoc filter to process code blocks with class ``ditaa`` to images. Needs `ditaa.jar` from http://ditaa.sourceforge.net/. ``theorem.py`` Pandoc filter to convert divs with ``class="theorem"`` to LaTeX theorem environments in LaTeX output, and to numbered theorems in HTML output. ``tikz.py`` Pandoc filter to process raw latex tikz environments into images. Assumes that pdflatex is in the path, and that the standalone package is available. Also assumes that ImageMagick's convert is in the path. Images are put in the ``tikz-images`` directory. API documentation ----------------- By default most filters use ``get_filename4code`` to create a directory ``...-images`` to save temporary files. This directory doesn't get removed as it can be used as a cache so that later pandoc runs don't have to recreate files if they already exist. The directory is generated in the current directory. If you prefer to have a clean directory after running pandoc filters, you can set an environment variable ``PANDOCFILTER_CLEANUP`` to any non-empty value such as `1` which forces the code to create a temporary directory that will be removed by the end of execution. pandocfilters-1.5.0/examples/000077500000000000000000000000001412001430500161565ustar00rootroot00000000000000pandocfilters-1.5.0/examples/Makefile000066400000000000000000000010631412001430500176160ustar00rootroot00000000000000 ALLSAMPLES = $(basename $(wildcard *-sample.md)) ALLPDF = $(addsuffix .pdf,$(ALLSAMPLES)) PYTHON=/usr/bin/python2 all: ${ALLPDF} lilypond-sample.pdf: lilypond-sample.md pandoc --latex-engine lualatex --filter ./$(subst -sample.md,.py,$<) $< -o $@ || touch $@ gabc-sample.pdf: gabc-sample.md pandoc --latex-engine lualatex --filter ./$(subst -sample.md,.py,$<) $< -o $@ || touch $@ %.pdf: %.md echo $(subst -sample.md,.py,$<) pandoc --filter ./$(subst -sample.md,.py,$<) $< -o $@ || touch $@ clean: $(RM) -f ${ALLPDF} *.pyc $(RM) -rf *-images tmp_ly pandocfilters-1.5.0/examples/abc-sample.md000066400000000000000000000027311412001430500205070ustar00rootroot00000000000000 Use this ``` X:7 T:Qui Tolis (Trio) C:André Raison M:3/4 L:1/4 Q:1/4=92 %%staves {(Pos1 Pos2) Trompette} K:F % V:Pos1 %%MIDI program 78 "Positif"x3 |x3 |c'>ba|Pga/g/f|:g2a |ba2 |g2c- |c2P=B |c>de |fga | V:Pos2 %%MIDI program 78 Mf>ed|cd/c/B|PA2d |ef/e/d |:e2f |ef2 |c>BA |GA/G/F |E>FG |ABc- | V:Trompette %%MIDI program 56 "Trompette"z3|z3 |z3 |z3 |:Mc>BA|PGA/G/F|PE>EF|PEF/E/D|C>CPB,|A,G,F,-| ``` to get ```abc X:7 T:Qui Tolis (Trio) C:André Raison M:3/4 L:1/4 Q:1/4=92 %%staves {(Pos1 Pos2) Trompette} K:F % V:Pos1 %%MIDI program 78 "Positif"x3 |x3 |c'>ba|Pga/g/f|:g2a |ba2 |g2c- |c2P=B |c>de |fga | V:Pos2 %%MIDI program 78 Mf>ed|cd/c/B|PA2d |ef/e/d |:e2f |ef2 |c>BA |GA/G/F |E>FG |ABc- | V:Trompette %%MIDI program 56 "Trompette"z3|z3 |z3 |z3 |:Mc>BA|PGA/G/F|PE>EF|PEF/E/D|C>CPB,|A,G,F,-| ``` See [(this is a link to whatever)](#whatever) for an example with options `{.abc #whatever caption="this is the caption" width=50%}`. ```{.abc #whatever caption="this is the caption" width=50%} X:7 T:Qui Tolis (Trio) C:André Raison M:3/4 L:1/4 Q:1/4=92 %%staves {(Pos1 Pos2) Trompette} K:F % V:Pos1 %%MIDI program 78 "Positif"x3 |x3 |c'>ba|Pga/g/f|:g2a |ba2 |g2c- |c2P=B |c>de |fga | V:Pos2 %%MIDI program 78 Mf>ed|cd/c/B|PA2d |ef/e/d |:e2f |ef2 |c>BA |GA/G/F |E>FG |ABc- | V:Trompette %%MIDI program 56 "Trompette"z3|z3 |z3 |z3 |:Mc>BA|PGA/G/F|PE>EF|PEF/E/D|C>CPB,|A,G,F,-| ``` pandocfilters-1.5.0/examples/abc.py000077500000000000000000000024431412001430500172630ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to process code blocks with class "abc" containing ABC notation into images. Assumes that abcm2ps and ImageMagick's convert are in the path. Images are put in the abc-images directory. """ import os import sys from subprocess import Popen, PIPE, call from pandocfilters import toJSONFilter, Para, Image, get_caption, get_filename4code, get_extension def abc2eps(abc_src, filetype, outfile): p = Popen(["abcm2ps", "-O", outfile + '.eps', "-"], stdin=PIPE) p.stdin.write(abc_src) p.communicate() p.stdin.close() call(["convert", outfile + '.eps', outfile + '.' + filetype]) def abc(key, value, format, _): if key == 'CodeBlock': [[ident, classes, keyvals], code] = value if "abc" in classes: caption, typef, keyvals = get_caption(keyvals) outfile = get_filename4code("abc", code) filetype = get_extension(format, "png", html="png", latex="pdf") dest = outfile + '.' + filetype if not os.path.isfile(dest): abc2eps(code.encode("utf-8"), filetype, outfile) sys.stderr.write('Created image ' + dest + '\n') return Para([Image([ident, [], keyvals], caption, [dest, typef])]) if __name__ == "__main__": toJSONFilter(abc) pandocfilters-1.5.0/examples/blockdiag-sample.md000066400000000000000000000103501412001430500216750ustar00rootroot00000000000000Use this ``` blockdiag { A -> B -> C -> D; A -> E -> F -> G; } ``` to get ```blockdiag blockdiag { A -> B -> C -> D; A -> E -> F -> G; } ``` with Äüö ```blockdiag blockdiag { Ä -> Bü -> Cö -> D; Ä -> E -> F -> G; } ``` See [(this is a link to whatever)](#whatever) for an example with options `{.plantuml #whatever caption="this is the caption" width=65%}` ```{.blockdiag #whatever caption="this is the caption" width=65%} blockdiag { A -> B -> C -> D; A -> E -> F -> G; } ``` DRY: no need to include the type twice ```{.blockdiag #whatever caption="this is the caption" width=65%} A -> B -> C -> D; A -> E -> F -> G; ``` # Samples from , , ... ```{.blockdiag caption="blockdiag: shape of nodes" width=80%} // standard node shapes box [shape = box]; square [shape = square]; roundedbox [shape = roundedbox]; dots [shape = dots]; circle [shape = circle]; ellipse [shape = ellipse]; diamond [shape = diamond]; minidiamond [shape = minidiamond]; note [shape = note]; mail [shape = mail]; cloud [shape = cloud]; actor [shape = actor]; beginpoint [shape = beginpoint]; endpoint [shape = endpoint]; box -> square -> roundedbox -> dots; circle -> ellipse -> diamond -> minidiamond; note -> mail -> cloud -> actor; beginpoint -> endpoint; // node shapes for flowcharts condition [shape = flowchart.condition]; database [shape = flowchart.database]; terminator [shape = flowchart.terminator]; input [shape = flowchart.input]; loopin [shape = flowchart.loopin]; loopout [shape = flowchart.loopout]; condition -> database -> terminator -> input; loopin -> loopout; ``` ```{.actdiag caption="actdiag: simple diagram" width=80%} write -> convert -> image lane user { label = "User" write [label = "Writing reST"]; image [label = "Get diagram IMAGE"]; } lane actdiag { convert [label = "Convert reST to Image"]; } ``` ```{.nwdiag caption="nwdiag: simple diagram" width=80%} nwdiag { network dmz { address = "210.x.x.x/24" web01 [address = "210.x.x.1"]; web02 [address = "210.x.x.2"]; } network internal { address = "172.x.x.x/24"; web01 [address = "172.x.x.1"]; web02 [address = "172.x.x.2"]; db01; db02; } } ``` ```{.nwdiag caption="nwdiag: peer networks" width=80%} inet [shape = cloud]; inet -- router; network { router; web01; web02; } ``` ```{.rackdiag caption="rackdiag: multiple racks" width=80%} // define 1st rack rack { 16U; // define rack items 1: UPS [2U]; 3: DB Server 4: Web Server 5: Web Server 6: Web Server 7: Load Balancer 8: L3 Switch } // define 2nd rack rack { 12U; // define rack items 1: UPS [2U]; 3: DB Server 4: Web Server 5: Web Server 6: Web Server 7: Load Balancer 8: L3 Switch } ``` ```{.packetdiag caption="packetdiag: Structure of TCP Header"} colwidth = 32 node_height = 72 0-15: Source Port 16-31: Destination Port 32-63: Sequence Number 64-95: Acknowledgment Number 96-99: Data Offset 100-105: Reserved 106: URG [rotate = 270] 107: ACK [rotate = 270] 108: PSH [rotate = 270] 109: RST [rotate = 270] 110: SYN [rotate = 270] 111: FIN [rotate = 270] 112-127: Window 128-143: Checksum 144-159: Urgent Pointer 160-191: (Options and Padding) 192-223: data [colheight = 3] ``` ```{.seqdiag caption="seqdiag: simple diagram" width=80%} browser -> webserver [label = "GET /index.html"]; browser <-- webserver; browser -> webserver [label = "POST /blog/comment"]; webserver -> database [label = "INSERT comment"]; webserver <-- database; browser <-- webserver; ``` ```{.seqdiag caption="seqdiag: order of elements" width=80%} seqdiag { # define order of elements # seqdiag sorts elements by order they appear browser; database; webserver; browser -> webserver [label = "GET /index.html"]; browser <-- webserver; browser -> webserver [label = "POST /blog/comment"]; webserver -> database [label = "INSERT comment"]; webserver <-- database; browser <-- webserver; } ``` pandocfilters-1.5.0/examples/blockdiag.py000066400000000000000000000025351412001430500204540ustar00rootroot00000000000000#!/usr/bin/env python """ Filter to process code blocks with class "blockdiag" into generated images. Needs utils from http://blockdiag.com """ import os import sys from subprocess import call from pandocfilters import toJSONFilter, Para, Image, get_filename4code, get_caption, get_extension def blockdiag(key, value, format, _): if key == 'CodeBlock': [[ident, classes, keyvals], code] = value all_kw = { "actdiag", "blockdiag", "nwdiag", "packetdiag", "rackdiag", "seqdiag" } kw = all_kw & set(classes) if len(kw) == 1: caption, typef, keyvals = get_caption(keyvals) filename = get_filename4code("blockdiag", code) filetype = get_extension(format, "png", html="svg", latex="pdf") src = filename + '.diag' dest = filename + '.' + filetype if not os.path.isfile(dest): cmd = str(list(kw)[0]) if not code.startswith(cmd): code = cmd + "{\n" + code + "\n}\n" with open(src, "w") as f: f.write(code) call([cmd, "-a", "-T"+filetype, src]) sys.stderr.write('Created image ('+ cmd + ") " + dest + '\n') return Para([Image([ident, [], keyvals], caption, [dest, typef])]) if __name__ == "__main__": toJSONFilter(blockdiag) pandocfilters-1.5.0/examples/caps-sample.md000066400000000000000000000000451412001430500207040ustar00rootroot00000000000000 This is the caps sample with Äüö.pandocfilters-1.5.0/examples/caps.py000077500000000000000000000004741412001430500174660ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to convert all regular text to uppercase. Code, link URLs, etc. are not affected. """ from pandocfilters import toJSONFilter, Str def caps(key, value, format, meta): if key == 'Str': return Str(value.upper()) if __name__ == "__main__": toJSONFilter(caps) pandocfilters-1.5.0/examples/comments-sample.md000066400000000000000000000002041412001430500216000ustar00rootroot00000000000000 Regular text with Äüö. This is a comment with Äüö This is regular text again.pandocfilters-1.5.0/examples/comments.py000077500000000000000000000014101412001430500203540ustar00rootroot00000000000000#!/usr/bin/env python from pandocfilters import toJSONFilter import re """ Pandoc filter that causes everything between '' and '' to be ignored. The comment lines must appear on lines by themselves, with blank lines surrounding them. """ incomment = False def comment(k, v, fmt, meta): global incomment if k == 'RawBlock': fmt, s = v if fmt == "html": if re.search("", s): incomment = True return [] elif re.search("", s): incomment = False return [] if incomment: return [] # suppress anything in a comment if __name__ == "__main__": toJSONFilter(comment) pandocfilters-1.5.0/examples/deemph-sample.md000066400000000000000000000001351412001430500212200ustar00rootroot00000000000000This is the deemph sample. This is *emphasis with Äüö* text which will be shown in caps. pandocfilters-1.5.0/examples/deemph.py000077500000000000000000000005011412001430500177710ustar00rootroot00000000000000#!/usr/bin/env python from pandocfilters import walk, toJSONFilter from caps import caps """ Pandoc filter that causes emphasized text to be displayed in ALL CAPS. """ def deemph(key, val, fmt, meta): if key == 'Emph': return walk(val, caps, fmt, meta) if __name__ == "__main__": toJSONFilter(deemph) pandocfilters-1.5.0/examples/deflists-sample.md000066400000000000000000000003501412001430500215720ustar00rootroot00000000000000Some Definitions Term 1 : Definition 1 Term 2 with *inline markup* : Definition 2 { some code, part of Definition 2 } Third paragraph of definition 2. Term with Äüö : Definition with Äüö Regular Text.pandocfilters-1.5.0/examples/deflists.py000077500000000000000000000010211412001430500203420ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to convert definition lists to bullet lists with the defined terms in strong emphasis (for compatibility with standard markdown). """ from pandocfilters import toJSONFilter, BulletList, Para, Strong def deflists(key, value, format, meta): if key == 'DefinitionList': return BulletList([tobullet(t, d) for [t, d] in value]) def tobullet(term, defs): return([Para([Strong(term)])] + [b for d in defs for b in d]) if __name__ == "__main__": toJSONFilter(deflists) pandocfilters-1.5.0/examples/ditaa-sample.md000077500000000000000000000007571412001430500210550ustar00rootroot00000000000000 ```ditaa +-------------------+ +----------------+ |cGRE API {io}+------------------->+cGRE BackEnd | +-------------------+ +--------+-------+ | | | +----------------+ | |cBLU DB {s}+<----------+ +----------------+ ``` pandocfilters-1.5.0/examples/ditaa.py000077500000000000000000000022501412001430500176140ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to process code blocks with class "ditaa" into images. Needs `ditaa.jar` from http://ditaa.sourceforge.net/. """ import os import sys import pprint from subprocess import call from pandocfilters import toJSONFilter, Para, Image, get_filename4code, get_caption, get_extension def ditaa(key, value, format, _): if key == 'CodeBlock': [[ident, classes, keyvals], code] = value if "ditaa" in classes: caption, typef, keyvals = get_caption(keyvals) filename = get_filename4code("ditaa", code) filetype = get_extension(format, "png", html="svg", latex="eps") src = filename + '.txt' dest = filename + '.' + filetype if not os.path.isfile(dest): with open(src, "w") as f: f.write(code) call(["java", "-jar", "ditaa.jar", src]) pprint.pprint(['Created image ', dest, 'typef=', typef, 'ident=', ident, 'keyvals=', keyvals, 'caption=', caption], sys.stderr) return Para([Image([ident, [], keyvals], caption, [dest, typef])]) if __name__ == "__main__": toJSONFilter(ditaa) pandocfilters-1.5.0/examples/gabc-sample.md000066400000000000000000000006531412001430500206570ustar00rootroot00000000000000--- header-includes: - \usepackage{libertine} - \usepackage[autocompile]{gregoriotex} --- Use this ~~~~~~ ```gabc (c4) A(f)ve(c) Ma(d)rí(dh'!iv)a.(h.) (::) ``` ~~~~~~ to get ```gabc (c4) A(f)ve(c) Ma(d)rí(dh'!iv)a.(h.) (::) ``` and this ~~~~~~ `gabc-score`{.gabc staffsize=12 annotation=Off. mode=2.} ~~~~~~ to get the score in `gabc-score.gabc` : `gabc-score`{.gabc staffsize=12 annotation=Off. mode=2.} pandocfilters-1.5.0/examples/gabc-score.gabc000066400000000000000000000011171412001430500210010ustar00rootroot00000000000000name:Ave María; %% (c4) A(fg/hgh fhf/gvFE. d!ef!g'h fhf/gh)ve(g.) *(;) Ma(h)rí(jj//jjjvH'GFgh!jvHF'g)a,(g.) (:) grá(g_d/fv.efd de!f'g)ti(fg)a(g) ple(ghhg)na,(g.) (:) Dó(jvIHk_j ijh/ig./hi/jg.,jvIHk_j ijh/ig./hi/jg)mi(fg)nus(g.) (,) te(ggghvGFg_d//gjhi)cum :(hg..) (:) be(h)ne(jj)dí(jk/lvlk)cta(jkkj) tu(ji/jkhhg.) (;) in(g) mu(gjjvI'H)li(hkj)é(jjvI'H)ri(jvIHij)bus,(i.) (:) et(g) be(i)ne(jkj)dí(hjgh)ctus(fg!hvhg.) (;) fru(g_f/ghffe)ctus(d.) ven(de!f'g/hvF'ED,de!f'g)tris(fhfg) tu(ghhg)i.(g.) (::) T. P. Al(h!iwji~)le(jkJH'//gi. hjIH'//g!jj/hig___)lú(ghg___)ia.(g.) (::) pandocfilters-1.5.0/examples/gabc.py000077500000000000000000000156031412001430500174340ustar00rootroot00000000000000#!/usr/bin/env python3 """ Pandoc filter to convert code blocks with class "gabc" to LaTeX \\gabcsnippet commands in LaTeX output, and to images in HTML output. Assumes Ghostscript, LuaLaTeX, [Gregorio](http://gregorio-project.github.io/) and a reasonable selection of LaTeX packages are installed. """ import os from sys import getfilesystemencoding, stderr from subprocess import Popen, call, PIPE from itertools import chain from glob import iglob from hashlib import sha1 from pandocfilters import toJSONFilter, RawBlock, RawInline, Para, Image STDERR = stderr IMAGEDIR = "tmp_gabc" LATEX_DOC = """\\documentclass{article} \\usepackage{libertine} \\usepackage[autocompile,allowdeprecated=false]{gregoriotex} \\catcode`\\℣=\\active \\def ℣#1{{\\Vbar\\hspace{-.25ex}#1}} \\catcode`\\℟=\\active \\def ℟#1{{\\Rbar\\hspace{-.25ex}#1}} \\catcode`\\†=\\active \\def †{{\\GreDagger}} \\catcode`\\✠=\\active \\def ✠{{\\grecross}} \\pagestyle{empty} \\begin{document} %s \\end{document} """ def sha(code): """Returns sha1 hash of the code""" return sha1(code.encode(getfilesystemencoding())).hexdigest() def latex(code): """LaTeX inline""" return RawInline('latex', code) def latexblock(code): """LaTeX block""" return RawBlock('latex', code) def htmlblock(code): """Html block""" return RawBlock('html', code) def latexsnippet(code, kvs, staffsize=17, initiallines=1): """Take in account key/values""" snippet = '' staffsize = int(kvs['staffsize']) if 'staffsize' in kvs \ else staffsize initiallines = int(kvs['initiallines']) if 'initiallines' in kvs \ else initiallines annotationsize = .5 * staffsize if 'mode' in kvs: snippet = ( "\\greannotation{{\\fontsize{%s}{%s}\\selectfont{}%s}}\n" % (annotationsize, annotationsize, kvs['mode']) ) + snippet if 'annotation' in kvs: snippet = ( "\\grechangedim{annotationseparation}{%s mm}{fixed}\n" "\\greannotation{{\\fontsize{%s}{%s}\\selectfont{}%s}}\n" % (staffsize / 60, annotationsize, annotationsize, kvs['annotation']) ) + snippet snippet = ( "\\gresetinitiallines{%s}\n" % initiallines + "\\grechangestaffsize{%s}\n" % staffsize + "\\grechangestyle{initial}{\\fontsize{%s}{%s}\\selectfont{}}" % (2.5 * staffsize, 2.5 * staffsize) ) + snippet snippet = "\\setlength{\\parskip}{0pt}\n" + snippet + code return snippet def latex2png(snippet, outfile): """Compiles a LaTeX snippet to png""" pngimage = os.path.join(IMAGEDIR, outfile + '.png') texdocument = os.path.join(IMAGEDIR, 'tmp.tex') with open(texdocument, 'w') as doc: doc.write(LATEX_DOC % (snippet)) environment = os.environ environment['shell_escape_commands'] = \ "bibtex,bibtex8,kpsewhich,makeindex,mpost,repstopdf," + \ ','.join( os.path.basename(n) for n in chain.from_iterable( iglob(os.path.join(chemin, 'gregorio*')) for chemin in os.environ["PATH"].split(os.pathsep) ) ) proc = Popen( ["lualatex", '-output-directory=' + IMAGEDIR, texdocument], stdin=PIPE, stdout=STDERR, env=environment ) proc.communicate() proc.stdin.close() call(["pdfcrop", os.path.join(IMAGEDIR, "tmp.pdf")], stdout=STDERR) call( [ "gs", "-sDEVICE=pngalpha", "-r144", "-sOutputFile=" + pngimage, os.path.join(IMAGEDIR, "tmp-crop.pdf"), ], stdout=STDERR, ) def png(contents, latex_command): """Creates a png if needed.""" outfile = sha(contents + latex_command) src = os.path.join(IMAGEDIR, outfile + '.png') if not os.path.isfile(src): try: os.mkdir(IMAGEDIR) stderr.write('Created directory ' + IMAGEDIR + '\n') except OSError: pass latex2png(latex_command + "{" + contents + "}", outfile) stderr.write('Created image ' + src + '\n') return src def properties(meta): try: staffsize = int( meta['music']['c']['gregorio']['c']['staffsize']['c'] ) except (KeyError, TypeError): staffsize = 17 try: initiallines = int( meta['music']['c']['gregorio']['c']['initiallines']['c'] ) except (KeyError, TypeError): initiallines = 1 return staffsize, initiallines def gabc(key, value, fmt, meta): # pylint:disable=I0011,W0613 """Handle gabc file inclusion and gabc code block.""" if key == 'Code': [[ident, classes, kvs], contents] = value # pylint:disable=I0011,W0612 kvs = {key: value for key, value in kvs} if "gabc" in classes: staffsize, initiallines = properties(meta) if fmt == "latex": if ident == "": label = "" else: label = '\\label{' + ident + '}' return latex( "\n\\smallskip\n{%\n" + latexsnippet( '\\gregorioscore{' + contents + '}', kvs, staffsize, initiallines ) + "%\n}" + label ) else: infile = contents + ( '.gabc' if '.gabc' not in contents else '' ) with open(infile, 'r') as doc: code = doc.read().split('%%\n')[1] return [Image(['', [], []], [], [ png( contents, latexsnippet( '\\gregorioscore', kvs, staffsize, initiallines ) ), "" ])] elif key == 'CodeBlock': [[ident, classes, kvs], contents] = value kvs = {key: value for key, value in kvs} if "gabc" in classes: staffsize, initiallines = properties(meta) if fmt == "latex": if ident == "": label = "" else: label = '\\label{' + ident + '}' return [latexblock( "\n\\smallskip\n{%\n" + latexsnippet( '\\gabcsnippet{' + contents + '}', kvs, staffsize, initiallines ) + "%\n}" + label )] else: return Para([Image(['', [], []], [], [ png( contents, latexsnippet( '\\gabcsnippet', kvs, staffsize, initiallines ) ), "" ])]) if __name__ == "__main__": toJSONFilter(gabc) pandocfilters-1.5.0/examples/gitlab_markdown-sample.md000066400000000000000000000003431412001430500231230ustar00rootroot00000000000000Use this ```math a^2 + b^2 = c^2 ``` to get $$ a^2 + b^2 = c^2 $$ also you go from $`a^2 + b^2 = c^2`$ to $a^2 + b^2 = c^2$ `inline code` ``` fenced non-math code block ``` non-math code block by indentation pandocfilters-1.5.0/examples/gitlab_markdown.py000077500000000000000000000013301412001430500216740ustar00rootroot00000000000000#!/usr/bin/env python3 from pandocfilters import toJSONFilter, Math, Para """ Pandoc filter to convert gitlab flavored markdown to pandoc flavored markdown """ def gitlab_markdown(key, value, format, meta): if key == "CodeBlock": [[identification, classes, keyvals], code] = value if len(classes) > 0 and classes[0] == "math": fmt = {'t': 'DisplayMath', 'c': []} return Para([Math(fmt, code)]) elif key == "Math": [fmt, code] = value if isinstance(fmt, dict) and fmt['t'] == "InlineMath": # if fmt['t'] == "InlineMath": return Math(fmt, code.strip('`')) if __name__ == "__main__": toJSONFilter(gitlab_markdown) pandocfilters-1.5.0/examples/graphviz-sample.md000066400000000000000000000006211412001430500216100ustar00rootroot00000000000000Use this ``` digraph G {Hello->World} ``` to get ```graphviz digraph G {Hello->World} ``` with with Äüö ```graphviz digraph G {Hello->World with Äüö} ``` See [(this is a link to whatever)](#whatever) for an example with options `{.graphviz #whatever caption="this is the caption" width=35%}`: ```{.graphviz #whatever caption="this is the caption" width=35%} digraph G {Hello->World} ``` pandocfilters-1.5.0/examples/graphviz.py000077500000000000000000000020521412001430500203640ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to process code blocks with class "graphviz" into graphviz-generated images. Needs pygraphviz """ import os import sys import pygraphviz from pandocfilters import toJSONFilter, Para, Image, get_filename4code, get_caption, get_extension, get_value def graphviz(key, value, format, _): if key == 'CodeBlock': [[ident, classes, keyvals], code] = value if "graphviz" in classes: caption, typef, keyvals = get_caption(keyvals) prog, keyvals = get_value(keyvals, u"prog", u"dot") filetype = get_extension(format, "png", html="png", latex="pdf") dest = get_filename4code("graphviz", code, filetype) if not os.path.isfile(dest): g = pygraphviz.AGraph(string=code) g.layout() g.draw(dest, prog=prog) sys.stderr.write('Created image ' + dest + '\n') return Para([Image([ident, [], keyvals], caption, [dest, typef])]) if __name__ == "__main__": toJSONFilter(graphviz) pandocfilters-1.5.0/examples/includes.py000077500000000000000000000011631412001430500203420ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to process code blocks with class "include" and replace their content with the included file """ from pandocfilters import toJSONFilter def code_include(key, value, format, meta): if key == 'CodeBlock': [[ident, classes, namevals], code] = value for nameval in namevals: if 'include' in nameval: with open(nameval[1], 'rb') as content_file: content = unicode(content_file.read()) return {'CodeBlock': [[ident, classes, namevals], content]} if __name__ == "__main__": toJSONFilter(code_include) pandocfilters-1.5.0/examples/inlinenotes.py000066400000000000000000000016051412001430500210610ustar00rootroot00000000000000#!/usr/bin/env python from pandocfilters import toJSONFilter, RawInline, Space, Str, walk """ Pandoc filter for Markdown that converts most endnotes into Pandoc's inline notes. If input notes had multiple paragraphs, the paragraphs are joined by a space. But if an input note had any blocks other than paragraphs, the note is left as is. """ def query(k, v, f, meta): global inlines if k == 'BlockQuote': inlines.append(v) elif isinstance(v, list): if inlines and k == 'Para': inlines.append(Space()) inlines.extend(v) return v def inlinenotes(k, v, f, meta): global inlines inlines = [] if k == 'Note' and f == 'markdown': walk(v, query, f, meta) if all(isinstance(x, dict) for x in inlines): return [RawInline('html', '^[')] + inlines + [Str(']')] if __name__ == "__main__": toJSONFilter(inlinenotes) pandocfilters-1.5.0/examples/latexdivs-sample.md000066400000000000000000000010511412001430500217570ustar00rootroot00000000000000\newcommand{\eqn}{\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}}
Turned into a proof environment. $$\eqn$$
First class is picked and converted into a LaTeX environment. $$\eqn$$
Shouldn't be converted into LaTeX environments. Since LaTeX is false.
Also shouldn't be converted into LaTeX environments. Since LaTeX is not present.
pandocfilters-1.5.0/examples/latexdivs.py000077500000000000000000000016061412001430500205410ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to convert divs with latex="true" to LaTeX environments in LaTeX output. The first class will be regarded as the name of the latex environment e.g.
...
will becomes \begin{note}...\end{note} """ from pandocfilters import toJSONFilter, RawBlock, Div def latex(x): return RawBlock('latex', x) def latexdivs(key, value, format, meta): if key == 'Div': [[ident, classes, kvs], contents] = value if ["latex","true"] in kvs: if format == "latex": if ident == "": label = "" else: label = '\\label{' + ident + '}' return([latex('\\begin{' + classes[0] + '}' + label)] + contents + [latex('\\end{' + classes[0] + '}')]) if __name__ == "__main__": toJSONFilter(latexdivs) pandocfilters-1.5.0/examples/lilypond-sample.md000066400000000000000000000004701412001430500216120ustar00rootroot00000000000000--- header-includes: - \usepackage{lyluatex} --- Use this ~~~~~~ ```ly \relative c' { c4 d e f g a b c } ``` ~~~~~~ to get ```ly \relative c' { c4 d e f g a b c } ``` and this ~~~~~~ `lilypond-score`{.ly staffsize=12} ~~~~~~ to get the score in `ly-score.ly` : `lilypond-score`{.ly staffsize=12} pandocfilters-1.5.0/examples/lilypond-score.ly000077500000000000000000000037441412001430500215020ustar00rootroot00000000000000\version "2.18" \language "français" \header { tagline = "" composer = "" } MetriqueArmure = { \tempo 2.=50 \time 6/4 \key sib \major } italique = { \override Score . LyricText #'font-shape = #'italic } roman = { \override Score . LyricText #'font-shape = #'roman } MusiqueCouplet = \relative do' { \partial 2. re4\p re^"Solo" re sol2. la2 la4 sib2 sib4 \breathe la4 sib la sol2. \acciaccatura {la16[ sol]} fad2 sol4 la2 r4 re,2 re4 sol2 sol4 la\< sol la sib2\! \acciaccatura {la16[ sol]} fa4 \breathe sib2 do4 re2 do4 sol2 la4 sib2. ~ sib2 \bar "||" } MusiqueRefrainI = \relative do'' { re4\f^"Chœur" re2 do4 sib2 la4 sol2. fad2 \breathe re4 sol2 la4 sib2 do4 re2.~ re4 \oneVoice r \voiceOne re\f re2 do4 sib2 la4 sol2. fad2 \oneVoice r4 \voiceOne sol2 la4\< sib la sol\! la2. sib2( la4) sol2.\fermata \bar "|." } MusiqueRefrainII = \relative do'' { sib4 sib2 la4 sol2 re4 mib4 re dod re2 do4 sib2 re4 sol2 sol4 fad2.~ fad4 s sib4 sib2 la4 sol2 re4 mib4 re dod re2 s4 sib2 do4 re do sib do2. re2( do4) sib2. } ParolesCouplet = \lyricmode { Le soir é -- tend sur la Ter -- re Son grand man -- teau de ve -- lours, Et le camp, calme et so -- li -- tai -- re, Se re -- cueille en ton a -- mour. } ParolesRefrain = \lyricmode { \italique Ô Vier -- ge de lu -- miè -- re, É -- toi -- le de nos cœurs, En -- tends no -- tre pri -- è -- re, No -- tre_- Da -- me des É -- clai -- reurs_! } \score{ << \new Staff << \set Staff.midiInstrument = "flute" \set Staff.autoBeaming = ##f \new Voice = "couplet" { \override Score.PaperColumn #'keep-inside-line = ##t \MetriqueArmure \MusiqueCouplet \voiceOne \MusiqueRefrainI } \new Voice = "refrainII" { s4*50 \voiceTwo \MusiqueRefrainII } >> \new Lyrics \lyricsto couplet { \ParolesCouplet \ParolesRefrain } >> \layout{} \midi{} } pandocfilters-1.5.0/examples/lilypond.py000077500000000000000000000106221412001430500203660ustar00rootroot00000000000000#!/usr/bin/env python3 """ Pandoc filter to process code blocks with class "ly" containing Lilypond notation. Assumes that Lilypond and Ghostscript are installed, plus [lyluatex](https://github.com/jperon/lyluatex) package for LaTeX, with LuaLaTeX. """ import os from sys import getfilesystemencoding, stderr from subprocess import Popen, call, PIPE from hashlib import sha1 from pandocfilters import toJSONFilter, stringify,\ Para, Image, RawInline, RawBlock IMAGEDIR = "tmp_ly" LATEX_DOC = """\\documentclass{article} \\usepackage{libertine} \\usepackage{lyluatex} \\pagestyle{empty} \\begin{document} %s \\end{document} """ def sha(x): return sha1(x.encode(getfilesystemencoding())).hexdigest() def latex(code): """LaTeX inline""" return RawInline('latex', code) def latexblock(code): """LaTeX block""" return RawBlock('latex', code) def ly2png(lily, outfile, kvs): p = Popen([ "lilypond", "-dno-point-and-click", "-dbackend=eps", "-djob-count=2", "-ddelete-intermediate-files", "-o", outfile, "-" ], stdin=PIPE, stdout=stderr) p.stdin.write(("\\paper{\n" "indent=0\\mm\n" "oddFooterMarkup=##f\n" "oddHeaderMarkup=##f\n" "bookTitleMarkup = ##f\n" "scoreTitleMarkup = ##f\n" "line-width = %s\n" "}\n" "#(set-global-staff-size %s)\n" % ( kvs['width'][:-2] + '\\' + kvs['width'][-2:], kvs['staffsize']) + lily).encode("utf-8")) p.communicate() p.stdin.close() call([ "gs", "-sDEVICE=pngalpha", "-r144", "-sOutputFile=" + outfile + '.png', outfile + '.pdf', ], stdout=stderr) def png(contents, kvs): """Creates a png if needed.""" outfile = os.path.join(IMAGEDIR, sha(contents + str(kvs['staffsize']))) src = outfile + '.png' if not os.path.isfile(src): try: os.mkdir(IMAGEDIR) stderr.write('Created directory ' + IMAGEDIR + '\n') except OSError: pass ly2png(contents, outfile, kvs) stderr.write('Created image ' + src + '\n') return src def calc_params(kvs, meta): if 'staffsize' not in kvs: try: kvs['staffsize'] = int( meta['music']['c']['lilypond']['c']['staffsize']['c'] ) except (KeyError, TypeError): kvs['staffsize'] = 20 if 'width' not in kvs: try: kvs['width'] = \ meta['music']['c']['lilypond']['c']['width']['c'][0]['c'] except (KeyError, TypeError): kvs['width'] = '210mm' return kvs def lily(key, value, fmt, meta): if key == 'Code': [[ident, classes, kvs], contents] = value # pylint:disable=I0011,W0612 kvs = {key: value for key, value in kvs} if "ly" in classes: kvs = calc_params(kvs, meta) if fmt == "latex": if ident == "": label = "" else: label = '\\label{' + ident + '}' return latex( '\\includely[staffsize=%s]{%s}' % ( kvs['staffsize'], contents ) + label ) else: infile = contents + ( '.ly' if '.ly' not in contents else '' ) with open(infile, 'r') as doc: code = doc.read() return [ Image(['', [], []], [], [png(code, kvs), ""] ) ] if key == 'CodeBlock': [[ident, classes, kvs], code] = value kvs = {key: value for key, value in kvs} if "ly" in classes: kvs = calc_params(kvs, meta) if fmt == "latex": if ident == "": label = "" else: label = '\\label{' + ident + '}' return latexblock( '\\lily[staffsize=%s]{%s}' % (kvs['staffsize'], code) + label ) else: return Para([ Image( ['', [], []], [], [png(code, kvs), ""] ) ]) if __name__ == "__main__": toJSONFilter(lily) pandocfilters-1.5.0/examples/metavars-sample.md000066400000000000000000000001121412001430500215730ustar00rootroot00000000000000--- author: Caleb Hyde --- # %{author} This was written by %{author} pandocfilters-1.5.0/examples/metavars.py000077500000000000000000000015211412001430500203540ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to allow interpolation of metadata fields into a document. %{fields} will be replaced by the field's value, assuming it is of the type MetaInlines or MetaString. """ from pandocfilters import toJSONFilter, attributes, Span, Str import re pattern = re.compile('%\{(.*)\}$') def metavars(key, value, format, meta): if key == 'Str': m = pattern.match(value) if m: field = m.group(1) result = meta.get(field, {}) if 'MetaInlines' in result['t']: return Span(attributes({'class': 'interpolated', 'field': field}), result['c']) elif 'MetaString' in result['t']: return Str(result['c']) if __name__ == "__main__": toJSONFilter(metavars) pandocfilters-1.5.0/examples/myemph-sample.md000066400000000000000000000001461412001430500212570ustar00rootroot00000000000000\newcommand{\myemph}[1]{ START-MYEMPH #1 END-MYEMPH } This is same text with *emphasis with Äüö*.pandocfilters-1.5.0/examples/myemph.py000077500000000000000000000007211412001430500200320ustar00rootroot00000000000000#!/usr/bin/env python from pandocfilters import toJSONFilter, RawInline """ Pandoc filter that causes emphasis to be rendered using the custom macro '\myemph{...}' rather than '\emph{...}' in latex. Other output formats are unaffected. """ def latex(s): return RawInline('latex', s) def myemph(k, v, f, meta): if k == 'Emph' and f == 'latex': return [latex('\\myemph{')] + v + [latex('}')] if __name__ == "__main__": toJSONFilter(myemph) pandocfilters-1.5.0/examples/plantuml-sample.md000066400000000000000000000015461412001430500216210ustar00rootroot00000000000000Use this ``` Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: another authentication Response ``` to get ```plantuml Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: another authentication Response ``` with Äüö ```plantuml Älöc -> Bob: Authentication Request Bob --> Älöc: Authentication Response Älöc -> Bob: Another authentication Request Älöc <-- Bob: another authentication Response ``` See [(this is a link to whatever)](#whatever) for an example with options `{.plantuml #whatever caption="this is the caption" width=65%}` ```{.plantuml #whatever caption="this is the caption" width=65%} Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response ``` pandocfilters-1.5.0/examples/plantuml.py000077500000000000000000000023471412001430500203750ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to process code blocks with class "plantuml" into plant-generated images. Needs `plantuml.jar` from http://plantuml.com/. """ import os import sys from subprocess import call from pandocfilters import toJSONFilter, Para, Image, get_filename4code, get_caption, get_extension def plantuml(key, value, format, _): if key == 'CodeBlock': [[ident, classes, keyvals], code] = value if "plantuml" in classes: caption, typef, keyvals = get_caption(keyvals) filename = get_filename4code("plantuml", code) filetype = get_extension(format, "png", html="svg", latex="eps") src = filename + '.uml' dest = filename + '.' + filetype if not os.path.isfile(dest): if not code.startswith("@start"): code = "@startuml\n" + code + "\n@enduml\n" with open(src, "w") as f: f.write(code) call(["java", "-jar", "plantuml.jar", "-t"+filetype, src]) sys.stderr.write('Created image ' + dest + '\n') return Para([Image([ident, [], keyvals], caption, [dest, typef])]) if __name__ == "__main__": toJSONFilter(plantuml) pandocfilters-1.5.0/examples/theorem-sample.md000066400000000000000000000002321412001430500214170ustar00rootroot00000000000000--- header-includes: - \newtheorem{theorem}{Theorem} --- Regular Text.
This is my theorem with Äüö.
Regular Text. pandocfilters-1.5.0/examples/theorem.py000077500000000000000000000022571412001430500202040ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to convert divs with class="theorem" to LaTeX theorem environments in LaTeX output, and to numbered theorems in HTML output. """ from pandocfilters import toJSONFilter, RawBlock, Div theoremcount = 0 def latex(x): return RawBlock('latex', x) def html(x): return RawBlock('html', x) def theorems(key, value, format, meta): if key == 'Div': [[ident, classes, kvs], contents] = value if "theorem" in classes: if format == "latex": if ident == "": label = "" else: label = '\\label{' + ident + '}' return([latex('\\begin{theorem}' + label)] + contents + [latex('\\end{theorem}')]) elif format == "html" or format == "html5": global theoremcount theoremcount = theoremcount + 1 newcontents = [html('
Theorem ' + str(theoremcount) + '
'), html('
')] + contents + [html('
\n')] return Div([ident, classes, kvs], newcontents) if __name__ == "__main__": toJSONFilter(theorems) pandocfilters-1.5.0/examples/tikz-sample.md000066400000000000000000000013661412001430500207460ustar00rootroot00000000000000Use this ```latex \begin{tikzpicture} \def \n {5} \def \radius {3cm} \def \margin {8} % margin in angles, depends on the radius \foreach \s in {1,...,\n} { \node[draw, circle] at ({360/\n * (\s - 1)}:\radius) {$\s$}; \draw[->, >=latex] ({360/\n * (\s - 1)+\margin}:\radius) arc ({360/\n * (\s - 1)+\margin}:{360/\n * (\s)-\margin}:\radius); } \end{tikzpicture} ``` to get ```latex \begin{tikzpicture} \def \n {5} \def \radius {3cm} \def \margin {8} % margin in angles, depends on the radius \foreach \s in {1,...,\n} { \node[draw, circle] at ({360/\n * (\s - 1)}:\radius) {$\s$}; \draw[->, >=latex] ({360/\n * (\s - 1)+\margin}:\radius) arc ({360/\n * (\s - 1)+\margin}:{360/\n * (\s)-\margin}:\radius); } \end{tikzpicture} ``` pandocfilters-1.5.0/examples/tikz.py000077500000000000000000000032351412001430500175170ustar00rootroot00000000000000#!/usr/bin/env python """ Pandoc filter to process raw latex tikz environments into images. Assumes that pdflatex is in the path, and that the standalone package is available. Also assumes that ImageMagick's convert is in the path. Images are put in the tikz-images directory. """ import os import re import shutil import sys from subprocess import call from tempfile import mkdtemp from pandocfilters import toJSONFilter, Para, Image, get_filename4code, get_extension def tikz2image(tikz_src, filetype, outfile): tmpdir = mkdtemp() olddir = os.getcwd() os.chdir(tmpdir) f = open('tikz.tex', 'w') f.write("""\\documentclass{standalone} \\usepackage{tikz} \\begin{document} """) f.write(tikz_src) f.write("\n\\end{document}\n") f.close() call(["pdflatex", 'tikz.tex'], stdout=sys.stderr) os.chdir(olddir) if filetype == 'pdf': shutil.copyfile(tmpdir + '/tikz.pdf', outfile + '.pdf') else: call(["convert", tmpdir + '/tikz.pdf', outfile + '.' + filetype]) shutil.rmtree(tmpdir) def tikz(key, value, format, _): if key == 'RawBlock': [fmt, code] = value if fmt == "latex" and re.match("\\\\begin{tikzpicture}", code): outfile = get_filename4code("tikz", code) filetype = get_extension(format, "png", html="png", latex="pdf") src = outfile + '.' + filetype if not os.path.isfile(src): tikz2image(code, filetype, outfile) sys.stderr.write('Created image ' + src + '\n') return Para([Image(['', [], []], [], [src, ""])]) if __name__ == "__main__": toJSONFilter(tikz) pandocfilters-1.5.0/pandocfilters.py000077500000000000000000000215341412001430500175570ustar00rootroot00000000000000# Author: John MacFarlane # Copyright: (C) 2013 John MacFarlane # License: BSD3 """ Functions to aid writing python scripts that process the pandoc AST serialized as JSON. """ import codecs import hashlib import io import json import os import sys import atexit import shutil import tempfile # some utility-functions: make it easier to create your own filters def get_filename4code(module, content, ext=None): """Generate filename based on content The function ensures that the (temporary) directory exists, so that the file can be written. By default, the directory won't be cleaned up, so a filter can use the directory as a cache and decide not to regenerate if there's no change. In case the user preferres the files to be temporary files, an environment variable `PANDOCFILTER_CLEANUP` can be set to any non-empty value such as `1` to make sure the directory is created in a temporary location and removed after finishing the filter. In this case there's no caching and files will be regenerated each time the filter is run. Example: filename = get_filename4code("myfilter", code) """ if os.getenv('PANDOCFILTER_CLEANUP'): imagedir = tempfile.mkdtemp(prefix=module) atexit.register(lambda: shutil.rmtree(imagedir)) else: imagedir = module + "-images" fn = hashlib.sha1(content.encode(sys.getfilesystemencoding())).hexdigest() try: os.mkdir(imagedir) sys.stderr.write('Created directory ' + imagedir + '\n') except OSError: sys.stderr.write('Could not create directory "' + imagedir + '"\n') if ext: fn += "." + ext return os.path.join(imagedir, fn) def get_value(kv, key, value = None): """get value from the keyvalues (options)""" res = [] for k, v in kv: if k == key: value = v else: res.append([k, v]) return value, res def get_caption(kv): """get caption from the keyvalues (options) Example: if key == 'CodeBlock': [[ident, classes, keyvals], code] = value caption, typef, keyvals = get_caption(keyvals) ... return Para([Image([ident, [], keyvals], caption, [filename, typef])]) """ caption = [] typef = "" value, res = get_value(kv, u"caption") if value is not None: caption = [Str(value)] typef = "fig:" return caption, typef, res def get_extension(format, default, **alternates): """get the extension for the result, needs a default and some specialisations Example: filetype = get_extension(format, "png", html="svg", latex="eps") """ try: return alternates[format] except KeyError: return default # end of utilities def walk(x, action, format, meta): """Walk a tree, applying an action to every object. Returns a modified tree. An action is a function of the form `action(key, value, format, meta)`, where: * `key` is the type of the pandoc object (e.g. 'Str', 'Para') `value` is * the contents of the object (e.g. a string for 'Str', a list of inline elements for 'Para') * `format` is the target output format (as supplied by the `format` argument of `walk`) * `meta` is the document's metadata The return of an action is either: * `None`: this means that the object should remain unchanged * a pandoc object: this will replace the original object * a list of pandoc objects: these will replace the original object; the list is merged with the neighbors of the orignal objects (spliced into the list the original object belongs to); returning an empty list deletes the object """ if isinstance(x, list): array = [] for item in x: if isinstance(item, dict) and 't' in item: res = action(item['t'], item['c'] if 'c' in item else None, format, meta) if res is None: array.append(walk(item, action, format, meta)) elif isinstance(res, list): for z in res: array.append(walk(z, action, format, meta)) else: array.append(walk(res, action, format, meta)) else: array.append(walk(item, action, format, meta)) return array elif isinstance(x, dict): return {k: walk(v, action, format, meta) for k, v in x.items()} else: return x def toJSONFilter(action): """Like `toJSONFilters`, but takes a single action as argument. """ toJSONFilters([action]) def toJSONFilters(actions): """Generate a JSON-to-JSON filter from stdin to stdout The filter: * reads a JSON-formatted pandoc document from stdin * transforms it by walking the tree and performing the actions * returns a new JSON-formatted pandoc document to stdout The argument `actions` is a list of functions of the form `action(key, value, format, meta)`, as described in more detail under `walk`. This function calls `applyJSONFilters`, with the `format` argument provided by the first command-line argument, if present. (Pandoc sets this by default when calling filters.) """ try: input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') except AttributeError: # Python 2 does not have sys.stdin.buffer. # REF: https://stackoverflow.com/questions/2467928/python-unicodeencode input_stream = codecs.getreader("utf-8")(sys.stdin) source = input_stream.read() if len(sys.argv) > 1: format = sys.argv[1] else: format = "" sys.stdout.write(applyJSONFilters(actions, source, format)) def applyJSONFilters(actions, source, format=""): """Walk through JSON structure and apply filters This: * reads a JSON-formatted pandoc document from a source string * transforms it by walking the tree and performing the actions * returns a new JSON-formatted pandoc document as a string The `actions` argument is a list of functions (see `walk` for a full description). The argument `source` is a string encoded JSON object. The argument `format` is a string describing the output format. Returns a the new JSON-formatted pandoc document. """ doc = json.loads(source) if 'meta' in doc: meta = doc['meta'] elif doc[0]: # old API meta = doc[0]['unMeta'] else: meta = {} altered = doc for action in actions: altered = walk(altered, action, format, meta) return json.dumps(altered) def stringify(x): """Walks the tree x and returns concatenated string content, leaving out all formatting. """ result = [] def go(key, val, format, meta): if key in ['Str', 'MetaString']: result.append(val) elif key == 'Code': result.append(val[1]) elif key == 'Math': result.append(val[1]) elif key == 'LineBreak': result.append(" ") elif key == 'SoftBreak': result.append(" ") elif key == 'Space': result.append(" ") walk(x, go, "", {}) return ''.join(result) def attributes(attrs): """Returns an attribute list, constructed from the dictionary attrs. """ attrs = attrs or {} ident = attrs.get("id", "") classes = attrs.get("classes", []) keyvals = [[x, attrs[x]] for x in attrs if (x != "classes" and x != "id")] return [ident, classes, keyvals] def elt(eltType, numargs): def fun(*args): lenargs = len(args) if lenargs != numargs: raise ValueError(eltType + ' expects ' + str(numargs) + ' arguments, but given ' + str(lenargs)) if numargs == 0: xs = [] elif len(args) == 1: xs = args[0] else: xs = list(args) return {'t': eltType, 'c': xs} return fun # Constructors for block elements Plain = elt('Plain', 1) Para = elt('Para', 1) CodeBlock = elt('CodeBlock', 2) RawBlock = elt('RawBlock', 2) BlockQuote = elt('BlockQuote', 1) OrderedList = elt('OrderedList', 2) BulletList = elt('BulletList', 1) DefinitionList = elt('DefinitionList', 1) Header = elt('Header', 3) HorizontalRule = elt('HorizontalRule', 0) Table = elt('Table', 5) Div = elt('Div', 2) Null = elt('Null', 0) # Constructors for inline elements Str = elt('Str', 1) Emph = elt('Emph', 1) Strong = elt('Strong', 1) Strikeout = elt('Strikeout', 1) Superscript = elt('Superscript', 1) Subscript = elt('Subscript', 1) SmallCaps = elt('SmallCaps', 1) Quoted = elt('Quoted', 2) Cite = elt('Cite', 2) Code = elt('Code', 2) Space = elt('Space', 0) LineBreak = elt('LineBreak', 0) Math = elt('Math', 2) RawInline = elt('RawInline', 2) Link = elt('Link', 3) Image = elt('Image', 3) Note = elt('Note', 1) SoftBreak = elt('SoftBreak', 0) Span = elt('Span', 2) pandocfilters-1.5.0/setup.cfg000066400000000000000000000000321412001430500161540ustar00rootroot00000000000000[bdist_wheel] universal=1 pandocfilters-1.5.0/setup.py000066400000000000000000000026671412001430500160650ustar00rootroot00000000000000import setuptools from distutils.core import setup import os def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() setup(name='pandocfilters', version='1.5.0', description='Utilities for writing pandoc filters in python', long_description=read('README.rst'), author='John MacFarlane', author_email='fiddlosopher@gmail.com', url='http://github.com/jgm/pandocfilters', py_modules=['pandocfilters'], license="BSD-3-Clause", keywords=['pandoc'], python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Console', 'Intended Audience :: End Users/Desktop', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Text Processing :: Filters', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', ], )