Lorsque vous entourez plusieurs fois une zone avec la même mise en forme, vous pouvez créer votre propre \begin{name}…\end{name}. La base est \newenvironment. Si une macro est une *commande* faite maison, un environnement en est le pendant bloc. Cette page parcourt les bases : le code séparé exécuté au début et à la fin, le passage d’arguments et son piège, la redéfinition d’un environnement existant, puis le moderne \NewDocumentEnvironment.
Définir un environnement avec \newenvironment
L’outil de base est \newenvironment{name}{⟨begin-def⟩}{⟨end-def⟩}. Le premier argument est le nom de l’environnement voulu, sans antislash ; les deux suivants sont le code à exécuter au début et le code à exécuter à la fin. Quand LaTeX rencontre \begin{name}, il exécute ⟨begin-def⟩ ; quand il rencontre \end{name}, il exécute ⟨end-def⟩ ; le corps entre les deux est composé normalement.
% プリアンブルで定義 / define in the preamble
\newenvironment{warning}{%
\par\noindent\textbf{注意:}\itshape
}{%
\par
}
% 本文で使う / use it in the body
\begin{warning}
この操作は元に戻せません。
\end{warning}Une propriété décisive : un environnement forme lui-même un groupe implicite, donc une portée locale. Les règles de LaTeX stipulent que le code ⟨begin-def⟩, le corps de l’environnement et le code ⟨end-def⟩ sont tous traités dans un même groupe. Ainsi, toute modification de police ou d’espacement faite dans ⟨begin-def⟩ est annulée automatiquement à \end{name} et ne fuit pas vers le texte autour. C’est pourquoi, dans l’exemple, seul le corps devient italique même si \itshape n’est jamais désactivé explicitement.
Ce groupement automatique est très pratique pour confiner un changement de police ou d’espacement à une zone précise. Avec une macro (\newcommand), il faudrait entourer soi-même le contenu de { … } pour créer un groupe ; avec un environnement, \begin…\end joue déjà ce rôle.
Environnements avec arguments — et pourquoi le code de fin ne les voit pas
Pour faire varier le contenu à chaque appel, donnez des arguments à l’environnement. Comme avec \newcommand, on écrit le nombre d’arguments entre crochets après le nom, puis on les utilise dans ⟨begin-def⟩ sous la forme #1, #2, etc. : \newenvironment{name}[⟨nargs⟩]{⟨begin-def⟩}{⟨end-def⟩} (de #1 à #9, neuf au maximum).
% 見出しの語を引数で受け取る / take the heading word as an argument
\newenvironment{point}[1]{%
\par\noindent\textbf{#1}\quad
}{%
\par
}
\begin{point}{結論}
早めにバックアップを取ること。
\end{point}De même qu’avec \newcommand, on peut aussi rendre le premier argument optionnel, avec une valeur par défaut. En doublant les crochets — \newenvironment{name}[⟨nargs⟩][⟨default⟩]{...}{...} — #1 devient un argument optionnel dont la valeur par défaut est ⟨default⟩. On l’ouvre alors par \begin{name} (valeur par défaut) ou \begin{name}[x] (#1 vaut x). Comme pour \newcommand, ⟨nargs⟩ dans [⟨nargs⟩] est le nombre total d’arguments, optionnel compris.
Voici le piège propre aux environnements, et le plus important. Les arguments #1, #2, … ne peuvent être utilisés que dans ⟨begin-def⟩ ; ils ne sont pas disponibles dans ⟨end-def⟩. La règle le dit explicitement : le code de fin ne doit pas contenir de paramètres, donc pas de #1, #2, etc. En bref, au moment où \end{name} s’exécute, les arguments ne sont plus là. Écrire #1 dans ⟨end-def⟩ ne développe pas l’argument ; cela provoque une erreur.
Si vous avez besoin de la valeur d’un argument à la fin, la méthode classique consiste à la sauvegarder pendant que vous êtes encore dans ⟨begin-def⟩. Pour du texte, stockez-la dans une boîte (réservée avec \newsavebox, remplie avec \sbox), ou faites-la mémoriser par une macro via \newcommand/\def, puis récupérez-la dans ⟨end-def⟩. Comme tout l’environnement est un groupe, ce qui est enregistré dans ⟨begin-def⟩ survit jusqu’à ⟨end-def⟩. L’exemple ci-dessous imprime une attribution à la fin d’une citation : la source arrive en #1 (par défaut Shakespeare), est stockée dans \quoteauthor, puis utilisée à la fermeture.
\newsavebox{\quoteauthor}
\newenvironment{citequote}[1][Shakespeare]{%
\sbox\quoteauthor{#1}% begin-def で引数を保存 / save the arg here
\begin{quotation}
}{%
\hspace{1em plus 1fill}---\usebox{\quoteauthor}% end-def で取り出す
\end{quotation}%
}
\begin{citequote}
To be, or not to be.
\end{citequote}
\begin{citequote}[Knuth]
Premature optimization is the root of all evil.
\end{citequote}\renewenvironment et les noms déjà existants
Les environnements ont le même filet de sécurité que \newcommand : \newenvironment ne réussit que si le nom n’est pas déjà défini. Utilisé sur un environnement existant, il s’arrête avec LaTeX Error: Command \name already defined. (l’environnement name est soutenu en interne par une commande \name, d’où ce libellé). C’est voulu, pour éviter d’écraser silencieusement un environnement existant.
Pour retravailler un environnement existant, utilisez \renewenvironment. Il prend les arguments exactement comme \newenvironment, y compris [⟨nargs⟩][⟨default⟩]; seul le comportement change. \renewenvironment signale une erreur si la cible n’est pas déjà définie : c’est le miroir de \newenvironment. On l’utilise pour remplacer le contenu d’environnements intégrés comme quote ou itemize.
% 既存の quote を、本文を斜体にする版へ作り直す
\renewenvironment{quote}{%
\list{}{\rightmargin\leftmargin}\item\relax\itshape
}{%
\endlist
}Quelques règles s’appliquent. D’abord, un nom d’environnement ne peut pas commencer par la chaîne end : le traitement de \end{...} utilise en interne une commande nommée \end<name>, et cette restriction évite les collisions. Ensuite, \newenvironment et \renewenvironment ont une forme étoilée, écrite avec * après le nom, qui diffère dans le traitement des espaces de fin dans les arguments ; la forme sans étoile suffit généralement. Il n’existe pas dans le standard d’équivalent environnement à \providecommand ; si vous en avez besoin, utilisez l’interface moderne de la section suivante.
Schémas courants
En pratique, définir un environnement personnel revient le plus souvent à trois schémas. Tous partagent la même ossature : préparer dans ⟨begin-def⟩, puis nettoyer dans ⟨end-def⟩.
- Envelopper le contenu dans une mise en forme — régler la police, la taille ou l’alignement dans
⟨begin-def⟩et laisser le corps prendre cet aspect. Grâce au groupement,⟨end-def⟩peut être vide et le changement se rétablit quand même. - Ajouter de l’espace avant et après — placer un espace vertical comme
\par\medskipau début de⟨begin-def⟩et à la fin de⟨end-def⟩, encadrant le corps par des marges verticales. - S’appuyer sur un environnement existant — ouvrir un autre environnement avec
\begin{...}dans⟨begin-def⟩et fermer le\end{...}correspondant dans⟨end-def⟩. C’est ainsi qu’on ajoute un peu de comportement àquote,centeroulist.
Le troisième schéma, s’appuyer sur un environnement existant, est le plus fréquent. Un environnement smallquote qui réutilise quotation en plus petit active simplement \small, ouvre \begin{quotation} dans ⟨begin-def⟩, puis ferme \end{quotation} dans ⟨end-def⟩. Le comportement de l’environnement sous-jacent, comme l’indentation et les marges, est conservé.
% 1) 書式で包む / wrap in formatting
\newenvironment{aside}{\par\small\itshape}{\par}
% 2) 前後に空きを入れる / add space around
\newenvironment{spaced}{\par\medskip\noindent}{\par\medskip}
% 3) 既存の環境の上に作る / build on quotation
\newenvironment{smallquote}{%
\small\begin{quotation}
}{%
\end{quotation}
}Veillez à fermer dans ⟨end-def⟩ tout ce que vous avez ouvert dans ⟨begin-def⟩, en gardant les paires équilibrées. Il est aussi utile de terminer les lignes de code par % pour que les espaces parasites à la fin de ⟨begin-def⟩ ou d’une ligne de code ne s’infiltrent pas dans la sortie ; c’est pourquoi les lignes des exemples multilignes ci-dessus se terminent par %.
Le moderne \NewDocumentEnvironment
LaTeX moderne offre une méthode plus puissante : \NewDocumentEnvironment{name}{⟨arg-spec⟩}{⟨begin-code⟩}{⟨end-code⟩}. Elle correspond à \NewDocumentCommand côté macros ; à l’origine fonction du package xparse, elle fait partie du noyau LaTeX depuis octobre 2020 et s’utilise sans \usepackage. Au lieu d’un nombre d’arguments, on déclare une spécification d’arguments (arg-spec) : une chaîne de lettres comme m (obligatoire), o (optionnel), O{default} (optionnel avec valeur par défaut) ou s (étoile optionnelle). La page « xparse » détaille ces spécificateurs.
Cette interface dépasse l’ancien \newenvironment de deux façons. D’abord, elle peut prendre plusieurs arguments optionnels et gérer proprement les variantes étoilées. Ensuite, point décisif, les arguments sont accessibles dans ⟨end-code⟩ aussi bien que dans ⟨begin-code⟩. La documentation du noyau le dit clairement : le code de début comme le code de fin peuvent accéder aux arguments définis par ⟨arg-spec⟩. La gymnastique de la boîte sauvegardée devient inutile.
% #1 を begin でも end でも使える / #1 usable in both begin and end
\NewDocumentEnvironment{citequote}{O{Shakespeare}}{%
\begin{quotation}
}{%
\hspace{1em plus 1fill}---#1%
\end{quotation}%
}
\begin{citequote}[Knuth]
Premature optimization is the root of all evil.
\end{citequote}\NewDocumentEnvironment vient aussi avec la famille qui correspond aux variantes de \newenvironment : \RenewDocumentEnvironment (redéfinir), \ProvideDocumentEnvironment (définir seulement si absent) et \DeclareDocumentEnvironment (définir quoi qu’il existe déjà). Pour du nouveau code, cette interface moderne est recommandée, à la fois pour la souplesse des arguments et parce que le code de fin peut les voir.