マクロツイーター

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

LaTeX Workshopでllmkしてみたらアレだった件

VSCode上でLaTeXの統合環境を実現するための拡張機能としては「LaTeX Workshop」が事実上の標準となっている。LaTeX Workshopでは「実行するコマンドのリスト」の指定を完全にユーザに委ねる設計になっている。このため、原理的には、「llmk」などの新しいビルドツールと組み合わせて使えることが期待できる。

一週間ほど前に、めでたくllmkがCTANTeX Liveに収録されたので、さっそく「LaTeX Workshopとllmkを組み合わせる」設定を試してみたら、LaTeX Workshopがアレなせいでアレだった、という話。

LaTeX Workshopやllmk自体に関する解説は一切省略する。

なぜLaTeX Workshopでllmkしたかったか

基本的にLaTeX Workshopのビルドは「ある決まったコマンドの列(レシピと呼ばれる)を実行する」というものなので、異なる「コマンドの列」を必要とする文書を扱うたびにレシピを(メニューから)切り替える必要がある。LaTeX WorkshopではLatexmkを呼び出すレシピが既定で登録されていて、Latexmkを使うとある程度は「コマンドの列」の違いを吸収できるが、Latexmkには「利用するTeXエンジンをソースファイルから判別する」機能は持っていないため、エンジン選択の煩雑さは残る。

一方、llmkを使うと「利用するTeXエンジンをソースファイルから判別する」ことが可能になるため、「レシピの切替」の考慮が全く不要になって、幸せになると考えた次第である。

LaTeX Workshopを設定した

llmk <ファイル名>」だけを実行するレシピを登録する。

[setting.json 追記]
{
    //...
    "latex-workshop.latex.recipes": [
        {
            "name": "llmk",
            "tools": [
                "llmk"
            ]
        },
        // 他のレシピ設定...
    ],
    "latex-workshop.latex.tools": [
        {
            "name": "llmk",
            "command": "llmk",
            "args": [
                "%DOC%"
            ],
            "env": {}
        },
        // 他のツール設定...
    ],
    // ...
}

簡単な文書でテストした

「uplatex→dvipdfmx」でビルドできる単純なupLaTeX文書を用意した。

※先頭行にllmkのためのマジックコメントがある。

[main.tex]
%#!uplatex
\documentclass[uplatex,dvipdfmx,9pt,a5paper]{jsarticle}
\usepackage[scale=0.9]{geometry}
\usepackage{scsnowman}
\begin{document}
\section{\TeX}
{\TeX}はアレ。
\section{結論☃}
{\centering\scsnowman[scale=10, 
  hat,snow,arms,buttons,muffler=red]\par}
\end{document}

これをコマンドシェルからllmkでビルドしてみる。

llmk main.tex

すると、「uplatex2回1→dvipdfmx」が実行されて正常にビルドが完了する。

f:id:zrbabbler:20200923164449p:plain
PDF出力(素敵)

では、このソースファイルをVSCodeで開いて、LaTeX Workshopの「llmk」レシピでビルドしてみる。

f:id:zrbabbler:20200923165317p:plain
LaTeX WorkshopでビルドしてPDFを表示した様子

これは想定通りの結果になった。

チョット複雑な文書でテストした

フツーにllmkしたら想定通り

続いて、相互参照やbibファイルからの文献参照を含んだ、チョット複雑なupLaTeX文書を用意してみた。

※このソースには一か所ミスがある。8行目に\ref{sec:sconclusion}とあるが、これは\ref{sec:conclusion}の誤りである。

[main.tex]
%#!uplatex
\documentclass[uplatex,dvipdfmx,9pt,a5paper]{jsarticle}
\usepackage[scale=0.9]{geometry}
\usepackage{scsnowman}
\begin{document}
\section{はじめに}
\ref{sec:tex}節で{\TeX}\cite{texbook}についてdisる。
\ref{sec:sconclusion}節で結論を述べる。
\section{\TeX}\label{sec:tex}
{\TeX}はアレ。
\section{結論☃}\label{sec:conclusion}
{\centering\scsnowman[scale=10, 
  hat,snow,arms,buttons,muffler=red]\par}
\bibliographystyle{plain}\bibliography{main}
\end{document}
[main.bib]
@Book{texbook,
  author =       "Donald Ervin Knuth",
  title =        "The {\TeX}book",
  volume =       "A",
  publisher =    "Addison-Wesley",
  address =      "Reading, MA, USA",
  edition =      "23rd printing, with corrections.",
  pages =        "ix + 483",
  year =         "1993",
  series =       "Computers and typesetting",
}

先ほどと同様にコマンドシェルで「llmk main.tex」でビルドすると、「uplatex2回→bibtex→uplatex2回→dvipdfmx」と実行されて次の出力が得られる。

\refの誤りのところが??になっている。

f:id:zrbabbler:20200923171909p:plain
PDF出力(素敵)

この文書では\refの引数が一か所誤っているため、解決できない参照が最後まで残り、最後のuplatexの実行において以下の警告が発生している。

LaTeX Warning: Reference `sec:sconclusion' on page 1 undefined on input line 8.

LaTeX Warning: There were undefined references.

LaTeX Workshopでllmkしたらアレ

では、このソースファイルをLaTeX Workshopでビルドしたらどうなるか。

f:id:zrbabbler:20200923174050p:plain
LaTeX WorkshopでビルドしてPDFを表示した様子

出力されたPDFを見ると、先ほど示したものと全く同じになっている。つまり、llmkの実行は最後のuplatexの実行まで想定通りに行われたと推定できる。

しかし、今回のビルドの結果には大きな問題がある。それは「PROBLEMS」の表示である。

f:id:zrbabbler:20200923183739p:plain
アレな警告の通知

ここにはLaTeXの実行中に発生したエラーや警告の内容が掲示される。先述の通り、このソースファイルをビルドすると、最終的に2個の警告が発生するはずである。ところが実際にはPROBLEMSには14個もの警告が出ている。しかも、よく見ると、最終的には正常に解決しているはずのsec:texや文献texbookに対しても「参照未解決」の警告が出ているのである。

sec:textexbookの参照は初回のuplatexの実行のときは解決できないはずである。参照未解決の警告の異常な多さを考えると、「途中のものを含めて全てのuplatexの実行における警告をLaTeX Workshopが拾ってしまっている」と推定できる。

※途中の警告を拾うため、仮に「誤りがなくて最終的に全ての参照が解決されるLaTeX文書」をビルドした場合でも警告が発生したような表示になる。

やっぱり、LaTeX Workshopがアレ

本来問題がないはずの箇所でエラー・警告が通知されるのではPROBLEMS機能がまるで役に立たない。「最後のLaTeXエンジンの実行」で発生したエラー・警告だけを拾うべきなのは明らかだろう。

しかし冷静に考えてみると、「最後のLaTeXエンジンの実行」だけ見る、というのは無理な要求であると思えてくる。なぜなら、LaTeX Workshopからみると、ビルドにおいては「llmk」という単一のコマンドを実行したにすぎないわけで、その標準出力や標準エラーのテキストから「LaTeXのエラー・警告」を拾うとしても、「最後のLaTeXエンジンの実行」に相当する部分を抜粋できそうにない……。

……いや待て、全く同じことはLatexmkを使う場合にも成立するはずである。しかしLaTeX Workshopが既定で設定を登録しているくらいだから、Latexmkで同じ問題が起こっているはずがない。実際に、Latexmkで(upLaTeX用の設定を用意して)ビルドしてみると、PROBLEMSの通知は正常(警告2個)になる。なぜLatexmkの場合は「最後のLaTeXエンジンの実行」の部分を抜粋できるのだろうか。

チョットLaTeX Workshopのソースコードを眺めてみると……あっ!

f:id:zrbabbler:20200923185614p:plain

なんと、Latexmk専用の処理が書かれている!

Latexmkが実際にコマンドを起動する際に次のようなメッセージを端末に出力しているのだが:

Latexmk: applying rule 'latex'

要するに、LaTeX Workshopは、このメッセージを目印にして「抜粋」の処理を行っているようである。

試しに、llmkのプログラムに細工をして、このLatexmkのメッセージを出力するようにしてみると……。

f:id:zrbabbler:20200923183647p:plain
マトモな警告の通知

ああっ、PROBLEMSの通知が正常になった!

………………これはひどい

まとめ


  1. \sectionの情報が.auxファイルに書き出されるため、uplatexは2回実行される。