Le problème de départ est relativement simple: imaginons deux packages qui définissent la même commande, \internal@macro. Bien entendu, les deux auteurs des deux packages ne se sont pas concertés, ne se connaissent pas, et s'ignorent d'autant plus que personne avant toi n'a essayé de faire marcher les deux package en même temps.
Cela peut mener a une variété intéressante de résultats possibles, parmi lesquels:
- Les deux packages définissent la macro en question avec \newcommand, dans ce cas là, on récupère un message d'erreur lors du chargement du second package (c'est probablement le cas le plus favorable).
- Le premier package (dans l'ordre de chargement) utilise \def et le second \newcommand. Ça donne le même résultat: message d'erreur lors du chargement du second package.
- Le second package utilise \def (indépendament de ce que fait le premier). Le chargement des packages se passe bien (sans erreur). L'utilisation du deuxième se passe bien (il fait ce à quoi on s'attends). Par contre, l'utilisation du premier donne des erreurs, et/ou des résultats inattendus, et/ou innexpliqués.
On pourrait modifier l'un des deux packages pour changer le nom de la macro incriminée, mais ce n'est pas très satisfaisant. En effet, le document compilera, mais il faudra refaire la modification à chaque mise à jour de LaTeX, et le document ne pourra être envoyé à personne. Trop compliqué. Et pas terrible.
La solution que je propose est un poil plus intéressante. On procède par étape: d'abord, on charge le premier package, puis on sauve la définition de la macro incriminée, puis on supprime cette définition, puis on charge le deuxième package, puis on sauve sa définition de la macro, puis on supprime cette définition. Ensuite, dans le document, selon le package auquel on souhaite faite appel à un instant donné, on rappel l'une ou l'autre macro.
Ça donnerait un truc dans ce genre là:
\usepackage{un} \let\internal@macro@un\internal@macro \let\internal@macro\undefined \usepackage{deux} \let\internal@macro@deux\internal@macro \let\internal@macro\undefined ... \let\internal@macro\internal@macro@un \begin{un} Ici on utilise l'environnement un définit par le package un. \end{un} ... \let\internal@macro\internal@macro@deux \begin{deux} Ici on utilise l'environnement deux définit par le package deux. \end{deux}
Jusque là, ça marche. Mais c'est un peu lourd. Par exemple, si les deux packages en question ont 12 macros en commun, c'est vite pénible de basculer de l'un à l'autre, et il faut se souvenir de toutes les macros à changer.
Ce que fait contextsw c'est tout simplement ce que je viens de décrire là, mais de manière automatique. Ce qui donnera par exemple:
\usepackage{contextsw} \newcontext{un} \newcontext{deux} \usepackage{un} \repeatesavecmd{un}{internal@macro,une@autre} \usepackage{deux} \repeatesavecmd{deux}{internal@macro,une@autre} ... \forcontext{un} \begin{un} Ici on utilise l'environnement un définit par le package un. \end{un} ... \forcontext{deux} \begin{deux} Ici on utilise l'environnement deux définit par le package deux. \end{deux}
Le package sait aussi gérer des définitions conflictuelles de caractères (actifs ou pas). Par exemple, un package qui veut absolument que tel caractère soit actif, alors qu'un autre est radicalement contre cette idée. On sait faire. De même, deux packages souhaitent rendre actif un caractère, mais ne souhaitent pas lui donner la même signification (que ce soit en mode texte ou en mode maths). On sait faire aussi.
- Tout dans un tar.gz ici
- Tout dans un zip, un autre jour, j'ai pas de zip
- Le fichier source principal contextsw.dtx
- Le fichier de génération (le type MIME est mauvais, apache croit que c'est un fichier x-internet-signup, mais ça n'empêche pas de le télécharger) contextsw.ins
Les rapports de bug sont à envoyer à mon adresse mail (ci-dessous) et seront traités... quand j'aurais le temps. Merci de mettre la balise [bug] dans le sujet du mail.