--[[ -- This filter creates the ToC from the headings so if it's applied before -- heading transformations, transformations do not appear in the ToC. -- -- It's useful for HTML output where the anchors are added in an extra filter. -- Default ToC included the anchor. Using this filter anchor is not included. -- -- It supports toc-depth metadata field. --]] pandoc.utils = require 'pandoc.utils' list_of_headers = {} if FORMAT:match 'html' then function headers2link_and_level(headers) local links = {} for i, v in ipairs(headers) do local l = pandoc.Link( pandoc.utils.stringify(v), "#"..v.identifier ) table.insert(links,{ v.level, pandoc.Plain( l ) }) end return links end function create_ol(headers, toc_depth) if #headers == 0 then return pandoc.Null() end local links = headers2link_and_level(headers) -- min_level doesn't have to be 1, it could be larger local min_level = -1 for i, v in ipairs(links) do if min_level == -1 or v[1] < min_level then min_level = v[1] end end -- max level needed for grouping local max_level = 0 if toc_depth >= 1 then -- toc_depth is set, so remove elements with larger level than -- max_level max_level = min_level + toc_depth - 1 local i = 1 while i <= #links do if links[i][1] > max_level then table.remove(links, i) i = i - 1 end i = i + 1 end else -- toc_depth not set so get the max_level from the contents for i, v in ipairs(links) do if v[1] > max_level then max_level = v[1] end end end -- Iterate trough valid levels while max_level > min_level do local i = 1 local tmp = {} while i <= #links do local level = links[i][1] -- Element's level if level == max_level then -- Found group -- If group is found, it usually has a parent local parent = links[i-1] if parent[1] == level - 1 then -- It's the direct parent, add it's contents parent = parent[2] else -- Not direct parent, warn and discard io.stderr:write("[WARNING] Element of level ") io.stderr:write(tostring(parent[1])) io.stderr:write(" has no direct children: ") io.stderr:write(pandoc.utils.stringify(parent[2])) io.stderr:write("\n") parent = pandoc.Null() end while i <= #links and links[i][1] == level do -- Capture the group table.insert(tmp, table.remove(links, i)[2]) end if #tmp ~= 0 then -- There was a group, convert it to -- {parent, OrderedList(group)} local children = pandoc.OrderedList(tmp) local pos = i if parent.t ~= "Null" then -- There was a parent: extract it from links table.remove(links, i-1) pos = i - 1 end table.insert(links, pos, {level-1, {parent, children}}) tmp = {} end end i = i + 1 end max_level = max_level - 1 end local lis = {} for i,v in pairs(links) do _,lis[i] = table.unpack(v) end return pandoc.OrderedList(lis) end function Meta(m) local toc_depth if m["toc-depth"] ~= nil then toc_depth = tonumber(m["toc-depth"][1]["c"]) else toc_depth = -1 end m["table-of-contents"] = pandoc.MetaBlocks({create_ol(list_of_headers, toc_depth)}) return m end function Header(el) table.insert(list_of_headers, el) return el end end