add _extensions

This commit is contained in:
2026-05-21 13:37:53 +08:00
parent 6a9a5fc90e
commit 61bd0bea2f
252 changed files with 33972 additions and 1 deletions
@@ -0,0 +1,180 @@
-- Prepare LaTeX headers so quotation marks render correctly in the PDF body
-- while keeping proper Unicode text in PDF bookmarks.
--- Copyright: © 2025Present Tom Ben
--- License: MIT License
local function format_is(name)
return FORMAT:match(name) ~= nil
end
local function to_macro_block(inlines)
return pandoc.walk_block(pandoc.Plain(inlines), {
Quoted = function(el)
local opening, closing
if el.quotetype == "SingleQuote" then
opening = pandoc.RawInline('latex', "`")
closing = pandoc.RawInline('latex', "'")
else
opening = pandoc.RawInline('latex', "``")
closing = pandoc.RawInline('latex', "''")
end
local result = pandoc.Inlines { opening }
for _, inline in ipairs(el.content) do
result:insert(inline)
end
result:insert(closing)
return result
end
})
end
local function to_unicode_block(inlines)
return pandoc.walk_block(pandoc.Plain(inlines), {
Quoted = function(el)
local opening, closing
if el.quotetype == "SingleQuote" then
opening, closing = '', ''
else
opening, closing = '', ''
end
local result = pandoc.Inlines { pandoc.Str(opening) }
for _, inline in ipairs(el.content) do
result:insert(inline)
end
result:insert(pandoc.Str(closing))
return result
end,
Str = function(el)
-- Replace guillemets with curly quotes for PDF bookmarks
local text = el.text
text = text:gsub('«', '')
text = text:gsub('»', '')
text = text:gsub('', '')
text = text:gsub('', '')
if text ~= el.text then
return pandoc.Str(text)
end
return el
end
})
end
function Header(header)
if not format_is('latex') then
return header
end
local attr = header.attr
local macro_block = to_macro_block(header.content)
local unicode_block = to_unicode_block(header.content)
local latex_doc = pandoc.Pandoc({ macro_block }, pandoc.Meta {})
local latex_body = pandoc.write(latex_doc, 'latex')
:gsub('%s+$', '')
:gsub('\n', ' ')
local bookmark_text = pandoc.utils.stringify(unicode_block)
:gsub('\n', ' ')
attr.attributes['data-tex-body'] = latex_body
attr.attributes['data-bookmark'] = bookmark_text
return header
end
local latex_heading_levels = {
"section",
"subsection",
"subsubsection",
"paragraph",
"subparagraph",
"subparagraph"
}
local function escape_tex_argument(text)
local map = {
['\\'] = '\\\\',
['{'] = '\\{',
['}'] = '\\}',
['%'] = '\\%',
['#'] = '\\#',
['&'] = '\\&',
['_'] = '\\_',
['^'] = '\\^{}',
['~'] = '\\~{}'
}
return text:gsub('[\\%%#&_{}%^~]', map)
end
local function heading_to_raw(header)
local tex_body = header.attr.attributes['data-tex-body']
if not tex_body then
return nil
end
local bookmark = header.attr.attributes['data-bookmark'] or pandoc.utils.stringify(header)
header.attr.attributes['data-tex-body'] = nil
header.attr.attributes['data-bookmark'] = nil
local short_attr = header.attr.attributes['short-title'] or header.attr.attributes['short']
if short_attr and short_attr ~= '' then
bookmark = short_attr
end
bookmark = tostring(bookmark):gsub('\n', ' ')
local level_index = math.min(header.level, #latex_heading_levels)
local command = latex_heading_levels[level_index]
local classes = header.attr.classes or {}
local unnumbered = false
for _, class in ipairs(classes) do
if class == 'unnumbered' then
unnumbered = true
break
end
end
local number_attr = header.attr.attributes['number']
if number_attr == 'no' or number_attr == 'false' or number_attr == '0' then
unnumbered = true
end
local star = unnumbered and '*' or ''
local bookmark_escaped = escape_tex_argument(bookmark)
local texorpdfstring = '\\texorpdfstring{' .. tex_body .. '}{' .. bookmark_escaped .. '}'
local pieces = { '\\' .. command .. star .. '{' .. texorpdfstring .. '}' }
local identifier = header.attr.identifier
if identifier and identifier ~= '' then
table.insert(pieces, '\\label{' .. identifier .. '}')
end
if unnumbered then
table.insert(pieces, '\\addcontentsline{toc}{' .. command .. '}{' .. bookmark_escaped .. '}')
end
return pandoc.RawBlock('latex', table.concat(pieces, '') .. '\n')
end
function Pandoc(doc)
if not format_is('latex') then
return doc
end
local blocks = pandoc.List:new()
for _, block in ipairs(doc.blocks) do
if block.t == 'Header' then
blocks:insert(heading_to_raw(block) or block)
else
blocks:insert(block)
end
end
doc.blocks = blocks
return doc
end
return {
{ Header = Header },
{ Pandoc = Pandoc }
}