codemirror-rails 3.18 → 3.19

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 (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");