Repository navigation
Expand file tree
/
Copy pathkindle-filter.lua
More file actions
158 lines (141 loc) · 4.78 KB
/
Copy pathkindle-filter.lua
File metadata and controls
158 lines (141 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
-- kindle-filter.lua
-- Pandoc Lua filter for Kindle EPUB output
-- Adapts box-filter.lua for HTML/EPUB output instead of LaTeX
-- Handles: Part dividers, epigraphs, styled boxes, horizontal rules.
-- Map div classes to HTML div classes for CSS styling
local box_map = {
technical = "technical-box",
insight = "insight-box",
caution = "caution-box",
example = "example-box",
patient = "insight-box",
regulatory = "example-box",
}
-- Handle fenced divs: ::: {.technical} ... :::
function Div(el)
for cls, html_cls in pairs(box_map) do
if el.classes:includes(cls) then
local blocks = {}
table.insert(blocks, pandoc.RawBlock("html",
'<div class="' .. html_cls .. '">'))
for _, b in ipairs(el.content) do
table.insert(blocks, b)
end
table.insert(blocks, pandoc.RawBlock("html", '</div>'))
return blocks
end
end
end
-- Handle blockquotes: epigraphs and Technical Detail boxes
function BlockQuote(el)
if #el.content > 0 then
local first = el.content[1]
if first.t == "Para" and #first.content > 0 then
local first_inline = first.content[1]
-- Epigraph detection: blockquote starting with italic text in quotes
if first_inline.t == "Emph" then
local emph_text = pandoc.utils.stringify(first_inline)
if emph_text:match('^[\"\x93]') or emph_text:match("^[\'\x91]") then
local quote_parts = {}
local attribution = ""
for _, block in ipairs(el.content) do
if block.t == "Para" then
local line = pandoc.utils.stringify(block)
if line:match("^%-%-") then
attribution = line:gsub("^%-+%s*", "")
else
table.insert(quote_parts, line)
end
end
end
local quote_text = table.concat(quote_parts, " ")
quote_text = quote_text:gsub('^[\"\x93\x94]', '')
quote_text = quote_text:gsub('[\"\x93\x94]$', '')
local html = '<div class="epigraph">\n'
html = html .. '<p><em>' .. quote_text .. '</em></p>\n'
if attribution ~= "" then
html = html .. '<p class="attribution">' .. attribution .. '</p>\n'
end
html = html .. '</div>'
return pandoc.RawBlock("html", html)
end
end
-- Auto-detect blockquotes starting with "Technical Detail"
if first_inline.t == "Strong" then
local text = pandoc.utils.stringify(first_inline)
if text:match("^Technical Detail") then
local blocks = {}
table.insert(blocks, pandoc.RawBlock("html",
'<div class="technical-box">'))
-- Rebuild without the bold label
local new_inlines = {}
local started = false
for i, inline in ipairs(first.content) do
if i == 1 then
-- skip
elseif not started and inline.t == "Space" then
started = true
else
started = true
table.insert(new_inlines, inline)
end
end
if #new_inlines > 0 then
table.insert(blocks, pandoc.Para(new_inlines))
end
for i = 2, #el.content do
table.insert(blocks, el.content[i])
end
table.insert(blocks, pandoc.RawBlock("html", '</div>'))
return blocks
end
end
end
end
end
-- Process blocks: Part headings, HR suppression
function Blocks(blocks)
local result = {}
local n = #blocks
for i = 1, n do
local el = blocks[i]
-- Handle Part headings → styled div
if el.t == "Header" and el.level == 1 then
local text = pandoc.utils.stringify(el)
if text:match("^Part [IVX]+:") or text:match("^Part [IVX]+ ") then
table.insert(result, pandoc.RawBlock("html",
'<div class="part-divider"><p>' .. text .. '</p></div>'))
goto continue
end
end
-- Handle HorizontalRule: suppress most, keep structural ones
if el.t == "HorizontalRule" then
local prev = (i > 1) and blocks[i - 1] or nil
local next_el = (i < n) and blocks[i + 1] or nil
if next_el and next_el.t == "Header" then
goto continue
end
if prev and prev.t == "Header" then
goto continue
end
if next_el and next_el.t == "RawBlock" then
goto continue
end
if prev and prev.t == "RawBlock" then
local content = prev.text or ""
if content:match("part%-divider") or content:match("epigraph") then
goto continue
end
end
if i <= 2 or i >= n - 1 then
goto continue
end
-- Keep as simple HR
table.insert(result, pandoc.RawBlock("html", "<hr />"))
goto continue
end
table.insert(result, el)
::continue::
end
return result
end