マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

落ちない tangle を作る話

Lua の実行途中で TeX コードを実行する」ための「tangle モジュール」(以前の記事を参照)の改良の話。

従来(ixbase0 パッケージ、IXbase バンドル)の tangle では、大本の Lua コードを開始するときに、

\directlua{
  tangle.execute(function()
    % 実行するコード
  end)
}

のように起動する約束になっていた。この tangle.execute() が、コルーチン中断後に必要な処理(Lua コード再開のための \directlua を吐き出す、等)を行う。この起動プロトコルの部分に TeX の処理を絡めることで、Lua コード再開の \directlua 実行が「書出コード」を抜けた後で起こるようにした。TeX コードが絡むので、開始部分に(単なる \directlua や luacode* 環境でなくて)独自の命令・環境を用いることになる。

……全く説明の体を成していないが、実際のパッケージの使い方を見れば判ると思う。BXluatool バンドルの bxluatangle パッケージが tangle モジュールの改良版にあたる。「途中で TeX を実行したい」Lua コードがある場合は \directlua や luacode* の代わりに以下のようにして Lua コードを記述する。*1

% \directlua の代わり
\tangleluaexec{
  % 実行するコード
}

% luacode* 環境の代わり
\begin{tangleluacode*}
  -- 実行するコード
\end{tangleluacode*}

Lua コード中で TeX コードの実行を完了させるには、bxlt.run_tex() を実行する。((BXluatool バンドルを通じて Lua モジュールの名前は bxlt としている。ixbase0 では tangle.run_tex() であった。))

以前の記事で落ちていた例をこのパッケージで実装すると次のようになる。

% 文字コードは UTF-8
\documentclass[a4paper]{article}
\usepackage{bxluatangle,luacode,bxluafacade}

\begin{luacode*}
function truncate_to_width(str)
  local wdt = bxlt.length.ttwTarget.width
  local max = str:len()
  for l = 1, str:len() do
    -- あえて線形探索を使う
    texio.write("("..l..")") -- デバッグ出力(*)
    -- str:sub(1,l) を組版しその幅を \ttwMeasured に代入する
    tex.print([[\settowidth{\ttwMeasured}{]]..str:sub(1, l)..[[}%]])
    bxlt.run_tex() -- TeX の実行を完了させる
    local wdm = bxlt.length.ttwMeasured.width
    if wdm > wdt then
      max = l - 1; break
    end
  end
  tex.print(str:sub(1, max))
end
\end{luacode*}

\newlength{\ttwTarget}
\newlength{\ttwMeasured}
\newcommand*{\truncatetowidth}[2]{%
  \setlength{\ttwTarget}{#1}%
  \tangleluaexec{
    truncate_to_width(\luastring{#2})
  }%
}

\begin{document}
\begin{itemize}
\item \truncatetowidth {10pt}{I never feel like saying hello to world!}
\item \truncatetowidth {50pt}{I never feel like saying hello to world!}
\item \truncatetowidth {90pt}{I never feel like saying hello to world!}
\item \truncatetowidth{130pt}{I never feel like saying hello to world!}
\item \truncatetowidth{170pt}{I never feel like saying hello to world!}
\end{itemize}
\end{document}

今度は、ループ回数が増えても TeX の制限に引っかかることなく正常に動作している。

This is LuaTeX, Version beta-0.70.2-2012052919 (TeX Live 2012/W32TeX)
 restricted \write18 enabled.
……(中略)……
(./test.aux) (c:/usr/local/share/texmf/tex/latex/base/omscmr.fd)(1)(2)(3)(1)(2)
(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13
)(14)(15)(16)(17)(18)(19)(20)(21)(22)(23)(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12
)(13)(14)(15)(16)(17)(18)(19)(20)(21)(22)(23)(24)(25)(26)(27)(28)(29)(30)(31)(3
2)(33)(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(14)(15)(16)(17)(18)(19)(20)(2
1)(22)(23)(24)(25)(26)(27)(28)(29)(30)(31)(32)(33)(34)(35)(36)(37)(38)(39)(40)
[1{c:/usr/local/share/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./test.aux) )

 263 words of node memory still in use:
   2 hlist, 1 vlist, 1 rule, 2 glue, 40 glue_spec, 1 write nodes
   avail lists: 1:1,2:12,3:16,4:123,5:12,6:106,7:1,9:24,10:2
<c:/usr/local/share/texmf/fonts/type1/public/amsfonts/cm/cmr10.pfb><c:/usr/loca
l/share/texmf/fonts/type1/public/amsfonts/cm/cmsy10.pfb>
Output written on test.pdf (1 page, 21625 bytes).
Transcript written on test.log.

*1:これを「tangle 付で実行する」という。