Dès que vous voulez une commande avec plusieurs arguments optionnels ou une vraie variante étoilée, compter les arguments à la manière de \newcommand ne suffit plus. La réponse moderne est \NewDocumentCommand, qui déclare le *type* de chaque argument par une chaîne de lettres. Né dans le package xparse, il fait aujourd’hui partie du noyau LaTeX. Cette page couvre la mini-langue de spécification des arguments et les commandes de test qui inspectent ce que l’utilisateur a fourni.
Désormais dans le noyau
Autrefois, \usepackage{xparse} était nécessaire ; depuis la version LaTeX d’octobre 2020, ce mécanisme vit dans le noyau lui-même. Des commandes comme \NewDocumentCommand sont disponibles d’emblée, et charger xparse est rarement utile. Le fichier du noyau qui les implémente s’appelle ltcmd, et le package xparse est officiellement qualifié d’« obsolete ». À part quelques types d’arguments obsolètes, le nouveau code peut utiliser ces commandes sans rien charger.
L’idée de cette interface est de séparer le sens, donc l’interface, de l’implémentation. On déclare la suite d’arguments visible par l’utilisateur — obligatoires, optionnels, étoilés — comme une spécification d’arguments (arg-spec), puis le corps reçoit toujours des arguments normalisés sous la forme #1, #2, etc. Les bases de \newcommand sont sur la page « Définir des macros » ; les connaître rend le contraste plus clair.
Définir commandes et environnements
La forme de base est \NewDocumentCommand{\cmd}{⟨arg-spec⟩}{⟨code⟩} : nom de commande, spécification d’arguments, corps. Comme \newcommand, elle possède des variantes selon le but ; ce qui change est leur comportement face à un nom déjà défini.
| Commande | Face à un nom existant |
|---|---|
\NewDocumentCommand | Erreur si déjà défini |
\RenewDocumentCommand | Erreur si pas encore défini (le retravaille) |
\ProvideDocumentCommand | Définit seulement si absent |
\DeclareDocumentCommand | Écrase toujours (à utiliser avec retenue) |
Les environnements ont le même traitement avec \NewDocumentEnvironment{⟨env⟩}{⟨arg-spec⟩}{⟨start code⟩}{⟨end code⟩} (et \Renew…, \Provide…, \Declare…). Les arguments sont donnés après \begin{⟨env⟩} et visibles dans le code de début comme dans celui de fin ; voir la page sur les environnements personnalisés. Bonus : toute commande créée ainsi est automatiquement robuste (via le mécanisme \protected d’e-TeX), donc pas besoin de \protect dans un titre ou une légende.
Il existe aussi une variante expansible, \NewExpandableDocumentCommand. Elle s’utilise dans des contextes où la commande est développée, par exemple dans \edef ou \write, mais les types d’arguments autorisés sont restreints : les tests booléens comme s/t et le verbatim v ne sont pas disponibles. Pour un document ordinaire, la forme standard est celle à choisir.
Langage de spécification des arguments
Une spécification d’arguments est une chaîne où chaque lettre nomme le type d’un argument : obligatoire, optionnel, étoilé, délimité par certains caractères, etc. Chaque type arrive dans le corps comme #1, #2, etc., mais le point subtil est qu’un argument optionnel non fourni reçoit une valeur spéciale. Les principaux types sont résumés ci-dessous.
| Type | Écriture | Sens | Arrivée dans le corps |
|---|---|---|---|
m | m | Argument obligatoire {} | Un #1 ordinaire |
o | o | Argument optionnel [...] | -NoValue- si absent |
O | O{default} | Optionnel avec valeur par défaut | default si absent |
s | s | Étoile optionnelle * | \BooleanTrue / \BooleanFalse |
t | t⟨char⟩ | Token caractère optionnel donné | \BooleanTrue / \BooleanFalse |
r | r⟨d1⟩⟨d2⟩ | Obligatoire, délimité par d1…d2 | -NoValue- après erreur si absent |
d | d⟨d1⟩⟨d2⟩ | Optionnel, délimité par d1…d2 | -NoValue- si absent |
e | e{⟨tokens⟩} | Embellissements, par ex. ^, _ | Chacun -NoValue- si absent |
v | v | Argument verbatim | Les caractères littéraux |
m est l’argument obligatoire de base : il accepte un groupe entre accolades ou un token unique, et les {} extérieures sont retirées avant que le corps ne le voie. o est l’argument optionnel [...] standard, et O{default} le même avec valeur par défaut. Les types majuscules comme O et D permettent de donner une valeur par défaut, tandis que leurs versions minuscules o/d renvoient le marqueur spécial -NoValue-.
s détecte une étoile * en tête : présente, elle donne \BooleanTrue, absente, \BooleanFalse. La généralisation à un caractère unique est t⟨char⟩ ; t+, par exemple, signale la présence de + comme booléen. r⟨d1⟩⟨d2⟩ est un argument délimité obligatoire, entouré de délimiteurs choisis, par exemple r() pour des parenthèses ; si le délimiteur ouvrant manque, il émet une erreur et insère -NoValue-. La version optionnelle délimitée est d⟨d1⟩⟨d2⟩.
Plus particulier, e{⟨tokens⟩} rassemble des embellissements comme ^ et _. Avec e{^_}, il récupère ^{...} et _{...} dans n’importe quel ordre, et ceux qui manquent deviennent -NoValue- ; les tokens listés doivent être distincts. v lit un argument verbatim, comme \verb. Les délimiteurs des types délimités (r, d, …) ne peuvent pas être les caractères de groupement TeX { et } ; on choisit donc des paires naturelles comme [], () ou "".
Inspecter les arguments : les tests
Pour gérer un argument optionnel ou une étoile, il faut tester dans le corps s’il a été fourni. Deux familles de commandes le font. \IfNoValueTF{#1}{⟨if no value⟩}{⟨if value⟩} vérifie si l’argument vaut -NoValue-, c’est-à-dire s’il est absent : absent, il exécute la première branche ; présent, la seconde. L’inverse \IfValueTF existe aussi, ainsi que les formes à une seule branche (\IfNoValueT / \IfNoValueF, \IfValueT / \IfValueF).
Pour le booléen produit par s ou t, utilisez \IfBooleanTF{#1}{⟨if starred⟩}{⟨if not⟩} : si #1 vaut \BooleanTrue, la première branche s’exécute ; avec \BooleanFalse, la seconde. Les formes \IfBooleanT / \IfBooleanF existent aussi. Règle pratique : \IfNoValueTF et proches servent aux arguments optionnels comme o/d; \IfBooleanTF et proches aux booléens s/t. Enfin, -NoValue- est conçu pour ne pas correspondre au texte littéral -NoValue- ; testez-le toujours avec \IfNoValueTF plutôt qu’en comparant des chaînes.
Exemple : étoile plus option avec défaut
Construisons une commande avec variante étoilée et argument optionnel à valeur par défaut, grâce à la spécification s O{} m. L’exemple est une commande de titre : #1 est l’étoile, testée par \IfBooleanTF; #2 le titre court optionnel, vide par défaut ; #3 le titre principal.
\NewDocumentCommand{\heading}{s O{} m}{%
\IfBooleanTF{#1}%
{\textbf{#3}}% 星つき: 番号なしの見出し / starred: unnumbered
{\section%
\IfNoValueTF{#2}%
{{#3}}% 短縮見出しなし / no short title
{[#2]{#3}}% 短縮見出しあり / with short title
}%
}
% 使用例 / usage
\heading{Introduction} % 通常の番号つき節
\heading[Intro]{A Long Introduction} % 目次用に短縮見出しを指定
\heading*{Preface} % 星つき: 太字の無番号見出しSubtilité : ne confondez pas o et O{}. Avec o, un argument absent devient -NoValue-, donc on branche avec \IfNoValueTF comme ci-dessus. Avec O{}, au contraire, une valeur est toujours présente, vide si omise ; on teste alors le contenu vide, avec \tl_if_blank:nTF (expl3) ou \ifblank (etoolbox), pas avec \IfNoValueTF. Dans l’exemple, il faudrait donc un argument optionnel o sans valeur par défaut pour que la branche \IfNoValueTF ait le comportement voulu.
Pourquoi c’est mieux que \newcommand
\newcommand n’autorise qu’un seul argument optionnel, le premier, et ne fournit pas de variante étoilée intégrée. Le contournement classique consistait à écrire à la main des mécanismes bas niveau comme \@ifstar et \@ifnextchar, mais ils exigent \makeatletter, sont fragiles face aux espaces et aux imbrications, et peu lisibles.
- Plusieurs arguments optionnels indépendants (
o o m,O{a} O{b} m, …). - Vraies variantes étoilées avec
splus\IfBooleanTF, sans bricolage\@ifstar. - Valeurs par défaut déclaratives :
O{default}suffit à fixer la valeur quand elle est omise. - Robuste dès le départ : pas de
\protectdans les titres ou légendes. - Des syntaxes d’entrée que
\newcommandne peut pas exprimer : arguments délimités (r,d) et embellissements (e).
En résumé, une simple abréviation convient très bien à \newcommand, mais dès que la structure des arguments devient un peu élaborée, \NewDocumentCommand est le premier choix. Quand le corps doit ensuite devenir un petit programme, l’associer à expl3, la couche de programmation LaTeX3, est l’étape naturelle. Pour créer classes et packages, voir la page d’auteur.