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>
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.
13 " ============================================================================
15 " Section: script init stuff {{{1
16 if exists("loaded_nerd_comments")
20 echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
23 let loaded_nerd_comments = 1
25 " Function: s:InitVariable() function {{{2
26 " This function is used to initialise a given variable to a given value. The
27 " variable is only initialised if it does not exist prior
30 " -var: the name of the var to be initialised
31 " -value: the value to initialise var to
34 " 1 if the var is set, 0 otherwise
35 function s:InitVariable(var, value)
37 exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
43 " Section: space string init{{{2
44 " When putting spaces after the left delim and before the right we use
45 " s:spaceStr for the space char. This way we can make it add anything after
46 " the left and before the right by modifying this variable
48 let s:lenSpaceStr = strlen(s:spaceStr)
50 " Section: variable init calls {{{2
51 call s:InitVariable("g:NERDAllowAnyVisualDelims", 1)
52 call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0)
53 call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0)
54 call s:InitVariable("g:NERDCompactSexyComs", 0)
55 call s:InitVariable("g:NERDCreateDefaultMappings", 1)
56 call s:InitVariable("g:NERDDefaultNesting", 1)
57 call s:InitVariable("g:NERDMenuMode", 3)
58 call s:InitVariable("g:NERDLPlace", "[>")
59 call s:InitVariable("g:NERDUsePlaceHolders", 1)
60 call s:InitVariable("g:NERDRemoveAltComs", 1)
61 call s:InitVariable("g:NERDRemoveExtraSpaces", 1)
62 call s:InitVariable("g:NERDRPlace", "<]")
63 call s:InitVariable("g:NERDSpaceDelims", 0)
64 call s:InitVariable("g:NERDDelimiterRequests", 1)
66 let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
67 "vf ;;dA:
\ehcs"'A {
\ej^f(lyi(k$p0f{a
\eA }
\e0f{a 'left':
\ejdd^
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': ';' }
379 " Section: Comment mapping functions, autocommands and commands {{{1
380 " ============================================================================
381 " Section: Comment enabler autocommands {{{2
382 " ============================================================================
384 augroup commentEnablers
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)
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)
396 " Function: s:SetUpForNewFiletype(filetype) function {{{2
397 " This function is responsible for setting up buffer scoped variables for the
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.
405 function s:SetUpForNewFiletype(filetype, forceReset)
406 let b:NERDSexyComMarker = ''
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] = ''
416 let b:NERDCommenterDelims = s:CreateDelimMapFromCms()
421 function s:CreateDelimMapFromCms()
423 \ 'left': substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', ''),
424 \ 'right': substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g'),
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.
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'] == ''
443 call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0)
448 "save the current delimiters
449 let tempLeft = s:Left()
450 let tempRight = s:Right()
452 "swap current delimiters for alternative
453 let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt']
454 let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt']
456 "set the previously current delimiters to be the new alternative ones
457 let b:NERDCommenterDelims['leftAlt'] = tempLeft
458 let b:NERDCommenterDelims['rightAlt'] = tempRight
460 "tell the user what comment delimiters they are now using
462 call s:NerdEcho("Now using " . s:Left() . " " . s:Right() . " to delimit comments", 1)
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})
477 " get the len of the right delim
478 let lenRight = strlen(right)
480 let isLineEmpty = strlen(getline(".")) == 0
481 let insOrApp = (isLineEmpty==1 ? 'i' : 'A')
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 . " "
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
490 let leftMoveAmount = lenRight
491 execute ":normal! " . leftMoveAmount . "h"
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.
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
509 let bottom = a:bottom
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)
519 "find out how many tabs are in the top line and adjust the left
520 "boundary accordingly
521 let numTabs = s:NumberOfLeadingTabs(topline)
523 let lSide = &ts * lSide
525 let lSide = (lSide - numTabs) + (&ts * numTabs)
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)
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.
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)
556 "start the commenting from the top and keep commenting till we reach the
559 while currentLine <= bottom
561 "check if we are allowed to comment this line
562 if s:CanCommentLine(a:forceNested, currentLine)
564 "convert the leading tabs into spaces
565 let theLine = getline(currentLine)
566 let lineHasLeadTabs = s:HasLeadingTabs(theLine)
568 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
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
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
578 call setline(currentLine, theLine)
579 if s:CanPlaceCursor(currentLine, lSide)
581 let leftSpaced = s:Left({'space': 1})
582 let rightSpaced = s:Right({'space': 1})
584 "stick the left delimiter down
585 let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
588 "stick the right delimiter down
589 let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced))
591 let firstLeftDelim = s:FindDelimiterIndex(s:Left(), theLine)
592 let lastRightDelim = s:LastIndexOfDelim(s:Right(), theLine)
594 if firstLeftDelim != -1 && lastRightDelim != -1
595 let searchStr = strpart(theLine, 0, lastRightDelim)
596 let searchStr = strpart(searchStr, firstLeftDelim+strlen(s:Left()))
598 "replace the outter most delims in searchStr with
600 let theLineWithPlaceHolders = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, searchStr)
602 "add the right delimiter onto the line
603 let theLine = strpart(theLine, 0, firstLeftDelim+strlen(s:Left())) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
609 "restore tabs if needed
611 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
614 call setline(currentLine, theLine)
617 let currentLine = currentLine + 1
620 "if we switched delims then we gotta go back to what they were before
621 if switchedDelims == 1
622 call s:SwitchToAlternativeDelimiters(0)
626 " Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2
627 " This function comments a range of lines.
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)
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}))
645 " now we actually comment the lines. Do it line by line
646 let currentLine = a:firstLine
647 while currentLine <= a:lastLine
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)
660 " find out if the line is commented using normal delims and/or
662 let isCommented = s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)
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)
669 let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
672 let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx)
674 let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
679 " restore leading tabs if appropriate
680 if lineHasLeadingTabs
681 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
684 " we are done with this line
685 call setline(currentLine, theLine)
686 let currentLine = currentLine + 1
691 " Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2
692 " This function comments a range of lines in a minimal style. I
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'
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.'
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)
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
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)
730 call setline(a:firstLine, theLine)
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)
740 call setline(a:lastLine, theLine)
743 " Function: s:CommentLinesSexy(topline, bottomline) function {{{2
744 " This function is used to comment lines in the 'Sexy' style. eg in c:
746 " * This is a sexy comment
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)
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.'
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'
766 let sexyComMarker = s:GetSexyComMarker(0,0)
767 let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
770 " we jam the comment as far to the right as possible
771 let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
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 : '')
779 "comment the top line
780 let theLine = getline(a:topline)
781 let lineHasTabs = s:HasLeadingTabs(theLine)
783 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
785 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
786 let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
788 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
790 call setline(a:topline, theLine)
792 "comment the bottom line
793 if a:bottomline != a:topline
794 let theLine = getline(a:bottomline)
795 let lineHasTabs = s:HasLeadingTabs(theLine)
797 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
799 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
801 let theLine = s:AddRightDelim(spaceString . right, theLine)
803 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
805 call setline(a:bottomline, theLine)
808 " add the left delimiter one line above the lines that are to be commented
809 call cursor(a:topline, 1)
811 let theLine = repeat(' ', leftAlignIndx) . left
813 " Make sure tabs are respected
815 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
817 call setline(a:topline, theLine)
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)
823 let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right
825 " Make sure tabs are respected
827 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
829 call setline(a:bottomline+2, theLine)
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)
841 let theLine = s:ConvertLeadingTabsToSpaces(theLine)
844 let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
846 " add the sexyComMarker
847 let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
850 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
854 " set the line and move onto the next one
855 call setline(currentLine, theLine)
856 let currentLine = currentLine + 1
861 " Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2
862 " Applies "toggle" commenting to the given range of lines
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
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)
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)
884 let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
885 let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
888 " restore leading tabs if appropriate
889 if lineHasLeadingTabs
890 let theLine = s:ConvertLeadingSpacesToTabs(theLine)
893 " we are done with this line
894 call setline(currentLine, theLine)
895 let currentLine = currentLine + 1
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.
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)
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)
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)
923 "there are multiple lines in the comment
925 "comment the top line
926 call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
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)
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)
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)
945 "if we switched delims then we gotta go back to what they were before
946 if switchedDelims == 1
947 call s:SwitchToAlternativeDelimiters(0)
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
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)
960 " go thru all lines in the given range
961 let currentLine = a:firstLine
962 while currentLine <= a:lastLine
963 let theLine = getline(currentLine)
965 let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
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
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])
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
981 " the line isnt commented
983 call s:CommentLinesToggle(1, currentLine, currentLine)
984 let currentLine = currentLine + 1
990 " Function: NERDComment(isVisual, type) function {{{2
991 " This function is a Wrapper for the main commenting functions
994 " -isVisual: a flag indicating whether the comment is requested in visual
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
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)
1009 let firstLine = line("'<")
1010 let lastLine = line("'>")
1011 let firstCol = col("'<")
1012 let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0)
1014 let firstLine = a:firstline
1015 let lastLine = a:lastline
1018 let countWasGiven = (a:isVisual == 0 && firstLine != lastLine)
1020 let forceNested = (a:type == 'nested' || g:NERDDefaultNesting)
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)
1028 call s:CommentLines(forceNested, "none", firstLine, lastLine)
1031 elseif a:type == 'alignLeft' || a:type == 'alignBoth'
1033 if a:type == "alignLeft"
1035 elseif a:type == "alignBoth"
1038 call s:CommentLines(forceNested, align, firstLine, lastLine)
1040 elseif a:type == 'invert'
1041 call s:InvertComment(firstLine, lastLine)
1043 elseif a:type == 'sexy'
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)
1052 elseif a:type == 'toggle'
1053 let theLine = getline(firstLine)
1055 if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
1056 call s:UncommentLines(firstLine, lastLine)
1058 call s:CommentLinesToggle(forceNested, firstLine, lastLine)
1061 elseif a:type == 'minimal'
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)
1070 elseif a:type == 'toEOL'
1071 call s:SaveScreenState()
1072 call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1)
1073 call s:RestoreScreenState()
1075 elseif a:type == 'append'
1076 call s:AppendCommentToLine()
1078 elseif a:type == 'insert'
1079 call s:PlaceDelimitersAndInsBetween()
1081 elseif a:type == 'uncomment'
1082 call s:UncommentLines(firstLine, lastLine)
1084 elseif a:type == 'yank'
1087 elseif countWasGiven
1088 execute firstLine .','. lastLine .'yank'
1092 execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")'
1095 let &ignorecase = oldIgnoreCase
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})
1106 let theLine = getline(".")
1107 let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab)
1109 "convert tabs to spaces and adjust the cursors column to take this into
1111 let untabbedCol = s:UntabbedCol(theLine, col("."))
1112 call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine))
1113 call cursor(line("."), untabbedCol)
1115 " get the len of the right delim
1116 let lenRight = strlen(right)
1118 let isDelimOnEOL = col(".") >= strlen(getline("."))
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')
1124 " place the delimiters down. We do it differently depending on whether
1125 " there is a left AND right delimiter
1127 execute ":normal! " . insOrApp . left . right
1128 execute ":normal! " . lenRight . "h"
1130 execute ":normal! " . insOrApp . left
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.
1136 execute 'normal! a '
1141 "if needed convert spaces back to tabs and adjust the cursors col
1144 let tabbedCol = s:TabbedCol(getline("."), col("."))
1145 call setline(line("."), s:ConvertLeadingSpacesToTabs(getline(".")))
1146 call cursor(line("."), tabbedCol)
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.
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 ""
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)
1166 let l:right = a:right
1167 let lenLeft = strlen(left)
1168 let lenRight = strlen(right)
1170 let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
1174 "look for the left delimiter, if we find it, remove it.
1175 let leftIndx = s:FindDelimiterIndex(a:left, line)
1177 let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
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)
1186 "look for the right delimiter, if we find it, remove it
1187 let rightIndx = s:FindDelimiterIndex(a:right, line)
1189 let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
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)
1201 " Function: s:UncommentLines(topLine, bottomLine) {{{2
1202 " This function uncomments the given lines
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
1217 "go thru each line uncommenting each line removing sexy comments
1218 let currentLine = firstline
1219 while currentLine <= lastline
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)
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
1228 let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
1230 call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
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
1238 "no sexy com was detected so uncomment the line as normal
1240 call s:UncommentLinesNormal(currentLine, currentLine)
1241 let currentLine = currentLine + 1
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
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)
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.'
1263 let leftUnEsc = s:GetSexyComLeft(0,0)
1264 let rightUnEsc = s:GetSexyComRight(0,0)
1266 let sexyComMarker = s:GetSexyComMarker(0, 1)
1267 let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
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)
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
1276 let currentLine = a:topline+1
1277 while currentLine < a:bottomline
1278 let theLine = getline(currentLine)
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)
1286 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1289 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1291 let theLine = s:ConvertLeadingWhiteSpace(theLine)
1293 " move onto the next line
1294 call setline(currentLine, theLine)
1295 let currentLine = currentLine + 1
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
1302 " get the first line so we can remove the left delim from it
1303 let theLine = getline(a:topline)
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)
1309 let bottomline = bottomline - 1
1311 " topline contains more than just the left delim
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)
1320 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
1322 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1323 call setline(a:topline, theLine)
1326 " get the last line so we can remove the right delim
1327 let theLine = getline(bottomline)
1329 " if the bottomline contains only the right delim then just delete it
1330 if theLine =~ '^[ \t]*' . right . '[ \t]*$'
1331 call cursor(bottomline, 1)
1334 " the last line contains more than the right delim
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)
1342 let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
1345 " if the last line also starts with a sexy comment marker then we
1346 " remove this as well
1347 if theLine =~ '^[ \t]*' . sexyComMarker
1349 " remove the sexyComMarker. If there is a space after it then
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)
1355 let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
1359 let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
1360 call setline(bottomline, theLine)
1364 " Function: s:UncommentLineNormal(line) {{{2
1365 " uncomments the given line and returns the result
1367 " -line: the line to uncomment
1368 function s:UncommentLineNormal(line)
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)
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)
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)
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
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)
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)
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)
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)
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)
1415 let right = s:Right()
1418 let right = s:Right({'alt': 1})
1419 let left = s:Left({'alt': 1})
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
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)
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)
1437 let line = s:ConvertLeadingWhiteSpace(line)
1442 " Function: s:UncommentLinesNormal(topline, bottomline) {{{2
1443 " This function is called to uncomment lines that arent a sexy comment
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
1456 " Section: Other helper functions {{{1
1457 " ============================================================================
1459 " Function: s:AddLeftDelim(delim, theLine) {{{2
1461 function s:AddLeftDelim(delim, theLine)
1462 return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '')
1465 " Function: s:AddLeftDelimAligned(delim, theLine) {{{2
1467 function s:AddLeftDelimAligned(delim, theLine, alignIndx)
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))
1476 return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
1479 " Function: s:AddRightDelim(delim, theLine) {{{2
1481 function s:AddRightDelim(delim, theLine)
1485 return substitute(a:theLine, '$', a:delim, '')
1489 " Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2
1491 function s:AddRightDelimAligned(delim, theLine, alignIndx)
1496 " when we align the right delim we are just adding spaces
1497 " so we get a string containing the needed spaces (it
1499 let extraSpaces = ''
1500 let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine))
1502 " add the right delim
1503 return substitute(a:theLine, '$', extraSpaces . a:delim, '')
1507 " Function: s:AltMultipart() {{{2
1508 " returns 1 if the alternative delims are multipart
1509 function s:AltMultipart()
1510 return b:NERDCommenterDelims['rightAlt'] != ''
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
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)
1524 " make sure we don't comment lines that are just spaces or tabs or empty.
1525 if theLine =~ "^[ \t]*$"
1529 "if the line is part of a sexy comment then just flag it...
1530 if s:IsInSexyComment(a:lineNum)
1534 let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
1536 "if the line isnt commented return true
1541 "if the line is commented but nesting is allowed then return true
1542 if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)
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)
1554 call cursor(a:line, a:col)
1555 let success = (line(".") == a:line && col(".") == a:col)
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)
1569 let currentLine = currentLine + 1
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
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
1585 " make sure we don't comment lines that are just spaces or tabs or empty.
1586 if theLine =~ "^[ \t]*$"
1590 "if the line is part of a sexy comment then just flag it...
1591 if s:IsInSexyComment(a:lineNum)
1598 " Function: s:ConvertLeadingSpacesToTabs(line) {{{2
1599 " This function takes a line and converts all leading tabs on that line into
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' , "")
1614 " Function: s:ConvertLeadingTabsToSpaces(line) {{{2
1615 " This function takes a line and converts all leading spaces on that line into
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() , "")
1629 " Function: s:ConvertLeadingWhiteSpace(line) {{{2
1630 " Converts the leading white space to tabs/spaces depending on &ts
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")
1641 let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
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
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)
1660 "if there is an instance of searchstr in str process it
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)
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)
1671 return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
1675 " Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2
1676 " Returns 1 if the given block of lines has a delimiter (a:delim) in it
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
1688 let currentLine = currentLine + 1
1693 " Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2
1694 " Returns 1 if the given block has a >= 1 multipart delimiter in it
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()
1701 return s:DoesBlockHaveDelim(s:Left(), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right(), a:top, a:bottom)
1703 return s:DoesBlockHaveDelim(s:Left({'alt': 1}), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right({'alt': 1}), a:top, a:bottom)
1710 " Function: s:Esc(str) {{{2
1711 " Escapes all the tricky chars in the given string
1713 let charsToEsc = '*/\."&$+'
1714 return escape(a:str, charsToEsc)
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
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)
1726 "make sure the delimiter isnt empty otherwise we go into an infinite loop.
1727 if a:delimiter == ""
1732 let l:delimiter = a:delimiter
1733 let lenDel = strlen(l:delimiter)
1735 "get the index of the first occurrence of the delimiter
1736 let delIndx = stridx(a:line, l:delimiter)
1738 "keep looping thru the line till we either find a real comment delimiter
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
1746 if s:IsDelimValid(l:delimiter, delIndx, a:line)
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)
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
1759 if distToNextDelim == -1
1762 let delIndx = delIndx + lenDel + distToNextDelim
1766 "there is no comment delimiter on this line
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
1775 " -lineNum: the line number that is to be tested whether it is the
1776 " top/bottom/middle line of a sexy com
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)
1783 "find which delimiters to look for as the start/end delims of the comment
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})
1796 let sexyComMarker = s:GetSexyComMarker(0, 1)
1798 "initialise the top/bottom line numbers of the sexy comment to -1
1802 let currentLine = a:lineNum
1803 while top == -1 || bottom == -1
1804 let theLine = getline(currentLine)
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
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
1815 "the right delimiter is on the same line as the last sexyComMarker
1816 elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right
1817 let bottom = currentLine
1819 "we have not found the top or bottom line so we assume currentLine is an
1820 "intermediate line and look to prove otherwise
1823 "if the line doesnt start with a sexyComMarker then it is not a sexy
1825 if theLine !~ '^[ \t]*' . sexyComMarker
1831 "if top is -1 then we havent found the top yet so keep looking up
1833 let currentLine = currentLine - 1
1834 "if we have found the top line then go down looking for the bottom
1836 let currentLine = currentLine + 1
1841 return [top, bottom]
1845 " Function: s:GetSexyComMarker() {{{2
1846 " Returns the sexy comment marker for the current filetype.
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
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
1859 "if there is no hardcoded marker then we find one
1860 if sexyComMarker == ''
1862 "if the filetype has c style comments then use standard c sexy
1864 if s:HasCStyleComments()
1865 let sexyComMarker = '*'
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}))
1873 if s:Multipart() && lenLeft >= lenLeftAlt
1875 elseif s:AltMultipart()
1876 let left = s:Left({'alt': 1})
1881 "get the last char of left
1882 let sexyComMarker = strpart(left, strlen(left)-1)
1886 if a:space && g:NERDSpaceDelims
1887 let sexyComMarker = sexyComMarker . s:spaceStr
1891 let sexyComMarker = s:Esc(sexyComMarker)
1894 return sexyComMarker
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
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}))
1909 "assume c style sexy comments if possible
1910 if s:HasCStyleComments()
1913 "grab the longest left delim that has a right
1914 if s:Multipart() && lenLeft >= lenLeftAlt
1916 elseif s:AltMultipart()
1917 let left = s:Left({'alt': 1})
1923 if a:space && g:NERDSpaceDelims
1924 let left = left . s:spaceStr
1928 let left = s:Esc(left)
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.
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}))
1947 "assume c style sexy comments if possible
1948 if s:HasCStyleComments()
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})
1961 if a:space && g:NERDSpaceDelims
1962 let right = s:spaceStr . right
1966 let right = s:Esc(right)
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()
1978 " Function: s:HasLeadingTabs(...) {{{2
1979 " Returns 1 if any of the given strings have leading tabs
1980 function s:HasLeadingTabs(...)
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}) == '*/')
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
1999 " -lineNum: the line number of the line to check
2000 function s:IsCommentedNormOrSexy(lineNum)
2001 let theLine = getline(a:lineNum)
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)
2008 "if the line is part of a sexy comment return 1
2009 if s:IsInSexyComment(a:lineNum)
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
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())
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)
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
2045 " Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2
2046 " Finds the type of the outtermost delims on the line
2049 " -line: the line that to check if the outtermost comments on it are
2051 " -left/right: the left and right delimiters to check for
2052 " -leftAlt/rightAlt: the left and right alternative delimiters to check for
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
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)
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()
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()
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.
2098 " -delimiter: the delimiter we are validating
2099 " -delIndx: the position of delimiter in line
2100 " -line: the line that delimiter occurs in
2103 " 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
2105 function s:IsDelimValid(delimiter, delIndx, line)
2106 "get the delimiter without the escchars
2107 let l:delimiter = a:delimiter
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))
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, '"', "\\"))
2119 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\"))
2122 if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\"))
2127 "if the comment delimiter is escaped, assume it isnt a real delimiter
2128 if s:IsEscaped(a:line, a:delIndx, "\\")
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, '"', "\\"))
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 . "\\}\".*$"
2146 let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\")
2147 let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\")
2149 "if the quote is inside brackets then assume it isnt a comment
2150 if numLeftParen > numRightParen
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, "\"", "\\"))
2165 " Function: s:IsNumEven(num) {{{2
2166 " A small function the returns 1 if the input number is even and 0 otherwise
2168 " -num: the number to check
2169 function s:IsNumEven(num)
2170 return (a:num % 2) == 0
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)
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
2184 let curIndx = a:indx-1
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
2190 "we have found another esc char so add one to the count and move left
2192 let numEscChars = numEscChars + 1
2193 let curIndx = curIndx - 1
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)
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))
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.
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)
2216 "get the delim set that would be used for a sexy comment
2221 let right = s:Right()
2222 elseif s:AltMultipart()
2223 let left = s:Left({'alt': 1})
2224 let right = s:Right({'alt': 1})
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
2237 "if there is < 2 lines in the comment it cannot be sexy
2238 if (bottomline - topline) <= 0
2242 "if the top line doesnt begin with a left delim then the comment isnt sexy
2243 if getline(a:topline) !~ '^[ \t]*' . left
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
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
2257 "if the bottom line doesnt begin with a right delim then the comment isnt
2259 if getline(a:bottomline) !~ '^.*' . right . '$'
2263 let sexyComMarker = s:GetSexyComMarker(0, 1)
2265 "check each of the intermediate lines to make sure they start with a
2267 let currentLine = a:topline+1
2268 while currentLine < a:bottomline
2269 let theLine = getline(currentLine)
2271 if theLine !~ '^[ \t]*' . sexyComMarker
2275 "if there is a right delim in an intermediate line then the block isnt
2277 if s:FindDelimiterIndex(right, theLine) != -1
2281 let currentLine = currentLine + 1
2284 "we have not found anything to suggest that this isnt a sexy comment so
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
2293 " -delim: the delimiter to look for
2294 " -str: the string to look for delim in
2295 function s:LastIndexOfDelim(delim, str)
2297 let lenDelim = strlen(delim)
2299 "set index to the first occurrence of delim. If there is no occurrence then
2301 let indx = s:FindDelimiterIndex(delim, a:str)
2306 "keep moving to the next instance of delim in str till there is none left
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)
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
2317 let indx = indx + indx2 + lenDelim
2327 " Function: s:Left(...) {{{2
2328 " returns left delimiter data
2329 function s:Left(...)
2330 let params = a:0 ? a:1 : {}
2332 let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['leftAlt'] : b:NERDCommenterDelims['left']
2338 if has_key(params, 'space') && g:NERDSpaceDelims
2339 let delim = delim . s:spaceStr
2342 if has_key(params, 'esc')
2343 let delim = s:Esc(delim)
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.
2353 " -countCommentedLines: 1 if lines that are commented are to be checked as
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)
2360 " declare the left most index as an extreme value
2361 let leftMostIndx = 1000
2363 " go thru the block line by line updating leftMostIndx
2364 let currentLine = a:topline
2365 while currentLine <= a:bottomline
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
2382 " move on to the next line
2383 let currentLine = currentLine + 1
2386 if leftMostIndx == 1000
2393 " Function: s:Multipart() {{{2
2394 " returns 1 if the current delims are multipart
2395 function s:Multipart()
2396 return s:Right() != ''
2399 " Function: s:NerdEcho(msg, typeOfMsg) {{{2
2401 " -msg: the message to echo
2402 " -typeOfMsg: 0 = warning message
2403 " 1 = normal message
2404 function s:NerdEcho(msg, typeOfMsg)
2407 echom 'NERDCommenter:' . a:msg
2409 elseif a:typeOfMsg == 1
2410 echom 'NERDCommenter:' . a:msg
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', ""))
2420 " Function: s:NumLinesInBuf() {{{2
2421 " Returns the number of lines in the current buffer
2422 function s:NumLinesInBuf()
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.
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)
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
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)
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))
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
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
2475 function s:ReplaceRightMostDelim(toReplace, replacor, str)
2476 let toReplace = a:toReplace
2477 let replacor = a:replacor
2478 let lenToReplace = strlen(toReplace)
2480 "get the index of the last delim in str
2481 let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
2483 "if there IS a delimiter in str, replace it and return the result
2485 if indxToReplace != -1
2486 let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
2491 "FUNCTION: s:RestoreScreenState() {{{2
2493 "Sets the screen state back to what it was when s:SaveScreenState was last
2496 function s:RestoreScreenState()
2497 if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos")
2498 throw 'NERDCommenter exception: cannot restore screen'
2501 call cursor(t:NERDComOldTopLine, 0)
2503 call setpos(".", t:NERDComOldPos)
2506 " Function: s:Right(...) {{{2
2507 " returns right delimiter data
2508 function s:Right(...)
2509 let params = a:0 ? a:1 : {}
2511 let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['rightAlt'] : b:NERDCommenterDelims['right']
2517 if has_key(params, 'space') && g:NERDSpaceDelims
2518 let delim = s:spaceStr . delim
2521 if has_key(params, 'esc')
2522 let delim = s:Esc(delim)
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.
2532 " -countCommentedLines: 1 if lines that are commented are to be checked as
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
2540 " go thru the block line by line updating rightMostIndx
2541 let currentLine = a:topline
2542 while currentLine <= a:bottomline
2544 " get the next line and see if it is commentable, otherwise it doesnt
2546 let theLine = getline(currentLine)
2547 if a:countEmptyLines || theLine !~ '^[ \t]*$'
2549 if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine))
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
2560 " move on to the next line
2561 let currentLine = currentLine + 1
2564 return rightMostIndx
2567 "FUNCTION: s:SaveScreenState() {{{2
2568 "Saves the current cursor position in the current buffer and the window
2570 function s:SaveScreenState()
2571 let t:NERDComOldPos = getpos(".")
2572 let t:NERDComOldTopLine = line("w0")
2575 " Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2
2576 " This function takes a line and swaps the outter most multi-part delims for
2579 " -line: the line to swap the delims in
2581 function s:SwapOutterMultiPartDelimsForPlaceHolders(line)
2582 " find out if the line is commented using normal delims and/or
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)
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)
2594 "similarly if the line is commented with the alternative
2596 elseif isCommentedAlt && s:AltMultipart()
2597 let line2 = s:ReplaceDelims(s:Left({'alt': 1}), s:Right({'alt': 1}), g:NERDLPlace, g:NERDRPlace, a:line)
2603 " Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2
2604 " This function takes a line and swaps the outtermost place holders for
2607 " -line: the line to swap the delims in
2609 function s:SwapOutterPlaceHoldersForMultiPartDelims(line)
2614 let right = s:Right()
2615 elseif s:AltMultipart()
2616 let left = s:Left({'alt': 1})
2617 let right = s:Right({'alt': 1})
2620 let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
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
2627 " -line:the line to get the rel col for
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)
2634 "FUNCTION: s:TabSpace() {{{2
2635 "returns a string of spaces equal in length to &tabstop
2636 function s:TabSpace()
2638 let spacesPerTab = &tabstop
2639 while spacesPerTab > 0
2640 let tabSpace = tabSpace . " "
2641 let spacesPerTab = spacesPerTab - 1
2646 " Function: s:UnEsc(str, escChar) {{{2
2647 " This function removes all the escape chars from a string
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")
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.
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)
2666 " Section: Comment mapping setup {{{1
2667 " ===========================================================================
2669 " switch to/from alternative delimiters
2670 nnoremap <plug>NERDCommenterAltDelims :call <SID>SwitchToAlternativeDelimiters(1)<cr>
2673 nnoremap <silent> <plug>NERDCommenterComment :call NERDComment(0, "norm")<cr>
2674 vnoremap <silent> <plug>NERDCommenterComment <ESC>:call NERDComment(1, "norm")<cr>
2677 nnoremap <silent> <plug>NERDCommenterToggle :call NERDComment(0, "toggle")<cr>
2678 vnoremap <silent> <plug>NERDCommenterToggle <ESC>:call NERDComment(1, "toggle")<cr>
2681 nnoremap <silent> <plug>NERDCommenterMinimal :call NERDComment(0, "minimal")<cr>
2682 vnoremap <silent> <plug>NERDCommenterMinimal <ESC>:call NERDComment(1, "minimal")<cr>
2685 nnoremap <silent> <plug>NERDCommenterSexy :call NERDComment(0, "sexy")<CR>
2686 vnoremap <silent> <plug>NERDCommenterSexy <ESC>:call NERDComment(1, "sexy")<CR>
2689 nnoremap <silent> <plug>NERDCommenterInvert :call NERDComment(0, "invert")<CR>
2690 vnoremap <silent> <plug>NERDCommenterInvert <ESC>:call NERDComment(1, "invert")<CR>
2693 nmap <silent> <plug>NERDCommenterYank :call NERDComment(0, "yank")<CR>
2694 vmap <silent> <plug>NERDCommenterYank <ESC>:call NERDComment(1, "yank")<CR>
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>
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>
2705 nnoremap <silent> <plug>NERDCommenterNest :call NERDComment(0, "nested")<cr>
2706 vnoremap <silent> <plug>NERDCommenterNest <ESC>:call NERDComment(1, "nested")<cr>
2709 nnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(0, "uncomment")<cr>
2710 vnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(1, "uncomment")<cr>
2712 " comment till the end of the line
2713 nnoremap <silent> <plug>NERDCommenterToEOL :call NERDComment(0, "toEOL")<cr>
2716 nmap <silent> <plug>NERDCommenterAppend :call NERDComment(0, "append")<cr>
2719 inoremap <silent> <plug>NERDCommenterInInsert <SPACE><BS><ESC>:call NERDComment(0, "insert")<CR>
2722 function! s:CreateMaps(target, combo)
2723 if !hasmapto(a:target, 'n')
2724 exec 'nmap ' . a:combo . ' ' . a:target
2727 if !hasmapto(a:target, 'v')
2728 exec 'vmap ' . a:combo . ' ' . a:target
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')
2746 if !hasmapto('<plug>NERDCommenterAltDelims', 'n')
2747 nmap <leader>ca <plug>NERDCommenterAltDelims
2753 " Section: Menu item setup {{{1
2754 " ===========================================================================
2755 "check if the user wants the menu to be displayed
2756 if g:NERDMenuMode != 0
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'
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
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>'
2790 " vim: set foldmethod=marker :