Legilibre / Archeo-Lex-web

An elegant and modern git repository viewer
BSD 3-Clause "New" or "Revised" License
3 stars 0 forks source link

Améliorer la lisibilité des diffs de façon globale et non locale #3

Open Seb35 opened 6 years ago

Seb35 commented 6 years ago

Quoique j’y ai déjà passé du temps pour faire des diffs “lisibles”, la situation est améliorable. #2 va changer la logique interne mais le rendu devrait être identique à l’actuel.

Basiquement, je me suis tourné vers l’algorithme de Ratcliff-Obershelp, qui ne semble pas très connu, mais qui est tout de même implémenté dans la librairie standard difflib de Python. Essentiellement il recherche les plus grandes zones contiguës de texte, puis, à gauche et à droite recherche à nouveau les plus grandes zones contiguës de texte, et ainsi de suite. Ce qui n’est pas dans les zones contiguës de texte sont des différences (suppression, ajout ou modification).

Cœur du problème : là où les choses deviennent plus discutables, c’est sur la quantité d’alternances "texte identique" / "textes différents" et a fortiori lorsque les "textes différents" impliquent des retours à la ligne et a fortiori lorsque l’un des "textes différents" a un retour à la ligne et pas l’autre. Cela donne parfois un aspect visuel d’une « soupe de rose, vert et gris ».


Dans la 1re version qui travaillait au niveau du caractère (version toujours actuelle mais pas pour longtemps), j’imposais que les zones de texte commun fassent au moins 5 caractères ou aient un retour à la ligne (cette 2e condition est, je pense, importante car un retour à la ligne est fortement signifiant, et a contrario s’il était mis dans les "textes différents" cela ferait 2 retours à la ligne (un rose + un vert).

J’ai dans l’idée que pour optimiser la lisibilité des diffs il faut d’abord obtenir un diff minimal ou quasi-minimal puis appliquer une fonction globale de "balance" qui rendrait l’aspect visuel convenable. Possiblement des raffinements pourraient ensuite être appliqués.

  1. La version brute – le diff minimal ou quasi-minimal – peut s’obtenir facilement avec un des algorithmes existants (Myers ou Ratcliff-Obershelp, les deux sont disponibles dans la classe Diff). J’entends par "diff quasi-minimal" un diff dont le script d’édition n’est pas forcément minimal (au sens de Myers), c’est (pour ce que j’en connais) Ratcliff-Obershelp.
  2. La fonction globale de "balance" est le point central de cette issue. Il s’agirait d’équilibrer les alternances "texte identique"/"textes différents" (les "textes différents" étant de 3 types : ajout, suppression, modification) en tenant compte des retours à la ligne. Il est possible qu’il faille traiter de façons différentes des retours à la ligne détectés comme "texte identique" dans le diff minimal, en fonction du contexte. Possiblement une des choses qui auraient un poids plus important serait également les points de numérotation "\na. ", "\nb. "… ou "\n1. ", "\n2. "….
  3. La fonction de raffinement serait pour changer localement certains détails. Pour rendre à César, c’est ma mère qui a pensé à ce point : les accords des verbes (ou autres) qui changent notamment sur des singulier/pluriel, par exemple "Est autorisé la vente de produits de beauté." → "Sont autorisés la vente de produits de beauté et le prêt de glaces parfumées à la vanille." peut devenir "-Est-+Sont+ autorisé+s+ la vente de produits de beauté+ et le prêt de glaces parfumées à la vanille+."

Noter que le résultat de cette issue sera de faire des diffs "plus grands" en faisant globalement disparaître des parties de "texte identique" au profit des "textes différents", au point parfois que des articles montreront des diffs "article entièrement réécrit" alors qu’on pourrait trouver des expressions isolées identiques. Cela serait une feature et non un bug car a contrario (la situation actuelle) il y aurait des expressions isolées autour desquelles danseraient le reste du texte, alors même que, par exemple, ces expressions isolées seraient dans des paragraphes "globalement différents", il s’agit donc de diminuer l’importance d’expressions isolées par rapport à la masse globale du texte.

Seb35 commented 6 years ago

La fonction globale prendrait en entrée le diff minimal ou quasi-minimal (soit uniquement les zones de texte identique soit les opcodes des modifications, à choisir) et rendrait en sortie un diff "mieux équilibré visuellement" (zones de texte identique ou opcodes des modifications, à choisir).

À l’intérieur de cette fonction de balance, une première étape serait de classifier les différentes situations (retours à la ligne et points de numérotation en premier lieu mais ça pourrait être ensuite enrichi, sous réserve des performances), puis en fonction des situations rencontrées et de leurs poids respectifs les zones de texte identique seraient réduites.

Seb35 commented 6 years ago

L’idée de cette issue est née en parcourant les diffs générés sur https://archeo-lex.fr (bien prendre la version intitulée "mot-à-mot"), mais il faut que je donne des exemples précis de diffs à améliorer. N’hésitez pas à donner de tels liens assortis de commentaires sur les améliorations à faire.

Seb35 commented 6 years ago

Aussi, dans la fonction de balance, il peut être réfléchi une importance relative des poids "mot" et des poids "ligne". Par exemple dans ce diff les lignes sont marquées comme modifiées (en rose/vert clair) mais les mots réellement modifiés sont surlignés (en rose/vert foncé).

Quoique cela a à voir en partie avec le rendu graphique (si des mots sont modifiés il est facile d’indiquer que la ligne est en partie modifiée), on peut penser à prendre cela en compte plus en amont. Peut-être par exemple avec un seuil "si la ligne à modifiée à plus de X caractères|mots ou|et|et/ou à plus de Y % caractères|mots, considérer la ligne comme entièrement modifiée".

Dans le diff donné en exemple, GitHub considère comme deux lignes différentes "\t$charsA = str_split($stringA);" et "\t$charsA = [];". Personnellement ça m’interroge, j’aurais peut-être choisi de faire un diff uniquement sur la partie de ligne modifiée, mais je comprends aussi que ça fait sens par rapport au fait que 6 lignes sont ensuite ajoutées et que cela fait un bloc peut-être plus facilement compréhensible par un humain. (Peut-être aussi que les diffs GitHub sont orientés ligne puis raffinés en mot-à-mot, les lignes de code informatique sont souvent relativement courtes et un diff orienté ligne est déjà globalement satisfaisant.)

Seb35 commented 6 years ago

https://neil.fraser.name/writing/diff/ <- pas encore lu exhaustivement, mais de nombreuses directions dans lesquelles améliorer les diffs