Jerad Rutnam Jerad Rutnam - 3 months ago 15
Javascript Question

How to write a brackets extension for a new language?

I'm writing a brackets extension for a new text language, which is a mix of html and handlebars + javascript. And I want to write a Code Mode by using existing CodeMirror modes e.g. htmlmixed, javascript, handlebars.

This is what I have currently (main.js),

define(function (require, exports, module) {

var CodeMirror = brackets.getModule("thirdparty/CodeMirror/lib/codemirror"),
LanguageManager = brackets.getModule("language/LanguageManager");

CodeMirror.defineMode('htmlbars', function (config, parserConfig) {

var htmlMode = CodeMirror.getMode(config, "htmlmixed"),
javascriptMode = CodeMirror.getMode(config, "javascript"),
handlebarsMode = CodeMirror.getMode(config, "handlebars");

function html(stream, state) {
var style = htmlMode.token(stream, state.htmlState);
return style;
}

return {
startState: function() {
var state = htmlMode.startState();
return {token: html, localMode: null, localState: null, htmlState: state};
},

copyState: function(state) {
if (state.localState)
var local = CodeMirror.copyState(state.localMode, state.localState);
return { token: state.token, localMode: state.localMode, localState: local,
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
},

token: function(stream, state) {
return state.token(stream, state);
},

indent: function(state, textAfter) {
if (!state.localMode || /^\s*<\//.test(textAfter))
return htmlMode.indent(state.htmlState, textAfter);
else if (state.localMode.indent)
return state.localMode.indent(state.localState, textAfter);
else
return CodeMirror.Pass;
},

innerMode: function(state) {
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
}
};
});

CodeMirror.defineMIME("text/x-xhbs", "htmlbars");

LanguageManager.defineLanguage("htmlbars", {
name: "Htmlbars",
mode: ["htmlbars", "text/x-hbs"],
fileExtensions: ["xhbs"]
});

});





So what I want to know is how can define here to use javascript mode if element startswith
<%
and ends with
%>
etc ... currently it only works for
html


Please let me know if needs any more details.

Thanks! :)

Answer

You can easily achieve this by using CodeMirror Multiplex Mode,

e.g.

define(function (require, exports, module) {

    var CodeMirror = brackets.getModule("thirdparty/CodeMirror/lib/codemirror"),
        LanguageManager = brackets.getModule("language/LanguageManager");

    brackets.getModule(["thirdparty/CodeMirror/mode/handlebars/handlebars", "thirdparty/CodeMirror/mode/javascript/javascript"], function () {
        CodeMirror.defineMode("htmlbars", function (config) {
            return CodeMirror.multiplexingMode(
                CodeMirror.getMode(config, "text/html"),
                {
                    open: "<%",
                    close: "%>",
                    mode: CodeMirror.getMode(config, "javascript"),
                    parseDelimiters: true
                },
                {
                    open: "{{",
                    close: "}}",
                    mode: CodeMirror.getMode(config, "handlebars"),
                    parseDelimiters: true
                }
            );
        });

        CodeMirror.defineMIME("text/x-xhbs", "htmlbars");

        LanguageManager.defineLanguage("htmlbars", {
            name: "Htmlbars",
            mode: ["htmlbars", "text/x-hbs"],
            fileExtensions: ["xhbs"]
        });
    });

});

Official Demo: https://codemirror.net/demo/multiplex.html

Hope this will helps someone else. :)

Comments