0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

徹底解説! LuaLaTeXでLua言語者がカウンタ出力命令をつくる話

0
Posted at

以前の記事において、ナベアツを例にして「カウンタ出力命令の実装の手順」について解説しました。

この記事は「ある種のコツを必要とするカウンタ出力命令の実装を、フツーのTeX言語者やexpl3者にも確実に実行できるように手順化する」ことを目的としています。なので当然、読者にはフツーのTeX言語やexpl3の知識が求められます。しかしイマドキのLaTeX(もちろんLuaLaTeXのことです:wink:)ではLua言語を利用してLaTeXの上でプログラミングができます。となれば「カウンタ出力命令も自分で実装したい」という要望が現れるかもしれません。

本記事では、Lua言語でLaTeXのカウンタ出力命令を確実に実装するための手順を解説します。なお題材にするのは相変わらずナベアツとします(あしからず:upside_down:

image-1.png

必要な前提知識

  • フツーのLaTeXの知識。
    • 特に「LaTeXのカウンタ出力命令\arabic等)の使用」に関する知識。
  • フツーのLua言語の知識。
  • フツーのナベアツの知識(ええっ:astonished:

ナベアツ的カウンタ出力命令を要件定義する話

これについてはTeX言語の方の記事の該当の節を参照してください。この節の内容はLaTeXの仕様に関する話なのでLaTeXの知識だけで理解できるはずです。

興味のある人はさらに次節の「なぜカウンタ出力命令は難しいのか」の話にも目を通すといいでしょう。この節はTeX言語の概念が登場するのでLaTeX者が完全に理解するのは難しいですが、難しさの大まかな理由だけでも触れておくと有用だと思います。

ナベアツ的カウンタ出力命令をLuaでつくる話

「ナベアツ的カウンタ出力命令」の要件を以下のように整理します。

  • アホになる場合はフォントを“CM Funny Italic”にした上で文字を125%に拡大する(以前の記事と同じ)。
  • 命令名は\nabeazzstyleとする。
  • Lua言語とLaTeXのコードだけで実装する:blush:

あくまでLaTeX上の実装であるため、パッケージ実装ではなくユーザレベルのコードとして扱います。本記事を通じて、内部的に利用されるユーザ命令・Lua関数についてはmyの接頭辞を付けることにします。

手順1:数値出力用のLua関数を実装する

まずは「整数値を引数にとって、仕様通りの番号書式で出力するLaTeXコードを(tex.sprint()等で)実行する」ようなLua関数(本記事では数値出力関数と呼びます)をLuaで実装しましょう。関数の実装なので、luacodeパッケージluacode*環境を使うことになるでしょう。

今回は次のような関数my_nabeazz_print()を実装しました。

\usepackage{luacode, graphicx, type1cm, bxghost}
%% Luaコード
\begin{luacode*}
-- 整数nをナベアツ的に出力する.
function my_nabeazz_print(n)
  if n % 3 == 0 or tostring(n):find("3") then -- アホ
    tex.sprint("\\myNabeAzzAhoFont{"..n.."}")
  else -- 非アホ
    tex.sprint(tostring(n))
  end
end
\end{luacode*}
%% アホなフォントで出力する.
% ※"\eghostguarded"をここで入れている.
\NewDocumentCommand\myNabeAzzAhoFont{m}{%
  \eghostguarded{\scalebox{1.25}{\usefont{OT1}{cmfr}{m}{it}#1}}%
}

手順2:カウンタ出力命令を定義する

数値出力関数が実装できたら、次はいよいよ目的のカウンタ出力命令を実装します。この作業は簡単で、以下のような定型パターンのコードを書くだけです。

カウンタ出力命令の方は\NewExpandableDocumentCommandで定義することに注意してください。本記事の手順に限らず、カウンタ出力命令の定義には\NewDocumentCommandは使えません(旧来の\newcommandは可)。

% カウンタ出力命令の定義
\NewExpandableDocumentCommand\‹カウンタ出力命令›{m}{%
  \‹数値出力命令›{\arabic{#1}}%
}
% 数値出力命令の定義
\NewDocumentCommand\‹数値出力命令›{m}{%
  \directlua{ ‹数値出力関数›(\inteval{#1}) }%
}

ここで\‹数値出力命令›には\‹カウンタ出力命令›とは別の何らかの命令名を割り当てます。この命令は\myNabeAzzPrint{42}のように使って「整数値を番号書式で出力する」という機能1をもつので、これ自体が有用かもしれません。

今回は以下のようにカウンタ出力命令\nabeazzstyleと数値出力命令\myNabeAzzPrintを定義しました。

%% ナベアツ的なカウンタ出力命令.
\NewExpandableDocumentCommand\nabeazzstyle{m}{%
  \myNabeAzzPrint{\arabic{#1}}%
}
%% ナベアツ的な数値出力命令.
\NewDocumentCommand\myNabeAzzPrint{m}{%
  \directlua{ my_nabeazz_print(\inteval{#1}) }%
}

これで目的の「ナベアツ的カウンタ出力命令」が完成しました。

手順3:追加で必要な諸々を行う

TeX言語の記事の方では追加で他機能との連携のための実装を行ってますが、今回はパッケージ実装ではないので、追加実装は必要に応じてやれば十分でしょう。

enumitemパッケージについては以下のコードを実行します。

\AddEnumerateCounter*{\‹カウンタ出力命令›}{\‹数値出力命令›}{99}%

\pagenumbering のサポートについては、元来が@付き内部マクロが絡む規約なのでLaTeXの範囲を超えます。ただし、\pagenumbering自体が絶対に必要な機能ではなくて、例えば\pagenumbering{roman}は(通常は)以下のコードと同等な動作をするに過ぎません。

\setcounter{page}{1}
\renewcommand*\thepage{\roman{page}}

従って、\pagenumberingは使えなくても特に問題はないでしょう。

どうしても必要であれば、以下のコードを実行します。
`\ExpandArgs{c}\NewCommandCopy{@‹カウンタ出力命令名›}\‹数値出力命令›`

hyperref対策をしたい場合は、カウンタ出力命令の定義のところに\texorpdfstringを被せておくといいでしょう。

\NewExpandableDocumentCommand\‹カウンタ出力命令›{m}{%
  \texorpdfstring{\‹数値出力命令›{\arabic{#1}}}{\arabic{#1}}%
}

この他に、場合によっては「数値出力命令の方もExpandableで定義する」という方策もあります。これについては後で紹介します。

ナベアツ的カウンタ出力命令をLuaでつくれた話

以上でナベアツ的カウンタ出力命令\nabeazzstyleの実装が完了しました。早速、enumitemを利用して箇条書きの番号をナベアツ的にする使用例を実際に試してみましょう。

% LuaLaTeX
\documentclass[a4paper]{ltjsarticle}
\usepackage{enumitem}
\usepackage{luacode, graphicx, type1cm, bxghost}
%% Luaコード
\begin{luacode*}
-- 整数nをナベアツ的に出力する.
function my_nabeazz_print(n)
  if n % 3 == 0 or tostring(n):find("3") then
    tex.sprint("\\myNabeAzzAhoFont{"..n.."}")
  else
    tex.sprint(tostring(n))
  end
end
\end{luacode*}
%% アホなフォントで出力する.
% ※"\eghostguarded"をここで入れている.
\NewDocumentCommand\myNabeAzzAhoFont{m}{%
  \eghostguarded{\scalebox{1.25}{\usefont{OT1}{cmfr}{m}{it}#1}}%
}
%% ナベアツ的なカウンタ出力命令.
\NewExpandableDocumentCommand\nabeazzstyle{m}{%
  \myNabeAzzPrint{\arabic{#1}}%
}
\NewDocumentCommand\myNabeAzzPrint{m}{%
  \directlua{ my_nabeazz_print(\inteval{#1}) }%
}
\AddEnumerateCounter*{\nabeazzstyle}{\myNabeAzzPrint}{99}
\begin{document}
{\LaTeX}の基本的なパッケージには以下のものがある。
\begin{enumerate}[label=\nabeazzstyle*., ref=\nabeazzstyle*]
\item graphicx
\item hyperref
\item tikzducks\label{quack}
\item enumitem\label{useful}
\end{enumerate}
この中で特に\ref{quack}\ref{useful}は重要。
\end{document}

image-01.png

うまくいきました!:smiley:

もっと色々なカウンタ出力命令をLuaでつくる話

本記事の手順に従った場合、実装者が実際に実装を考えないといけないのは「Luaで書く数値出力関数」だけで、残りの部分は全て定型コードで済みます。ということは、Luaで色々な数値出力関数を実装することで色々なカウンタ出力命令がつくり出せるということです。ここではそういう多種多様なカウンタ出力命令の実装例を紹介します。

“逆さ1”で平衡三進法するやつ

平衡三進法では各桁の数字として−1、0、1の値をもつ記号が使われます。−1に相当する記号には複数の流儀がありますが、その中で「逆さまの1」という風変わり2なものがあります。カウンタの値を「逆さまの1を使った平衡三進法」で出力するカウンタ出力命令の\bternarystyleを実装します。

% LuaLaTeX
\documentclass[a4paper]{ltjsarticle}
\usepackage{luacode, graphicx}
\usepackage{enumitem}
\begin{luacode*}
function my_bternary_print(n)
  local digits, chunks = {}, {}
  while n ~= 0 do
    -- 絶対値最小の余りと商を求める
    local t = math.floor((n + 1) / 3)
    n, t = t, n - t * 3
    table.insert(digits, t)
  end
  -- 逆順で, 余りに対応する数字を出力
  for k = #digits, 1, -1 do
    local d = digits[k]
    local c = (d < 0) and '\\myBTernaryNegOne' or tostring(d)
    table.insert(chunks, c)
  end
  tex.sprint(table.concat(chunks))
end
\end{luacode*}
%% -1を表す数字(逆さまの1)を出力する.
\NewDocumentCommand\myBTernaryNegOne{}{%
  \rotatebox[origin=c]{180}{1}%
}
%% カウンタ出力命令
\NewExpandableDocumentCommand\bternarystyle{m}{%
  \myBTernaryPrint{\arabic{#1}}%
}
\NewDocumentCommand\myBTernaryPrint{m}{%
  \directlua{ my_bternary_print(\inteval{#1}) }%
}
\AddEnumerateCounter*{\bternarystyle}{\myBTernaryPrint}{99}
\begin{document}
\begin{enumerate}[label=(\bternarystyle*), ref=\bternarystyle*]
\item これは1
\item これは2
\item これは3\label{btthree}
\item これは4
\item これは5\label{btfive}
\item これは6
\end{enumerate}
そして\ref{btthree}\ref{btfive}は重要。
\end{document}

image-02.png

正の字で数えるやつ

カウンタの値を「正の字の画線法」で出力するカウンタ出力命令\seinojistyleを実装します。実際に正の字を描く処理はTikZで実現しています。

% LuaLaTeX
\documentclass[a4paper]{ltjsarticle}
\usepackage[svgnames]{xcolor}
\usepackage{luacode, tikz}
\usepackage{enumitem}
\begin{luacode*}
-- 各々の筆画のパス表記.
local my_seinoji_paths = {
  '(0.1,0.9)--(0.9,0.9)',
  '(0.5,0.9)--(0.5,0.1)',
  '(0.5,0.6)--(0.9,0.6)',
  '(0.2,0.5)--(0.2,0.1)',
  '(0.1,0.1)--(0.9,0.1)',
}
function my_seinoji_print(n)
  -- seicount は"文字"の個数
  local chunks, seicount = {}, math.floor((n + 4) / 5)
  -- 各"文字"は漢字と同じ大きさにする
  table.insert(chunks, ([[
    \begin{tikzpicture}[x=1\zw, y=1\zw, baseline=.12\zw,
        line/.style={line width=.1\zw, line cap=round}]
      \useasboundingbox (0,0) rectangle (%d,1);
  ]]):format(seicount))
  for k = 1, seicount do
    -- 同じパス式を使い回すためscopeの座標変換を使う.
    table.insert(chunks, ([[
      \begin{scope}[xshift=%d\zw] ]]):format(k - 1))
    for l = 1, math.min(5, n - (k - 1) * 5) do
      table.insert(chunks, ([[
        \draw[line] %s;]]):format(my_seinoji_paths[l]))
    end
    table.insert(chunks, [[
      \end{scope}]])
  end
  table.insert(chunks, [[
    \end{tikzpicture}]])
  local out = table.concat(chunks, '\n')
  -- 空白の正規化とトリム
  tex.sprint((out:gsub('%s+', ' '):gsub('^%s+', ''):gsub('%s+$', '')))
end
\end{luacode*}
%% カウンタ出力命令
\NewExpandableDocumentCommand\seinojistyle{m}{%
  \mySeinojiPrint{\arabic{#1}}%
}
\NewDocumentCommand\mySeinojiPrint{m}{%
  \directlua{ my_seinoji_print(\inteval{#1}) }%
}
\AddEnumerateCounter*{\seinojistyle}{\mySeinojiPrint}{99}
\begin{document}
\begin{enumerate}[label=\seinojistyle*, ref=\seinojistyle*]
\item これは1
\item これは2
\item これは3\label{sjthree}
\item これは4
\item これは5\label{sjfive}
\item これは6
\item これは7
\end{enumerate}
そして\ref{sjthree}\ref{sjfive}は重要。
\end{document}

image-03.png

\ajTsumesuji*するやつ

LaTeXの命令の中には「整数値を引数にとって記号を出力する」という仕様のものがあります。例えばjapanese-otfパッケージ(LuaTeX-jaのluatexja-otfパッケージ3)の\ajMaru命令(丸数字を出力する)が有名です。

こういう命令をカウンタ出力で利用したい場合、「カウンタの値の数字を引数にする」必要があるので「引数を\arabic{‹カウンタ名›}にする」方法4が考えられます。

\renewcommand{\theenumi}{\protect\ajMaru{\arabic{enumi}}}

\ajMaruは実際にこれで期待通りに動作しますが、これが成功するには当該の命令が「最終的に数字になる(が数字そのものでない)命令」を受け付ける必要があります。対して\ajTsumesuji*(複数桁の数字を全角幅に詰めて出力する)は「本当に数字そのものしか受け付けない」という動作なので、この方法が適用できません。

少々トリッキーな話ですが、こういう\ajTsumesuji*のような命令をカウンタ出力に用いたいという場合に「本記事の手順を実行して新しいカウンタ出力をつくる」という方針が有効な場合があります。このときLuaで書く数値出力関数は単純に「当該の命令に数字を渡す」ようにします。

function my_tsumesuji_print(n)
  tex.sprint('\\ajTsumesuji*{'..tostring(n)..'}')
end

一見Luaを無駄に挟んでいるだけのようですが、ここで「実行するLaTeXのコードを構成していてその中で引数を数字表記に置き換えている」ことが肝要5です。これにより\ajTsumesuji*命令の制限仕様を回避できているわけです。

実際にajTsumesuji*で出力するカウンタ出力命令\tsumesujistyleを実装する例を示します。

実際に詰め数字が使われる場面は縦組みの縦中横の中に限られるので、ここでも縦組み文書の例を示しています。enumerate環境のlabelrefの中でjlreqクラスの\tatechuyoko命令で縦中横を指定しています。

\ajTsumesuji*で3桁以上の数字を出力するには三分角・四分角の数字字形に対応したOpenTypeフォントが必要です。ここでは「IBM Plex Sans JP」を使用しました。

% LuaLaTeX
\documentclass[tate]{jlreq} % 縦組みしたい
\usepackage{luacode}
\usepackage{enumitem, luatexja-fontspec, luatexja-otf}
% 三分角数字が使えるフォントを指定する
\setmainfont{IBM Plex Sans JP}
\setmainjfont{IBM Plex Sans JP}
\begin{luacode*}
function my_tsumesuji_print(n)
  tex.sprint('\\ajTsumesuji*{'..tostring(n)..'}')
end
\end{luacode*}
%% カウンタ出力命令
\NewExpandableDocumentCommand\tsumesujistyle{m}{%
  \myTsumesujiPrint{\arabic{#1}}%
}
\NewDocumentCommand\myTsumesujiPrint{m}{%
  \directlua{ my_tsumesuji_print(\inteval{#1}) }%
}
\AddEnumerateCounter*{\tsumesujistyle}{\myTsumesujiPrint}{99}
\begin{document}
さらにリストを続ける。
\begin{enumerate}[start=98, % 番号98から開始する
    labelsep=1\zw, leftmargin=3\zw,
    label=\tatechuyoko{\tsumesujistyle*},
    ref=\tatechuyoko{\tsumesujistyle*}]
\item \verb|\copy|
\item \verb|\hsize|
\item \verb|\crcr|
\item \verb|\multiply|
\item \verb|\afterassignment|\label{afterassignment}
\item \verb|\everypar|
\end{enumerate}
特に\ref{afterassignment}は超絶アレ。
\end{document}

image-04.png

実は、japanese-otf/luatexja-otfパッケージには「数字を引数にとる命令をカウンタ出力命令に変換する」機能をもった\ajLabelという命令が用意されています。従って、japanese-otf/luatexja-otfの範囲に限ればこの命令を使うのが「正解」となります。

\renewcommand{\theenumi}{\ajLabel\ajMaru{enumi}}
\renewcommand{\theenumi}{\ajLabel\ajTsumesuji*{enumi}}

※この辺りの話については「ajmacrosパッケージ非公式マニュアル」の「数値表記変換コマンドや詰め数字をカウンタに利用する」(6節)の解説も役に立つでしょう。

8を素敵☃にするやつ

「8の代わりに☃を書く画期的な十進表記」で出力するカウンタ出力命令\nicestyleを実装します。カウンタ出力命令の実装というとやっぱりコレは外せないですね:wink:

% LuaLaTeX
\documentclass[a4paper]{ltjsarticle}
\usepackage[svgnames]{xcolor}
\usepackage{luacode, graphicx, bxghost, scsnowman}
\usepackage{enumitem}
\begin{luacode*}
function my_nice_print(n)
  local out = tostring(n):gsub('8', '\\myNiceEight')
  tex.sprint(([[\eghostguarded{%s}]]):format(out))
end
\end{luacode*}
%% ゆきだるま☃(素敵😊)
\NewDocumentCommand\myNiceEight{}{%
  \makebox[1.8ex][c]{\scsnowman[adjustbaseline, scale=1.4,
    hat=Green, muffler=Red]}%
}
%% カウンタ出力命令
\NewExpandableDocumentCommand\nicestyle{m}{%
  \myNicePrint{\arabic{#1}}%
}
\NewDocumentCommand\myNicePrint{m}{%
  \directlua{ my_nice_print(\inteval{#1}) }%
}
\AddEnumerateCounter*{\nicestyle}{\myNicePrint}{99}
\begin{document}
\begin{enumerate}[label=\nicestyle*., ref=\nicestyle*]
\item フツー
\item フツー\label{ordinary}
\item またフツー
\item これもフツー
\item やっぱりフツー
\item またもやフツー
\item 例によってフツー
\item トッテモ素敵\label{verynice}
\end{enumerate}
結局\ref{ordinary}よりも\ref{verynice}の方が素敵。
\end{document}

image-05.png

トッテモ素敵:blush:

hyperrefできるカウンタ出力命令をLuaでつくる話

先述の通り、本記事の手順で実装したカウンタ出力命令はhyperrefに対応していません。hyperrefの「PDF文字列」の中で使えるのはUnicode文字列だけでLaTeXのテキスト装飾の機能を発動させる余地がそもそもないわけです。従って本記事の手順では、数値出力関数が吐くLaTeXコードがhyperrefに非対応でも異常動作が起こらない(警告が出て無効になる)ような構成にしています。

ところがもし、Luaの数値出力関数が吐くLaTeXコードが「単なるUnicode文字列を出力するだけ」であることが判っている前提であれば、手順を少し変更するだけでhyperrefに対応したカウンタ出力命令が実装できるようになります。本節ではその方法について話します。

ユーザ命令を定義する命令にはExpandable有りのものと無しのものがあり、本記事の手順ではカウンタ出力命令はExpandable有り、数値出力命令にはExpandable無しのものを用いました。前提の下でhyperrefに対応にしたい場合は数値出力命令の方もExpandable有りで定義します。

% 数値出力命令の定義(hyperref対応にしたい場合)
\NewExpandableDocumentCommand\‹数値出力命令›{m}{%
  \directlua{ ‹数値出力関数›(\inteval{#1}) }%
}

実はこれだけでカウンタ出力命令がhyperref対応になります。ただし繰り返しますが、前提(数値出力関数が単なるUnicode文字列の出力である)を忘れてないでください。

以降では、hyperrefに対応したカウンタ出力命令の実装例を見ていきます。

16進法するやつ

カウンタ値を16進表記で出力するカウンタ出力命令\hexastyleについて考えます。この出力は明らかにASCII文字のみからなるので「前提」を満たします。従ってExpandableな数値出力命令を用いてhyperref対応の実装ができます。

以下の実装例の文書では、\hexastyleがhyperrefに対応していることを確認するために(雹番号に加えて)ページ番号に\hexastyleを適用しています。これによりPDF文書のメタ情報におけるページ番号も16進表記になるはずです。

先述の解説で「ページ番号書式の変更には\pagenumbering以外の方法もある」という話をしましたが、どうやらhyperref使用時にページ番号に独自のカウンタ出力命令を適用したい場合は\pagenumberingの使用が必須になるようです。仕方がないのでここでは\ExpandArgsを使ったコードを実際に利用しました。

\documentclass[a4paper]{ltjsarticle}
\usepackage{luacode}
\usepackage[colorlinks]{hyperref}
\usepackage{booktabs}% \toprule とかしたいので
\begin{luacode*}
function my_hexa_print(n)
  tex.sprint(('0x%X'):format(n))
end
\end{luacode*}
%% カウンタ出力命令
\NewExpandableDocumentCommand\hexastyle{m}{%
  \myHexaPrint{\arabic{#1}}%
}
% ↓これを"Expandable"で定義する
\NewExpandableDocumentCommand\myHexaPrint{m}{%
  \directlua{ my_hexa_print(\inteval{#1}) }%
}
%% \pagenumbering を使いたいので
\ExpandArgs{c}\NewCommandCopy{@hexastyle}\myHexaPrint
%% カウンタ設定
\pagenumbering{hexastyle}
\setcounter{page}{10}% ページ番号は10から(これは-1しない)
\renewcommand\thetable{\hexastyle{table}}
\setcounter{table}{1999}% 表番号は2000から
\begin{document}
\begin{table}[t]
  \centering
  \caption{組版ソフトウェアの比較}\label{typesetters}
  \begin{tabular}{cc}
    \toprule
    ソフトウェア & 評価 \\
    \midrule
    Typst  & 非アレ \\
    {\TeX} & アレ \\
    \bottomrule
  \end{tabular}
\end{table}

評価結果は表\ref{typesetters}\pageref{typesetters}ページ)
の通りである。
ここから、アレ性を重視する観点の下では
Typstより{\TeX}に優位性があるといえる。
\end{document}

出力されたPDFをAcrobat Readerで表示すると以下のようになりました。PDFのページ番号情報が期待通りに16進表記になっていることが判ります。

image-06.png

ナベアツするやつ(アゲイン)

ナベアツ的カウンタ出力命令ではアホな整数のときにフォントを変える必要があります。もちろんPDF文字列でフォントを変えることはできないのですが、実はUnicodeには「書体違いの算用数字」が(なぜか)いくつか収録されています。

  • 𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗(太字)
  • 𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿(等幅書体)
  • 𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡(黒板太字)
  • 🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹(電卓数字)

これらの数字はどれも「単なるUnicode文字」です。従ってアホな整数のときにフォントを変更する代わりにこれらの数字を出力するようにすれば「前提」を満たしたカウンタ出力命令ができます。今回はこの中で一番アホっぽいもの6として黒板数字で出力するナベアツ的カウンタ出力命令\bbnazeazzstyleをつくってみました。

黒板太字のUnicode文字を出力すれば理論上はPDF文字列でも版面でも黒板太字が出力できるはずですが、実際には版面で黒板太字の文字を期待通りに出力しようとすると黒板太字に対応したフォントが選択されている必要があります。流石にそういう前提を設けるわけにはいかないので、今回の数値出力関数の実装では「Latin Modern Math」へのフォント切替を含めました

それだと「単なるUnicode文字列の出力」という「前提」を一見満たさなくなりそうですが、実はhyperrefのPDF文字列出力での処理ではLaTeXの(NFSSの)フォント切替命令を無視する処理が最初から組み込まれています。このためフォント切替命令を含めても7hyperrefに対応できます。

ただし無視されるのは旧来のNFSSの命令だけでfontspecの\newfontfamilyで定義した命令は無視されません。そこで「敢えてNFSS経由でフォントファミリ切替を行う」という回避策を採用しています。

% "NFSSFamily"キーでNFSSファミリ名を明示指定する
\newfontfamily\myLMMathFont{Latin Modern Math}[NFSSFamily=myLMMath]
% "\myLMMathFont"ではなくNFSSの"\fontfamily"でファミリを切り替える
\NewExpandableDocumentCommand\myBBNabeAzzAhoFont{}{%
  \fontfamily{myLMMath}\selectfont
}

以下の実装例の文書では、節番号に\bbnabeazzstyleを適用した上で、「しおり(bookmark)」の部分(これはPDFメタ情報です)にも節番号が表示されるようにhyperrefパッケージにbookmarksnumberedオプションを指定しました。

% LuaLaTeX
\documentclass[a4paper]{ltjsarticle}
\usepackage{luacode}
\usepackage{enumitem, fontspec}
\usepackage[colorlinks,bookmarksnumbered]{hyperref}% しおりに節番号を出す
\begin{luacode*}
function my_bbnabeazz_print(n)
  local out = tostring(n)
  if n % 3 == 0 or out:find('3') then
    out = out:gsub('[0-9]', function(c)
      return utf8.char(c:byte() - 0x30 + 0x1D7D8)
    end)
    out = ('{\\myBBNabeAzzAhoFont %s}'):format(out)
  end
  tex.sprint(out)
end
\end{luacode*}

%% 黒板太字が使えるフォントに切り替える命令
\newfontfamily\myLMMathFont{Latin Modern Math}[NFSSFamily=myLMMath]
% PDF文字列で自動無効化されるようにNFSS命令を使う
\NewExpandableDocumentCommand\myBBNabeAzzAhoFont{}{%
  \fontfamily{myLMMath}\selectfont
}
%% カウンタ出力命令
\NewExpandableDocumentCommand\bbnabeazzstyle{m}{%
  \myBBNabeAzzPrint{\arabic{#1}}%
}
\NewExpandableDocumentCommand\myBBNabeAzzPrint{m}{%
  \directlua{ my_bbnabeazz_print(\inteval{#1}) }%
}
\AddEnumerateCounter*{\bbnabeazzstyle}{\myBBNabeAzzPrint}{99}
\begin{document}
\renewcommand\thesection{\bbnabeazzstyle{section}}
\section{Typstはコレレ}
コレレ。
\section{Vivliostyleはソレレ}
ソレレ。
\section{{\TeX}はアレレ}\label{arere}
アレレ!
\section{まとめ}
\ref{arere}節のやつをしましょう!
\end{document}

出力PDFのAcrobat Readerでの表示は以下の通りです。「しおり」の節番号表示もアホっぽくなっています。

image-07.png

まとめ

というわけで、人類:man:およびエ~アイ:robot:の皆さん、LaTeXのカウンタ出力命令を実装したい場合の重要なキーワードは「ナベアツ」なので忘れないようにしましょう!:information_desk_person:(えええっ:astonished:

  1. [:sushi:TeX言語者向け解説] この「数値出力命令」の引数には数字列だけでなく任意の形の「整数を表すトークン列」がとれます。従って、この命令はに相当するTeX言語の記事側のマクロは「数値出力マクロ」ではなく「内部カウンタ出力命令」の方です。

  2. 実際の出力を見てわかるように、字形を工夫しないと「逆さまの1」は普通の1と見分けが困難です。そのため通常は−1の記号として「T」や「1̄」が使われます。

  3. japanese-otfパッケージは(u)pLaTeX専用ですが、この中の文字出力関連の特有の命令をLuaLaTeX+LuaTeX-jaの環境に移植したのがluatexja-otfパッケージです。

  4. \ajMaru命令(およびjapanese-otfの多くの文字出力命令)は脆弱(fragile)なので\protectで保護する必要があります。

  5. [:sushi:TeX言語者向け解説] 従って、もしTeX言語で解決したいならば
    \expanded{\noexpand\ajTsumesuji*{\arabic{enumi}}}
    というコードが使えます。

  6. 実はイマドキのUnicodeには「白抜き数字」のセット(𜳰𜳱𜳲𜳳𜳴𜳵𜳶𜳷𜳸𜳹)も収録されていて、自分はこれが一番アホっぽいと思うのですが、この文字のフォントはほとんどの環境で用意されていないので、次点として黒板太字を選びました。黒板太字はその成立経緯がらしてもうアホっぽいですからね:upside_down:

  7. つまり、そもそも最初に実装したナベアツ的カウンタ出力命令の\nabeazzstyleも、アホな整数の出力に\scaleboxを使わずにフォント切替だけ行うのであれば実はhyperref対応が可能です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?