10

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?

2

1 Answer 1

11

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}
9
  • 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, 2017 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, 2017 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, 2017 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, 2017 at 16:08
  • 2
    Shouldn't \@checkend{mastermulticols} be \@checkend{#1}?
    – cgnieder
    Jan 31, 2017 at 16:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .