You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:16:18