Environments – How to Wrap Environment in Another Environment with Hooks

environmentshooks

This problem is distilled from an environment that needs to use its body either wrapped in a minipage or not. Furthermore, this environment is to be automatically wrapped around all uses of another environment (e.g. flushleft in the following).

Explicitly wrapping myEnv around another environment works:

\documentclass{article}

\usepackage{xparse}
\usepackage{amsmath}

\NewDocumentEnvironment{myEnv}{O{}+b}
  {B {#2}}
  {{#2} E}

\begin{document}

\begin{myEnv}
\begin{flushleft}
  flushleft
\end{flushleft}
\end{myEnv}

\end{document}

However, if I try to use environment hooks like this:

\documentclass{article}

\usepackage{xparse}
\usepackage{amsmath}

\NewDocumentEnvironment{myEnv}{O{}+b}
  {B {#2}}
  {{#2} E}

\BeforeBeginEnvironment{flushleft}{\begin{myEnv}}
\AfterEndEnvironment{flushleft}{\end{myEnv}}

\begin{document}

\begin{flushleft}
  body
\end{flushleft}

\end{document}

then I get this error:

Extra }, or forgotten \endgroup.
\environment myEnv code #1#2->B {#2}
                                    
l.17 \end
         {flushleft}

To reiterate, I'd like to have all uses of the flushleft environment to be modified as if they were explicitly wrapped in myEnv.
What's wrong with the above? Maybe the myEnv hooks are invoked for more times than I expect them to?

Best Answer

The problem here is that the +b argument is not correctly recognized by myEnv when flushleft is redefined with the hooks. I think what happens is that flushleft can't pass the body as an argument to myEnv, because it simply does not take it as an argument in the first place. I see two solutions here.

  1. Remove the body from myEnv's definition if you don't really need it.
\documentclass{article}
\usepackage{amsmath}

\NewDocumentEnvironment{myEnv}{O{}}
  {B}
  {E}
\BeforeBeginEnvironment{flushleft}{\begin{myEnv}}
\AfterEndEnvironment{flushleft}{\end{myEnv}}

\begin{document}

\begin{flushleft}
  body
\end{flushleft}

\end{document}
  1. Redefine flushleft so that it understands the body as an argument. In that case you don't need the hooks, because you already redefine flushleft so you can just add myEnv in the new definition.
\documentclass{article}
\usepackage{amsmath}

\NewDocumentEnvironment{myEnv}{O{} +b}
  {B {#2}}
  {{#2} E}
\let\oldflushleft\flushleft
\let\endoldflushleft\endflushleft
\RenewDocumentEnvironment{flushleft}{+b}
    {\begin{myEnv}\oldflushleft #1}
    {\endoldflushleft\end{myEnv}}

\begin{document}

\begin{flushleft}
  body
\end{flushleft}

\end{document}
Related Question