自定义ACE HTML模式使用push替代next切换状态失效问题求助
自定义ACE的HTML模式适配Lit-HTML模板字符串问题
问题背景
我想要自定义ACE的HTML模式来编辑Lit-HTML模板字符串,已经在start状态中添加了匹配${的规则,用来切换到js-start状态。用next: 'js-start'时功能正常,但因为JavaScript代码里可能嵌套HTML(包裹在lit.html...中),必须改用push替代next,可改用push`后规则就失效了。
后续疑问
${可能出现在任意位置,是否需要把这条新规则复制到HTML定义的所有状态中?也就是this.$highlightRules.$rules里所有不以js-或css-开头的状态。
代码片段
const editor = ace.edit(wrap); const HtmlMode = ace.require("ace/mode/html").Mode; const CustomMode = function() { HtmlMode.call(this); const HtmlHighlightRules = ace.require("ace/mode/html_highlight_rules").HtmlHighlightRules; this.$highlightRules = new HtmlHighlightRules(); this.$highlightRules.$rules.start.unshift({ token: "punctuation.definition.tag", regex: /\${/, // works next: 'js-start', // does not work //push: 'js-start', }); }; CustomMode.prototype = Object.create(HtmlMode.prototype); CustomMode.prototype.constructor = CustomMode; CustomMode.prototype.$id = "ace/mode/lit-html"; editor.getSession().setMode(new CustomMode());
现象
使用next时,<p class="something">${Math.random()}</p>这类内容能被正确高亮,但改用push后,Math.random()不再被高亮,ACE没有切换到js-start状态。
解决方案
1. push失效的修复
ACE状态栈机制中,默认js-start状态匹配闭合}的规则用的是next而非pop,导致压入的js-start状态无法正确弹出,后续状态逻辑混乱。你需要修改该规则的行为:
const CustomMode = function() { HtmlMode.call(this); const HtmlHighlightRules = ace.require("ace/mode/html_highlight_rules").HtmlHighlightRules; this.$highlightRules = new HtmlHighlightRules(); // 修改js-start状态中匹配闭合}的规则,改用pop const jsStartRules = this.$highlightRules.$rules['js-start']; for (let rule of jsStartRules) { if (rule.regex?.source === '}') { rule.next = undefined; rule.pop = true; break; } } // 保留push规则 this.$highlightRules.$rules.start.unshift({ token: "punctuation.definition.tag", regex: /\${/, push: 'js-start', }); };
2. 全局添加${匹配规则
是的,必须把这条规则添加到所有非JS、非CSS的HTML状态中,因为${}可以出现在HTML标签属性、文本、注释等任意位置,对应ACE里不同的HTML状态(如tag-open、attribute-value、comment等)。可以通过遍历批量添加:
const CustomMode = function() { HtmlMode.call(this); const HtmlHighlightRules = ace.require("ace/mode/html_highlight_rules").HtmlHighlightRules; this.$highlightRules = new HtmlHighlightRules(); // 修改js-start状态的闭合规则(同上) const jsStartRules = this.$highlightRules.$rules['js-start']; for (let rule of jsStartRules) { if (rule.regex?.source === '}') { rule.next = undefined; rule.pop = true; break; } } // 批量给所有非JS/CSS状态添加${匹配规则 const allRules = this.$highlightRules.$rules; for (let stateName in allRules) { if (!stateName.startsWith('js-') && !stateName.startsWith('css-')) { allRules[stateName].unshift({ token: "punctuation.definition.tag", regex: /\${/, push: 'js-start', }); } } };
这样即可实现任意位置${}的正确高亮,同时支持嵌套Lit-HTML模板的解析。
内容的提问来源于stack exchange,提问作者JYone3A
相关产品推荐
相关产品推荐

