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.

I have a problem with nesting environments. I have created a MWE for this. I have environment {env1} which I want to contain environments {env2} and {env3} in the following way. What's wrong with the following code?

\documentclass{article}

\newenvironment{env1}{}{}
\newenvironment{env2}{}{}
\newenvironment{env3}{}{}

\newenvironment{test1}%
{\begin{env1} \begin{env2}}%
{\end{env2}}

\newenvironment{test2}%
{\begin{env3}}%
{\end{env3} \end{env1}}


\begin{document}

    \begin{test1}
        This is test1
    \end{test1}

    \begin{test2}
        This is test2
    \end{test2}

\end{document}

Edit:

It seems that in order to solve this problem I need to give the details of my lengthy code... (wanted to avoid it because of the length) So here it is: I tried to apply Patrick's patch, as it looked closest to what I wanted. Unfortunately it doesn't work.

In my code, env1=block, env2=exercise*, env3=solution*, test1=exercise, test2=solution. The "exercise" and "solution" macros are designed to ease writing when the block of exercises consists of only 1 exercise and 1 solution, and it automatically build the block around the exercise* and solution*.

\documentclass{article}
\usepackage{color}

\newcommand{\thickline}{\noindent\textcolor{blue}{\rule{\textwidth}{5pt}}}

\newenvironment{block}
{\bigskip\par\thickline\nopagebreak\par%
\begin{minipage}{\dimexpr\textwidth-\parindent\relax}\small}
{\end{minipage}\par\smallskip\nopagebreak\thickline\bigskip}

\newenvironment{exercise*}[1]
{\medskip\smallskip\par\noindent\textbf{Exercise (#1):}}
{\bigskip}

\newenvironment{solution*}
{\par\noindent\textbf{Solution:}}
{\medskip\smallskip}

%***Patrick's solution:*** (doesn't seem to work, see below)
\newenvironment{exercise}[1]%
    {\csname block\endcsname \begin{exercise*}{#1}}%
    {\end{exercise*}}

\newenvironment{solution}%
{\begin{solution*}}%
{\end{solution*} \csname endblock\endcsname}
%**************

\begin{document}
%This works. (using the 3 environments)
    \begin{block}
        \begin{exercise*}{hmmm}
            First exercise
        \end{exercise*}

        \begin{solution*}
            First Solution
        \end{solution*}
    \end{block}

    %This doesn't work (Patrick's definitions with csname):
    \begin{exercise}{hmmm}
        exercise
    \end{exercise}

    \begin{solution}
        solution
    \end{solution}
    %************

\end{document}

Edit 2

In case the block consists of more than one exercise, I want them to be separated by a thin line, defined by

\newcommand{\thinline}{\noindent\textcolor{red}{\rule{\textwidth}{2pt}}}

and the thick lines would come at the beginning and end of the block. So if there are 2 exercises in the block, for example, it would look like:

\thickline

Exercise (First exercise):

This is exercise 1

Solution:

Solution 1

\thinline

Exercise (Second exercise):

This is exercise 2

Solution:

Solution 2

\thickline

share|improve this question
    
For starters you have some typos: 'evn1' instead of 'env1'. –  Count Zero Oct 6 '11 at 10:18
    
Was that the critical part? –  Andro Oct 6 '11 at 10:34
    
A remark: the \csname .. \endcsname is only necessary because of the number in the command name. With the environment block you can write just block and \endblock. It has no influence on nesting / your problem. –  topskip Oct 6 '11 at 13:12
    
@Patrick: Oh, ok. I didn't know that –  Andro Oct 6 '11 at 13:52
add comment

3 Answers

Your test1 and test2 environments must be used one after the other, so probably another strategy is better:

\newenvironment{test}
  {\begin{env1}\begin{env2}}
  {\end{env3}\end{env1}}

\newcommand{\testbreak}[1]{\end{env2}#1\begin{env3}}

\begin{test}
Contents for env2
\testbreak{...}
Contents for env3
\end{test}

Possible text to be set between env2 and env3 can be specified as argument to \testbreak, with a suitable definition.

EDIT:

With your example at hand, the proposal is

\newif\ifsolution
\newenvironment{exercise}[1]
  {\begin{block}\begin{exercise*}{#1}}
  {\ifsolution\end{solution*}\else\end{exercise*}\fi\end{block}}
\newcommand\solution{\end{exercise*}\solutiontrue\begin{solution*}}

Exercises can then be typeset in the exercise environment, where \solution (which may not be present) will start the solution.

\begin{exercise}{difficult}
  exercise
\solution
  solution
\end{exercise}

\begin{exercise}{easy}
exercise
\end{exercise}
share|improve this answer
    
Thanks, but I'd like to keep the 3 entities as environments. See the edit in my message –  Andro Oct 6 '11 at 13:03
    
@Andro See edited answer –  egreg Oct 6 '11 at 13:18
    
Thanks. That looks good! I also want to know if it can automatically implement a functionality I wanted to use (I planned to do it manually, but if automatism is possible I would prefer it). See my edited message –  Andro Oct 6 '11 at 13:59
    
@Andro Define a \newexercise macro, along the lines of \solution; you'll need a new conditional. –  egreg Oct 6 '11 at 21:42
add comment

This is not recommended, I assume, as it does no proper environment initialization/checking. Some LaTeX experts could explain what is missing.

\documentclass{article}

\newenvironment{env1}{(begin env1)}{(end env1)}
\newenvironment{env2}{(begin env2)}{(end env2)}
\newenvironment{env3}{(begin env3)}{(end env3)}

\newenvironment{test1}%
{\csname env1\endcsname \begin{env2}}%
{\end{env2}}

\newenvironment{test2}%
{\begin{env3}}%
{\end{env3} \csname endenv1\endcsname}


\begin{document}

    \begin{test1}
        This is test1
    \end{test1}

    \begin{test2}
        This is test2
    \end{test2}

\end{document}

The \csname env1\endcsname construct builds a control sequence \env1 where 1 is part of the macro name. When you've got numbers in a macro name, you have to make special arrangements to create a macro name.

share|improve this answer
    
Nice touch, but I still don't see how env1 and endenv1 relate to each other. What I see here is still nesting in the most traditional sense. –  Count Zero Oct 6 '11 at 11:23
    
@CountZero I just want to solve the problem. If Andro had provided more information I could have written something about whether this approach solves his problem or not. There is nothing special I want to show. (Or perhaps I don't get your comment right.) –  topskip Oct 6 '11 at 11:32
    
@Patrick thanks, I tried to apply it but it doesn't seem to work. See the edit in my message, with details of my actual code. –  Andro Oct 6 '11 at 13:03
add comment

You can't nest environments that way. An environment has to have a \begin{env-name} and an \end{env-name} statement. You broke that rule when you separated the beginning and end of env1 across test1 and test2. This is not permitted, because by defining test1 and test2 you define two new scopes. Once you use an environment inside them, you also have to finish them within the same scope. This is a basic programming rule; unfortunately for you it's impossible to break an environment up like that.

share|improve this answer
1  
Basic programming rules applying to TeX? I wish this could be true. –  topskip Oct 6 '11 at 10:24
    
@Patrick: And why wouldn't that be true? Where do you start a procedure/function/environment/etc. without closing it? –  Count Zero Oct 6 '11 at 10:49
    
Is there a way around this, maybe with an appropriate package, or organizing it differently? My goal was to create a macro that automatically "appends" env1 as the container without writing it explicitly every time. –  Andro Oct 6 '11 at 10:51
    
@CountZero you can use e.g. \begingroup in one definition and \endgroup in another definition. I don't think TeX's programming language can be compared to any other well known language. –  topskip Oct 6 '11 at 11:04
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.