本文主要是介绍实际项目中如何加入语法检测功能。官方文档链接https://github.com/ajaxorg/ace/wiki/Syntax-validation
代码编辑器ace,使用webworker进行实时语法检查。目前支持JavaScript,json,php,coffeescript,css,xquery模式。
根据官方https://ace.c9.io/#nav=higlighter的例子,在项目开发中,新增了Formula的语法高亮,下面是定义Mode并增加语法高亮的部分代码
//parserNet是parser模块,在发生错误的时候会主动调用parseError方法
至于怎么实现语法检测的功能,比较复杂,涉及到编译原理,语法词法分析的知识。这个我了解的也只是入门,有时间的时候再介绍吧
ace.define("ace/mode/formula", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/formula_highlight_rules"], function (acequire, exports, module) { var oop = acequire("../lib/oop"); var TextMode = acequire("./text").Mode; var FormulaHighlightRules = acequire("./formula_highlight_rules").FormulaHighlightRules; var Mode = function () { this.HighlightRules = FormulaHighlightRules; this.$behaviour = this.$defaultBehaviour; }; oop.inherits(Mode, TextMode); (function () { this.lineCommentStart = "//"; this.$id = "ace/mode/formula"; this.createWorker = function (session) { var worker = { //编辑器销毁或修改模式的时候 terminate: function () { session.clearAnnotations(); //清除错误信息 this.$worker = null; if (this.$doc) this.$doc.off("change", this.changeListener); this.changeListener = null; this.$doc = null; }, //文档变化的回调 _changeListener: function () { if (!this.$doc) return; var val = this.$doc.getValue(); if (val.trim() === "") { session.clearAnnotations(); //清除错误信息 return; } var res = []; //重写parserNet.parseError方法,收集错误信息 parserNet.parseError = function (str, obj) { var column = obj.loc ? obj.loc.first_column : 0; res.push({ column: column, raw: str, row: obj.line, text: str, type: "error" }) } try { //parserNet.parse实时检测代码功能 parserNet.parse(val); } catch (e) { } session.setAnnotations(res)//显示错误信息 }, //绑定文档对象的时候 attachToDocument(doc) { if (this.$doc) this.terminate(); this.$doc = doc; this.changeListener = _.debounce(this._changeListener.bind(this), 500); this.changeListener(); //绑定change文档事件 doc.on("change", this.changeListener); }, //响应weoker中发出的消息,this.sender.emit("annotate",[])消息,也可以定义其他的消息名称 annotate(results) { session.setAnnotations(results); } };
//绑定文档 worker.attachToDocument(session.getDocument()); return worker; }; }).call(Mode.prototype);
在实际项目中,有可能是给ace已存在的高亮增加语法检测,下面是webpack打包项目中的写法,主要参考怎么引用已存在的ace模式
import ‘brace/mode/mysql.js‘ import {parserMySql} from ‘../mysql/mysqlParser.js‘; var MysqlMode = ace.acequire("ace/mode/mysql").Mode; (function () { this.createWorker = function (session) { var worker = { terminate: function () { session.clearAnnotations(); this.$worker = null; if (this.$doc) this.$doc.off("change", this.changeListener); this.changeListener = null; this.$doc = null; }, _changeListener: function () { if (!this.$doc) return; var val = this.$doc.getValue(); var res = []; parserMySql.parseError = function (str, obj) { var column = obj.loc ? obj.loc.first_column : 0; res.push({ column: column, raw: str, row: obj.line, text: str, type: "error" }) } if (val.trim().length === 0) { res.push({ column: 0, raw: "该字段不能为空", row: 0, text: "该字段不能为空", type: "error" }) } else { try { parserMySql.parse(val); } catch (e) { } } session.setAnnotations(res) }, attachToDocument(doc) { if (this.$doc) this.terminate(); this.$doc = doc; this.changeListener = _.debounce(this._changeListener.bind(this), 500); this.changeListener(); doc.on("change", this.changeListener); }, annotate(results) { session.setAnnotations(results); } }; worker.attachToDocument(session.getDocument()); return worker; }; }).call(MysqlMode.prototype);