Переопределение \include

Переопределение \include

Загадочный выбор, сделанный Лесли Лэмпортом, заключался в определении \includeтаким образом, чтобы выдать \clearpageперед чтением файла. Это меня уже давно озадачивает, так как это не очень хороший выбор с точки зрения интерфейса автора. Этот вопрос состоит из двух частей:

  1. Есть ли веские причины для такого решения?
  2. Что может сломаться, если переопределить команду?

MWE ниже показывает такое переопределение (я назвал команду, \includexно она отлично работает, даже если она названа \include). Мое собственное подозрение, что это было введено на ранней стадии для решения проблем с twocolumns, но в нем нет ничего, source2eобъясняющего это решение.

\documentclass{book}
\usepackage{filecontents}
\makeatletter
\def\includex#1{\relax
  \ifnum\@auxout=\@partaux
    \@latex@error{\string\include\space cannot be nested}\@eha
  \else \@includex#1 \fi}

\def\@includex#1 {%
  %\clearpage
  \if@filesw
    \immediate\write\@mainaux{\string\@input{#1.aux}}%
  \fi
  \@tempswatrue
  \if@partsw
    \@tempswafalse
    \edef\reserved@b{#1}%
    \@for\reserved@a:=\@partlist\do
      {\ifx\reserved@a\reserved@b\@tempswatrue\fi}%
  \fi
  \if@tempswa
    \let\@auxout\@partaux
    \if@filesw
      \immediate\openout\@partaux #1.aux
      \immediate\write\@partaux{\relax}%
    \fi
    \@input@{#1.tex}%
    %\clearpage
    \@writeckpt{#1}%
    \if@filesw
      \immediate\closeout\@partaux
    \fi
  \else
    \deadcycles\z@
    \@nameuse{cp@#1}%
  \fi
  \let\@auxout\@mainaux
}
\begin{filecontents}{A.tex}
This is file A
This is the A file
\end{filecontents}
\begin{filecontents}{B.tex}
This is the B file
\end{filecontents}
\begin{filecontents}{C.tex}
This is the C file
\end{filecontents}
\includeonly{A,C}
\begin{document}
\includex{A}
\includex{B}
\includex{C}
\end{document}

решение1

Целью этого \includeмеханизма является обеспечение возможности частичной компиляции документа при внесении небольшого количества изменений без необходимости перекомпиляции всего документа и при этом корректное разрешение перекрестных ссылок и т. д. (даже на части, находящиеся за пределами текущей части, находящейся под ножом).

Чтобы это работало, часть или части, которые включены, должны быть самодостаточными в том смысле, что изменения в них не делают автоматически (и всегда) форматирование других частей, не включенных, недействительным. Чтобы сделать это возможным (по крайней мере для небольших изменений), необходимы следующие предварительные условия:

  • Механизм должен гарантировать, что небольшие изменения длины текста в компилируемой части не приведут к изменению форматирования в других некомпилируемых частях.
  • Поплавки в скомпилированных частях должны быть размещены в скомпилированных частях

Если какой-либо из вышеперечисленных пунктов недействителен, то использование \include(почти) всегда приведет к недействительным документам, тогда как в текущей схеме вы можете включать все части по отдельности и по-прежнему получать и поддерживать действительный документ. (Просто для справки: когда мы выпустили первое издание LaTeX Companion, потребовалась уйма времени, чтобы скомпилировать эту книгу, и даже второе издание заняло около 30 минут в 2004 году, чтобы скомпилировать все примеры + все страницы и перепройти всю книгу (я думаю, 5 раз), чтобы успешно разрешить все перекрестные ссылки. Поэтому построение всего по главам было важным, и даже тогда компиляция заняла много времени :-)

Конечно, первый пункт станет недействительным в тот момент, когда будет добавлено или удалено много текста, например, если результирующий документ станет на одну или несколько страниц длиннее или короче.

Таким образом, использование разрывов страниц на границах включенных частей просто необходимо для того, чтобы сделать механизм полезным в первую очередь, а также необходимо \clearpageдля того, чтобы гарантировать, что плавающие элементы остаются внутри включенной части и не перемещаются внутрь или наружу.

@egreg уже дал дополнительное объяснение, что механизм записи данных aux-файла работает только \shipoutдля того, чтобы было невозможно (или, по крайней мере, нелегко) гарантировать, что такие вещи, как перекрестные ссылки или данные для оглавления не будут потеряны. Технически можно было бы придумать возможность управлять этим, но используя более одного aux-файла на включение, но это не решит проблему выше.

Наконец, это не изобретение команды проекта LaTeX, это восходит к оригинальному проекту Лесли Лэмпорта и существовало с версии LaTeX 2.08 (по крайней мере), то есть до 1986 года.

решение2

Предположим, у вас есть

\include{fileA}
\include{fileB}

Если нет \clearpagewhen fileAends и TeX начинает читать fileB, может быть \writeотносительное к fileApending и оно потеряется: \writeкоманды относительно \labelвыполняются при shipout, а не немедленно. Когда произойдет следующий shipout, fileA.auxфайл уже будет закрыт.

Если вы попробуете ваш пример, добавив \labelкоманду к каждому из них,никтоиз них будут записаны куда угодно (но не в .logфайл), поскольку отправка происходит, когда .auxфайлы уже закрыты.

Связанный контент