]>
Commit | Line | Data |
---|---|---|
06a3d686 BB |
1 | (function() { |
2 | var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; | |
3 | function findMatchingBracket(cm) { | |
4 | var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1; | |
5 | var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; | |
6 | if (!match) return null; | |
7 | var forward = match.charAt(1) == ">", d = forward ? 1 : -1; | |
8 | var style = cm.getTokenAt({line: cur.line, ch: pos + 1}).type; | |
9 | ||
10 | var stack = [line.text.charAt(pos)], re = /[(){}[\]]/; | |
11 | function scan(line, lineNo, start) { | |
12 | if (!line.text) return; | |
13 | var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1; | |
14 | if (start != null) pos = start + d; | |
15 | for (; pos != end; pos += d) { | |
16 | var ch = line.text.charAt(pos); | |
17 | if (re.test(ch) && cm.getTokenAt({line: lineNo, ch: pos + 1}).type == style) { | |
18 | var match = matching[ch]; | |
19 | if (match.charAt(1) == ">" == forward) stack.push(ch); | |
20 | else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false}; | |
21 | else if (!stack.length) return {pos: pos, match: true}; | |
22 | } | |
23 | } | |
24 | } | |
25 | for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) { | |
26 | if (i == cur.line) found = scan(line, i, pos); | |
27 | else found = scan(cm.getLineHandle(i), i); | |
28 | if (found) break; | |
29 | } | |
30 | return {from: {line: cur.line, ch: pos}, to: found && {line: i, ch: found.pos}, match: found && found.match}; | |
31 | } | |
32 | ||
33 | function matchBrackets(cm, autoclear) { | |
34 | var found = findMatchingBracket(cm); | |
35 | if (!found) return; | |
36 | var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; | |
37 | var one = cm.markText(found.from, {line: found.from.line, ch: found.from.ch + 1}, | |
38 | {className: style}); | |
39 | var two = found.to && cm.markText(found.to, {line: found.to.line, ch: found.to.ch + 1}, | |
40 | {className: style}); | |
41 | var clear = function() { | |
42 | cm.operation(function() { one.clear(); two && two.clear(); }); | |
43 | }; | |
44 | if (autoclear) setTimeout(clear, 800); | |
45 | else return clear; | |
46 | } | |
47 | ||
48 | var currentlyHighlighted = null; | |
49 | function doMatchBrackets(cm) { | |
50 | cm.operation(function() { | |
51 | if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} | |
52 | if (!cm.somethingSelected()) currentlyHighlighted = matchBrackets(cm, false); | |
53 | }); | |
54 | } | |
55 | ||
56 | CodeMirror.defineOption("matchBrackets", false, function(cm, val) { | |
57 | if (val) cm.on("cursorActivity", doMatchBrackets); | |
58 | else cm.off("cursorActivity", doMatchBrackets); | |
59 | }); | |
60 | ||
61 | CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); | |
62 | CodeMirror.defineExtension("findMatchingBracket", function(){return findMatchingBracket(this);}); | |
63 | })(); |