commit 74c5c4085f651e77c3c1ccb6ec67a32312f81101 Author: gryf Date: Sun Apr 11 20:35:38 2010 +0200 Moja dawna konfiguracja diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..10027c4 --- /dev/null +++ b/.vimrc @@ -0,0 +1,370 @@ +" gvim settings: +" +"set guifontset=-misc-fixed-medium-r-normal-*-*-120-*-*-c-*-iso8859-2 +"set guifont=-misc-fixed-medium-r-normal-*-*-120-*-*-c-*-iso8859-2 +"set mouse=a +"set guifontset="Monospace 13" +"set guifont="Monospace 13" +"colorscheme pablo + + +" vim setting: +" +set bg=dark +" +" VIM configuration file +" Author: Piotr Debicki (pdebicki@poczta.onet.pl) +"""""""" +" +" Always set autoindenting on +" + set autoindent +" +" Automatically save modifications to files when +" using critical commands +" + set autowrite +" +" Allow backspacing over everything in insert mode +" + set backspace=2 +" +" Don't make a backup before overwriting +" + set nobackup +" +" Reset cinwords - this suxx with smartindent +" + set cinwords= +" +" Use Vim settings, rather then Vi settings +" + set nocompatible +" +" Ask for confirmation rather then refuse certain commands +" + set confirm +" +" Type of in written files +" + set fileformats=unix,dos +" +" Automatic formatting settings +" + set formatoptions=croq +" +" Keep hidden windows +" + set hidden +" +" Keep 50 lines of command line history +" + set history=50 +" +" Don't highlight search patterns +" + set nohlsearch +" +" Ignore case in search patterns +" + set ignorecase +" +" Always show statusbar +" + set laststatus=2 +" +" Don't update screen while executing macros +" + set lazyredraw +" +" Strings to use in 'list' mode +" + set listchars=tab:>-,trail:-,eol:$ +" +" Show the cursor position all the time +" + set ruler +" +" Content of the ruler string +" + set rulerformat=%l,%c%V%=#%n\ %3p%% +" +" Minimal number of lines to scroll when the cursor gets off the screen +" +" set scrolljump=1 +" +" Minimal number of screen lines to keep above and below the cursor +" + set scrolloff=3 +" +" Define the behavior of the selection +" + set selection=exclusive +" +" Name of the shell to use for ! and :! commands +" +" set shell=binbash +" +" Number of spaces to use for each step of (auto)indent +" + set shiftwidth=4 +" +" Abbreviate some messages +" + set shortmess=atToOI +" +" String to put at the start of lines that have been wrapped +" + set showbreak=> +" +" Show (partial) command in status line +" + set showcmd +" +" When a bracket is inserted, briefly jump to the matching one +" + set showmatch +" +" Do smart autoindenting when starting a new line +" + set smartindent +" +" Create new window below current one +" + set splitbelow +" +" Use swap file +" + set swapfile +" +" Turn beeping off +" + set t_vb= +" +" Set tab stop to 4 +" + set tabstop=4 +" +" Turn off scrolling -> faster +" +" set ttyscroll=0 +" +" After typing this many chars the swap file will be written to disk +" + set updatecount=50 +" +" Configure .viminfo +" + set viminfo='20,\"50 +" +" Cursor keys wrap to previous/next line +" + set whichwrap+=<,>,[,] +" +" Character to start wildcard expansion in the command-line +" + set wildchar= +" +" Put command-line completion in an enhanced mode +" + set wildmenu +" +" Turn line wrapping off (a ja chcę wrap) +" +" set nowrap +" +" Number of characters from the right window border where wrapping starts +" + set wrapmargin=1 +" +" Turn syntax highlighting on +" + syntax on + +" +" wgrywaj również widoki dla plików php +" + + au BufWinLeave *.php mkview + au BufWinEnter *.php silent loadview + +" +" ============================ +" Abbreviations +" ============================ +" +" Some C abbreviations +" + iab Zmain int main(int argc, char *argv[]) + iab Zinc #include + iab Zdef #define +" +" Some other abbreviations +" + iab Zdate =strftime("%y%m%d") + iab Ztime =strftime("%H:%M:%S") + iab Zmymail pdebicki@poczta.onet.pl + iab Zmyphone 0 502 935 242 + iab Zfilename =expand("%:t:r") + iab Zfilepath =expand("%:p") +" +" ============================ +" Customization +" ============================ +" +" Function keys +" + nmap 3K + nmap :cnext + nmap :cprevious + nmap :clist + nmap :make + nmap :!! + nmap :call SwitchTabstop() + nmap :call SwitchSyntax() + nmap :call SwitchIndent() + imap 3Ki + imap :cnext + imap :cprevious + imap :clist + imap :make + imap :!! + imap :call SwitchTabstop()i + imap :call SwitchSyntax()i + imap :call SwitchIndent()i +" +" Show next buffer +" + nmap :bnext +" +" Execute shell commands easier +" + nmap ! :! +" +" Align line +" + nmap ,ac :center + nmap ,al :left + nmap ,ar :right +" +" Print the ASCII value of the character under the cursor +" + nmap ,as :ascii +" +" Change type of - unix/dos +" + nmap ,eol :call ChangeFileFormat() +" +" Insert C/C++ source footer +" + nmap ,fo :%r $HOME/src/TEMPLATE/FOOTER +" +" Insert C/C++ source header +" + nmap ,he :0r $HOME/src/TEMPLATE/HEADER +" +" Turn highlight search on/off +" + nmap ,hs :call ToggleOption('hlsearch') +" +" Turn line numbers on/off +" + nmap ,nu :call ToggleOption('number') +" +" Remove all empty lines +" + nmap ,re :g/^$/d +" +" Edit .vimrc +" + nmap ,rc :n $HOME/.vimrc +" +" Turn line wrapping on/off +" + nmap ,wr :call ToggleOption('wrap') +" +" Show white spaces on/off +" + nmap ,ws :call ToggleOption('list') +" +" Make selection lowercase +" + vmap ,l u +" +" Rot13 encode selection +" + vmap ,r g? +" +" Make selection switch case +" + vmap ,s ~ +" +" Make selection uppercase +" + vmap ,u U +" +" tym, oto, skrótem komentuj/unkomentuj całe linie, bloki, etc. +" niezbędny plugin enhcommentify w ~/.vim/plugin +" +nmap :call EnhancedCommentify('', 'guess')j +vmap :call EnhancedCommentify('', 'guess')j + +" +" ============================ +" Functions +" ============================ + +function ToggleOption (option) + execute 'set ' . a:option . '!' + execute 'echo "' . a:option . ':" strpart("OFFON",3*&' . a:option . ',3)' +endfunction + +function ChangeFileFormat() + if &fileformat == "unix" + set fileformat=dos + echo " type: DOS" + else + set fileformat=unix + echo " type: UNIX" + endif +endfunction + +function SwitchTabstop() + if &tabstop == 4 + set tabstop=8 + echo "Tabstop = 8" + else + set tabstop=4 + echo "Tabstop = 4" + endif +endfunction + +function SwitchSyntax() + if has("syntax_items") + syntax off + echo "Syntax highlighting OFF" + else + syntax on + echo "Syntax highlighting ON" + endif +endfunction + +function SwitchIndent() + if &autoindent + set noautoindent + set nosmartindent + set formatoptions= + echo "Indent OFF" + else + set autoindent + set smartindent + set formatoptions=croq + echo "Indent ON" + endif +endfunction + +" vim:ts=4:sw=4:wrap: +" - EOF - + + + diff --git a/plugin/EnhancedCommentify.vim b/plugin/EnhancedCommentify.vim new file mode 100644 index 0000000..1451373 --- /dev/null +++ b/plugin/EnhancedCommentify.vim @@ -0,0 +1,1579 @@ +" EnhancedCommentify.vim +" Maintainer: Meikel Brandmeyer +" Version: 2.2 +" Last Change: Monday, 27th September 2004 + +" License: +" Copyright (c) 2002,2003,2004 Meikel Brandmeyer, Kaiserslautern. +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" * Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" * Neither the name of the author nor the names of its contributors may be +" used to endorse or promote products derived from this software without +" specific prior written permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +" Description: +" This is a (well... more or less) simple script to comment lines in a program. +" Currently supported languages are C, C++, PHP, the vim scripting +" language, python, HTML, Perl, LISP, Tex, Shell, CAOS and others. + +" Bugfixes: +" 2.2 +" Fixed problem with UseSyntax (thanks to Pieter Naaijkens) +" Fixed typo in ParseCommentsOp (commstr -> commStr). +" Fixed support for ocaml (thanks to Zhang Le) +" 2.1 +" Fixed problems with alignement when a line contains tabs +" Fixed (resp. cleaned up) issues with overrideEL (thanks to Steve Hall) +" Fixed problems with javascript detection (thanks to Brian Neu) +" Changed Buffer init to BufWinEnter in order to use the modelines. +" 2.0 +" Fixed invalid expression '\'' -> "'" (thanks to Zak Beck) +" Setting AltOpen/AltClose to '' (ie. disabling it) would +" insert '/*' resp. '*/' for character in a line (thanks to Ben Kibbey) +" 1.8 +" Backslashes in comment symbols should not be escaped. +" typo (commensSymbol -> commentSymbol) (thanks to Steve Butts) +" typo (== -> =) +" Fixed hardwired '|+'-'+|' pair. +" 1.7 +" Lines were not correctly decommentified, when there was whitespace +" at the beginning of the line. (thanks to Xiangjiang Ma) +" Fixed error detecting '*sh' filetypes. +" 1.3 +" hlsearch was set unconditionally (thanks to Mary Ellen Foster) +" made function silent (thanks to Mare Ellen Foster) + +" Changelog: +" 2.2 +" Added possibility to override the modes, in which keybindings are +" defined. +" Keybindings may be defined local to every buffer now. +" If a filetype is unknown, one can turn off the keybindings now. +" 2.1 +" Removed any cursor movement. The script should now be free of +" side-effects. +" The script now uses &commentstring to determine the right +" comment strings. Fallback is still the ugly if-thingy. +" Script can now interpret &comments in order to add a middle +" string in blocks. +" Added EnhancedCommentifySet for use by other scripts. (Necessary?) +" Added MultiPartBlocks for languages with multipart-comments. +" Added parsing for comments option if using MultiPartBlocks. +" 2.0 +" IMPORTANT: EnhancedCommentify is now licensed under BSD license +" for distribution with Cream! However this shouldn't +" change anything... +" useBlockIndent does no longer depend on respectIndent. +" Added code to cope with 'C' in '&cpo'. (thanks to Luc Hermitte +" for pointing this out!) +" Added EnhCommentifyIdentFrontOnly option. +" All options are now handled on a per buffer basis. So options +" can be overriden for different buffers. +" 1.9 +" Filetype is now recognized via regular expressions. +" All known filetypes are (more or less) supported. +" Decomments multipart-block comments. +" Added RespectIndent, AlignRight and synID-guessing. +" Switched to buffer variables. +" 1.8 +" Added Ada support. (thanks to Preben Randhol) +" Added Latte support. +" Added blocksupport and possibility to specify action (comment or +" decomment). It's also possible to guess the action line by line or +" using the first line of a block. +" Thanks to Xiangjiang Ma and John Orr for the rich feedback on these +" issues. +" Decomments /*foo();*/, when PrettyComments is set. +" Added 'vhdl' and 'verilog'. (thanks to Steve Butts) +" 1.7 +" Added different options to control behaviour of the plugin. +" Changed default Keybindings to proper plugin settings. +" 1.6 +" Now supports 'm4', 'config', 'automake' +" 'vb', 'aspvbs', 'plsql' (thanks to Zak Beck) +" 1.5 +" Now supports 'java', 'xml', 'jproperties'. (thanks to Scott Stirling) +" 1.4 +" Lines containing only whitespace are now considered empty. +" Added Tcl support. +" Multipart comments are now escaped with configurable alternative +" strings. Prevents nesting errors (eg. /**/*/ in C) +" 1.3 +" Doesn't break lines like +" foo(); /* bar */ +" when doing commentify. + +" Install Details: +" Simply drop this file into your $HOME/.vim/plugin directory. + +if exists("DidEnhancedCommentify") + finish +endif +let DidEnhancedCommentify = 1 + +let s:savedCpo = &cpo +set cpo-=C + +" Note: These must be defined here, since they are used during +" initialisation. +" +" InitBooleanVariable(confVar, scriptVar, defaultVal) +" confVar -- name of the configuration variable +" scriptVar -- name of the variable to set +" defaultVal -- default value +" +" Tests on existence of configuration variable and sets scriptVar +" according to its contents. +" +function s:InitBooleanVariable(confVar, scriptVar, defaultVal) + let regex = a:defaultVal ? 'no*' : 'ye*s*' + + if exists(a:confVar) && {a:confVar} =~? regex + let {a:scriptVar} = !a:defaultVal + else + let {a:scriptVar} = a:defaultVal + endif +endfunction + +" +" InitStringVariable(confVar, scriptVar, defaultVal) +" confVar -- name of the configuration variable +" scriptVar -- name of the variable to set +" defaultVal -- default value +" +" Tests on existence of configuration variable and sets scriptVar +" to its contents. +" +function s:InitStringVariable(confVar, scriptVar, defaultVal) + if exists(a:confVar) + execute "let ". a:scriptVar ." = ". a:confVar + else + let {a:scriptVar} = a:defaultVal + endif +endfunction + +" +" InitScriptVariables(nameSpace) +" nameSpace -- may be "g" for global or "b" for local +" +" Initialises the script variables. +" +function s:InitScriptVariables(nameSpace) + let ns = a:nameSpace " just for abbreviation + let lns = (ns == "g") ? "s" : "b" " 'local namespace' + + " Comment escape strings... + call s:InitStringVariable(ns .":EnhCommentifyAltOpen", lns .":ECaltOpen", + \ s:ECaltOpen) + call s:InitStringVariable(ns .":EnhCommentifyAltClose", lns .":ECaltClose", + \ s:ECaltClose) + + call s:InitBooleanVariable(ns .":EnhCommentifyIgnoreWS", lns .":ECignoreWS", + \ s:ECignoreWS) + + " Adding a space between comment strings and code... + if exists(ns .":EnhCommentifyPretty") + if {ns}:EnhCommentifyPretty =~? 'ye*s*' + let {lns}:ECprettyComments = ' ' + let {lns}:ECprettyUnComments = ' \=' + else + let {lns}:ECprettyComments = '' + let {lns}:ECprettyUnComments = '' + endif + else + let {lns}:ECprettyComments = s:ECprettyComments + let {lns}:ECprettyUnComments = s:ECprettyUnComments + endif + + " Identification string settings... + call s:InitStringVariable(ns .":EnhCommentifyIdentString", + \ lns .":ECidentFront", s:ECidentFront) + let {lns}:ECidentBack = + \ (exists(ns .":EnhCommentifyIdentFrontOnly") + \ && {ns}:EnhCommentifyIdentFrontOnly =~? 'ye*s*') + \ ? '' + \ : {lns}:ECidentFront + + " Wether to use syntax items... + call s:InitBooleanVariable(ns .":EnhCommentifyUseSyntax", + \ lns .":ECuseSyntax", s:ECuseSyntax) + + " Should the script respect line indentation, when inserting strings? + call s:InitBooleanVariable(ns .":EnhCommentifyRespectIndent", + \ lns .":ECrespectIndent", s:ECrespectIndent) + + " Keybindings... + call s:InitBooleanVariable(ns .":EnhCommentifyUseAltKeys", + \ lns .":ECuseAltKeys", s:ECuseAltKeys) + call s:InitBooleanVariable(ns .":EnhCommentifyBindPerBuffer", + \ lns .":ECbindPerBuffer", s:ECbindPerBuffer) + call s:InitBooleanVariable(ns .":EnhCommentifyBindInNormal", + \ lns .":ECbindInNormal", s:ECbindInNormal) + call s:InitBooleanVariable(ns .":EnhCommentifyBindInInsert", + \ lns .":ECbindInInsert", s:ECbindInInsert) + call s:InitBooleanVariable(ns .":EnhCommentifyBindInVisual", + \ lns .":ECbindInVisual", s:ECbindInVisual) + call s:InitBooleanVariable(ns .":EnhCommentifyUserBindings", + \ lns .":ECuserBindings", s:ECuserBindings) + call s:InitBooleanVariable(ns .":EnhCommentifyTraditionalMode", + \ lns .":ECtraditionalMode", s:ECtraditionalMode) + call s:InitBooleanVariable(ns .":EnhCommentifyFirstLineMode", + \ lns .":ECfirstLineMode", s:ECfirstLineMode) + call s:InitBooleanVariable(ns .":EnhCommentifyUserMode", + \ lns .":ECuserMode", s:ECuserMode) + call s:InitBooleanVariable(ns .":EnhCommentifyBindUnknown", + \ lns .":ECbindUnknown", s:ECbindUnknown) + + " Block stuff... + call s:InitBooleanVariable(ns .":EnhCommentifyAlignRight", + \ lns .":ECalignRight", s:ECalignRight) + call s:InitBooleanVariable(ns .":EnhCommentifyUseBlockIndent", + \ lns .":ECuseBlockIndent", s:ECuseBlockIndent) + call s:InitBooleanVariable(ns .":EnhCommentifyMultiPartBlocks", + \ lns .":ECuseMPBlock", s:ECuseMPBlock) + call s:InitBooleanVariable(ns .":EnhCommentifyCommentsOp", + \ lns .":ECuseCommentsOp", s:ECuseCommentsOp) + + let {lns}:ECsaveWhite = ({lns}:ECrespectIndent + \ || {lns}:ECignoreWS || {lns}:ECuseBlockIndent) + \ ? '\(\s*\)' + \ : '' + + if !{lns}:ECrespectIndent + let {lns}:ECuseBlockIndent = 0 + endif + + if {lns}:ECrespectIndent + let {lns}:ECrespectWhite = '\1' + let {lns}:ECignoreWhite = '' + elseif {lns}:ECignoreWS + let {lns}:ECrespectWhite = '' + let {lns}:ECignoreWhite = '\1' + else + let {lns}:ECrespectWhite = '' + let {lns}:ECignoreWhite = '' + endif + + " Using comments option, doesn't make sense without useMPBlock + "if lns == 'b' && b:ECuseCommentsOp + " let b:ECuseMPBlock = 1 + "endif +endfunction + +" +" EnhancedCommentifySet(option, value, ...) +" option -- which option +" value -- value which will be asigned to the option +" +" The purpose of this function is mainly to act as an interface to the +" outer world. It hides the internally used variables. +" +function EnhancedCommentifySet(option, value) + if a:option == 'AltOpen' + let oldval = b:ECaltOpen + let b:ECaltOpen = a:value + elseif a:option == 'AltClose' + let oldval = b:ECaltClose + let b:ECaltClose = a:value + elseif a:option == 'IdentString' + let oldval = b:ECidentFront + let b:ECidentFront = a:value + elseif a:option == 'IdentFrontOnly' + let oldval = (b:ECidentBack == '') ? 'Yes' : 'No' + let b:ECidentBack = (a:value =~? 'ye*s*') ? '' : b:ECidentFront + elseif a:option == 'RespectIndent' + let oldval = b:ECrespectIndent + let b:ECrespectIndent = (a:value =~? 'ye*s*') ? 1 : 0 + elseif a:option == 'IgnoreWS' + let oldval = b:ECignoreWS + let b:ECignoreWS = (a:value =~? 'ye*s*') ? 1 : 0 + elseif a:option == 'Pretty' + let oldval = (b:ECprettyComments == ' ') ? 'Yes' : 'No' + if a:value =~? 'ye*s*' + let b:ECprettyComments = ' ' + let b:ECprettyUnComments = ' \=' + else + let b:ECprettyComments = '' + let b:ECprettyUnComments = '' + endif + elseif a:option == 'MultiPartBlocks' + let oldval = b:ECuseMPBlock + let b:ECuseMPBlock = (a:value =~? 'ye*s*') ? 1 : 0 + elseif a:option == 'CommentsOp' + let oldval = b:ECuseCommentsOp + let b:ECuseCommentsOp = (a:value =~? 'ye*s*') ? 1 : 0 + elseif a:option == 'UseBlockIndent' + let oldval = b:ECuseBlockIndent + let b:ECuseBlockIndent = (a:value =~? 'ye*s*') ? 1 : 0 + elseif a:option == 'AlignRight' + let oldval = b:ECalignRight + let b:ECalignRight = (a:value =~? 'ye*s*') ? 1 : 0 + elseif a:option == 'UseSyntax' + let oldval = b:ECuseSyntax + let b:ECuseSyntax = (a:value =~? 'ye*s*') ? 1 : 0 + else + if (has("dialog_gui") && has("gui_running")) + call confirm("EnhancedCommentifySet: Unknwon option '" + \ . option . "'") + else + echohl ErrorMsg + echo "EnhancedCommentifySet: Unknown option '". option ."'" + echohl None + endif + endif + + if oldval == 1 + let oldval = 'Yes' + elseif oldval == 0 + let oldval = 'No' + endif + + return oldval +endfunction + +" Initial settings. +" +" Setting the default options resp. taking user preferences. +if !exists("g:EnhCommentifyUserMode") + \ && !exists("g:EnhCommentifyFirstLineMode") + \ && !exists("g:EnhCommentifyTraditionalMode") + \ && !exists("g:EnhCommentifyUserBindings") + let g:EnhCommentifyTraditionalMode = 'Yes' +endif + +" These will be the default settings for the script: +let s:ECaltOpen = "|+" +let s:ECaltClose = "+|" +let s:ECignoreWS = 1 +let s:ECprettyComments = '' +let s:ECprettyUnComments = '' +let s:ECidentFront = '' +let s:ECuseSyntax = 0 +let s:ECrespectIndent = 0 +let s:ECalignRight = 0 +let s:ECuseBlockIndent = 0 +let s:ECuseMPBlock = 0 +let s:ECuseCommentsOp = 0 +let s:ECuseAltKeys = 0 +let s:ECbindPerBuffer = 0 +let s:ECbindInNormal = 1 +let s:ECbindInInsert = 1 +let s:ECbindInVisual = 1 +let s:ECuserBindings = 0 +let s:ECtraditionalMode = 0 +let s:ECfirstLineMode = 0 +let s:ECuserMode = 1 +let s:ECbindUnknown = 1 + +" Now initialise the global defaults with the preferences set +" by the user in his .vimrc. Settings local to a buffer will be +" done later on, when the script is first called in a buffer. +" +call s:InitScriptVariables("g") + +" Globally used variables with some initialisation. +" FIXME: explain what they are good for +" +let s:Action = 'guess' +let s:firstOfBlock = 1 +let s:blockAction = 'comment' +let s:blockIndentRegex = '' +let s:blockIndent = 0 +let s:inBlock = 0 +let s:tabConvert = '' +let s:overrideEmptyLines = 0 +let s:emptyLines = 'no' +let s:maxLen = 0 + +function EnhancedCommentifyInitBuffer() + if !exists("b:ECdidBufferInit") + call s:InitScriptVariables("b") + + if !exists("b:EnhCommentifyFallbackTest") + let b:EnhCommentifyFallbackTest = 0 + endif + + call s:GetFileTypeSettings(&ft) + call s:CheckPossibleEmbedding(&ft) + + " + " If the filetype is not supported and the user wants us to, we do not + " add keybindings. + " + if s:ECbindPerBuffer + if b:ECcommentOpen != "" || b:ECbindUnknown + call s:SetKeybindings("l") + endif + endif + + let b:ECdidBufferInit = 1 + let b:ECsyntax = &ft + endif +endfunction + +autocmd BufWinEnter,BufNewFile * call EnhancedCommentifyInitBuffer() + +" +" EnhancedCommentify(emptyLines, action, ...) +" overrideEL -- commentify empty lines +" may be 'yes', 'no' or '' for guessing +" action -- action which should be executed: +" * guess: +" toggle commetification (old behaviour) +" * comment: +" comment lines +" * decomment: +" decomment lines +" * first: +" use first line of block to determine action +" a:1, a:2 -- first and last line of block, which should be +" processed. +" +" Commentifies the current line. +" +function EnhancedCommentify(overrideEL, action, ...) + if a:overrideEL != '' + let s:overrideEmptyLines = 1 + endif + + " Now do the buffer initialisation. Every buffer will get + " it's pendant to a global variable (eg. s:ECalignRight -> b:ECalignRight). + " The local variable is actually used, whereas the global variable + " holds the defaults from the user's .vimrc. In this way the settings + " can be overriden for single buffers. + " + " NOTE: Buffer init is done by autocommands now. + " + + let b:ECemptyLines = a:overrideEL + + " The language is not supported. + if b:ECcommentOpen == '' + if (has("dialog_gui") && has("gui_running")) + call confirm("This filetype is currently _not_ supported!\n" + \ ."Please consider contacting the author in order" + \ ." to add this filetype.", "", 1, "Error") + else + echohl ErrorMsg + echo "This filetype is currently _not_ supported!" + echo "Please consider contacting the author in order to add" + echo "this filetype in future releases!" + echohl None + endif + return + endif + + let lnum = line(".") + + " Now some initialisations... + let s:Action = a:action + + " FIXME: Is there really _no_ function to simplify this??? + " (Maybe something like 'let foo = 8x" "'?) + if s:tabConvert == '' && strlen(s:tabConvert) != &tabstop + let s:tabConvert = '' + let i = 0 + while i < &tabstop + let s:tabConvert = s:tabConvert .' ' + let i = i + 1 + endwhile + endif + + if a:0 == 2 + let s:startBlock = a:1 + let s:i = a:1 + let s:endBlock = a:2 + + let s:inBlock = 1 + else + let s:startBlock = lnum + let s:i = lnum + let s:endBlock = lnum + + let s:inBlock = 0 + endif + + if b:ECuseSyntax && b:ECpossibleEmbedding + let column = indent(s:startBlock) + 1 + if !&expandtab + let rem = column % &tabstop + let column = ((column - rem) / &tabstop) + rem + endif + call s:CheckSyntax(s:startBlock, column) + endif + + " Get the indent of the less indented line of the block. + if s:inBlock && (b:ECuseBlockIndent || b:ECalignRight) + call s:DoBlockComputations(s:startBlock, s:endBlock) + endif + + while s:i <= s:endBlock + let lineString = getline(s:i) + let lineString = s:TabsToSpaces(lineString) + + " If we should comment "empty" lines, we have to add + " the correct indent, if we use blockIndent. + if b:ECemptyLines =~? 'ye*s*' + \ && b:ECuseBlockIndent + \ && lineString =~ "^\s*$" + let i = 0 + while i < s:blockIndent + let lineString = " " . lineString + let i = i + 1 + endwhile + endif + + " Don't comment empty lines. + if lineString !~ "^\s*$" + \ || b:ECemptyLines =~? 'ye*s*' + if b:ECcommentClose != '' + let lineString = s:CommentifyMultiPart(lineString, + \ b:ECcommentOpen, + \ b:ECcommentClose, + \ b:ECcommentMiddle) + else + let lineString = s:CommentifySinglePart(lineString, + \ b:ECcommentOpen) + endif + endif + + " Revert the above: If the line is "empty" and we + " used blockIndent, we remove the spaces. + " FIXME: Why does "^\s*$" not work? + if b:ECemptyLines =~? 'ye*s*' + \ && b:ECuseBlockIndent + \ && lineString =~ "^" . s:blockIndentRegex ."\s*$" + let lineString = + \ substitute(lineString, s:blockIndentRegex, + \ '', '') + endif + + let lineString = s:SpacesToTabs(lineString) + call setline(s:i, lineString) + + let s:i = s:i + 1 + let s:firstOfBlock = 0 + endwhile + + let s:firstOfBlock = 1 +endfunction + +" +" DoBlockComputations(start, end) +" start -- number of first line +" end -- number of last line +" +" This function does some computations which are necessary for useBlockIndent +" and alignRight. ie. find smallest indent and longest line. +" +function s:DoBlockComputations(start, end) + let i = a:start + let len = 0 + let amount = 100000 " this should be enough ... + + while i <= a:end + if b:ECuseBlockIndent && getline(i) !~ '^\s*$' + let cur = indent(i) + if cur < amount + let amount = cur + endif + endif + + if b:ECalignRight + let cur = s:GetLineLen(s:TabsToSpaces(getline(i)), + \ s:GetLineLen(b:ECcommentOpen, 0) + \ + strlen(b:ECprettyComments)) + if b:ECuseMPBlock + let cur = cur + s:GetLineLen(b:ECcommentOpen, 0) + \ + strlen(b:ECprettyComments) + endif + + if len < cur + let len = cur + endif + endif + + let i = i + 1 + endwhile + + if b:ECuseBlockIndent + if amount > 0 + let regex = '\( \{'. amount .'}\)' + else + let regex = '' + endif + let s:blockIndentRegex = regex + let s:blockIndent = amount + endif + + if b:ECalignRight + let s:maxLen = len + endif +endfunction + +" +" CheckSyntax(line, column) +" line -- line of line +" column -- column of line +" Check what syntax is active during call of main function. First hit +" wins. If the filetype changes during the block, we ignore that. +" Adjust the filetype if necessary. +" +function s:CheckSyntax(line, column) + let ft = "" + let synFiletype = synIDattr(synID(a:line, a:column, 1), "name") + + " FIXME: This feature currently relies on a certain format + " of the names of syntax items: the filetype must be prepended + " in lowwer case letters, followed by at least one upper case + " letter. + if match(synFiletype, '\l\+\u') == 0 + let ft = substitute(synFiletype, '^\(\l\+\)\u.*$', '\1', "") + endif + + if ft == "" + execute "let specialCase = ". b:EnhCommentifyFallbackTest + + if specialCase + let ft = b:EnhCommentifyFallbackValue + else + " Fallback: If nothing holds, use normal filetype! + let ft = &ft + endif + endif + + " Nothing changed! + if ft == b:ECsyntax + return + endif + + let b:ECsyntax = ft + call s:GetFileTypeSettings(ft) +endfunction + +" +" GetFileTypeSettings(ft) +" ft -- filetype +" +" This functions sets some buffer-variables, which control the comment +" strings and 'empty lines'-handling. +" +function s:GetFileTypeSettings(ft) + let fileType = a:ft + + " I learned about the commentstring option. Let's use it. + " For now we ignore it, if it is "/*%s*/". This is the + " default. We cannot check wether this is default or C or + " something other like CSS, etc. We have to wait, until the + " filetypes adopt this option. + if &commentstring != "/*%s*/" && !b:ECuseSyntax + let b:ECcommentOpen = + \ substitute(&commentstring, '%s.*', "", "") + let b:ECcommentClose = + \ substitute(&commentstring, '.*%s', "", "") + " Multipart comments: + elseif fileType =~ '^\(c\|b\|css\|csc\|cupl\|indent\|jam\|lex\|lifelines\|'. + \ 'lite\|nqc\|phtml\|progress\|rexx\|rpl\|sas\|sdl\|sl\|'. + \ 'strace\|xpm\|yacc\)$' + let b:ECcommentOpen = '/*' + let b:ECcommentClose = '*/' + elseif fileType =~ '^\(html\|xml\|dtd\|sgmllnx\)$' + let b:ECcommentOpen = '' + elseif fileType =~ '^\(sgml\|smil\)$' + let b:ECcommentOpen = '' + elseif fileType == 'atlas' + let b:ECcommentOpen = 'C' + let b:ECcommentClose = '$' + elseif fileType =~ '^\(catalog\|sgmldecl\)$' + let b:ECcommentOpen = '--' + let b:ECcommentClose = '--' + elseif fileType == 'dtml' + let b:ECcommentOpen = '' + let b:ECcommentClose = '' + elseif fileType == 'htmlos' + let b:ECcommentOpen = '#' + let b:ECcommentClose = '/#' + elseif fileType =~ '^\(jgraph\|lotos\|mma\|modula2\|modula3\|pascal\|'. + \ 'ocaml\|sml\)$' + let b:ECcommentOpen = '(*' + let b:ECcommentClose = '*)' + elseif fileType == 'jsp' + let b:ECcommentOpen = '<%--' + let b:ECcommentClose = '--%>' + elseif fileType == 'model' + let b:ECcommentOpen = '$' + let b:ECcommentClose = '$' + elseif fileType == 'st' + let b:ECcommentOpen = '"' + let b:ECcommentClose = '"' + elseif fileType =~ '^\(tssgm\|tssop\)$' + let b:ECcommentOpen = 'comment = "' + let b:ECcommentClose = '"' + " Singlepart comments: + elseif fileType =~ '^\(ox\|cpp\|php\|java\|verilog\|acedb\|ch\|clean\|'. + \ 'clipper\|cs\|dot\|dylan\|hercules\|idl\|ishd\|javascript\|'. + \ 'kscript\|mel\|named\|openroad\|pccts\|pfmain\|pike\|'. + \ 'pilrc\|plm\|pov\|rc\|scilab\|specman\|tads\|tsalt\|uc\|'. + \ 'xkb\)$' + let b:ECcommentOpen = '//' + let b:ECcommentClose = '' + elseif fileType =~ '^\(vim\|abel\)$' + let b:ECcommentOpen = '"' + let b:ECcommentClose = '' + elseif fileType =~ '^\(lisp\|scheme\|scsh\|amiga\|asm\|asm68k\|bindzone\|'. + \ 'def\|dns\|dosini\|dracula\|dsl\|idlang\|iss\|jess\|kix\|'. + \ 'masm\|monk\|nasm\|ncf\|omnimark\|pic\|povini\|rebol\|'. + \ 'registry\|samba\|skill\|smith\|tags\|tasm\|tf\|winbatch\|'. + \ 'wvdial\|z8a\)$' + let b:ECcommentOpen = ';' + let b:ECcommentClose = '' + elseif fileType =~ '^\(python\|perl\|[^w]*sh$\|tcl\|jproperties\|make\|'. + \ 'robots\|apacha\|apachestyle\|awk\|bc\|cfg\|cl\|conf\|'. + \ 'crontab\|diff\|ecd\|elmfilt\|eterm\|expect\|exports\|'. + \ 'fgl\|fvwm\|gdb\|gnuplot\|gtkrc\|hb\|hog\|ia64\|icon\|'. + \ 'inittab\|lftp\|lilo\|lout\|lss\|lynx\|maple\|mush\|'. + \ 'muttrc\|nsis\|ora\|pcap\|pine\|po\|procmail\|'. + \ 'psf\|ptcap\|r\|radiance\|ratpoison\|readline\remind\|'. + \ 'ruby\|screen\|sed\|sm\|snnsnet\|snnspat\|snnsres\|spec\|'. + \ 'squid\|terminfo\|tidy\|tli\|tsscl\|vgrindefs\|vrml\|'. + \ 'wget\|wml\|xf86conf\|xmath\)$' + let b:ECcommentOpen = '#' + let b:ECcommentClose = '' + elseif fileType == 'webmacro' + let b:ECcommentOpen = '##' + let b:ECcommentClose = '' + elseif fileType == 'ppwiz' + let b:ECcommentOpen = ';;' + let b:ECcommentClose = '' + elseif fileType == 'latte' + let b:ECcommentOpen = '\\;' + let b:ECcommentClose = '' + elseif fileType =~ '^\(tex\|abc\|erlang\|ist\|lprolog\|matlab\|mf\|'. + \ 'postscr\|ppd\|prolog\|simula\|slang\|slrnrc\|slrnsc\|'. + \ 'texmf\|virata\)$' + let b:ECcommentOpen = '%' + let b:ECcommentClose = '' + elseif fileType =~ '^\(caos\|cterm\|form\|foxpro\|sicad\|snobol4\)$' + let b:ECcommentOpen = '*' + let b:ECcommentClose = '' + elseif fileType =~ '^\(m4\|config\|automake\)$' + let b:ECcommentOpen = 'dnl ' + let b:ECcommentClose = '' + elseif fileType =~ '^\(vb\|aspvbs\|ave\|basic\|elf\|lscript\)$' + let b:ECcommentOpen = "'" + let b:ECcommentClose = '' + elseif fileType =~ '^\(plsql\|vhdl\|ahdl\|ada\|asn\|csp\|eiffel\|gdmo\|'. + \ 'haskell\|lace\|lua\|mib\|sather\|sql\|sqlforms\|sqlj\|'. + \ 'stp\)$' + let b:ECcommentOpen = '--' + let b:ECcommentClose = '' + elseif fileType == 'abaqus' + let b:ECcommentOpen = '**' + let b:ECcommentClose = '' + elseif fileType =~ '^\(aml\|natural\|vsejcl\)$' + let b:ECcommentOpen = '/*' + let b:ECcommentClose = '' + elseif fileType == 'ampl' + let b:ECcommentOpen = '\\#' + let b:ECcommentClose = '' + elseif fileType == 'bdf' + let b:ECcommentOpen = 'COMMENT ' + let b:ECcommentClose = '' + elseif fileType == 'btm' + let b:ECcommentOpen = '::' + let b:ECcommentClose = '' + elseif fileType == 'dcl' + let b:ECcommentOpen = '$!' + let b:ECcommentClose = '' + elseif fileType == 'dosbatch' + let b:ECcommentOpen = 'rem ' + let b:ECcommentClose = '' + elseif fileType == 'focexec' + let b:ECcommentOpen = '-*' + let b:ECcommentClose = '' + elseif fileType == 'forth' + let b:ECcommentOpen = '\\ ' + let b:ECcommentClose = '' + elseif fileType =~ '^\(fortran\|inform\|sqr\|uil\|xdefaults\|'. + \ 'xmodmap\|xpm2\)$' + let b:ECcommentOpen = '!' + let b:ECcommentClose = '' + elseif fileType == 'gp' + let b:ECcommentOpen = '\\\\' + let b:ECcommentClose = '' + elseif fileType =~ '^\(master\|nastran\|sinda\|spice\|tak\|trasys\)$' + let b:ECcommentOpen = '$' + let b:ECcommentClose = '' + elseif fileType == 'nroff' || fileType == 'groff' + let b:ECcommentOpen = ".\\\\\"" + let b:ECcommentClose = '' + elseif fileType == 'opl' + let b:ECcommentOpen = 'REM ' + let b:ECcommentClose = '' + elseif fileType == 'texinfo' + let b:ECcommentOpen = '@c ' + let b:ECcommentClose = '' + else + let b:ECcommentOpen = '' + let b:ECcommentClose = '' + endif + + if b:ECuseCommentsOp + let b:ECcommentMiddle = + \ s:ParseCommentsOp(b:ECcommentOpen, b:ECcommentClose) + if b:ECcommentMiddle == '' + let b:ECuseCommentsOp = 0 + endif + else + let b:ECcommentMiddle = '' + endif + + if !s:overrideEmptyLines + call s:CommentEmptyLines(fileType) + endif +endfunction + +" +" ParseCommentsOp(commentOpen, commentClose) +" commentOpen -- comment-open string +" commentClose-- comment-close string +" +" Try to extract the middle comment string from &comments. First hit wins. +" If nothing is found '' is returned. +" +function s:ParseCommentsOp(commentOpen, commentClose) + let commStr = &comments + let offset = 0 + let commentMiddle = '' + + while commStr != '' + " + " First decompose &omments into consecutive s-, m- and e-parts. + " + let s = stridx(commStr, 's') + if s == -1 + return '' + endif + + let commStr = strpart(commStr, s) + let comma = stridx(commStr, ',') + if comma == -1 + return '' + endif + let sPart = strpart(commStr, 0, comma) + + let commStr = strpart(commStr, comma) + let m = stridx(commStr, 'm') + if m == -1 + return '' + endif + + let commStr = strpart(commStr, m) + let comma = stridx(commStr, ',') + if comma == -1 + return '' + endif + let mPart = strpart(commStr, 0, comma) + + let commStr = strpart(commStr, comma) + let e = stridx(commStr, 'e') + if e == -1 + return '' + endif + + let commStr = strpart(commStr, e) + let comma = stridx(commStr, ',') + if comma == -1 + let comma = strlen(commStr) + endif + let ePart = strpart(commStr, 0, comma) + + let commStr = strpart(commStr, comma) + + " + " Now check wether this is what we want: + " Are the comment string the same? + " + let sColon = stridx(sPart, ':') + let eColon = stridx(ePart, ':') + if sColon == -1 || eColon == -1 + return '' + endif + if strpart(sPart, sColon + 1) != a:commentOpen + \ || strpart(ePart, eColon + 1) != a:commentClose + continue + endif + + let mColon = stridx(mPart, ':') + if mColon == -1 + return '' + endif + let commentMiddle = strpart(mPart, mColon + 1) + + " + " Check for any alignement. + " + let i = 1 + while sPart[i] != ':' + if sPart[i] == 'r' + let offset = strlen(a:commentOpen) - strlen(commentMiddle) + break + elseif sPart[i] == 'l' + let offset = 0 + break + elseif s:isDigit(sPart[i]) + let j = 1 + while s:isDigit(sPart[i + j]) + let j = j + 1 + endwhile + let offset = 1 * strpart(sPart, i, j) + break + endif + let i = i + 1 + endwhile + + if offset == 0 + let i = 1 + while ePart[i] != ':' + if ePart[i] == 'r' + let offset = strlen(a:commentClose) - strlen(commentMiddle) + break + elseif ePart[i] == 'l' + let offset = 0 + break + elseif s:isDigit(ePart[i]) + let j = 1 + while s:isDigit(ePart[i + j]) + let j = j + 1 + endwhile + let offset = 1 * strpart(ePart, i, j) + break + endif + + let i = i + 1 + endwhile + endif + + while offset > 0 + let commentMiddle = " " . commentMiddle + let offset = offset - 1 + endwhile + + break + endwhile + + return commentMiddle +endfunction + +" +" isDigit(char) +" +" Nomen est Omen. +" +function s:isDigit(char) + let r = 0 + + let charVal = char2nr(a:char) + + if charVal >= 48 && charVal <= 57 + let r = 1 + endif + + return r +endfunction + +" +" CommentEmptyLines(ft) +" ft -- filetype of current buffer +" +" Decides, if empty lines should be commentified or not. Add the filetype, +" you want to change, to the apropriate if-clause. +" +function s:CommentEmptyLines(ft) + " FIXME: Quick hack (tm)! + if 0 + " Add special filetypes here. + elseif b:ECcommentClose == '' + let b:ECemptyLines = 'yes' + else + let b:ECemptyLines = 'no' + endif +endfunction + +" +" CheckPossibleEmbedding(ft) +" ft -- the filetype of current buffer +" +" Check wether it makes sense to allow checking for the synIDs. +" Eg. C will never have embedded code... +" +function s:CheckPossibleEmbedding(ft) + if a:ft =~ '^\(php\|vim\|latte\|html\)$' + let b:ECpossibleEmbedding = 1 + else + " Since getting the synID is slow, we set the default to 'no'! + " There are also some 'broken' languages like the filetype for + " autoconf's configure.in's ('config'). + let b:ECpossibleEmbedding = 0 + endif +endfunction + +" +" CommentifyMultiPart(lineString, commentStart, commentEnd, action) +" lineString -- line to commentify +" commentStart -- comment-start string, eg '/*' +" commentEnd -- comment-end string, eg. '*/' +" commentMiddle -- comment-middle string, eg. ' *' +" +" This function commentifies code of languages, which have multipart +" comment strings, eg. '/*' - '*/' of C. +" +function s:CommentifyMultiPart(lineString, commentStart, + \ commentEnd, commentMiddle) + if s:Action == 'guess' || s:Action == 'first' || b:ECuseMPBlock + let todo = s:DecideWhatToDo(a:lineString, a:commentStart, a:commentEnd) + else + let todo = s:Action + endif + + if todo == 'decomment' + return s:UnCommentify(a:lineString, a:commentStart, + \ a:commentEnd, a:commentMiddle) + else + return s:Commentify(a:lineString, a:commentStart, + \ a:commentEnd, a:commentMiddle) + endif +endfunction + +" +" CommentifySinglePart(lineString, commentSymbol) +" lineString -- line to commentify +" commentSymbol -- comment string, eg '#' +" +" This function is used for all languages, whose comment strings +" consist only of one string at the beginning of a line. +" +function s:CommentifySinglePart(lineString, commentSymbol) + if s:Action == 'guess' || s:Action == 'first' + let todo = s:DecideWhatToDo(a:lineString, a:commentSymbol) + else + let todo = s:Action + endif + + if todo == 'decomment' + return s:UnCommentify(a:lineString, a:commentSymbol) + else + return s:Commentify(a:lineString, a:commentSymbol) + endif +endfunction + +" +" Escape(lineString, commentStart, commentEnd) +" +" Escape already present symbols. +" +function s:Escape(lineString, commentStart, commentEnd) + let line = a:lineString + + if b:ECaltOpen != '' + let line = substitute(line, s:EscapeString(a:commentStart), + \ b:ECaltOpen, "g") + endif + if b:ECaltClose != '' + let line = substitute(line, s:EscapeString(a:commentEnd), + \ b:ECaltClose, "g") + endif + + return line +endfunction + +" +" UnEscape(lineString, commentStart, commentEnd) +" +" Unescape already present escape symbols. +" +function s:UnEscape(lineString, commentStart, commentEnd) + let line = a:lineString + + if b:ECaltOpen != '' + let line = substitute(line, s:EscapeString(b:ECaltOpen), + \ a:commentStart, "g") + endif + if b:ECaltClose != '' + let line = substitute(line, s:EscapeString(b:ECaltClose), + \ a:commentEnd, "g") + endif + + return line +endfunction + +" +" Commentify(lineString, commentSymbol, [commentEnd]) +" lineString -- the line in work +" commentSymbol -- string to insert at the beginning of the line +" commentEnd -- string to insert at the end of the line +" may be omitted +" +" This function inserts the start- (and if given the end-) string of the +" comment in the current line. +" +function s:Commentify(lineString, commentSymbol, ...) + let line = a:lineString + let j = 0 + + " If a end string is present, insert it too. + if a:0 > 0 + " First we have to escape any comment already contained in the line, + " since (at least for C) comments are not allowed to nest. + let line = s:Escape(line, a:commentSymbol, a:1) + + if b:ECuseCommentsOp && b:ECuseMPBlock + \ && a:0 > 1 + \ && s:i > s:startBlock + let line = substitute(line, s:LookFor('commentmiddle'), + \ s:SubstituteWith('commentmiddle', a:2), "") + endif + + if !b:ECuseMPBlock || (b:ECuseMPBlock && s:i == s:endBlock) + " Align the closing part to the right. + if b:ECalignRight && s:inBlock + let len = s:GetLineLen(line, strlen(a:commentSymbol) + \ + strlen(b:ECprettyComments)) + while j < s:maxLen - len + let line = line .' ' + let j = j + 1 + endwhile + endif + + let line = substitute(line, s:LookFor('commentend'), + \ s:SubstituteWith('commentend', a:1), "") + endif + endif + + " insert the comment symbol + if !b:ECuseMPBlock || a:0 == 0 || (b:ECuseMPBlock && s:i == s:startBlock) + let line = substitute(line, s:LookFor('commentstart'), + \ s:SubstituteWith('commentstart', a:commentSymbol), "") + endif + + return line +endfunction + +" +" UnCommentify(lineString, commentSymbol, [commentEnd]) +" lineString -- the line in work +" commentSymbol -- string to remove at the beginning of the line +" commentEnd -- string to remove at the end of the line +" may be omitted +" +" This function removes the start- (and if given the end-) string of the +" comment in the current line. +" +function s:UnCommentify(lineString, commentSymbol, ...) + let line = a:lineString + + " remove the first comment symbol found on a line + if a:0 == 0 || !b:ECuseMPBlock || (b:ECuseMPBlock && s:i == s:startBlock) + let line = substitute(line, s:LookFor('decommentstart', + \ a:commentSymbol), + \ s:SubstituteWith('decommentstart'), "") + endif + + " If a end string is present, we have to remove it, too. + if a:0 > 0 + " First, we remove the trailing comment symbol. + if !b:ECuseMPBlock || (b:ECuseMPBlock && s:i == s:endBlock) + let line = substitute(line, s:LookFor('decommentend', a:1), + \ s:SubstituteWith('decommentend'), "") + + " Remove any trailing whitespace, if we used alignRight. + if b:ECalignRight + let line = substitute(line, ' *$', '', "") + endif + endif + + " Maybe we added a middle string. Remove it here. + if b:ECuseCommentsOp && b:ECuseMPBlock + \ && a:0 > 1 + \ && s:i > s:startBlock + let line = substitute(line, s:LookFor('decommentmiddle', a:2), + \ s:SubstituteWith('decommentmiddle'), "") + endif + + " Remove escaped inner comments. + let line = s:UnEscape(line, a:commentSymbol, a:1) + endif + + return line +endfunction + +" +" GetLineLen(line, offset) +" line -- line of which length should be computed +" offset -- maybe a shift of the line to the right +" +" Expands '\t' to it's tabstop value. +" +function s:GetLineLen(line, offset) + let len = a:offset + let i = 0 + + while a:line[i] != "" + if a:line[i] == "\t" + let len = (((len / &tabstop) + 1) * &tabstop) + else + let len = len + 1 + endif + let i = i + 1 + endwhile + + return len +endfunction + +" +" EscapeString(string) +" string -- string to process +" +" Escapes characters in 'string', which have some function in +" regular expressions, with a '\'. +" +" Returns the escaped string. +" +function s:EscapeString(string) + return escape(a:string, "*{}[]$^-") +endfunction + +" +" LookFor(what, ...) +" what -- what type of regular expression +" * checkstart: +" * checkend: +" check for comment at start/end of line +" * commentstart: +" * commentend: +" insert comment strings +" * decommentstart: +" * decommentend: +" remove comment strings +" a:1 -- comment string +" +function s:LookFor(what, ...) + if b:ECuseBlockIndent && s:inBlock + let handleWhitespace = s:blockIndentRegex + else + let handleWhitespace = b:ECsaveWhite + endif + + if a:what == 'checkstart' + let regex = '^'. b:ECsaveWhite . s:EscapeString(a:1) + \ . s:EscapeString(b:ECidentFront) + elseif a:what == 'checkend' + let regex = s:EscapeString(b:ECidentBack) + \ . s:EscapeString(a:1) . b:ECsaveWhite . '$' + elseif a:what == 'commentstart' + let regex = '^'. handleWhitespace + elseif a:what == 'commentmiddle' + let regex = '^'. handleWhitespace + elseif a:what == 'commentend' + let regex = '$' + elseif a:what == 'decommentstart' + let regex = '^'. b:ECsaveWhite . s:EscapeString(a:1) + \ . s:EscapeString(b:ECidentFront) . b:ECprettyUnComments + elseif a:what == 'decommentmiddle' + let regex = '^'. b:ECsaveWhite . s:EscapeString(a:1) + \ . s:EscapeString(b:ECidentFront) . b:ECprettyUnComments + elseif a:what == 'decommentend' + let regex = b:ECprettyUnComments . s:EscapeString(b:ECidentBack) + \ . s:EscapeString(a:1) . b:ECsaveWhite .'$' + endif + + return regex +endfunction + +" +" SubstituteWith(what, ...) +" what -- what type of regular expression +" * commentstart: +" * commentend: +" insert comment strings +" * decommentstart: +" * decommentend: +" remove comment strings +" a:1 -- comment string +" +function s:SubstituteWith(what, ...) + if a:what == 'commentstart' + \ || a:what == 'commentmiddle' + \ || a:what == 'commentend' + let commentSymbol = a:1 + else + let commentSymbol = '' + endif + + if b:ECuseBlockIndent && s:inBlock + let handleWhitespace = '\1' . commentSymbol + else + let handleWhitespace = b:ECrespectWhite . commentSymbol + \ . b:ECignoreWhite + endif + + if a:what == 'commentstart' + let regex = handleWhitespace . b:ECidentFront + \ . b:ECprettyComments + elseif a:what == 'commentmiddle' + let regex = handleWhitespace . b:ECidentFront + \ . b:ECprettyComments + elseif a:what == 'commentend' + let regex = b:ECprettyComments . b:ECidentBack . a:1 + elseif a:what == 'decommentstart' + \ || a:what == 'decommentmiddle' + \ || a:what == 'decommentend' + let regex = handleWhitespace + endif + + return regex +endfunction + +" +" +" DecideWhatToDo(lineString, commentStart, ...) +" lineString -- first line of block +" commentStart -- comment start symbol +" a:1 -- comment end symbol +" +function s:DecideWhatToDo(lineString, commentStart, ...) + " If we checked already, we return our previous result. + if !s:firstOfBlock + \ && (s:Action == 'first' + \ || (b:ECuseMPBlock && s:inBlock && a:0)) + return s:blockAction + endif + + let s:blockAction = 'comment' + + if s:inBlock && a:0 && b:ECuseMPBlock + let first = getline(s:startBlock) + let last = getline(s:endBlock) + + if first =~ s:LookFor('checkstart', a:commentStart) + \ && first !~ s:LookFor('checkend', a:1) + \ && last !~ s:LookFor('checkstart', a:commentStart) + \ && last =~ s:LookFor('checkend', a:1) + let s:blockAction = 'decomment' + endif + + return s:blockAction + endif + + if a:lineString =~ s:LookFor('checkstart', a:commentStart) + let s:blockAction = 'decomment' + endif + + if a:0 + if a:lineString !~ s:LookFor('checkend', a:1) + let s:blockAction = 'comment' + endif + endif + + let s:firstOfBlock = 0 + return s:blockAction +endfunction + +" +" TabsToSpaces(str) +" str -- string to convert +" +" Convert leading tabs of given string to spaces. +" +function s:TabsToSpaces(str) + let string = a:str + + " FIXME: Can we use something like retab? I don't think so, + " because retab changes every whitespace in the line, but we + " wan't to modify only the leading spaces. Is this a problem? + while string =~ '^\( *\)\t' + let string = substitute(string, '^\( *\)\t', '\1'. s:tabConvert, "") + endwhile + + return string +endfunction + +" +" SpacesToTabs(str) +" str -- string to convert +" +" Convert leading spaces of given string to tabs. +" +function s:SpacesToTabs(str) + let string = a:str + + if !&expandtab + while string =~ '^\(\t*\)'. s:tabConvert + let string = substitute(string, '^\(\t*\)'. s:tabConvert, + \ '\1\t', "") + endwhile + endif + + return string +endfunction + +" +" EnhCommentifyFallback4Embedded(test, fallback) +" test -- test for the special case +" fallback -- filetype instead of normal fallback +" +" This function is global. It should be called from filetype +" plugins like php, where the normal fallback behaviour may +" not work. One may use 'synFiletype' to reference the guessed +" filetype via synID. +" +function EnhCommentifyFallback4Embedded(test, fallback) + let b:EnhCommentifyFallbackTest = a:test + let b:EnhCommentifyFallbackValue = a:fallback +endfunction + +" +" Keyboard mappings. +" +noremap Comment + \ :call EnhancedCommentify('', 'comment') +noremap DeComment + \ :call EnhancedCommentify('', 'decomment') +noremap Traditional + \ :call EnhancedCommentify('', 'guess') +noremap FirstLine + \ :call EnhancedCommentify('', 'first') + +noremap VisualComment + \ :call EnhancedCommentify('', 'comment', + \ line("'<"), line("'>")) +noremap VisualDeComment + \ :call EnhancedCommentify('', 'decomment', + \ line("'<"), line("'>")) +noremap VisualTraditional + \ :call EnhancedCommentify('', 'guess', + \ line("'<"), line("'>")) +noremap VisualFirstLine + \ :call EnhancedCommentify('', 'first', + \ line("'<"), line("'>")) +" +" Finally set keybindings. +" +" SetKeybindings(where) +" where -- "l" for local to the buffer, "g" for global +" +function s:SetKeybindings(where) + if a:where == "l" + let where = "" + let ns = "b" + else + let where = "" + let ns = "s" + endif + + execute "let userBindings = ". ns .":ECuserBindings" + execute "let useAltKeys = ". ns .":ECuseAltKeys" + execute "let traditionalMode = ". ns .":ECtraditionalMode" + execute "let firstLineMode = ". ns .":ECfirstLineMode" + execute "let bindInNormal = ". ns .":ECbindInNormal" + execute "let bindInInsert = ". ns .":ECbindInInsert" + execute "let bindInVisual = ". ns .":ECbindInVisual" + + if userBindings + " + " *** Put your personal bindings here! *** + " + else + if useAltKeys + let s:c = '' + let s:x = '' + let s:C = '' + let s:X = '' + else + let s:c = 'c' + let s:x = 'x' + let s:C = 'C' + let s:X = 'X' + endif + + if traditionalMode + let s:Method = 'Traditional' + elseif firstLineMode + let s:Method = 'FirstLine' + else + let s:Method = 'Comment' + + " Decomment must be defined here. Everything else is mapped below. + if bindInNormal + execute 'nmap '. where .' '. s:C + \ .' DeCommentj' + execute 'nmap '. where .' '. s:X + \ .' DeComment' + endif + + if bindInInsert + execute 'imap '. where .' '. s:C + \ .' DeCommentji' + execute 'imap '. where .' '. s:X + \ .' DeCommenti' + endif + + if bindInVisual + execute 'vmap '. where .' '. s:C + \ .' VisualDeCommentj' + execute 'vmap '. where .' '. s:X + \ .' VisualDeComment' + endif + endif + + if bindInNormal + execute 'nmap '. where .' '. s:c + \ .' '. s:Method .'j' + execute 'nmap '. where .' '. s:x + \ .' '. s:Method + endif + + if bindInInsert + execute 'imap '. where .' '. s:c + \ .' '. s:Method .'ji' + execute 'imap '. where .' '. s:x + \ .' '. s:Method + endif + + if bindInVisual + execute 'vmap '. s:c + \ .' Visual'. s:Method .'j' + execute 'vmap '. where .' '. s:x + \ .' Visual'. s:Method + endif + endif +endfunction + +if !s:ECbindPerBuffer + call s:SetKeybindings("g") +endif + +let &cpo = s:savedCpo + +" vim: set sts=4 sw=4 ts=8 :