如果你是一位筆記愛好者,同時又從事編程相關工作,那自然聽說或使用過 Markdown
筆者在剛接觸編程時,有專門分析過 Markdown 的技術實現,時間轉眼過去一兩年,已經是一名深度的 Markdown 使用用戶,所有的文檔筆記和 ssg 博客內容都是出自於 Markdown...
現在回過頭來看,不禁想挖掘 Markdown 的發展歷史,順便將以前的技術分析統一成文,方便後續思考
主要人物#
作者 - John Gruber#
John Gruber 出生於費城,獲得了德雷克賽爾大學計算機科學學士學位,曾先後供職於 Bare Bones Software 和 Joyent。John Gruber 在 2002 年創建了個人博客 Daring Fireball,核心內容是關於蘋果公司的各類信息。
關於這位老哥的故事還可以多說幾句,他自 2006 年開始全職經營博客。他同時主持一檔名為 The Talk Show 的播客節目。最近幾年的 WWDC 大會期間,The Talk Show 都會邀請到蘋果高管進行面對面。蘋果高級副總裁 Phil Schiller、Eddy Cue、Craig Federighi,蘋果 AR 負責人 Mike Rockwell,銷售主管 Greg Joswiak 在 WWDC 2015 - 2018 期間先後在 The Talk Show 上亮相
John Gruber 在 Daring Fireball: Dive Into Markdown 中寫到在還沒有 Markdown 的當年,用 BBEdit 編輯和預覽 HTML 並拷貝到 Movable Type 發布的不愉快經歷。這種不爽的體驗促使他做出改變,為了更好地進行博客寫作,兩年後(2004 年)他發布了一個叫 Markdown 的工具
布道者 - Jeff Atwood#
Jeff Atwood 軟件工程師。先後創建了著名的編程問答網站 Stack Overflow 和開源論壇軟件 Discourse
前者是程序員解決問題三大件之一,另外兩個是 Google 和 Github;而後者是目前首選的架設論壇的開源軟件
Jeff 在 Markdown 發布的同一年開始自己的博客 Coding Horror。在該博客中,他表示自己是 Markdown 忠實鐵粉,記錄了他如何在早期的 Stack Overflow 使用 Markdown 的語法用於書寫問題和答案(Discourse 的也是集成 Markdown
發展歷史#
2004 - Markdown 起源#
2004 年 3 月,John Grube 發表了第一篇關於 Markdown 文章 Daring Fireball: Introducing Markdown,開始公開測試 Markdown
同年 8 月正式發布 Markdown 1.0
在 2004 年 12 月更新到 1.0.1 版本,修復了一些缺陷。同時把 license 由 1.0 版本的 GPL 修改為更寬鬆的 BSD-style license
自此,John Gruber 再也沒有更新過 Markdown,不論是用 Perl 編寫用於轉換為 HTML 的工具,還是 Markdown 的語法規則
2007 - ## Pandoc#
Pandoc 是 John MacFarlane 開發的一款萬能文檔轉換工具。Pandoc 可以在幾十種文檔格式之間相互轉換。Pandoc 早期就加入對 Markdown 格式的支持。這使得會有更多早期的用戶嘗試 Markdown 工具寫作
2008 - Stack Overflow#
2008 年,Stack Overflow 的聯合創始人 Jeff Atwood 選定 Markdown 作為 Stack Overflow 用戶編寫和回答問題的語法方案。經過一年半的實踐,Jeff Atwood 在 Responsible Open Source Code Parenting 說到:
I’m a big fan of John Gruber’s Markdown. When it comes to humane markup languages for the web, I don’t think anyone’s quite nailed it like Mr. Gruber. 我是 Markdown 的忠實鐵粉。說到網頁人性化的標記語言時,我認為沒有任何人可以像 Gruber 先生那樣優秀。在一開始他的思路就非常明確。
With a year and a half of real world Markdown experience under our belts on Stack Overflow, we’ve been quite happy. I’d say that Markdown is the worst form of markup except for all the other forms of markup that I’ve tried. Stack Overflow 線上使用 Markdown 一年半之後,我們感到相當滿意。我必須得說, Markdown 是最糟糕的標記形式,除了其他所有我已經試過的。
On 15 Mar 2008, at 02:55, John Gruber wrote: I despise what you’ve done with Text::Markdown, which is to more or less make it an alias for MultiMarkdown, almost every part of which I disagree with in terms of syntax additions.
John Gruber 對 Markdown 社區的態度極其冷淡。Jeff Atwood 對此感到非常失望
Jeff Atwood 是最熱心的 Markdown 布道者,用他的影響力不斷地向世人闡述使用 Markdown 的好處;同時 Jeff Atwood 埋怨 John Gruber 對 Markdown 的發展毫不關心
因 Stack Overflow 的影響力,Markdown 逐漸開始在程序員的世界裡流行起來。
2009 - Github Flavored Markdown#
Github 大約在 2009 年開始使用 Markdown 1.0 的派生版本 GitHub Flavored Markdown (GFM)。其中最主要區別在於以下兩點:
- 段落換行的界定:Github 認為一個換行符(回車鍵)即為新起一個段落更符合人們的預期。Markdown 1.0 則需要一行空白行(兩個回車鍵)。我深刻理解 Github 的努力,因為我第一次使用 Stack Overflow 時也為此感到困惑過。
- 下劃線用來分割多個單詞表示一個整體時,不應該處理為斜體
2012 - who’s with me?#
Jeff 在 The Future of Markdown 中提議 Stack Exchange、GitHub、Meteor 和 Reddit 等其他有一定訪問量的網站一起努力制定出 Markdown 標準規範和用於測試 Markdown 實現的標準測試用例。Jeff 希望這個標準規範主要內容包含:
- 把 John Gruber 的 Markdown 文檔用正式的語言規範進行標準化;
- 提供三個可選項,且給予更穩妥的默認值:a) 默認關閉在單詞內部的強調標記;b) 默認打開自動添加超鏈接;c) 默認打開回車鍵即換行;
- 驗證 Markdown 實現的一組測試用例;
- 對 Markdown 中存在邊界模糊的情況進行清理和調整;
- 對 Markdown 不同流行版本的處理。
Jeff 便在這個時候開始組建工作小組,成員列表如下:
- John MacFarlane, jgm@berkeley.edu
- David Greenspan, david@meteor.com
- Vicent Marti, vicent@github.com
- Neil Williams, neil@reddit.com
- Benjamin Dumke-von der Ehe, ben@stackexchange.com
- Jeff Atwood, jatwood@codinghorror.com
2014 - Standard Markdown & CommonMark#
Jeff 所組建的工作小組經過兩年的努力,在 2014 年 9 月發布名為 Standard Markdown 的項目。因 John Gruber 反對這個名稱,Jeff 將這個項目名稱修改為 CommonMark。CommonMark 規範主要由 Pandoc 的作者 John MacFarlane 編寫,其中包含了 624 個測試用例,C 和 JavaScript 的規範實現。
2016 - text/Markdown#
互聯網技術標準制定機構 IETF 發布 RFC 7763 - The text/Markdown Media Type 和 RFC 7764 - Guidance on Markdown 兩份徵求意見稿,收錄 Markdown 格式作為互聯網媒體標準格式 text/Markdown。同時為了區分不同 Markdown 版本,提供一個可選參數 variant=Identifer。RFC7764 中收錄了不同 Markdown 版本 Identifier 的值,同時指出不同版本之間的區別:
text/Markdown
或text/Markdown; variant=Original
John Gruber 發布的最原始版本;text/Markdown; variant=MultiMarkdown
MultiMarkdown;text/Markdown; variant=GFM
GitHub Flavored Markdown;text/Markdown; variant=pandoc
Pandoc;text/Markdown; variant=Fountain
Fountain;text/Markdown; variant=CommonMark
CommonMark;text/Markdown; variant=kramdown-rfc2629
Markdown for RFCs;text/Markdown; variant=rfc7328
Pandoc2rfc;text/Markdown; variant=Extra
PHP Markdown Extra。
2017 - GitHub Flavored Markdown Spec#
GitHub Flavored Markdown 基於 CommonMark Spec 發布了自己 spec,支持表格、任務列表和刪除線,禁止 HTML 原始標籤。測試用例從 624 個增加到 651 個。
現在#
Markdown 已經是事實上的無處不在。也是諸多筆記和寫作軟件首選支持的格式
John Gruber 為了方便更新他的博客,發布了 Markdown。但在此後的 10 多年裡,他再也沒有更新 Markdown,他的博客裡在這之後也幾乎看不到關於 Markdown 的只言片語
而另外一個人,却十年如一日地愛著 Markdown,在他的 Stack Overflow 和 Discourse 中使用 Markdown,並長期有組織地推廣 Markdown。
我們記住 Markdown 的創造者 John Gruber 的同時,也一並銘記 Jeff Atwood 為 Markdown 做出的巨大努力。
技術原理#
就當下的 Markdown 主流版本做的分析
typora#
大家都知道在 md 界中一個叫 typora 的軟件,以其實時預覽的功能廣各位 coder 歡迎,typora 如何使用不再過多介紹
核心技術點:Electron + node 技術棧
Electron 是一個使用 JavaScript、HTML 和 CSS 構建桌面應用程序的框架。嵌入 Chromium 和 Node.js 到二進制的 Electron 允許您保持一個 JavaScript 代碼代碼庫並創建在 Windows 上運行的跨平台應用 macOS 和 Linux—— 不需要本地開發經驗。
參考:簡介 | Electron
如上所說 typora 的顯示,其實本質上還是以 html 網頁的形式呈現,但是因為 electron 的技術實現,使得在 app 底座上能夠顯示 html 的內容
vscode 的 md 功能#
本質上與 typora 一樣,因為 vscode 本身也是用 typescript + electron
實現的桌面端 app
預覽#
通過 vscode.window.createWebviewPanel 創建一個 webview,指定在側邊打開,之後通過該 panel 對象的 webview.html 屬性來設置 html。
html 是通過編輯器的 Markdown 內容生成的,編輯器內容通過 editor.document.getText () 拿到,然後調用第三方的 Markdown 轉 html 的庫來生成。
這樣就完成了 Markdown 的預覽。
編輯 + 更新#
預覽之後需要更新,監聽 vscode.workspace.onDidSaveTextDocument 和 vscode.workspace.onDidChangeTextDocument 的事件,在文檔更新和保存的時候,拿到編輯器的內容,重新生成 html,然後設置到 webview。
webviewPanel 支持 webview.postMessage (message); 的方式傳遞消息,支持 updateHTML 等一系列 command,可以通過傳遞消息來觸發。
但是怎麼知道哪個文檔更新哪個 webview 呢?
可以維護一個 map,在創建 webviewPanel 的時候記錄到 map 中,key 為文件路徑,這樣更新的時候就能查找到對應的 webview 進行更新。
這樣,就完成了 Markdown 內容的更新。
實時預覽#
這裡把 typora 的實時預覽單獨拿出來介紹下,畢竟 typora 的大火除了其自身界面簡介友好,還有其實時預覽的功能
實時預覽就是用 md 語法寫完一個語法塊,頁面內容就能渲染出來
實現思路:
- 監聽 input 輸入
- 在 debounce 處理(防抖)之後調用 md parser 進行實時解析
- 渲染到對應位置上
其實實現思路也很直觀,並不是什么驚奇的 idea