為什麼我的 Markdown 會跑版?

Markdown 的發展史簡介

這個問題困擾了我好一陣子,直到有朋友和我說,Markdown 有很多種標準,頓時茅塞頓開。既然程式語言有分版本,HTML 也有不同版本,那麼副檔名都是 .md 的 Markdown 也有很多種版本,似乎也是合理的事情。

那下一個問題就是:

Markdown 有沒有一個統一的標準?

答案是沒有的。

而且也不會有,因為大家需要的 Markdown 可能不太一樣

最簡單的例子就是換行,就標準的 Markdown 語法,當你在 .md 檔內換行,並不會真的換行。如果你要做到換行,必須在行尾加入兩個空白,或是手動插入 <br>。不過像是台灣知名的線上筆記服務 HackMD,就很貼心的配合了台灣人的打字習慣,幫你把每個換行都變成真正的換行。

其實包含 HackMD 在內,大部分的 Markdown 服務都有切換換行模式的選項,為了滿足每種人。也因此 Markdown 不會有真正統一的標準。

但是撇除這種選項式的差別之外,目前最知名的應該是 CommonMark 了,若要問為什麼叫 CommonMark 這個名字?而 CommonMark 跟一般的 Markdown 有什麼差別?就必須從 Markdown 的歷史說起。

The Origin

一切的開端,是 2004 時 John Gruber 提出的 Markdown 標準,也是一般所說的經典的 Markdown,以 BSD 開源。

Markdown 的理念

John Gruber 的文章寫道:

The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions.

簡單來說,就是想要創造一個易讀而且易寫的格式,也因此和 reStructuredText 一同被歸類為輕量級的標記語言(當然不只這兩種,可以參考 GitHub 支援列表)。比起更早出現的 reStructuredText,Markdown 似乎又更簡單一些,雖然 Markdown 比起 reStructuredText 的功能較少,而且標準化也較晚,但並不影響 Markdown 受歡迎的程度。

John Grube 以 Perl 寫了第一個 Markdown to html 轉換器,一般被稱為 Markdown.pl,但沒多久就沒有繼續維護了。而且隨著使用的人越來越多,漸漸有定義相關的問題產生出來,於是後來群雄並起,產生了各種分支。

原始 Markdown 的語法的中文翻譯可以看這個網站。或是 Markdown Guide 這邊有個英文的對照表

值得一提的是,這時候的 Markdown 的 Code Block 並不是大家熟悉的那種 ``` 開頭並且可以註記語言種類的 fenced code block:

```javascript
console.log('Hello, markdown!')
```

而是利用縮排的 indented code block,並不支援 syntax highlighting(因為不能註記語言種類)。注意前面有四個空格(或是一個 tab):

    console.log('Hello, markdown!')

Markdown Extra

2005 年由 Michel Fprtin 發表,基於原始 Markdown 並修改及新增一些功能,並在當時希望這些能成為未來 Markdown 的標準(下面的 CommonMark 和 GFM 都分別和 Markdown Extra 有一些相同的特色),除了表格之外,其中比較特別的功能是支援腳註(Footnotes)和縮寫。官方編譯是 PHP Markdown

因為不是這篇的重點,詳細介紹可以到他們的網站

MultiMarkdown (MMD)

就在 Markdown Extra 發表的隔天,Fletcher T. Penney 發表了 MultiMarkdown,同樣也是基於原始 Markdown,希望能夠變得更接近像是 XHTML 或是 LaTeX 之類的排版語言,可以看作者的介紹

It adds multiple syntax features (tables, footnotes, and citations, to name a few), in addition to the various output formats listed above (Markdown only creates HTML). Additionally, it builds in “smart” typography for various languages (proper left- and right-sided quotes, for example).

一樣支援表格和腳註等功能,但為了進一步進行更複雜的編寫,也支援引用、數學式、圖片說明等等功能。另外也支援更多的輸出格式,例如 PDF 和 OPML(一種開放式文件檔案格式,可以進一步讓 Microsoft Word 使用)。官方編譯器是原始的 Markdown.pl 的延伸,存放在這個 repo

CommonMark

因為原始 Markdown 就這樣缺乏後續的維護,因此就有人提出要接續幫 Markdown 進行語法的標準化以及規範的進一步維護,這就是 CommonMark 的開端。從 2012 年開始,包括 Jeff Atwood(Stack Overflow 的共同創辦者之一) 在內的一群人啟動了所謂的 Markdown 標準化工作(Standard Markdown,這個專案原本的名字,但是在原作者要求之下改名為 CommonMark,還為此叫他們換掉原本的 domain 並且不能直接重新導向到新網站)。

根據 Jeff Atwood (註:高中力學教的阿特午機的阿特午,英文也是 Atwood)的 blog 文章,這個計畫有以下的目標:

  • 定義更明確的 spec,把可能有爭議的語法全部定義清楚要怎麼轉換成 HTML(所以這個檔案超長)
  • 新增一些選項,可以被關閉 / 開啟以符合各種需求,例如:
    • intra-word emphasis:字串內部的強調是否要用空格隔開
    • auto-hyperlink:是否自動為文章中的網址建立超連結
    • automatic return-based linebreaks:是否要把 return 視為換行
  • 測試集(和 spec 放在同一個 repo)
  • 整理已知的變體(雖然 CommonMark 本身就是個變體

因此 CommonMark 和原始的 Markdown 有這些差別:

新增項目(有許多並非 CommonMark 的創舉,而是很多已經在使用的 Markdown 已經先加入了):

  • 所有 symbol 都可以被 backslash-escaped(中文叫跳脫字元,為了防止和保留字元混淆,因此在打某些特定符號的時候,例如\的時候,必須要打成\\。),因為他們發現一般人很難記得哪些字元要 escape XD
  • 加入 backslash 換行機制(原本只能雙空白,很難在文字編輯器上面被注意到)
  • 1)也可以被當作數字列表(原本只能用 1.
  • 允許非 1 開始的數字列表
  • 加入大家很常用的 Fenced code blocks:用 ```~~~ 開頭

更動:

  • 當使用了不同的 list 的符號,會被判斷成分開的 list(例如: -, +, * 以及 1., 1)
  • > 用空行分開後,會被判斷成分開的 Quote,而不是合併成一個
  • Link Syntax 改善,e.g. 單引號也可以被用在 Reference Link 的 Title 裡面(原本只有 Inline Link 可以)

CommonMark 旨在建立一個嚴謹的標準,而不是支援更多的功能,雖然上面有提到新增的語法,但是那些都是替代性語法,並不是真正的新功能。也因此,只要是原始 Markdown 沒有的功能, CommonMark 也不會有。

官方提供的編譯器有兩個,一個是 cmark,一個是 CommonMark.js,從名稱就能看出是基於什麼語言、或是給什麼語言用的了。

GitHub Flavored Markdown (GFM)

GFM,中文意思是「GitHub 偏好的 Markdown」,2017 年發布,基於 CommonMark,再加上一些 GitHub 上可能會用到的功能,簡單來說,就是 GitHub 現在正在用的 Markdown(但其實在 GFM 之前的 2012 年,GitHub 就有支援 Markdown 了)。

主要擴充:

GFM 的規範在此,這邊僅列出和 CommonMark 不同之處(其實它就是直接從 CommonMark 的 cmark 拉個分支出來

關於 HackMD

HackMD

在台灣寫一篇 Markdown 的文章,不能不提一下 HackMD

HackMD 是基於 Markdown 之上(其實他們並沒有說清楚是基於哪種 Markdown 之上,不過你想的到的功能他們都有,甚至還能插入 YouTube 影片),加上一堆很 fancy 的語法,又是台灣出產的線上筆記服務,只要打開瀏覽器就能使用,而且還能即時預覽!

有開源版本 CodiMD,也提供企業版的 SaaS (Software-as-a-Service),還能把版本歷史整合進 GitHub,讓大家愛上 Markdown 的好地方。

介紹的部分我就不多敘述,隨手 Google 兩篇看起來不錯的介紹:

個人認為在台灣的 Markdown 推廣,HackMD 一定會扮演一個重要的角色,因為真的太好用了,而且又免費!根本佛心來著。

小結

Markdown 有各種規範,也有各種選項可以調整,像是我的網站是基於 Hugo,一個 Go 編寫的靜態網站生成器(SSG),所以採用了同樣是 Go 編寫的 blackfriday 來編譯(0.60 版之後的 Hugo 已經改為使用 Goldmark 作為 Markdown 編譯器了,詳情在這篇文章:Now CommonMark Compliant)。

為了能夠方便寫作,我在我的網站把可調選項(例如換行)調整成和 HackMD 的選項一樣,希望能夠最大化相容,並且最小化需要額外修改的地方。

寫了這麼多,希望大家在處理各種 .md 檔的時候,在享受 Markdown 帶來的便利(和潮感)之外,不要跟我一樣四處踩雷 QQ

參考資料

我在寫這篇的時候讀的文章,有些連結附在文章裡面了,就不再貼一次: