0
|
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
2 // Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
|
3
|
|
4 (function(mod) {
|
|
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
6 mod(require("../../lib/codemirror"));
|
|
7 else if (typeof define == "function" && define.amd) // AMD
|
|
8 define(["../../lib/codemirror"], mod);
|
|
9 else // Plain browser env
|
|
10 mod(CodeMirror);
|
|
11 })(function(CodeMirror) {
|
|
12 "use strict";
|
|
13
|
|
14 function bracketFolding(pairs) {
|
|
15 return function(cm, start) {
|
|
16 var line = start.line, lineText = cm.getLine(line);
|
|
17
|
|
18 function findOpening(pair) {
|
|
19 var tokenType;
|
|
20 for (var at = start.ch, pass = 0;;) {
|
|
21 var found = at <= 0 ? -1 : lineText.lastIndexOf(pair[0], at - 1);
|
|
22 if (found == -1) {
|
|
23 if (pass == 1) break;
|
|
24 pass = 1;
|
|
25 at = lineText.length;
|
|
26 continue;
|
|
27 }
|
|
28 if (pass == 1 && found < start.ch) break;
|
|
29 tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
|
|
30 if (!/^(comment|string)/.test(tokenType)) return {ch: found + 1, tokenType: tokenType, pair: pair};
|
|
31 at = found - 1;
|
|
32 }
|
|
33 }
|
|
34
|
|
35 function findRange(found) {
|
|
36 var count = 1, lastLine = cm.lastLine(), end, startCh = found.ch, endCh
|
|
37 outer: for (var i = line; i <= lastLine; ++i) {
|
|
38 var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
|
39 for (;;) {
|
|
40 var nextOpen = text.indexOf(found.pair[0], pos), nextClose = text.indexOf(found.pair[1], pos);
|
|
41 if (nextOpen < 0) nextOpen = text.length;
|
|
42 if (nextClose < 0) nextClose = text.length;
|
|
43 pos = Math.min(nextOpen, nextClose);
|
|
44 if (pos == text.length) break;
|
|
45 if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == found.tokenType) {
|
|
46 if (pos == nextOpen) ++count;
|
|
47 else if (!--count) { end = i; endCh = pos; break outer; }
|
|
48 }
|
|
49 ++pos;
|
|
50 }
|
|
51 }
|
|
52
|
|
53 if (end == null || line == end) return null
|
|
54 return {from: CodeMirror.Pos(line, startCh),
|
|
55 to: CodeMirror.Pos(end, endCh)};
|
|
56 }
|
|
57
|
|
58 var found = []
|
|
59 for (var i = 0; i < pairs.length; i++) {
|
|
60 var open = findOpening(pairs[i])
|
|
61 if (open) found.push(open)
|
|
62 }
|
|
63 found.sort(function(a, b) { return a.ch - b.ch })
|
|
64 for (var i = 0; i < found.length; i++) {
|
|
65 var range = findRange(found[i])
|
|
66 if (range) return range
|
|
67 }
|
|
68 return null
|
|
69 }
|
|
70 }
|
|
71
|
|
72 CodeMirror.registerHelper("fold", "brace", bracketFolding([["{", "}"], ["[", "]"]]));
|
|
73
|
|
74 CodeMirror.registerHelper("fold", "brace-paren", bracketFolding([["{", "}"], ["[", "]"], ["(", ")"]]));
|
|
75
|
|
76 CodeMirror.registerHelper("fold", "import", function(cm, start) {
|
|
77 function hasImport(line) {
|
|
78 if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
|
79 var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
|
80 if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
|
81 if (start.type != "keyword" || start.string != "import") return null;
|
|
82 // Now find closing semicolon, return its position
|
|
83 for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
|
|
84 var text = cm.getLine(i), semi = text.indexOf(";");
|
|
85 if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
|
|
86 }
|
|
87 }
|
|
88
|
|
89 var startLine = start.line, has = hasImport(startLine), prev;
|
|
90 if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
|
|
91 return null;
|
|
92 for (var end = has.end;;) {
|
|
93 var next = hasImport(end.line + 1);
|
|
94 if (next == null) break;
|
|
95 end = next.end;
|
|
96 }
|
|
97 return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
|
|
98 });
|
|
99
|
|
100 CodeMirror.registerHelper("fold", "include", function(cm, start) {
|
|
101 function hasInclude(line) {
|
|
102 if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
|
103 var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
|
104 if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
|
105 if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
|
|
106 }
|
|
107
|
|
108 var startLine = start.line, has = hasInclude(startLine);
|
|
109 if (has == null || hasInclude(startLine - 1) != null) return null;
|
|
110 for (var end = startLine;;) {
|
|
111 var next = hasInclude(end + 1);
|
|
112 if (next == null) break;
|
|
113 ++end;
|
|
114 }
|
|
115 return {from: CodeMirror.Pos(startLine, has + 1),
|
|
116 to: cm.clipPos(CodeMirror.Pos(end))};
|
|
117 });
|
|
118
|
|
119 });
|