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

Mais dans le GIF, l’indentation est réglé sur 2 ou sur 4 ? D’après la ligne 3 et les commentaires lignes 6–7-8 c’est deux, mais d’après les indentations vert, bleu et jaune c’est quatre, ou deux tabulations, mais ça devient vite chiant si on doit appuyer deux fois sur tab pour indenter. Et surtout, on perd le principe : une tabulation = un bloc de code. Ou alors y’a un truc que j’ai pas compris ?

À part ça, j’adore le principe !

Mais dans le GIF, l’indentation est réglé sur 2 ou sur 4 ? D’après la ligne 3 et les commentaires lignes 6–7–8 c’est deux, mais d’après les indentations vert, bleu et jaune c’est quatre, ou deux tabulations, mais ça devient vite chiant si on doit appuyer deux fois sur tab pour indenter. Et surtout, on perd le principe : une tabulation = un bloc de code. Ou alors y’a un truc que j’ai pas compris ?

Si j’ai bien compris, l'indentation est réglée sur 4, mais l’utilisation d’une tabulation pour aligner est sur 2. C’est le rôle (aligner ou indenter) et non plus l’outil (tabulation) qui a un minium associé.

+0 -0

Dans l’idée c’est pas bête, en pratique c’est trop imprévisible je trouve. Au moins, par blocs de 8, on sait où ça va tomber. Et justement, j’estime qu’autant utiliser des espaces au début, ça peut passer, autant « au milieu », il faut absolument utiliser les tabulations. Comme quoi, ça dépends vraiment de chacun :D

+0 -0

@Gabbro : je ne trouve pas où dans le billet cette distinction est faite. De ce que j’ai compris, les tabulations (l’outil) ont un minimum mais s’adapte en fonction des lignes environnantes, sans distinction entre indentation et alignement.


@Breizh : on évite les tabulations "au milieu" parce que l’affichage n’est pas le même partout. Exemple :

class Foo:
    def bar(arg1,
            arg2):
        pass

Ici, que ça soit des tabulations qui sont utilisés pour indenter, ça ne change rien. Par contre, il faut utiliser des espaces pour aligner l’argument 2, sinon il ne sera pas aligné de la même façon chez tout le monde.

Ça se tiens comme argument, surtout en Python.

Mais personnellement, une tabulation ça sers à ça. Et ça fait 8 colonnes, tout autre réglage est du bidouillage :p (mais n’ouvrons pas le débat, ce n’est que mon avis, je comprends tout à fait que ça soit considéré comme pas pratique par d’autres. D’autant plus que je code peu).

+0 -2

@Gabbro : je ne trouve pas où dans le billet cette distinction est faite. De ce que j’ai compris, les tabulations (l’outil) ont un minimum mais s’adapte en fonction des lignes environnantes, sans distinction entre indentation et alignement.

Je me plante peut-être. :-° Après, je ne vois pas d’autres explications.

Et ça fait 8 colonnes, tout autre réglage est du bidouillage

Tu pointes du doigt le gros problème des tabulations pour aligner : si j’ai un autre réglage (disons… 4), alors ce sera aligné chez toi, mais pas chez moi.

+0 -0

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.

+1 -0

J’ai pas regardé les détails de son algorithme de layout, donc je ne suis pas sûr pour la distinction sur les largeur d’indentation dont parlent @tleb et @Gabbro. (À mon avis la page manque d’un pseudo-code précis pour clarifier tout ça.)

En fait je trouve que le mieux ce serait de rajouter un nouveau caractère de tabulation, distinct de \t, pour avoir ce comportement. Comme ça c’est clair, en particulier, que l’utilisateur veut cette sémantique plutôt qu’une autre. D’un côté, rajouter un nouveau caractère semble lourd et compliqué, c’est pour ça sans doute que l’auteur n’y a même pas pensé (et puis la sémantique standard actuelle de \t est compliquée et sans doute utile pour peu de gens), mais en même temps on vient en quelques années de standardiser des centaines de smileys, alors pourquoi pas un nouveau caractère de tabulation alignée.

Je pense pas que ce soit vraiment un standard, c’est simplement que si tu fais un echo -e 'bla\tbla' dans n’importe quel terminal (du moins sous Linux et probablement MacOS), y compris les consoles de base, ça se calera sur des multiples de 8. Je vais me renseigner, voir si un jour y’a eu une définition pour ça.

+0 -0

J’ai trouvé. Les taquets de tabulation étaient réglables à l’époque où c’était mécanique (pour permettre de faire des tableaux, et des alignements – donc bien pour aligner « au milieu »), et une généralité de 5 à 6 caractères pour le premier (alinéa) s’était mise en place. Quand on est arrivés aux premières machines électroniques, les tabulations sont passées à 8 caractères car il était plus simple de gérer une puissance de 2. C’est ensuite devenu un standard de facto.

Source : https://en.wikipedia.org/wiki/Tab_key

Du coup, effectivement, c’est pas déconnant de faire des tabulations élastiques. Par contre, ça risque d’être techniquement difficile à implémenter partout, ça ne peut être un simple caractère.

+0 -0

Dans le terminal XFCE, j’ai le droit à la largeur de 5 caractères pour un \t.

Fumble

Surprenant, mais bon à savoir.

EDIT : Hum… je me demande…

╭─breizh at thinkpad in /home/breizh
╰─λ echo -e 'bla\tbla\n12345678'                                                                                                                                                                                                  0 < 20:52:37
bla     bla
12345678

Ça va au multiple de 8 suivant, ça n’ajoute pas 8. C’est bien comme cela que tu as compté ? Ici j’ai mis des espaces, apparemment ça rends différemment sinon.

+0 -0

Oui, c’est ce que je disais, dès que c’est voué à être public, il faut donner un cadre (ou coding style), à défaut d’en respecter un existant. Tant que c’est cohérent, y’a pas de raison que ça ne soit pas lisible.

Et on ne pourra jamais définir un cadre universel, il y a bien trop de conventions importantes existantes. De plus, il existes des outils, comme EditorConfig qui permettent de définir le coding style via un fichier de configuration. Cela permet, pour les éditeurs qui le supportent, de définir automatiquement le style pour tout un projet, et pour tout le monde (cela évite de reconfigurer son IDE en fonction du projet, et c’est plus universel qu’un .vimrc ou une « Vim magic line », ou équivalent d’autres éditeurs).

+0 -0

Je trouve l’approche des tabulations élastiques intéressantes, mais je trouve gênant que cela nécessite de connaître le fichier dans sa totalité pour bien afficher les lignes.

Je ne vois pas bien comment ça pourrait s’utiliser avec des outils comme diff ou grep Pour ce dernier je trouverais bizarre que l’affichage diffère suivant le nombre de lignes dans le résultat par exemple.

@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.

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