読者です 読者をやめる 読者になる 読者になる

LaTeXをquickrunで楽に処理する

LaTeX Vim

LaTeXの文章を書かなければいけない頻度というのは, なぜか波があります. LaTeXの文章を多く書かなければならない時期とそうでない時期. そして, 多く書かなければならない時期が来るたびに, LaTeXの環境が整って来て, コンパイルなどがどんどん楽になっていくのです.

最近がわりと多く書いてる時期にあたり, それにともなってコンパイルも楽にするようにならねーかなーというわけで, quickrunを使うようになった記録です.


対象読者:

対象としない読者:

  • omakeで継続監視ビルドうめぇwww
  • Vimって何?Emacsうめぇwww
  • LaTeXって何?


Vimmerならquickrunはお使いかと思いますが, 万一使われていないようでしたら
thinca/vim-quickrun · GitHub
からインストールしてください. 設定や使い方などはdoc/を参照してください.


まずは, LaTeXの文章をコンパイルして文章を開くスクリプトを書いてみます. (Mac用)

#!/bin/sh

cp $1 temp.tex
platex temp.tex && \
  dvipdfmx temp.dvi && \
  open -a Preview temp.pdf
rm temp.log temp.dvi

コメントとしては,

  • いつも使ってるコマンドに書きなおしてください(例えばpdflatexとか)
  • もしbibとかの処理を書くなら書いておいてください, でも, あまりおすすめはしません(重くなるので; bibは最終稿でちゃんと処理すれば...)
  • 二回コンパイル?んなもん書いてるうちにaux出来ます

くらいです.


上のスクリプトを"autolatex"という名前で保存し, 実行権限を与えてパスの通っているところに放り込んでおきます. (AutoLaTeX: how to automatize LaTeX compilationとは関係ありません) 筆者は複数のPCを使っているので,

export PATH=$PATH:~/Dropbox/bin/

とやってこの中に放り込んでます.

適当なLaTeXの文章を

autolatex hoge.tex

コンパイル, pdfを開くことができたらOKです.


quickrunの設定をします. .vimrcファイルに

let g:quickrun_config.tex = {'command' : 'autolatex'}

とします. 後は, LaTeXのソースをVimで開き, 編集してquickrunを実行するだけです. ね, 簡単でしょう?


もうちょっとautolatexを改善します. 私の持っているUbuntuでは, なぜか日本語はeuc-jpじゃないとダメっぽいので, Macならutf-8のまま, Ubuntuならeuc-jpに変換する処理にします. (編集する文章はすべてutf-8で統一しています)

#!/bin/sh

if [ `uname` = "Darwin" ]; then
  cp $1 temp.tex
  platex temp.tex && \
    dvipdfmx temp.dvi && \
    open -a Preview temp.pdf
else
  nkf -e $1 > temp.tex
  platex temp.tex && \
    dvipdfmx temp.dvi && \
    evince temp.pdf
fi
rm temp.log temp.dvi

簡単ですね.


さて, 文章は書いていくとどんどん長くなります. 長くなるとコンパイルの時間が長くなってイライラします. 「この図だけコンパイルしたい, この数式あたりだけコンパイルしたい」みたいな要望が出てきます. \if0 ... \fiで要らない部分を隠すのもいいのですが, それさえ面倒なのです.

LaTeXには\inputというコマンドがあります. 例えば
main.tex:

\documentclass[a4paper,11pt]{article}
\begin{document}
\section{nyan section}
\subsection{hunya subsection}
nya-!!!
\section{wan section}
\subsection{waooon subsection}
wa-!!!
\end{document}

みたいな文章があったとします. 文章が長くなってきたなーって時に, これをファイルを分割して
main.tex:

\documentclass[a4paper,11pt]{article}
\begin{document}
\input nyan.tex
\input wan.tex
\end{document}

nyan.tex:

\section{nyan section}
\subsection{hunya subsection}
nya-!!!

wan.tex:

\section{wan section}
\subsection{waooon subsection}
wa-!!!

みたいにファイルを分けることができます.

この方法でメインの文章は\inputコマンドだけ, みたいな状況にできてハッピーなのですが, そうなるとnyan.texとかwan.texとか「だけ」コンパイルして確かめたくなります. しかし, これらの分割された文章は\begin{document}も\documentclassもないLaTeXとしては不完全なファイルになっています.

理想としては, wan.texVimで編集して, quickrunで「この章だけ」の結果を見ることです. そうすればコンパイルの時間も短くなりますし. 問題は, main.texでstyファイルを使っている場合です.
main.tex:

\documentclass[a4paper,11pt]{article}
\usepackage{amssymb,amsmath}
\usepackage{bm}
\usepackage{enumerate}
\usepackage{color}
\def\definedby{:=}
\begin{document}
\input nyan.tex
\input wan.tex
\end{document}

云々かんぬんです. これらをnyan.texとかwan.texとかで使ってると, 酷いとalign環境がありません!って怒られます.

私はいつも, 同じディレクトリーにそのプロジェクト用のprelude.styを作って
main.tex:

\documentclass[a4paper,11pt]{article}
\usepackage{prelude}
\begin{document}
\input nyan.tex
\input wan.tex
\end{document}

prelude.sty:

\usepackage{amssymb,amsmath}
\usepackage{bm}
\usepackage{enumerate}
\usepackage{color}
\def\definedby{:=}

とすることにしています. つまり, すべてのusepackageとかdefとかnewcommandを一つのファイルに書いてしまうのです. ポイントは, prelude.styをTeXのパスの通る場所に置かずに, 文章のディレクトリーに置いておくことですね. ディレクトリーによって, 内容のばらばらなprelude.styが出来るじゃないか!って怒る人がいそうですが, それで困ったことはありません.

で, nyan.texとかをコンパイルできるようにautolatexを書きなおしたのが次のスクリプトです.

#!/bin/sh

if [ $# -ne 1 ]; then
  exit 1
fi

file *.tex > /dev/null
if [ $? -ne 0 ]; then
  exit 1
else
  cat *.tex | grep '^\\documentclass' > /dev/null
fi

if [ $? -ne 0 ]; then
  documentclass="\\documentclass[a4paper,11pt]{article}"
else
  documentclass=`cat *.tex | grep '^\\\\documentclass' | head -n 1`
fi

cat $1 | grep 'documentclass' > /dev/null
isdocument=$?
if [ $isdocument -ne 0 ]; then
  echo $documentclass > temp.tex
  if [ -f prelude.sty ]; then
    echo "\\\\usepackage{prelude}" >> temp.tex
  fi
  echo "\\\\begin{document}" >> temp.tex
else
  echo "" > temp.tex
fi

if [ `uname` = "Darwin" ]; then
  cat $1 >> temp.tex
  if [ $isdocument -ne 0 ]; then
    echo "\\\\end{document}" >> temp.tex
  fi
  platex temp.tex && \
    dvipdfmx temp.dvi && \
    open -a Preview temp.pdf
else
  nkf -e $1 >> temp.tex
  if [ $isdocument -ne 0 ]; then
    echo "\\\\end{document}" >> temp.tex
  fi
  platex temp.tex && \
    dvipdfmx temp.dvi && \
    evince temp.pdf
fi
rm temp.log temp.dvi

これでnyan.texとかもコンパイルできるはずです. nyan.texのように\documentclassが書かれていない文章では, これを書いた上でprelude.styを読み込み, ファイルの内容を\begin{document}と\end{document}で優しく包んでコンパイルします.


更に, euc-jpに変換しなきゃいけない環境で, 文章をすべてutf-8で書いてる場合はもうちょっと頑張らなきゃいけないです. temp.texeuc-jpにしても, inputされてるファイルがutf-8ならうまく処理できないので. euc-jpを変換する前にファイルをinputしちゃえばいいですね. cppを使ったら楽ですかね?

#!/bin/sh
...
  # nkf -e $1 >> .temp.tex
  cat $1 | sed 's/\\input \(.*\)/#include "\1"/' | cpp | sed 's/^#.*//' |\
    sed 's/\\input \(.*\)/#include "\1"/' | cpp | sed 's/^#.*//' | nkf -e >> temp.tex
...

\inputしてるファイルの中で更に\inputしてる可能性があるので, 何回も処理しなきゃ... まぁ日本語の文章あまり書かないので問題無いですね.


quickrun+LaTeXの, 優れている点を挙げておきます.

  • C++Haskell等, 他の言語を扱っている時と同じような感覚で実行できる.
  • 出力がVimの中で表示されるため, 端末を変えなくて良い
  • omakeの継続監視ビルドは, 保存するたびに処理が動いてうざい(これは意図しない. 保存するという処理と, コンパイルするという処理は分けておきたい)
  • quickrunは, 保存しないでも実行できる!
  • ファイル分割で軽快コンパイル!ソースの部分的なものでも! (別に\inputを使わなくても, test.texとか適当なファイルにxy-picなどの図だけ書いて何回も素早くコンパイルしたいみたいな場面に便利です)

劣っている点は次のような感じです.

  • 「よし, コンパイルしよう」と思ってquickrunを動かします. 自動ではありません. (私は自動で動かす利点が分かりません)
  • 文章全体をコンパイルしたものを参照しつつ, 小さな部分をコンパイルしたいみたいなときは, temp.pdfを他の名前にcpしておく必要があります. (このような状況はあまりありません)
  • 便利さ故に, コマンドをそのうち忘れてきます. たまには忘れないように, 普段使っていないシェルで(つまり補完が効かないとか), きちんとコマンドを打つようにするといいかもしれません.
  • Windowsのことは知りません.


今の段階では, この運用で自分は満足しています. 皆さんも自分に合う運用をしてください. ではではよいquickrun+LaTeXライフを〜.

追記: 2012/10/08

やはり文章全体をコンパイルしたものと, 細かくコンパイルしたものを分けたくなったので, ちょっとだけ追記しました.
文章全体をmain.texとして, それをコンパイルするときはdocument.pdfにコンパイルするようにしました. 便利便利.

追記: 2012/10/20

bibファイルの処理を付け加えました.

追記: 2012/10/21

行末の\\をcppが処理してしまうので, それを戻す処理を付け加えました.

追記: 2012/11/05

jbibtexの処理を加えました.
コメント入れました.

追記: 2012/11/15

\documentclassの前にスペースを入れるようにしました. これによって, temp.texやdocument.pdfの\documentclassをgrepで読み取らないようにします.

追記: 2012/11/19

Ubuntu用の処理がおかしかったのを直しました.

追記: 2013/7/28

xy-picを使うならばpsを介するようにしました.
cppのオプションでコメントを削除しないようにしました.
#をpragma文として認識しないように置換する処理にしました.
部分コンパイル時, prelude.styがなくてもメインのファイルを探してプリアンブルをコピーするようにしました.
この変更によって, documentclass文が複数行になった場合にも対応出きるようになりました.
prelude.styがなく, さらにメインのファイルがみつからないのに, align環境, \bm, \includegraphicsを使おうとしているときは, 適切にusepackageを補うようにしました.
cppを使用しないようにしました.
IFSを設定して行頭スペースを削除しないようにしました.
行末に改行を入れるようにしました.

追記: 2013/8/17

オプションを解析するときに\rを消去するようにしました.

追記: 2013/8/18

abcパッケージを検知するようになりました.

追記: 2013/8/19

スペースを含むディレクトリーでも実行できるようにしました.

追記: 2014/4/24

出力のファイル名を「% filename fooname」のように指定できるようにしました.

追記: 2014/5/9

Ubuntuで, platexがutf8をサポートする時はnkfのオプションを-wを使うようにしました.

追記: 2014/5/13

GitHubに置くことにしました.
GitHub: itchyny - autolatex
多くのバグを修正しました.

  • ファイルのエンコーディングに寄ってはsedがエラーを吐くことを修正しました
  • 出力のファイル名をtempやdocumentじゃなくて、元のファイルの名前を使うようになりました.
  • スペースを含むパスでも動くようにしました.
  • ハイフンから始まるファイルでもコンパイルできるようになりました.
  • bashでのみ動くコードをshで動くようにしました.
  • 同じディレクトリーにハイフンから始まるファイルがあってもきちんと動作するようにしました.
  • ファイルの最後に改行がなくても動作するようにしました.