# 介绍
# 1. 什么是 GitHub Flavored Markdown?
GitHub Flavored Markdown,通常缩写为 GFM,是 Markdown 的方言,目前在 GitHub.com 和 GitHub Enterprise 上为用户内容而支持。
基于 CommonMark 规范的正式规范,定义了这种方言的语法和语义。
GFM 是 CommonMark 的严格超集。GitHub 用户内容中支持的所有功能以及未在原始 CommonMark 规范中指定的功能,因此被称为扩展,并且如此突出显示。
虽然 GFM 支持广泛的输入,但值得注意的是,在 GFM 转换为 HTML 之后,GitHub.com 和 GitHub Enterprise 会执行额外的后处理和消毒(sanitization),以此确保网站的安全性和一致性。
# 2. 什么是 Markdown?
Markdown 是一种用于编写结构化文档的纯文本格式,基于表示电子邮件和 usenet 帖子格式的约定。它由 John Gruber 开发(在 Aaron Swartz 的帮助下),并于 2004 年以语法描述 (opens new window)和 Perl 脚本(Markdown.pl
)的形式发布。用于将 Markdown 转换为 HTML。在接下来的十年中,许多语言都发展出了许多实现。有些人使用脚注,表格和其他文档元素的约定扩展了原始 Markdown 语法。有些人允许 Markdown 文档以 HTML 以外的格式呈现。像 Reddit,StackOverflow 和 GitHub 这样的网站有数百万人在使用 Markdown。 Markdown 开始在网络之外使用,编写书籍,文章,幻灯片,信件和讲义。
Markdown 与许多其他轻量级标记语法的区别在于它的可读性。格鲁伯写道:
Markdown 格式化语法的首要设计目标是使其尽可能可读。这个想法是 Markdown 格式的文档应该像普通文本一样可以发布,而不是看起来像是用标签或格式化指令标记的。(http://daringfireball.net/projects/markdown/ (opens new window))
可以通过将 AsciiDoc (opens new window) 的样本与 Markdown 的等价样本进行比较来说明这一点。以下是 AsciiDoc 手册中的 AsciiDoc 示例:
1. List item one.
+
List item one continued with a second paragraph followed by an
Indented block.
+
.................
$ ls *.sh
$ mv *.sh ~/tmp
.................
+
List item continued with a third paragraph.
2. List item two continued with an open block.
+
--
This paragraph is part of the preceding list item.
a. This list is nested and does not require explicit item
continuation.
+
This paragraph is part of the preceding list item.
b. List item b.
This paragraph belongs to item two of the outer list.
--
这是 Markdown 的等价物:
1. List item one.
List item one continued with a second paragraph followed by an
Indented block.
$ ls *.sh
$ mv *.sh ~/tmp
List item continued with a third paragraph.
2. List item two continued with an open block.
This paragraph is part of the preceding list item.
1. This list is nested and does not require explicit item continuation.
This paragraph is part of the preceding list item.
2. List item b.
This paragraph belongs to item two of the outer list.
可以说,AsciiDoc 版本更容易编写:你不必担心缩进。但 Markdown 版本更容易阅读。列表项的嵌套在源码中是显而易见的,而不仅仅是在处理后的文档中。
# 3. 为什么需要规范?
John Gruber 的 Markdown 语法的规范描述 (opens new window)没有明确指定语法。以下是一些未答复的问题示例:
- 子列表需要多少缩进?
规范说延续段落需要缩进四个空格,但对于子列表并不完全明确。很自然地认为它们也必须缩进四个空格,但是 Markdown.pl
并不需要这样。这不是一个“极端情况”,并且在这个问题上的实现之间的分歧,经常导致用户在真实文档中的意外。(参考 John Gruber 的评论 (opens new window)。)
- 在块引用或标题之前是否需要空行?
大多数实现不需要空行。但是,这可能会导致硬包装(hard-wrapped)文本出现意外结果,并导致解析模糊(请注意,某些实现会将标题置于 blockquote 中,而其他实现则不会)。(John Gruber也发言赞成要求空行 (opens new window)。)
缩进代码块之前是否需要空行? (
Markdown.pl
需要它,但文档中没有提到,有些实现不需要它。)paragraph code?
确定列表项何时包含在
<p>
标签中的确切规则是什么?列表可以部分“松散”还是部分“紧凑”?我们应该怎么处理这样的列表?1. one 2. two 3. three
还是这样?
1. one - a - b 2. two
(这是一些 John Gruber 的相关评论于此 (opens new window)。)
列表标记可以缩进吗?有序列表标记可以右对齐吗?
8. item 1 9. item 2 10. item 2a
这个列表中的第二项是主题中断,还是两个主题中断分隔的列表?
* a * * * * * * b
当列表标记从数字变为符号时,我们有两个列表还是一个? (Markdown 语法描述提示两个,但 perl 脚本和许多其他实现则生成一个。)
1. fee 2. fie - foe - fum
内联结构标记的优先规则是什么?例如,以下是有效链接,还是代码优先?
[a backtick (`)](/url) and [another backtick (`)](/url).
强调和强调标记的优先规则是什么?例如,如何解析以下内容?
*foo *bar* baz*
块级和内联级结构之间的优先级规则是什么?例如,如何解析以下内容?
- `a long code span can contain a hyphen like this - and it can screw things up`
列表项能否包括章节标题?(
Markdown.pl
不允许这样做,但允许 blockquotes 包含标题。)- # Heading
列表可以有空项吗?
* a * * b
可以在块引号或列表项内定义链接引用吗?
> Blockquote [foo]. > > [foo]: /url
如果同一参考有多个定义,哪个优先?
[foo]: /url1 [foo]: /url2 [foo][]
没有规范的情况下,早期的实施者咨询了 Markdown.pl
以解决这些含糊之处。但是 Markdown.pl
非常多,并且在很多情况下都给出了非常不好的结果,所以它不是一个令人满意的替代规范。
由于没有明确的规范,实现方式有很大差异。因此,用户经常会惊讶地发现,在一个系统上呈现单向的文档(例如,Github wiki)在另一个系统上呈现的方式不同(例如,使用 pandoc 转换为 docbook)。更糟糕的是,由于 Markdown 中没有任何内容被视为“语法错误”,因此通常不会立即发现分歧。
# 4. 关于本文档
本文档试图明确指定 Markdown 语法。它包含许多并排 Markdown 和 HTML 的示例。这些旨在兼容一致性测试。随附的脚本 spec_tests.py
可用于针对任何 Markdown 程序运行测试:
python test/spec_tests.py --spec spec.txt --program PROGRAM
由于本文档描述了如何将 Markdown 解析为抽象语法树,因此使用语法树的抽象表示而不是 HTML 是有意义的。但 HTML 能够表示我们需要进行的结构区分,并且测试的 HTML 选择使得可以在不编写抽象语法树渲染器的情况下针对实现运行测试。
该文档是从一个文本文件 spec.txt
生成的,用 Markdown 编写,带有一个小扩展,用于并排测试。脚本 tools/makespec.py
可用于将 spec.txt
转换为 HTML 或 CommonMark(之后可以将其转换为其他格式)。
在示例中,→
字符用于表示 tab。