Skip to content

Commit 4274ec0

Browse files
committed
Rewrite as_inlines, as_blocks with focus on performance
This also fixes unwanted behavior of `as_blocks`, which would treat a list of Inline elements as a list of singleton Plain elements, leading to bad results.
1 parent c7e4597 commit 4274ec0

File tree

1 file changed

+63
-47
lines changed

1 file changed

+63
-47
lines changed

src/resources/pandoc/datadir/_utils.lua

Lines changed: 63 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -265,59 +265,75 @@ local function get_type(v)
265265
return pandoc_type
266266
end
267267

268-
local function as_inlines(v)
269-
if v == nil then
270-
return pandoc.Inlines({})
271-
end
272-
local t = pandoc.utils.type(v)
273-
if t == "Inlines" then
274-
---@cast v pandoc.Inlines
275-
return v
276-
elseif t == "Blocks" then
277-
return pandoc.utils.blocks_to_inlines(v)
278-
elseif t == "Inline" then
279-
return pandoc.Inlines({v})
280-
elseif t == "Block" then
281-
return pandoc.utils.blocks_to_inlines({v})
282-
end
268+
--- Blocks metatable
269+
local BlocksMT = getmetatable(pandoc.Blocks{})
270+
--- Inlines metatable
271+
local InlinesMT = getmetatable(pandoc.Inlines{})
283272

284-
if type(v) == "table" then
285-
local result = pandoc.Inlines({})
286-
for i, v in ipairs(v) do
287-
tappend(result, as_inlines(v))
273+
--- Turns the given object into a `Inlines` list.
274+
--
275+
-- Works mostly like `pandoc.Inlines`, but doesn't a do a full
276+
-- unmarshal/marshal roundtrip. This buys performance, at the cost of
277+
-- less thorough type checks.
278+
--
279+
-- NOTE: The input object might be modified *destructively*!
280+
local function as_inlines(obj)
281+
local pt = pandoc.utils.type(obj)
282+
if pt == 'Inlines' then
283+
return obj
284+
elseif pt == "Inline" then
285+
-- Faster than calling pandoc.Inlines
286+
return setmetatable({obj}, InlinesMT)
287+
elseif pt == 'List' or pt == 'table' then
288+
if obj[1] and pandoc.utils.type(obj[1]) == 'Block' then
289+
return pandoc.utils.blocks_to_inlines(obj)
288290
end
289-
return result
291+
-- Faster than calling pandoc.Inlines
292+
return setmetatable(obj, InlinesMT)
293+
elseif pt == "Block" then
294+
return pandoc.utils.blocks_to_inlines({obj})
295+
elseif pt == "Blocks" then
296+
return pandoc.utils.blocks_to_inlines(obj)
297+
else
298+
return pandoc.Inlines(obj or {})
290299
end
291-
292-
-- luacov: disable
293-
fatal("as_inlines: invalid type " .. t)
294-
return pandoc.Inlines({})
295-
-- luacov: enable
296300
end
297301

298-
local function as_blocks(v)
299-
if v == nil then
300-
return pandoc.Blocks({})
301-
end
302-
local t = pandoc.utils.type(v)
303-
if t == "Blocks" then
304-
return v
305-
elseif t == "Inlines" then
306-
return pandoc.Blocks({pandoc.Plain(v)})
307-
elseif t == "Block" then
308-
return pandoc.Blocks({v})
309-
elseif t == "Inline" then
310-
return pandoc.Blocks({pandoc.Plain(v)})
311-
end
312-
313-
if type(v) == "table" then
314-
return pandoc.Blocks(v)
302+
--- Turns the given object into a `Blocks` list.
303+
--
304+
-- Works mostly like `pandoc.Blocks`, but doesn't a do a full
305+
-- unmarshal/marshal roundtrip. This buys performance, at the cost of
306+
-- less thorough type checks.
307+
--
308+
-- NOTE: The input object might be modified *destructively*!
309+
--
310+
-- This might need some benchmarking.
311+
local function as_blocks(obj)
312+
local pt = pandoc.utils.type(obj)
313+
if pt == 'Blocks' then
314+
return obj
315+
elseif pt == 'Block' then
316+
-- Assigning a metatable directly is faster than calling
317+
-- `pandoc.Blocks`.
318+
return setmetatable({obj}, BlocksMT)
319+
elseif pt == 'Inline' then
320+
return setmetatable({pandoc.Plain{obj}}, BlocksMT)
321+
elseif pt == 'Inlines' then
322+
if next(obj) then
323+
return setmetatable({pandoc.Plain(obj)}, BlocksMT)
324+
end
325+
return setmetatable({}, BlocksMT)
326+
elseif pt == 'List' or (pt == 'table' and obj[1]) then
327+
if pandoc.utils.type(obj[1]) == 'Inline' then
328+
obj = {pandoc.Plain(obj)}
329+
end
330+
return setmetatable(obj, BlocksMT)
331+
elseif (pt == 'table' and obj.long) or pt == 'Caption' then
332+
-- Looks like a Caption
333+
return as_blocks(obj.long)
334+
else
335+
return pandoc.Blocks(obj or {})
315336
end
316-
317-
-- luacov: disable
318-
fatal("as_blocks: invalid type " .. t)
319-
return pandoc.Blocks({})
320-
-- luacov: enable
321337
end
322338

323339
local function match_fun(reset, ...)

0 commit comments

Comments
 (0)