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
) {
15 var nonWS
= /[^\s\u00a0]/;
16 var Pos
= CodeMirror
.Pos
;
18 function firstNonWS(str
) {
19 var found
= str
.search(nonWS
);
20 return found
== -1 ? 0 : found
;
23 CodeMirror
.commands
.toggleComment = function(cm
) {
24 var minLine
= Infinity
, ranges
= cm
.listSelections(), mode
= null;
25 for (var i
= ranges
.length
- 1; i
>= 0; i
--) {
26 var from = ranges
[i
].from(), to
= ranges
[i
].to();
27 if (from.line
>= minLine
) continue;
28 if (to
.line
>= minLine
) to
= Pos(minLine
, 0);
31 if (cm
.uncomment(from, to
)) mode
= "un";
32 else { cm
.lineComment(from, to
); mode
= "line"; }
33 } else if (mode
== "un") {
34 cm
.uncomment(from, to
);
36 cm
.lineComment(from, to
);
41 CodeMirror
.defineExtension("lineComment", function(from, to
, options
) {
42 if (!options
) options
= noOptions
;
43 var self
= this, mode
= self
.getModeAt(from);
44 var commentString
= options
.lineComment
|| mode
.lineComment
;
46 if (options
.blockCommentStart
|| mode
.blockCommentStart
) {
47 options
.fullLines
= true;
48 self
.blockComment(from, to
, options
);
52 var firstLine
= self
.getLine(from.line
);
53 if (firstLine
== null) return;
54 var end
= Math
.min(to
.ch
!= 0 || to
.line
== from.line
? to
.line
+ 1 : to
.line
, self
.lastLine() + 1);
55 var pad
= options
.padding
== null ? " " : options
.padding
;
56 var blankLines
= options
.commentBlankLines
|| from.line
== to
.line
;
58 self
.operation(function() {
60 var baseString
= firstLine
.slice(0, firstNonWS(firstLine
));
61 for (var i
= from.line
; i
< end
; ++i
) {
62 var line
= self
.getLine(i
), cut
= baseString
.length
;
63 if (!blankLines
&& !nonWS
.test(line
)) continue;
64 if (line
.slice(0, cut
) != baseString
) cut
= firstNonWS(line
);
65 self
.replaceRange(baseString
+ commentString
+ pad
, Pos(i
, 0), Pos(i
, cut
));
68 for (var i
= from.line
; i
< end
; ++i
) {
69 if (blankLines
|| nonWS
.test(self
.getLine(i
)))
70 self
.replaceRange(commentString
+ pad
, Pos(i
, 0));
76 CodeMirror
.defineExtension("blockComment", function(from, to
, options
) {
77 if (!options
) options
= noOptions
;
78 var self
= this, mode
= self
.getModeAt(from);
79 var startString
= options
.blockCommentStart
|| mode
.blockCommentStart
;
80 var endString
= options
.blockCommentEnd
|| mode
.blockCommentEnd
;
81 if (!startString
|| !endString
) {
82 if ((options
.lineComment
|| mode
.lineComment
) && options
.fullLines
!= false)
83 self
.lineComment(from, to
, options
);
87 var end
= Math
.min(to
.line
, self
.lastLine());
88 if (end
!= from.line
&& to
.ch
== 0 && nonWS
.test(self
.getLine(end
))) --end
;
90 var pad
= options
.padding
== null ? " " : options
.padding
;
91 if (from.line
> end
) return;
93 self
.operation(function() {
94 if (options
.fullLines
!= false) {
95 var lastLineHasText
= nonWS
.test(self
.getLine(end
));
96 self
.replaceRange(pad
+ endString
, Pos(end
));
97 self
.replaceRange(startString
+ pad
, Pos(from.line
, 0));
98 var lead
= options
.blockCommentLead
|| mode
.blockCommentLead
;
99 if (lead
!= null) for (var i
= from.line
+ 1; i
<= end
; ++i
)
100 if (i
!= end
|| lastLineHasText
)
101 self
.replaceRange(lead
+ pad
, Pos(i
, 0));
103 self
.replaceRange(endString
, to
);
104 self
.replaceRange(startString
, from);
109 CodeMirror
.defineExtension("uncomment", function(from, to
, options
) {
110 if (!options
) options
= noOptions
;
111 var self
= this, mode
= self
.getModeAt(from);
112 var end
= Math
.min(to
.ch
!= 0 || to
.line
== from.line
? to
.line
: to
.line
- 1, self
.lastLine()), start
= Math
.min(from.line
, end
);
114 // Try finding line comments
115 var lineString
= options
.lineComment
|| mode
.lineComment
, lines
= [];
116 var pad
= options
.padding
== null ? " " : options
.padding
, didSomething
;
118 if (!lineString
) break lineComment
;
119 for (var i
= start
; i
<= end
; ++i
) {
120 var line
= self
.getLine(i
);
121 var found
= line
.indexOf(lineString
);
122 if (found
> -1 && !/comment/.test(self
.getTokenTypeAt(Pos(i
, found
+ 1)))) found
= -1;
123 if (found
== -1 && (i
!= end
|| i
== start
) && nonWS
.test(line
)) break lineComment
;
124 if (found
> -1 && nonWS
.test(line
.slice(0, found
))) break lineComment
;
127 self
.operation(function() {
128 for (var i
= start
; i
<= end
; ++i
) {
129 var line
= lines
[i
- start
];
130 var pos
= line
.indexOf(lineString
), endPos
= pos
+ lineString
.length
;
131 if (pos
< 0) continue;
132 if (line
.slice(endPos
, endPos
+ pad
.length
) == pad
) endPos
+= pad
.length
;
134 self
.replaceRange("", Pos(i
, pos
), Pos(i
, endPos
));
137 if (didSomething
) return true;
140 // Try block comments
141 var startString
= options
.blockCommentStart
|| mode
.blockCommentStart
;
142 var endString
= options
.blockCommentEnd
|| mode
.blockCommentEnd
;
143 if (!startString
|| !endString
) return false;
144 var lead
= options
.blockCommentLead
|| mode
.blockCommentLead
;
145 var startLine
= self
.getLine(start
), endLine
= end
== start
? startLine
: self
.getLine(end
);
146 var open
= startLine
.indexOf(startString
), close
= endLine
.lastIndexOf(endString
);
147 if (close
== -1 && start
!= end
) {
148 endLine
= self
.getLine(--end
);
149 close
= endLine
.lastIndexOf(endString
);
151 if (open
== -1 || close
== -1 ||
152 !/comment/.test(self
.getTokenTypeAt(Pos(start
, open
+ 1))) ||
153 !/comment/.test(self
.getTokenTypeAt(Pos(end
, close
+ 1))))
156 // Avoid killing block comments completely outside the selection.
157 // Positions of the last startString before the start of the selection, and the first endString after it.
158 var lastStart
= startLine
.lastIndexOf(startString
, from.ch
);
159 var firstEnd
= lastStart
== -1 ? -1 : startLine
.slice(0, from.ch
).indexOf(endString
, lastStart
+ startString
.length
);
160 if (lastStart
!= -1 && firstEnd
!= -1 && firstEnd
+ endString
.length
!= from.ch
) return false;
161 // Positions of the first endString after the end of the selection, and the last startString before it.
162 firstEnd
= endLine
.indexOf(endString
, to
.ch
);
163 var almostLastStart
= endLine
.slice(to
.ch
).lastIndexOf(startString
, firstEnd
- to
.ch
);
164 lastStart
= (firstEnd
== -1 || almostLastStart
== -1) ? -1 : to
.ch
+ almostLastStart
;
165 if (firstEnd
!= -1 && lastStart
!= -1 && lastStart
!= to
.ch
) return false;
167 self
.operation(function() {
168 self
.replaceRange("", Pos(end
, close
- (pad
&& endLine
.slice(close
- pad
.length
, close
) == pad
? pad
.length
: 0)),
169 Pos(end
, close
+ endString
.length
));
170 var openEnd
= open
+ startString
.length
;
171 if (pad
&& startLine
.slice(openEnd
, openEnd
+ pad
.length
) == pad
) openEnd
+= pad
.length
;
172 self
.replaceRange("", Pos(start
, open
), Pos(start
, openEnd
));
173 if (lead
) for (var i
= start
+ 1; i
<= end
; ++i
) {
174 var line
= self
.getLine(i
), found
= line
.indexOf(lead
);
175 if (found
== -1 || nonWS
.test(line
.slice(0, found
))) continue;
176 var foundEnd
= found
+ lead
.length
;
177 if (pad
&& line
.slice(foundEnd
, foundEnd
+ pad
.length
) == pad
) foundEnd
+= pad
.length
;
178 self
.replaceRange("", Pos(i
, found
), Pos(i
, foundEnd
));