codemirror-rails 3.12 → 3.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/codemirror-rails.gemspec +1 -1
  3. data/lib/codemirror/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/codemirror.js +168 -116
  5. data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +144 -0
  6. data/vendor/assets/javascripts/codemirror/addons/display/placeholder.js +4 -4
  7. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +2 -2
  8. data/vendor/assets/javascripts/codemirror/addons/fold/brace-fold.js +9 -3
  9. data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +13 -13
  10. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.js +5 -1
  11. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +13 -1
  12. data/vendor/assets/javascripts/codemirror/addons/search/match-highlighter.js +4 -4
  13. data/vendor/assets/javascripts/codemirror/addons/search/search.js +1 -1
  14. data/vendor/assets/javascripts/codemirror/addons/search/searchcursor.js +15 -5
  15. data/vendor/assets/javascripts/codemirror/addons/selection/active-line.js +6 -6
  16. data/vendor/assets/javascripts/codemirror/addons/selection/mark-selection.js +89 -15
  17. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +451 -187
  18. data/vendor/assets/javascripts/codemirror/modes/clike.js +6 -3
  19. data/vendor/assets/javascripts/codemirror/modes/clojure.js +3 -1
  20. data/vendor/assets/javascripts/codemirror/modes/cobol.js +240 -0
  21. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +2 -1
  22. data/vendor/assets/javascripts/codemirror/modes/commonlisp.js +5 -1
  23. data/vendor/assets/javascripts/codemirror/modes/css.js +63 -24
  24. data/vendor/assets/javascripts/codemirror/modes/erlang.js +3 -2
  25. data/vendor/assets/javascripts/codemirror/modes/gas.js +5 -1
  26. data/vendor/assets/javascripts/codemirror/modes/go.js +4 -1
  27. data/vendor/assets/javascripts/codemirror/modes/haml.js +153 -0
  28. data/vendor/assets/javascripts/codemirror/modes/haskell.js +5 -1
  29. data/vendor/assets/javascripts/codemirror/modes/javascript.js +5 -1
  30. data/vendor/assets/javascripts/codemirror/modes/less.js +0 -8
  31. data/vendor/assets/javascripts/codemirror/modes/lua.js +5 -1
  32. data/vendor/assets/javascripts/codemirror/modes/markdown.js +2 -2
  33. data/vendor/assets/javascripts/codemirror/modes/ocaml.js +4 -1
  34. data/vendor/assets/javascripts/codemirror/modes/php.js +3 -0
  35. data/vendor/assets/javascripts/codemirror/modes/python.js +2 -1
  36. data/vendor/assets/javascripts/codemirror/modes/ruby.js +2 -1
  37. data/vendor/assets/javascripts/codemirror/modes/rust.js +4 -1
  38. data/vendor/assets/javascripts/codemirror/modes/sass.js +8 -27
  39. data/vendor/assets/javascripts/codemirror/modes/scheme.js +3 -1
  40. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +6 -4
  41. data/vendor/assets/javascripts/codemirror/modes/sql.js +3 -4
  42. data/vendor/assets/javascripts/codemirror/modes/stex.js +1 -1
  43. data/vendor/assets/javascripts/codemirror/modes/xml.js +2 -0
  44. data/vendor/assets/javascripts/codemirror/modes/yaml.js +3 -1
  45. data/vendor/assets/stylesheets/codemirror.css +7 -4
  46. data/vendor/assets/stylesheets/codemirror/addons/lint/lint.css +3 -3
  47. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +1 -1
  48. metadata +14 -6
  49. data/vendor/assets/javascripts/codemirror/modes/test.js +0 -64
@@ -0,0 +1,144 @@
1
+ (function() {
2
+ "use strict";
3
+
4
+ var noOptions = {};
5
+ var nonWS = /[^\s\u00a0]/;
6
+ var Pos = CodeMirror.Pos;
7
+
8
+ function firstNonWS(str) {
9
+ var found = str.search(nonWS);
10
+ return found == -1 ? 0 : found;
11
+ }
12
+
13
+ CodeMirror.commands.toggleComment = function(cm) {
14
+ var from = cm.getCursor("start"), to = cm.getCursor("end");
15
+ cm.uncomment(from, to) || cm.lineComment(from, to);
16
+ };
17
+
18
+ CodeMirror.defineExtension("lineComment", function(from, to, options) {
19
+ if (!options) options = noOptions;
20
+ var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode;
21
+ var commentString = options.lineComment || mode.lineComment;
22
+ if (!commentString) {
23
+ if (options.blockCommentStart || mode.blockCommentStart) {
24
+ options.fullLines = true;
25
+ self.blockComment(from, to, options);
26
+ }
27
+ return;
28
+ }
29
+ var firstLine = self.getLine(from.line);
30
+ if (firstLine == null) return;
31
+ var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
32
+ var pad = options.padding == null ? " " : options.padding;
33
+ var blankLines = options.commentBlankLines;
34
+
35
+ self.operation(function() {
36
+ if (options.indent) {
37
+ var baseString = firstLine.slice(0, firstNonWS(firstLine));
38
+ for (var i = from.line; i < end; ++i) {
39
+ var line = self.getLine(i), cut = baseString.length;
40
+ if (!blankLines && !nonWS.test(line)) continue;
41
+ if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
42
+ self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
43
+ }
44
+ } else {
45
+ for (var i = from.line; i < end; ++i) {
46
+ if (blankLines || nonWS.test(self.getLine(i)))
47
+ self.replaceRange(commentString + pad, Pos(i, 0));
48
+ }
49
+ }
50
+ });
51
+ });
52
+
53
+ CodeMirror.defineExtension("blockComment", function(from, to, options) {
54
+ if (!options) options = noOptions;
55
+ var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode;
56
+ var startString = options.blockCommentStart || mode.blockCommentStart;
57
+ var endString = options.blockCommentEnd || mode.blockCommentEnd;
58
+ if (!startString || !endString) {
59
+ if ((options.lineComment || mode.lineComment) && options.fullLines != false)
60
+ self.lineComment(from, to, options);
61
+ return;
62
+ }
63
+
64
+ var end = Math.min(to.line, self.lastLine());
65
+ if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
66
+
67
+ var pad = options.padding == null ? " " : options.padding;
68
+ if (from.line > end) return;
69
+
70
+ self.operation(function() {
71
+ if (options.fullLines != false) {
72
+ var lastLineHasText = nonWS.test(self.getLine(end));
73
+ self.replaceRange(pad + endString, Pos(end));
74
+ self.replaceRange(startString + pad, Pos(from.line, 0));
75
+ var lead = options.blockCommentLead || mode.blockCommentLead;
76
+ if (lead != null) for (var i = from.line + 1; i <= end; ++i)
77
+ if (i != end || lastLineHasText)
78
+ self.replaceRange(lead + pad, Pos(i, 0));
79
+ } else {
80
+ self.replaceRange(endString, to);
81
+ self.replaceRange(startString, from);
82
+ }
83
+ });
84
+ });
85
+
86
+ CodeMirror.defineExtension("uncomment", function(from, to, options) {
87
+ if (!options) options = noOptions;
88
+ var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode;
89
+ var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end);
90
+
91
+ // Try finding line comments
92
+ var lineString = options.lineComment || mode.lineComment, lines = [];
93
+ var pad = options.padding == null ? " " : options.padding;
94
+ lineComment: for(;;) {
95
+ if (!lineString) break;
96
+ for (var i = start; i <= end; ++i) {
97
+ var line = self.getLine(i);
98
+ var found = line.indexOf(lineString);
99
+ if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
100
+ if (i != start && nonWS.test(line.slice(0, found))) break lineComment;
101
+ lines.push(line);
102
+ }
103
+ self.operation(function() {
104
+ for (var i = start; i <= end; ++i) {
105
+ var line = lines[i - start];
106
+ var pos = line.indexOf(lineString), endPos = pos + lineString.length;
107
+ if (pos < 0) continue;
108
+ if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
109
+ self.replaceRange("", Pos(i, pos), Pos(i, endPos));
110
+ }
111
+ });
112
+ return true;
113
+ }
114
+
115
+ // Try block comments
116
+ var startString = options.blockCommentStart || mode.blockCommentStart;
117
+ var endString = options.blockCommentEnd || mode.blockCommentEnd;
118
+ if (!startString || !endString) return false;
119
+ var lead = options.blockCommentLead || mode.blockCommentLead;
120
+ var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);
121
+ var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);
122
+ if (close == -1 && start != end) {
123
+ endLine = self.getLine(--end);
124
+ close = endLine.lastIndexOf(endString);
125
+ }
126
+ if (open == -1 || close == -1) return false;
127
+
128
+ self.operation(function() {
129
+ self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
130
+ Pos(end, close + endString.length));
131
+ var openEnd = open + startString.length;
132
+ if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
133
+ self.replaceRange("", Pos(start, open), Pos(start, openEnd));
134
+ if (lead) for (var i = start + 1; i <= end; ++i) {
135
+ var line = self.getLine(i), found = line.indexOf(lead);
136
+ if (found == -1 || nonWS.test(line.slice(0, found))) continue;
137
+ var foundEnd = found + lead.length;
138
+ if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
139
+ self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
140
+ }
141
+ });
142
+ return true;
143
+ });
144
+ })();
@@ -19,14 +19,14 @@
19
19
  });
20
20
 
21
21
  function clearPlaceholder(cm) {
22
- if (cm._placeholder) {
23
- cm._placeholder.parentNode.removeChild(cm._placeholder);
24
- cm._placeholder = null;
22
+ if (cm.state.placeholder) {
23
+ cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
24
+ cm.state.placeholder = null;
25
25
  }
26
26
  }
27
27
  function setPlaceholder(cm) {
28
28
  clearPlaceholder(cm);
29
- var elt = cm._placeholder = document.createElement("pre");
29
+ var elt = cm.state.placeholder = document.createElement("pre");
30
30
  elt.style.cssText = "height: 0; overflow: visible";
31
31
  elt.className = "CodeMirror-placeholder";
32
32
  elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
@@ -23,9 +23,9 @@
23
23
  return CodeMirror.Pass;
24
24
  }
25
25
  };
26
- var closingBrackets = [];
26
+ var closingBrackets = "";
27
27
  for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
28
- if (left != right) closingBrackets.push(right);
28
+ if (left != right) closingBrackets += right;
29
29
  function surround(cm) {
30
30
  var selection = cm.getSelection();
31
31
  cm.replaceSelection(left + selection + right);
@@ -3,17 +3,23 @@ CodeMirror.braceRangeFinder = function(cm, start) {
3
3
  var at = lineText.length, startChar, tokenType;
4
4
  for (; at > 0;) {
5
5
  var found = lineText.lastIndexOf("{", at);
6
- if (found < start.ch) break;
6
+ var startToken = '{', endToken = '}';
7
+ if (found < start.ch) {
8
+ found = lineText.lastIndexOf("[", at);
9
+ if (found < start.ch) break;
10
+ startToken = '['; endToken = ']';
11
+ }
12
+
7
13
  tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
8
14
  if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
9
15
  at = found - 1;
10
16
  }
11
- if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
17
+ if (startChar == null || lineText.lastIndexOf(startToken) > startChar) return;
12
18
  var count = 1, lastLine = cm.lineCount(), end, endCh;
13
19
  outer: for (var i = line + 1; i < lastLine; ++i) {
14
20
  var text = cm.getLine(i), pos = 0;
15
21
  for (;;) {
16
- var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
22
+ var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
17
23
  if (nextOpen < 0) nextOpen = text.length;
18
24
  if (nextClose < 0) nextClose = text.length;
19
25
  pos = Math.min(nextOpen, nextClose);
@@ -59,7 +59,7 @@ CodeMirror.validate = (function() {
59
59
  }
60
60
 
61
61
  function clearMarks(cm) {
62
- var state = cm._lintState;
62
+ var state = cm.state.lint;
63
63
  if (state.hasGutter) cm.clearGutter(GUTTER_ID);
64
64
  for (var i = 0; i < state.marked.length; ++i)
65
65
  state.marked[i].clear();
@@ -105,16 +105,16 @@ CodeMirror.validate = (function() {
105
105
  }
106
106
 
107
107
  function startLinting(cm) {
108
- var state = cm._lintState, options = state.options;
109
- if (options.async)
110
- options.getAnnotations(cm, updateLinting, options);
111
- else
112
- updateLinting(cm, options.getAnnotations(cm.getValue()));
108
+ var state = cm.state.lint, options = state.options;
109
+ if (options.async)
110
+ options.getAnnotations(cm, updateLinting, options);
111
+ else
112
+ updateLinting(cm, options.getAnnotations(cm.getValue()));
113
113
  }
114
114
 
115
115
  function updateLinting(cm, annotationsNotSorted) {
116
116
  clearMarks(cm);
117
- var state = cm._lintState, options = state.options;
117
+ var state = cm.state.lint, options = state.options;
118
118
 
119
119
  var annotations = groupByLine(annotationsNotSorted);
120
120
 
@@ -135,7 +135,7 @@ CodeMirror.validate = (function() {
135
135
  if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
136
136
 
137
137
  if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
138
- className: "CodeMirror-lint-span-" + severity,
138
+ className: "CodeMirror-lint-mark-" + severity,
139
139
  __annotation: ann
140
140
  }));
141
141
  }
@@ -148,7 +148,7 @@ CodeMirror.validate = (function() {
148
148
  }
149
149
 
150
150
  function onChange(cm) {
151
- var state = cm._lintState;
151
+ var state = cm.state.lint;
152
152
  clearTimeout(state.timeout);
153
153
  state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
154
154
  }
@@ -164,7 +164,7 @@ CodeMirror.validate = (function() {
164
164
  var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0];
165
165
 
166
166
  function onMouseOver(cm, e) {
167
- if (!/\bCodeMirror-lint-span-/.test((e.target || e.srcElement).className)) return;
167
+ if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return;
168
168
  for (var i = 0; i < nearby.length; i += 2) {
169
169
  var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i],
170
170
  top: e.clientY + nearby[i + 1]}));
@@ -179,14 +179,14 @@ CodeMirror.validate = (function() {
179
179
  if (old && old != CodeMirror.Init) {
180
180
  clearMarks(cm);
181
181
  cm.off("change", onChange);
182
- CodeMirror.off(cm.getWrapperElement(), "mouseover", cm._lintState.onMouseOver);
183
- delete cm._lintState;
182
+ CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
183
+ delete cm.state.lint;
184
184
  }
185
185
 
186
186
  if (val) {
187
187
  var gutters = cm.getOption("gutters"), hasLintGutter = false;
188
188
  for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
189
- var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter);
189
+ var state = cm.state.lint = new LintState(cm, parseOptions(val), hasLintGutter);
190
190
  cm.on("change", onChange);
191
191
  if (state.options.tooltips != false)
192
192
  CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
@@ -1,5 +1,7 @@
1
1
  CodeMirror.runMode = function(string, modespec, callback, options) {
2
2
  var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
3
+ var ie = /MSIE \d/.test(navigator.userAgent);
4
+ var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
3
5
 
4
6
  if (callback.nodeType == 1) {
5
7
  var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
@@ -7,7 +9,9 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
7
9
  node.innerHTML = "";
8
10
  callback = function(text, style) {
9
11
  if (text == "\n") {
10
- node.appendChild(document.createElement("br"));
12
+ // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
13
+ // Emitting a carriage return makes everything ok.
14
+ node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
11
15
  col = 0;
12
16
  return;
13
17
  }
@@ -60,8 +60,20 @@ exports.startState = function(mode, a1, a2) {
60
60
  };
61
61
 
62
62
  var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
63
- exports.defineMode = function(name, mode) { modes[name] = mode; };
63
+ exports.defineMode = function(name, mode) {
64
+ if (arguments.length > 2) {
65
+ mode.dependencies = [];
66
+ for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
67
+ }
68
+ modes[name] = mode;
69
+ };
64
70
  exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };
71
+
72
+ exports.defineMode("null", function() {
73
+ return {token: function(stream) {stream.skipToEnd();}};
74
+ });
75
+ exports.defineMIME("text/plain", "null");
76
+
65
77
  exports.getMode = function(options, spec) {
66
78
  if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
67
79
  spec = mimeModes[spec];
@@ -24,19 +24,19 @@
24
24
  CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
25
25
  var prev = old && old != CodeMirror.Init;
26
26
  if (val && !prev) {
27
- cm._matchHighlightState = new State(val);
27
+ cm.state.matchHighlighter = new State(val);
28
28
  cm.on("cursorActivity", highlightMatches);
29
29
  } else if (!val && prev) {
30
- var over = cm._matchHighlightState.overlay;
30
+ var over = cm.state.matchHighlighter.overlay;
31
31
  if (over) cm.removeOverlay(over);
32
- cm._matchHighlightState = null;
32
+ cm.state.matchHighlighter = null;
33
33
  cm.off("cursorActivity", highlightMatches);
34
34
  }
35
35
  });
36
36
 
37
37
  function highlightMatches(cm) {
38
38
  cm.operation(function() {
39
- var state = cm._matchHighlightState;
39
+ var state = cm.state.matchHighlighter;
40
40
  if (state.overlay) {
41
41
  cm.removeOverlay(state.overlay);
42
42
  state.overlay = null;
@@ -27,7 +27,7 @@
27
27
  this.overlay = null;
28
28
  }
29
29
  function getSearchState(cm) {
30
- return cm._searchState || (cm._searchState = new SearchState());
30
+ return cm.state.search || (cm.state.search = new SearchState());
31
31
  }
32
32
  function getSearchCursor(cm, query, pos) {
33
33
  // Heuristic: if the query string is all lowercase, do a case insensitive search.
@@ -24,16 +24,26 @@
24
24
  if (!newMatch) break;
25
25
  match = newMatch;
26
26
  start = match.index;
27
- cutOff = match.index + 1;
27
+ cutOff = match.index + (match[0].length || 1);
28
+ if (cutOff == line.length) break;
29
+ }
30
+ var matchLen = (match && match[0].length) || 0;
31
+ if (!matchLen) {
32
+ if (start == 0 && line.length == 0) {match = undefined;}
33
+ else if (start != doc.getLine(pos.line).length) {
34
+ matchLen++;
35
+ }
28
36
  }
29
37
  } else {
30
38
  query.lastIndex = pos.ch;
31
- var line = doc.getLine(pos.line), match = query.exec(line),
32
- start = match && match.index;
39
+ var line = doc.getLine(pos.line), match = query.exec(line);
40
+ var matchLen = (match && match[0].length) || 0;
41
+ var start = match && match.index;
42
+ if (start + matchLen != line.length && !matchLen) matchLen = 1;
33
43
  }
34
- if (match && match[0])
44
+ if (match && matchLen)
35
45
  return {from: Pos(pos.line, start),
36
- to: Pos(pos.line, start + match[0].length),
46
+ to: Pos(pos.line, start + matchLen),
37
47
  match: match};
38
48
  };
39
49
  } else { // String query
@@ -17,23 +17,23 @@
17
17
  } else if (!val && prev) {
18
18
  cm.off("cursorActivity", updateActiveLine);
19
19
  clearActiveLine(cm);
20
- delete cm._activeLine;
20
+ delete cm.state.activeLine;
21
21
  }
22
22
  });
23
23
 
24
24
  function clearActiveLine(cm) {
25
- if ("_activeLine" in cm) {
26
- cm.removeLineClass(cm._activeLine, "wrap", WRAP_CLASS);
27
- cm.removeLineClass(cm._activeLine, "background", BACK_CLASS);
25
+ if ("activeLine" in cm.state) {
26
+ cm.removeLineClass(cm.state.activeLine, "wrap", WRAP_CLASS);
27
+ cm.removeLineClass(cm.state.activeLine, "background", BACK_CLASS);
28
28
  }
29
29
  }
30
30
 
31
31
  function updateActiveLine(cm) {
32
32
  var line = cm.getLineHandle(cm.getCursor().line);
33
- if (cm._activeLine == line) return;
33
+ if (cm.state.activeLine == line) return;
34
34
  clearActiveLine(cm);
35
35
  cm.addLineClass(line, "wrap", WRAP_CLASS);
36
36
  cm.addLineClass(line, "background", BACK_CLASS);
37
- cm._activeLine = line;
37
+ cm.state.activeLine = line;
38
38
  }
39
39
  })();
@@ -1,7 +1,8 @@
1
1
  // Because sometimes you need to mark the selected *text*.
2
2
  //
3
3
  // Adds an option 'styleSelectedText' which, when enabled, gives
4
- // selected text the CSS class "CodeMirror-selectedtext".
4
+ // selected text the CSS class given as option value, or
5
+ // "CodeMirror-selectedtext" when the value is not a string.
5
6
 
6
7
  (function() {
7
8
  "use strict";
@@ -9,26 +10,99 @@
9
10
  CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) {
10
11
  var prev = old && old != CodeMirror.Init;
11
12
  if (val && !prev) {
12
- updateSelectedText(cm);
13
- cm.on("cursorActivity", updateSelectedText);
13
+ cm.state.markedSelection = [];
14
+ cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext";
15
+ reset(cm);
16
+ cm.on("cursorActivity", onCursorActivity);
17
+ cm.on("change", onChange);
14
18
  } else if (!val && prev) {
15
- cm.off("cursorActivity", updateSelectedText);
16
- clearSelectedText(cm);
17
- delete cm._selectionMark;
19
+ cm.off("cursorActivity", onCursorActivity);
20
+ cm.off("change", onChange);
21
+ clear(cm);
22
+ cm.state.markedSelection = cm.state.markedSelectionStyle = null;
18
23
  }
19
24
  });
20
25
 
21
- function clearSelectedText(cm) {
22
- if (cm._selectionMark) cm._selectionMark.clear();
26
+ function onCursorActivity(cm) {
27
+ cm.operation(function() { update(cm); });
23
28
  }
24
29
 
25
- function updateSelectedText(cm) {
26
- clearSelectedText(cm);
30
+ function onChange(cm) {
31
+ if (cm.state.markedSelection.length)
32
+ cm.operation(function() { clear(cm); });
33
+ }
34
+
35
+ var CHUNK_SIZE = 8;
36
+ var Pos = CodeMirror.Pos;
37
+
38
+ function cmp(pos1, pos2) {
39
+ return pos1.line - pos2.line || pos1.ch - pos2.ch;
40
+ }
41
+
42
+ function coverRange(cm, from, to, addAt) {
43
+ if (cmp(from, to) == 0) return;
44
+ var array = cm.state.markedSelection;
45
+ var cls = cm.state.markedSelectionStyle;
46
+ for (var line = from.line;;) {
47
+ var start = line == from.line ? from : Pos(line, 0);
48
+ var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line;
49
+ var end = atEnd ? to : Pos(endLine, 0);
50
+ var mark = cm.markText(start, end, {className: cls});
51
+ if (addAt == null) array.push(mark);
52
+ else array.splice(addAt++, 0, mark);
53
+ if (atEnd) break;
54
+ line = endLine;
55
+ }
56
+ }
27
57
 
28
- if (cm.somethingSelected())
29
- cm._selectionMark = cm.markText(cm.getCursor("start"), cm.getCursor("end"),
30
- {className: "CodeMirror-selectedtext"});
31
- else
32
- cm._selectionMark = null;
58
+ function clear(cm) {
59
+ var array = cm.state.markedSelection;
60
+ for (var i = 0; i < array.length; ++i) array[i].clear();
61
+ array.length = 0;
62
+ }
63
+
64
+ function reset(cm) {
65
+ clear(cm);
66
+ var from = cm.getCursor("start"), to = cm.getCursor("end");
67
+ coverRange(cm, from, to);
68
+ }
69
+
70
+ function update(cm) {
71
+ var from = cm.getCursor("start"), to = cm.getCursor("end");
72
+ if (cmp(from, to) == 0) return clear(cm);
73
+
74
+ var array = cm.state.markedSelection;
75
+ if (!array.length) return coverRange(cm, from, to);
76
+
77
+ var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
78
+ if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
79
+ cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
80
+ return reset(cm);
81
+
82
+ while (cmp(from, coverStart.from) > 0) {
83
+ array.shift().clear();
84
+ coverStart = array[0].find();
85
+ }
86
+ if (cmp(from, coverStart.from) < 0) {
87
+ if (coverStart.to.line - from.line < CHUNK_SIZE) {
88
+ array.shift().clear();
89
+ coverRange(cm, from, coverStart.to, 0);
90
+ } else {
91
+ coverRange(cm, from, coverStart.from, 0);
92
+ }
93
+ }
94
+
95
+ while (cmp(to, coverEnd.to) < 0) {
96
+ array.pop().clear();
97
+ coverEnd = array[array.length - 1].find();
98
+ }
99
+ if (cmp(to, coverEnd.to) > 0) {
100
+ if (to.line - coverEnd.from.line < CHUNK_SIZE) {
101
+ array.pop().clear();
102
+ coverRange(cm, coverEnd.from, to);
103
+ } else {
104
+ coverRange(cm, coverEnd.to, to);
105
+ }
106
+ }
33
107
  }
34
108
  })();