Dès que vous écrivez du code non trivial dans un package ou un préambule, vous avez besoin de choses que TeX brut rend pénibles : indicateurs booléens, tests « cette commande est-elle définie ? », tests « cette chaîne est-elle vide ? », et ajout de code à des commandes existantes. etoolbox fournit ces outils dans un style proche de LaTeX, tandis que pgfkeys sert de base aux interfaces de configuration key=value. Les deux sont des classiques en coulisse dans de nombreux packages.
Ce qu’est etoolbox
etoolbox (écrit par Philipp Lehman, maintenu aujourd’hui par Joseph Wright) est une boîte à outils de programmation pour auteurs de classes et de packages. Il enveloppe les primitives bas niveau ajoutées par e-TeX dans une interface de style LaTeX, et ajoute aussi divers outils généraux pratiques qui ne dépendent pas directement d’e-TeX. Comme tous les moteurs TeX modernes incluent e-TeX, il suffit d’écrire \usepackage{etoolbox}.
Même depuis la généralisation d’expl3, la couche de programmation LaTeX3, etoolbox reste populaire parce qu’il s’intègre directement au monde LaTeX2e. Des arguments que l’on écrit naturellement comme #1, la forme familière {vrai}{faux}, et surtout \patchcmd (ci-dessous) pour retoucher après coup les commandes d’un autre package, le rendent précieux dans les vrais préambules.
Indicateurs booléens : toggles et bools
Pour conserver un état vrai/faux comme « sommes-nous en mode brouillon ? », etoolbox propose deux familles. La recommandée est le toggle : il a son propre espace de noms et ne collisionne pas avec des commandes existantes. On le déclare avec \newtoggle{flag}, on le change avec \toggletrue{flag} / \togglefalse{flag} ou \settoggle{flag}{true}, et on branche avec \iftoggle{flag}{⟨true code⟩}{⟨false code⟩}. L’inverse se teste avec \nottoggle{flag}{⟨if not true⟩}{⟨if not false⟩}.
\usepackage{etoolbox}
\newtoggle{draft} % フラグを宣言 / declare the flag
\toggletrue{draft} % 真にする / set it true
% 本文や命令の中で分岐 / branch on it
\iftoggle{draft}
{\textbf{[DRAFT]}\ } % 真のとき / when true
{} % 偽のとき / when falseL’autre famille est le bool : \newbool{flag} / \setbool{flag}{true} / \booltrue{flag} / \boolfalse{flag}, testé par \ifbool{flag}{⟨true⟩}{⟨false⟩}. En interne, un bool utilise le même mécanisme que \newif de LaTeX et réserve donc un nom de commande, \ifflag. Les toggles suffisent souvent ; les bools aident quand il faut interagir avec du code fondé sur \newif.
| Commande | Sens | Notes |
|---|---|---|
\newtoggle{f} | Déclare le toggle f (faux au départ) | Espace de noms propre |
\settoggle{f}{v} | Fixe f à v (true/false) | Ou \toggletrue / \togglefalse |
\iftoggle{f}{T}{F} | T si vrai, F si faux | Prend trois arguments |
\ifbool{f}{T}{F} | Version booléenne de la branche | Même mécanisme que \newif |
Tests de définition et de chaînes
Pour écrire un package prudemment, on veut souvent savoir si une commande est déjà définie ou si un argument est vide. Dans etoolbox, tous les tests utilisent la même branche {⟨true⟩}{⟨false⟩}. Pour une définition, utilisez \ifdef{\cmd}{⟨true⟩}{⟨false⟩} ; pour tester par nom (une chaîne), \ifcsdef{name}{⟨true⟩}{⟨false⟩}. Les inverses \ifundef / \ifcsundef existent aussi.
Attention : le nom proche \ifdefined est une primitive e-TeX, pas une commande etoolbox de forme {true}{false}. Pour une branche binaire, utilisez \ifdef de etoolbox en passant la commande réelle, antislash compris. Côté chaînes, on dispose de \ifblank{⟨string⟩}{⟨true⟩}{⟨false⟩} pour « seulement des espaces ? », de son inverse \notblank, de \ifstrequal{⟨string⟩}{⟨string⟩}{⟨true⟩}{⟨false⟩} pour l’égalité, et de \ifstrempty pour la chaîne vide.
% 命令が未定義のときだけ用意する / provide a command only if missing
\ifdef{\highlight}
{} % 既にあれば何もしない / leave it alone
{\newcommand{\highlight}[1]{\textbf{#1}}}
% 引数が空かどうかで出し分け / vary on an empty argument
\newcommand{\field}[1]{\ifblank{#1}{(none)}{#1}}Hooks et ajout à des commandes
etoolbox fournit aussi des commandes pour les hooks, des emplacements contenant du code à exécuter à un moment donné. \AtBeginDocument / \AtEndDocument appartiennent au noyau LaTeX ; etoolbox les complète par \AtEndPreamble à la fin du préambule, \AfterEndDocument tout à la fin, et des hooks autour d’un environnement précis : \AtBeginEnvironment{⟨env⟩}{⟨code⟩} / \AtEndEnvironment / \BeforeBeginEnvironment / \AfterEndEnvironment.
Pour ajouter après coup du contenu à ces hooks, ou à n’importe quelle macro, on utilise les commandes d’ajout. \appto{\cmd}{⟨code⟩} ajoute à la fin, \preto{\cmd}{⟨code⟩} au début (\gappto est global, \eappto développe d’abord). Pour ajouter de façon sûre à une macro avec arguments, utilisez \apptocmd{\cmd}{⟨code⟩}{⟨success⟩}{⟨failure⟩} / \pretocmd, avec branches de succès et d’échec.
% すべての itemize の冒頭に行間設定を差し込む
\AtBeginEnvironment{itemize}{\setlength{\itemsep}{2pt}}
% 文書開始時に走るフックへ追記 / append to the begin-document hook
\appto{\@begindocumenthook}{\typeout{Hello from etoolbox}}Retoucher des commandes avec \patchcmd
L’outil le plus célèbre de etoolbox est \patchcmd. Il remplace seulement une partie du corps d’une commande déjà définie : pratique pour ajuster une commande d’un autre package ou du noyau sans la redéfinir entièrement. Sa forme prend cinq arguments :
\patchcmd{\cmd}{⟨search⟩}{⟨replace⟩}{⟨success⟩}{⟨failure⟩}Il cherche dans la définition de \cmd la première occurrence correspondant à ⟨search⟩ ; si elle existe, il substitue ⟨replace⟩ et exécute ⟨success⟩, sinon il laisse la commande intacte et exécute ⟨failure⟩. Seule la première occurrence est remplacée. ⟨success⟩ / ⟨failure⟩ peuvent être vides, mais il est plus sûr de mettre un avertissement dans la branche d’échec pour repérer un patch qui ne s’applique plus.
Deux conseils pratiques. D’abord, la commande cible et ⟨search⟩ contiennent presque toujours @ parce qu’elles sont internes ; entourez donc le patch de \makeatletter … \makeatother, ou tenez compte du fait que \patchcmd rend temporairement @ lettre pendant son travail. Ensuite, quand un patch ne prend pas, placez \tracingpatches dans le préambule : le log affichera des diagnostics comme « non défini » ou « motif introuvable ». Pour les spécifications d’arguments ou plusieurs remplacements, le package xpatch, extension de etoolbox, est commode.
\usepackage{etoolbox}
\makeatletter
% 例:ある内部命令 \@foo の定義中の \small を \footnotesize に差し替える
\patchcmd{\@foo}
{\small} % 探す / search
{\footnotesize} % 置き換える / replace
{} % 成功時 / on success
{\PackageWarning{mypkg}{Patch to \protect\@foo\space failed}} % 失敗時
\makeatotherListes et boucles
etoolbox offre aussi des listes internes légères et des façons de les parcourir. Ajoutez un élément avec \listadd{\mylist}{⟨item⟩}, puis appelez un gestionnaire à un argument sur chaque élément avec \forlistloop{⟨handler⟩}{\mylist}. Pour parcourir directement une chaîne séparée par des virgules, \docsvlist{a,b,c} et \forcsvlist{⟨handler⟩}{a,b,c} sont les options rapides. \DeclareListParser permet aussi de créer un parseur avec son propre séparateur.
% カンマ区切りの各要素を箇条書きにする / each CSV item becomes a bullet
\newcommand{\asitem}[1]{\item #1}
\begin{itemize}
\forcsvlist{\asitem}{apples, pears, plums}
\end{itemize}pgfkeys : base des interfaces key=value
pgfkeys est le puissant moteur clé-valeur inclus dans PGF/TikZ. La syntaxe familière de TikZ [draw, thick, fill=blue], ainsi que beaucoup d’interfaces de type \…setup{...}, sont largement implémentées avec lui. Le centre est \pgfkeys{/my/key=value}. Les clés sont organisées en espaces de noms par chemins (families) séparés par /, et chaque clé reçoit un gestionnaire qui dit quoi faire lorsqu’elle est appelée.
Les gestionnaires qui définissent les clés sont le point crucial. Pour stocker la valeur telle quelle dans une macro, utilisez .store in=\macro (en interne \def\macro{value}). Pour exécuter du code avec la valeur, utilisez .code={... #1 ...} ; la valeur passée arrive sous la forme #1. La valeur utilisée lorsque la clé est appelée sans =value se donne par .default=value, et la valeur initiale par .initial=value. Il existe aussi .is choice pour énumérer des choix.
\usepackage{pgfkeys}
% キーを定義する / define keys under /book
\pgfkeys{
/book/title/.store in = \bookTitle, % 値をマクロに格納
/book/edition/.code = {Edition #1}, % #1 は渡された値
/book/edition/.default = 1, % =値 省略時の既定
/book/draft/.initial = false, % 初期値
}
% キーを設定する / set them
\pgfkeys{/book/title=TeX by Topic, /book/edition=3}Quand un package expose une entrée \mypkgsetup{...}, il fixe souvent un chemin par défaut pour éviter aux utilisateurs de préfixer chaque clé par /mypkg/. L’idiome est \pgfqkeys{/mypkg}{⟨key list⟩} (le « q » signifie quick), raccourci de \pgfkeys{/mypkg/.cd, ⟨key list⟩}. Avec un wrapper d’une ligne comme ci-dessous, les utilisateurs configurent avec des noms de clés courts.
% パッケージ側:設定窓口を一行で / the package: a one-line entry point
\newcommand{\mypkgsetup}[1]{\pgfqkeys{/mypkg}{#1}}
% 利用者側:短いキー名で設定 / the user: short key names
\mypkgsetup{title = My Report, edition = 2}Côté LaTeX3, l’équivalent est l3keys, le module clé-valeur d’expl3, qui déclare des interfaces semblables avec \keys_define:nn et apparentés. Une séparation raisonnable : l3keys pour un nouveau package écrit en expl3, pgfkeys pour s’aligner sur du code ou des ressources issus de TikZ/pgf.