Hack本博客站点Markdown编辑器使之支持多种编程语言代码高亮
对于我们这些码农来说,代码就是everything,然而当我满怀期待的想要用这套中意的博客系统来发布代码时,才发现后台编辑器虽然看起来很洋气,代码语法高亮插件也有,但是支持的编程语言却是少的那么可怜的几种web相关的语种,实在令我大失所望。于是决心自救,找了各种搜索大妈,发现网上大部分的语法高亮插件都是基于JQuery前端的,就是待显示的源代码在访问者浏览器端通过js渲染高亮。随便尝试了两款如highlightjs和SyntaxHighlighter,期间会遇到一些疑难杂症,比如与已有的语法高亮插件不兼容,代码渲染互相影响,最让我受不了的是患有代码洁癖的我,不喜欢直接在博客框架里“硬编码”添加引入js此等难看又影响性能的事情。基于这些原因,我另辟途径,最终找到了这款名为“GeSHi”的真爱,并将之完美的融入到原有的markdown插件。
与网上各种主流的开源高亮插件不同,这款插件有种独行者的感觉。寻找它的过程中发现一条评论说,这款插件采用后台渲染的方法非常不可取。所谓后台渲染,就是区别于前面提到的前端渲染,把要显示的源代码在服务器后台渲染完成再到浏览器端显示。我能理解这个评论的意思,但是我完全不赞同此观点,原因在于没有不好的产品,只有使用不当的产品。如果这款插件被每次请求代码显示时都重新调用来渲染的话,确实会有别人担心的严重性能问题,影响服务端的负载。然而如果只是在最初被发布的时候渲染一下的话,反而就是一劳永逸,还无需在浏览器上重新渲染,瞬间劣势转为优势。当然,我大概也能理解为什么这款插件不能成为特别是一些大型网站的主流。
本博客系统的markdown插件也是很无奈,原本如此大名的东西在这里却有些失望,其在渲染代码时内部调用的是另外一个代码高亮插件,所以只能依赖没法指望。其实那个代码高亮插件的思想和“GeSHi”差不多,只是作者虽然给人留下了拓展语种的可能性,却没有人愿意去开拓(我没找见)。所以我一眼看到“GeSHi”的时候,它那就是那群星里最闪亮的存在了。
废话不说了,准备上代码了。首先到插件目录找到markdown的代码,定位到解析codeblock的部分:
<?php
//...
case 'codeblock':
// Codeblock
$attrs = empty( $element['lang'] ) ? '' : ' lang='.$element['lang'];
$attrs .= ' line=1'; // set this param because codehighlight plugin doesn't detect language without this
$text = implode( "\n", $element['lines'] );
$markup .= '<!-- codeblock '.$attrs.'--><pre class="codeblock"><code>'."\n".$text."\n".'</code></pre><!-- /codeblock -->'."\n";
break;
//...
?>
从这段代码可以看出markdown解析源代码时,获取编辑者指定的编程语言作为参数,把所有代码加入到一个pre和code标签里面,并在外层添加一个注释型codeblock标签供内置代码高亮插件识别。其实我要做的事情很简单,就是更改此处的流程,使之支持更多的语种,全部或部分交给“GeSHi”来解析。而要实现用“GeSHi”解析也很容易,就是将所有代码传入一个GeSHi对象里解析后加入到pre和code即可,这时就不在外层添加注释型codeblock标签让内置插件再进行二次解析了。另外还有一个问题是上面的变量$text为进行html格式化后的源代码,而要进行GeSHi的解析前需要未格式化的源代码,于是在解析前先转回格式化前的源代码交给GeSHi去自动格式化和解析,最终makeup就行:
<?php
//...
case 'codeblock':
// Codeblock
$attrs = empty( $element['lang'] ) ? '' : ' lang='.$element['lang'];
$attrs .= ' line=1'; // set this param because codehighlight plugin doesn't detect language without this
$text = implode( "\n", $element['lines'] );
if(in_array($element['lang'], array(/*"php", */"html", "css", "shell", "xml", "code")) == false and $element['lang'] != "")
{
include_once($_SERVER['DOCUMENT_ROOT'] . '/plugins/geshi/geshi/geshi.php');
//file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/plugins/geshi/geshi/xxx.log', $text);
$aTransSpecchar = array(
'&' => '&',
'"' => '"',
'<' => '<',
'>' => '>',
'SUB\\0' => '\\\\', //SUB is specialchars equ hex num 0x1a, here is for some trouble with expcept transform "\\\\" to "\\\0"
'<SEMI>' => ';',
'<PIPE>' => '|'
);
$text = strtr($text, $aTransSpecchar);
//$text = htmlspecialchars_decode($text);
$geshi = new GeSHi($text, $element['lang']);
$text = $geshi->parse_code();
$markup .= '<pre><code>'."\n".$text."\n".'</code></pre><!-- /codeblock -->'."\n";
}
else
{
$markup .= '<!-- codeblock '.$attrs.'--><pre class="codeblock"><code>'."\n".$text."\n".'</code></pre><!-- /codeblock -->'."\n";
}
break;
//...
?>
小结:实际上,”GeSHi“这款插件是非常适合本博客框架的,虽然我简单的hack还存在一些潜在的bug,比如撰写本文时发现还是有些特殊字符被二次转义了,但是大部分还是正常够用的了,后续如果有需求可以再稍微改善一下hack代码。再说说这款插件的优点,目前最新版支持多达222种不同的语种的代码高亮,并且对应语种非常容易添加或修改渲染格式以满足更多的需求,借鉴一下网上的一句话:这还没用到”GeSHi“的高级特性。
2 条评论
评论 从: haharen [游客]
通过 markdown 编辑器的 codeblock 标签来渲染代码高亮,非常不错的想法,效果看起来也很好,受教了。
表单载入中...
@haharen,本来因为这个问题差点没放弃这套优秀的框架,后来硬着不愿放弃的心态找了相关资料给补上了,其实谈不上完美哈,只不过感觉挺适合的!