]> ruderich.org/simon Gitweb - config/dotfiles.git/blob - vim/bundle/nerdcommenter/plugin/NERD_commenter.vim
colors/simon.vim: Disable reverse for TabLineFill.
[config/dotfiles.git] / vim / bundle / nerdcommenter / plugin / NERD_commenter.vim
1 " ============================================================================
2 " File:        NERD_commenter.vim
3 " Description: vim global plugin that provides easy code commenting
4 " Maintainer:  Martin Grenfell <martin.grenfell at gmail dot com>
5 " Version:     2.3.0
6 " Last Change: 08th December, 2010
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.
12 "
13 " ============================================================================
14
15 " Section: script init stuff {{{1
16 if exists("loaded_nerd_comments")
17     finish
18 endif
19 if v:version < 700
20     echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
21     finish
22 endif
23 let loaded_nerd_comments = 1
24
25 " Function: s:InitVariable() function {{{2
26 " This function is used to initialise a given variable to a given value. The
27 " variable is only initialised if it does not exist prior
28 "
29 " Args:
30 "   -var: the name of the var to be initialised
31 "   -value: the value to initialise var to
32 "
33 " Returns:
34 "   1 if the var is set, 0 otherwise
35 function s:InitVariable(var, value)
36     if !exists(a:var)
37         exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
38         return 1
39     endif
40     return 0
41 endfunction
42
43 " Section: space string init{{{2
44 " When putting spaces after the left delim and before the right we use
45 " s:spaceStr for the space char. This way we can make it add anything after
46 " the left and before the right by modifying this variable
47 let s:spaceStr = ' '
48 let s:lenSpaceStr = strlen(s:spaceStr)
49
50 " Section: variable init calls {{{2
51 call s:InitVariable("g:NERDAllowAnyVisualDelims", 1)
52 call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0)
53 call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0)
54 call s:InitVariable("g:NERDCompactSexyComs", 0)
55 call s:InitVariable("g:NERDCreateDefaultMappings", 1)
56 call s:InitVariable("g:NERDDefaultNesting", 1)
57 call s:InitVariable("g:NERDMenuMode", 3)
58 call s:InitVariable("g:NERDLPlace", "[>")
59 call s:InitVariable("g:NERDUsePlaceHolders", 1)
60 call s:InitVariable("g:NERDRemoveAltComs", 1)
61 call s:InitVariable("g:NERDRemoveExtraSpaces", 1)
62 call s:InitVariable("g:NERDRPlace", "<]")
63 call s:InitVariable("g:NERDSpaceDelims", 0)
64 call s:InitVariable("g:NERDDelimiterRequests", 1)
65
66 let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
67 "vf ;;dA:\ehcs"'A {\ej^f(lyi(k$p0f{a \eA }\e0f{a 'left':\ejdd^
68
69 let s:delimiterMap = {
70     \ 'aap': { 'left': '#' },
71     \ 'abc': { 'left': '%' },
72     \ 'acedb': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
73     \ 'actionscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
74     \ 'ada': { 'left': '--', 'leftAlt': '--  ' },
75     \ 'ahdl': { 'left': '--' },
76     \ 'ahk': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' },
77     \ 'amiga': { 'left': ';' },
78     \ 'aml': { 'left': '/*' },
79     \ 'ampl': { 'left': '#' },
80     \ 'apache': { 'left': '#' },
81     \ 'apachestyle': { 'left': '#' },
82     \ 'asciidoc': { 'left': '//' },
83     \ 'applescript': { 'left': '--', 'leftAlt': '(*', 'rightAlt': '*)' },
84     \ 'asm68k': { 'left': ';' },
85     \ 'asm': { 'left': ';', 'leftAlt': '#' },
86     \ 'asn': { 'left': '--' },
87     \ 'aspvbs': { 'left': '''' },
88     \ 'asterisk': { 'left': ';' },
89     \ 'asy': { 'left': '//' },
90     \ 'atlas': { 'left': 'C', 'right': '$' },
91     \ 'autohotkey': { 'left': ';' },
92     \ 'autoit': { 'left': ';' },
93     \ 'ave': { 'left': "'" },
94     \ 'awk': { 'left': '#' },
95     \ 'basic': { 'left': "'", 'leftAlt': 'REM ' },
96     \ 'bbx': { 'left': '%' },
97     \ 'bc': { 'left': '#' },
98     \ 'bib': { 'left': '%' },
99     \ 'bindzone': { 'left': ';' },
100     \ 'bst': { 'left': '%' },
101     \ 'btm': { 'left': '::' },
102     \ 'caos': { 'left': '*' },
103     \ 'calibre': { 'left': '//' },
104     \ 'catalog': { 'left': '--', 'right': '--' },
105     \ 'c': { 'left': '/*','right': '*/', 'leftAlt': '//' },
106     \ 'cfg': { 'left': '#' },
107     \ 'cg': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
108     \ 'ch': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
109     \ 'cl': { 'left': '#' },
110     \ 'clean': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
111     \ 'clipper': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
112     \ 'clojure': { 'left': ';' },
113     \ 'cmake': { 'left': '#' },
114     \ 'conkyrc': { 'left': '#' },
115     \ 'cpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
116     \ 'crontab': { 'left': '#' },
117     \ 'cs': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
118     \ 'csp': { 'left': '--' },
119     \ 'cterm': { 'left': '*' },
120     \ 'cucumber': { 'left': '#' },
121     \ 'cvs': { 'left': 'CVS:' },
122     \ 'd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
123     \ 'dcl': { 'left': '$!' },
124     \ 'dakota': { 'left': '#' },
125     \ 'debcontrol': { 'left': '#' },
126     \ 'debsources': { 'left': '#' },
127     \ 'def': { 'left': ';' },
128     \ 'desktop': { 'left': '#' },
129     \ 'dhcpd': { 'left': '#' },
130     \ 'diff': { 'left': '#' },
131     \ 'django': { 'left': '<!--','right': '-->', 'leftAlt': '{#', 'rightAlt': '#}' },
132     \ 'docbk': { 'left': '<!--', 'right': '-->' },
133     \ 'dns': { 'left': ';' },
134     \ 'dosbatch': { 'left': 'REM ', 'leftAlt': '::' },
135     \ 'dosini': { 'left': ';' },
136     \ 'dot': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
137     \ 'dracula': { 'left': ';' },
138     \ 'dsl': { 'left': ';' },
139     \ 'dtml': { 'left': '<dtml-comment>', 'right': '</dtml-comment>' },
140     \ 'dylan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
141     \ 'ebuild': { 'left': '#' },
142     \ 'ecd': { 'left': '#' },
143     \ 'eclass': { 'left': '#' },
144     \ 'eiffel': { 'left': '--' },
145     \ 'elf': { 'left': "'" },
146     \ 'elmfilt': { 'left': '#' },
147     \ 'erlang': { 'left': '%' },
148     \ 'eruby': { 'left': '<%#', 'right': '%>', 'leftAlt': '<!--', 'rightAlt': '-->' },
149     \ 'expect': { 'left': '#' },
150     \ 'exports': { 'left': '#' },
151     \ 'factor': { 'left': '! ', 'leftAlt': '!# ' },
152     \ 'fgl': { 'left': '#' },
153     \ 'focexec': { 'left': '-*' },
154     \ 'form': { 'left': '*' },
155     \ 'foxpro': { 'left': '*' },
156     \ 'fstab': { 'left': '#' },
157     \ 'fvwm': { 'left': '#' },
158     \ 'fx': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
159     \ 'gams': { 'left': '*' },
160     \ 'gdb': { 'left': '#' },
161     \ 'gdmo': { 'left': '--' },
162     \ 'geek': { 'left': 'GEEK_COMMENT:' },
163     \ 'genshi': { 'left': '<!--','right': '-->', 'leftAlt': '{#', 'rightAlt': '#}' },
164     \ 'gentoo-conf-d': { 'left': '#' },
165     \ 'gentoo-env-d': { 'left': '#' },
166     \ 'gentoo-init-d': { 'left': '#' },
167     \ 'gentoo-make-conf': { 'left': '#' },
168     \ 'gentoo-package-keywords': { 'left': '#' },
169     \ 'gentoo-package-mask': { 'left': '#' },
170     \ 'gentoo-package-use': { 'left': '#' },
171     \ 'gitcommit': { 'left': '#' },
172     \ 'gitconfig': { 'left': ';' },
173     \ 'gitrebase': { 'left': '#' },
174     \ 'gnuplot': { 'left': '#' },
175     \ 'groovy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
176     \ 'gsp': { 'left': '<%--', 'right': '--%>' },
177     \ 'gtkrc': { 'left': '#' },
178     \ 'haskell': { 'left': '{-','right': '-}', 'leftAlt': '--' },
179     \ 'hb': { 'left': '#' },
180     \ 'h': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
181     \ 'haml': { 'left': '-#', 'leftAlt': '/' },
182     \ 'hercules': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
183     \ 'hog': { 'left': '#' },
184     \ 'hostsaccess': { 'left': '#' },
185     \ 'htmlcheetah': { 'left': '##' },
186     \ 'htmldjango': { 'left': '<!--','right': '-->', 'leftAlt': '{#', 'rightAlt': '#}' },
187     \ 'htmlos': { 'left': '#', 'right': '/#' },
188     \ 'ia64': { 'left': '#' },
189     \ 'icon': { 'left': '#' },
190     \ 'idlang': { 'left': ';' },
191     \ 'idl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
192     \ 'inform': { 'left': '!' },
193     \ 'inittab': { 'left': '#' },
194     \ 'ishd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
195     \ 'iss': { 'left': ';' },
196     \ 'ist': { 'left': '%' },
197     \ 'java': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
198     \ 'javacc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
199     \ 'javascript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
200     \ 'javascript.jquery': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
201     \ 'jess': { 'left': ';' },
202     \ 'jgraph': { 'left': '(*', 'right': '*)' },
203     \ 'jproperties': { 'left': '#' },
204     \ 'jsp': { 'left': '<%--', 'right': '--%>' },
205     \ 'kix': { 'left': ';' },
206     \ 'kscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
207     \ 'lace': { 'left': '--' },
208     \ 'ldif': { 'left': '#' },
209     \ 'lilo': { 'left': '#' },
210     \ 'lilypond': { 'left': '%' },
211     \ 'liquid': { 'left': '{%', 'right': '%}' },
212     \ 'lisp': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' },
213     \ 'llvm': { 'left': ';' },
214     \ 'lotos': { 'left': '(*', 'right': '*)' },
215     \ 'lout': { 'left': '#' },
216     \ 'lprolog': { 'left': '%' },
217     \ 'lscript': { 'left': "'" },
218     \ 'lss': { 'left': '#' },
219     \ 'lua': { 'left': '--', 'leftAlt': '--[[', 'rightAlt': ']]' },
220     \ 'lynx': { 'left': '#' },
221     \ 'lytex': { 'left': '%' },
222     \ 'mail': { 'left': '> ' },
223     \ 'mako': { 'left': '##' },
224     \ 'man': { 'left': '."' },
225     \ 'map': { 'left': '%' },
226     \ 'maple': { 'left': '#' },
227     \ 'markdown': { 'left': '<!--', 'right': '-->' },
228     \ 'masm': { 'left': ';' },
229     \ 'mason': { 'left': '<% #', 'right': '%>' },
230     \ 'master': { 'left': '$' },
231     \ 'matlab': { 'left': '%' },
232     \ 'mel': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
233     \ 'mib': { 'left': '--' },
234     \ 'mkd': { 'left': '>' },
235     \ 'mma': { 'left': '(*', 'right': '*)' },
236     \ 'model': { 'left': '$', 'right': '$' },
237     \ 'moduala.': { 'left': '(*', 'right': '*)' },
238     \ 'modula2': { 'left': '(*', 'right': '*)' },
239     \ 'modula3': { 'left': '(*', 'right': '*)' },
240     \ 'monk': { 'left': ';' },
241     \ 'mush': { 'left': '#' },
242     \ 'named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
243     \ 'nasm': { 'left': ';' },
244     \ 'nastran': { 'left': '$' },
245     \ 'natural': { 'left': '/*' },
246     \ 'ncf': { 'left': ';' },
247     \ 'newlisp': { 'left': ';' },
248     \ 'nroff': { 'left': '\"' },
249     \ 'nsis': { 'left': '#' },
250     \ 'ntp': { 'left': '#' },
251     \ 'objc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
252     \ 'objcpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
253     \ 'objj': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
254     \ 'ocaml': { 'left': '(*', 'right': '*)' },
255     \ 'occam': { 'left': '--' },
256     \ 'omlet': { 'left': '(*', 'right': '*)' },
257     \ 'omnimark': { 'left': ';' },
258     \ 'openroad': { 'left': '//' },
259     \ 'opl': { 'left': "REM" },
260     \ 'ora': { 'left': '#' },
261     \ 'ox': { 'left': '//' },
262     \ 'pascal': { 'left': '{','right': '}', 'leftAlt': '(*', 'rightAlt': '*)' },
263     \ 'patran': { 'left': '$', 'leftAlt': '/*', 'rightAlt': '*/' },
264     \ 'pcap': { 'left': '#' },
265     \ 'pccts': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
266     \ 'pdf': { 'left': '%' },
267     \ 'pfmain': { 'left': '//' },
268     \ 'php': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
269     \ 'pic': { 'left': ';' },
270     \ 'pike': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
271     \ 'pilrc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
272     \ 'pine': { 'left': '#' },
273     \ 'plm': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
274     \ 'plsql': { 'left': '--', 'leftAlt': '/*', 'rightAlt': '*/' },
275     \ 'po': { 'left': '#' },
276     \ 'postscr': { 'left': '%' },
277     \ 'pov': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
278     \ 'povini': { 'left': ';' },
279     \ 'ppd': { 'left': '%' },
280     \ 'ppwiz': { 'left': ';;' },
281     \ 'processing': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
282     \ 'prolog': { 'left': '%', 'leftAlt': '/*', 'rightAlt': '*/' },
283     \ 'ps1': { 'left': '#' },
284     \ 'psf': { 'left': '#' },
285     \ 'ptcap': { 'left': '#' },
286     \ 'python': { 'left': '#' },
287     \ 'radiance': { 'left': '#' },
288     \ 'ratpoison': { 'left': '#' },
289     \ 'r': { 'left': '#' },
290     \ 'rc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
291     \ 'rebol': { 'left': ';' },
292     \ 'registry': { 'left': ';' },
293     \ 'remind': { 'left': '#' },
294     \ 'resolv': { 'left': '#' },
295     \ 'rgb': { 'left': '!' },
296     \ 'rib': { 'left': '#' },
297     \ 'robots': { 'left': '#' },
298     \ 'sa': { 'left': '--' },
299     \ 'samba': { 'left': ';', 'leftAlt': '#' },
300     \ 'sass': { 'left': '//', 'leftAlt': '/*' },
301     \ 'sather': { 'left': '--' },
302     \ 'scala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
303     \ 'scilab': { 'left': '//' },
304     \ 'scsh': { 'left': ';' },
305     \ 'sed': { 'left': '#' },
306     \ 'sgmldecl': { 'left': '--', 'right': '--' },
307     \ 'sgmllnx': { 'left': '<!--', 'right': '-->' },
308     \ 'sicad': { 'left': '*' },
309     \ 'simula': { 'left': '%', 'leftAlt': '--' },
310     \ 'sinda': { 'left': '$' },
311     \ 'skill': { 'left': ';' },
312     \ 'slang': { 'left': '%' },
313     \ 'slice': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
314     \ 'slrnrc': { 'left': '%' },
315     \ 'sm': { 'left': '#' },
316     \ 'smarty': { 'left': '{*', 'right': '*}' },
317     \ 'smil': { 'left': '<!', 'right': '>' },
318     \ 'smith': { 'left': ';' },
319     \ 'sml': { 'left': '(*', 'right': '*)' },
320     \ 'snnsnet': { 'left': '#' },
321     \ 'snnspat': { 'left': '#' },
322     \ 'snnsres': { 'left': '#' },
323     \ 'snobol4': { 'left': '*' },
324     \ 'spec': { 'left': '#' },
325     \ 'specman': { 'left': '//' },
326     \ 'spectre': { 'left': '//', 'leftAlt': '*' },
327     \ 'spice': { 'left': '$' },
328     \ 'sql': { 'left': '--' },
329     \ 'sqlforms': { 'left': '--' },
330     \ 'sqlj': { 'left': '--' },
331     \ 'sqr': { 'left': '!' },
332     \ 'squid': { 'left': '#' },
333     \ 'st': { 'left': '"' },
334     \ 'stp': { 'left': '--' },
335     \ 'systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
336     \ 'tads': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
337     \ 'tags': { 'left': ';' },
338     \ 'tak': { 'left': '$' },
339     \ 'tasm': { 'left': ';' },
340     \ 'tcl': { 'left': '#' },
341     \ 'texinfo': { 'left': "@c " },
342     \ 'texmf': { 'left': '%' },
343     \ 'tf': { 'left': ';' },
344     \ 'tidy': { 'left': '#' },
345     \ 'tli': { 'left': '#' },
346     \ 'tmux': { 'left': '#' },
347     \ 'trasys': { 'left': "$" },
348     \ 'tsalt': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
349     \ 'tsscl': { 'left': '#' },
350     \ 'tssgm': { 'left': "comment = '", 'right': "'" },
351     \ 'txt2tags': { 'left': '%' },
352     \ 'uc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
353     \ 'uil': { 'left': '!' },
354     \ 'vb': { 'left': "'" },
355     \ 'velocity': { 'left': "##", 'right': "", 'leftAlt': '#*', 'rightAlt': '*#' },
356     \ 'vera': { 'left': '/*','right': '*/', 'leftAlt': '//' },
357     \ 'verilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
358     \ 'verilog_systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
359     \ 'vgrindefs': { 'left': '#' },
360     \ 'vhdl': { 'left': '--' },
361     \ 'vimperator': { 'left': '"' },
362     \ 'virata': { 'left': '%' },
363     \ 'vrml': { 'left': '#' },
364     \ 'vsejcl': { 'left': '/*' },
365     \ 'webmacro': { 'left': '##' },
366     \ 'wget': { 'left': '#' },
367     \ 'Wikipedia': { 'left': '<!--', 'right': '-->' },
368     \ 'winbatch': { 'left': ';' },
369     \ 'wml': { 'left': '#' },
370     \ 'wvdial': { 'left': ';' },
371     \ 'xdefaults': { 'left': '!' },
372     \ 'xkb': { 'left': '//' },
373     \ 'xmath': { 'left': '#' },
374     \ 'xpm2': { 'left': '!' },
375     \ 'xquery': { 'left': '(:', 'right': ':)' },
376     \ 'z8a': { 'left': ';' }
377     \ }
378
379 " Section: Comment mapping functions, autocommands and commands {{{1
380 " ============================================================================
381 " Section: Comment enabler autocommands {{{2
382 " ============================================================================
383
384 augroup commentEnablers
385
386     "if the user enters a buffer or reads a buffer then we gotta set up
387     "the comment delimiters for that new filetype
388     autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0)
389
390     "if the filetype of a buffer changes, force the script to reset the
391     "delims for the buffer
392     autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1)
393 augroup END
394
395
396 " Function: s:SetUpForNewFiletype(filetype) function {{{2
397 " This function is responsible for setting up buffer scoped variables for the
398 " given filetype.
399 "
400 " Args:
401 "   -filetype: the filetype to set delimiters for
402 "   -forceReset: 1 if the delimiters should be reset if they have already be
403 "    set for this buffer.
404 "
405 function s:SetUpForNewFiletype(filetype, forceReset)
406     let b:NERDSexyComMarker = ''
407
408     if has_key(s:delimiterMap, a:filetype)
409         let b:NERDCommenterDelims = s:delimiterMap[a:filetype]
410         for i in ['left', 'leftAlt', 'right', 'rightAlt']
411             if !has_key(b:NERDCommenterDelims, i)
412                 let b:NERDCommenterDelims[i] = ''
413             endif
414         endfor
415     else
416         let b:NERDCommenterDelims = s:CreateDelimMapFromCms()
417     endif
418
419 endfunction
420
421 function s:CreateDelimMapFromCms()
422     return {
423         \ 'left': substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', ''),
424         \ 'right': substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g'),
425         \ 'leftAlt': '',
426         \ 'rightAlt': '' }
427 endfunction
428
429 " Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2
430 " This function is used to swap the delimiters that are being used to the
431 " alternative delimiters for that filetype. For example, if a c++ file is
432 " being edited and // comments are being used, after this function is called
433 " /**/ comments will be used.
434 "
435 " Args:
436 "   -printMsgs: if this is 1 then a message is echoed to the user telling them
437 "    if this function changed the delimiters or not
438 function s:SwitchToAlternativeDelimiters(printMsgs)
439     "if both of the alternative delimiters are empty then there is no
440     "alternative comment style so bail out
441     if b:NERDCommenterDelims['leftAlt'] == '' && b:NERDCommenterDelims['rightAlt'] == ''
442         if a:printMsgs
443             call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0)
444         endif
445         return 0
446     endif
447
448     "save the current delimiters
449     let tempLeft = s:Left()
450     let tempRight = s:Right()
451
452     "swap current delimiters for alternative
453     let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt']
454     let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt']
455
456     "set the previously current delimiters to be the new alternative ones
457     let b:NERDCommenterDelims['leftAlt'] = tempLeft
458     let b:NERDCommenterDelims['rightAlt'] = tempRight
459
460     "tell the user what comment delimiters they are now using
461     if a:printMsgs
462         call s:NerdEcho("Now using " . s:Left() . " " . s:Right() . " to delimit comments", 1)
463     endif
464
465     return 1
466 endfunction
467
468 " Section: Comment delimiter add/removal functions {{{1
469 " ============================================================================
470 " Function: s:AppendCommentToLine(){{{2
471 " This function appends comment delimiters at the EOL and places the cursor in
472 " position to start typing the comment
473 function s:AppendCommentToLine()
474     let left = s:Left({'space': 1})
475     let right = s:Right({'space': 1})
476
477     " get the len of the right delim
478     let lenRight = strlen(right)
479
480     let isLineEmpty = strlen(getline(".")) == 0
481     let insOrApp = (isLineEmpty==1 ? 'i' : 'A')
482
483     "stick the delimiters down at the end of the line. We have to format the
484     "comment with spaces as appropriate
485     execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " "
486
487     " if there is a right delimiter then we gotta move the cursor left
488     " by the len of the right delimiter so we insert between the delimiters
489     if lenRight > 0
490         let leftMoveAmount = lenRight
491         execute ":normal! " . leftMoveAmount . "h"
492     endif
493     startinsert
494 endfunction
495
496 " Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2
497 " This function is used to comment out a region of code. This region is
498 " specified as a bounding box by arguments to the function.
499 "
500 " Args:
501 "   -top: the line number for the top line of code in the region
502 "   -bottom: the line number for the bottom line of code in the region
503 "   -lSide: the column number for the left most column in the region
504 "   -rSide: the column number for the right most column in the region
505 "   -forceNested: a flag indicating whether comments should be nested
506 function s:CommentBlock(top, bottom, lSide, rSide, forceNested )
507     " we need to create local copies of these arguments so we can modify them
508     let top = a:top
509     let bottom = a:bottom
510     let lSide = a:lSide
511     let rSide = a:rSide
512
513     "if the top or bottom line starts with tabs we have to adjust the left and
514     "right boundaries so that they are set as though the tabs were spaces
515     let topline = getline(top)
516     let bottomline = getline(bottom)
517     if s:HasLeadingTabs(topline, bottomline)
518
519         "find out how many tabs are in the top line and adjust the left
520         "boundary accordingly
521         let numTabs = s:NumberOfLeadingTabs(topline)
522         if lSide < numTabs
523             let lSide = &ts * lSide
524         else
525             let lSide = (lSide - numTabs) + (&ts * numTabs)
526         endif
527
528         "find out how many tabs are in the bottom line and adjust the right
529         "boundary accordingly
530         let numTabs = s:NumberOfLeadingTabs(bottomline)
531         let rSide = (rSide - numTabs) + (&ts * numTabs)
532     endif
533
534     "we must check that bottom IS actually below top, if it is not then we
535     "swap top and bottom. Similarly for left and right.
536     if bottom < top
537         let temp = top
538         let top = bottom
539         let bottom = top
540     endif
541     if rSide < lSide
542         let temp = lSide
543         let lSide = rSide
544         let rSide = temp
545     endif
546
547     "if the current delimiters arent multipart then we will switch to the
548     "alternative delims (if THEY are) as the comment will be better and more
549     "accurate with multipart delims
550     let switchedDelims = 0
551     if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart()
552         let switchedDelims = 1
553         call s:SwitchToAlternativeDelimiters(0)
554     endif
555
556     "start the commenting from the top and keep commenting till we reach the
557     "bottom
558     let currentLine=top
559     while currentLine <= bottom
560
561         "check if we are allowed to comment this line
562         if s:CanCommentLine(a:forceNested, currentLine)
563
564             "convert the leading tabs into spaces
565             let theLine = getline(currentLine)
566             let lineHasLeadTabs = s:HasLeadingTabs(theLine)
567             if lineHasLeadTabs
568                 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
569             endif
570
571             "dont comment lines that begin after the right boundary of the
572             "block unless the user has specified to do so
573             if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty
574
575                 "attempt to place the cursor in on the left of the boundary box,
576                 "then check if we were successful, if not then we cant comment this
577                 "line
578                 call setline(currentLine, theLine)
579                 if s:CanPlaceCursor(currentLine, lSide)
580
581                     let leftSpaced = s:Left({'space': 1})
582                     let rightSpaced = s:Right({'space': 1})
583
584                     "stick the left delimiter down
585                     let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
586
587                     if s:Multipart()
588                         "stick the right delimiter down
589                         let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced))
590
591                         let firstLeftDelim = s:FindDelimiterIndex(s:Left(), theLine)
592                         let lastRightDelim = s:LastIndexOfDelim(s:Right(), theLine)
593
594                         if firstLeftDelim != -1 && lastRightDelim != -1
595                             let searchStr = strpart(theLine, 0, lastRightDelim)
596                             let searchStr = strpart(searchStr, firstLeftDelim+strlen(s:Left()))
597
598                             "replace the outter most delims in searchStr with
599                             "place-holders
600                             let theLineWithPlaceHolders = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, searchStr)
601
602                             "add the right delimiter onto the line
603                             let theLine = strpart(theLine, 0, firstLeftDelim+strlen(s:Left())) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
604                         endif
605                     endif
606                 endif
607             endif
608
609             "restore tabs if needed
610             if lineHasLeadTabs
611                 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
612             endif
613
614             call setline(currentLine, theLine)
615         endif
616
617         let currentLine = currentLine + 1
618     endwhile
619
620     "if we switched delims then we gotta go back to what they were before
621     if switchedDelims == 1
622         call s:SwitchToAlternativeDelimiters(0)
623     endif
624 endfunction
625
626 " Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2
627 " This function comments a range of lines.
628 "
629 " Args:
630 "   -forceNested: a flag indicating whether the called is requesting the comment
631 "    to be nested if need be
632 "   -align: should be "left" or "both" or "none"
633 "   -firstLine/lastLine: the top and bottom lines to comment
634 function s:CommentLines(forceNested, align, firstLine, lastLine)
635     " we need to get the left and right indexes of the leftmost char in the
636     " block of of lines and the right most char so that we can do alignment of
637     " the delimiters if the user has specified
638     let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
639     let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
640
641     " gotta add the length of the left delimiter onto the rightAlignIndx cos
642     " we'll be adding a left delim to the line
643     let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1}))
644
645     " now we actually comment the lines. Do it line by line
646     let currentLine = a:firstLine
647     while currentLine <= a:lastLine
648
649         " get the next line, check commentability and convert spaces to tabs
650         let theLine = getline(currentLine)
651         let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
652         let theLine = s:ConvertLeadingTabsToSpaces(theLine)
653         if s:CanCommentLine(a:forceNested, currentLine)
654             "if the user has specified forceNesting then we check to see if we
655             "need to switch delimiters for place-holders
656             if a:forceNested && g:NERDUsePlaceHolders
657                 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
658             endif
659
660             " find out if the line is commented using normal delims and/or
661             " alternate ones
662             let isCommented = s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)
663
664             " check if we can comment this line
665             if !isCommented || g:NERDUsePlaceHolders || s:Multipart()
666                 if a:align == "left" || a:align == "both"
667                     let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx)
668                 else
669                     let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
670                 endif
671                 if a:align == "both"
672                     let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx)
673                 else
674                     let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
675                 endif
676             endif
677         endif
678
679         " restore leading tabs if appropriate
680         if lineHasLeadingTabs
681             let theLine = s:ConvertLeadingSpacesToTabs(theLine)
682         endif
683
684         " we are done with this line
685         call setline(currentLine, theLine)
686         let currentLine = currentLine + 1
687     endwhile
688
689 endfunction
690
691 " Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2
692 " This function comments a range of lines in a minimal style. I
693 "
694 " Args:
695 "   -firstLine/lastLine: the top and bottom lines to comment
696 function s:CommentLinesMinimal(firstLine, lastLine)
697     "check that minimal comments can be done on this filetype
698     if !s:HasMultipartDelims()
699         throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters'
700     endif
701
702     "if we need to use place holders for the comment, make sure they are
703     "enabled for this filetype
704     if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine)
705         throw 'NERDCommenter.Settings exception: Place holders are required but disabled.'
706     endif
707
708     "get the left and right delims to smack on
709     let left = s:GetSexyComLeft(g:NERDSpaceDelims,0)
710     let right = s:GetSexyComRight(g:NERDSpaceDelims,0)
711
712     "make sure all multipart delims on the lines are replaced with
713     "placeholders to prevent illegal syntax
714     let currentLine = a:firstLine
715     while(currentLine <= a:lastLine)
716         let theLine = getline(currentLine)
717         let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine)
718         call setline(currentLine, theLine)
719         let currentLine = currentLine + 1
720     endwhile
721
722     "add the delim to the top line
723     let theLine = getline(a:firstLine)
724     let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
725     let theLine = s:ConvertLeadingTabsToSpaces(theLine)
726     let theLine = s:AddLeftDelim(left, theLine)
727     if lineHasLeadingTabs
728         let theLine = s:ConvertLeadingSpacesToTabs(theLine)
729     endif
730     call setline(a:firstLine, theLine)
731
732     "add the delim to the bottom line
733     let theLine = getline(a:lastLine)
734     let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
735     let theLine = s:ConvertLeadingTabsToSpaces(theLine)
736     let theLine = s:AddRightDelim(right, theLine)
737     if lineHasLeadingTabs
738         let theLine = s:ConvertLeadingSpacesToTabs(theLine)
739     endif
740     call setline(a:lastLine, theLine)
741 endfunction
742
743 " Function: s:CommentLinesSexy(topline, bottomline) function {{{2
744 " This function is used to comment lines in the 'Sexy' style. eg in c:
745 " /*
746 "  * This is a sexy comment
747 "  */
748 " Args:
749 "   -topline: the line num of the top line in the sexy comment
750 "   -bottomline: the line num of the bottom line in the sexy comment
751 function s:CommentLinesSexy(topline, bottomline)
752     let left = s:GetSexyComLeft(0, 0)
753     let right = s:GetSexyComRight(0, 0)
754
755     "check if we can do a sexy comment with the available delimiters
756     if left == -1 || right == -1
757         throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.'
758     endif
759
760     "make sure the lines arent already commented sexually
761     if !s:CanSexyCommentLines(a:topline, a:bottomline)
762         throw 'NERDCommenter.Nesting exception: cannot nest sexy comments'
763     endif
764
765
766     let sexyComMarker = s:GetSexyComMarker(0,0)
767     let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
768
769
770     " we jam the comment as far to the right as possible
771     let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
772
773     "check if we should use the compact style i.e that the left/right
774     "delimiters should appear on the first and last lines of the code and not
775     "on separate lines above/below the first/last lines of code
776     if g:NERDCompactSexyComs
777         let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '')
778
779         "comment the top line
780         let theLine = getline(a:topline)
781         let lineHasTabs = s:HasLeadingTabs(theLine)
782         if lineHasTabs
783             let theLine = s:ConvertLeadingTabsToSpaces(theLine)
784         endif
785         let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
786         let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
787         if lineHasTabs
788             let theLine = s:ConvertLeadingSpacesToTabs(theLine)
789         endif
790         call setline(a:topline, theLine)
791
792         "comment the bottom line
793         if a:bottomline != a:topline
794             let theLine = getline(a:bottomline)
795             let lineHasTabs = s:HasLeadingTabs(theLine)
796             if lineHasTabs
797                 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
798             endif
799             let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
800         endif
801         let theLine = s:AddRightDelim(spaceString . right, theLine)
802         if lineHasTabs
803             let theLine = s:ConvertLeadingSpacesToTabs(theLine)
804         endif
805         call setline(a:bottomline, theLine)
806     else
807
808         " add the left delimiter one line above the lines that are to be commented
809         call cursor(a:topline, 1)
810         execute 'normal! O'
811         let theLine = repeat(' ', leftAlignIndx) . left
812
813         " Make sure tabs are respected
814         if !&expandtab
815            let theLine = s:ConvertLeadingSpacesToTabs(theLine)
816         endif
817         call setline(a:topline, theLine)
818
819         " add the right delimiter after bottom line (we have to add 1 cos we moved
820         " the lines down when we added the left delim
821         call cursor(a:bottomline+1, 1)
822         execute 'normal! o'
823         let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right
824
825         " Make sure tabs are respected
826         if !&expandtab
827            let theLine = s:ConvertLeadingSpacesToTabs(theLine)
828         endif
829         call setline(a:bottomline+2, theLine)
830
831     endif
832
833     " go thru each line adding the sexyComMarker marker to the start of each
834     " line in the appropriate place to align them with the comment delims
835     let currentLine = a:topline+1
836     while currentLine <= a:bottomline + !g:NERDCompactSexyComs
837         " get the line and convert the tabs to spaces
838         let theLine = getline(currentLine)
839         let lineHasTabs = s:HasLeadingTabs(theLine)
840         if lineHasTabs
841             let theLine = s:ConvertLeadingTabsToSpaces(theLine)
842         endif
843
844         let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
845
846         " add the sexyComMarker
847         let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
848
849         if lineHasTabs
850             let theLine = s:ConvertLeadingSpacesToTabs(theLine)
851         endif
852
853
854         " set the line and move onto the next one
855         call setline(currentLine, theLine)
856         let currentLine = currentLine + 1
857     endwhile
858
859 endfunction
860
861 " Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2
862 " Applies "toggle" commenting to the given range of lines
863 "
864 " Args:
865 "   -forceNested: a flag indicating whether the called is requesting the comment
866 "    to be nested if need be
867 "   -firstLine/lastLine: the top and bottom lines to comment
868 function s:CommentLinesToggle(forceNested, firstLine, lastLine)
869     let currentLine = a:firstLine
870     while currentLine <= a:lastLine
871
872         " get the next line, check commentability and convert spaces to tabs
873         let theLine = getline(currentLine)
874         let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
875         let theLine = s:ConvertLeadingTabsToSpaces(theLine)
876         if s:CanToggleCommentLine(a:forceNested, currentLine)
877
878             "if the user has specified forceNesting then we check to see if we
879             "need to switch delimiters for place-holders
880             if g:NERDUsePlaceHolders
881                 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
882             endif
883
884             let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
885             let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
886         endif
887
888         " restore leading tabs if appropriate
889         if lineHasLeadingTabs
890             let theLine = s:ConvertLeadingSpacesToTabs(theLine)
891         endif
892
893         " we are done with this line
894         call setline(currentLine, theLine)
895         let currentLine = currentLine + 1
896     endwhile
897
898 endfunction
899
900 " Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2
901 " This function comments chunks of text selected in visual mode.
902 " It will comment exactly the text that they have selected.
903 " Args:
904 "   -topLine: the line num of the top line in the sexy comment
905 "   -topCol: top left col for this comment
906 "   -bottomline: the line num of the bottom line in the sexy comment
907 "   -bottomCol: the bottom right col for this comment
908 "   -forceNested: whether the caller wants comments to be nested if the
909 "    line(s) are already commented
910 function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested)
911
912     "switch delims (if we can) if the current set isnt multipart
913     let switchedDelims = 0
914     if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims
915         let switchedDelims = 1
916         call s:SwitchToAlternativeDelimiters(0)
917     endif
918
919     "if there is only one line in the comment then just do it
920     if a:topLine == a:bottomLine
921         call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested)
922
923     "there are multiple lines in the comment
924     else
925         "comment the top line
926         call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
927
928         "comment out all the lines in the middle of the comment
929         let topOfRange = a:topLine+1
930         let bottomOfRange = a:bottomLine-1
931         if topOfRange <= bottomOfRange
932             call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange)
933         endif
934
935         "comment the bottom line
936         let bottom = getline(a:bottomLine)
937         let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', ''))
938         call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested)
939
940     endif
941
942     "stick the cursor back on the char it was on before the comment
943     call cursor(a:topLine, a:topCol + strlen(s:Left()) + g:NERDSpaceDelims)
944
945     "if we switched delims then we gotta go back to what they were before
946     if switchedDelims == 1
947         call s:SwitchToAlternativeDelimiters(0)
948     endif
949
950 endfunction
951
952 " Function: s:InvertComment(firstLine, lastLine) function {{{2
953 " Inverts the comments on the lines between and including the given line
954 " numbers i.e all commented lines are uncommented and vice versa
955 " Args:
956 "   -firstLine: the top of the range of lines to be inverted
957 "   -lastLine: the bottom of the range of lines to be inverted
958 function s:InvertComment(firstLine, lastLine)
959
960     " go thru all lines in the given range
961     let currentLine = a:firstLine
962     while currentLine <= a:lastLine
963         let theLine = getline(currentLine)
964
965         let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
966
967         " if the line is commented normally, uncomment it
968         if s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
969             call s:UncommentLines(currentLine, currentLine)
970             let currentLine = currentLine + 1
971
972         " check if the line is commented sexually
973         elseif !empty(sexyComBounds)
974             let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
975             call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
976
977             "move to the line after last line of the sexy comment
978             let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
979             let currentLine = sexyComBounds[1] - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1
980
981         " the line isnt commented
982         else
983             call s:CommentLinesToggle(1, currentLine, currentLine)
984             let currentLine = currentLine + 1
985         endif
986
987     endwhile
988 endfunction
989
990 " Function: NERDComment(isVisual, type) function {{{2
991 " This function is a Wrapper for the main commenting functions
992 "
993 " Args:
994 "   -isVisual: a flag indicating whether the comment is requested in visual
995 "    mode or not
996 "   -type: the type of commenting requested. Can be 'sexy', 'invert',
997 "    'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm',
998 "    'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank'
999 function! NERDComment(isVisual, type) range
1000     " we want case sensitivity when commenting
1001     let oldIgnoreCase = &ignorecase
1002     set noignorecase
1003
1004     if !exists("g:did_load_ftplugin") || g:did_load_ftplugin != 1
1005         call s:NerdEcho("filetype plugins should be enabled. See :help NERDComInstallation and :help :filetype-plugin-on", 0)
1006     endif
1007
1008     if a:isVisual
1009         let firstLine = line("'<")
1010         let lastLine = line("'>")
1011         let firstCol = col("'<")
1012         let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0)
1013     else
1014         let firstLine = a:firstline
1015         let lastLine = a:lastline
1016     endif
1017
1018     let countWasGiven = (a:isVisual == 0 && firstLine != lastLine)
1019
1020     let forceNested = (a:type == 'nested' || g:NERDDefaultNesting)
1021
1022     if a:type == 'norm' || a:type == 'nested'
1023         if a:isVisual && visualmode() == "\16"
1024             call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested)
1025         elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims()))
1026             call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested)
1027         else
1028             call s:CommentLines(forceNested, "none", firstLine, lastLine)
1029         endif
1030
1031     elseif a:type == 'alignLeft' || a:type == 'alignBoth'
1032         let align = "none"
1033         if a:type == "alignLeft"
1034             let align = "left"
1035         elseif a:type == "alignBoth"
1036             let align = "both"
1037         endif
1038         call s:CommentLines(forceNested, align, firstLine, lastLine)
1039
1040     elseif a:type == 'invert'
1041         call s:InvertComment(firstLine, lastLine)
1042
1043     elseif a:type == 'sexy'
1044         try
1045             call s:CommentLinesSexy(firstLine, lastLine)
1046         catch /NERDCommenter.Delimiters/
1047             call s:CommentLines(forceNested, "none", firstLine, lastLine)
1048         catch /NERDCommenter.Nesting/
1049             call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0)
1050         endtry
1051
1052     elseif a:type == 'toggle'
1053         let theLine = getline(firstLine)
1054
1055         if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
1056             call s:UncommentLines(firstLine, lastLine)
1057         else
1058             call s:CommentLinesToggle(forceNested, firstLine, lastLine)
1059         endif
1060
1061     elseif a:type == 'minimal'
1062         try
1063             call s:CommentLinesMinimal(firstLine, lastLine)
1064         catch /NERDCommenter.Delimiters/
1065             call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0)
1066         catch /NERDCommenter.Settings/
1067             call s:NerdEcho("Place holders are required but disabled.", 0)
1068         endtry
1069
1070     elseif a:type == 'toEOL'
1071         call s:SaveScreenState()
1072         call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1)
1073         call s:RestoreScreenState()
1074
1075     elseif a:type == 'append'
1076         call s:AppendCommentToLine()
1077
1078     elseif a:type == 'insert'
1079         call s:PlaceDelimitersAndInsBetween()
1080
1081     elseif a:type == 'uncomment'
1082         call s:UncommentLines(firstLine, lastLine)
1083
1084     elseif a:type == 'yank'
1085         if a:isVisual
1086             normal! gvy
1087         elseif countWasGiven
1088             execute firstLine .','. lastLine .'yank'
1089         else
1090             normal! yy
1091         endif
1092         execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")'
1093     endif
1094
1095     let &ignorecase = oldIgnoreCase
1096 endfunction
1097
1098 " Function: s:PlaceDelimitersAndInsBetween() function {{{2
1099 " This is function is called to place comment delimiters down and place the
1100 " cursor between them
1101 function s:PlaceDelimitersAndInsBetween()
1102     " get the left and right delimiters without any escape chars in them
1103     let left = s:Left({'space': 1})
1104     let right = s:Right({'space': 1})
1105
1106     let theLine = getline(".")
1107     let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab)
1108
1109     "convert tabs to spaces and adjust the cursors column to take this into
1110     "account
1111     let untabbedCol = s:UntabbedCol(theLine, col("."))
1112     call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine))
1113     call cursor(line("."), untabbedCol)
1114
1115     " get the len of the right delim
1116     let lenRight = strlen(right)
1117
1118     let isDelimOnEOL = col(".") >= strlen(getline("."))
1119
1120     " if the cursor is in the first col then we gotta insert rather than
1121     " append the comment delimiters here
1122     let insOrApp = (col(".")==1 ? 'i' : 'a')
1123
1124     " place the delimiters down. We do it differently depending on whether
1125     " there is a left AND right delimiter
1126     if lenRight > 0
1127         execute ":normal! " . insOrApp . left . right
1128         execute ":normal! " . lenRight . "h"
1129     else
1130         execute ":normal! " . insOrApp . left
1131
1132         " if we are tacking the delim on the EOL then we gotta add a space
1133         " after it cos when we go out of insert mode the cursor will move back
1134         " one and the user wont be in position to type the comment.
1135         if isDelimOnEOL
1136             execute 'normal! a '
1137         endif
1138     endif
1139     normal! l
1140
1141     "if needed convert spaces back to tabs and adjust the cursors col
1142     "accordingly
1143     if lineHasLeadTabs
1144         let tabbedCol = s:TabbedCol(getline("."), col("."))
1145         call setline(line("."), s:ConvertLeadingSpacesToTabs(getline(".")))
1146         call cursor(line("."), tabbedCol)
1147     endif
1148
1149     startinsert
1150 endfunction
1151
1152 " Function: s:RemoveDelimiters(left, right, line) {{{2
1153 " this function is called to remove the first left comment delimiter and the
1154 " last right delimiter of the given line.
1155 "
1156 " The args left and right must be strings. If there is no right delimiter (as
1157 " is the case for e.g vim file comments) them the arg right should be ""
1158 "
1159 " Args:
1160 "   -left: the left comment delimiter
1161 "   -right: the right comment delimiter
1162 "   -line: the line to remove the delimiters from
1163 function s:RemoveDelimiters(left, right, line)
1164
1165     let l:left = a:left
1166     let l:right = a:right
1167     let lenLeft = strlen(left)
1168     let lenRight = strlen(right)
1169
1170     let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
1171
1172     let line = a:line
1173
1174     "look for the left delimiter, if we find it, remove it.
1175     let leftIndx = s:FindDelimiterIndex(a:left, line)
1176     if leftIndx != -1
1177         let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
1178
1179         "if the user has specified that there is a space after the left delim
1180         "then check for the space and remove it if it is there
1181         if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr
1182             let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr)
1183         endif
1184     endif
1185
1186     "look for the right delimiter, if we find it, remove it
1187     let rightIndx = s:FindDelimiterIndex(a:right, line)
1188     if rightIndx != -1
1189         let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
1190
1191         "if the user has specified that there is a space before the right delim
1192         "then check for the space and remove it if it is there
1193         if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart()
1194             let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx)
1195         endif
1196     endif
1197
1198     return line
1199 endfunction
1200
1201 " Function: s:UncommentLines(topLine, bottomLine) {{{2
1202 " This function uncomments the given lines
1203 "
1204 " Args:
1205 " topLine: the top line of the visual selection to uncomment
1206 " bottomLine: the bottom line of the visual selection to uncomment
1207 function s:UncommentLines(topLine, bottomLine)
1208     "make local copies of a:firstline and a:lastline and, if need be, swap
1209     "them around if the top line is below the bottom
1210     let l:firstline = a:topLine
1211     let l:lastline = a:bottomLine
1212     if firstline > lastline
1213         let firstline = lastline
1214         let lastline = a:topLine
1215     endif
1216
1217     "go thru each line uncommenting each line removing sexy comments
1218     let currentLine = firstline
1219     while currentLine <= lastline
1220
1221         "check the current line to see if it is part of a sexy comment
1222         let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
1223         if !empty(sexyComBounds)
1224
1225             "we need to store the num lines in the buf before the comment is
1226             "removed so we know how many lines were removed when the sexy com
1227             "was removed
1228             let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
1229
1230             call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
1231
1232             "move to the line after last line of the sexy comment
1233             let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
1234             let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved
1235             let currentLine = sexyComBounds[1] - numLinesRemoved + 1
1236             let lastline = lastline - numLinesRemoved
1237
1238         "no sexy com was detected so uncomment the line as normal
1239         else
1240             call s:UncommentLinesNormal(currentLine, currentLine)
1241             let currentLine = currentLine + 1
1242         endif
1243     endwhile
1244
1245 endfunction
1246
1247 " Function: s:UncommentLinesSexy(topline, bottomline) {{{2
1248 " This function removes all the comment characters associated with the sexy
1249 " comment spanning the given lines
1250 " Args:
1251 "   -topline/bottomline: the top/bottom lines of the sexy comment
1252 function s:UncommentLinesSexy(topline, bottomline)
1253     let left = s:GetSexyComLeft(0,1)
1254     let right = s:GetSexyComRight(0,1)
1255
1256
1257     "check if it is even possible for sexy comments to exist with the
1258     "available delimiters
1259     if left == -1 || right == -1
1260         throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.'
1261     endif
1262
1263     let leftUnEsc = s:GetSexyComLeft(0,0)
1264     let rightUnEsc = s:GetSexyComRight(0,0)
1265
1266     let sexyComMarker = s:GetSexyComMarker(0, 1)
1267     let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
1268
1269     "the markerOffset is how far right we need to move the sexyComMarker to
1270     "line it up with the end of the left delim
1271     let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc)
1272
1273     " go thru the intermediate lines of the sexy comment and remove the
1274     " sexy comment markers (eg the '*'s on the start of line in a c sexy
1275     " comment)
1276     let currentLine = a:topline+1
1277     while currentLine < a:bottomline
1278         let theLine = getline(currentLine)
1279
1280         " remove the sexy comment marker from the line. We also remove the
1281         " space after it if there is one and if appropriate options are set
1282         let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
1283         if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr  && g:NERDSpaceDelims
1284             let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
1285         else
1286             let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1287         endif
1288
1289         let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1290
1291         let theLine = s:ConvertLeadingWhiteSpace(theLine)
1292
1293         " move onto the next line
1294         call setline(currentLine, theLine)
1295         let currentLine = currentLine + 1
1296     endwhile
1297
1298     " gotta make a copy of a:bottomline cos we modify the position of the
1299     " last line  it if we remove the topline
1300     let bottomline = a:bottomline
1301
1302     " get the first line so we can remove the left delim from it
1303     let theLine = getline(a:topline)
1304
1305     " if the first line contains only the left delim then just delete it
1306     if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs
1307         call cursor(a:topline, 1)
1308         normal! dd
1309         let bottomline = bottomline - 1
1310
1311     " topline contains more than just the left delim
1312     else
1313
1314         " remove the delim. If there is a space after it
1315         " then remove this too if appropriate
1316         let delimIndx = stridx(theLine, leftUnEsc)
1317         if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
1318             let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr)
1319         else
1320             let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
1321         endif
1322         let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1323         call setline(a:topline, theLine)
1324     endif
1325
1326     " get the last line so we can remove the right delim
1327     let theLine = getline(bottomline)
1328
1329     " if the bottomline contains only the right delim then just delete it
1330     if theLine =~ '^[ \t]*' . right . '[ \t]*$'
1331         call cursor(bottomline, 1)
1332         normal! dd
1333
1334     " the last line contains more than the right delim
1335     else
1336         " remove the right delim. If there is a space after it and
1337         " if the appropriate options are set then remove this too.
1338         let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine)
1339         if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr  && g:NERDSpaceDelims
1340             let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr)
1341         else
1342             let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
1343         endif
1344
1345         " if the last line also starts with a sexy comment marker then we
1346         " remove this as well
1347         if theLine =~ '^[ \t]*' . sexyComMarker
1348
1349             " remove the sexyComMarker. If there is a space after it then
1350             " remove that too
1351             let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
1352             if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr  && g:NERDSpaceDelims
1353                 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
1354             else
1355                 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1356             endif
1357         endif
1358
1359         let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1360         call setline(bottomline, theLine)
1361     endif
1362 endfunction
1363
1364 " Function: s:UncommentLineNormal(line) {{{2
1365 " uncomments the given line and returns the result
1366 " Args:
1367 "   -line: the line to uncomment
1368 function s:UncommentLineNormal(line)
1369     let line = a:line
1370
1371     "get the comment status on the line so we know how it is commented
1372     let lineCommentStatus =  s:IsCommentedOuttermost(s:Left(), s:Right(), s:Left({'alt': 1}), s:Right({'alt': 1}), line)
1373
1374     "it is commented with s:Left() and s:Right() so remove these delims
1375     if lineCommentStatus == 1
1376         let line = s:RemoveDelimiters(s:Left(), s:Right(), line)
1377
1378     "it is commented with s:Left({'alt': 1}) and s:Right({'alt': 1}) so remove these delims
1379     elseif lineCommentStatus == 2 && g:NERDRemoveAltComs
1380         let line = s:RemoveDelimiters(s:Left({'alt': 1}), s:Right({'alt': 1}), line)
1381
1382     "it is not properly commented with any delims so we check if it has
1383     "any random left or right delims on it and remove the outtermost ones
1384     else
1385         "get the positions of all delim types on the line
1386         let indxLeft = s:FindDelimiterIndex(s:Left(), line)
1387         let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line)
1388         let indxRight = s:FindDelimiterIndex(s:Right(), line)
1389         let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line)
1390
1391         "remove the outter most left comment delim
1392         if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1)
1393             let line = s:RemoveDelimiters(s:Left(), '', line)
1394         elseif indxLeftAlt != -1
1395             let line = s:RemoveDelimiters(s:Left({'alt': 1}), '', line)
1396         endif
1397
1398         "remove the outter most right comment delim
1399         if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1)
1400             let line = s:RemoveDelimiters('', s:Right(), line)
1401         elseif indxRightAlt != -1
1402             let line = s:RemoveDelimiters('', s:Right({'alt': 1}), line)
1403         endif
1404     endif
1405
1406
1407     let indxLeft = s:FindDelimiterIndex(s:Left(), line)
1408     let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line)
1409     let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line)
1410
1411     let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
1412     let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line)
1413     let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
1414
1415     let right = s:Right()
1416     let left = s:Left()
1417     if !s:Multipart()
1418         let right = s:Right({'alt': 1})
1419         let left = s:Left({'alt': 1})
1420     endif
1421
1422
1423     "if there are place-holders on the line then we check to see if they are
1424     "the outtermost delimiters on the line. If so then we replace them with
1425     "real delimiters
1426     if indxLeftPlace != -1
1427         if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
1428             let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
1429         endif
1430     elseif indxRightPlace != -1
1431         if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
1432             let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
1433         endif
1434
1435     endif
1436
1437     let line = s:ConvertLeadingWhiteSpace(line)
1438
1439     return line
1440 endfunction
1441
1442 " Function: s:UncommentLinesNormal(topline, bottomline) {{{2
1443 " This function is called to uncomment lines that arent a sexy comment
1444 " Args:
1445 "   -topline/bottomline: the top/bottom line numbers of the comment
1446 function s:UncommentLinesNormal(topline, bottomline)
1447     let currentLine = a:topline
1448     while currentLine <= a:bottomline
1449         let line = getline(currentLine)
1450         call setline(currentLine, s:UncommentLineNormal(line))
1451         let currentLine = currentLine + 1
1452     endwhile
1453 endfunction
1454
1455
1456 " Section: Other helper functions {{{1
1457 " ============================================================================
1458
1459 " Function: s:AddLeftDelim(delim, theLine) {{{2
1460 " Args:
1461 function s:AddLeftDelim(delim, theLine)
1462     return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '')
1463 endfunction
1464
1465 " Function: s:AddLeftDelimAligned(delim, theLine) {{{2
1466 " Args:
1467 function s:AddLeftDelimAligned(delim, theLine, alignIndx)
1468
1469     "if the line is not long enough then bung some extra spaces on the front
1470     "so we can align the delim properly
1471     let theLine = a:theLine
1472     if strlen(theLine) < a:alignIndx
1473         let theLine = repeat(' ', a:alignIndx - strlen(theLine))
1474     endif
1475
1476     return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
1477 endfunction
1478
1479 " Function: s:AddRightDelim(delim, theLine) {{{2
1480 " Args:
1481 function s:AddRightDelim(delim, theLine)
1482     if a:delim == ''
1483         return a:theLine
1484     else
1485         return substitute(a:theLine, '$', a:delim, '')
1486     endif
1487 endfunction
1488
1489 " Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2
1490 " Args:
1491 function s:AddRightDelimAligned(delim, theLine, alignIndx)
1492     if a:delim == ""
1493         return a:theLine
1494     else
1495
1496         " when we align the right delim we are just adding spaces
1497         " so we get a string containing the needed spaces (it
1498         " could be empty)
1499         let extraSpaces = ''
1500         let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine))
1501
1502         " add the right delim
1503         return substitute(a:theLine, '$', extraSpaces . a:delim, '')
1504     endif
1505 endfunction
1506
1507 " Function: s:AltMultipart() {{{2
1508 " returns 1 if the alternative delims are multipart
1509 function s:AltMultipart()
1510     return b:NERDCommenterDelims['rightAlt'] != ''
1511 endfunction
1512
1513 " Function: s:CanCommentLine(forceNested, line) {{{2
1514 "This function is used to determine whether the given line can be commented.
1515 "It returns 1 if it can be and 0 otherwise
1516 "
1517 " Args:
1518 "   -forceNested: a flag indicating whether the caller wants comments to be nested
1519 "    if the current line is already commented
1520 "   -lineNum: the line num of the line to check for commentability
1521 function s:CanCommentLine(forceNested, lineNum)
1522     let theLine = getline(a:lineNum)
1523
1524     " make sure we don't comment lines that are just spaces or tabs or empty.
1525     if theLine =~ "^[ \t]*$"
1526         return 0
1527     endif
1528
1529     "if the line is part of a sexy comment then just flag it...
1530     if s:IsInSexyComment(a:lineNum)
1531         return 0
1532     endif
1533
1534     let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
1535
1536     "if the line isnt commented return true
1537     if !isCommented
1538         return 1
1539     endif
1540
1541     "if the line is commented but nesting is allowed then return true
1542     if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)
1543         return 1
1544     endif
1545
1546     return 0
1547 endfunction
1548
1549 " Function: s:CanPlaceCursor(line, col) {{{2
1550 " returns 1 if the cursor can be placed exactly in the given position
1551 function s:CanPlaceCursor(line, col)
1552     let c = col(".")
1553     let l = line(".")
1554     call cursor(a:line, a:col)
1555     let success = (line(".") == a:line && col(".") == a:col)
1556     call cursor(l,c)
1557     return success
1558 endfunction
1559
1560 " Function: s:CanSexyCommentLines(topline, bottomline) {{{2
1561 " Return: 1 if the given lines can be commented sexually, 0 otherwise
1562 function s:CanSexyCommentLines(topline, bottomline)
1563     " see if the selected regions have any sexy comments
1564     let currentLine = a:topline
1565     while(currentLine <= a:bottomline)
1566         if s:IsInSexyComment(currentLine)
1567             return 0
1568         endif
1569         let currentLine = currentLine + 1
1570     endwhile
1571     return 1
1572 endfunction
1573 " Function: s:CanToggleCommentLine(forceNested, line) {{{2
1574 "This function is used to determine whether the given line can be toggle commented.
1575 "It returns 1 if it can be and 0 otherwise
1576 "
1577 " Args:
1578 "   -lineNum: the line num of the line to check for commentability
1579 function s:CanToggleCommentLine(forceNested, lineNum)
1580     let theLine = getline(a:lineNum)
1581     if (s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)) && !a:forceNested
1582         return 0
1583     endif
1584
1585     " make sure we don't comment lines that are just spaces or tabs or empty.
1586     if theLine =~ "^[ \t]*$"
1587         return 0
1588     endif
1589
1590     "if the line is part of a sexy comment then just flag it...
1591     if s:IsInSexyComment(a:lineNum)
1592         return 0
1593     endif
1594
1595     return 1
1596 endfunction
1597
1598 " Function: s:ConvertLeadingSpacesToTabs(line) {{{2
1599 " This function takes a line and converts all leading tabs on that line into
1600 " spaces
1601 "
1602 " Args:
1603 "   -line: the line whose leading tabs will be converted
1604 function s:ConvertLeadingSpacesToTabs(line)
1605     let toReturn  = a:line
1606     while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$'
1607         let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$'  ,  '\1\t\2' , "")
1608     endwhile
1609
1610     return toReturn
1611 endfunction
1612
1613
1614 " Function: s:ConvertLeadingTabsToSpaces(line) {{{2
1615 " This function takes a line and converts all leading spaces on that line into
1616 " tabs
1617 "
1618 " Args:
1619 "   -line: the line whose leading spaces will be converted
1620 function s:ConvertLeadingTabsToSpaces(line)
1621     let toReturn  = a:line
1622     while toReturn =~ '^\( *\)\t'
1623         let toReturn = substitute(toReturn, '^\( *\)\t',  '\1' . s:TabSpace() , "")
1624     endwhile
1625
1626     return toReturn
1627 endfunction
1628
1629 " Function: s:ConvertLeadingWhiteSpace(line) {{{2
1630 " Converts the leading white space to tabs/spaces depending on &ts
1631 "
1632 " Args:
1633 "   -line: the line to convert
1634 function s:ConvertLeadingWhiteSpace(line)
1635     let toReturn = a:line
1636     while toReturn =~ '^ *\t'
1637         let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g")
1638     endwhile
1639
1640     if !&expandtab
1641         let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
1642     endif
1643
1644     return toReturn
1645 endfunction
1646
1647
1648 " Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2
1649 " This function counts the number of substrings contained in another string.
1650 " These substrings are only counted if they are not escaped with escChar
1651 " Args:
1652 "   -str: the string to look for searchstr in
1653 "   -searchstr: the substring to search for in str
1654 "   -escChar: the escape character which, when preceding an instance of
1655 "    searchstr, will cause it not to be counted
1656 function s:CountNonESCedOccurances(str, searchstr, escChar)
1657     "get the index of the first occurrence of searchstr
1658     let indx = stridx(a:str, a:searchstr)
1659
1660     "if there is an instance of searchstr in str process it
1661     if indx != -1
1662         "get the remainder of str after this instance of searchstr is removed
1663         let lensearchstr = strlen(a:searchstr)
1664         let strLeft = strpart(a:str, indx+lensearchstr)
1665
1666         "if this instance of searchstr is not escaped, add one to the count
1667         "and recurse. If it is escaped, just recurse
1668         if !s:IsEscaped(a:str, indx, a:escChar)
1669             return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
1670         else
1671             return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
1672         endif
1673     endif
1674 endfunction
1675 " Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2
1676 " Returns 1 if the given block of lines has a delimiter (a:delim) in it
1677 " Args:
1678 "   -delim: the comment delimiter to check the block for
1679 "   -top: the top line number of the block
1680 "   -bottom: the bottom line number of the block
1681 function s:DoesBlockHaveDelim(delim, top, bottom)
1682     let currentLine = a:top
1683     while currentLine < a:bottom
1684         let theline = getline(currentLine)
1685         if s:FindDelimiterIndex(a:delim, theline) != -1
1686             return 1
1687         endif
1688         let currentLine = currentLine + 1
1689     endwhile
1690     return 0
1691 endfunction
1692
1693 " Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2
1694 " Returns 1 if the given block has a >= 1 multipart delimiter in it
1695 " Args:
1696 "   -top: the top line number of the block
1697 "   -bottom: the bottom line number of the block
1698 function s:DoesBlockHaveMultipartDelim(top, bottom)
1699     if s:HasMultipartDelims()
1700         if s:Multipart()
1701             return s:DoesBlockHaveDelim(s:Left(), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right(), a:top, a:bottom)
1702         else
1703             return s:DoesBlockHaveDelim(s:Left({'alt': 1}), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right({'alt': 1}), a:top, a:bottom)
1704         endif
1705     endif
1706     return 0
1707 endfunction
1708
1709
1710 " Function: s:Esc(str) {{{2
1711 " Escapes all the tricky chars in the given string
1712 function s:Esc(str)
1713     let charsToEsc = '*/\."&$+'
1714     return escape(a:str, charsToEsc)
1715 endfunction
1716
1717 " Function: s:FindDelimiterIndex(delimiter, line) {{{2
1718 " This function is used to get the string index of the input comment delimiter
1719 " on the input line. If no valid comment delimiter is found in the line then
1720 " -1 is returned
1721 " Args:
1722 "   -delimiter: the delimiter we are looking to find the index of
1723 "   -line: the line we are looking for delimiter on
1724 function s:FindDelimiterIndex(delimiter, line)
1725
1726     "make sure the delimiter isnt empty otherwise we go into an infinite loop.
1727     if a:delimiter == ""
1728         return -1
1729     endif
1730
1731
1732     let l:delimiter = a:delimiter
1733     let lenDel = strlen(l:delimiter)
1734
1735     "get the index of the first occurrence of the delimiter
1736     let delIndx = stridx(a:line, l:delimiter)
1737
1738     "keep looping thru the line till we either find a real comment delimiter
1739     "or run off the EOL
1740     while delIndx != -1
1741
1742         "if we are not off the EOL get the str before the possible delimiter
1743         "in question and check if it really is a delimiter. If it is, return
1744         "its position
1745         if delIndx != -1
1746             if s:IsDelimValid(l:delimiter, delIndx, a:line)
1747                 return delIndx
1748             endif
1749         endif
1750
1751         "we have not yet found a real comment delimiter so move past the
1752         "current one we are lookin at
1753         let restOfLine = strpart(a:line, delIndx + lenDel)
1754         let distToNextDelim = stridx(restOfLine , l:delimiter)
1755
1756         "if distToNextDelim is -1 then there is no more potential delimiters
1757         "on the line so set delIndx to -1. Otherwise, move along the line by
1758         "distToNextDelim
1759         if distToNextDelim == -1
1760             let delIndx = -1
1761         else
1762             let delIndx = delIndx + lenDel + distToNextDelim
1763         endif
1764     endwhile
1765
1766     "there is no comment delimiter on this line
1767     return -1
1768 endfunction
1769
1770 " Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2
1771 " This function takes in a line number and tests whether this line number is
1772 " the top/bottom/middle line of a sexy comment. If it is then the top/bottom
1773 " lines of the sexy comment are returned
1774 " Args:
1775 "   -lineNum: the line number that is to be tested whether it is the
1776 "    top/bottom/middle line of a sexy com
1777 " Returns:
1778 "   A string that has the top/bottom lines of the sexy comment encoded in it.
1779 "   The format is 'topline,bottomline'. If a:lineNum turns out not to be the
1780 "   top/bottom/middle of a sexy comment then -1 is returned
1781 function s:FindBoundingLinesOfSexyCom(lineNum)
1782
1783     "find which delimiters to look for as the start/end delims of the comment
1784     let left = ''
1785     let right = ''
1786     if s:Multipart()
1787         let left = s:Left({'esc': 1})
1788         let right = s:Right({'esc': 1})
1789     elseif s:AltMultipart()
1790         let left = s:Left({'alt': 1, 'esc': 1})
1791         let right = s:Right({'alt': 1, 'esc': 1})
1792     else
1793         return []
1794     endif
1795
1796     let sexyComMarker = s:GetSexyComMarker(0, 1)
1797
1798     "initialise the top/bottom line numbers of the sexy comment to -1
1799     let top = -1
1800     let bottom = -1
1801
1802     let currentLine = a:lineNum
1803     while top == -1 || bottom == -1
1804         let theLine = getline(currentLine)
1805
1806         "check if the current line is the top of the sexy comment
1807         if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf()
1808             let top = currentLine
1809             let currentLine = a:lineNum
1810
1811         "check if the current line is the bottom of the sexy comment
1812         elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1
1813             let bottom = currentLine
1814
1815         "the right delimiter is on the same line as the last sexyComMarker
1816         elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right
1817             let bottom = currentLine
1818
1819         "we have not found the top or bottom line so we assume currentLine is an
1820         "intermediate line and look to prove otherwise
1821         else
1822
1823             "if the line doesnt start with a sexyComMarker then it is not a sexy
1824             "comment
1825             if theLine !~ '^[ \t]*' . sexyComMarker
1826                 return []
1827             endif
1828
1829         endif
1830
1831         "if top is -1 then we havent found the top yet so keep looking up
1832         if top == -1
1833             let currentLine = currentLine - 1
1834         "if we have found the top line then go down looking for the bottom
1835         else
1836             let currentLine = currentLine + 1
1837         endif
1838
1839     endwhile
1840
1841     return [top, bottom]
1842 endfunction
1843
1844
1845 " Function: s:GetSexyComMarker() {{{2
1846 " Returns the sexy comment marker for the current filetype.
1847 "
1848 " C style sexy comments are assumed if possible. If not then the sexy comment
1849 " marker is the last char of the delimiter pair that has both left and right
1850 " delims and has the longest left delim
1851 "
1852 " Args:
1853 "   -space: specifies whether the marker is to have a space string after it
1854 "    (the space string will only be added if NERDSpaceDelims is set)
1855 "   -esc: specifies whether the tricky chars in the marker are to be ESCed
1856 function s:GetSexyComMarker(space, esc)
1857     let sexyComMarker = b:NERDSexyComMarker
1858
1859     "if there is no hardcoded marker then we find one
1860     if sexyComMarker == ''
1861
1862         "if the filetype has c style comments then use standard c sexy
1863         "comments
1864         if s:HasCStyleComments()
1865             let sexyComMarker = '*'
1866         else
1867             "find a comment marker by getting the longest available left delim
1868             "(that has a corresponding right delim) and taking the last char
1869             let lenLeft = strlen(s:Left())
1870             let lenLeftAlt = strlen(s:Left({'alt': 1}))
1871             let left = ''
1872             let right = ''
1873             if s:Multipart() && lenLeft >= lenLeftAlt
1874                 let left = s:Left()
1875             elseif s:AltMultipart()
1876                 let left = s:Left({'alt': 1})
1877             else
1878                 return -1
1879             endif
1880
1881             "get the last char of left
1882             let sexyComMarker = strpart(left, strlen(left)-1)
1883         endif
1884     endif
1885
1886     if a:space && g:NERDSpaceDelims
1887         let sexyComMarker = sexyComMarker . s:spaceStr
1888     endif
1889
1890     if a:esc
1891         let sexyComMarker = s:Esc(sexyComMarker)
1892     endif
1893
1894     return sexyComMarker
1895 endfunction
1896
1897 " Function: s:GetSexyComLeft(space, esc) {{{2
1898 " Returns the left delimiter for sexy comments for this filetype or -1 if
1899 " there is none. C style sexy comments are used if possible
1900 " Args:
1901 "   -space: specifies if the delim has a space string on the end
1902 "   (the space string will only be added if NERDSpaceDelims is set)
1903 "   -esc: specifies whether the tricky chars in the string are ESCed
1904 function s:GetSexyComLeft(space, esc)
1905     let lenLeft = strlen(s:Left())
1906     let lenLeftAlt = strlen(s:Left({'alt': 1}))
1907     let left = ''
1908
1909     "assume c style sexy comments if possible
1910     if s:HasCStyleComments()
1911         let left = '/*'
1912     else
1913         "grab the longest left delim that has a right
1914         if s:Multipart() && lenLeft >= lenLeftAlt
1915             let left = s:Left()
1916         elseif s:AltMultipart()
1917             let left = s:Left({'alt': 1})
1918         else
1919             return -1
1920         endif
1921     endif
1922
1923     if a:space && g:NERDSpaceDelims
1924         let left = left . s:spaceStr
1925     endif
1926
1927     if a:esc
1928         let left = s:Esc(left)
1929     endif
1930
1931     return left
1932 endfunction
1933
1934 " Function: s:GetSexyComRight(space, esc) {{{2
1935 " Returns the right delimiter for sexy comments for this filetype or -1 if
1936 " there is none. C style sexy comments are used if possible.
1937 " Args:
1938 "   -space: specifies if the delim has a space string on the start
1939 "   (the space string will only be added if NERDSpaceDelims
1940 "   is specified for the current filetype)
1941 "   -esc: specifies whether the tricky chars in the string are ESCed
1942 function s:GetSexyComRight(space, esc)
1943     let lenLeft = strlen(s:Left())
1944     let lenLeftAlt = strlen(s:Left({'alt': 1}))
1945     let right = ''
1946
1947     "assume c style sexy comments if possible
1948     if s:HasCStyleComments()
1949         let right = '*/'
1950     else
1951         "grab the right delim that pairs with the longest left delim
1952         if s:Multipart() && lenLeft >= lenLeftAlt
1953             let right = s:Right()
1954         elseif s:AltMultipart()
1955             let right = s:Right({'alt': 1})
1956         else
1957             return -1
1958         endif
1959     endif
1960
1961     if a:space && g:NERDSpaceDelims
1962         let right = s:spaceStr . right
1963     endif
1964
1965     if a:esc
1966         let right = s:Esc(right)
1967     endif
1968
1969     return right
1970 endfunction
1971
1972 " Function: s:HasMultipartDelims() {{{2
1973 " Returns 1 iff the current filetype has at least one set of multipart delims
1974 function s:HasMultipartDelims()
1975     return s:Multipart() || s:AltMultipart()
1976 endfunction
1977
1978 " Function: s:HasLeadingTabs(...) {{{2
1979 " Returns 1 if any of the given strings have leading tabs
1980 function s:HasLeadingTabs(...)
1981     for s in a:000
1982         if s =~ '^\t.*'
1983             return 1
1984         end
1985     endfor
1986     return 0
1987 endfunction
1988 " Function: s:HasCStyleComments() {{{2
1989 " Returns 1 iff the current filetype has c style comment delimiters
1990 function s:HasCStyleComments()
1991     return (s:Left() == '/*' && s:Right() == '*/') || (s:Left({'alt': 1}) == '/*' && s:Right({'alt': 1}) == '*/')
1992 endfunction
1993
1994 " Function: s:IsCommentedNormOrSexy(lineNum) {{{2
1995 "This function is used to determine whether the given line is commented with
1996 "either set of delimiters or if it is part of a sexy comment
1997 "
1998 " Args:
1999 "   -lineNum: the line number of the line to check
2000 function s:IsCommentedNormOrSexy(lineNum)
2001     let theLine = getline(a:lineNum)
2002
2003     "if the line is commented normally return 1
2004     if s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)
2005         return 1
2006     endif
2007
2008     "if the line is part of a sexy comment return 1
2009     if s:IsInSexyComment(a:lineNum)
2010         return 1
2011     endif
2012     return 0
2013 endfunction
2014
2015 " Function: s:IsCommented(left, right, line) {{{2
2016 "This function is used to determine whether the given line is commented with
2017 "the given delimiters
2018 "
2019 " Args:
2020 "   -line: the line that to check if commented
2021 "   -left/right: the left and right delimiters to check for
2022 function s:IsCommented(left, right, line)
2023     "if the line isnt commented return true
2024     if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart())
2025         return 1
2026     endif
2027     return 0
2028 endfunction
2029
2030 " Function: s:IsCommentedFromStartOfLine(left, line) {{{2
2031 "This function is used to determine whether the given line is commented with
2032 "the given delimiters at the start of the line i.e the left delimiter is the
2033 "first thing on the line (apart from spaces\tabs)
2034 "
2035 " Args:
2036 "   -line: the line that to check if commented
2037 "   -left: the left delimiter to check for
2038 function s:IsCommentedFromStartOfLine(left, line)
2039     let theLine = s:ConvertLeadingTabsToSpaces(a:line)
2040     let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', ''))
2041     let delimIndx = s:FindDelimiterIndex(a:left, theLine)
2042     return delimIndx == numSpaces
2043 endfunction
2044
2045 " Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2
2046 " Finds the type of the outtermost delims on the line
2047 "
2048 " Args:
2049 "   -line: the line that to check if the outtermost comments on it are
2050 "    left/right
2051 "   -left/right: the left and right delimiters to check for
2052 "   -leftAlt/rightAlt: the left and right alternative delimiters to check for
2053 "
2054 " Returns:
2055 "   0 if the line is not commented with either set of delims
2056 "   1 if the line is commented with the left/right delim set
2057 "   2 if the line is commented with the leftAlt/rightAlt delim set
2058 function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line)
2059     "get the first positions of the left delims and the last positions of the
2060     "right delims
2061     let indxLeft = s:FindDelimiterIndex(a:left, a:line)
2062     let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line)
2063     let indxRight = s:LastIndexOfDelim(a:right, a:line)
2064     let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line)
2065
2066     "check if the line has a left delim before a leftAlt delim
2067     if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1
2068         "check if the line has a right delim after any rightAlt delim
2069         if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart()
2070             return 1
2071         endif
2072
2073         "check if the line has a leftAlt delim before a left delim
2074     elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1
2075         "check if the line has a rightAlt delim after any right delim
2076         if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart()
2077             return 2
2078         endif
2079     else
2080         return 0
2081     endif
2082
2083     return 0
2084
2085 endfunction
2086
2087
2088 " Function: s:IsDelimValid(delimiter, delIndx, line) {{{2
2089 " This function is responsible for determining whether a given instance of a
2090 " comment delimiter is a real delimiter or not. For example, in java the
2091 " // string is a comment delimiter but in the line:
2092 "               System.out.println("//");
2093 " it does not count as a comment delimiter. This function is responsible for
2094 " distinguishing between such cases. It does so by applying a set of
2095 " heuristics that are not fool proof but should work most of the time.
2096 "
2097 " Args:
2098 "   -delimiter: the delimiter we are validating
2099 "   -delIndx: the position of delimiter in line
2100 "   -line: the line that delimiter occurs in
2101 "
2102 " Returns:
2103 " 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
2104 " 1 otherwise
2105 function s:IsDelimValid(delimiter, delIndx, line)
2106     "get the delimiter without the escchars
2107     let l:delimiter = a:delimiter
2108
2109     "get the strings before and after the delimiter
2110     let preComStr = strpart(a:line, 0, a:delIndx)
2111     let postComStr = strpart(a:line, a:delIndx+strlen(delimiter))
2112
2113     "to check if the delimiter is real, make sure it isnt preceded by
2114     "an odd number of quotes and followed by the same (which would indicate
2115     "that it is part of a string and therefore is not a comment)
2116     if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\"))
2117         return 0
2118     endif
2119     if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\"))
2120         return 0
2121     endif
2122     if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\"))
2123         return 0
2124     endif
2125
2126
2127     "if the comment delimiter is escaped, assume it isnt a real delimiter
2128     if s:IsEscaped(a:line, a:delIndx, "\\")
2129         return 0
2130     endif
2131
2132     "vim comments are so fuckin stupid!! Why the hell do they have comment
2133     "delimiters that are used elsewhere in the syntax?!?! We need to check
2134     "some conditions especially for vim
2135     if &filetype == "vim"
2136         if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\"))
2137             return 0
2138         endif
2139
2140         "if the delimiter is on the very first char of the line or is the
2141         "first non-tab/space char on the line then it is a valid comment delimiter
2142         if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$"
2143             return 1
2144         endif
2145
2146         let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\")
2147         let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\")
2148
2149         "if the quote is inside brackets then assume it isnt a comment
2150         if numLeftParen > numRightParen
2151             return 0
2152         endif
2153
2154         "if the line has an even num of unescaped "'s then we can assume that
2155         "any given " is not a comment delimiter
2156         if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\"))
2157             return 0
2158         endif
2159     endif
2160
2161     return 1
2162
2163 endfunction
2164
2165 " Function: s:IsNumEven(num) {{{2
2166 " A small function the returns 1 if the input number is even and 0 otherwise
2167 " Args:
2168 "   -num: the number to check
2169 function s:IsNumEven(num)
2170     return (a:num % 2) == 0
2171 endfunction
2172
2173 " Function: s:IsEscaped(str, indx, escChar) {{{2
2174 " This function takes a string, an index into that string and an esc char and
2175 " returns 1 if the char at the index is escaped (i.e if it is preceded by an
2176 " odd number of esc chars)
2177 " Args:
2178 "   -str: the string to check
2179 "   -indx: the index into str that we want to check
2180 "   -escChar: the escape char the char at indx may be ESCed with
2181 function s:IsEscaped(str, indx, escChar)
2182     "initialise numEscChars to 0 and look at the char before indx
2183     let numEscChars = 0
2184     let curIndx = a:indx-1
2185
2186     "keep going back thru str until we either reach the start of the str or
2187     "run out of esc chars
2188     while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar
2189
2190         "we have found another esc char so add one to the count and move left
2191         "one char
2192         let numEscChars  = numEscChars + 1
2193         let curIndx = curIndx - 1
2194
2195     endwhile
2196
2197     "if there is an odd num of esc chars directly before the char at indx then
2198     "the char at indx is escaped
2199     return !s:IsNumEven(numEscChars)
2200 endfunction
2201
2202 " Function: s:IsInSexyComment(line) {{{2
2203 " returns 1 if the given line number is part of a sexy comment
2204 function s:IsInSexyComment(line)
2205     return !empty(s:FindBoundingLinesOfSexyCom(a:line))
2206 endfunction
2207
2208 " Function: s:IsSexyComment(topline, bottomline) {{{2
2209 " This function takes in 2 line numbers and returns 1 if the lines between and
2210 " including the given line numbers are a sexy comment. It returns 0 otherwise.
2211 " Args:
2212 "   -topline: the line that the possible sexy comment starts on
2213 "   -bottomline: the line that the possible sexy comment stops on
2214 function s:IsSexyComment(topline, bottomline)
2215
2216     "get the delim set that would be used for a sexy comment
2217     let left = ''
2218     let right = ''
2219     if s:Multipart()
2220         let left = s:Left()
2221         let right = s:Right()
2222     elseif s:AltMultipart()
2223         let left = s:Left({'alt': 1})
2224         let right = s:Right({'alt': 1})
2225     else
2226         return 0
2227     endif
2228
2229     "swap the top and bottom line numbers around if need be
2230     let topline = a:topline
2231     let bottomline = a:bottomline
2232     if bottomline < topline
2233         topline = bottomline
2234         bottomline = a:topline
2235     endif
2236
2237     "if there is < 2 lines in the comment it cannot be sexy
2238     if (bottomline - topline) <= 0
2239         return 0
2240     endif
2241
2242     "if the top line doesnt begin with a left delim then the comment isnt sexy
2243     if getline(a:topline) !~ '^[ \t]*' . left
2244         return 0
2245     endif
2246
2247     "if there is a right delim on the top line then this isnt a sexy comment
2248     if s:FindDelimiterIndex(right, getline(a:topline)) != -1
2249         return 0
2250     endif
2251
2252     "if there is a left delim on the bottom line then this isnt a sexy comment
2253     if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1
2254         return 0
2255     endif
2256
2257     "if the bottom line doesnt begin with a right delim then the comment isnt
2258     "sexy
2259     if getline(a:bottomline) !~ '^.*' . right . '$'
2260         return 0
2261     endif
2262
2263     let sexyComMarker = s:GetSexyComMarker(0, 1)
2264
2265     "check each of the intermediate lines to make sure they start with a
2266     "sexyComMarker
2267     let currentLine = a:topline+1
2268     while currentLine < a:bottomline
2269         let theLine = getline(currentLine)
2270
2271         if theLine !~ '^[ \t]*' . sexyComMarker
2272             return 0
2273         endif
2274
2275         "if there is a right delim in an intermediate line then the block isnt
2276         "a sexy comment
2277         if s:FindDelimiterIndex(right, theLine) != -1
2278             return 0
2279         endif
2280
2281         let currentLine = currentLine + 1
2282     endwhile
2283
2284     "we have not found anything to suggest that this isnt a sexy comment so
2285     return 1
2286
2287 endfunction
2288
2289 " Function: s:LastIndexOfDelim(delim, str) {{{2
2290 " This function takes a string and a delimiter and returns the last index of
2291 " that delimiter in string
2292 " Args:
2293 "   -delim: the delimiter to look for
2294 "   -str: the string to look for delim in
2295 function s:LastIndexOfDelim(delim, str)
2296     let delim = a:delim
2297     let lenDelim = strlen(delim)
2298
2299     "set index to the first occurrence of delim. If there is no occurrence then
2300     "bail
2301     let indx = s:FindDelimiterIndex(delim, a:str)
2302     if indx == -1
2303         return -1
2304     endif
2305
2306     "keep moving to the next instance of delim in str till there is none left
2307     while 1
2308
2309         "search for the next delim after the previous one
2310         let searchStr = strpart(a:str, indx+lenDelim)
2311         let indx2 = s:FindDelimiterIndex(delim, searchStr)
2312
2313         "if we find a delim update indx to record the position of it, if we
2314         "dont find another delim then indx is the last one so break out of
2315         "this loop
2316         if indx2 != -1
2317             let indx = indx + indx2 + lenDelim
2318         else
2319             break
2320         endif
2321     endwhile
2322
2323     return indx
2324
2325 endfunction
2326
2327 " Function: s:Left(...) {{{2
2328 " returns left delimiter data
2329 function s:Left(...)
2330     let params = a:0 ? a:1 : {}
2331
2332     let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['leftAlt'] : b:NERDCommenterDelims['left'] 
2333
2334     if delim == ''
2335         return ''
2336     endif
2337
2338     if has_key(params, 'space') && g:NERDSpaceDelims
2339         let delim = delim . s:spaceStr
2340     endif
2341
2342     if has_key(params, 'esc')
2343         let delim = s:Esc(delim)
2344     endif
2345
2346     return delim
2347 endfunction
2348
2349 " Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
2350 " This function takes in 2 line numbers and returns the index of the left most
2351 " char (that is not a space or a tab) on all of these lines.
2352 " Args:
2353 "   -countCommentedLines: 1 if lines that are commented are to be checked as
2354 "    well. 0 otherwise
2355 "   -countEmptyLines: 1 if empty lines are to be counted in the search
2356 "   -topline: the top line to be checked
2357 "   -bottomline: the bottom line to be checked
2358 function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
2359
2360     " declare the left most index as an extreme value
2361     let leftMostIndx = 1000
2362
2363     " go thru the block line by line updating leftMostIndx
2364     let currentLine = a:topline
2365     while currentLine <= a:bottomline
2366
2367         " get the next line and if it is allowed to be commented, or is not
2368         " commented, check it
2369         let theLine = getline(currentLine)
2370         if a:countEmptyLines || theLine !~ '^[ \t]*$'
2371             if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine))
2372                 " convert spaces to tabs and get the number of leading spaces for
2373                 " this line and update leftMostIndx if need be
2374                 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
2375                 let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') )
2376                 if leadSpaceOfLine < leftMostIndx
2377                     let leftMostIndx = leadSpaceOfLine
2378                 endif
2379             endif
2380         endif
2381
2382         " move on to the next line
2383         let currentLine = currentLine + 1
2384     endwhile
2385
2386     if leftMostIndx == 1000
2387         return 0
2388     else
2389         return leftMostIndx
2390     endif
2391 endfunction
2392
2393 " Function: s:Multipart() {{{2
2394 " returns 1 if the current delims are multipart
2395 function s:Multipart()
2396     return s:Right() != ''
2397 endfunction
2398
2399 " Function: s:NerdEcho(msg, typeOfMsg) {{{2
2400 " Args:
2401 "   -msg: the message to echo
2402 "   -typeOfMsg: 0 = warning message
2403 "               1 = normal message
2404 function s:NerdEcho(msg, typeOfMsg)
2405     if a:typeOfMsg == 0
2406         echohl WarningMsg
2407         echom 'NERDCommenter:' . a:msg
2408         echohl None
2409     elseif a:typeOfMsg == 1
2410         echom 'NERDCommenter:' . a:msg
2411     endif
2412 endfunction
2413
2414 " Function: s:NumberOfLeadingTabs(s) {{{2
2415 " returns the number of leading tabs in the given string
2416 function s:NumberOfLeadingTabs(s)
2417     return strlen(substitute(a:s, '^\(\t*\).*$', '\1', ""))
2418 endfunction
2419
2420 " Function: s:NumLinesInBuf() {{{2
2421 " Returns the number of lines in the current buffer
2422 function s:NumLinesInBuf()
2423     return line('$')
2424 endfunction
2425
2426 " Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2
2427 " This function takes in a string, 2 delimiters in that string and 2 strings
2428 " to replace these delimiters with.
2429 "
2430 " Args:
2431 "   -toReplace1: the first delimiter to replace
2432 "   -toReplace2: the second delimiter to replace
2433 "   -replacor1: the string to replace toReplace1 with
2434 "   -replacor2: the string to replace toReplace2 with
2435 "   -str: the string that the delimiters to be replaced are in
2436 function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str)
2437     let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str)
2438     let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line)
2439     return line
2440 endfunction
2441
2442 " Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2
2443 " This function takes a string and a delimiter and replaces the left most
2444 " occurrence of this delimiter in the string with a given string
2445 "
2446 " Args:
2447 "   -toReplace: the delimiter in str that is to be replaced
2448 "   -replacor: the string to replace toReplace with
2449 "   -str: the string that contains toReplace
2450 function s:ReplaceLeftMostDelim(toReplace, replacor, str)
2451     let toReplace = a:toReplace
2452     let replacor = a:replacor
2453     "get the left most occurrence of toReplace
2454     let indxToReplace = s:FindDelimiterIndex(toReplace, a:str)
2455
2456     "if there IS an occurrence of toReplace in str then replace it and return
2457     "the resulting string
2458     if indxToReplace != -1
2459         let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
2460         return line
2461     endif
2462
2463     return a:str
2464 endfunction
2465
2466 " Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2
2467 " This function takes a string and a delimiter and replaces the right most
2468 " occurrence of this delimiter in the string with a given string
2469 "
2470 " Args:
2471 "   -toReplace: the delimiter in str that is to be replaced
2472 "   -replacor: the string to replace toReplace with
2473 "   -str: the string that contains toReplace
2474 "
2475 function s:ReplaceRightMostDelim(toReplace, replacor, str)
2476     let toReplace = a:toReplace
2477     let replacor = a:replacor
2478     let lenToReplace = strlen(toReplace)
2479
2480     "get the index of the last delim in str
2481     let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
2482
2483     "if there IS a delimiter in str, replace it and return the result
2484     let line = a:str
2485     if indxToReplace != -1
2486         let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
2487     endif
2488     return line
2489 endfunction
2490
2491 "FUNCTION: s:RestoreScreenState() {{{2
2492 "
2493 "Sets the screen state back to what it was when s:SaveScreenState was last
2494 "called.
2495 "
2496 function s:RestoreScreenState()
2497     if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos")
2498         throw 'NERDCommenter exception: cannot restore screen'
2499     endif
2500
2501     call cursor(t:NERDComOldTopLine, 0)
2502     normal! zt
2503     call setpos(".", t:NERDComOldPos)
2504 endfunction
2505
2506 " Function: s:Right(...) {{{2
2507 " returns right delimiter data
2508 function s:Right(...)
2509     let params = a:0 ? a:1 : {}
2510
2511     let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['rightAlt'] : b:NERDCommenterDelims['right'] 
2512
2513     if delim == ''
2514         return ''
2515     endif
2516
2517     if has_key(params, 'space') && g:NERDSpaceDelims
2518         let delim = s:spaceStr . delim
2519     endif
2520
2521     if has_key(params, 'esc')
2522         let delim = s:Esc(delim)
2523     endif
2524
2525     return delim
2526 endfunction
2527
2528 " Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
2529 " This function takes in 2 line numbers and returns the index of the right most
2530 " char on all of these lines.
2531 " Args:
2532 "   -countCommentedLines: 1 if lines that are commented are to be checked as
2533 "    well. 0 otherwise
2534 "   -countEmptyLines: 1 if empty lines are to be counted in the search
2535 "   -topline: the top line to be checked
2536 "   -bottomline: the bottom line to be checked
2537 function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
2538     let rightMostIndx = -1
2539
2540     " go thru the block line by line updating rightMostIndx
2541     let currentLine = a:topline
2542     while currentLine <= a:bottomline
2543
2544         " get the next line and see if it is commentable, otherwise it doesnt
2545         " count
2546         let theLine = getline(currentLine)
2547         if a:countEmptyLines || theLine !~ '^[ \t]*$'
2548
2549             if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine))
2550
2551                 " update rightMostIndx if need be
2552                 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
2553                 let lineLen = strlen(theLine)
2554                 if lineLen > rightMostIndx
2555                     let rightMostIndx = lineLen
2556                 endif
2557             endif
2558         endif
2559
2560         " move on to the next line
2561         let currentLine = currentLine + 1
2562     endwhile
2563
2564     return rightMostIndx
2565 endfunction
2566
2567 "FUNCTION: s:SaveScreenState() {{{2
2568 "Saves the current cursor position in the current buffer and the window
2569 "scroll position
2570 function s:SaveScreenState()
2571     let t:NERDComOldPos = getpos(".")
2572     let t:NERDComOldTopLine = line("w0")
2573 endfunction
2574
2575 " Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2
2576 " This function takes a line and swaps the outter most multi-part delims for
2577 " place holders
2578 " Args:
2579 "   -line: the line to swap the delims in
2580 "
2581 function s:SwapOutterMultiPartDelimsForPlaceHolders(line)
2582     " find out if the line is commented using normal delims and/or
2583     " alternate ones
2584     let isCommented = s:IsCommented(s:Left(), s:Right(), a:line)
2585     let isCommentedAlt = s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), a:line)
2586
2587     let line2 = a:line
2588
2589     "if the line is commented and there is a right delimiter, replace
2590     "the delims with place-holders
2591     if isCommented && s:Multipart()
2592         let line2 = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, a:line)
2593
2594     "similarly if the line is commented with the alternative
2595     "delimiters
2596     elseif isCommentedAlt && s:AltMultipart()
2597         let line2 = s:ReplaceDelims(s:Left({'alt': 1}), s:Right({'alt': 1}), g:NERDLPlace, g:NERDRPlace, a:line)
2598     endif
2599
2600     return line2
2601 endfunction
2602
2603 " Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2
2604 " This function takes a line and swaps the outtermost place holders for
2605 " multi-part delims
2606 " Args:
2607 "   -line: the line to swap the delims in
2608 "
2609 function s:SwapOutterPlaceHoldersForMultiPartDelims(line)
2610     let left = ''
2611     let right = ''
2612     if s:Multipart()
2613         let left = s:Left()
2614         let right = s:Right()
2615     elseif s:AltMultipart()
2616         let left = s:Left({'alt': 1})
2617         let right = s:Right({'alt': 1})
2618     endif
2619
2620     let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
2621     return line
2622 endfunction
2623 " Function: s:TabbedCol(line, col) {{{2
2624 " Gets the col number for given line and existing col number. The new col
2625 " number is the col number when all leading spaces are converted to tabs
2626 " Args:
2627 "   -line:the line to get the rel col for
2628 "   -col: the abs col
2629 function s:TabbedCol(line, col)
2630     let lineTruncated = strpart(a:line, 0, a:col)
2631     let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g')
2632     return strlen(lineSpacesToTabs)
2633 endfunction
2634 "FUNCTION: s:TabSpace() {{{2
2635 "returns a string of spaces equal in length to &tabstop
2636 function s:TabSpace()
2637     let tabSpace = ""
2638     let spacesPerTab = &tabstop
2639     while spacesPerTab > 0
2640         let tabSpace = tabSpace . " "
2641         let spacesPerTab = spacesPerTab - 1
2642     endwhile
2643     return tabSpace
2644 endfunction
2645
2646 " Function: s:UnEsc(str, escChar) {{{2
2647 " This function removes all the escape chars from a string
2648 " Args:
2649 "   -str: the string to remove esc chars from
2650 "   -escChar: the escape char to be removed
2651 function s:UnEsc(str, escChar)
2652     return substitute(a:str, a:escChar, "", "g")
2653 endfunction
2654
2655 " Function: s:UntabbedCol(line, col) {{{2
2656 " Takes a line and a col and returns the absolute column of col taking into
2657 " account that a tab is worth 3 or 4 (or whatever) spaces.
2658 " Args:
2659 "   -line:the line to get the abs col for
2660 "   -col: the col that doesnt take into account tabs
2661 function s:UntabbedCol(line, col)
2662     let lineTruncated = strpart(a:line, 0, a:col)
2663     let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g')
2664     return strlen(lineTabsToSpaces)
2665 endfunction
2666 " Section: Comment mapping setup {{{1
2667 " ===========================================================================
2668
2669 " switch to/from alternative delimiters
2670 nnoremap <plug>NERDCommenterAltDelims :call <SID>SwitchToAlternativeDelimiters(1)<cr>
2671
2672 " comment out lines
2673 nnoremap <silent> <plug>NERDCommenterComment :call NERDComment(0, "norm")<cr>
2674 vnoremap <silent> <plug>NERDCommenterComment <ESC>:call NERDComment(1, "norm")<cr>
2675
2676 " toggle comments
2677 nnoremap <silent> <plug>NERDCommenterToggle :call NERDComment(0, "toggle")<cr>
2678 vnoremap <silent> <plug>NERDCommenterToggle <ESC>:call NERDComment(1, "toggle")<cr>
2679
2680 " minimal comments
2681 nnoremap <silent> <plug>NERDCommenterMinimal :call NERDComment(0, "minimal")<cr>
2682 vnoremap <silent> <plug>NERDCommenterMinimal <ESC>:call NERDComment(1, "minimal")<cr>
2683
2684 " sexy comments
2685 nnoremap <silent> <plug>NERDCommenterSexy :call NERDComment(0, "sexy")<CR>
2686 vnoremap <silent> <plug>NERDCommenterSexy <ESC>:call NERDComment(1, "sexy")<CR>
2687
2688 " invert comments
2689 nnoremap <silent> <plug>NERDCommenterInvert :call NERDComment(0, "invert")<CR>
2690 vnoremap <silent> <plug>NERDCommenterInvert <ESC>:call NERDComment(1, "invert")<CR>
2691
2692 " yank then comment
2693 nmap <silent> <plug>NERDCommenterYank :call NERDComment(0, "yank")<CR>
2694 vmap <silent> <plug>NERDCommenterYank <ESC>:call NERDComment(1, "yank")<CR>
2695
2696 " left aligned comments
2697 nnoremap <silent> <plug>NERDCommenterAlignLeft :call NERDComment(0, "alignLeft")<cr>
2698 vnoremap <silent> <plug>NERDCommenterAlignLeft <ESC>:call NERDComment(1, "alignLeft")<cr>
2699
2700 " left and right aligned comments
2701 nnoremap <silent> <plug>NERDCommenterAlignBoth :call NERDComment(0, "alignBoth")<cr>
2702 vnoremap <silent> <plug>NERDCommenterAlignBoth <ESC>:call NERDComment(1, "alignBoth")<cr>
2703
2704 " nested comments
2705 nnoremap <silent> <plug>NERDCommenterNest :call NERDComment(0, "nested")<cr>
2706 vnoremap <silent> <plug>NERDCommenterNest <ESC>:call NERDComment(1, "nested")<cr>
2707
2708 " uncomment
2709 nnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(0, "uncomment")<cr>
2710 vnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(1, "uncomment")<cr>
2711
2712 " comment till the end of the line
2713 nnoremap <silent> <plug>NERDCommenterToEOL :call NERDComment(0, "toEOL")<cr>
2714
2715 " append comments
2716 nmap <silent> <plug>NERDCommenterAppend :call NERDComment(0, "append")<cr>
2717
2718 " insert comments
2719 inoremap <silent> <plug>NERDCommenterInInsert <SPACE><BS><ESC>:call NERDComment(0, "insert")<CR>
2720
2721
2722 function! s:CreateMaps(target, combo)
2723     if !hasmapto(a:target, 'n')
2724         exec 'nmap ' . a:combo . ' ' . a:target
2725     endif
2726
2727     if !hasmapto(a:target, 'v')
2728         exec 'vmap ' . a:combo . ' ' . a:target
2729     endif
2730 endfunction
2731
2732 if g:NERDCreateDefaultMappings
2733     call s:CreateMaps('<plug>NERDCommenterComment',    '<leader>cc')
2734     call s:CreateMaps('<plug>NERDCommenterToggle',     '<leader>c<space>')
2735     call s:CreateMaps('<plug>NERDCommenterMinimal',    '<leader>cm')
2736     call s:CreateMaps('<plug>NERDCommenterSexy',       '<leader>cs')
2737     call s:CreateMaps('<plug>NERDCommenterInvert',     '<leader>ci')
2738     call s:CreateMaps('<plug>NERDCommenterYank',       '<leader>cy')
2739     call s:CreateMaps('<plug>NERDCommenterAlignLeft',  '<leader>cl')
2740     call s:CreateMaps('<plug>NERDCommenterAlignBoth',  '<leader>cb')
2741     call s:CreateMaps('<plug>NERDCommenterNest',       '<leader>cn')
2742     call s:CreateMaps('<plug>NERDCommenterUncomment',  '<leader>cu')
2743     call s:CreateMaps('<plug>NERDCommenterToEOL',      '<leader>c$')
2744     call s:CreateMaps('<plug>NERDCommenterAppend',     '<leader>cA')
2745
2746     if !hasmapto('<plug>NERDCommenterAltDelims', 'n')
2747         nmap <leader>ca <plug>NERDCommenterAltDelims
2748     endif
2749 endif
2750
2751
2752
2753 " Section: Menu item setup {{{1
2754 " ===========================================================================
2755 "check if the user wants the menu to be displayed
2756 if g:NERDMenuMode != 0
2757
2758     let menuRoot = ""
2759     if g:NERDMenuMode == 1
2760         let menuRoot = 'comment'
2761     elseif g:NERDMenuMode == 2
2762         let menuRoot = '&comment'
2763     elseif g:NERDMenuMode == 3
2764         let menuRoot = '&Plugin.&comment'
2765     endif
2766
2767     function! s:CreateMenuItems(target, desc, root)
2768         exec 'nmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
2769         exec 'vmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
2770     endfunction
2771     call s:CreateMenuItems("<plug>NERDCommenterComment",    'Comment', menuRoot)
2772     call s:CreateMenuItems("<plug>NERDCommenterToggle",     'Toggle', menuRoot)
2773     call s:CreateMenuItems('<plug>NERDCommenterMinimal',    'Minimal', menuRoot)
2774     call s:CreateMenuItems('<plug>NERDCommenterNest',       'Nested', menuRoot)
2775     exec 'nmenu <silent> '. menuRoot .'.To\ EOL <plug>NERDCommenterToEOL'
2776     call s:CreateMenuItems('<plug>NERDCommenterInvert',     'Invert', menuRoot)
2777     call s:CreateMenuItems('<plug>NERDCommenterSexy',       'Sexy', menuRoot)
2778     call s:CreateMenuItems('<plug>NERDCommenterYank',       'Yank\ then\ comment', menuRoot)
2779     exec 'nmenu <silent> '. menuRoot .'.Append <plug>NERDCommenterAppend'
2780     exec 'menu <silent> '. menuRoot .'.-Sep-    :'
2781     call s:CreateMenuItems('<plug>NERDCommenterAlignLeft',  'Left\ aligned', menuRoot)
2782     call s:CreateMenuItems('<plug>NERDCommenterAlignBoth',  'Left\ and\ right\ aligned', menuRoot)
2783     exec 'menu <silent> '. menuRoot .'.-Sep2-    :'
2784     call s:CreateMenuItems('<plug>NERDCommenterUncomment',  'Uncomment', menuRoot)
2785     exec 'nmenu <silent> '. menuRoot .'.Switch\ Delimiters <plug>NERDCommenterAltDelims'
2786     exec 'imenu <silent> '. menuRoot .'.Insert\ Comment\ Here <plug>NERDCommenterInInsert'
2787     exec 'menu <silent> '. menuRoot .'.-Sep3-    :'
2788     exec 'menu <silent>'. menuRoot .'.Help :help NERDCommenterContents<CR>'
2789 endif
2790 " vim: set foldmethod=marker :