[2012-06-08編集]IXbase バンドルを BXluatool バンドルとして再編した。それに合わせて記事の内容も書き直した。
かなり昔に「思わず Lua で LaTeX してみた」で紹介したように、LuaLaTeX においては、「Lua コードの呼出」を利用することで、LaTeX のマクロ(ユーザ定義命令)の知識だけでかなり複雑な処理ができる。*1LaTeX のマクロで実装すべきなのは、「LaTeX の命令に渡された引数を適切に Lua の関数に渡す」ということだけである。しかし、ここで「LaTeX のマクロ(\newcommand
等)」では解決できないタイプの構造がある。それが verbatim な入力である。そこで、LuaLaTeX において verbatim 入力の扱いを可能にするパッケージを作ってみた。
- BXluatool パッケージバンドル (github/zr-tex8r)
この中の bxluavienv パッケージ。(バンドル内部で依存があり得るので一括してインストールしてほしい。)
※注意 「思わず Lua で…」の解説では、(La)TeX の特殊文字を含む Lua コードを記述するのに、ixbase0 という独自のパッケージを用意してそこで提供される execluacodeblock 環境を用いていた。今では、同じ機能を luacode* 環境として提供する luacode パッケージが CTAN にある(W32TeX にも TeX Live にも収録済)ので、それを用いるのがよいであろう。本記事でも、ixbase0 でなく、luacode を用いることにする。なお、ixbase0 について、luacode と重複する機能を整理したのが同じバンドルに含まれる bxluafacade と bxluatangle である。
このパッケージは次の命令を提供する。
\DeclareVerbInputEnvironment{<名前>}[<整数n>]{<本体>}
: n−1 個の(非 verbatim な)引数を伴う、中身を verbatim に扱う環境(「verbatim入力環境」と呼ぶ)を指定の名前で定義する。環境の処理内容は本体部で指定され、ここは n 個の引数をもつ命令の定義(\newcommand
)と同様の方式で記述する。一番最後の引数(#n
)は環境の中身の文字列((カテゴリコードは(空白文字も含めて)全て 12 であり、改行は CR(^^M
)として表される。))を表し、それ以外の(n−1 個の)引数は環境に渡された実際の引数を現す。n の既定値は 1 (つまり引数のない環境に対応する)である。
最も基本的なパターンが、引数のない環境 hoge があって、その中身の文字列を(verbatim に)Lua の関数 foo に渡せばよいという場合である。これは次のようにして実現できる。
\DeclareVerbInputEnvironment{foo}{% % #1 に環境の中身の文字列が入っている \directlua{ foo(\luastringN{#1}) }% }
\luastringN
は文字列を Lua の文字列リテラルの形に変換するための luacode の命令である。((つまり、「\luastringN{\textbf{A}}
」は「"\\textbf {A}"
」に展開される。ixbase0 の \ixstring
命令と同じ。なお、この記事を書いた当初は \luastring
としていたが、これは引数を完全展開してから文字列リテラルに変換するので、\ixstring
とは異なる。無論、verbatim 入力については展開しても何も変わらない。))環境の中身 #1
を Lua 関数に渡せたので、後は好きなように Lua コードでそれを処理することができる。多くの場合、tex.sprint()
((tex.sprint()
は引数の文字列の各々を「単純に」順に TeX 入力として書き出す。「思わず…」で紹介した tex.print()
と異なり「行として扱う」処理を行わない。通常は sprint
の方が使い易いであろう。)) で LaTeX 側に何か「結果」を返すことになるだろう。
より完全な例を挙げておく。以下の例では、makeshorthands という環境を定義している。これは複数の「略記用」の命令を一度に定義するためのもので、
% 引数は命令名の接頭辞 \begin{makeshorthands}{zzz} aaa=bbbb ccc=dddd # コメント …(同様の形式の行が続く) \end{makeshorthands}
のように用いると、
\newcommand*{\zzzaaa}{bbbb} \newcommand*{\zzzccc}{dddd} ……
という LaTeX 命令が実行され複数の命令が定義される。
\documentclass{article} \usepackage{bxluavienv} \usepackage{luacode} \DeclareVerbInputEnvironment{makeshorthands}[2]{% \directlua{ % Lua 関数に引数を丸投げするだけ make_shorthands(\luastring{#1}, \luastring{#2}) } } \begin{luacode*} -- Lua 関数が実際の仕事をしている shorthands = {} function make_shorthands (prefix, datatable) for _, row in ipairs(datatable:explode("\r+")) do local key, val = row:gsub("%s.*#.*", ""):match("^%s*(%a+)=(.*)$") if not key then error("bad line: "..row) end local csname = "\\"..prefix..key tex.sprint("\\newcommand*{", csname, "}{", val, "}") end end \end{luacode*} \begin{document} % makeshorthands の用例 \begin{makeshorthands}{logo} luatex=Lua\TeX lualatex=Lua\LaTeX context=Con{\TeX}t # not have 'Lua' in name texinfo=Texinfo # yeah! ^^; \end{makeshorthands} This is \logolualatex! \end{document}
make_shorthands()
関数の引数 datatable に渡されるのは、#
等の「特殊文字」もそのままに含まれる文字列である。((なお、改行は CR になるので、string.explode()
の引数が "\n+"
でなく "\r+"
であることに注意。さらに、「中身そのまま」ということは、\begin
のある行の末尾の改行も文字列に含まれることにも注意。(explode
の "\r+"
指定だとこれは問題にならない。)))ところで、出力においては、\LaTeX
はちゃんと制御綴として認識されている(verbatim でない)が、これは、Lua から TeX に結果を書き出した時に(通常のカテゴリコードで)トークン化が行われるからである。