3

I have been exploring different methods of suppressing environment content under some conditionals. The problem with environments is that a lot of the tricks don't work because of how the environment scans for an end token and so suppressing content can often fail to find the end of the suppression. For example:

\begin{document}
\newif\iftest
\testfalse
\newenvironment{testenv}{\iftest}{\fi}
\begin{document}
\begin{testenv}
text!
\end{testenv}
\end{document}

This returns "incomplete iffalse" because it fails to find the \fi since it can't execute the \end{testenv} while it looks for the \fi (thus not finding the end. This part I get.

I've tried various other avenues but I'd like to stay away from verbatim environments as I'd like to nest this eventually and nesting verbatim environments is a monumental headache.

But then, I tripped across the "suppress" command found here: Selectively suppress generation of typeset output.

So I built the following working code:

\documentclass{article}
\usepackage{amsthm}
\usepackage{environ}

\newif\iftest
\testfalse

\NewEnviron{testenv}{\iftest\BODY\else Nope! \fi}
\newcommand{\Test}{}

\makeatletter
\font\dummyft@=dummy \relax
\def\suppress{%
  \begingroup\par
  \parskip\z@
  \offinterlineskip
  \baselineskip=\z@skip
  \lineskip=\z@skip
  \lineskiplimit=\maxdimen
  \dummyft@
  \count@\sixt@@n
  \loop\ifnum\count@ >\z@
    \advance\count@\m@ne
    \textfont\count@\dummyft@
    \scriptfont\count@\dummyft@
    \scriptscriptfont\count@\dummyft@
  \repeat
  \let\selectfont\relax
  \let\mathversion\@gobble
  \let\getanddefine@fonts\@gobbletwo
  \tracinglostchars\z@
  \frenchspacing
  \hbadness\@M}
\def\endsuppress{\par\endgroup}
\makeatother

\newenvironment{testenvtwo}{
\iftest\else\suppress\fi
}{
\iftest\else\endsuppress\fi
}

\begin{document}

Th below should read "Nope"

\begin{testenv}
This shouldn't show!
\end{testenv}

\hrule

Below this should be nothing

\begin{testenvtwo}
This also shouldn't show!
\end{testenvtwo}

\hrule

\testtrue

Below this should be "This should show!"

\begin{testenv}
This should show!
\end{testenv}

\hrule

Below this should be "This also should show!"


\begin{testenvtwo}
This also should show!
\end{testenvtwo}

\hrule

\end{document}

So, why does \suppress command here manage to work correctly when various other methods fail? I can't really understand how \suppress works in practice, but I think it's just gobbling everything it sees until the \endsuppress maybe? But this seems like it should be the same problem as with the \if \fi type structure.

If anyone can enlighten me as to why this works when \fi and environment hooks from etoolbox and the like failed, I'd really appreciate it. I'd like to be able to make this kind of command in the future, so I'm trying to understand how it works.

2 Answers 2

2

The problem is that \fi is never seen.

Suppose you have this plain TeX file

\newif\iftest
\def\blurb{\fi}

\testtrue

\iftest
Yes
\blurb

\testfalse
No
\blurb

\bye

In the case \iftest returns true, \blurb gets expanded and so TeX is able to see the \fi matching \iftest.

When \iftest returns false, TeX skips the true test without expansion, so it will get to \bye having not yet seen the matching \fi.

The same happens with your code.

\documentclass{article}
\begin{document}
\newif\iftest
\testfalse
\newenvironment{testenv}{\iftest}{\fi}
\begin{document}
\begin{testenv}
text!
\end{testenv}
\end{document}

When \begin{testenv} is executed, TeX gets to see \iftest, which returns false, so it will skip tokens until seeing the token \else or the token \fi. TeX finds none, because no expansion is performed during this skipping token phase. The skipping will arrive to the end of the file, unless some explicit token \else or\fi` happens to be scanned. Explicit in the sense of not being hidden in a macro.

There is no safe way to bury \fi in the \end part of an environment; such thing will only work if the conditional returns true.

How does \suppress work? It simply chooses a font with no character at all and redefines the font changing command \selectfont to do nothing; also the math fonts are set to nothing. But try with \rule{1cm}{1cm} in the environment and you'll see something printed. Of course also \rule could be disabled.

There is no problem with the conditionals, because TeX will see the complete \iftest...\fi in both the begin and end parts.

4
  • Right, I understand why the conditional fails in the environment definition, and gave it as an example of various types of approaches I was trying to use. But the real question is, what is suppress doing that is fundamentally different than a conditional, that lets it work when conditionals don't. I really can't understand the suppress macros, but it seems like it needs to know when to "stop" gobbling, and that seems like a conditional check, which seems like it should fail for the same reason a regular conditional fails. But apparently it doesn't.
    – Jason
    Mar 28, 2018 at 17:43
  • @Jason \suppress actually typesets everything, although in a font that has no character to print.
    – egreg
    Mar 28, 2018 at 17:45
  • Ah, this makes sense. Mind explaining where in the suppress code it is managing to define a font with no character to print? I assume it's the \font\dummyft@ command but I don't have any experience defining my own font, so how do I see that this font has no characters to "print"?
    – Jason
    Mar 29, 2018 at 11:47
  • @Jason \font\dummyft@=dummy; then \dummyft@ is assigned to every math group and chosen as text font.
    – egreg
    Mar 29, 2018 at 12:19
0

If you want an environment that is suppressed if the condition is false, use the environ package to grab the whole environment contents and only show them when the condition is true.

\documentclass{article} 

\newif\iftest 
\testfalse

\usepackage{environ} 
\NewEnviron{test}{\iftest\BODY\fi}

\begin{document} 
\begin{test}
    Should not appear
\end{test} 

\testtrue  
\begin{test}
    Should appear
\end{test} 
\end{document}
2
  • This was my original solution, and it works fine until you want to start dealing with verbatim environments and nesting. For a variety of reasons the cls file I'm helping with can't use environ commands in particular contexts so I was trying to find another workaround.
    – Jason
    Mar 28, 2018 at 17:41
  • Okay, well hopefully this will help someone else. You might make add a second, less-minimal example that demonstrates the special cases you mention. Mar 28, 2018 at 17:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .