|
| 1 | +--- include-files.lua – filter to include Markdown files |
| 2 | +--- |
| 3 | +--- Copyright: © 2019–2021 Albert Krewinkel |
| 4 | +--- License: MIT – see LICENSE file for details |
| 5 | + |
| 6 | +-- Module pandoc.path is required and was added in version 2.12 |
| 7 | +PANDOC_VERSION:must_be_at_least '2.12' |
| 8 | + |
| 9 | +local List = require 'pandoc.List' |
| 10 | +local path = require 'pandoc.path' |
| 11 | +local system = require 'pandoc.system' |
| 12 | + |
| 13 | +--- Get include auto mode |
| 14 | +local include_auto = false |
| 15 | +function get_vars (meta) |
| 16 | + if meta['include-auto'] then |
| 17 | + include_auto = true |
| 18 | + end |
| 19 | +end |
| 20 | + |
| 21 | +--- Keep last heading level found |
| 22 | +local last_heading_level = 0 |
| 23 | +function update_last_level(header) |
| 24 | + last_heading_level = header.level |
| 25 | +end |
| 26 | + |
| 27 | +--- Update contents of included file |
| 28 | +local function update_contents(blocks, shift_by, include_path) |
| 29 | + local update_contents_filter = { |
| 30 | + -- Shift headings in block list by given number |
| 31 | + Header = function (header) |
| 32 | + if shift_by then |
| 33 | + header.level = header.level + shift_by |
| 34 | + end |
| 35 | + return header |
| 36 | + end, |
| 37 | + -- If image paths are relative then prepend include file path |
| 38 | + Image = function (image) |
| 39 | + if path.is_relative(image.src) then |
| 40 | + image.src = path.normalize(path.join({include_path, image.src})) |
| 41 | + end |
| 42 | + return image |
| 43 | + end, |
| 44 | + -- Update path for include-code-files.lua filter style CodeBlocks |
| 45 | + CodeBlock = function (cb) |
| 46 | + if cb.attributes.include and path.is_relative(cb.attributes.include) then |
| 47 | + cb.attributes.include = |
| 48 | + path.normalize(path.join({include_path, cb.attributes.include})) |
| 49 | + end |
| 50 | + return cb |
| 51 | + end |
| 52 | + } |
| 53 | + |
| 54 | + return pandoc.walk_block(pandoc.Div(blocks), update_contents_filter).content |
| 55 | +end |
| 56 | + |
| 57 | +--- Filter function for code blocks |
| 58 | +local transclude |
| 59 | +function transclude (cb) |
| 60 | + -- ignore code blocks which are not of class "include". |
| 61 | + if not cb.classes:includes 'include' then |
| 62 | + return |
| 63 | + end |
| 64 | + |
| 65 | + -- Markdown is used if this is nil. |
| 66 | + local format = cb.attributes['format'] |
| 67 | + |
| 68 | + -- Attributes shift headings |
| 69 | + local shift_heading_level_by = 0 |
| 70 | + local shift_input = cb.attributes['shift-heading-level-by'] |
| 71 | + if shift_input then |
| 72 | + shift_heading_level_by = tonumber(shift_input) |
| 73 | + else |
| 74 | + if include_auto then |
| 75 | + -- Auto shift headings |
| 76 | + shift_heading_level_by = last_heading_level |
| 77 | + end |
| 78 | + end |
| 79 | + |
| 80 | + --- keep track of level before recusion |
| 81 | + local buffer_last_heading_level = last_heading_level |
| 82 | + |
| 83 | + local blocks = List:new() |
| 84 | + for line in cb.text:gmatch('[^\n]+') do |
| 85 | + if line:sub(1,2) ~= '//' then |
| 86 | + local fh = io.open(line) |
| 87 | + if not fh then |
| 88 | + io.stderr:write("Cannot open file " .. line .. " | Skipping includes\n") |
| 89 | + else |
| 90 | + local contents = pandoc.read(fh:read '*a', format).blocks |
| 91 | + last_heading_level = 0 |
| 92 | + -- recursive transclusion |
| 93 | + contents = system.with_working_directory( |
| 94 | + path.directory(line), |
| 95 | + function () |
| 96 | + return pandoc.walk_block( |
| 97 | + pandoc.Div(contents), |
| 98 | + { Header = update_last_level, CodeBlock = transclude } |
| 99 | + ) |
| 100 | + end).content |
| 101 | + --- reset to level before recursion |
| 102 | + last_heading_level = buffer_last_heading_level |
| 103 | + blocks:extend(update_contents(contents, shift_heading_level_by, |
| 104 | + path.directory(line))) |
| 105 | + fh:close() |
| 106 | + end |
| 107 | + end |
| 108 | + end |
| 109 | + return blocks |
| 110 | +end |
| 111 | + |
| 112 | +return { |
| 113 | + { Meta = get_vars }, |
| 114 | + { Header = update_last_level, CodeBlock = transclude } |
| 115 | +} |
0 commit comments