7

How can I redefine an environment with an argument such as the multicols environment? The Goal is to define two sets of commands each of them based on the native multicols environment:

\LetLtxMacro\oldmulticols\multicols
% first command
\newenvironment{mastermulticols}[1]
    { do some stuff \begin{\oldmulticols}{#1}
    {\end{\oldmulticols} do some stuff}

% second command
\renewenvironment{multicols}[1]
    {do some other stuff \begin{\oldmulticols}{#1}
    {\end{oldmulticols} do some other stuff}

It is important to me that I can use the second command with \begin{multicols}{some number}because there are already many occurrances of \begin{multicols}in my document. So make two different environment with \newenvironment{} with two different names is not helpfull to me.

I saw the approach with the \LetLtxMacro\oldmulticols\multicolscommand in an answer by egreg dealing with the figure environment that takes no additional argument.

My problem is that I don't know the exact syntax to do so. Can anbody help me with this issue?

  • Defining \oldmulticols does not provide the old \endmulticols automatically – user31729 Jan 31 '17 at 15:24
8

You don't need \LetLtxMacro in this case. Rather you should not redefine the environment with an argument: just pass it to the saved macro (unless you need to do something at the very start of the environment.

\documentclass{article}
\usepackage{multicol}

\usepackage{lipsum}

\let\FMmulticols\multicols
\let\endFMmulticols\endmulticols

\renewenvironment{multicols}
 {<some stuff before>\FMmulticols}
 {\endFMmulticols<some stuff after>}

\begin{document}

\begin{multicols}{2}[\section{A section title to show it works}]
\lipsum[1-2]
\end{multicols}

\end{document}

enter image description here

A different (and even more flexible) strategy is with etoolbox:

\documentclass{article}
\usepackage{multicol}
\usepackage{etoolbox}

\usepackage{lipsum}

\BeforeBeginEnvironment{multicols}{%
  <some stuff before>%
}
\AfterEndEnvironment{multicols}{%
  <some stuff after>%
}

\begin{document}

\begin{multicols}{2}[\section{A section title to show it works}]
\lipsum[1-2]
\end{multicols}

\end{document}

For implementation reasons, it is not really possible to define an environment in terms of multicols, because this one checks explicitly for \end{multicols}.

Here's a generic approach that can be combined with the \BeforeBeginEnvironment and \AfterEndEnvironment approach for adding stuff to the standard multicols.

\documentclass{article}
\usepackage{multicol,etoolbox}

\usepackage{lipsum}

% keep copies of the original to be on the safe side
\let\FMmulticols\multicols
\let\endFMmulticols\endmulticols

\makeatletter
\newcommand{\newmulticolsenvironment}[3]{%
  \newenvironment{#1}{#2\FMmulticols}{}%
  \toks@=\expandafter{\endFMmulticols#3}%
  \expandafter\edef\csname end#1\endcsname{\the\toks@}%
  \expandafter\patchcmd\csname end#1\endcsname
    {\@checkend{multicols}}
    {\@checkend{#1}}
    {}{}%
}

\newmulticolsenvironment{mastermulticols}
 {<some stuff before>}
 {<some stuff after>}

\begin{document}

\begin{mastermulticols}{2}[\section{A section title to show it works}]
\lipsum[1-2]
\end{mastermulticols}

\end{document}

Addition for the *-version

With some stretch, we can also define the *-version for every environment we define with \newmulticolsenvironment:

\documentclass{article}
\usepackage{multicol,etoolbox}

\usepackage{lipsum}

% keep copies of the original to be on the safe side
\let\FMmulticols\multicols
\let\endFMmulticols\endmulticols
\letcs\FMmulticolsstar{multicols*}
\letcs\endFMmulticolsstar{endmulticols*}
\patchcmd{\FMmulticolsstar}{\begin{multicols}}{}{}{}
\patchcmd{\endFMmulticolsstar}{\end{multicols}}{}{}{}

\makeatletter
\newcommand{\newmulticolsenvironment}[3]{%
  \newenvironment{#1}{#2\FMmulticols}{}%
  \toks@=\expandafter{\endFMmulticols#3}%
  \expandafter\edef\csname end#1\endcsname{\the\toks@}%
  \expandafter\patchcmd\csname end#1\endcsname
    {\@checkend{multicols}}
    {\@checkend{#1}}
    {}{}%
  \newenvironment{#1*}
    {#2\FMmulticolsstar\begin{#1}}
    {\endFMmulticolsstar\end{#1}#3}%
}

\newmulticolsenvironment{mastermulticols}
 {<some stuff before>}
 {<some stuff after>}

\begin{document}

\begin{mastermulticols*}{2}[\section{A section title to show it works}]
\lipsum[1-4]
\end{mastermulticols*}

\end{document}
| improve this answer | |
  • The first approach doesn't seem to work when defining a new environment (like OP's mastermulticols), i.e., when using \newenvironment{mastermulticols} instead of \renewenvironment{multicols}. (Haven't yet looked at the second approach.) – gernot Jan 31 '17 at 15:49
  • @gernot For implementation reasons, also mastermulticols should be defined with \FMmulticols and \endFMmulticols, not with \begin{FMmulticols} and \end{FMmulticols}. – egreg Jan 31 '17 at 15:59
  • Yes, sure. But in your code, replacing \renewenvironment{multicols} by \newenvironment{mastermulticols} and \begin/\end{multicols} by \begin/\end{mastermulticols} leads to the error \begin{mastermulticols} on input line 15 ended by \end{multicols}. So your solution does not yet address the second request. – gernot Jan 31 '17 at 16:04
  • @gernot Yes, I hate when the LaTeX developers use for their packages tricks that go against their own guidelines. ;-) – egreg Jan 31 '17 at 16:08
  • 2
    Shouldn't \@checkend{mastermulticols} be \@checkend{#1}? – cgnieder Jan 31 '17 at 16:31

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.