local label_map = {} -- label has to be unique! -- helper functions for debugging local function show(s) io.stderr:write("[Debug] " .. s .. "\n") end local function collect_labels(blk) if blk.identifier and blk.identifier ~= "" then label_map[blk.identifier] = blk:clone() end return nil end local function dfs(blk, stack) -- depth first search on a top level blk -- check for identifier and build label_map if blk.identifier and blk.identifier ~= "" then label_map[blk.identifier] = blk:clone() table.insert(stack, blk.identifier) end -- recurse into child blocks -- type matters. see https://hackage-content.haskell.org/package/pandoc-types-1.23.1/docs/Text-Pandoc-Definition.html#t:Block -- fortunately, we only need to recurse on divs. if blk.t == 'Div' then for _, inner in ipairs(blk.content) do dfs(inner, stack) end end -- pop if blk.identifier and blk.identifier ~= "" then table.remove(stack) -- pop end end local function words(s) local res = {} for part in s:gmatch("[^,]+") do -- split by commas local trimmed = part:match("^%s*(.-)%s*$") -- remove leading/trailing spaces if trimmed ~= "" then table.insert(res, trimmed) end end return res end local function replace(e) local include = e.attributes["include"] if include then local blocks = {} -- Replace the Div contents for _, l in ipairs(words(include)) do if label_map[l] then table.insert(blocks, label_map[l]:clone()) show("insert [" .. label_map[l].identifier .. ']\n') else io.stderr:write("Cannot find AST node with label " .. l .. "\n") end end return pandoc.Div(blocks, e.attr) end return e -- no change end return { -- traverse = 'topdown', Pandoc = function(doc) -- collect labels for _, blk in ipairs(doc.blocks) do dfs(blk,{}) end -- replace for i, blk in ipairs(doc.blocks) do doc.blocks[i] = replace(blk) end return doc end }