Loading... # 背景 ace editor是一个代码编辑器,支持各种高亮和语法校验,但是我在做一个需求的时候需要给toml加上语法校验,但是toml没有相应的官方syntax validation worker存在,所以本文主要就是关于如何接入一个custom的worker到ace editor中。 # 正文 这里我使用的是react-ace+vite,关于这部分的文档非常的少,所以我通过不断的搜索和尝试才最终实现了这个效果。 首先,我们需要从ace-builds的src-noconflict中找到worker-json.js,将其直接拷贝下来。 https://raw.githubusercontent.com/ajaxorg/ace-builds/master/src-noconflict/worker-json.js 然后将其中的所有json和Json替换成toml和Toml,之后,我们找到 `ace/toml/toml_parse`这个定义部分,把function内部的逻辑删除,之后,找一个toml parser库,这里我选择的是https://github.com/iarna/iarna-toml这个库,我们只需要把这个parser库的lib文件夹里面的js代码进行一些改动,合成为一个文件塞入到function中就可以了。 ```javascript ace.define("ace/mode/toml/toml_parse", [], function (require, exports, module) { // 替换的代码逻辑 } ``` 主要的改动点就是把require部分直接变成对应文件的内容,然后,因为vite默认是没有window.global这个全局的define的,所以我们可以选择在index.ts里面增加以下代码行,或者把 `global.`前缀删除掉。 最后就是把parse-pretty-error.js和parse-string.js中的内容导入进这个函数的最后部分,然后把前面定义的 `module.exports`都删除即可。 ```javascript ... function prettyError(err, buf) { /* istanbul ignore if */ if (err.pos == null || err.line == null) return err let msg = err.message msg += ` at row ${err.line + 1}, col ${err.col + 1}, pos ${err.pos}:\n` /* istanbul ignore else */ if (buf && buf.split) { const lines = buf.split(/\n/) const lineNumWidth = String(Math.min(lines.length, err.line + 3)).length let linePadding = ' ' while (linePadding.length < lineNumWidth) linePadding += ' ' for (let ii = Math.max(0, err.line - 1); ii < Math.min(lines.length, err.line + 2); ++ii) { let lineNum = String(ii + 1) if (lineNum.length < lineNumWidth) lineNum = ' ' + lineNum if (err.line === ii) { msg += lineNum + '> ' + lines[ii] + '\n' msg += linePadding + ' ' for (let hh = 0; hh < err.col; ++hh) { msg += ' ' } msg += '^\n' } else { msg += lineNum + ': ' + lines[ii] + '\n' } } } err.message = msg + '\n' return err } const TOMLParser = makeParserClass(Parser); function parseString(str) { str = str.toString('utf8') const parser = new TOMLParser() try { parser.parse(str) return parser.finish() } catch (err) { throw prettyError(err, str) } } module.exports = parseString ``` 这个修改过的文件源码,可以直接到这个链接看:https://gist.github.com/SnowWarri0r/8ae79581b2defdddd88a697b97afb21d 然后关于mode部分的extend,这里就直接给出源码了,然后这里要注意的是,我把worker-toml.js直接放到了public文件夹,所以这里的ace.config.setModuleUrl就是这么写的,如果想要自定义也可以自行修改文件夹,这个东西的原理就是利用了Web Worker,具体的可以去看MDN:https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers ```typescript import "brace/mode/toml"; import ace from "ace-builds/src-noconflict/ace"; ace.config.setModuleUrl("ace/mode/toml_worker", "/worker-toml.js"); const WorkerClient = (window.ace as any).acequire("ace/worker/worker_client").WorkerClient; export default class TomlMode extends (window.ace as any).acequire("ace/mode/toml").Mode { constructor() { super(); this.createWorker = function (session: any) { const worker = new WorkerClient(["ace"], "ace/mode/toml_worker", "TomlWorker"); worker.attachToDocument(session.getDocument()); worker.on("annotate", function (e: any) { session.setAnnotations(e.data); }); worker.on("terminate", function () { session.clearAnnotations(); }); return worker; } } } ``` 这样写完之后,就可以在你想引入的地方new一个TomlMode对象,然后对editor的session调用setMode方法即可。 # 参考文章 https://github.com/iarna/iarna-toml https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers https://github.com/thlorenz/brace/issues/128 https://github.com/securingsincity/react-ace/issues/725 https://github.com/ajaxorg/ace/wiki/Syntax-validation https://medium.com/@valentin.shamsnejad/how-to-add-yaml-syntax-validation-to-ace-editor-6db1dff4ab1b Last modification:March 6, 2024 © Allow specification reprint Support Appreciate the author AliPayWeChat Like 如果觉得我的文章对你有用,请随意赞赏