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")
22 let loaded_nerd_comments = 1
24 " Function: s:InitVariable() function {{{2
25 " This function is used to initialise a given variable to a given value. The
26 " variable is only initialised if it does not exist prior
29 " -var: the name of the var to be initialised
30 " -value: the value to initialise var to
33 " 1 if the var is set, 0 otherwise
34 function s:InitVariable(var, value)
36 exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
42 " Section: space string init{{{2
43 " When putting spaces after the left delim and before the right we use
44 " s:spaceStr for the space char. This way we can make it add anything after
45 " the left and before the right by modifying this variable
47 let s:lenSpaceStr = strlen(s:spaceStr)
49 " Section: variable init calls {{{2
50 call s:InitVariable("g:NERDAllowAnyVisualDelims", 1)
51 call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0)
52 call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0)
53 call s:InitVariable("g:NERDCompactSexyComs", 0)
54 call s:InitVariable("g:NERDCreateDefaultMappings", 1)
55 call s:InitVariable("g:NERDDefaultNesting", 1)
56 call s:InitVariable("g:NERDMenuMode", 3)
57 call s:InitVariable("g:NERDLPlace", "[>")
58 call s:InitVariable("g:NERDUsePlaceHolders", 1)
59 call s:InitVariable("g:NERDRemoveAltComs", 1)
60 call s:InitVariable("g:NERDRemoveExtraSpaces", 1)
61 call s:InitVariable("g:NERDRPlace", "<]")
62 call s:InitVariable("g:NERDSpaceDelims", 0)
63 call s:InitVariable("g:NERDDelimiterRequests", 1)
67 let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
69 " Section: Comment mapping functions, autocommands and commands {{{1
70 " ============================================================================
71 " Section: Comment enabler autocommands {{{2
72 " ============================================================================
74 augroup commentEnablers
76 "if the user enters a buffer or reads a buffer then we gotta set up
77 "the comment delimiters for that new filetype
78 autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0)
80 "if the filetype of a buffer changes, force the script to reset the
81 "delims for the buffer
82 autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1)
86 " Function: s:SetUpForNewFiletype(filetype) function {{{2
87 " This function is responsible for setting up buffer scoped variables for the
90 " These variables include the comment delimiters for the given filetype and calls
91 " MapDelimiters or MapDelimitersWithAlternative passing in these delimiters.
94 " -filetype: the filetype to set delimiters for
95 " -forceReset: 1 if the delimiters should be reset if they have already be
96 " set for this buffer.
98 function s:SetUpForNewFiletype(filetype, forceReset)
99 "if we have already set the delimiters for this buffer then dont go thru
101 if !a:forceReset && exists("b:NERDLeft") && b:NERDLeft != ''
105 let b:NERDSexyComMarker = ''
107 "check the filetype against all known filetypes to see if we have
108 "hardcoded the comment delimiters to use
110 call s:MapDelimiters('', '')
111 elseif a:filetype ==? "aap"
112 call s:MapDelimiters('#', '')
113 elseif a:filetype ==? "abc"
114 call s:MapDelimiters('%', '')
115 elseif a:filetype ==? "acedb"
116 call s:MapDelimitersWithAlternative('//','', '/*','*/')
117 elseif a:filetype ==? "actionscript"
118 call s:MapDelimitersWithAlternative('//','', '/*','*/')
119 elseif a:filetype ==? "ada"
120 call s:MapDelimitersWithAlternative('--','', '-- ', '')
121 elseif a:filetype ==? "ahdl"
122 call s:MapDelimiters('--', '')
123 elseif a:filetype ==? "ahk"
124 call s:MapDelimitersWithAlternative(';', '', '/*', '*/')
125 elseif a:filetype ==? "amiga"
126 call s:MapDelimiters(';', '')
127 elseif a:filetype ==? "aml"
128 call s:MapDelimiters('/*', '')
129 elseif a:filetype ==? "ampl"
130 call s:MapDelimiters('#', '')
131 elseif a:filetype ==? "apache"
132 call s:MapDelimiters('#', '')
133 elseif a:filetype ==? "apachestyle"
134 call s:MapDelimiters('#', '')
135 elseif a:filetype ==? "asciidoc"
136 call s:MapDelimiters('//', '')
137 elseif a:filetype ==? "applescript"
138 call s:MapDelimitersWithAlternative('--', '', '(*', '*)')
139 elseif a:filetype ==? "asm68k"
140 call s:MapDelimiters(';', '')
141 elseif a:filetype ==? "asm"
142 call s:MapDelimitersWithAlternative(';', '', '#', '')
143 elseif a:filetype ==? "asn"
144 call s:MapDelimiters('--', '')
145 elseif a:filetype ==? "aspvbs"
146 call s:MapDelimiters('''', '')
147 elseif a:filetype ==? "asterisk"
148 call s:MapDelimiters(';', '')
149 elseif a:filetype ==? "asy"
150 call s:MapDelimiters('//', '')
151 elseif a:filetype ==? "atlas"
152 call s:MapDelimiters('C','$')
153 elseif a:filetype ==? "autohotkey"
154 call s:MapDelimiters(';','')
155 elseif a:filetype ==? "autoit"
156 call s:MapDelimiters(';','')
157 elseif a:filetype ==? "ave"
158 call s:MapDelimiters("'",'')
159 elseif a:filetype ==? "awk"
160 call s:MapDelimiters('#','')
161 elseif a:filetype ==? "basic"
162 call s:MapDelimitersWithAlternative("'",'', 'REM ', '')
163 elseif a:filetype ==? "bbx"
164 call s:MapDelimiters('%', '')
165 elseif a:filetype ==? "bc"
166 call s:MapDelimiters('#', '')
167 elseif a:filetype ==? "bib"
168 call s:MapDelimiters('%','')
169 elseif a:filetype ==? "bindzone"
170 call s:MapDelimiters(';', '')
171 elseif a:filetype ==? "bst"
172 call s:MapDelimiters('%', '')
173 elseif a:filetype ==? "btm"
174 call s:MapDelimiters('::', '')
175 elseif a:filetype ==? "caos"
176 call s:MapDelimiters('*', '')
177 elseif a:filetype ==? "calibre"
178 call s:MapDelimiters('//','')
179 elseif a:filetype ==? "catalog"
180 call s:MapDelimiters('--','--')
181 elseif a:filetype ==? "c"
182 call s:MapDelimitersWithAlternative('/*','*/', '//', '')
183 elseif a:filetype ==? "cfg"
184 call s:MapDelimiters('#', '')
185 elseif a:filetype ==? "cg"
186 call s:MapDelimitersWithAlternative('//','', '/*','*/')
187 elseif a:filetype ==? "ch"
188 call s:MapDelimitersWithAlternative('//','', '/*','*/')
189 elseif a:filetype ==? "cl"
190 call s:MapDelimiters('#', '')
191 elseif a:filetype ==? "clean"
192 call s:MapDelimitersWithAlternative('//','', '/*','*/')
193 elseif a:filetype ==? "clipper"
194 call s:MapDelimitersWithAlternative('//','', '/*','*/')
195 elseif a:filetype ==? "clojure"
196 call s:MapDelimiters(';', '')
197 elseif a:filetype ==? "cmake"
198 call s:MapDelimiters('#','')
199 elseif a:filetype ==? "conkyrc"
200 call s:MapDelimiters('#', '')
201 elseif a:filetype ==? "cpp"
202 call s:MapDelimitersWithAlternative('//','', '/*','*/')
203 elseif a:filetype ==? "crontab"
204 call s:MapDelimiters('#', '')
205 elseif a:filetype ==? "cs"
206 call s:MapDelimitersWithAlternative('//','', '/*','*/')
207 elseif a:filetype ==? "csp"
208 call s:MapDelimiters('--', '')
209 elseif a:filetype ==? "cterm"
210 call s:MapDelimiters('*', '')
211 elseif a:filetype ==? "cucumber"
212 call s:MapDelimiters('#','')
213 elseif a:filetype ==? "cvs"
214 call s:MapDelimiters('CVS:','')
215 elseif a:filetype ==? "d"
216 call s:MapDelimitersWithAlternative('//','', '/*','*/')
217 elseif a:filetype ==? "dcl"
218 call s:MapDelimiters('$!', '')
219 elseif a:filetype ==? "dakota"
220 call s:MapDelimiters('#', '')
221 elseif a:filetype ==? "debcontrol"
222 call s:MapDelimiters('#', '')
223 elseif a:filetype ==? "debsources"
224 call s:MapDelimiters('#', '')
225 elseif a:filetype ==? "def"
226 call s:MapDelimiters(';', '')
227 elseif a:filetype ==? "desktop"
228 call s:MapDelimiters('#', '')
229 elseif a:filetype ==? "dhcpd"
230 call s:MapDelimiters('#', '')
231 elseif a:filetype ==? "diff"
232 call s:MapDelimiters('#', '')
233 elseif a:filetype ==? "django"
234 call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
235 elseif a:filetype ==? "docbk"
236 call s:MapDelimiters('<!--', '-->')
237 elseif a:filetype ==? "dns"
238 call s:MapDelimiters(';', '')
239 elseif a:filetype ==? "dosbatch"
240 call s:MapDelimitersWithAlternative('REM ','', '::', '')
241 elseif a:filetype ==? "dosini"
242 call s:MapDelimiters(';', '')
243 elseif a:filetype ==? "dot"
244 call s:MapDelimitersWithAlternative('//','', '/*','*/')
245 elseif a:filetype ==? "dracula"
246 call s:MapDelimiters(';', '')
247 elseif a:filetype ==? "dsl"
248 call s:MapDelimiters(';', '')
249 elseif a:filetype ==? "dtml"
250 call s:MapDelimiters('<dtml-comment>','</dtml-comment>')
251 elseif a:filetype ==? "dylan"
252 call s:MapDelimitersWithAlternative('//','', '/*','*/')
253 elseif a:filetype ==? 'ebuild'
254 call s:MapDelimiters('#', '')
255 elseif a:filetype ==? "ecd"
256 call s:MapDelimiters('#', '')
257 elseif a:filetype ==? 'eclass'
258 call s:MapDelimiters('#', '')
259 elseif a:filetype ==? "eiffel"
260 call s:MapDelimiters('--', '')
261 elseif a:filetype ==? "elf"
262 call s:MapDelimiters("'", '')
263 elseif a:filetype ==? "elmfilt"
264 call s:MapDelimiters('#', '')
265 elseif a:filetype ==? "erlang"
266 call s:MapDelimiters('%', '')
267 elseif a:filetype ==? "eruby"
268 call s:MapDelimitersWithAlternative('<%#', '%>', '<!--', '-->')
269 elseif a:filetype ==? "expect"
270 call s:MapDelimiters('#', '')
271 elseif a:filetype ==? "exports"
272 call s:MapDelimiters('#', '')
273 elseif a:filetype ==? "factor"
274 call s:MapDelimitersWithAlternative('! ', '', '!# ', '')
275 elseif a:filetype ==? "fgl"
276 call s:MapDelimiters('#', '')
277 elseif a:filetype ==? "focexec"
278 call s:MapDelimiters('-*', '')
279 elseif a:filetype ==? "form"
280 call s:MapDelimiters('*', '')
281 elseif a:filetype ==? "foxpro"
282 call s:MapDelimiters('*', '')
283 elseif a:filetype ==? "fstab"
284 call s:MapDelimiters('#', '')
285 elseif a:filetype ==? "fvwm"
286 call s:MapDelimiters('#', '')
287 elseif a:filetype ==? "fx"
288 call s:MapDelimitersWithAlternative('//','', '/*','*/')
289 elseif a:filetype ==? "gams"
290 call s:MapDelimiters('*', '')
291 elseif a:filetype ==? "gdb"
292 call s:MapDelimiters('#', '')
293 elseif a:filetype ==? "gdmo"
294 call s:MapDelimiters('--', '')
295 elseif a:filetype ==? "geek"
296 call s:MapDelimiters('GEEK_COMMENT:', '')
297 elseif a:filetype ==? "genshi"
298 call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
299 elseif a:filetype ==? "gentoo-conf-d"
300 call s:MapDelimiters('#', '')
301 elseif a:filetype ==? "gentoo-env-d"
302 call s:MapDelimiters('#', '')
303 elseif a:filetype ==? "gentoo-init-d"
304 call s:MapDelimiters('#', '')
305 elseif a:filetype ==? "gentoo-make-conf"
306 call s:MapDelimiters('#', '')
307 elseif a:filetype ==? 'gentoo-package-keywords'
308 call s:MapDelimiters('#', '')
309 elseif a:filetype ==? 'gentoo-package-mask'
310 call s:MapDelimiters('#', '')
311 elseif a:filetype ==? 'gentoo-package-use'
312 call s:MapDelimiters('#', '')
313 elseif a:filetype ==? 'gitcommit'
314 call s:MapDelimiters('#', '')
315 elseif a:filetype ==? 'gitconfig'
316 call s:MapDelimiters(';', '')
317 elseif a:filetype ==? 'gitrebase'
318 call s:MapDelimiters('#', '')
319 elseif a:filetype ==? "gnuplot"
320 call s:MapDelimiters('#','')
321 elseif a:filetype ==? "groovy"
322 call s:MapDelimitersWithAlternative('//','', '/*','*/')
323 elseif a:filetype ==? "gtkrc"
324 call s:MapDelimiters('#', '')
325 elseif a:filetype ==? "haskell"
326 call s:MapDelimitersWithAlternative('{-','-}', '--', '')
327 elseif a:filetype ==? "hb"
328 call s:MapDelimiters('#', '')
329 elseif a:filetype ==? "h"
330 call s:MapDelimitersWithAlternative('//','', '/*','*/')
331 elseif a:filetype ==? "haml"
332 call s:MapDelimitersWithAlternative('-#', '', '/', '')
333 elseif a:filetype ==? "hercules"
334 call s:MapDelimitersWithAlternative('//','', '/*','*/')
335 elseif a:filetype ==? "hog"
336 call s:MapDelimiters('#', '')
337 elseif a:filetype ==? "hostsaccess"
338 call s:MapDelimiters('#', '')
339 elseif a:filetype ==? "htmlcheetah"
340 call s:MapDelimiters('##','')
341 elseif a:filetype ==? "htmldjango"
342 call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
343 elseif a:filetype ==? "htmlos"
344 call s:MapDelimiters('#','/#')
345 elseif a:filetype ==? "ia64"
346 call s:MapDelimiters('#', '')
347 elseif a:filetype ==? "icon"
348 call s:MapDelimiters('#', '')
349 elseif a:filetype ==? "idlang"
350 call s:MapDelimiters(';', '')
351 elseif a:filetype ==? "idl"
352 call s:MapDelimitersWithAlternative('//','', '/*','*/')
353 elseif a:filetype ==? "inform"
354 call s:MapDelimiters('!', '')
355 elseif a:filetype ==? "inittab"
356 call s:MapDelimiters('#', '')
357 elseif a:filetype ==? "ishd"
358 call s:MapDelimitersWithAlternative('//','', '/*','*/')
359 elseif a:filetype ==? "iss"
360 call s:MapDelimiters(';', '')
361 elseif a:filetype ==? "ist"
362 call s:MapDelimiters('%', '')
363 elseif a:filetype ==? "java"
364 call s:MapDelimitersWithAlternative('//','', '/*','*/')
365 elseif a:filetype ==? "javacc"
366 call s:MapDelimitersWithAlternative('//','', '/*','*/')
367 elseif a:filetype ==? "javascript"
368 call s:MapDelimitersWithAlternative('//','', '/*','*/')
369 elseif a:filetype == "javascript.jquery"
370 call s:MapDelimitersWithAlternative('//','', '/*','*/')
371 elseif a:filetype ==? "jess"
372 call s:MapDelimiters(';', '')
373 elseif a:filetype ==? "jgraph"
374 call s:MapDelimiters('(*','*)')
375 elseif a:filetype ==? "jproperties"
376 call s:MapDelimiters('#','')
377 elseif a:filetype ==? "jsp"
378 call s:MapDelimiters('<%--', '--%>')
379 elseif a:filetype ==? "kix"
380 call s:MapDelimiters(';', '')
381 elseif a:filetype ==? "kscript"
382 call s:MapDelimitersWithAlternative('//','', '/*','*/')
383 elseif a:filetype ==? "lace"
384 call s:MapDelimiters('--', '')
385 elseif a:filetype ==? "ldif"
386 call s:MapDelimiters('#', '')
387 elseif a:filetype ==? "lilo"
388 call s:MapDelimiters('#', '')
389 elseif a:filetype ==? "lilypond"
390 call s:MapDelimiters('%', '')
391 elseif a:filetype ==? "liquid"
392 call s:MapDelimiters('{%', '%}')
393 elseif a:filetype ==? "lisp"
394 call s:MapDelimitersWithAlternative(';','', '#|', '|#')
395 elseif a:filetype ==? "llvm"
396 call s:MapDelimiters(';','')
397 elseif a:filetype ==? "lotos"
398 call s:MapDelimiters('(*','*)')
399 elseif a:filetype ==? "lout"
400 call s:MapDelimiters('#', '')
401 elseif a:filetype ==? "lprolog"
402 call s:MapDelimiters('%', '')
403 elseif a:filetype ==? "lscript"
404 call s:MapDelimiters("'", '')
405 elseif a:filetype ==? "lss"
406 call s:MapDelimiters('#', '')
407 elseif a:filetype ==? "lua"
408 call s:MapDelimitersWithAlternative('--','', '--[[', ']]')
409 elseif a:filetype ==? "lynx"
410 call s:MapDelimiters('#', '')
411 elseif a:filetype ==? "lytex"
412 call s:MapDelimiters('%', '')
413 elseif a:filetype ==? "mail"
414 call s:MapDelimiters('> ','')
415 elseif a:filetype ==? "mako"
416 call s:MapDelimiters('##', '')
417 elseif a:filetype ==? "man"
418 call s:MapDelimiters('."', '')
419 elseif a:filetype ==? "map"
420 call s:MapDelimiters('%', '')
421 elseif a:filetype ==? "maple"
422 call s:MapDelimiters('#', '')
423 elseif a:filetype ==? "markdown"
424 call s:MapDelimiters('<!--', '-->')
425 elseif a:filetype ==? "masm"
426 call s:MapDelimiters(';', '')
427 elseif a:filetype ==? "mason"
428 call s:MapDelimiters('<% #', '%>')
429 elseif a:filetype ==? "master"
430 call s:MapDelimiters('$', '')
431 elseif a:filetype ==? "matlab"
432 call s:MapDelimiters('%', '')
433 elseif a:filetype ==? "mel"
434 call s:MapDelimitersWithAlternative('//','', '/*','*/')
435 elseif a:filetype ==? "mib"
436 call s:MapDelimiters('--', '')
437 elseif a:filetype ==? "mkd"
438 call s:MapDelimiters('>', '')
439 elseif a:filetype ==? "mma"
440 call s:MapDelimiters('(*','*)')
441 elseif a:filetype ==? "model"
442 call s:MapDelimiters('$','$')
443 elseif a:filetype =~ "moduala."
444 call s:MapDelimiters('(*','*)')
445 elseif a:filetype ==? "modula2"
446 call s:MapDelimiters('(*','*)')
447 elseif a:filetype ==? "modula3"
448 call s:MapDelimiters('(*','*)')
449 elseif a:filetype ==? "monk"
450 call s:MapDelimiters(';', '')
451 elseif a:filetype ==? "mush"
452 call s:MapDelimiters('#', '')
453 elseif a:filetype ==? "named"
454 call s:MapDelimitersWithAlternative('//','', '/*','*/')
455 elseif a:filetype ==? "nasm"
456 call s:MapDelimiters(';', '')
457 elseif a:filetype ==? "nastran"
458 call s:MapDelimiters('$', '')
459 elseif a:filetype ==? "natural"
460 call s:MapDelimiters('/*', '')
461 elseif a:filetype ==? "ncf"
462 call s:MapDelimiters(';', '')
463 elseif a:filetype ==? "newlisp"
464 call s:MapDelimiters(';','')
465 elseif a:filetype ==? "nroff"
466 call s:MapDelimiters('\"', '')
467 elseif a:filetype ==? "nsis"
468 call s:MapDelimiters('#', '')
469 elseif a:filetype ==? "ntp"
470 call s:MapDelimiters('#', '')
471 elseif a:filetype ==? "objc"
472 call s:MapDelimitersWithAlternative('//','', '/*','*/')
473 elseif a:filetype ==? "objcpp"
474 call s:MapDelimitersWithAlternative('//','', '/*','*/')
475 elseif a:filetype ==? "objj"
476 call s:MapDelimitersWithAlternative('//','', '/*','*/')
477 elseif a:filetype ==? "ocaml"
478 call s:MapDelimiters('(*','*)')
479 elseif a:filetype ==? "occam"
480 call s:MapDelimiters('--','')
481 elseif a:filetype ==? "omlet"
482 call s:MapDelimiters('(*','*)')
483 elseif a:filetype ==? "omnimark"
484 call s:MapDelimiters(';', '')
485 elseif a:filetype ==? "openroad"
486 call s:MapDelimiters('//', '')
487 elseif a:filetype ==? "opl"
488 call s:MapDelimiters("REM", "")
489 elseif a:filetype ==? "ora"
490 call s:MapDelimiters('#', '')
491 elseif a:filetype ==? "ox"
492 call s:MapDelimiters('//', '')
493 elseif a:filetype ==? "pascal"
494 call s:MapDelimitersWithAlternative('{','}', '(*', '*)')
495 elseif a:filetype ==? "patran"
496 call s:MapDelimitersWithAlternative('$','','/*', '*/')
497 elseif a:filetype ==? "pcap"
498 call s:MapDelimiters('#', '')
499 elseif a:filetype ==? "pccts"
500 call s:MapDelimitersWithAlternative('//','', '/*','*/')
501 elseif a:filetype ==? "pdf"
502 call s:MapDelimiters('%', '')
503 elseif a:filetype ==? "pfmain"
504 call s:MapDelimiters('//', '')
505 elseif a:filetype ==? "php"
506 call s:MapDelimitersWithAlternative('//','','/*', '*/')
507 elseif a:filetype ==? "pic"
508 call s:MapDelimiters(';', '')
509 elseif a:filetype ==? "pike"
510 call s:MapDelimitersWithAlternative('//','', '/*','*/')
511 elseif a:filetype ==? "pilrc"
512 call s:MapDelimitersWithAlternative('//','', '/*','*/')
513 elseif a:filetype ==? "pine"
514 call s:MapDelimiters('#', '')
515 elseif a:filetype ==? "plm"
516 call s:MapDelimitersWithAlternative('//','', '/*','*/')
517 elseif a:filetype ==? "plsql"
518 call s:MapDelimitersWithAlternative('--', '', '/*', '*/')
519 elseif a:filetype ==? "po"
520 call s:MapDelimiters('#', '')
521 elseif a:filetype ==? "postscr"
522 call s:MapDelimiters('%', '')
523 elseif a:filetype ==? "pov"
524 call s:MapDelimitersWithAlternative('//','', '/*','*/')
525 elseif a:filetype ==? "povini"
526 call s:MapDelimiters(';', '')
527 elseif a:filetype ==? "ppd"
528 call s:MapDelimiters('%', '')
529 elseif a:filetype ==? "ppwiz"
530 call s:MapDelimiters(';;', '')
531 elseif a:filetype ==? "processing"
532 call s:MapDelimitersWithAlternative('//','', '/*','*/')
533 elseif a:filetype ==? "prolog"
534 call s:MapDelimitersWithAlternative('%','','/*','*/')
535 elseif a:filetype ==? "ps1"
536 call s:MapDelimiters('#', '')
537 elseif a:filetype ==? "psf"
538 call s:MapDelimiters('#', '')
539 elseif a:filetype ==? "ptcap"
540 call s:MapDelimiters('#', '')
541 elseif a:filetype ==? "radiance"
542 call s:MapDelimiters('#', '')
543 elseif a:filetype ==? "ratpoison"
544 call s:MapDelimiters('#', '')
545 elseif a:filetype ==? "r"
546 call s:MapDelimiters('#', '')
547 elseif a:filetype ==? "rc"
548 call s:MapDelimitersWithAlternative('//','', '/*','*/')
549 elseif a:filetype ==? "rebol"
550 call s:MapDelimiters(';', '')
551 elseif a:filetype ==? "registry"
552 call s:MapDelimiters(';', '')
553 elseif a:filetype ==? "remind"
554 call s:MapDelimiters('#', '')
555 elseif a:filetype ==? "resolv"
556 call s:MapDelimiters('#', '')
557 elseif a:filetype ==? "rgb"
558 call s:MapDelimiters('!', '')
559 elseif a:filetype ==? "rib"
560 call s:MapDelimiters('#','')
561 elseif a:filetype ==? "robots"
562 call s:MapDelimiters('#', '')
563 elseif a:filetype ==? "sa"
564 call s:MapDelimiters('--','')
565 elseif a:filetype ==? "samba"
566 call s:MapDelimitersWithAlternative(';','', '#', '')
567 elseif a:filetype ==? "sass"
568 call s:MapDelimitersWithAlternative('//','', '/*', '')
569 elseif a:filetype ==? "sather"
570 call s:MapDelimiters('--', '')
571 elseif a:filetype ==? "scala"
572 call s:MapDelimitersWithAlternative('//','', '/*','*/')
573 elseif a:filetype ==? "scilab"
574 call s:MapDelimiters('//', '')
575 elseif a:filetype ==? "scsh"
576 call s:MapDelimiters(';', '')
577 elseif a:filetype ==? "sed"
578 call s:MapDelimiters('#', '')
579 elseif a:filetype ==? "sgmldecl"
580 call s:MapDelimiters('--','--')
581 elseif a:filetype ==? "sgmllnx"
582 call s:MapDelimiters('<!--','-->')
583 elseif a:filetype ==? "sicad"
584 call s:MapDelimiters('*', '')
585 elseif a:filetype ==? "simula"
586 call s:MapDelimitersWithAlternative('%', '', '--', '')
587 elseif a:filetype ==? "sinda"
588 call s:MapDelimiters('$', '')
589 elseif a:filetype ==? "skill"
590 call s:MapDelimiters(';', '')
591 elseif a:filetype ==? "slang"
592 call s:MapDelimiters('%', '')
593 elseif a:filetype ==? "slice"
594 call s:MapDelimitersWithAlternative('//','', '/*','*/')
595 elseif a:filetype ==? "slrnrc"
596 call s:MapDelimiters('%', '')
597 elseif a:filetype ==? "sm"
598 call s:MapDelimiters('#', '')
599 elseif a:filetype ==? "smarty"
600 call s:MapDelimiters('{*', '*}')
601 elseif a:filetype ==? "smil"
602 call s:MapDelimiters('<!','>')
603 elseif a:filetype ==? "smith"
604 call s:MapDelimiters(';', '')
605 elseif a:filetype ==? "sml"
606 call s:MapDelimiters('(*','*)')
607 elseif a:filetype ==? "snnsnet"
608 call s:MapDelimiters('#', '')
609 elseif a:filetype ==? "snnspat"
610 call s:MapDelimiters('#', '')
611 elseif a:filetype ==? "snnsres"
612 call s:MapDelimiters('#', '')
613 elseif a:filetype ==? "snobol4"
614 call s:MapDelimiters('*', '')
615 elseif a:filetype ==? "spec"
616 call s:MapDelimiters('#', '')
617 elseif a:filetype ==? "specman"
618 call s:MapDelimiters('//', '')
619 elseif a:filetype ==? "spectre"
620 call s:MapDelimitersWithAlternative('//', '', '*', '')
621 elseif a:filetype ==? "spice"
622 call s:MapDelimiters('$', '')
623 elseif a:filetype ==? "sql"
624 call s:MapDelimiters('--', '')
625 elseif a:filetype ==? "sqlforms"
626 call s:MapDelimiters('--', '')
627 elseif a:filetype ==? "sqlj"
628 call s:MapDelimiters('--', '')
629 elseif a:filetype ==? "sqr"
630 call s:MapDelimiters('!', '')
631 elseif a:filetype ==? "squid"
632 call s:MapDelimiters('#', '')
633 elseif a:filetype ==? "st"
634 call s:MapDelimiters('"','')
635 elseif a:filetype ==? "stp"
636 call s:MapDelimiters('--', '')
637 elseif a:filetype ==? "systemverilog"
638 call s:MapDelimitersWithAlternative('//','', '/*','*/')
639 elseif a:filetype ==? "tads"
640 call s:MapDelimitersWithAlternative('//','', '/*','*/')
641 elseif a:filetype ==? "tags"
642 call s:MapDelimiters(';', '')
643 elseif a:filetype ==? "tak"
644 call s:MapDelimiters('$', '')
645 elseif a:filetype ==? "tasm"
646 call s:MapDelimiters(';', '')
647 elseif a:filetype ==? "tcl"
648 call s:MapDelimiters('#','')
649 elseif a:filetype ==? "texinfo"
650 call s:MapDelimiters("@c ", "")
651 elseif a:filetype ==? "texmf"
652 call s:MapDelimiters('%', '')
653 elseif a:filetype ==? "tf"
654 call s:MapDelimiters(';', '')
655 elseif a:filetype ==? "tidy"
656 call s:MapDelimiters('#', '')
657 elseif a:filetype ==? "tli"
658 call s:MapDelimiters('#', '')
659 elseif a:filetype ==? "trasys"
660 call s:MapDelimiters("$", "")
661 elseif a:filetype ==? "tsalt"
662 call s:MapDelimitersWithAlternative('//','', '/*','*/')
663 elseif a:filetype ==? "tsscl"
664 call s:MapDelimiters('#', '')
665 elseif a:filetype ==? "tssgm"
666 call s:MapDelimiters("comment = '","'")
667 elseif a:filetype ==? "txt2tags"
668 call s:MapDelimiters('%','')
669 elseif a:filetype ==? "uc"
670 call s:MapDelimitersWithAlternative('//','', '/*','*/')
671 elseif a:filetype ==? "uil"
672 call s:MapDelimiters('!', '')
673 elseif a:filetype ==? "vb"
674 call s:MapDelimiters("'","")
675 elseif a:filetype ==? "velocity"
676 call s:MapDelimitersWithAlternative("##","", '#*', '*#')
677 elseif a:filetype ==? "vera"
678 call s:MapDelimitersWithAlternative('/*','*/','//','')
679 elseif a:filetype ==? "verilog"
680 call s:MapDelimitersWithAlternative('//','', '/*','*/')
681 elseif a:filetype ==? "verilog_systemverilog"
682 call s:MapDelimitersWithAlternative('//','', '/*','*/')
683 elseif a:filetype ==? "vgrindefs"
684 call s:MapDelimiters('#', '')
685 elseif a:filetype ==? "vhdl"
686 call s:MapDelimiters('--', '')
687 elseif a:filetype ==? "vimperator"
688 call s:MapDelimiters('"','')
689 elseif a:filetype ==? "virata"
690 call s:MapDelimiters('%', '')
691 elseif a:filetype ==? "vrml"
692 call s:MapDelimiters('#', '')
693 elseif a:filetype ==? "vsejcl"
694 call s:MapDelimiters('/*', '')
695 elseif a:filetype ==? "webmacro"
696 call s:MapDelimiters('##', '')
697 elseif a:filetype ==? "wget"
698 call s:MapDelimiters('#', '')
699 elseif a:filetype ==? "Wikipedia"
700 call s:MapDelimiters('<!--','-->')
701 elseif a:filetype ==? "winbatch"
702 call s:MapDelimiters(';', '')
703 elseif a:filetype ==? "wml"
704 call s:MapDelimiters('#', '')
705 elseif a:filetype ==? "wvdial"
706 call s:MapDelimiters(';', '')
707 elseif a:filetype ==? "xdefaults"
708 call s:MapDelimiters('!', '')
709 elseif a:filetype ==? "xkb"
710 call s:MapDelimiters('//', '')
711 elseif a:filetype ==? "xmath"
712 call s:MapDelimiters('#', '')
713 elseif a:filetype ==? "xpm2"
714 call s:MapDelimiters('!', '')
715 elseif a:filetype ==? "xquery"
716 call s:MapDelimiters('(:',':)')
717 elseif a:filetype ==? "z8a"
718 call s:MapDelimiters(';', '')
722 "extract the delims from &commentstring
723 let left= substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', '')
724 let right= substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g')
725 call s:MapDelimiters(left,right)
730 " Function: s:MapDelimiters(left, right) function {{{2
731 " This function is a wrapper for s:MapDelimiters(left, right, leftAlt, rightAlt, useAlt) and is called when there
732 " is no alternative comment delimiters for the current filetype
735 " -left: the left comment delimiter
736 " -right: the right comment delimiter
737 function s:MapDelimiters(left, right)
738 call s:MapDelimitersWithAlternative(a:left, a:right, "", "")
741 " Function: s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt) function {{{2
742 " this function sets up the comment delimiter buffer variables
745 " -left: the string defining the comment start delimiter
746 " -right: the string defining the comment end delimiter
747 " -leftAlt: the string for the alternative comment style defining the comment start delimiter
748 " -rightAlt: the string for the alternative comment style defining the comment end delimiter
749 function s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt)
750 if !exists('g:NERD_' . &filetype . '_alt_style')
751 let b:NERDLeft = a:left
752 let b:NERDRight = a:right
753 let b:NERDLeftAlt = a:leftAlt
754 let b:NERDRightAlt = a:rightAlt
756 let b:NERDLeft = a:leftAlt
757 let b:NERDRight = a:rightAlt
758 let b:NERDLeftAlt = a:left
759 let b:NERDRightAlt = a:right
763 " Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2
764 " This function is used to swap the delimiters that are being used to the
765 " alternative delimiters for that filetype. For example, if a c++ file is
766 " being edited and // comments are being used, after this function is called
767 " /**/ comments will be used.
770 " -printMsgs: if this is 1 then a message is echoed to the user telling them
771 " if this function changed the delimiters or not
772 function s:SwitchToAlternativeDelimiters(printMsgs)
773 "if both of the alternative delimiters are empty then there is no
774 "alternative comment style so bail out
775 if b:NERDLeftAlt == "" && b:NERDRightAlt == ""
777 call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0)
782 "save the current delimiters
783 let tempLeft = b:NERDLeft
784 let tempRight = b:NERDRight
786 "swap current delimiters for alternative
787 let b:NERDLeft = b:NERDLeftAlt
788 let b:NERDRight = b:NERDRightAlt
790 "set the previously current delimiters to be the new alternative ones
791 let b:NERDLeftAlt = tempLeft
792 let b:NERDRightAlt = tempRight
794 "tell the user what comment delimiters they are now using
796 let leftNoEsc = b:NERDLeft
797 let rightNoEsc = b:NERDRight
798 call s:NerdEcho("Now using " . leftNoEsc . " " . rightNoEsc . " to delimit comments", 1)
804 " Section: Comment delimiter add/removal functions {{{1
805 " ============================================================================
806 " Function: s:AppendCommentToLine(){{{2
807 " This function appends comment delimiters at the EOL and places the cursor in
808 " position to start typing the comment
809 function s:AppendCommentToLine()
810 let left = s:GetLeft(0,1,0)
811 let right = s:GetRight(0,1,0)
813 " get the len of the right delim
814 let lenRight = strlen(right)
816 let isLineEmpty = strlen(getline(".")) == 0
817 let insOrApp = (isLineEmpty==1 ? 'i' : 'A')
819 "stick the delimiters down at the end of the line. We have to format the
820 "comment with spaces as appropriate
821 execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " "
823 " if there is a right delimiter then we gotta move the cursor left
824 " by the len of the right delimiter so we insert between the delimiters
826 let leftMoveAmount = lenRight
827 execute ":normal! " . leftMoveAmount . "h"
832 " Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2
833 " This function is used to comment out a region of code. This region is
834 " specified as a bounding box by arguments to the function.
837 " -top: the line number for the top line of code in the region
838 " -bottom: the line number for the bottom line of code in the region
839 " -lSide: the column number for the left most column in the region
840 " -rSide: the column number for the right most column in the region
841 " -forceNested: a flag indicating whether comments should be nested
842 function s:CommentBlock(top, bottom, lSide, rSide, forceNested )
843 " we need to create local copies of these arguments so we can modify them
845 let bottom = a:bottom
849 "if the top or bottom line starts with tabs we have to adjust the left and
850 "right boundaries so that they are set as though the tabs were spaces
851 let topline = getline(top)
852 let bottomline = getline(bottom)
853 if s:HasLeadingTabs(topline, bottomline)
855 "find out how many tabs are in the top line and adjust the left
856 "boundary accordingly
857 let numTabs = s:NumberOfLeadingTabs(topline)
859 let lSide = &ts * lSide
861 let lSide = (lSide - numTabs) + (&ts * numTabs)
864 "find out how many tabs are in the bottom line and adjust the right
865 "boundary accordingly
866 let numTabs = s:NumberOfLeadingTabs(bottomline)
867 let rSide = (rSide - numTabs) + (&ts * numTabs)
870 "we must check that bottom IS actually below top, if it is not then we
871 "swap top and bottom. Similarly for left and right.
883 "if the current delimiters arent multipart then we will switch to the
884 "alternative delims (if THEY are) as the comment will be better and more
885 "accurate with multipart delims
886 let switchedDelims = 0
887 if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart()
888 let switchedDelims = 1
889 call s:SwitchToAlternativeDelimiters(0)
892 "start the commenting from the top and keep commenting till we reach the
895 while currentLine <= bottom
897 "check if we are allowed to comment this line
898 if s:CanCommentLine(a:forceNested, currentLine)
900 "convert the leading tabs into spaces
901 let theLine = getline(currentLine)
902 let lineHasLeadTabs = s:HasLeadingTabs(theLine)
904 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
907 "dont comment lines that begin after the right boundary of the
908 "block unless the user has specified to do so
909 if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty
911 "attempt to place the cursor in on the left of the boundary box,
912 "then check if we were successful, if not then we cant comment this
914 call setline(currentLine, theLine)
915 if s:CanPlaceCursor(currentLine, lSide)
917 let leftSpaced = s:GetLeft(0,1,0)
918 let rightSpaced = s:GetRight(0,1,0)
920 "stick the left delimiter down
921 let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
924 "stick the right delimiter down
925 let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced))
927 let firstLeftDelim = s:FindDelimiterIndex(b:NERDLeft, theLine)
928 let lastRightDelim = s:LastIndexOfDelim(b:NERDRight, theLine)
930 if firstLeftDelim != -1 && lastRightDelim != -1
931 let searchStr = strpart(theLine, 0, lastRightDelim)
932 let searchStr = strpart(searchStr, firstLeftDelim+strlen(b:NERDLeft))
934 "replace the outter most delims in searchStr with
936 let theLineWithPlaceHolders = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, searchStr)
938 "add the right delimiter onto the line
939 let theLine = strpart(theLine, 0, firstLeftDelim+strlen(b:NERDLeft)) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
945 "restore tabs if needed
947 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
950 call setline(currentLine, theLine)
953 let currentLine = currentLine + 1
956 "if we switched delims then we gotta go back to what they were before
957 if switchedDelims == 1
958 call s:SwitchToAlternativeDelimiters(0)
962 " Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2
963 " This function comments a range of lines.
966 " -forceNested: a flag indicating whether the called is requesting the comment
967 " to be nested if need be
968 " -align: should be "left" or "both" or "none"
969 " -firstLine/lastLine: the top and bottom lines to comment
970 function s:CommentLines(forceNested, align, firstLine, lastLine)
971 " we need to get the left and right indexes of the leftmost char in the
972 " block of of lines and the right most char so that we can do alignment of
973 " the delimiters if the user has specified
974 let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
975 let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
977 " gotta add the length of the left delimiter onto the rightAlignIndx cos
978 " we'll be adding a left delim to the line
979 let rightAlignIndx = rightAlignIndx + strlen(s:GetLeft(0,1,0))
981 " now we actually comment the lines. Do it line by line
982 let currentLine = a:firstLine
983 while currentLine <= a:lastLine
985 " get the next line, check commentability and convert spaces to tabs
986 let theLine = getline(currentLine)
987 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
988 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
989 if s:CanCommentLine(a:forceNested, currentLine)
990 "if the user has specified forceNesting then we check to see if we
991 "need to switch delimiters for place-holders
992 if a:forceNested && g:NERDUsePlaceHolders
993 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
996 " find out if the line is commented using normal delims and/or
998 let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)
1000 " check if we can comment this line
1001 if !isCommented || g:NERDUsePlaceHolders || s:Multipart()
1002 if a:align == "left" || a:align == "both"
1003 let theLine = s:AddLeftDelimAligned(s:GetLeft(0,1,0), theLine, leftAlignIndx)
1005 let theLine = s:AddLeftDelim(s:GetLeft(0,1,0), theLine)
1007 if a:align == "both"
1008 let theLine = s:AddRightDelimAligned(s:GetRight(0,1,0), theLine, rightAlignIndx)
1010 let theLine = s:AddRightDelim(s:GetRight(0,1,0), theLine)
1015 " restore leading tabs if appropriate
1016 if lineHasLeadingTabs
1017 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1020 " we are done with this line
1021 call setline(currentLine, theLine)
1022 let currentLine = currentLine + 1
1027 " Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2
1028 " This function comments a range of lines in a minimal style. I
1031 " -firstLine/lastLine: the top and bottom lines to comment
1032 function s:CommentLinesMinimal(firstLine, lastLine)
1033 "check that minimal comments can be done on this filetype
1034 if !s:HasMultipartDelims()
1035 throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters'
1038 "if we need to use place holders for the comment, make sure they are
1039 "enabled for this filetype
1040 if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine)
1041 throw 'NERDCommenter.Settings exception: Placeoholders are required but disabled.'
1044 "get the left and right delims to smack on
1045 let left = s:GetSexyComLeft(g:NERDSpaceDelims,0)
1046 let right = s:GetSexyComRight(g:NERDSpaceDelims,0)
1048 "make sure all multipart delims on the lines are replaced with
1049 "placeholders to prevent illegal syntax
1050 let currentLine = a:firstLine
1051 while(currentLine <= a:lastLine)
1052 let theLine = getline(currentLine)
1053 let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine)
1054 call setline(currentLine, theLine)
1055 let currentLine = currentLine + 1
1058 "add the delim to the top line
1059 let theLine = getline(a:firstLine)
1060 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
1061 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1062 let theLine = s:AddLeftDelim(left, theLine)
1063 if lineHasLeadingTabs
1064 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1066 call setline(a:firstLine, theLine)
1068 "add the delim to the bottom line
1069 let theLine = getline(a:lastLine)
1070 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
1071 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1072 let theLine = s:AddRightDelim(right, theLine)
1073 if lineHasLeadingTabs
1074 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1076 call setline(a:lastLine, theLine)
1079 " Function: s:CommentLinesSexy(topline, bottomline) function {{{2
1080 " This function is used to comment lines in the 'Sexy' style. eg in c:
1082 " * This is a sexy comment
1085 " -topline: the line num of the top line in the sexy comment
1086 " -bottomline: the line num of the bottom line in the sexy comment
1087 function s:CommentLinesSexy(topline, bottomline)
1088 let left = s:GetSexyComLeft(0, 0)
1089 let right = s:GetSexyComRight(0, 0)
1091 "check if we can do a sexy comment with the available delimiters
1092 if left == -1 || right == -1
1093 throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.'
1096 "make sure the lines arent already commented sexually
1097 if !s:CanSexyCommentLines(a:topline, a:bottomline)
1098 throw 'NERDCommenter.Nesting exception: cannot nest sexy comments'
1102 let sexyComMarker = s:GetSexyComMarker(0,0)
1103 let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
1106 " we jam the comment as far to the right as possible
1107 let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
1109 "check if we should use the compact style i.e that the left/right
1110 "delimiters should appear on the first and last lines of the code and not
1111 "on separate lines above/below the first/last lines of code
1112 if g:NERDCompactSexyComs
1113 let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '')
1115 "comment the top line
1116 let theLine = getline(a:topline)
1117 let lineHasTabs = s:HasLeadingTabs(theLine)
1119 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1121 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1122 let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
1124 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1126 call setline(a:topline, theLine)
1128 "comment the bottom line
1129 if a:bottomline != a:topline
1130 let theLine = getline(a:bottomline)
1131 let lineHasTabs = s:HasLeadingTabs(theLine)
1133 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1135 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1137 let theLine = s:AddRightDelim(spaceString . right, theLine)
1139 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1141 call setline(a:bottomline, theLine)
1144 " add the left delimiter one line above the lines that are to be commented
1145 call cursor(a:topline, 1)
1147 call setline(a:topline, repeat(' ', leftAlignIndx) . left )
1149 " add the right delimiter after bottom line (we have to add 1 cos we moved
1150 " the lines down when we added the left delim
1151 call cursor(a:bottomline+1, 1)
1153 call setline(a:bottomline+2, repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right )
1157 " go thru each line adding the sexyComMarker marker to the start of each
1158 " line in the appropriate place to align them with the comment delims
1159 let currentLine = a:topline+1
1160 while currentLine <= a:bottomline + !g:NERDCompactSexyComs
1161 " get the line and convert the tabs to spaces
1162 let theLine = getline(currentLine)
1163 let lineHasTabs = s:HasLeadingTabs(theLine)
1165 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1168 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1170 " add the sexyComMarker
1171 let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
1174 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1178 " set the line and move onto the next one
1179 call setline(currentLine, theLine)
1180 let currentLine = currentLine + 1
1185 " Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2
1186 " Applies "toggle" commenting to the given range of lines
1189 " -forceNested: a flag indicating whether the called is requesting the comment
1190 " to be nested if need be
1191 " -firstLine/lastLine: the top and bottom lines to comment
1192 function s:CommentLinesToggle(forceNested, firstLine, lastLine)
1193 let currentLine = a:firstLine
1194 while currentLine <= a:lastLine
1196 " get the next line, check commentability and convert spaces to tabs
1197 let theLine = getline(currentLine)
1198 let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
1199 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
1200 if s:CanToggleCommentLine(a:forceNested, currentLine)
1202 "if the user has specified forceNesting then we check to see if we
1203 "need to switch delimiters for place-holders
1204 if g:NERDUsePlaceHolders
1205 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
1208 let theLine = s:AddLeftDelim(s:GetLeft(0, 1, 0), theLine)
1209 let theLine = s:AddRightDelim(s:GetRight(0, 1, 0), theLine)
1212 " restore leading tabs if appropriate
1213 if lineHasLeadingTabs
1214 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
1217 " we are done with this line
1218 call setline(currentLine, theLine)
1219 let currentLine = currentLine + 1
1224 " Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2
1225 " This function comments chunks of text selected in visual mode.
1226 " It will comment exactly the text that they have selected.
1228 " -topLine: the line num of the top line in the sexy comment
1229 " -topCol: top left col for this comment
1230 " -bottomline: the line num of the bottom line in the sexy comment
1231 " -bottomCol: the bottom right col for this comment
1232 " -forceNested: whether the caller wants comments to be nested if the
1233 " line(s) are already commented
1234 function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested)
1236 "switch delims (if we can) if the current set isnt multipart
1237 let switchedDelims = 0
1238 if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims
1239 let switchedDelims = 1
1240 call s:SwitchToAlternativeDelimiters(0)
1243 "if there is only one line in the comment then just do it
1244 if a:topLine == a:bottomLine
1245 call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested)
1247 "there are multiple lines in the comment
1249 "comment the top line
1250 call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
1252 "comment out all the lines in the middle of the comment
1253 let topOfRange = a:topLine+1
1254 let bottomOfRange = a:bottomLine-1
1255 if topOfRange <= bottomOfRange
1256 call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange)
1259 "comment the bottom line
1260 let bottom = getline(a:bottomLine)
1261 let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', ''))
1262 call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested)
1266 "stick the cursor back on the char it was on before the comment
1267 call cursor(a:topLine, a:topCol + strlen(b:NERDLeft) + g:NERDSpaceDelims)
1269 "if we switched delims then we gotta go back to what they were before
1270 if switchedDelims == 1
1271 call s:SwitchToAlternativeDelimiters(0)
1276 " Function: s:InvertComment(firstLine, lastLine) function {{{2
1277 " Inverts the comments on the lines between and including the given line
1278 " numbers i.e all commented lines are uncommented and vice versa
1280 " -firstLine: the top of the range of lines to be inverted
1281 " -lastLine: the bottom of the range of lines to be inverted
1282 function s:InvertComment(firstLine, lastLine)
1284 " go thru all lines in the given range
1285 let currentLine = a:firstLine
1286 while currentLine <= a:lastLine
1287 let theLine = getline(currentLine)
1289 let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
1291 " if the line is commented normally, uncomment it
1292 if s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)
1293 call s:UncommentLines(currentLine, currentLine)
1294 let currentLine = currentLine + 1
1296 " check if the line is commented sexually
1297 elseif !empty(sexyComBounds)
1298 let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
1299 call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
1301 "move to the line after last line of the sexy comment
1302 let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
1303 let currentLine = bottomBound - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1
1305 " the line isnt commented
1307 call s:CommentLinesToggle(1, currentLine, currentLine)
1308 let currentLine = currentLine + 1
1314 " Function: NERDComment(isVisual, type) function {{{2
1315 " This function is a Wrapper for the main commenting functions
1318 " -isVisual: a flag indicating whether the comment is requested in visual
1320 " -type: the type of commenting requested. Can be 'sexy', 'invert',
1321 " 'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm',
1322 " 'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank'
1323 function! NERDComment(isVisual, type) range
1324 " we want case sensitivity when commenting
1325 let oldIgnoreCase = &ignorecase
1329 let firstLine = line("'<")
1330 let lastLine = line("'>")
1331 let firstCol = col("'<")
1332 let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0)
1334 let firstLine = a:firstline
1335 let lastLine = a:lastline
1338 let countWasGiven = (a:isVisual == 0 && firstLine != lastLine)
1340 let forceNested = (a:type == 'nested' || g:NERDDefaultNesting)
1342 if a:type == 'norm' || a:type == 'nested'
1343 if a:isVisual && visualmode() == "
\16"
1344 call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested)
1345 elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims()))
1346 call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested)
1348 call s:CommentLines(forceNested, "none", firstLine, lastLine)
1351 elseif a:type == 'alignLeft' || a:type == 'alignBoth'
1353 if a:type == "alignLeft"
1355 elseif a:type == "alignBoth"
1358 call s:CommentLines(forceNested, align, firstLine, lastLine)
1360 elseif a:type == 'invert'
1361 call s:InvertComment(firstLine, lastLine)
1363 elseif a:type == 'sexy'
1365 call s:CommentLinesSexy(firstLine, lastLine)
1366 catch /NERDCommenter.Delimiters/
1367 call s:CommentLines(forceNested, "none", firstLine, lastLine)
1368 catch /NERDCommenter.Nesting/
1369 call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0)
1372 elseif a:type == 'toggle'
1373 let theLine = getline(firstLine)
1375 if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)
1376 call s:UncommentLines(firstLine, lastLine)
1378 call s:CommentLinesToggle(forceNested, firstLine, lastLine)
1381 elseif a:type == 'minimal'
1383 call s:CommentLinesMinimal(firstLine, lastLine)
1384 catch /NERDCommenter.Delimiters/
1385 call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0)
1386 catch /NERDCommenter.Settings/
1387 call s:NerdEcho("Place holders are required but disabled.", 0)
1390 elseif a:type == 'toEOL'
1391 call s:SaveScreenState()
1392 call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1)
1393 call s:RestoreScreenState()
1395 elseif a:type == 'append'
1396 call s:AppendCommentToLine()
1398 elseif a:type == 'insert'
1399 call s:PlaceDelimitersAndInsBetween()
1401 elseif a:type == 'uncomment'
1402 call s:UncommentLines(firstLine, lastLine)
1404 elseif a:type == 'yank'
1407 elseif countWasGiven
1408 execute firstLine .','. lastLine .'yank'
1412 execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")'
1415 let &ignorecase = oldIgnoreCase
1418 " Function: s:PlaceDelimitersAndInsBetween() function {{{2
1419 " This is function is called to place comment delimiters down and place the
1420 " cursor between them
1421 function s:PlaceDelimitersAndInsBetween()
1422 " get the left and right delimiters without any escape chars in them
1423 let left = s:GetLeft(0, 1, 0)
1424 let right = s:GetRight(0, 1, 0)
1426 let theLine = getline(".")
1427 let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab)
1429 "convert tabs to spaces and adjust the cursors column to take this into
1431 let untabbedCol = s:UntabbedCol(theLine, col("."))
1432 call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine))
1433 call cursor(line("."), untabbedCol)
1435 " get the len of the right delim
1436 let lenRight = strlen(right)
1438 let isDelimOnEOL = col(".") >= strlen(getline("."))
1440 " if the cursor is in the first col then we gotta insert rather than
1441 " append the comment delimiters here
1442 let insOrApp = (col(".")==1 ? 'i' : 'a')
1444 " place the delimiters down. We do it differently depending on whether
1445 " there is a left AND right delimiter
1447 execute ":normal! " . insOrApp . left . right
1448 execute ":normal! " . lenRight . "h"
1450 execute ":normal! " . insOrApp . left
1452 " if we are tacking the delim on the EOL then we gotta add a space
1453 " after it cos when we go out of insert mode the cursor will move back
1454 " one and the user wont be in position to type the comment.
1456 execute 'normal! a '
1461 "if needed convert spaces back to tabs and adjust the cursors col
1464 let tabbedCol = s:TabbedCol(getline("."), col("."))
1465 call setline(line("."), s:ConvertLeadingSpacesToTabs(getline(".")))
1466 call cursor(line("."), tabbedCol)
1472 " Function: s:RemoveDelimiters(left, right, line) {{{2
1473 " this function is called to remove the first left comment delimiter and the
1474 " last right delimiter of the given line.
1476 " The args left and right must be strings. If there is no right delimiter (as
1477 " is the case for e.g vim file comments) them the arg right should be ""
1480 " -left: the left comment delimiter
1481 " -right: the right comment delimiter
1482 " -line: the line to remove the delimiters from
1483 function s:RemoveDelimiters(left, right, line)
1486 let l:right = a:right
1487 let lenLeft = strlen(left)
1488 let lenRight = strlen(right)
1490 let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
1494 "look for the left delimiter, if we find it, remove it.
1495 let leftIndx = s:FindDelimiterIndex(a:left, line)
1497 let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
1499 "if the user has specified that there is a space after the left delim
1500 "then check for the space and remove it if it is there
1501 if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr
1502 let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr)
1506 "look for the right delimiter, if we find it, remove it
1507 let rightIndx = s:FindDelimiterIndex(a:right, line)
1509 let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
1511 "if the user has specified that there is a space before the right delim
1512 "then check for the space and remove it if it is there
1513 if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart()
1514 let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx)
1521 " Function: s:UncommentLines(topLine, bottomLine) {{{2
1522 " This function uncomments the given lines
1525 " topLine: the top line of the visual selection to uncomment
1526 " bottomLine: the bottom line of the visual selection to uncomment
1527 function s:UncommentLines(topLine, bottomLine)
1528 "make local copies of a:firstline and a:lastline and, if need be, swap
1529 "them around if the top line is below the bottom
1530 let l:firstline = a:topLine
1531 let l:lastline = a:bottomLine
1532 if firstline > lastline
1533 let firstline = lastline
1534 let lastline = a:topLine
1537 "go thru each line uncommenting each line removing sexy comments
1538 let currentLine = firstline
1539 while currentLine <= lastline
1541 "check the current line to see if it is part of a sexy comment
1542 let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
1543 if !empty(sexyComBounds)
1545 "we need to store the num lines in the buf before the comment is
1546 "removed so we know how many lines were removed when the sexy com
1548 let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
1550 call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
1552 "move to the line after last line of the sexy comment
1553 let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
1554 let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved
1555 let currentLine = sexyComBounds[1] - numLinesRemoved + 1
1556 let lastline = lastline - numLinesRemoved
1558 "no sexy com was detected so uncomment the line as normal
1560 call s:UncommentLinesNormal(currentLine, currentLine)
1561 let currentLine = currentLine + 1
1567 " Function: s:UncommentLinesSexy(topline, bottomline) {{{2
1568 " This function removes all the comment characters associated with the sexy
1569 " comment spanning the given lines
1571 " -topline/bottomline: the top/bottom lines of the sexy comment
1572 function s:UncommentLinesSexy(topline, bottomline)
1573 let left = s:GetSexyComLeft(0,1)
1574 let right = s:GetSexyComRight(0,1)
1577 "check if it is even possible for sexy comments to exist with the
1578 "available delimiters
1579 if left == -1 || right == -1
1580 throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.'
1583 let leftUnEsc = s:GetSexyComLeft(0,0)
1584 let rightUnEsc = s:GetSexyComRight(0,0)
1586 let sexyComMarker = s:GetSexyComMarker(0, 1)
1587 let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
1589 "the markerOffset is how far right we need to move the sexyComMarker to
1590 "line it up with the end of the left delim
1591 let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc)
1593 " go thru the intermediate lines of the sexy comment and remove the
1594 " sexy comment markers (eg the '*'s on the start of line in a c sexy
1596 let currentLine = a:topline+1
1597 while currentLine < a:bottomline
1598 let theLine = getline(currentLine)
1600 " remove the sexy comment marker from the line. We also remove the
1601 " space after it if there is one and if appropriate options are set
1602 let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
1603 if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1604 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
1606 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1609 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1611 let theLine = s:ConvertLeadingWhiteSpace(theLine)
1613 " move onto the next line
1614 call setline(currentLine, theLine)
1615 let currentLine = currentLine + 1
1618 " gotta make a copy of a:bottomline cos we modify the position of the
1619 " last line it if we remove the topline
1620 let bottomline = a:bottomline
1622 " get the first line so we can remove the left delim from it
1623 let theLine = getline(a:topline)
1625 " if the first line contains only the left delim then just delete it
1626 if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs
1627 call cursor(a:topline, 1)
1629 let bottomline = bottomline - 1
1631 " topline contains more than just the left delim
1634 " remove the delim. If there is a space after it
1635 " then remove this too if appropriate
1636 let delimIndx = stridx(theLine, leftUnEsc)
1637 if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1638 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr)
1640 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
1642 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1643 call setline(a:topline, theLine)
1646 " get the last line so we can remove the right delim
1647 let theLine = getline(bottomline)
1649 " if the bottomline contains only the right delim then just delete it
1650 if theLine =~ '^[ \t]*' . right . '[ \t]*$'
1651 call cursor(bottomline, 1)
1654 " the last line contains more than the right delim
1656 " remove the right delim. If there is a space after it and
1657 " if the appropriate options are set then remove this too.
1658 let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine)
1659 if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1660 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr)
1662 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
1665 " if the last line also starts with a sexy comment marker then we
1666 " remove this as well
1667 if theLine =~ '^[ \t]*' . sexyComMarker
1669 " remove the sexyComMarker. If there is a space after it then
1671 let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
1672 if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1673 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
1675 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1679 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1680 call setline(bottomline, theLine)
1684 " Function: s:UncommentLineNormal(line) {{{2
1685 " uncomments the given line and returns the result
1687 " -line: the line to uncomment
1688 function s:UncommentLineNormal(line)
1691 "get the comment status on the line so we know how it is commented
1692 let lineCommentStatus = s:IsCommentedOuttermost(b:NERDLeft, b:NERDRight, b:NERDLeftAlt, b:NERDRightAlt, line)
1694 "it is commented with b:NERDLeft and b:NERDRight so remove these delims
1695 if lineCommentStatus == 1
1696 let line = s:RemoveDelimiters(b:NERDLeft, b:NERDRight, line)
1698 "it is commented with b:NERDLeftAlt and b:NERDRightAlt so remove these delims
1699 elseif lineCommentStatus == 2 && g:NERDRemoveAltComs
1700 let line = s:RemoveDelimiters(b:NERDLeftAlt, b:NERDRightAlt, line)
1702 "it is not properly commented with any delims so we check if it has
1703 "any random left or right delims on it and remove the outtermost ones
1705 "get the positions of all delim types on the line
1706 let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line)
1707 let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line)
1708 let indxRight = s:FindDelimiterIndex(b:NERDRight, line)
1709 let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line)
1711 "remove the outter most left comment delim
1712 if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1)
1713 let line = s:RemoveDelimiters(b:NERDLeft, '', line)
1714 elseif indxLeftAlt != -1
1715 let line = s:RemoveDelimiters(b:NERDLeftAlt, '', line)
1718 "remove the outter most right comment delim
1719 if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1)
1720 let line = s:RemoveDelimiters('', b:NERDRight, line)
1721 elseif indxRightAlt != -1
1722 let line = s:RemoveDelimiters('', b:NERDRightAlt, line)
1727 let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line)
1728 let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line)
1729 let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line)
1731 let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
1732 let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line)
1733 let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
1735 let right = b:NERDRight
1736 let left = b:NERDLeft
1738 let right = b:NERDRightAlt
1739 let left = b:NERDLeftAlt
1743 "if there are place-holders on the line then we check to see if they are
1744 "the outtermost delimiters on the line. If so then we replace them with
1746 if indxLeftPlace != -1
1747 if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
1748 let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
1750 elseif indxRightPlace != -1
1751 if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
1752 let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
1757 let line = s:ConvertLeadingWhiteSpace(line)
1762 " Function: s:UncommentLinesNormal(topline, bottomline) {{{2
1763 " This function is called to uncomment lines that arent a sexy comment
1765 " -topline/bottomline: the top/bottom line numbers of the comment
1766 function s:UncommentLinesNormal(topline, bottomline)
1767 let currentLine = a:topline
1768 while currentLine <= a:bottomline
1769 let line = getline(currentLine)
1770 call setline(currentLine, s:UncommentLineNormal(line))
1771 let currentLine = currentLine + 1
1776 " Section: Other helper functions {{{1
1777 " ============================================================================
1779 " Function: s:AddLeftDelim(delim, theLine) {{{2
1781 function s:AddLeftDelim(delim, theLine)
1782 return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '')
1785 " Function: s:AddLeftDelimAligned(delim, theLine) {{{2
1787 function s:AddLeftDelimAligned(delim, theLine, alignIndx)
1789 "if the line is not long enough then bung some extra spaces on the front
1790 "so we can align the delim properly
1791 let theLine = a:theLine
1792 if strlen(theLine) < a:alignIndx
1793 let theLine = repeat(' ', a:alignIndx - strlen(theLine))
1796 return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
1799 " Function: s:AddRightDelim(delim, theLine) {{{2
1801 function s:AddRightDelim(delim, theLine)
1805 return substitute(a:theLine, '$', a:delim, '')
1809 " Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2
1811 function s:AddRightDelimAligned(delim, theLine, alignIndx)
1816 " when we align the right delim we are just adding spaces
1817 " so we get a string containing the needed spaces (it
1819 let extraSpaces = ''
1820 let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine))
1822 " add the right delim
1823 return substitute(a:theLine, '$', extraSpaces . a:delim, '')
1827 " Function: s:AltMultipart() {{{2
1828 " returns 1 if the alternative delims are multipart
1829 function s:AltMultipart()
1830 return b:NERDRightAlt != ''
1833 " Function: s:CanCommentLine(forceNested, line) {{{2
1834 "This function is used to determine whether the given line can be commented.
1835 "It returns 1 if it can be and 0 otherwise
1838 " -forceNested: a flag indicating whether the caller wants comments to be nested
1839 " if the current line is already commented
1840 " -lineNum: the line num of the line to check for commentability
1841 function s:CanCommentLine(forceNested, lineNum)
1842 let theLine = getline(a:lineNum)
1844 " make sure we don't comment lines that are just spaces or tabs or empty.
1845 if theLine =~ "^[ \t]*$"
1849 "if the line is part of a sexy comment then just flag it...
1850 if s:IsInSexyComment(a:lineNum)
1854 let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
1856 "if the line isnt commented return true
1861 "if the line is commented but nesting is allowed then return true
1862 if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)
1869 " Function: s:CanPlaceCursor(line, col) {{{2
1870 " returns 1 if the cursor can be placed exactly in the given position
1871 function s:CanPlaceCursor(line, col)
1874 call cursor(a:line, a:col)
1875 let success = (line(".") == a:line && col(".") == a:col)
1880 " Function: s:CanSexyCommentLines(topline, bottomline) {{{2
1881 " Return: 1 if the given lines can be commented sexually, 0 otherwise
1882 function s:CanSexyCommentLines(topline, bottomline)
1883 " see if the selected regions have any sexy comments
1884 let currentLine = a:topline
1885 while(currentLine <= a:bottomline)
1886 if s:IsInSexyComment(currentLine)
1889 let currentLine = currentLine + 1
1893 " Function: s:CanToggleCommentLine(forceNested, line) {{{2
1894 "This function is used to determine whether the given line can be toggle commented.
1895 "It returns 1 if it can be and 0 otherwise
1898 " -lineNum: the line num of the line to check for commentability
1899 function s:CanToggleCommentLine(forceNested, lineNum)
1900 let theLine = getline(a:lineNum)
1901 if (s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)) && !a:forceNested
1905 " make sure we don't comment lines that are just spaces or tabs or empty.
1906 if theLine =~ "^[ \t]*$"
1910 "if the line is part of a sexy comment then just flag it...
1911 if s:IsInSexyComment(a:lineNum)
1918 " Function: s:ConvertLeadingSpacesToTabs(line) {{{2
1919 " This function takes a line and converts all leading tabs on that line into
1923 " -line: the line whose leading tabs will be converted
1924 function s:ConvertLeadingSpacesToTabs(line)
1925 let toReturn = a:line
1926 while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$'
1927 let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "")
1934 " Function: s:ConvertLeadingTabsToSpaces(line) {{{2
1935 " This function takes a line and converts all leading spaces on that line into
1939 " -line: the line whose leading spaces will be converted
1940 function s:ConvertLeadingTabsToSpaces(line)
1941 let toReturn = a:line
1942 while toReturn =~ '^\( *\)\t'
1943 let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "")
1949 " Function: s:ConvertLeadingWhiteSpace(line) {{{2
1950 " Converts the leading white space to tabs/spaces depending on &ts
1953 " -line: the line to convert
1954 function s:ConvertLeadingWhiteSpace(line)
1955 let toReturn = a:line
1956 while toReturn =~ '^ *\t'
1957 let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g")
1961 let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
1968 " Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2
1969 " This function counts the number of substrings contained in another string.
1970 " These substrings are only counted if they are not escaped with escChar
1972 " -str: the string to look for searchstr in
1973 " -searchstr: the substring to search for in str
1974 " -escChar: the escape character which, when preceding an instance of
1975 " searchstr, will cause it not to be counted
1976 function s:CountNonESCedOccurances(str, searchstr, escChar)
1977 "get the index of the first occurrence of searchstr
1978 let indx = stridx(a:str, a:searchstr)
1980 "if there is an instance of searchstr in str process it
1982 "get the remainder of str after this instance of searchstr is removed
1983 let lensearchstr = strlen(a:searchstr)
1984 let strLeft = strpart(a:str, indx+lensearchstr)
1986 "if this instance of searchstr is not escaped, add one to the count
1987 "and recurse. If it is escaped, just recurse
1988 if !s:IsEscaped(a:str, indx, a:escChar)
1989 return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
1991 return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
1995 " Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2
1996 " Returns 1 if the given block of lines has a delimiter (a:delim) in it
1998 " -delim: the comment delimiter to check the block for
1999 " -top: the top line number of the block
2000 " -bottom: the bottom line number of the block
2001 function s:DoesBlockHaveDelim(delim, top, bottom)
2002 let currentLine = a:top
2003 while currentLine < a:bottom
2004 let theline = getline(currentLine)
2005 if s:FindDelimiterIndex(a:delim, theline) != -1
2008 let currentLine = currentLine + 1
2013 " Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2
2014 " Returns 1 if the given block has a >= 1 multipart delimiter in it
2016 " -top: the top line number of the block
2017 " -bottom: the bottom line number of the block
2018 function s:DoesBlockHaveMultipartDelim(top, bottom)
2019 if s:HasMultipartDelims()
2021 return s:DoesBlockHaveDelim(b:NERDLeft, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRight, a:top, a:bottom)
2023 return s:DoesBlockHaveDelim(b:NERDLeftAlt, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRightAlt, a:top, a:bottom)
2030 " Function: s:Esc(str) {{{2
2031 " Escapes all the tricky chars in the given string
2033 let charsToEsc = '*/\."&$+'
2034 return escape(a:str, charsToEsc)
2037 " Function: s:FindDelimiterIndex(delimiter, line) {{{2
2038 " This function is used to get the string index of the input comment delimiter
2039 " on the input line. If no valid comment delimiter is found in the line then
2042 " -delimiter: the delimiter we are looking to find the index of
2043 " -line: the line we are looking for delimiter on
2044 function s:FindDelimiterIndex(delimiter, line)
2046 "make sure the delimiter isnt empty otherwise we go into an infinite loop.
2047 if a:delimiter == ""
2052 let l:delimiter = a:delimiter
2053 let lenDel = strlen(l:delimiter)
2055 "get the index of the first occurrence of the delimiter
2056 let delIndx = stridx(a:line, l:delimiter)
2058 "keep looping thru the line till we either find a real comment delimiter
2062 "if we are not off the EOL get the str before the possible delimiter
2063 "in question and check if it really is a delimiter. If it is, return
2066 if s:IsDelimValid(l:delimiter, delIndx, a:line)
2071 "we have not yet found a real comment delimiter so move past the
2072 "current one we are lookin at
2073 let restOfLine = strpart(a:line, delIndx + lenDel)
2074 let distToNextDelim = stridx(restOfLine , l:delimiter)
2076 "if distToNextDelim is -1 then there is no more potential delimiters
2077 "on the line so set delIndx to -1. Otherwise, move along the line by
2079 if distToNextDelim == -1
2082 let delIndx = delIndx + lenDel + distToNextDelim
2086 "there is no comment delimiter on this line
2090 " Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2
2091 " This function takes in a line number and tests whether this line number is
2092 " the top/bottom/middle line of a sexy comment. If it is then the top/bottom
2093 " lines of the sexy comment are returned
2095 " -lineNum: the line number that is to be tested whether it is the
2096 " top/bottom/middle line of a sexy com
2098 " A string that has the top/bottom lines of the sexy comment encoded in it.
2099 " The format is 'topline,bottomline'. If a:lineNum turns out not to be the
2100 " top/bottom/middle of a sexy comment then -1 is returned
2101 function s:FindBoundingLinesOfSexyCom(lineNum)
2103 "find which delimiters to look for as the start/end delims of the comment
2107 let left = s:GetLeft(0,0,1)
2108 let right = s:GetRight(0,0,1)
2109 elseif s:AltMultipart()
2110 let left = s:GetLeft(1,0,1)
2111 let right = s:GetRight(1,0,1)
2116 let sexyComMarker = s:GetSexyComMarker(0, 1)
2118 "initialise the top/bottom line numbers of the sexy comment to -1
2122 let currentLine = a:lineNum
2123 while top == -1 || bottom == -1
2124 let theLine = getline(currentLine)
2126 "check if the current line is the top of the sexy comment
2127 if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf()
2128 let top = currentLine
2129 let currentLine = a:lineNum
2131 "check if the current line is the bottom of the sexy comment
2132 elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1
2133 let bottom = currentLine
2135 "the right delimiter is on the same line as the last sexyComMarker
2136 elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right
2137 let bottom = currentLine
2139 "we have not found the top or bottom line so we assume currentLine is an
2140 "intermediate line and look to prove otherwise
2143 "if the line doesnt start with a sexyComMarker then it is not a sexy
2145 if theLine !~ '^[ \t]*' . sexyComMarker
2151 "if top is -1 then we havent found the top yet so keep looking up
2153 let currentLine = currentLine - 1
2154 "if we have found the top line then go down looking for the bottom
2156 let currentLine = currentLine + 1
2161 return [top, bottom]
2165 " Function: s:GetLeft(alt, space, esc) {{{2
2166 " returns the left/left-alternative delimiter
2168 " -alt: specifies whether to get left or left-alternative delim
2169 " -space: specifies whether the delim should be spaced or not
2170 " (the space string will only be added if NERDSpaceDelims is set)
2171 " -esc: specifies whether the tricky chars in the delim should be ESCed
2172 function s:GetLeft(alt, space, esc)
2173 let delim = b:NERDLeft
2176 if b:NERDLeftAlt == ''
2179 let delim = b:NERDLeftAlt
2186 if a:space && g:NERDSpaceDelims
2187 let delim = delim . s:spaceStr
2191 let delim = s:Esc(delim)
2197 " Function: s:GetRight(alt, space, esc) {{{2
2198 " returns the right/right-alternative delimiter
2200 " -alt: specifies whether to get right or right-alternative delim
2201 " -space: specifies whether the delim should be spaced or not
2202 " (the space string will only be added if NERDSpaceDelims is set)
2203 " -esc: specifies whether the tricky chars in the delim should be ESCed
2204 function s:GetRight(alt, space, esc)
2205 let delim = b:NERDRight
2208 if !s:AltMultipart()
2211 let delim = b:NERDRightAlt
2218 if a:space && g:NERDSpaceDelims
2219 let delim = s:spaceStr . delim
2223 let delim = s:Esc(delim)
2230 " Function: s:GetSexyComMarker() {{{2
2231 " Returns the sexy comment marker for the current filetype.
2233 " C style sexy comments are assumed if possible. If not then the sexy comment
2234 " marker is the last char of the delimiter pair that has both left and right
2235 " delims and has the longest left delim
2238 " -space: specifies whether the marker is to have a space string after it
2239 " (the space string will only be added if NERDSpaceDelims is set)
2240 " -esc: specifies whether the tricky chars in the marker are to be ESCed
2241 function s:GetSexyComMarker(space, esc)
2242 let sexyComMarker = b:NERDSexyComMarker
2244 "if there is no hardcoded marker then we find one
2245 if sexyComMarker == ''
2247 "if the filetype has c style comments then use standard c sexy
2249 if s:HasCStyleComments()
2250 let sexyComMarker = '*'
2252 "find a comment marker by getting the longest available left delim
2253 "(that has a corresponding right delim) and taking the last char
2254 let lenLeft = strlen(b:NERDLeft)
2255 let lenLeftAlt = strlen(b:NERDLeftAlt)
2258 if s:Multipart() && lenLeft >= lenLeftAlt
2259 let left = b:NERDLeft
2260 elseif s:AltMultipart()
2261 let left = b:NERDLeftAlt
2266 "get the last char of left
2267 let sexyComMarker = strpart(left, strlen(left)-1)
2271 if a:space && g:NERDSpaceDelims
2272 let sexyComMarker = sexyComMarker . s:spaceStr
2276 let sexyComMarker = s:Esc(sexyComMarker)
2279 return sexyComMarker
2282 " Function: s:GetSexyComLeft(space, esc) {{{2
2283 " Returns the left delimiter for sexy comments for this filetype or -1 if
2284 " there is none. C style sexy comments are used if possible
2286 " -space: specifies if the delim has a space string on the end
2287 " (the space string will only be added if NERDSpaceDelims is set)
2288 " -esc: specifies whether the tricky chars in the string are ESCed
2289 function s:GetSexyComLeft(space, esc)
2290 let lenLeft = strlen(b:NERDLeft)
2291 let lenLeftAlt = strlen(b:NERDLeftAlt)
2294 "assume c style sexy comments if possible
2295 if s:HasCStyleComments()
2298 "grab the longest left delim that has a right
2299 if s:Multipart() && lenLeft >= lenLeftAlt
2300 let left = b:NERDLeft
2301 elseif s:AltMultipart()
2302 let left = b:NERDLeftAlt
2308 if a:space && g:NERDSpaceDelims
2309 let left = left . s:spaceStr
2313 let left = s:Esc(left)
2319 " Function: s:GetSexyComRight(space, esc) {{{2
2320 " Returns the right delimiter for sexy comments for this filetype or -1 if
2321 " there is none. C style sexy comments are used if possible.
2323 " -space: specifies if the delim has a space string on the start
2324 " (the space string will only be added if NERDSpaceDelims
2325 " is specified for the current filetype)
2326 " -esc: specifies whether the tricky chars in the string are ESCed
2327 function s:GetSexyComRight(space, esc)
2328 let lenLeft = strlen(b:NERDLeft)
2329 let lenLeftAlt = strlen(b:NERDLeftAlt)
2332 "assume c style sexy comments if possible
2333 if s:HasCStyleComments()
2336 "grab the right delim that pairs with the longest left delim
2337 if s:Multipart() && lenLeft >= lenLeftAlt
2338 let right = b:NERDRight
2339 elseif s:AltMultipart()
2340 let right = b:NERDRightAlt
2346 if a:space && g:NERDSpaceDelims
2347 let right = s:spaceStr . right
2351 let right = s:Esc(right)
2357 " Function: s:HasMultipartDelims() {{{2
2358 " Returns 1 iff the current filetype has at least one set of multipart delims
2359 function s:HasMultipartDelims()
2360 return s:Multipart() || s:AltMultipart()
2363 " Function: s:HasLeadingTabs(...) {{{2
2364 " Returns 1 if any of the given strings have leading tabs
2365 function s:HasLeadingTabs(...)
2373 " Function: s:HasCStyleComments() {{{2
2374 " Returns 1 iff the current filetype has c style comment delimiters
2375 function s:HasCStyleComments()
2376 return (b:NERDLeft == '/*' && b:NERDRight == '*/') || (b:NERDLeftAlt == '/*' && b:NERDRightAlt == '*/')
2379 " Function: s:IsCommentedNormOrSexy(lineNum) {{{2
2380 "This function is used to determine whether the given line is commented with
2381 "either set of delimiters or if it is part of a sexy comment
2384 " -lineNum: the line number of the line to check
2385 function s:IsCommentedNormOrSexy(lineNum)
2386 let theLine = getline(a:lineNum)
2388 "if the line is commented normally return 1
2389 if s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)
2393 "if the line is part of a sexy comment return 1
2394 if s:IsInSexyComment(a:lineNum)
2400 " Function: s:IsCommented(left, right, line) {{{2
2401 "This function is used to determine whether the given line is commented with
2402 "the given delimiters
2405 " -line: the line that to check if commented
2406 " -left/right: the left and right delimiters to check for
2407 function s:IsCommented(left, right, line)
2408 "if the line isnt commented return true
2409 if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart())
2415 " Function: s:IsCommentedFromStartOfLine(left, line) {{{2
2416 "This function is used to determine whether the given line is commented with
2417 "the given delimiters at the start of the line i.e the left delimiter is the
2418 "first thing on the line (apart from spaces\tabs)
2421 " -line: the line that to check if commented
2422 " -left: the left delimiter to check for
2423 function s:IsCommentedFromStartOfLine(left, line)
2424 let theLine = s:ConvertLeadingTabsToSpaces(a:line)
2425 let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', ''))
2426 let delimIndx = s:FindDelimiterIndex(a:left, theLine)
2427 return delimIndx == numSpaces
2430 " Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2
2431 " Finds the type of the outtermost delims on the line
2434 " -line: the line that to check if the outtermost comments on it are
2436 " -left/right: the left and right delimiters to check for
2437 " -leftAlt/rightAlt: the left and right alternative delimiters to check for
2440 " 0 if the line is not commented with either set of delims
2441 " 1 if the line is commented with the left/right delim set
2442 " 2 if the line is commented with the leftAlt/rightAlt delim set
2443 function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line)
2444 "get the first positions of the left delims and the last positions of the
2446 let indxLeft = s:FindDelimiterIndex(a:left, a:line)
2447 let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line)
2448 let indxRight = s:LastIndexOfDelim(a:right, a:line)
2449 let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line)
2451 "check if the line has a left delim before a leftAlt delim
2452 if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1
2453 "check if the line has a right delim after any rightAlt delim
2454 if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart()
2458 "check if the line has a leftAlt delim before a left delim
2459 elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1
2460 "check if the line has a rightAlt delim after any right delim
2461 if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart()
2473 " Function: s:IsDelimValid(delimiter, delIndx, line) {{{2
2474 " This function is responsible for determining whether a given instance of a
2475 " comment delimiter is a real delimiter or not. For example, in java the
2476 " // string is a comment delimiter but in the line:
2477 " System.out.println("//");
2478 " it does not count as a comment delimiter. This function is responsible for
2479 " distinguishing between such cases. It does so by applying a set of
2480 " heuristics that are not fool proof but should work most of the time.
2483 " -delimiter: the delimiter we are validating
2484 " -delIndx: the position of delimiter in line
2485 " -line: the line that delimiter occurs in
2488 " 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
2490 function s:IsDelimValid(delimiter, delIndx, line)
2491 "get the delimiter without the escchars
2492 let l:delimiter = a:delimiter
2494 "get the strings before and after the delimiter
2495 let preComStr = strpart(a:line, 0, a:delIndx)
2496 let postComStr = strpart(a:line, a:delIndx+strlen(delimiter))
2498 "to check if the delimiter is real, make sure it isnt preceded by
2499 "an odd number of quotes and followed by the same (which would indicate
2500 "that it is part of a string and therefore is not a comment)
2501 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\"))
2504 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\"))
2507 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\"))
2512 "if the comment delimiter is escaped, assume it isnt a real delimiter
2513 if s:IsEscaped(a:line, a:delIndx, "\\")
2517 "vim comments are so fuckin stupid!! Why the hell do they have comment
2518 "delimiters that are used elsewhere in the syntax?!?! We need to check
2519 "some conditions especially for vim
2520 if &filetype == "vim"
2521 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\"))
2525 "if the delimiter is on the very first char of the line or is the
2526 "first non-tab/space char on the line then it is a valid comment delimiter
2527 if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$"
2531 let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\")
2532 let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\")
2534 "if the quote is inside brackets then assume it isnt a comment
2535 if numLeftParen > numRightParen
2539 "if the line has an even num of unescaped "'s then we can assume that
2540 "any given " is not a comment delimiter
2541 if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\"))
2550 " Function: s:IsNumEven(num) {{{2
2551 " A small function the returns 1 if the input number is even and 0 otherwise
2553 " -num: the number to check
2554 function s:IsNumEven(num)
2555 return (a:num % 2) == 0
2558 " Function: s:IsEscaped(str, indx, escChar) {{{2
2559 " This function takes a string, an index into that string and an esc char and
2560 " returns 1 if the char at the index is escaped (i.e if it is preceded by an
2561 " odd number of esc chars)
2563 " -str: the string to check
2564 " -indx: the index into str that we want to check
2565 " -escChar: the escape char the char at indx may be ESCed with
2566 function s:IsEscaped(str, indx, escChar)
2567 "initialise numEscChars to 0 and look at the char before indx
2569 let curIndx = a:indx-1
2571 "keep going back thru str until we either reach the start of the str or
2572 "run out of esc chars
2573 while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar
2575 "we have found another esc char so add one to the count and move left
2577 let numEscChars = numEscChars + 1
2578 let curIndx = curIndx - 1
2582 "if there is an odd num of esc chars directly before the char at indx then
2583 "the char at indx is escaped
2584 return !s:IsNumEven(numEscChars)
2587 " Function: s:IsInSexyComment(line) {{{2
2588 " returns 1 if the given line number is part of a sexy comment
2589 function s:IsInSexyComment(line)
2590 return !empty(s:FindBoundingLinesOfSexyCom(a:line))
2593 " Function: s:IsSexyComment(topline, bottomline) {{{2
2594 " This function takes in 2 line numbers and returns 1 if the lines between and
2595 " including the given line numbers are a sexy comment. It returns 0 otherwise.
2597 " -topline: the line that the possible sexy comment starts on
2598 " -bottomline: the line that the possible sexy comment stops on
2599 function s:IsSexyComment(topline, bottomline)
2601 "get the delim set that would be used for a sexy comment
2605 let left = b:NERDLeft
2606 let right = b:NERDRight
2607 elseif s:AltMultipart()
2608 let left = b:NERDLeftAlt
2609 let right = b:NERDRightAlt
2614 "swap the top and bottom line numbers around if need be
2615 let topline = a:topline
2616 let bottomline = a:bottomline
2617 if bottomline < topline
2618 topline = bottomline
2619 bottomline = a:topline
2622 "if there is < 2 lines in the comment it cannot be sexy
2623 if (bottomline - topline) <= 0
2627 "if the top line doesnt begin with a left delim then the comment isnt sexy
2628 if getline(a:topline) !~ '^[ \t]*' . left
2632 "if there is a right delim on the top line then this isnt a sexy comment
2633 if s:FindDelimiterIndex(right, getline(a:topline)) != -1
2637 "if there is a left delim on the bottom line then this isnt a sexy comment
2638 if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1
2642 "if the bottom line doesnt begin with a right delim then the comment isnt
2644 if getline(a:bottomline) !~ '^.*' . right . '$'
2648 let sexyComMarker = s:GetSexyComMarker(0, 1)
2650 "check each of the intermediate lines to make sure they start with a
2652 let currentLine = a:topline+1
2653 while currentLine < a:bottomline
2654 let theLine = getline(currentLine)
2656 if theLine !~ '^[ \t]*' . sexyComMarker
2660 "if there is a right delim in an intermediate line then the block isnt
2662 if s:FindDelimiterIndex(right, theLine) != -1
2666 let currentLine = currentLine + 1
2669 "we have not found anything to suggest that this isnt a sexy comment so
2674 " Function: s:LastIndexOfDelim(delim, str) {{{2
2675 " This function takes a string and a delimiter and returns the last index of
2676 " that delimiter in string
2678 " -delim: the delimiter to look for
2679 " -str: the string to look for delim in
2680 function s:LastIndexOfDelim(delim, str)
2682 let lenDelim = strlen(delim)
2684 "set index to the first occurrence of delim. If there is no occurrence then
2686 let indx = s:FindDelimiterIndex(delim, a:str)
2691 "keep moving to the next instance of delim in str till there is none left
2694 "search for the next delim after the previous one
2695 let searchStr = strpart(a:str, indx+lenDelim)
2696 let indx2 = s:FindDelimiterIndex(delim, searchStr)
2698 "if we find a delim update indx to record the position of it, if we
2699 "dont find another delim then indx is the last one so break out of
2702 let indx = indx + indx2 + lenDelim
2712 " Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
2713 " This function takes in 2 line numbers and returns the index of the left most
2714 " char (that is not a space or a tab) on all of these lines.
2716 " -countCommentedLines: 1 if lines that are commented are to be checked as
2718 " -countEmptyLines: 1 if empty lines are to be counted in the search
2719 " -topline: the top line to be checked
2720 " -bottomline: the bottom line to be checked
2721 function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
2723 " declare the left most index as an extreme value
2724 let leftMostIndx = 1000
2726 " go thru the block line by line updating leftMostIndx
2727 let currentLine = a:topline
2728 while currentLine <= a:bottomline
2730 " get the next line and if it is allowed to be commented, or is not
2731 " commented, check it
2732 let theLine = getline(currentLine)
2733 if a:countEmptyLines || theLine !~ '^[ \t]*$'
2734 if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine))
2735 " convert spaces to tabs and get the number of leading spaces for
2736 " this line and update leftMostIndx if need be
2737 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
2738 let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') )
2739 if leadSpaceOfLine < leftMostIndx
2740 let leftMostIndx = leadSpaceOfLine
2745 " move on to the next line
2746 let currentLine = currentLine + 1
2749 if leftMostIndx == 1000
2756 " Function: s:Multipart() {{{2
2757 " returns 1 if the current delims are multipart
2758 function s:Multipart()
2759 return b:NERDRight != ''
2762 " Function: s:NerdEcho(msg, typeOfMsg) {{{2
2764 " -msg: the message to echo
2765 " -typeOfMsg: 0 = warning message
2766 " 1 = normal message
2767 function s:NerdEcho(msg, typeOfMsg)
2770 echo 'NERDCommenter:' . a:msg
2772 elseif a:typeOfMsg == 1
2773 echo 'NERDCommenter:' . a:msg
2777 " Function: s:NumberOfLeadingTabs(s) {{{2
2778 " returns the number of leading tabs in the given string
2779 function s:NumberOfLeadingTabs(s)
2780 return strlen(substitute(a:s, '^\(\t*\).*$', '\1', ""))
2783 " Function: s:NumLinesInBuf() {{{2
2784 " Returns the number of lines in the current buffer
2785 function s:NumLinesInBuf()
2789 " Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2
2790 " This function takes in a string, 2 delimiters in that string and 2 strings
2791 " to replace these delimiters with.
2794 " -toReplace1: the first delimiter to replace
2795 " -toReplace2: the second delimiter to replace
2796 " -replacor1: the string to replace toReplace1 with
2797 " -replacor2: the string to replace toReplace2 with
2798 " -str: the string that the delimiters to be replaced are in
2799 function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str)
2800 let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str)
2801 let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line)
2805 " Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2
2806 " This function takes a string and a delimiter and replaces the left most
2807 " occurrence of this delimiter in the string with a given string
2810 " -toReplace: the delimiter in str that is to be replaced
2811 " -replacor: the string to replace toReplace with
2812 " -str: the string that contains toReplace
2813 function s:ReplaceLeftMostDelim(toReplace, replacor, str)
2814 let toReplace = a:toReplace
2815 let replacor = a:replacor
2816 "get the left most occurrence of toReplace
2817 let indxToReplace = s:FindDelimiterIndex(toReplace, a:str)
2819 "if there IS an occurrence of toReplace in str then replace it and return
2820 "the resulting string
2821 if indxToReplace != -1
2822 let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
2829 " Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2
2830 " This function takes a string and a delimiter and replaces the right most
2831 " occurrence of this delimiter in the string with a given string
2834 " -toReplace: the delimiter in str that is to be replaced
2835 " -replacor: the string to replace toReplace with
2836 " -str: the string that contains toReplace
2838 function s:ReplaceRightMostDelim(toReplace, replacor, str)
2839 let toReplace = a:toReplace
2840 let replacor = a:replacor
2841 let lenToReplace = strlen(toReplace)
2843 "get the index of the last delim in str
2844 let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
2846 "if there IS a delimiter in str, replace it and return the result
2848 if indxToReplace != -1
2849 let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
2854 "FUNCTION: s:RestoreScreenState() {{{2
2856 "Sets the screen state back to what it was when s:SaveScreenState was last
2859 function s:RestoreScreenState()
2860 if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos")
2861 throw 'NERDCommenter exception: cannot restore screen'
2864 call cursor(t:NERDComOldTopLine, 0)
2866 call setpos(".", t:NERDComOldPos)
2869 " Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
2870 " This function takes in 2 line numbers and returns the index of the right most
2871 " char on all of these lines.
2873 " -countCommentedLines: 1 if lines that are commented are to be checked as
2875 " -countEmptyLines: 1 if empty lines are to be counted in the search
2876 " -topline: the top line to be checked
2877 " -bottomline: the bottom line to be checked
2878 function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
2879 let rightMostIndx = -1
2881 " go thru the block line by line updating rightMostIndx
2882 let currentLine = a:topline
2883 while currentLine <= a:bottomline
2885 " get the next line and see if it is commentable, otherwise it doesnt
2887 let theLine = getline(currentLine)
2888 if a:countEmptyLines || theLine !~ '^[ \t]*$'
2890 if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine))
2892 " update rightMostIndx if need be
2893 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
2894 let lineLen = strlen(theLine)
2895 if lineLen > rightMostIndx
2896 let rightMostIndx = lineLen
2901 " move on to the next line
2902 let currentLine = currentLine + 1
2905 return rightMostIndx
2908 "FUNCTION: s:SaveScreenState() {{{2
2909 "Saves the current cursor position in the current buffer and the window
2911 function s:SaveScreenState()
2912 let t:NERDComOldPos = getpos(".")
2913 let t:NERDComOldTopLine = line("w0")
2916 " Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2
2917 " This function takes a line and swaps the outter most multi-part delims for
2920 " -line: the line to swap the delims in
2922 function s:SwapOutterMultiPartDelimsForPlaceHolders(line)
2923 " find out if the line is commented using normal delims and/or
2925 let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, a:line)
2926 let isCommentedAlt = s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, a:line)
2930 "if the line is commented and there is a right delimiter, replace
2931 "the delims with place-holders
2932 if isCommented && s:Multipart()
2933 let line2 = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, a:line)
2935 "similarly if the line is commented with the alternative
2937 elseif isCommentedAlt && s:AltMultipart()
2938 let line2 = s:ReplaceDelims(b:NERDLeftAlt, b:NERDRightAlt, g:NERDLPlace, g:NERDRPlace, a:line)
2944 " Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2
2945 " This function takes a line and swaps the outtermost place holders for
2948 " -line: the line to swap the delims in
2950 function s:SwapOutterPlaceHoldersForMultiPartDelims(line)
2954 let left = b:NERDLeft
2955 let right = b:NERDRight
2956 elseif s:AltMultipart()
2957 let left = b:NERDLeftAlt
2958 let right = b:NERDRightAlt
2961 let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
2964 " Function: s:TabbedCol(line, col) {{{2
2965 " Gets the col number for given line and existing col number. The new col
2966 " number is the col number when all leading spaces are converted to tabs
2968 " -line:the line to get the rel col for
2970 function s:TabbedCol(line, col)
2971 let lineTruncated = strpart(a:line, 0, a:col)
2972 let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g')
2973 return strlen(lineSpacesToTabs)
2975 "FUNCTION: s:TabSpace() {{{2
2976 "returns a string of spaces equal in length to &tabstop
2977 function s:TabSpace()
2979 let spacesPerTab = &tabstop
2980 while spacesPerTab > 0
2981 let tabSpace = tabSpace . " "
2982 let spacesPerTab = spacesPerTab - 1
2987 " Function: s:UnEsc(str, escChar) {{{2
2988 " This function removes all the escape chars from a string
2990 " -str: the string to remove esc chars from
2991 " -escChar: the escape char to be removed
2992 function s:UnEsc(str, escChar)
2993 return substitute(a:str, a:escChar, "", "g")
2996 " Function: s:UntabbedCol(line, col) {{{2
2997 " Takes a line and a col and returns the absolute column of col taking into
2998 " account that a tab is worth 3 or 4 (or whatever) spaces.
3000 " -line:the line to get the abs col for
3001 " -col: the col that doesnt take into account tabs
3002 function s:UntabbedCol(line, col)
3003 let lineTruncated = strpart(a:line, 0, a:col)
3004 let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g')
3005 return strlen(lineTabsToSpaces)
3007 " Section: Comment mapping setup {{{1
3008 " ===========================================================================
3010 " switch to/from alternative delimiters
3011 nnoremap <plug>NERDCommenterAltDelims :call <SID>SwitchToAlternativeDelimiters(1)<cr>
3014 nnoremap <silent> <plug>NERDCommenterComment :call NERDComment(0, "norm")<cr>
3015 vnoremap <silent> <plug>NERDCommenterComment <ESC>:call NERDComment(1, "norm")<cr>
3018 nnoremap <silent> <plug>NERDCommenterToggle :call NERDComment(0, "toggle")<cr>
3019 vnoremap <silent> <plug>NERDCommenterToggle <ESC>:call NERDComment(1, "toggle")<cr>
3022 nnoremap <silent> <plug>NERDCommenterMinimal :call NERDComment(0, "minimal")<cr>
3023 vnoremap <silent> <plug>NERDCommenterMinimal <ESC>:call NERDComment(1, "minimal")<cr>
3026 nnoremap <silent> <plug>NERDCommenterSexy :call NERDComment(0, "sexy")<CR>
3027 vnoremap <silent> <plug>NERDCommenterSexy <ESC>:call NERDComment(1, "sexy")<CR>
3030 nnoremap <silent> <plug>NERDCommenterInvert :call NERDComment(0, "invert")<CR>
3031 vnoremap <silent> <plug>NERDCommenterInvert <ESC>:call NERDComment(1, "invert")<CR>
3034 nmap <silent> <plug>NERDCommenterYank :call NERDComment(0, "yank")<CR>
3035 vmap <silent> <plug>NERDCommenterYank <ESC>:call NERDComment(1, "yank")<CR>
3037 " left aligned comments
3038 nnoremap <silent> <plug>NERDCommenterAlignLeft :call NERDComment(0, "alignLeft")<cr>
3039 vnoremap <silent> <plug>NERDCommenterAlignLeft <ESC>:call NERDComment(1, "alignLeft")<cr>
3041 " left and right aligned comments
3042 nnoremap <silent> <plug>NERDCommenterAlignBoth :call NERDComment(0, "alignBoth")<cr>
3043 vnoremap <silent> <plug>NERDCommenterAlignBoth <ESC>:call NERDComment(1, "alignBoth")<cr>
3046 nnoremap <silent> <plug>NERDCommenterNest :call NERDComment(0, "nested")<cr>
3047 vnoremap <silent> <plug>NERDCommenterNest <ESC>:call NERDComment(1, "nested")<cr>
3050 nnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(0, "uncomment")<cr>
3051 vnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(1, "uncomment")<cr>
3053 " comment till the end of the line
3054 nnoremap <silent> <plug>NERDCommenterToEOL :call NERDComment(0, "toEOL")<cr>
3057 nmap <silent> <plug>NERDCommenterAppend :call NERDComment(0, "append")<cr>
3060 inoremap <silent> <plug>NERDCommenterInInsert <SPACE><BS><ESC>:call NERDComment(0, "insert")<CR>
3063 function! s:CreateMaps(target, combo)
3064 if !hasmapto(a:target, 'n')
3065 exec 'nmap ' . a:combo . ' ' . a:target
3068 if !hasmapto(a:target, 'v')
3069 exec 'vmap ' . a:combo . ' ' . a:target
3073 if g:NERDCreateDefaultMappings
3074 call s:CreateMaps('<plug>NERDCommenterComment', ',cc')
3075 call s:CreateMaps('<plug>NERDCommenterToggle', ',c<space>')
3076 call s:CreateMaps('<plug>NERDCommenterMinimal', ',cm')
3077 call s:CreateMaps('<plug>NERDCommenterSexy', ',cs')
3078 call s:CreateMaps('<plug>NERDCommenterInvert', ',ci')
3079 call s:CreateMaps('<plug>NERDCommenterYank', ',cy')
3080 call s:CreateMaps('<plug>NERDCommenterAlignLeft', ',cl')
3081 call s:CreateMaps('<plug>NERDCommenterAlignBoth', ',cb')
3082 call s:CreateMaps('<plug>NERDCommenterNest', ',cn')
3083 call s:CreateMaps('<plug>NERDCommenterUncomment', ',cu')
3084 call s:CreateMaps('<plug>NERDCommenterToEOL', ',c$')
3085 call s:CreateMaps('<plug>NERDCommenterAppend', ',cA')
3087 if !hasmapto('<plug>NERDCommenterAltDelims', 'n')
3088 nmap ,ca <plug>NERDCommenterAltDelims
3094 " Section: Menu item setup {{{1
3095 " ===========================================================================
3096 "check if the user wants the menu to be displayed
3097 if g:NERDMenuMode != 0
3100 if g:NERDMenuMode == 1
3101 let menuRoot = 'comment'
3102 elseif g:NERDMenuMode == 2
3103 let menuRoot = '&comment'
3104 elseif g:NERDMenuMode == 3
3105 let menuRoot = '&Plugin.&comment'
3108 function! s:CreateMenuItems(target, desc, root)
3109 exec 'nmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
3110 exec 'vmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
3112 call s:CreateMenuItems("<plug>NERDCommenterComment", 'Comment', menuRoot)
3113 call s:CreateMenuItems("<plug>NERDCommenterToggle", 'Toggle', menuRoot)
3114 call s:CreateMenuItems('<plug>NERDCommenterMinimal', 'Minimal', menuRoot)
3115 call s:CreateMenuItems('<plug>NERDCommenterNest', 'Nested', menuRoot)
3116 exec 'nmenu <silent> '. menuRoot .'.To\ EOL <plug>NERDCommenterToEOL'
3117 call s:CreateMenuItems('<plug>NERDCommenterInvert', 'Invert', menuRoot)
3118 call s:CreateMenuItems('<plug>NERDCommenterSexy', 'Sexy', menuRoot)
3119 call s:CreateMenuItems('<plug>NERDCommenterYank', 'Yank\ then\ comment', menuRoot)
3120 exec 'nmenu <silent> '. menuRoot .'.Append <plug>NERDCommenterAppend'
3121 exec 'menu <silent> '. menuRoot .'.-Sep- :'
3122 call s:CreateMenuItems('<plug>NERDCommenterAlignLeft', 'Left\ aligned', menuRoot)
3123 call s:CreateMenuItems('<plug>NERDCommenterAlignBoth', 'Left\ and\ right\ aligned', menuRoot)
3124 exec 'menu <silent> '. menuRoot .'.-Sep2- :'
3125 call s:CreateMenuItems('<plug>NERDCommenterUncomment', 'Uncomment', menuRoot)
3126 exec 'nmenu <silent> '. menuRoot .'.Switch\ Delimiters <plug>NERDCommenterAltDelims'
3127 exec 'imenu <silent> '. menuRoot .'.Insert\ Comment\ Here <plug>NERDCommenterInInsert'
3128 exec 'menu <silent> '. menuRoot .'.-Sep3- :'
3129 exec 'menu <silent>'. menuRoot .'.Help :help NERDCommenterContents<CR>'
3131 " vim: set foldmethod=marker :