重点解説！ イマドキのLaTeXの“命令フック機能”

:::note info
これは「[TeX & LaTeX Advent Caleandar 2024](https://adventar.org/calendars/10647)」の25日目の記事です。
（24日目は [k16shikano さん](https://zenn.dev/k16/articles/6da054a486d37b)です。）
:::

LaTeXカーネルの“凍結解除”が宣言されたのが2015年の1月のことなので、それからほぼ10年の年月が経ちました。この10年の間に数多くの機能がLaTeX**カーネル**（パッケージではなく）に追加されていることは最近の[TeXConf][wtsnjp-2024]（や[Online.tex][aminophen-2020]）をチェックしている人ならご存じでしょう。

一方で、日本語のLaTeX界隈において、そういう“新しいカーネルの機能”についての具体的な**使い方の解説**が積極的に流布されているかというと、残念ながらそういう活動は停滞気味です。結果的に、カーネルの新機能があっても**​「使い方を知らないので使えない」​**状態になっています。

本記事では、カーネルの新機能のうち、“LaTeXマクロを作成する”程度のレベルの人にとって有用な**​「命令に対するフック」​**について解説します。

:::note info
本記事の内容はTeX Live **2022以降**のLaTeX[^latex-ver]を前提とします。
:::

[^latex-ver]: 厳密にいうと、LaTeXカーネルの2021-06-01版以降となります。

## 前提知識

* **LaTeXの範囲の**マクロ（ユーザ定義命令）の作成ができること。
    - 記事全体の方針としてはTeX言語の知識は仮定しない。

ただし、本記事では部分的に“TeX言語学習者向きの内容”を挟むことがあります。そういう部分には（[例によって][ifthen]）:sushi:を付けて明示することにします。

## お題：“オレ的重要”命令

今回紹介する機能は“LaTeXマクロの作成”に役立つもの、ということでした。従って、具体的にLaTeXマクロを作成する“お題”を考えてみましょう。

いま、文書中に **“オレ的重要”** という意味のマークアープを導入したいとします。“オレ的重要”は以下のようなテキスト装飾で表すことにします。

* 既に強調（`\emph`）の中にいる場合は太字（`\textbf`）を指定する。
* それ以外の場合は強調（`\emph`）を指定する。

:::note info
LaTeXの強調は引数型命令`\emph`の他に宣言型命令`\em`[^two-letter]でも指定できますが、話を簡単にするため`\em`の使用は考慮外とします。また、`\emph`がネストする場合も考慮外とします。
:::

[^two-letter]: `\em`は「2文字からなるフォント命令」ですが、いわゆる（使ってはいけない）「二文字フォント命令」ではなくて正式なLaTeX2eの命令です。

この“オレ的重要”のテキスト装飾を行うための（引数型の）命令`\myImportant`を作ってみましょう。つまり、作るべき命令の**仕様**は以下の通りです

- `\myImportant{<テキスト>}`： “オレ的重要”のテキスト装飾（先述の通り）を施した状態で引数のテキストを出力する。  
※`\em`やネストした`\emph`と併用した場合の`\myImportant`の動作は未定義とします。

:::note info
`\emph`はLaTeXの標準的な命令ですが、「`\emph`がどう実装されているか」はもちろんのこと、「`\emph`がどういう装飾（イタリック・色を変える・点滅させる:astonished:など）を行うのか」は一般に使用する文書クラスに依存することに注意しましょう。ここでは`\emph`の実装・仕様が何であっても`\myImportant`は仕様通りに動作する必要があるとします。
:::

### あるべき姿

イメージを把握しやすいように、`\myImportant`命令を使用する例を先に挙げておきます。以下のようなテスト文書test.texを用意しました。

```tex:test.tex
% pdfLaTeX文書
\documentclass[a4paper]{article}
\usepackage{myimportant} % ここに'\myImportant'の実装がある
\begin{document}
% '\emph'の外で使う場合
The {\TeX} language is \myImportant{dangerous}.

% '\emph'の中で使う場合
\emph{The {\TeX} language is \myImportant{dangerous}.}
\end{document}
```

この中で読み込んでいる`myimportant`パッケージに`\myImportant`命令の実装が記述されているものとします。標準のarticleクラスでは`\emph`命令はイタリックで表現されるので、`\myImportant`が仕様通りに実装されていれば、以下のような出力結果が得られるはずです。

![image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/d0c32c15-92d1-df1f-16fb-255eff047c98.png)

## 方針を考えてみる

この問題で最も難しい箇所はやはり「現在`\emph`の中にいるのかを判定する」ことでしょう。そういう判定を行う命令はLaTeXの標準的な仕様としては規定されていません。

:::note info
TeX言語:sushi:の知識を使えば「現在のフォントの状態がどうであるか」を調べられますが、そもそも「`\emph`がどういう装飾を行うか」が不明である以上「フォントのどの状態を調べるか」も不明であるため、判定は不可能です。
:::

そこで、「`\emph`の中であるか」を表す**フラグを自分で用意する**ことにしましょう。その上でフラグの状態が実際の`\emph`の使用状況と“連動”するようにします。具体的な方針は以下のようになります。

 1. 「`\emph`の中であるか」を表すフラグを用意する。
 2. 「フラグを参照して`\textbf`と`\emph`の適切な方を実行する」ように`\myImportant`を実装する。
 3. フラグが仕様を満たす、つまり「実際に`\emph`の中に入っている時だけフラグが真になる」ように何らかの**細工を施す**。

明らかに難しいのが3であり、これを実現するには結局「`\emph`に“フラグの値を変更する”という**動作を追加する**」ことは避けられません。このように既存の命令に何かの動作を追加することを(La)TeX界隈では**​「フックする」​**と呼びます。もちろん「命令をフックする」というのは「命令の実装を改変する」ということなので、旧来のLaTeXの常識に従えば、これを“LaTeXの範囲”で行う（つまり、上記の方針に従って`\myImportant`を実装する）ことは不可能[^revise]です。

[^revise]: “LaTeXの範囲”においては、特に“改変することが規定”された命令（カウンタ表示の`\enumi`など）以外は改変してはいけないからです。

:::note info
とはいっても「命令をフックするだけなら元の命令の実装:sushi:を理解できなくてもよい」という事情があるため、「LaTeXマクロが書けるがTeX言語は知らない」程度のレベルの人の間で「命令をフックする」技法は実際に使われています。その結果として「TeX言語の罠に嵌って事故が起こる」事例もよく見かけます:upside_down:
:::

ところがイマドキの新しいLaTeXでは状況が違います。「既存の命令をフックする」という機能がカーネルで**サポートされている**のです。これをうまく利用すれば、従来は“LaTeXの範囲”でできなかった`\myImportant`のような命令が作れるようになるはずです:smiley:

## 簡単なやつを先に済ませておく

「フックする」の話（手順3）に入る前に、その他の部分である手順1と2を片付けておきましょう。“LaTeXの範囲”で簡単な条件分岐を行いたいので[**ifthenパッケージ**][ifthen]を利用することにします。

### フラグを定義する

ifthenパッケージでは`\newboolean`命令でフラグ（真偽値変数）を定義できます。「`\emph`の中であるか」を表すフラグの名前を`myInEmph`としましょう。

```tex
% 変数'myInEmph': 今'\emph'の中であるか.
\newboolean{myInEmph}
```

### フラグの値により条件分岐する

条件分岐をするのに使うのは`\ifthenelse`命令です。この条件部で`\boolean{myInEmph}`と書くことで先ほど定義した`myInEmph`の現在の値を参照できます。これを利用して、`\myImportant`命令の定義は以下のように書けます。

:::note info
イマドキのLaTeXの話なので、マクロ定義にも`\newcommand`ではなくイマドキの[“xparse系”の命令][xparse]​[^xparse]である`\NewDocumentCommand`を使うことにしましょう。
:::

[^xparse]: 新しい（2020-10-01以降の）LaTeXカーネルでは“xparse系”の命令は最初から提供されていて、xparseパッケージを読み込む必要はありません。

```tex
% \myImportant{<テキスト>}: "オレ的重要"の装飾付きでテキストを出力する.
\NewDocumentCommand\myImportant{m}{%
  \ifthenelse{\boolean{myInEmph}}{%
    % フラグmyInEmphが真の場合の処理
    \textbf{#1}% '\emph'の中なので太字
  }{%else
    % myInEmphが偽の場合の処理
    \emph{#1}% '\emph'の外なので'\emph'
  }%
}
```

### 参考:sushi:：TeX言語する場合

もちろん、TeX言語:sushi:の条件分岐を「ちゃんと知っていて使える:muscle:」人であれば、ifthenパッケージの代わりにTeX言語のif文を使ってもかまいません。例えば以下のようなコードになります[^switch]。

[^switch]: コメント中に「スイッチ」というTeX用語がありますが、これは「`\newif`で定義されるif-トークン」のことを指します。

:::note info
`\myImportant`は公開の命令なので[^protected]、`\def`ではなく`\NewDocumentCommand`で定義すべきです。
:::

[^protected]: 詳細は省きますが、命令のユースケースから考えて「この命令は“保護付”で定義するのが好ましい」ことにも注意しましょう。

```tex
% スイッチ'my@in@emph': 今'\emph'の中であるか.
\newif\ifmy@in@emph
% \myImportant{<text>}: "オレ的重要"の装飾付きでテキストを出力する.
\NewDocumentCommand\myImportant{m}{%
  \ifmy@in@emph
    \textbf{#1}%
  \else
    \emph{#1}%
  \fi
}
```

以降ではifthenを用いたコードの方を採用します。

## \\emph をフックする方針

いよいよ本題の「`\emph`を**フックする**」実装について検討しましょう。

求める動作は「`\emph`の中である場合にだけフラグ`myInEmph`が真になる」ということです。これを実現する簡単な方法は、`\emph`の動作の前後にそれぞれ「`myInEmph`を真にする」「`myInEmph`を偽にする」という動作を追加することです[^no-nest]。概念的なコードで表すと以下のようになります。

[^no-nest]: `\emph`がネストする場合はこれでは失敗しますが、仕様としてネストはサポートしないことにしたのでした。
               
```tex:(概念的コード)
\RenewDocumentCommand\emph{m}{% 再定義する
  \setboolean{myInEmph}{true}% フラグを真にする
  "従来の\emph"{#1}%
  \setboolean{myInEmph}{false}% フラグを偽にする
}
```

## 参考:sushi:：旧来のTeX者の方法

:::note warn
この節の内容:sushi:は本題とは無関係なので、LaTeX者の皆さんは丸ごとスキップしてかまいません。
:::

イマドキの方法を紹介する前に、旧来のTeX言語で使われてきた手法を復習しておきます。

### 愚直に再定義する方法

「`\emph`をフックする」ための最も愚直な方法は「`\emph`の**定義を調べて**、その上で動作を追加した形で再定義する」というものです。

`latex null`を実行してLaTeXを対話モードで起動した後で、`\ShowCommand`命令を利用して`\emph`の定義を調べます。

:::note info
`\ShowCommand`は「プリミティブ`\show`のLaTeX用拡張版」に相当するイマドキのLaTeX命令で、“LaTeXの命令定義がTeXのマクロ定義に単純には対応**しない**”場合[^non-simple]にも適切な定義本体のコードが出力されます。
:::

[^non-simple]: 「`\DeclareRobustCommand`でLaTeX保護付命令を定義する」「`\newcommand`系命令でオプション引数付の命令を定義する」「xparse系の命令（`\NewDocumentCommand`等）で命令を定義する」という場合が該当します。

```text
*\ShowCommand\emph
> \emph=robust macro:
->\protect \emph␣ .

> \emph␣=\long macro:
#1->\ifmmode \nfss@text {\em #1}\else \hmode@bgroup \text@command {#1}\em \chec
k@icl #1\check@icr \expandafter \egroup \fi .
```

ここから、`\emph`はLaTeX保護付の（`\DeclareRobustCommand`で定義された）命令であることがわかります。

:::note info
`\emph`のLaTeX保護付命令の実行は「`emph␣`（末尾に空白）という名前の制御綴[^cseq]」に移譲されます。この制御綴を`\emph␣`と書くことにします。上の画面でこの制御綴を表す`\emph `の表示の部分を敢えて`\emph␣`と書きました[^show^space]。
:::

[^cseq]: 本記事ではTeX用語の「control sequence」の訳語として**​「制御綴」​**を用います。
[^show^space]: 実際の`\ShowCommand`の実行では`␣`の部分は単に空白として表示されます。`\emph  .`のように“空白が2つ空いている”ことから「末尾に空白をもつ制御綴名」であることを判断する必要があります。

`\emph`のカーネルでの元々の定義は以下のように書けます[^real-emph]。

[^real-emph]: ただし実際には`\emph`命令は`\DeclareTextFontCommand`によって定義されています。

```tex
% '\emph'の元々の定義.
\DeclareRobustCommand\emph[1]{%
  \ifmmode
    \nfss@text{\em #1}%
  \else
    \hmode@bgroup
      \text@command{#1}\em
      \check@icl#1\check@icr
    \expandafter\egroup
  \fi
}
```

ここまで把握できれば`\emph`を実際に再定義するのは簡単です。先頭と末尾に`\setboolean`のコードを追加すればいいだけです。

```tex
% '\emph'を再定義する.
\DeclareRobustCommand\emph[1]{%
  \setboolean{myInEmph}{true}%←追加
  \ifmmode
    \nfss@text{\em #1}%
  \else
    \hmode@bgroup
      \text@command{#1}\em
      \check@icl#1\check@icr
    \expandafter\egroup
  \fi
  \setboolean{myInEmph}{false}%←追加
}
```

手順1～3で記述したコードをまとめると`\myImportant`の実装が完成します。

<details><summary>myimportant.sty（愚直に再定義バージョン）</summary>

```tex:myimportant.sty（愚直に再定義バージョン）
\RequirePackage{ifthen}
% 変数'myInEmph': 今'\emph'の中であるか.
\newboolean{myInEmph}
% \myImportant{<テキスト>}: "オレ的重要"の装飾付きでテキストを出力する.
\NewDocumentCommand\myImportant{m}{%
  \ifthenelse{\boolean{myInEmph}}{%
    % フラグmyInEmphが真の場合の処理
    \textbf{#1}%
  }{%else
    % myInEmphが偽の場合の処理
    \emph{#1}%
  }%
}
% '\emph'を再定義する.
\DeclareRobustCommand\emph[1]{%
  \setboolean{myInEmph}{true}%←追加
  \ifmmode
    \nfss@text{\em #1}%
  \else
    \hmode@bgroup
      \text@command{#1}\em
      \check@icl#1\check@icr
    \expandafter\egroup
  \fi
  \setboolean{myInEmph}{false}%←追加
}
```

</details>

このパッケージファイルmyimportant.styを用意してテスト文書test.texを実際にタイプセットすると想定通り（冒頭の画像で示した）の出力結果が得られます。ということは、これで「お題」を解決したことになるのでしょうか？

残念ながら**違います**。なぜなら、お題では「事前には`\emph`の**仕様・実装が不明**である」という条件が付いているからです。「現在の仕様に基づいて新しい実装を作る」という愚直な方法はそもそも通用しないのでした。

### 別の命令にコピーする方法

既存の命令を「フックする」ための他の手法として「既存の命令を**別の名前の命令にコピーする**」というものがあります。前節で示した`\emph`の再定義の“概念的コード”を改めて見てみましょう。

```tex:(概念的コード)
\RenewDocumentCommand\emph{m}{% 再定義する
  \setboolean{myInEmph}{true}% フラグを真にする
  "従来の\emph"{#1}%
  \setboolean{myInEmph}{false}% フラグを偽にする
}
```

もちろんこのコードはそのままでは使えませんが、もし「従来の`\emph`」の同等の動作をする命令が**別の名前**、例えば`\my@org@emph`で定義されているとすれば、その`\my@org@emph`を使って`\emph`が素直に再定義できるはずです。

```tex:(実際のコード)
% '\emph'を再定義する.
\RenewDocumentCommand\emph{m}{%
  \setboolean{myInEmph}{true}% フラグを真にする
  % '\my@org@emph'が従来の'\emph'と等価だと仮定する
  \my@org@emph{#1}% 
  \setboolean{myInEmph}{false}% フラグを偽にする
}
```

ということは、上の再定義を行う**前に**「`\emph`を`\my@org@emph`にコピーする」という手順を行えばよいことになります。

ところがここで問題があります。それは「命令を確実に**コピーするのは案外難しい**」ということです。一見すると、単純にTeXプリミティブの`\let`を使えばいいように見えます。

```tex
% 命令をコピーする
\let\my@org@emph\emph
```

しかしこれは正しくありません。先述の通り、`\emph`は`\DeclareRobustCommand`で定義されたLaTeX保護付命令であるため、“`\emph`**命令**の定義”の実体は実際には`\emph␣`というTeX**マクロ**に定義されているからです。従って「`\emph`**マクロ**を`\my@org@emph`**マクロ**にコピーする」とともに「`\emph␣`マクロを`\my@org@emph␣`マクロにコピーする」という手順を行わないとコピー先の`\my@org@emph`**命令**が正常に動作しないのです。結局「`\emph`命令を`\my@org@emph`**命令**にコピーする」コードは以下のようになります。

```tex
% '\emph'マクロを'\my@org@emph'にコピー
\let\my@org@emph\emph
% '\emph␣'マクロを'\my@org@emph␣'にコピー
\ExpandArgs{cc}\let{my@org@emph }{emph }
```

:::note info
`\ExpandArgs`は「命令の引数を制御綴名から制御綴に転換させる」という機能をもったイマドキのLaTeX命令です。`\ExpandArgs{cc}`はちょうどexpl3の`\exp_args:Ncc`と同じ働きをします。
:::

これで一応動くようになるのですが、ここで再び“お題の条件”が問題になります。カーネル標準の`\emph`は確かにLaTeX保護付命令なのですが、お題の条件では`\emph`の特定の実装を前提にできません。すると、そもそも`\emph`が“どのように定義されたLaTeX命令”かも不明となり、「`\emph`命令を`\my@org@emph`命令に確実にコピーする」手順も不明になりそうです。

ところが実は、イマドキのLaTeXには「LaTeXの命令をコピーする」ための機能が備わっています。それが`\DeclareCommandCopy`命令です。

  * `\DeclareCommandCopy\命令A\命令B`： LaTeXの命令`\命令B`を`\命令A`にコピーする。`\命令B`が“TeXのマクロ定義に単純には対応しない”方式で定義された場合でも正しくコピーされる[^command-copy-1][^command-copy-2]。

[^command-copy-1]: つまり`\命令B`は`\命令A`を定義したのと同じ定義文（`\NewDocumentCommand`等）で定義したのと等価になります。コピーされるのは「`\NewDocumentCommand`に与えた定義本体」の範囲のコードであり、そこで参照されている下請けのマクロまでコピーされるわけではありません。
[^command-copy-2]: `\DeclareCommandCopy`は`\命令A`が定義済の場合も無条件で定義を上書きします。“Declare”を“New”や“Renew”に変えた名前の命令もあり、それぞれ名前から予想される通りの動作をします。

この`\DeclareCommandCopy`を使えば「命令のコピー」の問題を完全に解決できます。

```tex
% '\emph'命令の現在の定義を'\my@org@emph'にコピー
\DeclareCommandCopy\my@org@emph\emph
```

以上のコードをまとめると“お題の条件”を満たす`\myImportant`の実装が完成します。

<details><summary>myimportant.sty（別命令にコピーバージョン）</summary>

```tex:myimportant.sty（別命令にコピーバージョン）
\RequirePackage{ifthen}
% 変数'myInEmph': 今'\emph'の中であるか.
\newboolean{myInEmph}
% \myImportant{<テキスト>}: "オレ的重要"の装飾付きでテキストを出力する.
\NewDocumentCommand\myImportant{m}{%
  \ifthenelse{\boolean{myInEmph}}{%
    % フラグmyInEmphが真の場合の処理
    \textbf{#1}%
  }{%else
    % myInEmphが偽の場合の処理
    \emph{#1}%
  }%
}
% '\emph'命令の現在の定義を'\my@org@emph'にコピー
\DeclareCommandCopy\my@org@emph\emph
% '\emph'を再定義する.
\RenewDocumentCommand\emph{m}{%
  \setboolean{myInEmph}{true}% フラグを真にする
  \my@org@emph{#1}% 
  \setboolean{myInEmph}{false}% フラグを偽にする
}
```

</details>

## LaTeXの“命令フック機能”を使う方法

さて、かなり遠回りしてきましたが、いよいよ本題の「イマドキのLaTeXの命令フック機能」に話を移しましょう。

### 命令フック機能

新しいLaTeXで提供される**命令フック機能**は、任意の命令を対象にして、その**先頭および末尾に新たな動作を追加**することを可能にします。

  * `\AddToHook{cmd/‹命令名›/before}{‹コード›}`： LaTeXの命令`\‹命令名›`について、その先頭で`‹コード›`が実行されるようにする。
  * `\AddToHook{cmd/‹命令名›/after}{‹コード›}`： LaTeXの命令`\‹命令名›`について、その末尾で`‹コード›`が実行されるようにする。

:::note info
もちろん、対象の命令が“TeXのマクロ定義に単純には対応しない”方式で定義されたものでも正しく動作します。
:::

命令の代わりに環境を対象とした形式もあります。

  * `\AddToHook{env/‹環境名›/before}{‹コード›}`： 指定の名前のLaTeXの環境について、その先頭（グルーピングに入る前）で`‹コード›`が実行されるようにする。
  * `\AddToHook{env/‹環境名›/after}{‹コード›}`： 指定の名前のLaTeXの環境について、その末尾（グルーピングを出た後）で`‹コード›`が実行されるようにする。

つまり、新しいLaTeXの命令フック機能は、従来「命令の別名へのコピー」という技法で対応していた「命令のフック」という操作を、もっと安全でかつ直感的な方法で扱えるようにしたものといえるでしょう。

### イマドキの方法でフックする

それでは早速、イマドキの命令フック機能を利用して“お題”の手順3を実装してみましょう。「`\emph`命令の先頭と末尾に必要な`\setboolean`のコードを追加したい」ので以下のようになります。

```tex
% '\emph'にフックを施す.
\AddToHook{cmd/emph/before}{%
  \setboolean{myInEmph}{true}%
}
\AddToHook{cmd/emph/after}{%
  \setboolean{myInEmph}{false}%
}
```

フック機能はまさに“フックするための機能”であるため、極めて直接的に要件が実現できることが判ります。

手順1～3のコードをまとめたものは以下の通りです。全体としてLaTeXユーザにも十分に理解しやすい感じになっています。

```tex:myimportant.sty（イマドキのLaTeXバージョン）
\RequirePackage{ifthen}
% 変数'myInEmph': 今'\emph'の中であるか.
\newboolean{myInEmph}
% \myImportant{<テキスト>}: "オレ的重要"の装飾付きでテキストを出力する.
\NewDocumentCommand\myImportant{m}{%
  \ifthenelse{\boolean{myInEmph}}{%
    % フラグmyInEmphが真の場合の処理
    \textbf{#1}%
  }{%else
    % myInEmphが偽の場合の処理
    \emph{#1}%
  }%
}
% '\emph'にフックを施す.
\AddToHook{cmd/emph/before}{%
  \setboolean{myInEmph}{true}%
}
\AddToHook{cmd/emph/after}{%
  \setboolean{myInEmph}{false}%
}
```

このパッケージファイルmyimportant.styを用意してテスト文書test.texを実際にタイプセットしてみると、以下の出力結果が得られます。

![image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/d0c32c15-92d1-df1f-16fb-255eff047c98.png)

想定通りの結果が得られていることが判ります:blush:

### 別の \\emph で試してみる

“お題の条件”では「元々の`\emph`の動作が何であっても`\myImportant`が仕様通りに動く」ことが求められていました。`\emph`がLaTeX標準と異なっても正常動作することを確認しましょう。

例えば、`\emph`を「文字色を赤にする」という動作で再定義します。さらに新しい`\emph`の定義には（`\DeclareRobustCommand`でなく）xparse系の`\RenewDocumentCommand`を用いることにします。

```tex:text2.tex
% pdfLaTeX文書
\documentclass[a4paper]{article}
\usepackage{xcolor} % '\color'のため
% '\emph'の定義を変更してみる.
\RenewDocumentCommand\emph{+m}{%
  {\color{red}#1}% 文字色を赤にする
}
% (これ以降はtest.texと同じ)
\usepackage{myimportant}
\begin{document}
% '\emph'の外で使う場合
The {\TeX} language is \myImportant{dangerous}.

% '\emph'の中で使う場合
\emph{The {\TeX} language is \myImportant{dangerous}.}
\end{document}
```

出力結果は以下の通りです。この場合も想定通りの結果が得られました:blush::blush:

![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/60a02bb4-9809-7b60-a8aa-305cd3f0ef68.png)

## まとめ

イマドキのLaTeXには旧来のLaTeXにはなかった便利な命令がイロイロあります:smiley: 皆さんも、イマドキのLaTeX命令の使い方をドンドン解説しましょう！:information_desk_person: 

[aminophen-2020]: https://aminophen.github.io/slide/hytexonline20.pdf
[wtsnjp-2024]: https://speakerdeck.com/wtsnjp/texconf2024-ltnews
[ifthen]: https://qiita.com/zr_tex8r/items/71ae46c9c4e8cb575073
[xparse]: https://qiita.com/zr_tex8r/items/50168ad7087516c3e139