summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEkaitz Zarraga <ekaitz@elenq.tech>2020-05-28 16:10:52 +0200
committerEkaitz Zarraga <ekaitz@elenq.tech>2020-05-28 16:10:52 +0200
commitf4afc91c0785cb112bc507b0450f86278ad1cc2a (patch)
treeb4c77e459a262226ff3adb57ebc59673d6d0f280
parent2449a674f035e1b0d9e456d1499f6a957f21af8a (diff)
ToC filter
-rw-r--r--filters/toc.lua128
1 files changed, 128 insertions, 0 deletions
diff --git a/filters/toc.lua b/filters/toc.lua
new file mode 100644
index 0000000..479b082
--- /dev/null
+++ b/filters/toc.lua
@@ -0,0 +1,128 @@
+--[[
+-- 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
+
+ -- TODO: ReMOVE THIS
+ function headers2links_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 = headers2links_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