Last active
June 13, 2019 02:02
-
-
Save hmenke/a41574ef0b5000635986f0dec73e066f to your computer and use it in GitHub Desktop.
tag_math
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local unimath_symbols = require("unimath_symbols") | |
local convert_char = unimath_symbols.convert_char | |
local converters = {} | |
local function convert(n) | |
local id = n.id | |
local type = node.type(id) | |
local typeconv = converters[type] | |
if typeconv then | |
return typeconv(n) or "" | |
else | |
texio.write_nl("tag_math warning: no conversion available for " .. type) | |
return "" | |
end | |
end | |
function converters.noad(n) | |
if not (n.nucleus.head or n.nucleus.char) then | |
-- This is a thing, e.g. ${}$ is just an empty noad | |
return | |
end | |
local result = convert(n.nucleus) | |
local subtype = node.subtypes(n.id)[n.subtype] | |
if subtype == "oplimits" then | |
result = result .. "\\limits" | |
elseif subtype == "opdisplaylimits" then | |
result = result .. "\\displaylimits" | |
end | |
if n.sub then | |
result = result .. "_{" .. convert(n.sub) .. "}" | |
end | |
if n.sup then | |
result = result .. "^{" .. convert(n.sup) .. "}" | |
end | |
return result | |
end | |
function converters.math_char(n) | |
return convert_char(n.char) | |
end | |
function converters.sub_mlist(n) | |
local result = "" | |
for n in node.traverse(n.head) do | |
result = result .. convert(n) | |
end | |
return result | |
end | |
function converters.fence(n, subtype) | |
local subtype = node.subtypes(n.id)[n.subtype] | |
local leftright = { left = "\\left", right = "\\right" } | |
local result | |
if n.delim.small_char ~= 0 then | |
result = convert_char(n.delim.small_char) | |
elseif n.delim.large_char ~= 0 then | |
result = convert_char(n.delim.large_char) | |
else | |
result = "." | |
end | |
return leftright[subtype] .. result | |
end | |
function converters.fraction(n) | |
local num = convert(n.num) | |
local denom = convert(n.denom) | |
return "\\frac{" .. num .. "}{" .. denom .. "}" | |
end | |
function converters.radical(n) | |
local result = "\\sqrt{" .. convert(n.nucleus) .. "}" | |
if n.sub then | |
result = result .. "_{" .. convert(n.sub) .. "}" | |
end | |
if n.sup then | |
result = result .. "^{" .. convert(n.sup) .. "}" | |
end | |
return result | |
end | |
function converters.style(n) | |
return "\\" .. n.style .. "style" | |
end | |
function converters.accent(n) | |
local result = convert(n.nucleus) | |
if n.accent then | |
result = convert(n.accent) .. "{" .. result .. "}" | |
end | |
if n.bot_accent then | |
result = convert(n.bot_accent) .. "{" .. result .. "}" | |
end | |
if n.sub then | |
result = result .. "_{" .. convert(n.sub) .. "}" | |
end | |
if n.sup then | |
result = result .. "^{" .. convert(n.sup) .. "}" | |
end | |
return result | |
end | |
function converters.glue(n) | |
-- FIXME: any glue is treated like space | |
return " " | |
end | |
function converters.kern(n) | |
-- FIXME: any kern is just dropped | |
return "" | |
end | |
local function callback(head, display_type, need_penalties) | |
local text = {} | |
for n in node.traverse(head) do | |
text[#text + 1] = convert(n) | |
end | |
-- concatenate, escape, and remove quotes | |
local actual_text = string.sub(string.format("%q", table.concat(text)), 2, -2) | |
if display_type == "display" then | |
actual_text = "\\\\[" .. actual_text .. "\\\\]" | |
elseif display_type == "text" then | |
actual_text = "\\\\(" .. actual_text .. "\\\\)" | |
end | |
local BDC = node.new("whatsit", "pdf_literal") | |
BDC.data = "/Span <</ActualText(" .. actual_text .. ")>> BDC" | |
BDC.mode = 2 | |
head = node.insert_before(head, head, BDC) | |
local EMC = node.new("whatsit", "pdf_literal") | |
EMC.data = "EMC" | |
EMC.mode = 2 | |
head = node.insert_after(head, node.tail(head), EMC) | |
return head | |
end | |
return { callback = callback } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\pdfvariable compresslevel 0 | |
\pdfvariable objcompresslevel 0 | |
\documentclass{article} | |
\pagestyle{empty} | |
\usepackage{amsmath} | |
\usepackage{unicode-math} | |
\DeclareMathOperator\Res{Res} | |
\directlua{tag_math = require("tag_math")} | |
\AtBeginDocument{\directlua{ | |
luatexbase.add_to_callback("mlist_to_hlist", | |
function(head, display_type, need_penalties) | |
head = tag_math.callback(head, display_type, need_penalties) | |
return node.mlist_to_hlist(head, display_type, need_penalties) | |
end, "tag_math") | |
}} | |
\begin{document} | |
$ | |
\frac{1}{2\pi i} \int\limits_\gamma f\left(x^{\symbf{N}\in\mathbb{C}^{N\times 10}}\right) | |
= \sum_{k=1}^m n(\gamma;a_k)\Res(f;a_k)\,. | |
$ | |
\[ | |
\frac{1}{\sqrt{2\pi}^2 i} \int\limits_\gamma f\left(x^{\symbf{N}\in\mathbb{C}^{N\times 10}}\right) | |
= \sum_{k=1}^m n(\gamma;a_k)\Res(f;a_k)\,. | |
\] | |
$a^2 + b^2 = c^2$ | |
$$a^2 + b^2 = c^2$$ | |
\(a^2 + b^2 = c^2\) | |
\[a^2 + b^2 = c^2\] | |
% tag_math warning: no conversion available for sub_box | |
% That is because \eqno is a \hbox in math mode | |
\begin{equation} | |
a^2 + b^2 = c^2 | |
\end{equation} | |
% Ideas for handling environments: | |
% | |
% Instead of flushing /ActualText for each mlist immediately, insert whatsits | |
% to delimit the environment and insert a whatsit at the head or tail with the | |
% /ActualText inside for each mlist. Then in post_linebreak_filter (or | |
% earlier?), scan for environment and the nested /ActualText whatsits and | |
% assemble a single BDC and EMC whatsit from them. | |
% Clear downside: this is a two stage process which requires extensive | |
% bookkeeping across callbacks. | |
\begin{align} | |
a^2 + b^2 &= c^2 \\ | |
a^2 + b^2 &= c^2 | |
\end{align} | |
% Accents | |
% Why does this appear *before* the equation environment in the PDF??? | |
$\threeunderdot{\hat{x}_a^b}_c^d$ | |
\end{document} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local unimath_symbols = {} | |
local f = io.open(kpse.find_file("unicode-math-table.tex"), "r") | |
for line in f:lines() do | |
local slot, cmd = string.match(line, [[^\UnicodeMathSymbol{"([%a%d]*)}{([^}%s]*)%s*}]]) | |
if slot then | |
unimath_symbols[tonumber(slot, 16)] = cmd | |
end | |
end | |
f:close() | |
return { | |
convert_char = function(c) | |
return unimath_symbols[c] or utf.char(c) | |
end | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment