Comment définir des arguments de forme « clé-valeur » ?#

Lorsque nous avons abordé la question « Comment dépasser la limite des 9 arguments pour une commande ? », nous avons suggéré qu’un grand nombre d’arguments, distingués uniquement par leur position, n’était pas très agréable pour l’utilisateur et qu’une extension telle que keyval offrait une interface utilisateur plus pratique permettant de faire des commandes comme celle-ci :

\instancefleur{espece=Primula veris,
  famille=Primulaceae,
  localisation=Coldham's Common,
  typeemplacement=Paturage,
  date=24/04/1995,
  nombre=50,
  typesol=alkaline
}

Nous examinons ici les extensions utilisables pour créer une telle interface utilisateur.

1.  Avec l’extension keyval#

L’extension la plus simple (pour du moins) pour obtenir des arguments « clé-valeur » reste keyval. Elle dispose :

  • d’une commande \define@key pour déclarer une clé et sa définition ;

  • d’une macro \setkeys pour donner des valeurs aux paramètres d’une ou plusieurs clés.

Ainsi :

\documentclass{article}
  \usepackage{lmodern}   % Caractères plus lisibles
  \pagestyle{empty}      % N'affiche pas de numéro de page
  \usepackage{keyval}

\makeatletter
\define@key{idee}{soitx}{soit $x$ = #1 }
\define@key{idee}{soity}[0]{soit $y$ = #1 }
\makeatother

\begin{document}
Voici nos conclusions : \setkeys{idee}{soitx=3,soity}.

Elles diffèrent de : \setkeys{idee}{soity = 1, soitx=2}

Et plus encore de : \setkeys{idee}{soitx=1}.
\end{document}

Ici, deux clés, soitx et soity, ont été définies pour la famille idee, et ont ensuite été exécutées avec la commande \setkeys :

  • au premier appel, on peut observer l’effet de l’argument par défaut de soity ;

  • au deuxième appel, on peut noter que l’ordre d’appel des clés est important ;

  • au dernier appel, on peut noter que seules les clés appelées sont exécutées.

En fait, les deux appels à define@key sont simplement des commandes de définition (quoique cette définition soit un peu plus élaborée pour \KV@idee@soity) :

\newcommand{\KV@idee@soitx}[1]{soit $x$ = #1}

La commande \setkeys sait comment trouver ces commandes quand elle doit traiter chaque clé. Pour cela, elle reconstitue le nom de la commande :

  • il commence toujours par KV@ avec keyval ;

  • il se poursuit avec le nom de la famille (idee, ici) suivi d’un autre @ ;

  • et il s’achève avec le nom de la clé souhaitée.

Ces commandes simples sont suffisantes, en fait, pour traiter l’exemple botanique proposé en début de cet article, ceci en remplacement des commandes à arguments multiples vues à la question « Comment dépasser la limite des 9 arguments pour une commande ? ». De même, ces commandes suffisent à gérer les arguments optionnels de la commande \includegraphics de l’extension graphicx (de fait, keyval a été conçu pour cet usage).

Cependant, l’extension s’avère trop limitée si nous voulons créer des options de extensions sous la forme de « clé-valeur ». Des extensions comme hyperref présentent des options d’extension extrêmement compliquées et nécessitent un traitement de ces clés lorsque la commande\ProcessOptions s’active : keyval ne peut pas faire cela tout seul.

1.1.  Pour aller un peu plus loin avec keyval#

L’extension kvoptions, de Heiko Oberdiek, nous vient ici en aide : elle permet au programmeur de déclarer des options de classe ou d’extension qui fonctionnent comme des paires clé/valeur. L’extension définit les commandes :

  • \DeclareBoolOption pour les options dont la valeur doit être soit true (vrai) soit false (faux) ;

  • \DeclareStringOption pour toutes les autres options qui ont une valeur.

Les clés sont déclarées à l’aide de keyval et peuvent rester disponibles pour être utilisées dans le document, ou peuvent être « annulées » pour éviter toute confusion. Si vous avez chargé kvoptions, l’option \DeclareOption de devient \DeclareVoidOption (c’est une option sans valeur), et \DeclareOption* devient \DeclareDefaultOption`.

Heiko fournit également l’extension kvsetkeys : elle propose une version plus robuste et plus pratique de la commande \setkeys.

2.  Avec l’extension xkeyval#

L’extension xkeyval, de Hendri Adriaens, offre plus de flexibilité et de robustesse que keyval. Comme kvoptions, l’extension propose aussi des mécanismes pour permettre des options de classe et d’extension sous forme « clé-valeur » (avec les commandes \DeclareOptionX, \ExecuteOptionsX et \ProcessOptionsX).

Les extensions de la famille pstricks utilisent un dérivé de xkeyval appelé pst-xkey pour leur propre système « clé-valeur ».

3.  Avec l’extension pgfkeys#

L’extension graphique tikz (ou pgf) possède sa propre extension dédiée au système « clé-valeur », appelée pgfkeys. La documentation de cette extension (incluse dans l’énorme manuel de tikz, en partie VII) contient une comparaison utile avec d’autres systèmes clé-valeur, ce qui permet entre autres de noter quelques différences notables :

  • les clés sont organisées en une structure arborescente, alors que keyval et xkeyval associent tous deux les clés à une famille ;

  • pgfkeys prend en charge les codes de clé à plusieurs arguments ;

  • et pgfkeys peut prendre en charge les fonctions de rappel (call-backs) lorsqu’une clé inconnue apparaît (ces éléments sont appelés des gestionnaires ou handlers).

Les clés sont organisées dans un arbre qui rappelle l’arbre des fichiers d’Unix. Une clé typique peut être /tikz/coordinate system/x ou simplement /x. Lorsque vous spécifiez des clés, vous pouvez fournir le chemin complet de la clé, mais, en général, vous ne fournissez que le nom de la clé et le « chemin » est ajouté automatiquement. Ainsi, une commande pgfkeys pourrait être :

À faire

Faire un exemple compilable.

\pgfkeys{/ma cle=salut,/votre cle/cle principale=une valeur,
  cle sans chemin= autre valeur}

Pour chaque clé mentionnée, le code associé sera exécuté, ce dernier étant également configuré à l’aide de \pgfkeys :

\pgfkeys{/ma clé/.code=La valeur est "#1".}

Après quoi

\pgfkeys{/ma cle=coucou !}

va juste produire

La valeur est "coucou !".

Le manuel continue en montrant comment définir une clé avec deux arguments, comment fournir une valeur par défaut pour une clé et comment définir des alias pour des séquences de clés particulières (appelées « styles »). Dans l’ensemble, il s’agit d’un système bien pensé, offrant une grande flexibilité qui n’est pas disponible avec les autres extensions traitant des paires « clé-valeur ». Cependant, il ne semble pas y avoir de mécanisme permettant d’utiliser les clés pgfkeys dans les options d’une autre extension, comme le fait kvoptions.

4.  Avec l’extension l3keys#

L’ensemble l3kernel pour inclut l’extension l3keys. Inspiré par pgfkeys, il fournit au programmeur une méthode pour créer des clés. Comme pour keyval et ses dérivés, l3keys utilise des commandes distinctes pour définir et paramétrer les clés. L’extension l3keys2e permet de traiter les options des classes et des extensions à l’aide de l3keys. Le code L3kernel peut être utilisé dans des documents existants, de sorte que l3keys est « directement » disponible pour le programmeur

5.  Avec l’extension scrbase#

Une autre extension de système « clé-valeur » appartenant à un ensemble plus large est scrbase : elle utilise les fonctionnalités de keyval pour construire une large gamme de commandes, à l’origine pour une utilisation dans l’ensemble KOMA-script.

L’extension s’appuie sur les commandes de keyval ou de xkeyval et possède une structure de la « famille de clés ». L’utilisateur peut définir les « membres » d’une famille et les clés sont définies par rapport aux membres. Par exemple, l’extension scrbase fait partie de l’ensemble KOMA-script. Ses clés sont donc toutes membres de la famille scrbase au sein de la famille KOMA. La commande \FamilyProcessOptions permet au programmeur de traiter les options d’extension en fonction de famille de clés de l’extension. Notez qu’il n’y a pas de traitement dédié pour les options d’extension traditionnelles, comme dans le paquetage kvoptions.

À faire

Revoir ce point, avec un éventuel exemple (car la source décrit une situation ancienne).

6.  Avec l’extension getoptk#

Toutes les extensions citées auparavant sont destinées à un usage avec Il existe également une extension pensée pour Plain , getoptk. Elle utilise une syntaxe inspirée de celle de primitives telles que \hrule et \hbox et nous permet l’exemple suivant, extrait du manuel de l’extension :

\begindisplay file {chapter1} literal offset 20pt