|
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod); else // Plain browser env
mod(CodeMirror); })(function(CodeMirror) { "use strict";
// full haml mode. This handled embedded ruby and html fragments too
CodeMirror.defineMode("haml", function(config) { var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); var rubyMode = CodeMirror.getMode(config, "ruby");
function rubyInQuote(endQuote) { return function(stream, state) { var ch = stream.peek(); if (ch == endQuote && state.rubyState.tokenize.length == 1) { // step out of ruby context as it seems to complete processing all the braces
stream.next(); state.tokenize = html; return "closeAttributeTag"; } else { return ruby(stream, state); } }; }
function ruby(stream, state) { if (stream.match("-#")) { stream.skipToEnd(); return "comment"; } return rubyMode.token(stream, state.rubyState); }
function html(stream, state) { var ch = stream.peek();
// handle haml declarations. All declarations that cant be handled here
// will be passed to html mode
if (state.previousToken.style == "comment" ) { if (state.indented > state.previousToken.indented) { stream.skipToEnd(); return "commentLine"; } }
if (state.startOfLine) { if (ch == "!" && stream.match("!!")) { stream.skipToEnd(); return "tag"; } else if (stream.match(/^%[\w:#\.]+=/)) { state.tokenize = ruby; return "hamlTag"; } else if (stream.match(/^%[\w:]+/)) { return "hamlTag"; } else if (ch == "/" ) { stream.skipToEnd(); return "comment"; } }
if (state.startOfLine || state.previousToken.style == "hamlTag") { if ( ch == "#" || ch == ".") { stream.match(/[\w-#\.]*/); return "hamlAttribute"; } }
// do not handle --> as valid ruby, make it HTML close comment instead
if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) { state.tokenize = ruby; return state.tokenize(stream, state); }
if (state.previousToken.style == "hamlTag" || state.previousToken.style == "closeAttributeTag" || state.previousToken.style == "hamlAttribute") { if (ch == "(") { state.tokenize = rubyInQuote(")"); return state.tokenize(stream, state); } else if (ch == "{") { if (!stream.match(/^\{%.*/)) { state.tokenize = rubyInQuote("}"); return state.tokenize(stream, state); } } }
return htmlMode.token(stream, state.htmlState); }
return { // default to html mode
startState: function() { var htmlState = CodeMirror.startState(htmlMode); var rubyState = CodeMirror.startState(rubyMode); return { htmlState: htmlState, rubyState: rubyState, indented: 0, previousToken: { style: null, indented: 0}, tokenize: html }; },
copyState: function(state) { return { htmlState : CodeMirror.copyState(htmlMode, state.htmlState), rubyState: CodeMirror.copyState(rubyMode, state.rubyState), indented: state.indented, previousToken: state.previousToken, tokenize: state.tokenize }; },
token: function(stream, state) { if (stream.sol()) { state.indented = stream.indentation(); state.startOfLine = true; } if (stream.eatSpace()) return null; var style = state.tokenize(stream, state); state.startOfLine = false; // dont record comment line as we only want to measure comment line with
// the opening comment block
if (style && style != "commentLine") { state.previousToken = { style: style, indented: state.indented }; } // if current state is ruby and the previous token is not `,` reset the
// tokenize to html
if (stream.eol() && state.tokenize == ruby) { stream.backUp(1); var ch = stream.peek(); stream.next(); if (ch && ch != ",") { state.tokenize = html; } } // reprocess some of the specific style tag when finish setting previousToken
if (style == "hamlTag") { style = "tag"; } else if (style == "commentLine") { style = "comment"; } else if (style == "hamlAttribute") { style = "attribute"; } else if (style == "closeAttributeTag") { style = null; } return style; } }; }, "htmlmixed", "ruby");
CodeMirror.defineMIME("text/x-haml", "haml"); });
|