rOpenSci | Résoudre ses problèmes de Pandoc en tant qu'utilisateur·rice de R

Résoudre ses problèmes de Pandoc en tant qu’utilisateur·rice de R

Merci à Hugo Gruson pour ses commentaires utiles sur cette traduction!

Le logiciel libre Pandoc par John MacFarlane est un outil très utile : par exemple, Yanina Bellini Saibene, community manager de rOpenSci, a récemment demandé à Maëlle si elle pouvait convertir un document Google en livre Quarto. Maëlle a répondu à la demande en combinant Pandoc (conversion de docx en HTML puis en Markdown par le biais de pandoc::pandoc_convert()) et XPath. Tu peux trouver le paquet expérimental qui en résulte, quartificate, sur GitHub. Pandoc n’est pas seulement utile de manière anecdotique : il est utilisé par R Markdown et par Quarto. Alors, que tu jongles avec des documents de différents formats ou que tu cherches simplement à publier tes analyses reproductibles, tu as peut-être utilisé Pandoc (même si tu ne le savais pas !), ou peut-être que tu… devrais utiliser Pandoc.

Parfois, tout se passe bien, parfois, tu penses à Pandoc parce qu’il semble être la source d’une erreur. Dans ces cas-là, Maëlle, qui a assisté au travail de détective de Christophe1 dans plusieurs issues GitHub, a tendance à se demander “Que ferait Christophe ?”. La réponse est probablement “lire la doc et enquêter”. Dans ce billet, nous rassemblons des ressources et des astuces pour t’aider à dépanner tes soucis Pandoc en tant qu’utilisateur·rice de R.

🔗 Pandoc 101

Supposons que nous ayons un fichier Markdown et que nous voulons le convertir en HTML. Nous pouvons le faire à partir de R en appelant la fonction pandoc::pandoc_convert()2 qui est une interface Pandoc pour R. Si tu préfères le terminal, l’interface en ligne de commande pandoc te sera utile. Dans la suite de ce billet, nous utiliserons le paquet R pandoc pour les exemples.

# Créons un fichier temporaire d'exemple Markdown
md_lines <- c(
  "# Important announcement", "",
  "[Pandoc](https://pandoc.org/) is **great**!"
)
md_file <- withr::local_tempfile()
brio::write_lines(md_lines, md_file)

# Convertissons-le en un fichier temporaire HTML
html_file <- withr::local_tempfile()
pandoc::pandoc_convert(
  file = md_file, 
  from = "markdown", 
  to = "html", 
  output = html_file
)
## /tmp/Rtmp1xdbdw/file273fd5b95f546
# Lisons le résultat !
brio::read_lines(html_file)
## [1] "<h1 id=\"important-announcement\">Important announcement</h1>"
## [2] "<p><a href=\"https://pandoc.org/\">Pandoc</a> is"             
## [3] "<strong>great</strong>!</p>"

Cette magie de passer d’un langage de balisage à un autre est le travail de Pandoc. Pandoc prend en charge de nombreux formats d’entrée et de sortie, avec des réglages disponibles pour divers éléments.

Par exemple, nous pourrions modifier légèrement l’appel pour ne pas obtenir d’identifiant pour l’en-tête h1 dans le HTML (c’est-à-dire supprimer l’élément id de l’en-tête <h1> ).

pandoc::pandoc_convert(
  file = md_file, 
  from = "markdown-auto_identifiers", 
  to = "html", 
  output = html_file
)
## /tmp/Rtmp1xdbdw/file273fd5b95f546
brio::read_lines(html_file)
## [1] "<h1>Important announcement</h1>"                 
## [2] "<p><a href=\"https://pandoc.org/\">Pandoc</a> is"
## [3] "<strong>great</strong>!</p>"

Ce n’est qu’un aperçu de ce que Pandoc peut faire.

🔗 Quand Pandoc est-il le problème (ou la solution) ?

Si tu fais appel à Pandoc toi-même, directement ou par l’intermédiaire de pandoc de Christophe, tu sauras évidemment que Pandoc est impliqué dans le processus.

Dans d’autres cas, Pandoc peut être enfoui sous des couches d’autres logiciels. Par exemple, avec R Markdown, le paquet rmarkdown appellera d’abord knitr avant d’appeler Pandoc. Même chose avec Quarto qui appellera knitr ou jupyter avant d’appeler Pandoc.

Voici quelques éléments pour t’aider à déterminer si c’est Pandoc qui te fait trébucher :

  • Si tu obtiens une erreur avec ton code R, Pandoc n’est pas en cause.

  • Si tu peux voir une erreur Pandoc dans la sortie, cela signifie généralement que quelque chose ne va pas pendant l’étape de conversion Pandoc. Le débogage à l’aide du fichier d’entrée transmis à Pandoc sera le plus facile. Si l’outil que tu utilises crée cette entrée pour toi (comme R Markdown ou Quarto), ajoute la configuration pour conserver l’entrée Markdown. Lis la sous-section suivante pour plus de détails !

  • Si tu te dis “mais ça marchait hier !”, par exemple “je n’ai rien changé du côté de R mais ça ne marche plus” : peut-être que la version de Pandoc a changé ? Un changement de version de Pandoc, peut-être en utilisant la fonctionnalité du paquet pandoc pour gérer la version de Pandoc, par exemple, peut révéler un problème avec une nouvelle version de Pandoc, mais c’est rare.

Dans tous les cas, Pandoc peut aussi être ton problème si tu repousses les limites de ce que tu peux réaliser avec un autre outil en utilisant Pandoc. Par exemple, si tu veux une conversion particulière, comme avoir des emojis à la :​grin: dans tes diapositives Quarto reveal.js, tu devras peut-être modifier quelque chose lié à Pandoc.

🔗 Comment accéder à l’entrée de Pandoc

Même si Pandoc est un convertisseur générique qui peut gérer plusieurs formats en entrée et en sortie, dans l’écosystème R Markdown et Quarto, le format d’entrée sera toujours Markdown par le biais d’un fichier .md.

Lorsque l’on utilise un .Rmd ou un .qmd le document sera converti en .md par knitr avec tout le code et les résultats assemblés. C’est l’entrée que Pandoc utilisera pour convertir le document en sortie souhaitée. Le cookbook (livre de recettes) R Markdown de Yihui Xie, Christophe Dervieux et Emily Riederer propose un diagramme pratique pour comprendre cette relation.

En général, les outils de ce type ont une certaine configuration qui te permet de garder les intermédiaires pour déboguer plus facilement : keep_md ou keep-md respectivement pour les formats R Markdown et Quarto.

L’exploration de ce fichier intermédiaire en entrée de Pandoc peut aider à comprendre ce qui sera vu par Pandoc et peut t’aider à déboguer, ou au moins à construire un meilleur exemple reproductible de ton problème.

🔗 Parler Pandoc

Maintenant que tu comprends la relation entre R et Pandoc, l’étape suivante consiste à comprendre le fonctionnement de Pandoc. Pensais-tu que nous n’irions pas aussi loin ? Malheureusement, c’est lorsqu’on commence à explorer le fonctionnement d’un outil que toute la… magie se dévoile 😉 .

Tout d’abord, comment trouver la documentation de Pandoc ? Tu peux taper pandoc::pandoc_browse_manual(). Ou tu peux mettre un signet sur la page URL du manuel Pandoc. Il s’agit d’un MANUEL tout en majuscules, ce qui souligne l’importance de le lire : si tu le parcours au moins une fois, tu auras une meilleure idée de ce qu’il contient… et de la façon dont les choses sont référencées dans le monde Pandoc, de sorte que tu pourras poser de meilleures questions à ton moteur de recherche ou à tes collaborateur·rice·s ! Tu peux même être récompensé pour avoir lu le MANUEL Pandoc !

Ensuite, comment apprendre à “parler Pandoc” ?

Tu peux utiliser un moteur de recherche pour affiner tes mots-clés : tu trouveras peut-être des fils de discussion avec des questions posées par des personnes utilisant le même vocabulaire approximatif que le tien, avec des réponses plus affinées. Par exemple, Maëlle cherchait récemment une option dont elle connaissait l’existence, pour transformer des choses qui ressemblent à des URL en Markdown, comme https://ropensci.org, en liens en HTML, par exemple <a href="https://ropensci.org">https://ropensci.org</a>. Elle a d’abord cherché des “raw/naked links”, avant de (re)découvrir qu’il s’agit de bare URIs, avec l’extension appelée autolink_bare_uris.

En parlant d’extension ! Quel est le vocabulaire de base dont on a besoin pour résoudre un problème avec Pandoc ? Cela vient avec le temps mais une bonne liste de départ serait…

🔗 Formats

Le format que Pandoc convertit depuis et vers. Il y a une liste impressionnante sur le site page d’accueil de Pandoc. docx, gfm (GitHub flavored Markdown), HTML, RTF…

Dans Quarto et R Markdown, tu es censé·e écrire par défaut en “Pandoc’s Markdown”, qui est une variante spéciale de Markdown.

🔗 Extension

Les Extensions modifient le comportement des lecteurs et des rédacteurs de Pandoc. Les extensions sont des prolongements (ou des contractions, puisqu’elles peuvent être désactivées) de formats et non de Pandoc. Par exemple, “smart” interprétera certains éléments typographiques, par exemple deux tirets en tiret long3, et est activée par défaut pour Markdown. Donc, si tu veux convertir du Markdown en HTML sans transformer les deux tirets, tu utiliseras markdown-smart comme format d’entrée. Cela signifie que markdown moins l’extension smart. Toutes les extensions ne fonctionnent pas pour un format, alors assure-toi de lire la documentation (😉 ). Tu peux utiliser pandoc::pandoc_list_extensions() pour lister les extensions disponibles pour un format. Un format que Maëlle utilise souvent lorsqu’elle produit des diapositives avec Quarto est le suivant

format:
  revealjs:  
    from: markdown+emoji

pour avoir l’indispensable conversion des emojis. 🎉

Tu trouveras ci-dessous un exemple dans lequel nous appelons directement Pandoc. Note que dans cet exemple, nous utilisons directement des chaînes de texte, sans rien écrire dans des fichiers, ce qui peut être pratique parfois !

# tiret long
pandoc::pandoc_convert(
  text = "I like Pandoc -- when it works as I want it to!",
  from = "markdown",
  to = "html"
)
## <p>I like Pandoc – when it works as I want it to!</p>
# pas de tiret long
pandoc::pandoc_convert(
  text = "I like Pandoc -- when it works as I want it to!",
  from = "markdown-smart",
  to = "html"
)
## <p>I like Pandoc -- when it works as I want it to!</p>

Généralement, en utilisant R Markdown ou Quarto, il n’y a pas besoin de modifier les extensions mais elles peuvent être la source des ennuis ou des différences que tu vois parfois.

🔗 Options

Tu vois comment nous nous sommes abstenus de qualifier les extensions d’“options” ? Parce que les options sont autre chose ! Ce sont des sortes d’arguments pour les appels Pandoc. Par exemple --mathml est une option pour rendre les mathématiques en MathML.

Certaines options peuvent être cachées par l’outil que tu utilises pour appeler Pandoc, ou facilement exposées en tant qu’argument : par exemple, l’option to de l’argument pandoc::pandoc_convert() est en fait une option Pandoc.

Ci-dessous, nous utilisons une option pour décaler les niveaux d’en-tête de 1, ce qui augmente le numéro de niveau de l’en-tête et réduit ainsi l’importance de l’en-tête.

pandoc::pandoc_convert(
  text = "# Important announcement\n\nPandoc is cool!",
  from = "markdown",
  to = "HTML", 
  args = c("--shift-heading-level-by=1")
)
## <h2 id="important-announcement">Important announcement</h2>
## <p>Pandoc is cool!</p>

Vois comment l’en-tête “Annonce importante” devient un h 2 dans le résultat.

Ces options peuvent être définies avec Pandoc en utilisant le format YAML à l’aide d’un fichier de défauts, defaults file. Il s’agit d’une autre technique avancée que nous n’aborderons pas en détail… mais tu connais maintenant les defaults file4.

🔗 Variables

Les variables sont les métadonnées que tu as peut-être l’habitude de transmettre à Pandoc via l’en-tête YAML (pour R Markdown et Quarto). Elles seront généralement utilisées dans les modèles pour choisir un contenu et un comportement spécifiques pour le format de sortie.

Elles peuvent également être passées via la ligne de commande, par exemple la fonction de format de sortie de rmarkdown peut les créer en tant qu’arguments de ligne de commande avec rmarkdown::pandoc_variable_arg().

🔗 Templates (Modèles)

Si tu demandes à Pandoc de créer un diaporama reveal.js, il le fera en utilisant son modèle par défaut. Le modèle est rempli avec ton contenu Markup mais aussi avec des variables comme les noms des auteurs. Tu peux fournir tes propres custom templates (modèles personnalisés) en utilisant l’option --template. pandoc::pandoc_export_template() crée un fichier contenant le modèle par défaut pour une version spécifique de Pandoc, que tu peux explorer ou utiliser comme point de départ pour créer ton propre modèle.

🔗 Raw attributes (Attributs bruts)

Supposons que tu aies du HTML brut dans ton document Markdown. Tu peux le protéger de l’analyse Pandoc en l’enveloppant dans un raw attribute (attribut brut). Ceci est par exemple utilisé par hugodown pour protéger les shortcodes Hugo.

Attention, cela fait partie de l’extension raw_attribute et peut donc ne pas être incluse par défaut et ne pas être prise en charge par le format que tu as choisi.

🔗 Comment utiliser ces choses ?

Ce dont tu as besoin pour résoudre un défi Pandoc donné peut être un format, une extension ou une option. C’est à toi de trouver la bonne combinaison, mais avoir une vague compréhension de ce que sont ces choses et comment les utiliser t’aidera. Une autre chose qui t’aidera, c’est de savoir comment passer ces choses à Pandoc en utilisant l’interface Pandoc de ton choix :

  • Si tu appelles Pandoc directement ou avec le paquetage pandoc, cela devrait être relativement simple (voir les liens et les exemples ci-dessus).
  • Si tu utilises R Markdown ou Quarto, tu devras peut-être rechercher, par exemple “R Markdown custom Pandoc templates” (modèles Pandoc personnalisés pour R Markdown). Par ailleurs, il existe peut-être une façon plus native d’utiliser R Markdown ou Quarto pour atteindre ton objectif sans avoir à utiliser Pandoc. Il est important de garder à l’esprit que ces outils exploitent largement Pandoc et visent à le rendre plus simple à prendre en main : les concepts sont les mêmes mais ils devraient être plus faciles à utiliser, même s’ils ne sont pas aussi variés.

🔗 Comment expérimenter avec Pandoc ?

Une fois que tu sais que ton problème vient de Pandoc, comment créer un exemple reproductible ? De manière peut-être surprenante, même si c’est très bien de créer un reprex (exemple reproductible) Pandoc, tu ne peux pas le créer avec le paquet reprex, parce que reprex utilise la machinerie R Markdown.

Dans ce billet, nous avons montré quelques exemples, en appelant Pandoc directement sur des chaînes de caractères, ou sur des fichiers temporaires créés avec withr.

Voici le code Rmd habituel de Christophe, fourni en tant que RStudio snippet:

dir.create(tmp_dir <- tempfile())
owd <- setwd(tmp_dir)
xfun::write_utf8(c(
    "---",
    "title: test",
    "---",
    "",
    "# A header",
    ${1:""}
), "test.Rmd")
rmarkdown::render("test.Rmd", "${2:html_document}"${3})
setwd(owd)
unlink(tmp_dir, recursive = TRUE)

Dans tous les cas, comme pour tout reprex, il faudra le rendre minimal.

Pour dépanner le comportement de Pandoc à l’aide d’autres outils, voici quelques conseils utiles :

  • Tu peux tester Pandoc dans ton navigateur sur pandoc.org/try.

  • Avec Quarto, tu peux accéder au Pandoc intégré avec la commande quarto pandoc. C’est comme si tu appelais pandoc directement, mais en utilisant la version fournie avec la version de Quarto que tu utilises.

  • Avec R Markdown, rmarkdown::find_pandoc() te permettra de savoir où se trouve le binaire Pandoc. Tu peux l’exécuter dans un terminal, ou utiliser la famille de fonctions rmarkdown::pandoc_*.

  • Dans R, le paquet pandoc peut t’aider à exécuter une version spécifique, à comparer entre les versions et à isoler ton travail Pandoc.

Quel que soit l’outil que tu utilises, une fois que tu connais le numéro de version, tu peux exécuter Pandoc lui-même (à partir de R avec le paquet pandoc, à partir d’un terminal) en installant la bonne version.

🔗 Suivre l’évolution de Pandoc, ou épingler une version Pandoc !

Suivre l’évolution de Pandoc n’est vraiment pas obligatoire et la lecture du changelog (journal des modifications) pourrait être difficile à suivre sans une bonne compréhension du fonctionnement de Pandoc. Tu pourrais t’abonner à la liste de diffusion Pandoc. Mais il se peut, rarement, que tu aies besoin de passer au peigne fin la liste de modifications de Pandoc lorsque tu remarqueras quelque chose d’anormal.

Fais attention à la version de Pandoc que tu utilises localement et en intégration continue, surtout quand quelque chose ne fonctionne que sur ta machine.

Pour savoir quelle version de Pandoc tu utilises, tu peux utiliser…

Alors oui, faire attention à la version de Pandoc demande un peu d’attention.

Avec Quarto, c’est moins un problème qu’avec R Markdown puisque Quarto épingle une version de Pandoc. Dans le développement R Markdown, le but est de bien fonctionner avec la dernière version de Pandoc tout en continuant à fonctionner avec les versions plus anciennes. Il est important de le comprendre car cela peut signifier que des systèmes différents peuvent obtenir des résultats différents même s’ils ont la même version de R Markdown parce que la version de Pandoc n’est pas la même. Comme souvent avec R, il est préférable de mettre à jour régulièrement sauf si tu as une raison particulière de ne pas le faire.

Conseil particulier si tu construis quelque chose avec Pandoc sur un système d’intégration continue : épingle une version de Pandoc pour ta configuration de production (GitHub Actions workflow par exemple) afin qu’elle corresponde à ton environnement de développement local5.

Le paquet pandoc possède également des aides très pratiques de type withr pour exécuter le code avec une version donnée de Pandoc : pandoc::local_pandoc_version() et pandoc::with_pandoc_version(); ainsi qu’un argument version dans pandoc::pandoc_convert(). Cette fonction spéciale a pour but de faciliter les tests et le débogage entre plusieurs versions de Pandoc !

🔗 Au-delà de la documentation officielle, au-delà de Pandoc

Si la lecture de la documentation et l’expérimentation ne te permettent pas d’arriver à tes fins, que faire ?

  • Les réponses de John MacFarlane dans les questions GitHub peuvent être instructives. Voir cet exemple.
  • Tu pourrais parcourir, ou participer, à la liste de discussion Pandoc.
  • Si ton problème est lié à Pandoc pour R Markdown ou Quarto en particulier, rends-toi sur le forum de la communauté Posit ou dans leurs dépôts Github respectifs.

Et si Pandoc n’est pas suffisant pour ton cas d’utilisation ?

  • Quarto est en fait une interface plus facile à utiliser de Pandoc avec beaucoup de fonctionnalités supplémentaires et de nouveaux paramètres par défaut pour améliorer Pandoc pour la publication scientifique. Donc en général, si Pandoc n’est pas suffisant (ou difficile à utiliser), va voir Quarto (qui a des projets, etc.). Utiliser Quarto avec des fichiers Markdown (.md) revient à utiliser un Pandoc plus intelligent (pas de R, pas de calcul, seulement une conversion de texte).
  • Tu pourrais construire sur Pandoc. Christophe recommande de se renseigner sur les filtres Lua. Voir Filtres Lua pour Quarto; Filtres Lua pour R Markdown. Maëlle n’a pas encore appris à les utiliser, et a tendance à convertir les choses en HTML puis à les analyser avec xml26.
  • Tu pourrais ouvrir une feature request (demande de fonctionnalité) de Pandoc.
  • Tu peux utiliser autre chose que Pandoc, comme le paquet commonmark de Jeroen Ooms; ou le paquet markdown de Yihui Xie ou le paquet tinkr de Zhian Kamvar qui utilisent commonmark.

🔗 Conclusion

Dans ce billet, nous avons partagé quelques ressources utiles pour dépanner tes problèmes avec Pandoc. Il est crucial de se rappeler que même si cela peut sembler insurmontable, tes compétences et ton vocabulaire Pandoc s’amélioreront avec la pratique, comme par exemple en convertissant des documents Google pour une collègue ! 😉

En tant qu’utilisateur·rice de R, n’oublie pas que Pandoc soutient un grand nombre de tes outils de publication ; et qu’il existe un paquet R pratique pour interagir avec Pandoc : pandoc 🎉.

Si tu aimes jouer avec des fichiers de différents formats, tu pourrais aussi apprécier la lecture de cet article de blog sur rtika par Sasha Goodman.


  1. Si tu veux lire des exemples de dépannage, vois ceci: issue dans rmarkdown et l’issue correspondante de Pandoc; ou ceci Question pandoc↩︎

  2. Le paquet R pandochttps://github.com/cderv/pandoc est un développement assez récent et permet d’accéder à l’interface de programmation Pandoc à partir de R. Tu peux aussi utiliser la méthode plus habituelle rmarkdown::pandoc_convert() pour accéder à Pandoc utilisé avec R Markdown. ↩︎

  3. Maëlle pensait qu’il s’agissait de “long dashes” en anglais alors qu’on les appelle “em dash” en anglais. Parler pandoc nécessite parfois d’avoir un peu de vocabulaire typographique anglais ! ↩︎

  4. Au fait, c’est ce que Quarto exploite en interne pour que les options YAML du document puissent être transmises à Pandoc. Utile à savoir si tu débogues Pandoc dans Quarto. ↩︎

  5. C’est aussi une stratégie que l’on peut utiliser avec Hugo lors de la construction d’un site web statique ! Cela permet de s’épargner bien des maux de tête. ↩︎

  6. Bien que cela puisse faire en sorte que les flux de travail ressemblent au jeu The incredible machine↩︎