語法高亮庫基礎原理
在研究使用能夠在web頁面上代碼語法高顯的解決方案時,發現有很多現成的開源庫。比較中意的有prism.js,highlightjs。他們的原理基本上核心就兩點:
1. 利用html的<pre>特性:即原封不動顯示code
2. 針對不同源代碼其語法結構特點,設計該語言的正則匹配規則集。庫代碼將針對待高顯的源代碼做正則匹配,形成新的顯示內容,該內容由瀏覽器在<pre>元素中原樣展示
在試用prism或者highlightjs時,簡單的css代碼可以非常方便的工作,但是當我試着高顯c語言代碼時,就發生問題了。prism.js會將<stdlib.h>整個剔除。
最后研究下來,原因是和這類基於正則的語法高亮的基石頭--pre元素的工作機制有關.解決方案就是必須在加載含html entity的代碼之前必須做 轉換,比如 < 就翻譯為 < 這樣pre元素就無法將其解析為html markup,而是解析為 < 這個字符來顯示。 為了滿足我的好奇心,我再繼續深挖下去:
https://www.sitepoint.com/everything-need-know-html-pre-element/
<pre>是怎么工作的?
html的pre元素是一個簡單而又有語意的顯示"格式化內容"的方式,比如顯示源代碼。
在html document中,pre元素代表着"preformatted text".這意味着你的tab縮進,多空格,新轉行標識等其他編排格式將被原封保留,而不是像普通html元素一樣將多個space空格合並。。
默認情況下,瀏覽器在渲染pre元素的內容時使用"單空格"或者說 固定長度 的字體。
如果你將上面的內容放到一個其他的非pre元素中,則所有的額外空格,new lines,以及縮進格式都將被忽略。因此雖然你的代碼為這個樣子:
<div> Jack: Hello. How are you? Jill: I'm great. Thanks for asking. </div>
但是瀏覽器卻渲染成:
Jack: Hello. How are you? Jill: I'm great. Thanks for asking.
但是,如果我們把上面的html代碼放到pre元素中,
<pre> Jack: Hello. How are you? Jill: I'm great. Thanks for asking. </pre>
將會渲染成:
正確地marking up source code
如上面描述,pre元素用於那些具有能夠影響內容的真實含義的排版格式的文本,比如源代碼,藝術字體等。
如果你想在html document中渲染一塊而不是一行源代碼,你應該使用一個code 元素包含代碼並且嵌入在pre元素中。這是有語意的,對於搜索引擎尤為重要,因為這將告訴搜索引擎,code中是計算機源代碼,而非文檔內容
我們來看一下語意化地構建一段javascript代碼:
<pre><code>// Logs "Hello World!" // in the browser's developer console console.log("Hello World!");</code></pre>
使用內嵌在pre元素中的html的元素
在pre元素中,如果你不將內容進行escape,這時,如果內容出現html標簽比如<h1>則瀏覽器會以html元素的普通渲染方式只渲染其tag中的內容,而不會將<h1>作為普通的文本進行顯示!!!
正因為如此,
1. 如果你希望將內容作為源代碼原封不動顯示,則必須escape <,"等html entity;
2. 如果你希望使用h1標簽進行格式化pre中的源代碼,則你不能escape <,"等html entity
我們看以下例子,在html中,em和strong元素用於格式化其內嵌文本的:
從上面的實例可以看出,針對語法高亮顯示這個需求,我們可以借用highlight.js或者prism.js對於源代碼進行格式化,通過增加不同的html tag並作相應的css styling來實現不同語法部分的高亮顯示!!同時又能夠保持源代碼的格式輸出不變
常見問題
overflows
如果pre元素中的text比較長,超過了pre元素的寬度,這時有以下解決方案:
1. pre增加overflow auto,實現自動加一個滾動條
pre { overflow: auto; }
2.pre增加white-space: pre-wrap實現轉行
pre { white-space: pre-wrap; }
我比較傾向於第一個方案,因為這忠實地反映了原內容的格式
渲染html源代碼
正如前面提到過的,在pre元素中可以內嵌html來做css格式調整,但是如果希望在pre元素中原封不動地展示html代碼,又該怎么辦呢?
答案就是escape那些html預留的字符.這些字符被稱為html entity.核心的就是<,>,",詳細的html entity列表你可以在這里查看:
https://dev.w3.org/html5/html-author/charref
實際上即便是c語言代碼,也存在着類似問題,究其原因是比如 #inclue <stdio.h>這一個代碼,其中包含了< 這個tag起始,而highlightjs或者prismjs將無法正確處理,一個比較好的辦法是使用一個plugin,在正式pattern matching之前做escape操作就好了!
markup最佳實踐
<pre><code>Line 1 (first line) Line 2 Line 3 Line 4 (last line)</code></pre>
如果不遵循以上最佳實踐,可能帶來的問題是瀏覽器可能會自動給你錯位