codemirror-rails 3.12 → 3.13

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