Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

This question led to a new package:
newenviron

I want to define some environments, which place their content into multiple different other environments. To access the contents I used the environ package, which introduces the \BODY command. However at some point pdflatex seemed to be stuck in an infinite loop.

I reduced it to a minimal example:

\documentclass{article}
\usepackage{environ}

\NewEnviron{assertion}{Assertion: \BODY}
\NewEnviron{outerassertion}{\begin{assertion}\BODY\end{assertion}}

\begin{document}

\begin{assertion}
test
\end{assertion}

\begin{outerassertion}
test2
\end{outerassertion}
\end{document}

Any ideas how to work around this problem? I guess, the problem is with the \BODY command since everything works fine as long as I use it in only one of the new environments.

share|improve this question
add comment

2 Answers 2

up vote 15 down vote accepted

As you suspected you are getting a clash on \BODY essentially the outer environment does

  \def\BODY{\BODY}

which puts TeX in a loop, you can do

\documentclass{article}
\usepackage{environ}

\NewEnviron{assertion}{Assertion: \BODY}{}
\NewEnviron{outerassertion}{\let\xBODY\BODY\begin{assertion}\xBODY\end{assertion}}{}

\begin{document}



\begin{assertion}
test
\end{assertion}

\begin{outerassertion}
test2
\end{outerassertion}
\end{document}

Although in this case it would be simpler and more efficient to use a standard \newenvironment definition which would avoid the problem completely.

share|improve this answer
    
looks like this solved the problem. thanks a lot! –  bln-tom Mar 9 '13 at 14:02
add comment

David has given a simple, commonsense solution, but your question has led to a package called newenviron, which may be used without a trick on the part of the user. \envbody and \<env name>body can be used to apply some code to the body of an environment.

\begin{filecontents*}{newenviron.sty}
% Collect environment body in macros \envbody and \<env name>body.
\@ifpackageloaded{catoptions}{}{\RequirePackage{catoptions}[2011/12/12]}
\UseNormalCatcodes
\StyleFilePurpose{Collect and execute environment body (AM)}
\StyleFileRCSInfo
$Id: newenviron.sty,v 1.0 2013/03/08 09:00:00 Ahmed Musa Exp $
\ProvidesPackage{newenviron}[\StyleFileInfo]
\NeedsTeXFormat{LaTeX2e}[2011/06/27]
\cptnewvariables{toks}[nenv@]{temptoks}
\new@def\nenv@gobbletomarker#1\nenv@endmarker{}
\new@def*\nevn@quark{}
\new@def*\AlwaysTrimEnvEntries{\global\nenv@alwaystrimtrue}
\new@def*\nenv@trimspace{%
  \ifdefboolTF{nenv@alwaystrim}\cpttrimspace\unexpanded
}
\new@def*\nenv@everybegin@hook{}
\robust@def*\EveryBeginOfEnvironment#1{%
  \xifinsetTF
  {\detokenize{\nevn@quark#1\nevn@quark}}
  {\cptoxdetok\nenv@everybegin@hook}{}{%
    \edef\nenv@everybegin@hook{%
      \expandcsonce\nenv@everybegin@hook
      \noexpand\nevn@quark\unexpanded{#1}\noexpand\nevn@quark
    }%
  }%
}
\new@def*\nenv@everyend@hook{}
\robust@def*\EveryEndOfEnvironment#1{%
  \xifinsetTF
  {\detokenize{\nevn@quark#1\nevn@quark}}
  {\cptoxdetok\nenv@everyend@hook}{}{%
    \edef\nenv@everyend@hook{%
      \expandcsonce\nenv@everyend@hook
      \noexpand\nevn@quark\unexpanded{#1}\noexpand\nevn@quark
    }%
  }%
}
\EveryEndOfEnvironment{\@ignoretrue}
\robust@def*\nenv@appto#1#2{%
  \ifdefTF#1{%
    \edef#1{\expandcsonce#1\unexpanded{#2}}%
  }{%
    \edef#1{\unexpanded{#2}}%
  }%
}
%
% \newenviron<optional *>
%   {<name>}[<narg>][<default of 1st arg>]{<start-code>}{<end-code>}
%
% \renewenviron<optional *>
%   {<name>}[<narg>][<default of 1st arg>]{<start-code>}{<end-code>}
%
\robust@def*\newenviron{\cpt@starorlong\nenv@newenviron}
\robust@def*\nenv@newenviron#1{%
  \edef\cpt@tempa{\nenv@trimspace{#1}}%
  \cptexpandarg\cpt@testopt
    {\nenv@newenviron@a{\expandcsonce\cpt@tempa}}{0}%
}
\robust@def*\nenv@newenviron@a#1[#2]{%
  \cpt@ifbrack{\nenv@newenviron@b#1[#2]}{\nenv@newenviron@c{#1}{[#2]}}%
}
\robust@def*\nenv@newenviron@b#1[#2][#3]{\nenv@newenviron@c{#1}{[#2][{#3}]}}
\robust@def\nenv@newenviron@c#1#2#3#4{%
  \ifcsndefTF{#1}{}{\letcsntocsn{#1}{end#1}}%
  \aftercsname\new@command{#1}#2{%
    \edef\nenv@beforebody{\nenv@trimspace{#3}}%
    \nenv@everybegin@hook
    \nenv@collectbody
  }%
  \l@ngrel@x\csn@edef{end#1}{%
    \def\noexpand\cpt@prova{\nenv@trimspace{#4}}\noexpand\cpt@prova
    \noexpand\nenv@everyend@hook
  }%
}
\robust@def*\nenv@collectbody{%
  \begingroup
  \toks@{}%
  \everyeof{\end{EOF}\relax}%
  \nenv@collectbody@a
}
\robust@def\nenv@collectbody@a#1\end#2{%
  \nenv@temptoks{%
    \cptexpanded{%
      \toks@{%
        \the\toks@\nenv@trimspace{#1}%
        \noexpand\end{\expandcsonce\cpt@argofend}%
      }%
    }%
    \nenv@collectbody@a
  }%
  \edef\cpt@argofend{\cpttrimspace{#2}}%
  \ifcseqTF\cpt@argofend\@currenvir{%
    \def\cpt@tempa{}%
    \nenv@pushbegin#1\begin\end\nenv@endmarker
    \ifcsemptyTF\cpt@tempa{%
      \cptexpanded{\endgroup
        \csn@edef{\@currenvir body}{%
          \noexpand\unexpanded{\the\toks@\nenv@trimspace{#1}}%
        }%
        \letcstocsn\noexpand\envbody{\@currenvir body}%
        \unexpanded{%
          \nenv@beforebody\relax
          \ifdefboolTF{nenv@alwaystrim}\@ignoretrue\relax
        }%
        \noexpand\end{\cpt@argofend}%
      }%
    }{%
      \the\nenv@temptoks
    }%
  }{%
    \oifstrcmpTF{\cpt@argofend}{document}{%
      \expandafter\endgroup\expandafter
        \@checkend\expandafter{\cpt@argofend}%
    }{%
      \oifstrcmpTF{\cpt@argofend}{EOF}{%
        \expandafter\endgroup\expandafter
          \@checkend\expandafter{\cpt@argofend}%
      }{%
        \the\nenv@temptoks
      }%
    }%
  }%
}
\new@def\nenv@pushbegin#1\begin#2{%
  \expandafter\ifx\cpt@car#2x\car@nil\end
    \expandafter\@gobble
  \else
    \edef\cpt@prova{\cpttrimspace{#2}}%
    \ifx\cpt@prova\cpt@argofend
      \def\cpt@tempa{x}%
      \expandafter\expandafter\expandafter\nenv@gobbletomarker
    \else
      \expandafter\expandafter\expandafter\nenv@pushbegin
    \fi
  \fi
}
\robust@def*\renewenviron{\cpt@starorlong\nenv@renewenviron}
\robust@def*\nenv@renewenviron#1{%
  \edef\cpt@tempa{\nenv@trimspace{#1}}%
  \ifcsndefTF\cpt@tempa
    {}
    {\@latex@error{Environment #1 is undefined}\@ehd}%
  \letcsntocs\cpt@tempa\relax
  \letcsntocs{end\cpt@tempa}\relax
  \expandafter\nenv@newenviron\expandafter{\cpt@tempa}%
}
\XDeclareBooleanOption{alwaystrim}[true](nenv@){}{}
\XDeclareOption*{\@@warning{Unknown option '\CurrentOption' ignored}}
\XExecuteOptions{alwaystrim}
\XProcessOptions*\relax
\endinput
\end{filecontents*}

Example:

\documentclass{article}
\usepackage{newenviron,xcolor}

% \envbody will always work for 'unnested' environments:
%   \newenviron{assertion}{}{Assertion: \envbody}

% But if you intend to nest the environment, it will be safer to use \assertionbody:
\newenviron{assertion}{%
  \def\acmd##1{##1}% test <start-code>.
}{%
  \def\bcmd##1{##1}% test <end-code>.
  Assertion: \assertionbody
}
\newenviron{outerassertion}{%
  % Put any start code here.
}{%
  \textcolor{blue}{Outer assertion:} %
  \begin{assertion}\outerassertionbody\end{assertion}%
}

\begin{document}

% Just for testing:
\EveryEndOfEnvironment{\def\ccmd#1{#1}}

\begin{assertion}
  test
\end{assertion}
\endgraf\bigskip

\begin{outerassertion}
  test2
\end{outerassertion}
\endgraf\bigskip

\begin{assertion}
  Level-1 test.
  \begin{assertion}
  Another level-1 test.
  \end{assertion}
\end{assertion}
\endgraf\bigskip

% Another test. Note the use of \usename{env-1body} and \usename{env-2body}:
\newenviron{env-1}[2][blue]{%
  \fboxrule=#2\relax
  \cptdimdef\temp{.5\textwidth}%
  \endgraf\noindent
  \fcolorbox{#1}{gray!10}{\parbox{\temp}{\textcolor{#1}{\usename{env-1body}}}}%
}{}
\newenviron*{env-2}[1][black]{%
  \noindent
  \fcolorbox{#1}{gray!30}{%
    \parbox{.7\textwidth}{%
      \leftskip=1cm
      \textcolor{#1}{\usename{env-2body}}%
    }%
  }%
}{%
  \def\testcmd##1{##1}% test <end-code>.
}

\begin{env-2}[red]
  Outer box\endgraf
  \def\tempa#1{***#1***}\tempa{aa}%
  \endgraf\vspace*{5mm}%
  \begin{env-1}[blue]{1pt}%
    Inner box\endgraf\vspace*{5mm}%
    \def\tempa#1{+++#1+++}\tempa{bb}%
  \end{env-1}%
  \begin{env-1}[brown]{4pt}%
    Inner box\endgraf\vspace*{5mm}%
    \def\tempa#1{---#1---}\tempa{cc}%
  \end{env-1}%
\end{env-2}

\end{document}

enter image description here

share|improve this answer
    
this sounds pretty interesting! I'll test it tomorrow. –  bln-tom Mar 9 '13 at 23:43
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.