レポートを書こう
これは ISer Advent Calendar 2021 の18日目の記事です.
理学部情報科学科に所属しているのに紙のレポートを提出しているんですか?まさかね.
今回は私のレポート執筆環境の紹介です.全知の方向けに端的に言うと,「markdownを書き,pandocでfilterを適用しつつ.tex
に変換し,LuaLaTeXでコンパイルするフローを変更監視付きで行う」をしています.以下はそれぞれの技術についての詳細です.
Markdown
HTMLを簡単に書ける言語,もとい,文書の構造を少ない記号とインデントだけで表現できる言語です.装飾部分を意識せずに文書を書けるように,文法で制限していると考えるとmarkdownで書く意義が伝わると思います.
ここでは,たくさんあることで有名なMarkdownの方言のうち,markdown.pl
ではなくpandocが認識するPandoc’s Markdownを扱います.レポートではこれを書きます.
LaTeX
出題されるレポートの内容上,数式が多く,また複雑になる上に,レイアウトにはそこまでこだわらなくてよいので,組版1自体はLaTeXで行うことにします.LaTeXは皆さんご存知2だと思うので説明は省きます.
レポートではこれを極力書きません.最悪処理系TeXに依存したコードを書きたくないので.
Pandoc
Pandocはマークアップ言語間で文書を変換するフリーウェアです.重要なことはすべてマニュアルに書いてある.
Pandoc is a Haskell library for converting from one markup format to another, and a command-line tool that uses this library.
この"converting"は,それぞれの言語間に特殊な変換を施しているのではなく,pandoc独自の中間表現(Pandoc AST)を経由して実現されます.入力言語からASTへの変換をreader,ASTから出力言語への変換をwriterと呼びます.
Pandoc is structured as a set of readers, which translate various input formats into an abstract syntax tree (the Pandoc AST) representing a structured document, and a set of writers, which render this AST into various output formats. Pictorially:
[input format] ==reader==> [Pandoc AST] ==writer==> [output format]
This architecture allows pandoc to perform × conversions with readers and writers.
https://pandoc.org/using-the-pandoc-api.html
この記事では入力言語としてmarkdown
を選択し,出力言語としてlatex
やpdf
を選択することを想定します.
他にもhtml
やdocx
などに対応しており,後述のfilterも活用することで様々な用途で活用できます.
Readerやwriterを自分で作ることもできますが,この記事ではそこまで触れません.
Install
Pandoc - Installing pandocに書いてあります.最新版を入れるのがまあまあめんどくさいですし,後述のfilterで他のなんらかの環境を一緒に入れることになると思うので,Dockerを使いましょう.公式imageをFROM
したり,COPY --from=
の対象にして/usr/local/bin/
の関連ファイルをコピーしたりすれば動きます.
私と実験のグループが一緒になってしまった被害者さんたちにはもうDockerをinstallしてもらっていますし,堂々とDockerを登場させられますね.
Pandoc’s Markdown
Pandocは,markdownの様々な方言にわたってそれぞれの文法を一つずつ拡張機能と捉え,拡張機能の特定の集まりをデフォルト(pandoc’s markdown)とし,拡張機能単位で有効化/無効化することが可能です.
これも全部ここに書いてあります.優秀なドキュメント.
https://pandoc.org/MANUAL.html#pandocs-markdown
PDF Output
Pandocの出力言語にpdf
を選択すると,pdf-engine
で指定されたプログラムを用いてコンパイルを行います.
それに渡されるオプションはpdf-engine-opt
で渡します.
Default File
コマンドラインオプションが与えられなかった場合のフォールバックを指定できます.いちいち長いコマンドを書かずに設定ファイル化できるので,使わない手はありません.
https://pandoc.org/MANUAL.html#default-files
実体はただのyamlです.ここで定義したオブジェクトのうち,variables
の中身がそのまま定義済み変数となり,template内で参照できます.
Template
-s
(--standalone
)を引数に含む場合,そのwriterの言語の処理系で自己完結するファイルを生成するようにできます.これを指定しなかった場合との差異を埋めるのがtemplateです.
デフォルトのtemplateは
pandoc -D latex
によりstdoutに書かれます.
Templateは,プリアンブルに書かなければならないものにも使えます.例えば\usepackage{}
とか\tcbuselibrary{most}
みたいなものの有無や順序,引数などを適当に変数リストから拾ってtemplateで条件分岐することで実現できます.
私はLuaLaTeXのデフォルトの数式フォントが好きではないので,
\setmathfont{Latin Modern Math} \setmathfont{TeX Gyre Pagella Math}[range={bb,bbit}, Scale=MatchUppercase] \setmathfont[range=\setminus]{Xits Math}
こういうのも追記しています.3行目はLatin Modern Math
に無い\setminus
を適当なところから借りるものです.
Filter
Pandocの変換過程でPandoc ASTを経由することにさっき触れました.Pandoc ASTをPandoc ASTに変換する関数があれば,文書構造だけを見て別の構造を変換できます.それがpandoc filterです.合成に関して単位的半群なのでいくらでも適用できます.
https://pandoc.org/filters.html
Filterは任意の言語で書くことができます.AST上の値がadjacently taggedなjsonになってstdoutに流されるので,それを歩けば良いです.HaskellやLuaなど一部の言語では,AST上の値に対する関数を書くだけでfilterの機能をするようにサポートされています.
公式の例(残念ながらpython)が割と網羅的で良い感じです.pythonを使うならpanflute
を使うとpandocfilters
ライブラリよりも意味が取りやすいコードが書けるらしいです.
上のページやリポジトリからもわかるように,filterの用途は多岐にわたります.他のプログラムの入力をfenced_code_blocks
に書き,出力を埋め込むという使い方が特に有効で,当環境でも頻繁に用いています.
Crossref
数式を文書内で参照するような場合,crossref
の機能でラベル付けしたものを参照すると,自動で番号が振られます.これもfilterです.ただ,これは独自のAST上の型を持っているわけではなく,直にstringを書き換えるものなので,filterを適用するとラベルの情報は消えます.
引用が生じるほど構成がごちゃごちゃしたレポートを書きたくないので,最近の私は使っていません.
Citeproc
論文を引用したくなることがあります.citeproc
オプションを使うと適切な形式で引用ができます.
citeproc
はbuilt-inなfilterとして実装されているので,他のfilterとの順を扱う場合はciteproc
をオプションではなくfilterとして渡します.
cite-method
オプションはlatex
出力にのみ有効であり,これにbiblatex
を指定すると,hyperref
の\autoref
により引用し,末尾に\printbibliography
をするようになります.cleveref
を使いたかったらfilterを書きましょう.
biblatexでコンパイルする場合,texファイルを複数回コンパイルする必要があるのでした.
to: pdf pdf-engine: lualatex
は1度しかコンパイルを発火しないので,このような場合にはこれは使えず,texファイルをlatexmkの類でコンパイルすることになります.このような事情もあって,pdf-engine
にコンパイルを任せきっていません.
VSCode
definition_lists
のような,よくあるmarkdownに無いような文法を含んでおり,VS Codeに標準で備わっているsyntax highlightの不足を補う必要3が出てきます.重要なことはここに.
Syntax highlightを提供するには,addonのcontributeにTextMate文法の定義ファイルを与えます.
その実体(yaml
など)は機械的に生成できるため,MSが開発しているmarkdownのsyntax highlightのリポジトリと同じように,ある程度出力を自動化すると楽です.
TextMate文法は公式のreferenceがあり,他のsyntax highlightを提供するコードからも学ぶことができます.
Environment
これらを用いた最終的な環境について簡単に書きます.
拡張機能も作ったのでエディタはVS Codeです.Syntax highlightだけならAtomとかでも使えるんでしょうけど.
LuaLaTeXとpandocとluaの処理系を共存させたいので,適当なdocker containerを建てており,書いたレポートはdockerのマウントによりコンテナと入出力しています.
変更の監視は,手癖でnode.js
のchokidar
インスタンスの.on('change',
にpandoc
コマンドを走らせるexec()
を置いています.
pandoc
の起動引数にはデフォルトファイルを渡しており,その中に大勢の変数をくっつけています.文書のメタデータからは改変したlatex
用のtemplateや,bibliography
に値を渡しています.
他のメタデータとして,LaTeXの対応マクロに変換されるtitle
とauthor
を与えています.
メタデータ以外のmarkdownの部分は,普通のmarkdownの文法に加え,pipe_tables
,definition_lists
,footnotes
とinline_notes
,fenced_code_blocks
などを用いて書きます.数式はLaTeXに変換される自作の言語のparserとfilterを使ってtex_math_dollars
に,命題や証明の枠はdivをLaTeXの定理環境に変換するfilterを使ってfenced_divs
に,オートマトンとか構文木を書くときはgraphviz
をfilter化したものを使って,クラス名を与えたfenced_code_blocks
に,構造式もopenbabel
をfilter化したものを使い,引用はciteproc
を使うので,Zoteroに文献を追加し.bib
ファイルのパスをbibliography
に渡します.こう見るとほとんどfilterでできているような気がしてきますね.
どうしても生のLaTeXを書く必要があるときはraw_attribute
で書きます.
おわり
Pandocとpandoc filterで生活を豊かにする記事でした.明日の記事誰か書いてください.
-
LaTeXでレポートを書いている,という人はそこそこいるものの,モダンな仕様や便利なpackageを追えている人はそう多くないですよね.まだplatexでコンパイルしていたり,
\newcommand
,{\bf }
,eqnarray
を使っていたり,偏微分をいちいち\partial
を使って書いていたりしてませんよね.bxjs系記事,unicode-mathなどをLuaLaTeX/XeLaTeX上で使えてますよね.↩ -
数式にハイライトを入れたくて拡張機能を作った数日後に
June 2021 (version 1.58)
が出て,時間がだいぶ無駄になったどころかファイルの関連付けの上書きまでされたという経験があります.あとvscodeがあんまりエラーを吐いてくれなくてつらい.↩