openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

haml.js (5353B)


      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 embedded 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 = CodeMirror.startState(htmlMode);
    102         var rubyState = CodeMirror.startState(rubyMode);
    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 });