1 " ============================================================================
2 " File: NERD_commenter.vim
3 " Description: vim global plugin that provides easy code commenting
4 " Maintainer: Martin Grenfell <martin_grenfell at msn dot com>
6 " Last Change: 30th March, 2008
7 " License: This program is free software. It comes without any warranty,
8 " to the extent permitted by applicable law. You can redistribute
9 " it and/or modify it under the terms of the Do What The Fuck You
10 " Want To Public License, Version 2, as published by Sam Hocevar.
11 " See http://sam.zoy.org/wtfpl/COPYING for more details.
13 " ============================================================================
15 " Section: script init stuff {{{1
16 if exists("loaded_nerd_comments")
20 echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
23 let loaded_nerd_comments = 1
25 " Function: s:InitVariable() function {{{2
26 " This function is used to initialise a given variable to a given value. The
27 " variable is only initialised if it does not exist prior
30 " -var: the name of the var to be initialised
31 " -value: the value to initialise var to
34 " 1 if the var is set, 0 otherwise
35 function s:InitVariable(var, value)
37 exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
43 " Section: space string init{{{2
44 " When putting spaces after the left delim and before the right we use
45 " s:spaceStr for the space char. This way we can make it add anything after
46 " the left and before the right by modifying this variable
48 let s:lenSpaceStr = strlen(s:spaceStr)
50 " Section: variable init calls {{{2
51 call s:InitVariable("g:NERDAllowAnyVisualDelims", 1)
52 call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0)
53 call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0)
54 call s:InitVariable("g:NERDCompactSexyComs", 0)
55 call s:InitVariable("g:NERDCreateDefaultMappings", 1)
56 call s:InitVariable("g:NERDDefaultNesting", 1)
57 call s:InitVariable("g:NERDMenuMode", 3)
58 call s:InitVariable("g:NERDLPlace", "[>")
59 call s:InitVariable("g:NERDUsePlaceHolders", 1)
60 call s:InitVariable("g:NERDRemoveAltComs", 1)
61 call s:InitVariable("g:NERDRemoveExtraSpaces", 1)
62 call s:InitVariable("g:NERDRPlace", "<]")
63 call s:InitVariable("g:NERDSpaceDelims", 0)
64 call s:InitVariable("g:NERDDelimiterRequests", 1)
68 let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
70 " Section: Comment mapping functions, autocommands and commands {{{1
71 " ============================================================================
72 " Section: Comment enabler autocommands {{{2
73 " ============================================================================
75 augroup commentEnablers
77 "if the user enters a buffer or reads a buffer then we gotta set up
78 "the comment delimiters for that new filetype
79 autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0)
81 "if the filetype of a buffer changes, force the script to reset the
82 "delims for the buffer
83 autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1)
87 " Function: s:SetUpForNewFiletype(filetype) function {{{2
88 " This function is responsible for setting up buffer scoped variables for the
91 " These variables include the comment delimiters for the given filetype and calls
92 " MapDelimiters or MapDelimitersWithAlternative passing in these delimiters.
95 " -filetype: the filetype to set delimiters for
96 " -forceReset: 1 if the delimiters should be reset if they have already be
97 " set for this buffer.
99 function s:SetUpForNewFiletype(filetype, forceReset)
100 "if we have already set the delimiters for this buffer then dont go thru
102 if !a:forceReset && exists("b:NERDLeft") && b:NERDLeft != ''
106 let b:NERDSexyComMarker = ''
108 "check the filetype against all known filetypes to see if we have
109 "hardcoded the comment delimiters to use
111 call s:MapDelimiters('', '')
112 elseif a:filetype ==? "aap"
113 call s:MapDelimiters('#', '')
114 elseif a:filetype ==? "abc"
115 call s:MapDelimiters('%', '')
116 elseif a:filetype ==? "acedb"
117 call s:MapDelimitersWithAlternative('//','', '/*','*/')
118 elseif a:filetype ==? "actionscript"
119 call s:MapDelimitersWithAlternative('//','', '/*','*/')
120 elseif a:filetype ==? "ada"
121 call s:MapDelimitersWithAlternative('--','', '-- ', '')
122 elseif a:filetype ==? "ahdl"
123 call s:MapDelimiters('--', '')
124 elseif a:filetype ==? "ahk"
125 call s:MapDelimitersWithAlternative(';', '', '/*', '*/')
126 elseif a:filetype ==? "amiga"
127 call s:MapDelimiters(';', '')
128 elseif a:filetype ==? "aml"
129 call s:MapDelimiters('/*', '')
130 elseif a:filetype ==? "ampl"
131 call s:MapDelimiters('#', '')
132 elseif a:filetype ==? "apache"
133 call s:MapDelimiters('#', '')
134 elseif a:filetype ==? "apachestyle"
135 call s:MapDelimiters('#', '')
136 elseif a:filetype ==? "asciidoc"
137 call s:MapDelimiters('//', '')
138 elseif a:filetype ==? "applescript"
139 call s:MapDelimitersWithAlternative('--', '', '(*', '*)')
140 elseif a:filetype ==? "asm68k"
141 call s:MapDelimiters(';', '')
142 elseif a:filetype ==? "asm"
143 call s:MapDelimitersWithAlternative(';', '', '#', '')
144 elseif a:filetype ==? "asn"
145 call s:MapDelimiters('--', '')
146 elseif a:filetype ==? "aspvbs"
147 call s:MapDelimiters('''', '')
148 elseif a:filetype ==? "asterisk"
149 call s:MapDelimiters(';', '')
150 elseif a:filetype ==? "asy"
151 call s:MapDelimiters('//', '')
152 elseif a:filetype ==? "atlas"
153 call s:MapDelimiters('C','$')
154 elseif a:filetype ==? "autohotkey"
155 call s:MapDelimiters(';','')
156 elseif a:filetype ==? "autoit"
157 call s:MapDelimiters(';','')
158 elseif a:filetype ==? "ave"
159 call s:MapDelimiters("'",'')
160 elseif a:filetype ==? "awk"
161 call s:MapDelimiters('#','')
162 elseif a:filetype ==? "basic"
163 call s:MapDelimitersWithAlternative("'",'', 'REM ', '')
164 elseif a:filetype ==? "bbx"
165 call s:MapDelimiters('%', '')
166 elseif a:filetype ==? "bc"
167 call s:MapDelimiters('#', '')
168 elseif a:filetype ==? "bib"
169 call s:MapDelimiters('%','')
170 elseif a:filetype ==? "bindzone"
171 call s:MapDelimiters(';', '')
172 elseif a:filetype ==? "bst"
173 call s:MapDelimiters('%', '')
174 elseif a:filetype ==? "btm"
175 call s:MapDelimiters('::', '')
176 elseif a:filetype ==? "caos"
177 call s:MapDelimiters('*', '')
178 elseif a:filetype ==? "calibre"
179 call s:MapDelimiters('//','')
180 elseif a:filetype ==? "catalog"
181 call s:MapDelimiters('--','--')
182 elseif a:filetype ==? "c"
183 call s:MapDelimitersWithAlternative('/*','*/', '//', '')
184 elseif a:filetype ==? "cfg"
185 call s:MapDelimiters('#', '')
186 elseif a:filetype ==? "cg"
187 call s:MapDelimitersWithAlternative('//','', '/*','*/')
188 elseif a:filetype ==? "ch"
189 call s:MapDelimitersWithAlternative('//','', '/*','*/')
190 elseif a:filetype ==? "cl"
191 call s:MapDelimiters('#', '')
192 elseif a:filetype ==? "clean"
193 call s:MapDelimitersWithAlternative('//','', '/*','*/')
194 elseif a:filetype ==? "clipper"
195 call s:MapDelimitersWithAlternative('//','', '/*','*/')
196 elseif a:filetype ==? "clojure"
197 call s:MapDelimiters(';', '')
198 elseif a:filetype ==? "cmake"
199 call s:MapDelimiters('#','')
200 elseif a:filetype ==? "conkyrc"
201 call s:MapDelimiters('#', '')
202 elseif a:filetype ==? "cpp"
203 call s:MapDelimitersWithAlternative('//','', '/*','*/')
204 elseif a:filetype ==? "crontab"
205 call s:MapDelimiters('#', '')
206 elseif a:filetype ==? "cs"
207 call s:MapDelimitersWithAlternative('//','', '/*','*/')
208 elseif a:filetype ==? "csp"
209 call s:MapDelimiters('--', '')
210 elseif a:filetype ==? "cterm"
211 call s:MapDelimiters('*', '')
212 elseif a:filetype ==? "cucumber"
213 call s:MapDelimiters('#','')
214 elseif a:filetype ==? "cvs"
215 call s:MapDelimiters('CVS:','')
216 elseif a:filetype ==? "d"
217 call s:MapDelimitersWithAlternative('//','', '/*','*/')
218 elseif a:filetype ==? "dcl"
219 call s:MapDelimiters('$!', '')
220 elseif a:filetype ==? "dakota"
221 call s:MapDelimiters('#', '')
222 elseif a:filetype ==? "debcontrol"
223 call s:MapDelimiters('#', '')
224 elseif a:filetype ==? "debsources"
225 call s:MapDelimiters('#', '')
226 elseif a:filetype ==? "def"
227 call s:MapDelimiters(';', '')
228 elseif a:filetype ==? "desktop"
229 call s:MapDelimiters('#', '')
230 elseif a:filetype ==? "dhcpd"
231 call s:MapDelimiters('#', '')
232 elseif a:filetype ==? "diff"
233 call s:MapDelimiters('#', '')
234 elseif a:filetype ==? "django"
235 call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
236 elseif a:filetype ==? "docbk"
237 call s:MapDelimiters('<!--', '-->')
238 elseif a:filetype ==? "dns"
239 call s:MapDelimiters(';', '')
240 elseif a:filetype ==? "dosbatch"
241 call s:MapDelimitersWithAlternative('REM ','', '::', '')
242 elseif a:filetype ==? "dosini"
243 call s:MapDelimiters(';', '')
244 elseif a:filetype ==? "dot"
245 call s:MapDelimitersWithAlternative('//','', '/*','*/')
246 elseif a:filetype ==? "dracula"
247 call s:MapDelimiters(';', '')
248 elseif a:filetype ==? "dsl"
249 call s:MapDelimiters(';', '')
250 elseif a:filetype ==? "dtml"
251 call s:MapDelimiters('<dtml-comment>','</dtml-comment>')
252 elseif a:filetype ==? "dylan"
253 call s:MapDelimitersWithAlternative('//','', '/*','*/')
254 elseif a:filetype ==? 'ebuild'
255 call s:MapDelimiters('#', '')
256 elseif a:filetype ==? "ecd"
257 call s:MapDelimiters('#', '')
258 elseif a:filetype ==? 'eclass'
259 call s:MapDelimiters('#', '')
260 elseif a:filetype ==? "eiffel"
261 call s:MapDelimiters('--', '')
262 elseif a:filetype ==? "elf"
263 call s:MapDelimiters("'", '')
264 elseif a:filetype ==? "elmfilt"
265 call s:MapDelimiters('#', '')
266 elseif a:filetype ==? "erlang"
267 call s:MapDelimiters('%', '')
268 elseif a:filetype ==? "eruby"
269 call s:MapDelimitersWithAlternative('<%#', '%>', '<!--', '-->')
270 elseif a:filetype ==? "expect"
271 call s:MapDelimiters('#', '')
272 elseif a:filetype ==? "exports"
273 call s:MapDelimiters('#', '')
274 elseif a:filetype ==? "factor"
275 call s:MapDelimitersWithAlternative('! ', '', '!# ', '')
276 elseif a:filetype ==? "fgl"
277 call s:MapDelimiters('#', '')
278 elseif a:filetype ==? "focexec"
279 call s:MapDelimiters('-*', '')
280 elseif a:filetype ==? "form"
281 call s:MapDelimiters('*', '')
282 elseif a:filetype ==? "foxpro"
283 call s:MapDelimiters('*', '')
284 elseif a:filetype ==? "fstab"
285 call s:MapDelimiters('#', '')
286 elseif a:filetype ==? "fvwm"
287 call s:MapDelimiters('#', '')
288 elseif a:filetype ==? "fx"
289 call s:MapDelimitersWithAlternative('//','', '/*','*/')
290 elseif a:filetype ==? "gams"
291 call s:MapDelimiters('*', '')
292 elseif a:filetype ==? "gdb"
293 call s:MapDelimiters('#', '')
294 elseif a:filetype ==? "gdmo"
295 call s:MapDelimiters('--', '')
296 elseif a:filetype ==? "geek"
297 call s:MapDelimiters('GEEK_COMMENT:', '')
298 elseif a:filetype ==? "genshi"
299 call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
300 elseif a:filetype ==? "gentoo-conf-d"
301 call s:MapDelimiters('#', '')
302 elseif a:filetype ==? "gentoo-env-d"
303 call s:MapDelimiters('#', '')
304 elseif a:filetype ==? "gentoo-init-d"
305 call s:MapDelimiters('#', '')
306 elseif a:filetype ==? "gentoo-make-conf"
307 call s:MapDelimiters('#', '')
308 elseif a:filetype ==? 'gentoo-package-keywords'
309 call s:MapDelimiters('#', '')
310 elseif a:filetype ==? 'gentoo-package-mask'
311 call s:MapDelimiters('#', '')
312 elseif a:filetype ==? 'gentoo-package-use'
313 call s:MapDelimiters('#', '')
314 elseif a:filetype ==? 'gitcommit'
315 call s:MapDelimiters('#', '')
316 elseif a:filetype ==? 'gitconfig'
317 call s:MapDelimiters(';', '')
318 elseif a:filetype ==? 'gitrebase'
319 call s:MapDelimiters('#', '')
320 elseif a:filetype ==? "gnuplot"
321 call s:MapDelimiters('#','')
322 elseif a:filetype ==? "groovy"
323 call s:MapDelimitersWithAlternative('//','', '/*','*/')
324 elseif a:filetype ==? "gtkrc"
325 call s:MapDelimiters('#', '')
326 elseif a:filetype ==? "haskell"
327 call s:MapDelimitersWithAlternative('{-','-}', '--', '')
328 elseif a:filetype ==? "hb"
329 call s:MapDelimiters('#', '')
330 elseif a:filetype ==? "h"
331 call s:MapDelimitersWithAlternative('//','', '/*','*/')
332 elseif a:filetype ==? "haml"
333 call s:MapDelimitersWithAlternative('-#', '', '/', '')
334 elseif a:filetype ==? "hercules"
335 call s:MapDelimitersWithAlternative('//','', '/*','*/')
336 elseif a:filetype ==? "hog"
337 call s:MapDelimiters('#', '')
338 elseif a:filetype ==? "hostsaccess"
339 call s:MapDelimiters('#', '')
340 elseif a:filetype ==? "htmlcheetah"
341 call s:MapDelimiters('##','')
342 elseif a:filetype ==? "htmldjango"
343 call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
344 elseif a:filetype ==? "htmlos"
345 call s:MapDelimiters('#','/#')
346 elseif a:filetype ==? "ia64"
347 call s:MapDelimiters('#', '')
348 elseif a:filetype ==? "icon"
349 call s:MapDelimiters('#', '')
350 elseif a:filetype ==? "idlang"
351 call s:MapDelimiters(';', '')
352 elseif a:filetype ==? "idl"
353 call s:MapDelimitersWithAlternative('//','', '/*','*/')
354 elseif a:filetype ==? "inform"
355 call s:MapDelimiters('!', '')
356 elseif a:filetype ==? "inittab"
357 call s:MapDelimiters('#', '')
358 elseif a:filetype ==? "ishd"
359 call s:MapDelimitersWithAlternative('//','', '/*','*/')
360 elseif a:filetype ==? "iss"
361 call s:MapDelimiters(';', '')
362 elseif a:filetype ==? "ist"
363 call s:MapDelimiters('%', '')
364 elseif a:filetype ==? "java"
365 call s:MapDelimitersWithAlternative('//','', '/*','*/')
366 elseif a:filetype ==? "javacc"
367 call s:MapDelimitersWithAlternative('//','', '/*','*/')
368 elseif a:filetype ==? "javascript"
369 call s:MapDelimitersWithAlternative('//','', '/*','*/')
370 elseif a:filetype == "javascript.jquery"
371 call s:MapDelimitersWithAlternative('//','', '/*','*/')
372 elseif a:filetype ==? "jess"
373 call s:MapDelimiters(';', '')
374 elseif a:filetype ==? "jgraph"
375 call s:MapDelimiters('(*','*)')
376 elseif a:filetype ==? "jproperties"
377 call s:MapDelimiters('#','')
378 elseif a:filetype ==? "jsp"
379 call s:MapDelimiters('<%--', '--%>')
380 elseif a:filetype ==? "kix"
381 call s:MapDelimiters(';', '')
382 elseif a:filetype ==? "kscript"
383 call s:MapDelimitersWithAlternative('//','', '/*','*/')
384 elseif a:filetype ==? "lace"
385 call s:MapDelimiters('--', '')
386 elseif a:filetype ==? "ldif"
387 call s:MapDelimiters('#', '')
388 elseif a:filetype ==? "lilo"
389 call s:MapDelimiters('#', '')
390 elseif a:filetype ==? "lilypond"
391 call s:MapDelimiters('%', '')
392 elseif a:filetype ==? "liquid"
393 call s:MapDelimiters('{%', '%}')
394 elseif a:filetype ==? "lisp"
395 call s:MapDelimitersWithAlternative(';','', '#|', '|#')
396 elseif a:filetype ==? "llvm"
397 call s:MapDelimiters(';','')
398 elseif a:filetype ==? "lotos"
399 call s:MapDelimiters('(*','*)')
400 elseif a:filetype ==? "lout"
401 call s:MapDelimiters('#', '')
402 elseif a:filetype ==? "lprolog"
403 call s:MapDelimiters('%', '')
404 elseif a:filetype ==? "lscript"
405 call s:MapDelimiters("'", '')
406 elseif a:filetype ==? "lss"
407 call s:MapDelimiters('#', '')
408 elseif a:filetype ==? "lua"
409 call s:MapDelimitersWithAlternative('--','', '--[[', ']]')
410 elseif a:filetype ==? "lynx"
411 call s:MapDelimiters('#', '')
412 elseif a:filetype ==? "lytex"
413 call s:MapDelimiters('%', '')
414 elseif a:filetype ==? "mail"
415 call s:MapDelimiters('> ','')
416 elseif a:filetype ==? "mako"
417 call s:MapDelimiters('##', '')
418 elseif a:filetype ==? "man"
419 call s:MapDelimiters('."', '')
420 elseif a:filetype ==? "map"
421 call s:MapDelimiters('%', '')
422 elseif a:filetype ==? "maple"
423 call s:MapDelimiters('#', '')
424 elseif a:filetype ==? "markdown"
425 call s:MapDelimiters('<!--', '-->')
426 elseif a:filetype ==? "masm"
427 call s:MapDelimiters(';', '')
428 elseif a:filetype ==? "mason"
429 call s:MapDelimiters('<% #', '%>')
430 elseif a:filetype ==? "master"
431 call s:MapDelimiters('$', '')
432 elseif a:filetype ==? "matlab"
433 call s:MapDelimiters('%', '')
434 elseif a:filetype ==? "mel"
435 call s:MapDelimitersWithAlternative('//','', '/*','*/')
436 elseif a:filetype ==? "mib"
437 call s:MapDelimiters('--', '')
438 elseif a:filetype ==? "mkd"
439 call s:MapDelimiters('>', '')
440 elseif a:filetype ==? "mma"
441 call s:MapDelimiters('(*','*)')
442 elseif a:filetype ==? "model"
443 call s:MapDelimiters('$','$')
444 elseif a:filetype =~ "moduala."
445 call s:MapDelimiters('(*','*)')
446 elseif a:filetype ==? "modula2"
447 call s:MapDelimiters('(*','*)')
448 elseif a:filetype ==? "modula3"
449 call s:MapDelimiters('(*','*)')
450 elseif a:filetype ==? "monk"
451 call s:MapDelimiters(';', '')
452 elseif a:filetype ==? "mush"
453 call s:MapDelimiters('#', '')
454 elseif a:filetype ==? "named"
455 call s:MapDelimitersWithAlternative('//','', '/*','*/')
456 elseif a:filetype ==? "nasm"
457 call s:MapDelimiters(';', '')
458 elseif a:filetype ==? "nastran"
459 call s:MapDelimiters('$', '')
460 elseif a:filetype ==? "natural"
461 call s:MapDelimiters('/*', '')
462 elseif a:filetype ==? "ncf"
463 call s:MapDelimiters(';', '')
464 elseif a:filetype ==? "newlisp"
465 call s:MapDelimiters(';','')
466 elseif a:filetype ==? "nroff"
467 call s:MapDelimiters('\"', '')
468 elseif a:filetype ==? "nsis"
469 call s:MapDelimiters('#', '')
470 elseif a:filetype ==? "ntp"
471 call s:MapDelimiters('#', '')
472 elseif a:filetype ==? "objc"
473 call s:MapDelimitersWithAlternative('//','', '/*','*/')
474 elseif a:filetype ==? "objcpp"
475 call s:MapDelimitersWithAlternative('//','', '/*','*/')
476 elseif a:filetype ==? "objj"
477 call s:MapDelimitersWithAlternative('//','', '/*','*/')
478 elseif a:filetype ==? "ocaml"
479 call s:MapDelimiters('(*','*)')
480 elseif a:filetype ==? "occam"
481 call s:MapDelimiters('--','')
482 elseif a:filetype ==? "omlet"
483 call s:MapDelimiters('(*','*)')
484 elseif a:filetype ==? "omnimark"
485 call s:MapDelimiters(';', '')
486 elseif a:filetype ==? "openroad"
487 call s:MapDelimiters('//', '')
488 elseif a:filetype ==? "opl"
489 call s:MapDelimiters("REM", "")
490 elseif a:filetype ==? "ora"
491 call s:MapDelimiters('#', '')
492 elseif a:filetype ==? "ox"
493 call s:MapDelimiters('//', '')
494 elseif a:filetype ==? "pascal"
495 call s:MapDelimitersWithAlternative('{','}', '(*', '*)')
496 elseif a:filetype ==? "patran"
497 call s:MapDelimitersWithAlternative('$','','/*', '*/')
498 elseif a:filetype ==? "pcap"
499 call s:MapDelimiters('#', '')
500 elseif a:filetype ==? "pccts"
501 call s:MapDelimitersWithAlternative('//','', '/*','*/')
502 elseif a:filetype ==? "pdf"
503 call s:MapDelimiters('%', '')
504 elseif a:filetype ==? "pfmain"
505 call s:MapDelimiters('//', '')
506 elseif a:filetype ==? "php"
507 call s:MapDelimitersWithAlternative('//','','/*', '*/')
508 elseif a:filetype ==? "pic"
509 call s:MapDelimiters(';', '')
510 elseif a:filetype ==? "pike"
511 call s:MapDelimitersWithAlternative('//','', '/*','*/')
512 elseif a:filetype ==? "pilrc"
513 call s:MapDelimitersWithAlternative('//','', '/*','*/')
514 elseif a:filetype ==? "pine"
515 call s:MapDelimiters('#', '')
516 elseif a:filetype ==? "plm"
517 call s:MapDelimitersWithAlternative('//','', '/*','*/')
518 elseif a:filetype ==? "plsql"
519 call s:MapDelimitersWithAlternative('--', '', '/*', '*/')
520 elseif a:filetype ==? "po"
521 call s:MapDelimiters('#', '')
522 elseif a:filetype ==? "postscr"
523 call s:MapDelimiters('%', '')
524 elseif a:filetype ==? "pov"
525 call s:MapDelimitersWithAlternative('//','', '/*','*/')
526 elseif a:filetype ==? "povini"
527 call s:MapDelimiters(';', '')
528 elseif a:filetype ==? "ppd"
529 call s:MapDelimiters('%', '')
530 elseif a:filetype ==? "ppwiz"
531 call s:MapDelimiters(';;', '')
532 elseif a:filetype ==? "processing"
533 call s:MapDelimitersWithAlternative('//','', '/*','*/')
534 elseif a:filetype ==? "prolog"
535 call s:MapDelimitersWithAlternative('%','','/*','*/')
536 elseif a:filetype ==? "ps1"
537 call s:MapDelimiters('#', '')
538 elseif a:filetype ==? "psf"
539 call s:MapDelimiters('#', '')
540 elseif a:filetype ==? "ptcap"
541 call s:MapDelimiters('#', '')
542 elseif a:filetype ==? "radiance"
543 call s:MapDelimiters('#', '')
544 elseif a:filetype ==? "ratpoison"
545 call s:MapDelimiters('#', '')
546 elseif a:filetype ==? "r"
547 call s:MapDelimiters('#', '')
548 elseif a:filetype ==? "rc"
549 call s:MapDelimitersWithAlternative('//','', '/*','*/')
550 elseif a:filetype ==? "rebol"
551 call s:MapDelimiters(';', '')
552 elseif a:filetype ==? "registry"
553 call s:MapDelimiters(';', '')
554 elseif a:filetype ==? "remind"
555 call s:MapDelimiters('#', '')
556 elseif a:filetype ==? "resolv"
557 call s:MapDelimiters('#', '')
558 elseif a:filetype ==? "rgb"
559 call s:MapDelimiters('!', '')
560 elseif a:filetype ==? "rib"
561 call s:MapDelimiters('#','')
562 elseif a:filetype ==? "robots"
563 call s:MapDelimiters('#', '')
564 elseif a:filetype ==? "sa"
565 call s:MapDelimiters('--','')
566 elseif a:filetype ==? "samba"
567 call s:MapDelimitersWithAlternative(';','', '#', '')
568 elseif a:filetype ==? "sass"
569 call s:MapDelimitersWithAlternative('//','', '/*', '')
570 elseif a:filetype ==? "sather"
571 call s:MapDelimiters('--', '')
572 elseif a:filetype ==? "scala"
573 call s:MapDelimitersWithAlternative('//','', '/*','*/')
574 elseif a:filetype ==? "scilab"
575 call s:MapDelimiters('//', '')
576 elseif a:filetype ==? "scsh"
577 call s:MapDelimiters(';', '')
578 elseif a:filetype ==? "sed"
579 call s:MapDelimiters('#', '')
580 elseif a:filetype ==? "sgmldecl"
581 call s:MapDelimiters('--','--')
582 elseif a:filetype ==? "sgmllnx"
583 call s:MapDelimiters('<!--','-->')
584 elseif a:filetype ==? "sicad"
585 call s:MapDelimiters('*', '')
586 elseif a:filetype ==? "simula"
587 call s:MapDelimitersWithAlternative('%', '', '--', '')
588 elseif a:filetype ==? "sinda"
589 call s:MapDelimiters('$', '')
590 elseif a:filetype ==? "skill"
591 call s:MapDelimiters(';', '')
592 elseif a:filetype ==? "slang"
593 call s:MapDelimiters('%', '')
594 elseif a:filetype ==? "slice"
595 call s:MapDelimitersWithAlternative('//','', '/*','*/')
596 elseif a:filetype ==? "slrnrc"
597 call s:MapDelimiters('%', '')
598 elseif a:filetype ==? "sm"
599 call s:MapDelimiters('#', '')
600 elseif a:filetype ==? "smarty"
601 call s:MapDelimiters('{*', '*}')
602 elseif a:filetype ==? "smil"
603 call s:MapDelimiters('<!','>')
604 elseif a:filetype ==? "smith"
605 call s:MapDelimiters(';', '')
606 elseif a:filetype ==? "sml"
607 call s:MapDelimiters('(*','*)')
608 elseif a:filetype ==? "snnsnet"
609 call s:MapDelimiters('#', '')
610 elseif a:filetype ==? "snnspat"
611 call s:MapDelimiters('#', '')
612 elseif a:filetype ==? "snnsres"
613 call s:MapDelimiters('#', '')
614 elseif a:filetype ==? "snobol4"
615 call s:MapDelimiters('*', '')
616 elseif a:filetype ==? "spec"
617 call s:MapDelimiters('#', '')
618 elseif a:filetype ==? "specman"
619 call s:MapDelimiters('//', '')
620 elseif a:filetype ==? "spectre"
621 call s:MapDelimitersWithAlternative('//', '', '*', '')
622 elseif a:filetype ==? "spice"
623 call s:MapDelimiters('$', '')
624 elseif a:filetype ==? "sql"
625 call s:MapDelimiters('--', '')
626 elseif a:filetype ==? "sqlforms"
627 call s:MapDelimiters('--', '')
628 elseif a:filetype ==? "sqlj"
629 call s:MapDelimiters('--', '')
630 elseif a:filetype ==? "sqr"
631 call s:MapDelimiters('!', '')
632 elseif a:filetype ==? "squid"
633 call s:MapDelimiters('#', '')
634 elseif a:filetype ==? "st"
635 call s:MapDelimiters('"','')
636 elseif a:filetype ==? "stp"
637 call s:MapDelimiters('--', '')
638 elseif a:filetype ==? "systemverilog"
639 call s:MapDelimitersWithAlternative('//','', '/*','*/')
640 elseif a:filetype ==? "tads"
641 call s:MapDelimitersWithAlternative('//','', '/*','*/')
642 elseif a:filetype ==? "tags"
643 call s:MapDelimiters(';', '')
644 elseif a:filetype ==? "tak"
645 call s:MapDelimiters('$', '')
646 elseif a:filetype ==? "tasm"
647 call s:MapDelimiters(';', '')
648 elseif a:filetype ==? "tcl"
649 call s:MapDelimiters('#','')
650 elseif a:filetype ==? "texinfo"
651 call s:MapDelimiters("@c ", "")
652 elseif a:filetype ==? "texmf"
653 call s:MapDelimiters('%', '')
654 elseif a:filetype ==? "tf"
655 call s:MapDelimiters(';', '')
656 elseif a:filetype ==? "tidy"
657 call s:MapDelimiters('#', '')
658 elseif a:filetype ==? "tli"
659 call s:MapDelimiters('#', '')
660 elseif a:filetype ==? "trasys"
661 call s:MapDelimiters("$", "")
662 elseif a:filetype ==? "tsalt"
663 call s:MapDelimitersWithAlternative('//','', '/*','*/')
664 elseif a:filetype ==? "tsscl"
665 call s:MapDelimiters('#', '')
666 elseif a:filetype ==? "tssgm"
667 call s:MapDelimiters("comment = '","'")
668 elseif a:filetype ==? "txt2tags"
669 call s:MapDelimiters('%','')
670 elseif a:filetype ==? "uc"
671 call s:MapDelimitersWithAlternative('//','', '/*','*/')
672 elseif a:filetype ==? "uil"
673 call s:MapDelimiters('!', '')
674 elseif a:filetype ==? "vb"
675 call s:MapDelimiters("'","")
676 elseif a:filetype ==? "velocity"
677 call s:MapDelimitersWithAlternative("##","", '#*', '*#')
678 elseif a:filetype ==? "vera"
679 call s:MapDelimitersWithAlternative('/*','*/','//','')
680 elseif a:filetype ==? "verilog"
681 call s:MapDelimitersWithAlternative('//','', '/*','*/')
682 elseif a:filetype ==? "verilog_systemverilog"
683 call s:MapDelimitersWithAlternative('//','', '/*','*/')
684 elseif a:filetype ==? "vgrindefs"
685 call s:MapDelimiters('#', '')
686 elseif a:filetype ==? "vhdl"
687 call s:MapDelimiters('--', '')
688 elseif a:filetype ==? "vimperator"
689 call s:MapDelimiters('"','')
690 elseif a:filetype ==? "virata"
691 call s:MapDelimiters('%', '')
692 elseif a:filetype ==? "vrml"
693 call s:MapDelimiters('#', '')
694 elseif a:filetype ==? "vsejcl"
695 call s:MapDelimiters('/*', '')
696 elseif a:filetype ==? "webmacro"
697 call s:MapDelimiters('##', '')
698 elseif a:filetype ==? "wget"
699 call s:MapDelimiters('#', '')
700 elseif a:filetype ==? "Wikipedia"
701 call s:MapDelimiters('<!--','-->')
702 elseif a:filetype ==? "winbatch"
703 call s:MapDelimiters(';', '')
704 elseif a:filetype ==? "wml"
705 call s:MapDelimiters('#', '')
706 elseif a:filetype ==? "wvdial"
707 call s:MapDelimiters(';', '')
708 elseif a:filetype ==? "xdefaults"
709 call s:MapDelimiters('!', '')
710 elseif a:filetype ==? "xkb"
711 call s:MapDelimiters('//', '')
712 elseif a:filetype ==? "xmath"
713 call s:MapDelimiters('#', '')
714 elseif a:filetype ==? "xpm2"
715 call s:MapDelimiters('!', '')
716 elseif a:filetype ==? "xquery"
717 call s:MapDelimiters('(:',':)')
718 elseif a:filetype ==? "z8a"
719 call s:MapDelimiters(';', '')
723 "extract the delims from &commentstring
724 let left= substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', '')
725 let right= substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g')
726 call s:MapDelimiters(left,right)
731 " Function: s:MapDelimiters(left, right) function {{{2
732 " This function is a wrapper for s:MapDelimiters(left, right, leftAlt, rightAlt, useAlt) and is called when there
733 " is no alternative comment delimiters for the current filetype
736 " -left: the left comment delimiter
737 " -right: the right comment delimiter
738 function s:MapDelimiters(left, right)
739 call s:MapDelimitersWithAlternative(a:left, a:right, "", "")
742 " Function: s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt) function {{{2
743 " this function sets up the comment delimiter buffer variables
746 " -left: the string defining the comment start delimiter
747 " -right: the string defining the comment end delimiter
748 " -leftAlt: the string for the alternative comment style defining the comment start delimiter
749 " -rightAlt: the string for the alternative comment style defining the comment end delimiter
750 function s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt)
751 if !exists('g:NERD_' . &filetype . '_alt_style')
752 let b:NERDLeft = a:left
753 let b:NERDRight = a:right
754 let b:NERDLeftAlt = a:leftAlt
755 let b:NERDRightAlt = a:rightAlt
757 let b:NERDLeft = a:leftAlt
758 let b:NERDRight = a:rightAlt
759 let b:NERDLeftAlt = a:left
760 let b:NERDRightAlt = a:right
764 " Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2
765 " This function is used to swap the delimiters that are being used to the
766 " alternative delimiters for that filetype. For example, if a c++ file is
767 " being edited and // comments are being used, after this function is called
768 " /**/ comments will be used.
771 " -printMsgs: if this is 1 then a message is echoed to the user telling them
772 " if this function changed the delimiters or not
773 function s:SwitchToAlternativeDelimiters(printMsgs)
774 "if both of the alternative delimiters are empty then there is no
775 "alternative comment style so bail out
776 if b:NERDLeftAlt == "" && b:NERDRightAlt == ""
778 call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0)
783 "save the current delimiters
784 let tempLeft = b:NERDLeft
785 let tempRight = b:NERDRight
787 "swap current delimiters for alternative
788 let b:NERDLeft = b:NERDLeftAlt
789 let b:NERDRight = b:NERDRightAlt
791 "set the previously current delimiters to be the new alternative ones
792 let b:NERDLeftAlt = tempLeft
793 let b:NERDRightAlt = tempRight
795 "tell the user what comment delimiters they are now using
797 let leftNoEsc = b:NERDLeft
798 let rightNoEsc = b:NERDRight
799 call s:NerdEcho("Now using " . leftNoEsc . " " . rightNoEsc . " to delimit comments", 1)
805 " Section: Comment delimiter add/removal functions {{{1
806 " ============================================================================
807 " Function: s:AppendCommentToLine(){{{2
808 " This function appends comment delimiters at the EOL and places the cursor in
809 " position to start typing the comment
810 function s:AppendCommentToLine()
811 let left = s:GetLeft(0,1,0)
812 let right = s:GetRight(0,1,0)
814 " get the len of the right delim
815 let lenRight = strlen(right)
817 let isLineEmpty = strlen(getline(".")) == 0
818 let insOrApp = (isLineEmpty==1 ? 'i' : 'A')
820 "stick the delimiters down at the end of the line. We have to format the
821 "comment with spaces as appropriate
822 execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " "
824 " if there is a right delimiter then we gotta move the cursor left
825 " by the len of the right delimiter so we insert between the delimiters
827 let leftMoveAmount = lenRight
828 execute ":normal! " . leftMoveAmount . "h"
833 " Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2
834 " This function is used to comment out a region of code. This region is
835 " specified as a bounding box by arguments to the function.
838 " -top: the line number for the top line of code in the region
839 " -bottom: the line number for the bottom line of code in the region
840 " -lSide: the column number for the left most column in the region
841 " -rSide: the column number for the right most column in the region
842 " -forceNested: a flag indicating whether comments should be nested
843 function s:CommentBlock(top, bottom, lSide, rSide, forceNested )
844 " we need to create local copies of these arguments so we can modify them
846 let bottom = a:bottom
850 "if the top or bottom line starts with tabs we have to adjust the left and
851 "right boundaries so that they are set as though the tabs were spaces
852 let topline = getline(top)
853 let bottomline = getline(bottom)
854 if s:HasLeadingTabs(topline, bottomline)
856 "find out how many tabs are in the top line and adjust the left
857 "boundary accordingly
858 let numTabs = s:NumberOfLeadingTabs(topline)
860 let lSide = &ts * lSide
862 let lSide = (lSide - numTabs) + (&ts * numTabs)
865 "find out how many tabs are in the bottom line and adjust the right
866 "boundary accordingly
867 let numTabs = s:NumberOfLeadingTabs(bottomline)
868 let rSide = (rSide - numTabs) + (&ts * numTabs)
871 "we must check that bottom IS actually below top, if it is not then we
872 "swap top and bottom. Similarly for left and right.
884 "if the current delimiters arent multipart then we will switch to the
885 "alternative delims (if THEY are) as the comment will be better and more
886 "accurate with multipart delims
887 let switchedDelims = 0
888 if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart()
889 let switchedDelims = 1
890 call s:SwitchToAlternativeDelimiters(0)
893 "start the commenting from the top and keep commenting till we reach the
896 while currentLine <= bottom
898 "check if we are allowed to comment this line
899 if s:CanCommentLine(a:forceNested, currentLine)
901 "convert the leading tabs into spaces
902 let theLine = getline(currentLine)
903 let lineHasLeadTabs = s:HasLeadingTabs(theLine)
905 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
908 "dont comment lines that begin after the right boundary of the
909 "block unless the user has specified to do so
910 if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty
912 "attempt to place the cursor in on the left of the boundary box,
913 "then check if we were successful, if not then we cant comment this
915 call setline(currentLine, theLine)
916 if s:CanPlaceCursor(currentLine, lSide)
918 let leftSpaced = s:GetLeft(0,1,0)
919 let rightSpaced = s:GetRight(0,1,0)
921 "stick the left delimiter down
922 let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
925 "stick the right delimiter down
926 let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced))
928 let firstLeftDelim = s:FindDelimiterIndex(b:NERDLeft, theLine)
929 let lastRightDelim = s:LastIndexOfDelim(b:NERDRight, theLine)
931 if firstLeftDelim != -1 && lastRightDelim != -1
932 let searchStr = strpart(theLine, 0, lastRightDelim)
933 let searchStr = strpart(searchStr, firstLeftDelim+strlen(b:NERDLeft))
935 "replace the outter most delims in searchStr with
937 let theLineWithPlaceHolders = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, searchStr)
939 "add the right delimiter onto the line
940 let theLine = strpart(theLine, 0, firstLeftDelim+strlen(b:NERDLeft)) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
946 "restore tabs if needed
948 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
951 call setline(currentLine, theLine)
954 let currentLine = currentLine + 1
957 "if we switched delims then we gotta go back to what they were before
958 if switchedDelims == 1
959 call s:SwitchToAlternativeDelimiters(0)
963 " Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2
964 " This function comments a range of lines.
967 " -forceNested: a flag indicating whether the called is requesting the comment
968 " to be nested if need be
969 " -align: should be "left" or "both" or "none"
970 " -firstLine/lastLine: the top and bottom lines to comment
971 function s:CommentLines(forceNested, align, firstLine, lastLine)
972 " we need to get the left and right indexes of the leftmost char in the
973 " block of of lines and the right most char so that we can do alignment of
974 " the delimiters if the user has specified
975 let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
976 let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
978 " gotta add the length of the left delimiter onto the rightAlignIndx cos
979 " we'll be adding a left delim to the line
980 let rightAlignIndx = rightAlignIndx + strlen(s:GetLeft(0,1,0))
982 " now we actually comment the lines. Do it line by line
983 let currentLine = a:firstLine
984 while currentLine <= a:lastLine
986 " get the next line, check commentability and convert spaces to tabs
987 let theLine = getline(currentLine)
988 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
989 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
990 if s:CanCommentLine(a:forceNested, currentLine)
991 "if the user has specified forceNesting then we check to see if we
992 "need to switch delimiters for place-holders
993 if a:forceNested && g:NERDUsePlaceHolders
994 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
997 " find out if the line is commented using normal delims and/or
999 let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)
1001 " check if we can comment this line
1002 if !isCommented || g:NERDUsePlaceHolders || s:Multipart()
1003 if a:align == "left" || a:align == "both"
1004 let theLine = s:AddLeftDelimAligned(s:GetLeft(0,1,0), theLine, leftAlignIndx)
1006 let theLine = s:AddLeftDelim(s:GetLeft(0,1,0), theLine)
1008 if a:align == "both"
1009 let theLine = s:AddRightDelimAligned(s:GetRight(0,1,0), theLine, rightAlignIndx)
1011 let theLine = s:AddRightDelim(s:GetRight(0,1,0), theLine)
1016 " restore leading tabs if appropriate
1017 if lineHasLeadingTabs
1018 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1021 " we are done with this line
1022 call setline(currentLine, theLine)
1023 let currentLine = currentLine + 1
1028 " Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2
1029 " This function comments a range of lines in a minimal style. I
1032 " -firstLine/lastLine: the top and bottom lines to comment
1033 function s:CommentLinesMinimal(firstLine, lastLine)
1034 "check that minimal comments can be done on this filetype
1035 if !s:HasMultipartDelims()
1036 throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters'
1039 "if we need to use place holders for the comment, make sure they are
1040 "enabled for this filetype
1041 if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine)
1042 throw 'NERDCommenter.Settings exception: Placeoholders are required but disabled.'
1045 "get the left and right delims to smack on
1046 let left = s:GetSexyComLeft(g:NERDSpaceDelims,0)
1047 let right = s:GetSexyComRight(g:NERDSpaceDelims,0)
1049 "make sure all multipart delims on the lines are replaced with
1050 "placeholders to prevent illegal syntax
1051 let currentLine = a:firstLine
1052 while(currentLine <= a:lastLine)
1053 let theLine = getline(currentLine)
1054 let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine)
1055 call setline(currentLine, theLine)
1056 let currentLine = currentLine + 1
1059 "add the delim to the top line
1060 let theLine = getline(a:firstLine)
1061 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
1062 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1063 let theLine = s:AddLeftDelim(left, theLine)
1064 if lineHasLeadingTabs
1065 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1067 call setline(a:firstLine, theLine)
1069 "add the delim to the bottom line
1070 let theLine = getline(a:lastLine)
1071 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
1072 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1073 let theLine = s:AddRightDelim(right, theLine)
1074 if lineHasLeadingTabs
1075 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1077 call setline(a:lastLine, theLine)
1080 " Function: s:CommentLinesSexy(topline, bottomline) function {{{2
1081 " This function is used to comment lines in the 'Sexy' style. eg in c:
1083 " * This is a sexy comment
1086 " -topline: the line num of the top line in the sexy comment
1087 " -bottomline: the line num of the bottom line in the sexy comment
1088 function s:CommentLinesSexy(topline, bottomline)
1089 let left = s:GetSexyComLeft(0, 0)
1090 let right = s:GetSexyComRight(0, 0)
1092 "check if we can do a sexy comment with the available delimiters
1093 if left == -1 || right == -1
1094 throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.'
1097 "make sure the lines arent already commented sexually
1098 if !s:CanSexyCommentLines(a:topline, a:bottomline)
1099 throw 'NERDCommenter.Nesting exception: cannot nest sexy comments'
1103 let sexyComMarker = s:GetSexyComMarker(0,0)
1104 let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
1107 " we jam the comment as far to the right as possible
1108 let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
1110 "check if we should use the compact style i.e that the left/right
1111 "delimiters should appear on the first and last lines of the code and not
1112 "on separate lines above/below the first/last lines of code
1113 if g:NERDCompactSexyComs
1114 let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '')
1116 "comment the top line
1117 let theLine = getline(a:topline)
1118 let lineHasTabs = s:HasLeadingTabs(theLine)
1120 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1122 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1123 let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
1125 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1127 call setline(a:topline, theLine)
1129 "comment the bottom line
1130 if a:bottomline != a:topline
1131 let theLine = getline(a:bottomline)
1132 let lineHasTabs = s:HasLeadingTabs(theLine)
1134 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1136 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1138 let theLine = s:AddRightDelim(spaceString . right, theLine)
1140 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1142 call setline(a:bottomline, theLine)
1145 " add the left delimiter one line above the lines that are to be commented
1146 call cursor(a:topline, 1)
1148 call setline(a:topline, repeat(' ', leftAlignIndx) . left )
1150 " add the right delimiter after bottom line (we have to add 1 cos we moved
1151 " the lines down when we added the left delim
1152 call cursor(a:bottomline+1, 1)
1154 call setline(a:bottomline+2, repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right )
1158 " go thru each line adding the sexyComMarker marker to the start of each
1159 " line in the appropriate place to align them with the comment delims
1160 let currentLine = a:topline+1
1161 while currentLine <= a:bottomline + !g:NERDCompactSexyComs
1162 " get the line and convert the tabs to spaces
1163 let theLine = getline(currentLine)
1164 let lineHasTabs = s:HasLeadingTabs(theLine)
1166 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1169 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1171 " add the sexyComMarker
1172 let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
1175 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1179 " set the line and move onto the next one
1180 call setline(currentLine, theLine)
1181 let currentLine = currentLine + 1
1186 " Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2
1187 " Applies "toggle" commenting to the given range of lines
1190 " -forceNested: a flag indicating whether the called is requesting the comment
1191 " to be nested if need be
1192 " -firstLine/lastLine: the top and bottom lines to comment
1193 function s:CommentLinesToggle(forceNested, firstLine, lastLine)
1194 let currentLine = a:firstLine
1195 while currentLine <= a:lastLine
1197 " get the next line, check commentability and convert spaces to tabs
1198 let theLine = getline(currentLine)
1199 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
1200 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1201 if s:CanToggleCommentLine(a:forceNested, currentLine)
1203 "if the user has specified forceNesting then we check to see if we
1204 "need to switch delimiters for place-holders
1205 if g:NERDUsePlaceHolders
1206 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1209 let theLine = s:AddLeftDelim(s:GetLeft(0, 1, 0), theLine)
1210 let theLine = s:AddRightDelim(s:GetRight(0, 1, 0), theLine)
1213 " restore leading tabs if appropriate
1214 if lineHasLeadingTabs
1215 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1218 " we are done with this line
1219 call setline(currentLine, theLine)
1220 let currentLine = currentLine + 1
1225 " Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2
1226 " This function comments chunks of text selected in visual mode.
1227 " It will comment exactly the text that they have selected.
1229 " -topLine: the line num of the top line in the sexy comment
1230 " -topCol: top left col for this comment
1231 " -bottomline: the line num of the bottom line in the sexy comment
1232 " -bottomCol: the bottom right col for this comment
1233 " -forceNested: whether the caller wants comments to be nested if the
1234 " line(s) are already commented
1235 function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested)
1237 "switch delims (if we can) if the current set isnt multipart
1238 let switchedDelims = 0
1239 if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims
1240 let switchedDelims = 1
1241 call s:SwitchToAlternativeDelimiters(0)
1244 "if there is only one line in the comment then just do it
1245 if a:topLine == a:bottomLine
1246 call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested)
1248 "there are multiple lines in the comment
1250 "comment the top line
1251 call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
1253 "comment out all the lines in the middle of the comment
1254 let topOfRange = a:topLine+1
1255 let bottomOfRange = a:bottomLine-1
1256 if topOfRange <= bottomOfRange
1257 call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange)
1260 "comment the bottom line
1261 let bottom = getline(a:bottomLine)
1262 let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', ''))
1263 call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested)
1267 "stick the cursor back on the char it was on before the comment
1268 call cursor(a:topLine, a:topCol + strlen(b:NERDLeft) + g:NERDSpaceDelims)
1270 "if we switched delims then we gotta go back to what they were before
1271 if switchedDelims == 1
1272 call s:SwitchToAlternativeDelimiters(0)
1277 " Function: s:InvertComment(firstLine, lastLine) function {{{2
1278 " Inverts the comments on the lines between and including the given line
1279 " numbers i.e all commented lines are uncommented and vice versa
1281 " -firstLine: the top of the range of lines to be inverted
1282 " -lastLine: the bottom of the range of lines to be inverted
1283 function s:InvertComment(firstLine, lastLine)
1285 " go thru all lines in the given range
1286 let currentLine = a:firstLine
1287 while currentLine <= a:lastLine
1288 let theLine = getline(currentLine)
1290 let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
1292 " if the line is commented normally, uncomment it
1293 if s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)
1294 call s:UncommentLines(currentLine, currentLine)
1295 let currentLine = currentLine + 1
1297 " check if the line is commented sexually
1298 elseif !empty(sexyComBounds)
1299 let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
1300 call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
1302 "move to the line after last line of the sexy comment
1303 let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
1304 let currentLine = bottomBound - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1
1306 " the line isnt commented
1308 call s:CommentLinesToggle(1, currentLine, currentLine)
1309 let currentLine = currentLine + 1
1315 " Function: NERDComment(isVisual, type) function {{{2
1316 " This function is a Wrapper for the main commenting functions
1319 " -isVisual: a flag indicating whether the comment is requested in visual
1321 " -type: the type of commenting requested. Can be 'sexy', 'invert',
1322 " 'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm',
1323 " 'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank'
1324 function! NERDComment(isVisual, type) range
1325 " we want case sensitivity when commenting
1326 let oldIgnoreCase = &ignorecase
1330 let firstLine = line("'<")
1331 let lastLine = line("'>")
1332 let firstCol = col("'<")
1333 let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0)
1335 let firstLine = a:firstline
1336 let lastLine = a:lastline
1339 let countWasGiven = (a:isVisual == 0 && firstLine != lastLine)
1341 let forceNested = (a:type == 'nested' || g:NERDDefaultNesting)
1343 if a:type == 'norm' || a:type == 'nested'
1344 if a:isVisual && visualmode() == "
\16"
1345 call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested)
1346 elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims()))
1347 call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested)
1349 call s:CommentLines(forceNested, "none", firstLine, lastLine)
1352 elseif a:type == 'alignLeft' || a:type == 'alignBoth'
1354 if a:type == "alignLeft"
1356 elseif a:type == "alignBoth"
1359 call s:CommentLines(forceNested, align, firstLine, lastLine)
1361 elseif a:type == 'invert'
1362 call s:InvertComment(firstLine, lastLine)
1364 elseif a:type == 'sexy'
1366 call s:CommentLinesSexy(firstLine, lastLine)
1367 catch /NERDCommenter.Delimiters/
1368 call s:CommentLines(forceNested, "none", firstLine, lastLine)
1369 catch /NERDCommenter.Nesting/
1370 call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0)
1373 elseif a:type == 'toggle'
1374 let theLine = getline(firstLine)
1376 if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)
1377 call s:UncommentLines(firstLine, lastLine)
1379 call s:CommentLinesToggle(forceNested, firstLine, lastLine)
1382 elseif a:type == 'minimal'
1384 call s:CommentLinesMinimal(firstLine, lastLine)
1385 catch /NERDCommenter.Delimiters/
1386 call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0)
1387 catch /NERDCommenter.Settings/
1388 call s:NerdEcho("Place holders are required but disabled.", 0)
1391 elseif a:type == 'toEOL'
1392 call s:SaveScreenState()
1393 call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1)
1394 call s:RestoreScreenState()
1396 elseif a:type == 'append'
1397 call s:AppendCommentToLine()
1399 elseif a:type == 'insert'
1400 call s:PlaceDelimitersAndInsBetween()
1402 elseif a:type == 'uncomment'
1403 call s:UncommentLines(firstLine, lastLine)
1405 elseif a:type == 'yank'
1408 elseif countWasGiven
1409 execute firstLine .','. lastLine .'yank'
1413 execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")'
1416 let &ignorecase = oldIgnoreCase
1419 " Function: s:PlaceDelimitersAndInsBetween() function {{{2
1420 " This is function is called to place comment delimiters down and place the
1421 " cursor between them
1422 function s:PlaceDelimitersAndInsBetween()
1423 " get the left and right delimiters without any escape chars in them
1424 let left = s:GetLeft(0, 1, 0)
1425 let right = s:GetRight(0, 1, 0)
1427 let theLine = getline(".")
1428 let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab)
1430 "convert tabs to spaces and adjust the cursors column to take this into
1432 let untabbedCol = s:UntabbedCol(theLine, col("."))
1433 call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine))
1434 call cursor(line("."), untabbedCol)
1436 " get the len of the right delim
1437 let lenRight = strlen(right)
1439 let isDelimOnEOL = col(".") >= strlen(getline("."))
1441 " if the cursor is in the first col then we gotta insert rather than
1442 " append the comment delimiters here
1443 let insOrApp = (col(".")==1 ? 'i' : 'a')
1445 " place the delimiters down. We do it differently depending on whether
1446 " there is a left AND right delimiter
1448 execute ":normal! " . insOrApp . left . right
1449 execute ":normal! " . lenRight . "h"
1451 execute ":normal! " . insOrApp . left
1453 " if we are tacking the delim on the EOL then we gotta add a space
1454 " after it cos when we go out of insert mode the cursor will move back
1455 " one and the user wont be in position to type the comment.
1457 execute 'normal! a '
1462 "if needed convert spaces back to tabs and adjust the cursors col
1465 let tabbedCol = s:TabbedCol(getline("."), col("."))
1466 call setline(line("."), s:ConvertLeadingSpacesToTabs(getline(".")))
1467 call cursor(line("."), tabbedCol)
1473 " Function: s:RemoveDelimiters(left, right, line) {{{2
1474 " this function is called to remove the first left comment delimiter and the
1475 " last right delimiter of the given line.
1477 " The args left and right must be strings. If there is no right delimiter (as
1478 " is the case for e.g vim file comments) them the arg right should be ""
1481 " -left: the left comment delimiter
1482 " -right: the right comment delimiter
1483 " -line: the line to remove the delimiters from
1484 function s:RemoveDelimiters(left, right, line)
1487 let l:right = a:right
1488 let lenLeft = strlen(left)
1489 let lenRight = strlen(right)
1491 let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
1495 "look for the left delimiter, if we find it, remove it.
1496 let leftIndx = s:FindDelimiterIndex(a:left, line)
1498 let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
1500 "if the user has specified that there is a space after the left delim
1501 "then check for the space and remove it if it is there
1502 if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr
1503 let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr)
1507 "look for the right delimiter, if we find it, remove it
1508 let rightIndx = s:FindDelimiterIndex(a:right, line)
1510 let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
1512 "if the user has specified that there is a space before the right delim
1513 "then check for the space and remove it if it is there
1514 if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart()
1515 let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx)
1522 " Function: s:UncommentLines(topLine, bottomLine) {{{2
1523 " This function uncomments the given lines
1526 " topLine: the top line of the visual selection to uncomment
1527 " bottomLine: the bottom line of the visual selection to uncomment
1528 function s:UncommentLines(topLine, bottomLine)
1529 "make local copies of a:firstline and a:lastline and, if need be, swap
1530 "them around if the top line is below the bottom
1531 let l:firstline = a:topLine
1532 let l:lastline = a:bottomLine
1533 if firstline > lastline
1534 let firstline = lastline
1535 let lastline = a:topLine
1538 "go thru each line uncommenting each line removing sexy comments
1539 let currentLine = firstline
1540 while currentLine <= lastline
1542 "check the current line to see if it is part of a sexy comment
1543 let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
1544 if !empty(sexyComBounds)
1546 "we need to store the num lines in the buf before the comment is
1547 "removed so we know how many lines were removed when the sexy com
1549 let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
1551 call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
1553 "move to the line after last line of the sexy comment
1554 let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
1555 let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved
1556 let currentLine = sexyComBounds[1] - numLinesRemoved + 1
1557 let lastline = lastline - numLinesRemoved
1559 "no sexy com was detected so uncomment the line as normal
1561 call s:UncommentLinesNormal(currentLine, currentLine)
1562 let currentLine = currentLine + 1
1568 " Function: s:UncommentLinesSexy(topline, bottomline) {{{2
1569 " This function removes all the comment characters associated with the sexy
1570 " comment spanning the given lines
1572 " -topline/bottomline: the top/bottom lines of the sexy comment
1573 function s:UncommentLinesSexy(topline, bottomline)
1574 let left = s:GetSexyComLeft(0,1)
1575 let right = s:GetSexyComRight(0,1)
1578 "check if it is even possible for sexy comments to exist with the
1579 "available delimiters
1580 if left == -1 || right == -1
1581 throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.'
1584 let leftUnEsc = s:GetSexyComLeft(0,0)
1585 let rightUnEsc = s:GetSexyComRight(0,0)
1587 let sexyComMarker = s:GetSexyComMarker(0, 1)
1588 let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
1590 "the markerOffset is how far right we need to move the sexyComMarker to
1591 "line it up with the end of the left delim
1592 let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc)
1594 " go thru the intermediate lines of the sexy comment and remove the
1595 " sexy comment markers (eg the '*'s on the start of line in a c sexy
1597 let currentLine = a:topline+1
1598 while currentLine < a:bottomline
1599 let theLine = getline(currentLine)
1601 " remove the sexy comment marker from the line. We also remove the
1602 " space after it if there is one and if appropriate options are set
1603 let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
1604 if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1605 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
1607 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1610 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1612 let theLine = s:ConvertLeadingWhiteSpace(theLine)
1614 " move onto the next line
1615 call setline(currentLine, theLine)
1616 let currentLine = currentLine + 1
1619 " gotta make a copy of a:bottomline cos we modify the position of the
1620 " last line it if we remove the topline
1621 let bottomline = a:bottomline
1623 " get the first line so we can remove the left delim from it
1624 let theLine = getline(a:topline)
1626 " if the first line contains only the left delim then just delete it
1627 if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs
1628 call cursor(a:topline, 1)
1630 let bottomline = bottomline - 1
1632 " topline contains more than just the left delim
1635 " remove the delim. If there is a space after it
1636 " then remove this too if appropriate
1637 let delimIndx = stridx(theLine, leftUnEsc)
1638 if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1639 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr)
1641 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
1643 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1644 call setline(a:topline, theLine)
1647 " get the last line so we can remove the right delim
1648 let theLine = getline(bottomline)
1650 " if the bottomline contains only the right delim then just delete it
1651 if theLine =~ '^[ \t]*' . right . '[ \t]*$'
1652 call cursor(bottomline, 1)
1655 " the last line contains more than the right delim
1657 " remove the right delim. If there is a space after it and
1658 " if the appropriate options are set then remove this too.
1659 let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine)
1660 if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1661 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr)
1663 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
1666 " if the last line also starts with a sexy comment marker then we
1667 " remove this as well
1668 if theLine =~ '^[ \t]*' . sexyComMarker
1670 " remove the sexyComMarker. If there is a space after it then
1672 let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
1673 if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1674 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
1676 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1680 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1681 call setline(bottomline, theLine)
1685 " Function: s:UncommentLineNormal(line) {{{2
1686 " uncomments the given line and returns the result
1688 " -line: the line to uncomment
1689 function s:UncommentLineNormal(line)
1692 "get the comment status on the line so we know how it is commented
1693 let lineCommentStatus = s:IsCommentedOuttermost(b:NERDLeft, b:NERDRight, b:NERDLeftAlt, b:NERDRightAlt, line)
1695 "it is commented with b:NERDLeft and b:NERDRight so remove these delims
1696 if lineCommentStatus == 1
1697 let line = s:RemoveDelimiters(b:NERDLeft, b:NERDRight, line)
1699 "it is commented with b:NERDLeftAlt and b:NERDRightAlt so remove these delims
1700 elseif lineCommentStatus == 2 && g:NERDRemoveAltComs
1701 let line = s:RemoveDelimiters(b:NERDLeftAlt, b:NERDRightAlt, line)
1703 "it is not properly commented with any delims so we check if it has
1704 "any random left or right delims on it and remove the outtermost ones
1706 "get the positions of all delim types on the line
1707 let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line)
1708 let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line)
1709 let indxRight = s:FindDelimiterIndex(b:NERDRight, line)
1710 let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line)
1712 "remove the outter most left comment delim
1713 if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1)
1714 let line = s:RemoveDelimiters(b:NERDLeft, '', line)
1715 elseif indxLeftAlt != -1
1716 let line = s:RemoveDelimiters(b:NERDLeftAlt, '', line)
1719 "remove the outter most right comment delim
1720 if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1)
1721 let line = s:RemoveDelimiters('', b:NERDRight, line)
1722 elseif indxRightAlt != -1
1723 let line = s:RemoveDelimiters('', b:NERDRightAlt, line)
1728 let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line)
1729 let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line)
1730 let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line)
1732 let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
1733 let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line)
1734 let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
1736 let right = b:NERDRight
1737 let left = b:NERDLeft
1739 let right = b:NERDRightAlt
1740 let left = b:NERDLeftAlt
1744 "if there are place-holders on the line then we check to see if they are
1745 "the outtermost delimiters on the line. If so then we replace them with
1747 if indxLeftPlace != -1
1748 if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
1749 let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
1751 elseif indxRightPlace != -1
1752 if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
1753 let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
1758 let line = s:ConvertLeadingWhiteSpace(line)
1763 " Function: s:UncommentLinesNormal(topline, bottomline) {{{2
1764 " This function is called to uncomment lines that arent a sexy comment
1766 " -topline/bottomline: the top/bottom line numbers of the comment
1767 function s:UncommentLinesNormal(topline, bottomline)
1768 let currentLine = a:topline
1769 while currentLine <= a:bottomline
1770 let line = getline(currentLine)
1771 call setline(currentLine, s:UncommentLineNormal(line))
1772 let currentLine = currentLine + 1
1777 " Section: Other helper functions {{{1
1778 " ============================================================================
1780 " Function: s:AddLeftDelim(delim, theLine) {{{2
1782 function s:AddLeftDelim(delim, theLine)
1783 return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '')
1786 " Function: s:AddLeftDelimAligned(delim, theLine) {{{2
1788 function s:AddLeftDelimAligned(delim, theLine, alignIndx)
1790 "if the line is not long enough then bung some extra spaces on the front
1791 "so we can align the delim properly
1792 let theLine = a:theLine
1793 if strlen(theLine) < a:alignIndx
1794 let theLine = repeat(' ', a:alignIndx - strlen(theLine))
1797 return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
1800 " Function: s:AddRightDelim(delim, theLine) {{{2
1802 function s:AddRightDelim(delim, theLine)
1806 return substitute(a:theLine, '$', a:delim, '')
1810 " Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2
1812 function s:AddRightDelimAligned(delim, theLine, alignIndx)
1817 " when we align the right delim we are just adding spaces
1818 " so we get a string containing the needed spaces (it
1820 let extraSpaces = ''
1821 let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine))
1823 " add the right delim
1824 return substitute(a:theLine, '$', extraSpaces . a:delim, '')
1828 " Function: s:AltMultipart() {{{2
1829 " returns 1 if the alternative delims are multipart
1830 function s:AltMultipart()
1831 return b:NERDRightAlt != ''
1834 " Function: s:CanCommentLine(forceNested, line) {{{2
1835 "This function is used to determine whether the given line can be commented.
1836 "It returns 1 if it can be and 0 otherwise
1839 " -forceNested: a flag indicating whether the caller wants comments to be nested
1840 " if the current line is already commented
1841 " -lineNum: the line num of the line to check for commentability
1842 function s:CanCommentLine(forceNested, lineNum)
1843 let theLine = getline(a:lineNum)
1845 " make sure we don't comment lines that are just spaces or tabs or empty.
1846 if theLine =~ "^[ \t]*$"
1850 "if the line is part of a sexy comment then just flag it...
1851 if s:IsInSexyComment(a:lineNum)
1855 let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
1857 "if the line isnt commented return true
1862 "if the line is commented but nesting is allowed then return true
1863 if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)
1870 " Function: s:CanPlaceCursor(line, col) {{{2
1871 " returns 1 if the cursor can be placed exactly in the given position
1872 function s:CanPlaceCursor(line, col)
1875 call cursor(a:line, a:col)
1876 let success = (line(".") == a:line && col(".") == a:col)
1881 " Function: s:CanSexyCommentLines(topline, bottomline) {{{2
1882 " Return: 1 if the given lines can be commented sexually, 0 otherwise
1883 function s:CanSexyCommentLines(topline, bottomline)
1884 " see if the selected regions have any sexy comments
1885 let currentLine = a:topline
1886 while(currentLine <= a:bottomline)
1887 if s:IsInSexyComment(currentLine)
1890 let currentLine = currentLine + 1
1894 " Function: s:CanToggleCommentLine(forceNested, line) {{{2
1895 "This function is used to determine whether the given line can be toggle commented.
1896 "It returns 1 if it can be and 0 otherwise
1899 " -lineNum: the line num of the line to check for commentability
1900 function s:CanToggleCommentLine(forceNested, lineNum)
1901 let theLine = getline(a:lineNum)
1902 if (s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)) && !a:forceNested
1906 " make sure we don't comment lines that are just spaces or tabs or empty.
1907 if theLine =~ "^[ \t]*$"
1911 "if the line is part of a sexy comment then just flag it...
1912 if s:IsInSexyComment(a:lineNum)
1919 " Function: s:ConvertLeadingSpacesToTabs(line) {{{2
1920 " This function takes a line and converts all leading tabs on that line into
1924 " -line: the line whose leading tabs will be converted
1925 function s:ConvertLeadingSpacesToTabs(line)
1926 let toReturn = a:line
1927 while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$'
1928 let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "")
1935 " Function: s:ConvertLeadingTabsToSpaces(line) {{{2
1936 " This function takes a line and converts all leading spaces on that line into
1940 " -line: the line whose leading spaces will be converted
1941 function s:ConvertLeadingTabsToSpaces(line)
1942 let toReturn = a:line
1943 while toReturn =~ '^\( *\)\t'
1944 let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "")
1950 " Function: s:ConvertLeadingWhiteSpace(line) {{{2
1951 " Converts the leading white space to tabs/spaces depending on &ts
1954 " -line: the line to convert
1955 function s:ConvertLeadingWhiteSpace(line)
1956 let toReturn = a:line
1957 while toReturn =~ '^ *\t'
1958 let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g")
1962 let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
1969 " Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2
1970 " This function counts the number of substrings contained in another string.
1971 " These substrings are only counted if they are not escaped with escChar
1973 " -str: the string to look for searchstr in
1974 " -searchstr: the substring to search for in str
1975 " -escChar: the escape character which, when preceding an instance of
1976 " searchstr, will cause it not to be counted
1977 function s:CountNonESCedOccurances(str, searchstr, escChar)
1978 "get the index of the first occurrence of searchstr
1979 let indx = stridx(a:str, a:searchstr)
1981 "if there is an instance of searchstr in str process it
1983 "get the remainder of str after this instance of searchstr is removed
1984 let lensearchstr = strlen(a:searchstr)
1985 let strLeft = strpart(a:str, indx+lensearchstr)
1987 "if this instance of searchstr is not escaped, add one to the count
1988 "and recurse. If it is escaped, just recurse
1989 if !s:IsEscaped(a:str, indx, a:escChar)
1990 return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
1992 return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
1996 " Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2
1997 " Returns 1 if the given block of lines has a delimiter (a:delim) in it
1999 " -delim: the comment delimiter to check the block for
2000 " -top: the top line number of the block
2001 " -bottom: the bottom line number of the block
2002 function s:DoesBlockHaveDelim(delim, top, bottom)
2003 let currentLine = a:top
2004 while currentLine < a:bottom
2005 let theline = getline(currentLine)
2006 if s:FindDelimiterIndex(a:delim, theline) != -1
2009 let currentLine = currentLine + 1
2014 " Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2
2015 " Returns 1 if the given block has a >= 1 multipart delimiter in it
2017 " -top: the top line number of the block
2018 " -bottom: the bottom line number of the block
2019 function s:DoesBlockHaveMultipartDelim(top, bottom)
2020 if s:HasMultipartDelims()
2022 return s:DoesBlockHaveDelim(b:NERDLeft, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRight, a:top, a:bottom)
2024 return s:DoesBlockHaveDelim(b:NERDLeftAlt, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRightAlt, a:top, a:bottom)
2031 " Function: s:Esc(str) {{{2
2032 " Escapes all the tricky chars in the given string
2034 let charsToEsc = '*/\."&$+'
2035 return escape(a:str, charsToEsc)
2038 " Function: s:FindDelimiterIndex(delimiter, line) {{{2
2039 " This function is used to get the string index of the input comment delimiter
2040 " on the input line. If no valid comment delimiter is found in the line then
2043 " -delimiter: the delimiter we are looking to find the index of
2044 " -line: the line we are looking for delimiter on
2045 function s:FindDelimiterIndex(delimiter, line)
2047 "make sure the delimiter isnt empty otherwise we go into an infinite loop.
2048 if a:delimiter == ""
2053 let l:delimiter = a:delimiter
2054 let lenDel = strlen(l:delimiter)
2056 "get the index of the first occurrence of the delimiter
2057 let delIndx = stridx(a:line, l:delimiter)
2059 "keep looping thru the line till we either find a real comment delimiter
2063 "if we are not off the EOL get the str before the possible delimiter
2064 "in question and check if it really is a delimiter. If it is, return
2067 if s:IsDelimValid(l:delimiter, delIndx, a:line)
2072 "we have not yet found a real comment delimiter so move past the
2073 "current one we are lookin at
2074 let restOfLine = strpart(a:line, delIndx + lenDel)
2075 let distToNextDelim = stridx(restOfLine , l:delimiter)
2077 "if distToNextDelim is -1 then there is no more potential delimiters
2078 "on the line so set delIndx to -1. Otherwise, move along the line by
2080 if distToNextDelim == -1
2083 let delIndx = delIndx + lenDel + distToNextDelim
2087 "there is no comment delimiter on this line
2091 " Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2
2092 " This function takes in a line number and tests whether this line number is
2093 " the top/bottom/middle line of a sexy comment. If it is then the top/bottom
2094 " lines of the sexy comment are returned
2096 " -lineNum: the line number that is to be tested whether it is the
2097 " top/bottom/middle line of a sexy com
2099 " A string that has the top/bottom lines of the sexy comment encoded in it.
2100 " The format is 'topline,bottomline'. If a:lineNum turns out not to be the
2101 " top/bottom/middle of a sexy comment then -1 is returned
2102 function s:FindBoundingLinesOfSexyCom(lineNum)
2104 "find which delimiters to look for as the start/end delims of the comment
2108 let left = s:GetLeft(0,0,1)
2109 let right = s:GetRight(0,0,1)
2110 elseif s:AltMultipart()
2111 let left = s:GetLeft(1,0,1)
2112 let right = s:GetRight(1,0,1)
2117 let sexyComMarker = s:GetSexyComMarker(0, 1)
2119 "initialise the top/bottom line numbers of the sexy comment to -1
2123 let currentLine = a:lineNum
2124 while top == -1 || bottom == -1
2125 let theLine = getline(currentLine)
2127 "check if the current line is the top of the sexy comment
2128 if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf()
2129 let top = currentLine
2130 let currentLine = a:lineNum
2132 "check if the current line is the bottom of the sexy comment
2133 elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1
2134 let bottom = currentLine
2136 "the right delimiter is on the same line as the last sexyComMarker
2137 elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right
2138 let bottom = currentLine
2140 "we have not found the top or bottom line so we assume currentLine is an
2141 "intermediate line and look to prove otherwise
2144 "if the line doesnt start with a sexyComMarker then it is not a sexy
2146 if theLine !~ '^[ \t]*' . sexyComMarker
2152 "if top is -1 then we havent found the top yet so keep looking up
2154 let currentLine = currentLine - 1
2155 "if we have found the top line then go down looking for the bottom
2157 let currentLine = currentLine + 1
2162 return [top, bottom]
2166 " Function: s:GetLeft(alt, space, esc) {{{2
2167 " returns the left/left-alternative delimiter
2169 " -alt: specifies whether to get left or left-alternative delim
2170 " -space: specifies whether the delim should be spaced or not
2171 " (the space string will only be added if NERDSpaceDelims is set)
2172 " -esc: specifies whether the tricky chars in the delim should be ESCed
2173 function s:GetLeft(alt, space, esc)
2174 let delim = b:NERDLeft
2177 if b:NERDLeftAlt == ''
2180 let delim = b:NERDLeftAlt
2187 if a:space && g:NERDSpaceDelims
2188 let delim = delim . s:spaceStr
2192 let delim = s:Esc(delim)
2198 " Function: s:GetRight(alt, space, esc) {{{2
2199 " returns the right/right-alternative delimiter
2201 " -alt: specifies whether to get right or right-alternative delim
2202 " -space: specifies whether the delim should be spaced or not
2203 " (the space string will only be added if NERDSpaceDelims is set)
2204 " -esc: specifies whether the tricky chars in the delim should be ESCed
2205 function s:GetRight(alt, space, esc)
2206 let delim = b:NERDRight
2209 if !s:AltMultipart()
2212 let delim = b:NERDRightAlt
2219 if a:space && g:NERDSpaceDelims
2220 let delim = s:spaceStr . delim
2224 let delim = s:Esc(delim)
2231 " Function: s:GetSexyComMarker() {{{2
2232 " Returns the sexy comment marker for the current filetype.
2234 " C style sexy comments are assumed if possible. If not then the sexy comment
2235 " marker is the last char of the delimiter pair that has both left and right
2236 " delims and has the longest left delim
2239 " -space: specifies whether the marker is to have a space string after it
2240 " (the space string will only be added if NERDSpaceDelims is set)
2241 " -esc: specifies whether the tricky chars in the marker are to be ESCed
2242 function s:GetSexyComMarker(space, esc)
2243 let sexyComMarker = b:NERDSexyComMarker
2245 "if there is no hardcoded marker then we find one
2246 if sexyComMarker == ''
2248 "if the filetype has c style comments then use standard c sexy
2250 if s:HasCStyleComments()
2251 let sexyComMarker = '*'
2253 "find a comment marker by getting the longest available left delim
2254 "(that has a corresponding right delim) and taking the last char
2255 let lenLeft = strlen(b:NERDLeft)
2256 let lenLeftAlt = strlen(b:NERDLeftAlt)
2259 if s:Multipart() && lenLeft >= lenLeftAlt
2260 let left = b:NERDLeft
2261 elseif s:AltMultipart()
2262 let left = b:NERDLeftAlt
2267 "get the last char of left
2268 let sexyComMarker = strpart(left, strlen(left)-1)
2272 if a:space && g:NERDSpaceDelims
2273 let sexyComMarker = sexyComMarker . s:spaceStr
2277 let sexyComMarker = s:Esc(sexyComMarker)
2280 return sexyComMarker
2283 " Function: s:GetSexyComLeft(space, esc) {{{2
2284 " Returns the left delimiter for sexy comments for this filetype or -1 if
2285 " there is none. C style sexy comments are used if possible
2287 " -space: specifies if the delim has a space string on the end
2288 " (the space string will only be added if NERDSpaceDelims is set)
2289 " -esc: specifies whether the tricky chars in the string are ESCed
2290 function s:GetSexyComLeft(space, esc)
2291 let lenLeft = strlen(b:NERDLeft)
2292 let lenLeftAlt = strlen(b:NERDLeftAlt)
2295 "assume c style sexy comments if possible
2296 if s:HasCStyleComments()
2299 "grab the longest left delim that has a right
2300 if s:Multipart() && lenLeft >= lenLeftAlt
2301 let left = b:NERDLeft
2302 elseif s:AltMultipart()
2303 let left = b:NERDLeftAlt
2309 if a:space && g:NERDSpaceDelims
2310 let left = left . s:spaceStr
2314 let left = s:Esc(left)
2320 " Function: s:GetSexyComRight(space, esc) {{{2
2321 " Returns the right delimiter for sexy comments for this filetype or -1 if
2322 " there is none. C style sexy comments are used if possible.
2324 " -space: specifies if the delim has a space string on the start
2325 " (the space string will only be added if NERDSpaceDelims
2326 " is specified for the current filetype)
2327 " -esc: specifies whether the tricky chars in the string are ESCed
2328 function s:GetSexyComRight(space, esc)
2329 let lenLeft = strlen(b:NERDLeft)
2330 let lenLeftAlt = strlen(b:NERDLeftAlt)
2333 "assume c style sexy comments if possible
2334 if s:HasCStyleComments()
2337 "grab the right delim that pairs with the longest left delim
2338 if s:Multipart() && lenLeft >= lenLeftAlt
2339 let right = b:NERDRight
2340 elseif s:AltMultipart()
2341 let right = b:NERDRightAlt
2347 if a:space && g:NERDSpaceDelims
2348 let right = s:spaceStr . right
2352 let right = s:Esc(right)
2358 " Function: s:HasMultipartDelims() {{{2
2359 " Returns 1 iff the current filetype has at least one set of multipart delims
2360 function s:HasMultipartDelims()
2361 return s:Multipart() || s:AltMultipart()
2364 " Function: s:HasLeadingTabs(...) {{{2
2365 " Returns 1 if any of the given strings have leading tabs
2366 function s:HasLeadingTabs(...)
2374 " Function: s:HasCStyleComments() {{{2
2375 " Returns 1 iff the current filetype has c style comment delimiters
2376 function s:HasCStyleComments()
2377 return (b:NERDLeft == '/*' && b:NERDRight == '*/') || (b:NERDLeftAlt == '/*' && b:NERDRightAlt == '*/')
2380 " Function: s:IsCommentedNormOrSexy(lineNum) {{{2
2381 "This function is used to determine whether the given line is commented with
2382 "either set of delimiters or if it is part of a sexy comment
2385 " -lineNum: the line number of the line to check
2386 function s:IsCommentedNormOrSexy(lineNum)
2387 let theLine = getline(a:lineNum)
2389 "if the line is commented normally return 1
2390 if s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)
2394 "if the line is part of a sexy comment return 1
2395 if s:IsInSexyComment(a:lineNum)
2401 " Function: s:IsCommented(left, right, line) {{{2
2402 "This function is used to determine whether the given line is commented with
2403 "the given delimiters
2406 " -line: the line that to check if commented
2407 " -left/right: the left and right delimiters to check for
2408 function s:IsCommented(left, right, line)
2409 "if the line isnt commented return true
2410 if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart())
2416 " Function: s:IsCommentedFromStartOfLine(left, line) {{{2
2417 "This function is used to determine whether the given line is commented with
2418 "the given delimiters at the start of the line i.e the left delimiter is the
2419 "first thing on the line (apart from spaces\tabs)
2422 " -line: the line that to check if commented
2423 " -left: the left delimiter to check for
2424 function s:IsCommentedFromStartOfLine(left, line)
2425 let theLine = s:ConvertLeadingTabsToSpaces(a:line)
2426 let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', ''))
2427 let delimIndx = s:FindDelimiterIndex(a:left, theLine)
2428 return delimIndx == numSpaces
2431 " Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2
2432 " Finds the type of the outtermost delims on the line
2435 " -line: the line that to check if the outtermost comments on it are
2437 " -left/right: the left and right delimiters to check for
2438 " -leftAlt/rightAlt: the left and right alternative delimiters to check for
2441 " 0 if the line is not commented with either set of delims
2442 " 1 if the line is commented with the left/right delim set
2443 " 2 if the line is commented with the leftAlt/rightAlt delim set
2444 function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line)
2445 "get the first positions of the left delims and the last positions of the
2447 let indxLeft = s:FindDelimiterIndex(a:left, a:line)
2448 let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line)
2449 let indxRight = s:LastIndexOfDelim(a:right, a:line)
2450 let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line)
2452 "check if the line has a left delim before a leftAlt delim
2453 if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1
2454 "check if the line has a right delim after any rightAlt delim
2455 if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart()
2459 "check if the line has a leftAlt delim before a left delim
2460 elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1
2461 "check if the line has a rightAlt delim after any right delim
2462 if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart()
2474 " Function: s:IsDelimValid(delimiter, delIndx, line) {{{2
2475 " This function is responsible for determining whether a given instance of a
2476 " comment delimiter is a real delimiter or not. For example, in java the
2477 " // string is a comment delimiter but in the line:
2478 " System.out.println("//");
2479 " it does not count as a comment delimiter. This function is responsible for
2480 " distinguishing between such cases. It does so by applying a set of
2481 " heuristics that are not fool proof but should work most of the time.
2484 " -delimiter: the delimiter we are validating
2485 " -delIndx: the position of delimiter in line
2486 " -line: the line that delimiter occurs in
2489 " 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
2491 function s:IsDelimValid(delimiter, delIndx, line)
2492 "get the delimiter without the escchars
2493 let l:delimiter = a:delimiter
2495 "get the strings before and after the delimiter
2496 let preComStr = strpart(a:line, 0, a:delIndx)
2497 let postComStr = strpart(a:line, a:delIndx+strlen(delimiter))
2499 "to check if the delimiter is real, make sure it isnt preceded by
2500 "an odd number of quotes and followed by the same (which would indicate
2501 "that it is part of a string and therefore is not a comment)
2502 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\"))
2505 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\"))
2508 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\"))
2513 "if the comment delimiter is escaped, assume it isnt a real delimiter
2514 if s:IsEscaped(a:line, a:delIndx, "\\")
2518 "vim comments are so fuckin stupid!! Why the hell do they have comment
2519 "delimiters that are used elsewhere in the syntax?!?! We need to check
2520 "some conditions especially for vim
2521 if &filetype == "vim"
2522 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\"))
2526 "if the delimiter is on the very first char of the line or is the
2527 "first non-tab/space char on the line then it is a valid comment delimiter
2528 if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$"
2532 let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\")
2533 let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\")
2535 "if the quote is inside brackets then assume it isnt a comment
2536 if numLeftParen > numRightParen
2540 "if the line has an even num of unescaped "'s then we can assume that
2541 "any given " is not a comment delimiter
2542 if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\"))
2551 " Function: s:IsNumEven(num) {{{2
2552 " A small function the returns 1 if the input number is even and 0 otherwise
2554 " -num: the number to check
2555 function s:IsNumEven(num)
2556 return (a:num % 2) == 0
2559 " Function: s:IsEscaped(str, indx, escChar) {{{2
2560 " This function takes a string, an index into that string and an esc char and
2561 " returns 1 if the char at the index is escaped (i.e if it is preceded by an
2562 " odd number of esc chars)
2564 " -str: the string to check
2565 " -indx: the index into str that we want to check
2566 " -escChar: the escape char the char at indx may be ESCed with
2567 function s:IsEscaped(str, indx, escChar)
2568 "initialise numEscChars to 0 and look at the char before indx
2570 let curIndx = a:indx-1
2572 "keep going back thru str until we either reach the start of the str or
2573 "run out of esc chars
2574 while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar
2576 "we have found another esc char so add one to the count and move left
2578 let numEscChars = numEscChars + 1
2579 let curIndx = curIndx - 1
2583 "if there is an odd num of esc chars directly before the char at indx then
2584 "the char at indx is escaped
2585 return !s:IsNumEven(numEscChars)
2588 " Function: s:IsInSexyComment(line) {{{2
2589 " returns 1 if the given line number is part of a sexy comment
2590 function s:IsInSexyComment(line)
2591 return !empty(s:FindBoundingLinesOfSexyCom(a:line))
2594 " Function: s:IsSexyComment(topline, bottomline) {{{2
2595 " This function takes in 2 line numbers and returns 1 if the lines between and
2596 " including the given line numbers are a sexy comment. It returns 0 otherwise.
2598 " -topline: the line that the possible sexy comment starts on
2599 " -bottomline: the line that the possible sexy comment stops on
2600 function s:IsSexyComment(topline, bottomline)
2602 "get the delim set that would be used for a sexy comment
2606 let left = b:NERDLeft
2607 let right = b:NERDRight
2608 elseif s:AltMultipart()
2609 let left = b:NERDLeftAlt
2610 let right = b:NERDRightAlt
2615 "swap the top and bottom line numbers around if need be
2616 let topline = a:topline
2617 let bottomline = a:bottomline
2618 if bottomline < topline
2619 topline = bottomline
2620 bottomline = a:topline
2623 "if there is < 2 lines in the comment it cannot be sexy
2624 if (bottomline - topline) <= 0
2628 "if the top line doesnt begin with a left delim then the comment isnt sexy
2629 if getline(a:topline) !~ '^[ \t]*' . left
2633 "if there is a right delim on the top line then this isnt a sexy comment
2634 if s:FindDelimiterIndex(right, getline(a:topline)) != -1
2638 "if there is a left delim on the bottom line then this isnt a sexy comment
2639 if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1
2643 "if the bottom line doesnt begin with a right delim then the comment isnt
2645 if getline(a:bottomline) !~ '^.*' . right . '$'
2649 let sexyComMarker = s:GetSexyComMarker(0, 1)
2651 "check each of the intermediate lines to make sure they start with a
2653 let currentLine = a:topline+1
2654 while currentLine < a:bottomline
2655 let theLine = getline(currentLine)
2657 if theLine !~ '^[ \t]*' . sexyComMarker
2661 "if there is a right delim in an intermediate line then the block isnt
2663 if s:FindDelimiterIndex(right, theLine) != -1
2667 let currentLine = currentLine + 1
2670 "we have not found anything to suggest that this isnt a sexy comment so
2675 " Function: s:LastIndexOfDelim(delim, str) {{{2
2676 " This function takes a string and a delimiter and returns the last index of
2677 " that delimiter in string
2679 " -delim: the delimiter to look for
2680 " -str: the string to look for delim in
2681 function s:LastIndexOfDelim(delim, str)
2683 let lenDelim = strlen(delim)
2685 "set index to the first occurrence of delim. If there is no occurrence then
2687 let indx = s:FindDelimiterIndex(delim, a:str)
2692 "keep moving to the next instance of delim in str till there is none left
2695 "search for the next delim after the previous one
2696 let searchStr = strpart(a:str, indx+lenDelim)
2697 let indx2 = s:FindDelimiterIndex(delim, searchStr)
2699 "if we find a delim update indx to record the position of it, if we
2700 "dont find another delim then indx is the last one so break out of
2703 let indx = indx + indx2 + lenDelim
2713 " Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
2714 " This function takes in 2 line numbers and returns the index of the left most
2715 " char (that is not a space or a tab) on all of these lines.
2717 " -countCommentedLines: 1 if lines that are commented are to be checked as
2719 " -countEmptyLines: 1 if empty lines are to be counted in the search
2720 " -topline: the top line to be checked
2721 " -bottomline: the bottom line to be checked
2722 function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
2724 " declare the left most index as an extreme value
2725 let leftMostIndx = 1000
2727 " go thru the block line by line updating leftMostIndx
2728 let currentLine = a:topline
2729 while currentLine <= a:bottomline
2731 " get the next line and if it is allowed to be commented, or is not
2732 " commented, check it
2733 let theLine = getline(currentLine)
2734 if a:countEmptyLines || theLine !~ '^[ \t]*$'
2735 if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine))
2736 " convert spaces to tabs and get the number of leading spaces for
2737 " this line and update leftMostIndx if need be
2738 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
2739 let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') )
2740 if leadSpaceOfLine < leftMostIndx
2741 let leftMostIndx = leadSpaceOfLine
2746 " move on to the next line
2747 let currentLine = currentLine + 1
2750 if leftMostIndx == 1000
2757 " Function: s:Multipart() {{{2
2758 " returns 1 if the current delims are multipart
2759 function s:Multipart()
2760 return b:NERDRight != ''
2763 " Function: s:NerdEcho(msg, typeOfMsg) {{{2
2765 " -msg: the message to echo
2766 " -typeOfMsg: 0 = warning message
2767 " 1 = normal message
2768 function s:NerdEcho(msg, typeOfMsg)
2771 echo 'NERDCommenter:' . a:msg
2773 elseif a:typeOfMsg == 1
2774 echo 'NERDCommenter:' . a:msg
2778 " Function: s:NumberOfLeadingTabs(s) {{{2
2779 " returns the number of leading tabs in the given string
2780 function s:NumberOfLeadingTabs(s)
2781 return strlen(substitute(a:s, '^\(\t*\).*$', '\1', ""))
2784 " Function: s:NumLinesInBuf() {{{2
2785 " Returns the number of lines in the current buffer
2786 function s:NumLinesInBuf()
2790 " Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2
2791 " This function takes in a string, 2 delimiters in that string and 2 strings
2792 " to replace these delimiters with.
2795 " -toReplace1: the first delimiter to replace
2796 " -toReplace2: the second delimiter to replace
2797 " -replacor1: the string to replace toReplace1 with
2798 " -replacor2: the string to replace toReplace2 with
2799 " -str: the string that the delimiters to be replaced are in
2800 function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str)
2801 let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str)
2802 let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line)
2806 " Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2
2807 " This function takes a string and a delimiter and replaces the left most
2808 " occurrence of this delimiter in the string with a given string
2811 " -toReplace: the delimiter in str that is to be replaced
2812 " -replacor: the string to replace toReplace with
2813 " -str: the string that contains toReplace
2814 function s:ReplaceLeftMostDelim(toReplace, replacor, str)
2815 let toReplace = a:toReplace
2816 let replacor = a:replacor
2817 "get the left most occurrence of toReplace
2818 let indxToReplace = s:FindDelimiterIndex(toReplace, a:str)
2820 "if there IS an occurrence of toReplace in str then replace it and return
2821 "the resulting string
2822 if indxToReplace != -1
2823 let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
2830 " Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2
2831 " This function takes a string and a delimiter and replaces the right most
2832 " occurrence of this delimiter in the string with a given string
2835 " -toReplace: the delimiter in str that is to be replaced
2836 " -replacor: the string to replace toReplace with
2837 " -str: the string that contains toReplace
2839 function s:ReplaceRightMostDelim(toReplace, replacor, str)
2840 let toReplace = a:toReplace
2841 let replacor = a:replacor
2842 let lenToReplace = strlen(toReplace)
2844 "get the index of the last delim in str
2845 let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
2847 "if there IS a delimiter in str, replace it and return the result
2849 if indxToReplace != -1
2850 let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
2855 "FUNCTION: s:RestoreScreenState() {{{2
2857 "Sets the screen state back to what it was when s:SaveScreenState was last
2860 function s:RestoreScreenState()
2861 if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos")
2862 throw 'NERDCommenter exception: cannot restore screen'
2865 call cursor(t:NERDComOldTopLine, 0)
2867 call setpos(".", t:NERDComOldPos)
2870 " Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
2871 " This function takes in 2 line numbers and returns the index of the right most
2872 " char on all of these lines.
2874 " -countCommentedLines: 1 if lines that are commented are to be checked as
2876 " -countEmptyLines: 1 if empty lines are to be counted in the search
2877 " -topline: the top line to be checked
2878 " -bottomline: the bottom line to be checked
2879 function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
2880 let rightMostIndx = -1
2882 " go thru the block line by line updating rightMostIndx
2883 let currentLine = a:topline
2884 while currentLine <= a:bottomline
2886 " get the next line and see if it is commentable, otherwise it doesnt
2888 let theLine = getline(currentLine)
2889 if a:countEmptyLines || theLine !~ '^[ \t]*$'
2891 if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine))
2893 " update rightMostIndx if need be
2894 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
2895 let lineLen = strlen(theLine)
2896 if lineLen > rightMostIndx
2897 let rightMostIndx = lineLen
2902 " move on to the next line
2903 let currentLine = currentLine + 1
2906 return rightMostIndx
2909 "FUNCTION: s:SaveScreenState() {{{2
2910 "Saves the current cursor position in the current buffer and the window
2912 function s:SaveScreenState()
2913 let t:NERDComOldPos = getpos(".")
2914 let t:NERDComOldTopLine = line("w0")
2917 " Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2
2918 " This function takes a line and swaps the outter most multi-part delims for
2921 " -line: the line to swap the delims in
2923 function s:SwapOutterMultiPartDelimsForPlaceHolders(line)
2924 " find out if the line is commented using normal delims and/or
2926 let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, a:line)
2927 let isCommentedAlt = s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, a:line)
2931 "if the line is commented and there is a right delimiter, replace
2932 "the delims with place-holders
2933 if isCommented && s:Multipart()
2934 let line2 = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, a:line)
2936 "similarly if the line is commented with the alternative
2938 elseif isCommentedAlt && s:AltMultipart()
2939 let line2 = s:ReplaceDelims(b:NERDLeftAlt, b:NERDRightAlt, g:NERDLPlace, g:NERDRPlace, a:line)
2945 " Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2
2946 " This function takes a line and swaps the outtermost place holders for
2949 " -line: the line to swap the delims in
2951 function s:SwapOutterPlaceHoldersForMultiPartDelims(line)
2955 let left = b:NERDLeft
2956 let right = b:NERDRight
2957 elseif s:AltMultipart()
2958 let left = b:NERDLeftAlt
2959 let right = b:NERDRightAlt
2962 let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
2965 " Function: s:TabbedCol(line, col) {{{2
2966 " Gets the col number for given line and existing col number. The new col
2967 " number is the col number when all leading spaces are converted to tabs
2969 " -line:the line to get the rel col for
2971 function s:TabbedCol(line, col)
2972 let lineTruncated = strpart(a:line, 0, a:col)
2973 let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g')
2974 return strlen(lineSpacesToTabs)
2976 "FUNCTION: s:TabSpace() {{{2
2977 "returns a string of spaces equal in length to &tabstop
2978 function s:TabSpace()
2980 let spacesPerTab = &tabstop
2981 while spacesPerTab > 0
2982 let tabSpace = tabSpace . " "
2983 let spacesPerTab = spacesPerTab - 1
2988 " Function: s:UnEsc(str, escChar) {{{2
2989 " This function removes all the escape chars from a string
2991 " -str: the string to remove esc chars from
2992 " -escChar: the escape char to be removed
2993 function s:UnEsc(str, escChar)
2994 return substitute(a:str, a:escChar, "", "g")
2997 " Function: s:UntabbedCol(line, col) {{{2
2998 " Takes a line and a col and returns the absolute column of col taking into
2999 " account that a tab is worth 3 or 4 (or whatever) spaces.
3001 " -line:the line to get the abs col for
3002 " -col: the col that doesnt take into account tabs
3003 function s:UntabbedCol(line, col)
3004 let lineTruncated = strpart(a:line, 0, a:col)
3005 let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g')
3006 return strlen(lineTabsToSpaces)
3008 " Section: Comment mapping setup {{{1
3009 " ===========================================================================
3011 " switch to/from alternative delimiters
3012 nnoremap <plug>NERDCommenterAltDelims :call <SID>SwitchToAlternativeDelimiters(1)<cr>
3015 nnoremap <silent> <plug>NERDCommenterComment :call NERDComment(0, "norm")<cr>
3016 vnoremap <silent> <plug>NERDCommenterComment <ESC>:call NERDComment(1, "norm")<cr>
3019 nnoremap <silent> <plug>NERDCommenterToggle :call NERDComment(0, "toggle")<cr>
3020 vnoremap <silent> <plug>NERDCommenterToggle <ESC>:call NERDComment(1, "toggle")<cr>
3023 nnoremap <silent> <plug>NERDCommenterMinimal :call NERDComment(0, "minimal")<cr>
3024 vnoremap <silent> <plug>NERDCommenterMinimal <ESC>:call NERDComment(1, "minimal")<cr>
3027 nnoremap <silent> <plug>NERDCommenterSexy :call NERDComment(0, "sexy")<CR>
3028 vnoremap <silent> <plug>NERDCommenterSexy <ESC>:call NERDComment(1, "sexy")<CR>
3031 nnoremap <silent> <plug>NERDCommenterInvert :call NERDComment(0, "invert")<CR>
3032 vnoremap <silent> <plug>NERDCommenterInvert <ESC>:call NERDComment(1, "invert")<CR>
3035 nmap <silent> <plug>NERDCommenterYank :call NERDComment(0, "yank")<CR>
3036 vmap <silent> <plug>NERDCommenterYank <ESC>:call NERDComment(1, "yank")<CR>
3038 " left aligned comments
3039 nnoremap <silent> <plug>NERDCommenterAlignLeft :call NERDComment(0, "alignLeft")<cr>
3040 vnoremap <silent> <plug>NERDCommenterAlignLeft <ESC>:call NERDComment(1, "alignLeft")<cr>
3042 " left and right aligned comments
3043 nnoremap <silent> <plug>NERDCommenterAlignBoth :call NERDComment(0, "alignBoth")<cr>
3044 vnoremap <silent> <plug>NERDCommenterAlignBoth <ESC>:call NERDComment(1, "alignBoth")<cr>
3047 nnoremap <silent> <plug>NERDCommenterNest :call NERDComment(0, "nested")<cr>
3048 vnoremap <silent> <plug>NERDCommenterNest <ESC>:call NERDComment(1, "nested")<cr>
3051 nnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(0, "uncomment")<cr>
3052 vnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(1, "uncomment")<cr>
3054 " comment till the end of the line
3055 nnoremap <silent> <plug>NERDCommenterToEOL :call NERDComment(0, "toEOL")<cr>
3058 nmap <silent> <plug>NERDCommenterAppend :call NERDComment(0, "append")<cr>
3061 inoremap <silent> <plug>NERDCommenterInInsert <SPACE><BS><ESC>:call NERDComment(0, "insert")<CR>
3064 function! s:CreateMaps(target, combo)
3065 if !hasmapto(a:target, 'n')
3066 exec 'nmap ' . a:combo . ' ' . a:target
3069 if !hasmapto(a:target, 'v')
3070 exec 'vmap ' . a:combo . ' ' . a:target
3074 if g:NERDCreateDefaultMappings
3075 call s:CreateMaps('<plug>NERDCommenterComment', ',cc')
3076 call s:CreateMaps('<plug>NERDCommenterToggle', ',c<space>')
3077 call s:CreateMaps('<plug>NERDCommenterMinimal', ',cm')
3078 call s:CreateMaps('<plug>NERDCommenterSexy', ',cs')
3079 call s:CreateMaps('<plug>NERDCommenterInvert', ',ci')
3080 call s:CreateMaps('<plug>NERDCommenterYank', ',cy')
3081 call s:CreateMaps('<plug>NERDCommenterAlignLeft', ',cl')
3082 call s:CreateMaps('<plug>NERDCommenterAlignBoth', ',cb')
3083 call s:CreateMaps('<plug>NERDCommenterNest', ',cn')
3084 call s:CreateMaps('<plug>NERDCommenterUncomment', ',cu')
3085 call s:CreateMaps('<plug>NERDCommenterToEOL', ',c$')
3086 call s:CreateMaps('<plug>NERDCommenterAppend', ',cA')
3088 if !hasmapto('<plug>NERDCommenterAltDelims', 'n')
3089 nmap ,ca <plug>NERDCommenterAltDelims
3095 " Section: Menu item setup {{{1
3096 " ===========================================================================
3097 "check if the user wants the menu to be displayed
3098 if g:NERDMenuMode != 0
3101 if g:NERDMenuMode == 1
3102 let menuRoot = 'comment'
3103 elseif g:NERDMenuMode == 2
3104 let menuRoot = '&comment'
3105 elseif g:NERDMenuMode == 3
3106 let menuRoot = '&Plugin.&comment'
3109 function! s:CreateMenuItems(target, desc, root)
3110 exec 'nmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
3111 exec 'vmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
3113 call s:CreateMenuItems("<plug>NERDCommenterComment", 'Comment', menuRoot)
3114 call s:CreateMenuItems("<plug>NERDCommenterToggle", 'Toggle', menuRoot)
3115 call s:CreateMenuItems('<plug>NERDCommenterMinimal', 'Minimal', menuRoot)
3116 call s:CreateMenuItems('<plug>NERDCommenterNest', 'Nested', menuRoot)
3117 exec 'nmenu <silent> '. menuRoot .'.To\ EOL <plug>NERDCommenterToEOL'
3118 call s:CreateMenuItems('<plug>NERDCommenterInvert', 'Invert', menuRoot)
3119 call s:CreateMenuItems('<plug>NERDCommenterSexy', 'Sexy', menuRoot)
3120 call s:CreateMenuItems('<plug>NERDCommenterYank', 'Yank\ then\ comment', menuRoot)
3121 exec 'nmenu <silent> '. menuRoot .'.Append <plug>NERDCommenterAppend'
3122 exec 'menu <silent> '. menuRoot .'.-Sep- :'
3123 call s:CreateMenuItems('<plug>NERDCommenterAlignLeft', 'Left\ aligned', menuRoot)
3124 call s:CreateMenuItems('<plug>NERDCommenterAlignBoth', 'Left\ and\ right\ aligned', menuRoot)
3125 exec 'menu <silent> '. menuRoot .'.-Sep2- :'
3126 call s:CreateMenuItems('<plug>NERDCommenterUncomment', 'Uncomment', menuRoot)
3127 exec 'nmenu <silent> '. menuRoot .'.Switch\ Delimiters <plug>NERDCommenterAltDelims'
3128 exec 'imenu <silent> '. menuRoot .'.Insert\ Comment\ Here <plug>NERDCommenterInInsert'
3129 exec 'menu <silent> '. menuRoot .'.-Sep3- :'
3130 exec 'menu <silent>'. menuRoot .'.Help :help NERDCommenterContents<CR>'
3132 " vim: set foldmethod=marker :