/ _extensions / pandoc-ext / abstract-section / abstract-section.lua
abstract-section.lua
 1  --[[
 2  abstract-section – move an "abstract" section into document metadata
 3  
 4  Copyright: © 2017–2023 Albert Krewinkel
 5  License:   MIT – see LICENSE file for details
 6  ]]
 7  local stringify = (require 'pandoc.utils').stringify
 8  local section_identifiers = {
 9    abstract = true,
10  }
11  local collected = {}
12  --- The level of the highest heading that was seen so far. Abstracts
13  --- must be at or above this level to prevent nested sections from being
14  --- treated as metadata. Only top-level sections should become metadata.
15  local toplevel = 6
16  
17  --- Extract abstract from a list of blocks.
18  local function abstract_from_blocklist (blocks)
19    local body_blocks = {}
20    local looking_at_section = false
21  
22    for _, block in ipairs(blocks) do
23      if block.t == 'Header' and block.level <= toplevel then
24        toplevel = block.level
25        if section_identifiers[block.identifier] then
26          looking_at_section = block.identifier
27          collected[looking_at_section] = {}
28        else
29          looking_at_section = false
30          body_blocks[#body_blocks + 1] = block
31        end
32      elseif looking_at_section then
33        if block.t == 'HorizontalRule' then
34          looking_at_section = false
35        else
36          local collect = collected[looking_at_section]
37          collect[#collect + 1] = block
38        end
39      else
40        body_blocks[#body_blocks + 1] = block
41      end
42    end
43  
44    return body_blocks
45  end
46  
47  Pandoc = function (doc)
48    local meta = doc.meta
49  
50    -- configure
51    section_identifiers_list =
52      (doc.meta['abstract-section'] or {})['section-identifiers']
53    if section_identifiers_list and #section_identifiers_list > 0 then
54      section_identifiers = {}
55      for i, ident in ipairs(section_identifiers_list) do
56        section_identifiers[stringify(ident)] = true
57      end
58    end
59    -- unset config in meta
60    doc.meta['abstract-section'] = nil
61  
62    local blocks = {}
63    if PANDOC_VERSION >= {2,17} then
64      -- Walk all block lists by default
65      blocks = doc.blocks:walk{Blocks = abstract_from_blocklist}
66    elseif PANDOC_VERSION >= {2,9,2} then
67      -- Do the same with pandoc versions that don't have walk methods but the
68      -- `walk_block` function.
69      blocks = pandoc.utils.walk_block(
70        pandoc.Div(doc.blocks),
71        {Blocks = abstract_from_blocklist}
72      ).content
73    else
74      -- otherwise, just check the top-level block-list
75      blocks = abstract_from_blocklist(doc.blocks)
76    end
77    for metakey in pairs(section_identifiers) do
78      metakey = stringify(metakey)
79      local abstract = collected[metakey]
80      if not meta[metakey] and abstract and #abstract > 0 then
81        meta[metakey] = pandoc.MetaBlocks(abstract)
82      end
83    end
84    return pandoc.Pandoc(blocks, meta)
85  end