SyntaxHighlighter, php et scripts Bash
Par Cyril le jeudi 6 août 2009, vers 11:03 - Le site - Lien permanent
SyntaxHighlighter : présentation
J'ai découvert il y a quelques semaines un (gros) bout de code génial. Comme le dit le site dédié, il s'agit d'un code de surlignage syntaxique, ou comment rendre des bouts de codes déjà lisibles encore plus lisibles.
L'utiliser n'est pas très compliqué, puisqu'il suffit de télécharger le dernier .zip, de le dézipper et de regarder ce qu'on trouve. Un répertoire scripts contenant en particulier shCore.js qui est le cœur de la machinerie, ainsi que plein de shBrush*.js, qui contiennent les définitions des syntaxes pour différents langages. Personnellement, je n'ai pas besoin de tout, donc je n'ai choisi de garder que ce qui m'intéresse : Bash, Php, Plain que j'utiliserai souvent, Css, JScript et Sql un peu moins, et puis aussi au cas où Diff, Perl, Python, Xml. Un dossier styles contient lui les fichiers de mise en page css, parmis lesquels shCore.css est obligatoire et ensuite shThemeDefault.css correspond au seul thème écrit en noir sur blanc (les autres font du blanc sur noir, je déteste ça). Sans oublier les trois icônes qui seront affichées dans la toolbar et l'icône de retour à la ligne.
Donc on prend tous ces fichiers, on met tout ça dans un répertoire, appelé par exemple syntaxhighlighter, à la racine du site. Il ne reste plus qu'à modifier les pages web en ayant besoin. Il faut rajouter dans l'entête html :
[html]
<script type="text/javascript" src="/syntaxhighlighter/shCore.js"></script>
<link type="text/css" rel="stylesheet" href="/syntaxhighlighter/shCore.css"/>
<link type="text/css" rel="stylesheet" href="/syntaxhighlighter/shThemeDefault.css"/>
<script type="text/javascript" src="/syntaxhighlighter/shBrushPlain.js"></script>
<script type="text/javascript" src="/syntaxhighlighter/shBrushBash.js"></script>
<script type="text/javascript">
SyntaxHighlighter.all();
</script>
Ensuite, tous les paragraphes de type <pre> seront analysés, pour peu qu'on dise à quel langage ils correspondent, en ajustant la classe :
[html] <pre class="brush: bash">
par exemple. J'ajoute aussi, pour éviter la numérotation des lignes quand il s'agit d'une simple ligne de commande :
[html] <pre class="brush: plain; gutter: false">
Mais il y a encore deux trois détails à gérer. Petits trucs et astuces pour pouvoir afficher des scripts bash comme cela est réalisé sur mon site.
Pour le transcript, deux problèmes
Balises malgré elles
SyntaxHighlighter transforme tous les chevrons « < » et « > » en entités html correspondantes, respectivement « < » (less than) et « > » (greater than). Ce ne serait pas grave s'il ne le faisait pas seulement pour presque tous les chevrons... Or il cherche à détecter automatiquement les balises (ce qui n'est pas très malin dans du code bash d'ailleurs, ce qui fait que mon adresse mail par exemple était comprise comme une balise, dégradant quelque peu la suite de l'affichage. Total : il faut le faire pour lui.
Au départ, j'avais choisi d'utiliser readline en php, à savoir
[php]
<pre class="brush: bash">
<?PHP @readline('compil'); ?>
</pre>
Mais transformer les chevrons à l'avance n'est pas beaucoup plus compliqué :
[php]
<pre class="brush: bash">
<?PHP echo str_replace('<','<',str_replace('>','>',file_get_contents('compil'))); ?>
</pre>
Vous aurez remarqué que du coup, dès que le fichier est modifié, c'est le code de la dernière version qui s'affiche. Zéro maintenance (le fichier compil est un lien symbolique vers /usr/local/bin/compil sur mon serveur).
Décidément, ces chevrons...
Et c'est à ce moment que l'on relit un peu ce qui s'affiche à l'écran, et qu'on se rend compte que plein de chevrons (mais pas tous) sont restés à l'état d'entités html. Alors qu'en enlevant l'influence de SyntaxHighlighter, on obtient bien le résultat attendu. Il m'aura fallu quelques minutes pour me souvenir que lt et gt, sont des mots-clés en bash, justement pour des tests numériques plus grand/plus petit (ouais, tout est lié). Un grand dilemme se pose alors. Soit on laisse comme ça, et le code affiché est faux. Soit on s'arrange pour ne jamais avoir de chevrons (ce qui est impossible quand on a besoin de redirections). Soit on commente les mots-clés gt et lt dans le fichier de définition shBrushBash.js, et tant pis pour leurs rares apparences en tant que tests, où ils ne seront pas colorés comme il faut. J'ai choisi cette dernière solution.
Pour l'aide
Ah, là ça se corse. Au départ j'avais recopié telle quelle la réponse de compil -h. Je me suis dit alors « mais si t'as une coquille dans l'aide ou que tu la modifies, il faudra revenir ici... au secours ». Alors j'ai trouvé un moyen. Après plusieurs tâtonnements et hésitations sur la meilleure fonction php entre exec, system et passthru, j'ai opté pour
[php]
<pre class="aide">
$ compil -h
<?PHP
exec('[ ! -e compil.help -o compil -nt compil.help ] && compil -h | tr -d "\033" | sed -e "s/\[1m/<b>/g" -e "s/\[0m/<\/b>/g" > compil.help');
@readfile('compil.help'); ?>
</pre>
Explication : la dernière commande lit et affiche un fichier compil.help. On va donc y mettre l'aide. Problème, j'utilise un formatage à base de caractères bizarres qui permettent de mettre en gras du texte en console. On prend donc le résultat de compil -h, on en vire donc le caractère bizarre (grâce à la commande tr -d), puis on identifie le début et la fin des mises en gras, que l'on remplace de façon moche mais fonctionnelle par des balises de formatage html.
Le début est un test, qui permet d'exécuter la commande seulement si compil.help n'existe pas ou est plus ancien que compil. Cela semble fonctionner à peu près correctement.