• indexa.png
  • indexb.png

La coloration syntaxique (syntax highlighting) s’est rendue indispensable à tous les développeurs de programmes informatiques. Lorsque l’on écrit une application, on utilise ordinairement un éditeur spécialisé ou un IDE (environnement de développement intégré). Lourd ou léger, ce type d’arsenal propose toujours un espace de saisie favorisant la lisibilité structurelle du code et la détection des erreurs de syntaxe. Le module de coloration syntaxique permet au programmeur de voir immédiatement les strates d’un programme, ses différents composants atomiques. On aura par exemple : en rose, les mots réservés du langage de programmation (for, if, else, switch, etc.) ; en rouge (et dans une police avec zéro barré), les nombres utiles ; en bleu, tous les opérateurs (arithmétiques, logiques, binaires, etc) ; en gris, les commentaires (parties non interprétées par l’analyseur), etc.

Le fait d’écrire et de se relire en couleurs, comme à travers un jeu de calques hiérarchisés, rend le code moins ésotérique, plus facile à suivre.

Avec InDesign CS4, il est possible de transporter ce principe de mise en forme intelligente au sein d’un style de paragraphe. Pour ce faire, nous allons utiliser les styles Grep, nouvelle fonctionnalité permettant le formatage conditionnel de bouts de texte, contrôlé par des expressions régulières. Pile poil ce que doit savoir faire un coloriseur syntaxique...

Les « Grep Styles » pour Indesign CS4

Lorsque l’on jette un premier œil dans l’onglet « Style GREP » apparu parmi les options d’un style de paragraphe, on reconnaît aussitôt l’interface et la logique caractéristique des styles imbriqués :

Figure 1 - Onglet GREP Styles dans les options d’un style de paragraphe

Il ne serait pas exagéré, d’ailleurs, de résumer les choses ainsi : les styles GREP généralisent les styles imbriqués aux expressions régulières. Appuyez sur le bouton « Nouveau style GREP ». InDesign vous crache une règle par défaut illustrant le mécanisme. Cette règle va s’appliquer sélectivement aux textes composés dans le style de paragraphe que nous sommes en train d’usiner. Le motif « \d+ » capture toute séquence d’un ou plusieurs chiffres. À l’étage supérieur (« Appliquer le style : »), sélectionnez un style de caractère un peu plus agissant que le bien nommé [Sans]. Si vous cochez alors la case « Aperçu » en bas du dialogue, vous apercevez avec ivresse que tous les chiffres se trouvant dans les paragraphes visés prennent la mise en forme induite par le style de caractère demandé, par exemple une couleur distincte.

Simples et puissantes, les règles de styles GREP peuvent se conjuguer en série dans un même style de paragraphe, à l’instar des styles imbriqués. Ainsi, rien ne vous interdirait de repeindre en bleu tous les chiffres, en rouge toutes les voyelles, en gris les mots écrits en majuscules, que sais-je encore ?

Dans son billet « 5 Cool Things You Can Do with GREP Styles », David Blatner exposait tout récemment quelques-uns des bénéfices que l’on peut tirer des Grep Styles : mise en forme des chiffres, prescription de mots insécables, ajustement du tiret cadratin selon la fonte, éclipse de caractères parasites(1)...

(1) Encore que la technique proposée par Olav Kvern (réduction de corps, étroitisation à 1 %) présente quelques inconvénients ! Sûr que les experts finiront par améliorer cela.

Une petite coloration pour miss Javascript ?

Mais peut-on exploiter les styles GREP pour orchestrer une coloration syntaxique acceptable ? Par exemple, parviendrait-on à mettre en forme le texte d’un programme Javascript en lui appliquant, seulement et d’un seul coup, un style de paragraphe ? Relevons le défi et créons ensemble un style nommé JAVASCRIPT ou HIGHLIGHTER, à votre convenance, reposant initialement sur la police et les réglages que vous voudrez. (L’espacement fixe est néanmoins recommandé, il en va de la lisibilité des sabirs informatiques.)

Pour simplifier la démonstration, notre cahier des charges se limitera à cinq niveaux syntaxiques :

1. Mots réservés. — Tous devront apparaître dans le style de caractère KEYWORD (magenta). On ne capturera que les termes suivants : abstract, break, byte, case, catch, char, class, const, continue, default, delete, do, double, else, extends, false, final, finally, float, for, function, goto, if, implements, import, in, instanceof, int, interface, long, native, null, package, private, protected, public, reset, return, short, static, super, switch, synchronized, this, throw, transient, true, try, var, void, while, with.

2. Opérateurs. — On s’intéressera ici, d’une part aux symboles * + - / : ! $ % & < = > ? [ ] | ~ (dont on admettra qu’ils peuvent se combiner librement pour former des opérateurs complexes), d’autre part aux quatre opérateurs lexicaux classiques : new, is, sizeof, typeof. Ces composants devront être rendus dans le style OPERATOR (bleu).

3. Séparateurs. — Les séparateurs Javascript regroupent parenthèses ouvrante et fermante, accolades ouvrante et fermante, virgule et point-virgule. Ces composants seront rendus dans le style SEPARATOR (vert).

4. Nombres (expressions numérales). — La syntaxe d’un nombre est complexe. Elle peut introduire point décimal, écritures en bases octales et hexadécimale, exposants... Nous essaierons de synthétiser un algorithme de capture à peu près acceptable, tout en empêchant l’interpénétration avec les noms de variables. Par exemple, 23 sera bien expertisé comme un numéral, mais pas var23. Les expressions retenues à cette étape seront composées dans le style NUMBER (rouge, police avec zéro barré).

5. Commentaires. — Enfin, les commentaires sont les portions de texte situés entre les marqueurs /* et */ (même s’étendant sur plusieurs lignes, en principe) ou situées sur une seule ligne après une double barre oblique (//). Dans cet exercice, on se cantonnera à capturer les commentaires d’une ligne, car la gestion multiligne, croyez-moi, dépasse largement le cadre d’une modeste introduction aux styles Grep. Les commentaires seront stylisés dans une teinte plus légère (noir 30%).

D’ores et déjà, il apparaît que ces sous-styles syntaxiques nous préparent quelques conflits. Par exemple, l’expression true tombe dans le style KEYWORD, l’expression 5 tombe dans le style NUMBER, mais l’expression true5 ne doit tomber ni dans l’un ni dans l’autre. De même, toute expression qui aurait été préalablement reconnue parmi les niveaux 1 à 4 (mot-clé, opérateur, séparateur, numéral) doit finalement s’effacer si elle est en position de commentaire. En cela, l’ordre de spécification des styles GREP a son importance.

Voyons notre stratégie en détail :

Figure 2 - Création de la règle n°1 : capture des mots réservés Javascript

Pour capturer les mots réservés et rien que les mots réservés, on façonne une première règle reconnaissant tout terme de la liste donnée plus haut, mais sous réserve qu’il soit bien en minuscule — sensibilité à la casse : (?-i) en GREP — et sous réserve qu’il ne soit pas environné de lettres parasites — on utilisera les marqueurs de début et de fin de mot \< et \>. Je ne donne ci-dessous qu’une version abrégée de la liste, les points de suspension indiquent évidemment les termes à restituer :

KEYWORDS
 
(1)      (?-i)\<(abstract|break|byte|case| ... |void|while|with)\>

Figure 3 - Test de la règle GREP Style n°1

Pour traiter les opérateurs (niveau 2 de notre cahier des charges), nous allons invoquer à la suite deux règles Grep style complémentaires. La première s’occupe des opérateurs lexicaux et fonctionne exactement comme la chasse aux mots réservés. La seconde utilise un motif de classe GREP (entre crochets) et regroupe tous les opérateurs que nous visons. Observez que l’opérateur - (moins) est placé au début de la classe afin d’éviter une interprétation comme séparateur d’intervalle Posix. Les crochets étant des opérateurs Javascript, il faut les inclure dans l’ensemble mais on doit alors utiliser l’antislash antéposé comme caractère d’échappement. Il en résulte une instruction quelque peu cabalistique. Le + final indique que le motif embrasse toute séquence d’un ou plusieurs caractères de la classe, toute combinaison d’opérateurs est donc considérée comme un opérateur (+=, <<, etc.). Ce + collecteur pourrait vous sembler superflu puisque de toute façon, à l’unité, les symboles opérateurs seront reconnus et stylisés comme voulu. Cependant, d’une part ce regroupement est plus conforme à la syntaxe réelle des opérateurs (quoique nous l’ayons sauvagement simplifiée), d’autre part on peut raisonnablement penser qu’il réduira la charge pour InDesign.

OPERATORS
 
(2a)      (?-i)\<(is|new|sizeof|typeof)\>
 
(2b)      [-~\[\]!$%&*+/:<=>?^|]+

Bien entendu, les motifs capturés aux règles (2a) et (2b) sont adressés au style de caractère OPERATOR, qui passe ses éléments en bleu :

Figure 4 - Test des opérateurs (règle 2b)

Les séparateurs du niveau 3 (parenthèses, accolade, virgule et point-virgule) ne posent aucune difficulté. Pour la cohérence sémantique de la chose, permettez-moi d’ajoindre à cet ensemble l’espace générique GREP (\s), qui recouvre tous les caractères blancs. Ça ne change rien graphiquement, à moins que l’on fasse subir aux signes séparateurs un régime particulier (changement de corps, par exemple).

Ainsi obtient-on la règle no 3, associée à un style OPERATOR passant les caractères en vert :

SEPARATORS
 
(3)      [(){},;\s]+

Capture des nombres

NB. — Les lecteurs pressés ou allergiques aux expressions régulières peuvent éluder cette section.

Dans les langages inspirés du C et en Javascript en particulier, une expression numérale possède l’une des formes suivantes :

// Syntaxes possibles d'un numeral en JS
 
0;  // zero
123;  // entier simple: [1-9][0-9]*
123.456;  // decimal simple: [1-9][0-9]*\.[0-9]+
0.123  // decimal sur zero optionnel: 0?\.[0-9]+
1.23e4;  // exposant: un des 3 schemas ci-dessus suivi de [+-]eE[0-9]+
0377;  // entier octal: 0[0-7]+
0x2F;  // entier hexa: 0x[0-9a-fA-F]+

Ces échantillons disparates montrent qu’il est peu trivial de capturer toutes les possibilités, et seulement elles, avec un seul hameçon Grep. Et comme nous ne voulons pas faire trop souffrir le moteur d’InDesign, déjà bien sollicité par les règles précédentes, nous allons simplifier la question et considérer qu’un numéral revêt l’un des motifs suivants :

NUMBERS
 
(4a)      \<[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?
 
(4b)      \<0x[0-9a-fA-F]+

La première règle attrape grosso modo les nombres exprimés en base décimale(2) ou octale(3), tout en tolérant quelques syntaxes pathologiques du genre 089 ou 03e+5. Si vous saisissez .25 au lieu de 0.25, alors le point décimal préfixe ne sera pas gobé. Bon, on n’attend pas non plus d’un style de paragraphe qu’il analyse et interprète tout ! La deuxième règle s’occupe spécifiquement de la notation hexadécimale, elle va par exemple reconnaître une écriture comme 0x0A2F.

(2) On peut également utiliser le métacaractère \d en lieu et place de la classe [0-9]. C’est plus compact mais un peu moins lisible pour les néophytes.
(3) En Javascript, un nombre octal s’exprime par un zéro préfixe, puis utilise les chiffres de 0 à 7.

Remarquez le caractère initial \< employé dans les deux règles : il impose au premier caractère du motif capturé d’être un premier caractère de mot (au sens large). Autrement dit, dans une expression comme var22, il interdira de considérer 22 comme un nombre.

Figure 5 - Traitement des nombres

Capture des commentaires

La stratégie de capture des commentaires est inspirée de la méthode exposée par Jeffrey Friedl dans Mastering Regular Expressions (O’Reilly, 1997). Les commentaires astérisqués posent en effet une sorte de casse-tête chinois à ceux qui s’aventurent dans les profondeurs de ce problème, aussi nous contentons-nous ici d’une solution approchée qui limite sa portée à la ligne courante — j’insiste ! — et qui requiert la balise de fermeture */ (astérisque suivi de barre oblique).

Aucun problème en revanche pour les commentaires introduits par la double barre oblique (//.*). Nous obtenons alors les ultimes règles de notre chapelet de Grep styles, (5a) et (5b) :

COMMENTS
 
(5a)      /\*+[^*]*\*+([^/*][^*]*\*+)*/
(5b)      //.*

Ces règles sont chargées d’appliquer le style COMMENT (texte grisé) et il est important qu’elle soient listées en dernier (en bas) dans la rubrique « styles GREP » :

Figure 6 - Agencement des deux dernières règles Grep

En effet, supposons qu’apparaisse à l’intérieur d’un commentaire le motif d’un nombre (niveau 4) ou d’un mot réservé (niveau 1). L’expression ne doit pas pour autant être stylisée comme nombre ou comme mot-clé. La zone de commentaire agit comme une sorte d’étouffoir : quoi qu’il s’y trouve, ce n’est pas du code interprétable et ce doit donc être composé comme simple commentaire sans autre enrichissement. En positionnant la capture des commentaire et l’application du style COMMENT à la fin des opérations, nous garantissons le bon déroulement de cette mise en forme.

Démo finale

Démonstration finale avec l’ensemble des styles en action :

À lire aussi :
      — « Thérapie de GREP avec InDesign » ;
      — « Comment fixer nos tirets à l’alinéa ? » ;
      — Table des caractères spéciaux (ID CS3) ;
      — http://indesignsecrets.com/5-cool-things-you-can-do-with-grep-styles.php.

BlogNot! est une émission produite par Marc Autret depuis 2004, à consommer de préférence en cuves acclimatées aux spécifications XHTML et CSS.
Pour harceler la rédaction : marcautret(at)free(point)fr