Fins de tabulation élastiques: la bonne manière d'indenter et d'aligner le code

Il y a des débats sans fin sur l’usage de tabulations ou d’espaces pour indenter et aligner son code. Chaque approche a ses avantages et des inconvénients, ses fidèles et ses ennemis.

(Indenter, c’est mettre de l’espace au début des lignes pour montrer visuellement les relations d’emboîtement logique des différentes de code. Aligner, c’est mettre de l’espace avant un morceau de texte, pas forcément en début de ligne, pour créer un lien visuel entre plusieurs morceaux sur des lignes voisines qui est logiquement lié.)

L’approche des "fins de tabulations élastiques" (elastic tabstops) est clairement la meilleure solution à ce problème — j’explique en quoi elle consiste ci-dessous, je vous laisse vous convaincre que c’est la solution ultime. Elle a un seul défaut : elle n’est pas utilisable en pratique parce qu’elle n’est pas disponible dans les éditeurs que nous utilisons. C’est un défaut qui ne peut se régler qu’en communicant à son sujet pour que plus de gens y pensent et l’adopte, pour créer un environnement où elle est utilisable.

Qui, Quand

Les tabulations élastiques ont été inventées en 2006 par Nick Gavgaard, et le document explicatif de référence (en anglais) est son site web, http://nickgravgaard.com/elastic-tabstops/.

Il y recense aussi des plugins pour quelques éditeurs de texte (il maintient un plugin pour Visual Studio), mais les éditeurs libres sont assez mal lotis (Nick Gavgaard a écrit un plugin Gedit, mais il n’est pas maintenu et plus compatible avec des changements d’API). Il y a par contre des bibliothèques de formatage de texte qui ont adopté ce concept, par exemple le paquet tabwriter de la bibliothèque standard Go.

Quoi

La "fin de tabulation", c’est l’endroit où un éditeur de texte va mettre le curseur après l’usage d’un caractère de tabulation.

La façon standard de calculer, c’est qu’il met le curseur à la colonne dont le numéro prochain multiple de N, la "largeur de tabs" choisie par l’utilisateur. Typiquement N=8, donc si on n’a rien écrit et qu’on appuie sur tab on se retrouve à la colonne 8, et si on écrit un mot de 4 lettres (donc on est en 12) et qu’on ré-appuie sur tab, on se retrouve à la colonne 16.

012345678901234567890123456789
\t      foo\t   bar
\t      foo2\t  baz
\t      long word\t     rest

Ça permet d’aligner facilement des fragments de texte… tant qu’ils font moins de 8 caractères. Mais dès qu’on dépasse 8 caractères, ou dès qu’on commence un peu trop près du prochain multiple de 8, c’est la galère. En pratique les gens s’entendent pour dire que si on veut utiliser des tabulations, il ne faut les utiliser qu’en début de la ligne (pour indenter), car en milieu de ligne c’est trop imprévisible, et aligner avec des espaces. Mais aligner, c’est joli et souvent utile, et avec des espaces c’est galère — sauf si notre éditeur a un mode spécial pour cela.

L’idée des "fins de tabulation élastique", c’est qu’au lieu de fixer pour chaque ligne la position des fins de tabulation, on les positionne en fonction des lignes adjacentes pour préserver l’alignement. Concrètement, si deux lignes sont adjacentes, on regarde combien de tabulation elles ont en commun (elles n’ont pas forcément le même nombre de tabulations), et on demande à ce que ces tabulations communes, comptées à partir du début de la ligne, soit alignées verticalement. Enfin, on demande une largeur minimale de blanc (choisie par l’éditeur ou l’afficheur de texte) pour chaque tabulation. Dans l’exemple précédent, si on demande une largeur minimale de 4 (par exemple), et qu’on écrit le texte ligne par ligne, on a d’abord

012345678901234567890123456789
\t  foo\t  bar

puis on ajoute la deuxième ligne; la deuxième tabulation finit un peu plus loin (pour respecter la largeur minimale), donc la deuxième tabulation de la première ligne se décale aussi

012345678901234567890123456789
\t  foo\t   bar
\t  foo2\t  baz

pareil, quand on ajoute la troisième, les fins de tabulations des deux premières lignes se décalent de façon élastique:

012345678901234567890123456789
\t  foo\t        bar
\t  foo2\t       baz
\t  long word\t  rest

Pour la même chose en plus clair et plus joli, Nick Gravgaard a fait des animations plus visuelles:

animation de tabulation élastique
animation de tabulation élastique


31 commentaires

@tleb: Clairement, mais je ne trouve pas génial de devoir dans tous les cas lire le fichier dans sa totalité et de le garder en mémoire, ou de le lire deux fois (quand c’est possible) en se souvenant de ce contexte.

L’idée n’est pas mauvaise mais en pratique c’est inutilisable.
Ca devrait resté un plugin dans un éditeur de texte.

+3 -0

Ben les terminaux par exemple pourraient prendre ça en compte pour le rendu, ainsi que les browsers dans les <code> ou <pre> par exemple.

@entwanne: une implémentation qui ne calcule les largeurs de colonne que sur la partie visible du code me paraît très raisonnable. Le plus simple c’est de faire le rendu de chaque ligne en fonction uniquement de que tu as vu dans le passé, mais de refaire les rendus des colonnes précédentes (de la partie visible) quand tu rends une ligne. Ainsi, tu n’as pas besoin de lire de texte à l’avance (une interface en pure streaming convient), mais tu dois de temps en temps décaler des lignes déjà rendues — comme sur l’animation, en fait.

mais tu dois de temps en temps décaler des lignes déjà rendues — comme sur l’animation, en fait.

Bonjour le cauchemar question UX, déjà qu’avoir des tabs qui varient de taille suivant l’éditeur c’est pénible, si en plus elles varient avec le texte affiché on s’en sort plus…

+1 -0

Ben… si, comme sur l’animation, où ça a l’air tout à fait naturel que les tabs varient quand le texte change.

Si on fait de la lecture par bloc, et pas en pur streaming, on peut avoir plus d’information au moment du rendu, et calculer des meilleures positions de tab dès le départ. Du moment que chaque cellule du document (chaque zone de tabs alignés ensemble) est moins longue qu’un bloc (typiquement dans un programme information, entre deux fonctions toplevel il n’y a pas de cellule commune, et les blocs de buffering plus que le corps d’une fonction), on est dans un régime où il n’y a jamais besoin de changer les positions des tabs après affichage, donc le reflow est un cas exceptionnel.

Ouais, mais normalement, une tabulation, c’est 8 colonnes. Un \t dans une console ira sur un multiple de 8, pas de 4. Mais bon, les goûts, les couleurs… pour les trucs perso, chacun fait ce qu’il veut, et si ça deviens collaboratif, on garde la norme en place (ou en défini une). Le principal étant d’être cohérent.

Breizh

Même en console ça se configure (en tout cas dans les Unix-like) et heureusement. Et aucune norme n’impose une largeur de tabulation…

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte