4

I would like to define a environment inside another environment, but I need to make sure the new environment is unique, so there can only be of them. The unique environment should also be able to be any point of the outlaying environment. So the code would be something like:

\begin{myenv}
    \begin{env} ... \end{env}
    \begin{env} ... \end{env}
    \begin{unique-env} 
       there can be no other environments of this type in myenv
    \end{unique-env}
    \begin{env} ... \end{env}
\end{myenv}

I have found out how to check that the unique environment exists inside myenv, but not how I can make sure it is the only one of this kind.

I will try to clarify a bit. I need this to be legal:

\begin{some_env} 
  \begin{unique-env} 
    Something 
  \end{unique-env} 
\end{some_env} 

And this to be illegal:

\begin{some_env} 
  \begin{unique-env} 
    Something 
  \end{unique-env} 
  \begin{unique-env} 
    Something 
  \end{unique-env} 
\end{some_env}

Where the some_env is also something I have defined.

What I need to be unique doesn't need to be a environment, it could also be a command

\begin{some_env} 
  \uniquesCommand{Something}
\end{some_env} 
  • I don't understand. So you can have only one unique-env inside myenv? Or if you have unique-env, you can't have any other environments? – Werner Apr 28 '16 at 19:12
  • @Werner I have tried clarifying it a bit now, I hope it helps. – mallereik May 1 '16 at 15:59
2

It's possible to use a new counter that is checked at the start-up code of the environment. If the counter is equal to zero, all is fine, increase the counter to indicate that is zero not any longer, if the counter is not zero right from the start (because it has been increased already) issue an error message.

At the end of the environment the counter is reset to zero.

A counter has the advantage that it's global, it survives the end of the group (established due to the environment). One could use something like \ifisinside statement too, if \global\isinsidetrue is applied.

Of course, it's no failsafe method -- a manual modification of the uniquenv counter will either allow nested uniquenv or disallow even the first usage of the environment, depending on the manipulation.

Note: The document below 'fails' by design here!!!!

\documentclass{article}


\newcounter{uniquenv}
\newenvironment{uniquenv}{%
  \ifnum\value{uniquenv} = 0 
  \stepcounter{uniquenv}%
  \else
        \GenericError{Error}{nested unique env}{You can't use a nested unique env^^J
Remove all env except the outer one!}{}
  \fi
}{%
  \setcounter{uniquenv}{0}
}



\begin{document}

\begin{figure}
  \begin{uniquenv}
    Foo
  \end{uniquenv}

  \begin{uniquenv}
  \begin{uniquenv}
    Foo inside
  \end{uniquenv}
  \end{uniquenv}

\end{figure}

\end{document}

Update No reuse within someenv:

\documentclass{article}


\newcounter{uniquenv}



\newenvironment{someenv}{}{}

\usepackage{etoolbox}

\AtBeginDocument{someenv}{\setcounter{uniquenv}{0}}


\newenvironment{uniquenv}{%
  \ifnum\value{uniquenv} = 0 
  \stepcounter{uniquenv}%
  \else
        \GenericError{Error}{nested unique env}{You can't use a nested unique env^^J
Remove all env except the outer one!}{}
  \fi
}{%
}



\begin{document}

\begin{someenv}
  \begin{uniquenv}
    Something
  \end{uniquenv}
\end{someenv}


\begin{someenv}
  \begin{uniquenv}
    Something
  \end{uniquenv}

  \begin{uniquenv}
    Something more
  \end{uniquenv}
\end{someenv}


\end{document}
| improve this answer | |
  • This seems almost like what I need. But I need this to be legal: \begin{some_env} \begin{unique-env} Something \end{unique-env} \end{some_env} And this to be illegal: \begin{some_env} \begin{unique-env} Something \end{unique-env} \begin{unique-env} Something more \end{unique-env} \end{some_env} Where the some_env is also something I have defined. – mallereik May 1 '16 at 15:28
  • @mallereik: What do you mean? Legal? – user31729 May 1 '16 at 15:29
  • Sorry, my first comment, so I didn't know hitting enter would post it. @ChristianHupfer – mallereik May 1 '16 at 15:32
  • @mallereik: See the update at the bottom of my answer please – user31729 May 1 '16 at 15:40
  • I got it working by modifying your second suggestion. – mallereik May 1 '16 at 16:11
0

Here's a possibility:

\documentclass{article}
\usepackage{etoolbox}

\newenvironment{myenv}
  {\global\uniqueenvfalse
   \BeforeBeginEnvironment{unique-env}{\ifuniqueenv\errmessage{ONLY ONE}\fi}
   something at startup\par}
  {\par something at end}

\newenvironment{unique-env}
  {\par\global\uniqueenvtrue}
  {\par}

\newif\ifuniqueenv

\begin{document}

\begin{myenv}

Text

\begin{unique-env}
This should appear only once inside \texttt{myenv}
\end{unique-env}

Other text

\begin{unique-env}
This should appear only once inside \texttt{myenv}
\end{unique-env}

Other text

\end{myenv}

\end{document}

This produces

! ONLY ONE.
\@beforebegin@unique-env@hook ...essage {ONLY ONE}
                                                  \fi 
l.28 \begin{unique-env}

? 
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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