我想写 Cirru 的语法高亮, 实际上我失败了, 或者说花的心思不够多吧.
Highlight.js 的文档和代码示例还是比较不错的, 只是..
写 CodeMirror 和 Pygments 的插件时, 全局传递的状态非常有用,
CoderMirror 只有一个状态, 而 Pygments 和 Lexer 类似有状态的数组,
然而, 比如 Sublime 就没有状态传递的方式, Highlight.js 更糟糕.
开发流程
Fork 的成本并不高, 我把文档页面上的步骤大概翻译一下:
http://highlightjs.readthedocs.org/en/latest/contribution.html
- 首先
git clone
代码, 确认已经安装python3
- 在
src/langauges/
下创建文件, 比如我是cirru.js
-
cirru.js
文件头部写如一些语言相关的信息, 比如
js
/* Language: Cirru Author: Jiyin Yiyong
Contributors: Jiyin Yiyong Description: Cirru is an indentation-based grammar for programming languages. See http://cirru.org/ */
- 在
src/test.html
里按照格式加入自己的语言, 注意属性对应语言名字 - 开发调试... 测试..
- 在
docs/css-classes-reference.rst
里写下自己用到class
http://highlightjs.readthedocs.org/en/latest/css-classes-reference.htm... - 在
AUTHOR.*.txt
里加上自己的名字 - 发送 PR.
测试环境
其实测试比较麻烦, 每次修改文件以后都需要进行编译, 或者说合并
在 tools/
目录下运行命令将 JS 打包, 然后可以浏览器打开 src/test.html
测试:
bash
python3 build.py
或者如果只是打包一种或者几种语言, 通过参数指定:
bash
python3 build.py -n cirru
测试的语言下, 会有对应的一些数字, 这是 Highlight.js 在用多种语言检测代码,
比如这里是 Scala 和 CoffeeSript 代码示例中的匹配结果:
如果其他语言的匹配结果过高, 会提示测试失败.. 不过调试过程中不大看这个.
高亮语法
直接用 JSON 的例子来说明问题吧:
js
/* Language: JSON Author: Ivan Sagalaev
*/ function(hljs) { var LITERALS = {literal: 'true false null'}; var TYPES = [ hljs.QUOTE_STRING_MODE, hljs.C_NUMBER_MODE ]; var VALUE_CONTAINER = { className: 'value', end: ',', endsWithParent: true, excludeEnd: true, contains: TYPES, keywords: LITERALS }; var OBJECT = { begin: '{', end: '}', contains: [ { className: 'attribute', begin: '\\s*"', end: '"\\s*:\\s*', excludeBegin: true, excludeEnd: true, contains: [hljs.BACKSLASH_ESCAPE], illegal: '\\n', starts: VALUE_CONTAINER } ], illegal: '\\S' }; var ARRAY = { begin: '\\[', end: '\\]', contains: [hljs.inherit(VALUE_CONTAINER, {className: null})], // inherit is also a workaround for a bug that makes shared modes with endsWithParent compile only the ending of one of the parents illegal: '\\S' }; TYPES.splice(TYPES.length, 0, OBJECT, ARRAY); return { contains: TYPES, keywords: LITERALS, illegal: '\\S' }; }
首先, 关键字通过声明可以自动高亮, 不用太多问题了.
然后是 contains
里增加可以被高亮出来的模式,
其中 begin
end
标记模式的开始和结尾, 比如 [
和 ]
的效果,cantains
可以进行嵌套, 定义比如 "escape" 之类的语法.
一些技巧:
- 只有
begin
没有end
时,begin
的内容就是匹配字符串内容, - 虽然例子上都是字符串表示的正则, 但内部实现来说, 直接写正则更方便,
- 文档上有
starts
属性, 表示在当前模式结束后立即进行对应模式, -
hljs.BACKSLASH_ESCAPE
这些内置模式可以加快书写
更多细节请参考文档, 或者 src/languages/
下丰富的例子:
- Language definition guide
- Mode reference
结果
我尝试改了几个小时, 结果不理想, 没有想到好的方案:
https://github.com/Cirru/highlight.js/commit/428f198c285319cb4a06381f2...
主要是开头说过的问题, Highlight.js 没有状态的概念,
而 Cirru 将表达式第一个标识符作为函数处理, 就很不方便,
在 Sublime 里我做的处理比较 tricky, 也许未来还是要换..
暂时就这些了.
返回博客首页: http://blog.tiye.me