codemirror-rails 2.3 → 2.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/README.md +0 -16
  2. data/codemirror-rails.gemspec +1 -1
  3. data/lib/codemirror/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/codemirror.js +323 -687
  5. data/vendor/assets/javascripts/codemirror/modes/clike.js +3 -40
  6. data/vendor/assets/javascripts/codemirror/modes/clojure.js +14 -14
  7. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +0 -6
  8. data/vendor/assets/javascripts/codemirror/modes/css.js +1 -1
  9. data/vendor/assets/javascripts/codemirror/modes/diff.js +5 -24
  10. data/vendor/assets/javascripts/codemirror/modes/gfm.js +4 -40
  11. data/vendor/assets/javascripts/codemirror/modes/go.js +22 -20
  12. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +1 -1
  13. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +2 -4
  14. data/vendor/assets/javascripts/codemirror/modes/javascript.js +7 -8
  15. data/vendor/assets/javascripts/codemirror/modes/less.js +54 -100
  16. data/vendor/assets/javascripts/codemirror/modes/markdown.js +49 -52
  17. data/vendor/assets/javascripts/codemirror/modes/pascal.js +46 -2
  18. data/vendor/assets/javascripts/codemirror/modes/perl.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/modes/php.js +25 -54
  20. data/vendor/assets/javascripts/codemirror/modes/python.js +16 -14
  21. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.js +1 -1
  22. data/vendor/assets/javascripts/codemirror/modes/rst.js +1 -1
  23. data/vendor/assets/javascripts/codemirror/modes/ruby.js +9 -4
  24. data/vendor/assets/javascripts/codemirror/modes/scheme.js +46 -74
  25. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +16 -16
  26. data/vendor/assets/javascripts/codemirror/modes/stex.js +6 -21
  27. data/vendor/assets/javascripts/codemirror/modes/tiddlywiki.js +45 -55
  28. data/vendor/assets/javascripts/codemirror/modes/xml.js +14 -79
  29. data/vendor/assets/javascripts/codemirror/{utils/overlay.js → overlay.js} +2 -3
  30. data/vendor/assets/javascripts/codemirror/runmode.js +27 -0
  31. data/vendor/assets/stylesheets/codemirror.css +2 -63
  32. data/vendor/assets/stylesheets/codemirror/modes/tiddlywiki.css +21 -14
  33. data/vendor/assets/stylesheets/codemirror/themes/eclipse.css +1 -1
  34. data/vendor/assets/stylesheets/codemirror/themes/elegant.css +2 -2
  35. data/vendor/assets/stylesheets/codemirror/themes/neat.css +3 -3
  36. data/vendor/assets/stylesheets/codemirror/themes/night.css +1 -1
  37. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +2 -2
  38. metadata +6 -39
  39. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +0 -29
  40. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +0 -766
  41. data/vendor/assets/javascripts/codemirror/modes/ecl.js +0 -203
  42. data/vendor/assets/javascripts/codemirror/modes/erlang.js +0 -251
  43. data/vendor/assets/javascripts/codemirror/modes/pig.js +0 -172
  44. data/vendor/assets/javascripts/codemirror/modes/properties.js +0 -63
  45. data/vendor/assets/javascripts/codemirror/modes/shell.js +0 -103
  46. data/vendor/assets/javascripts/codemirror/modes/smarty.js +0 -148
  47. data/vendor/assets/javascripts/codemirror/modes/tiki.js +0 -316
  48. data/vendor/assets/javascripts/codemirror/modes/vbscript.js +0 -26
  49. data/vendor/assets/javascripts/codemirror/modes/xquery.js +0 -448
  50. data/vendor/assets/javascripts/codemirror/utils/closetag.js +0 -146
  51. data/vendor/assets/javascripts/codemirror/utils/dialog.js +0 -63
  52. data/vendor/assets/javascripts/codemirror/utils/foldcode.js +0 -196
  53. data/vendor/assets/javascripts/codemirror/utils/formatting.js +0 -297
  54. data/vendor/assets/javascripts/codemirror/utils/javascript-hint.js +0 -134
  55. data/vendor/assets/javascripts/codemirror/utils/loadmode.js +0 -51
  56. data/vendor/assets/javascripts/codemirror/utils/match-highlighter.js +0 -44
  57. data/vendor/assets/javascripts/codemirror/utils/multiplex.js +0 -72
  58. data/vendor/assets/javascripts/codemirror/utils/pig-hint.js +0 -123
  59. data/vendor/assets/javascripts/codemirror/utils/runmode.js +0 -49
  60. data/vendor/assets/javascripts/codemirror/utils/search.js +0 -118
  61. data/vendor/assets/javascripts/codemirror/utils/searchcursor.js +0 -117
  62. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +0 -72
  63. data/vendor/assets/stylesheets/codemirror/modes/tiki.css +0 -26
  64. data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +0 -81
  65. data/vendor/assets/stylesheets/codemirror/themes/blackboard.css +0 -25
  66. data/vendor/assets/stylesheets/codemirror/themes/erlang-dark.css +0 -21
  67. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +0 -44
  68. data/vendor/assets/stylesheets/codemirror/themes/vibrant-ink.css +0 -27
  69. data/vendor/assets/stylesheets/codemirror/themes/xq-dark.css +0 -46
  70. data/vendor/assets/stylesheets/codemirror/utils/dialog.css +0 -23
  71. data/vendor/assets/stylesheets/codemirror/utils/simple-hint.css +0 -16
@@ -1,146 +0,0 @@
1
- /**
2
- * Tag-closer extension for CodeMirror.
3
- *
4
- * This extension adds a "closeTag" utility function that can be used with key bindings to
5
- * insert a matching end tag after the ">" character of a start tag has been typed. It can
6
- * also complete "</" if a matching start tag is found. It will correctly ignore signal
7
- * characters for empty tags, comments, CDATA, etc.
8
- *
9
- * The function depends on internal parser state to identify tags. It is compatible with the
10
- * following CodeMirror modes and will ignore all others:
11
- * - htmlmixed
12
- * - xml
13
- *
14
- * See demos/closetag.html for a usage example.
15
- *
16
- * @author Nathan Williams <nathan@nlwillia.net>
17
- * Contributed under the same license terms as CodeMirror.
18
- */
19
- (function() {
20
- /** Option that allows tag closing behavior to be toggled. Default is true. */
21
- CodeMirror.defaults['closeTagEnabled'] = true;
22
-
23
- /** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */
24
- CodeMirror.defaults['closeTagIndent'] = ['applet', 'blockquote', 'body', 'button', 'div', 'dl', 'fieldset', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'iframe', 'layer', 'legend', 'object', 'ol', 'p', 'select', 'table', 'ul'];
25
-
26
- /**
27
- * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
28
- * - cm: The editor instance.
29
- * - ch: The character being processed.
30
- * - indent: Optional. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option.
31
- * Pass false to disable indentation. Pass an array to override the default list of tag names.
32
- */
33
- CodeMirror.defineExtension("closeTag", function(cm, ch, indent) {
34
- if (!cm.getOption('closeTagEnabled')) {
35
- throw CodeMirror.Pass;
36
- }
37
-
38
- var mode = cm.getOption('mode');
39
-
40
- if (mode == 'text/html') {
41
-
42
- /*
43
- * Relevant structure of token:
44
- *
45
- * htmlmixed
46
- * className
47
- * state
48
- * htmlState
49
- * type
50
- * context
51
- * tagName
52
- * mode
53
- *
54
- * xml
55
- * className
56
- * state
57
- * tagName
58
- * type
59
- */
60
-
61
- var pos = cm.getCursor();
62
- var tok = cm.getTokenAt(pos);
63
- var state = tok.state;
64
-
65
- if (state.mode && state.mode != 'html') {
66
- throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode.
67
- }
68
-
69
- if (ch == '>') {
70
- var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
71
-
72
- if (tok.className == 'tag' && type == 'closeTag') {
73
- throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag.
74
- }
75
-
76
- cm.replaceSelection('>'); // Mode state won't update until we finish the tag.
77
- pos = {line: pos.line, ch: pos.ch + 1};
78
- cm.setCursor(pos);
79
-
80
- tok = cm.getTokenAt(cm.getCursor());
81
- state = tok.state;
82
- type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
83
-
84
- if (tok.className == 'tag' && type != 'selfcloseTag') {
85
- var tagName = state.htmlState ? state.htmlState.context.tagName : state.tagName; // htmlmixed : xml
86
- if (tagName.length > 0) {
87
- insertEndTag(cm, indent, pos, tagName);
88
- }
89
- return;
90
- }
91
-
92
- // Undo the '>' insert and allow cm to handle the key instead.
93
- cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos);
94
- cm.replaceSelection("");
95
-
96
- } else if (ch == '/') {
97
- if (tok.className == 'tag' && tok.string == '<') {
98
- var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : state.context.tagName; // htmlmixed : xml # extra htmlmized check is for '</' edge case
99
- if (tagName.length > 0) {
100
- completeEndTag(cm, pos, tagName);
101
- return;
102
- }
103
- }
104
- }
105
-
106
- }
107
-
108
- throw CodeMirror.Pass; // Bubble if not handled
109
- });
110
-
111
- function insertEndTag(cm, indent, pos, tagName) {
112
- if (shouldIndent(cm, indent, tagName)) {
113
- cm.replaceSelection('\n\n</' + tagName + '>', 'end');
114
- cm.indentLine(pos.line + 1);
115
- cm.indentLine(pos.line + 2);
116
- cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length});
117
- } else {
118
- cm.replaceSelection('</' + tagName + '>');
119
- cm.setCursor(pos);
120
- }
121
- }
122
-
123
- function shouldIndent(cm, indent, tagName) {
124
- if (typeof indent == 'undefined' || indent == null || indent == true) {
125
- indent = cm.getOption('closeTagIndent');
126
- }
127
- if (!indent) {
128
- indent = [];
129
- }
130
- return indexOf(indent, tagName.toLowerCase()) != -1;
131
- }
132
-
133
- // C&P from codemirror.js...would be nice if this were visible to utilities.
134
- function indexOf(collection, elt) {
135
- if (collection.indexOf) return collection.indexOf(elt);
136
- for (var i = 0, e = collection.length; i < e; ++i)
137
- if (collection[i] == elt) return i;
138
- return -1;
139
- }
140
-
141
- function completeEndTag(cm, pos, tagName) {
142
- cm.replaceSelection('/' + tagName + '>');
143
- cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 });
144
- }
145
-
146
- })();
@@ -1,63 +0,0 @@
1
- // Open simple dialogs on top of an editor. Relies on dialog.css.
2
-
3
- (function() {
4
- function dialogDiv(cm, template) {
5
- var wrap = cm.getWrapperElement();
6
- var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
7
- dialog.className = "CodeMirror-dialog";
8
- dialog.innerHTML = '<div>' + template + '</div>';
9
- return dialog;
10
- }
11
-
12
- CodeMirror.defineExtension("openDialog", function(template, callback) {
13
- var dialog = dialogDiv(this, template);
14
- var closed = false, me = this;
15
- function close() {
16
- if (closed) return;
17
- closed = true;
18
- dialog.parentNode.removeChild(dialog);
19
- }
20
- var inp = dialog.getElementsByTagName("input")[0];
21
- if (inp) {
22
- CodeMirror.connect(inp, "keydown", function(e) {
23
- if (e.keyCode == 13 || e.keyCode == 27) {
24
- CodeMirror.e_stop(e);
25
- close();
26
- me.focus();
27
- if (e.keyCode == 13) callback(inp.value);
28
- }
29
- });
30
- inp.focus();
31
- CodeMirror.connect(inp, "blur", close);
32
- }
33
- return close;
34
- });
35
-
36
- CodeMirror.defineExtension("openConfirm", function(template, callbacks) {
37
- var dialog = dialogDiv(this, template);
38
- var buttons = dialog.getElementsByTagName("button");
39
- var closed = false, me = this, blurring = 1;
40
- function close() {
41
- if (closed) return;
42
- closed = true;
43
- dialog.parentNode.removeChild(dialog);
44
- me.focus();
45
- }
46
- buttons[0].focus();
47
- for (var i = 0; i < buttons.length; ++i) {
48
- var b = buttons[i];
49
- (function(callback) {
50
- CodeMirror.connect(b, "click", function(e) {
51
- CodeMirror.e_preventDefault(e);
52
- close();
53
- if (callback) callback(me);
54
- });
55
- })(callbacks[i]);
56
- CodeMirror.connect(b, "blur", function() {
57
- --blurring;
58
- setTimeout(function() { if (blurring <= 0) close(); }, 200);
59
- });
60
- CodeMirror.connect(b, "focus", function() { ++blurring; });
61
- }
62
- });
63
- })();
@@ -1,196 +0,0 @@
1
- // the tagRangeFinder function is
2
- // Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
3
- // released under the MIT license (../../LICENSE) like the rest of CodeMirror
4
- CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
5
- var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
6
- var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
7
- var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
8
-
9
- var lineText = cm.getLine(line);
10
- var found = false;
11
- var tag = null;
12
- var pos = 0;
13
- while (!found) {
14
- pos = lineText.indexOf("<", pos);
15
- if (-1 == pos) // no tag on line
16
- return;
17
- if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
18
- pos++;
19
- continue;
20
- }
21
- // ok we weem to have a start tag
22
- if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
23
- pos++;
24
- continue;
25
- }
26
- var gtPos = lineText.indexOf(">", pos + 1);
27
- if (-1 == gtPos) { // end of start tag not in line
28
- var l = line + 1;
29
- var foundGt = false;
30
- var lastLine = cm.lineCount();
31
- while (l < lastLine && !foundGt) {
32
- var lt = cm.getLine(l);
33
- var gt = lt.indexOf(">");
34
- if (-1 != gt) { // found a >
35
- foundGt = true;
36
- var slash = lt.lastIndexOf("/", gt);
37
- if (-1 != slash && slash < gt) {
38
- var str = lineText.substr(slash, gt - slash + 1);
39
- if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
40
- if (hideEnd === true) l++;
41
- return l;
42
- }
43
- }
44
- }
45
- l++;
46
- }
47
- found = true;
48
- }
49
- else {
50
- var slashPos = lineText.lastIndexOf("/", gtPos);
51
- if (-1 == slashPos) { // cannot be empty tag
52
- found = true;
53
- // don't continue
54
- }
55
- else { // empty tag?
56
- // check if really empty tag
57
- var str = lineText.substr(slashPos, gtPos - slashPos + 1);
58
- if (!str.match( /\/\s*\>/ )) { // finally not empty
59
- found = true;
60
- // don't continue
61
- }
62
- }
63
- }
64
- if (found) {
65
- var subLine = lineText.substr(pos + 1);
66
- tag = subLine.match(xmlNAMERegExp);
67
- if (tag) {
68
- // we have an element name, wooohooo !
69
- tag = tag[0];
70
- // do we have the close tag on same line ???
71
- if (-1 != lineText.indexOf("</" + tag + ">", pos)) // yep
72
- {
73
- found = false;
74
- }
75
- // we don't, so we have a candidate...
76
- }
77
- else
78
- found = false;
79
- }
80
- if (!found)
81
- pos++;
82
- }
83
-
84
- if (found) {
85
- var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
86
- var startTagRegExp = new RegExp(startTag, "g");
87
- var endTag = "</" + tag + ">";
88
- var depth = 1;
89
- var l = line + 1;
90
- var lastLine = cm.lineCount();
91
- while (l < lastLine) {
92
- lineText = cm.getLine(l);
93
- var match = lineText.match(startTagRegExp);
94
- if (match) {
95
- for (var i = 0; i < match.length; i++) {
96
- if (match[i] == endTag)
97
- depth--;
98
- else
99
- depth++;
100
- if (!depth) {
101
- if (hideEnd === true) l++;
102
- return l;
103
- }
104
- }
105
- }
106
- l++;
107
- }
108
- return;
109
- }
110
- };
111
-
112
- CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
113
- var lineText = cm.getLine(line), at = lineText.length, startChar, tokenType;
114
- for (;;) {
115
- var found = lineText.lastIndexOf("{", at);
116
- if (found < 0) break;
117
- tokenType = cm.getTokenAt({line: line, ch: found}).className;
118
- if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
119
- at = found - 1;
120
- }
121
- if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
122
- var count = 1, lastLine = cm.lineCount(), end;
123
- outer: for (var i = line + 1; i < lastLine; ++i) {
124
- var text = cm.getLine(i), pos = 0;
125
- for (;;) {
126
- var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
127
- if (nextOpen < 0) nextOpen = text.length;
128
- if (nextClose < 0) nextClose = text.length;
129
- pos = Math.min(nextOpen, nextClose);
130
- if (pos == text.length) break;
131
- if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) {
132
- if (pos == nextOpen) ++count;
133
- else if (!--count) { end = i; break outer; }
134
- }
135
- ++pos;
136
- }
137
- }
138
- if (end == null || end == line + 1) return;
139
- if (hideEnd === true) end++;
140
- return end;
141
- };
142
-
143
- CodeMirror.indentRangeFinder = function(cm, line) {
144
- var tabSize = cm.getOption("tabSize");
145
- var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
146
- for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
147
- var handle = cm.getLineHandle(i);
148
- if (!/^\s*$/.test(handle.text)) {
149
- if (handle.indentation(tabSize) <= myIndent) break;
150
- last = i;
151
- }
152
- }
153
- if (!last) return null;
154
- return last + 1;
155
- };
156
-
157
- CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
158
- var folded = [];
159
- if (markText == null) markText = '<div style="position: absolute; left: 2px; color:#600">&#x25bc;</div>%N%';
160
-
161
- function isFolded(cm, n) {
162
- for (var i = 0; i < folded.length; ++i) {
163
- var start = cm.lineInfo(folded[i].start);
164
- if (!start) folded.splice(i--, 1);
165
- else if (start.line == n) return {pos: i, region: folded[i]};
166
- }
167
- }
168
-
169
- function expand(cm, region) {
170
- cm.clearMarker(region.start);
171
- for (var i = 0; i < region.hidden.length; ++i)
172
- cm.showLine(region.hidden[i]);
173
- }
174
-
175
- return function(cm, line) {
176
- cm.operation(function() {
177
- var known = isFolded(cm, line);
178
- if (known) {
179
- folded.splice(known.pos, 1);
180
- expand(cm, known.region);
181
- } else {
182
- var end = rangeFinder(cm, line, hideEnd);
183
- if (end == null) return;
184
- var hidden = [];
185
- for (var i = line + 1; i < end; ++i) {
186
- var handle = cm.hideLine(i);
187
- if (handle) hidden.push(handle);
188
- }
189
- var first = cm.setMarker(line, markText);
190
- var region = {start: first, hidden: hidden};
191
- cm.onDeleteLine(first, function() { expand(cm, region); });
192
- folded.push(region);
193
- }
194
- });
195
- };
196
- };
@@ -1,297 +0,0 @@
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");
57
- }
58
- });
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
-
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("//.*([\r\n]|$)")
104
- ];
105
- var nonBreakableBlocks = new Array();
106
- for (var i = 0; i < nonBreakableRegexes.length; i++) {
107
- var curPos = 0;
108
- while (curPos < text.length) {
109
- var m = text.substr(curPos).match(nonBreakableRegexes[i]);
110
- if (m != null) {
111
- nonBreakableBlocks.push({
112
- start: curPos + m.index,
113
- end: curPos + m.index + m[0].length
114
- });
115
- curPos += m.index + Math.max(1, m[0].length);
116
- }
117
- else { // No more matches
118
- break;
119
- }
120
- }
121
- }
122
- nonBreakableBlocks.sort(function (a, b) {
123
- return a.start - b.start;
124
- });
125
-
126
- return nonBreakableBlocks;
127
- },
128
-
129
- autoFormatLineBreaks: function (text, startPos, endPos) {
130
- text = text.substring(startPos, endPos);
131
- var curPos = 0;
132
- var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
133
- var nonBreakableBlocks = this.getNonBreakableBlocks(text);
134
- if (nonBreakableBlocks != null) {
135
- var res = "";
136
- for (var i = 0; i < nonBreakableBlocks.length; i++) {
137
- if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
138
- res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
139
- curPos = nonBreakableBlocks[i].start;
140
- }
141
- if (nonBreakableBlocks[i].start <= curPos
142
- && nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
143
- res += text.substring(curPos, nonBreakableBlocks[i].end);
144
- curPos = nonBreakableBlocks[i].end;
145
- }
146
- }
147
- if (curPos < text.length - 1) {
148
- res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
149
- }
150
- return res;
151
- }
152
- else {
153
- return text.replace(reLinesSplitter, "$1\n$2");
154
- }
155
- }
156
- };
157
-
158
- CodeMirror.modeExtensions["xml"] = {
159
- commentStart: "<!--",
160
- commentEnd: "-->",
161
- wordWrapChars: [">"],
162
-
163
- autoFormatLineBreaks: function (text, startPos, endPos) {
164
- text = text.substring(startPos, endPos);
165
- var lines = text.split("\n");
166
- var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
167
- var reOpenBrackets = new RegExp("<", "g");
168
- var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
169
- for (var i = 0; i < lines.length; i++) {
170
- var mToProcess = lines[i].match(reProcessedPortion);
171
- if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
172
- lines[i] = mToProcess[1]
173
- + mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
174
- + mToProcess[3];
175
- continue;
176
- }
177
- }
178
-
179
- return lines.join("\n");
180
- }
181
- };
182
-
183
- CodeMirror.modeExtensions["htmlmixed"] = {
184
- commentStart: "<!--",
185
- commentEnd: "-->",
186
- wordWrapChars: [">", ";", "\\{", "\\}"],
187
-
188
- getModeInfos: function (text, absPos) {
189
- var modeInfos = new Array();
190
- modeInfos[0] =
191
- {
192
- pos: 0,
193
- modeExt: CodeMirror.modeExtensions["xml"],
194
- modeName: "xml"
195
- };
196
-
197
- var modeMatchers = new Array();
198
- modeMatchers[0] =
199
- {
200
- regex: new RegExp("<style[^>]*>([\\s\\S]*?)(</style[^>]*>|$)", "i"),
201
- modeExt: CodeMirror.modeExtensions["css"],
202
- modeName: "css"
203
- };
204
- modeMatchers[1] =
205
- {
206
- regex: new RegExp("<script[^>]*>([\\s\\S]*?)(</script[^>]*>|$)", "i"),
207
- modeExt: CodeMirror.modeExtensions["javascript"],
208
- modeName: "javascript"
209
- };
210
-
211
- var lastCharPos = (typeof (absPos) !== "undefined" ? absPos : text.length - 1);
212
- // Detect modes for the entire text
213
- for (var i = 0; i < modeMatchers.length; i++) {
214
- var curPos = 0;
215
- while (curPos <= lastCharPos) {
216
- var m = text.substr(curPos).match(modeMatchers[i].regex);
217
- if (m != null) {
218
- if (m.length > 1 && m[1].length > 0) {
219
- // Push block begin pos
220
- var blockBegin = curPos + m.index + m[0].indexOf(m[1]);
221
- modeInfos.push(
222
- {
223
- pos: blockBegin,
224
- modeExt: modeMatchers[i].modeExt,
225
- modeName: modeMatchers[i].modeName
226
- });
227
- // Push block end pos
228
- modeInfos.push(
229
- {
230
- pos: blockBegin + m[1].length,
231
- modeExt: modeInfos[0].modeExt,
232
- modeName: modeInfos[0].modeName
233
- });
234
- curPos += m.index + m[0].length;
235
- continue;
236
- }
237
- else {
238
- curPos += m.index + Math.max(m[0].length, 1);
239
- }
240
- }
241
- else { // No more matches
242
- break;
243
- }
244
- }
245
- }
246
- // Sort mode infos
247
- modeInfos.sort(function sortModeInfo(a, b) {
248
- return a.pos - b.pos;
249
- });
250
-
251
- return modeInfos;
252
- },
253
-
254
- autoFormatLineBreaks: function (text, startPos, endPos) {
255
- var modeInfos = this.getModeInfos(text);
256
- var reBlockStartsWithNewline = new RegExp("^\\s*?\n");
257
- var reBlockEndsWithNewline = new RegExp("\n\\s*?$");
258
- var res = "";
259
- // Use modes info to break lines correspondingly
260
- if (modeInfos.length > 1) { // Deal with multi-mode text
261
- for (var i = 1; i <= modeInfos.length; i++) {
262
- var selStart = modeInfos[i - 1].pos;
263
- var selEnd = (i < modeInfos.length ? modeInfos[i].pos : endPos);
264
-
265
- if (selStart >= endPos) { // The block starts later than the needed fragment
266
- break;
267
- }
268
- if (selStart < startPos) {
269
- if (selEnd <= startPos) { // The block starts earlier than the needed fragment
270
- continue;
271
- }
272
- selStart = startPos;
273
- }
274
- if (selEnd > endPos) {
275
- selEnd = endPos;
276
- }
277
- var textPortion = text.substring(selStart, selEnd);
278
- if (modeInfos[i - 1].modeName != "xml") { // Starting a CSS or JavaScript block
279
- if (!reBlockStartsWithNewline.test(textPortion)
280
- && selStart > 0) { // The block does not start with a line break
281
- textPortion = "\n" + textPortion;
282
- }
283
- if (!reBlockEndsWithNewline.test(textPortion)
284
- && selEnd < text.length - 1) { // The block does not end with a line break
285
- textPortion += "\n";
286
- }
287
- }
288
- res += modeInfos[i - 1].modeExt.autoFormatLineBreaks(textPortion);
289
- }
290
- }
291
- else { // Single-mode text
292
- res = modeInfos[0].modeExt.autoFormatLineBreaks(text.substring(startPos, endPos));
293
- }
294
-
295
- return res;
296
- }
297
- };