3

When working on a book I'd like to "ignore"(not compile) all chapters but the current one. I know there are methods to use like include and such BUT I do not want to use external files or some complex method.

I simply want to use \iffalse and fi(or something similar) BUT I want it transparent:

e.g.,

\ignorechapters{3,4} % <- Ignores all chapters **BUT** 3,4

and that is all that is needed so that only chapters 3 and 4 show up in the pdf.

So what is needed to do this? I imagine each \chapter macro will need to be modified in a robust way so that it will conditionally include the chapter or not

e.g., normally one has

\chapter[mc]{my chapter}
....
\chapter[mc2]{my chapter 2}
....
\chapter[mc3]{my chapter 3}

and I do this manually:

\chapter[mc]{my chapter}
\iffalse
....
\fi
\chapter[mc2]{my chapter 2}
\iffalse
....
\fi
\chapter[mc3]{my chapter 3}

and as you can see, it each \iffalse and \fi could easily be consumed into the \chapter macro without causing problems and done so transparently. (Assuming we can modify \chapter easily and not break it's original functionality)

--- Edit pseudo-code

newchapter macro
if previous chapter ignored  % Obviously if previous chapter doesn't exist this should be ignored
   insert `\fi`
end
if chapter ignored
   insert `\iffalse`
end
   insert `chapter data`
end macro

Hence the the newchapter macro will insert a \fi then an \iffalse into the stream if necessary.

We would also have to override the \end{document} to insert the final \fi if necessary(if the last chapter is to be ignored(which means it has an \iffalse and requires a \fi).

2 Answers2

10

The following example implements the syntax described in the question. I have renamed \ignorechapters to \includechapters, because the chapters in the argument should be included, not ignored. Also I follow the convention of \includeonly: If \includechapters is not specified, all chapters are included. Otherwise the chapters are included that are specified. Starred chapters and chapters that are not followed by \iffalse are always included.

The normal syntax for \chapter is supported:

  • \chapter*{...}
  • \chapter{...}
  • \chapter[...]{...}

Excluded chapters

  • call \cleardoublepage,
  • increment their chapter number and
  • write an entry into the table of contents.

Package ltxcmds is only needed for a more robust \ltx@ifnextchar that also allows a conditional as next token.

\documentclass{book}
\usepackage{ltxcmds}

\makeatletter
\newcommand*{\includechapters}[1]{%
  \def\@includechapters{#1}%
}
\let\@includechapters\relax
\newcommand*{\org@chapter}{}
\let\org@chapter\chapter
\renewcommand*{\chapter}{%
  \@ifstar{\org@chapter*}{\chapter@aux}%
}
\newcommand*{\chapter@aux}{%
  \begingroup
  \@ifnextchar[{\chapter@aux@opt}{%
    \toks@{\org@chapter}%
    \let\chapter@tocentry\relax
    \chapter@@aux
  }%
}
\def\chapter@aux@opt[#1]{%
  \toks@{\org@chapter[{#1}]}%
  \def\chapter@tocentry{#1}%
  \chapter@@aux
}
\newcommand*{\chapter@@aux}[1]{%
  \toks@\expandafter{\the\toks@{#1}}%
  \ifx\chapter@tocentry\relax
    \def\chapter@tocentry{#1}%
  \fi
  \ltx@ifnextchar\iffalse{%
    \chapter@select
  }{%
    \expandafter\endgroup
    \the\toks@
  }%
}
\newcommand*{\chapter@select}[1]{%
  \ifx\@includechapters\relax
    \def\x{true}%
  \else
    \def\x{false}%
    \@for\ch:=\@includechapters\do{%
      \ifnum\ch=\numexpr\value{chapter}+1\relax
        \def\x{true}%
      \fi
    }%
  \fi
  \csname if\x\endcsname
  \else
    \cleardoublepage
    \refstepcounter{chapter}%
    \addcontentsline{toc}{chapter}{%
      \protect\numberline{\thechapter}%
      \chapter@tocentry
    }%
  \fi
  \expandafter\endgroup
  \csname if\x\expandafter\endcsname
  \the\toks@
}

\makeatother

\includechapters{2}

\begin{document}
\tableofcontents

\chapter[mc]{my chapter}
\iffalse
....
\fi
\chapter[mc2]{my chapter 2}
\iffalse 
....  
\fi  
\chapter[mc3]{my chapter 3}

\end{document}

The example includes the table of contents (starred chapter), excludes "my chapter", includes "my chapter 2", because it is listed in \includechapters, and includes "my chapter 3", because it is not followed by \iffalse.

Update: The method with \iffalse will not work, if the markup should be hidden inside \chapter without explicit markup for the end of chapter. When \iffalse is active, then TeX's fast scanning looks for conditional tokens only to find the matching \fi. Therefore a command token with the meaning of \fi that is not hidden inside macros is needed at any case.

Method via discarding pages

The following methods uses the property of chapters that they start and end at page breaks. If a chapter is ignored, then the chapter is typeset as usual, but the pages are discarded.

\documentclass{book}

\usepackage{atbegshi}

\makeatletter
\newcommand*{\includechapters}[1]{%
  \def\@includechapters{#1}%
}
\let\@includechapters\relax
\newcommand*{\org@chapter}{}
\newif\if@ignore@chapter
\renewcommand*{\@ignore@chaptertrue}{\global\let\if@ignore@chapter\iftrue}
\renewcommand*{\@ignore@chapterfalse}{\global\let\if@ignore@chapter\iffalse}
\AtBeginShipout{%
  \if@ignore@chapter
    \AtBeginShipoutDiscard
  \fi
}
\let\org@chapter\chapter
\renewcommand*{\chapter}{%
  \cleardoublepage
  \@ignore@chapterfalse
  \@ifstar{\org@chapter*}{\chapter@aux}%
}
\newcommand*{\chapter@aux}{%
  \begingroup
  \@ifnextchar[{\chapter@aux@opt}{%
    \toks@{\org@chapter}%
    \let\chapter@tocentry\relax
    \chapter@@aux
  }%
}
\def\chapter@aux@opt[#1]{%
  \toks@{\org@chapter[{#1}]}%
  \def\chapter@tocentry{#1}%
  \chapter@@aux
}
\newcommand*{\chapter@@aux}[1]{%
  \toks@\expandafter{\the\toks@{#1}}%
  \ifx\chapter@tocentry\relax
    \def\chapter@tocentry{#1}%
  \fi
  \ifx\@includechapters\relax
    \@ignore@chapterfalse
  \else
    \@ignore@chaptertrue
    \@for\ch:=\@includechapters\do{%
      \ifnum\ch=\numexpr\value{chapter}+1\relax
        \@ignore@chapterfalse
      \fi
    }%
  \fi
  \expandafter\endgroup\the\toks@
}
\makeatother

\includechapters{2}

\begin{document}
\tableofcontents

\chapter[mc]{my chapter}
....\the\currentgrouplevel
\chapter[mc2]{my chapter 2}
....
\chapter[mc3]{my chapter 3}

\end{document}

Now only the pages of the table of contents and chapter "my chapter 2" are included.

Heiko Oberdiek
  • 271,626
  • I think this is on the right track but you misinterpreted my question slightly. I do not want to have to explicitly use \iffalse and \fi. I want it to be automatically inserted. What you have will work so I have marked it as correct but please try and fix it. – AbstractDissonance Sep 14 '12 at 02:04
  • your example should look like \chapter[mc]{my chapter} .... \chapter[mc2]{my chapter 2} .... \chapter[mc3]{my chapter 3} at the bottom. – AbstractDissonance Sep 14 '12 at 02:06
  • (Note that the behavior you have of your example is correct but instead of inserting the \iffalse and \fi's you delete them) – AbstractDissonance Sep 14 '12 at 02:07
  • That's not possible. The \fi must be visible somehow, otherwise all would be ignored including \end{document} if a chapter is skipped. Even with the comment package you need a markup for the end of chapter that cannot be hidden inside macros. – Heiko Oberdiek Sep 14 '12 at 02:38
  • huh? It definitely is possible. Your macro must be logical enough to realize it is the last chapter! (the same type of logic must prevent a \fi from the first chapter. I'll ammend my questio with some pseudo code. – AbstractDissonance Sep 14 '12 at 02:51
  • Essentially all it boils down to is checking if a chapter number is in the included chapters list and if it isn't we surround everything in the the chapter with a \iffalse and \fi(exactly how one would do it manually). (one doesn't even need to do this... possibly just ignoring the chapter has the same effect). – AbstractDissonance Sep 14 '12 at 03:00
  • No. If \iffalse is active, then it needs a command token with the meaning of \fi that cannot be hidden inside macros. And the last chapter is known at the very end of document. – Heiko Oberdiek Sep 14 '12 at 03:03
  • There is a \fi macro trick, do you know about it? – AbstractDissonance Sep 14 '12 at 03:04
  • If using \iffalse and \fi are complicated you can chose just to ignore all the chapter tokens. There is no real reason to use \iffalse and \fi if using macros. I used them because it is required, or some variant, when having to do it by hand. – AbstractDissonance Sep 14 '12 at 03:06
  • See the edited answer for a different method via discarding pages. – Heiko Oberdiek Sep 14 '12 at 03:11
  • That looks like it does the job! I really appreciate it. It makes it very easy to remove chapters if necessary. – AbstractDissonance Sep 14 '12 at 03:18
  • and I was also able to plug in play into my project without having modify anything but insert the \includeonly macro! Just what I wanted! – AbstractDissonance Sep 14 '12 at 03:20
3

You could load the comment package and surround the temporarily unwanted chapters with \begin{comment} and \end{comment} instructions. Note that these instructions must be on lines by themselves, with no leading blank (space) characters preceding them on the line.

Mico
  • 506,678
  • You can also add various names for comments, e.g. \includecomment{chapter1} and surround the first chapter by \begin{chapter1} and \end{chapter1}. (You can find more details in the comment package documentation.) – Martin Sep 14 '12 at 04:31