ace-editor

Custom rule added to the HTML mode that uses "push" instead of "next" doesn't work


I want to customize the HTML mode so I can edit LIT-html template strings with it. I did add a rule to start that matches ${, switching the state to js-start. This works when I add next: 'js-start' to the rule. However, as the JavaScript code can include nested HTML (wrapped in lit.html`...` ), I would have to use push instead of next, but then the rule does not seem to work any more.

As a follow-up, as ${ can occur anywhere, I assume I will have to copy my new rule to any state defined for HTML, right? (i.e. all states on this.$highlightRules.$rules that do not start with js- or css-).

Code Snippet:

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());

As expected, something like <p class="something">${Math.random()}</p> is correctly higlighted. But as soon as I use push instead of next, Math.random() is not highlighted, i.e. ACE does not switch to js-start.


Solution

  • You'll want to call

    this.$highlightRules.normalizeRules()
    

    after adding rules that push/pop - these are a shorthand for supplying functions that manipulate the state "stack".