Skyduino:~#
Articles
librairie, programmation, projet, python

[PySkCode] Réinventons la roue carrée, mais avec des jantes chromées

Bonjour tout le monde !

Dans un précédent article qui remonte déjà à plusieurs mois (le temps passe vite), j’avais dit tout le mal que je pensai de HTML et j’avais expliqué pourquoi HTML n’était tout simplement pas fait pour les rédacteurs web. Pour résumer rapidement, mon point de vue dans l’article était le suivant : on demande à un rédacteur de rédiger du texte (en bon français de préférence), pas de faire du développement web. « Chacun son métier » comme on dit.

J’avais conclu mon article en disant que le mieux serait d’avoir une syntaxe légère, typée Markdown, mais en version boosté aux stéroïdes pour avoir sous la main tous les outils syntaxiques couramment utilisés par un rédacteur lambda. À défaut, j’avais précisé qu’un bon compromis serait une syntaxe typée HTML/XML, mais plus légère et avec un jeu de balises par défaut de bien plus haut niveau que du simple HTML brut.

Il s’avère qu’implémenter un interpréteur pour une syntaxe comme Markdown est un vrai casse-tête technique. Ce genre de syntaxe n’est tout simplement pas conçu pour être facilement interprété par un ordinateur. Je m’en étais méchamment rendu compte en tentant de faire mon propre interpréteur Markdown, il y a de cela plus d’un an (projet abandonné depuis).

Ayant besoin d’un moyen d’écrire mes articles pour le site Carnet du Maker, j’avais commencé à chercher un peu avant début août un substitue à HTML, facile à interpréter et facile à utiliser. Voir idéalement, prêt à l’emploi avec Python 3.x et Django.

J’avais besoin d’une syntaxe à la fois :
– facile à interpréter,
– facile à étendre (pour ajouter des fonctionnalités rapidement dés que besoin),
– facile à utiliser,
– sans contrainte concernant la méthode de saisie (clavier, smartphone, police monospace ou non, etc.),
– de haut niveau, c’est à dire pouvant être exporté en HTML pour le web ou vers un autre format (texte par exemple pour des mails, etc.).

Idéalement, il me fallait une syntaxe que les internautes connaissent déjà. Le même code est utilisé sur le site CDM pour gérer les messages du forum et les articles (avec bien évidemment des limitations en fonction du niveau d’autorisation des utilisateurs).

Personnellement, une syntaxe proche de l’assembleur avec des marqueurs à chaque début de ligne ne me dérangerait pas le moins du monde (ce serait même plutôt pratique sur plusieurs points). Mais pour un utilisateur lambda, l’assembleur … gloups. Alors, certes, j’aurai pu imaginer avoir deux systèmes de rédaction séparés, un pour moi et un pour les autres, mais ce serait avoir deux fois plus de code à maintenir et ça ce n’est pas cool.

Du coup, j’ai cherché et j’ai trouvé. Certains ont déjà dû comprendre ce que j’ai choisi comme syntaxe rien qu’en regardant le titre de cet article, pour les autres, j’en suis sûr, vous avez déjà entendu parler de BBCode. Vous avez même peut-être déjà utilisé cette syntaxe.
BBCode est une syntaxe inspirée et proche (très proche même) de HTML qui est couramment utilisée sur les forums partout sur le web pour parler entre internautes (BBCode est l’acronyme de « Bulletin Board Code », littéralement « langage de forum »). C’est old-school comme syntaxe (1998 quand même), mais au moins ça marche, même si jamais personne n’a vraiment fait de norme pour expliquer comment ça doit marcher (contrairement à HTML qui est normé de manière tellement stricte que ça en devient un problème, voir annexe plus bas).

Le but de BBCode est simple : avoir un langage de haut niveau qui ressemble à HTML, mais qui propose en supplément une montagne de raccourcis pour faire des choses relativement complexe sans se prendre la tête, comme des citations avec source, des boites d’alertes, des notes de bas de page, etc. Ça n’empêche pas BBCode d’avoir un certain nombre de défauts (dont beaucoup sont communs à HTML et expliquaient dans mon précédent article), mais c’est déjà beaucoup mieux que du HTML brut.

J’avais donc entrepris début août l’écriture de mon propre interpréteur BBCode pour Python 3.x, à défaut d’avoir pu en trouver un tout prêt, dont le code ne se résume pas à un unique fichier de 534 lignes sans réelle documentation, commentaires, ni même tests. Mais comme les deux derniers mois ont été particulièrement remplis pour moi (plus de détails ici) je n’ai pas eu le temps de finir mon code jusqu’à aujourd’hui.

Amis et collègues amateurs de programmation Python, j’ai donc le plaisir de vous annoncer que le projet PySkCode est désormais suffisamment abouti pour être utilisé en dehors d’un simple code de test.
J’ai passé les deux dernières semaines à terminer le code, écrire un bon paquet d’utilitaires et faire de tests unitaires dans le but de rendre cet interpréteur BBCode ultra flexible et ultra puissant.

Il reste encore des choses à faire pour que le projet PySkCode soit achevé, à savoir :
– gérer les smileys,
– gérer les remplacements cosmétiques (- > qui devient → exemple),
– implémenter le code de validation des balises (pour interdire un titre dans un titre par exemple),
– terminer d’écrire les tests unitaires restant pour avoir un coverage de 100% des cas d’usages.

Concernant les smileys, c’est loin d’être critique, de même pour les remplacements cosmétiques. Ce sont deux points qui pourront être implémentés assez rapidement une fois les choses plus importantes terminées.

Pour le code de validation, c’est déjà un peu plus embêtant, mais pas tant que ça en fait. Aucun interpréteur BBCode que j’ai pu croiser par le passé ne fait de réelle validation sur les balises imbriquées. Mon code est conçu pour faire de son mieux et donner un résultat le plus cohérent possible sans planter si ce qu’on lui passe en entrée n’a strictement aucun sens. Ainsi, même si la partie validation n’est pas encore implémentée ce n’est pas vraiment un problème des plus critique. La validation avant affichage sera une fonctionnalité bonus une fois implémenté.

Ce qui pose problème, c’est les tests unitaires manquants sur une petite dizaine de classes/fonctions. J’ai testé manuellement chaque morceau de code, je suis donc assez confiant de son bon fonctionnement, mais tant qu’un test unitaire n’est pas là pour dire « oui, ça marche » ça reste un peu embêtant.

J’ai décidé de partir du principe que le code était suffisamment stable pour être intégré dans le site CDM. Je vais donc reprendre les travaux sur le site CDM et je reviendrai par la suite sur le projet PySkCode pour faire les dernières finitions. Au passage, j’aurai surement pas mal de modifications à réaliser suite aux divers retours utilisateurs.

Je suis bien décidé à commencer l’année 2016 avec un site fonctionnel, un forum sur lequel on peut discuter et au moins un article dans une catégorie 😉

Annexe : Pourquoi faire un parseur BBCode ? Pourquoi ne pas utiliser un parseur HTML classique avec des balises HTML « maisons » ?

Tout simplement parce que ça ne marche pas.

La norme HTML est bien trop stricte et les implémentations des interpréteurs HTML sont bien trop respectueuses de la norme pour permettre des balises HTML « maisons ».
C’est bête à dire, mais HTML n’a jamais été conçu pour être étendu. On est donc vite limité par les contraintes de la norme et par les choix techniques très discutables de la W3C sur certains points.

Exemple simple, mais représentatif du problème : la balise code. On serait tenté de s’approprier la balise code et d’ajouter un attribut « language » à la balise pour faire de la coloration syntaxique.
Pas de bol, la balise code n’est pas une balise de type « donnée ». Si vous avez du HTML dans une balise code, il sera traité comme du HTML, pas comme du texte.

Je vous laisse donc imaginez ce qu’il se passe quand en tente de faire ceci :

<code language="cpp">
#include <stdio.h>

// ...
</code>

Indice : en fonction de l’interpréteur HTML, <stdio.h> va générer un warning de détection de balise HTML inconnue. C’est du reste assez marrant, car un nom de balise en HTML ne devrait pas pouvoir contenir de point.

Du coup, comment résoudre ce problème ? Échapper les caractères spéciaux dans les balises code avant de donner le texte à l’interpréteur ? Oui mais comment ? Avec des expressions régulières ? SUREMENT PAS ! Avec un autre parseur HTML ? On tourne un peu en rond …

Tant bien même on trouverait LE parseur HTML, celui qui permet de choisir quelles balises sont de type « donnée ». Il faudrait encore que celui-ci supporte HTML5 et ne soit pas trop intelligent. Car oui, un parseur XML/HTML trop intelligent est … une faille de sécurité. Il faudrait en plus qu’il soit documenté, testé et qu’il dispose d’une API suffisamment riche pour construire son code par dessus.

Autant dire qu’un tel parseur n’existe pas. Et c’est bien pour cela que j’ai dû réinventer ma propre roue carrée, en lui ajoutant des jantes chromées.

Publicités

Discussion

12 réflexions sur “[PySkCode] Réinventons la roue carrée, mais avec des jantes chromées

  1. Pourquoi ne pas partir de documents LibreOffice et établir un convertisseur?
    Il y a bien des années (avant 2000), j’avais fait pareil avec MS Publisher 97/98 puis 2000. Le convertisseur traduisait l’export HTML « à la sauce MS » en HTML universel.

    Publié par jmparatte | 24 novembre 2015, 7 h 44 min
    • C’était une des contraintes du projet (que j’ai oublié de re-préciser) : le rédacteur doit pouvoir rédiger son texte depuis le site, directement via une zone de texte classique.
      Un workflow à base de convertisseur OpenDocument/HTML n’est pas envisageable car les utilisateurs du site utilisent le même système de rédaction (limité logiciellement) pour le forum/commentaires/etc.

      Publié par Skywodd | 24 novembre 2015, 11 h 04 min
  2. Bonjour
    Merci à toi de partager tes questionnements et tes codes.
    Quelle est la différence entre ton module est les 2 suivants?
    https://github.com/dcwatson/bbcode
    https://code.google.com/p/postmarkup/wiki/Usage
    Pour ma prise de note j’utilise zim (http://zim-wiki.org/) qui utilise une sorte de markdown. Un des reproche que je ferai c’est l’impossibilité d’imbriquer des balises. Est ce que bbcode le permet?
    Thierry

    Publié par Thierry | 24 novembre 2015, 9 h 14 min
    • > Quelle est la différence entre ton module est les 2 suivants?

      D’un point de vue des fonctionnalités pour l’utilisateur :
      – Gestion des caractères d’échappements dans les attributs des balises. Dans un parseur BBCode classique, si tu as une valeur avec un espace, une simple quote et une double quote, tu ne peux plus rien faire.
      – Gestion intelligente des balises autofermantes (style XHTML).
      – Mise en avant (par défaut, désactivable) des balises non reconnues.

      D’un point de vue des fonctionnalités pour le développeur :
      – Code conçu de zéro pour être flexible et extensible.
      – Choix par balise du comportement de l’interpréteur, avec une grande finesse dans les options.
      – Compatible Python 3.x uniquement (pas de six/2to3 ou autre surcouche logicielle de compatibilité 2.x).
      – Implémentation des balises via un pattern délégation et des classes objets, contrairement aux autres parseurs qui ne sont rien de plus qu’un méli-mélo de fonction de callback et de dictionnaires Python.
      – Document DOM en sortie du parseur, donc possibilité de modifier le document après interprétation.
      – Possibilité de choisir le caractère de début/fin de balise, ainsi que le niveau de rétrocompatibilité souhaité. En changeant quatre paramètres, il est possible de demander à mon code d’interpréter du HTML ou XHTML.
      – Rendu HTML, texte et SkCode séparés. Cela permet d’avoir une version HTML bien propre, mais aussi une version texte qui ne se limite pas à simplement supprimer les balises.
      – Lots d’utilitaires fournis avec le code pour extraire des sommaires, récupérer le HTML des notes de bas de page, lister les acronymes, etc.
      – Bases pour un système de validation fort des balises imbriquées (en travaux, cf article).
      – Jeu de balises par défaut couvrant tous les cas d’usages classiques pour de la rédaction de documents riches.
      – Rétrocompatibilité avec les balises BBCode classique.
      – Paramètres par défaut compatible avec de la saisie utilisateur non sûre.

      Tout cela est possible, car mon parseur est conçu autour d’un trio normalement utilisé pour faire des compilateurs ou des outils d’analyse syntaxique : lexer (texte -> balise), tokenizer (texte -> tokens), parser (aka « tree builder », tokens -> arbre de syntaxe abstraite « AST »).

      Les parseurs BBCode classiques se contentent de faire une bête traduction BBCode -> HTML, sans autre forme de procès. Le moteur de BBCode Shortcode de WordPress est même un cran au-dessus en terme de bêtise, car la conversion se fait avec une expression régulière des plus bancale.

      > Pour ma prise de note j’utilise zim (http://zim-wiki.org/) qui utilise une sorte de markdown. Un des reproche que je ferai c’est l’impossibilité d’imbriquer des balises.
      > Est ce que bbcode le permet?

      Oui, l’imbrication de balise est même un des points clefs de la syntaxe BBCode (mais aussi HTML, et plus généralement de toute syntaxe typée SGML). Chaque balise fait une petit chose bien précise. Et c’est en empilant les balises qu’on obtient la mise en page souhaité.

      Publié par Skywodd | 24 novembre 2015, 11 h 40 min
  3. et comment se débrouille ton parseur avec un genre de
    [[code]]
    int i = booboo[3];
    [[/code]]

    ou un simple [font size=1%] non fermé ?

    t’as un truc en ligne qui permet le torturer un peu?

    Edit Skywodd: J’ai échappé la balise code pour que WordPress ne fasse pas ça sauce dans son coin.
    Edit Skywodd n°2: Quand je disais un peu plus haut que le système de WordPress était bancale … En voila la preuve, la syntaxe d’échappement ne marche pas.

    Publié par f4grx | 24 novembre 2015, 10 h 46 min
    • ah ben code est une balise bbcode qui passe dans les commentaires wordpress 😀

      j’te laisse voir la source de mon commentaire 🙂

      Publié par f4grx | 24 novembre 2015, 10 h 46 min
    • La balise code est déclarée comme une balise « données ».
      Tout ce qui se trouve avant la balise fermante est conservé sans modification.

      Pour les balises non fermées il y a deux possibilités, soit :
      1) Les balises sont fermés automatiquement (mode par défaut)
      2) Les balises non fermées sont traitées comme des balises invalides.

      Publié par Skywodd | 24 novembre 2015, 13 h 47 min
  4. Et pourquoi pas intégrer CodeMirror (http://codemirror.net)?
    Jantes chromées et DeLorean incluses.

    Publié par mc | 13 décembre 2015, 11 h 29 min

Rétroliens/Pings

  1. Pingback: [PySkCode] Site de test en ligne | Skyduino - Le DIY à la française - 25 novembre 2015

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

Skyduino devient Carnet du Maker

Le site Carnet du Maker remplace désormais le blog Skyduino pour tout ce qui touche à l'Arduino, l'informatique et au DIY.