codemirror-rails 2.33 → 2.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. data/lib/codemirror/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/codemirror.js +359 -453
  3. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +4 -1
  4. data/vendor/assets/javascripts/codemirror/modes/clojure.js +7 -8
  5. data/vendor/assets/javascripts/codemirror/modes/commonlisp.js +101 -0
  6. data/vendor/assets/javascripts/codemirror/modes/css.js +336 -62
  7. data/vendor/assets/javascripts/codemirror/modes/gfm.js +6 -1
  8. data/vendor/assets/javascripts/codemirror/modes/haxe.js +0 -3
  9. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +5 -1
  10. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +11 -12
  11. data/vendor/assets/javascripts/codemirror/modes/javascript.js +1 -1
  12. data/vendor/assets/javascripts/codemirror/modes/markdown.js +131 -17
  13. data/vendor/assets/javascripts/codemirror/modes/php.js +4 -6
  14. data/vendor/assets/javascripts/codemirror/modes/shell.js +1 -1
  15. data/vendor/assets/javascripts/codemirror/modes/tiki.js +0 -7
  16. data/vendor/assets/javascripts/codemirror/modes/vb.js +2 -2
  17. data/vendor/assets/javascripts/codemirror/modes/xml.js +0 -8
  18. data/vendor/assets/javascripts/codemirror/utils/closetag.js +35 -35
  19. data/vendor/assets/javascripts/codemirror/utils/formatting.js +147 -253
  20. data/vendor/assets/javascripts/codemirror/utils/multiplex.js +4 -8
  21. data/vendor/assets/javascripts/codemirror/utils/overlay.js +3 -1
  22. data/vendor/assets/javascripts/codemirror/utils/runmode-standalone.js +90 -0
  23. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +1 -1
  24. data/vendor/assets/stylesheets/codemirror.css +2 -2
  25. metadata +14 -12
@@ -301,13 +301,6 @@ CodeMirror.defineMode('tiki', function(config, parserConfig) {
301
301
  if (context) return context.indent + indentUnit;
302
302
  else return 0;
303
303
  },
304
- compareStates: function(a, b) {
305
- if (a.indented != b.indented || a.pluginName != b.pluginName) return false;
306
- for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
307
- if (!ca || !cb) return ca == cb;
308
- if (ca.pluginName != cb.pluginName) return false;
309
- }
310
- },
311
304
  electricChars: "/"
312
305
  };
313
306
  });
@@ -12,8 +12,8 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
12
12
  var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
13
13
  var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
14
14
 
15
- var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property'];
16
- var middleKeywords = ['else','elseif','case'];
15
+ var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property', 'try'];
16
+ var middleKeywords = ['else','elseif','case', 'catch'];
17
17
  var endKeywords = ['next','loop'];
18
18
 
19
19
  var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'in']);
@@ -308,14 +308,6 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
308
308
  else return 0;
309
309
  },
310
310
 
311
- compareStates: function(a, b) {
312
- if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
313
- for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
314
- if (!ca || !cb) return ca == cb;
315
- if (ca.tagName != cb.tagName || ca.indent != cb.indent) return false;
316
- }
317
- },
318
-
319
311
  electricChars: "/"
320
312
  };
321
313
  });
@@ -26,6 +26,11 @@
26
26
  /** Array of tag names where an end tag is forbidden. */
27
27
  CodeMirror.defaults['closeTagVoid'] = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
28
28
 
29
+ function innerState(cm, state) {
30
+ return CodeMirror.innerMode(cm.getMode(), state).state;
31
+ }
32
+
33
+
29
34
  /**
30
35
  * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
31
36
  * - cm: The editor instance.
@@ -39,40 +44,34 @@
39
44
  throw CodeMirror.Pass;
40
45
  }
41
46
 
42
- var mode = cm.getOption('mode');
43
-
44
- if (mode == 'text/html' || mode == 'xml') {
47
+ /*
48
+ * Relevant structure of token:
49
+ *
50
+ * htmlmixed
51
+ * className
52
+ * state
53
+ * htmlState
54
+ * type
55
+ * tagName
56
+ * context
57
+ * tagName
58
+ * mode
59
+ *
60
+ * xml
61
+ * className
62
+ * state
63
+ * tagName
64
+ * type
65
+ */
45
66
 
46
- /*
47
- * Relevant structure of token:
48
- *
49
- * htmlmixed
50
- * className
51
- * state
52
- * htmlState
53
- * type
54
- * tagName
55
- * context
56
- * tagName
57
- * mode
58
- *
59
- * xml
60
- * className
61
- * state
62
- * tagName
63
- * type
64
- */
65
-
66
- var pos = cm.getCursor();
67
- var tok = cm.getTokenAt(pos);
68
- var state = tok.state;
69
-
70
- if (state.mode && state.mode != 'html') {
71
- throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode.
72
- }
67
+ var pos = cm.getCursor();
68
+ var tok = cm.getTokenAt(pos);
69
+ var state = innerState(cm, tok.state);
70
+
71
+ if (state) {
73
72
 
74
73
  if (ch == '>') {
75
- var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
74
+ var type = state.type;
76
75
 
77
76
  if (tok.className == 'tag' && type == 'closeTag') {
78
77
  throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag.
@@ -83,11 +82,12 @@
83
82
  cm.setCursor(pos);
84
83
 
85
84
  tok = cm.getTokenAt(cm.getCursor());
86
- state = tok.state;
87
- type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
85
+ state = innerState(cm, tok.state);
86
+ if (!state) throw CodeMirror.Pass;
87
+ var type = state.type;
88
88
 
89
89
  if (tok.className == 'tag' && type != 'selfcloseTag') {
90
- var tagName = state.htmlState ? state.htmlState.tagName : state.tagName; // htmlmixed : xml
90
+ var tagName = state.tagName;
91
91
  if (tagName.length > 0 && shouldClose(cm, vd, tagName)) {
92
92
  insertEndTag(cm, indent, pos, tagName);
93
93
  }
@@ -100,7 +100,7 @@
100
100
 
101
101
  } else if (ch == '/') {
102
102
  if (tok.className == 'tag' && tok.string == '<') {
103
- var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : (state.context ? state.context.tagName : ''); // htmlmixed : xml
103
+ var ctx = state.context, tagName = ctx ? ctx.tagName : '';
104
104
  if (tagName.length > 0) {
105
105
  completeEndTag(cm, pos, tagName);
106
106
  return;
@@ -1,110 +1,22 @@
1
1
  // ============== Formatting extensions ============================
2
- // A common storage for all mode-specific formatting features
3
- if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
4
-
5
- // Returns the extension of the editor's current mode
6
- CodeMirror.defineExtension("getModeExt", function () {
7
- var mname = CodeMirror.resolveMode(this.getOption("mode")).name;
8
- var ext = CodeMirror.modeExtensions[mname];
9
- if (!ext) throw new Error("No extensions found for mode " + mname);
10
- return ext;
11
- });
12
-
13
- // If the current mode is 'htmlmixed', returns the extension of a mode located at
14
- // the specified position (can be htmlmixed, css or javascript). Otherwise, simply
15
- // returns the extension of the editor's current mode.
16
- CodeMirror.defineExtension("getModeExtAtPos", function (pos) {
17
- var token = this.getTokenAt(pos);
18
- if (token && token.state && token.state.mode)
19
- return CodeMirror.modeExtensions[token.state.mode == "html" ? "htmlmixed" : token.state.mode];
20
- else
21
- return this.getModeExt();
22
- });
23
-
24
- // Comment/uncomment the specified range
25
- CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
26
- var curMode = this.getModeExtAtPos(this.getCursor());
27
- if (isComment) { // Comment range
28
- var commentedText = this.getRange(from, to);
29
- this.replaceRange(curMode.commentStart + this.getRange(from, to) + curMode.commentEnd
30
- , from, to);
31
- if (from.line == to.line && from.ch == to.ch) { // An empty comment inserted - put cursor inside
32
- this.setCursor(from.line, from.ch + curMode.commentStart.length);
33
- }
34
- }
35
- else { // Uncomment range
36
- var selText = this.getRange(from, to);
37
- var startIndex = selText.indexOf(curMode.commentStart);
38
- var endIndex = selText.lastIndexOf(curMode.commentEnd);
39
- if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
40
- // Take string till comment start
41
- selText = selText.substr(0, startIndex)
42
- // From comment start till comment end
43
- + selText.substring(startIndex + curMode.commentStart.length, endIndex)
44
- // From comment end till string end
45
- + selText.substr(endIndex + curMode.commentEnd.length);
46
- }
47
- this.replaceRange(selText, from, to);
48
- }
49
- });
50
-
51
- // Applies automatic mode-aware indentation to the specified range
52
- CodeMirror.defineExtension("autoIndentRange", function (from, to) {
53
- var cmInstance = this;
54
- this.operation(function () {
55
- for (var i = from.line; i <= to.line; i++) {
56
- cmInstance.indentLine(i, "smart");
2
+ (function() {
3
+ // Define extensions for a few modes
4
+ CodeMirror.extendMode("css", {
5
+ commentStart: "/*",
6
+ commentEnd: "*/",
7
+ wordWrapChars: [";", "\\{", "\\}"],
8
+ autoFormatLineBreaks: function (text) {
9
+ return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
57
10
  }
58
11
  });
59
- });
60
-
61
- // Applies automatic formatting to the specified range
62
- CodeMirror.defineExtension("autoFormatRange", function (from, to) {
63
- var absStart = this.indexFromPos(from);
64
- var absEnd = this.indexFromPos(to);
65
- // Insert additional line breaks where necessary according to the
66
- // mode's syntax
67
- var res = this.getModeExt().autoFormatLineBreaks(this.getValue(), absStart, absEnd);
68
- var cmInstance = this;
69
-
70
- // Replace and auto-indent the range
71
- this.operation(function () {
72
- cmInstance.replaceRange(res, from, to);
73
- var startLine = cmInstance.posFromIndex(absStart).line;
74
- var endLine = cmInstance.posFromIndex(absStart + res.length).line;
75
- for (var i = startLine; i <= endLine; i++) {
76
- cmInstance.indentLine(i, "smart");
77
- }
78
- });
79
- });
80
-
81
- // Define extensions for a few modes
82
-
83
- CodeMirror.modeExtensions["css"] = {
84
- commentStart: "/*",
85
- commentEnd: "*/",
86
- wordWrapChars: [";", "\\{", "\\}"],
87
- autoFormatLineBreaks: function (text, startPos, endPos) {
88
- text = text.substring(startPos, endPos);
89
- return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
90
- }
91
- };
92
12
 
93
- CodeMirror.modeExtensions["javascript"] = {
94
- commentStart: "/*",
95
- commentEnd: "*/",
96
- wordWrapChars: [";", "\\{", "\\}"],
97
-
98
- getNonBreakableBlocks: function (text) {
99
- var nonBreakableRegexes = [
100
- new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
101
- new RegExp("\\\\\"([\\s\\S]*?)(\\\\\"|$)"),
102
- new RegExp("\\\\\'([\\s\\S]*?)(\\\\\'|$)"),
103
- new RegExp("'([\\s\\S]*?)('|$)"),
104
- new RegExp("\"([\\s\\S]*?)(\"|$)"),
105
- new RegExp("//.*([\r\n]|$)")
106
- ];
107
- var nonBreakableBlocks = new Array();
13
+ function jsNonBreakableBlocks(text) {
14
+ var nonBreakableRegexes = [/for\s*?\((.*?)\)/,
15
+ /\"(.*?)(\"|$)/,
16
+ /\'(.*?)(\'|$)/,
17
+ /\/\*(.*?)(\*\/|$)/,
18
+ /\/\/.*/];
19
+ var nonBreakableBlocks = [];
108
20
  for (var i = 0; i < nonBreakableRegexes.length; i++) {
109
21
  var curPos = 0;
110
22
  while (curPos < text.length) {
@@ -126,174 +38,156 @@ CodeMirror.modeExtensions["javascript"] = {
126
38
  });
127
39
 
128
40
  return nonBreakableBlocks;
129
- },
41
+ }
130
42
 
131
- autoFormatLineBreaks: function (text, startPos, endPos) {
132
- text = text.substring(startPos, endPos);
133
- var curPos = 0;
134
- var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n;])", "g");
135
- var nonBreakableBlocks = this.getNonBreakableBlocks(text);
136
- if (nonBreakableBlocks != null) {
137
- var res = "";
138
- for (var i = 0; i < nonBreakableBlocks.length; i++) {
139
- if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
140
- res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
141
- curPos = nonBreakableBlocks[i].start;
142
- }
143
- if (nonBreakableBlocks[i].start <= curPos
144
- && nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
145
- res += text.substring(curPos, nonBreakableBlocks[i].end);
146
- curPos = nonBreakableBlocks[i].end;
43
+ CodeMirror.extendMode("javascript", {
44
+ commentStart: "/*",
45
+ commentEnd: "*/",
46
+ wordWrapChars: [";", "\\{", "\\}"],
47
+
48
+ autoFormatLineBreaks: function (text) {
49
+ var curPos = 0;
50
+ var reLinesSplitter = /(;|\{|\})([^\r\n;])/g;
51
+ var nonBreakableBlocks = jsNonBreakableBlocks(text);
52
+ if (nonBreakableBlocks != null) {
53
+ var res = "";
54
+ for (var i = 0; i < nonBreakableBlocks.length; i++) {
55
+ if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
56
+ res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
57
+ curPos = nonBreakableBlocks[i].start;
58
+ }
59
+ if (nonBreakableBlocks[i].start <= curPos
60
+ && nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
61
+ res += text.substring(curPos, nonBreakableBlocks[i].end);
62
+ curPos = nonBreakableBlocks[i].end;
63
+ }
147
64
  }
65
+ if (curPos < text.length)
66
+ res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
67
+ return res;
68
+ } else {
69
+ return text.replace(reLinesSplitter, "$1\n$2");
148
70
  }
149
- if (curPos < text.length - 1) {
150
- res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
151
- }
152
- return res;
153
71
  }
154
- else {
155
- return text.replace(reLinesSplitter, "$1\n$2");
156
- }
157
- }
158
- };
159
-
160
- CodeMirror.modeExtensions["xml"] = {
161
- commentStart: "<!--",
162
- commentEnd: "-->",
163
- wordWrapChars: [">"],
72
+ });
164
73
 
165
- autoFormatLineBreaks: function (text, startPos, endPos) {
166
- text = text.substring(startPos, endPos);
167
- var lines = text.split("\n");
168
- var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
169
- var reOpenBrackets = new RegExp("<", "g");
170
- var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
171
- for (var i = 0; i < lines.length; i++) {
172
- var mToProcess = lines[i].match(reProcessedPortion);
173
- if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
174
- lines[i] = mToProcess[1]
74
+ CodeMirror.extendMode("xml", {
75
+ commentStart: "<!--",
76
+ commentEnd: "-->",
77
+ wordWrapChars: [">"],
78
+
79
+ autoFormatLineBreaks: function (text) {
80
+ var lines = text.split("\n");
81
+ var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
82
+ var reOpenBrackets = new RegExp("<", "g");
83
+ var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
84
+ for (var i = 0; i < lines.length; i++) {
85
+ var mToProcess = lines[i].match(reProcessedPortion);
86
+ if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
87
+ lines[i] = mToProcess[1]
175
88
  + mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
176
89
  + mToProcess[3];
177
- continue;
90
+ continue;
91
+ }
178
92
  }
93
+ return lines.join("\n");
179
94
  }
95
+ });
180
96
 
181
- return lines.join("\n");
97
+ function localModeAt(cm, pos) {
98
+ return CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(pos).state).mode;
182
99
  }
183
- };
184
-
185
- CodeMirror.modeExtensions["htmlmixed"] = {
186
- commentStart: "<!--",
187
- commentEnd: "-->",
188
- wordWrapChars: [">", ";", "\\{", "\\}"],
189
100
 
190
- getModeInfos: function (text, absPos) {
191
- var modeInfos = new Array();
192
- modeInfos[0] =
193
- {
194
- pos: 0,
195
- modeExt: CodeMirror.modeExtensions["xml"],
196
- modeName: "xml"
197
- };
198
-
199
- var modeMatchers = new Array();
200
- modeMatchers[0] =
201
- {
202
- regex: new RegExp("<style[^>]*>([\\s\\S]*?)(</style[^>]*>|$)", "i"),
203
- modeExt: CodeMirror.modeExtensions["css"],
204
- modeName: "css"
205
- };
206
- modeMatchers[1] =
207
- {
208
- regex: new RegExp("<script[^>]*>([\\s\\S]*?)(</script[^>]*>|$)", "i"),
209
- modeExt: CodeMirror.modeExtensions["javascript"],
210
- modeName: "javascript"
211
- };
101
+ function enumerateModesBetween(cm, line, start, end) {
102
+ var outer = cm.getMode(), text = cm.getLine(line);
103
+ if (end == null) end = text.length;
104
+ if (!outer.innerMode) return [{from: start, to: end, mode: outer}];
105
+ var state = cm.getTokenAt({line: line, ch: start}).state;
106
+ var mode = CodeMirror.innerMode(outer, state).mode;
107
+ var found = [], stream = new CodeMirror.StringStream(text);
108
+ stream.pos = stream.start = start;
109
+ for (;;) {
110
+ outer.token(stream, state);
111
+ var curMode = CodeMirror.innerMode(outer, state).mode;
112
+ if (curMode != mode) {
113
+ var cut = stream.start;
114
+ // Crappy heuristic to deal with the fact that a change in
115
+ // mode can occur both at the end and the start of a token,
116
+ // and we don't know which it was.
117
+ if (mode.name == "xml" && text.charAt(stream.pos - 1) == ">") cut = stream.pos;
118
+ found.push({from: start, to: cut, mode: mode});
119
+ start = cut;
120
+ mode = curMode;
121
+ }
122
+ if (stream.pos >= end) break;
123
+ stream.start = stream.pos;
124
+ }
125
+ if (start < end) found.push({from: start, to: end, mode: mode});
126
+ return found;
127
+ }
212
128
 
213
- var lastCharPos = (typeof (absPos) !== "undefined" ? absPos : text.length - 1);
214
- // Detect modes for the entire text
215
- for (var i = 0; i < modeMatchers.length; i++) {
216
- var curPos = 0;
217
- while (curPos <= lastCharPos) {
218
- var m = text.substr(curPos).match(modeMatchers[i].regex);
219
- if (m != null) {
220
- if (m.length > 1 && m[1].length > 0) {
221
- // Push block begin pos
222
- var blockBegin = curPos + m.index + m[0].indexOf(m[1]);
223
- modeInfos.push(
224
- {
225
- pos: blockBegin,
226
- modeExt: modeMatchers[i].modeExt,
227
- modeName: modeMatchers[i].modeName
228
- });
229
- // Push block end pos
230
- modeInfos.push(
231
- {
232
- pos: blockBegin + m[1].length,
233
- modeExt: modeInfos[0].modeExt,
234
- modeName: modeInfos[0].modeName
235
- });
236
- curPos += m.index + m[0].length;
237
- continue;
238
- }
239
- else {
240
- curPos += m.index + Math.max(m[0].length, 1);
241
- }
242
- }
243
- else { // No more matches
244
- break;
129
+ // Comment/uncomment the specified range
130
+ CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
131
+ var curMode = localModeAt(this, from), cm = this;
132
+ this.operation(function() {
133
+ if (isComment) { // Comment range
134
+ cm.replaceRange(curMode.commentEnd, to);
135
+ cm.replaceRange(curMode.commentStart, from);
136
+ if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
137
+ cm.setCursor(from.line, from.ch + curMode.commentStart.length);
138
+ } else { // Uncomment range
139
+ var selText = cm.getRange(from, to);
140
+ var startIndex = selText.indexOf(curMode.commentStart);
141
+ var endIndex = selText.lastIndexOf(curMode.commentEnd);
142
+ if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
143
+ // Take string till comment start
144
+ selText = selText.substr(0, startIndex)
145
+ // From comment start till comment end
146
+ + selText.substring(startIndex + curMode.commentStart.length, endIndex)
147
+ // From comment end till string end
148
+ + selText.substr(endIndex + curMode.commentEnd.length);
245
149
  }
150
+ cm.replaceRange(selText, from, to);
246
151
  }
247
- }
248
- // Sort mode infos
249
- modeInfos.sort(function sortModeInfo(a, b) {
250
- return a.pos - b.pos;
251
152
  });
153
+ });
252
154
 
253
- return modeInfos;
254
- },
255
-
256
- autoFormatLineBreaks: function (text, startPos, endPos) {
257
- var modeInfos = this.getModeInfos(text);
258
- var reBlockStartsWithNewline = new RegExp("^\\s*?\n");
259
- var reBlockEndsWithNewline = new RegExp("\n\\s*?$");
260
- var res = "";
261
- // Use modes info to break lines correspondingly
262
- if (modeInfos.length > 1) { // Deal with multi-mode text
263
- for (var i = 1; i <= modeInfos.length; i++) {
264
- var selStart = modeInfos[i - 1].pos;
265
- var selEnd = (i < modeInfos.length ? modeInfos[i].pos : endPos);
155
+ // Applies automatic mode-aware indentation to the specified range
156
+ CodeMirror.defineExtension("autoIndentRange", function (from, to) {
157
+ var cmInstance = this;
158
+ this.operation(function () {
159
+ for (var i = from.line; i <= to.line; i++) {
160
+ cmInstance.indentLine(i, "smart");
161
+ }
162
+ });
163
+ });
266
164
 
267
- if (selStart >= endPos) { // The block starts later than the needed fragment
268
- break;
165
+ // Applies automatic formatting to the specified range
166
+ CodeMirror.defineExtension("autoFormatRange", function (from, to) {
167
+ var cm = this;
168
+ cm.operation(function () {
169
+ for (var cur = from.line, end = to.line; cur <= end; ++cur) {
170
+ var f = {line: cur, ch: cur == from.line ? from.ch : 0};
171
+ var t = {line: cur, ch: cur == end ? to.ch : null};
172
+ var modes = enumerateModesBetween(cm, cur, f.ch, t.ch), mangled = "";
173
+ var text = cm.getRange(f, t);
174
+ for (var i = 0; i < modes.length; ++i) {
175
+ var part = modes.length > 1 ? text.slice(modes[i].from, modes[i].to) : text;
176
+ if (mangled) mangled += "\n";
177
+ if (modes[i].mode.autoFormatLineBreaks) {
178
+ mangled += modes[i].mode.autoFormatLineBreaks(part);
179
+ } else mangled += text;
269
180
  }
270
- if (selStart < startPos) {
271
- if (selEnd <= startPos) { // The block starts earlier than the needed fragment
272
- continue;
273
- }
274
- selStart = startPos;
275
- }
276
- if (selEnd > endPos) {
277
- selEnd = endPos;
278
- }
279
- var textPortion = text.substring(selStart, selEnd);
280
- if (modeInfos[i - 1].modeName != "xml") { // Starting a CSS or JavaScript block
281
- if (!reBlockStartsWithNewline.test(textPortion)
282
- && selStart > 0) { // The block does not start with a line break
283
- textPortion = "\n" + textPortion;
284
- }
285
- if (!reBlockEndsWithNewline.test(textPortion)
286
- && selEnd < text.length - 1) { // The block does not end with a line break
287
- textPortion += "\n";
288
- }
181
+ if (mangled != text) {
182
+ for (var count = 0, pos = mangled.indexOf("\n"); pos != -1; pos = mangled.indexOf("\n", pos + 1), ++count) {}
183
+ cm.replaceRange(mangled, f, t);
184
+ cur += count;
185
+ end += count;
289
186
  }
290
- res += modeInfos[i - 1].modeExt.autoFormatLineBreaks(textPortion);
291
187
  }
292
- }
293
- else { // Single-mode text
294
- res = modeInfos[0].modeExt.autoFormatLineBreaks(text.substring(startPos, endPos));
295
- }
296
-
297
- return res;
298
- }
299
- };
188
+ for (var cur = from.line + 1; cur <= end; ++cur)
189
+ cm.indentLine(cur, "smart");
190
+ cm.setSelection(from, cm.getCursor(false));
191
+ });
192
+ });
193
+ })();