github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/app/public/codemirror/mode/haml/haml.js (about)

     1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
     2  // Distributed under an MIT license: http://codemirror.net/LICENSE
     3  
     4  (function(mod) {
     5    if (typeof exports == "object" && typeof module == "object") // CommonJS
     6      mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby"));
     7    else if (typeof define == "function" && define.amd) // AMD
     8      define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod);
     9    else // Plain browser env
    10      mod(CodeMirror);
    11  })(function(CodeMirror) {
    12  "use strict";
    13  
    14    // full haml mode. This handled embeded ruby and html fragments too
    15    CodeMirror.defineMode("haml", function(config) {
    16      var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"});
    17      var rubyMode = CodeMirror.getMode(config, "ruby");
    18  
    19      function rubyInQuote(endQuote) {
    20        return function(stream, state) {
    21          var ch = stream.peek();
    22          if (ch == endQuote && state.rubyState.tokenize.length == 1) {
    23            // step out of ruby context as it seems to complete processing all the braces
    24            stream.next();
    25            state.tokenize = html;
    26            return "closeAttributeTag";
    27          } else {
    28            return ruby(stream, state);
    29          }
    30        };
    31      }
    32  
    33      function ruby(stream, state) {
    34        if (stream.match("-#")) {
    35          stream.skipToEnd();
    36          return "comment";
    37        }
    38        return rubyMode.token(stream, state.rubyState);
    39      }
    40  
    41      function html(stream, state) {
    42        var ch = stream.peek();
    43  
    44        // handle haml declarations. All declarations that cant be handled here
    45        // will be passed to html mode
    46        if (state.previousToken.style == "comment" ) {
    47          if (state.indented > state.previousToken.indented) {
    48            stream.skipToEnd();
    49            return "commentLine";
    50          }
    51        }
    52  
    53        if (state.startOfLine) {
    54          if (ch == "!" && stream.match("!!")) {
    55            stream.skipToEnd();
    56            return "tag";
    57          } else if (stream.match(/^%[\w:#\.]+=/)) {
    58            state.tokenize = ruby;
    59            return "hamlTag";
    60          } else if (stream.match(/^%[\w:]+/)) {
    61            return "hamlTag";
    62          } else if (ch == "/" ) {
    63            stream.skipToEnd();
    64            return "comment";
    65          }
    66        }
    67  
    68        if (state.startOfLine || state.previousToken.style == "hamlTag") {
    69          if ( ch == "#" || ch == ".") {
    70            stream.match(/[\w-#\.]*/);
    71            return "hamlAttribute";
    72          }
    73        }
    74  
    75        // donot handle --> as valid ruby, make it HTML close comment instead
    76        if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) {
    77          state.tokenize = ruby;
    78          return state.tokenize(stream, state);
    79        }
    80  
    81        if (state.previousToken.style == "hamlTag" ||
    82            state.previousToken.style == "closeAttributeTag" ||
    83            state.previousToken.style == "hamlAttribute") {
    84          if (ch == "(") {
    85            state.tokenize = rubyInQuote(")");
    86            return state.tokenize(stream, state);
    87          } else if (ch == "{") {
    88            if (!stream.match(/^\{%.*/)) {
    89              state.tokenize = rubyInQuote("}");
    90              return state.tokenize(stream, state);
    91            }
    92          }
    93        }
    94  
    95        return htmlMode.token(stream, state.htmlState);
    96      }
    97  
    98      return {
    99        // default to html mode
   100        startState: function() {
   101          var htmlState = htmlMode.startState();
   102          var rubyState = rubyMode.startState();
   103          return {
   104            htmlState: htmlState,
   105            rubyState: rubyState,
   106            indented: 0,
   107            previousToken: { style: null, indented: 0},
   108            tokenize: html
   109          };
   110        },
   111  
   112        copyState: function(state) {
   113          return {
   114            htmlState : CodeMirror.copyState(htmlMode, state.htmlState),
   115            rubyState: CodeMirror.copyState(rubyMode, state.rubyState),
   116            indented: state.indented,
   117            previousToken: state.previousToken,
   118            tokenize: state.tokenize
   119          };
   120        },
   121  
   122        token: function(stream, state) {
   123          if (stream.sol()) {
   124            state.indented = stream.indentation();
   125            state.startOfLine = true;
   126          }
   127          if (stream.eatSpace()) return null;
   128          var style = state.tokenize(stream, state);
   129          state.startOfLine = false;
   130          // dont record comment line as we only want to measure comment line with
   131          // the opening comment block
   132          if (style && style != "commentLine") {
   133            state.previousToken = { style: style, indented: state.indented };
   134          }
   135          // if current state is ruby and the previous token is not `,` reset the
   136          // tokenize to html
   137          if (stream.eol() && state.tokenize == ruby) {
   138            stream.backUp(1);
   139            var ch = stream.peek();
   140            stream.next();
   141            if (ch && ch != ",") {
   142              state.tokenize = html;
   143            }
   144          }
   145          // reprocess some of the specific style tag when finish setting previousToken
   146          if (style == "hamlTag") {
   147            style = "tag";
   148          } else if (style == "commentLine") {
   149            style = "comment";
   150          } else if (style == "hamlAttribute") {
   151            style = "attribute";
   152          } else if (style == "closeAttributeTag") {
   153            style = null;
   154          }
   155          return style;
   156        }
   157      };
   158    }, "htmlmixed", "ruby");
   159  
   160    CodeMirror.defineMIME("text/x-haml", "haml");
   161  });