Wie kann ich am einfachsten eine Umgebung modifizieren, ohne eine neue definieren zu müssen? So dass ich in längeren Dokumenten nicht alles umbenennen muss, sondern nur etwas in die Präambel einzufügen brauche.

Genauer, es soll am Beginn der Umgebung jeweils von mir eingefügter Code ausgeführt werden.

Zum Beispiel:

  • Alle Zitate sollen kleiner werden, d.h. am Beginn jeder quote-Umgebung soll ein \small eingefügt werden.

  • Variante: Alle quote-Zitate sollen italic sein.

Die Wirkung der eingefügten Formatierungen endet ja automatisch mit dem Ende der Umgebung, recht praktisch.

Wie geht sowas?

gefragt 14 Jul '13, 00:29

Helmut's gravatar image

Helmut
489161722
Akzeptiert-Rate: 100%


Umgebungen wie quote bestehen im Prinzip aus einem Befehl zum Beginnen der Umgebung, \quote, sowie einem Befehl zum Beenden der Umgebung: \endquote. Man könnte den Code also einfach an den Startbefehl anhängen, durch Redefinition oder Patchen.

Einige Möglichkeiten:

  1. Redefinition, Vermeidung einer Rekursion durch Vertauschung der Auswertungsreihenfolge mittels \expandafter:

    \expandafter\def\expandafter\quote\expandafter{\quote\small}
    

    Ein simples \renewcommand*{\quote}{\quote\small} würde nämlich fehlschlagen, da das rechte quote expandiert wird und durch die Redefinition ersetzt wird, und dann wieder und wieder ... die Rekursion bricht mit einem Fehler ab. \expandafter expandiert das hinter einem Makro stehende Makro zuerst, was die Rekursion vermeidet. Mehrfaches \expandafter wie hier baut die Reihenfolge noch weiter um.

    Nachteil: funktioniert nicht, wenn die Umgebung ein Argument verlangt. (Marco Daniel)

  2. Anhängen mittels internem Makro \g@addto@macro:

    \makeatletter
    \g@addto@macro{\quote}{\small}
    \makeatother
    

    Nachteil: Auch hier nicht geeignet, wenn die Umgebung ein Argument verlangt. Von der Verwendung interner Makros (erkennbar am @ im Namen) wird auch abgeraten. Der Schutz interner Makros macht auch \makeatletter und \makeatother nötig. Doch letztlich ist es ein simpler Befehl, um an ein Makro anzuhängen.

  3. Patchen mit etoolbox:

    \usepackage{etoolbox}
    \AtBeginEnvironment{quote}{\small}
    

    Empfehlenswerter Weg, wenn man das Paket laden kann: funktioniert auch, wenn das Makro Argumente verwendet. Man muss aber mit \begin{Umgebung} ... \end{Umgebung} arbeiten, wie es sich gehört, nicht die Abkürzung \Umgebung ... \endUmgebung benutzen. (Clemens, Marco) Und etoolbox kann noch sehr viel mehr.

Auch wenn es diese Wege gibt, ist es oft besser, eine eigene Umgebung mit neuem Namen zu definieren. Denn sonst kann man Seiteneffekte haben: andere Pakete oder Klassen können diese Umgebung ja implizit verwenden, wie z.B. quotation durch abstract in scrartcl verwendet wird (saputello). Siehe dazu seine Antwort. Es kann natürlich auch gewollt sein, dass man die implizite Verwendung genauso hiermit anpasst, dann hat die Änderung der originalen Umgebung natürlich ihren Sinn.

Permanenter link

beantwortet 14 Jul '13, 00:39

stefan's gravatar image

stefan ♦♦
18.1k143048
Akzeptiert-Rate: 48%

bearbeitet 14 Jul '13, 13:05

Man sollte vielleicht erwähnen, dass der Patch mit \AtBeginEnvironment nur Auswirkungen hat, wenn man die Umgebung als solche aufruft, also mit \begin{<env>} und \end{<env>}, während die anderen auch alle etwaigen direkten Aufrufe ändert.

(14 Jul '13, 09:42) cgnieder

Die ersten beiden Möglichkeiten schlagen fehl, sobald die Umgebung ein verpflichtendes Argument hat. Ich rate daher dazu, diese Möglichkeiten nicht gesondert hervorzuheben. Bei etoolbox klappt es deswegen, weil etoolbox mit \AtBeginEnvironment nicht die Umgebung ändert, sonder die Anweisung \begin, was bereits von Clemens gesagt wurde. Allerdings ist es guter Stil, mit begin zu arbeiten ;-)

(14 Jul '13, 10:51) Marco_D

Bevor auf Möglichkeiten der Redefinition von Befehlen zurückgegriffen wird, sollte man stets schauen, ob nicht ein Paket (evtl. sogar schon geladen) diverse Modifikationen erlaubt. Im Normalfall ist das robuster als etwaige Hacks.

Ich will Hacks nicht verteufeln

Für die quote Umgebung hat Thomas Titz ein Paket geschrieben, dass die Umgebung quoting bereitstellt, aber diverse Modifikationen zulässt:

\documentclass{article}
\usepackage{quoting}
\usepackage{lipsum}
\quotingsetup{font=small}
\begin{document}
\begin{quoting}
\lipsum[2]
\end{quoting}

\begin{quoting}[font+=itshape]
\lipsum[2]
\end{quoting}

\begin{quoting}[font={}]
\lipsum[2]
\end{quoting}

\begin{quoting}[font=bfseries]
\lipsum[2]
\end{quoting}
\end{document}
Permanenter link

beantwortet 14 Jul '13, 11:06

Marco_D's gravatar image

Marco_D
43015
Akzeptiert-Rate: 36%

bearbeitet 14 Jul '13, 11:07

Wenn sich etwas findet, verwende ich gern fertige Lösungen. Daher danke für den quoting-Paket-Tipp! Hier wollte ich gern etwas dazulernen, um selbst auch mal was schnell anpassen zu können. Mit "Hacks" kann man auf die Schnelle mal was reparieren oder im Dokument umsetzen, auf eigene Gefahr eben.

(14 Jul '13, 11:46) Helmut

Statt eine existierende Umgebung umzudefinieren, ist es oftmals sicherer eine neue Umgebung zu definieren, die auf einer existierenden Umgebung basiert. Grund dafür ist, dass einige Umgebungen auch intern in Klassen oder Paketen verwendet werden. Das trifft beispielsweise in hohem Maße auf die Umgebung tabular und auch auf quote oder quotation zu. Mit einem modernen Editor ist es meist auch kein Problem, im Quelltext alle Umgebungen foo durch fooneu zu ersetzen.

Für das Definieren einer eigenen Umgebung unter Verwendung einer existierenden, gibt es zwei unterschiedliche Möglichkeiten:

\newenvironment{fooneu}{%
  \begin{fooalt}%
    % Hier die gewünschten Ergänzungen einfügen.
}{%
  \end{fooalt}%
}

oder

\newenvironment{fooneu}{%
  \fooalt
}{%
  \csname endfooalt\endcsname
}

Die erste Möglichkeit entspricht dabei der reinen Lehre, dass man in LaTeX nur die LaTeX-Benutzerschnittstelle verwenden sollte, die bei Umgebungen nun einmal aus \begin{…} und \end{…} besteht. Allerdings hat sie einen Nachteil, wenn ein Anwender bei \end{fooneu} einen Fehler macht. Dazu ein Beispiel:

\documentclass{article}
\newenvironment{newquote}{%
  \begin{quote}%
  \small
}{%
  \end{quote}%
}
\begin{document}
\begin{newquote}
Dieses Beispiel erzeugt eine verwirrende Fehlermeldung.
\end{NEWQUOTE}% ← absichtlicher Fehler
\end{document}

Die zugehörige Fehlermeldung lautet:

! LaTeX Error: \begin{quote} on input line 9 ended by \end{NEWQUOTE}.

Für den eingeweihten Anwender, der um die Definition von newquote weiß, ist die Fehlermeldung einleuchtend, da hier tatsächlich die quote-Umgebung aus dem \begin-Teil von newquote mit \end{NEWQUOTE} beendet wird. Wer die Definition von newquote nichts in die Betrachtung mit einbezieht, wird allerdings verwirrt sein.

Vergleichen wir dieselbe Fehlanwendung mit der zweiten Form der Definition:

\documentclass{article}
\newenvironment{newquote}{%
  \quote
  \small
}{%
  \csname endquote\endcsname
}
\begin{document}
\begin{newquote}
Dieses Beispiel erzeugt eine verwirrende Fehlermeldung.
\end{NEWQUOTE}% ← absichtlicher Fehler
\end{document}

Hier lautet die Fehlermeldung:

! LaTeX Error: \begin{newquote} on input line 9 ended by \end{NEWQUOTE}.

Damit entspricht sie den Erwartungen eines durchschnittlichen Anwenders. Hier wurde die Tatsache genutzt, dass LaTeX intern eine Umgebung foo als Anweisungen \foo und \endfoo definiert, wobei der \begin-Code in \foo und der \end-Code in \endfoo abgelegt ist.

Um zu verstehen, warum im \end-Teil der Definition dann nicht einfach \endfoo statt \csname endfoo\endcsname verwendet wurde, muss man wissen, dass LaTeX innerhalb von \end nicht wirklich \endfoo, sondern selbst ebenfalls \csname foo\endcsname aufruft. Das funktioniert auch, falls \endfoo gar nicht definiert ist, weil \csname foo\endcsname in diesem Fall \endfoo auf \relax setzt. In einigen Paketen sind deshalb die zur einer Umgebung gehörenden \end-Anweisungen gar nicht erst definiert. Ein expliziter Aufruf von \endfoo würde in diesem Fall einen Fehler aufgrund einer undefined controll sequence, also einer nicht definierten Anweisung ergeben. Natürlich ist es kein guter Stil, eine Umgebung foo so zu definieren, dass die zugehörige Anweisung \endfoo nicht definiert ist.

Aber auch diese Form der Definition hat ihre Grenzen. So gibt es einige Umgebungen, die gar keine echten LaTeX-Umgebungen sind. Dazu gehören beispielsweise die Umgebungen von amsmath oder die Umgebungen die mit Hilfe des Pakets environ definiert wurden, aber auch die filecontents- oder die verbatim-Umgebung und vergleichbare Umgebungen. Bei all diesen Umgebungen wird der Inhalt der Umgebung eher wie das Argument eines Befehls als wie der Inhalt einer normalen Umgebung behandelt. Bei all diesen Umgebungen ist sowohl bei ihrer Verwendung in andere Umgebungen als auch bei ihrer Umdefinierung daher besondere Vorsicht walten zu lassen. Näheres ist ggf. den entsprechenden Anleitungen zu entnehmen.

Zu beachten ist auch, dass die lrbox-Umgebung von LaTeX selbst, ebenfalls eine besondere Umgebung ist, die explizit zur Verwendung in anderen Umgebungen entworfen ist. Sie ist daher immer in der Form \begin{lrbox} und \end{lrbox} zu verwenden.

Permanenter link

beantwortet 14 Jul '13, 12:26

saputello's gravatar image

saputello
11.1k154365
Akzeptiert-Rate: 51%

Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×16

gestellte Frage: 14 Jul '13, 00:29

Frage wurde gesehen: 11,824 Mal

zuletzt geändert: 14 Jul '13, 13:05