add vim conf files
[arrow.git] / conf_slk120 / vim / _vim / plugin / EnhancedCommentify.vim
blob14513736dd51c08c4a218f4cebcd1e758e8ccba7
1 " EnhancedCommentify.vim
2 " Maintainer:   Meikel Brandmeyer <Brandels_Mikesh@web.de>
3 " Version:      2.2
4 " Last Change:  Monday, 27th September 2004
6 " License:
7 " Copyright (c) 2002,2003,2004 Meikel Brandmeyer, Kaiserslautern.
8 " All rights reserved.
10 " Redistribution and use in source and binary forms, with or without
11 " modification, are permitted provided that the following conditions are met:
13 "   * Redistributions of source code must retain the above copyright notice,
14 "     this list of conditions and the following disclaimer.
15 "   * Redistributions in binary form must reproduce the above copyright notice,
16 "     this list of conditions and the following disclaimer in the documentation
17 "     and/or other materials provided with the distribution.
18 "   * Neither the name of the author nor the names of its contributors may be
19 "     used to endorse or promote products derived from this software without
20 "     specific prior written permission.
22 " THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
26 " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 " Description: 
34 " This is a (well... more or less) simple script to comment lines in a program.
35 " Currently supported languages are C, C++, PHP, the vim scripting
36 " language, python, HTML, Perl, LISP, Tex, Shell, CAOS and others.
38 " Bugfixes:
39 "   2.2
40 "   Fixed problem with UseSyntax (thanks to Pieter Naaijkens) 
41 "   Fixed typo in ParseCommentsOp (commstr -> commStr). 
42 "   Fixed support for ocaml (thanks to Zhang Le)
43 "   2.1
44 "   Fixed problems with alignement when a line contains tabs 
45 "   Fixed (resp. cleaned up) issues with overrideEL (thanks to Steve Hall) 
46 "   Fixed problems with javascript detection (thanks to Brian Neu) 
47 "   Changed Buffer init to BufWinEnter in order to use the modelines. 
48 "   2.0
49 "   Fixed invalid expression '\'' -> "'" (thanks to Zak Beck)
50 "   Setting AltOpen/AltClose to '' (ie. disabling it) would
51 "   insert '/*' resp. '*/' for character in a line (thanks to Ben Kibbey)
52 "   1.8
53 "   Backslashes in comment symbols should not be escaped.
54 "   typo (commensSymbol -> commentSymbol) (thanks to Steve Butts) 
55 "   typo (== -> =) 
56 "   Fixed hardwired '|+'-'+|' pair. 
57 "   1.7
58 "   Lines were not correctly decommentified, when there was whitespace
59 "   at the beginning of the line.    (thanks to Xiangjiang Ma) 
60 "   Fixed error detecting '*sh' filetypes. 
61 "   1.3
62 "   hlsearch was set unconditionally (thanks to Mary Ellen Foster)
63 "   made function silent             (thanks to Mare Ellen Foster)
65 " Changelog:
66 "   2.2
67 "   Added possibility to override the modes, in which keybindings are
68 "   defined.
69 "   Keybindings may be defined local to every buffer now.
70 "   If a filetype is unknown, one can turn off the keybindings now. 
71 "   2.1
72 "   Removed any cursor movement. The script should now be free of
73 "   side-effects.
74 "   The script now uses &commentstring to determine the right
75 "   comment strings. Fallback is still the ugly if-thingy.
76 "   Script can now interpret &comments in order to add a middle
77 "   string in blocks.
78 "   Added EnhancedCommentifySet for use by other scripts. (Necessary?) 
79 "   Added MultiPartBlocks for languages with multipart-comments.
80 "   Added parsing for comments option if using MultiPartBlocks.
81 "   2.0
82 "   IMPORTANT: EnhancedCommentify is now licensed under BSD license
83 "              for distribution with Cream! However this shouldn't
84 "              change anything... 
85 "   useBlockIndent does no longer depend on respectIndent. 
86 "   Added code to cope with 'C' in '&cpo'. (thanks to Luc Hermitte
87 "   for pointing this out!)
88 "   Added EnhCommentifyIdentFrontOnly option.
89 "   All options are now handled on a per buffer basis. So options
90 "   can be overriden for different buffers. 
91 "   1.9
92 "   Filetype is now recognized via regular expressions.
93 "   All known filetypes are (more or less) supported.
94 "   Decomments multipart-block comments.
95 "   Added RespectIndent, AlignRight and synID-guessing.
96 "   Switched to buffer variables.
97 "   1.8
98 "   Added Ada support. (thanks to Preben Randhol) 
99 "   Added Latte support.
100 "   Added blocksupport and possibility to specify action (comment or
101 "   decomment). It's also possible to guess the action line by line or
102 "   using the first line of a block.
103 "   Thanks to Xiangjiang Ma and John Orr for the rich feedback on these
104 "   issues.
105 "   Decomments /*foo();*/, when PrettyComments is set.
106 "   Added 'vhdl' and 'verilog'. (thanks to Steve Butts) 
107 "   1.7
108 "   Added different options to control behaviour of the plugin. 
109 "   Changed default Keybindings to proper plugin settings.
110 "   1.6
111 "   Now supports 'm4', 'config', 'automake'
112 "   'vb', 'aspvbs', 'plsql' (thanks to Zak Beck)
113 "   1.5
114 "   Now supports 'java', 'xml', 'jproperties'. (thanks to Scott Stirling)
115 "   1.4
116 "   Lines containing only whitespace are now considered empty.
117 "   Added Tcl support.
118 "   Multipart comments are now escaped with configurable alternative
119 "   strings. Prevents nesting errors (eg. /**/*/ in C)
120 "   1.3
121 "   Doesn't break lines like
122 "       foo(); /* bar */
123 "   when doing commentify.
125 " Install Details:
126 " Simply drop this file into your $HOME/.vim/plugin directory.
128 if exists("DidEnhancedCommentify")
129     finish
130 endif
131 let DidEnhancedCommentify = 1
133 let s:savedCpo = &cpo
134 set cpo-=C
136 " Note: These must be defined here, since they are used during
137 "       initialisation.
139 " InitBooleanVariable(confVar, scriptVar, defaultVal)
140 "       confVar         -- name of the configuration variable
141 "       scriptVar       -- name of the variable to set
142 "       defaultVal      -- default value
144 " Tests on existence of configuration variable and sets scriptVar
145 " according to its contents.
147 function s:InitBooleanVariable(confVar, scriptVar, defaultVal)
148     let regex = a:defaultVal ? 'no*' : 'ye*s*'
150     if exists(a:confVar) && {a:confVar} =~? regex
151         let {a:scriptVar} = !a:defaultVal
152     else
153         let {a:scriptVar} = a:defaultVal
154     endif
155 endfunction
156     
158 " InitStringVariable(confVar, scriptVar, defaultVal)
159 "       confVar         -- name of the configuration variable
160 "       scriptVar       -- name of the variable to set
161 "       defaultVal      -- default value
163 " Tests on existence of configuration variable and sets scriptVar
164 " to its contents.
166 function s:InitStringVariable(confVar, scriptVar, defaultVal)
167     if exists(a:confVar)
168         execute "let ". a:scriptVar ." = ". a:confVar
169     else
170         let {a:scriptVar} = a:defaultVal
171     endif
172 endfunction
175 " InitScriptVariables(nameSpace)
176 "       nameSpace       -- may be "g" for global or "b" for local
178 " Initialises the script variables.
180 function s:InitScriptVariables(nameSpace)
181     let ns = a:nameSpace        " just for abbreviation
182     let lns = (ns == "g") ? "s" : "b" " 'local namespace'
184     " Comment escape strings...
185     call s:InitStringVariable(ns .":EnhCommentifyAltOpen", lns .":ECaltOpen",
186                 \ s:ECaltOpen)
187     call s:InitStringVariable(ns .":EnhCommentifyAltClose", lns .":ECaltClose",
188                 \ s:ECaltClose)
190     call s:InitBooleanVariable(ns .":EnhCommentifyIgnoreWS", lns .":ECignoreWS",
191                 \ s:ECignoreWS)
193     " Adding a space between comment strings and code...
194     if exists(ns .":EnhCommentifyPretty")
195         if {ns}:EnhCommentifyPretty =~? 'ye*s*'
196             let {lns}:ECprettyComments = ' '
197             let {lns}:ECprettyUnComments = ' \='
198         else
199             let {lns}:ECprettyComments = ''
200             let {lns}:ECprettyUnComments = ''
201         endif
202     else
203         let {lns}:ECprettyComments = s:ECprettyComments
204         let {lns}:ECprettyUnComments = s:ECprettyUnComments
205     endif
207     " Identification string settings...
208     call s:InitStringVariable(ns .":EnhCommentifyIdentString",
209                 \ lns .":ECidentFront", s:ECidentFront)
210     let {lns}:ECidentBack =
211                 \ (exists(ns .":EnhCommentifyIdentFrontOnly")
212                 \           && {ns}:EnhCommentifyIdentFrontOnly =~? 'ye*s*')
213                 \ ? ''
214                 \ : {lns}:ECidentFront
216     " Wether to use syntax items...
217     call s:InitBooleanVariable(ns .":EnhCommentifyUseSyntax",
218                 \ lns .":ECuseSyntax", s:ECuseSyntax)
220     " Should the script respect line indentation, when inserting strings?
221     call s:InitBooleanVariable(ns .":EnhCommentifyRespectIndent",
222                 \ lns .":ECrespectIndent", s:ECrespectIndent)
224     " Keybindings...
225     call s:InitBooleanVariable(ns .":EnhCommentifyUseAltKeys",
226                 \ lns .":ECuseAltKeys", s:ECuseAltKeys)
227     call s:InitBooleanVariable(ns .":EnhCommentifyBindPerBuffer",
228                 \ lns .":ECbindPerBuffer", s:ECbindPerBuffer)
229     call s:InitBooleanVariable(ns .":EnhCommentifyBindInNormal",
230                 \ lns .":ECbindInNormal", s:ECbindInNormal)
231     call s:InitBooleanVariable(ns .":EnhCommentifyBindInInsert",
232                 \ lns .":ECbindInInsert", s:ECbindInInsert)
233     call s:InitBooleanVariable(ns .":EnhCommentifyBindInVisual",
234                 \ lns .":ECbindInVisual", s:ECbindInVisual)
235     call s:InitBooleanVariable(ns .":EnhCommentifyUserBindings",
236                 \ lns .":ECuserBindings", s:ECuserBindings)
237     call s:InitBooleanVariable(ns .":EnhCommentifyTraditionalMode",
238                 \ lns .":ECtraditionalMode", s:ECtraditionalMode)
239     call s:InitBooleanVariable(ns .":EnhCommentifyFirstLineMode",
240                 \ lns .":ECfirstLineMode", s:ECfirstLineMode)
241     call s:InitBooleanVariable(ns .":EnhCommentifyUserMode",
242                 \ lns .":ECuserMode", s:ECuserMode)
243     call s:InitBooleanVariable(ns .":EnhCommentifyBindUnknown",
244                 \ lns .":ECbindUnknown", s:ECbindUnknown)
246     " Block stuff...
247     call s:InitBooleanVariable(ns .":EnhCommentifyAlignRight",
248                 \ lns .":ECalignRight", s:ECalignRight)
249     call s:InitBooleanVariable(ns .":EnhCommentifyUseBlockIndent",
250                 \ lns .":ECuseBlockIndent", s:ECuseBlockIndent)
251     call s:InitBooleanVariable(ns .":EnhCommentifyMultiPartBlocks",
252                 \ lns .":ECuseMPBlock", s:ECuseMPBlock)
253     call s:InitBooleanVariable(ns .":EnhCommentifyCommentsOp",
254                 \ lns .":ECuseCommentsOp", s:ECuseCommentsOp)
256     let {lns}:ECsaveWhite = ({lns}:ECrespectIndent
257                 \ || {lns}:ECignoreWS || {lns}:ECuseBlockIndent)
258                 \       ? '\(\s*\)'
259                 \       : ''
261     if !{lns}:ECrespectIndent
262         let {lns}:ECuseBlockIndent = 0
263     endif
265     if {lns}:ECrespectIndent
266         let {lns}:ECrespectWhite = '\1'
267         let {lns}:ECignoreWhite = ''
268     elseif {lns}:ECignoreWS
269         let {lns}:ECrespectWhite = ''
270         let {lns}:ECignoreWhite = '\1'
271     else
272         let {lns}:ECrespectWhite = ''
273         let {lns}:ECignoreWhite = ''
274     endif
276     " Using comments option, doesn't make sense without useMPBlock
277     "if lns == 'b' && b:ECuseCommentsOp
278     "       let b:ECuseMPBlock = 1
279     "endif
280 endfunction
283 " EnhancedCommentifySet(option, value, ...)
284 "       option  -- which option
285 "       value   -- value which will be asigned to the option
287 " The purpose of this function is mainly to act as an interface to the
288 " outer world. It hides the internally used variables.
290 function EnhancedCommentifySet(option, value)
291     if a:option == 'AltOpen'
292         let oldval = b:ECaltOpen
293         let b:ECaltOpen = a:value
294     elseif a:option == 'AltClose'
295         let oldval = b:ECaltClose
296         let b:ECaltClose = a:value
297     elseif a:option == 'IdentString'
298         let oldval = b:ECidentFront
299         let b:ECidentFront = a:value
300     elseif a:option == 'IdentFrontOnly'
301         let oldval = (b:ECidentBack == '') ? 'Yes' : 'No'
302         let b:ECidentBack = (a:value =~? 'ye*s*') ? '' : b:ECidentFront
303     elseif a:option == 'RespectIndent'
304         let oldval = b:ECrespectIndent
305         let b:ECrespectIndent = (a:value =~? 'ye*s*') ? 1 : 0
306     elseif a:option == 'IgnoreWS'
307         let oldval = b:ECignoreWS
308         let b:ECignoreWS = (a:value =~? 'ye*s*') ? 1 : 0
309     elseif a:option == 'Pretty'
310         let oldval = (b:ECprettyComments == ' ') ? 'Yes' : 'No'
311         if a:value =~? 'ye*s*'
312             let b:ECprettyComments = ' '
313             let b:ECprettyUnComments = ' \='
314         else
315             let b:ECprettyComments = ''
316             let b:ECprettyUnComments = ''
317         endif
318     elseif a:option == 'MultiPartBlocks'
319         let oldval = b:ECuseMPBlock
320         let b:ECuseMPBlock = (a:value =~? 'ye*s*') ? 1 : 0
321     elseif a:option == 'CommentsOp'
322         let oldval = b:ECuseCommentsOp
323         let b:ECuseCommentsOp = (a:value =~? 'ye*s*') ? 1 : 0
324     elseif a:option == 'UseBlockIndent'
325         let oldval = b:ECuseBlockIndent
326         let b:ECuseBlockIndent = (a:value =~? 'ye*s*') ? 1 : 0
327     elseif a:option == 'AlignRight'
328         let oldval = b:ECalignRight
329         let b:ECalignRight = (a:value =~? 'ye*s*') ? 1 : 0
330     elseif a:option == 'UseSyntax'
331         let oldval = b:ECuseSyntax
332         let b:ECuseSyntax = (a:value =~? 'ye*s*') ? 1 : 0
333     else
334         if (has("dialog_gui") && has("gui_running"))
335             call confirm("EnhancedCommentifySet: Unknwon option '"
336                         \ . option . "'")
337         else
338             echohl ErrorMsg
339             echo "EnhancedCommentifySet: Unknown option '". option ."'"
340             echohl None
341         endif
342     endif
344     if oldval == 1
345         let oldval = 'Yes'
346     elseif oldval == 0
347         let oldval = 'No'
348     endif
350     return oldval
351 endfunction
353 " Initial settings.
355 " Setting the default options resp. taking user preferences.
356 if !exists("g:EnhCommentifyUserMode")
357             \ && !exists("g:EnhCommentifyFirstLineMode")
358             \ && !exists("g:EnhCommentifyTraditionalMode")
359             \ && !exists("g:EnhCommentifyUserBindings")
360     let g:EnhCommentifyTraditionalMode = 'Yes'
361 endif
363 " These will be the default settings for the script:
364 let s:ECaltOpen = "|+"
365 let s:ECaltClose = "+|"
366 let s:ECignoreWS = 1
367 let s:ECprettyComments = ''
368 let s:ECprettyUnComments = ''
369 let s:ECidentFront = ''
370 let s:ECuseSyntax = 0
371 let s:ECrespectIndent = 0
372 let s:ECalignRight = 0
373 let s:ECuseBlockIndent = 0
374 let s:ECuseMPBlock = 0
375 let s:ECuseCommentsOp = 0
376 let s:ECuseAltKeys = 0
377 let s:ECbindPerBuffer = 0
378 let s:ECbindInNormal = 1
379 let s:ECbindInInsert = 1
380 let s:ECbindInVisual = 1
381 let s:ECuserBindings = 0
382 let s:ECtraditionalMode = 0
383 let s:ECfirstLineMode = 0
384 let s:ECuserMode = 1
385 let s:ECbindUnknown = 1
387 " Now initialise the global defaults with the preferences set
388 " by the user in his .vimrc. Settings local to a buffer will be
389 " done later on, when the script is first called in a buffer.
391 call s:InitScriptVariables("g")
393 " Globally used variables with some initialisation.
394 " FIXME: explain what they are good for
396 let s:Action = 'guess'
397 let s:firstOfBlock = 1
398 let s:blockAction = 'comment'
399 let s:blockIndentRegex = ''
400 let s:blockIndent = 0
401 let s:inBlock = 0
402 let s:tabConvert = ''
403 let s:overrideEmptyLines = 0
404 let s:emptyLines = 'no'
405 let s:maxLen = 0
407 function EnhancedCommentifyInitBuffer()
408     if !exists("b:ECdidBufferInit")
409         call s:InitScriptVariables("b")
410         
411         if !exists("b:EnhCommentifyFallbackTest")
412             let b:EnhCommentifyFallbackTest = 0
413         endif
415         call s:GetFileTypeSettings(&ft)
416         call s:CheckPossibleEmbedding(&ft)
418         "
419         " If the filetype is not supported and the user wants us to, we do not
420         " add keybindings.
421         "
422         if s:ECbindPerBuffer
423             if b:ECcommentOpen != "" || b:ECbindUnknown
424                 call s:SetKeybindings("l")
425             endif
426         endif
428         let b:ECdidBufferInit = 1
429         let b:ECsyntax = &ft
430     endif
431 endfunction
433 autocmd BufWinEnter,BufNewFile  *       call EnhancedCommentifyInitBuffer()
436 " EnhancedCommentify(emptyLines, action, ...)
437 "       overrideEL      -- commentify empty lines
438 "                          may be 'yes', 'no' or '' for guessing
439 "       action          -- action which should be executed:
440 "                           * guess:
441 "                             toggle commetification (old behaviour)
442 "                           * comment:
443 "                             comment lines
444 "                           * decomment:
445 "                             decomment lines
446 "                           * first:
447 "                             use first line of block to determine action 
448 "       a:1, a:2        -- first and last line of block, which should be
449 "                          processed. 
451 " Commentifies the current line.
453 function EnhancedCommentify(overrideEL, action, ...)
454     if a:overrideEL != ''
455         let s:overrideEmptyLines = 1
456     endif
458     " Now do the buffer initialisation. Every buffer will get
459     " it's pendant to a global variable (eg. s:ECalignRight -> b:ECalignRight).
460     " The local variable is actually used, whereas the global variable
461     " holds the defaults from the user's .vimrc. In this way the settings
462     " can be overriden for single buffers.
463     " 
464     " NOTE: Buffer init is done by autocommands now.
465     "
467     let b:ECemptyLines = a:overrideEL
469     " The language is not supported.
470     if b:ECcommentOpen == ''
471         if (has("dialog_gui") && has("gui_running"))
472             call confirm("This filetype is currently _not_ supported!\n"
473                         \ ."Please consider contacting the author in order"
474                         \ ." to add this filetype.", "", 1, "Error")
475         else
476             echohl ErrorMsg
477             echo "This filetype is currently _not_ supported!"
478             echo "Please consider contacting the author in order to add"
479             echo "this filetype in future releases!"
480             echohl None
481         endif
482         return
483     endif
485     let lnum = line(".")
487     " Now some initialisations...
488     let s:Action = a:action
490     " FIXME: Is there really _no_ function to simplify this???
491     " (Maybe something like 'let foo = 8x" "'?) 
492     if s:tabConvert == '' && strlen(s:tabConvert) != &tabstop
493         let s:tabConvert = ''
494         let i = 0
495         while i < &tabstop
496             let s:tabConvert = s:tabConvert .' '
497             let i = i + 1
498         endwhile
499     endif
501     if a:0 == 2
502         let s:startBlock = a:1
503         let s:i = a:1
504         let s:endBlock = a:2
506         let s:inBlock = 1
507     else
508         let s:startBlock = lnum
509         let s:i = lnum
510         let s:endBlock = lnum
512         let s:inBlock = 0
513     endif
515     if b:ECuseSyntax && b:ECpossibleEmbedding
516         let column = indent(s:startBlock) + 1
517         if !&expandtab
518                 let rem = column % &tabstop
519                 let column = ((column - rem) / &tabstop) + rem
520         endif
521         call s:CheckSyntax(s:startBlock, column)
522     endif
524     " Get the indent of the less indented line of the block.
525     if s:inBlock && (b:ECuseBlockIndent || b:ECalignRight)
526         call s:DoBlockComputations(s:startBlock, s:endBlock)
527     endif
529     while s:i <= s:endBlock
530         let lineString = getline(s:i)
531         let lineString = s:TabsToSpaces(lineString) 
533         " If we should comment "empty" lines, we have to add
534         " the correct indent, if we use blockIndent.
535         if b:ECemptyLines =~? 'ye*s*'
536                         \ && b:ECuseBlockIndent
537                         \ && lineString =~ "^\s*$"
538             let i = 0
539             while i < s:blockIndent
540                 let lineString = " " . lineString
541                 let i = i + 1
542             endwhile
543         endif
545         " Don't comment empty lines.
546         if lineString !~ "^\s*$"
547                     \ || b:ECemptyLines =~? 'ye*s*'
548             if b:ECcommentClose != ''
549                 let lineString = s:CommentifyMultiPart(lineString,
550                             \ b:ECcommentOpen,
551                             \ b:ECcommentClose,
552                             \ b:ECcommentMiddle)
553             else
554                 let lineString = s:CommentifySinglePart(lineString,
555                             \ b:ECcommentOpen)
556             endif
557         endif
559         " Revert the above: If the line is "empty" and we
560         " used blockIndent, we remove the spaces.
561         " FIXME: Why does "^\s*$" not work? 
562         if b:ECemptyLines =~? 'ye*s*'
563                     \ && b:ECuseBlockIndent
564                     \ && lineString =~ "^" . s:blockIndentRegex ."\s*$"
565             let lineString =
566                         \ substitute(lineString, s:blockIndentRegex,
567                         \     '', '')
568         endif
570         let lineString = s:SpacesToTabs(lineString)
571         call setline(s:i, lineString)
573         let s:i = s:i + 1
574         let s:firstOfBlock = 0
575     endwhile
577     let s:firstOfBlock = 1
578 endfunction
581 " DoBlockComputations(start, end)
582 "           start       -- number of first line
583 "           end         -- number of last line
585 " This function does some computations which are necessary for useBlockIndent
586 " and alignRight. ie. find smallest indent and longest line.
588 function s:DoBlockComputations(start, end)
589     let i = a:start
590     let len = 0
591     let amount = 100000     " this should be enough ...
592     
593     while i <= a:end
594         if b:ECuseBlockIndent && getline(i) !~ '^\s*$'
595             let cur = indent(i)
596             if cur < amount
597                 let amount = cur
598             endif
599         endif
601         if b:ECalignRight
602             let cur = s:GetLineLen(s:TabsToSpaces(getline(i)),
603                         \ s:GetLineLen(b:ECcommentOpen, 0)
604                         \ + strlen(b:ECprettyComments))
605             if b:ECuseMPBlock
606                 let cur = cur + s:GetLineLen(b:ECcommentOpen, 0)
607                             \ + strlen(b:ECprettyComments)
608             endif
610             if len < cur
611                 let len = cur
612             endif
613         endif
614         
615         let i = i + 1
616     endwhile
618     if b:ECuseBlockIndent
619         if amount > 0
620             let regex = '\( \{'. amount .'}\)'
621         else
622             let regex = ''
623         endif
624         let s:blockIndentRegex = regex
625         let s:blockIndent = amount
626     endif
628     if b:ECalignRight
629         let s:maxLen = len
630     endif
631 endfunction
634 " CheckSyntax(line, column)
635 "       line        -- line of line
636 "       column      -- column of line
637 " Check what syntax is active during call of main function. First hit
638 " wins. If the filetype changes during the block, we ignore that.
639 " Adjust the filetype if necessary.
641 function s:CheckSyntax(line, column)
642     let ft = ""
643     let synFiletype = synIDattr(synID(a:line, a:column, 1), "name")
645     " FIXME: This feature currently relies on a certain format
646     " of the names of syntax items: the filetype must be prepended
647     " in lowwer case letters, followed by at least one upper case
648     " letter.
649     if match(synFiletype, '\l\+\u') == 0
650         let ft = substitute(synFiletype, '^\(\l\+\)\u.*$', '\1', "")
651     endif
653     if ft == ""
654         execute "let specialCase = ". b:EnhCommentifyFallbackTest
656         if specialCase
657             let ft = b:EnhCommentifyFallbackValue
658         else
659             " Fallback: If nothing holds, use normal filetype!
660             let ft = &ft
661         endif
662     endif
663     
664     " Nothing changed!
665     if ft == b:ECsyntax
666         return
667     endif
669     let b:ECsyntax = ft
670     call s:GetFileTypeSettings(ft)
671 endfunction
674 " GetFileTypeSettings(ft)
675 "       ft          -- filetype
677 " This functions sets some buffer-variables, which control the comment
678 " strings and 'empty lines'-handling.
680 function s:GetFileTypeSettings(ft)
681     let fileType = a:ft
683     " I learned about the commentstring option. Let's use it.
684     " For now we ignore it, if it is "/*%s*/". This is the
685     " default. We cannot check wether this is default or C or
686     " something other like CSS, etc. We have to wait, until the
687     " filetypes adopt this option.
688     if &commentstring != "/*%s*/" && !b:ECuseSyntax
689         let b:ECcommentOpen =
690                     \ substitute(&commentstring, '%s.*', "", "")
691         let b:ECcommentClose =
692                     \ substitute(&commentstring, '.*%s', "", "")
693     " Multipart comments:
694     elseif fileType =~ '^\(c\|b\|css\|csc\|cupl\|indent\|jam\|lex\|lifelines\|'.
695                 \ 'lite\|nqc\|phtml\|progress\|rexx\|rpl\|sas\|sdl\|sl\|'.
696                 \ 'strace\|xpm\|yacc\)$'
697         let b:ECcommentOpen = '/*'
698         let b:ECcommentClose = '*/'
699     elseif fileType =~ '^\(html\|xml\|dtd\|sgmllnx\)$'
700         let b:ECcommentOpen = '<!--'
701         let b:ECcommentClose = '-->'
702     elseif fileType =~ '^\(sgml\|smil\)$'
703         let b:ECcommentOpen = '<!'
704         let b:ECcommentClose = '>'
705     elseif fileType == 'atlas'
706         let b:ECcommentOpen = 'C'
707         let b:ECcommentClose = '$'
708     elseif fileType =~ '^\(catalog\|sgmldecl\)$'
709         let b:ECcommentOpen = '--'
710         let b:ECcommentClose = '--'
711     elseif fileType == 'dtml'
712         let b:ECcommentOpen = '<dtml-comment>'
713         let b:ECcommentClose = '</dtml-comment>'
714     elseif fileType == 'htmlos'
715         let b:ECcommentOpen = '#'
716         let b:ECcommentClose = '/#'
717     elseif fileType =~ '^\(jgraph\|lotos\|mma\|modula2\|modula3\|pascal\|'.
718                 \ 'ocaml\|sml\)$'
719         let b:ECcommentOpen = '(*'
720         let b:ECcommentClose = '*)'
721     elseif fileType == 'jsp'
722         let b:ECcommentOpen = '<%--'
723         let b:ECcommentClose = '--%>'
724     elseif fileType == 'model'
725         let b:ECcommentOpen = '$'
726         let b:ECcommentClose = '$'
727     elseif fileType == 'st'
728         let b:ECcommentOpen = '"'
729         let b:ECcommentClose = '"'
730     elseif fileType =~ '^\(tssgm\|tssop\)$'
731         let b:ECcommentOpen = 'comment = "'
732         let b:ECcommentClose = '"'
733     " Singlepart comments:
734     elseif fileType =~ '^\(ox\|cpp\|php\|java\|verilog\|acedb\|ch\|clean\|'.
735                 \ 'clipper\|cs\|dot\|dylan\|hercules\|idl\|ishd\|javascript\|'.
736                 \ 'kscript\|mel\|named\|openroad\|pccts\|pfmain\|pike\|'.
737                 \ 'pilrc\|plm\|pov\|rc\|scilab\|specman\|tads\|tsalt\|uc\|'.
738                 \ 'xkb\)$'
739         let b:ECcommentOpen = '//'
740         let b:ECcommentClose = ''
741     elseif fileType =~ '^\(vim\|abel\)$'
742         let b:ECcommentOpen = '"'
743         let b:ECcommentClose = ''
744     elseif fileType =~ '^\(lisp\|scheme\|scsh\|amiga\|asm\|asm68k\|bindzone\|'.
745                 \ 'def\|dns\|dosini\|dracula\|dsl\|idlang\|iss\|jess\|kix\|'.
746                 \ 'masm\|monk\|nasm\|ncf\|omnimark\|pic\|povini\|rebol\|'.
747                 \ 'registry\|samba\|skill\|smith\|tags\|tasm\|tf\|winbatch\|'.
748                 \ 'wvdial\|z8a\)$'
749         let b:ECcommentOpen = ';'
750         let b:ECcommentClose = ''
751     elseif fileType =~ '^\(python\|perl\|[^w]*sh$\|tcl\|jproperties\|make\|'.
752                 \ 'robots\|apacha\|apachestyle\|awk\|bc\|cfg\|cl\|conf\|'.
753                 \ 'crontab\|diff\|ecd\|elmfilt\|eterm\|expect\|exports\|'.
754                 \ 'fgl\|fvwm\|gdb\|gnuplot\|gtkrc\|hb\|hog\|ia64\|icon\|'.
755                 \ 'inittab\|lftp\|lilo\|lout\|lss\|lynx\|maple\|mush\|'.
756                 \ 'muttrc\|nsis\|ora\|pcap\|pine\|po\|procmail\|'.
757                 \ 'psf\|ptcap\|r\|radiance\|ratpoison\|readline\remind\|'.
758                 \ 'ruby\|screen\|sed\|sm\|snnsnet\|snnspat\|snnsres\|spec\|'.
759                 \ 'squid\|terminfo\|tidy\|tli\|tsscl\|vgrindefs\|vrml\|'.
760                 \ 'wget\|wml\|xf86conf\|xmath\)$'
761         let b:ECcommentOpen = '#'
762         let b:ECcommentClose = ''
763     elseif fileType == 'webmacro'
764         let b:ECcommentOpen = '##'
765         let b:ECcommentClose = ''
766     elseif fileType == 'ppwiz'
767         let b:ECcommentOpen = ';;'
768         let b:ECcommentClose = ''
769     elseif fileType == 'latte'
770         let b:ECcommentOpen = '\\;'
771         let b:ECcommentClose = ''
772     elseif fileType =~ '^\(tex\|abc\|erlang\|ist\|lprolog\|matlab\|mf\|'.
773                 \ 'postscr\|ppd\|prolog\|simula\|slang\|slrnrc\|slrnsc\|'.
774                 \ 'texmf\|virata\)$'
775         let b:ECcommentOpen = '%'
776         let b:ECcommentClose = ''
777     elseif fileType =~ '^\(caos\|cterm\|form\|foxpro\|sicad\|snobol4\)$'
778         let b:ECcommentOpen = '*'
779         let b:ECcommentClose = ''
780     elseif fileType =~ '^\(m4\|config\|automake\)$'
781         let b:ECcommentOpen = 'dnl '
782         let b:ECcommentClose = ''
783     elseif fileType =~ '^\(vb\|aspvbs\|ave\|basic\|elf\|lscript\)$'
784         let b:ECcommentOpen = "'"
785         let b:ECcommentClose = ''
786     elseif fileType =~ '^\(plsql\|vhdl\|ahdl\|ada\|asn\|csp\|eiffel\|gdmo\|'.
787                 \ 'haskell\|lace\|lua\|mib\|sather\|sql\|sqlforms\|sqlj\|'.
788                 \ 'stp\)$'
789         let b:ECcommentOpen = '--'
790         let b:ECcommentClose = ''
791     elseif fileType == 'abaqus'
792         let b:ECcommentOpen = '**'
793         let b:ECcommentClose = ''
794     elseif fileType =~ '^\(aml\|natural\|vsejcl\)$'
795         let b:ECcommentOpen = '/*'
796         let b:ECcommentClose = ''
797     elseif fileType == 'ampl'
798         let b:ECcommentOpen = '\\#'
799         let b:ECcommentClose = ''
800     elseif fileType == 'bdf'
801         let b:ECcommentOpen = 'COMMENT '
802         let b:ECcommentClose = ''
803     elseif fileType == 'btm'
804         let b:ECcommentOpen = '::'
805         let b:ECcommentClose = ''
806     elseif fileType == 'dcl'
807         let b:ECcommentOpen = '$!'
808         let b:ECcommentClose = ''
809     elseif fileType == 'dosbatch'
810         let b:ECcommentOpen = 'rem '
811         let b:ECcommentClose = ''
812     elseif fileType == 'focexec'
813         let b:ECcommentOpen = '-*'
814         let b:ECcommentClose = ''
815     elseif fileType == 'forth'
816         let b:ECcommentOpen = '\\ '
817         let b:ECcommentClose = ''
818     elseif fileType =~ '^\(fortran\|inform\|sqr\|uil\|xdefaults\|'.
819                 \ 'xmodmap\|xpm2\)$'
820         let b:ECcommentOpen = '!'
821         let b:ECcommentClose = ''
822     elseif fileType == 'gp'
823         let b:ECcommentOpen = '\\\\'
824         let b:ECcommentClose = ''
825     elseif fileType =~ '^\(master\|nastran\|sinda\|spice\|tak\|trasys\)$'
826         let b:ECcommentOpen = '$'
827         let b:ECcommentClose = ''
828     elseif fileType == 'nroff' || fileType == 'groff'
829         let b:ECcommentOpen = ".\\\\\""
830         let b:ECcommentClose = ''
831     elseif fileType == 'opl'
832         let b:ECcommentOpen = 'REM '
833         let b:ECcommentClose = ''
834     elseif fileType == 'texinfo'
835         let b:ECcommentOpen = '@c '
836         let b:ECcommentClose = ''
837     else 
838         let b:ECcommentOpen = ''
839         let b:ECcommentClose = ''
840     endif
842     if b:ECuseCommentsOp
843         let b:ECcommentMiddle =
844                     \ s:ParseCommentsOp(b:ECcommentOpen, b:ECcommentClose)
845         if b:ECcommentMiddle == ''
846             let b:ECuseCommentsOp = 0
847         endif
848     else
849         let b:ECcommentMiddle = ''
850     endif
852     if !s:overrideEmptyLines
853         call s:CommentEmptyLines(fileType)
854     endif
855 endfunction
858 " ParseCommentsOp(commentOpen, commentClose)
859 "       commentOpen -- comment-open string
860 "       commentClose-- comment-close string
862 " Try to extract the middle comment string from &comments. First hit wins.
863 " If nothing is found '' is returned.
865 function s:ParseCommentsOp(commentOpen, commentClose)
866     let commStr = &comments
867     let offset = 0
868     let commentMiddle = ''
870     while commStr != ''
871         "
872         " First decompose &omments into consecutive s-, m- and e-parts.
873         "
874         let s = stridx(commStr, 's')
875         if s == -1
876             return ''
877         endif
879         let commStr = strpart(commStr, s)
880         let comma = stridx(commStr, ',')
881         if comma == -1
882             return ''
883         endif
884         let sPart = strpart(commStr, 0, comma)
886         let commStr = strpart(commStr, comma)
887         let m = stridx(commStr, 'm')
888         if m == -1
889             return ''
890         endif
892         let commStr = strpart(commStr, m)
893         let comma = stridx(commStr, ',')
894         if comma == -1
895             return ''
896         endif
897         let mPart = strpart(commStr, 0, comma)
899         let commStr = strpart(commStr, comma)
900         let e = stridx(commStr, 'e')
901         if e == -1
902             return ''
903         endif
905         let commStr = strpart(commStr, e)
906         let comma = stridx(commStr, ',')
907         if comma == -1
908             let comma = strlen(commStr)
909         endif
910         let ePart = strpart(commStr, 0, comma)
912         let commStr = strpart(commStr, comma)
914         "
915         " Now check wether this is what we want:
916         " Are the comment string the same?
917         "
918         let sColon = stridx(sPart, ':')
919         let eColon = stridx(ePart, ':')
920         if sColon == -1 || eColon == -1
921             return ''
922         endif
923         if strpart(sPart, sColon + 1) != a:commentOpen
924                     \ || strpart(ePart, eColon + 1) != a:commentClose
925             continue
926         endif
928         let mColon = stridx(mPart, ':')
929         if mColon == -1
930             return ''
931         endif
932         let commentMiddle = strpart(mPart, mColon + 1)
934         "
935         " Check for any alignement.
936         "
937         let i = 1
938         while sPart[i] != ':'
939             if sPart[i] == 'r'
940                 let offset = strlen(a:commentOpen) - strlen(commentMiddle)
941                 break
942             elseif sPart[i] == 'l'
943                 let offset = 0
944                 break
945             elseif s:isDigit(sPart[i])
946                 let j = 1
947                 while s:isDigit(sPart[i + j])
948                     let j = j + 1
949                 endwhile
950                 let offset = 1 * strpart(sPart, i, j)
951                 break
952             endif
953             let i = i + 1
954         endwhile
956         if offset == 0
957             let i = 1
958             while ePart[i] != ':'
959                 if ePart[i] == 'r'
960                     let offset = strlen(a:commentClose) - strlen(commentMiddle)
961                     break
962                 elseif ePart[i] == 'l'
963                     let offset = 0
964                     break
965                 elseif s:isDigit(ePart[i])
966                     let j = 1
967                     while s:isDigit(ePart[i + j])
968                         let j = j + 1
969                     endwhile
970                     let offset = 1 * strpart(ePart, i, j)
971                     break
972                 endif
974                 let i = i + 1
975             endwhile
976         endif
978         while offset > 0
979             let commentMiddle = " " . commentMiddle
980             let offset = offset - 1
981         endwhile
983         break
984     endwhile
986     return commentMiddle
987 endfunction
990 " isDigit(char)
992 " Nomen est Omen.
994 function s:isDigit(char)
995     let r = 0
997     let charVal = char2nr(a:char)
999     if charVal >= 48 && charVal <= 57
1000         let r = 1
1001     endif
1003     return r
1004 endfunction
1007 " CommentEmptyLines(ft)
1008 "       ft          -- filetype of current buffer
1010 " Decides, if empty lines should be commentified or not. Add the filetype,
1011 " you want to change, to the apropriate if-clause.
1013 function s:CommentEmptyLines(ft)
1014     " FIXME: Quick hack (tm)!
1015     if 0
1016         " Add special filetypes here.
1017     elseif b:ECcommentClose == ''
1018         let b:ECemptyLines = 'yes'
1019     else
1020         let b:ECemptyLines = 'no'
1021     endif
1022 endfunction
1025 " CheckPossibleEmbedding(ft)
1026 "       ft      -- the filetype of current buffer
1028 " Check wether it makes sense to allow checking for the synIDs.
1029 " Eg. C will never have embedded code...
1031 function s:CheckPossibleEmbedding(ft)
1032     if a:ft =~ '^\(php\|vim\|latte\|html\)$'
1033         let b:ECpossibleEmbedding = 1
1034     else
1035         " Since getting the synID is slow, we set the default to 'no'!
1036         " There are also some 'broken' languages like the filetype for
1037         " autoconf's configure.in's ('config'). 
1038         let b:ECpossibleEmbedding = 0
1039     endif
1040 endfunction
1043 " CommentifyMultiPart(lineString, commentStart, commentEnd, action)
1044 "       lineString      -- line to commentify
1045 "       commentStart    -- comment-start string, eg '/*'
1046 "       commentEnd      -- comment-end string, eg. '*/'
1047 "       commentMiddle   -- comment-middle string, eg. ' *'      
1049 " This function commentifies code of languages, which have multipart
1050 " comment strings, eg. '/*' - '*/' of C.
1052 function s:CommentifyMultiPart(lineString, commentStart,
1053             \ commentEnd, commentMiddle)
1054     if s:Action == 'guess' || s:Action == 'first' || b:ECuseMPBlock
1055         let todo = s:DecideWhatToDo(a:lineString, a:commentStart, a:commentEnd)
1056     else
1057         let todo = s:Action
1058     endif
1060     if todo == 'decomment'
1061         return s:UnCommentify(a:lineString, a:commentStart,
1062                     \ a:commentEnd, a:commentMiddle)
1063     else
1064         return s:Commentify(a:lineString, a:commentStart,
1065                     \ a:commentEnd, a:commentMiddle)
1066     endif
1067 endfunction
1070 " CommentifySinglePart(lineString, commentSymbol)
1071 "       lineString      -- line to commentify
1072 "       commentSymbol   -- comment string, eg '#'
1074 " This function is used for all languages, whose comment strings
1075 " consist only of one string at the beginning of a line.
1077 function s:CommentifySinglePart(lineString, commentSymbol)
1078     if s:Action == 'guess' || s:Action == 'first'
1079         let todo = s:DecideWhatToDo(a:lineString, a:commentSymbol)
1080     else
1081         let todo = s:Action
1082     endif
1084     if todo == 'decomment'
1085         return s:UnCommentify(a:lineString, a:commentSymbol)
1086     else
1087         return s:Commentify(a:lineString, a:commentSymbol)
1088     endif
1089 endfunction
1092 " Escape(lineString, commentStart, commentEnd)
1094 " Escape already present symbols.
1096 function s:Escape(lineString, commentStart, commentEnd)
1097     let line = a:lineString
1099     if b:ECaltOpen != ''
1100         let line = substitute(line, s:EscapeString(a:commentStart),
1101                     \ b:ECaltOpen, "g")
1102     endif
1103     if b:ECaltClose != ''
1104         let line = substitute(line, s:EscapeString(a:commentEnd),
1105                     \ b:ECaltClose, "g")
1106     endif
1108     return line
1109 endfunction
1112 " UnEscape(lineString, commentStart, commentEnd)
1114 " Unescape already present escape symbols.
1116 function s:UnEscape(lineString, commentStart, commentEnd)
1117     let line = a:lineString
1119     if b:ECaltOpen != ''
1120         let line = substitute(line, s:EscapeString(b:ECaltOpen),
1121                     \ a:commentStart, "g")
1122     endif
1123     if b:ECaltClose != ''
1124         let line = substitute(line, s:EscapeString(b:ECaltClose),
1125                     \ a:commentEnd, "g")
1126     endif
1128     return line
1129 endfunction
1132 " Commentify(lineString, commentSymbol, [commentEnd])
1133 "       lineString      -- the line in work
1134 "       commentSymbol   -- string to insert at the beginning of the line
1135 "       commentEnd      -- string to insert at the end of the line
1136 "                          may be omitted
1138 " This function inserts the start- (and if given the end-) string of the
1139 " comment in the current line.
1141 function s:Commentify(lineString, commentSymbol, ...)
1142     let line = a:lineString
1143     let j = 0
1145     " If a end string is present, insert it too.
1146     if a:0 > 0
1147         " First we have to escape any comment already contained in the line,
1148         " since (at least for C) comments are not allowed to nest.
1149         let line = s:Escape(line, a:commentSymbol, a:1)
1151         if b:ECuseCommentsOp && b:ECuseMPBlock
1152                     \ && a:0 > 1
1153                     \ && s:i > s:startBlock
1154             let line = substitute(line, s:LookFor('commentmiddle'),
1155                         \ s:SubstituteWith('commentmiddle', a:2), "")
1156         endif
1157             
1158         if !b:ECuseMPBlock || (b:ECuseMPBlock && s:i == s:endBlock)
1159             " Align the closing part to the right.
1160             if b:ECalignRight && s:inBlock
1161                 let len = s:GetLineLen(line, strlen(a:commentSymbol)
1162                             \ + strlen(b:ECprettyComments))
1163                 while j < s:maxLen - len
1164                     let line = line .' '
1165                     let j = j + 1
1166                 endwhile
1167             endif
1169             let line = substitute(line, s:LookFor('commentend'),
1170                         \ s:SubstituteWith('commentend', a:1), "")
1171         endif
1172     endif
1173     
1174     " insert the comment symbol
1175     if !b:ECuseMPBlock || a:0 == 0 || (b:ECuseMPBlock && s:i == s:startBlock) 
1176         let line = substitute(line, s:LookFor('commentstart'),
1177                     \ s:SubstituteWith('commentstart', a:commentSymbol), "")
1178     endif
1179     
1180     return line
1181 endfunction
1184 " UnCommentify(lineString, commentSymbol, [commentEnd])
1185 "       lineString      -- the line in work
1186 "       commentSymbol   -- string to remove at the beginning of the line
1187 "       commentEnd      -- string to remove at the end of the line
1188 "                          may be omitted
1190 " This function removes the start- (and if given the end-) string of the
1191 " comment in the current line.
1193 function s:UnCommentify(lineString, commentSymbol, ...)
1194     let line = a:lineString
1196     " remove the first comment symbol found on a line
1197     if a:0 == 0 || !b:ECuseMPBlock || (b:ECuseMPBlock && s:i == s:startBlock) 
1198         let line = substitute(line, s:LookFor('decommentstart',
1199                     \   a:commentSymbol),
1200                     \ s:SubstituteWith('decommentstart'), "")
1201     endif
1203     " If a end string is present, we have to remove it, too.
1204     if a:0 > 0
1205         " First, we remove the trailing comment symbol.
1206         if !b:ECuseMPBlock || (b:ECuseMPBlock && s:i == s:endBlock) 
1207             let line = substitute(line, s:LookFor('decommentend', a:1),
1208                         \ s:SubstituteWith('decommentend'), "")
1210             " Remove any trailing whitespace, if we used alignRight.
1211             if b:ECalignRight
1212                 let line = substitute(line, ' *$', '', "")
1213             endif
1214         endif
1216         " Maybe we added a middle string. Remove it here.
1217         if b:ECuseCommentsOp && b:ECuseMPBlock
1218                     \ && a:0 > 1
1219                     \ && s:i > s:startBlock
1220             let line = substitute(line, s:LookFor('decommentmiddle', a:2),
1221                         \ s:SubstituteWith('decommentmiddle'), "")
1222         endif
1224         " Remove escaped inner comments.
1225         let line = s:UnEscape(line, a:commentSymbol, a:1)
1226     endif
1228     return line
1229 endfunction
1232 " GetLineLen(line, offset)
1233 "       line        -- line of which length should be computed
1234 "       offset      -- maybe a shift of the line to the right
1236 " Expands '\t' to it's tabstop value.
1238 function s:GetLineLen(line, offset)
1239     let len = a:offset
1240     let i = 0
1241     
1242     while a:line[i] != ""
1243         if a:line[i] == "\t"
1244             let len = (((len / &tabstop) + 1) * &tabstop)
1245         else
1246             let len = len + 1
1247         endif
1248         let i = i + 1
1249     endwhile
1251     return len
1252 endfunction
1253      
1255 " EscapeString(string)
1256 "       string      -- string to process
1258 " Escapes characters in 'string', which have some function in
1259 " regular expressions, with a '\'.
1261 " Returns the escaped string.
1263 function s:EscapeString(string)
1264     return escape(a:string, "*{}[]$^-")
1265 endfunction
1268 " LookFor(what, ...)
1269 "       what        -- what type of regular expression
1270 "                       * checkstart:
1271 "                       * checkend:
1272 "                         check for comment at start/end of line
1273 "                       * commentstart:
1274 "                       * commentend:
1275 "                         insert comment strings
1276 "                       * decommentstart:
1277 "                       * decommentend:
1278 "                         remove comment strings
1279 "       a:1         -- comment string
1281 function s:LookFor(what, ...)
1282     if b:ECuseBlockIndent && s:inBlock
1283         let handleWhitespace = s:blockIndentRegex
1284     else
1285         let handleWhitespace = b:ECsaveWhite
1286     endif
1287         
1288     if a:what == 'checkstart'
1289         let regex = '^'. b:ECsaveWhite . s:EscapeString(a:1)
1290                     \ . s:EscapeString(b:ECidentFront)
1291     elseif a:what == 'checkend'
1292         let regex = s:EscapeString(b:ECidentBack)
1293                     \ . s:EscapeString(a:1) . b:ECsaveWhite . '$'
1294     elseif a:what == 'commentstart'
1295         let regex = '^'. handleWhitespace
1296     elseif a:what == 'commentmiddle'
1297         let regex = '^'. handleWhitespace
1298     elseif a:what == 'commentend'
1299         let regex = '$'
1300     elseif a:what == 'decommentstart'
1301         let regex = '^'. b:ECsaveWhite . s:EscapeString(a:1)
1302                     \ . s:EscapeString(b:ECidentFront) . b:ECprettyUnComments
1303     elseif a:what == 'decommentmiddle'
1304         let regex = '^'. b:ECsaveWhite . s:EscapeString(a:1)
1305                     \ . s:EscapeString(b:ECidentFront) . b:ECprettyUnComments
1306     elseif a:what == 'decommentend'
1307         let regex = b:ECprettyUnComments . s:EscapeString(b:ECidentBack)
1308                     \ . s:EscapeString(a:1) . b:ECsaveWhite .'$'
1309     endif
1311     return regex
1312 endfunction
1315 " SubstituteWith(what, ...)
1316 "       what        -- what type of regular expression
1317 "                       * commentstart:
1318 "                       * commentend:
1319 "                         insert comment strings
1320 "                       * decommentstart:
1321 "                       * decommentend:
1322 "                         remove comment strings
1323 "       a:1         -- comment string
1325 function s:SubstituteWith(what, ...)
1326     if a:what == 'commentstart'
1327                 \ || a:what == 'commentmiddle'
1328                 \ || a:what == 'commentend'
1329         let commentSymbol = a:1
1330     else
1331         let commentSymbol = ''
1332     endif
1334     if b:ECuseBlockIndent && s:inBlock
1335         let handleWhitespace = '\1' . commentSymbol
1336     else
1337         let handleWhitespace = b:ECrespectWhite . commentSymbol
1338                     \ . b:ECignoreWhite
1339     endif
1340         
1341     if a:what == 'commentstart'
1342         let regex = handleWhitespace . b:ECidentFront
1343                     \ . b:ECprettyComments
1344     elseif a:what == 'commentmiddle'
1345         let regex = handleWhitespace . b:ECidentFront
1346                     \ . b:ECprettyComments
1347     elseif a:what == 'commentend'
1348         let regex = b:ECprettyComments . b:ECidentBack . a:1
1349     elseif a:what == 'decommentstart'
1350                 \ || a:what == 'decommentmiddle'
1351                 \ || a:what == 'decommentend'
1352         let regex = handleWhitespace
1353     endif
1355     return regex
1356 endfunction
1360 " DecideWhatToDo(lineString, commentStart, ...)
1361 "       lineString      -- first line of block
1362 "       commentStart    -- comment start symbol
1363 "       a:1             -- comment end symbol
1365 function s:DecideWhatToDo(lineString, commentStart, ...)
1366     " If we checked already, we return our previous result.
1367     if !s:firstOfBlock
1368                 \ && (s:Action == 'first'
1369                 \       || (b:ECuseMPBlock && s:inBlock && a:0))
1370         return s:blockAction
1371     endif
1373     let s:blockAction = 'comment'
1375     if s:inBlock && a:0 && b:ECuseMPBlock
1376         let first = getline(s:startBlock)
1377         let last = getline(s:endBlock)
1379         if first =~ s:LookFor('checkstart', a:commentStart)
1380                 \ && first !~ s:LookFor('checkend', a:1)
1381                 \ && last !~ s:LookFor('checkstart', a:commentStart)
1382                 \ && last =~ s:LookFor('checkend', a:1)
1383             let s:blockAction = 'decomment'
1384         endif
1386         return s:blockAction
1387     endif
1389     if a:lineString =~ s:LookFor('checkstart', a:commentStart)
1390         let s:blockAction = 'decomment'
1391     endif
1393     if a:0
1394         if a:lineString !~ s:LookFor('checkend', a:1)
1395             let s:blockAction = 'comment'
1396         endif
1397     endif
1399     let s:firstOfBlock = 0
1400     return s:blockAction
1401 endfunction
1404 " TabsToSpaces(str)
1405 "       str         -- string to convert
1407 " Convert leading tabs of given string to spaces.
1409 function s:TabsToSpaces(str)
1410     let string = a:str
1412     " FIXME: Can we use something like retab? I don't think so,
1413     " because retab changes every whitespace in the line, but we
1414     " wan't to modify only the leading spaces. Is this a problem?
1415     while string =~ '^\( *\)\t'
1416         let string = substitute(string, '^\( *\)\t', '\1'. s:tabConvert, "")
1417     endwhile
1419     return string
1420 endfunction
1423 " SpacesToTabs(str)
1424 "       str         -- string to convert
1426 " Convert leading spaces of given string to tabs.
1428 function s:SpacesToTabs(str)
1429     let string = a:str
1431     if !&expandtab
1432         while string =~ '^\(\t*\)'. s:tabConvert
1433             let string = substitute(string, '^\(\t*\)'. s:tabConvert,
1434                         \ '\1\t', "")
1435         endwhile
1436     endif
1438     return string
1439 endfunction
1442 " EnhCommentifyFallback4Embedded(test, fallback)
1443 "       test        -- test for the special case
1444 "       fallback    -- filetype instead of normal fallback
1446 " This function is global. It should be called from filetype
1447 " plugins like php, where the normal fallback behaviour may
1448 " not work. One may use 'synFiletype' to reference the guessed
1449 " filetype via synID.
1451 function EnhCommentifyFallback4Embedded(test, fallback)
1452     let b:EnhCommentifyFallbackTest = a:test
1453     let b:EnhCommentifyFallbackValue = a:fallback
1454 endfunction
1457 " Keyboard mappings.
1459 noremap <Plug>Comment
1460             \ :call EnhancedCommentify('', 'comment')<CR>
1461 noremap <Plug>DeComment
1462             \ :call EnhancedCommentify('', 'decomment')<CR>
1463 noremap <Plug>Traditional
1464             \ :call EnhancedCommentify('', 'guess')<CR>
1465 noremap <Plug>FirstLine
1466             \ :call EnhancedCommentify('', 'first')<CR>
1468 noremap <Plug>VisualComment
1469             \ <Esc>:call EnhancedCommentify('', 'comment',
1470             \                               line("'<"), line("'>"))<CR>
1471 noremap <Plug>VisualDeComment
1472             \ <Esc>:call EnhancedCommentify('', 'decomment',
1473             \                               line("'<"), line("'>"))<CR>
1474 noremap <Plug>VisualTraditional
1475             \ <Esc>:call EnhancedCommentify('', 'guess',
1476             \                               line("'<"), line("'>"))<CR>
1477 noremap <Plug>VisualFirstLine
1478             \ <Esc>:call EnhancedCommentify('', 'first',
1479             \                               line("'<"), line("'>"))<CR>
1481 " Finally set keybindings.
1483 " SetKeybindings(where)
1484 "       where       -- "l" for local to the buffer, "g" for global
1486 function s:SetKeybindings(where)
1487     if a:where == "l"
1488         let where = "<buffer>"
1489         let ns = "b"
1490     else
1491         let where = ""
1492         let ns = "s"
1493     endif
1495     execute "let userBindings = ". ns .":ECuserBindings"
1496     execute "let useAltKeys = ". ns .":ECuseAltKeys"
1497     execute "let traditionalMode = ". ns .":ECtraditionalMode"
1498     execute "let firstLineMode = ". ns .":ECfirstLineMode"
1499     execute "let bindInNormal = ". ns .":ECbindInNormal"
1500     execute "let bindInInsert = ". ns .":ECbindInInsert"
1501     execute "let bindInVisual = ". ns .":ECbindInVisual"
1503     if userBindings
1504         "
1505         " *** Put your personal bindings here! ***
1506         "
1507     else
1508         if useAltKeys
1509             let s:c = '<M-c>'
1510             let s:x = '<M-x>'
1511             let s:C = '<M-v>'
1512             let s:X = '<M-y>'
1513         else
1514             let s:c = '<Leader>c'
1515             let s:x = '<Leader>x'
1516             let s:C = '<Leader>C'
1517             let s:X = '<Leader>X'
1518         endif
1520         if traditionalMode
1521             let s:Method = 'Traditional'
1522         elseif firstLineMode
1523             let s:Method = 'FirstLine'
1524         else
1525             let s:Method = 'Comment'
1527             " Decomment must be defined here. Everything else is mapped below.
1528             if bindInNormal 
1529                 execute 'nmap '. where .' <silent> <unique> '. s:C
1530                             \ .' <Plug>DeCommentj'
1531                 execute 'nmap '. where .' <silent> <unique> '. s:X
1532                             \ .' <Plug>DeComment'
1533             endif
1535             if bindInInsert
1536                 execute 'imap '. where .' <silent> <unique> '. s:C
1537                             \ .' <Esc><Plug>DeCommentji'
1538                 execute 'imap '. where .' <silent> <unique> '. s:X
1539                             \ .' <Esc><Plug>DeCommenti'
1540             endif
1542             if bindInVisual
1543                 execute 'vmap '. where .' <silent> <unique> '. s:C
1544                             \ .' <Plug>VisualDeCommentj'
1545                 execute 'vmap '. where .' <silent> <unique> '. s:X
1546                             \ .' <Plug>VisualDeComment'
1547             endif
1548         endif
1550         if bindInNormal
1551             execute 'nmap '. where .' <silent> <unique> '. s:c
1552                         \ .' <Plug>'. s:Method .'j'
1553             execute 'nmap '. where .' <silent> <unique> '. s:x
1554                         \ .' <Plug>'. s:Method
1555         endif
1557         if bindInInsert
1558             execute 'imap '. where .' <silent> <unique> '. s:c
1559                         \ .' <Esc><Plug>'. s:Method .'ji'
1560             execute 'imap '. where .' <silent> <unique> '. s:x
1561                         \ .' <Esc><Plug>'. s:Method
1562         endif
1564         if bindInVisual
1565             execute 'vmap <silent> <unique> '. s:c
1566                         \ .' <Plug>Visual'. s:Method .'j'
1567             execute 'vmap '. where .' <silent> <unique> '. s:x
1568                         \ .' <Plug>Visual'. s:Method
1569         endif
1570     endif
1571 endfunction
1573 if !s:ECbindPerBuffer
1574     call s:SetKeybindings("g")
1575 endif
1577 let &cpo = s:savedCpo
1579 " vim: set sts=4 sw=4 ts=8 :