Markdown et pandoc

Lors d’une discussion concernant l’Ă©criture de mon livre, j’ai expliquĂ© quels outils j’ai utilisĂ©.
Parmi ces outils, j’ai eu un usage de pandoc pour convertir du texte du format markdown en fichier .docx
.
Pour le rendu du manuscrit, mon Ă©diteur m’a demandĂ© un rendu au format .docx
, avec la contrainte d’un document par chapitre.
Les documents devaient suivre une feuille de style particuliÚre qui était fournie. La feuille de style contenait les styles pour les titres, citations, blocs de code, etc.
Je pense que ce format est le plus pratique pour les Ă©quipes de l’Ă©diteur. Mais la perspective de travailler dans Word ne m’enchantait pas (d’ailleurs, j’utilise LibreOffice sur mes postes Linux), je voulais pouvoir archiver mon travail sur Git, et inclure dans mes chapitres du code rĂ©ellement fonctionnel. J’ai donc cherchĂ© un moyen de pouvoir travailler dans un format de type markdown, que je pouvais prĂ©-processer.
pandoc et markdown
pandoc est un outil de conversion de documents. Il gÚre de nombreux formats en entrée et en sortie, dont le markdown et le docx !
AprĂšs avoir installĂ© l’outil, on peut convertir des documents. L’option -o
permet de prĂ©ciser le fichier de sortie, le format est dĂ©tectĂ© Ă partir de l’extension du fichier :
# générer un doc html
$ pandoc file.md -o file.html
# générer un word
$ pandoc file.md -o file.docx
La gĂ©nĂ©ration par dĂ©faut en format docx est tout Ă fait correcte et prend en compte les diffĂ©rents niveaux de titre, la gestion du gras et de l’italique, le code et les blocs de citation, ainsi que les listes, tableaux et images. Bref, tout ce qu’on peut basiquement faire en markdown.
Le markdown suivant :
# Content
Emphasis, aka italics, with *asterisks* or _underscores_.
Strong emphasis, aka bold, with **asterisks** or __underscores__.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
[I'm an inline-style link](https://www.google.com)

# Lists
1. First ordered list item
2. Another item
* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number
1. Ordered sub-list
4. And another item.
# Code and Syntax Highlighting
Inline `code` has `back-ticks around` it.
Use 3 backticks to create a code block
```shell
#!/bin/sh
echo "Hello World"
```
# Blockquotes
> Blockquotes are very handy in email to emulate reply text.
> This line is part of the same quote.
# Tables
| First Header | Second Header |
| ------------- | ------------- |
| Content Cell | Content Cell |
| Content Cell | Content Cell |
est transformé en docx avec la commande pandoc sample.md -o sample.docx
Le rĂ©sultat n’est pas des plus stylĂ©s, mais est dĂ©jĂ plutĂŽt pas mal, on voit bien que markdown est bien supportĂ© :
Rendre le document stylé
Lorsqu’il gĂ©nĂšre le fichier docx, pandoc peut utiliser un document qui lui servira de rĂ©fĂ©rence pour les styles.
La premiÚre étape consiste alors à générer le document de référence en utilisant la commande pandoc -o custom-reference.docx --print-default-data-file reference.docx
.
Cette commande génÚre alors le document contenant les styles par défaut.
Le contenu de ce document importe peu, il contient quelques éléments pouvant servir de test, seuls seront utilisés les styles.
Les styles utilisés par pandoc sont décrits dans sa documentation.
Ă noter que le code source inline est reprĂ©sentĂ© par le style de caractĂšres Verbatim Char, et le code source en blocs prendra le style de paragraphe Source Code (qui n’est pas créé par dĂ©faut dans le document de rĂ©fĂ©rence).
Pour redimensionner les images, il est aussi possible de préciser leur taille en attribut :
{ width=50% }
Une fois ce document personnalisĂ©, on gĂ©nĂ©re les fichiers docx en utilisant l’option --reference-doc=custom-reference.docx
:
pandoc sample.md -o sample-with-style.docx --reference-doc=custom-reference.docx
Pré-processing
L’utilisation du format texte markdown Ă©tant donc possible, je souhaitais pouvoir prĂ©-processer mes fichiers markdown pour :
- inclure du code source réel dans le document
- générer mes diagrammes au format drawio en png et les inclure dans le document généré
J’ai donc Ă©crit un peu de script qui fait tout ça.
Inclure le code depuis des fichiers externes
Il est possible avec pandoc d’exĂ©cuter des filtres pendant l’exĂ©cution de la transformation. L’utilisation des filtres n’est cependant pas trĂšs bien documentĂ©e, et s’appuie sur la manipulation d’un AST au format JSON. Cette approche, bien que plutĂŽt propre, me semblait quand mĂȘme compliquĂ©e pour simplement inclure du code dans mes fichiers.
J’ai donc trouvĂ© une autre solution plus simple : dans mes fichiers markdown, j’utilise une syntaxe de Commentaires pour recrĂ©er une espĂšce de macro, que je fais prĂ©-processer par un script shell.
La macro d’inclusion de code que j’ai utilisĂ©e est celle-ci :
[//]: # (INCLUDECODE FICHIER_A_INCLURE)
La syntaxe [//]: # ()
correspond Ă l’Ă©quivalent d’un commentaire markdown (cf ce stackoverflow).
J’ai alors simplement utilisĂ© un commentaire INCLUDECODE
devant ĂȘtre suivi du nom du fichier Ă inclure.
Pour prĂ©-processer ces macros, j’utilise la puissance du shell et le fait que pandoc accepte le contenu du document Ă transformer sur STDIN
.
Les 2 commandes suivantes ont un comportement identique (au delta de l’exĂ©cution d’un cat
en plus) :
# direct
$ pandoc sample.md -o sample.docx
# pipes
$ cat sample.md | pandoc -o sample.docx
Avec ce fonctionnement, il est facile de glisser un script shell entre deux :
$ cat sample.md |
./include-code-macro.sh |
pandoc -o sample.docx
Le script shell intercepte les lignes correspondant à la macro et insÚre le contenu du fichier référencé :
#!/bin/bash
regex='\[\/\/\]: # \(INCLUDECODE (.*)\)'
# Process input line by line
while IFS= read -r line; do
# Extract the filename using regex
if [[ "$line" =~ $regex ]]; then
filename="${BASH_REMATCH[1]}"
# Find the file
if [[ $? -eq 0 ]]; then
# Output the file content wrapped in code blocks
echo '```'
cat "$filename"
echo '```'
fi
else
# Output the line as is
echo "$line"
fi
done
exit 0
Ce petit script (trĂšs moche) fait permet donc d’inclure facilement mes fichiers externes. Cela me permet de les modifier sur le cĂŽtĂ©, et de regĂ©nĂ©rer mes documents d’un coup.
Générer des diagrammes drawio et les inclure
Pour gĂ©rer des diagrammes drawio Ă la volĂ©e, j’ai simplement suivi le mĂȘme principe : une syntaxe de type macro et un script pour la traiter.
La macro pour extraire un diagramme est du mĂȘme type :
[//]: # (DIAGRAM FICHIER_A_INCLURE)
Et le script est aussi similaire, il utilise le CLI de drawio pour exporter le diagramme dans un .png
, qui est ensuite inclus dans le markdown :
regex='\[\/\/\]: # \(DIAGRAM (.*)\)'
# Process input line by line
while IFS= read -r line; do
# Extract the filename using regex
if [[ "$line" =~ $regex ]]; then
filename="${BASH_REMATCH[1]}"
# Find the file
if [[ $? -eq 0 ]]; then
# export drawio diagram
drawio -x -f png --width 1024 -t "$filename" >/dev/null 2>&1
exported_file=$(basename "$filename" .drawio)
# add markdown for exported diagram
echo ""
fi
else
# Output the line as is
echo "$line"
fi
done
exit 0
J’aurais aussi pu utiliser directement une directive d’image de cette maniĂšre :

mais j’ai prĂ©fĂ©rĂ© rester avec mon format de macro. Cela me laissait la possibilitĂ© de factoriser mes scripts et d’introduire d’autres macros si besoin (besoin que je n’ai pas eu Ă©videmment, YAGNI comme on dit).
Je m’Ă©tais aussi laissĂ© la possibilitĂ© d’affiner les scripts pour redimensionner prĂ©cisĂ©ment les diagrammes, ou inclure du code entre 2 lignes, mais je n’en ai pas eu le besoin non plus.
La commande définitive
En cumulant tout ce qu’on a vu, la commande suivante fait l’inclusion du code, la gĂ©nĂ©ration des diagrammes Ă la volĂ©e, et la conversion en .docx
avec un style fourni :
$ cat sample.md |
./include-code-macro.sh |
./include-diagram-macro.sh |
pandoc -o sample-final.docx --reference-doc=custom-reference.docx
Le document généré par cette commande est maintenant complet :
Conclusion
pandoc permet de générer des documents Word assez propres de mon point de vue. Avec un peu de travail sur la feuille de style, il est assez facile de personnaliser le rendu des documents.
C’est d’ailleurs cette façon de gĂ©nĂ©rer les documents que j’ai utilisĂ©e pour Ă©crire (et compiler) mon livre !
En utilisant la puissance du shell, il est relativement facile de scripter l’inclusion d’Ă©lĂ©ments externes comme du code source, des diagrammes ou d’autres fichiers.
Liens et références
- Installation de pandoc
- Option
--reference-doc
- Les commentaires en markdown sur StackOverFlow
Photo de couverture par Arisa Chattasa sur Unsplash