| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 | // CodeMirror, copyright (c) by Marijn Haverbeke and others// Distributed under an MIT license: https://codemirror.net/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");});
 |