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