Lualatex + unicode-math 很棒,但我希望能够输入 $Â$ (in vscode
) 来获得与输入 $\hat A$ 相同的效果。所以我写了下面的笨重代码,它完全符合我的要求,但必须有一种更干净/更便宜的方法来实现同样的效果吗?当我说昂贵时,我的意思是它会搜索行中的每个字符,然后逐步执行,更改输入。
关于我的LuaLaTeX代码可以改进吗?我正在寻找仅限 lualatex 的解决方案。
% !TeX program = lualatex
\documentclass{article}
\usepackage{unicode-math}
\usepackage{fontspec}
\setmathfont{STIX Two Math} % for the weird accents
\directlua{
function fixline( line, nm, str, ch )
beg,fin = unicode.utf8.find( line, ch )
if beg == nil then return line end
lastp = 0
lastc = 0
nline = ""
for p,c in utf8.codes( line ) do
if c == nm then
if lastc == 0 then
else
nline = nline..str..utf8.char( lastc )
end
lastc = 0
else
if lastc == 0 then
else
nline = nline..utf8.char( lastc )
end
lastc = c
end
lastp = p
end
if lastc == 0 then
else
nline = nline..utf8.char( lastc )
end
return nline
end
function ParseMe( line )
line = fixline( line, 770, "\\hat ", "̂" )
line = fixline( line, 771, "\\tilde ", "̃" )
line = fixline( line, 772, "\\bar ", "̄" )
line = fixline( line, 773, "\\tilde ", "̃" )
line = fixline( line, 774, "\\breve ", "̆" )
line = fixline( line, 775, "\\dot ", "̇" )
line = fixline( line, 776, "\\ddot ", "̈" )
line = fixline( line, 778, "\\ocirc ", "̊" )
line = fixline( line, 780, "\\check ", "̌" )
line = fixline( line, 768, "\\grave ", "̀" )
line = fixline( line, 769, "\\acute ", "́" )
line = fixline( line, 8407, "\\vec ", "⃗" )
line = fixline( line, 8411, "\\dddot ", "⃛" )
line = fixline( line, 777, "\\ovhook ", "̉" )
line = fixline( line, 786, "\\oturnedcomma ", "̒" )
line = fixline( line, 784, "\\candra ", "̐" )
line = fixline( line, 8406, "\\overleftarrow ", "⃖" )
line = fixline( line, 8432, "\\asteraccent ", "⃰" )
line = fixline( line, 8423, "\\annuity ", "⃧" )
line = fixline( line, 8417, "\\overleftrightarrow ", "⃡" )
line = fixline( line, 8401, "\\rightharpoonaccent ", "⃑" )
line = fixline( line, 8400, "\\leftharpoonaccent ", "⃐" )
line = fixline( line, 794, "\\droang ", "̚" )
line = fixline( line, 789, "\\ocommatopright ", "̕" )
line = fixline( line, 8425, "\\widebridgeabove ", "⃩" )
return line
end
id,error = luatexbase.add_to_callback("process_input_buffer", ParseMe, "Beautiful Accents" )
}
\begin{document}
\[
Ã,Â,Ă,Ā,Ȧ,Ä,Å,Ǎ,A⃗,À,Á,A⃛,Ả,A⃖,A̐,A⃰,A̒,A̕,A̚,A⃐,A⃑,A⃡,A⃧,A⃩,Â
\]
\end{document}
答案1
我想说使用pre_mlist_to_hlist_filter
回调直接对节点进行操作比在里面进行文本替换要干净得多process_input_buffer
,但也复杂得多:
\documentclass[12pt,fleqn]{article}
\pagestyle{empty}
\setlength{\parindent}{0pt}
\usepackage{unicode-math}
\setmathfont{STIX Two Math}
\csname@mathmargin\endcsname=0pt
\usepackage{luacode}
\begin{luacode*}
-- Save local versions of some frequently-used globals
local combining_classes = require("luaotfload-unicode").ccc
local fields = node.fields
local get_font = font.getfont
local ipairs = ipairs
local is_node = node.is_node
local new_node = node.new
local slide = node.slide
-- Define some constants
local ACCENT = 200 -- Something with a “Canonical Combining Class Value”
-- ≥ 200 is probably an accent
local accent_id = node.id("accent")
local BAD_FIELDS = {
id = true,
next = true,
prev = true,
subtype = true,
}
local mathchar_id = node.id("math_char")
local noad_id = node.id("noad")
-- The main function
local function fix_accents(head)
-- Loop through all the nodes
local n = head
repeat
-- Recurse
for _, field in ipairs(fields(n.id)) do
if is_node(n[field]) and field ~= "attr" then
n[field] = fix_accents(n[field])
end
end
-- See if the current node is an accent character typeset as a
-- regular math character
if n.id == noad_id and
n.nucleus and
n.nucleus.id == mathchar_id and
(combining_classes[n.nucleus.char] or 0) >= ACCENT
then
-- Get the accent and the preceding character (its base)
local accent = n
local base = n.prev
-- Create a new “accent” node
local new = new_node(accent_id)
-- Copy over all the fields
for _, field in ipairs(fields(accent.id)) do
if not BAD_FIELDS[field] and accent[field] then
new[field] = accent[field]
end
end
for _, field in ipairs(fields(base.id)) do
if not BAD_FIELDS[field] and base[field] then
new[field] = base[field]
end
end
-- Set the new nucleus and accent fields
new.nucleus = base.nucleus
new.accent = accent.nucleus
-- Get the fonts used for the accent and the base
local accent_font = get_font(accent.nucleus.font)
local base_font = get_font(base.nucleus.font)
-- If the accent isn't available in its original font, check
-- if it's in the base glyph's font
if not accent_font.characters[accent.nucleus.char] and
base_font.characters[accent.nucleus.char]
then
-- Use the base glyph's font
new.accent.fam = new.nucleus.fam
end
-- Replace the accent and base nodes with the new “accent” node
if base.prev then
base.prev.next = new
else
head = new
end
new.next = accent.next
n = new
slide(head)
end
n = n.next
until not n
return head
end
-- Define the callback
luatexbase.add_to_callback(
"pre_mlist_to_hlist_filter",
fix_accents,
"fix_accents"
)
\end{luacode*}
\begin{document}
\begin{tabular}{p{8em}p{6em}}
All the accents:
\begin{equation*}
\begin{array}{*5c}
à &  & Ă & Ā & Ȧ \\
Ä & Å & Ǎ & A⃗ & À \\
Á & A⃛ & Ả & A⃖ & A̐ \\
A⃰ & A̒ & A̕ & A̚ & A⃐ \\
A⃑ & A⃡ & A⃧ & A⃩ & Ẫ
\end{array}
\end{equation*}
&
Nested:
\begin{equation*}
\sqrt[A̚]{Â^{\frac{Ã}{Å_{A⃰^{Ä}}}}}
\end{equation*}
\end{tabular}
\end{document}