在 LuaLateX 中获取重音数学符号的更简洁方法

在 LuaLateX 中获取重音数学符号的更简洁方法

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}

输出

相关内容