|
1 | 1 | -- _utils.lua |
2 | 2 | -- Copyright (C) 2020-2022 Posit Software, PBC |
3 | 3 |
|
| 4 | +--- The pandoc module. Imported to avoid 'no such variable' |
| 5 | +--- warnings in some editors. |
| 6 | +local pandoc = require 'pandoc' |
| 7 | + |
4 | 8 | -- improved formatting for dumping tables and quarto's emulated pandoc nodes |
5 | 9 | function tdump (tbl, raw) |
6 | 10 |
|
@@ -265,59 +269,75 @@ local function get_type(v) |
265 | 269 | return pandoc_type |
266 | 270 | end |
267 | 271 |
|
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 |
| 272 | +--- Blocks metatable |
| 273 | +local BlocksMT = getmetatable(pandoc.Blocks{}) |
| 274 | +--- Inlines metatable |
| 275 | +local InlinesMT = getmetatable(pandoc.Inlines{}) |
283 | 276 |
|
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)) |
| 277 | +--- Turns the given object into a `Inlines` list. |
| 278 | +-- |
| 279 | +-- Works mostly like `pandoc.Inlines`, but doesn't a do a full |
| 280 | +-- unmarshal/marshal roundtrip. This buys performance, at the cost of |
| 281 | +-- less thorough type checks. |
| 282 | +-- |
| 283 | +-- NOTE: The input object might be modified *destructively*! |
| 284 | +local function as_inlines(obj) |
| 285 | + local pt = pandoc.utils.type(obj) |
| 286 | + if pt == 'Inlines' then |
| 287 | + return obj |
| 288 | + elseif pt == "Inline" then |
| 289 | + -- Faster than calling pandoc.Inlines |
| 290 | + return setmetatable({obj}, InlinesMT) |
| 291 | + elseif pt == 'List' or pt == 'table' then |
| 292 | + if obj[1] and pandoc.utils.type(obj[1]) == 'Block' then |
| 293 | + return pandoc.utils.blocks_to_inlines(obj) |
288 | 294 | end |
289 | | - return result |
| 295 | + -- Faster than calling pandoc.Inlines |
| 296 | + return setmetatable(obj, InlinesMT) |
| 297 | + elseif pt == "Block" then |
| 298 | + return pandoc.utils.blocks_to_inlines({obj}) |
| 299 | + elseif pt == "Blocks" then |
| 300 | + return pandoc.utils.blocks_to_inlines(obj) |
| 301 | + else |
| 302 | + return pandoc.Inlines(obj or {}) |
290 | 303 | end |
291 | | - |
292 | | - -- luacov: disable |
293 | | - fatal("as_inlines: invalid type " .. t) |
294 | | - return pandoc.Inlines({}) |
295 | | - -- luacov: enable |
296 | 304 | end |
297 | 305 |
|
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) |
| 306 | +--- Turns the given object into a `Blocks` list. |
| 307 | +-- |
| 308 | +-- Works mostly like `pandoc.Blocks`, but doesn't a do a full |
| 309 | +-- unmarshal/marshal roundtrip. This buys performance, at the cost of |
| 310 | +-- less thorough type checks. |
| 311 | +-- |
| 312 | +-- NOTE: The input object might be modified *destructively*! |
| 313 | +-- |
| 314 | +-- This might need some benchmarking. |
| 315 | +local function as_blocks(obj) |
| 316 | + local pt = pandoc.utils.type(obj) |
| 317 | + if pt == 'Blocks' then |
| 318 | + return obj |
| 319 | + elseif pt == 'Block' then |
| 320 | + -- Assigning a metatable directly is faster than calling |
| 321 | + -- `pandoc.Blocks`. |
| 322 | + return setmetatable({obj}, BlocksMT) |
| 323 | + elseif pt == 'Inline' then |
| 324 | + return setmetatable({pandoc.Plain{obj}}, BlocksMT) |
| 325 | + elseif pt == 'Inlines' then |
| 326 | + if next(obj) then |
| 327 | + return setmetatable({pandoc.Plain(obj)}, BlocksMT) |
| 328 | + end |
| 329 | + return setmetatable({}, BlocksMT) |
| 330 | + elseif pt == 'List' or (pt == 'table' and obj[1]) then |
| 331 | + if pandoc.utils.type(obj[1]) == 'Inline' then |
| 332 | + obj = {pandoc.Plain(obj)} |
| 333 | + end |
| 334 | + return setmetatable(obj, BlocksMT) |
| 335 | + elseif (pt == 'table' and obj.long) or pt == 'Caption' then |
| 336 | + -- Looks like a Caption |
| 337 | + return as_blocks(obj.long) |
| 338 | + else |
| 339 | + return pandoc.Blocks(obj or {}) |
315 | 340 | end |
316 | | - |
317 | | - -- luacov: disable |
318 | | - fatal("as_blocks: invalid type " .. t) |
319 | | - return pandoc.Blocks({}) |
320 | | - -- luacov: enable |
321 | 341 | end |
322 | 342 |
|
323 | 343 | local function match_fun(reset, ...) |
|
0 commit comments