Pandoc 二十年

Lobsters Hottest 新闻

摘要

John MacFarlane 回顾了 Pandoc 二十年的发展历程,这款通用文档转换器从 2006 年基于 Haskell 起步,到如今被全球学术和写作工具广泛采用。

<p><a href="https://lobste.rs/s/blflqs/twenty_years_pandoc">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/03 21:38

# Pandoc - 二十年历程 来源:https://pandoc.org/twenty-years-of-pandoc.html 2006年8月3日,我将第一个版本的pandoc上传到了我的网站,并以自由的GPL许可证发布。Pandoc 0.1由大约3000行Haskell代码组成,除了GHC的标准库外没有任何依赖。它可以将Markdown、reStructuredText、HTML和LaTeX文档转换为这些格式中的任何一种,外加RTF或S5。当时我并不知道,这仅仅是接下来二十年间超过两百个版本的第一个;这个项目会成为用Haskell编写的最流行的程序(https://github.com/EvanLi/Github-Ranking/blob/master/Top100/Haskell.md);我会在修复错误、改进和项目管理上花费无数小时;我会与许多其他国家的程序员合作;pandoc会支持超过五十种文档格式;它会允许自动生成引文和参考书目;它会集成到像Quarto(https://quarto.org/)和Jupyter Notebook(https://jupyter.org/)这样的学术写作工具中;它会安装在世界各地的数百万台计算机上。 这一切是如何发生的?我想利用pandoc的生日来讲述这个项目的故事,尽我所能回忆。 *约翰·麦克法兰* *2026年8月2日* ## 史前史 人们经常问:为什么pandoc是用Haskell写的?这个问题本可以有很多好的答案:Haskell是一种非常适合编写这类应用程序的语言。但事实上,我并没有决定编写一个文档转换器,然后再决定使用Haskell。我先是决定使用Haskell,然后才决定用它编写一个文档转换器。 我是从一位哲学逻辑学家朋友格雷格·雷斯塔尔(Greg Restall)(https://consequently.org/)的博客上听说Haskell的。关于一本Haskell入门书,他说:“我很高兴这不是我很久以前1986年计算机科学入门课程的教科书。如果是的话,我可能会爱上计算,永远不会成为哲学家”(consequently.org(https://consequently.org/news/2004/05/10/haskell_and_logic/))。 出于对此的好奇(并且没有理会雷斯塔尔关于这可能会影响我未来哲学生产力的警告),我阅读了《A Gentle Introduction to Haskell》(https://www.haskell.org/tutorial/index.html)以了解这门语言的基础。但真正学习编程语言的唯一方法是用它写点东西。我看到Haskell很适合编写解析器和编译器,并且它附带了一个非常好的解析器组合子库(parsec),所以我决定编写一个Markdown解析器。 当时,已经有Perl、Python、Ruby和PHP版本的Markdown实现;它们都通过一系列正则表达式(https://en.wikipedia.org/wiki/Regular_expression)转换直接将Markdown转换为HTML。Pandoc采取了不同的方法。它使用解析器组合子解析Markdown,并生成一个真正的抽象语法树(AST)(https://en.wikipedia.org/wiki/Abstract_syntax_tree),然后可以将其渲染为HTML或其他格式。这是一种更可靠的架构(避免了许多正则表达式版本的怪癖)。它也更具可扩展性:通过编写*N*个解析器(“读取器”)和*M*个渲染器(“写入器”),可以支持*N × M*种转换。很快我添加了一个针对reStructuredText的读取器,因为我的许多讲义和 handout 都是用这种格式保存的。我还添加了一个LaTeX写入器,因为我想能够生成PDF。然后我又添加了一个Markdown写入器,这样我就可以开始将我的reStructuredText笔记转换为Markdown。项目从此就像滚雪球一样发展起来。 因此,一个最初只是出于拖延而诞生的项目,在Haskell写作的乐趣以及它对我自己学术工作日益增长的实用性中得到了滋养。 ## 最初的发布(2006–8) 2006年8月3日,我决定在我的网站上公开源代码。此时pandoc已经支持HTML、LaTeX、RST和Markdown作为输入和输出格式,以及RTF作为输出格式;还可以通过LaTeX生成PDF。 第一次发布时,除了给两个朋友发邮件外,我没有尝试宣传这个项目。那是在社交媒体(无论如何我从未使用过)、GitHub和Haskell包仓库Hackage出现之前。但显然有些人偶然在我的网站上发现了它并开始使用。10月,一位土耳其开发者Recai Oktaş联系了我,他正在努力获得Debian开发者认证,并希望为Debian linux打包pandoc。所以我与他合作完成了这项工作。这对我来说是一次很棒的学习经历,也大大提高了项目的知名度。 2007年期间,我继续改进pandoc,主要是根据自己的需求。0.3版本添加了DocBook写入器和现在标准的Markdown脚注语法。0.4版本添加了对Markdown表格、定义列表、上标/下标、删除线和增强的有序列表的支持,以及groff man page和ConTeXt的写入器。这是第一个发布到Hackage(https://hackage.haskell.org/)Haskell包仓库的版本,该仓库始于2007年。Hackage存档和新的`cabal-install`工具(自动解析和获取依赖)为依赖外部包提供了可能。 ## Pandoc 1(2008–17) Pandoc 1.0于2008年9月发布,新增了MediaWiki、GNU Texinfo(由Peter Wang贡献)、OpenDocument(由Andrea Rossato贡献)、ODT的写入器,以及带自动语法高亮的分隔代码块(现在称为“围栏”)。对ODT的支持需要能够创建zip存档,而当时没有Haskell包可以做到这一点,所以我创建了一个(`zip-archive`(https://hackage.haskell.org/package/zip-archive)),使用了优秀的`binary`包进行二进制解析和序列化。对语法高亮的支持需要一个语法高亮库,这在Haskell中也不存在。为此,我编写了`highlighting-kate`(https://hackage.haskell.org/package/highlighting-kate),它解析Kate文本编辑器使用的XML语法定义并将它们转换为Haskell代码高亮器。这使得pandoc能够立刻支持大量的语法。这个版本还包含使用CSL样式(https://citationstyles.org/)自动生成引文和参考书目的支持,使用了Andrea Rossato的`citeproc-hs`(https://hackage.haskell.org/package/citeproc-hs)库。 在整个这一时期,我参与了与其他Markdown实现者在(现已关闭的)`markdown-discuss`邮件列表(https://www.mail-archive.com/[email protected]/mail15.html)上的讨论。分隔代码块的语法——pandoc早在GitHub推广围栏代码块之前很久就支持了——是与PHP Markdown Extra的维护者Michel Fortin合作制定的。在向pandoc的Markdown添加扩展时,我注意参考已有的先例,例如复制了PHP Markdown Extra的定义列表语法。在此期间,我也意识到了Markdown语法中的许多歧义——这种情况我后来在commonmark项目中试图改进。 pandoc的下一个重大变化出现在1.4版本(2010年1月发布),它引入了一个灵活的模板(https://pandoc.org/MANUAL.html#templates)系统,取代了硬编码的页眉,使pandoc的输出更加可定制。 2010年,我们从Google Code(https://code.google.com/archive/p/pandoc/)迁移到了GitHub(https://github.com/jgm/pandoc),这进一步提升了项目的知名度。2010年和2011年的后续版本增加了对EPUB输出、Org-mode输出(由Puneeth Chaganti贡献)和Textile输入(由Paul Rivier贡献)的支持。Pandoc还通过我的`texmath`(https://github.com/jgm/texmath)库,支持将TeX数学转换为MathML(用于DocBook或HTML)。 Pandoc 1.9于2012年发布,终于使得生成Word docx输出成为可能。为了正确处理公式,我为`texmath`添加了对Word的OMML格式的支持。这个版本还增加了AsciiDoc写入器以及对Beamer和DZSlides的支持,在1.9.3中我们获得了DocBook读取器(由Mauro Bieg贡献,他后来成为了长期贡献者)。 2013年,我们专注于几个使pandoc更加灵活和可定制的特性。第一个是精细的Markdown“扩展”(https://pandoc.org/MANUAL.html#extensions)系统,允许支持当时正在激增的许多Markdown变体。第二个是在Markdown中包含YAML元数据块(https://pandoc.org/MANUAL.html#extension-yaml_metadata_block)的能力,其中的任意结构化字段可以填充模板变量。第三个是能够以Lua创建自定义写入器(https://pandoc.org/custom-writers.html),允许用户支持临时性的输出格式。第四个是引入JSON过滤器(https://pandoc.org/filters.html)——用户创建的程序,用于转换pandoc AST的JSON序列化,从而可以在解析阶段和渲染阶段之间自定义文档。引文处理从pandoc的核心移出,成为一个外部过滤器`pandoc-citeproc`(https://hackage.haskell.org/package/pandoc-citeproc)。 这个时代新增了reveal.js、EPUB v3、DokuWiki和FictionBook2输出;OPML输入和输出;以及Haddock和MediaWiki输入。值得注意的贡献者包括David Lazar(Haddock)和Sergey Astanin(FictionBook2)。 2014年迎来了三位新贡献者,他们后来为项目做出了许多贡献。Albert Krewinkel添加了对Org-mode输入的支持;Jesse Rosenthal添加了Word docx读取器(完全支持修订跟踪);Matthew Pickering(当时是牛津大学的学生,我作为Google Summer of Code学生对他进行“指导”)添加了EPUB和Txt2Tags作为输入格式。支持EPUB输入需要能够转换MathML公式,所以Pickering还研究了`texmath`。我们所在的时区非常不同,我记得每天早上醒来都会发现Pickering在夜里完成的所有工作。(Pickering后来成为了`ghc`编译器的核心维护者之一。)所有这些贡献都包含在pandoc 1.13中发布,还有Clare Macrae的DokuWiki写入器。 自2012年以来,我一直参与一个工作组,旨在制定Markdown语法的无歧义规范。该工作组由Jeff Atwood发起,成员包括来自GitHub、Reddit和Stack Overflow的代表。工作组在2012年进行了密集的讨论,但在2013年逐渐沉寂。我仍然相信这个项目,不想让我们所做的工作白费,所以在2014年8月,在学年开始之前,我坐下来撰写了一份Markdown规范,以及JavaScript和C语言的解析器。我将规范草稿发送给John Gruber征求意见,但没有收到回复,所以几周后我们发布了规范。此时,Gruber强烈反对,并要求我们不要把这个项目称为“Standard Markdown”,所以我们把名字改成了“commonmark”。这个项目是成功的,因为除少数例外,大多数Markdown处理器在其核心规则上都实现了commonmark规范(https://spec.commonmark.org/)。(Commonmark本身不涉及扩展。) Pandoc 1.14(2015年)增加了对commonmark和许多扩展的支持(起初通过绑定到C库`libcmark`(https://github.com/commonmark/cmark),但后来在2020年,通过我的Haskell包`commonmark`、`commonmark-extensions`和`commonmark-pandoc`(https://github.com/jgm/commonmark-hs))。我最终打算用commonmark核心替换pandoc的旧版Markdown解析器,但仍有一些关键扩展尚未实现,所以pandoc用户仍然必须在将文档解析为`markdown`(带pandoc扩展的Markdown)或`gfm`或`commonmark`或`commonmark_x`(带许多扩展的commonmark)之间做出选择。具有讽刺意味的是,尽管我是commonmark规范的作者,pandoc仍然使用pre-commonmark的Markdown解析器! 接下来的几年,pandoc AST发生了一些重要变化,增加了图像和链接属性、SoftBreak元素(使pandoc能够保留原始源文件中的换行,或者根据命令行设置进行换行)以及LineBlock元素。MarLinn添加了ODT读取器,Chris Forster添加了TEI写入器,Ivo Clarysse添加了对DocBook 5的支持。 ## Pandoc 2(2017–23) Pandoc 2.0(2017年发布)带来了一些巨大的架构变化,这些变化是与Jesse Rosenthal合作制定的。过去,pandoc的大多数读取器(解析器)和写入器(渲染器)都是“纯”的(https://en.wikipedia.org/wiki/Pure_function)(也就是说,它们的Haskell类型阻止它们产生任何副作用,包括I/O操作)。但某些格式需要能够进行I/O才能完全忠实地转换。(例如,reStructuredText有一种包含文件的语法,因此解析器需要能够读取文件;在其他一些格式中,图像需要显式大小,因此渲染器必须能够读取图像文件,甚至可能通过HTTP获取它们并确定它们的大小。)我们设计了一个系统,允许pandoc的读取器和写入器在PandocMonad(https://hackage-content.haskell.org/package/pandoc-3.10.1/docs/Text-Pandoc-Class.html#t:PandocMonad)类型类的任何实例中运行,并且我们提供了纯实例(可用于受控测试,以及在我们希望禁止I/O的情况下)和允许I/O操作的实例。该系统还提供了一种处理docx或EPUB等格式中作为资源包含的图像的方法。 另一个重大变化是引入了Lua过滤器(https://pandoc.org/lua-filters.html):过滤器在嵌入式Lua解释器中运行,直接操作pandoc AST,除了pandoc本身外不需要任何软件,并且性能远优于JSON过滤器。这得益于Albert Krewinkel的巨量工作,他基于`hslua`(https://hackage.haskell.org/package/hslua)——一个Haskell-Lua桥接库——实现了这一点。 此外,pandoc 2.0在pandoc的Markdown中引入了原生属性语法,并支持GitHub风格的Markdown(https://github.github.com/gfm/)、Emacs Muse(Alexander Krotov)、TikiWiki、Vimwiki(Yuchen Pei)、Creole(Sascha Wilde)、groff ms和JATS。旧的`highlighting-kate`被新的`skylighting`(https://github.com/jgm/skylighting)取代,后者提供了更好的性能和更准确的KDE语法定义解释。一个PowerPoint写入器(由Jesse Rosenthal贡献)很快随之而来,以及支持FictionBook2(Krotov)和man(Yan Pashkovsky和我)作为输入格式。 2018年,项目收到了来自Handshake(https://handshake.org/grant-sponsors/)的慷慨的10万美元捐款,我们在接下来的五年里用这笔钱为最活跃的维护者提供小额津贴。 2019年,添加了对`ipynb`(Jupyter笔记本)的支持,使pandoc可用于数据科学工作流,并且Jira wiki标记被支持为输出格式。通过pandoc 2.8,可以使用默认文件(https://pandoc.org/MANUAL.html#defaults-files)来指定默认选项集合。 用户长期以来一直抱怨pandoc的表格模型过于严格,甚至不支持行和列跨度。在广泛讨论了表格格式需要什么之后,Christian Despres设计了新的表格类型,并修改了所有读取器和写入器以使用它(这是一项大工程)。 此时pandoc已经支持了cita

相似文章

@0xQiYan: 兄弟们,平时有没有经常有各种格式转需要会员的情况,还在没有会员而烦恼? 发现一个各种格式转的开源项目,微软谷歌没做到的,一位哲学教授用业余时间搞定了。 Pandoc——文档转换神器,一条命令,几秒钟,50多种格式随便转。Word转PDF,…

X AI KOLs Timeline

介绍开源文档转换神器Pandoc,由哲学教授约翰·麦克法兰用业余时间开发,支持50多种格式互转,免费、开源、纯本地运行。

RISC OS Open 二十周年

Hacker News Top

RISC OS Open 迎来二十周年,回顾了将 RISC OS 操作系统开源过程中的关键里程碑,包括其移植到 Raspberry Pi。

Pandoc Templates

Hacker News Top

Pandoc Templates 提供针对期刊的 pandoc 模板,支持主要的统计学期刊,如 JASA、Biometrics 和 The R Journal。

Mercurial, 20年并持续:我们如何依然活跃?[视频]

Hacker News Top

这场FOSDEM 2026演讲探讨了分布式版本控制系统Mercurial如何在诞生20年后依然保持活跃和竞争力,尽管在人气上败给了Git。演讲者讨论了该项目的历史、社区、技术创新以及对版本控制未来的启示。