1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
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
11 })(function(CodeMirror
) {
12 var DEFAULT_BRACKETS
= "()[]{}''\"\"";
13 var DEFAULT_EXPLODE_ON_ENTER
= "[]{}";
14 var SPACE_CHAR_REGEX
= /\s/;
16 var Pos
= CodeMirror
.Pos
;
18 CodeMirror
.defineOption("autoCloseBrackets", false, function(cm
, val
, old
) {
19 if (old
!= CodeMirror
.Init
&& old
)
20 cm
.removeKeyMap("autoCloseBrackets");
22 var pairs
= DEFAULT_BRACKETS
, explode
= DEFAULT_EXPLODE_ON_ENTER
;
23 if (typeof val
== "string") pairs
= val
;
24 else if (typeof val
== "object") {
25 if (val
.pairs
!= null) pairs
= val
.pairs
;
26 if (val
.explode
!= null) explode
= val
.explode
;
28 var map
= buildKeymap(pairs
);
29 if (explode
) map
.Enter
= buildExplodeHandler(explode
);
33 function charsAround(cm
, pos
) {
34 var str
= cm
.getRange(Pos(pos
.line
, pos
.ch
- 1),
35 Pos(pos
.line
, pos
.ch
+ 1));
36 return str
.length
== 2 ? str
: null;
39 function buildKeymap(pairs
) {
41 name
: "autoCloseBrackets",
42 Backspace: function(cm
) {
43 if (cm
.getOption("disableInput")) return CodeMirror
.Pass
;
44 var ranges
= cm
.listSelections();
45 for (var i
= 0; i
< ranges
.length
; i
++) {
46 if (!ranges
[i
].empty()) return CodeMirror
.Pass
;
47 var around
= charsAround(cm
, ranges
[i
].head
);
48 if (!around
|| pairs
.indexOf(around
) % 2 != 0) return CodeMirror
.Pass
;
50 for (var i
= ranges
.length
- 1; i
>= 0; i
--) {
51 var cur
= ranges
[i
].head
;
52 cm
.replaceRange("", Pos(cur
.line
, cur
.ch
- 1), Pos(cur
.line
, cur
.ch
+ 1));
56 var closingBrackets
= "";
57 for (var i
= 0; i
< pairs
.length
; i
+= 2) (function(left
, right
) {
58 if (left
!= right
) closingBrackets
+= right
;
59 map
["'" + left
+ "'"] = function(cm
) {
60 if (cm
.getOption("disableInput")) return CodeMirror
.Pass
;
61 var ranges
= cm
.listSelections(), type
, next
;
62 for (var i
= 0; i
< ranges
.length
; i
++) {
63 var range
= ranges
[i
], cur
= range
.head
, curType
;
64 if (left
== "'" && cm
.getTokenTypeAt(cur
) == "comment")
65 return CodeMirror
.Pass
;
66 var next
= cm
.getRange(cur
, Pos(cur
.line
, cur
.ch
+ 1));
69 else if (left
== right
&& next
== right
) {
70 if (cm
.getRange(cur
, Pos(cur
.line
, cur
.ch
+ 3)) == left
+ left
+ left
)
71 curType
= "skipThree";
74 } else if (left
== right
&& cur
.ch
> 1 &&
75 cm
.getRange(Pos(cur
.line
, cur
.ch
- 2), cur
) == left
+ left
&&
76 (cur
.ch
<= 2 || cm
.getRange(Pos(cur
.line
, cur
.ch
- 3), Pos(cur
.line
, cur
.ch
- 2)) != left
))
78 else if (left
== right
&& CodeMirror
.isWordChar(next
))
79 return CodeMirror
.Pass
;
80 else if (cm
.getLine(cur
.line
).length
== cur
.ch
|| closingBrackets
.indexOf(next
) >= 0 || SPACE_CHAR_REGEX
.test(next
))
83 return CodeMirror
.Pass
;
84 if (!type
) type
= curType
;
85 else if (type
!= curType
) return CodeMirror
.Pass
;
88 cm
.operation(function() {
90 cm
.execCommand("goCharRight");
91 } else if (type
== "skipThree") {
92 for (var i
= 0; i
< 3; i
++)
93 cm
.execCommand("goCharRight");
94 } else if (type
== "surround") {
95 var sels
= cm
.getSelections();
96 for (var i
= 0; i
< sels
.length
; i
++)
97 sels
[i
] = left
+ sels
[i
] + right
;
98 cm
.replaceSelections(sels
, "around");
99 } else if (type
== "both") {
100 cm
.replaceSelection(left
+ right
, null);
101 cm
.execCommand("goCharLeft");
102 } else if (type
== "addFour") {
103 cm
.replaceSelection(left
+ left
+ left
+ left
, "before");
104 cm
.execCommand("goCharRight");
108 if (left
!= right
) map
["'" + right
+ "'"] = function(cm
) {
109 var ranges
= cm
.listSelections();
110 for (var i
= 0; i
< ranges
.length
; i
++) {
111 var range
= ranges
[i
];
112 if (!range
.empty() ||
113 cm
.getRange(range
.head
, Pos(range
.head
.line
, range
.head
.ch
+ 1)) != right
)
114 return CodeMirror
.Pass
;
116 cm
.execCommand("goCharRight");
118 })(pairs
.charAt(i
), pairs
.charAt(i
+ 1));
122 function buildExplodeHandler(pairs
) {
123 return function(cm
) {
124 if (cm
.getOption("disableInput")) return CodeMirror
.Pass
;
125 var ranges
= cm
.listSelections();
126 for (var i
= 0; i
< ranges
.length
; i
++) {
127 if (!ranges
[i
].empty()) return CodeMirror
.Pass
;
128 var around
= charsAround(cm
, ranges
[i
].head
);
129 if (!around
|| pairs
.indexOf(around
) % 2 != 0) return CodeMirror
.Pass
;
131 cm
.operation(function() {
132 cm
.replaceSelection("\n\n", null);
133 cm
.execCommand("goCharLeft");
134 ranges
= cm
.listSelections();
135 for (var i
= 0; i
< ranges
.length
; i
++) {
136 var line
= ranges
[i
].head
.line
;
137 cm
.indentLine(line
, null, true);
138 cm
.indentLine(line
+ 1, null, true);