# Son package

# Écrire son propre package

## Pourquoi ?

Définir son propre package permet :

- de ne pas avoir à toujours insérer toujours les mêmes lignes :

      \usepackage[francais]{babel}
      \usepackage[latin1]{inputenc}
      \usepackage[T1]{fontenc}
      \usepackage[dvips]{graphicx}
      \usepackage{amsmath}
      \usepackage{amssymb}

- de ne pas avoir à redéfinir toutes ses macros et aussi de gagner du temps à force de s'habituer à ses commandes persos ;
- d'avoir des documents cohérents entre eux.

## Principe

Nous allons créer un fichier « `mon_package.sty` » (ou tout autre nom qui ne crée de doublon) qui comportera les instructions qui permettront :

- de charger nos extensions préférées ;
- de définir nos commandes préférées ;
- de passer des options lors du chargement du package qui lui donneront un comportement particulier.

## Organisation

### Listing

    %% Informations générales
    \NeedsTeXFormat{LaTeX2e}[1999/01/01]
    \ProvidesPackage{mon_package}[2003/01/01]

    %% Chargement des extensions
    \RequirePackage[dvips]{graphicx}

    %% Déclaration des options
    \DeclareOption{option}{...}
    \DeclareOption*{...}
    \ProcessOptions

    %% Définition des commandes
    \newcommand{\blabla}{Super commande}

    %% Fin du package
    \endinput

### Explications

- `\NeedsTeXFormat{<formar>}[<version>]` : informe TeX du format (LaTeX2e, donc refus de LaTeX2.09, plain TeX, eplain TeX, AMS-TeX, etc.) nécessaire pour l'utilisation du package, on peut spécifier un argument optionnel (entre crochets) permettant d'utiliser des versions récentes dudit format ;
- `\ProvidesPackage{<package>}[<version>]` : le package s'identifie (là encore on peut donner en argument optionnel une date de version) ;
- `\RequirePackage[<options>]{<package>}` : équivalent de `\usepackage` pour l'écriture d'un package ou d'une classe, on peut passer des options au package comme habituellement ;
- `\DeclareOption{<option>}{<action>}` : déclare une option qui peut être passée lors de l'appel du package, lorsque l'option `<option>` est passée `<action>` est exécutée ;
- `\DeclareOption*{<action>}` : comportement adopté par le package quand il est confronté à une option passée qui n'est pas déclarée ;
- `\ProcessOptions` : exécute le code des options passées, si cette commande n'existe pas dans le package les options seront sans effet (bien prendre conscience que les declarations n'exécutent pas de code!) ;
- `\newcommand{\commande}{<code>}` : définition d'une nouvelle commande (voir la page sur les macros) ;
- `\endinput` : fin du package.

## Exemple simple

Supposons qu'il m'arrive d'écrire des documents sans algorithmes et d'autres avec. Lorsque j'en ai besoin je charge les packages `algorithm` et `algorithmic` qui permettent de mettre en forme des algorithmes, d'en faire une « liste des algorithmes » et de les rendre flottants (voir la page...). Je peux encore utiliser mon propre package pour gérer ces cas, il suffit d'introduire une option « algo » quand on a besoin des fonctionnalités idoines. Voilà comment :

    %% (...) \NeedsTeXFormat et \ProvidesPackage
    \newif\if@algo \@algofalse
    \DeclareOption{algo}{\@algotrue}
    \DeclareOption*{}%% Ne rien faire quand une option est inconnue
    \ProcessOptions

    \if@algo
      \RequirePackage{algorithm}
      \RequirePackage{algorithmic}
      \RequirePackage{mes-commandes-algo}
      \newcommand{\algorithme}{Blabla}
    \fi
    %% (...) \newcommand's et \endinput

La commande `\newif\ifquelquechose` crée trois commandes :

- `\ifquelquechose` à utiliser ainsi (la partie « else » est facultative)

      \ifquelquechose
        Code si oui
      \else
        Code si non
      \fi

- `\quelquechosetrue` `\ifquelquechose` devient équivalent à if true ;
- `\quelquechosefalse` `\ifquelquechose` devient équivalent à if false.

Dans notre exemple on crée une instruction conditionnelle `\if@algo` qui est équivalente à if false (à cause de `\@algofalse`). Cependant, si l'option « algo » est passée au package, on exécute `\@algotrue` qui a pour effet de rendre `\if@algo` équivalent à if true. Les packages relatifs à l'algo (et les commandes définies dans le bloc) seront chargés si et seulement si l'option « algo » aura été passée dans le fichier `.tex` :

- soit au niveau du `\usepackage`

      \documentclass[a4paper, dvips]{article}
      \usepackage[algo]{mon_package}
      \begin{document}
       .
       .
       .
      \end{document}

- soit au niveau du `\documentclass`

      \documentclass[a4paper, dvips, algo]{article}
      \usepackage{mon_package}
      \begin{document}
       .
       .
       .
      \end{document}

Remarque : notons que dans les packages « @ » est une lettre (contrairement aux document `.tex` où « @ » est un symbole) et que donc on peut écrire des noms de commandes avec « @ ». D'où les noms `\makeatletter` et `\makeatother` utilisées dans des cas un peu exceptionnels. Dans un fichier `.tex`, « `\if@algo` » aurait été interprétée comme la commande `\if` suivie de « @algo ».

## Exemple moins simple, plus réaliste

### Listing

    \NeedsTeXFormat{LaTeX2e}[1999/01/01]
    \ProvidesPackage{mon_package}[2003/01/01]

    \newif\if@algo     \@algofalse
    \newif\if@listings \@listingsfalse

    \DeclareOption{listings}{\@listingstrue}
    \DeclareOption{algo}{\@algotrue}
    \DeclareOption*{\PassOptionsToPackage{\CurrentOption}{babel}}
    \ProcessOptions

    \RequirePackage{babel}

    \if@algo
      \RequirePackage{algorithm}
      \RequirePackage{algorithmic}
      \RequirePackage{mes-commandes-algo}
    \fi

    \if@listings
      \RequirePackage{listings}
      \RequirePackage{verbatim}
      \RequirePackage{moreverb}
      \RequirePackage{mes-commandes-listings}
    \fi

    \endinput

### Explications

On déclare comme précédemment deux options « normales » : `algo` et `listings` mais quand on est face à une option inconnue on la passe à babel, ainsi :

    \documentclass[a4paper]{article}
    \usepackage[algo, listings, english, greek, francais]{mon_package}
    \begin{document}
     .
     .
     .
    \end{document}

sera équivalent à charger les modules d'algorithmiques, les modules de d'écriture de programmes, et babel avec les options `english`, `greek` et `francais` (dans cet ordre). La commande `\PassOptionsToPackage{<options>}{<package>}` ne charge pas le package `<package>`, elle rajoute les `<options>` à la liste d'options qui seront passées au package `<package>` lors de l'appel `\RequirePackage{<package>}`.

Remarque : les options déclarées avec `\DeclareOption{...}{...}` peuvent être passées comme options globales du document comme dans :

    \documentclass[a4paper, algo, listings]{article}
    \usepackage[english, greek, francais]{mon_package}
    \begin{document}
     .
     .
     .
    \end{document}

En revanche les langages doivent être passés au package lui-même (notamment babel n'a pas tenté de trouver un langage nommé « a4paper » ce qui aurait abouti à une erreur).

### Limitations

D'une part on ne peut pas utiliser ce mécanisme pour plusieurs packages auquel on passerait les options non déclarées avec `\DeclareOption{...}{...}` et d'autre part on ne peut pas s'abstenir de passer au moins une option de langage au package.

## Exemple (très) compliqué

### Prérequis

- Avoir lu la doc du package `keyval` de David Carliste (ou peut-être prochainement une page tuteurs à ce sujet) ;
- `\@ifundefined{commande}{<then>}{<else>}` : si `\commande` (avec le backslash contrairement à l'argument de `\@ifundefined`) n'est pas définie alors exécute `<then>` sinon exécute `<else>` (LaTeX interne) ;
- `\PackageWarning{<package>}{<texte>}` : produit un warning lors de la compilation (par opposition à `\PackageError{...}{...}`) ;
- `\CurrentOption` : l'option en cours de traitement ;
- le reste c'est du TeX, donc il ne vaut mieux pas s'attarder dessus.

### Listing général

    \NeedsTeXFormat{LaTeX2e}[1999/01/01]
    \ProvidesPackage{mon_package}[2003/01/01]
    \RequirePackage{keyval}

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Pour gérer les deux types d'options :                                  %
    %  1. les options normales (\DeclareOption{...}{...})                    %
    %  2. les options type key-val option=value (\define@key{...}{...}{...}) %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \@ifundefined{my@unusedlist}{%
      \let\my@unusedlist\@empty}{}
    \@ifundefined{my@extractkey}{%
      \def\my@extractkey#1=#2\my@extractkey{#1}}{}
    \newcommand{\ProcessUnusedOptions}[1]{%
      \let\my@tempa\@empty
      \let\my@tempb\@empty
      \@for\CurrentOption:=\my@unusedlist\do{%
        \expandafter\expandafter\expandafter\def
        \expandafter\expandafter\expandafter\my@key
        \expandafter\expandafter\expandafter{%
          \expandafter\my@extractkey\CurrentOption=\my@extractkey}%
        \@ifundefined{KV@#1@\my@key}{%
          \edef\my@tempa{\my@tempa,\CurrentOption,}}{%
          \edef\my@tempb{\my@tempb,\CurrentOption,}}}%
      \@for\CurrentOption:=\my@tempa\do{%
        \ifx\CurrentOption\@empty\else
          \PackageWarning{mypack}{`\CurrentOption' not defined.}\fi}%
      \edef\my@tempb{%
        \noexpand\setkeys{#1}{\my@tempb}}%
      \my@tempb
      \AtEndOfPackage{\let\@unprocessedoptions\relax}}

    \DeclareOption*{%
      \expandafter\expandafter\expandafter\def
      \expandafter\expandafter\expandafter\my@unusedlist
      \expandafter\expandafter\expandafter{%
        \expandafter\my@unusedlist\expandafter,%
        \CurrentOption}}
    %%%%%%%%%%%%%%%
    % Fin du bloc %
    %%%%%%%%%%%%%%%

    %% Options «normales»
    \DeclareOption{foo}{<action foo>}
    \DeclareOption{bar}{<action bar>}

    %% Options passées sous forme key=val
    \define@key{mypack}{<key1>}{<action 1> dépendant de #1}
    \define@key{mypack}{<key2>}[<default>]{<action 2> dépendant de #1}

    \ProcessOptions
    \ProcessUnusedOptions{mypack}

    \endinput

### Explications

Dans l'exemple suivant

    \documentclass[foo]{article}
    \usepackage[foo, key1=value1, key2=value2]{mypack}
    \begin{document}
     .
     .
     .
    \end{document}

l'option `foo` va agir comme dans les exemples simples, `key1=value1` va exécuter le code `<action 1>` en utilisant `value1` en lieu et place de `#1`. Idem pour `key2=value2` sauf que on peut omettre la partie « `=value2` » auquel cas `<action 2>` est exécuté en utilisant `<default>` à la place de `#1`. Par exemple si `mon_package.sty` contient :

    %% (...)
    \newcounter{nombre}
    \define@key{mypack}{number}[14]{%
      \setcounter{nombre}{#1}}
    %% (...)

on pourra l'appeler ainsi

    \documentclass[foo]{article}
    \usepackage[number=10]{mypack}
    \begin{document}
     .
    \thenombre\ affiche 10.
     .
     .
    \end{document}

ou encore comme cela

    \documentclass[foo]{article}
    \usepackage[number]{mypack}
    \begin{document}
     .
    \thenombre\ affiche 14.
     .
     .
    \end{document}

ou bien sûr sans option du tout (auquel cas le code `\setcounter` ne sera pas exécuté et donc le compteur `nombre` vaudra zéro).

### Exemple d'application

Si `mon_package` contient :

    \newcommand{\pack@languages}{francais}
    \define@key{mypack}{language}{%
      \renewcommand{\pack@languages}{#1}}
    \RequirePackage[\pack@languages]{babel}

alors on peut l'appeler ainsi

    \documentclass[a4paper]{article}
    \usepackage[language={english, francais}]{mon_package}
    \newcommand{\option}{\texttt}
    \begin{document}
     .
    \paragraph{Remarque}
    Noter les accolades pour que l'option \option{francais} ne soit pas
    passée comme une option à part.
     .
     .
    \end{document}

ou encore ainsi :

    \documentclass[a4paper]{article}
    \usepackage{mon_package}
    \newcommand{\option}{\texttt}
    \begin{document}
     .
    Babel chargé avec l'option \option{francais}.
     .
     .
    \end{document}

Là encore les options de langages ne pourront pas être spécifiées globalement avec la commande `\documentclass`. (La raison en est que les options globales qui ne correspondent pas à des options déclarées avec `\DeclareOption` ne sont pas transmises à `\DeclareOption*`.)

## Utiliser son package

Le package `mon_package` doit pouvoir être trouvé par LaTeX, pour cela on peut :

- mettre le fichier `mon_package` dans le même répertoire que les fichier `.tex` qui l'utilisent ;
- mettre le fichier dans un répertoire de son compte (par exemple `~/texmf/tex/latex/perso/` et créer la variable d'environnement `export TEXINPUTS=$HOME/texmf//:` (certaines distributions permettent de créer un fichier ls-R grâce à la commande `texhash`) ;
- si l'on est root sur sa machine on peut le mettre dans l'arborescence texmf classique (mais ça ne facilite pas des upgrades des distributions LaTeX) et exécuter la commande `mktexlsr`.

## Documentation et aide

Pour une documentation concernant l'écriture de classe et de packages : `clsguide` (à noter également les documentations `fntguide`, `usrguide`) pour une documentation générale sur LaTeX : `source2e` ou plus soft The not so short introduction to LaTeX (disponible en français !).

Sur internet : CTAN, les newsgroup `fr.comp.text.tex` et `comp.text.tex` sur lesquels on peut faire une recherche via Google. Par exemple comment réaliser le symbole « 1 » avec une double barre pour désigner une fonction indicatrice ? La réponse se trouve sur Google, groupes et taper « `group:fr.comp.text.tex 1 barre indicatrice` ». C'est une source d'informations inépuisable. Sinon les tuteurs ou forum `ens.forum.informatique.tex`.

Auteur : Josselin Noirel (16/03/2003)