Comment gérer les espaces dans les commandes ?#

Il est très facile d’écrire des commandes qui produisent dans les documents des espaces là où ils ne sont ni souhaités ni attendus. Les espaces introduits par les commandes sont particulièrement insidieux dans la mesure où ils ne s’amalgament pas avec les espaces autour de la commande (contrairement aux espaces consécutifs que vous tapez), de sorte que votre document final peut comporter un seul espace assez large s’avérant être composé de plusieurs espaces non amalgamés. Et bien sûr, votre résultat peut aussi comporter un espace là où il n’y en avait pas du tout.

Les espaces sont produits, à l’intérieur d’une commande comme ailleurs, par des caractères d’espacement ou de tabulation, comme par des caractères de fin de ligne. Il y a deux règles de base à retenir lors de l’écriture d’une commande :

  • les règles d’ignorance des espaces lorsque vous tapez des commandes sont les mêmes que celles qui s’appliquent lorsque vous tapez du texte ordinaire ;

  • les règles d’ignorance des espaces ne s’appliquent pas aux espaces produits pendant qu’une commande est traitée.

Les espaces sont ignorés en mode vertical (entre les paragraphes), en début de ligne et après un nom de commande. Comme les séquences d’espaces sont fusionnées en une seule, on a l’impression que les espaces sont ignorés s’ils suivent un autre espace. L’espace peut aussi avoir une signification syntaxique après certains types d’arguments non encadrés (par exemple, les assignations de variables count et dimen dans Plain et après certaines commandes (par exemple, dans \hbox to). À nouveau, cela peut donner l’impression que ces espaces particuliers sont ignorés.

Considérons la commande suivante, assez fidèlement adaptée d’une macro apparue sur comp.text.tex :

\newcommand{\stline}[1]{ \bigskip \makebox[2cm]{ \textbf{#1} } }

La définition de la commande contient cinq espaces :

  • après le { d’ouverture du corps de la commande : cet espace sera ignoré, non pas parce que « la commande apparaît au début d’une ligne », mais plutôt parce que la commande a été conçue pour fonctionner entre les paragraphes ;

  • après \bigskip : cet espace sera ignoré (pendant que la commande est en cours de définition) parce qu’il suit un nom de commande ;

  • après le { de l’argument obligatoire de \makebox : même si cet espace apparaîtra inévitablement au début d’une ligne de sortie, il ne sera pas ignoré ;

  • après le } fermant l’argument de \textbf : cet espace ne sera pas ignoré, mais peut être négligé si l’argument est bien en deçà des 2cm qui lui sont alloués ;

  • après le } fermant l’argument obligatoire de \makebox : cet espace ne sera pas ignoré.

L’auteur original de la commande s’était inquiété du fait que le début des lignes contenant cette commande n’était pas dans la marge de gauche et que le texte apparaissant après la commande n’était pas toujours correctement aligné. Ces problèmes provenaient de l’espace au début de l’argument obligatoire de \makebox et de l’espace immédiatement après ce même argument. Il avait écrit sa commande de cette façon pour souligner la signification de ses différentes parties ; malheureusement, la signification était se perdait dans les problèmes que la commande causait.

La principale technique pour supprimer les espaces est l’utilisation des caractères % : tout ce qui suit un % est ignoré, même la fin de ligne elle-même (de sorte que même la fin de ligne ne peut pas contribuer à un espace non désiré). La seconde technique consiste à s’assurer que la fin de ligne est précédée d’un nom de commande (puisque la fin de ligne se comporte comme un espace, elle sera ignorée après un nom de commande). Ainsi, la commande ci-dessus serait écrite (par un programmeur expérimenté soucieux de mettre l’accent sur la structure) :

\newcommand{\stline}[1]{%
  \bigskip
  \makebox[2cm]{%
    \textbf{#1}\relax
  }%
}

On a veillé à ce que chaque espace dans la définition révisée soit ignoré, de sorte qu’aucun n’apparaît dans la sortie. La définition révisée adopte l’approche « ceinture et bretelles », en traitant explicitement chaque fin de ligne (bien que, comme indiqué ci-dessus, un espace introduit à la fin de la première ligne de la macro aurait été ignoré dans l’utilisation réelle de la commande). C’est la meilleure manière de procéder, en fait : il est plus facile de supprimer aveuglément les espaces que d’analyser à chaque point si vous avez réellement besoin de le faire. Trois techniques ont été utilisées pour supprimer les espaces :

  • placer un caractère % à la fin d’une ligne (comme dans les lignes 1, 3 et 5) ;

  • terminer une ligne « naturellement » par une séquence de contrôle, comme à la ligne 2,

  • terminer une ligne par une séquence de contrôle « artificielle », comme à la ligne 4 ; la séquence de contrôle dans ce cas (\relax) est incontournable dans de nombreuses circonstances (comme ici), mais cet usage est déconseillé et un caractère % aurait été préférable.

Attention à la tentation (courante) de placer une espace avant un caractère % : si vous faites cela, vous pourriez tout aussi bien omettre le %.

Dans la « vraie vie », bien sûr, les espaces qui apparaissent dans les commandes sont bien plus énigmatiques que ceux de l’exemple ci-dessus. Les espaces les plus courants proviennent des fins de ligne non protégées, erreur qui apparaît occasionnellement même dans les commandes écrites par les programmeurs les plus accomplis.