0

Since it seems that the LaTeX convention is to use globally scoped instead of locally scoped commands/environments (which makes sense now for a complex reason), I am wondering how to handle the case where I want two different implementations of the same command/environment name.

For example, say I have this:

\NewDocumentEnvironment{myenva}{} {
  \NewDocumentCommand{\mycmd}{m} {

  }
}

\NewDocumentEnvironment{myenvb}{} {
  \NewDocumentCommand{\mycmd}{m} {

  }
}

Instead of writing that as nested, I would write it as something like:

\NewDocumentCommand{\mycmd}{} {
  \if environment is myenva {
    \typeout{myenva}
  }

  \if environment is myenvb {
    \typeout{myenvb}
  }

  \else {
    throw error This needs to be in myenva or myenvb.
  }
}

\NewDocumentEnvironment{myenva}{} {

}

\NewDocumentEnvironment{myenvb}{} {

}

The following is a MWE:

\documentclass[a4paper]{article}

\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\mycmd}{} {
  \if environment is myenva {
    \typeout{myenva}
  }

  \if environment is myenvb {
    \typeout{myenvb}
  }

  \else {
    \PackageError{mypackage}{This needs to be in myenva or myenvb.}{}
  }
}

\NewDocumentEnvironment{myenva}{} {

}

\NewDocumentEnvironment{myenvb}{} {

}

\begin{document}

\begin{myenva}
  Hello
  \mycmd{}
\end{myenva}

\begin{myenvb}
  world
  \mycmd{}
\end{myenvb}

\end{document}

Wondering if this is the right approach, and how to get it working (i.e. checking that it is in the correct environment). Another approach would be to reopen the command definition if that's possible in LaTeX3, so it would be slightly cleaner / have separation of concerns.

\NewDocumentCommand{\mycmd}{} {
  \if environment is myenva {
    \typeout{myenva}
  }
}

% something along these lines:

\RenewDocumentCommand{\mycmd}{}{
  \super{}

  \if environment is myenvb {
    \typeout{myenvb}
  }
}

Not sure the way to get this working (how to check for the right environment). Also I've read somewhere that potentially throwing an error if it's the wrong environment might be a good option, so wasn't sure if I should include that. Might be useful for debugging and making it more robust.

Also, I would like to avoid having to pass around the environment name, such as like this:

\mycmd{myenva}
\mycmd{myenvb}
3

In LaTeX2e the current environments name is stored in \@currenvir. This can be used to define \mycmd to call the correct command. So I would either use this:

\documentclass[]{article}

\usepackage{xparse}
\makeatletter
\NewDocumentCommand\mycmd{}{\csname mycmd@\@currenvir\endcsname}
\NewDocumentCommand\mycmd@enva{}{myenva}
\NewDocumentCommand\mycmd@envb{}{myenvb}
\NewDocumentEnvironment{enva}{}{}{}
\NewDocumentEnvironment{envb}{}{}{}
\makeatother

\begin{document}
\begin{enva}
  \mycmd
\end{enva}

\begin{envb}
  \mycmd
\end{envb}
\end{document}

Or this:

\documentclass[]{article}

\usepackage{xparse}
\makeatletter
\NewDocumentCommand\mycmd@enva{}{myenva}
\NewDocumentCommand\mycmd@envb{}{myenvb}
\NewDocumentEnvironment{enva}{}{\let\mycmd\mycmd@enva}{}
\NewDocumentEnvironment{envb}{}{\let\mycmd\mycmd@envb}{}
\makeatother

\begin{document}
\begin{enva}
  \mycmd
\end{enva}

\begin{envb}
  \mycmd
\end{envb}
\end{document}

The problem with the first is that it would fail if you nest an environment in enva since \@currenvir would be the name of that environment. So the latter (\letting \mycmd to the correct definition) seems more robust.

| improve this answer | |
  • Although from my understanding we shouldn't define commands inside environments, they should always be global if they are used in the document. – Lance Pollard Mar 26 '18 at 22:08
  • @LancePollard if your environment is kind of special there is nothing bad about defining a local command. It really depends on the syntax you want to create. And you can define a global version of \mycmd which issues an error, something like: \NewDocumentCommand\mycmd{}{\PackageError{LancePollard}{Don't use \string\mycmd\ outside of 'enva' or 'envb'}{}} Then it is defined globally but throws an error when used, but doesn't if you \let it to another definition inside your environment. – Skillmon likes topanswers.xyz Mar 26 '18 at 22:26

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.