CodeMirror.defineMode("helma-skin", function(config, parserConfig) { //config settings var macroStartRegex = parserConfig.macroStartRegex || /^<%/i, macroEndRegex = parserConfig.macroEndRegex || /^%>/i; //inner modes var htmlMixedMode; var macroMode = { startState: function() { return {} }, token: function(stream, state) { var c = stream.next(); return 'helma-macro'; } } //tokenizer when in html mode function htmlDispatch(stream, state) { if (stream.match(macroStartRegex, false)) { state.token=macroDispatch; return macroMode.token(stream, state.macroState); } else return htmlMixedMode.token(stream, state.htmlState); } //tokenizer when in macro mode function macroDispatch(stream, state) { if (stream.match(macroEndRegex, false)) { state.token=htmlDispatch; return htmlMixedMode.token(stream, state.htmlState); } else{ var style = macroMode.token(stream, state.macroState); return style; } } return { startState: function() { htmlMixedMode = htmlMixedMode || CodeMirror.getMode(config, "htmlmixed"); return { token : parserConfig.startOpen ? macroDispatch : htmlDispatch, htmlState : htmlMixedMode.startState(), macroState : macroMode.startState() } }, token: function(stream, state) { return state.token(stream, state); }, indent: function(state, textAfter) { if (state.token == htmlDispatch) return htmlMixedMode.indent(state.htmlState, textAfter); else return macroMode.indent(state.macroState, textAfter); }, copyState: function(state) { return { token : state.token, htmlState : CodeMirror.copyState(htmlMixedMode, state.htmlState), macroState : CodeMirror.copyState(macroMode, state.macroState) } }, electricChars: "/{}:" } }, "htmlmixed"); CodeMirror.defineMIME("application/x-helma-skin", { name: "helma-skin" });