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,137 @@
-- Process quotes for Chinese bibliographies in HTML, EPUB, LaTeX and Typst
--- Copyright: © 2024Present Tom Ben
--- License: MIT License
function is_chinese(text)
return text:find("[\228-\233][\128-\191][\128-\191]")
end
local left_double_quote = "\226\128\156" -- “
local right_double_quote = "\226\128\157" -- ”
local left_single_quote = "\226\128\152" --
local right_single_quote = "\226\128\153" --
local function stringify_inline(inline)
if inline.t == "Str" then
return inline.text
end
if pandoc.utils and pandoc.utils.stringify then
return pandoc.utils.stringify(inline)
end
return ""
end
local function text_between(elements, start_idx, end_idx)
if end_idx <= start_idx + 1 then
return ""
end
local buffer = {}
for j = start_idx + 1, end_idx - 1 do
local text = stringify_inline(elements[j])
if text ~= "" then
table.insert(buffer, text)
end
end
return table.concat(buffer)
end
local function find_closing(elements, start_idx, target)
for j = start_idx, #elements do
local el = elements[j]
if el.t == "Str" and el.text == target then
return j
end
end
return nil
end
local function process_default_quotes(block)
local elements = block.c
for i, el in ipairs(elements) do
if el.t == "Str" and (el.text == left_double_quote or el.text == right_double_quote) then
local prev_text = i > 1 and elements[i - 1].t == "Str" and elements[i - 1].text or ""
local next_text = i < #elements and elements[i + 1].t == "Str" and elements[i + 1].text or ""
if is_chinese(prev_text) or is_chinese(next_text) then
local replaced_text
if FORMAT:match 'html' or FORMAT:match 'epub' then
replaced_text = (el.text == left_double_quote) and "" or ""
elseif FORMAT:match 'latex' then
replaced_text = (el.text == left_double_quote) and "«" or "»"
end
if replaced_text then
elements[i] = pandoc.Str(replaced_text)
end
end
end
end
return block
end
local function process_typst_quotes(block)
local elements = block.c
local processed = {}
local quote_pairs = {
{
left = left_double_quote,
right = right_double_quote,
latin = '"',
chinese_left = "«",
chinese_right = "»"
},
{
left = left_single_quote,
right = right_single_quote,
latin = "'",
chinese_left = "",
chinese_right = ""
}
}
for i = 1, #elements do
if not processed[i] then
local el = elements[i]
if el.t == "Str" then
for _, quote in ipairs(quote_pairs) do
if el.text == quote.left then
local closing_idx = find_closing(elements, i + 1, quote.right)
if closing_idx then
local enclosed_text = text_between(elements, i, closing_idx)
local has_chinese = is_chinese(enclosed_text or "")
if has_chinese then
elements[i] = pandoc.Str(quote.chinese_left)
elements[closing_idx] = pandoc.Str(quote.chinese_right)
else
elements[i] = pandoc.RawInline("typst", quote.latin)
elements[closing_idx] = pandoc.RawInline("typst", quote.latin)
end
processed[closing_idx] = true
end
break
elseif el.text == quote.right then
processed[i] = true
end
end
end
end
end
return block
end
function quotes_in_bib(block)
if FORMAT:match 'typst' then
return process_typst_quotes(block)
end
return process_default_quotes(block)
end
function Pandoc(doc)
for i, block in ipairs(doc.blocks) do
if block.t == "Div" then
doc.blocks[i] = pandoc.walk_block(block, { Span = quotes_in_bib })
end
end
return doc
end