Ensure description or itemize

Is there a way to make sure that a macro can only be used inside a specific environment, say description?

I am looking for something like the \ensuremath macro.

-
Please clarify this question. The \ensuremath macro switches to math mode to typeset its argument if necessary. If your macro is called outside a description, do you want it to flag an error, or start a description? –  Ian Thompson Jan 31 '12 at 16:36
Rather than make an answer that's only a link, here's a link to something I wrote in response to a similar question: tex.stackexchange.com/a/39755/575 –  Ryan Reich Feb 1 '12 at 3:29

You can modify the definition of the environment in order to set the command to either work or not. For the description environment, you could use the following code for example:

\documentclass{article}
\let\olddesc\description
\def\myrealcmd#1{\textbf{#1}}
\def\myfakecmd#1{#1}
\let\mycmd\myfakecmd
\def\description{\let\mycmd\myrealcmd\olddesc}
\begin{document}
\noindent This is a \mycmd{test} outside of description.
\begin{description}
\item This is a \mycmd{test} inside of one description.
\begin{description}
\item This is a \mycmd{test} inside of two descriptions.
\end{description}
\item This is a \mycmd{test} after a nested description.
\end{description}
And a \mycmd{test} outside again.
\end{document}


With the following result:

-
Nested description environments will break this, won't they? Because after the end of the inside description, the end code will be run… –  Seamus Jan 31 '12 at 18:00
@Seamus: You are correct, I added a simple counter to solve this issue. –  Roelof Spijker Jan 31 '12 at 18:31
@Seamus: I had composed an answer that include this tweak but then saw that it was not necessary. I had tested both this and egreg's solution, and both just worked fine. I assumed it was due to some sort of grouping effect. So you can probably put your original simpler solution back (unless I am missing something). –  Peter Grill Jan 31 '12 at 18:39
@PeterGrill: I think the original would not work when you have a first level of description, then one within that and then an item after that. That is, within the first description, but after the second level description has finished. Because then the end of the second level description will have set \mycmd to \fakecmd. –  Roelof Spijker Feb 1 '12 at 0:50
@wh1t3: Tried exactly (which is your updated MWE) and the original solution still works. –  Peter Grill Feb 1 '12 at 1:14

The etoolbox package provides hooks for the environments; so you can define a "hidden" macro and then activate it only in selected environments

\usepackage{etoolbox}
\makeatletter % protect the definition of \mymacro
\newcommand{\@mymacro}{whatever}
\AtBeginEnvironment{description}{\let\mymacro\@mymacro}
\makeatother

% now we help users
\newcommand{\mymacro}{%
\PackageError{mypackage}
{\protect\mymacro\space outside description'}
{You can use \protect\mymacro\space only inside description'}%
}


You can add other environments and also provide a different meaning in different environments:

\usepackage{etoolbox}
\makeatletter % protect the definition of \mymacro
\newcommand{\description@mymacro}{whatever}
\AtBeginEnvironment{description}{\let\mymacro\description@mymacro}
\newcommand{\itemize@mymacro}{whatever}
\AtBeginEnvironment{itemize}{\let\mymacro\itemize@mymacro}
\makeatother

-
The output of \PackageError needs a space following \protect\mymacro. I tried the usual \  and ~ but I guess that is not the correct way to insert space there. –  Peter Grill Jan 31 '12 at 16:50
Yes, one needs \space (I always forget). One can use \noexpand instead of \protect, but the latter is good practice. –  egreg Jan 31 '12 at 16:52

The current environment name is stored in \@currenvir so you could test that that was description or whatever, but nested environments would mask that. If you need your macro to be allowed anywhere in description, even in a nested tabular or itemize, say, then you would need to save \@currenvir into another macro at the start of description (either explicitly or by patching the definition of \description then you can test this local macro without it being over-written by nested environments.

-