codemirror-rails 3.13 → 3.14
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.
- checksums.yaml +4 -4
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +328 -250
- data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +7 -6
- data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +33 -7
- data/vendor/assets/javascripts/codemirror/addons/edit/matchbrackets.js +14 -10
- data/vendor/assets/javascripts/codemirror/addons/edit/trailingspace.js +15 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/brace-fold.js +70 -17
- data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +56 -20
- data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +135 -39
- data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +324 -571
- data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +199 -109
- data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +60 -113
- data/vendor/assets/javascripts/codemirror/addons/lint/coffeescript-lint.js +24 -0
- data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +431 -0
- data/vendor/assets/javascripts/codemirror/addons/mode/multiplex.js +7 -1
- data/vendor/assets/javascripts/codemirror/addons/search/match-highlighter.js +46 -20
- data/vendor/assets/javascripts/codemirror/addons/search/search.js +1 -1
- data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +370 -13
- data/vendor/assets/javascripts/codemirror/keymaps/extra.js +43 -0
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +535 -214
- data/vendor/assets/javascripts/codemirror/modes/clike.js +56 -0
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +19 -14
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/ruby.js +67 -16
- data/vendor/assets/javascripts/codemirror/modes/smarty.js +167 -110
- data/vendor/assets/javascripts/codemirror/modes/sql.js +97 -15
- data/vendor/assets/javascripts/codemirror/modes/xml.js +14 -18
- data/vendor/assets/stylesheets/codemirror.css +0 -1
- data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +82 -0
- metadata +7 -2
@@ -30,7 +30,7 @@
|
|
30
30
|
if (firstLine == null) return;
|
31
31
|
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
|
32
32
|
var pad = options.padding == null ? " " : options.padding;
|
33
|
-
var blankLines = options.commentBlankLines;
|
33
|
+
var blankLines = options.commentBlankLines || from.line == to.line;
|
34
34
|
|
35
35
|
self.operation(function() {
|
36
36
|
if (options.indent) {
|
@@ -90,14 +90,14 @@
|
|
90
90
|
|
91
91
|
// Try finding line comments
|
92
92
|
var lineString = options.lineComment || mode.lineComment, lines = [];
|
93
|
-
var pad = options.padding == null ? " " : options.padding;
|
94
|
-
lineComment:
|
95
|
-
if (!lineString) break;
|
93
|
+
var pad = options.padding == null ? " " : options.padding, didSomething;
|
94
|
+
lineComment: {
|
95
|
+
if (!lineString) break lineComment;
|
96
96
|
for (var i = start; i <= end; ++i) {
|
97
97
|
var line = self.getLine(i);
|
98
98
|
var found = line.indexOf(lineString);
|
99
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;
|
100
|
+
if (i != start && found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
|
101
101
|
lines.push(line);
|
102
102
|
}
|
103
103
|
self.operation(function() {
|
@@ -106,10 +106,11 @@
|
|
106
106
|
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
|
107
107
|
if (pos < 0) continue;
|
108
108
|
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
|
109
|
+
didSomething = true;
|
109
110
|
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
|
110
111
|
}
|
111
112
|
});
|
112
|
-
return true;
|
113
|
+
if (didSomething) return true;
|
113
114
|
}
|
114
115
|
|
115
116
|
// Try block comments
|
@@ -1,23 +1,36 @@
|
|
1
1
|
(function() {
|
2
2
|
var DEFAULT_BRACKETS = "()[]{}''\"\"";
|
3
|
+
var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
|
3
4
|
var SPACE_CHAR_REGEX = /\s/;
|
4
5
|
|
5
6
|
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
|
6
|
-
|
7
|
-
if (val && !wasOn)
|
8
|
-
cm.addKeyMap(buildKeymap(typeof val == "string" ? val : DEFAULT_BRACKETS));
|
9
|
-
else if (!val && wasOn)
|
7
|
+
if (old != CodeMirror.Init && old)
|
10
8
|
cm.removeKeyMap("autoCloseBrackets");
|
9
|
+
if (!val) return;
|
10
|
+
var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
|
11
|
+
if (typeof val == "string") pairs = val;
|
12
|
+
else if (typeof val == "object") {
|
13
|
+
if (val.pairs != null) pairs = val.pairs;
|
14
|
+
if (val.explode != null) explode = val.explode;
|
15
|
+
}
|
16
|
+
var map = buildKeymap(pairs);
|
17
|
+
if (explode) map.Enter = buildExplodeHandler(explode);
|
18
|
+
cm.addKeyMap(map);
|
11
19
|
});
|
12
20
|
|
21
|
+
function charsAround(cm, pos) {
|
22
|
+
var str = cm.getRange(CodeMirror.Pos(pos.line, pos.ch - 1),
|
23
|
+
CodeMirror.Pos(pos.line, pos.ch + 1));
|
24
|
+
return str.length == 2 ? str : null;
|
25
|
+
}
|
26
|
+
|
13
27
|
function buildKeymap(pairs) {
|
14
28
|
var map = {
|
15
29
|
name : "autoCloseBrackets",
|
16
30
|
Backspace: function(cm) {
|
17
31
|
if (cm.somethingSelected()) return CodeMirror.Pass;
|
18
|
-
var cur = cm.getCursor(),
|
19
|
-
if (
|
20
|
-
pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0)
|
32
|
+
var cur = cm.getCursor(), around = charsAround(cm, cur);
|
33
|
+
if (around && pairs.indexOf(around) % 2 == 0)
|
21
34
|
cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
|
22
35
|
else
|
23
36
|
return CodeMirror.Pass;
|
@@ -51,4 +64,17 @@
|
|
51
64
|
})(pairs.charAt(i), pairs.charAt(i + 1));
|
52
65
|
return map;
|
53
66
|
}
|
67
|
+
|
68
|
+
function buildExplodeHandler(pairs) {
|
69
|
+
return function(cm) {
|
70
|
+
var cur = cm.getCursor(), around = charsAround(cm, cur);
|
71
|
+
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
72
|
+
cm.operation(function() {
|
73
|
+
var newPos = CodeMirror.Pos(cur.line + 1, 0);
|
74
|
+
cm.replaceSelection("\n\n", {anchor: newPos, head: newPos}, "+input");
|
75
|
+
cm.indentLine(cur.line + 1, null, true);
|
76
|
+
cm.indentLine(cur.line + 2, null, true);
|
77
|
+
});
|
78
|
+
};
|
79
|
+
}
|
54
80
|
})();
|
@@ -5,25 +5,26 @@
|
|
5
5
|
var Pos = CodeMirror.Pos;
|
6
6
|
|
7
7
|
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
8
|
-
function findMatchingBracket(cm) {
|
9
|
-
var
|
8
|
+
function findMatchingBracket(cm, where, strict) {
|
9
|
+
var state = cm.state.matchBrackets;
|
10
|
+
var maxScanLen = (state && state.maxScanLineLength) || 10000;
|
10
11
|
|
11
|
-
var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
|
12
|
+
var cur = where || cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
|
12
13
|
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
|
13
14
|
if (!match) return null;
|
14
15
|
var forward = match.charAt(1) == ">", d = forward ? 1 : -1;
|
15
|
-
|
16
|
+
if (strict && forward != (pos == cur.ch)) return null;
|
17
|
+
var style = cm.getTokenTypeAt(Pos(cur.line, pos + 1));
|
16
18
|
|
17
19
|
var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
|
18
20
|
function scan(line, lineNo, start) {
|
19
21
|
if (!line.text) return;
|
20
22
|
var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1;
|
21
23
|
if (line.text.length > maxScanLen) return null;
|
22
|
-
var checkTokenStyles = line.text.length < 1000;
|
23
24
|
if (start != null) pos = start + d;
|
24
25
|
for (; pos != end; pos += d) {
|
25
26
|
var ch = line.text.charAt(pos);
|
26
|
-
if (re.test(ch) &&
|
27
|
+
if (re.test(ch) && cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style) {
|
27
28
|
var match = matching[ch];
|
28
29
|
if (match.charAt(1) == ">" == forward) stack.push(ch);
|
29
30
|
else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
|
@@ -36,12 +37,13 @@
|
|
36
37
|
else found = scan(cm.getLineHandle(i), i);
|
37
38
|
if (found) break;
|
38
39
|
}
|
39
|
-
return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos),
|
40
|
+
return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos),
|
41
|
+
match: found && found.match, forward: forward};
|
40
42
|
}
|
41
43
|
|
42
44
|
function matchBrackets(cm, autoclear) {
|
43
45
|
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
44
|
-
var maxHighlightLen = cm.state.
|
46
|
+
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
|
45
47
|
var found = findMatchingBracket(cm);
|
46
48
|
if (!found || cm.getLine(found.from.line).length > maxHighlightLen ||
|
47
49
|
found.to && cm.getLine(found.to.line).length > maxHighlightLen)
|
@@ -72,11 +74,13 @@
|
|
72
74
|
if (old && old != CodeMirror.Init)
|
73
75
|
cm.off("cursorActivity", doMatchBrackets);
|
74
76
|
if (val) {
|
75
|
-
cm.state.
|
77
|
+
cm.state.matchBrackets = typeof val == "object" ? val : {};
|
76
78
|
cm.on("cursorActivity", doMatchBrackets);
|
77
79
|
}
|
78
80
|
});
|
79
81
|
|
80
82
|
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
|
81
|
-
CodeMirror.defineExtension("findMatchingBracket", function(){
|
83
|
+
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict){
|
84
|
+
return findMatchingBracket(this, pos, strict);
|
85
|
+
});
|
82
86
|
})();
|
@@ -0,0 +1,15 @@
|
|
1
|
+
CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
|
2
|
+
if (prev == CodeMirror.Init) prev = false;
|
3
|
+
if (prev && !val)
|
4
|
+
cm.removeOverlay("trailingspace");
|
5
|
+
else if (!prev && val)
|
6
|
+
cm.addOverlay({
|
7
|
+
token: function(stream) {
|
8
|
+
for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
|
9
|
+
if (i > stream.pos) { stream.pos = i; return null; }
|
10
|
+
stream.pos = l;
|
11
|
+
return "trailingspace";
|
12
|
+
},
|
13
|
+
name: "trailingspace"
|
14
|
+
});
|
15
|
+
});
|
@@ -1,23 +1,33 @@
|
|
1
1
|
CodeMirror.braceRangeFinder = function(cm, start) {
|
2
2
|
var line = start.line, lineText = cm.getLine(line);
|
3
|
-
var
|
4
|
-
|
5
|
-
|
6
|
-
var
|
7
|
-
|
8
|
-
found
|
9
|
-
|
10
|
-
|
3
|
+
var startCh, tokenType;
|
4
|
+
|
5
|
+
function findOpening(openCh) {
|
6
|
+
for (var at = start.ch, pass = 0;;) {
|
7
|
+
var found = lineText.lastIndexOf(openCh, at - 1);
|
8
|
+
if (found == -1) {
|
9
|
+
if (pass == 1) break;
|
10
|
+
pass = 1;
|
11
|
+
at = lineText.length;
|
12
|
+
continue;
|
13
|
+
}
|
14
|
+
if (pass == 1 && found < start.ch) break;
|
15
|
+
tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
|
16
|
+
if (!/^(comment|string)/.test(tokenType)) return found + 1;
|
17
|
+
at = found - 1;
|
11
18
|
}
|
19
|
+
}
|
12
20
|
|
13
|
-
|
14
|
-
|
15
|
-
|
21
|
+
var startToken = "{", endToken = "}", startCh = findOpening("{");
|
22
|
+
if (startCh == null) {
|
23
|
+
startToken = "[", endToken = "]";
|
24
|
+
startCh = findOpening("[");
|
16
25
|
}
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
26
|
+
|
27
|
+
if (startCh == null) return;
|
28
|
+
var count = 1, lastLine = cm.lastLine(), end, endCh;
|
29
|
+
outer: for (var i = line; i <= lastLine; ++i) {
|
30
|
+
var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
21
31
|
for (;;) {
|
22
32
|
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
|
23
33
|
if (nextOpen < 0) nextOpen = text.length;
|
@@ -31,7 +41,50 @@ CodeMirror.braceRangeFinder = function(cm, start) {
|
|
31
41
|
++pos;
|
32
42
|
}
|
33
43
|
}
|
34
|
-
if (end == null ||
|
35
|
-
return {from: CodeMirror.Pos(line,
|
44
|
+
if (end == null || line == end && endCh == startCh) return;
|
45
|
+
return {from: CodeMirror.Pos(line, startCh),
|
36
46
|
to: CodeMirror.Pos(end, endCh)};
|
37
47
|
};
|
48
|
+
|
49
|
+
CodeMirror.importRangeFinder = function(cm, start) {
|
50
|
+
function hasImport(line) {
|
51
|
+
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
52
|
+
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
53
|
+
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
54
|
+
if (start.type != "keyword" || start.string != "import") return null;
|
55
|
+
// Now find closing semicolon, return its position
|
56
|
+
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
|
57
|
+
var text = cm.getLine(i), semi = text.indexOf(";");
|
58
|
+
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
var start = start.line, has = hasImport(start), prev;
|
63
|
+
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
|
64
|
+
return null;
|
65
|
+
for (var end = has.end;;) {
|
66
|
+
var next = hasImport(end.line + 1);
|
67
|
+
if (next == null) break;
|
68
|
+
end = next.end;
|
69
|
+
}
|
70
|
+
return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
|
71
|
+
};
|
72
|
+
|
73
|
+
CodeMirror.includeRangeFinder = function(cm, start) {
|
74
|
+
function hasInclude(line) {
|
75
|
+
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
76
|
+
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
77
|
+
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
78
|
+
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
|
79
|
+
}
|
80
|
+
|
81
|
+
var start = start.line, has = hasInclude(start);
|
82
|
+
if (has == null || hasInclude(start - 1) != null) return null;
|
83
|
+
for (var end = start;;) {
|
84
|
+
var next = hasInclude(end + 1);
|
85
|
+
if (next == null) break;
|
86
|
+
++end;
|
87
|
+
}
|
88
|
+
return {from: CodeMirror.Pos(start, has + 1),
|
89
|
+
to: cm.clipPos(CodeMirror.Pos(end))};
|
90
|
+
};
|
@@ -1,32 +1,68 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
if (typeof widget == "string") {
|
4
|
-
var text = document.createTextNode(widget);
|
5
|
-
widget = document.createElement("span");
|
6
|
-
widget.appendChild(text);
|
7
|
-
widget.className = "CodeMirror-foldmarker";
|
8
|
-
}
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
9
3
|
|
10
|
-
|
4
|
+
function doFold(cm, pos, options) {
|
5
|
+
var finder = options.call ? options : (options && options.rangeFinder);
|
6
|
+
if (!finder) return;
|
11
7
|
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
|
12
|
-
var
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
var minSize = options && options.minFoldSize || 0;
|
9
|
+
|
10
|
+
function getRange(allowFolded) {
|
11
|
+
var range = finder(cm, pos);
|
12
|
+
if (!range || range.to.line - range.from.line < minSize) return null;
|
13
|
+
var marks = cm.findMarksAt(range.from);
|
14
|
+
for (var i = 0; i < marks.length; ++i) {
|
15
|
+
if (marks[i].__isFold) {
|
16
|
+
if (!allowFolded) return null;
|
17
|
+
range.cleared = true;
|
18
|
+
marks[i].clear();
|
19
|
+
}
|
20
20
|
}
|
21
|
+
return range;
|
22
|
+
}
|
23
|
+
|
24
|
+
var range = getRange(true);
|
25
|
+
if (options && options.scanUp) while (!range && pos.line > cm.firstLine()) {
|
26
|
+
pos = CodeMirror.Pos(pos.line - 1, 0);
|
27
|
+
range = getRange(false);
|
21
28
|
}
|
22
|
-
if (cleared) return;
|
29
|
+
if (!range || range.cleared) return;
|
23
30
|
|
24
|
-
var myWidget =
|
31
|
+
var myWidget = makeWidget(options);
|
25
32
|
CodeMirror.on(myWidget, "mousedown", function() {myRange.clear();});
|
26
33
|
var myRange = cm.markText(range.from, range.to, {
|
27
34
|
replacedWith: myWidget,
|
28
35
|
clearOnEnter: true,
|
29
36
|
__isFold: true
|
30
37
|
});
|
38
|
+
}
|
39
|
+
|
40
|
+
function makeWidget(options) {
|
41
|
+
var widget = (options && options.widget) || "\u2194";
|
42
|
+
if (typeof widget == "string") {
|
43
|
+
var text = document.createTextNode(widget);
|
44
|
+
widget = document.createElement("span");
|
45
|
+
widget.appendChild(text);
|
46
|
+
widget.className = "CodeMirror-foldmarker";
|
47
|
+
}
|
48
|
+
return widget;
|
49
|
+
}
|
50
|
+
|
51
|
+
// Clumsy backwards-compatible interface
|
52
|
+
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
|
53
|
+
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
|
54
|
+
};
|
55
|
+
|
56
|
+
// New-style interface
|
57
|
+
CodeMirror.defineExtension("foldCode", function(pos, options) { doFold(this, pos, options); });
|
58
|
+
|
59
|
+
CodeMirror.combineRangeFinders = function() {
|
60
|
+
var funcs = Array.prototype.slice.call(arguments, 0);
|
61
|
+
return function(cm, start) {
|
62
|
+
for (var i = 0; i < funcs.length; ++i) {
|
63
|
+
var found = funcs[i](cm, start);
|
64
|
+
if (found) return found;
|
65
|
+
}
|
66
|
+
};
|
31
67
|
};
|
32
|
-
};
|
68
|
+
})();
|
@@ -1,64 +1,160 @@
|
|
1
|
-
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
var Pos = CodeMirror.Pos;
|
5
|
+
|
2
6
|
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";
|
3
7
|
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
4
8
|
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
|
5
9
|
|
6
|
-
|
7
|
-
|
10
|
+
function Iter(cm, line, ch) {
|
11
|
+
this.line = line; this.ch = ch;
|
12
|
+
this.cm = cm; this.text = cm.getLine(line);
|
13
|
+
}
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
function tagAt(iter, ch) {
|
16
|
+
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
|
17
|
+
return type && /\btag\b/.test(type);
|
18
|
+
}
|
19
|
+
|
20
|
+
function nextLine(iter) {
|
21
|
+
if (iter.line >= iter.cm.lastLine()) return;
|
22
|
+
iter.ch = 0;
|
23
|
+
iter.text = iter.cm.getLine(++iter.line);
|
24
|
+
return true;
|
25
|
+
}
|
26
|
+
function prevLine(iter) {
|
27
|
+
if (iter.line <= iter.cm.firstLine()) return;
|
28
|
+
iter.text = iter.cm.getLine(--iter.line);
|
29
|
+
iter.ch = iter.text.length;
|
30
|
+
return true;
|
31
|
+
}
|
32
|
+
|
33
|
+
function toTagEnd(iter) {
|
34
|
+
for (;;) {
|
35
|
+
var gt = iter.text.indexOf(">", iter.ch);
|
36
|
+
if (gt == -1) { if (nextLine(iter)) continue; else return; }
|
37
|
+
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
|
38
|
+
var lastSlash = iter.text.lastIndexOf("/", gt);
|
39
|
+
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
40
|
+
iter.ch = gt + 1;
|
41
|
+
return selfClose ? "selfClose" : "regular";
|
24
42
|
}
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
43
|
+
}
|
44
|
+
function toTagStart(iter) {
|
45
|
+
for (;;) {
|
46
|
+
var lt = iter.text.lastIndexOf("<", iter.ch - 1);
|
47
|
+
if (lt == -1) { if (prevLine(iter)) continue; else return; }
|
48
|
+
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
|
49
|
+
xmlTagStart.lastIndex = lt;
|
50
|
+
iter.ch = lt;
|
51
|
+
var match = xmlTagStart.exec(iter.text);
|
52
|
+
if (match && match.index == lt) return match;
|
33
53
|
}
|
54
|
+
}
|
34
55
|
|
35
|
-
|
56
|
+
function toNextTag(iter) {
|
36
57
|
for (;;) {
|
37
|
-
|
38
|
-
|
39
|
-
if (!
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
58
|
+
xmlTagStart.lastIndex = iter.ch;
|
59
|
+
var found = xmlTagStart.exec(iter.text);
|
60
|
+
if (!found) { if (nextLine(iter)) continue; else return; }
|
61
|
+
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
|
62
|
+
iter.ch = found.index + found[0].length;
|
63
|
+
return found;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
function toPrevTag(iter) {
|
67
|
+
for (;;) {
|
68
|
+
var gt = iter.text.lastIndexOf(">", iter.ch - 1);
|
69
|
+
if (gt == -1) { if (prevLine(iter)) continue; else return; }
|
70
|
+
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
|
71
|
+
var lastSlash = iter.text.lastIndexOf("/", gt);
|
72
|
+
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
73
|
+
iter.ch = gt + 1;
|
74
|
+
return selfClose ? "selfClose" : "regular";
|
44
75
|
}
|
76
|
+
}
|
45
77
|
|
78
|
+
function findMatchingClose(iter, tag) {
|
79
|
+
var stack = [];
|
46
80
|
for (;;) {
|
47
|
-
var next = toNextTag(), end,
|
48
|
-
if (!next || !(end = toTagEnd())) return;
|
81
|
+
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
|
82
|
+
if (!next || !(end = toTagEnd(iter))) return;
|
49
83
|
if (end == "selfClose") continue;
|
50
84
|
if (next[1]) { // closing tag
|
51
85
|
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
|
52
86
|
stack.length = i;
|
53
87
|
break;
|
54
88
|
}
|
55
|
-
if (!
|
56
|
-
|
57
|
-
|
89
|
+
if (i < 0 && (!tag || tag == next[2])) return {
|
90
|
+
tag: next[2],
|
91
|
+
from: Pos(startLine, startCh),
|
92
|
+
to: Pos(iter.line, iter.ch)
|
58
93
|
};
|
59
94
|
} else { // opening tag
|
60
95
|
stack.push(next[2]);
|
61
96
|
}
|
62
97
|
}
|
98
|
+
}
|
99
|
+
function findMatchingOpen(iter, tag) {
|
100
|
+
var stack = [];
|
101
|
+
for (;;) {
|
102
|
+
var prev = toPrevTag(iter);
|
103
|
+
if (!prev) return;
|
104
|
+
if (prev == "selfClose") { toTagStart(iter); continue; }
|
105
|
+
var endLine = iter.line, endCh = iter.ch;
|
106
|
+
var start = toTagStart(iter);
|
107
|
+
if (!start) return;
|
108
|
+
if (start[1]) { // closing tag
|
109
|
+
stack.push(start[2]);
|
110
|
+
} else { // opening tag
|
111
|
+
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
|
112
|
+
stack.length = i;
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
if (i < 0 && (!tag || tag == start[2])) return {
|
116
|
+
tag: start[2],
|
117
|
+
from: Pos(iter.line, iter.ch),
|
118
|
+
to: Pos(endLine, endCh)
|
119
|
+
};
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
CodeMirror.tagRangeFinder = function(cm, start) {
|
125
|
+
var iter = new Iter(cm, start.line, 0);
|
126
|
+
for (;;) {
|
127
|
+
var openTag = toNextTag(iter), end;
|
128
|
+
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
|
129
|
+
if (!openTag[1] && end != "selfClose") {
|
130
|
+
var start = Pos(iter.line, iter.ch);
|
131
|
+
var close = findMatchingClose(iter, openTag[2]);
|
132
|
+
return close && {from: start, to: close.from};
|
133
|
+
}
|
134
|
+
}
|
135
|
+
};
|
136
|
+
|
137
|
+
CodeMirror.findMatchingTag = function(cm, pos) {
|
138
|
+
var iter = new Iter(cm, pos.line, pos.ch);
|
139
|
+
var end = toTagEnd(iter), start = toTagStart(iter);
|
140
|
+
if (!end || end == "selfClose" || !start) return;
|
141
|
+
|
142
|
+
if (start[1]) { // closing tag
|
143
|
+
return findMatchingOpen(iter, start[2]);
|
144
|
+
} else { // opening tag
|
145
|
+
toTagEnd(iter);
|
146
|
+
return findMatchingClose(iter, start[2]);
|
147
|
+
}
|
148
|
+
};
|
149
|
+
|
150
|
+
CodeMirror.findEnclosingTag = function(cm, pos) {
|
151
|
+
var iter = new Iter(cm, pos.line, pos.ch);
|
152
|
+
for (;;) {
|
153
|
+
var open = findMatchingOpen(iter);
|
154
|
+
if (!open) break;
|
155
|
+
var forward = new Iter(cm, pos.line, pos.ch);
|
156
|
+
var close = findMatchingClose(forward, open.tag);
|
157
|
+
if (close) return {open: open, close: close};
|
158
|
+
}
|
63
159
|
};
|
64
160
|
})();
|