codemirror-rails 3.18 → 3.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +42 -19
  4. data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +1 -1
  5. data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +6 -4
  7. data/vendor/assets/javascripts/codemirror/addons/fold/foldgutter.js +2 -0
  8. data/vendor/assets/javascripts/codemirror/addons/fold/indent-fold.js +21 -7
  9. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +3 -19
  10. data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +105 -0
  11. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +1 -0
  12. data/vendor/assets/javascripts/codemirror/addons/search/search.js +2 -0
  13. data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +1 -1
  14. data/vendor/assets/javascripts/codemirror/addons/wrap/hardwrap.js +99 -0
  15. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +55 -17
  16. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +314 -313
  17. data/vendor/assets/javascripts/codemirror/modes/css.js +19 -7
  18. data/vendor/assets/javascripts/codemirror/modes/eiffel.js +147 -0
  19. data/vendor/assets/javascripts/codemirror/modes/gfm.js +2 -1
  20. data/vendor/assets/javascripts/codemirror/modes/gherkin.js +168 -0
  21. data/vendor/assets/javascripts/codemirror/modes/less.js +110 -22
  22. data/vendor/assets/javascripts/codemirror/modes/php.js +4 -4
  23. data/vendor/assets/javascripts/codemirror/modes/smartymixed.js +6 -1
  24. data/vendor/assets/javascripts/codemirror/modes/sql.js +15 -2
  25. data/vendor/assets/javascripts/codemirror/modes/xml.js +7 -3
  26. data/vendor/assets/stylesheets/codemirror.css +1 -1
  27. data/vendor/assets/stylesheets/codemirror/addons/fold/foldgutter.css +21 -0
  28. data/vendor/assets/stylesheets/codemirror/addons/lint/lint.css +1 -0
  29. data/vendor/assets/stylesheets/codemirror/themes/3024-day.css +1 -1
  30. data/vendor/assets/stylesheets/codemirror/themes/3024-night.css +1 -1
  31. data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +1 -1
  32. data/vendor/assets/stylesheets/codemirror/themes/base16-dark.css +1 -1
  33. data/vendor/assets/stylesheets/codemirror/themes/base16-light.css +1 -1
  34. data/vendor/assets/stylesheets/codemirror/themes/blackboard.css +1 -1
  35. data/vendor/assets/stylesheets/codemirror/themes/cobalt.css +1 -1
  36. data/vendor/assets/stylesheets/codemirror/themes/eclipse.css +1 -1
  37. data/vendor/assets/stylesheets/codemirror/themes/elegant.css +1 -1
  38. data/vendor/assets/stylesheets/codemirror/themes/erlang-dark.css +1 -1
  39. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +1 -1
  40. data/vendor/assets/stylesheets/codemirror/themes/mbo.css +35 -0
  41. data/vendor/assets/stylesheets/codemirror/themes/midnight.css +1 -1
  42. data/vendor/assets/stylesheets/codemirror/themes/monokai.css +1 -1
  43. data/vendor/assets/stylesheets/codemirror/themes/night.css +1 -1
  44. data/vendor/assets/stylesheets/codemirror/themes/paraiso-dark.css +1 -1
  45. data/vendor/assets/stylesheets/codemirror/themes/paraiso-light.css +1 -1
  46. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +1 -1
  47. data/vendor/assets/stylesheets/codemirror/themes/solarized.css +7 -7
  48. data/vendor/assets/stylesheets/codemirror/themes/the-matrix.css +1 -1
  49. data/vendor/assets/stylesheets/codemirror/themes/tomorrow-night-eighties.css +1 -1
  50. data/vendor/assets/stylesheets/codemirror/themes/twilight.css +1 -1
  51. data/vendor/assets/stylesheets/codemirror/themes/vibrant-ink.css +1 -1
  52. data/vendor/assets/stylesheets/codemirror/themes/xq-dark.css +1 -1
  53. data/vendor/assets/stylesheets/codemirror/themes/xq-light.css +1 -1
  54. metadata +7 -1
@@ -439,7 +439,7 @@
439
439
  for (var file in perFile) {
440
440
  var known = ts.docs[file], chs = perFile[file];;
441
441
  if (!known) continue;
442
- chs.sort(function(a, b) { return cmpPos(b, a); });
442
+ chs.sort(function(a, b) { return cmpPos(b.start, a.start); });
443
443
  var origin = "*rename" + (++nextChangeOrig);
444
444
  for (var i = 0; i < chs.length; ++i) {
445
445
  var ch = chs[i];
@@ -0,0 +1,99 @@
1
+ (function() {
2
+ "use strict";
3
+
4
+ var Pos = CodeMirror.Pos;
5
+
6
+ function findParagraph(cm, pos, options) {
7
+ var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart");
8
+ for (var start = pos.line, first = cm.firstLine(); start > first; --start) {
9
+ var line = cm.getLine(start);
10
+ if (startRE && startRE.test(line)) break;
11
+ if (!/\S/.test(line)) { ++start; break; }
12
+ }
13
+ var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd");
14
+ for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) {
15
+ var line = cm.getLine(end);
16
+ if (endRE && endRE.test(line)) { ++end; break; }
17
+ if (!/\S/.test(line)) break;
18
+ }
19
+ return {from: start, to: end};
20
+ }
21
+
22
+ function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
23
+ for (var at = column; at > 0; --at)
24
+ if (wrapOn.test(text.slice(at - 1, at + 1))) break;
25
+ if (at == 0) at = column;
26
+ var endOfText = at;
27
+ if (killTrailingSpace)
28
+ while (text.charAt(endOfText - 1) == " ") --endOfText;
29
+ return {from: endOfText, to: at};
30
+ }
31
+
32
+ function wrapRange(cm, from, to, options) {
33
+ from = cm.clipPos(from); to = cm.clipPos(to);
34
+ var column = options.column || 80;
35
+ var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/;
36
+ var killTrailing = options.killTrailingSpace !== false;
37
+ var changes = [], curLine = "", curNo = from.line;
38
+ var lines = cm.getRange(from, to, false);
39
+ for (var i = 0; i < lines.length; ++i) {
40
+ var text = lines[i], oldLen = curLine.length, spaceInserted = 0;
41
+ if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) {
42
+ curLine += " ";
43
+ spaceInserted = 1;
44
+ }
45
+ curLine += text;
46
+ if (i) {
47
+ var firstBreak = curLine.length > column && findBreakPoint(curLine, column, wrapOn, killTrailing);
48
+ // If this isn't broken, or is broken at a different point, remove old break
49
+ if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {
50
+ changes.push({text: spaceInserted ? " " : "",
51
+ from: Pos(curNo, oldLen),
52
+ to: Pos(curNo + 1, 0)});
53
+ } else {
54
+ curLine = text;
55
+ ++curNo;
56
+ }
57
+ }
58
+ while (curLine.length > column) {
59
+ var bp = findBreakPoint(curLine, column, wrapOn, killTrailing);
60
+ changes.push({text: "\n",
61
+ from: Pos(curNo, bp.from),
62
+ to: Pos(curNo, bp.to)});
63
+ curLine = curLine.slice(bp.to);
64
+ ++curNo;
65
+ }
66
+ }
67
+ if (changes.length) cm.operation(function() {
68
+ for (var i = 0; i < changes.length; ++i) {
69
+ var change = changes[i];
70
+ cm.replaceRange(change.text, change.from, change.to);
71
+ }
72
+ });
73
+ }
74
+
75
+ CodeMirror.defineExtension("wrapParagraph", function(pos, options) {
76
+ options = options || {};
77
+ if (!pos) pos = this.getCursor();
78
+ var para = findParagraph(this, pos, options);
79
+ wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options);
80
+ });
81
+
82
+ CodeMirror.defineExtension("wrapRange", function(from, to, options) {
83
+ wrapRange(this, from, to, options || {});
84
+ });
85
+
86
+ CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) {
87
+ options = options || {};
88
+ var cm = this, paras = [];
89
+ for (var line = from.line; line <= to.line;) {
90
+ var para = findParagraph(cm, Pos(line, 0), options);
91
+ paras.push(para);
92
+ line = para.to;
93
+ }
94
+ if (paras.length) cm.operation(function() {
95
+ for (var i = paras.length - 1; i >= 0; --i)
96
+ wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options);
97
+ });
98
+ });
99
+ })();
@@ -76,8 +76,10 @@
76
76
  { keys: ['<C-p>'], type: 'keyToKey', toKeys: ['k'] },
77
77
  { keys: ['C-['], type: 'keyToKey', toKeys: ['<Esc>'] },
78
78
  { keys: ['<C-c>'], type: 'keyToKey', toKeys: ['<Esc>'] },
79
- { keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'] },
80
- { keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'] },
79
+ { keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'], context: 'normal' },
80
+ { keys: ['s'], type: 'keyToKey', toKeys: ['x', 'i'], context: 'visual'},
81
+ { keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'], context: 'normal' },
82
+ { keys: ['S'], type: 'keyToKey', toKeys: ['d', 'c', 'c'], context: 'visual' },
81
83
  { keys: ['<Home>'], type: 'keyToKey', toKeys: ['0'] },
82
84
  { keys: ['<End>'], type: 'keyToKey', toKeys: ['$'] },
83
85
  { keys: ['<PageUp>'], type: 'keyToKey', toKeys: ['<C-b>'] },
@@ -609,6 +611,9 @@
609
611
  }
610
612
  commandDispatcher.processCommand(cm, vim, command);
611
613
  }
614
+ },
615
+ handleEx: function(cm, input) {
616
+ exCommandDispatcher.processCommand(cm, input);
612
617
  }
613
618
  };
614
619
 
@@ -695,6 +700,9 @@
695
700
  if (linewise && text.charAt(0) == '\n') {
696
701
  text = text.slice(1) + '\n';
697
702
  }
703
+ if(linewise && text.charAt(text.length - 1) !== '\n'){
704
+ text += '\n';
705
+ }
698
706
  // Lowercase and uppercase registers refer to the same register.
699
707
  // Uppercase just means append.
700
708
  var register = this.isValidRegister(registerName) ?
@@ -766,44 +774,74 @@
766
774
  matchCommand: function(key, keyMap, vim) {
767
775
  var inputState = vim.inputState;
768
776
  var keys = inputState.keyBuffer.concat(key);
777
+ var matchedCommands = [];
778
+ var selectedCharacter;
769
779
  for (var i = 0; i < keyMap.length; i++) {
770
780
  var command = keyMap[i];
771
781
  if (matchKeysPartial(keys, command.keys)) {
772
- if (keys.length < command.keys.length) {
773
- // Matches part of a multi-key command. Buffer and wait for next
774
- // stroke.
775
- inputState.keyBuffer.push(key);
776
- return null;
777
- }
778
782
  if (inputState.operator && command.type == 'action') {
779
783
  // Ignore matched action commands after an operator. Operators
780
784
  // only operate on motions. This check is really for text
781
785
  // objects since aW, a[ etcs conflicts with a.
782
786
  continue;
783
787
  }
784
- // Matches whole comand. Return the command.
788
+ // Match commands that take <character> as an argument.
785
789
  if (command.keys[keys.length - 1] == 'character') {
786
- inputState.selectedCharacter = keys[keys.length - 1];
787
- if(inputState.selectedCharacter.length>1){
788
- switch(inputState.selectedCharacter){
790
+ selectedCharacter = keys[keys.length - 1];
791
+ if(selectedCharacter.length>1){
792
+ switch(selectedCharacter){
789
793
  case '<CR>':
790
- inputState.selectedCharacter='\n';
794
+ selectedCharacter='\n';
791
795
  break;
792
796
  case '<Space>':
793
- inputState.selectedCharacter=' ';
797
+ selectedCharacter=' ';
794
798
  break;
795
799
  default:
796
800
  continue;
797
801
  }
798
802
  }
799
803
  }
804
+ // Add the command to the list of matched commands. Choose the best
805
+ // command later.
806
+ matchedCommands.push(command);
807
+ }
808
+ }
809
+
810
+ // Returns the command if it is a full match, or null if not.
811
+ function getFullyMatchedCommandOrNull(command) {
812
+ if (keys.length < command.keys.length) {
813
+ // Matches part of a multi-key command. Buffer and wait for next
814
+ // stroke.
815
+ inputState.keyBuffer.push(key);
816
+ return null;
817
+ } else {
818
+ if (command.keys[keys.length - 1] == 'character') {
819
+ inputState.selectedCharacter = selectedCharacter;
820
+ }
821
+ // Clear the buffer since a full match was found.
800
822
  inputState.keyBuffer = [];
801
823
  return command;
802
824
  }
803
825
  }
804
- // Clear the buffer since there are no partial matches.
805
- inputState.keyBuffer = [];
806
- return null;
826
+
827
+ if (!matchedCommands.length) {
828
+ // Clear the buffer since there were no matches.
829
+ inputState.keyBuffer = [];
830
+ return null;
831
+ } else if (matchedCommands.length == 1) {
832
+ return getFullyMatchedCommandOrNull(matchedCommands[0]);
833
+ } else {
834
+ // Find the best match in the list of matchedCommands.
835
+ var context = vim.visualMode ? 'visual' : 'normal';
836
+ var bestMatch = matchedCommands[0]; // Default to first in the list.
837
+ for (var i = 0; i < matchedCommands.length; i++) {
838
+ if (matchedCommands[i].context == context) {
839
+ bestMatch = matchedCommands[i];
840
+ break;
841
+ }
842
+ }
843
+ return getFullyMatchedCommandOrNull(bestMatch);
844
+ }
807
845
  },
808
846
  processCommand: function(cm, vim, command) {
809
847
  vim.inputState.repeatOverride = command.repeatOverride;
@@ -2,347 +2,348 @@
2
2
  * Link to the project's GitHub page:
3
3
  * https://github.com/pickhardt/coffeescript-codemirror-mode
4
4
  */
5
- CodeMirror.defineMode('coffeescript', function(conf) {
6
- var ERRORCLASS = 'error';
7
-
8
- function wordRegexp(words) {
9
- return new RegExp("^((" + words.join(")|(") + "))\\b");
10
- }
11
-
12
- var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\?]");
13
- var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\},:`=;\\.]');
14
- var doubleOperators = new RegExp("^((\->)|(\=>)|(\\+\\+)|(\\+\\=)|(\\-\\-)|(\\-\\=)|(\\*\\*)|(\\*\\=)|(\\/\\/)|(\\/\\=)|(==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//))");
15
- var doubleDelimiters = new RegExp("^((\\.\\.)|(\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
16
- var tripleDelimiters = new RegExp("^((\\.\\.\\.)|(//=)|(>>=)|(<<=)|(\\*\\*=))");
17
- var identifiers = new RegExp("^[_A-Za-z$][_A-Za-z$0-9]*");
18
- var properties = new RegExp("^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*");
19
-
20
- var wordOperators = wordRegexp(['and', 'or', 'not',
21
- 'is', 'isnt', 'in',
22
- 'instanceof', 'typeof']);
23
- var indentKeywords = ['for', 'while', 'loop', 'if', 'unless', 'else',
24
- 'switch', 'try', 'catch', 'finally', 'class'];
25
- var commonKeywords = ['break', 'by', 'continue', 'debugger', 'delete',
26
- 'do', 'in', 'of', 'new', 'return', 'then',
27
- 'this', 'throw', 'when', 'until'];
28
-
29
- var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
30
-
31
- indentKeywords = wordRegexp(indentKeywords);
32
-
33
-
34
- var stringPrefixes = new RegExp("^('{3}|\"{3}|['\"])");
35
- var regexPrefixes = new RegExp("^(/{3}|/)");
36
- var commonConstants = ['Infinity', 'NaN', 'undefined', 'null', 'true', 'false', 'on', 'off', 'yes', 'no'];
37
- var constants = wordRegexp(commonConstants);
38
-
39
- // Tokenizers
40
- function tokenBase(stream, state) {
41
- // Handle scope changes
42
- if (stream.sol()) {
43
- var scopeOffset = state.scopes[0].offset;
44
- if (stream.eatSpace()) {
45
- var lineOffset = stream.indentation();
46
- if (lineOffset > scopeOffset) {
47
- return 'indent';
48
- } else if (lineOffset < scopeOffset) {
49
- return 'dedent';
50
- }
51
- return null;
52
- } else {
53
- if (scopeOffset > 0) {
54
- dedent(stream, state);
55
- }
56
- }
5
+ CodeMirror.defineMode("coffeescript", function(conf) {
6
+ var ERRORCLASS = "error";
7
+
8
+ function wordRegexp(words) {
9
+ return new RegExp("^((" + words.join(")|(") + "))\\b");
10
+ }
11
+
12
+ var operators = /^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?)/;
13
+ var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/;
14
+ var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/;
15
+ var properties = /^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*/;
16
+
17
+ var wordOperators = wordRegexp(["and", "or", "not",
18
+ "is", "isnt", "in",
19
+ "instanceof", "typeof"]);
20
+ var indentKeywords = ["for", "while", "loop", "if", "unless", "else",
21
+ "switch", "try", "catch", "finally", "class"];
22
+ var commonKeywords = ["break", "by", "continue", "debugger", "delete",
23
+ "do", "in", "of", "new", "return", "then",
24
+ "this", "throw", "when", "until"];
25
+
26
+ var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
27
+
28
+ indentKeywords = wordRegexp(indentKeywords);
29
+
30
+
31
+ var stringPrefixes = /^('{3}|\"{3}|['\"])/;
32
+ var regexPrefixes = /^(\/{3}|\/)/;
33
+ var commonConstants = ["Infinity", "NaN", "undefined", "null", "true", "false", "on", "off", "yes", "no"];
34
+ var constants = wordRegexp(commonConstants);
35
+
36
+ // Tokenizers
37
+ function tokenBase(stream, state) {
38
+ // Handle scope changes
39
+ if (stream.sol()) {
40
+ if (state.scope.align === null) state.scope.align = false;
41
+ var scopeOffset = state.scope.offset;
42
+ if (stream.eatSpace()) {
43
+ var lineOffset = stream.indentation();
44
+ if (lineOffset > scopeOffset && state.scope.type == "coffee") {
45
+ return "indent";
46
+ } else if (lineOffset < scopeOffset) {
47
+ return "dedent";
57
48
  }
58
- if (stream.eatSpace()) {
59
- return null;
60
- }
61
-
62
- var ch = stream.peek();
63
-
64
- // Handle docco title comment (single line)
65
- if (stream.match("####")) {
66
- stream.skipToEnd();
67
- return 'comment';
68
- }
69
-
70
- // Handle multi line comments
71
- if (stream.match("###")) {
72
- state.tokenize = longComment;
73
- return state.tokenize(stream, state);
49
+ return null;
50
+ } else {
51
+ if (scopeOffset > 0) {
52
+ dedent(stream, state);
74
53
  }
54
+ }
55
+ }
56
+ if (stream.eatSpace()) {
57
+ return null;
58
+ }
75
59
 
76
- // Single line comment
77
- if (ch === '#') {
78
- stream.skipToEnd();
79
- return 'comment';
80
- }
60
+ var ch = stream.peek();
81
61
 
82
- // Handle number literals
83
- if (stream.match(/^-?[0-9\.]/, false)) {
84
- var floatLiteral = false;
85
- // Floats
86
- if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
87
- floatLiteral = true;
88
- }
89
- if (stream.match(/^-?\d+\.\d*/)) {
90
- floatLiteral = true;
91
- }
92
- if (stream.match(/^-?\.\d+/)) {
93
- floatLiteral = true;
94
- }
95
-
96
- if (floatLiteral) {
97
- // prevent from getting extra . on 1..
98
- if (stream.peek() == "."){
99
- stream.backUp(1);
100
- }
101
- return 'number';
102
- }
103
- // Integers
104
- var intLiteral = false;
105
- // Hex
106
- if (stream.match(/^-?0x[0-9a-f]+/i)) {
107
- intLiteral = true;
108
- }
109
- // Decimal
110
- if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
111
- intLiteral = true;
112
- }
113
- // Zero by itself with no other piece of number.
114
- if (stream.match(/^-?0(?![\dx])/i)) {
115
- intLiteral = true;
116
- }
117
- if (intLiteral) {
118
- return 'number';
119
- }
120
- }
62
+ // Handle docco title comment (single line)
63
+ if (stream.match("####")) {
64
+ stream.skipToEnd();
65
+ return "comment";
66
+ }
121
67
 
122
- // Handle strings
123
- if (stream.match(stringPrefixes)) {
124
- state.tokenize = tokenFactory(stream.current(), 'string');
125
- return state.tokenize(stream, state);
126
- }
127
- // Handle regex literals
128
- if (stream.match(regexPrefixes)) {
129
- if (stream.current() != '/' || stream.match(/^.*\//, false)) { // prevent highlight of division
130
- state.tokenize = tokenFactory(stream.current(), 'string-2');
131
- return state.tokenize(stream, state);
132
- } else {
133
- stream.backUp(1);
134
- }
135
- }
68
+ // Handle multi line comments
69
+ if (stream.match("###")) {
70
+ state.tokenize = longComment;
71
+ return state.tokenize(stream, state);
72
+ }
136
73
 
137
- // Handle operators and delimiters
138
- if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
139
- return 'punctuation';
140
- }
141
- if (stream.match(doubleOperators)
142
- || stream.match(singleOperators)
143
- || stream.match(wordOperators)) {
144
- return 'operator';
145
- }
146
- if (stream.match(singleDelimiters)) {
147
- return 'punctuation';
148
- }
74
+ // Single line comment
75
+ if (ch === "#") {
76
+ stream.skipToEnd();
77
+ return "comment";
78
+ }
149
79
 
150
- if (stream.match(constants)) {
151
- return 'atom';
80
+ // Handle number literals
81
+ if (stream.match(/^-?[0-9\.]/, false)) {
82
+ var floatLiteral = false;
83
+ // Floats
84
+ if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
85
+ floatLiteral = true;
86
+ }
87
+ if (stream.match(/^-?\d+\.\d*/)) {
88
+ floatLiteral = true;
89
+ }
90
+ if (stream.match(/^-?\.\d+/)) {
91
+ floatLiteral = true;
92
+ }
93
+
94
+ if (floatLiteral) {
95
+ // prevent from getting extra . on 1..
96
+ if (stream.peek() == "."){
97
+ stream.backUp(1);
152
98
  }
99
+ return "number";
100
+ }
101
+ // Integers
102
+ var intLiteral = false;
103
+ // Hex
104
+ if (stream.match(/^-?0x[0-9a-f]+/i)) {
105
+ intLiteral = true;
106
+ }
107
+ // Decimal
108
+ if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
109
+ intLiteral = true;
110
+ }
111
+ // Zero by itself with no other piece of number.
112
+ if (stream.match(/^-?0(?![\dx])/i)) {
113
+ intLiteral = true;
114
+ }
115
+ if (intLiteral) {
116
+ return "number";
117
+ }
118
+ }
153
119
 
154
- if (stream.match(keywords)) {
155
- return 'keyword';
156
- }
120
+ // Handle strings
121
+ if (stream.match(stringPrefixes)) {
122
+ state.tokenize = tokenFactory(stream.current(), "string");
123
+ return state.tokenize(stream, state);
124
+ }
125
+ // Handle regex literals
126
+ if (stream.match(regexPrefixes)) {
127
+ if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division
128
+ state.tokenize = tokenFactory(stream.current(), "string-2");
129
+ return state.tokenize(stream, state);
130
+ } else {
131
+ stream.backUp(1);
132
+ }
133
+ }
157
134
 
158
- if (stream.match(identifiers)) {
159
- return 'variable';
160
- }
135
+ // Handle operators and delimiters
136
+ if (stream.match(operators) || stream.match(wordOperators)) {
137
+ return "operator";
138
+ }
139
+ if (stream.match(delimiters)) {
140
+ return "punctuation";
141
+ }
161
142
 
162
- if (stream.match(properties)) {
163
- return 'property';
164
- }
143
+ if (stream.match(constants)) {
144
+ return "atom";
145
+ }
165
146
 
166
- // Handle non-detected items
167
- stream.next();
168
- return ERRORCLASS;
147
+ if (stream.match(keywords)) {
148
+ return "keyword";
169
149
  }
170
150
 
171
- function tokenFactory(delimiter, outclass) {
172
- var singleline = delimiter.length == 1;
173
- return function(stream, state) {
174
- while (!stream.eol()) {
175
- stream.eatWhile(/[^'"\/\\]/);
176
- if (stream.eat('\\')) {
177
- stream.next();
178
- if (singleline && stream.eol()) {
179
- return outclass;
180
- }
181
- } else if (stream.match(delimiter)) {
182
- state.tokenize = tokenBase;
183
- return outclass;
184
- } else {
185
- stream.eat(/['"\/]/);
186
- }
187
- }
188
- if (singleline) {
189
- if (conf.mode.singleLineStringErrors) {
190
- outclass = ERRORCLASS;
191
- } else {
192
- state.tokenize = tokenBase;
193
- }
194
- }
195
- return outclass;
196
- };
151
+ if (stream.match(identifiers)) {
152
+ return "variable";
197
153
  }
198
154
 
199
- function longComment(stream, state) {
200
- while (!stream.eol()) {
201
- stream.eatWhile(/[^#]/);
202
- if (stream.match("###")) {
203
- state.tokenize = tokenBase;
204
- break;
205
- }
206
- stream.eatWhile("#");
207
- }
208
- return "comment";
155
+ if (stream.match(properties)) {
156
+ return "property";
209
157
  }
210
158
 
211
- function indent(stream, state, type) {
212
- type = type || 'coffee';
213
- var indentUnit = 0;
214
- if (type === 'coffee') {
215
- for (var i = 0; i < state.scopes.length; i++) {
216
- if (state.scopes[i].type === 'coffee') {
217
- indentUnit = state.scopes[i].offset + conf.indentUnit;
218
- break;
219
- }
220
- }
159
+ // Handle non-detected items
160
+ stream.next();
161
+ return ERRORCLASS;
162
+ }
163
+
164
+ function tokenFactory(delimiter, outclass) {
165
+ var singleline = delimiter.length == 1;
166
+ return function(stream, state) {
167
+ while (!stream.eol()) {
168
+ stream.eatWhile(/[^'"\/\\]/);
169
+ if (stream.eat("\\")) {
170
+ stream.next();
171
+ if (singleline && stream.eol()) {
172
+ return outclass;
173
+ }
174
+ } else if (stream.match(delimiter)) {
175
+ state.tokenize = tokenBase;
176
+ return outclass;
221
177
  } else {
222
- indentUnit = stream.column() + stream.current().length;
178
+ stream.eat(/['"\/]/);
223
179
  }
224
- state.scopes.unshift({
225
- offset: indentUnit,
226
- type: type
227
- });
228
- }
229
-
230
- function dedent(stream, state) {
231
- if (state.scopes.length == 1) return;
232
- if (state.scopes[0].type === 'coffee') {
233
- var _indent = stream.indentation();
234
- var _indent_index = -1;
235
- for (var i = 0; i < state.scopes.length; ++i) {
236
- if (_indent === state.scopes[i].offset) {
237
- _indent_index = i;
238
- break;
239
- }
240
- }
241
- if (_indent_index === -1) {
242
- return true;
243
- }
244
- while (state.scopes[0].offset !== _indent) {
245
- state.scopes.shift();
246
- }
247
- return false;
180
+ }
181
+ if (singleline) {
182
+ if (conf.mode.singleLineStringErrors) {
183
+ outclass = ERRORCLASS;
248
184
  } else {
249
- state.scopes.shift();
250
- return false;
185
+ state.tokenize = tokenBase;
251
186
  }
187
+ }
188
+ return outclass;
189
+ };
190
+ }
191
+
192
+ function longComment(stream, state) {
193
+ while (!stream.eol()) {
194
+ stream.eatWhile(/[^#]/);
195
+ if (stream.match("###")) {
196
+ state.tokenize = tokenBase;
197
+ break;
198
+ }
199
+ stream.eatWhile("#");
252
200
  }
253
-
254
- function tokenLexer(stream, state) {
255
- var style = state.tokenize(stream, state);
256
- var current = stream.current();
257
-
258
- // Handle '.' connected identifiers
259
- if (current === '.') {
260
- style = state.tokenize(stream, state);
261
- current = stream.current();
262
- if (/^\.[\w$]+$/.test(current)) {
263
- return 'variable';
264
- } else {
265
- return ERRORCLASS;
266
- }
267
- }
268
-
269
- // Handle scope changes.
270
- if (current === 'return') {
271
- state.dedent += 1;
272
- }
273
- if (((current === '->' || current === '=>') &&
274
- !state.lambda &&
275
- state.scopes[0].type == 'coffee' &&
276
- stream.peek() === '')
277
- || style === 'indent') {
278
- indent(stream, state);
279
- }
280
- var delimiter_index = '[({'.indexOf(current);
281
- if (delimiter_index !== -1) {
282
- indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
283
- }
284
- if (indentKeywords.exec(current)){
285
- indent(stream, state);
286
- }
287
- if (current == 'then'){
288
- dedent(stream, state);
289
- }
290
-
291
-
292
- if (style === 'dedent') {
293
- if (dedent(stream, state)) {
294
- return ERRORCLASS;
295
- }
296
- }
297
- delimiter_index = '])}'.indexOf(current);
298
- if (delimiter_index !== -1) {
299
- if (dedent(stream, state)) {
300
- return ERRORCLASS;
301
- }
302
- }
303
- if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') {
304
- if (state.scopes.length > 1) state.scopes.shift();
305
- state.dedent -= 1;
201
+ return "comment";
202
+ }
203
+
204
+ function indent(stream, state, type) {
205
+ type = type || "coffee";
206
+ var offset = 0, align = false, alignOffset = null;
207
+ for (var scope = state.scope; scope; scope = scope.prev) {
208
+ if (scope.type === "coffee") {
209
+ offset = scope.offset + conf.indentUnit;
210
+ break;
211
+ }
212
+ }
213
+ if (type !== "coffee") {
214
+ align = null;
215
+ alignOffset = stream.column() + stream.current().length;
216
+ }
217
+ state.scope = {
218
+ offset: offset,
219
+ type: type,
220
+ prev: state.scope,
221
+ align: align,
222
+ alignOffset: alignOffset
223
+ };
224
+ }
225
+
226
+ function dedent(stream, state) {
227
+ if (!state.scope.prev) return;
228
+ if (state.scope.type === "coffee") {
229
+ var _indent = stream.indentation();
230
+ var matched = false;
231
+ for (var scope = state.scope; scope; scope = scope.prev) {
232
+ if (_indent === scope.offset) {
233
+ matched = true;
234
+ break;
306
235
  }
307
-
308
- return style;
236
+ }
237
+ if (!matched) {
238
+ return true;
239
+ }
240
+ while (state.scope.prev && state.scope.offset !== _indent) {
241
+ state.scope = state.scope.prev;
242
+ }
243
+ return false;
244
+ } else {
245
+ state.scope = state.scope.prev;
246
+ return false;
247
+ }
248
+ }
249
+
250
+ function tokenLexer(stream, state) {
251
+ var style = state.tokenize(stream, state);
252
+ var current = stream.current();
253
+
254
+ // Handle "." connected identifiers
255
+ if (current === ".") {
256
+ style = state.tokenize(stream, state);
257
+ current = stream.current();
258
+ if (/^\.[\w$]+$/.test(current)) {
259
+ return "variable";
260
+ } else {
261
+ return ERRORCLASS;
262
+ }
309
263
  }
310
264
 
311
- var external = {
312
- startState: function(basecolumn) {
313
- return {
314
- tokenize: tokenBase,
315
- scopes: [{offset:basecolumn || 0, type:'coffee'}],
316
- lastToken: null,
317
- lambda: false,
318
- dedent: 0
319
- };
320
- },
321
-
322
- token: function(stream, state) {
323
- var style = tokenLexer(stream, state);
324
-
325
- state.lastToken = {style:style, content: stream.current()};
326
-
327
- if (stream.eol() && stream.lambda) {
328
- state.lambda = false;
329
- }
330
-
331
- return style;
332
- },
265
+ // Handle scope changes.
266
+ if (current === "return") {
267
+ state.dedent += 1;
268
+ }
269
+ if (((current === "->" || current === "=>") &&
270
+ !state.lambda &&
271
+ state.scope.type == "coffee" &&
272
+ !stream.peek())
273
+ || style === "indent") {
274
+ indent(stream, state);
275
+ }
276
+ var delimiter_index = "[({".indexOf(current);
277
+ if (delimiter_index !== -1) {
278
+ indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
279
+ }
280
+ if (indentKeywords.exec(current)){
281
+ indent(stream, state);
282
+ }
283
+ if (current == "then"){
284
+ dedent(stream, state);
285
+ }
333
286
 
334
- indent: function(state) {
335
- if (state.tokenize != tokenBase) {
336
- return 0;
337
- }
338
287
 
339
- return state.scopes[0].offset;
340
- },
288
+ if (style === "dedent") {
289
+ if (dedent(stream, state)) {
290
+ return ERRORCLASS;
291
+ }
292
+ }
293
+ delimiter_index = "])}".indexOf(current);
294
+ if (delimiter_index !== -1) {
295
+ if (dedent(stream, state)) {
296
+ return ERRORCLASS;
297
+ }
298
+ }
299
+ if (state.dedent > 0 && stream.eol() && state.scope.type == "coffee") {
300
+ if (state.scope.prev) state.scope = state.scope.prev;
301
+ state.dedent -= 1;
302
+ }
341
303
 
342
- lineComment: "#",
343
- fold: "indent"
344
- };
345
- return external;
304
+ return style;
305
+ }
306
+
307
+ var external = {
308
+ startState: function(basecolumn) {
309
+ return {
310
+ tokenize: tokenBase,
311
+ scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false},
312
+ lastToken: null,
313
+ lambda: false,
314
+ dedent: 0
315
+ };
316
+ },
317
+
318
+ token: function(stream, state) {
319
+ var fillAlign = state.scope.align === null && state.scope;
320
+ if (fillAlign && stream.sol()) fillAlign.align = false;
321
+
322
+ var style = tokenLexer(stream, state);
323
+ if (fillAlign && style && style != "comment") fillAlign.align = true;
324
+
325
+ state.lastToken = {style:style, content: stream.current()};
326
+
327
+ if (stream.eol() && stream.lambda) {
328
+ state.lambda = false;
329
+ }
330
+
331
+ return style;
332
+ },
333
+
334
+ indent: function(state, text) {
335
+ if (state.tokenize != tokenBase) return 0;
336
+ var closes = state.scope.type === (text && text.charAt(0));
337
+ if (state.scope.align)
338
+ return state.scope.alignOffset - (closes ? 1 : 0);
339
+ else
340
+ return (closes ? state.scope.prev : state.scope).offset;
341
+ },
342
+
343
+ lineComment: "#",
344
+ fold: "indent"
345
+ };
346
+ return external;
346
347
  });
347
348
 
348
- CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript');
349
+ CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");