├── .github └── workflows │ └── wheel.yaml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── lua ├── aafigure.lua ├── csv2table-simple.lua ├── csv2table.lua ├── default_loader.lua ├── docx-appendixheadings.lua ├── docx-apply-cell-styles.lua ├── docx-colored-span.lua ├── docx-comment.lua ├── docx-custom-span-styles.lua ├── docx-extract-bullet-lists.lua ├── docx-image-styles.lua ├── docx-pagebreak-toc.lua ├── docx-unnumberedheadings.lua ├── hide-frontpage-metadata.lua ├── listingtable.lua ├── metadata-file.yaml ├── preprocess.lua ├── removable-note.lua ├── svgbob.lua ├── svgconvert.lua ├── table-width-simple.lua ├── table-width.lua ├── tex-landscape.lua ├── tex-quote.lua ├── tex-remove-sout.lua ├── tex-rowcolors-reset.lua ├── tex-underline.lua ├── utils.lua └── wavedrom.lua ├── pandocker_lua_filters └── __init__.py ├── scripts ├── Dockerfile ├── svgbob.sh └── wavedrom.sh ├── setup.py └── tests ├── .circleci └── config.yml ├── .gitignore ├── Makefile ├── data ├── aafigure.txt ├── bit.yaml ├── io_plan.csv ├── json.json ├── svgbob.bob └── table.csv ├── images ├── bitfield.svg └── dummy.png └── markdown ├── TITLE.md ├── config.yaml ├── rest.rst ├── section1.md └── section2.md /.github/workflows/wheel.yaml: -------------------------------------------------------------------------------- 1 | name: Build python wheel package 2 | on: [ push, create ] 3 | jobs: 4 | make-wavedrom: 5 | name: Compile svgbob 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@v4 10 | with: 11 | fetch-depth: 0 12 | - name: Install dependencies 13 | run: | 14 | pip3 install wheel setuptools setuptools_scm 15 | - name: Build svgbob image 16 | run: | 17 | docker build scripts/ -t svgbob 18 | - name: Build wheel 19 | run: make wheel 20 | - name: Upload artifact wheel (at a push) 21 | uses: actions/upload-artifact@v4 22 | with: 23 | name: wheel package 24 | path: dist 25 | - name: Upload to pypi (at a tag) 26 | uses: pypa/gh-action-pypi-publish@release/v1 27 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') 28 | with: 29 | user: ${{ secrets.PYPI_USERNAME }} 30 | password: ${{ secrets.PYPI_PASSWORD }} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | pandocker_lua_filters/version.py 106 | windows/ 107 | mac/ 108 | linux/ 109 | .npm/ 110 | .nexe/ 111 | .config/ 112 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 pandocker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: html 2 | 3 | initdir: 4 | cd tests; \ 5 | make initdir 6 | 7 | html: 8 | cd tests; \ 9 | make html 10 | 11 | install: 12 | pip3 install --break-system-packages -U . 13 | 14 | uninstall: 15 | pip3 uninstall --break-system-packages -y pandocker-lua-filters 16 | 17 | reinstall: uninstall install 18 | # pip3 install . 19 | 20 | clean: 21 | rm -rf dist 22 | touch pandocker_lua_filters/version.py 23 | rm pandocker_lua_filters/version.py 24 | cd tests; \ 25 | make clean 26 | 27 | tex: 28 | cd tests; \ 29 | make tex 30 | 31 | docx: 32 | cd tests; \ 33 | make docx 34 | 35 | pdf: 36 | cd tests; \ 37 | make pdf 38 | 39 | native: 40 | cd tests; \ 41 | make native 42 | 43 | #wavedrom: 44 | # @echo "wavedrom" 45 | # docker run --rm -v $(PWD):/root -w /tmp node:10 /root/scripts/wavedrom.sh 46 | 47 | build/svgbob: svgbob 48 | build/svgbob.bin: svgbob 49 | build/svgbob.exe: svgbob 50 | svgbob: 51 | @echo "svgbob" 52 | docker run --rm -v $(PWD):/tmp -w /tmp svgbob ./scripts/svgbob.sh 53 | 54 | wheel: build/svgbob build/svgbob.bin build/svgbob.exe 55 | sudo python3 setup.py bdist_wheel 56 | 57 | check: wheel 58 | twine check dist/pandocker_lua_filters*.whl 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pandocker-lua-filters 2 | 3 | Lua filters for pandoc 4 | 5 | ## Install 6 | 7 | - installs as a python package for ease of use 8 | - `pip install pandocker-lua-filters` 9 | - Lua filters should be installed under `/share/lua/{5.3|5.4}/pandocker` where 10 | `` can be confirmed by `python -c "import sys; print(sys.prefix)"`. It install **both** 5.3 and 5.4 11 | directories no matter of actual lua versions in system. 12 | This `/share/lua/{5.3|5.4}` should be added to `package.path` which can be confirmed 13 | by `lua -e "print(package.path)"`. 14 | 15 | ## General use 16 | 17 | #### Convert AAFigure ascii art 18 | 19 | - requires `aafigure` python package 20 | 21 | [**`aafigure.lua`**](lua/aafigure.lua) 22 | 23 | #### Convert CSV into table 24 | 25 | - requires `csv` and `penlight` luarocks packages 26 | - Pandoc below 2.10 applies "simple" filters 27 | 28 | [**`csv2table.lua`**](lua/csv2table.lua)
29 | [**`csv2table-simple.lua`**](lua/csv2table-simple.lua) 30 | 31 | #### Replace `title` `subtitle` `date` `author` metadata 32 | 33 | [**`hide-frontpage-metadata`**](lua/hide-frontpage-metadata.lua) 34 | 35 | #### Text file listing 36 | 37 | - requires `penlight` luarocks package 38 | 39 | [**`listingtable.lua`**](lua/listingtable.lua) 40 | 41 | #### Concatenate text files 42 | 43 | [**`preprocess.lua`**](lua/preprocess.lua) 44 | 45 | #### Removable note block 46 | 47 | [**`removable-note.lua`**](lua/removable-note.lua) 48 | 49 | #### Convert svgbob ascii art 50 | 51 | [**`svgbob.lua`**](lua/svgbob.lua) 52 | 53 | #### Convert SVG images to other formats 54 | 55 | - requires `rsvg-convert` in `$PATH` 56 | 57 | [**`svgconvert.lua`**](lua/svgconvert.lua) 58 | 59 | #### Applies table attributes to a table 60 | 61 | - requires `penlight` luarocks package 62 | - Pandoc below 2.10 applies "simple" filters 63 | 64 | [**`table-width.lua`**](lua/table-width.lua)
65 | [**`table-width-simple.lua`**](lua/table-width-simple.lua) 66 | 67 | #### Wavedrom / Bit-Field 68 | 69 | - requires `wavedrom-cli` in `$PATH` (`npm i -g wavedrom-cli`) 70 | - requires `lyaml` and `lua-cjson2` luarocks packages 71 | 72 | [**`wavedrom.lua`**](lua/wavedrom.lua) 73 | 74 | ## *LaTeX* output only 75 | 76 | #### Landscape pages 77 | 78 | [**`tex-landscape.lua`**](lua/tex-landscape.lua) 79 | 80 | 85 | 86 | #### Applies underline to `.underline` class span 87 | 88 | [**`tex-underline.lua`**](lua/tex-underline.lua) 89 | 90 | ## *Docx* output only 91 | 92 | #### Inserts a comment 93 | 94 | [**`docx-comment.lua`**](lua/docx-comment.lua) 95 | 96 | #### Apply custom (paragraph) styles for each table cell 97 | 98 | [**`docx-apply-cell-styles.lua`**](lua/docx-apply-cell-styles.lua) 99 | 100 | #### Apply custom (paragraph) styles for image and its caption 101 | 102 | [**`docx-image-styles.lua`**](lua/docx-image-styles.lua) 103 | 104 | #### Apply custom (character) styles for any span 105 | 106 | [**`docx-custom-span-styles.lua`**](lua/docx-custom-span-styles.lua) 107 | 108 | #### Apply in-place color for any span 109 | 110 | [**`docx-colored-span.lua`**](lua/docx-colored-span.lua) 111 | 112 | #### Apply custom (paragraph) styles for any unnumbered bullet lists 113 | 114 | Finds unnumbered bullet lists down to 3rd level and applies custom paragraph styles. 115 | **4th level and lower list items are escalated to 3rd level**. 116 | 117 | [**`docx-extract-bullet-lists.lua`**](lua/docx-extract-bullet-lists.lua) 118 | 119 | ##### Requirement for template 120 | 121 | - Prepare `Bullet List 1` to `Bullet List 3` paragraph styles (by the way this is 1st level list item) 122 | - Otherwise these headers inherit `Body` style (this is 2nd level) 123 | 124 | | Level | Unnumbered | 125 | |:-----:|:--------------| 126 | | 1 | Bullet List 1 | 127 | | 2 | Bullet List 2 | 128 | | 3+ | Bullet List 3 | 129 | 130 | #### TOC / Pagebreak / Linebreak / Sub section TOC 131 | 132 | [**`docx-pagebreak-toc.lua`**](lua/docx-pagebreak-toc.lua) 133 | 134 | - Adds TOC(Table Of Contents), sub sections, a line break or a page break at any point of document 135 | 136 | ##### Requirement for template 137 | 138 | TOC title is set to "Table of Contents" by default. Metadata `toc-title` overrides this setting. 139 | 140 | #### Appendix headings 141 | 142 | [**`docx-appendixheadings.lua`**](lua/docx-appendixheadings.lua) 143 | 144 | - Makes `appendix` class work to _appendix_ headings in DOCX format 145 | - Limited to level-1 to 5 headings 146 | 147 | ##### Requirement for template 148 | 149 | - Prepare `Appendix Heading 1` to `Appendix Heading 5` heading styles 150 | - Otherwise these headers inherit `Body` style 151 | 152 | | Level | Numbered | Unnumbered | 153 | |:-----:|:----------|:-------------------| 154 | | 1 | Heading 1 | Appendix Heading 1 | 155 | | 2 | Heading 2 | Appendix Heading 2 | 156 | | 3 | Heading 3 | Appendix Heading 3 | 157 | | 4 | Heading 4 | Appendix Heading 4 | 158 | | 5 | Heading 5 | Appendix Heading 5 | 159 | | 6 | Heading 6 | | 160 | 161 | #### Unnumbered headings 162 | 163 | [**`docx-unnumberedheadings.lua`**](lua/docx-unnumberedheadings.lua) 164 | 165 | - Makes `UnnumberHeadings` class work to _unnumber_ headings in DOCX format 166 | - Limited to level-1 to 5 headings 167 | 168 | ##### Requirement for template 169 | 170 | - Prepare `Heading Unnumbered 1` to `Heading Unnumbered 5` heading styles 171 | - Otherwise these headers inherit `Body` style 172 | 173 | | Level | Numbered | Unnumbered | 174 | |:-----:|:----------|:---------------------| 175 | | 1 | Heading 1 | Heading Unnumbered 1 | 176 | | 2 | Heading 2 | Heading Unnumbered 2 | 177 | | 3 | Heading 3 | Heading Unnumbered 3 | 178 | | 4 | Heading 4 | Heading Unnumbered 4 | 179 | | 5 | Heading 5 | Heading Unnumbered 5 | 180 | | 6 | Heading 6 | | 181 | 182 | #### Figure styles 183 | 184 | [**`docx-image-styles.lua`**](lua/docx-image-styles.lua) 185 | 186 | - Processes only paragraph having single image link 187 | - Blank lines required before and after image link 188 | - Requires `Graphic Anchor` and `Figure Caption` paragraph styles in template 189 | otherwise these styles inherit `Body` style 190 | - the filter creates two divs having `custom-style` attribute 191 | - after process the image is placed in `custom-style="Graphic Anchor"` div and its caption is 192 | in `custom-style="Figure Caption"` 193 | div respectively 194 | 195 | ##### Requirement for template 196 | 197 | - Prepare `Graphic Anchor` and `Figure Caption` styles 198 | 199 | # samples 200 | 201 | ```markdown 202 | ![Centered image](https://github.com/pandocker/pandoc-docx-utils-py/raw/master/qr.png){width=100mm #fig:centered} 203 | ``` 204 | 205 | ## Want a new feature? 206 | 207 | Feature request (via issues) and PRs are welcome. Post questions in issues with `[Q]` in issue title. 208 | 209 | ### DIY 210 | 211 | As lua filters only requires pandoc itself, it is relatively easy 212 | to try develop a new filter. I recommend to use `k4zuki/pandocker-alpine` 213 | *docker image* like 214 | 215 | - `docker pull k4zuki/pandocker-alpine` to get image 216 | - clone this repo `git clone git@github.com:pandocker/pandocker-lua-filters.git` 217 | - `cd pandocker-lua-filters` 218 | - `docker run --rm -it -v/$PWD:/workdir k4zuki/pandocker-alpine` to start docker image 219 | - `make install` to install filters in image. They are installed in `/usr/local/share/lua/5.3/pandocker/` 220 | - `make reinstall` to *reinstall* so that filters will be updated 221 | - `make uninstall` to uninstall filters 222 | - `make html|pdf|docx` to compile test document 223 | - edit `tests/Makefile` to configure options for pandoc 224 | 225 | You don't have to `reinstall` for every source code updates. Instead edit `tests/Makefile` 226 | to run your new filter from inside repository. 227 | -------------------------------------------------------------------------------- /lua/aafigure.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # aafigure.lua 3 | ]] 4 | PANDOC_VERSION:must_be_at_least '2.8' 5 | 6 | local abs_pwd = require("pandoc.system").get_working_directory() 7 | local stringify = require("pandoc.utils").stringify 8 | 9 | --local pretty = require("pl.pretty") 10 | 11 | local debug = require("pandocker.utils").debug 12 | local file_exists = require("pandocker.utils").file_exists 13 | 14 | local util_get_meta = require("pandocker.utils").util_get_meta 15 | local platform = require("pandocker.utils").get_os() 16 | local base = require("pandocker.utils").package_base_path() 17 | 18 | local META_KEY = "aafigure" 19 | local meta = {} 20 | 21 | local default_meta = require("pandocker.default_loader")[META_KEY] 22 | assert(default_meta) 23 | 24 | local MESSAGE = "[ lua ] convert aafigure to svg/%s.svg" 25 | local BYPASS = "[ lua ] Skipping conversion as target 'svg/%s.svg' exists" 26 | local NOT_FOUND = "[ lua ] %s: file not found" 27 | local AAFIGURE = "%s/bin/%s" 28 | 29 | local function get_meta(mt) 30 | meta = util_get_meta(mt, default_meta, META_KEY) 31 | --debug(stringify(meta)) 32 | end 33 | 34 | function Link(el) 35 | if el.classes:includes(META_KEY) then 36 | if tostring(PANDOC_VERSION) == "2.15" then 37 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 38 | return 39 | end 40 | --debug("Link in 'wavedrom' class") 41 | if stringify(el.content) == "" then 42 | el.content = el.target 43 | end 44 | local idn = el.identifier 45 | 46 | -- remove classes 47 | local classes = {} 48 | for i, v in ipairs(el.classes) do 49 | if v ~= META_KEY then 50 | table.insert(classes, v) 51 | end 52 | end 53 | 54 | -- main block 55 | local source_file = stringify(el.target) 56 | local source_ext = source_file:match('.*%.(.*)') 57 | if file_exists(source_file) then 58 | -- reads file contents as string anyway; assuming input a JSON file 59 | 60 | local attr = pandoc.Attr(idn, classes, el.attributes) 61 | local content = io.open(source_file, "rb"):read("a") 62 | local hash = pandoc.utils.sha1(content) 63 | local fullpath = string.format("%s/svg/%s.svg", abs_pwd, hash) 64 | 65 | if not file_exists(fullpath) then 66 | local aafigure = META_KEY 67 | pandoc.pipe(aafigure, { source_file, "-o", fullpath }, "") 68 | debug(string.format(MESSAGE, hash)) 69 | else 70 | debug(string.format(BYPASS, hash)) 71 | end 72 | local img = pandoc.Image(el.content, fullpath, "fig:", attr) 73 | --pretty.dump(img) 74 | return img 75 | else 76 | debug(string.format(NOT_FOUND, source_file)) 77 | end 78 | end 79 | end 80 | 81 | if tostring(PANDOC_VERSION) ~= "2.15" then 82 | --debug(tostring(tostring(PANDOC_VERSION) == "2.15")) 83 | return { { Meta = get_meta }, { Link = Link } } 84 | else 85 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 86 | return 87 | end 88 | -------------------------------------------------------------------------------- /lua/csv2table-simple.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # csv2table.lua 3 | 4 | Converts Link to a csv file into Table object 5 | 6 | ## Syntax 7 | 8 | [Caption](/path/to/file){.table width=[w1,w2,...] header=true nocaption=true alignment=a1a2... \ 9 | subset_from=(y1,x1) subset_to=(y2,x2) #tbl:table} 10 | where, 11 | 12 | - Caption: caption of this table. if not given filename is used 13 | - /path/to/file : path to file. relative to directory where pandoc is invoked 14 | - header : flag to let first row as header row. defaults true 15 | - nocaption : Flag to unset temporary caption. defaults false 16 | - w1,w2,... : width value for each column. if not fully given padded by 17 | (1 - (sum of given widths)) / (number of unnumbered columns) 18 | e.g. When [0.5] is given for 4-column table, the first column will have 0.5 and the rest will have 0.16667 each 19 | of page width (i.e. (1 - 0.5) / 3) 20 | - a1a2... : alignment list for each column. c=Center, d=Default, l=Left, r=Right. 21 | if not given padded by d 22 | - subset_from : (row,col) pair to specify coordinate to cut FROM 23 | - subset_to : (row,col) pair to specify coordinate to cut TO 24 | - delimiter : separator character such as ";". default is "," 25 | 26 | ### Equivalent output 27 | 28 | : Caption {#tbl:table} 29 | 30 | | Header | Row | Table | 31 | |:----------|:-----:|------:| 32 | | Cell | Cell | Cell | 33 | 34 | ]] 35 | 36 | --local pretty = require("pl.pretty") 37 | require("pl.stringx").import() 38 | local List = require("pl.List") 39 | local tablex = require("pl.tablex") 40 | local seq = require("pl.seq") 41 | local csv = require("csv") 42 | 43 | local stringify = require("pandoc.utils").stringify 44 | local debug = require("pandocker.utils").debug 45 | local file_exists = require("pandocker.utils").file_exists 46 | 47 | local MESSAGE = "[ lua ] insert a table from %s" 48 | local FILE_NOT_FOUND = "[ lua ] %s: file not found" 49 | 50 | local table_template = [==[ 51 | | table | 52 | |-------| 53 | | cell | 54 | 55 | Table: caption 56 | ]==] 57 | 58 | local my_table = pandoc.read(table_template, "markdown").blocks[1] 59 | 60 | local empty_attr = { "", {}, {} } 61 | local empty_row = function() 62 | return { {} } 63 | end 64 | 65 | local function get_tf(item, default) 66 | if type(item) == "string" then 67 | item = string.upper(item) 68 | if tablex.search({ "TRUE", "YES" }, item) then 69 | return true 70 | else 71 | return false 72 | end 73 | else 74 | return default 75 | end 76 | end 77 | 78 | local function get_cell(c) 79 | if type(c) ~= "string" then 80 | c = tostring(c) 81 | end 82 | --pretty.dump(c) 83 | 84 | local _cell = pandoc.read(c, "markdown").blocks 85 | return _cell -- List of Blocks 86 | end 87 | 88 | local function get_row(t) 89 | local row = {} 90 | for _, v in ipairs(t) do 91 | --dump(get_cell(v), "") 92 | table.insert(row, get_cell(v)) 93 | end 94 | return row -- List of List of Blocks 95 | end 96 | 97 | local ALIGN = { ["D"] = pandoc.AlignDefault, 98 | ["L"] = pandoc.AlignLeft, 99 | ["C"] = pandoc.AlignCenter, 100 | ["R"] = pandoc.AlignRight 101 | } 102 | 103 | local function get_xy(attr) 104 | local _y = 1 105 | local _x = 1 106 | _y, _x = string.match(attr, "(%d+),(%d+)") 107 | --debug(attr .. " " .. _y .. " " .. _x) 108 | _y = tonumber(_y) 109 | _x = tonumber(_x) 110 | return _y, _x 111 | end 112 | 113 | local function get_widths(attr) 114 | local widths = List() 115 | for num in string.gmatch(attr, "(%d+%.?%d*),?") do 116 | --debug(num) 117 | widths:append(tonumber(num)) 118 | end 119 | return widths 120 | end 121 | 122 | local function get_alignments(attr) 123 | local alignment = List() 124 | for al in string.gmatch(attr, "[dlrcDLRC]") do 125 | --debug(al) 126 | alignment:append(ALIGN[al:upper()]) 127 | end 128 | return alignment 129 | end 130 | 131 | local function tabular(el) 132 | if el.classes:includes "table" then 133 | if tostring(PANDOC_VERSION) == "2.15" then 134 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 135 | return 136 | end 137 | local tab = {} 138 | local source_file = stringify(el.target) 139 | local header_avail = get_tf(el.attributes.header, true) 140 | local header = empty_row() 141 | local nocaption = get_tf(el.attributes.nocaption, false) 142 | local y_from = 1 143 | local x_from = 1 144 | local y_to = -1 145 | local x_to = -1 146 | local caption = "" 147 | local alignment = List() 148 | local widths = List() 149 | local delimiter = el.attributes.delimiter 150 | if el.attributes.delimiter == nil then 151 | delimiter = "," 152 | else 153 | debug("[ Lua ] apply different CSV delimiter for parse") 154 | end 155 | 156 | if file_exists(source_file) then 157 | tab = csv.open(source_file, { separator = delimiter }) 158 | --pretty.dump(tab) 159 | else 160 | debug(string.format(FILE_NOT_FOUND, source_file)) 161 | return 162 | end 163 | if stringify(el.content) == "" then 164 | if nocaption then 165 | caption = {} 166 | else 167 | caption = { pandoc.Str(el.target) } 168 | end 169 | else 170 | caption = el.content 171 | end 172 | --pretty.dump(caption) 173 | if el.identifier ~= "" then 174 | caption = List(caption) 175 | caption:append(pandoc.Space()) 176 | caption:append(pandoc.Str("{#" .. el.identifier .. "}")) 177 | end 178 | if el.attributes.subset_from ~= nil then 179 | y_from, x_from = get_xy(el.attributes.subset_from) 180 | end 181 | if el.attributes.subset_to ~= nil then 182 | y_to, x_to = get_xy(el.attributes.subset_to) 183 | if x_to < x_from then 184 | x_to = x_from 185 | end 186 | if y_to < y_from then 187 | y_to = y_from 188 | end 189 | end 190 | if el.attributes.alignment ~= nil then 191 | alignment = get_alignments(el.attributes.alignment) 192 | end 193 | if el.attributes.width ~= nil then 194 | widths = get_widths(el.attributes.width) 195 | end 196 | local rows = List() 197 | local i = 1 198 | local col_max = 1 199 | for row in tab:lines() do 200 | if i >= y_from then 201 | row = List(row):slice(x_from, x_to) 202 | --pretty.dump(row) 203 | col_max = math.max(col_max, #row) 204 | rows:append(get_row(row)) 205 | if y_to > 0 and i >= y_to then 206 | break 207 | end 208 | end 209 | i = i + 1 210 | end 211 | if header_avail then 212 | header = rows:pop(1) 213 | --pretty.dump(header) 214 | end 215 | --pretty.dump(header) 216 | while col_max > #alignment do 217 | alignment:append(ALIGN.D) 218 | end 219 | 220 | local rest = 1 - seq.sum(widths) 221 | local rest_columns_width = 0 222 | if rest <= 1 then 223 | rest_columns_width = rest / (col_max - #widths) 224 | end 225 | --debug(rest_width) 226 | 227 | while col_max > #widths do 228 | if FORMAT == "docx" then 229 | widths:append(0.01) 230 | else 231 | widths:append(rest_columns_width) 232 | end 233 | end 234 | --pretty.dump(alignment) 235 | debug(string.format(MESSAGE, source_file)) 236 | return pandoc.Table( 237 | caption, 238 | alignment, 239 | widths, 240 | header, 241 | rows 242 | ) 243 | end 244 | end 245 | 246 | local function link2table(el) 247 | if #el.content == 1 and el.content[1].tag == "Link" then 248 | return tabular(el.content[1]) 249 | end 250 | end 251 | 252 | if PANDOC_VERSION < { 2, 10 } then 253 | return { { Para = link2table } } 254 | end 255 | -------------------------------------------------------------------------------- /lua/csv2table.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # csv2table.lua 3 | 4 | Converts Link to a csv file into Table object 5 | 6 | ## Syntax 7 | 8 | [Caption](/path/to/file){.table width=[w1,w2,...] header=true nocaption=true alignment=a1a2... \ 9 | subset_from=(y1,x1) subset_to=(y2,x2) #tbl:table} 10 | where, 11 | 12 | - Caption: caption of this table. if not given filename is used 13 | - /path/to/file : path to file. relative to directory where pandoc is invoked 14 | - header : flag to let first row as header row. defaults true 15 | - nocaption : Flag to unset temporary caption. defaults false 16 | - w1,w2,... : width value for each column. if not fully given padded by 17 | (1 - (sum of given widths)) / (number of unnumbered columns) 18 | e.g. When [0.5] is given for 4-column table, the first column will have 0.5 and the rest will have 0.16667 each 19 | of page width (i.e. (1 - 0.5) / 3) 20 | - a1a2... : alignment list for each column. c=Center, d=Default, l=Left, r=Right. 21 | if not given padded by d 22 | - subset_from : (row,col) pair to specify coordinate to cut FROM 23 | - subset_to : (row,col) pair to specify coordinate to cut TO 24 | - delimiter : separator character such as ";". default is "," 25 | 26 | ### Equivalent output 27 | 28 | : Caption {#tbl:table} 29 | 30 | | Header | Row | Table | 31 | |:----------|:-----:|------:| 32 | | Cell | Cell | Cell | 33 | 34 | ]] 35 | 36 | local pretty = require("pl.pretty") 37 | require("pl.stringx").import() 38 | local List = require("pl.List") 39 | local tablex = require("pl.tablex") 40 | local seq = require("pl.seq") 41 | local csv = require("csv") 42 | 43 | local stringify = require("pandoc.utils").stringify 44 | local debug = require("pandocker.utils").debug 45 | local file_exists = require("pandocker.utils").file_exists 46 | 47 | local MESSAGE = "[ lua ] insert a table from %s" 48 | local FILE_NOT_FOUND = "[ lua ] %s: file not found" 49 | 50 | local table_template = [==[ 51 | | table | 52 | |-------| 53 | | cell | 54 | 55 | Table: caption 56 | ]==] 57 | 58 | local my_table = pandoc.read(table_template, "markdown").blocks[1] 59 | 60 | local empty_attr = { "", {}, {} } 61 | local empty_row = function() 62 | return { empty_attr, {} } 63 | end 64 | 65 | local function get_tf(item, default) 66 | if type(item) == "string" then 67 | item = string.upper(item) 68 | if tablex.search({ "TRUE", "YES" }, item) then 69 | return true 70 | else 71 | return false 72 | end 73 | else 74 | return default 75 | end 76 | end 77 | 78 | local function get_cell(c) 79 | if type(c) ~= "string" then 80 | c = tostring(c) 81 | end 82 | --pretty.dump(c) 83 | 84 | local _cell = pandoc.read(c, "markdown").blocks 85 | return { attr = empty_attr, 86 | alignment = pandoc.AlignDefault, 87 | row_span = 1, 88 | col_span = 1, 89 | contents = pandoc.List(_cell) } -- Cell 90 | end 91 | 92 | local function get_row(t) 93 | local row = {} 94 | for _, v in ipairs(t) do 95 | --dump(get_cell(v), "") 96 | table.insert(row, get_cell(v)) 97 | end 98 | return { empty_attr, row } 99 | end 100 | 101 | local ALIGN = { ["D"] = pandoc.AlignDefault, 102 | ["L"] = pandoc.AlignLeft, 103 | ["C"] = pandoc.AlignCenter, 104 | ["R"] = pandoc.AlignRight 105 | } 106 | 107 | local function get_xy(attr) 108 | local _y = 1 109 | local _x = 1 110 | _y, _x = string.match(attr, "(%d+),(%d+)") 111 | --debug(attr .. " " .. _y .. " " .. _x) 112 | _y = tonumber(_y) 113 | _x = tonumber(_x) 114 | return _y, _x 115 | end 116 | 117 | local function get_widths(attr) 118 | local widths = List() 119 | for num in string.gmatch(attr, "(%d+%.?%d*),?") do 120 | --debug(num) 121 | widths:append(tonumber(num)) 122 | end 123 | return widths 124 | end 125 | 126 | local function get_alignments(attr) 127 | local alignment = List() 128 | for al in string.gmatch(attr, "[dlrcDLRC]") do 129 | --debug(al) 130 | alignment:append(ALIGN[al:upper()]) 131 | end 132 | return alignment 133 | end 134 | 135 | local function tabular(el) 136 | if el.classes:includes "table" then 137 | if tostring(PANDOC_VERSION) == "2.15" then 138 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 139 | return 140 | end 141 | local tab = {} 142 | local source_file = stringify(el.target) 143 | local header_avail = get_tf(el.attributes.header, true) 144 | local header = empty_row() 145 | local nocaption = get_tf(el.attributes.nocaption, false) 146 | local y_from = 1 147 | local x_from = 1 148 | local y_to = -1 149 | local x_to = -1 150 | local caption = "" 151 | local alignment = List() 152 | local widths = List() 153 | local delimiter = el.attributes.delimiter 154 | if el.attributes.delimiter == nil then 155 | delimiter = "," 156 | else 157 | debug("[ Lua ] apply different CSV delimiter for parse") 158 | end 159 | 160 | if file_exists(source_file) then 161 | tab = csv.open(source_file, { separator = delimiter }) 162 | --pretty.dump(tab) 163 | else 164 | debug(string.format(FILE_NOT_FOUND, source_file)) 165 | return 166 | end 167 | if stringify(el.content) == "" then 168 | if nocaption then 169 | caption = {} 170 | else 171 | caption = { pandoc.Str(el.target) } 172 | end 173 | else 174 | caption = el.content 175 | end 176 | --pretty.dump(caption) 177 | if el.identifier ~= "" then 178 | caption = List(caption) 179 | caption:append(pandoc.Space()) 180 | caption:append(pandoc.Str("{#" .. el.identifier .. "}")) 181 | end 182 | if el.attributes.subset_from ~= nil then 183 | y_from, x_from = get_xy(el.attributes.subset_from) 184 | end 185 | if el.attributes.subset_to ~= nil then 186 | y_to, x_to = get_xy(el.attributes.subset_to) 187 | if x_to < x_from then 188 | x_to = x_from 189 | end 190 | if y_to < y_from then 191 | y_to = y_from 192 | end 193 | end 194 | if el.attributes.alignment ~= nil then 195 | alignment = get_alignments(el.attributes.alignment) 196 | end 197 | if el.attributes.width ~= nil then 198 | widths = get_widths(el.attributes.width) 199 | end 200 | local rows = List() 201 | local i = 1 202 | local col_max = 1 203 | for row in tab:lines() do 204 | if i >= y_from then 205 | row = List(row):slice(x_from, x_to) 206 | --pretty.dump(row) 207 | col_max = math.max(col_max, #row) 208 | rows:append(get_row(row)) 209 | if y_to > 0 and i >= y_to then 210 | break 211 | end 212 | end 213 | i = i + 1 214 | end 215 | if header_avail then 216 | header = rows:pop(1) 217 | --pretty.dump(header) 218 | end 219 | --pretty.dump(header) 220 | while col_max > #alignment do 221 | alignment:append(ALIGN.D) 222 | end 223 | 224 | local rest = 1 - seq.sum(widths) 225 | local rest_columns_width = 0 226 | if 0 < rest and rest <= 1 then 227 | rest_columns_width = rest / (col_max - #widths) 228 | else 229 | debug("[ Lua ] Sum of width exceeds page width") 230 | end 231 | --debug(rest_width) 232 | 233 | while col_max > #widths do 234 | widths:append(rest_columns_width) 235 | end 236 | --pretty.dump(alignment) 237 | debug(string.format(MESSAGE, source_file)) 238 | --pretty.dump(header) 239 | local table = my_table:clone() 240 | --debug("table." .. tostring(tablex.keys(table))) 241 | --debug(tostring(tablex.keys(table.head))) 242 | if tablex.find(tablex.keys(table.head), "rows") ~= nil then 243 | -- pandoc >= 2.17 244 | table.head.rows = { header } 245 | else 246 | -- pandoc < 2.17 247 | table.head[2] = { header } 248 | end 249 | --pretty.dump(table.head) 250 | table.caption = { long = { pandoc.Plain(caption) } } 251 | --pretty.dump(table.caption) 252 | table.colspecs = tablex.zip(alignment, widths) 253 | --pretty.dump(table.colspecs) 254 | table.bodies = { { attr = empty_attr, 255 | head = { }, 256 | body = rows, 257 | row_head_columns = 0 } } 258 | --pretty.dump(table.bodies) 259 | return table 260 | end 261 | end 262 | 263 | local function link2table(el) 264 | if #el.content == 1 and el.content[1].tag == "Link" then 265 | return tabular(el.content[1]) 266 | end 267 | end 268 | 269 | if PANDOC_VERSION >= { 2, 10 } then 270 | return { { Para = link2table } } 271 | end 272 | -------------------------------------------------------------------------------- /lua/default_loader.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | HIGHLY INSPIRED FROM https://pandoc.org/lua-filters.html#default-metadata-file 3 | ]] 4 | -- read metadata file (placed same directory as this file) into string 5 | --local debug = require("pandocker.utils").debug 6 | 7 | local pwd, _ = require("pandocker.utils").basename(PANDOC_SCRIPT_FILE) 8 | local metafile = io.open(pwd .. 'metadata-file.yaml', 'r') 9 | local content = metafile:read("*a") 10 | metafile:close() 11 | -- get metadata 12 | local default_meta = pandoc.read(content, "markdown").meta 13 | --[[ 14 | for i, v in pairs(default_meta) do 15 | debug(pandoc.utils.stringify(i) .. " = " .. pandoc.utils.stringify(v)) 16 | end 17 | ]] 18 | return default_meta 19 | -------------------------------------------------------------------------------- /lua/docx-appendixheadings.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # AppendixHeadings 3 | 4 | ## Function 5 | 6 | Applies level 1~5 headers in 'appendix' class to use dedicated headers 7 | 8 | * Works with docx output only 9 | * Level 6 and lower level headers are remain untouched 10 | * "Appendix Heading x" must be prepared in template or inherits default style 11 | 12 | | Level | Numbered | Appendix | 13 | |-------------------------------------------| 14 | | 1 | Heading 1 | Appendix Heading 1 | 15 | | 2 | Heading 2 | Appendix Heading 2 | 16 | | 3 | Heading 3 | Appendix Heading 3 | 17 | | 4 | Heading 4 | Appendix Heading 4 | 18 | | 5 | Heading 5 | Appendix Heading 5 | 19 | | 6+ | Heading 6 | | 20 | ]] 21 | 22 | local debug = require("pandocker.utils").debug 23 | 24 | local META_KEY = "heading-appendix" 25 | local CLASS_KEY = "appendix" 26 | 27 | local default_meta = require("pandocker.default_loader")[META_KEY] 28 | assert(default_meta) 29 | 30 | local meta = {} 31 | local APPLY_DEFAULT = "[ lua ] metadata '%s' was not found in source, applying default %s." 32 | local TOO_DEEP_LEVEL = "[ lua ] unnumbered heading greater than level %d is found and ignored" 33 | local MAX_HEADING_LEVEL = 5 34 | 35 | if FORMAT == "docx" or FORMAT == "native" then 36 | local function get_vars (mt) 37 | meta = mt[META_KEY] 38 | if meta ~= nil then 39 | for k, v in pairs(default_meta) do 40 | if meta[k] == nil then 41 | meta[k] = v 42 | local d = pandoc.utils.stringify(mt[META_KEY][k]) 43 | debug(string.format(APPLY_DEFAULT, META_KEY .. "." .. k, d)) 44 | end 45 | end 46 | else 47 | meta = default_meta 48 | debug(string.format(APPLY_DEFAULT, META_KEY, "")) 49 | --debug("metadata 'heading-unnumbered' was not found in source, applying defaults.") 50 | end 51 | end 52 | 53 | local function replace(el) 54 | if el.classes:includes(CLASS_KEY) then 55 | if el.level <= MAX_HEADING_LEVEL then 56 | local style = pandoc.utils.stringify(meta[tostring(el.level)]) 57 | el.attributes["custom-style"] = style 58 | local content = pandoc.Para(el.content) 59 | local attr = pandoc.Attr(el.identifier, el.classes, el.attributes) 60 | 61 | --debug(pandoc.utils.stringify(content)) 62 | --debug(pandoc.utils.stringify(div)) 63 | return pandoc.Div(content, attr) 64 | else 65 | debug(string.format(TOO_DEEP_LEVEL, MAX_HEADING_LEVEL)) 66 | end 67 | end 68 | --debug(el.level .. tostring(el.classes[1])) 69 | end 70 | 71 | return { { Meta = get_vars }, { Header = replace } } 72 | end 73 | -------------------------------------------------------------------------------- /lua/docx-apply-cell-styles.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # docx-apply-cell-styles.lua 3 | 4 | Finds table; get list of alignment; get list of styles to apply; apply styles for each cell 5 | ]] 6 | --local pretty = require("pl.pretty") 7 | 8 | local stringify = require("pandoc.utils").stringify 9 | local debug = require("pandocker.utils").debug 10 | local util_get_meta = require("pandocker.utils").util_get_meta 11 | 12 | local meta_key = "table-cell-styles" 13 | local meta = {} 14 | local default_meta = require("pandocker.default_loader")[meta_key] 15 | 16 | local tablex = require("pl.tablex") 17 | 18 | MESSAGE = "[ lua ] Apply table cell styles" 19 | 20 | if FORMAT == "docx" or FORMAT == "native" then 21 | 22 | local function get_meta(mt) 23 | meta = util_get_meta(mt, default_meta, meta_key) 24 | end 25 | 26 | local function get_header_styles(align) 27 | local aligns_table = { 28 | AlignDefault = stringify(meta["header-default"]), 29 | AlignLeft = stringify(meta["header-left"]), 30 | AlignCenter = stringify(meta["header-center"]), 31 | AlignRight = stringify(meta["header-right"]) } 32 | --debug(aligns_table[align]) 33 | return aligns_table[align] 34 | end 35 | 36 | local function get_body_styles(align) 37 | --pretty.dump(meta) 38 | local aligns_table = { 39 | AlignDefault = stringify(meta["body-default"]), 40 | AlignLeft = stringify(meta["body-left"]), 41 | AlignCenter = stringify(meta["body-center"]), 42 | AlignRight = stringify(meta["body-right"]) } 43 | --debug(aligns_table[align]) 44 | return aligns_table[align] 45 | end 46 | 47 | local function plain2para(el) 48 | --pretty.dump(el.content) 49 | --pretty.dump(el.tag) 50 | if el.tag == "Plain" then 51 | el = pandoc.Para(el.content) 52 | end 53 | return el 54 | end 55 | 56 | local function get_aligns(el) 57 | local aligns = {} 58 | for _, v in ipairs(el.colspecs) do 59 | table.insert(aligns, v[1]) 60 | end 61 | return aligns 62 | end 63 | 64 | local function get_headers(el) 65 | local headers = {} 66 | headers = el.head 67 | return headers 68 | end 69 | 70 | local function get_body_rows(el) 71 | local rows = {} 72 | rows = el.bodies[1].body 73 | return rows 74 | end 75 | 76 | local function apply_rows_styles(rows, styles) 77 | local row_attr = {} 78 | local _cell = {} 79 | --local rows_attr = rows[1] 80 | --rows = rows[2] 81 | for i, row in ipairs(rows) do 82 | if tablex.find(tablex.keys(row), "cells") ~= nil then 83 | -- pandoc >= 2.17 84 | row_attr = row.attr 85 | row = row.cells 86 | else 87 | -- pandoc < 2.17 88 | row_attr = row[1] 89 | row = row[2] 90 | end 91 | --debug(tostring(tablex.deepcompare(empty_attr, row_attr))) 92 | for j, cell in ipairs(row) do 93 | --pretty.dump(cell.contents) 94 | _cell = pandoc.Div(cell.contents) 95 | _cell["attr"]["attributes"]["custom-style"] = stringify(styles[j]) 96 | cell.contents = { _cell } 97 | row[j] = cell 98 | end 99 | rows[i] = { row_attr, row } 100 | end 101 | return rows 102 | end 103 | 104 | local function apply_header_styles(header, styles) 105 | local headers 106 | local header_attr = nil 107 | if tablex.find(tablex.keys(header), "rows") ~= nil then 108 | -- pandoc >= 2.17 109 | header_attr = header.attr 110 | headers = header.rows 111 | header.rows = apply_rows_styles(headers, styles) 112 | return header 113 | else 114 | --debug("header[1]." .. tostring(tablex.keys(header[1]))) 115 | -- pandoc < 2.17 116 | header_attr = header[1] 117 | headers = header[2] 118 | header = apply_rows_styles(headers, styles) 119 | return { header_attr, header } 120 | end 121 | end 122 | 123 | local function apply_cell_styles(el) 124 | debug(MESSAGE) 125 | local aligns = get_aligns(el) 126 | local headers = get_headers(el) 127 | local rows = get_body_rows(el) 128 | --pretty.dump(aligns) 129 | local body_styles = {} 130 | local header_styles = {} 131 | for _, v in ipairs(aligns) do 132 | table.insert(body_styles, get_body_styles(v)) 133 | table.insert(header_styles, get_header_styles(v)) 134 | end 135 | --pretty.dump(body_styles) 136 | --pretty.dump(header_styles) 137 | el.head = apply_header_styles(headers, header_styles) 138 | rows = apply_rows_styles(rows, body_styles) 139 | 140 | return el 141 | end 142 | 143 | local function apply_simple_cell_styles(el) 144 | debug(MESSAGE) 145 | local body_styles = {} 146 | local header_styles = {} 147 | for _, v in ipairs(el.aligns) do 148 | table.insert(body_styles, get_body_styles(v)) 149 | table.insert(header_styles, get_header_styles(v)) 150 | end 151 | for i, header in ipairs(el.headers) do 152 | if #header > 0 then 153 | local header_cell = pandoc.Div(header) 154 | header_cell["attr"]["attributes"]["custom-style"] = stringify(header_styles[i]) 155 | el.headers[i] = { header_cell } 156 | end 157 | end 158 | 159 | for i, row in ipairs(el.rows) do 160 | for j, cell in ipairs(row) do 161 | --cell = plain2para(cell) 162 | local body_cell = pandoc.Div(cell) 163 | body_cell["attr"]["attributes"]["custom-style"] = stringify(body_styles[j]) 164 | el.rows[i][j] = { body_cell } 165 | end 166 | end 167 | return el 168 | end 169 | 170 | local function version_switch (el) 171 | -- apply plein2para() for each Plain in el 172 | el = pandoc.walk_block(el, { Plain = plain2para }) 173 | if PANDOC_VERSION < { 2, 10 } then 174 | return apply_simple_cell_styles(el) 175 | else 176 | return apply_cell_styles(el) 177 | end 178 | end 179 | return { { Meta = get_meta }, { Table = version_switch } } 180 | 181 | end 182 | 183 | -------------------------------------------------------------------------------- /lua/docx-colored-span.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # docx-colored-span.lua 3 | 4 | Highlights a span in specified foreground and background colors. 5 | Foreground is specified by RRGGBB style hex value; Background is chosen from color name list. 6 | It won't change text content regardless of colors. 7 | 8 | ## Syntax 9 | 10 | 11 | [Highlighted text 1]{.highlight foreground="ABABAB"} 12 | 13 | 14 | [Highlighted text 2]{.highlight background="lightgray"} 15 | 16 | 17 | [Highlighted text 3]{.highlight foreground="ABABAB" background="darkgray"} 18 | 19 | ]] 20 | 21 | local List = require("pandoc").List 22 | local stringify = require("pandoc.utils").stringify 23 | 24 | local debug = require("pandocker.utils").debug 25 | local MESSAGE = "[ lua ] Colored span found" 26 | local KEY = "highlight" 27 | 28 | local COLORHEAD = pandoc.RawInline("openxml", "") 29 | local COLORMID = pandoc.RawInline("openxml", "") 30 | local COLORFOOT = pandoc.RawInline("openxml", "") 31 | local FG_KEY = "foreground" 32 | local FG_TAG = "" 33 | local FG_MESSAGE = "[ lua ] `- Foreground color - 0x%s" 34 | local BG_KEY = "background" 35 | local BG_TAG = "" 36 | local BG_MESSAGE = "[ lua ] `- Background color - %s" 37 | 38 | local BG_TABLE = List({ 39 | default = 'default', 40 | black = 'black', 41 | blue = 'blue', 42 | cyan = 'cyan', 43 | green = 'green', 44 | magenta = 'magenta', 45 | red = 'red', 46 | white = 'white', 47 | yellow = 'yellow', 48 | 49 | lightgray = 'lightgray', 50 | 51 | darkblue = 'darkBlue', 52 | darkcyan = 'darkCyan', 53 | darkgray = 'darkGray', 54 | darkgreen = 'darkGreen', 55 | darkmagenta = 'darkMagenta', 56 | darkred = 'darkRed', 57 | darkyellow = 'darkYellow', 58 | }) 59 | 60 | --[[ 61 | ``{=openxml} 62 | **Span** 63 | ``{=openxml} 64 | ]] 65 | 66 | if FORMAT == "docx" or FORMAT == "native" then 67 | local function replace(el) 68 | if el.classes:includes(KEY) then 69 | local foreground = pandoc.Span({}) 70 | local background = pandoc.Span({}) 71 | local fg_name = "" 72 | local bg_name = "default" 73 | 74 | debug(MESSAGE) 75 | 76 | if el.attributes[FG_KEY] ~= nil then 77 | -- 'foreground' attribute value is not blank nor nil 78 | fg_name = el.attributes[FG_KEY] 79 | if string.match(fg_name, "^[0-9a-fA-F].....$") ~= nil then 80 | debug(string.format(FG_MESSAGE, fg_name)) 81 | foreground = pandoc.RawInline("openxml", string.format(FG_TAG, fg_name)) 82 | end 83 | el.attributes[FG_KEY] = nil 84 | end 85 | 86 | if el.attributes[BG_KEY] ~= nil then 87 | -- 'background' attribute value is not blank nor nil 88 | bg_name = el.attributes[BG_KEY] 89 | if BG_TABLE[string.lower(bg_name)] ~= nil then 90 | debug(string.format(BG_MESSAGE, BG_TABLE[bg_name])) 91 | background = pandoc.RawInline("openxml", string.format(BG_TAG, BG_TABLE[bg_name])) 92 | else 93 | debug(string.format("[ Lua ] `- Background color %s is not found", bg_name)) 94 | end 95 | el.attributes[BG_KEY] = nil 96 | end 97 | 98 | return pandoc.Span({ COLORHEAD, foreground, background, COLORMID, el, COLORFOOT }) 99 | end 100 | end 101 | return { { Span = replace } } 102 | end 103 | -------------------------------------------------------------------------------- /lua/docx-comment.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Generated by EmmyLua(https://github.com/EmmyLua) 3 | Created by yamamoto. 4 | DateTime: 2020/10/04 16:54 5 | 6 | # docx-comment.lua 7 | 8 | Convert a span with `comment` attribute 9 | 10 | [Comment point to]{comment="Comment string"} 11 | 12 | to Docx comment 13 | 14 | [Comment string]{.comment-start}Comment point to[]{.comment-end} 15 | 16 | ]] 17 | 18 | --local stringify = require("pandoc.utils").stringify 19 | local List = require("pandoc").List 20 | 21 | local debug = require("pandocker.utils").debug 22 | local KEY = "comment" 23 | 24 | if FORMAT == "docx" or FORMAT == "native" then 25 | local function replace(el) 26 | if not List({ nil, "" }):includes(el.attributes[KEY]) then 27 | -- 'comment' attribute value is not blank nor nil 28 | local comment_string = el.attributes[KEY] 29 | debug(comment_string) 30 | local comment_start = pandoc.Span({ pandoc.Str(comment_string) }, { "", { "comment-start" }, {} }) 31 | local comment_end = pandoc.Span(pandoc.Null, { "", { "comment-end" }, {} }) 32 | el.attributes[KEY] = nil 33 | return pandoc.Span({ comment_start, el, comment_end }) 34 | end 35 | end 36 | end 37 | 38 | return { { Span = replace } } 39 | -------------------------------------------------------------------------------- /lua/docx-custom-span-styles.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # docx-custom-span-styles.lua 3 | 4 | - Generated by EmmyLua(https://github.com/EmmyLua) 5 | - Created by yamamoto. 6 | - DateTime: 2020/06/29 4:58 7 | 8 | ## Function 9 | 10 | Detects Span in custom class listed in config file and apply custom-styles attribute. 11 | 12 | ]] 13 | --local pretty = require("pl.pretty") 14 | 15 | local debug = require("pandocker.utils").debug 16 | local util_get_meta = require("pandocker.utils").util_get_meta 17 | 18 | local META_KEY = "custom-spans" 19 | 20 | local default_meta = require("pandocker.default_loader")[META_KEY] 21 | assert(default_meta) 22 | 23 | local meta = {} 24 | local APPLY_DEFAULT = "[ lua ] metadata '%s' was not found in source, applying default %s." 25 | local APPLY = "[ lua ] '%s' class Span found and applied '%s' custom character style" 26 | 27 | if FORMAT == "docx" or FORMAT == "native" then 28 | local function get_vars(mt) 29 | meta = util_get_meta(mt, default_meta, META_KEY) 30 | end 31 | 32 | local function replace(el) 33 | for k, v in pairs(meta) do 34 | if el.classes:includes(k) then 35 | local style = pandoc.utils.stringify(v) 36 | --debug(k .. ", " .. style) 37 | el.attributes["custom-style"] = style 38 | debug(string.format(APPLY, k, style)) 39 | end 40 | end 41 | 42 | return el 43 | end 44 | 45 | return { { Meta = get_vars }, { Span = replace } } 46 | 47 | end 48 | -------------------------------------------------------------------------------- /lua/docx-extract-bullet-lists.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # docx-extract-bullet-lists.lua 3 | 4 | Finds and converts all bullet lists into Divs in certain styles 5 | Level-4 and deeper level items are promoted to level-3 6 | 7 | ## Syntax 8 | ```markdown 9 | # Inputs 10 | 11 | - Level1 12 | - Level2 13 | - Level3 14 | - Level4 15 | 16 | 17 | # Equivalent outputs 18 | 19 | :::{custom-style="Bullet List 1"} 20 | Level1 21 | ::: 22 | 23 | :::{custom-style="Bullet List 2"} 24 | Level2 25 | ::: 26 | 27 | :::{custom-style="Bullet List 3"} 28 | Level3 29 | ::: 30 | 31 | :::{custom-style="Bullet List 3"} 32 | Level4 33 | ::: 34 | ``` 35 | ]] 36 | 37 | local stringify = require("pandoc.utils").stringify 38 | 39 | --local pretty = require("pl.pretty") 40 | 41 | local debug = require("pandocker.utils").debug 42 | local util_get_meta = require("pandocker.utils").util_get_meta 43 | 44 | local META_KEY = "bullet-style" 45 | local meta = {} 46 | local MAX_DEPTH = 3 47 | local TOO_DEEP = "[ lua ] Listed item found at too deep level. Promote to level-%d." 48 | 49 | local default_meta = require("pandocker.default_loader")[META_KEY] 50 | assert(default_meta) 51 | 52 | if FORMAT == "docx" or FORMAT == "native" then 53 | 54 | local function get_meta(mt) 55 | meta = util_get_meta(mt, default_meta, META_KEY) 56 | --debug(stringify(meta)) 57 | end 58 | 59 | local function get_style(depth) 60 | local style = "" 61 | if depth > MAX_DEPTH then 62 | style = meta[tostring(MAX_DEPTH)] 63 | debug(string.format(TOO_DEEP, MAX_DEPTH)) 64 | --debug(stringify(meta[tostring(max_depth)])) 65 | else 66 | style = meta[tostring(depth)] 67 | --debug(stringify(meta[tostring(depth)])) 68 | end 69 | return style 70 | end 71 | 72 | local function combine_para_plain(paras, depth) 73 | local _content = {} 74 | for idx, para in ipairs(paras) do 75 | table.insert(_content, para.content) 76 | if idx ~= #paras then 77 | table.insert(_content, {}) 78 | end 79 | end 80 | 81 | bullet = pandoc.Div({ pandoc.LineBlock(_content) }) 82 | bullet["attr"]["attributes"]["custom-style"] = stringify(get_style(depth)) 83 | table.insert(bl, bullet) 84 | end 85 | 86 | local function extract_bullet_list(el, depth) 87 | local paras = {} 88 | local style = get_style(depth) 89 | 90 | for _, blocks in ipairs(el.content) do 91 | --debug(depth .. ", " .. #v .. ", " .. stringify(v)) 92 | for idx, block in ipairs(blocks) do 93 | if block.tag ~= "Para" and block.tag ~= "Plain" then 94 | combine_para_plain(paras, depth) 95 | paras = {} 96 | if block.tag == "BulletList" then 97 | extract_bullet_list(block, depth + 1) 98 | else 99 | bullet = pandoc.Div(block) 100 | bullet["attr"]["attributes"]["custom-style"] = stringify(style) 101 | table.insert(bl, bullet) 102 | end 103 | else 104 | table.insert(paras, block) 105 | if idx == #blocks then 106 | combine_para_plain(paras, depth) 107 | paras = {} 108 | end 109 | --debug(depth .. " " .. e.tag .. " " .. stringify(e)) 110 | end 111 | end 112 | end 113 | end 114 | 115 | local function bulletlist_to_divs(doc) 116 | local head = {} 117 | local tail = {} 118 | 119 | for i, el in ipairs(doc.blocks) do 120 | bl = {} 121 | if el.tag == "BulletList" then 122 | debug("[ lua ] Bullet list found") 123 | extract_bullet_list(el, 1) 124 | table.move(doc.blocks, 1, i - 1, 1, head) -- head has contents before BulletList 125 | table.move(doc.blocks, i + 1, #doc.blocks, 1, tail) -- tail has after BulletList 126 | table.move(bl, 1, #bl, #head + 1, head) -- concat head and bl -> head 127 | table.move(tail, 1, #tail, #head + 1, head) -- concat head and tail 128 | doc.blocks = head 129 | return bulletlist_to_divs(doc) 130 | --debug(stringify(bl)) 131 | end 132 | end 133 | return doc 134 | end 135 | 136 | return { { Meta = get_meta }, { Pandoc = bulletlist_to_divs } } 137 | end 138 | -------------------------------------------------------------------------------- /lua/docx-image-styles.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # docx-image-styles.lua 3 | 4 | applies different styles image and its caption 5 | when image link does not have caption 6 | ]] 7 | 8 | --local pretty = require("pl.pretty") 9 | --require("pl.stringx").import() 10 | 11 | local stringify = require("pandoc.utils").stringify 12 | local debug = require("pandocker.utils").debug 13 | --local file_exists = require("pandocker.utils").file_exists 14 | 15 | local MESSAGE = "[ lua ] Para having one Image element found" 16 | local NOT_FOUND = "[ lua ] metadata '%s' was not found in source, applying default %s." 17 | 18 | local default_meta = require("pandocker.default_loader")["figure-styles"] 19 | 20 | if FORMAT == "docx" or FORMAT == "native" then 21 | local function get_vars (mt) 22 | meta = mt["figure-styles"] 23 | if meta ~= nil then 24 | for k, v in pairs(default_meta) do 25 | if meta[k] == nil then 26 | meta[k] = v 27 | local d = pandoc.utils.stringify(mt["figure-styles"][k]) 28 | debug(string.format(NOT_FOUND, "figure-styles." .. k, d)) 29 | end 30 | end 31 | else 32 | meta = default_meta 33 | debug(string.format(NOT_FOUND, "figure-styles", "")) 34 | --debug("metadata 'heading-unnumbered' was not found in source, applying defaults.") 35 | end 36 | end 37 | 38 | local function para(elem) 39 | if #elem.content == 1 and elem.content[1].tag == "Image" then 40 | debug(MESSAGE) 41 | image = elem.content[1] 42 | --debug(stringify(image.src)) 43 | local caption_div = pandoc.Div({}) 44 | local image_div = pandoc.Div({}) 45 | caption_div["attr"]["attributes"]["custom-style"] = stringify(meta["caption"]) 46 | image_div["attr"]["attributes"]["custom-style"] = stringify(meta["anchor"]) 47 | 48 | if stringify(image.caption) ~= "" then 49 | caption_div.content = { pandoc.Para(image.caption) } 50 | image.caption = {} 51 | image.title = "" 52 | end 53 | image_div.content = { pandoc.Para(image) } 54 | 55 | if PANDOC_VERSION < (3) then 56 | return { image_div, caption_div } 57 | else 58 | return { image_div }--, caption_div 59 | end 60 | end 61 | end 62 | 63 | if PANDOC_VERSION < (3) then 64 | return { { Meta = get_vars }, { Para = para } } 65 | else 66 | return { { Meta = get_vars }, { Plain = para } } 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lua/docx-pagebreak-toc.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # docx-pagebreak-toc.lua 3 | 4 | Finds commands to insert TOC, sub section TOC, line break or a page break 5 | Only works for `docx` format 6 | TOC title is set to "Table of Contents" by default. Metadata `toc-title` overrides this setting. 7 | 8 | ## Syntax 9 | 10 | ```markdown 11 | 12 | \toc 13 | 14 | 15 | \newpage 16 | 17 | 18 |
19 | 20 | 21 | # Level1 header {.subsection-toc} 22 | 23 | ``` 24 | ]] 25 | 26 | --local stringify = require("pandoc.utils").stringify 27 | --local pretty = require("pl.pretty") 28 | 29 | local debug = require("pandocker.utils").debug 30 | local strip = require("pl.stringx").strip 31 | 32 | local RAW_TOC_TEMPLATE = [[ 33 | 34 | 35 | 36 | 37 | 38 | %s 39 | 40 | 41 | 42 | 43 | 44 | 45 | ]] 46 | local RAW_PAGEBREAK = "" 47 | local NOT_FOUND = "[ lua ] metadata '%s' was not found in source, applying default %s." 48 | 49 | local meta_key = "toc-title" 50 | local default_meta = require("pandocker.default_loader")[meta_key] 51 | 52 | local function get_vars (mt) 53 | meta = mt[meta_key] 54 | if meta ~= nil and meta.tag == "MetaInlines" then 55 | meta = { table.unpack(meta) } 56 | else 57 | meta = { table.unpack(default_meta) } 58 | debug(string.format(NOT_FOUND, meta_key, "") 59 | ) 60 | end 61 | end 62 | 63 | local function toc(el) 64 | if el.text == "\\toc" then 65 | if FORMAT == "docx" or FORMAT == "native" then 66 | debug("[ lua ] insert Table of Contents") 67 | el.text = string.format(RAW_TOC_TEMPLATE, [[TOC \o "1-3" \h \z \u]]) 68 | el.format = "openxml" 69 | local para = pandoc.Para(meta) 70 | local div = pandoc.Div({ para, el }) 71 | div["attr"]["attributes"]["custom-style"] = "TOC Heading" 72 | return div 73 | else 74 | --debug("\\toc, not docx") 75 | return {} 76 | end 77 | elseif el.text == "\\newpage" then 78 | if FORMAT == "docx" or FORMAT == "native" then 79 | debug("[ lua ] insert a Pagebreak") 80 | el.text = RAW_PAGEBREAK 81 | el.format = "openxml" 82 | return el 83 | elseif FORMAT ~= "latex" then 84 | --debug("\\newpage, not docx nor latex") 85 | return {} 86 | end 87 | end 88 | --elseif FORMAT == "latex" then 89 | end 90 | 91 | local function linebreak(el) 92 | 93 | local text = strip(el.text) 94 | --debug('"' .. el.text .. '", "' .. text .. '"') 95 | if text == "
" then 96 | if FORMAT == "docx" or FORMAT == "native" then 97 | debug("[ lua ] insert a LineBreak") 98 | el = pandoc.LineBreak() 99 | return el 100 | end 101 | end 102 | end 103 | 104 | local function subsection_toc(el) 105 | if FORMAT == "docx" or FORMAT == "native" then 106 | if el.level == 1 then 107 | if el.classes:find("subsection-toc") then 108 | local id = el.identifier 109 | debug("[ lua ] insert subsection TOC for #" .. id) 110 | local subsectoc = string.format(RAW_TOC_TEMPLATE, [[TOC \o "2-2" \h \b ”]] .. id .. [[” \u]]) 111 | return { el, pandoc.RawBlock("openxml", subsectoc) } 112 | end 113 | end 114 | end 115 | 116 | end 117 | 118 | return { { Meta = get_vars }, { RawBlock = toc }, { RawInline = linebreak }, { Header = subsection_toc } } 119 | -------------------------------------------------------------------------------- /lua/docx-unnumberedheadings.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # UnnumberedHeadings 3 | 4 | ## Function 5 | 6 | Converts level 1~5 headers in 'unnumbered' class to unnumbered headers 7 | 8 | * Works with docx output only 9 | * Level 6 and lower level headers are remain untouched 10 | * "Heading Unnumbered x" must be prepared in template or inherits default style 11 | 12 | | Level | Numbered | Unnumbered | 13 | |-------------------------------------------| 14 | | 1 | Heading 1 | Heading Unnumbered 1 | 15 | | 2 | Heading 2 | Heading Unnumbered 2 | 16 | | 3 | Heading 3 | Heading Unnumbered 3 | 17 | | 4 | Heading 4 | Heading Unnumbered 4 | 18 | | 5 | Heading 5 | Heading Unnumbered 5 | 19 | | 6+ | Heading 6 | | 20 | ]] 21 | 22 | local debug = require("pandocker.utils").debug 23 | 24 | local META_KEY = "heading-unnumbered" 25 | local CLASS_KEY = "unnumbered" 26 | 27 | local default_meta = require("pandocker.default_loader")[META_KEY] 28 | assert(default_meta) 29 | 30 | local meta = {} 31 | local APPLY_DEFAULT = "[ lua ] metadata '%s' was not found in source, applying default %s." 32 | local TOO_DEEP_LEVEL = "[ lua ] unnumbered heading greater than level %d is found and ignored" 33 | local MAX_HEADING_LEVEL = 5 34 | 35 | if FORMAT == "docx" or FORMAT == "native" then 36 | local function get_vars (mt) 37 | meta = mt[META_KEY] 38 | if meta ~= nil then 39 | for k, v in pairs(default_meta) do 40 | if meta[k] == nil then 41 | meta[k] = v 42 | local d = pandoc.utils.stringify(mt[META_KEY][k]) 43 | debug(string.format(APPLY_DEFAULT, META_KEY .. "." .. k, d)) 44 | end 45 | end 46 | else 47 | meta = default_meta 48 | debug(string.format(APPLY_DEFAULT, META_KEY, "")) 49 | --debug("metadata 'heading-unnumbered' was not found in source, applying defaults.") 50 | end 51 | end 52 | 53 | local function replace(el) 54 | if el.classes:includes(CLASS_KEY) then 55 | if el.level <= MAX_HEADING_LEVEL then 56 | local style = pandoc.utils.stringify(meta[tostring(el.level)]) 57 | el.attributes["custom-style"] = style 58 | local content = pandoc.Para(el.content) 59 | local attr = pandoc.Attr(el.identifier, el.classes, el.attributes) 60 | 61 | --debug(pandoc.utils.stringify(content)) 62 | --debug(pandoc.utils.stringify(div)) 63 | return pandoc.Div(content, attr) 64 | else 65 | debug(string.format(TOO_DEEP_LEVEL, MAX_HEADING_LEVEL)) 66 | end 67 | end 68 | --debug(el.level .. tostring(el.classes[1])) 69 | end 70 | 71 | return { { Meta = get_vars }, { Header = replace } } 72 | end 73 | -------------------------------------------------------------------------------- /lua/hide-frontpage-metadata.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # hide-frontpage-metadata.lua 3 | 4 | hides certain metadata when LaTeX or Docx output 5 | 6 | ]] 7 | 8 | -- local pretty = require("pl.pretty") 9 | 10 | local stringify = require("pandoc.utils").stringify 11 | 12 | local debug = require("pandocker.utils").debug 13 | 14 | local MESSAGE = "[ lua ] metadata '%s' has found and removed" 15 | 16 | if FORMAT == "latex" or FORMAT == "docx" or FORMAT == "native" then 17 | local function get_vars (mt) 18 | local meta = { 19 | author = "author-meta", 20 | date = "date-meta", 21 | subtitle = "subtitle-meta", 22 | title = "title-meta", 23 | } 24 | 25 | for k, v in pairs(meta) do 26 | --debug(k .. ": " .. v) 27 | if mt[k] ~= nil then 28 | mt[v] = stringify(mt[k]) 29 | --debug(stringify(mt[k])) 30 | mt[k] = nil 31 | debug(string.format(MESSAGE, k)) 32 | end 33 | end 34 | --pretty.dump(mt) 35 | return mt 36 | end 37 | return { { Meta = get_vars } } 38 | end 39 | -------------------------------------------------------------------------------- /lua/listingtable.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # listingtable.lua 3 | 4 | Finds Link in `listingtable` class and get the file content into a CodeBlock 5 | Guesses included file type and adds to classes 6 | Cuts into subset if corresponding options are set 7 | 8 | ## Syntax 9 | 10 | ```markdown 11 | [Caption](/path/to/file){.listingtable } 12 | ``` 13 | 14 | ### Attributes 15 | 16 | - `from` 17 | - `startFrom` 18 | - `to` 19 | - `type` 20 | - `numbers` 21 | - `nocaption` 22 | 23 | ## Note 24 | 25 | | Link (content, target[, title[, attr] ]) 26 | | [content](target){.class-1 .class-2 attr=alpha attr=beta #lst:list} 27 | | | | | k v k v | | 28 | | | classes | | attributes | identifier 29 | | .listingtable type=plain numbers=left from=5 to=10 30 | ]] 31 | 32 | local tablex = require("pl.tablex") 33 | 34 | local stringify = require("pandoc.utils").stringify 35 | 36 | local debug = require("pandocker.utils").debug 37 | local get_tf = require("pandocker.utils").get_tf 38 | 39 | local function listingtable(el) 40 | --[[ 41 | debug(FORMAT) 42 | debug(stringify(el.content)) 43 | debug(stringify(el.target)) 44 | debug(stringify(el.identifier)) 45 | ]] 46 | 47 | if el.classes:includes "listingtable" then 48 | if tostring(PANDOC_VERSION) == "2.15" then 49 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 50 | return 51 | end 52 | if stringify(el.content) == "" then 53 | el.content = el.target 54 | end 55 | local listing_file = stringify(el.target) 56 | local lines = {} 57 | -- test if file exists 58 | if require("pandocker.utils").file_exists(listing_file) then 59 | 60 | --convert file contents to list of strings 61 | for line in io.lines(listing_file) do 62 | lines[#lines + 1] = line 63 | end 64 | debug(string.format("[ lua ] listing %s", listing_file)) 65 | else 66 | debug("Failed to open " .. el.target) 67 | return 68 | end 69 | local caption = pandoc.Str(stringify(el.content)) 70 | local file_type = el.attributes["type"] or "plain" 71 | local nocaption = get_tf(el.attributes.nocaption, false) 72 | local linefrom = tonumber(el.attributes["from"]) or 1 73 | if linefrom < 1 then 74 | linefrom = 1 75 | end 76 | 77 | local lineto = tonumber(el.attributes["to"]) or #lines 78 | if tonumber(lineto) > #lines then 79 | lineto = #lines 80 | end 81 | local attributes = {} 82 | for k, v in pairs(el.attributes) do 83 | if not tablex.search({ "type", "from", "to", "nocaption" }, k) then 84 | attributes[k] = v 85 | end 86 | end 87 | attributes["startFrom"] = el.attributes["startFrom"] or linefrom 88 | attributes["numbers"] = el.attributes["numbers"] or "left" 89 | 90 | local data = table.concat(lines, "\n", linefrom, lineto) 91 | --debug(data) 92 | local _, basename = require("pandocker.utils").basename(listing_file) 93 | local idn = el.identifier 94 | if idn == "" then 95 | idn = "lst:" .. string.gsub(basename, "%.", "_") 96 | end 97 | --debug(idn) 98 | 99 | el.classes:extend { file_type, "numberLines" } 100 | local attr = pandoc.Attr(idn, el.classes, attributes) 101 | local raw_code = pandoc.CodeBlock(data, attr) 102 | 103 | --[[ 104 | debug(stringify(caption)) 105 | debug(file_type) 106 | debug(linefrom) 107 | debug(lineto) 108 | debug(startFrom) 109 | debug(numbers) 110 | ]] 111 | 112 | local para = { raw_code } 113 | if not nocaption then 114 | table.insert(para, 1, pandoc.Para({ pandoc.Str("Listing:"), pandoc.Space(), caption })) 115 | end 116 | --debug(stringify(para)) 117 | return para 118 | end 119 | end 120 | 121 | function Para(el) 122 | if #(el.content) == 1 then 123 | el = el.content[1] 124 | if el.tag == "Link" then 125 | --debug("Para content is a Link") 126 | return listingtable(el) 127 | end 128 | end 129 | end 130 | -------------------------------------------------------------------------------- /lua/metadata-file.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rmnote: false 3 | 4 | include: [] 5 | 6 | tex-rowcolors: "\\\\rowcolors{3}{white!100!white}{table-gray!100!white!100}" 7 | 8 | lgeometry: "top=20truemm,bottom=20truemm,left=20truemm,right=20truemm" 9 | 10 | heading-unnumbered: 11 | 1: "Heading Unnumbered 1" 12 | 2: "Heading Unnumbered 2" 13 | 3: "Heading Unnumbered 3" 14 | 4: "Heading Unnumbered 4" 15 | 5: "Heading Unnumbered 5" 16 | 17 | heading-appendix: 18 | 1: "Appendix Heading 1" 19 | 2: "Appendix Heading 2" 20 | 3: "Appendix Heading 3" 21 | 4: "Appendix Heading 4" 22 | 5: "Appendix Heading 5" 23 | 24 | custom-spans: 25 | red: "WarningTok" 26 | green: "PreprocessorTok" 27 | blue: "AttributeTok" 28 | 29 | bullet-style: 30 | 1: "Bullet List 1" 31 | 2: "Bullet List 2" 32 | 3: "Bullet List 3" 33 | 34 | figure-styles: 35 | anchor: "Graphic Anchor" 36 | caption: "Figure Caption" 37 | 38 | toc-title: "Table of Contents" 39 | 40 | table-cell-styles: 41 | header-default: "Table Head Left" 42 | header-left: "Table Head Left" 43 | header-center: "Table Head Center" 44 | header-right: "Table Head Right" 45 | body-default: "Table Body Left" 46 | body-left: "Table Body Left" 47 | body-center: "Table Body Center" 48 | body-right: "Table Body Right" 49 | 50 | svgbob: 51 | font-family: "Arial" 52 | font-size: 14 53 | scale: 1 54 | stroke-width: 2 55 | 56 | aafigure: 57 | 58 | ... 59 | -------------------------------------------------------------------------------- /lua/preprocess.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # preprocess.lua 3 | 4 | Finds heading starting with `#include` and "filename" 5 | and tries to include contents of filename into AST tree 6 | 7 | - Metadata "include" is used as search path list 8 | - Does not apply to contents of a Div 9 | - search paths are inherited from option parameter for pandoc 10 | 11 | ## Syntax 12 | 13 | ```markdown 14 | # #include "section1.md" 15 | 19 | ``` 20 | ]] 21 | 22 | local stringify = require("pandoc.utils").stringify 23 | 24 | local debug = require("pandocker.utils").debug 25 | local file_exists = require("pandocker.utils").file_exists 26 | --local default_meta = require("pandocker.default_loader")["include"] 27 | --assert(default_meta ~= nil) 28 | 29 | --local search_paths = {} 30 | --local META_NOT_FOUND = "metadata '%s' was not found in source, applying default %s." 31 | local FILE_NOT_FOUND = "[ lua ] %s: file not found in search paths" 32 | 33 | local function dump(tt, mm) 34 | if mm == nil then 35 | mm = "" 36 | end 37 | for ii, vv in ipairs(tt) do 38 | print(mm, ii .. " " .. tostring(vv["tag"]) .. "(" .. stringify(vv) .. ")") 39 | end 40 | end 41 | 42 | --[[ 43 | local function store_meta (mt) 44 | search_paths = mt["include"] 45 | if search_paths == nil then 46 | search_paths = default_meta 47 | debug(string.format(META_NOT_FOUND, "include", "./")) 48 | end 49 | table.insert(search_paths, "") 50 | end 51 | ]] 52 | 53 | local function replace(el) 54 | local rep = el.content 55 | local sub 56 | local data 57 | if #rep == 3 then 58 | if tostring(PANDOC_VERSION) == "2.15" then 59 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 60 | return 61 | end 62 | --dump(rep) 63 | if rep[1] == pandoc.Str("#include") and rep[2].tag == "Space" and rep[3].tag == "Quoted" then 64 | for _, v in ipairs(PANDOC_STATE.resource_path) do 65 | local included = "./" .. stringify(v) .. "/" .. stringify(rep[3].content) 66 | if file_exists(included) then 67 | data = io.open(included, "r"):read("*a") 68 | sub = pandoc.read(data) 69 | --dump(sub.blocks) 70 | return sub 71 | end 72 | end 73 | debug(string.format(FILE_NOT_FOUND, stringify(rep[3].content))) 74 | --print(stringify(rep[3].content)) 75 | end 76 | end 77 | end 78 | 79 | local function preprocess(doc) 80 | local sub = {} 81 | local head = {} 82 | local tail = {} 83 | for i, el in ipairs(doc.blocks) do 84 | --print(i .. " " .. el.tag .. "(" .. stringify(el) .. ")") 85 | if el.tag == "Header" then 86 | sub = replace(el) 87 | --print(tostring(sub)) 88 | if sub ~= nil then 89 | --sub = preprocess(sub) 90 | --print(#sub.blocks) 91 | --print("\n--- counter reset?") 92 | table.move(doc.blocks, 1, i - 1, 1, head) -- head has contents before #include 93 | --dump(head, "hh") 94 | table.move(doc.blocks, i + 1, #doc.blocks, 1, tail) -- tail has after #include 95 | --dump(sub.blocks, "ss") 96 | --dump(tail, "tt") 97 | table.move(sub.blocks, 1, #sub.blocks, #head + 1, head) -- concat head and sub.blocks -> head 98 | table.move(tail, 1, #tail, #head + 1, head) -- concat head and tail 99 | --dump(head, " ") 100 | doc.blocks = head 101 | return preprocess(doc) 102 | end 103 | end 104 | end 105 | return doc 106 | end 107 | 108 | return { { Pandoc = preprocess } } 109 | -------------------------------------------------------------------------------- /lua/removable-note.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # removable-note.lua 3 | 4 | Finds "rmnote" class Div and removes if metadata "rmnote" is set `true` 5 | 6 | ## Syntax 7 | 8 | ```markdown 9 | ::: rmnote ::::::::::: 10 | - All the contents 11 | - inside this div 12 | 13 | is removed when flag is set `true`. 14 | :::::::::::::::::::::: 15 | ``` 16 | ]] 17 | 18 | local stringify = require("pandoc.utils").stringify 19 | 20 | local debug = require("pandocker.utils").debug 21 | local default_meta = require("pandocker.default_loader")["rmnote"] 22 | assert(default_meta ~= nil) 23 | 24 | local meta = {} 25 | local METADATA_NOT_FOUND = "[ lua ] metadata '%s' was not found in source, applying default %s." 26 | 27 | local function dump(tt, mm) 28 | for ii, vv in ipairs(tt) do 29 | print(mm .. ii .. " " .. tostring(vv["tag"]) .. "(" .. stringify(vv) .. ")") 30 | end 31 | end 32 | 33 | local function get_vars (mt) 34 | if tostring(PANDOC_VERSION) == "2.15" then 35 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 36 | return 37 | end 38 | meta = mt["rmnote"] 39 | if meta == nil then 40 | meta = default_meta 41 | debug(string.format(METADATA_NOT_FOUND, "rmnote", stringify(default_meta))) 42 | end 43 | meta = stringify(meta) 44 | --debug(tostring(meta == "true")) 45 | end 46 | 47 | local function remove(doc) 48 | for i, el in ipairs(doc.blocks) do 49 | --print(i .. " " .. el.tag .. "(" .. stringify(el) .. ")") 50 | if el.tag == "Div" and el.classes:find("rmnote") then 51 | if meta == "true" then 52 | --debug("remove") 53 | debug("[ lua ] Div in 'rmnote' class found and removed") 54 | table.remove(doc.blocks, i) 55 | end 56 | end 57 | end 58 | --dump(doc.blocks, " ") 59 | return doc 60 | end 61 | if tostring(PANDOC_VERSION) ~= "2.15" then 62 | return { { Meta = get_vars }, { Pandoc = remove } } 63 | else 64 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 65 | return 66 | end 67 | 68 | -------------------------------------------------------------------------------- /lua/svgbob.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # svgbob.lua 3 | ]] 4 | PANDOC_VERSION:must_be_at_least '2.8' 5 | 6 | local abs_pwd = require("pandoc.system").get_working_directory() 7 | local stringify = require("pandoc.utils").stringify 8 | 9 | --local pretty = require("pl.pretty") 10 | 11 | local debug = require("pandocker.utils").debug 12 | local file_exists = require("pandocker.utils").file_exists 13 | 14 | local util_get_meta = require("pandocker.utils").util_get_meta 15 | local platform = require("pandocker.utils").get_os() 16 | local base = require("pandocker.utils").package_base_path() 17 | 18 | local META_KEY = "svgbob" 19 | local meta = {} 20 | 21 | local default_meta = require("pandocker.default_loader")[META_KEY] 22 | assert(default_meta) 23 | 24 | local MESSAGE = "[ lua ] convert svgbob to svg/%s.svg" 25 | local BYPASS = "[ lua ] Skipping conversion as target 'svg/%s.svg' exists" 26 | local NOT_FOUND = "[ lua ] %s: file not found" 27 | local SVGBOB = "%s/bin/%s" 28 | 29 | local function get_meta(mt) 30 | meta = util_get_meta(mt, default_meta, META_KEY) 31 | --debug(stringify(meta)) 32 | end 33 | 34 | function Link(el) 35 | if el.classes:includes(META_KEY) then 36 | if tostring(PANDOC_VERSION) == "2.15" then 37 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 38 | return 39 | end 40 | --debug("Link in " .. META_KEY .. " class") 41 | if stringify(el.content) == "" then 42 | el.content = el.target 43 | end 44 | local idn = el.identifier 45 | 46 | -- remove svgbob classe 47 | local classes = {} 48 | for i, v in ipairs(el.classes) do 49 | if v ~= "svgbob" then 50 | table.insert(classes, v) 51 | end 52 | end 53 | 54 | -- main block 55 | local source_file = stringify(el.target) 56 | local source_ext = source_file:match('.*%.(.*)') 57 | if file_exists(source_file) then 58 | -- reads file contents as string anyway; assuming input a JSON file 59 | 60 | local attr = pandoc.Attr(idn, classes, el.attributes) 61 | local content = io.open(source_file, "rb"):read("a") 62 | local hash = pandoc.utils.sha1(content) 63 | local fullpath = string.format("%s/svg/%s.svg", abs_pwd, hash) 64 | 65 | if not file_exists(fullpath) then 66 | local font_family = '"' .. stringify(meta["font-family"]) .. '"' 67 | local font_size = stringify(meta["font-size"]) 68 | local scale = stringify(meta["scale"]) 69 | local stroke_width = stringify(meta["stroke-width"]) 70 | local svgbob = "svgbob" 71 | if string.find(platform, "Linux") then 72 | svgbob = string.format(SVGBOB, base, "pandocker/svgbob") 73 | elseif string.find(platform, "Darwin") then 74 | svgbob = string.format(SVGBOB, base, "pandocker/svgbob.bin") 75 | else 76 | svgbob = string.format(SVGBOB, base, "pandocker/svgbob.exe") 77 | end 78 | pandoc.pipe(svgbob, { source_file, 79 | "--font-family", font_family, 80 | "--font-size", font_size, 81 | "--scale", scale, 82 | "--stroke-width", stroke_width, 83 | "-o", fullpath }, "") 84 | debug(string.format(MESSAGE, hash)) 85 | else 86 | debug(string.format(BYPASS, hash)) 87 | end 88 | local img = pandoc.Image(el.content, fullpath, "fig:", attr) 89 | --pretty.dump(img) 90 | return img 91 | else 92 | debug(string.format(NOT_FOUND, source_file)) 93 | end 94 | end 95 | end 96 | 97 | return { { Meta = get_meta }, { Link = Link } } 98 | -------------------------------------------------------------------------------- /lua/svgconvert.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # svgconvert.lua 3 | 4 | 5 | # Note 6 | | Image (alt, src[, title[, attr] ]) 7 | | ![alt](src){.class-1 .class-2 attr=alpha attr=beta #fig:figure} 8 | | | | | k v k v | | 9 | | | classes | | attributes | | identifier 10 | | | (preserve) | | (preserve) | | (preserve) 11 | ]] 12 | 13 | PANDOC_VERSION:must_be_at_least '2.8' 14 | 15 | local stringify = require("pandoc.utils").stringify 16 | local get_current_directory = require("pandoc.system").get_working_directory 17 | 18 | local debug = require("pandocker.utils").debug 19 | local file_exists = require("pandocker.utils").file_exists 20 | 21 | local MESSAGE = "[ lua ] convert a svg file to svg/%s.%s" 22 | local BYPASS = "[ lua ] Skipping conversion as target 'svg/%s.%s' exists" 23 | local ERROR_MESSAGE = "[ lua ] %s: file not found" 24 | 25 | local get_ext = { 26 | ["html"] = "svg", 27 | ["html5"] = "svg", 28 | ["latex"] = "pdf", 29 | ["docx"] = "png", 30 | } 31 | 32 | function convert_from_svg(el) 33 | --for k, v in pairs(el) do 34 | -- print(stringify(k), stringify(v)) 35 | --end 36 | local ext = get_ext[FORMAT] or "png" 37 | local source_file = stringify(el.src) 38 | --debug(source_file) 39 | local source_base, source_ext = source_file:match('(.*)%.(.*)') 40 | if ext ~= "svg" and source_ext == "svg" then 41 | if file_exists(source_file) then 42 | local _, basename = require("pandocker.utils").basename(source_base) 43 | local abspath = get_current_directory() 44 | local fullpath = string.format("%s/svg/%s.%s", abspath, basename, ext) 45 | if not file_exists(fullpath) then 46 | pandoc.pipe("rsvg-convert", { source_file, "-f", ext, "-o", fullpath }, "") 47 | debug(string.format(MESSAGE, basename, ext)) 48 | else 49 | debug(string.format(BYPASS, basename, ext)) 50 | end 51 | el.src = fullpath 52 | --debug(abspath, path, source_file, basename, ext, fullpath) 53 | return el 54 | else 55 | debug(string.format(ERROR_MESSAGE, source_file)) 56 | end 57 | end 58 | end 59 | 60 | return { { Image = convert_from_svg } } 61 | -------------------------------------------------------------------------------- /lua/table-width-simple.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # table-width.lua 3 | 4 | Applies table attributes to a table inside a Div 5 | 6 | ## Syntax 7 | 8 | :::{.table width=[w1,w2,...] noheader=true|false} 9 | 10 | : Caption {#tbl:table} 11 | 12 | | Header | Row | Table | 13 | |:----------|:-----:|------:| 14 | | Cell | Cell | Cell | 15 | 16 | ::: 17 | 18 | where, 19 | 20 | - w1,w2,... : width value for each column. if not fully given padded by 21 | (1 - (sum of given widths)) / (number of unnumbered columns) 22 | e.g. When [0.5] is given for 4-column table, the first column will have 0.5 and the rest will have 0.16667 each 23 | of page width (i.e. (1 - 0.5) / 3) 24 | - noheader: flag if header row exists. `true` to move header row to head of body rows. 25 | Default is `false`. When table has only one blank row, header row overrides body row so that 26 | table has single row without header row. 27 | 28 | try: 29 | $ pandoc -t native -L lua/table-width.lua 30 | :::{.table width=[0.5] noheader=true} 31 | : Test1 32 | 33 | | Header | 34 | |:----------| 35 | | Cell | 36 | ::: 37 | 38 | :::{.table width=[0.5] noheader=true} 39 | : Test2 40 | 41 | | Cell | Cell | 42 | |:----------|----------:| 43 | | | | 44 | ::: 45 | 46 | :::{.table } 47 | | head | head2 | 48 | |----|----| 49 | |cell|cell| 50 | ::: 51 | 52 | 53 | :::{.table } 54 | |head| 55 | |----| 56 | | | 57 | ::: 58 | ]] 59 | 60 | --local stringify = require("pandoc.utils").stringify 61 | 62 | local pretty = require("pl.pretty") 63 | local seq = require("pl.seq") 64 | local tablex = require("pl.tablex") 65 | local List = require("pl.List") 66 | require("pl.stringx").import() 67 | 68 | local debug = require("pandocker.utils").debug 69 | local get_tf = require("pandocker.utils").get_tf 70 | 71 | local MESSAGE = "[ lua ] Div in 'table' class found" 72 | local NOHEADER_MESSAGE = "[ lua ] Move header row to body rows" 73 | local WIDTH_MESSAGE = "[ lua ] Adjust column ratio" 74 | local empty_attr = { "", {}, {} } 75 | local empty_cell = { attr = empty_attr, 76 | alignment = pandoc.AlignDefault, 77 | row_span = 1, 78 | col_span = 1, 79 | contents = {} } 80 | 81 | local function get_widths(attr) 82 | local widths = List() 83 | for num in string.gmatch(attr, "(%d+%.?%d*),?") do 84 | --debug(num) 85 | --[[ 86 | num = tonumber(num) 87 | if num == 0 and FORMAT == "docx" then 88 | num = 0.01 89 | end 90 | ]] 91 | widths:append(tonumber(num)) 92 | end 93 | --pretty.dump(widths) 94 | return widths 95 | end 96 | 97 | local function sum_content(row) 98 | local sum = 0 99 | -- Row is a list of Cell's 100 | --debug("simple_sum_content()") 101 | for _, cell in ipairs(row) do 102 | sum = sum + #cell 103 | end 104 | return sum 105 | end 106 | 107 | local function fill_widths(col_max, widths) 108 | if widths ~= nil then 109 | widths = get_widths(widths) 110 | debug(WIDTH_MESSAGE) 111 | else 112 | widths = {} 113 | end 114 | 115 | local rest = 1 - seq.sum(widths) 116 | local rest_columns_width = 0 117 | if rest <= 1 then 118 | rest_columns_width = rest / (col_max - #widths) 119 | end 120 | --debug(rest_columns_width) 121 | 122 | while col_max > #widths do 123 | if FORMAT == "docx" then 124 | table.insert(widths, 0.01) 125 | else 126 | table.insert(widths, rest_columns_width) 127 | end 128 | end 129 | --pretty.dump(widths) 130 | return widths 131 | end 132 | 133 | local function merge_colspecs(colspecs, widths) 134 | for idx, _ in ipairs(widths) do 135 | table.insert(colspecs[idx], widths[idx]) 136 | end 137 | pretty.dump(table.colspecs) 138 | return colspecs 139 | end 140 | 141 | local function table_width(tbl, attr) 142 | debug(MESSAGE) 143 | --pretty.dump(el.attributes["width"]) 144 | local widths = attr["width"] 145 | local noheader = get_tf(attr["noheader"], false) 146 | 147 | local headers = tbl.headers 148 | local body = tbl.rows 149 | local col_max = #tbl.widths 150 | 151 | if noheader and headers ~= {} then 152 | debug(NOHEADER_MESSAGE) 153 | if #body == 1 and sum_content(body[1]) == 0 then 154 | -- valid header row + first body row is blank 155 | -- -> remove header row + first body row has ex-header row contents 156 | debug("[ lua ] header row overrides first body row && remove header row (pandoc < 2.10)") 157 | tbl.rows[1] = headers 158 | else 159 | -- valid header row + first body row is not blank 160 | -- -> remove header row + ex-header row stacks at top of body rows 161 | debug("[ lua ] header row is inserted at head of body rows (pandoc < 2.10)") 162 | table.insert(tbl.rows, 1, headers) 163 | end 164 | tbl.headers = {} 165 | end 166 | widths = fill_widths(col_max, widths) 167 | tbl.widths = widths 168 | 169 | --pretty.dump(widths) 170 | return tbl 171 | end 172 | 173 | local function table_finder(el) 174 | if el.classes:find("table") then 175 | if #el.content == 1 and el.content[1].tag == "Table" then 176 | table_width(el.content[1], el.attributes) 177 | end 178 | end 179 | end 180 | 181 | if PANDOC_VERSION < { 2, 10 } then 182 | return { { Div = table_finder } } 183 | end 184 | -------------------------------------------------------------------------------- /lua/table-width.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # table-width.lua 3 | 4 | Applies table attributes to a table inside a Div 5 | 6 | ## Syntax 7 | 8 | :::{.table width=[w1,w2,...] noheader=true|false} 9 | 10 | : Caption {#tbl:table} 11 | 12 | | Header | Row | Table | 13 | |:----------|:-----:|------:| 14 | | Cell | Cell | Cell | 15 | 16 | ::: 17 | 18 | where, 19 | 20 | - w1,w2,... : width value for each column. if not fully given padded by 21 | (1 - (sum of given widths)) / (number of unnumbered columns) 22 | e.g. When [0.5] is given for 4-column table, the first column will have 0.5 and the rest will have 0.16667 each 23 | of page width (i.e. (1 - 0.5) / 3) 24 | - noheader: flag if header row exists. `true` to move header row to head of body rows. 25 | Default is `false`. When table has only one blank row, header row overrides body row so that 26 | table has single row without header row. 27 | 28 | try: 29 | $ pandoc -t native -L lua/table-width.lua 30 | :::{.table width=[0.5] noheader=true} 31 | : Test1 32 | 33 | | Header | 34 | |:----------| 35 | | Cell | 36 | ::: 37 | 38 | :::{.table width=[0.5] noheader=true} 39 | : Test2 40 | 41 | | Cell | Cell | 42 | |:----------|----------:| 43 | | | | 44 | ::: 45 | 46 | :::{.table } 47 | | head | head2 | 48 | |----|----| 49 | |cell|cell| 50 | ::: 51 | 52 | 53 | :::{.table } 54 | |head| 55 | |----| 56 | | | 57 | ::: 58 | ]] 59 | 60 | --local stringify = require("pandoc.utils").stringify 61 | 62 | local pretty = require("pl.pretty") 63 | local seq = require("pl.seq") 64 | local tablex = require("pl.tablex") 65 | local List = require("pl.List") 66 | require("pl.stringx").import() 67 | 68 | local debug = require("pandocker.utils").debug 69 | local get_tf = require("pandocker.utils").get_tf 70 | 71 | local MESSAGE = "[ lua ] Div in 'table' class found" 72 | local NOHEADER_MESSAGE = "[ lua ] Move header row to body rows" 73 | local WIDTH_MESSAGE = "[ lua ] Adjust column ratio" 74 | local empty_attr = { "", {}, {} } 75 | local empty_cell = { attr = empty_attr, 76 | alignment = pandoc.AlignDefault, 77 | row_span = 1, 78 | col_span = 1, 79 | contents = {} } 80 | 81 | local function get_widths(attr) 82 | local widths = List() 83 | for num in string.gmatch(attr, "(%d+%.?%d*),?") do 84 | --debug(num) 85 | num = tonumber(num) 86 | if num == 0 and FORMAT == "docx" then 87 | num = 0.01 88 | end 89 | widths:append(tonumber(num)) 90 | end 91 | --pretty.dump(widths) 92 | return widths 93 | end 94 | 95 | local function sum_content(row) 96 | local sum = 0 97 | local cells = 0 98 | if tablex.find(tablex.keys(row), "cells") ~= nil then 99 | cells = row.cells -- pandoc >= 2.17 100 | else 101 | cells = row[2] -- 2.10 <= pandoc < 2.17 102 | end 103 | --pretty.dump(el) 104 | --row _should_ be a list of cells but: 105 | --when whole row is blank cells, __row is a nil__ 106 | if row ~= nil then 107 | for _, cell in ipairs(cells) do 108 | --debug(tostring(tablex.deepcompare(empty_cell, cell))) 109 | if not tablex.deepcompare(empty_cell, cell) then 110 | --pretty.dump(cell) 111 | sum = sum + 1 112 | end 113 | end 114 | end 115 | return sum 116 | end 117 | 118 | local function fill_widths(col_max, widths) 119 | if widths ~= nil then 120 | widths = get_widths(widths) 121 | debug(WIDTH_MESSAGE) 122 | else 123 | widths = {} 124 | end 125 | 126 | local rest = 1 - seq.sum(widths) 127 | local rest_columns_width = 0 128 | if 0 < rest and rest <= 1 then 129 | rest_columns_width = rest / (col_max - #widths) 130 | else 131 | debug("[ Lua ] Sum of width exceeds page width") 132 | end 133 | --debug(rest_columns_width) 134 | 135 | while col_max > #widths do 136 | table.insert(widths, rest_columns_width) 137 | end 138 | --pretty.dump(widths) 139 | return widths 140 | end 141 | 142 | local function merge_colspecs(colspecs, widths) 143 | for idx, _ in ipairs(widths) do 144 | if #colspecs[idx] == 1 then 145 | table.insert(colspecs[idx], widths[idx]) 146 | else 147 | colspecs[idx][2] = widths[idx] 148 | end 149 | end 150 | --pretty.dump(colspecs) 151 | return colspecs 152 | end 153 | 154 | local function table_width(tbl) 155 | debug(MESSAGE) 156 | --pretty.dump(tbl.attributes.width) 157 | local widths = tbl.attributes.width 158 | local noheader = get_tf(tbl.attributes.noheader, false) 159 | local empty_row = { empty_attr, {} } 160 | 161 | --debug("tbl.attributes." .. tostring(tablex.keys(tbl.attributes))) 162 | --debug("tbl.head." .. tostring(tablex.keys(tbl.head))) 163 | --debug("tbl.bodies[1]." .. tostring(tablex.keys(tbl.bodies[1]))) 164 | 165 | --debug("tbl.head." .. tostring(tablex.keys(tbl.head))) 166 | local headers = nil 167 | if tablex.find(tablex.keys(tbl.head), "rows") ~= nil then 168 | headers = tbl.head.rows -- pandoc >= 2.17 169 | else 170 | headers = tbl.head[2] -- pandoc < 2.17 171 | end 172 | 173 | local body = tbl.bodies[1].body 174 | local col_max = #tbl.colspecs 175 | --pretty.dump(body) 176 | 177 | for _, v in ipairs(tablex.range(1, col_max)) do 178 | table.insert(empty_row[2], empty_cell) 179 | end 180 | 181 | if noheader and headers ~= {} then 182 | debug(NOHEADER_MESSAGE) 183 | --debug(#body) 184 | --debug(sum_content(body[1])) 185 | -- valid header row + first body row is blank 186 | if #body == 1 and sum_content(body[1]) == 0 then 187 | debug("[ lua ] header row overrides first body row && remove header row (pandoc >= 2.10)") 188 | tbl.bodies[1].body = headers 189 | else 190 | debug("[ lua ] header row is inserted at head of body rows (pandoc >= 2.10)") 191 | --pretty.dump(tbl.bodies[1].body) 192 | --pretty.dump(headers) 193 | table.insert(tbl.bodies[1].body, 1, headers[1]) 194 | end 195 | tbl.head = pandoc.TableHead({ }) 196 | end 197 | widths = fill_widths(col_max, widths) 198 | tbl.colspecs = merge_colspecs(tbl.colspecs, widths) 199 | --pretty.dump(tbl.colspecs) 200 | --pretty.dump(widths) 201 | return tbl 202 | end 203 | 204 | local function give_attribute_to_table(el) 205 | if el.classes:find("table") then 206 | if #el.content == 1 and el.content[1].tag == "Table" then 207 | el.content[1].attr = el.attr 208 | return { el.content[1] } 209 | end 210 | end 211 | end 212 | 213 | local function table_finder(el) 214 | if el.classes:find("table") then 215 | return { table_width(el) } 216 | end 217 | end 218 | 219 | if PANDOC_VERSION >= { 2, 10 } then 220 | return { { Div = give_attribute_to_table }, { Table = table_finder } } 221 | end 222 | -------------------------------------------------------------------------------- /lua/tex-landscape.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # tex-landscape.lua 3 | 4 | Finds `LANDSCAPE` class Div and inserts LaTeX RawBlock-s 5 | which sets contents of Div in landscape geometry. 6 | 7 | ## Syntax 8 | 9 | ```markdown 10 | ::: LANDSCAPE ::: 11 | # #include "section1.md" 12 | ::::::::::::::::: 13 | ``` 14 | ]] 15 | 16 | local stringify = require("pandoc.utils").stringify 17 | 18 | local debug = require("pandocker.utils").debug 19 | local default_meta = require("pandocker.default_loader")["lgeometry"] 20 | assert(default_meta ~= nil) 21 | 22 | local NOT_FOUND = "[ lua ] metadata '%s' was not found in source, applying default %s." 23 | local MESSAGE = "[ lua ] Div in 'LANDSCAPE' class found" 24 | 25 | local meta = {} 26 | local start_landscape = "" 27 | local stop_landscape = pandoc.RawBlock("latex", "\\end{landscape}\\restoregeometry") 28 | 29 | local function dump(tt, mm) 30 | for ii, vv in ipairs(tt) do 31 | print(mm .. ii .. " " .. tostring(vv["tag"]) .. "(" .. stringify(vv) .. ")") 32 | end 33 | end 34 | 35 | local function get_vars (mt) 36 | meta = mt["lgeometry"] 37 | if meta == nil then 38 | meta = default_meta 39 | debug(string.format(NOT_FOUND, "lgeometry", "")) 40 | end 41 | start_landscape = pandoc.RawBlock("latex", "\\newgeometry{" .. stringify(meta) .. "}\\begin{landscape}") 42 | end 43 | 44 | local function landscape(el) 45 | if el.classes:find("LANDSCAPE") then 46 | debug(MESSAGE) 47 | if FORMAT == "latex" then 48 | table.insert(el.content, 1, start_landscape) 49 | table.insert(el.content, stop_landscape) 50 | end 51 | return el.content 52 | end 53 | end 54 | 55 | return { { Meta = get_vars }, { Div = landscape } } 56 | -------------------------------------------------------------------------------- /lua/tex-quote.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | tex-quote.lua 3 | ]] 4 | 5 | local debug = require("pandocker.utils").debug 6 | 7 | local begin_env = pandoc.Para(pandoc.RawInline("latex", "\\begin{mdframed}[skipabove=3pt,hidealllines=true,leftline=true,linewidth=2pt]")) 8 | local end_env = pandoc.Para(pandoc.RawInline("latex", "\\end{mdframed}")) 9 | 10 | if FORMAT == "latex" then 11 | function BlockQuote(el) 12 | debug("[ lua ] BlockQuote found") 13 | --debug(pandoc.utils.stringify(el)) 14 | table.insert(el.content, 1, begin_env) 15 | table.insert(el.content, #el.content + 1, end_env) 16 | 17 | return pandoc.Div(el.content) 18 | end 19 | return { { BlockQuote = BlockQuote } } 20 | end 21 | -------------------------------------------------------------------------------- /lua/tex-remove-sout.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # tex-remove-sout.lua 3 | 4 | Removes Strikeout when tex output 5 | ]] 6 | 7 | local debug = require("pandocker.utils").debug 8 | local stringify = require("pandoc.utils").stringify 9 | 10 | if FORMAT == "latex" then 11 | function Strikeout(el) 12 | debug("[ lua ] strikeout span '" .. stringify(el.content) .. "' found and removed") 13 | return {} 14 | end 15 | return { { Strikeout = Strikeout } } 16 | end 17 | -------------------------------------------------------------------------------- /lua/tex-rowcolors-reset.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # tex-rowcolors-reset.lua 3 | 4 | Finds table and inserts tex command to reset row rule 5 | ]] 6 | 7 | local stringify = require("pandoc.utils").stringify 8 | 9 | local debug = require("pandocker.utils").debug 10 | local default_meta = require("pandocker.default_loader")["tex-rowcolors"] 11 | assert(default_meta) 12 | 13 | local METADATA_NOT_FOUND = "[ lua ] metadata '%s' was not found in source, applying default." 14 | 15 | local meta = {} 16 | local reset_colors = {} 17 | 18 | local function dump(tt, mm) 19 | for ii, vv in ipairs(tt) do 20 | print(mm .. ii .. " " .. tostring(vv["tag"]) .. "(" .. stringify(vv) .. ")") 21 | end 22 | end 23 | 24 | if FORMAT == "latex" then 25 | local function get_vars (mt) 26 | meta = mt["tex-rowcolors"] 27 | if meta == nil then 28 | meta = default_meta 29 | debug(string.format(METADATA_NOT_FOUND, "tex-rowcolors", "")) 30 | end 31 | reset_colors = pandoc.RawBlock("latex", stringify(meta)) 32 | end 33 | 34 | local function reset_table_color(el) 35 | return { reset_colors, el } 36 | end 37 | 38 | return { { Meta = get_vars }, { Table = reset_table_color } } 39 | end 40 | -------------------------------------------------------------------------------- /lua/tex-underline.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # tex-underline.lua 3 | 4 | Finds underline class span and convert it to \underline{} 5 | ]] 6 | 7 | --local debug = require("pandocker.utils").debug 8 | 9 | if FORMAT == "latex" then 10 | function Span(el) 11 | if el.classes[1] == "underline" then 12 | table.insert(el.content, 1, pandoc.RawInline("latex", "\\underline{")) 13 | table.insert(el.content, pandoc.RawInline("latex", "}")) 14 | end 15 | return el 16 | end 17 | return { { Span = Span } } 18 | end 19 | -------------------------------------------------------------------------------- /lua/utils.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # utils.lua 3 | 4 | Utility functions 5 | ]] 6 | 7 | local tablex = require("pl.tablex") 8 | 9 | local function debug(string) 10 | io.stderr:write(string .. "\n") 11 | end 12 | 13 | local function basename(path) 14 | --[[ 15 | INSPIRED FROM https://stackoverflow.com/a/17387077/6592473?stw=2 16 | split `path` into pwd and file 17 | 18 | | path | pwd | file | 19 | |---------------------------------------------------| 20 | | /path | / | path | 21 | | /path/to/file | /path/to/ | file | 22 | | /path/to/file/ | /path/to/file/ | nil | 23 | | /path/to/file.txt | /path/to/ | file.txt | 24 | ]] 25 | 26 | return path:match('(.*/)(.*)') 27 | end 28 | 29 | -- Return true if file exists and is readable. 30 | -- from http://lua-users.org/wiki/FileInputOutput 31 | local function file_exists(path) 32 | local file = io.open(path, "rb") 33 | if file then 34 | file:close() 35 | end 36 | return file ~= nil 37 | end 38 | 39 | local function get_tf(item, default) 40 | if type(item) == "string" then 41 | item = string.upper(item) 42 | if tablex.search({ "TRUE", "YES" }, item) then 43 | return true 44 | else 45 | return false 46 | end 47 | else 48 | return default 49 | end 50 | end 51 | 52 | -- requires global definition of `default_meta` and `meta_key` 53 | local function get_meta(doc_meta, default_meta, meta_key) 54 | local NOT_FOUND = "[ lua ] metadata '%s' was not found in source, applying default %s." 55 | 56 | meta = doc_meta[meta_key] 57 | if meta ~= nil then 58 | for k, v in pairs(default_meta) do 59 | if meta[k] == nil then 60 | meta[k] = v 61 | local d = pandoc.utils.stringify(doc_meta[meta_key][k]) 62 | debug(string.format(NOT_FOUND, meta_key .. "." .. k, d)) 63 | end 64 | end 65 | else 66 | meta = default_meta 67 | debug(string.format(NOT_FOUND, meta_key, "")) 68 | end 69 | --pretty.dump(meta) 70 | return meta 71 | end 72 | 73 | -- 74 | --[[ What operating system? 75 | Lua has only a small library of built in functions - often 76 | you have to pull in a library from another source, or write 77 | your own. 78 | 79 | Here is the start of a piece of code to identify operating 80 | system information (such as which OS you're running on. 81 | ]] 82 | 83 | local function getos() 84 | 85 | -- Unix, Linux varients 86 | fh, err = io.popen("uname -o 2>/dev/null", "r") 87 | if fh then 88 | osname = fh:read() 89 | end 90 | if osname then 91 | return osname 92 | end 93 | 94 | -- Add code for other operating systems here 95 | return "unknown" 96 | end 97 | 98 | local function package_base_path() 99 | local PACKAGE_BASE_PATH = "pip3 show pandocker-lua-filters | grep Location | cut -c11- | rev | cut -d/ -f4- | rev" 100 | local fh, err = io.popen(PACKAGE_BASE_PATH, "r") 101 | local base = "" 102 | if fh then 103 | base = fh:read() 104 | else 105 | base = "/" 106 | end 107 | return base 108 | end 109 | 110 | return { 111 | basename = basename, 112 | debug = debug, 113 | file_exists = file_exists, 114 | get_os = getos, 115 | get_tf = get_tf, 116 | util_get_meta = get_meta, 117 | package_base_path = package_base_path, 118 | } 119 | -------------------------------------------------------------------------------- /lua/wavedrom.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | # wavedrom.lua 3 | 4 | # Note 5 | | Link (content, target[, title[, attr] ]) 6 | | [content](target){.class-1 .class-2 attr=alpha attr=beta #lst:list} 7 | | | | | k v k v | | 8 | | | classes | | attributes | identifier 9 | | .listingtable type=plain numbers=left from=5 to=10 10 | | 11 | | Image (alt, src[, title[, attr] ]) 12 | | ![alt](src){.class-1 .class-2 attr=alpha attr=beta #fig:figure} 13 | | | | | k v k v | | 14 | | | classes | | attributes | | identifier 15 | | | (preserve) | | (preserve) | | (preserve) 16 | 17 | ]] 18 | PANDOC_VERSION:must_be_at_least '2.8' 19 | 20 | local yaml = require("lyaml") 21 | local json = require("cjson") 22 | 23 | local abs_pwd = require("pandoc.system").get_working_directory() 24 | local stringify = require("pandoc.utils").stringify 25 | 26 | --local pretty = require("pl.pretty") 27 | 28 | local debug = require("pandocker.utils").debug 29 | local file_exists = require("pandocker.utils").file_exists 30 | 31 | local INVALID_FILETYPE = "[ lua ] %s: invalid file format for wavedrom. must be JSON" -- or YAML 32 | local MESSAGE = "[ lua ] convert wavedrom to svg/%s.svg" 33 | local BYPASS = "[ lua ] Skipping conversion as target 'svg/%s.svg' exists" 34 | local NOT_FOUND = "[ lua ] %s: file not found" 35 | 36 | function Link(el) 37 | if el.classes:includes "wavedrom" or el.classes:includes "bitfield" then 38 | if tostring(PANDOC_VERSION) == "2.15" then 39 | debug("[ Lua ] " .. PANDOC_SCRIPT_FILE .. ": Pandoc version 2.15 is not supported. Bypassing.") 40 | return 41 | end 42 | --debug("Link in 'wavedrom' class") 43 | if stringify(el.content) == "" then 44 | el.content = el.target 45 | end 46 | local idn = el.identifier 47 | 48 | -- remove "wavedrom" and "bitfield" classes 49 | local classes = {} 50 | for i, v in ipairs(el.classes) do 51 | if v ~= "wavedrom" and v ~= "bitfield" then 52 | table.insert(classes, v) 53 | end 54 | end 55 | 56 | -- main block 57 | local source_file = stringify(el.target) 58 | local source_ext = source_file:match('.*%.(.*)') 59 | if file_exists(source_file) then 60 | -- reads file contents as string anyway; assuming input a JSON file 61 | local data = io.open(source_file, "r"):read("*a") 62 | if source_ext == "yaml" then 63 | -- if extension is YAML: convert to JSON string 64 | data = json.encode(yaml.load(data)) 65 | --debug(json.encode(yaml.load(data))) 66 | elseif source_ext ~= "json" then 67 | -- prints error message if extension is not YAML nor JSON 68 | debug(string.format(INVALID_FILETYPE, source_file)) 69 | return 70 | end 71 | 72 | local attr = pandoc.Attr(idn, classes, el.attributes) 73 | local content = io.open(source_file, "rb"):read("a") 74 | local hash = pandoc.utils.sha1(content) 75 | local fullpath = string.format("%s/svg/%s.svg", abs_pwd, hash) 76 | 77 | -- pipes JSON string to wavedrom-cli; equivalent to `echo | wavedrom-cli -i - -s ` 78 | if not file_exists(fullpath) then 79 | pandoc.pipe("wavedrom-cli", { "-i", "-", "-s", fullpath }, data) 80 | debug(string.format(MESSAGE, hash)) 81 | else 82 | debug(string.format(BYPASS, hash)) 83 | end 84 | local img = pandoc.Image(el.content, fullpath, "fig:", attr) 85 | --pretty.dump(img) 86 | return img 87 | else 88 | debug(string.format(NOT_FOUND, source_file)) 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /pandocker_lua_filters/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | MIT License 4 | 5 | Copyright (c) 2020 Kazuki Yamamoto 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | """ 25 | 26 | import argparse 27 | import platform 28 | from .version import version 29 | 30 | 31 | def main(): 32 | parser = argparse.ArgumentParser(description="") 33 | parser.add_argument('--version', action='version', version=str(version)) 34 | args = parser.parse_args() 35 | 36 | 37 | def get_platform(): 38 | pf = platform.platform() 39 | if pf.startswith("Windows"): 40 | print("Windows") 41 | elif pf.startswith("Darwin"): 42 | print("OSX") 43 | elif pf.startswith("Linux"): 44 | print("Linux") 45 | 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /scripts/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM joseluisq/rust-linux-darwin-builder 2 | 3 | RUN apt-get update 4 | RUN apt-get -y install gcc-mingw-w64 5 | RUN rustup update 6 | -------------------------------------------------------------------------------- /scripts/svgbob.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | sudo apt update 4 | sudo apt -y install gcc-mingw-w64 5 | rustup update 6 | 7 | rustup target add x86_64-unknown-linux-musl 8 | cargo install svgbob_cli --root=build/linux --target=x86_64-unknown-linux-musl 9 | mv build/linux/bin/svgbob_cli build/svgbob 10 | 11 | rustup target add x86_64-pc-windows-gnu 12 | cargo install svgbob_cli --root=build/windows --target=x86_64-pc-windows-gnu 13 | mv build/windows/bin/svgbob_cli.exe build/svgbob.exe 14 | 15 | rustup target add x86_64-apple-darwin 16 | cargo install svgbob_cli --root=build/osx --target=x86_64-apple-darwin 17 | mv build/osx/bin/svgbob_cli build/svgbob.bin 18 | 19 | ls build 20 | -------------------------------------------------------------------------------- /scripts/wavedrom.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | mkdir build 4 | cd build 5 | npm i wavedrom-cli nexe 6 | npx nexe --target linux-x64-10.16.0 -i ./node_modules/wavedrom-cli/wavedrom-cli.js -o /root/build/wavedrom-cli 7 | npx nexe --target windows-x64-10.16.0 -i ./node_modules/wavedrom-cli/wavedrom-cli.js -o /root/build/wavedrom-cli.exe 8 | npx nexe --target mac-x64-10.16.0 -i ./node_modules/wavedrom-cli/wavedrom-cli.js -o /root/build/wavedrom-cli.bin 9 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://packaging.python.org/en/latest/distributing.html 5 | https://github.com/pypa/sampleproject 6 | """ 7 | 8 | # Always prefer setuptools over distutils 9 | from setuptools import setup, find_packages 10 | from os import path 11 | # io.open is needed for projects that support Python 2.7 12 | # It ensures open() defaults to text mode with universal newlines, 13 | # and accepts an argument to specify the text encoding 14 | # Python 3 only projects can skip this import 15 | from io import open 16 | 17 | here = path.abspath(path.dirname(__file__)) 18 | 19 | list_of_filters = ["lua/aafigure.lua", 20 | "lua/csv2table.lua", 21 | "lua/csv2table-simple.lua", 22 | "lua/default_loader.lua", 23 | "lua/docx-appendixheadings.lua", 24 | "lua/docx-apply-cell-styles.lua", 25 | "lua/docx-comment.lua", 26 | "lua/docx-colored-span.lua", 27 | "lua/docx-custom-span-styles.lua", 28 | "lua/docx-extract-bullet-lists.lua", 29 | "lua/docx-image-styles.lua", 30 | "lua/docx-pagebreak-toc.lua", 31 | "lua/docx-unnumberedheadings.lua", 32 | "lua/hide-frontpage-metadata.lua", 33 | "lua/listingtable.lua", 34 | "lua/preprocess.lua", 35 | "lua/removable-note.lua", 36 | "lua/svgbob.lua", 37 | "lua/svgconvert.lua", 38 | "lua/table-width.lua", 39 | "lua/table-width-simple.lua", 40 | "lua/tex-landscape.lua", 41 | "lua/tex-quote.lua", 42 | "lua/tex-remove-sout.lua", 43 | "lua/tex-rowcolors-reset.lua", 44 | "lua/utils.lua", 45 | "lua/wavedrom.lua", 46 | 47 | "lua/metadata-file.yaml", 48 | ] 49 | # Get the long description from the README file 50 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 51 | long_description = f.read() 52 | 53 | # Arguments marked as "Required" below must be included for upload to PyPI. 54 | # Fields marked as "Optional" may be commented out. 55 | 56 | setup( 57 | # This is the name of your project. The first time you publish this 58 | # package, this name will be registered for you. It will determine how 59 | # users can install this project, e.g.: 60 | # 61 | # $ pip install sampleproject 62 | # 63 | # And where it will live on PyPI: https://pypi.org/project/sampleproject/ 64 | # 65 | # There are some restrictions on what makes a valid project name 66 | # specification here: 67 | # https://packaging.python.org/specifications/core-metadata/#name 68 | name='pandocker-lua-filters', # Required 69 | 70 | # Versions should comply with PEP 440: 71 | # https://www.python.org/dev/peps/pep-0440/ 72 | # 73 | # For a discussion on single-sourcing the version across setup.py and the 74 | # project code, see 75 | # https://packaging.python.org/en/latest/single_source_version.html 76 | # version='1.2.0', # Required 77 | use_scm_version={ 78 | "relative_to": __file__, 79 | "write_to": "pandocker_lua_filters/version.py", 80 | }, 81 | setup_requires=['setuptools_scm'], 82 | 83 | # This is a one-line description or tagline of what your project does. This 84 | # corresponds to the "Summary" metadata field: 85 | # https://packaging.python.org/specifications/core-metadata/#summary 86 | description='Lua filter collection for pandoc', # Optional 87 | 88 | # This is an optional longer description of your project that represents 89 | # the body of text which users will see when they visit PyPI. 90 | # 91 | # Often, this is the same as your README, so you can just read it in from 92 | # that file directly (as we have already done above) 93 | # 94 | # This field corresponds to the "Description" metadata field: 95 | # https://packaging.python.org/specifications/core-metadata/#description-optional 96 | long_description=long_description, # Optional 97 | 98 | # Denotes that our long_description is in Markdown; valid values are 99 | # text/plain, text/x-rst, and text/markdown 100 | # 101 | # Optional if long_description is written in reStructuredText (rst) but 102 | # required for plain-text or Markdown; if unspecified, "applications should 103 | # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and 104 | # fall back to text/plain if it is not valid rst" (see link below) 105 | # 106 | # This field corresponds to the "Description-Content-Type" metadata field: 107 | # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional 108 | long_description_content_type='text/markdown', # Optional (see note above) 109 | 110 | # This should be a valid link to your project's main homepage. 111 | # 112 | # This field corresponds to the "Home-Page" metadata field: 113 | # https://packaging.python.org/specifications/core-metadata/#home-page-optional 114 | url='https://github.com/pandocker/pandocker-lua-filters', # Optional 115 | 116 | # This should be your name or the name of the organization which owns the 117 | # project. 118 | author='pandocker', # Optional 119 | 120 | # This should be a valid email address corresponding to the author listed 121 | # above. 122 | author_email='pandocker@github.com', # Optional 123 | 124 | # Classifiers help users find your project by categorizing it. 125 | # 126 | # For a list of valid classifiers, see https://pypi.org/classifiers/ 127 | classifiers=[ # Optional 128 | # How mature is this project? Common values are 129 | # 3 - Alpha 130 | # 4 - Beta 131 | # 5 - Production/Stable 132 | 'Development Status :: 3 - Alpha', 133 | 134 | # Indicate who your project is intended for 135 | 'Intended Audience :: Developers', 136 | 'Topic :: Software Development :: Build Tools', 137 | 138 | # Pick your license as you wish 139 | 'License :: OSI Approved :: MIT License', 140 | 141 | # Specify the Python versions you support here. In particular, ensure 142 | # that you indicate whether you support Python 2, Python 3 or both. 143 | 'Programming Language :: Python :: 3.5', 144 | 'Programming Language :: Python :: 3.6', 145 | 'Programming Language :: Python :: 3.7', 146 | ], 147 | 148 | # This field adds keywords for your project which will appear on the 149 | # project page. What does your project relate to? 150 | # 151 | # Note that this is a string of words separated by whitespace, not a list. 152 | keywords='Pandoc Lua Filter', # Optional 153 | 154 | # You can just specify package directories manually here if your project is 155 | # simple. Or you can use find_packages(). 156 | # 157 | # Alternatively, if you just want to distribute a single Python file, use 158 | # the `py_modules` argument instead as follows, which will expect a file 159 | # called `my_module.py` to exist: 160 | # 161 | # py_modules=["my_module"], 162 | # 163 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required 164 | 165 | # This field lists other packages that your project depends on to run. 166 | # Any package you put here will be installed by pip when your project is 167 | # installed, so they must be valid existing projects. 168 | # 169 | # For an analysis of "install_requires" vs pip's requirements files see: 170 | # https://packaging.python.org/en/latest/requirements.html 171 | install_requires=["aafigure"], # Optional 172 | 173 | # List additional groups of dependencies here (e.g. development 174 | # dependencies). Users will be able to install these using the "extras" 175 | # syntax, for example: 176 | # 177 | # $ pip install sampleproject[dev] 178 | # 179 | # Similar to `install_requires` above, these must be valid existing 180 | # projects. 181 | # extras_require={ # Optional 182 | # 'dev': ['check-manifest'], 183 | # 'test': ['coverage'], 184 | # }, 185 | 186 | # If there are data files included in your packages that need to be 187 | # installed, specify them here. 188 | # 189 | # If using Python 2.6 or earlier, then these have to be included in 190 | # MANIFEST.in as well. 191 | # package_data={ # Optional 192 | # 'sample': ['package_data.dat'], 193 | # }, 194 | 195 | # Although 'package_data' is the preferred approach, in some case you may 196 | # need to place data files outside of your packages. See: 197 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files 198 | # 199 | # In this case, 'data_file' will be installed into '/my_data' 200 | data_files=[('share/lua/5.3/pandocker', list_of_filters), 201 | ('share/lua/5.4/pandocker', list_of_filters), 202 | ('bin/pandocker', ['build/svgbob', 203 | 'build/svgbob.bin', 204 | 'build/svgbob.exe', 205 | ]), 206 | ], # Optional 207 | 208 | # To provide executable scripts, use entry points in preference to the 209 | # "scripts" keyword. Entry points provide cross-platform support and allow 210 | # `pip` to create the appropriate form of executable for the target 211 | # platform. 212 | # 213 | # For example, the following would provide a command called `sample` which 214 | # executes the function `main` from this package when invoked: 215 | entry_points={ # Optional 216 | 'console_scripts': [ 217 | 'pandocker-lua-filters=pandocker_lua_filters:main', 218 | 'get-platform=pandocker_lua_filters:get_platform', 219 | ], 220 | }, 221 | 222 | # List additional URLs that are relevant to your project as a dict. 223 | # 224 | # This field corresponds to the "Project-URL" metadata fields: 225 | # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use 226 | # 227 | # Examples listed include a pattern for specifying where the package tracks 228 | # issues, where the source is hosted, where to say thanks to the package 229 | # maintainers, and where to support the project financially. The key is 230 | # what's used to render the link text on PyPI. 231 | project_urls={ # Optional 232 | 'Bug Reports': 'https://github.com/pandocker/pandocker-lua-filters/issues', 233 | # 'Funding': 'https://donate.pypi.org', 234 | # 'Say Thanks!': 'http://saythanks.io/to/example', 235 | 'Source': 'https://github.com/pandocker/pandocker-lua-filters/', 236 | }, 237 | ) 238 | -------------------------------------------------------------------------------- /tests/.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: k4zuki/pandocker:lua-filter 6 | steps: 7 | - checkout 8 | - run: 9 | name: get submodule 10 | command: git submodule update --init 11 | - run: 12 | name: Prepare QR code for this build 13 | command: | 14 | make initdir 15 | pip3 install qrcode 16 | # qr https://github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/releases/download/build-`date +%b-%d-%Y`-`git rev-parse --short HEAD`/Pandocker-Docs-`git rev-parse --short HEAD`.pdf > images/QRcode.png 17 | - run: 18 | name: Make HTML 19 | command: make initdir html 20 | - run: 21 | name: Make PDF 22 | command: make initdir pdf 23 | 24 | - run: 25 | name: Deploy preparation 26 | command: | 27 | mkdir deploy 28 | mv tests/Out/*.html deploy/`basename tests/Out/*.html .html`-`git rev-parse --short HEAD`.html 29 | mv tests/Out/*.pdf deploy/`basename tests/Out/*.pdf .pdf`-`git rev-parse --short HEAD`.pdf 30 | - run: 31 | name: Deploy 32 | command: | 33 | ghr -replace -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME build-`date +%b-%d-%Y`-`git rev-parse --short HEAD` deploy/ 34 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | Out/ 3 | .DS_Store 4 | svg/ 5 | pd-images/ 6 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | HOME = C:/Users/$(USERNAME) 3 | endif 4 | PIPBASE= $(shell get-pip-base) 5 | PANSTYLES= $(PIPBASE)/var 6 | MISC= $(PANSTYLES)/pandoc_misc 7 | MISC_SYS = $(MISC)/system 8 | MISC_USER = $(MISC)/user 9 | include $(MISC_SYS)/Makefile.in 10 | PROJECT= `pwd` 11 | 12 | ## userland: uncomment and replace 13 | # MDDIR:= markdown 14 | # DATADIR:= data 15 | # TARGETDIR:= Out 16 | # IMAGEDIR:= images 17 | 18 | # CONFIG:= config.yaml 19 | # INPUT:= TITLE.md 20 | # TARGET:= TARGET-$(DATE)-$(HASH) 21 | # REVERSE_INPUT:= reverse-input.docx 22 | #REFERENCE := $(DATADIR)/ref.docx 23 | #SYSTEM_DOCXFRONTPAGE := $(MDDIR)/frontpage.md 24 | # COREPROPFLAGS := --table "Normal Table=Centered" 25 | # COREPROPFLAGS += --paragraph "Normal=Body Text" 26 | ## 27 | LUA_FILTER_BASE = ../lua 28 | PANFLAGS := --read=markdown+east_asian_line_breaks 29 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/hide-frontpage-metadata.lua 30 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/aafigure.lua 31 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/removable-note.lua 32 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/tex-landscape.lua 33 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/preprocess.lua 34 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/docx-unnumberedheadings.lua 35 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/docx-pagebreak-toc.lua 36 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/csv2table.lua 37 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/csv2table-simple.lua 38 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/listingtable.lua 39 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/wavedrom.lua 40 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/svgbob.lua 41 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/tex-quote.lua 42 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/docx-colored-span.lua 43 | #PANFLAGS += --filter=pantable 44 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/table-width.lua 45 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/table-width-simple.lua 46 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/docx-apply-cell-styles.lua 47 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/docx-custom-span-styles.lua 48 | #PANFLAGS += --filter=pandocker-blockdiag-filters 49 | #PANFLAGS += --filter=pandoc-svgbob-filter 50 | PANFLAGS += --filter=pandoc-imagine 51 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/svgconvert.lua 52 | #PANFLAGS += --filter=pandocker-filters 53 | PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/docx-extract-bullet-lists.lua 54 | #PANFLAGS += --filter=pandoc-docx-extract-bullet-list 55 | #PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/tex-remove-sout.lua 56 | PANFLAGS += --filter=pandoc-crossref 57 | #PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/docx-image-styles.lua 58 | #PANFLAGS += --lua-filter=$(LUA_FILTER_BASE)/tex-rowcolors-reset.lua 59 | PANFLAGS += --listings 60 | PANFLAGS += --top-level-division=chapter 61 | PANFLAGS += --number-sections --highlight-style=kate 62 | PANFLAGS += -M short-hash=$(HASH) 63 | PANFLAGS += -M tables=true 64 | PANFLAGS += -M envversion=$(ENV_VERSION) 65 | #PFLAGS += $(PANFLAGS) 66 | #PANFLAGS = $(PFLAGS) 67 | 68 | include $(MISC_SYS)/Makefile 69 | 70 | native: $(TARGETDIR)/$(TARGET)-native.txt 71 | $(TARGETDIR)/$(TARGET)-native.txt: $(MDDIR)/$(INPUT) 72 | $(PANDOC) $(PANFLAGS) -M linkReferences=true \ 73 | $(MDDIR)/$(INPUT) -t native -o $(TARGETDIR)/$(TARGET)-native.txt 74 | -------------------------------------------------------------------------------- /tests/data/aafigure.txt: -------------------------------------------------------------------------------- 1 | A B 2 | AA BB 3 | AA BB 4 | 5 | ---- | ___ ~~~| 6 | | -- ___| | === 7 | ~~~ 8 | 9 | + 10 | | - + | - + | - + / - 11 | / / / / / / / / / / -- |/| / + 12 | | | | + + + - - - / / \ - \|/ |\ 13 | + + + +-+-+ | + 14 | | | | + + + - - - \ \ / - /|\ |/ 15 | \ \ \ \ \ \ \ \ \ \ -- |\| \ + 16 | | - + | - + | - + \ - 17 | + 18 | 19 | ---> | | | | | | 20 | ---< | | | | | | 21 | ---o ^ V v o O # 22 | ---O 23 | ---# 24 | -------------------------------------------------------------------------------- /tests/data/bit.yaml: -------------------------------------------------------------------------------- 1 | # list from LSB 2 | # bits: bit width 3 | # attr: information RO/WO/RW etc. 4 | # name: name of bitfield 5 | reg: 6 | - bits: 5 7 | - bits: 1 8 | attr: RW 9 | name: IPO 10 | - bits: 1 11 | attr: RW 12 | name: BRK 13 | - bits: 1 14 | name: CPK 15 | options: 16 | bits: 8 17 | fontfamily: "Source Code Pro" 18 | lanes: 1 19 | fontweight: "bold" 20 | -------------------------------------------------------------------------------- /tests/data/io_plan.csv: -------------------------------------------------------------------------------- 1 | POSITION;FUNCTION;PORT 2 | CLK tile[0, 0] clk_side=E Input0;LOGIC_AS_CLK0;i_lac0 3 | CLK tile[0, 0] clk_side=W Input0;OSC_CLK;i_clk 4 | IOB tile[0, 0] coord[ 0, 6] Output0;[PIN 13] GPIO0_OUT;o_row[1] 5 | IOB tile[0, 0] coord[ 0, 6] Output1;[PIN 13] GPIO0_OE;o_row_oe[1] 6 | IOB tile[0, 0] coord[ 0, 7] Output0;[PIN 14] GPIO1_OUT;o_row[3] 7 | IOB tile[0, 0] coord[ 0, 7] Output1;[PIN 14] GPIO1_OE;o_row_oe[3] 8 | IOB tile[0, 0] coord[ 0, 8] Output0;[PIN 15] GPIO2_OUT;o_row[5] 9 | IOB tile[0, 0] coord[ 0, 8] Output1;[PIN 15] GPIO2_OE;o_row_oe[5] 10 | IOB tile[0, 0] coord[ 0, 9] Output0;[PIN 16] GPIO3_OUT;o_row[7] 11 | IOB tile[0, 0] coord[ 0, 9] Output1;[PIN 16] GPIO3_OE;o_row_oe[7] 12 | IOB tile[0, 0] coord[ 0, 10] Output0;[PIN 17] GPIO4_OUT;o_row[0] 13 | IOB tile[0, 0] coord[ 0, 10] Output1;[PIN 17] GPIO4_OE;o_row_oe[0] 14 | IOB tile[0, 0] coord[ 0, 22] Output0;[PIN 18] GPIO5_OUT;o_row[2] 15 | IOB tile[0, 0] coord[ 0, 22] Output1;[PIN 18] GPIO5_OE;o_row_oe[2] 16 | IOB tile[0, 0] coord[ 0, 23] Output0;[PIN 19] GPIO6_OUT;o_row[4] 17 | IOB tile[0, 0] coord[ 0, 23] Output1;[PIN 19] GPIO6_OE;o_row_oe[4] 18 | IOB tile[0, 0] coord[ 0, 24] Output0;[PIN 20] GPIO7_OUT;o_row[6] 19 | IOB tile[0, 0] coord[ 0, 24] Output1;[PIN 20] GPIO7_OE;o_row_oe[6] 20 | IOB tile[0, 0] coord[ 0, 25] Output0;OSC_EN;osc_en 21 | IOB tile[0, 0] coord[31, 4] Output0;[PIN 9] GPIO18_OUT;testbus[2] 22 | IOB tile[0, 0] coord[31, 4] Output1;[PIN 9] GPIO18_OE;testbus_oe[2] 23 | IOB tile[0, 0] coord[31, 5] Output0;[PIN 8] GPIO17_OUT;testbus[1] 24 | IOB tile[0, 0] coord[31, 5] Output1;[PIN 8] GPIO17_OE;testbus_oe[1] 25 | IOB tile[0, 0] coord[31, 6] Output0;[PIN 7] GPIO16_OUT;testbus[0] 26 | IOB tile[0, 0] coord[31, 6] Output1;[PIN 7] GPIO16_OE;testbus_oe[0] 27 | IOB tile[0, 0] coord[31, 8] Output0;[PIN 6] GPIO15_OUT;o_col[1] 28 | IOB tile[0, 0] coord[31, 8] Output1;[PIN 6] GPIO15_OE;o_col_oe[1] 29 | IOB tile[0, 0] coord[31, 9] Output0;[PIN 5] GPIO14_OUT;o_col[3] 30 | IOB tile[0, 0] coord[31, 9] Output1;[PIN 5] GPIO14_OE;o_col_oe[3] 31 | IOB tile[0, 0] coord[31, 10] Input0;[PIN 11] nRST;i_nreset 32 | IOB tile[0, 0] coord[31, 11] Output0;REF_LOGIC_AS_CLK0;scan_clk_out 33 | IOB tile[0, 0] coord[31, 12] Output0;LOGIC_AS_CLK0_EN;scan_clk_oe 34 | IOB tile[0, 0] coord[31, 22] Output0;[PIN 4] GPIO13_OUT;o_col[5] 35 | IOB tile[0, 0] coord[31, 22] Output1;[PIN 4] GPIO13_OE;o_col_oe[5] 36 | IOB tile[0, 0] coord[31, 23] Output0;[PIN 3] GPIO12_OUT;o_col[7] 37 | IOB tile[0, 0] coord[31, 23] Output1;[PIN 3] GPIO12_OE;o_col_oe[7] 38 | IOB tile[0, 0] coord[31, 24] Output0;[PIN 2] GPIO11_OUT;o_col[0] 39 | IOB tile[0, 0] coord[31, 24] Output1;[PIN 2] GPIO11_OE;o_col_oe[0] 40 | IOB tile[0, 0] coord[31, 25] Output0;[PIN 1] GPIO10_OUT;o_col[2] 41 | IOB tile[0, 0] coord[31, 25] Output1;[PIN 1] GPIO10_OE;o_col_oe[2] 42 | IOB tile[0, 0] coord[31, 26] Output0;[PIN 24] GPIO9_OUT;o_col[4] 43 | IOB tile[0, 0] coord[31, 26] Output1;[PIN 24] GPIO9_OE;o_col_oe[4] 44 | IOB tile[0, 0] coord[31, 27] Output0;[PIN 23] GPIO8_OUT;o_col[6] 45 | IOB tile[0, 0] coord[31, 27] Output1;[PIN 23] GPIO8_OE;o_col_oe[6] 46 | -------------------------------------------------------------------------------- /tests/data/json.json: -------------------------------------------------------------------------------- 1 | { 2 | "reg": [ 3 | { 4 | "bits": 5, 5 | "attr": [ 6 | "001", 7 | "110" 8 | ] 9 | }, 10 | { 11 | "bits": 1, 12 | "attr": "RW", 13 | "name": "IPO" 14 | }, 15 | { 16 | "bits": 1, 17 | "attr": "RW", 18 | "name": "BRK" 19 | }, 20 | { 21 | "bits": 1, 22 | "name": "CPK" 23 | } 24 | ], 25 | "options": { 26 | "bits": 8, 27 | "fontfamily": "Source Code Pro", 28 | "lanes": 1, 29 | "fontweight": "bold" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/svgbob.bob: -------------------------------------------------------------------------------- 1 | "" 2 | +-----------+ 3 | |"svgbob" | 4 | +-----------+ 5 | "" 6 | -------------------------------------------------------------------------------- /tests/data/table.csv: -------------------------------------------------------------------------------- 1 | this,is,a table,"multi\ 2 | line\ 3 | title" 4 | to,show,an,example 5 | of,table,markdown,"importer\ 6 | of\ 7 | multiline" 8 | -------------------------------------------------------------------------------- /tests/images/bitfield.svg: -------------------------------------------------------------------------------- 1 | 2 | 04567IPOBRKCPKRWRW -------------------------------------------------------------------------------- /tests/images/dummy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandocker/pandocker-lua-filters/7cfef5806286494420d6861078d32d59799fa962/tests/images/dummy.png -------------------------------------------------------------------------------- /tests/markdown/TITLE.md: -------------------------------------------------------------------------------- 1 | \toc 2 | 3 | \newpage 4 | 5 | text

text 6 | text 7 | 8 | ::: {.table } 9 | 10 | | text
text | | 11 | |--------------|----| 12 | | | | 13 | | | | 14 | 15 | ::: 16 | 17 | :::{.table width=[0.5,0.3]} 18 | Table: table **width** {#tbl:table} 19 | 20 | | Table | Header | Row | 21 | |:------|:------:|-----:| 22 | | Cell | Cell | Cell | 23 | 24 | ::: 25 | 26 | [@fig:wavedrom-2] 27 | 28 | ::: {#fig:tiled-figures width=[0.5,0.5]} 29 | ::: {.table noheader=true} 30 | 31 | | [Wavedrom(BitField)](data/json.json){.wavedrom width=70mm #fig:wavedrom-1} | [AAFigure](data/aafigure.txt){.aafigure width=70mm #fig:wavedrom-2} | 32 | |:--------------------------------------------------------------------------:|:--------------------------------------------------------------------------:| 33 | | [svgbob](data/svgbob.bob){.svgbob width=70mm #fig:wavedrom-3} | [Wavedrom(BitField)](data/json.json){.wavedrom width=70mm #fig:wavedrom-4} | 34 | 35 | ::: 36 | 37 | Tiled figures
on a table 38 | 39 | ::: 40 | 41 | # #include "rest.rst" 42 | 43 | [CSV file with caption](data/table.csv){.table} 44 | 45 | [Alignment = DLCR](data/table.csv){.table alignment=DLCR width=[0.5]} 46 | 47 | [Subset table](data/table.csv){.table subset_from=(1,2)} 48 | 49 | [Set widths](data/table.csv){.table width=[0.2,0.3,0.2,0.3]} 50 | 51 | [CSV file with caption2](data/io_plan.csv){.table delimiter=";"} 52 | 53 | ##### Auto caption 54 | 55 | [](data/table.csv){.table width=[0.5]} 56 | 57 | ##### No caption 58 | 59 | [](data/table.csv){.table nocaption=true} 60 | 61 | [@tbl:table] 62 | 63 | ## Level2 64 | 65 | # Level1 unnumbered {-} 66 | 67 | # Level1 {.subsection-toc} 68 | 69 | ## Level2 unnumbered {-} 70 | 71 | ##### Level5 unnumbered {-} 72 | 73 | 74 | 75 | ::::::{custom-style="Heading Unnumbered 3"} 76 | Level3 *unnumbered* 77 | :::::: 78 | 79 | :::::{custom-style="Bullet List 1"} 80 | Bullet List 1 81 | 82 | :::{custom-style="Bullet List 2"} 83 | Bullet List 2 84 | ::: 85 | ::::: 86 | 87 | [red?]{.red} 88 | [green?]{.green} 89 | [blue?]{.blue} 90 | [foo?]{.default-paragraph-font} 91 | 92 | [[@lst:lst]]{.underline} 93 | 94 | > Lorem ipsum dolor sit amet, にほんご 95 | > 96 | > > consectetur adipiscing elit, sed do eiusmod 97 | > 98 | > tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 99 | > quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 100 | > Duis aute irure dolor in reprehenderit in voluptate velit esse cillum 101 | > dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, 102 | > sunt in culpa qui officia deserunt mollit anim id est laborum. 103 | 104 | [bit.yaml](data/bit.yaml){.bitfield} 105 | 106 | #### Level4 unnumbered {-} 107 | 108 | 109 | 110 | [Title](markdown/config.yaml){.listingtable from=2 to=5 #lst:lst} 111 | 112 | [Wavedrom(BitField)](data/tutorial_0.json){.wavedrom #fig:wavedrom} 113 | 114 | \newpage 115 | 116 | [](markdown/config.yaml){.listingtable type=yaml from=2 to=10 nocaption=true} 117 | 118 | ::: LANDSCAPE 119 | 120 | [](data/ditaa.puml){.listingtable type=puml #lst:ditaa-sample} 121 | 122 | [](data/ditaa.puml){.listingtable nocaption=true 123 | .plantuml #fig:ditaa-sample im_out="img" im_fmt='png' caption="PlantUML x ditaa x imagine"} 124 | 125 | ::: 126 | 127 | [This failes to list](markdown/config.yaml){.listingtable numbers=right type=yaml from=2 to=5 #lst:list} 128 | 129 | ![dummy](images/dummy.png) 130 | 131 | ::: LANDSCAPE ::: 132 | 133 | ##### Level5 134 | 135 | # #include "section2.md" 136 | 137 | ::: 138 | 139 | ~~Strikeout~~ ~~ごはんはおかず~~ 140 | -------------------------------------------------------------------------------- /tests/markdown/config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: 本のタイトル 3 | subtitle: 本の概要 4 | circle: サークル名 5 | author: 本の作者 6 | comiket: コミケ 7 | year: 出版年 8 | publisher: 印刷会社で印刷製本 9 | docrevision: "1.0" 10 | # front: images/front-image.png 11 | verbcolored: false 12 | # rmnote: false 13 | #toc-title: "Table of Contents" 14 | 15 | svgbob: 16 | font-family: "Source Code Pro" 17 | font-size: 14 18 | scale: 1 19 | stroke-width: 2 20 | 21 | heading-unnumbered: 22 | 1: "Heading Unnumbered 1" 23 | 2: "Heading Unnumbered 2" 24 | 3: "Heading Unnumbered 3" 25 | 4: "Heading Unnumbered 4" 26 | 5: "Heading Unnumbered 4" 27 | 28 | heading-appendix: 29 | 1: "Appendix Heading 1" 30 | 2: "Appendix Heading 2" 31 | 3: "Appendix Heading 3" 32 | 4: "Appendix Heading 4" 33 | 5: "Appendix Heading 5" 34 | 35 | bullet-style: 36 | 1: "Bullet List 1" 37 | 2: "Bullet List 2" 38 | 3: "Bullet List 3" 39 | 40 | numbered-bullets: 41 | 1: "Number Bullet" 42 | 2: "Number Bullet 2" 43 | 3: "Number Bullet 3" 44 | 45 | custom-spans: 46 | red: "WarningTok" 47 | green: "PreprocessorTok" 48 | blue: "AttributeTok" 49 | 50 | image-div-style: "Image Caption" 51 | 52 | docx_coreprop: 53 | # author: "K4ZUKI" # str 54 | # category: "Category" # str 55 | # comments: "Comment" # str 56 | # keywords: "Keyword1 Keyword2" # str 57 | # last_modified_by: "K4ZUKI" # str 58 | # last_printed: "31-Dec-2018" # datetime DD-MMM-YYYY 59 | # modified: "31-Dec-2018" # datetime DD-MMM-YYYY 60 | # revision: 1123 # int < 32768 61 | # subject: "SubjecT" # str 62 | # title: "Title" # str 63 | 64 | # created: "31-Dec-2018" # datetime DD-MMM-YYYY set externally 65 | # content_status: "Status" # ignored? 66 | # identifier: "ID" # ignored? 67 | # language: "Japanese" # ignored? 68 | # version: "Version" # ignored? 69 | 70 | table-alignment-in-page: center # left / center /right 71 | table-cell-vertical-alignment: center # top / center / bottom / both 72 | read-only-recommended: true 73 | disable-table-autofit: false # setting 'true' requires explicit column widths setting 74 | table: 75 | # "Normal Table": "Centered" 76 | paragraph: 77 | "Image Caption": "Figure Caption" 78 | # "Normal": "Body Text" 79 | # "First Paragraph": "Body Text" 80 | character: 81 | ... 82 | -------------------------------------------------------------------------------- /tests/markdown/rest.rst: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | $$////////////~rest.rst~start~////////////$$ 4 | 5 | - list 6 | - list depth-2 7 | - list depth-3 8 | - list depth-4 9 | - list depth-3 10 | - list depth-2 11 | - list depth-3 12 | 13 | $$////////////~rest.rst~end~////////////$$ 14 | 15 | \newpage 16 | -------------------------------------------------------------------------------- /tests/markdown/section1.md: -------------------------------------------------------------------------------- 1 | vvv section1.md start vvv 2 | 3 | ### This section is what is included 4 | 5 | - list 6 | - list depth-2 7 | - list depth-3 8 | - list depth-4 9 | - list depth-3 10 | - list depth-2 11 | - list depth-3 12 | 13 | ## #include "section2.md" 14 | 15 | ## #include "not-found.md" 16 | 17 | ## `#include "section2.md"` 18 | 19 | line break in single Para by a\ 20 | backslash 21 | 22 | \^\^\^ section1.md end \^\^\^ 23 | -------------------------------------------------------------------------------- /tests/markdown/section2.md: -------------------------------------------------------------------------------- 1 | $$////////////~section2.md~////////////$$ 2 | 3 | This section is what is included 2 4 | 5 | Table: table without setting column widths {.class .class2} 6 | 7 | | This | is | | 8 | |:-----|:---|:-----------------------------------------------------------------------:| 9 | | | a | [colored text]{.highlight foreground="5B9ACF" background="darkMagenta"} | 10 | 11 | ::: rmnote ::: 12 | Remove this block 13 | ::: 14 | 15 | - [Highlighted text 1]{.highlight foreground="ABABAB"} 16 | - [_Highlighted text 2_]{.highlight background="red"} 17 | - [_Highlighted **text 3**_]{.highlight foreground="7F7F7F" background="darkgray"} 19 | 20 | - $$////////////~section2.md~////////////$$ 21 | --------------------------------------------------------------------------------