URL: https://linuxfr.org/users/karchnu/journaux/redecouverte-roff Title: Redécouverte : Roff Authors: karchnu Date: 2022年01月19日T22:28:34+01:00 License: CC By-SA Tags: culture_unix, philosophie_unix, documentation, libreoffice, troff, groff et typographie Score: 69 Bonjour tout le monde ! Je me suis récemment intéressé à comment produire des documents PDF avec roff et ses différents outils (groff, pic, eqn, tbl, refer...). J'apprécie l'outil et le résultat, donc je voulais partager ça avec vous. (Il y a même du bonus à la fin.) Comme [la dépêche la plus complète sur Roff](https://linuxfr.org/news/a-la-recherche-des-sources-de-troff#toc_17) a été postée il y a quasiment dix ans, je suppose que de nombreux utilisateurs actuels du site ne connaissent pas cet outil, ou très peu. Je vais donc en toucher quelques mots, sans entrer dans les détails. Avant de commencer : je suis plutôt **novice**, et au-delà de quelques démonstrations, ce texte est le reflet de mon parcours avec l'outil. # Qu'est-ce que roff ? Roff est à la fois un langage et des « compilateurs » de ce langage. Des ensembles de macros existent pour rendre l'écriture plus agréable (et ajouter de la sémantique). Certaines macros sont spécialisées pour produire de la documentation de commandes et de code, d'autres pour écrire des romans, d'autres des documentations techniques, une thèse, [des présentations](https://bob.diertens.org/corner/useful/gpresent/), etc. Bien que sa conception remonte au début des années 70, Roff est **toujours d'actualité**. Différentes implémentations sont disponibles, comme [`groff`](https://savannah.gnu.org/git/?group=groff), ou des implémentations spécialisées, comme [`mandoc`](https://mandoc.bsd.lv/) pour la création de pages de manuel. Il est également utilisé pour la création de RFC ! Divers formats sont possibles, les plus courants sont les formats pdf et tty (pour des pages de manuel en ligne de commande), mais le html est aussi possible, ou encore le simple texte. NB : dans la suite je parle indistinctement de `roff` et `troff` pour désigner le langage. En ligne, vous trouverez les deux appellations. # Modèle commenté Se mettre à roff n'est pas trivial. La documentation pour un débutant est pas terrible, ce qui est quand même super dommage (et un peu ironique). L'outil mériterait pourtant d'être plus connu ! Donc rien de mieux qu'un modèle, fortement commenté, pour montrer l'exemple : * [Dépôt de code avec un modèle](https://git.baguette.netlib.re/karchnu/groff-template) * [Le modèle généré](https://t.karchnu.fr/doc/grofftut.pdf) (attention, **à voir HORS du navigateur** pour un bon rendu) Ce modèle a pour objectif de présenter les différents outils disponibles avec roff; le modèle est une démonstration de ce qu'on est **facilement** en mesure d'obtenir. J'ai fait ce document parce que c'est ce que j'aurais aimé avoir à mes débuts. Autre exemple (complet) de document : ```groff .TL \" titre du document Exemple de document .AU \" auteur Karchnu .AB \" début de l'abstract Ceci est un exemple de document écrit avec roff. .AE \" fin de l'abstract .NH \" titre de section Titre .PP \" paragraphe indenté Paragraphe. .PS \" début de dessin avec "pic" box line circle .PE \" fin de dessin avec "pic" ``` Le résultat ressemble à ceci :  Comme on peut voir, il n'y a que peu de code. Roff est un format pensé pour être écrit par des humains, il n'y a donc que très peu de superflu. # La voie d'UNIX Les outils autour de roff (groff, tbl, eqn, pic, grap, etc.) ont plein de qualités. ## Ligne par ligne La conception des outils est simple : tout repose sur la lecture ligne par ligne des sources. De fait, les outils sont simples à comprendre et à étendre. ## Une tâche, un outil Voici un exemple de compilation d'un document roff : ```sh soelim < sources.roff | eqn | tbl | pic | grap | refer | groff -Tpdf> document.pdf ``` Chaque outil gère un aspect du document : * soelim = interprète les requêtes ".so" (toutes les sources en un seul flux, un « include » si vous préférez) * eqn = équations * tbl = tableaux * pic = schémas * grap = graphes * refer = références bibliographiques * groff = compilateur de roff Chacun de ces outils prend en entrée le texte source de tout le document et produit du roff. ## Un outil, une langue Un document roff n'est pas écrit qu'en roff. Presque chaque outil a sa propre langue, permettant de décrire précisément **l'intention de l'auteur**. Le meilleur exemple de ça est pour moi **pic**. Voici l'exemple donné précédemment : ```groff box line circle ``` Ici il n'est plus question d'écrire du roff à la main, mais d'avoir un langage dédié à l'élaboration de schémas. Cela permet de décrire le rendu souhaité, sans distraction. Il est également possible de créer des fonctions pour factoriser au mieux le code. Du `roff` peut être inclus pour éviter de réécrire des fonctionnalités qui existent déjà (comme la gestion des polices par exemple). L'ensemble forme un tout cohérent. Faire des schémas comme ceux-ci est simple :   De plus, la description de ces schémas se rapproche de la programmation, et tout peut être paramétré. Il serait donc possible de modifier les tailles des différents composants de ces images de manière dynamique, via de simples variables. ## Modularité Les outils sont indépendants les uns des autres et peuvent être remplacés à tout moment. Si on a une nouvelle implémentation trop géniale de `tbl`, son remplacement dans la chaîne de compilation est trivial. ## Simplicité `roff` est largement moins complexe que LaTeX. Pas besoin de plusieurs giga d'espace disque pour générer un PDF avec deux paragraphes; seuls quelques binaires minuscules sont nécessaires. Autre métrique pour juger de la complexité de l'application : le temps de compilation est instantané, y compris sur de très vieilles machines et de gros documents. Cette rapidité a un effet de bord plutôt appréciable; il est possible d'avoir un rendu généré à chaque modification des fichiers. C'est ce que j'utilise pour avoir un retour immédiat de ce que j'écris grâce à [`entr`](https://github.com/clibs/entr). D'ailleurs, si vous utilisez le makefile de mon dépôt, vous pouvez juste taper `make serve` et vous aurez par défaut votre document généré dans `/tmp`, et regénéré à chaque modification. ## Sémantique Roff permet d'étendre le langage en créant des macros. Par exemple, je me suis fait une macro "SECTION" pour ajouter de nouveaux titres numérotés : ```groff .SECTION Nouveau chapitre Coucou ceci est le début du chapitre. ``` Les macros permettent de changer facilement le style du document, tout en ajoutant de la sémantique. Les différentes commandes (pic, grap, etc.) possèdent également des macros (ou fonctions). Cela permet de faire du code réutilisable et configurable. # Faire ses propres outils Créer de nouveaux outils pour roff est assez simple, il faut juste faire un programme qui prend en entrée les sources du document et renvoie des commandes roff. Compilation d'un document avec un nouvel outil révolutionnaire : ```sh eqn < source.roff | nouvel-outil | groff -Tpdf> document.pdf ``` Par exemple, j'ai ajouté de la coloration syntaxique avec [`ghighlight`](https://github.com/Gavinok/ghighlight) (préprocesseur roff, qui fait appel à [`source-highlight`](https://www.gnu.org/software/src-highlite/)). Dans les sources de mes documents, ça donne : ```C .SOURCE C int main (void) { return 0; } .SOURCE ``` Et voilà, on a du C coloré dans le document final. NB : j'ai également vu dans un ancien article linuxfr qu'il existait d'autres outils pour mettre de la coloration syntaxique dans troff. Notamment, [`vgrind`](https://www.computerhope.com/unix/uvgrind.htm) qui servait autrefois à ajouter de la couleur à du code dans le terminal, et qui peut se coupler avec [`ugrind`](https://github.com/pjfichet/ugrind) pour en faire un préprocesseur Roff. Je verrai plus tard si `vgrind` pourrait remplacer avantageusement ma solution, il semble couvrir moins de langages et ma solution fonctionne, donc bidouiller vgrind n'est pas dans mes priorités là tout de suite. # Un logiciel qui a 50 ans Je ne vais pas revenir sur toute l'histoire derrière Troff. D'[autres l'ont fait avant moi](https://linuxfr.org/news/a-la-recherche-des-sources-de-troff) et mieux que je ne saurais le faire. En revanche, le fait que ce langage soit si vieux est important à mentionner, à plusieurs égards. 1. Le langage est robuste dans le temps; il ne semble pas avoir beaucoup changé au fil des décennies. 2. La compilation d'un document roff est quasi instantanée, la complexité du langage étant adaptée aux machines des années 70. 3. Il existe plusieurs implémentations des mêmes outils, souvent faites à différentes époques. Cela peut engendrer des confusions. 4. La documentation autour du langage et de ses outils est inégale. * Certains outils ont une documentation exceptionnellement bonne, à l'instar de [pic](http://doc.cat-v.org/unix/v8/picmemo.pdf), ou de Roff lui-même qui a [une documentation toujours valide](http://www.kohala.com/start/troff/v7man/trofftut/trofftut.ps) (et excellente) depuis 1978. Le site [troff.org](https://troff.org/) aide beaucoup à se documenter. * En revanche, tout n'est pas simple, et la documentation des *requêtes* (commandes Roff) peut laisser à désirer. Notamment dans la documentation de [Groff](https://www.gnu.org/software/groff/), la seule implémentation que j'ai utilisée jusque-là. * Les pages de manuel sont souvent incomplètes ou pas à jour, mais ça s'améliore. 5. Malgré son âge et les nombreuses implémentations abandonnées, certaines implémentations sont toujours bien actives. Par exemple, Groff reçoit encore régulièrement de nombreux commits, et [`mandoc`](https://mandoc.bsd.lv/) a été présenté [en 2015](https://www.openbsd.org/papers/eurobsdcon2015-mandoc.pdf) puis [en 2018](https://www.bsdcan.org/2018/schedule/events/958.en.html) comme étant une implémentation dédiée à la création de pages de manuel (spécifiquement pour l'ensemble de macros **mdoc**). OpenBSD a officiellement adopté **mandoc** pour sa documentation. Roff a 50 ans, et a encore de beaux jours devant lui. Par ailleurs, je conseille la lecture de [For the love of troff](http://www.schemamania.org/troff/for-the-love-of-troff.pdf) qui explique pourquoi on ne se débarrassera pas d'un outil comme `troff` facilement. NB : *de ce que j'ai compris*, un jour `groff` a été devancé par TeX sur quelques points. Par exemple la gestion de l'alignement du texte sur les lignes, qui se faisait ligne-par-ligne au lieu de prendre en compte tout le paragraphe. De même, les équations étaient mieux gérées sur LaTeX. Mais le développement se déroulant à bon train, il ne me semble pas que ces critiques soient toujours d'actualité. Si vous en savez plus, n'hésitez pas à vous manifester dans les commentaires ! # Limitations **Je ne prétends pas être un expert**. Je suis un simple utilisateur qui a fait un petit bout de chemin avec ces outils et **uniquement avec les macros ms**. Parfois, ce chemin s'est transformé en parcours du combattant, voici quelques raisons : 1. **L'inclusion d'images**. C'est possible et je l'ai fait dans mon modèle présenté plus haut, mais les tailles des images sont mal gérées. J'ai un peu bidouillé pour que ça tombe en marche (2 lignes, rien de bien méchant). Par ailleurs, le format PS ou PDF semble imposé pour les images. 2. **Les références intra-document**. Faire référence à une section ou un chapitre par exemple. 1. La bibliographie est correctement gérée avec `refer`, mais l'outil ne gère pas les références vers des sections d'un document. 2. Les macros `ms` ne semblent pas comporter de macros pour gérer automatiquement des références. Il existe une macro pour créer un sommaire, mais c'est à peu près tout. 3. Il est possible d'écrire explicitement une référence. Le problème est qu'il faut gérer la numérotation des pages dans les références à la main. 4. Il est possible de faire [soit-même des macros gérant les références intra-document](https://www.reddit.com/r/groff/comments/mly4cb/an_intermediate_guide_to_groff_my_custom_ms/), c'est juste dommage que ce ne soit pas de base, surtout pour les débutants. 5. J'ai peut-être manqué l'outil qui fait ça et que tout le monde utilise depuis toujours, comme le dernier des boulets. À défaut de trouver une meilleure solution, j'ajouterai des macros pour gérer ça dans mon modèle. 3. **L'inclusion de nouvelles polices**. C'est faisable, mais pas simple. 1. C'est _simplifié_ en utilisant le script [`install-fonts.sh`](https://www.schaffter.ca/mom/bin/install-font.sh) ([un peu de documentation à ce propos](https://tkurtbond.github.io/posts/2021/07/17/groff-and-install-fontsh-and-installing-fonts-for-use-in-groff/)). 2. Pas de ligatures avec le script présenté au point précédent. J'ai ajouté la police [FiraCode](https://github.com/tonsky/FiraCode) et les ligatures ne sont pas présentes. Je n'ai pas suffisamment de connaissances à ce sujet pour savoir ce qui ne va pas. 3. Le format accepté des fichiers de polices est le TrueType Font (du moins, c'est le format qui peut être facilement converti dans le format accepté par `groff`), et je ne crois pas qu'il y ait beaucoup d'autres formats disponibles. 4. `neatroff` rend facile l'ajout de polices, mais je n'ai pas encore joué avec cette implémentation. 4. **Des notions contre-intuitives**. La gestion des environnements, par exemple, réserve quelques surprises. 5. **L'intégration de liens PDF**. * Il faut activer de nouvelles macros (les macros `ms` n'incluent pas la gestion de liens PDF). * Là encore, c'est géré de base dans `neatroff`. 6. **Rendu navigateur moche**. Je ne sais pas quelle est la cause, mais le texte de base est hideux. En bref, **rien d'insurmontable**. Ces problèmes peuvent probablement se résoudre en contactant une communauté d'utilisateurs. Je pense également que l'usage des macros `ms` y est pour quelque-chose, ces macros sont parmi les plus simples mais offrent moins de possibilités. Dans les problèmes rencontrés **mais réglés** : 1. **UTF-8**. Il faut appeler `preconv` dans la chaîne de compilation ou faire appel à `groff -k`. J'ai eu des problèmes (je ne me souviens plus des détails) qui m'ont mené à implémenter [un filtre](https://github.com/KaneRoot/grofftut/blob/master/bin/utf8-to-ms.sh) remplaçant les caractères UTF-8 (principalement des accents) en leurs macros `ms` respectives. Comme pour `preconv`, il suffit de mettre mon script dans le pipeline de compilation et l'UTF8 est géré. 2. La confusion entre les implémentations, les macros et où trouver de la documentation. Les pages de manuel sont parfois incohérentes entre elles, ou incomplètes, voire peu claires. Ça prend un peu de temps pour être à l'aise, et même si je n'ai pas encore appris tous les concepts, ça rentre petit à petit. 3. Sous OpenBSD, le fichier de configuration `troffrc` présent par défaut empêche catégoriquement de justifier les paragraphes. C'est pour cela que le dépôt du modèle inclut un `troffrc` personnalisé. Rien de bien méchant, mais c'était frustrant à mes débuts. En tout cas, avoir un exemple comme le modèle que je vous ai partagé m'aurait grandement aidé. # Pourquoi je m'y suis intéressé (optionnel, je raconte ma vie) Avant de terminer, un petit mot sur la raison qui m'a poussé à me renseigner sur Roff, **au cas où ça intéresse quelqu'un**. ## Mes débuts avec la typographie J'ai passé une thèse en 2019 en informatique. Cette expérience m'a obligé à bouffer de la création de documents à n'en plus finir (ma thèse a été 6 mois de développement, le reste c'est de l'écriture de papiers). J'aimais pas ça, mais petit à petit j'y ai pris goût. Écrire un papier, c'est voir son idée grandir, se développer, se préciser, et obtenir un meilleur rendu (pour satisfaire un journal qui récolte tout le fruit de ton travail sans un merci parce que t'es complètement sa p...). En tout cas, voir son papier gagner en maturité, voir le rendu s'améliorer sous les ~~ordres~~ conseils de son directeur de thèse, c'était assez plaisant. ## Lire et retenir Aujourd'hui, comme je n'ai pas eu le temps de le faire pendant mes études, je me documente sur plein de sujets qui m'intéressent. Par exemple, j'ai commencé à regarder des langages de programmation qui ont des paradigmes que je n'ai pas suffisamment explorés. Un peu d'astronomie, de politique aussi. Plus je bouquine, plus j'ai envie de résumer ce que je lis. **Documenter pour ne pas oublier**. Je ne suis pas un grand lecteur, et relire un livre m'est rébarbatif : je lis pour apprendre, pas pour le plaisir de lire. ## Documenter, mais quel format ? _Le format web_ : Résumer un livre via un article de blog n'est pas un format qui me convient. Le web est selon moi un foutoir incroyable, le html incluant de force une sémantique (pauvre) et se basant sur des outils trop compliqués. Tout change, tout le temps : les outils, les langages, les sites web. Je ne parle même pas des centaines de technos existantes et bâclées. Un site ça vit, ça meurt. Je veux sortir de cette logique. _Le format papier_ : Un document PS ou PDF s'approche du format papier, et selon moi les papiers de recherche ont le meilleur format pour résumer et expliquer des concepts. Comme le web, un document papier comporte des titres, tableaux, schémas, couleurs, graphes, équations et un style facilement modifiable. Mais le format papier possède également des notes en bas de page pour ce qui relève du détail anecdotique. C'est un format connu, universel et agréable. Autre avantage : pouvoir collecter ces documents sans l'intermédiaire du web (nos navigateurs sont des monstres), apprécier une lecture hors ligne. Tout ça c'est important **pour moi**. ## Documenter, mais quel outil ? Pour ma thèse, j'ai utilisé LaTeX, comme tout le monde. J'aime plutôt bien cet outil, mais je voulais en expérimenter d'autres, plus minimalistes. LaTeX a quelques gros avantages par rapport à sa concurrence (LibreOffice et MS Word), mais il reste plutôt gourmand (taille, durée de compilation) et complexe. Idem pour les outils qui gravitent autour. Au fond, ai-je besoin de quelque-chose d'aussi lourd pour mes documents perso ? Je veux un format papier et typographier sémantiquement mon document (par exemple, lorsque je cite un module ou une fonction). Au revoir markdown. Roff a piqué ma curiosité de part son âge et son adoption (plus ou moins) universelle sur les distributions Linux et les BSD. Après tout, pourquoi vouloir installer d'autres outils que ceux qui sont déjà présents, s'ils font le travail ? Puis je suis l'élite de la nation au RSA, j'ai le temps de me documenter sur des langages obscurs. ## Mes débuts avec roff (bonus !) Après avoir dissipé légèrement ma confusion entre tous les outils existants (implémentations, macros, les outils annexes), et surtout après avoir vu [une page montrant des exemples](https://troff.org/prog.html) qui m'a bien motivé à pratiquer, j'ai fait quelques tests sur ma machine. Par la suite j'ai résumé ce que je lisais avec `groff`. Je n'ai terminé aucun de mes documents pour le moment, j'ai un peu la bougeotte. J'ai quand même bien entamé certains sujets, quelques exemples de résumés : * [Haskell](https://t.karchnu.fr/doc/haskelltut.pdf) pour explorer la programmation fonctionnelle. Gros morceau que je tente d'expliquer à ma façon (sans trop de jargon mathématique). J'ai expliqué les bases et j'ajoute des parties de temps en temps. Mon objectif étant de résumer tout ce que j'ai pu lire sur le net à ce sujet; marre de fouiller des centaines de commentaires reddit pour avoir une explication cohérente. Une fois que le document sera suffisamment avancé j'en ferai peut-être une dépêche sur linuxfr (abonne-toi, mets la cloche). * [« A Universe From Nothing »](https://t.karchnu.fr/doc/universe-from-nothing.pdf) de *Lawrence Krauss*. Je m'intéresse aussi à l'astronomie, et j'ai commencé à résumer le livre. Je suis loin d'avoir fini de résumer (seuls les 2 premiers chapitres sont réellement là), mais ça peut donner une idée d'un rendu. J'ai également quelques notes par ailleurs, pas assez avancées pour être montrées pour le moment. Notamment mon point de vue sur les langages de programmation en général (petite explication du comment et du pourquoi de Haskell, LISP, tcl, Zig, assembleur, m4, dc, awk, etc.). NB : le style de ces documents n'est pas définitif. Je mets peut-être un peu trop de couleurs et la police pourrait être changée par endroits. Mais cela donne de bons exemples de ce qui est possible avec `troff`. # Conclusion Parfois j'ai l'impression que les outils disponibles pour `troff` sont en avance par rapport aux outils modernes. Par exemple, `pic` est un outil de programmation pour générer un schéma, avec tout la souplesse que ça apporte. Faire des schémas avec une GUI me semble, dans une certaine mesure, plus contraignant. C'est d'autant plus le cas quand on doit faire plusieurs schémas pour un même document, forcer le même style pour tous les schémas est trivial avec `pic` (mêmes polices, épaisseur de traits, etc.). Malgré avoir utilisé LaTeX pendant des années, j'ai davantage lu la documentation de `groff` et je pense mieux le maîtriser. Les documents produits sont d'une qualité suffisante à mon goût. Je vois encore des modifications à apporter à mes macros et je continue de jouer avec l'outil, mais j'ai suffisamment de recul pour comprendre que `roff` me convient. Bref, j'attends vos retours ou vos questions si vous en avez. Merci de m'avoir lu jusqu'ici ! PS: si vous éprouvez une haine viscérale envers Roff et consorts, passez votre chemin. J'ai aucun problème avec ça, mais ne perdons pas notre temps dans des dialogues de sourds. PS : si Sygne est toujours parmi nous, je veux bien savoir si son projet `utroff` est toujours pertinent. Il en avait fait des dépêches il y a maintenant 8 ans, et le site est malheureusement hors ligne maintenant.