Skip to content

Instantly share code, notes, and snippets.

@rauschma
Last active January 12, 2019 05:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rauschma/7f631cacad55b8b6c920b9334f711244 to your computer and use it in GitHub Desktop.
Save rauschma/7f631cacad55b8b6c920b9334f711244 to your computer and use it in GitHub Desktop.
title
Demo

Background {#background}

History

Tips

Main

Syntax {#syntax}

BEFORE

\ChapterToc

AFTER

Expressions

Special expressions

Statements

Library

Appendix

Acknowledgements

--[[
Features of this filter:
Not supported for HTML: --top-level-division=part. This filter numbers parts correctly.
Chapter TOCs via \ChapterToc
Configure:
--metadata=header_tools_add_numbers:true
--metadata=header_tools_has_parts:true
]]
local headersToIgnore = {
["List of Figures"] = true,
["List of Listings"] = true,
["List of Tables"] = true,
}
local PART_LEVEL
local CHAPTER_LEVEL
local DO_NUMBER_HEADERS
local idToChapterToc = {}
-- ////////// Visit Headers \\\\\\\\\\
-- Constantly update the counters (careful w.r.t. parts!)
-- If configured, prefer Headers with section numbers (text derived from counters)
-- Per chapter, collect the Headers (needed by chapter TOCs, below)
local counters = {}
local currentChapterToc
function VisitHeader(hdr)
local headerPlainText = pandoc.utils.stringify(hdr)
if headersToIgnore[headerPlainText] then
return nil
end
local counterStr = incCounters(hdr)
updateChapterToc(hdr, counterStr)
if DO_NUMBER_HEADERS then
local content = append({pandoc.Str(counterStr .. " ")}, hdr.content)
return pandoc.Header(hdr.level, content, hdr.attr)
else
return nil
end
end
function updateChapterToc(hdr, counterStr)
if hdr.level <= CHAPTER_LEVEL then
-- Part or new chapter? Don’t log sections, anymore
currentChapterToc = nil
end
if hdr.level == CHAPTER_LEVEL then
currentChapterToc = {}
idToChapterToc[hdr.identifier] = currentChapterToc
end
if hdr.level > CHAPTER_LEVEL and currentChapterToc ~= nil and (hdr.level - CHAPTER_LEVEL) <= 2 then
table.insert(currentChapterToc,
{
indent = hdr.level,
content = pandoc.Plain({
pandoc.Str(counterStr .. " "),
pandoc.Link(hdr.content, "#" .. hdr.identifier)
})
})
end
end
function incCounters(hdr)
local firstCounterLevel
if hdr.level == PART_LEVEL then
-- Parts don’t affect subsequent levels
addZerosUntilAtLevel(hdr.level)
firstCounterLevel = PART_LEVEL
else
addZerosUntilAtLevel(hdr.level)
pruneToLevel(hdr.level)
firstCounterLevel = CHAPTER_LEVEL
end
counters[hdr.level] = counters[hdr.level] + 1
return countersToString(firstCounterLevel, hdr.level)
end
function addZerosUntilAtLevel(level)
while #counters < level do
table.insert(counters, 0)
end
end
function pruneToLevel(level)
while #counters > level do
table.remove(counters)
end
end
function countersToString(firstCounterLevel, lastCounterLevel)
-- For parts, only the part number is used, subsequent levels are ignored
-- For chapters and lower, the part number is ignored
local result = ""
for k,v in pairs(counters) do
if k > lastCounterLevel then break end
if k >= firstCounterLevel then
if k == PART_LEVEL then
result = result .. pandoc.utils.to_roman_numeral(v) .. "."
else
result = result .. v .. "."
end
end
end
return result
end
-- ////////// Create chapter TOCs \\\\\\\\\\
local currentChapterId
function TrackChapterId(hdr)
if hdr.level == CHAPTER_LEVEL then
currentChapterId = hdr.identifier
end
end
function ChapterTocBlock(el)
if (el.format == "tex") then
if (el.text == "\\ChapterToc" and currentChapterId ~= nil) then
local result = {}
table.insert(result, pandoc.HorizontalRule())
local tocEntries = idToChapterToc[currentChapterId]
local bulletList = tocEntriesToBulletLists(tocEntries, 1, 0).bulletList
if bulletList ~= nil then
table.insert(result, pandoc.Div(bulletList, pandoc.Attr(nil, {"chapter-toc"})))
end
table.insert(result, pandoc.HorizontalRule())
return result
end
end
return nil
end
function tocEntriesToBulletLists(tocEntries, index, parentIndent)
if index > #tocEntries then
return { nextIndex = index, bulletList = nil }
end
local listIndent = tocEntries[index].indent
if listIndent <= parentIndent then
return { nextIndex = index, bulletList = nil }
end
local bulletListItems = {}
while true do
if index > #tocEntries then
break
end
local tocEntry = tocEntries[index]
if tocEntry.indent < listIndent then
break
end
if tocEntry.indent > listIndent then
-- Should have been collected as a child
error()
end
local children = tocEntriesToBulletLists(tocEntries, index+1, listIndent)
if children.bulletList ~= nil then
table.insert(bulletListItems, {tocEntry.content, children.bulletList})
else
table.insert(bulletListItems, {tocEntry.content})
end
index = children.nextIndex
end
return { nextIndex = index, bulletList = pandoc.BulletList(bulletListItems) }
end
function ChapterTocBlockLatex(el)
if (el.format == "tex") then
if (el.text == "\\ChapterToc") then
return pandoc.RawBlock("latex", "\\minitoc")
end
end
return nil
end
-- ////////// Set up everything \\\\\\\\\\
function setup(meta)
-- Command line: --metadata=header_tools_add_numbers:true
if meta.header_tools_add_numbers == true or meta.header_tools_add_numbers == false then
DO_NUMBER_HEADERS = meta.header_tools_add_numbers
else
error("Illegal value for 'header_tools_add_numbers': " .. meta.header_tools_add_numbers)
end
-- Command line: --metadata=header_tools_has_parts:true
if meta.header_tools_has_parts == true then
PART_LEVEL = 1
CHAPTER_LEVEL = 2
elseif meta.header_tools_has_parts == false then
PART_LEVEL = -1
CHAPTER_LEVEL = 1
else
error("Illegal value for 'header_tools_has_parts': " .. meta.header_tools_has_parts)
end
end
-- ////////// Tool functions \\\\\\\\\\
function insertInto(source, target)
for _,v in pairs(source) do
table.insert(target, v)
end
return target
end
function append(t1, t2)
local result = {};
insertInto(t1, result)
insertInto(t2, result)
return result
end
function printTable(tbl)
for k,v in pairs(tbl) do
print('KEY', k, 'VALUE', v)
end
end
-- ////////// Specify passes \\\\\\\\\\
if FORMAT == "latex" then
return {{RawBlock = ChapterTocBlockLatex}}
else
return {
{Meta = setup}, {Header = VisitHeader}, -- setup, number Headers
{Header = TrackChapterId, RawBlock = ChapterTocBlock} -- create chapter TOCs
}
end
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Demo</title>
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<header id="title-block-header">
<h1 class="title">Demo</h1>
</header>
<nav id="TOC">
<ul>
<li><a href="#background">I. Background</a><ul>
<li><a href="#history">1. History</a></li>
<li><a href="#tips">2. Tips</a></li>
</ul></li>
<li><a href="#main">II. Main</a><ul>
<li><a href="#syntax">3. Syntax</a><ul>
<li><a href="#expressions">3.1. Expressions</a></li>
<li><a href="#statements">3.2. Statements</a></li>
</ul></li>
<li><a href="#library">4. Library</a></li>
</ul></li>
<li><a href="#appendix">III. Appendix</a><ul>
<li><a href="#acknowledgements">5. Acknowledgements</a></li>
</ul></li>
</ul>
</nav>
<h1 id="background">I. Background</h1>
<h2 id="history">1. History</h2>
<h2 id="tips">2. Tips</h2>
<h1 id="main">II. Main</h1>
<h2 id="syntax">3. Syntax</h2>
<p>BEFORE</p>
<hr />
<div class="chapter-toc">
<ul>
<li>3.1. <a href="#expressions">Expressions</a>
<ul>
<li>3.1.1. <a href="#special-expressions">Special expressions</a></li>
</ul></li>
<li>3.2. <a href="#statements">Statements</a></li>
</ul>
</div>
<hr />
<p>AFTER</p>
<h3 id="expressions">3.1. Expressions</h3>
<h4 id="special-expressions">3.1.1. Special expressions</h4>
<h3 id="statements">3.2. Statements</h3>
<h2 id="library">4. Library</h2>
<h1 id="appendix">III. Appendix</h1>
<h2 id="acknowledgements">5. Acknowledgements</h2>
<!--
pandoc -t html --standalone --toc --lua-filter=header-tools.lua --metadata=header_tools_has_parts:true --metadata=header_tools_add_numbers:true header-tools-demo.md
-->
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment