codemirror-rails 2.2.1 → 2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README.md +8 -0
  2. data/codemirror-rails.gemspec +1 -1
  3. data/lib/codemirror/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/codemirror.js +842 -422
  5. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +2 -2
  6. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +722 -32
  7. data/vendor/assets/javascripts/codemirror/modes/clike.js +31 -9
  8. data/vendor/assets/javascripts/codemirror/modes/clojure.js +14 -14
  9. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +59 -37
  10. data/vendor/assets/javascripts/codemirror/modes/css.js +1 -1
  11. data/vendor/assets/javascripts/codemirror/modes/diff.js +24 -5
  12. data/vendor/assets/javascripts/codemirror/modes/ecl.js +203 -0
  13. data/vendor/assets/javascripts/codemirror/modes/erlang.js +251 -0
  14. data/vendor/assets/javascripts/codemirror/modes/gfm.js +40 -4
  15. data/vendor/assets/javascripts/codemirror/modes/go.js +170 -0
  16. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +1 -1
  17. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +4 -2
  18. data/vendor/assets/javascripts/codemirror/modes/javascript.js +10 -9
  19. data/vendor/assets/javascripts/codemirror/modes/less.js +232 -0
  20. data/vendor/assets/javascripts/codemirror/modes/markdown.js +52 -49
  21. data/vendor/assets/javascripts/codemirror/modes/mysql.js +188 -0
  22. data/vendor/assets/javascripts/codemirror/modes/pascal.js +2 -46
  23. data/vendor/assets/javascripts/codemirror/modes/perl.js +1 -1
  24. data/vendor/assets/javascripts/codemirror/modes/php.js +55 -25
  25. data/vendor/assets/javascripts/codemirror/modes/pig.js +172 -0
  26. data/vendor/assets/javascripts/codemirror/modes/properties.js +63 -0
  27. data/vendor/assets/javascripts/codemirror/modes/python.js +37 -32
  28. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.js +1 -1
  29. data/vendor/assets/javascripts/codemirror/modes/rst.js +1 -1
  30. data/vendor/assets/javascripts/codemirror/modes/ruby.js +14 -14
  31. data/vendor/assets/javascripts/codemirror/modes/rust.js +36 -15
  32. data/vendor/assets/javascripts/codemirror/modes/scheme.js +74 -46
  33. data/vendor/assets/javascripts/codemirror/modes/shell.js +103 -0
  34. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +16 -16
  35. data/vendor/assets/javascripts/codemirror/modes/smarty.js +148 -0
  36. data/vendor/assets/javascripts/codemirror/modes/stex.js +21 -6
  37. data/vendor/assets/javascripts/codemirror/modes/tiddlywiki.js +55 -45
  38. data/vendor/assets/javascripts/codemirror/modes/tiki.js +316 -0
  39. data/vendor/assets/javascripts/codemirror/modes/vbscript.js +26 -0
  40. data/vendor/assets/javascripts/codemirror/modes/verilog.js +194 -0
  41. data/vendor/assets/javascripts/codemirror/modes/xml.js +89 -16
  42. data/vendor/assets/javascripts/codemirror/modes/xmlpure.js +5 -0
  43. data/vendor/assets/javascripts/codemirror/modes/xquery.js +448 -0
  44. data/vendor/assets/javascripts/codemirror/utils/closetag.js +146 -0
  45. data/vendor/assets/javascripts/codemirror/utils/dialog.js +63 -0
  46. data/vendor/assets/javascripts/codemirror/utils/foldcode.js +196 -0
  47. data/vendor/assets/javascripts/codemirror/utils/formatting.js +297 -0
  48. data/vendor/assets/javascripts/codemirror/utils/javascript-hint.js +134 -0
  49. data/vendor/assets/javascripts/codemirror/utils/loadmode.js +51 -0
  50. data/vendor/assets/javascripts/codemirror/utils/match-highlighter.js +44 -0
  51. data/vendor/assets/javascripts/codemirror/utils/multiplex.js +72 -0
  52. data/vendor/assets/javascripts/codemirror/{overlay.js → utils/overlay.js} +3 -2
  53. data/vendor/assets/javascripts/codemirror/utils/pig-hint.js +123 -0
  54. data/vendor/assets/javascripts/codemirror/utils/runmode.js +49 -0
  55. data/vendor/assets/javascripts/codemirror/utils/search.js +118 -0
  56. data/vendor/assets/javascripts/codemirror/utils/searchcursor.js +117 -0
  57. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +72 -0
  58. data/vendor/assets/stylesheets/codemirror.css +69 -5
  59. data/vendor/assets/stylesheets/codemirror/modes/tiddlywiki.css +14 -21
  60. data/vendor/assets/stylesheets/codemirror/modes/tiki.css +26 -0
  61. data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +81 -0
  62. data/vendor/assets/stylesheets/codemirror/themes/blackboard.css +25 -0
  63. data/vendor/assets/stylesheets/codemirror/themes/cobalt.css +1 -1
  64. data/vendor/assets/stylesheets/codemirror/themes/eclipse.css +1 -1
  65. data/vendor/assets/stylesheets/codemirror/themes/elegant.css +2 -2
  66. data/vendor/assets/stylesheets/codemirror/themes/erlang-dark.css +21 -0
  67. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +44 -0
  68. data/vendor/assets/stylesheets/codemirror/themes/monokai.css +1 -1
  69. data/vendor/assets/stylesheets/codemirror/themes/neat.css +3 -3
  70. data/vendor/assets/stylesheets/codemirror/themes/night.css +1 -1
  71. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +2 -2
  72. data/vendor/assets/stylesheets/codemirror/themes/vibrant-ink.css +27 -0
  73. data/vendor/assets/stylesheets/codemirror/themes/xq-dark.css +46 -0
  74. data/vendor/assets/stylesheets/codemirror/utils/dialog.css +23 -0
  75. data/vendor/assets/stylesheets/codemirror/utils/simple-hint.css +16 -0
  76. metadata +41 -10
  77. data/vendor/assets/javascripts/codemirror/runmode.js +0 -27
  78. data/vendor/assets/stylesheets/codemirror/modes/clike.css +0 -7
  79. data/vendor/assets/stylesheets/codemirror/modes/markdown.css +0 -10
  80. data/vendor/assets/stylesheets/codemirror/modes/rst.css +0 -75
  81. data/vendor/assets/stylesheets/codemirror/themes/default.css +0 -19
@@ -61,7 +61,7 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
61
61
 
62
62
  electricChars: "/{}:"
63
63
  }
64
- });
64
+ }, "htmlmixed");
65
65
 
66
66
  CodeMirror.defineMIME("application/x-ejs", { name: "htmlembedded", scriptingModeSpec:"javascript"});
67
67
  CodeMirror.defineMIME("application/x-aspx", { name: "htmlembedded", scriptingModeSpec:"text/x-csharp"});
@@ -28,7 +28,7 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
28
28
  function javascript(stream, state) {
29
29
  if (stream.match(/^<\/\s*script\s*>/i, false)) {
30
30
  state.token = html;
31
- state.curState = null;
31
+ state.localState = null;
32
32
  state.mode = "html";
33
33
  return html(stream, state);
34
34
  }
@@ -73,11 +73,13 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
73
73
  },
74
74
 
75
75
  compareStates: function(a, b) {
76
+ if (a.mode != b.mode) return false;
77
+ if (a.localState) return CodeMirror.Pass;
76
78
  return htmlMode.compareStates(a.htmlState, b.htmlState);
77
79
  },
78
80
 
79
81
  electricChars: "/{}:"
80
82
  }
81
- });
83
+ }, "xml", "javascript", "css");
82
84
 
83
85
  CodeMirror.defineMIME("text/html", "htmlmixed");
@@ -54,7 +54,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
54
54
  stream.eatWhile(/[\da-f]/i);
55
55
  return ret("number", "number");
56
56
  }
57
- else if (/\d/.test(ch)) {
57
+ else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
58
58
  stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
59
59
  return ret("number", "number");
60
60
  }
@@ -69,7 +69,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
69
69
  else if (state.reAllowed) {
70
70
  nextUntilUnescaped(stream, "/");
71
71
  stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
72
- return ret("regexp", "string");
72
+ return ret("regexp", "string-2");
73
73
  }
74
74
  else {
75
75
  stream.eatWhile(isOperatorChar);
@@ -230,7 +230,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
230
230
  if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
231
231
  if (type == "function") return cont(functiondef);
232
232
  if (type == "keyword c") return cont(maybeexpression);
233
- if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
233
+ if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
234
234
  if (type == "operator") return cont(expression);
235
235
  if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
236
236
  if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
@@ -243,7 +243,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
243
243
 
244
244
  function maybeoperator(type, value) {
245
245
  if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
246
- if (type == "operator") return cont(expression);
246
+ if (type == "operator" || type == ":") return cont(expression);
247
247
  if (type == ";") return;
248
248
  if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
249
249
  if (type == ".") return cont(property, maybeoperator);
@@ -319,8 +319,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
319
319
  kwAllowed: true,
320
320
  cc: [],
321
321
  lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
322
- localVars: null,
323
- context: null,
322
+ localVars: parserConfig.localVars,
323
+ context: parserConfig.localVars && {vars: parserConfig.localVars},
324
324
  indented: 0
325
325
  };
326
326
  },
@@ -334,15 +334,16 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
334
334
  if (stream.eatSpace()) return null;
335
335
  var style = state.tokenize(stream, state);
336
336
  if (type == "comment") return style;
337
- state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
337
+ state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
338
338
  state.kwAllowed = type != '.';
339
339
  return parseJS(state, style, type, content, stream);
340
340
  },
341
341
 
342
342
  indent: function(state, textAfter) {
343
343
  if (state.tokenize != jsTokenBase) return 0;
344
- var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
345
- type = lexical.type, closing = firstChar == type;
344
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
345
+ if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
346
+ var type = lexical.type, closing = firstChar == type;
346
347
  if (type == "vardef") return lexical.indented + 4;
347
348
  else if (type == "form" && firstChar == "{") return lexical.indented;
348
349
  else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
@@ -0,0 +1,232 @@
1
+ /*
2
+ LESS mode - http://www.lesscss.org/
3
+ Ported to CodeMirror by Peter Kroon
4
+ */
5
+
6
+ CodeMirror.defineMode("less", function(config) {
7
+ var indentUnit = config.indentUnit, type;
8
+ function ret(style, tp) {type = tp; return style;}
9
+ //html5 tags
10
+ var tags = ["a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"];
11
+
12
+ function inTagsArray(val){
13
+ for(var i=0; i<tags.length; i++){
14
+ if(val === tags[i]){
15
+ return true;
16
+ }
17
+ }
18
+ }
19
+
20
+ function tokenBase(stream, state) {
21
+ var ch = stream.next();
22
+
23
+ if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
24
+ else if (ch == "/" && stream.eat("*")) {
25
+ state.tokenize = tokenCComment;
26
+ return tokenCComment(stream, state);
27
+ }
28
+ else if (ch == "<" && stream.eat("!")) {
29
+ state.tokenize = tokenSGMLComment;
30
+ return tokenSGMLComment(stream, state);
31
+ }
32
+ else if (ch == "=") ret(null, "compare");
33
+ else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
34
+ else if (ch == "\"" || ch == "'") {
35
+ state.tokenize = tokenString(ch);
36
+ return state.tokenize(stream, state);
37
+ }
38
+ else if (ch == "/") { // lesscss e.g.: .png will not be parsed as a class
39
+ if(stream.eat("/")){
40
+ state.tokenize = tokenSComment
41
+ return tokenSComment(stream, state);
42
+ }else{
43
+ stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/);
44
+ if(/\/|\)|#/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == ")")))return ret("string", "string");//let url(/images/logo.png) without quotes return as string
45
+ return ret("number", "unit");
46
+ }
47
+ }
48
+ else if (ch == "!") {
49
+ stream.match(/^\s*\w*/);
50
+ return ret("keyword", "important");
51
+ }
52
+ else if (/\d/.test(ch)) {
53
+ stream.eatWhile(/[\w.%]/);
54
+ return ret("number", "unit");
55
+ }
56
+ else if (/[,+<>*\/]/.test(ch)) {//removed . dot character original was [,.+>*\/]
57
+ return ret(null, "select-op");
58
+ }
59
+ else if (/[;{}:\[\]()]/.test(ch)) { //added () char for lesscss original was [;{}:\[\]]
60
+ if(ch == ":"){
61
+ stream.eatWhile(/[active|hover|link|visited]/);
62
+ if( stream.current().match(/active|hover|link|visited/)){
63
+ return ret("tag", "tag");
64
+ }else{
65
+ return ret(null, ch);
66
+ }
67
+ }else{
68
+ return ret(null, ch);
69
+ }
70
+ }
71
+ else if (ch == ".") { // lesscss
72
+ stream.eatWhile(/[\a-zA-Z0-9\-_]/);
73
+ return ret("tag", "tag");
74
+ }
75
+ else if (ch == "#") { // lesscss
76
+ //we don't eat white-space, we want the hex color and or id only
77
+ stream.eatWhile(/[A-Za-z0-9]/);
78
+ //check if there is a proper hex color length e.g. #eee || #eeeEEE
79
+ if(stream.current().length ===4 || stream.current().length ===7){
80
+ if(stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false) != null){//is there a valid hex color value present in the current stream
81
+ //when not a valid hex value, parse as id
82
+ if(stream.current().substring(1) != stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false))return ret("atom", "tag");
83
+ //eat white-space
84
+ stream.eatSpace();
85
+ //when hex value declaration doesn't end with [;,] but is does with a slash/cc comment treat it as an id, just like the other hex values that don't end with[;,]
86
+ if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) )return ret("atom", "tag");
87
+ //#time { color: #aaa }
88
+ else if(stream.peek() == "}" )return ret("number", "unit");
89
+ //we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa
90
+ else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag");
91
+ //when a hex value is on the end of a line, parse as id
92
+ else if(stream.eol())return ret("atom", "tag");
93
+ //default
94
+ else return ret("number", "unit");
95
+ }else{//when not a valid hexvalue in the current stream e.g. #footer
96
+ stream.eatWhile(/[\w\\\-]/);
97
+ return ret("atom", "tag");
98
+ }
99
+ }else{
100
+ stream.eatWhile(/[\w\\\-]/);
101
+ return ret("atom", "tag");
102
+ }
103
+ }
104
+ else if (ch == "&") {
105
+ stream.eatWhile(/[\w\-]/);
106
+ return ret(null, ch);
107
+ }
108
+ else {
109
+ stream.eatWhile(/[\w\\\-_%.{]/);
110
+ if(stream.current().match(/http|https/) != null){
111
+ stream.eatWhile(/[\w\\\-_%.{:\/]/);
112
+ return ret("string", "string");
113
+ }else if(stream.peek() == "<" || stream.peek() == ">"){
114
+ return ret("tag", "tag");
115
+ }else if( stream.peek().match(/\(/) != null ){// lessc
116
+ return ret(null, ch);
117
+ }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png)
118
+ return ret("string", "string");
119
+ }else if( stream.current().match(/\-\d|\-.\d/) ){ // lesscss match e.g.: -5px -0.4 etc... only colorize the minus sign
120
+ //stream.backUp(stream.current().length-1); //commment out these 2 comment if you want the minus sign to be parsed as null -500px
121
+ //return ret(null, ch);
122
+ return ret("number", "unit");
123
+ }else if( inTagsArray(stream.current()) ){ // lesscss match html tags
124
+ return ret("tag", "tag");
125
+ }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){
126
+ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){
127
+ stream.backUp(1);
128
+ return ret("tag", "tag");
129
+ }//end if
130
+ if( (stream.eatSpace() && stream.peek().match(/[{<>.a-zA-Z]/) != null) || stream.eol() )return ret("tag", "tag");//e.g. button.icon-plus
131
+ return ret("string", "string");//let url(/images/logo.png) without quotes return as string
132
+ }else if( stream.eol() ){
133
+ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1);
134
+ return ret("tag", "tag");
135
+ }else{
136
+ return ret("variable", "variable");
137
+ }
138
+ }
139
+
140
+ }
141
+
142
+ function tokenSComment(stream, state) {// SComment = Slash comment
143
+ stream.skipToEnd();
144
+ state.tokenize = tokenBase;
145
+ return ret("comment", "comment");
146
+ }
147
+
148
+ function tokenCComment(stream, state) {
149
+ var maybeEnd = false, ch;
150
+ while ((ch = stream.next()) != null) {
151
+ if (maybeEnd && ch == "/") {
152
+ state.tokenize = tokenBase;
153
+ break;
154
+ }
155
+ maybeEnd = (ch == "*");
156
+ }
157
+ return ret("comment", "comment");
158
+ }
159
+
160
+ function tokenSGMLComment(stream, state) {
161
+ var dashes = 0, ch;
162
+ while ((ch = stream.next()) != null) {
163
+ if (dashes >= 2 && ch == ">") {
164
+ state.tokenize = tokenBase;
165
+ break;
166
+ }
167
+ dashes = (ch == "-") ? dashes + 1 : 0;
168
+ }
169
+ return ret("comment", "comment");
170
+ }
171
+
172
+ function tokenString(quote) {
173
+ return function(stream, state) {
174
+ var escaped = false, ch;
175
+ while ((ch = stream.next()) != null) {
176
+ if (ch == quote && !escaped)
177
+ break;
178
+ escaped = !escaped && ch == "\\";
179
+ }
180
+ if (!escaped) state.tokenize = tokenBase;
181
+ return ret("string", "string");
182
+ };
183
+ }
184
+
185
+ return {
186
+ startState: function(base) {
187
+ return {tokenize: tokenBase,
188
+ baseIndent: base || 0,
189
+ stack: []};
190
+ },
191
+
192
+ token: function(stream, state) {
193
+ if (stream.eatSpace()) return null;
194
+ var style = state.tokenize(stream, state);
195
+
196
+ var context = state.stack[state.stack.length-1];
197
+ if (type == "hash" && context == "rule") style = "atom";
198
+ else if (style == "variable") {
199
+ if (context == "rule") style = null; //"tag"
200
+ else if (!context || context == "@media{"){
201
+ style = stream.current() == "when" ? "variable" :
202
+ stream.string.match(/#/g) != undefined ? null :
203
+ /[\s,|\s\)]/.test(stream.peek()) ? "tag" : null;
204
+ }
205
+ }
206
+
207
+ if (context == "rule" && /^[\{\};]$/.test(type))
208
+ state.stack.pop();
209
+ if (type == "{") {
210
+ if (context == "@media") state.stack[state.stack.length-1] = "@media{";
211
+ else state.stack.push("{");
212
+ }
213
+ else if (type == "}") state.stack.pop();
214
+ else if (type == "@media") state.stack.push("@media");
215
+ else if (context == "{" && type != "comment") state.stack.push("rule");
216
+ return style;
217
+ },
218
+
219
+ indent: function(state, textAfter) {
220
+ var n = state.stack.length;
221
+ if (/^\}/.test(textAfter))
222
+ n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
223
+ return state.baseIndent + n * indentUnit;
224
+ },
225
+
226
+ electricChars: "}"
227
+ };
228
+ });
229
+
230
+ CodeMirror.defineMIME("text/x-less", "less");
231
+ if (!CodeMirror.mimeModes.hasOwnProperty("text/css"))
232
+ CodeMirror.defineMIME("text/css", "less");
@@ -13,11 +13,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
13
13
  , strong = 'strong'
14
14
  , emstrong = 'emstrong';
15
15
 
16
- var hrRE = /^[*-=_]/
17
- , ulRE = /^[*-+]\s+/
18
- , olRE = /^[0-9]\.\s+/
16
+ var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
17
+ , ulRE = /^[*\-+]\s+/
18
+ , olRE = /^[0-9]+\.\s+/
19
19
  , headerRE = /^(?:\={3,}|-{3,})$/
20
- , codeRE = /^(k:\t|\s{4,})/
21
20
  , textRE = /^[^\[*_\\<>`]+/;
22
21
 
23
22
  function switchInline(stream, state, f) {
@@ -33,36 +32,32 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
33
32
 
34
33
  // Blocks
35
34
 
35
+ function blankLine(state) {
36
+ // Reset EM state
37
+ state.em = false;
38
+ // Reset STRONG state
39
+ state.strong = false;
40
+ return null;
41
+ }
42
+
36
43
  function blockNormal(stream, state) {
37
- if (stream.match(codeRE)) {
44
+ var match;
45
+ if (state.indentationDiff >= 4) {
46
+ state.indentation -= state.indentationDiff;
38
47
  stream.skipToEnd();
39
48
  return code;
40
- }
41
-
42
- if (stream.eatSpace()) {
49
+ } else if (stream.eatSpace()) {
43
50
  return null;
44
- }
45
-
46
- if (stream.peek() === '#' || stream.match(headerRE)) {
47
- stream.skipToEnd();
48
- return header;
49
- }
50
- if (stream.eat('>')) {
51
+ } else if (stream.peek() === '#' || stream.match(headerRE)) {
52
+ state.header = true;
53
+ } else if (stream.eat('>')) {
51
54
  state.indentation++;
52
- return quote;
53
- }
54
- if (stream.peek() === '[') {
55
+ state.quote = true;
56
+ } else if (stream.peek() === '[') {
55
57
  return switchInline(stream, state, footnoteLink);
56
- }
57
- if (hrRE.test(stream.peek())) {
58
- var re = new RegExp('(?:\s*['+stream.peek()+']){3,}$');
59
- if (stream.match(re, true)) {
60
- return hr;
61
- }
62
- }
63
-
64
- var match;
65
- if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
58
+ } else if (stream.match(hrRE, true)) {
59
+ return hr;
60
+ } else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
66
61
  state.indentation += match[0].length;
67
62
  return list;
68
63
  }
@@ -82,8 +77,15 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
82
77
 
83
78
  // Inline
84
79
  function getType(state) {
85
- return state.strong ? (state.em ? emstrong : strong)
86
- : (state.em ? em : null);
80
+ var styles = [];
81
+
82
+ if (state.strong) { styles.push(state.em ? emstrong : strong); }
83
+ else if (state.em) { styles.push(em); }
84
+
85
+ if (state.header) { styles.push(header); }
86
+ if (state.quote) { styles.push(quote); }
87
+
88
+ return styles.length ? styles.join(' ') : null;
87
89
  }
88
90
 
89
91
  function handleText(stream, state) {
@@ -192,7 +194,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
192
194
  inline: inlineNormal,
193
195
  text: handleText,
194
196
  em: false,
195
- strong: false
197
+ strong: false,
198
+ header: false,
199
+ quote: false
196
200
  };
197
201
  },
198
202
 
@@ -207,36 +211,35 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
207
211
  inline: s.inline,
208
212
  text: s.text,
209
213
  em: s.em,
210
- strong: s.strong
214
+ strong: s.strong,
215
+ header: s.header,
216
+ quote: s.quote
211
217
  };
212
218
  },
213
219
 
214
220
  token: function(stream, state) {
215
221
  if (stream.sol()) {
222
+ if (stream.match(/^\s*$/, true)) { return blankLine(state); }
223
+
224
+ // Reset state.header
225
+ state.header = false;
226
+ // Reset state.quote
227
+ state.quote = false;
228
+
216
229
  state.f = state.block;
217
- var previousIndentation = state.indentation
218
- , currentIndentation = 0;
219
- while (previousIndentation > 0) {
220
- if (stream.eat(' ')) {
221
- previousIndentation--;
222
- currentIndentation++;
223
- } else if (previousIndentation >= 4 && stream.eat('\t')) {
224
- previousIndentation -= 4;
225
- currentIndentation += 4;
226
- } else {
227
- break;
228
- }
229
- }
230
- state.indentation = currentIndentation;
231
-
232
- if (currentIndentation > 0) return null;
230
+ var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
231
+ state.indentationDiff = indentation - state.indentation;
232
+ state.indentation = indentation;
233
+ if (indentation > 0) { return null; }
233
234
  }
234
235
  return state.f(stream, state);
235
236
  },
236
237
 
238
+ blankLine: blankLine,
239
+
237
240
  getType: getType
238
241
  };
239
242
 
240
- });
243
+ }, "xml");
241
244
 
242
245
  CodeMirror.defineMIME("text/x-markdown", "markdown");