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