Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
776 lars 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
          state.tokenize = rubyInQuote("}");
89
          return state.tokenize(stream, state);
90
        }
91
      }
92
 
93
      return htmlMode.token(stream, state.htmlState);
94
    }
95
 
96
    return {
97
      // default to html mode
98
      startState: function() {
99
        var htmlState = htmlMode.startState();
100
        var rubyState = rubyMode.startState();
101
        return {
102
          htmlState: htmlState,
103
          rubyState: rubyState,
104
          indented: 0,
105
          previousToken: { style: null, indented: 0},
106
          tokenize: html
107
        };
108
      },
109
 
110
      copyState: function(state) {
111
        return {
112
          htmlState : CodeMirror.copyState(htmlMode, state.htmlState),
113
          rubyState: CodeMirror.copyState(rubyMode, state.rubyState),
114
          indented: state.indented,
115
          previousToken: state.previousToken,
116
          tokenize: state.tokenize
117
        };
118
      },
119
 
120
      token: function(stream, state) {
121
        if (stream.sol()) {
122
          state.indented = stream.indentation();
123
          state.startOfLine = true;
124
        }
125
        if (stream.eatSpace()) return null;
126
        var style = state.tokenize(stream, state);
127
        state.startOfLine = false;
128
        // dont record comment line as we only want to measure comment line with
129
        // the opening comment block
130
        if (style && style != "commentLine") {
131
          state.previousToken = { style: style, indented: state.indented };
132
        }
133
        // if current state is ruby and the previous token is not `,` reset the
134
        // tokenize to html
135
        if (stream.eol() && state.tokenize == ruby) {
136
          stream.backUp(1);
137
          var ch = stream.peek();
138
          stream.next();
139
          if (ch && ch != ",") {
140
            state.tokenize = html;
141
          }
142
        }
143
        // reprocess some of the specific style tag when finish setting previousToken
144
        if (style == "hamlTag") {
145
          style = "tag";
146
        } else if (style == "commentLine") {
147
          style = "comment";
148
        } else if (style == "hamlAttribute") {
149
          style = "attribute";
150
        } else if (style == "closeAttributeTag") {
151
          style = null;
152
        }
153
        return style;
154
      }
155
    };
156
  }, "htmlmixed", "ruby");
157
 
158
  CodeMirror.defineMIME("text/x-haml", "haml");
159
});