# How can I undo an etoolbox patch?

Suppose I patch an environment using an etoolbox command such as \AtBeginEnvironment or \AfterEndEnvironment, etc. How can I undo these changes at a later stage?

\documentclass{article}
\usepackage{etoolbox}
\let\olditemize\itemize
\let\oldenditemize\enditemize
\AfterEndEnvironment{itemize}{bleat bleat}
\begin{document}
\begin{itemize}
\item This is an item.
\end{itemize}
\let\itemize\olditemize        %Would like to undo the change
\let\enditemize\oldenditemize  %now, but this doesn't help.
\begin{itemize}
\item This is another item.
\end{itemize}
\end{document}

-

First of all note that \BeforeBeginEnvironment and \AfterEndEnvironment does not patch the environment itself. It only adds material to hooks. etoolbox patches usage of these hooks to \begin and \end. That's the reason why resetting \itemize and \enditemize to their original definitions does not change anything.

But you may simply undefine the environment end hook of itemize:

\documentclass{article}
\usepackage{etoolbox}
\AfterEndEnvironment{itemize}{bleat bleat}
\begin{document}
\begin{itemize}
\item This is an item.
\end{itemize}

\csundef{@afterend@itemize@hook}% undefine the end hook of itemize
\begin{itemize}
\item This is another item.
\end{itemize}
\end{document}


\csundef is a etoolbox command and \@afterend@itemize@hook is the environment end hook of environment itemize. The environment begin hook would be \@beforebegin@itemize@hook.

Maybe a feature request for commands like \CleanBeforeBeginEnvironment or \CleanAfterBeginEnvironment could be suggested.

Alternative: If you only want to remove something but not everything, you may try this:

\documentclass{article}
\usepackage{etoolbox}

\newrobustcmd*{\RemoveFromAfterEndEnvironment}[2]{%
\expandafter\patchcmd\csname @afterend@#1@hook\endcsname{#2}{}%
}

\AfterEndEnvironment{itemize}{bleat bleat\par}{}{}
\AfterEndEnvironment{itemize}{don't remove this\par}{}{}
\begin{document}
\begin{itemize}
\item This is an item.
\end{itemize}

\RemoveFromAfterEndEnvironment{itemize}{bleat bleat\par}{}{}
\begin{itemize}
\item This is another item.
\end{itemize}
\end{document}


The third and fourth arguments of \RemoveFromAfterEndEnviroment are the same like third and fourth arguments of \patchcmd.

-
...you should send a request to the package author. – Werner Dec 1 '11 at 7:35
@Werner: The user who needs it should do it … – Schweinebacke Dec 1 '11 at 8:20

There might be an official way, but defining a new command \AfterEndItemize to specify what you want to do after \end{itemize}, and then use \renewcommand to change \AfterEndItemize to not do anything seems to work:

\documentclass{article}
\usepackage{etoolbox}

\newcommand{\AfterEndItemize}{bleat bleat}%
\AfterEndEnvironment{itemize}{\AfterEndItemize}

\begin{document}
\begin{itemize}
\item This is an item.
\end{itemize}
%
\renewcommand{\AfterEndItemize}{}%
\begin{itemize}
\item This is another item.
\end{itemize}
\end{document}

-

use it this way:

\documentclass{article}

\let\End\end
\usepackage{etoolbox}
\AfterEndEnvironment{itemize}{bleat bleat}
\begin{document}

\begin{itemize}
\item This is an item.
\end{itemize}

\let\end\End
\begin{itemize}
\item This is the last item.
\end{itemize}

\end{document}

-
Could you describe a bit how that works? Aren't there any interactions with other (possibly nested) environments or if one also patches another environment? – Daniel Nov 30 '11 at 22:31
It is obvious that etoolbox does nothing with \itemize and \enditemize, otherwise the solution of the original poster would work. etoolbox redefines the \end{itemize}. If you want to have it local then simply put the one into a group. – Herbert Dec 1 '11 at 7:52
I am asking because of the \let\End\end and \let\end\End trick, which generalized effects are not immediately clear to the uninspired. Would your trick also work if: (1) I am about to patch a second environment (\AfterEndEnvironment{enumerate}{foo bar}), which (2) in the document is used nested within the first, and (3) should be "undoable" independently from the first. – Daniel Dec 1 '11 at 8:03
as I wrote, in that case you have to hold the undo locally – Herbert Dec 1 '11 at 8:15

Another way is: Use a boolean switch. Conveniently etoolbox provides such switches. Compare my question and the answers in etoolbox: environment hooks in boolean switch and look at this:

\documentclass{article}

\usepackage{setspace}
\doublespacing

\usepackage{etoolbox}
\newbool{tightspace}
\setbool{tightspace}{false} % that's the default state, so
% it's here only for clarity
%----------------------------%
\BeforeBeginEnvironment{itemize}{%
\ifbool{tightspace}{% true part:
\begin{spacing}{0.9}
}{%
% false part empty - should do nothing
}%
}
\AfterEndEnvironment{itemize}{%
\ifbool{tightspace}{% true part:
\end{spacing}
}{%
% false part
}%
}

\usepackage{lipsum}

\begin{document}

\begin{itemize}
\item \lipsum[1]
\end{itemize}

\begingroup
\setbool{tightspace}{true}

\verb|\setbool{tightspace}{true}| inside a group:

\begin{itemize}
\item \lipsum[2]
\end{itemize}
\endgroup

And from now all outside of groups:

Here is \verb|\setbool{tightspace}{false}| in effect:

\begin{itemize}
\item \lipsum[3]
\end{itemize}

\verb|\setbool{tightspace}{true}|:
\setbool{tightspace}{true}

\begin{itemize}
\item \lipsum[4]
\end{itemize}

And again \verb|\setbool{tightspace}{false}|:
\setbool{tightspace}{false}

\begin{itemize}
\item \lipsum[5]
\end{itemize}

\end{document}

-

My idea is that one should not do this, but rather define a new environment:

\newenvironment{itemizeplus}
{\begin{itemize}}
{\end{itemize}}
\AfterEndEnvironment{itemizeplus}{bleat bleat}


Thus the behavior of itemize and itemizeplus will be predictable throughout the document.

Note. A more efficient definition would be

\let\itemizeplus\itemize
\let\enditemizeplus\enditemize
\AfterEndEnvironment{itemizeplus}{bleat bleat}


or, perhaps better,

\let\itemizeplus\itemize
\def\enditemizeplus{\enditemize bleat bleat}

-