Skip to content

Commit aa58a81

Browse files
author
pedro
committed
repairing pandoc versions divergence
1 parent 00791d2 commit aa58a81

4 files changed

Lines changed: 85 additions & 27 deletions

File tree

_extensions/container-writer/container-writer.lua

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ local function process_metadata(meta)
5959

6060
local function add_list(list)
6161
if not list then return end
62-
local items = (pandoc.utils.type(list) == 'List') and list or { list }
63-
for _, item in ipairs(items) do
62+
for _, item in ipairs(list) do
6463
local t = pandoc.utils.type(item)
6564
if t == 'Meta' or t == 'table' then
6665
-- remap entry: {note.title: notetitle}
@@ -152,33 +151,84 @@ local function wrap_element(el, environment, is_inline)
152151
end
153152
end
154153

155-
--- Walks children looking for trigger.class whitelist matches.
156-
--- trigger : remaining path — current level name, used for child lookup and environment
154+
--- Pass 1: mark matching children with _cw_env and _cw_acc attributes.
155+
--- Does not substitute — lets the walk descend fully into nested levels
156+
--- before any replacement occurs. This avoids a Pandoc 3.9 behaviour where
157+
--- returning a replacement from a walk handler stops further descent.
158+
local function mark_children(el, accumulated)
159+
return el:walk {
160+
Div = function(child)
161+
local class = child.classes:find_if(function(c)
162+
return Whitelist[accumulated .. '.' .. c]
163+
end)
164+
if class then
165+
local entry = Whitelist[accumulated .. '.' .. class]
166+
local env = (entry == true) and class or entry
167+
local acc = accumulated .. '.' .. class
168+
child = mark_children(child, acc)
169+
child.attributes['_cw_env'] = env
170+
child.attributes['_cw_acc'] = acc
171+
return child
172+
end
173+
end,
174+
Span = function(child)
175+
local class = child.classes:find_if(function(c)
176+
return Whitelist[accumulated .. '.' .. c]
177+
end)
178+
if class then
179+
local entry = Whitelist[accumulated .. '.' .. class]
180+
local env = (entry == true) and class or entry
181+
local acc = accumulated .. '.' .. class
182+
child = mark_children(child, acc)
183+
child.attributes['_cw_env'] = env
184+
child.attributes['_cw_acc'] = acc
185+
return child
186+
end
187+
end,
188+
}
189+
end
190+
191+
--- Pass 2: substitute marked elements with their format-native wrapping.
192+
--- Runs bottom-up so inner elements are wrapped before outer ones.
193+
local function wrap_marked(el)
194+
return el:walk {
195+
Div = function(child)
196+
local env = child.attributes['_cw_env']
197+
local acc = child.attributes['_cw_acc']
198+
if env then
199+
child.attributes['_cw_env'] = nil
200+
child.attributes['_cw_acc'] = nil
201+
if in_whitelist(acc) then
202+
return wrap_element(child, env, false)
203+
end
204+
end
205+
end,
206+
Span = function(child)
207+
local env = child.attributes['_cw_env']
208+
local acc = child.attributes['_cw_acc']
209+
if env then
210+
child.attributes['_cw_env'] = nil
211+
child.attributes['_cw_acc'] = nil
212+
if in_whitelist(acc) then
213+
return wrap_element(child, env, true)
214+
end
215+
end
216+
end,
217+
}
218+
end
219+
220+
--- Processes children in two passes to support chains (note.title.icon) across
221+
--- all Pandoc versions. A single-pass approach (mark+substitute in one walk)
222+
--- breaks in Pandoc 3.9+: returning a replacement from a walk handler stops
223+
--- further descent into nested levels, so deeper chain entries are never seen.
224+
--- Pass 1 (mark_children) annotates matching elements without substituting,
225+
--- letting the walk descend fully. Pass 2 (wrap_marked) substitutes bottom-up.
226+
--- trigger : current level name, used as environment
157227
--- accumulated : full dot-chain so far, used for whitelist wrap check
158228
local function walk_element(el, is_inline, trigger, accumulated)
159229
if FORMAT ~= 'html' and FORMAT ~= 'epub' then
160-
el = el:walk {
161-
Div = function(child)
162-
local class = child.classes:find_if(function(c)
163-
return Whitelist[trigger .. '.' .. c]
164-
end)
165-
if class then
166-
local entry = Whitelist[trigger .. '.' .. class]
167-
local env = (entry == true) and class or entry
168-
return walk_element(child, false, env, accumulated .. '.' .. class)
169-
end
170-
end,
171-
Span = function(child)
172-
local class = child.classes:find_if(function(c)
173-
return Whitelist[trigger .. '.' .. c]
174-
end)
175-
if class then
176-
local entry = Whitelist[trigger .. '.' .. class]
177-
local env = (entry == true) and class or entry
178-
return walk_element(child, true, env, accumulated .. '.' .. class)
179-
end
180-
end,
181-
}
230+
el = mark_children(el, accumulated)
231+
el = wrap_marked(el)
182232
end
183233
if in_whitelist(accumulated) then
184234
return wrap_element(el, trigger, is_inline)

test/expected/child-chain-context.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
\starttitle
44

5+
\starticon
6+
57
!
68

9+
\stopicon
10+
711
Note title
812

913
\stoptitle

test/expected/child-chain-latex.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
\begin{title}
44

5+
\begin{icon}
6+
57
!
68

9+
\end{icon}
10+
711
Note title
812

913
\end{title}

test/expected/child-chain-typst.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#block[
44
!
55

6-
]
6+
] <icon>
77
Note title
88

99
] <title>

0 commit comments

Comments
 (0)