codemirror-rails 3.20 → 3.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +240 -135
  4. data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +6 -2
  5. data/vendor/assets/javascripts/codemirror/addons/comment/continuecomment.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +1 -0
  7. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +5 -3
  8. data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +10 -6
  9. data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +2 -0
  10. data/vendor/assets/javascripts/codemirror/addons/edit/matchbrackets.js +1 -1
  11. data/vendor/assets/javascripts/codemirror/addons/fold/comment-fold.js +3 -1
  12. data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +13 -2
  13. data/vendor/assets/javascripts/codemirror/addons/fold/foldgutter.js +1 -1
  14. data/vendor/assets/javascripts/codemirror/addons/fold/indent-fold.js +2 -2
  15. data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +6 -0
  16. data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +3 -5
  17. data/vendor/assets/javascripts/codemirror/addons/hint/css-hint.js +29 -33
  18. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/addons/hint/pig-hint.js +1 -1
  20. data/vendor/assets/javascripts/codemirror/addons/hint/python-hint.js +1 -5
  21. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +58 -9
  22. data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +58 -17
  23. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +5 -5
  24. data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +1 -1
  25. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +6 -1
  26. data/vendor/assets/javascripts/codemirror/addons/mode/multiplex.js +5 -3
  27. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode-standalone.js +26 -11
  28. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.js +1 -1
  29. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +22 -11
  30. data/vendor/assets/javascripts/codemirror/addons/search/search.js +22 -9
  31. data/vendor/assets/javascripts/codemirror/addons/search/searchcursor.js +48 -24
  32. data/vendor/assets/javascripts/codemirror/addons/selection/active-line.js +15 -9
  33. data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +3 -3
  34. data/vendor/assets/javascripts/codemirror/addons/wrap/hardwrap.js +21 -9
  35. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +12 -1
  36. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +110 -28
  37. data/vendor/assets/javascripts/codemirror/modes/clike.js +28 -9
  38. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +3 -4
  39. data/vendor/assets/javascripts/codemirror/modes/css.js +341 -297
  40. data/vendor/assets/javascripts/codemirror/modes/erlang.js +302 -179
  41. data/vendor/assets/javascripts/codemirror/modes/gfm.js +10 -5
  42. data/vendor/assets/javascripts/codemirror/modes/gherkin.js +45 -50
  43. data/vendor/assets/javascripts/codemirror/modes/haml.js +0 -4
  44. data/vendor/assets/javascripts/codemirror/modes/haskell.js +5 -3
  45. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +0 -2
  46. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +0 -2
  47. data/vendor/assets/javascripts/codemirror/modes/javascript.js +43 -30
  48. data/vendor/assets/javascripts/codemirror/modes/jinja2.js +13 -3
  49. data/vendor/assets/javascripts/codemirror/modes/less.js +7 -6
  50. data/vendor/assets/javascripts/codemirror/modes/markdown.js +231 -45
  51. data/vendor/assets/javascripts/codemirror/modes/{ocaml.js → mllike.js} +88 -13
  52. data/vendor/assets/javascripts/codemirror/modes/pegjs.js +5 -9
  53. data/vendor/assets/javascripts/codemirror/modes/php.js +6 -7
  54. data/vendor/assets/javascripts/codemirror/modes/python.js +6 -0
  55. data/vendor/assets/javascripts/codemirror/modes/r.js +5 -1
  56. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.js +1 -1
  57. data/vendor/assets/javascripts/codemirror/modes/ruby.js +3 -1
  58. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +4 -2
  59. data/vendor/assets/javascripts/codemirror/modes/smartymixed.js +0 -2
  60. data/vendor/assets/javascripts/codemirror/modes/sql.js +5 -4
  61. data/vendor/assets/javascripts/codemirror/modes/xml.js +87 -100
  62. data/vendor/assets/stylesheets/codemirror/themes/mbo.css +1 -1
  63. data/vendor/assets/stylesheets/codemirror/themes/midnight.css +1 -1
  64. data/vendor/assets/stylesheets/codemirror/themes/pastel-on-dark.css +49 -0
  65. data/vendor/assets/stylesheets/codemirror/themes/the-matrix.css +1 -1
  66. metadata +3 -2
@@ -1,45 +1,24 @@
1
- // block; "begin", "case", "fun", "if", "receive", "try": closed by "end"
2
- // block internal; "after", "catch", "of"
3
- // guard; "when", closed by "->"
4
- // "->" opens a clause, closed by ";" or "."
5
- // "<<" opens a binary, closed by ">>"
6
- // "," appears in arglists, lists, tuples and terminates lines of code
7
- // "." resets indentation to 0
8
- // obsolete; "cond", "let", "query"
1
+ /*jshint unused:true, eqnull:true, curly:true, bitwise:true */
2
+ /*jshint undef:true, latedef:true, trailing:true */
3
+ /*global CodeMirror:true */
4
+
5
+ // erlang mode.
6
+ // tokenizer -> token types -> CodeMirror styles
7
+ // tokenizer maintains a parse stack
8
+ // indenter uses the parse stack
9
+
10
+ // TODO indenter:
11
+ // bit syntax
12
+ // old guard/bif/conversion clashes (e.g. "float/1")
13
+ // type/spec/opaque
9
14
 
10
15
  CodeMirror.defineMIME("text/x-erlang", "erlang");
11
16
 
12
17
  CodeMirror.defineMode("erlang", function(cmCfg) {
18
+ "use strict";
13
19
 
14
- function rval(state,_stream,type) {
15
- // distinguish between "." as terminator and record field operator
16
- state.in_record = (type == "record");
17
-
18
- // erlang -> CodeMirror tag
19
- switch (type) {
20
- case "atom": return "atom";
21
- case "attribute": return "attribute";
22
- case "boolean": return "special";
23
- case "builtin": return "builtin";
24
- case "comment": return "comment";
25
- case "fun": return "meta";
26
- case "function": return "tag";
27
- case "guard": return "property";
28
- case "keyword": return "keyword";
29
- case "macro": return "variable-2";
30
- case "number": return "number";
31
- case "operator": return "operator";
32
- case "record": return "bracket";
33
- case "string": return "string";
34
- case "type": return "def";
35
- case "variable": return "variable";
36
- case "error": return "error";
37
- case "separator": return null;
38
- case "open_paren": return null;
39
- case "close_paren": return null;
40
- default: return null;
41
- }
42
- }
20
+ /////////////////////////////////////////////////////////////////////////////
21
+ // constants
43
22
 
44
23
  var typeWords = [
45
24
  "-type", "-spec", "-export_type", "-opaque"];
@@ -48,23 +27,23 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
48
27
  "after","begin","catch","case","cond","end","fun","if",
49
28
  "let","of","query","receive","try","when"];
50
29
 
51
- var separatorRE = /[\->\.,:;]/;
30
+ var separatorRE = /[\->,;]/;
52
31
  var separatorWords = [
53
- "->",";",":",".",","];
32
+ "->",";",","];
54
33
 
55
- var operatorWords = [
34
+ var operatorAtomWords = [
56
35
  "and","andalso","band","bnot","bor","bsl","bsr","bxor",
57
36
  "div","not","or","orelse","rem","xor"];
58
37
 
59
- var symbolRE = /[\+\-\*\/<>=\|:!]/;
60
- var symbolWords = [
61
- "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"];
38
+ var operatorSymbolRE = /[\+\-\*\/<>=\|:!]/;
39
+ var operatorSymbolWords = [
40
+ "=","+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"];
62
41
 
63
- var openParenRE = /[<\(\[\{]/;
42
+ var openParenRE = /[<\(\[\{]/;
64
43
  var openParenWords = [
65
44
  "<<","(","[","{"];
66
45
 
67
- var closeParenRE = /[>\)\]\}]/;
46
+ var closeParenRE = /[>\)\]\}]/;
68
47
  var closeParenWords = [
69
48
  "}","]",")",">>"];
70
49
 
@@ -99,23 +78,25 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
99
78
  "term_to_binary","time","throw","tl","trunc","tuple_size",
100
79
  "tuple_to_list","unlink","unregister","whereis"];
101
80
 
102
- // [Ø-Þ] [À-Ö]
103
- // [ß-ö] [ø-ÿ]
81
+ // upper case: [A-Z] [Ø-Þ] [À-Ö]
82
+ // lower case: [a-z] [ß-ö] [ø-ÿ]
104
83
  var anumRE = /[\w@Ø-ÞÀ-Öß-öø-ÿ]/;
105
84
  var escapesRE =
106
85
  /[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/;
107
86
 
108
- function tokenize(stream, state) {
87
+ /////////////////////////////////////////////////////////////////////////////
88
+ // tokenizer
109
89
 
90
+ function tokenizer(stream,state) {
110
91
  // in multi-line string
111
92
  if (state.in_string) {
112
- state.in_string = (!doubleQuote(stream));
93
+ state.in_string = (!doubleQuote(stream));
113
94
  return rval(state,stream,"string");
114
95
  }
115
96
 
116
97
  // in multi-line atom
117
98
  if (state.in_atom) {
118
- state.in_atom = (!singleQuote(stream));
99
+ state.in_atom = (!singleQuote(stream));
119
100
  return rval(state,stream,"atom");
120
101
  }
121
102
 
@@ -125,9 +106,9 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
125
106
  }
126
107
 
127
108
  // attributes and type specs
128
- if ((peekToken(state).token == "") &&
109
+ if (!peekToken(state) &&
129
110
  stream.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/)) {
130
- if (isMember(stream.current(),typeWords)) {
111
+ if (is_member(stream.current(),typeWords)) {
131
112
  return rval(state,stream,"type");
132
113
  }else{
133
114
  return rval(state,stream,"attribute");
@@ -142,32 +123,43 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
142
123
  return rval(state,stream,"comment");
143
124
  }
144
125
 
126
+ // colon
127
+ if (ch == ":") {
128
+ return rval(state,stream,"colon");
129
+ }
130
+
145
131
  // macro
146
132
  if (ch == '?') {
133
+ stream.eatSpace();
147
134
  stream.eatWhile(anumRE);
148
135
  return rval(state,stream,"macro");
149
136
  }
150
137
 
151
138
  // record
152
139
  if (ch == "#") {
140
+ stream.eatSpace();
153
141
  stream.eatWhile(anumRE);
154
142
  return rval(state,stream,"record");
155
143
  }
156
144
 
157
145
  // dollar escape
158
- if ( ch == "$" ) {
146
+ if (ch == "$") {
159
147
  if (stream.next() == "\\" && !stream.match(escapesRE)) {
160
148
  return rval(state,stream,"error");
161
149
  }
162
150
  return rval(state,stream,"number");
163
151
  }
164
152
 
153
+ // dot
154
+ if (ch == ".") {
155
+ return rval(state,stream,"dot");
156
+ }
157
+
165
158
  // quoted atom
166
159
  if (ch == '\'') {
167
160
  if (!(state.in_atom = (!singleQuote(stream)))) {
168
161
  if (stream.match(/\s*\/\s*[0-9]/,false)) {
169
162
  stream.match(/\s*\/\s*[0-9]/,true);
170
- popToken(state);
171
163
  return rval(state,stream,"fun"); // 'f'/0 style fun
172
164
  }
173
165
  if (stream.match(/\s*\(/,false) || stream.match(/\s*:/,false)) {
@@ -195,34 +187,37 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
195
187
 
196
188
  if (stream.match(/\s*\/\s*[0-9]/,false)) {
197
189
  stream.match(/\s*\/\s*[0-9]/,true);
198
- popToken(state);
199
190
  return rval(state,stream,"fun"); // f/0 style fun
200
191
  }
201
192
 
202
193
  var w = stream.current();
203
194
 
204
- if (isMember(w,keywordWords)) {
205
- pushToken(state,stream);
195
+ if (is_member(w,keywordWords)) {
206
196
  return rval(state,stream,"keyword");
197
+ }else if (is_member(w,operatorAtomWords)) {
198
+ return rval(state,stream,"operator");
207
199
  }else if (stream.match(/\s*\(/,false)) {
208
200
  // 'put' and 'erlang:put' are bifs, 'foo:put' is not
209
- if (isMember(w,bifWords) &&
210
- (!isPrev(stream,":") || isPrev(stream,"erlang:"))) {
201
+ if (is_member(w,bifWords) &&
202
+ ((peekToken(state).token != ":") ||
203
+ (peekToken(state,2).token == "erlang"))) {
211
204
  return rval(state,stream,"builtin");
212
- }else if (isMember(w,guardWords)) {
205
+ }else if (is_member(w,guardWords)) {
213
206
  return rval(state,stream,"guard");
214
207
  }else{
215
208
  return rval(state,stream,"function");
216
209
  }
217
- }else if (isMember(w,operatorWords)) {
210
+ }else if (is_member(w,operatorAtomWords)) {
218
211
  return rval(state,stream,"operator");
219
- }else if (stream.match(/\s*:/,false)) {
212
+ }else if (lookahead(stream) == ":") {
220
213
  if (w == "erlang") {
221
214
  return rval(state,stream,"builtin");
222
215
  } else {
223
216
  return rval(state,stream,"function");
224
217
  }
225
- }else if (isMember(w,["true","false"])) {
218
+ }else if (is_member(w,["true","false"])) {
219
+ return rval(state,stream,"boolean");
220
+ }else if (is_member(w,["true","false"])) {
226
221
  return rval(state,stream,"boolean");
227
222
  }else{
228
223
  return rval(state,stream,"atom");
@@ -234,15 +229,25 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
234
229
  var radixRE = /[0-9a-zA-Z]/; // 36#zZ style int
235
230
  if (digitRE.test(ch)) {
236
231
  stream.eatWhile(digitRE);
237
- if (stream.eat('#')) {
238
- stream.eatWhile(radixRE); // 36#aZ style integer
239
- } else {
240
- if (stream.eat('.')) { // float
241
- stream.eatWhile(digitRE);
232
+ if (stream.eat('#')) { // 36#aZ style integer
233
+ if (!stream.eatWhile(radixRE)) {
234
+ stream.backUp(1); //"36#" - syntax error
242
235
  }
243
- if (stream.eat(/[eE]/)) {
244
- stream.eat(/[-+]/); // float with exponent
245
- stream.eatWhile(digitRE);
236
+ } else if (stream.eat('.')) { // float
237
+ if (!stream.eatWhile(digitRE)) {
238
+ stream.backUp(1); // "3." - probably end of function
239
+ } else {
240
+ if (stream.eat(/[eE]/)) { // float with exponent
241
+ if (stream.eat(/[-+]/)) {
242
+ if (!stream.eatWhile(digitRE)) {
243
+ stream.backUp(2); // "2e-" - syntax error
244
+ }
245
+ } else {
246
+ if (!stream.eatWhile(digitRE)) {
247
+ stream.backUp(1); // "2e" - syntax error
248
+ }
249
+ }
250
+ }
246
251
  }
247
252
  }
248
253
  return rval(state,stream,"number"); // normal integer
@@ -250,50 +255,35 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
250
255
 
251
256
  // open parens
252
257
  if (nongreedy(stream,openParenRE,openParenWords)) {
253
- pushToken(state,stream);
254
258
  return rval(state,stream,"open_paren");
255
259
  }
256
260
 
257
261
  // close parens
258
262
  if (nongreedy(stream,closeParenRE,closeParenWords)) {
259
- pushToken(state,stream);
260
263
  return rval(state,stream,"close_paren");
261
264
  }
262
265
 
263
266
  // separators
264
267
  if (greedy(stream,separatorRE,separatorWords)) {
265
- // distinguish between "." as terminator and record field operator
266
- if (!state.in_record) {
267
- pushToken(state,stream);
268
- }
269
268
  return rval(state,stream,"separator");
270
269
  }
271
270
 
272
271
  // operators
273
- if (greedy(stream,symbolRE,symbolWords)) {
272
+ if (greedy(stream,operatorSymbolRE,operatorSymbolWords)) {
274
273
  return rval(state,stream,"operator");
275
274
  }
276
275
 
277
276
  return rval(state,stream,null);
278
277
  }
279
278
 
280
- function isPrev(stream,string) {
281
- var start = stream.start;
282
- var len = string.length;
283
- if (len <= start) {
284
- var word = stream.string.slice(start-len,start);
285
- return word == string;
286
- }else{
287
- return false;
288
- }
289
- }
290
-
279
+ /////////////////////////////////////////////////////////////////////////////
280
+ // utilities
291
281
  function nongreedy(stream,re,words) {
292
282
  if (stream.current().length == 1 && re.test(stream.current())) {
293
283
  stream.backUp(1);
294
284
  while (re.test(stream.peek())) {
295
285
  stream.next();
296
- if (isMember(stream.current(),words)) {
286
+ if (is_member(stream.current(),words)) {
297
287
  return true;
298
288
  }
299
289
  }
@@ -308,7 +298,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
308
298
  stream.next();
309
299
  }
310
300
  while (0 < stream.current().length) {
311
- if (isMember(stream.current(),words)) {
301
+ if (is_member(stream.current(),words)) {
312
302
  return true;
313
303
  }else{
314
304
  stream.backUp(1);
@@ -339,144 +329,277 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
339
329
  return false;
340
330
  }
341
331
 
342
- function isMember(element,list) {
332
+ function lookahead(stream) {
333
+ var m = stream.match(/([\n\s]+|%[^\n]*\n)*(.)/,false);
334
+ return m ? m.pop() : "";
335
+ }
336
+
337
+ function is_member(element,list) {
343
338
  return (-1 < list.indexOf(element));
344
339
  }
345
340
 
346
- /////////////////////////////////////////////////////////////////////////////
347
- function myIndent(state,textAfter) {
348
- var indent = cmCfg.indentUnit;
349
- var token = (peekToken(state)).token;
350
- var wordAfter = takewhile(textAfter,/[^a-z]/);
341
+ function rval(state,stream,type) {
351
342
 
352
- if (state.in_string || state.in_atom) {
353
- return CodeMirror.Pass;
354
- }else if (token == "") {
355
- return 0;
356
- }else if (isMember(token,openParenWords)) {
357
- return (peekToken(state)).column+token.length;
358
- }else if (token == "when") {
359
- return (peekToken(state)).column+token.length+1;
360
- }else if (token == "fun" && wordAfter == "") {
361
- return (peekToken(state)).column+token.length;
362
- }else if (token == "->") {
363
- if (isMember(wordAfter,["end","after","catch"])) {
364
- return peekToken(state,2).column;
365
- }else if (peekToken(state,2).token == "fun") {
366
- return peekToken(state,2).column+indent;
367
- }else if (peekToken(state,2).token == "") {
368
- return indent;
369
- }else{
370
- return (peekToken(state)).indent+indent;
371
- }
372
- }else if (isMember(wordAfter,["after","catch","of"])) {
373
- return (peekToken(state)).indent;
374
- }else{
375
- return (peekToken(state)).column+indent;
343
+ // parse stack
344
+ pushToken(state,realToken(type,stream));
345
+
346
+ // map erlang token type to CodeMirror style class
347
+ // erlang -> CodeMirror tag
348
+ switch (type) {
349
+ case "atom": return "atom";
350
+ case "attribute": return "attribute";
351
+ case "boolean": return "special";
352
+ case "builtin": return "builtin";
353
+ case "close_paren": return null;
354
+ case "colon": return null;
355
+ case "comment": return "comment";
356
+ case "dot": return null;
357
+ case "error": return "error";
358
+ case "fun": return "meta";
359
+ case "function": return "tag";
360
+ case "guard": return "property";
361
+ case "keyword": return "keyword";
362
+ case "macro": return "variable-2";
363
+ case "number": return "number";
364
+ case "open_paren": return null;
365
+ case "operator": return "operator";
366
+ case "record": return "bracket";
367
+ case "separator": return null;
368
+ case "string": return "string";
369
+ case "type": return "def";
370
+ case "variable": return "variable";
371
+ default: return null;
376
372
  }
377
373
  }
378
374
 
379
- function takewhile(str,re) {
380
- var m = str.match(re);
381
- return m ? str.slice(0,m.index) : str;
375
+ function aToken(tok,col,ind,typ) {
376
+ return {token: tok,
377
+ column: col,
378
+ indent: ind,
379
+ type: typ};
382
380
  }
383
381
 
384
- function Token(stream) {
385
- this.token = stream ? stream.current() : "";
386
- this.column = stream ? stream.column() : 0;
387
- this.indent = stream ? stream.indentation() : 0;
382
+ function realToken(type,stream) {
383
+ return aToken(stream.current(),
384
+ stream.column(),
385
+ stream.indentation(),
386
+ type);
388
387
  }
389
388
 
390
- function popToken(state) {
391
- return state.tokenStack.pop();
389
+ function fakeToken(type) {
390
+ return aToken(type,0,0,type);
392
391
  }
393
392
 
394
393
  function peekToken(state,depth) {
395
394
  var len = state.tokenStack.length;
396
395
  var dep = (depth ? depth : 1);
396
+
397
397
  if (len < dep) {
398
- return new Token;
398
+ return false;
399
399
  }else{
400
400
  return state.tokenStack[len-dep];
401
401
  }
402
402
  }
403
403
 
404
- function pushToken(state,stream) {
405
- var token = stream.current();
406
- var prev_token = peekToken(state).token;
404
+ function pushToken(state,token) {
407
405
 
408
- if (token == ".") {
409
- state.tokenStack = [];
410
- return false;
411
- }else if(isMember(token,[",", ":", "of", "cond", "let", "query"])) {
412
- return false;
413
- }else if (drop_last(prev_token,token)) {
414
- return false;
415
- }else if (drop_both(prev_token,token)) {
416
- popToken(state);
417
- return false;
418
- }else if (drop_first(prev_token,token)) {
419
- popToken(state);
420
- return pushToken(state,stream);
421
- }else if (isMember(token,["after","catch"])) {
422
- return false;
406
+ if (!(token.type == "comment" || token.type == "whitespace")) {
407
+ state.tokenStack = maybe_drop_pre(state.tokenStack,token);
408
+ state.tokenStack = maybe_drop_post(state.tokenStack);
409
+ }
410
+ }
411
+
412
+ function maybe_drop_pre(s,token) {
413
+ var last = s.length-1;
414
+
415
+ if (0 < last && s[last].type === "record" && token.type === "dot") {
416
+ s.pop();
417
+ }else if (0 < last && s[last].type === "group") {
418
+ s.pop();
419
+ s.push(token);
423
420
  }else{
424
- state.tokenStack.push(new Token(stream));
425
- return true;
421
+ s.push(token);
426
422
  }
423
+ return s;
427
424
  }
428
425
 
429
- function drop_last(open, close) {
430
- switch(open+" "+close) {
431
- case "when ;": return true;
432
- default: return false;
426
+ function maybe_drop_post(s) {
427
+ var last = s.length-1;
428
+
429
+ if (s[last].type === "dot") {
430
+ return [];
431
+ }
432
+ if (s[last].type === "fun" && s[last-1].token === "fun") {
433
+ return s.slice(0,last-1);
434
+ }
435
+ switch (s[s.length-1].token) {
436
+ case "}": return d(s,{g:["{"]});
437
+ case "]": return d(s,{i:["["]});
438
+ case ")": return d(s,{i:["("]});
439
+ case ">>": return d(s,{i:["<<"]});
440
+ case "end": return d(s,{i:["begin","case","fun","if","receive","try"]});
441
+ case ",": return d(s,{e:["begin","try","when","->",
442
+ ",","(","[","{","<<"]});
443
+ case "->": return d(s,{r:["when"],
444
+ m:["try","if","case","receive"]});
445
+ case ";": return d(s,{E:["case","fun","if","receive","try","when"]});
446
+ case "catch":return d(s,{e:["try"]});
447
+ case "of": return d(s,{e:["case"]});
448
+ case "after":return d(s,{e:["receive","try"]});
449
+ default: return s;
433
450
  }
434
451
  }
435
452
 
436
- function drop_first(open, close) {
437
- switch (open+" "+close) {
438
- case "when ->": return true;
439
- case "-> end": return true;
440
- default: return false;
453
+ function d(stack,tt) {
454
+ // stack is a stack of Token objects.
455
+ // tt is an object; {type:tokens}
456
+ // type is a char, tokens is a list of token strings.
457
+ // The function returns (possibly truncated) stack.
458
+ // It will descend the stack, looking for a Token such that Token.token
459
+ // is a member of tokens. If it does not find that, it will normally (but
460
+ // see "E" below) return stack. If it does find a match, it will remove
461
+ // all the Tokens between the top and the matched Token.
462
+ // If type is "m", that is all it does.
463
+ // If type is "i", it will also remove the matched Token and the top Token.
464
+ // If type is "g", like "i", but add a fake "group" token at the top.
465
+ // If type is "r", it will remove the matched Token, but not the top Token.
466
+ // If type is "e", it will keep the matched Token but not the top Token.
467
+ // If type is "E", it behaves as for type "e", except if there is no match,
468
+ // in which case it will return an empty stack.
469
+
470
+ for (var type in tt) {
471
+ var len = stack.length-1;
472
+ var tokens = tt[type];
473
+ for (var i = len-1; -1 < i ; i--) {
474
+ if (is_member(stack[i].token,tokens)) {
475
+ var ss = stack.slice(0,i);
476
+ switch (type) {
477
+ case "m": return ss.concat(stack[i]).concat(stack[len]);
478
+ case "r": return ss.concat(stack[len]);
479
+ case "i": return ss;
480
+ case "g": return ss.concat(fakeToken("group"));
481
+ case "E": return ss.concat(stack[i]);
482
+ case "e": return ss.concat(stack[i]);
483
+ }
484
+ }
485
+ }
441
486
  }
487
+ return (type == "E" ? [] : stack);
442
488
  }
443
489
 
444
- function drop_both(open, close) {
445
- switch (open+" "+close) {
446
- case "( )": return true;
447
- case "[ ]": return true;
448
- case "{ }": return true;
449
- case "<< >>": return true;
450
- case "begin end": return true;
451
- case "case end": return true;
452
- case "fun end": return true;
453
- case "if end": return true;
454
- case "receive end": return true;
455
- case "try end": return true;
456
- case "-> catch": return true;
457
- case "-> after": return true;
458
- case "-> ;": return true;
459
- default: return false;
490
+ /////////////////////////////////////////////////////////////////////////////
491
+ // indenter
492
+
493
+ function indenter(state,textAfter) {
494
+ var t;
495
+ var unit = cmCfg.indentUnit;
496
+ var wordAfter = wordafter(textAfter);
497
+ var currT = peekToken(state,1);
498
+ var prevT = peekToken(state,2);
499
+
500
+ if (state.in_string || state.in_atom) {
501
+ return CodeMirror.Pass;
502
+ }else if (!prevT) {
503
+ return 0;
504
+ }else if (currT.token == "when") {
505
+ return currT.column+unit;
506
+ }else if (wordAfter === "when" && prevT.type === "function") {
507
+ return prevT.indent+unit;
508
+ }else if (wordAfter === "(" && currT.token === "fun") {
509
+ return currT.column+3;
510
+ }else if (wordAfter === "catch" && (t = getToken(state,["try"]))) {
511
+ return t.column;
512
+ }else if (is_member(wordAfter,["end","after","of"])) {
513
+ t = getToken(state,["begin","case","fun","if","receive","try"]);
514
+ return t ? t.column : CodeMirror.Pass;
515
+ }else if (is_member(wordAfter,closeParenWords)) {
516
+ t = getToken(state,openParenWords);
517
+ return t ? t.column : CodeMirror.Pass;
518
+ }else if (is_member(currT.token,[",","|","||"]) ||
519
+ is_member(wordAfter,[",","|","||"])) {
520
+ t = postcommaToken(state);
521
+ return t ? t.column+t.token.length : unit;
522
+ }else if (currT.token == "->") {
523
+ if (is_member(prevT.token, ["receive","case","if","try"])) {
524
+ return prevT.column+unit+unit;
525
+ }else{
526
+ return prevT.column+unit;
527
+ }
528
+ }else if (is_member(currT.token,openParenWords)) {
529
+ return currT.column+currT.token.length;
530
+ }else{
531
+ t = defaultToken(state);
532
+ return truthy(t) ? t.column+unit : 0;
460
533
  }
461
534
  }
462
535
 
536
+ function wordafter(str) {
537
+ var m = str.match(/,|[a-z]+|\}|\]|\)|>>|\|+|\(/);
538
+
539
+ return truthy(m) && (m.index === 0) ? m[0] : "";
540
+ }
541
+
542
+ function postcommaToken(state) {
543
+ var objs = state.tokenStack.slice(0,-1);
544
+ var i = getTokenIndex(objs,"type",["open_paren"]);
545
+
546
+ return truthy(objs[i]) ? objs[i] : false;
547
+ }
548
+
549
+ function defaultToken(state) {
550
+ var objs = state.tokenStack;
551
+ var stop = getTokenIndex(objs,"type",["open_paren","separator","keyword"]);
552
+ var oper = getTokenIndex(objs,"type",["operator"]);
553
+
554
+ if (truthy(stop) && truthy(oper) && stop < oper) {
555
+ return objs[stop+1];
556
+ } else if (truthy(stop)) {
557
+ return objs[stop];
558
+ } else {
559
+ return false;
560
+ }
561
+ }
562
+
563
+ function getToken(state,tokens) {
564
+ var objs = state.tokenStack;
565
+ var i = getTokenIndex(objs,"token",tokens);
566
+
567
+ return truthy(objs[i]) ? objs[i] : false;
568
+ }
569
+
570
+ function getTokenIndex(objs,propname,propvals) {
571
+
572
+ for (var i = objs.length-1; -1 < i ; i--) {
573
+ if (is_member(objs[i][propname],propvals)) {
574
+ return i;
575
+ }
576
+ }
577
+ return false;
578
+ }
579
+
580
+ function truthy(x) {
581
+ return (x !== false) && (x != null);
582
+ }
583
+
584
+ /////////////////////////////////////////////////////////////////////////////
585
+ // this object defines the mode
586
+
463
587
  return {
464
588
  startState:
465
589
  function() {
466
590
  return {tokenStack: [],
467
- in_record: false,
468
591
  in_string: false,
469
592
  in_atom: false};
470
593
  },
471
594
 
472
595
  token:
473
596
  function(stream, state) {
474
- return tokenize(stream, state);
597
+ return tokenizer(stream, state);
475
598
  },
476
599
 
477
600
  indent:
478
601
  function(state, textAfter) {
479
- return myIndent(state,textAfter);
602
+ return indenter(state,textAfter);
480
603
  },
481
604
 
482
605
  lineComment: "%"