#!/usr/bin/env python3 r"""Insère un bloc Doxygen DEVANT une déclaration, sans voler la doc de sa voisine. POURQUOI CET OUTIL EXISTE ------------------------- La même erreur a été commise QUATRE FOIS en une semaine, par attention soutenue, et rattrapée quatre fois par `ci-quality` : /*! doc de A */ ← on insère ici, croyant précéder B… void A(); …et le bloc de A se retrouve accolé à B, void B(); qui hérite de `\param` qu'il n'a pas. Un outil qui attrape quatre fois la même erreur chez quelqu'un d'attentif ne signale pas un défaut d'attention : il signale que **le geste lui-même est piégeux**. Le contrôle rattrape après coup ; ce garde-fou-ci agit à l'écriture. CE QU'IL FAIT ------------- Il localise la déclaration, REMONTE au-dessus de son éventuel bloc `/*! … */` ou de ses lignes `//!`, et insère là. Le bloc existant reste donc collé à sa propre déclaration. python3 tools/inserer-doc.py `` est une sous-chaîne unique de la ligne de déclaration visée. """ import re, sys from pathlib import Path def debut_du_bloc_doc(lignes, i): """Remonte au-dessus du bloc de documentation attaché à la ligne i, s'il existe.""" j = i - 1 # lignes `//!` empilées while j >= 0 and lignes[j].lstrip().startswith('//!'): j -= 1 if j >= 0 and lignes[j].rstrip().endswith('*/'): # remonter jusqu'à l'ouverture du bloc k = j while k >= 0 and '/*!' not in lignes[k] and '/**' not in lignes[k]: k -= 1 if k >= 0: return k return j + 1 def principal(): if len(sys.argv) != 4: print(__doc__) return 2 fichier, ancre, bloc_f = Path(sys.argv[1]), sys.argv[2], Path(sys.argv[3]) lignes = fichier.read_text(encoding='utf-8').split('\n') cibles = [i for i, l in enumerate(lignes) if ancre in l] if len(cibles) != 1: print("✗ l'ancre doit désigner UNE ligne, trouvée %d fois" % len(cibles)) for i in cibles[:5]: print(" %s:%d %s" % (fichier, i + 1, lignes[i].strip()[:76])) return 1 i = cibles[0] pos = debut_du_bloc_doc(lignes, i) if pos != i: print(" note : une documentation existe déjà en %s:%d — insertion AU-DESSUS d'elle," % (fichier, pos + 1)) print(" pour qu'elle reste attachée à sa propre déclaration.") bloc = bloc_f.read_text(encoding='utf-8').rstrip('\n').split('\n') lignes[pos:pos] = bloc fichier.write_text('\n'.join(lignes), encoding='utf-8') print("✓ bloc inséré en %s:%d (%d lignes)" % (fichier, pos + 1, len(bloc))) return 0 if __name__ == '__main__': sys.exit(principal())