depth 1 replace

This commit is contained in:
2025-10-11 11:49:38 +08:00
parent 40f6d927cd
commit c7e1c1a8dc
4 changed files with 56 additions and 80 deletions

View File

@@ -6,4 +6,10 @@ This is a pandoc filter manipulating [fenced_divs](https://pandoc.org/MANUAL.htm
Inspired by [this joke](https://www.zhihu.com/question/586807834/answer/2973535981).
useful refs:
- https://pandoc.org/lua-filters.html
- https://pandoc.org/lua-filters.html
# How does this work?
`filter.lua` walks the AST. There are some special leaf nodes with a `include` attr which is a string containing labels of some other divs to be included here.
For each of `include` node `i`, we maintain a list `fa[i]` containing nodes with labels on the path `i -> root`. Then for each label `l` in `i`'s include list, one can see that every node in `fa[i]` depends on `l`. Thus we build a digraph G on labels. If G is a DAG, then we can use topological sort to rank its vertices and thus decide the order of substitution; Otherwise, G contains a directed cycle, the filter reports an error.

View File

@@ -1,3 +1,11 @@
local label_map = {} -- label has to be unique!
local function collect_labels(div) -- only collect labels in div
if div.identifier and div.identifier ~= "" then
label_map[div.identifier] = div:clone()
end
return nil
end
local function words(s)
local res = {}
@@ -10,27 +18,36 @@ local function words(s)
return res
end
local function label2Block(labels)
local contents = ""
for _,l in ipairs(words(labels)) do
-- use file for now.
local fh = io.open(l, "r")
if not fh then
io.stderr:write("Cannot open file: " .. l .. "\n")
return { pandoc.Plain { pandoc.Str("[Error: cannot read file " .. l .. "]") } }
end
contents = contents .. fh:read("*a")
fh:close()
end
return { pandoc.Plain { pandoc.Str(contents) } }
end
function Div(e)
local function replace(e)
local include = e.attributes["include"]
if include then
local blocks = label2Block(include)
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())
io.stderr:write("insert [" .. label_map[l].identifier .. ']\n')
else
io.stderr:write("Cannot find AST node with label " .. l)
end
end
return pandoc.Div(blocks, e.attr)
end
return nil -- no change
return e -- no change
end
return {
-- traverse = 'topdown',
Pandoc = function(doc)
-- collect labels
for _, blk in ipairs(doc.blocks) do
collect_labels(blk)
end
-- replace
for i, blk in ipairs(doc.blocks) do
doc.blocks[i] = replace(blk)
end
return doc
end
}

View File

@@ -1,7 +1,9 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce porta mattis neque, quis molestie nunc faucibus vitae. Phasellus vel commodo dolor, at faucibus arcu. Curabitur sit amet magna a neque euismod feugiat non et diam. Aliquam sit amet libero enim. Integer dignissim ullamcorper felis, ac ultrices turpis congue vel. Nulla id tempus orci. Curabitur ac vulputate tellus. Integer fermentum tempor facilisis. Duis egestas luctus tristique. Maecenas vitae arcu sit amet justo feugiat imperdiet. Nunc luctus erat sed ligula convallis hendrerit.
::: {#lorem}
Lorem ipsum dolor sit amet
:::
:::{include="README.md , filter.lua , ,"}
:::{include="lorem, thm2 , fakelabel , "}
:::

View File

@@ -1,62 +1,13 @@
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce porta
mattis neque, quis molestie nunc faucibus vitae. Phasellus vel commodo
dolor, at faucibus arcu. Curabitur sit amet magna a neque euismod
feugiat non et diam. Aliquam sit amet libero enim. Integer dignissim
ullamcorper felis, ac ultrices turpis congue vel. Nulla id tempus orci.
Curabitur ac vulputate tellus. Integer fermentum tempor facilisis. Duis
egestas luctus tristique. Maecenas vitae arcu sit amet justo feugiat
imperdiet. Nunc luctus erat sed ligula convallis hendrerit.</p>
<div data-include="README.md , filter.lua , ,">
# Piecewise Readable Filter
This is a pandoc filter manipulating
[fenced_divs](https://pandoc.org/MANUAL.html#extension-fenced_divs) in
pandoc markdown.
Inspired by [this
joke](https://www.zhihu.com/question/586807834/answer/2973535981).
useful refs:
- https://pandoc.org/lua-filters.html
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 label2Block(labels)
local contents = ""
for _,l in ipairs(words(labels)) do
-- use file for now.
local fh = io.open(l, "r")
if not fh then
io.stderr:write("Cannot open file: " .. l .. "\n")
return { pandoc.Plain { pandoc.Str("[Error: cannot read file
" .. l .. "]") } }
end
contents = contents .. fh:read("*a")
fh:close()
end
return { pandoc.Plain { pandoc.Str(contents) } }
end
function Div(e)
local include = e.attributes["include"]
if include then
local blocks = label2Block(include)
-- Replace the Div contents
return pandoc.Div(blocks, e.attr)
end
return nil -- no change
end
<div id="lorem">
<p>Lorem ipsum dolor sit amet</p>
</div>
<div data-include="lorem, thm2 , fakelabel , ">
<div id="lorem">
<p>Lorem ipsum dolor sit amet</p>
</div>
<div id="thm2" class="Theorem">
<p>test thm2</p>
</div>
</div>
<div class="Theorem">
<p>test thm1</p>