前端代码编辑器ace 语法高亮

代码编辑器codemirror和ace,都有接触过,主要是简单的api使用下。现在项目选用的ace。主要结合官网的文档,加入些自己的理解。官方原文链接https://ace.c9.io/#nav=higlighter

配置mode

  在线调试语法高亮 https://ace.c9.io/tool/mode_creator.html,可以自己练手下
  在ace项目的lib/ace/mode文件夹中已经定义了很多mode.下面介绍配置一个新的mode,其中包括 语法高亮规则,缩进规则,代码折叠规则。

语法高亮规则

语法高亮的规则可以继承其他规则,通过oop.inherits(MyNewHighlightRules, TextHighlightRules),比如php代码里面可以写html,所以继承HtmlHighlightRules。
ace高亮语法是一种状态机机制。每一个状态,里面可以包含多个 用正则表达式regex定义的token标记。token标记可以通过next属性决定下一个状态。

1 this.$rules = {
2     stateName: [{
3         token: token, // String, Array, or Function: the CSS token to apply
4         regex: regex, // String or RegExp: the regexp to match
5         next: next // [Optional] String: next state to enter
6     }]
7 };            

this.$rules对象用来定义状态机的规则。开始规则定义为start状态,按顺序检测start的token列表。
当检测到regex匹配的时候,文本包裹成`<span class="ace_${token}">${文本}</span>`,在编辑器显示。

1 token=='function' => class="ace_function"
2 token=='support.function' => class="ace_support ace_function"

定义regex

regex属性可以是正则表达式,也可以是正则表达式的字符串,字符串需要注意转义

1 {
2     token : "constant.language.escape",
3     regex : /$[wd]+/
4     regex : “\$[\w\d]+5 }

regex与token关系

regex不存在捕获,token可以是String, Function返回字符串
token函数也可以用来对regex匹配的内容,再进行细分

 1 {
 2     token: function(value) {
 3         if (colors.hasOwnProperty(value.toLowerCase())) {
 4             return "support.constant.color";
 5         } else if (fonts.hasOwnProperty(value.toLowerCase())) {
 6             return "support.constant.fonts";
 7         } else {
 8             return "text";
 9         }
10     },
11     regex: "\-?[a-zA-Z_][a-zA-Z0-9_\-]*"
12 }

regex存在捕获分组,token可以是String(所有分组都用一样的定义), Array(长度和分组数量相同,与分组结果11对应),或Function返回Array

 1 {
 2   token : "constant",
 3   regex : "INT_MAX|INT_MIN"
 4 } // INT_MAX -> constant(INT_MAX)
 5 
 6 {
 7   token : ["constant", "keyword"],
 8   regex : "^(#{1,6})(.+)$"
 9 } // ### Header -> constant(###), keyword( Header)
10 
11 {
12   token : "constant",
13   regex : "(a+)(b)(\1)"
14 } // aabaa -> constant(aabaa) :: abaa -> constant(aba) + a
15 
16 {
17   token : function (first, second) {
18     if (first == "a") return ["constant", "keyword"];
19     return ["keyword", "constant"];
20   },
21   regex: "(.)(world)"
22 } // aworld -> constant(a), keyword(world) :: bworld -> keyword(a), constant(world)

分组需要覆盖所有匹配结果,如果需要不匹配的话,请使用(?:), (hel)lo => (hel)(?:lo)

定义状态

语法高亮状态机,一般处于start状态,如果你定义了next,会流转到next指定的状态,一直流转下去。最后,应该回到start状态,对后面的文本继续进行检测。
可以理解是一个词法分析的过程。

 1 this.$rules = {
 2     "start" : [{
 3         token : "text",
 4         regex : "<\!\[CDATA\[",
 5         next : "cdata"
 6     }],
 7     "cdata" : [{
 8         token : "text",
 9         regex : "\]\]>",
10         next : "start"
11     }, {
12         defaultToken : "text"
13     }]
14 };

上面示例中,当检测到"<![cdata["字符串,标记器从start状态移动到cdata状态,默认使用text标记,直到遇到关闭符号“]]>”,重新回到start状态继续检测。

扩展高亮规则

如果你的语法中间,可以通过(<?lua, <?php)标识符来嵌入其他语言块。Ace可以使用一些有用的函数来进行扩展

getRules 获取存在的规则

1 var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules;
2 this.$rules = new HtmlHighlightRules().getRules();

addRules 合并规则

 1 this.$rules = {
 2     "start": [ /* ... */ ]
 3 };
 4 
 5 var newRules = {
 6     "start": [ /* ... */ ]
 7 }
 8 
 9 this.addRules(newRules, "new-");
10 
11 /*
12     this.$rules = {
13         "start": [ ... ],
14         "new-start": [ ... ]
15     };
16 */

embedRules 扩展规则

 1 this.addRules(newRules, "new-") == embedRules(this.$rules, "new-", newRules);
 2 
 3 var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules;
 4 var LuaHighlightRules = require("./lua_highlight_rules").LuaHighlightRules;
 5 
 6 var LuaPageHighlightRules = function() {
 7     this.$rules = new HtmlHighlightRules().getRules();
 8 
 9     for (var i in this.$rules) {
10         this.$rules[i].unshift({
11             token: "keyword",
12             regex: "<\%\=?",
13             next: "lua-start"
14         }, {
15             token: "keyword",
16             regex: "<\?lua\=?",
17             next: "lua-start"
18         });
19     }
20     this.embedRules(LuaHighlightRules, "lua-", [
21         {
22             token: "keyword",
23             regex: "\%>",
24             next: "start"
25         },
26         {
27             token: "keyword",
28             regex: "\?>",
29             next: "start"
30         }
31     ]);
32 }

当遇到'<%='或‘<?lua=’,就到lua-start状态,就使用LuaHighlightRules去检测下面的文本,直到遇到"%>", "?>"回到原来的HtmlHighlightRules;
上面例子会存在<%=?>的嵌套,存在些问题

原文地址:https://www.cnblogs.com/legu/p/8277197.html