5
if (typeof exports == "object" && typeof module == "object")
6
mod(require("../../lib/codemirror"));
7
else if (typeof define == "function" && define.amd)
8
define(["../../lib/codemirror"], mod);
11
})(function(CodeMirror) {
13
pairs: "()[]{}''\"\"",
14
closeBefore: ")]}'\":;>",
19
var Pos = CodeMirror.Pos;
21
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
22
if (old && old != CodeMirror.Init) {
23
cm.removeKeyMap(keyMap);
24
cm.state.closeBrackets = null;
27
ensureBound(getOption(val, "pairs"))
28
cm.state.closeBrackets = val;
33
function getOption(conf, name) {
34
if (name == "pairs" && typeof conf == "string") return conf;
35
if (typeof conf == "object" && conf[name] != null) return conf[name];
36
return defaults[name];
39
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
40
function ensureBound(chars) {
41
for (var i = 0; i < chars.length; i++) {
42
var ch = chars.charAt(i), key = "'" + ch + "'"
43
if (!keyMap[key]) keyMap[key] = handler(ch)
46
ensureBound(defaults.pairs + "`")
48
function handler(ch) {
49
return function(cm) { return handleChar(cm, ch); };
52
function getConfig(cm) {
53
var deflt = cm.state.closeBrackets;
54
if (!deflt || deflt.override) return deflt;
55
var mode = cm.getModeAt(cm.getCursor());
56
return mode.closeBrackets || deflt;
59
function handleBackspace(cm) {
60
var conf = getConfig(cm);
61
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
63
var pairs = getOption(conf, "pairs");
64
var ranges = cm.listSelections();
65
for (var i = 0; i < ranges.length; i++) {
66
if (!ranges[i].empty()) return CodeMirror.Pass;
67
var around = charsAround(cm, ranges[i].head);
68
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
70
for (var i = ranges.length - 1; i >= 0; i--) {
71
var cur = ranges[i].head;
72
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
76
function handleEnter(cm) {
77
var conf = getConfig(cm);
78
var explode = conf && getOption(conf, "explode");
79
if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
81
var ranges = cm.listSelections();
82
for (var i = 0; i < ranges.length; i++) {
83
if (!ranges[i].empty()) return CodeMirror.Pass;
84
var around = charsAround(cm, ranges[i].head);
85
if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
87
cm.operation(function() {
88
var linesep = cm.lineSeparator() || "\n";
89
cm.replaceSelection(linesep + linesep, null);
91
ranges = cm.listSelections();
92
for (var i = 0; i < ranges.length; i++) {
93
var line = ranges[i].head.line;
94
cm.indentLine(line, null, true);
95
cm.indentLine(line + 1, null, true);
100
function moveSel(cm, dir) {
101
var newRanges = [], ranges = cm.listSelections(), primary = 0
102
for (var i = 0; i < ranges.length; i++) {
103
var range = ranges[i]
104
if (range.head == cm.getCursor()) primary = i
105
var pos = range.head.ch || dir > 0 ? {line: range.head.line, ch: range.head.ch + dir} : {line: range.head.line - 1}
106
newRanges.push({anchor: pos, head: pos})
108
cm.setSelections(newRanges, primary)
111
function contractSelection(sel) {
112
var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
113
return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
114
head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
117
function handleChar(cm, ch) {
118
var conf = getConfig(cm);
119
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
121
var pairs = getOption(conf, "pairs");
122
var pos = pairs.indexOf(ch);
123
if (pos == -1) return CodeMirror.Pass;
125
var closeBefore = getOption(conf,"closeBefore");
127
var triples = getOption(conf, "triples");
129
var identical = pairs.charAt(pos + 1) == ch;
130
var ranges = cm.listSelections();
131
var opening = pos % 2 == 0;
134
for (var i = 0; i < ranges.length; i++) {
135
var range = ranges[i], cur = range.head, curType;
136
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
137
if (opening && !range.empty()) {
138
curType = "surround";
139
} else if ((identical || !opening) && next == ch) {
140
if (identical && stringStartsAfter(cm, cur))
142
else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
143
curType = "skipThree";
146
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
147
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) {
148
if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass;
150
} else if (identical) {
151
var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)
152
if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both";
153
else return CodeMirror.Pass;
154
} else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) {
157
return CodeMirror.Pass;
159
if (!type) type = curType;
160
else if (type != curType) return CodeMirror.Pass;
163
var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
164
var right = pos % 2 ? ch : pairs.charAt(pos + 1);
165
cm.operation(function() {
166
if (type == "skip") {
168
} else if (type == "skipThree") {
170
} else if (type == "surround") {
171
var sels = cm.getSelections();
172
for (var i = 0; i < sels.length; i++)
173
sels[i] = left + sels[i] + right;
174
cm.replaceSelections(sels, "around");
175
sels = cm.listSelections().slice();
176
for (var i = 0; i < sels.length; i++)
177
sels[i] = contractSelection(sels[i]);
178
cm.setSelections(sels);
179
} else if (type == "both") {
180
cm.replaceSelection(left + right, null);
181
cm.triggerElectric(left + right);
183
} else if (type == "addFour") {
184
cm.replaceSelection(left + left + left + left, "before");
190
function charsAround(cm, pos) {
191
var str = cm.getRange(Pos(pos.line, pos.ch - 1),
192
Pos(pos.line, pos.ch + 1));
193
return str.length == 2 ? str : null;
196
function stringStartsAfter(cm, pos) {
197
var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
198
return /\bstring/.test(token.type) && token.start == pos.ch &&
199
(pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos)))