annotate .cms/lib/codemirror/addon/edit/closebrackets.js @ 1:1d486627aa1e draft default tip

24.10
author Coffee CMS <info@coffee-cms.ru>
date Sat, 12 Oct 2024 02:51:39 +0000
parents 78edf6b517a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
2 // Distributed under an MIT license: https://codemirror.net/5/LICENSE
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
3
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
4 (function(mod) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
6 mod(require("../../lib/codemirror"));
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
7 else if (typeof define == "function" && define.amd) // AMD
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
8 define(["../../lib/codemirror"], mod);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
9 else // Plain browser env
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
10 mod(CodeMirror);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
11 })(function(CodeMirror) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
12 var defaults = {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
13 pairs: "()[]{}''\"\"",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
14 closeBefore: ")]}'\":;>",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
15 triples: "",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
16 explode: "[]{}"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
17 };
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
18
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
19 var Pos = CodeMirror.Pos;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
20
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
21 CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
22 if (old && old != CodeMirror.Init) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
23 cm.removeKeyMap(keyMap);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
24 cm.state.closeBrackets = null;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
25 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
26 if (val) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
27 ensureBound(getOption(val, "pairs"))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
28 cm.state.closeBrackets = val;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
29 cm.addKeyMap(keyMap);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
30 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
31 });
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
32
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
33 function getOption(conf, name) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
34 if (name == "pairs" && typeof conf == "string") return conf;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
35 if (typeof conf == "object" && conf[name] != null) return conf[name];
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
36 return defaults[name];
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
37 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
38
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
39 var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
40 function ensureBound(chars) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
41 for (var i = 0; i < chars.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
42 var ch = chars.charAt(i), key = "'" + ch + "'"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
43 if (!keyMap[key]) keyMap[key] = handler(ch)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
44 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
45 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
46 ensureBound(defaults.pairs + "`")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
47
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
48 function handler(ch) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
49 return function(cm) { return handleChar(cm, ch); };
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
50 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
51
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
52 function getConfig(cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
53 var deflt = cm.state.closeBrackets;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
54 if (!deflt || deflt.override) return deflt;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
55 var mode = cm.getModeAt(cm.getCursor());
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
56 return mode.closeBrackets || deflt;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
57 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
58
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
59 function handleBackspace(cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
60 var conf = getConfig(cm);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
61 if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
62
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
63 var pairs = getOption(conf, "pairs");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
64 var ranges = cm.listSelections();
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
65 for (var i = 0; i < ranges.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
66 if (!ranges[i].empty()) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
67 var around = charsAround(cm, ranges[i].head);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
68 if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
69 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
70 for (var i = ranges.length - 1; i >= 0; i--) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
71 var cur = ranges[i].head;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
72 cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
73 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
74 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
75
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
76 function handleEnter(cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
77 var conf = getConfig(cm);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
78 var explode = conf && getOption(conf, "explode");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
79 if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
80
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
81 var ranges = cm.listSelections();
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
82 for (var i = 0; i < ranges.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
83 if (!ranges[i].empty()) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
84 var around = charsAround(cm, ranges[i].head);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
85 if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
86 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
87 cm.operation(function() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
88 var linesep = cm.lineSeparator() || "\n";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
89 cm.replaceSelection(linesep + linesep, null);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
90 moveSel(cm, -1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
91 ranges = cm.listSelections();
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
92 for (var i = 0; i < ranges.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
93 var line = ranges[i].head.line;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
94 cm.indentLine(line, null, true);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
95 cm.indentLine(line + 1, null, true);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
96 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
97 });
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
98 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
99
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
100 function moveSel(cm, dir) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
101 var newRanges = [], ranges = cm.listSelections(), primary = 0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
102 for (var i = 0; i < ranges.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
103 var range = ranges[i]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
104 if (range.head == cm.getCursor()) primary = i
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
105 var pos = range.head.ch || dir > 0 ? {line: range.head.line, ch: range.head.ch + dir} : {line: range.head.line - 1}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
106 newRanges.push({anchor: pos, head: pos})
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
107 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
108 cm.setSelections(newRanges, primary)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
109 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
110
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
111 function contractSelection(sel) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
112 var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
113 return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
114 head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
115 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
116
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
117 function handleChar(cm, ch) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
118 var conf = getConfig(cm);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
119 if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
120
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
121 var pairs = getOption(conf, "pairs");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
122 var pos = pairs.indexOf(ch);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
123 if (pos == -1) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
124
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
125 var closeBefore = getOption(conf,"closeBefore");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
126
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
127 var triples = getOption(conf, "triples");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
128
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
129 var identical = pairs.charAt(pos + 1) == ch;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
130 var ranges = cm.listSelections();
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
131 var opening = pos % 2 == 0;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
132
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
133 var type;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
134 for (var i = 0; i < ranges.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
135 var range = ranges[i], cur = range.head, curType;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
136 var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
137 if (opening && !range.empty()) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
138 curType = "surround";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
139 } else if ((identical || !opening) && next == ch) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
140 if (identical && stringStartsAfter(cm, cur))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
141 curType = "both";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
142 else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
143 curType = "skipThree";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
144 else
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
145 curType = "skip";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
146 } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
147 cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
148 if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
149 curType = "addFour";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
150 } else if (identical) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
151 var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
152 if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
153 else return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
154 } else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
155 curType = "both";
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
156 } else {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
157 return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
158 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
159 if (!type) type = curType;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
160 else if (type != curType) return CodeMirror.Pass;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
161 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
162
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
163 var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
164 var right = pos % 2 ? ch : pairs.charAt(pos + 1);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
165 cm.operation(function() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
166 if (type == "skip") {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
167 moveSel(cm, 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
168 } else if (type == "skipThree") {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
169 moveSel(cm, 3)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
170 } else if (type == "surround") {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
171 var sels = cm.getSelections();
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
172 for (var i = 0; i < sels.length; i++)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
173 sels[i] = left + sels[i] + right;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
174 cm.replaceSelections(sels, "around");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
175 sels = cm.listSelections().slice();
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
176 for (var i = 0; i < sels.length; i++)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
177 sels[i] = contractSelection(sels[i]);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
178 cm.setSelections(sels);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
179 } else if (type == "both") {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
180 cm.replaceSelection(left + right, null);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
181 cm.triggerElectric(left + right);
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
182 moveSel(cm, -1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
183 } else if (type == "addFour") {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
184 cm.replaceSelection(left + left + left + left, "before");
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
185 moveSel(cm, 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
186 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
187 });
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
188 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
189
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
190 function charsAround(cm, pos) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
191 var str = cm.getRange(Pos(pos.line, pos.ch - 1),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
192 Pos(pos.line, pos.ch + 1));
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
193 return str.length == 2 ? str : null;
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
194 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
195
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
196 function stringStartsAfter(cm, pos) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
197 var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
198 return /\bstring/.test(token.type) && token.start == pos.ch &&
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
199 (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos)))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
200 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
201 });