将参数从 Latex 命令传递给 Lua 命令

将参数从 Latex 命令传递给 Lua 命令

我读过这篇文章使用 LuaLaTeX 自动改变字母间距(单词内间距)以避免出现松散的线条我想对其进行调整以创建一个\InterletterGlueEnable带有两个参数的命令。问题是我无法在用 Lua 编写的命令中传递这两个参数的值。你知道怎么做吗?
这是我的 MWE:

\documentclass{article}
\usepackage{luacode, xargs}
\usepackage[a4paper, landscape, left=1cm, right=1cm, top=1cm, bottom=1cm, nohead]{geometry}

\def\sample{%
Even though using "lorem ipsum" often arouses curiosity due to its resemblance to classical Latin, it is not intended to have meaning. Where text is visible in a document, people tend to focus on the textual content rather than upon overall presentation, so publishers use lorem ipsum when displaying a typeface or design in order to direct the focus to presentation. "Lorem ipsum" also approximates a typical distribution of spaces in English.\par
The most common lorem ipsum text reads as follows: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. The text is derived from Cicero's De Finibus Bonorum et Malorum (On the Ends of Goods and Evils, or alternatively [About] The Purposes of Good and Evil ).\par
}

\begin{luacode}
local interletter_glue = node.new('glue')
interletter_glue.width = tex.sp(0)
-- interletter_glue.stretch = tex.sp('5pt')
-- interletter_glue.shrink = tex.sp('1pt')
local interletter_pen = node.new('penalty')
interletter_pen.penalty = 10000

function add_interletter_glue(head, interletter_glue.stretch, interletter_glue.shrink) 
    for glyph in node.traverse_id(node.id('glyph'), head) do
        if glyph.prev and (glyph.prev.id == node.id('glyph') 
            or glyph.prev.id == node.id('disc') 
            or glyph.prev.id == node.id('kern')) then
            local g = node.copy(interletter_glue)
            node.insert_before(head, glyph, g)
            node.insert_before(head, g, node.copy(interletter_pen))
        end
    end
    return head
end
\end{luacode}

\newcommandx{\InterletterGlueEnable}[2][1=5pt, 2=1pt, usedefault]{\directlua{luatexbase.add_to_callback("pre_linebreak_filter", add_interletter_glue(,tex.sp('#1'),tex.sp('#2')), "variableInterletterSpacing")}}
\newcommand{\InterletterGlueDisable}{\directlua{luatexbase.remove_from_callback("pre_linebreak_filter", "variableInterletterSpacing")}}

\begin{document}
\begin{minipage}[t]{13em}
    \noindent\textbf{No tracking :}

    \sample
\end{minipage}
\qquad
\begin{minipage}[t]{13em}
    \InterletterGlueEnable
    \noindent\textbf{Tracking 1:}
    
    \sample
    \InterletterGlueDisable{}
\end{minipage}
\qquad
\begin{minipage}[t]{13em}
    \InterletterGlueEnable[0.5pt][0.1pt]
    \noindent \textbf{Tracking 2:}
    
    \sample
    \InterletterGlueDisable{}
\end{minipage}
\end{document}

答案1

存在多个问题:

  1. Lua 函数的参数名必须是普通变量名,这些变量名声明了具有函数作用域的变量。它们不能是现有变量的字段。因此你不能使用
    function add_interletter_glue(head, interletter_glue.stretch, interletter_glue.shrink)
    
    但必须使用类似
    function add_interletter_glue(head, ilg_stretch, ilg_shrink)
      interletter_glue.stretch = ilg_stretch
      interletter_glue.shrink = ilg_shrink
    
    反而。
  2. Lua 函数的参数列表不能以逗号开头,因此
    add_interletter_glue(,tex.sp('#1'),tex.sp('#2'))
    
    是不允许的。要修复函数的某些参数,同时仍保留带参数的函数,可以使用闭包和返回函数的函数.例如add_interletter_glue可以写成
    function add_interletter_glue(ilg_stretch, ilg_shrink)
        return function(head) 
            interletter_glue.stretch, interletter_glue.shrink = ilg_stretch, ilg_shrink
            for glyph in node.traverse_id(node.id('glyph'), head) do
                ...
            end
            return head
        end
    end
    
    成为一个具有两个参数的函数,返回一个具有一个参数的函数,该函数可用作回调。

这可以结合起来

\documentclass{article}
\usepackage{luacode}
\usepackage[a4paper, landscape, left=1cm, right=1cm, top=1cm, bottom=1cm, nohead]{geometry}

\def\sample{%
Even though using "lorem ipsum" often arouses curiosity due to its resemblance to classical Latin, it is not intended to have meaning. Where text is visible in a document, people tend to focus on the textual content rather than upon overall presentation, so publishers use lorem ipsum when displaying a typeface or design in order to direct the focus to presentation. "Lorem ipsum" also approximates a typical distribution of spaces in English.\par
The most common lorem ipsum text reads as follows: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. The text is derived from Cicero's De Finibus Bonorum et Malorum (On the Ends of Goods and Evils, or alternatively [About] The Purposes of Good and Evil ).\par
}

\begin{luacode}
local interletter_glue = node.new('glue')
interletter_glue.width = 0
local interletter_pen = node.new('penalty')
interletter_pen.penalty = 10000

function add_interletter_glue(interletter_glue_stretch, interletter_glue_shrink) 
  return function(head)
    for glyph in node.traverse_id(node.id('glyph'), head) do
        if glyph.prev and (glyph.prev.id == node.id('glyph') 
          or glyph.prev.id == node.id('disc') 
          or glyph.prev.id == node.id('kern')) then
        local g = node.copy(interletter_glue)
        g.attr = glyph.attr
        g.stretch = interletter_glue_stretch
        g.shrink = interletter_glue_shrink
        node.insert_before(head, glyph, g)
        local p = node.copy(interletter_pen)
        p.attr = glyph.attr
        node.insert_before(head, g, p)
      end
    end
    return head
  end
end
\end{luacode}

\NewDocumentCommand \InterletterGlueEnable {O{5pt} O{1pt}}{\directlua{luatexbase.add_to_callback("pre_linebreak_filter", add_interletter_glue(tex.sp('#1'),tex.sp('#2')), "variableInterletterSpacing")}}
\NewDocumentCommand \InterletterGlueDisable {}{\directlua{luatexbase.remove_from_callback("pre_linebreak_filter", "variableInterletterSpacing")}}

\begin{document}
\begin{minipage}[t]{13em}
  \noindent\textbf{No tracking :}

  \sample
\end{minipage}
\qquad
\begin{minipage}[t]{13em}
  \InterletterGlueEnable
  \noindent\textbf{Tracking 1:}
  
  \sample
  \InterletterGlueDisable
\end{minipage}
\qquad
\begin{minipage}[t]{13em}
  \InterletterGlueEnable[0.5pt][0.1pt]
  \noindent \textbf{Tracking 2:}
  
  \sample
  \InterletterGlueDisable
\end{minipage}
\end{document}

相关内容