Markdown是一种简洁的文本标记语言。 它基于纯文本,通过将某些字符当作记号,从而给文档标上一些结构。 跟HTML之类的纯标记语言相比,这些结构比较适合人眼阅读。 但是略显松散,不够严谨,机器解析起来比较容易出错。

Markdown的流行,在于它易于书写,适合对格式化要求不高的场景。同时作为一种中间格式,在不同的系统中受到广泛支持。

目前大部分的Markdown编辑器,形态都是文本编辑器。以纯文本的形式打开Markdown文件,然后对其解析,增加高亮。同时辅以分屏预览,让作者能够看到Markdown渲染出来的HTML页面。

对于简单的Markdown文本内容,上面的方式问题不大。但是对于复杂,文本中用于格式化的部分就会显得碍眼。对于复杂一点的格式,编辑容易出错,特别是针对Markdown不熟的用户来说。

另外就是,分屏预览,不仅挤占屏幕空间,而且滚动的时候存在不同步的问题。

有没有一款Markdown编辑器,可以帮助用户产生良好的Markdown文本,同时又带有lint功能,来帮助用户解决现有Markdown文本中存在的的问题,然后又能够帮助用户减少分屏预览时候的痛苦。

CommonMark Spec 3.0

1 Introduction

测试Markdown文本是否符合规范python test/spec_tests.py --spec spec.txt --program PROGRAM

2 Preliminaries

2.1 Characters and lines

字符定义为unicode码点。

单行定义为连续的非LF和CR字符,最后为行尾符。

空行是只包含空格符和制表符的单行。

一个统编空白字符式Zs分类中的任意码点,或制表符、行进符,块进符(form feed),回车符(carriage return)。

其他还区分了

  • ASCII控制字符
  • ASCII标点字符
  • 统编标点字符,即ASCII标点、或Pc, Pd, Pe, Pf, Pi, Po, Ps分类的码点。

2.2 Tabs

不展开成空格。但是需要的时候,会被等同成4个空格。

2.3 Insecure characters

U+0000必须替换成REPLACEMENT CHARACTERU+FFFD

2.4 Backslash escapes

任意ASCII标点可以捺线转义。捺线在其他字符前代表自己。

行尾的捺线表示一个硬换行(即<br />)。

捺线转义在 code blocks, code spans, autolinks, or raw HTML里面不工作。

2.5 Entity and numeric character references

HTML的Entity reference以及 numeric character reference在Markdown中可以用,但是受到一些限制。 (比如在code spans 或 code blocks中不可用)

Entity reference由&;构成,参考https://html.spec.whatwg.org/entities.json,例子如下:

&nbsp; &amp; &copy; &AElig; &Dcaron;
&frac34; &HilbertSpace; &DifferentialD;
&ClockwiseContourIntegral; &ngE;

Decimal numeric character references例子如下:

&#35; &#1234; &#992; &#0;

Hexadecimal numeric character references例子如下:

&#X22; &#XD06; &#xcab;

HTML中的一些entity reference可以省略末尾的分号,这不做支持。

3 Blocks and inlines

像paragraphs, block quotations, lists, headings, rules, code blocks这些,可以视作分块元素。

分块如block quotes和 list items可以包含其他分块。分块如headings 和paragraphs包含随行内容(如text, links, emphasized text, images, code spans等等)。

3.1 Precedence

提示分块的记号的优先级要高于提示随行的记号。

也就是说,解析可以分两部,先针对分块内容,再针对随行内容。

3.2 Container blocks and leaf blocks

分块可以有两种类型:容器块和子叶块。前者可以包含其他容器。

4 Leaf blocks

4.1 Thematic breaks

最多三个空格的缩进(超过就会被当成code block了)。然后是相同的三个或以上的-, _, *,每个之后可以跟任意数目的空格或制表符

Thematic breaks

  • 不要求前后有空行。
  • 可以破开一个段落。

优先级比setexheading低,比list高。

可以出现在list中。

4.2 ATX headings

前面的#个数代表层级,后面的#是可选的。 内容前后的空格和制表符会被去掉。 内容前面必须有一个空格或制表。

允许至多三个空格。 可以破开一个段落。 可以为空。

4.3 Setext headings

4.4 Indented code blocks

4.5 Fenced code blocks

4.6 HTML blocks

一个HTML分块是一组含有原始HTML字符串的行,在输出的时候不会被转义。

一共有7中HTML分块

  1. 起始条件:以<pre<script<style,或<textarea开始的,后跟一个空格、tab、字符串>,或行尾。
    • 结束条件:行包括</pre></script></style>,或</textarea>,不需要匹配起始条件
  2. 起始条件:行以为<!--开头
    • 结束条件:行包含-->
  3. 起始条件:<?,结束条件?>
  4. 起始条件:<!,后跟一个ASCII字母,结束条件>
  5. 起始条件: <![CDATA[,结束条件]]>
  6. <</开头,后跟众多可选标签的一个,后跟一个空格、一个tab、行尾、>,或/>,结束标识是一个空行
  7. 行以情况1中以外的一个完整的开标签开头,或者一个完整的闭标签,后跟0或多个空格以及tab,后跟空行。结束情况必须是一个空行。

HTML分块中的标签不会影响解析器状态。

类型7以外的HTML分块不会破开一个段落。

一个链接引用定义,含有一个链接标文,之前可以有至多三个空格的缩进,后有冒号,可选的空格或tab(包括至多一个行结束符),以链接目的地址,可选的空格或制表符(包括至多一个行结束符),一个可选的链接标题(必须跟之前的以空格或者tab分开)。不能出现其他任何字符。

链接引用定义可以出现在使用地之前、或者之后。

4.8 Paragraphs

不能被解释为其他分块的连续行,被解释为段落。

4.9 Blank lines

文档开头和末尾的空白行会被去掉。

分块元素之间的空白行会被忽略,除非用来区分一个列表是否是紧实还是松散的。

5 Container blocks

容器分块,顾名思义,可以容纳其他容器。 有两种基本的容器分块:blockquote和list item。 List则是list item的容器。

容器分块的语法是递归定义的。通常的形式如下:

X是一个分块序列,那么X转换的结果是一个Y类型的容器,以X为其内容。

5.1 Block quotes

分块引述记号为>,可以至多有三个空格缩进。

下列规则用于定义分块引述:

  1. 基本规则。如果一个连行串Ls构成一个分块序列Bs,那么在之前添加一个分块引述记号,会将Bs置于一个分块引述内。
  2. 惰性规则。比较复杂
  3. 接续规则。一个文档不能再一行上包含两个分块引述,除非有空行隔开。

除此之外,其他都不算。

5.2 List items

列表记号分逐点列表记号(-, + *)、有序列表记号1-9个阿拉伯数字(0-9)。(超过十个数字,有一些浏览器就会溢出)

5.2.1Motivation

略过。

5.3 Lists

一个列表是一至多个相同类别的列表项,它们可以以任意空白隔开。

6 Inlines

6.1 Code spans

……

6.2 Emphasis and strong emphasis

……

……

……

6.6 Raw HTML

……

6.7 Hard line breaks

……

6.8 Soft line breaks

……

6.9 Textual content

……

Appendix: A parsing strategy

(草草了事)