CotEditor から \includeonly でタイプセット

\include で分割した TeX ファイルを \includeonly で子ファイルのみをタイプセットする方法を考えてみました。

\includeonly への対応

TeX ファイル(親ファイル)を \include で子ファイルに分割している場合、\includeonly コマンドで特定の子ファイルのみをタイプセットできます。例えば、

\documentclass{jsbook}
\includeonly{chapter_3}
\begin{document}
\include{chapter_1}
\include{chapter_2}
\include{chapter_3}
\include{chapter_4}
\include{chapter_5}
\include{chapter_6}
\end{document}

というファイルをタイプセットすると、chapter_3.tex のみをタイプセットできるわけです。

便利な機能ではあるのですが、タイプセットしたい子ファイルが変更になるたびに親ファイルを書き換えなければならないのが煩わしいのでなんとかしたい、という問題意識です。

pdflatex なら -draftmode が使えるようですが、platex では使えません。platex + dvipdfmx であれば ClutTeX で代用できるかもしれませんが、残念ながら dvips には対応していません。

一番素朴な解決策としては、親ファイルに

\documentclass{jsbook}
\input{draft}
\begin{document}
\include{chapter_1}
\include{chapter_2}
\include{chapter_3}
\include{chapter_4}
\include{chapter_5}
\include{chapter_6}
\end{document}

などと書いておいて、draft.tex に \includeonly{chapter_3} を書き込む手法が考えられます(タイプセットが完了したらその都度 draft.tex を空にする)。また、最近の platex は platex.cfg というファイルがあればそれを読み込んでくれるようですので、それを利用する方法でも目的は達成できますが、この方法は使い勝手が悪いです。

そこで、「引数を受け取れるように親ファイルを作っておく」方針にします。具体的には、親ファイルのプリアンブルに以下の命令を書いておくことにします。

\ifdefined\args
\args
\fi

先ほどの親ファイルの例であれば、

\documentclass{jsbook}
\ifdefined\args
\args
\fi
\begin{document}
\include{chapter_1}
\include{chapter_2}
\include{chapter_3}
\include{chapter_4}
\include{chapter_5}
\include{chapter_6}
\end{document}

のようになります。そうしておけば、普通にタイプセットすることもできますし、

platex \def\args{\includeonly{chapter_3}} \input{親ファイル}

のようにして実行すると chapter_3.tex のみをタイプセットできます。

platex + dvips + ps2pdf + Skim

下記がそのための AppleScript です。

tell application "CotEditor"
	if exists front document then
		--
		-- 行番号を取得(Skim 用)
		--
		set thelinerange to line range of selection of front document
		set theline to item 1 of thelinerange
		--
		-- ex. thisfile: /Users/myname/Documents/file.tex
		--     thisdir : /Users/myname/Documents/
		--     thisbase: file
		--
		set thisfile to path of front document as Unicode text
		set thisdir to (do shell script "/usr/bin/dirname \"" & thisfile & "\"")
		set thisbase to (do shell script "/usr/bin/basename \"" & thisfile & "\" .tex")
		--
		-- file.tex の 1 行目に親ファイルを設定
		-- 行頭に % を(1 個以上)付ける。拡張子 .tex は無くても可。
		-- ex. %% main.tex
		--     thismain: main
		--
		set thismain to (do shell script "/usr/bin/head -1 \"" & thisfile & "\" | sed s/^\\%*\\ *// | sed s/\\.tex$//")
		--
		-- 親ファイルが存在しない場合は終了
		--
		tell application "Finder"
			if not (exists (thisdir & "/" & thismain & ".tex") as POSIX file) then
				return
			end if
		end tell
		--
		-- 実行するコマンド+引数: cd, platex, dvips, ps2pdf, skim
		--
		set cd to " cd \"" & thisdir & "\""
		set tex2dvi to "platex -synctex=1 -interaction=nonstopmode \\\\def\\\\args\\{\\\\includeonly\\{\"" & thisbase & "\"\\}\\} \\\\input\\{\"" & thismain & ".tex\"\\}"
		set dvi2ps to "dvips \"" & thismain & ".dvi\""
		set ps2pdf to "ps2pdf \"" & thismain & ".ps\""
		set skim to "/Applications/Skim.app/Contents/SharedSupport/displayline -g -r " & theline & " \"" & thismain & ".pdf\" \"" & thisbase & ".tex\""
		--
 		-- 上記を連結
		--
		set typeset to cd & " && " & tex2dvi & " && " & dvi2ps & " && " & ps2pdf & " && " & skim & " && cd -"

		tell application "Finder"
			if (exists (thisdir & "/" & thismain & ".tex") as POSIX file) then
				tell application "Terminal"
					launch
					if not (exists window 1) then
						reopen
						do script typeset in window 1
					else
						set targetWindow to window 0
						repeat with currentWindow in reverse of (get every windows)
							if currentWindow is not busy then
								set targetWindow to currentWindow
							end if
						end repeat
						if (targetWindow is window 0) then
							do script typeset
						else
							do script typeset in targetWindow
						end if
					end if
				end tell
			else
				display alert "TeX ファイルではないようです。"
			end if
		end tell
		activate
	end if
end tell