codemirror-rails 2.2.1 → 2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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");