codemirror-rails 2.22 → 2.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/lib/codemirror/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/codemirror.js +164 -83
  3. data/vendor/assets/javascripts/codemirror/modes/clojure.js +13 -13
  4. data/vendor/assets/javascripts/codemirror/modes/css.js +1 -1
  5. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/modes/javascript.js +3 -3
  7. data/vendor/assets/javascripts/codemirror/modes/less.js +86 -57
  8. data/vendor/assets/javascripts/codemirror/modes/markdown.js +29 -60
  9. data/vendor/assets/javascripts/codemirror/modes/properties.js +17 -11
  10. data/vendor/assets/javascripts/codemirror/modes/smarty.js +148 -0
  11. data/vendor/assets/javascripts/codemirror/modes/stex.js +15 -2
  12. data/vendor/assets/javascripts/codemirror/modes/tiddlywiki.js +41 -31
  13. data/vendor/assets/javascripts/codemirror/modes/vbscript.js +26 -0
  14. data/vendor/assets/javascripts/codemirror/modes/xml.js +2 -1
  15. data/vendor/assets/javascripts/codemirror/modes/xquery.js +448 -0
  16. data/vendor/assets/javascripts/codemirror/utils/closetag.js +174 -0
  17. data/vendor/assets/javascripts/codemirror/utils/foldcode.js +1 -1
  18. data/vendor/assets/javascripts/codemirror/utils/formatting.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/utils/javascript-hint.js +4 -2
  20. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +6 -0
  21. data/vendor/assets/stylesheets/codemirror.css +2 -0
  22. data/vendor/assets/stylesheets/codemirror/modes/tiddlywiki.css +1 -1
  23. data/vendor/assets/stylesheets/codemirror/themes/eclipse.css +1 -1
  24. data/vendor/assets/stylesheets/codemirror/themes/elegant.css +2 -2
  25. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +45 -0
  26. data/vendor/assets/stylesheets/codemirror/themes/neat.css +3 -3
  27. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +1 -1
  28. data/vendor/assets/stylesheets/codemirror/themes/xq-dark.css +46 -0
  29. metadata +10 -6
  30. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.css +0 -5
  31. data/vendor/assets/stylesheets/codemirror/modes/properties.css +0 -3
@@ -4,7 +4,7 @@
4
4
  */
5
5
  CodeMirror.defineMode("clojure", function (config, mode) {
6
6
  var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", TAG = "tag",
7
- ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD="keyword";
7
+ ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword";
8
8
  var INDENT_WORD_SKIP = 2, KEYWORDS_SKIP = 1;
9
9
 
10
10
  function makeKeywords(str) {
@@ -14,26 +14,25 @@ CodeMirror.defineMode("clojure", function (config, mode) {
14
14
  }
15
15
 
16
16
  var atoms = makeKeywords("true false nil");
17
-
17
+
18
18
  var keywords = makeKeywords(
19
- // Control structures
20
- "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle" +
19
+ "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle");
21
20
 
22
- // Built-ins
21
+ var builtins = makeKeywords(
23
22
  "* *1 *2 *3 *agent* *allow-unresolved-vars* *assert *clojure-version* *command-line-args* *compile-files* *compile-path* *e *err* *file* *flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *use-context-classloader* *warn-on-reflection* + - / < <= = == > >= accessor aclone agent agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec decimal? declare definline defmacro defmethod defmulti defn defn- defonce defstruct delay delay? deliver deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall doc dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq eval even? every? extend extend-protocol extend-type extends? extenders false? ffirst file-seq filter find find-doc find-ns find-var first float float-array float? floats flush fn fn? fnext for force format future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator hash hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map? mapcat max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod name namespace neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? or parents partial partition pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-doc print-dup print-method print-namespace-doc print-simple print-special-doc print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string reify reduce ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure release-pending-sends rem remove remove-method remove-ns repeat repeatedly replace replicate require reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-validator! set? short short-array shorts shutdown-agents slurp some sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-form-anchor special-symbol? split-at split-with str stream? string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync syntax-symbol-anchor take take-last take-nth take-while test the-ns time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-dec unchecked-divide unchecked-inc unchecked-multiply unchecked-negate unchecked-remainder unchecked-subtract underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision xml-seq");
24
23
 
25
24
  var indentKeys = makeKeywords(
26
25
  // Built-ins
27
- "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch" +
26
+ "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch " +
28
27
 
29
28
  // Binding forms
30
- "let letfn binding loop for doseq dotimes when-let if-let" +
29
+ "let letfn binding loop for doseq dotimes when-let if-let " +
31
30
 
32
31
  // Data structures
33
- "defstruct struct-map assoc" +
32
+ "defstruct struct-map assoc " +
34
33
 
35
34
  // clojure.test
36
- "testing deftest" +
35
+ "testing deftest " +
37
36
 
38
37
  // contrib
39
38
  "handler-case handle dotrace deftrace");
@@ -154,12 +153,11 @@ CodeMirror.defineMode("clojure", function (config, mode) {
154
153
  (;something else, bracket, etc.
155
154
  */
156
155
 
157
- while ((letter = stream.eat(tests.keyword_char)) != null) {
156
+ if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) {
158
157
  keyWord += letter;
159
158
  }
160
159
 
161
160
  if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word
162
-
163
161
  pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
164
162
  } else { // non-indent word
165
163
  // we continue eating the spaces
@@ -182,13 +180,15 @@ CodeMirror.defineMode("clojure", function (config, mode) {
182
180
  }
183
181
  } else if ( ch == ":" ) {
184
182
  stream.eatWhile(tests.lang_keyword);
185
- return TAG;
183
+ return ATOM;
186
184
  } else {
187
185
  stream.eatWhile(tests.basic);
188
186
 
189
187
  if (keywords && keywords.propertyIsEnumerable(stream.current())) {
188
+ returnType = KEYWORD;
189
+ } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {
190
190
  returnType = BUILTIN;
191
- } else if ( atoms && atoms.propertyIsEnumerable(stream.current()) ) {
191
+ } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {
192
192
  returnType = ATOM;
193
193
  } else returnType = null;
194
194
  }
@@ -92,7 +92,7 @@ CodeMirror.defineMode("css", function(config) {
92
92
  var style = state.tokenize(stream, state);
93
93
 
94
94
  var context = state.stack[state.stack.length-1];
95
- if (type == "hash" && context == "rule") style = "atom";
95
+ if (type == "hash" && context != "rule") style = "string-2";
96
96
  else if (style == "variable") {
97
97
  if (context == "rule") style = "number";
98
98
  else if (!context || context == "@media{") style = "tag";
@@ -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
  }
@@ -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,7 +334,7 @@ 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
  },
@@ -1,21 +1,26 @@
1
- CodeMirror.defineMode("less", function(config) {
1
+ /*
2
+ LESS mode - http://www.lesscss.org/
3
+ Ported to CodeMirror by Peter Kroon
4
+ */
5
+
6
+ CodeMirror.defineMode("css", function(config) {
2
7
  var indentUnit = config.indentUnit, type;
3
8
  function ret(style, tp) {type = tp; return style;}
4
9
  //html5 tags
5
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"];
6
11
 
7
12
  function inTagsArray(val){
8
- for(var i=0; i<tags.length; i++){
9
- if(val === tags[i]){
10
- return true;
11
- }
12
- }
13
+ for(var i=0; i<tags.length; i++){
14
+ if(val === tags[i]){
15
+ return true;
16
+ }
17
+ }
13
18
  }
14
19
 
15
20
  function tokenBase(stream, state) {
16
21
  var ch = stream.next();
17
22
 
18
- if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
23
+ if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
19
24
  else if (ch == "/" && stream.eat("*")) {
20
25
  state.tokenize = tokenCComment;
21
26
  return tokenCComment(stream, state);
@@ -30,15 +35,15 @@ CodeMirror.defineMode("less", function(config) {
30
35
  state.tokenize = tokenString(ch);
31
36
  return state.tokenize(stream, state);
32
37
  }
33
- else if (ch == "/") { // lesscss e.g.: .png will not be parsed as a class
34
- if(stream.eat("/")){
35
- state.tokenize = tokenSComment
38
+ else if (ch == "/") { // lesscss e.g.: .png will not be parsed as a class
39
+ if(stream.eat("/")){
40
+ state.tokenize = tokenSComment
36
41
  return tokenSComment(stream, state);
37
- }else{
38
- stream.eatWhile(/[\a-zA-Z0-9\-_.]/);
39
- if(stream.peek() == ")" || stream.peek() == "/")return ret("string", "string");//let url(/images/logo.png) without quotes return as string
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
40
45
  return ret("number", "unit");
41
- }
46
+ }
42
47
  }
43
48
  else if (ch == "!") {
44
49
  stream.match(/^\s*\w*/);
@@ -48,66 +53,86 @@ CodeMirror.defineMode("less", function(config) {
48
53
  stream.eatWhile(/[\w.%]/);
49
54
  return ret("number", "unit");
50
55
  }
51
- else if (/[,+>*\/]/.test(ch)) {//removed . dot character original was [,.+>*\/]
56
+ else if (/[,+<>*\/]/.test(ch)) {//removed . dot character original was [,.+>*\/]
52
57
  return ret(null, "select-op");
53
58
  }
54
59
  else if (/[;{}:\[\]()]/.test(ch)) { //added () char for lesscss original was [;{}:\[\]]
55
60
  if(ch == ":"){
56
- stream.eatWhile(/[active|hover|link|visited]/);
57
- if( stream.current().match(/active|hover|link|visited/)){
58
- return ret("tag", "tag");
59
- }else{
60
- return ret(null, ch);
61
- }
62
- }else{
63
- return ret(null, ch);
64
- }
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
+ }
65
70
  }
66
- else if (ch == ".") { // lesscss
67
- stream.eatWhile(/[\a-zA-Z0-9\-_]/);
71
+ else if (ch == ".") { // lesscss
72
+ stream.eatWhile(/[\a-zA-Z0-9\-_]/);
68
73
  return ret("tag", "tag");
69
74
  }
70
- else if (ch == "#") { // lesscss
71
- stream.match(/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/);
72
- if(stream.current().length >1){
73
- if(stream.current().match(/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/) != null){
74
- return ret("number", "unit");
75
- }else{
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 == "&") {
76
105
  stream.eatWhile(/[\w\-]/);
77
- return ret("atom", "tag");
106
+ return ret(null, ch);
107
+ }
108
+ else if (ch == "&") {
109
+ stream.eatWhile(/[\w\-]/);
110
+ return ret(null, ch);
78
111
  }
79
- }else{
80
- stream.eatWhile(/[\w\-]/);
81
- return ret("atom", "tag");
82
- }
83
- }
84
- else if (ch == "&") {
85
- stream.eatWhile(/[\w\-]/);
86
- return ret(null, ch);
87
- }
88
112
  else {
89
113
  stream.eatWhile(/[\w\\\-_.%]/);
90
- if( stream.eat("(") ){ // lesscss
91
- return ret(null, ch);
92
- }else if( stream.current().match(/\-\d|\-.\d/) ){ // lesscss match e.g.: -5px -0.4 etc...
93
- return ret("number", "unit");
94
- }else if( inTagsArray(stream.current()) ){ // lesscss match html tags
95
- return ret("tag", "tag");
96
- }else if( (stream.peek() == ")" || stream.peek() == "/") && stream.current().indexOf('.') !== -1){
97
- return ret("string", "string");//let url(logo.png) without quotes and froward slash return as string
98
- }else{
114
+ if( stream.peek().match(/\(/) != null ){// lesscss
115
+ stream.eatWhile(/[a-zA-Z\s]/);
116
+ if(stream.peek() == "(")return ret(null, ch);
117
+ }else if( stream.current().match(/\-\d|\-.\d/) ){ // lesscss match e.g.: -5px -0.4 etc...
118
+ return ret("number", "unit");
119
+ }else if( inTagsArray(stream.current()) ){ // lesscss match html tags
120
+ return ret("tag", "tag");
121
+ }else if( /\/|\)/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == ")")) && stream.current().indexOf(".") !== -1){
122
+ return ret("string", "string");//let url(/images/logo.png) without quotes return as string
123
+ }else{
99
124
  return ret("variable", "variable");
100
- }
125
+ }
101
126
  }
102
127
 
103
128
  }
104
129
 
105
130
  function tokenSComment(stream, state) {// SComment = Slash comment
106
131
  stream.skipToEnd();
107
- state.tokenize = tokenBase;
132
+ state.tokenize = tokenBase;
108
133
  return ret("comment", "comment");
109
134
  }
110
-
135
+
111
136
  function tokenCComment(stream, state) {
112
137
  var maybeEnd = false, ch;
113
138
  while ((ch = stream.next()) != null) {
@@ -146,7 +171,7 @@ CodeMirror.defineMode("less", function(config) {
146
171
  }
147
172
 
148
173
  return {
149
- startState: function(base) {
174
+ startState: function(base) {
150
175
  return {tokenize: tokenBase,
151
176
  baseIndent: base || 0,
152
177
  stack: []};
@@ -160,7 +185,11 @@ CodeMirror.defineMode("less", function(config) {
160
185
  if (type == "hash" && context == "rule") style = "atom";
161
186
  else if (style == "variable") {
162
187
  if (context == "rule") style = null; //"tag"
163
- else if (!context || context == "@media{") style = "tag";
188
+ else if (!context || context == "@media{"){
189
+ style = stream.current() == "when" ? "variable" :
190
+ stream.string.match(/#/g) != undefined ? null :
191
+ /[\s,|\s\)]/.test(stream.peek()) ? "tag" : null;
192
+ }
164
193
  }
165
194
 
166
195
  if (context == "rule" && /^[\{\};]$/.test(type))
@@ -186,4 +215,4 @@ CodeMirror.defineMode("less", function(config) {
186
215
  };
187
216
  });
188
217
 
189
- CodeMirror.defineMIME("text/less", "less");
218
+ CodeMirror.defineMIME("text/css", "css");
@@ -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+/
16
+ var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
17
+ , ulRE = /^[*\-+]\s+/
18
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,9 +32,18 @@ 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
44
  var match;
38
- if (stream.match(codeRE)) {
45
+ if (state.indentationDiff >= 4) {
46
+ state.indentation -= state.indentationDiff;
39
47
  stream.skipToEnd();
40
48
  return code;
41
49
  } else if (stream.eatSpace()) {
@@ -47,11 +55,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
47
55
  state.quote = true;
48
56
  } else if (stream.peek() === '[') {
49
57
  return switchInline(stream, state, footnoteLink);
50
- } else if (hrRE.test(stream.peek())) {
51
- var re = new RegExp('(?:\s*['+stream.peek()+']){3,}$');
52
- if (stream.match(re, true)) {
53
- return hr;
54
- }
58
+ } else if (stream.match(hrRE, true)) {
59
+ return hr;
55
60
  } else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
56
61
  state.indentation += match[0].length;
57
62
  return list;
@@ -72,39 +77,15 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
72
77
 
73
78
  // Inline
74
79
  function getType(state) {
80
+ var styles = [];
75
81
 
76
- // Set defaults
77
- returnValue = '';
78
-
79
- // Strong / Emphasis
80
- if(state.strong){
81
- if(state.em){
82
- returnValue += (returnValue ? ' ' : '') + emstrong;
83
- } else {
84
- returnValue += (returnValue ? ' ' : '') + strong;
85
- }
86
- } else {
87
- if(state.em){
88
- returnValue += (returnValue ? ' ' : '') + em;
89
- }
90
- }
91
-
92
- // Header
93
- if(state.header){
94
- returnValue += (returnValue ? ' ' : '') + header;
95
- }
96
-
97
- // Quotes
98
- if(state.quote){
99
- returnValue += (returnValue ? ' ' : '') + quote;
100
- }
101
-
102
- // Check valud and return
103
- if(!returnValue){
104
- returnValue = null;
105
- }
106
- return returnValue;
82
+ if (state.strong) { styles.push(state.em ? emstrong : strong); }
83
+ else if (state.em) { styles.push(em); }
107
84
 
85
+ if (state.header) { styles.push(header); }
86
+ if (state.quote) { styles.push(quote); }
87
+
88
+ return styles.length ? styles.join(' ') : null;
108
89
  }
109
90
 
110
91
  function handleText(stream, state) {
@@ -238,36 +219,24 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
238
219
 
239
220
  token: function(stream, state) {
240
221
  if (stream.sol()) {
241
- // Reset EM state
242
- state.em = false;
243
- // Reset STRONG state
244
- state.strong = false;
222
+ if (stream.match(/^\s*$/, true)) { return blankLine(state); }
223
+
245
224
  // Reset state.header
246
225
  state.header = false;
247
226
  // Reset state.quote
248
227
  state.quote = false;
249
228
 
250
229
  state.f = state.block;
251
- var previousIndentation = state.indentation
252
- , currentIndentation = 0;
253
- while (previousIndentation > 0) {
254
- if (stream.eat(' ')) {
255
- previousIndentation--;
256
- currentIndentation++;
257
- } else if (previousIndentation >= 4 && stream.eat('\t')) {
258
- previousIndentation -= 4;
259
- currentIndentation += 4;
260
- } else {
261
- break;
262
- }
263
- }
264
- state.indentation = currentIndentation;
265
-
266
- 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; }
267
234
  }
268
235
  return state.f(stream, state);
269
236
  },
270
237
 
238
+ blankLine: blankLine,
239
+
271
240
  getType: getType
272
241
  };
273
242