メモ: Pandocのテンプレートとデータディレクトリの優先順位

[Pandoc](http://pandoc.org/)のテンプレート・ユーザデータディレクトリに関して質問があったのでメモしておきます。

## 何の話か

Pandocの出力をカスタマイズする仕組みとして、テンプレートまたはユーザデータがあります。

詳細は [User's GuideのTemplates](http://pandoc.org/MANUAL.html#templates) を参照。

### テンプレート

例えばHTMLやLaTeXで出力する際に、「ヘッダ・フッタをカスタマイズしたい」「スタイルファイルへのリンクを挿入したい」「変数で条件分岐させたい」というケースに、ユーザはテンプレートを編集できます。

### ユーザデータ

テンプレートが使えない例外がたまにあり、例えばWord docx(docx)やLibre office Writer(odt)の書式カスタマイズはこちらでやります。

詳細は [ドキュメント変換ツールPandoc：ユーザーズガイドを熟読して分かったマニアックな使い方 - Qiita](http://qiita.com/sky_y/items/5fd5c9568ea550b1d7af) をご覧ください。

### ユーザデータディレクトリ

テンプレートとユーザデータを格納するディレクトリをデータディレクトリと呼び、そのうちユーザがカスタマイズするためのものをユーザデータディレクトリと呼びます。

データディレクトリのうち、特に「templates」以下のファイルを **テンプレート** と呼び、それ以外を **データファイル** と呼びます。

ただしテンプレートは

- `--template` オプションで指定する場合
- ユーザデータディレクトリを指定して格納する場合

があります。**後者では、ユーザデータディレクトリの中の「templates」ディレクトリにテンプレートを入れます。** （これを忘れると読まれません）

ユーザデータディレクトリには `--data-dir` オプションで直接指定できるものと、Pandocが（既定のデータディレクトリよりも優先して）勝手に読みにいくデフォルトユーザデータディレクトリがあります。

デフォルトユーザデータディレクトリの場所は通常、 `pandoc -v` で示されます。 (`Default user data directory: hoge` という形で)

実際には

- Windows 7以降: `%HOME%\AppData\Roaming\pandoc`
- Unix系 (macOS/Linux): `~/.pandoc`

であることが多いです。

ただし、勝手に作られるとは限らないので、そのディレクトリがない場合は自分でディレクトリを作ります。

以下、Pandocのテンプレートとユーザデータディレクトリについて、どのように適用されるのか（適用の優先順位）について説明します。

## 既定のデータディレクトリ

Pandocが既定で使うデータディレクトリが実際のマシン上でどこに置かれるかについては、ドキュメント上の明示はありません。ただし、GitHubディレクトリの

https://github.com/jgm/pandoc/tree/master/data

において、確認することができます。

ただし、公式で推奨する方法は、

- テンプレート: `pandoc -D FORMAT` または `pandoc --print-default-template FORMAT` (FORMATは `-f/-t` で指定するフォーマット名)
- ユーザデータ: `pandoc --print-default-data-file FILE` (FILEはデータファイルの名前)

によって出力することです。（標準出力に出るので、リダイレクトで保存します）

## テンプレート・ユーザデータディレクトリの優先順位

どの優先順位でテンプレートやユーザデータディレクトリが使われるかは、（よく読めば）[Pandocのユーザーズガイド](http://pandoc.org/MANUAL.html)に書かれています。

結論から言えば

テンプレートを引数で指定 (`--template`) > ユーザデータディレクトリを引数で指定 (`--data-dir`) > デフォルトユーザデータディレクトリ > Pandoc既定のデータディレクトリ

のようです。

順に見ていきます。

> --template=FILE
>
> Use FILE as a custom template for the generated document. Implies --standalone. See Templates, below, for a description of template syntax. If no extension is specified, an extension corresponding to the writer will be added, so that --template=special looks for special.html for HTML output. If the template is not found, pandoc will search for it in the templates subdirectory of the user data directory (see --data-dir). If this option is not used, a default template appropriate for the output format will be used (see -D/--print-default-template)

つまり `--template` が指定されたとき（一部推測込みになりますが）、順番は

1. カレントディレクトリを見る
    - 指定されている文字通りのファイル名を探す
    - 拡張子が無い場合は、出力フォーマットに対応する拡張子を勝手に補う
2.  `--data-dir` で指定されるユーザデータディレクトリの中にある「templates」ディレクトリを探す
3. デフォルトユーザデータディレクトリの中にある「templates」を探す
4. Pandoc既定のデータディレクトリの中にある「templates」を探す

となるようです。

## 実験

筆者環境 (Windows 10 build 15063, pandoc 1.19.2.1) で実験してみました。

- 特に意味はありませんが、Emacs org-mode (org)をフォーマットとして使います。
- 注意：Chocolatey v0.10.5 で入れたのですが、Chocolatey上では「pandoc 1.19.2.1」というバージョンなのに、 `pandoc -v` では「pandoc 2.0」と表示されます。実際には前者の「pandoc 1.19.2.1」が入っていると思われます。

### 1. デフォルトユーザデータディレクトリにテンプレートを格納

- Windowsなので `%HOME%\AppData\Roaming\pandoc` に `default.org` という名前でテンプレートファイルを作ります。
- bodyの下に「AAA」と表示されるようにします。

```default.org
$if(title)$                                             
#+TITLE: $title$                                        
                                                        
$endif$                                                 
$if(author)$                                            
#+AUTHOR: $for(author)$$author$$sep$; $endfor$          
$endif$                                                 
$if(date)$                                              
#+DATE: $date$                                          
                                                        
$endif$                                                 
$for(header-includes)$                                  
$header-includes$                                       
                                                        
$endfor$                                                
$for(include-before)$                                   
$include-before$                                        
                                                        
$endfor$                                                
$body$                                                  
AAA                                                     
$for(include-after)$                                    
                                                        
$include-after$                                         
$endfor$                                                
```

### 2. 適当なディレクトリにテンプレートを作成

bodyの下に「BBB」と表示されるようにします。

```tmp.org
$if(title)$
#+TITLE: $title$

$endif$
$if(author)$
#+AUTHOR: $for(author)$$author$$sep$; $endfor$
$endif$
$if(date)$
#+DATE: $date$

$endif$
$for(header-includes)$
$header-includes$

$endfor$
$for(include-before)$
$include-before$

$endfor$
$body$
BBB
$for(include-after)$

$include-after$
$endfor$
```

### 3. カレントディレクトリにtemplatesディレクトリを作成、その下にテンプレート作成

- 2.のtmp.orgと同じディレクトリにtemplatesディレクトリを作成
- その更に下にdefault.orgというテンプレートファイルを作成
- bodyの下に「CCC」と表示されるようにします。

```templates/default.org
$if(title)$
#+TITLE: $title$

$endif$
$if(author)$
#+AUTHOR: $for(author)$$author$$sep$; $endfor$
$endif$
$if(date)$
#+DATE: $date$

$endif$
$for(header-includes)$
$header-includes$

$endfor$
$for(include-before)$
$include-before$

$endfor$
$body$
CCC
$for(include-after)$

$include-after$
$endfor$
```

まとめると、こういう構造です。（実際に入れているファイルの一部は省略）

```
%HOME%/AppData/Roaming/pandoc/templates
└── default.org

カレントディレクトリ
├── templates
│   └── default.org
└── tmp.org
```


### 4. pandocコマンドを実行

```
$ echo '**hoge**' | pandoc -s -f markdown -t org  # (A)
*hoge*
AAA

$ echo '**hoge**' | pandoc -s -f markdown -t org --template tmp.org # (B)
*hoge*
BBB

$ echo '**hoge**' | pandoc -s -f markdown -t org --data-dir . # (C)
*hoge*
CCC

$ echo '**hoge**' | pandoc -s -f markdown -t org --data-dir . --template tmp.org # (D)
*hoge*
BBB

$ echo '**hoge**' | pandoc -s -f markdown -t org --template tmp.org --data-dir . # (E)
*hoge*
BBB

```

- (A) デフォルトユーザデータディレクトリが指定された
- (B) カレントディレクトリのテンプレート(tmp.org)が指定された
- (C) カレントディレクトリの中のtemplatesディレクトリにあるdefault.orgが指定された
- (D) カレントディレクトリのテンプレート(tmp.org)が指定された
    - `--template`オプションが優先され、`--data-dir`オプションは無視された
- (E) Dと同様（引数の順番を入れ替えたが、結果は同じだった）

### 5. 結論

先ほどのように

テンプレートを引数で指定 (`--template`) > ユーザデータディレクトリを引数で指定 (`--data-dir`) > デフォルトユーザデータディレクトリ

という優先順位を確認しました。（Pandoc既定のデータディレクトリについては実験を省略）

以上です。