The lstlisting
environment is like all verbatim environments special and doesn't work (well) inside another environments. You need to use \lstnewenvironment
as described in the listings
manual in section 4.16 Environments, p.40:
\lstnewenvironment
{<name>}[<number>][<opt. default arg.>]
{<starting code>}
{<ending code>}
Applied to your code:
\lstnewenvironment{listingh}[1][]{%
\vspace{-\baselineskip}%
\lstset{backgroundcolor=\color{yellow},#1}%
}{%
\vspace{-\baselineskip}%
}
Note the %
at the end of lines to avoid spurious spaces.
You need to use the fragile
option of the frame
environment (or command) if you use listings
or any other verbatim code.
The fellowship of \newenvironment
and \renewenvironment
commands
Yes, \renew...
will erase or redefine the previous definition (or eject an error message, if this has not been defined before.)
In many cases it's more suitable to make a wrapper environment, which does not attack the original environment.
\newenvironment{foo}{%
%startup code, i.e the \WritingHand and `\singlespacing`
\begin{quotation}
}{%
% end code
\ding{...}
\end{quotation}
}
Since environments use groups, the change of the line spacing within of foo
is safe outside, there is no need to explicitly switch back to \onehalfspacing
. This is true for all lengths/skips and colour settings.
\documentclass{article}
\usepackage{setspace}
\usepackage{pifont}
\usepackage{marvosym}
\onehalfspacing
\newenvironment{foo}{%
\singlespacing
\begin{quotation}
\WritingHand
}{%
\ding{47}
\end{quotation}
}
\begin{document}
% Compare the spacing outside and inside of foo environment
Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.
\begin{foo}
Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.
\end{foo}
\end{document}
![enter image description here](https://i.stack.imgur.com/9F3FY.jpg)
The renewenvironment
version
renewenvironment
is basically similar, but one has to keep in mind too design issues:
- Should the environment be extended/improved --> use the old definition
- Completely drop the old behaviour --> do not use the old definition (of course)
I assume that the old behaviour should be available still, so I tried the first approach:
- First store the old environment startup code, which is just the command
\quotation
, to something, say \latex@quotation
.
- Store the environment end code, which is
\endquotation
then, to \latex@endquotation
.
- Basically proceed as in the
\newenvironment
version and replace \begin{quotation}
with \latex@quotation
and \end{quotation}
with \latex@endquotation
.
The output is the same.
Important note: If the environment has optional arguments, it's better to use \LetLtxMacro
instead of \let
, you need the letltxmacro
package then.
\documentclass{article}
\usepackage{setspace}
\usepackage{pifont}
\usepackage{marvosym}
\onehalfspacing % for this document ....
\makeatletter
\let\latex@quotation\quotation
\let\latex@endquotation\endquotation
\renewenvironment{quotation}{%
\singlespacing
\latex@quotation
\WritingHand
}{%
\ding{47}
\latex@endquotation%
}
\makeatletter
\begin{document}
% Compare the spacing outside and inside of foo environment
Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.
\begin{quotation}
Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.
\end{quotation}
% And once again
Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.
\end{document}
Edit The shortest version: Use the xpatch
command and its \xpretocmd
and \xapptocmd
macros.
\documentclass{article}
\usepackage{setspace}
\usepackage{pifont}
\usepackage{marvosym}
\usepackage{xpatch}
\onehalfspacing % for this document ....
\newcommand{\lotrtext}{%
Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.
}
% Append the `\singlespacing` etc. after the `\quotation` startup is called
\xapptocmd{\quotation}{\singlespacing%
\WritingHand%
}{}{}
% Prepend `\ding{47}` before `\endquotation` comes into action.
\xpretocmd{\endquotation}{\ding{47}}{}{}
\begin{document}
% Compare the spacing outside and inside of foo environment
\lotrtext
\begin{quotation}
\lotrtext
\end{quotation}
% And once again
\lotrtext
\end{document}
And the final (?) remark -- your possibilities:
- Refine a wrapper with
\newenvironment
- Change or completely erase the previous definition with
\renewenvironment
- Patch the commands with
\xpretocmd
, \xapptocmd
or \xpatchcmd
which is something between the 1st and 2nd. way.
All depends on the requested design, there is no general rule. (And if redefinition or new definition, I suggest to use \NewDocumentEnvironment
or \RenewDocumentEnvironment
from the very powerful xparse
package.
Update
Mico made an important comment:
The package etoolbox
provides the commands \AtBeginEnvironment
and \AtEndEnvironment
, \BeforeBeginEnvironment
and \AfterEndEnvironment
which do basically the same what I've done with \xpretocmd
and \xapptocmd
or the explicit \renewenvironment
, however, to an existing environment only -- which of the etoolbox
commands should be used depends on the precise requirements, what should be done before or after the group begins/ends.
As an alternative, there is NewEnviron
from the environ
package, which allows for the saving of the environment body into \Body
macro.
Best Answer
The command form is easier:
If you really insist in using an environment, use
environ
:An implementation using
xparse
andexpl3
; the largest part of the code is the definition of the error messages in case the environment is called twice with the same argument.Without the error check, the code part would look like
Update
With
xparse
released 2019-05-03 the code can become