##背景
- TeXファイルが長くなったので節ごとに分割したい(します)。
- 節ごとのTeXファイルはそれぞれごとにコンパイルできてほしい。
-
\autoref
とかもいい感じに振る舞ってほしい。
上二つを実現する方法としてはsubfilesを使う方法がありますが、リンク先の記事でも言及されている通り、あまり3つ目の欲望が満たせそうにないので、今回は「仕掛け」を用いる方法を使います。
この記事は、上記の欲望が達成されたような気がする、という報告です。
→GitHubへ
##フォルダ構成
フォルダ構成は以下の通りとします:
Main
├── MainFile.tex
├── MainFile.aux など
├── Style
│ └── Test.sty
└── Sub
├── SubFile.tex
└── SubFile.aux など
SubFile.tex は例えば「Section 5に対応するファイル」のような感じで、
MainFile.tex はなんか全部inputされてる感じのやつを想定してます。
###中身
中身は以下の通りであるとします (「仕掛け」の記事で紹介されている「仕掛け」が施してあります)。
\newcommand{\MainFile}{MainFile}
\documentclass[uplatex,dvipdfmx]{jsarticle}
\input{Style/Test.sty}
\begin{document}
\section{親ファイル}\label{section: Main section}
あ
\begin{thm}\label{thm: main theorem}
え?
\end{thm}
\begin{lem}\label{lem: main lemma}
え?
\end{lem}
\input{Sub/SubFile.tex}
\autoref{section: Main section},\autoref{section: sub section},
\autoref{thm: main theorem},\autoref{thm: sub theorem},
\autoref{lem: main lemma},\autoref{lem: sub lemma},
\ref{section: Main section},\ref{section: sub section},
\ref{thm: main theorem},\ref{thm: sub theorem},
\ref{lem: main lemma},\ref{lem: sub lemma},
\end{document}
\ifcsname MainFile\endcsname\else
\documentclass[uplatex,dvipdfmx]{jsarticle}
\input{../Style/Test.sty}
\begin{document}
\fi
\SetTrueSecNumber{section: sub section}
\section{子ファイル}\label{section: sub section}
い
\begin{thm}\label{thm: sub theorem}
え?
\end{thm}
\begin{lem}\label{lem: sub lemma}
え?
\end{lem}
\autoref{section: Main section},\autoref{section: sub section},
\autoref{thm: main theorem},\autoref{thm: sub theorem},
\autoref{lem: main lemma},\autoref{lem: sub lemma},
\ref{section: Main section},\ref{section: sub section},
\ref{thm: main theorem},\ref{thm: sub theorem},
\ref{lem: main lemma},\ref{lem: sub lemma},
\ifcsname MainFile\endcsname\else
\end{document}
\fi
「仕掛け」の意味は当該記事を参照してください。
この仕掛けによって、MainFile.tex と SubFile.tex はそれぞれごとにコンパイルすることができます (もちろん、Test.sty にめちゃくちゃなことが書いてあったらエラー吐きますが)。
Style ファイルには以下の (上のファイルたちをまともに出力させるための) 事柄が既に書かれているとします (これらの意味については説明しません。ハイパーリンク系は青色にしてます)。
\usepackage{xcolor}
\usepackage{graphicx}
\usepackage[setpagesize=false]{hyperref}
\usepackage{aliascnt}
\hypersetup{colorlinks=true,citecolor=blue,linkcolor=blue,urlcolor=blue,}
\usepackage{amsthm}
\theoremstyle{definition}
\newtheorem{thm}{定理}[section]
\newaliascnt{lem}{thm}
\newtheorem{lem}[lem]{補題}
\aliascntresetthe{lem}
\renewcommand{\sectionautorefname}{節}
\newcommand{\thmautorefname}{定理}
\newcommand{\lemautorefname}{補題}
Subfilesの記事の最後の方にも書いてある通りですが、このままだと参照とかはあんまりいい感じじゃないです。なので、この.styにいろいろ追記して参照とかをいい感じにしていきます。
##やったこと
- 参照 (
\autoref
とか\ref
とか) もいい感じにした。
###「いい感じに」の定義
- MainFile.tex では通常通りに出力してほしい。
- MainFile.tex のラベルであって SubFile.tex 内のラベルにないものを SubFile.tex で参照した場合は、MainFile.tex 内での正しいナンバリングが (ハイパーリンクなしで) 印字されてほしい。
これらを実現するために、\label
と\ref
と\autoref
を再定義します。
##再定義
.sty ファイルに (\usepackage{hyperref}
よりも後に) 以下を書き込みます(コメントは直前に行った作業の説明です):
\usepackage{letltxmacro}%monkey patch
\makeatletter
\newcommand{\Test@FirstGroup}[5]{#1}%5個のうちの1番目
\newcommand{\Test@FourthGroup}[5]{#4}%5個のうちの4番目
\newcommand{\Test@NumberingPrint}[1]{%
\expandafter\Test@FirstGroup%
\romannumeral-`0\csname r@MainFile: #1\endcsname%
}%%ラベルに対してそのラベルが振られているものの番号(3.5とか)を文字列として返す
\def\Test@@NamingPrint#1.{%
\csname #1autorefname\endcsname%
}
\newcommand{\Test@NamingPrint}[1]{%
\expandafter\Test@@NamingPrint%
\romannumeral-`0\expandafter\Test@FourthGroup%
\romannumeral-`0\csname r@MainFile: #1\endcsname%
}%%ラベルに対して「定理3.5」や「補題1.9」や「節6」などを文字列として返す
\AtBeginDocument{%%hyperrefよりあとから書き換えるためにAtBeginDocumentする
\LetLtxMacro{\Test@LetLabel}{\label}%labelをコピー(letのようなもの)
\newcommand{\Test@TrueLabel}[1]{%
\ifcsname MainFile\endcsname%
\Test@LetLabel{MainFile: #1}\else%
\Test@LetLabel{SubFile: #1}\fi%
}%コンパイル場所によってlabelの振る舞いを変える
\renewcommand{\label}[1]{\Test@TrueLabel{#1}}%label再定義
\LetLtxMacro{\Test@LetRef}{\ref}%refをコピー
\newcommand{\Test@SubFile@TrueRef}[1]{%
\ifcsname r@SubFile: #1\endcsname%
\Test@LetRef{SubFile: #1}\else%
\textcolor{magenta}{\Test@NumberingPrint{#1}}\fi%
}%SubFileでのrefの振る舞い
\newcommand{\Test@TrueRef}[1]{%
\ifcsname MainFile\endcsname%
\Test@LetRef{MainFile: #1}\else%
\Test@SubFile@TrueRef{#1}\fi%
}%コンパイル場所によってrefの振る舞いを変える
\renewcommand{\ref}[1]{\Test@TrueRef{#1}}%ref再定義
\LetLtxMacro{\Test@LetAutoref}{\autoref}%autorefをコピー
\newcommand{\Test@SubFile@TrueAutoref}[1]{%
\ifcsname r@SubFile: #1\endcsname%
\Test@LetAutoref{SubFile: #1}\else%
\textcolor{magenta}{\Test@NamingPrint{#1}}\fi%
}%SubFileでのautorefの振る舞い
\newcommand{\Test@TrueAutoref}[1]{%
\ifcsname MainFile\endcsname%
\Test@LetAutoref{MainFile: #1}\else%
\Test@SubFile@TrueAutoref{#1}\fi%
}%コンパイル場所によってautorefの振る舞いを変える
\renewcommand{\autoref}[1]{\Test@TrueAutoref{#1}}%autoref再定義
}
%Sectionのラベルに対してMainFile内でのその節の番号を返す
\newcommand{\SetTrueSecNumber}[1]{%
\expandafter\newcount\csname Count@#1\endcsname
\csname Count@#1\endcsname=\Test@NumberingPrint{#1}
\expandafter\advance\csname Count@#1\endcsname by -1
\setcounter{section}{\csname Count@#1\endcsname}
}
%MainFileの.auxをinput
\ifcsname MainFile\endcsname\else%
\input{../MainFile.aux}\fi
\makeatother
コンパイルすると、
このようになります。
SubFile の magenta 色の部分は MainFile のラベルであり、SubFile ではただ色がついて印字されているだけになります。
青色はちゃんとクリックすると該当箇所へと飛びます。
これで期待通りの出力が得られた!
と思ったのですが、節番号がおかしいですね。
SubFile.tex の中の\section{子ファイル}
の直前の1行をコメントアウトしてから、
SubFile.tex を保存
→ MainFile.tex をコンパイル
→ コメントアウトをもとにもどして SubFile.tex をコンパイル
とします。すると
となり、節番号もちゃんとします。
嬉しいです。
後日、機会 (や要望) があれば、このTest.styの中身について詳しく説明します。
##発展
- 3層にする場合も同様です。SubFile の方で
\SubFile
というコマンドを定義して、適当に条件分岐を増やせば良いだけです。(cf. GitHub)。 - enumerate に対するラベルでも同様の振る舞いをします。
- このままだと
\eqref
はうまく振る舞いません。理由ですが、amsmath が行う数式環境内でのラベルの記録は、通常のラベルづけのコマンド\label
をコピーした\ltx@label
というものが行っているからです。なので、上の\label
の再定義を用いて\renewcommand{\ltx@label}{\label}
としてやる必要があります。これだけ書いていればあとはいい感じになってくれます。(cf. GitHub)。
##参考記事
効率的な LaTeX ファイル分割術
分割した LaTeX ファイルを subfiles を使ってコンパイルする