Warning, /sdk/kde-dev-scripts/kde-devel-vim.vim is written in an unsupported language. File is not indexed.

0001 " To use this file, add this line to your ~/.vimrc:, w/o the dquote
0002 " source /path/to/kde/sources/kdesdk/scripts/kde-devel-vim.vim
0003 "
0004 " For CreateChangeLogEntry() : If you don't want to re-enter your
0005 " Name/Email in each vim session then make sure to have the viminfo
0006 " option enabled in your ~/.vimrc, with the '!' flag, enabling persistent
0007 " storage of global variables. Something along the line of
0008 " set   viminfo=%,!,'50,\"100,:100,n~/.viminfo
0009 " should do the trick.
0010 "
0011 " To make use of the ,ll and ,lg shortcuts you need to have the files
0012 " GPLHEADER and LGPLHEADER in your home directory. Their content will be
0013 " copied as license header then.
0014 
0015 " Don't include these in filename completions
0016 set suffixes+=.lo,.o,.moc,.la,.closure,.loT
0017 
0018 " Search for headers here
0019 set path=.,/usr/include,/usr/local/include,
0020 if $QTDIR != ''
0021     let &path = &path . $QTDIR . '/include/,'
0022     let &path = &path . $QTDIR . '/include/Qt/,'
0023     let &path = &path . $QTDIR . '/include/QtCore/,'
0024     let &path = &path . $QTDIR . '/include/Qt3Support/,'
0025     let &path = &path . $QTDIR . '/include/QtAssistant/,'
0026     let &path = &path . $QTDIR . '/include/QtDBus/,'
0027     let &path = &path . $QTDIR . '/include/QtDesigner/,'
0028     let &path = &path . $QTDIR . '/include/QtGui/,'
0029     let &path = &path . $QTDIR . '/include/QtNetwork/,'
0030     let &path = &path . $QTDIR . '/include/QtOpenGL/,'
0031     let &path = &path . $QTDIR . '/include/QtSql/,'
0032     let &path = &path . $QTDIR . '/include/QtSvg/,'
0033     let &path = &path . $QTDIR . '/include/QtTest/,'
0034     let &path = &path . $QTDIR . '/include/QtUiTools/,'
0035     let &path = &path . $QTDIR . '/include/QtXml/,'
0036 endif
0037 if $KDEDIR != ''
0038     let &path = &path . $KDEDIR . '/include/,'
0039 endif
0040 if $KDEDIRS != ''
0041     let &path = &path . substitute( $KDEDIRS, '\(:\|$\)', '/include,', 'g' )
0042 endif
0043 set path+=,
0044 
0045 " Use makeobj to build
0046 set mp=makeobj
0047 
0048 " If TagList is Loaded then get a funny statusline
0049 " Only works if kde-devel-vim.vim is loaded after taglist.
0050 " Droping this script in ~/.vim/plugin works fine
0051 if exists('loaded_taglist')
0052     let Tlist_Process_File_Always=1
0053     set statusline=%<%f:[\ %{Tlist_Get_Tag_Prototype_By_Line()}\ ]\ %h%m%r%=%-14.(%l,%c%V%)\ %P
0054 endif
0055 
0056 " Insert tab character in whitespace-only lines, complete otherwise
0057 inoremap <Tab> <C-R>=SmartTab()<CR>
0058 
0059 if !exists("DisableSmartParens")
0060 " Insert a space after ( or [ and before ] or ) unless preceded by a matching
0061 " paren/bracket or space or inside a string or comment. Comments are only
0062 " recognized as such if they start on the current line :-(
0063 inoremap ( <C-R>=SmartParens( '(' )<CR>
0064 inoremap [ <C-R>=SmartParens( '[' )<CR>
0065 inoremap ] <C-R>=SmartParens( ']', '[' )<CR>
0066 inoremap ) <C-R>=SmartParens( ')', '(' )<CR>
0067 endif
0068 
0069 " Insert an #include statement for the current/last symbol
0070 inoremap <F5> <C-O>:call AddHeader()<CR>
0071 
0072 " Insert a forward declaration for the current/last symbol
0073 inoremap <S-F5> <C-O>:call AddForward()<CR>
0074 
0075 " Switch between header and implementation files on ,h
0076 nmap <silent> ,h :call SwitchHeaderImpl()<CR>
0077 nmap <silent> ,p :call SwitchPrivateHeaderImpl()<CR>
0078 
0079 " Comment selected lines on ,c in visual mode
0080 vmap ,c :s,^,//X ,<CR>:noh<CR>
0081 " Uncomment selected lines on ,u in visual mode
0082 vmap ,u :s,^//X ,,<CR>
0083 
0084 " Insert an include guard based on the file name on ,i
0085 nmap ,i :call IncludeGuard()<CR>
0086 
0087 " Insert license headers at the top of the file
0088 nmap ,lg :call LicenseHeader( "GPL" )<CR>
0089 nmap ,ll :call LicenseHeader( "LGPL" )<CR>
0090 nmap ,lm :call LicenseHeader( "MIT" )<CR>
0091 
0092 " Expand #i to #include <.h> or #include ".h". The latter is chosen
0093 " if the character typed after #i is a dquote
0094 " If the character is > #include <> is inserted (standard C++ headers w/o .h)
0095 iab #i <C-R>=SmartInclude()<CR>
0096 
0097 " Insert a stripped down CVS diff
0098 iab DIFF <Esc>:call RunDiff()<CR>
0099 
0100 " mark 'misplaced' tab characters
0101 set listchars=tab:·\ ,trail:·
0102 set list
0103 
0104 set incsearch
0105 
0106 function! SetCodingStyle()
0107     if &syntax == 'cmake'
0108         call SmartParensOff()
0109         set sw=3
0110         set ts=3
0111         set et
0112         set tw=0
0113         return
0114     endif
0115     if ( &syntax !~ '^\(c\|cpp\|java\)$' )
0116         return
0117     endif
0118     "the path for the file
0119     let pathfn = expand( '%:p:h' )
0120     if pathfn =~ 'nmm'
0121         call SmartParensOff()
0122         inoremap ( <C-R>=SpaceBetweenKeywordAndParens()<CR>
0123         let g:need_brace_on_next_line = '\<\(class\|namespace\|struct\)\>'
0124         let g:need_brace_on_same_line = '\<\(if\|else\|while\|switch\|do\|enum\|for\|try\|catch\)\>'
0125         set sw=4
0126         set ts=4
0127         set noet
0128         set tw=100
0129     elseif pathfn =~ 'xine-lib'
0130         call SmartParensOff()
0131         let g:need_brace_on_next_line = '\<\(class\|namespace\|struct\)\>'
0132         let g:need_brace_on_same_line = '\<\(if\|else\|while\|switch\|do\|foreach\|forever\|enum\|for\|try\|catch\)\>'
0133         set sw=2
0134         set sts=2
0135         set ts=8
0136         set noet
0137         "set tw=100
0138     elseif pathfn =~ 'kdemultimedia\/juk'
0139         call SmartParensOff()
0140         let g:need_brace_on_next_line = '\<\(class\|namespace\|struct\|if\|else\|while\|switch\|do\|foreach\|forever\|enum\|for\|try\|catch\)\>'
0141         let g:need_brace_on_same_line = ''
0142         set sw=4
0143         set sts=4
0144         set et
0145         "set tw=100
0146     elseif pathfn =~ 'kdenetwork\/kopete'
0147         call SmartParensOff()
0148         let g:need_brace_on_next_line = '\<\(class\|namespace\|struct\|if\|else\|while\|switch\|do\|foreach\|forever\|enum\|for\|try\|catch\)\>'
0149         let g:need_brace_on_same_line = ''
0150         set sw=4
0151         set sts=4
0152         set noet
0153         "set tw=100
0154     else   " kdelibs/kf5/qt coding style
0155         call SmartParensOff()
0156         inoremap ( <C-R>=SpaceBetweenKeywordAndParens()<CR>
0157         let g:need_brace_on_next_line = '\<\(class\|namespace\|struct\)\>'
0158         let g:need_brace_on_same_line = '\<\(if\|else\|while\|switch\|do\|foreach\|forever\|enum\|for\|try\|catch\)\>'
0159         set sw=4
0160         set sts=4
0161         set et
0162         "set tw=100
0163     endif
0164     if ( !exists("g:noautobrace") )
0165         call EnableSmartLineBreak()
0166     endif
0167 endfunction
0168 
0169 function! DisableSmartLineBreak()
0170     iunmap <CR>
0171     iuna else
0172 endfunction
0173 function! EnableSmartLineBreak()
0174     if exists("*pumvisible")
0175         inoremap <CR> <C-R>=pumvisible() ? "\<lt>CR>" : "\<lt>ESC>:call SmartLineBreak()\<lt>CR>a\<lt>CR>"<CR>
0176     else
0177         inoremap <CR> <ESC>:call SmartLineBreak()<CR>a<CR>
0178     endif
0179     iab else <C-R>=SmartElse()<CR>
0180 endfunction
0181 
0182 function! SmartElse()
0183     "let next = nr2char( getchar( 0 ) )
0184     let prefix = ''
0185     if strlen(g:need_brace_on_same_line) > 0 && 'else' =~ g:need_brace_on_same_line
0186         if getline('.') =~ '^\s*$'
0187             if getline(line('.') - 1) =~ '}$'
0188                 let prefix = prefix . "\<ESC>kmMjdd`MA "
0189             elseif getline(line('.') - 1) =~ '}\s*$'
0190                 let prefix = prefix . "\<ESC>kmMjdd`MA"
0191             endif
0192         endif
0193     endif
0194     return prefix . "else\<Right>"
0195 endfunction
0196 
0197 " automatic indenting is required for SmartLineBreak to work correctly
0198 filetype indent on
0199 
0200 function! CreateMatchLine()
0201     let linenum = line( '.' )
0202     let current_line = getline( linenum )
0203     " don't do magic if the cursor isn't at the end of the line or if it's
0204     " inside a // comment
0205     if col( '.' ) != strlen( current_line ) || match( current_line, '//' ) >= 0
0206         return ''
0207     endif
0208     " remove whitespace at the end
0209     if match( current_line, '\s\+$' ) >= 0
0210         :execute ':s/\s*$//'
0211         " the following is needed if return '' is called
0212         :execute "normal $"
0213     endif
0214     let current_line = getline( linenum )
0215     " remove all /* */ comments
0216     let current_line = substitute( current_line, '/\*.\{-}\*/', '', 'g' )
0217     " remove all strings
0218     let current_line = substitute( current_line, "'[^']*'", '', 'g' )
0219     let current_line = substitute( current_line, '"\(\\"\|[^"]\)*"', '', 'g' )
0220     " remove all ( )
0221     while current_line =~ '(.*)'
0222         let current_line = substitute( current_line, '([^()]*)', '', 'g' )
0223     endwhile
0224     " prepend earlier lines until we find a ; or {
0225     while linenum > 1 && current_line !~ ';' && current_line !~ '{.\+$'
0226         let linenum = linenum - 1
0227         let prev_line = getline(linenum)
0228         if synIDattr(synID(linenum, 1, 1), "name") == 'cComment' "inside a /* */ comment at the beginning of the line
0229             if stridx(prev_line, '*/') == -1
0230                 " next line please
0231                 let prev_line = ''
0232             else
0233                 " remove everything before */
0234                 let prev_line = substitute(prev_line, '^.*\*/', '*/', '')
0235             endif
0236         endif
0237         " remove // comment
0238         let prev_line = substitute(prev_line, '//.*$', '', '' )
0239         " concatenate the lines with a space in between
0240         let current_line = prev_line.' '.current_line
0241         " remove all /* */ comments
0242         let current_line = substitute( current_line, '/\*.\{-}\*/', '', 'g' )
0243         " remove all strings
0244         let current_line = substitute( current_line, "'[^']*'", '', 'g' )
0245         let current_line = substitute( current_line, '"\(\\"\|[^"]\)*"', '', 'g' )
0246         " remove all ( )
0247         while current_line =~ '(.*)'
0248             let current_line = substitute( current_line, '([^()]*)', '', 'g' )
0249         endwhile
0250     endwhile
0251     " remove everything until the last ;
0252     let current_line = substitute( current_line, '^.*;', '', '' )
0253     " remove everything until the last { which is not at the end of the line
0254     let current_line = substitute( current_line, '^.*{\(.\+\)$', '\1', '' )
0255     " remove all [ ]
0256     while current_line =~ '\[.*\]'
0257         let current_line = substitute( current_line, '\[[^\[\]]*\]', '', 'g' )
0258     endwhile
0259     " if <CR> was pressed inside ( ), [ ] or /* */ don't add braces
0260     if current_line =~ '[(\[]' || current_line =~ '/\*'
0261         return ''
0262     endif
0263     return current_line
0264 endfunction
0265 
0266 function! AddClosingBrace(current_line)
0267     if a:current_line =~ '\<enum\|class\|struct\>'
0268         :execute "normal o};\<ESC>k"
0269     elseif a:current_line =~ '\<namespace\>'
0270         let namespace = substitute( a:current_line, '^.*namespace\s\+', '', '' )
0271         let namespace = substitute( namespace, '\s.*$', '', '' )
0272         :execute "normal o} // namespace " . namespace . "\<ESC>k"
0273     else
0274         :execute "normal o}\<ESC>k"
0275     endif
0276 endfunction
0277 
0278 function! SmartLineBreak()
0279     if synIDattr(synID(line("."), col("."), 1), "name") == 'cComment' "inside a /* */ comment at the point where the line break occurs
0280         return
0281     endif
0282     let match_line = CreateMatchLine()
0283     if match_line == ''
0284         return
0285     endif
0286 
0287     let match_position1 = -1
0288     let match_position2 = -1
0289     if strlen(g:need_brace_on_same_line) > 0
0290         let match_position1 = match(match_line, g:need_brace_on_same_line)
0291         if match_position1 > 0
0292             while strpart(match_line, match_position1 - 1, 1) == '#'
0293                 let old_position = match_position1
0294                 let match_position1 = match(match_line, g:need_brace_on_same_line, match_position1 + 1)
0295                 if match_position1 == -1
0296                     if strpart(match_line, old_position, 2) == 'if'
0297                         :execute "normal o#endif\<ESC>k$"
0298                     endif
0299                     return
0300                 endif
0301             endwhile
0302         endif
0303     endif
0304     if strlen(g:need_brace_on_next_line) > 0 && match_position1 == -1
0305         let match_position2 = match(match_line, g:need_brace_on_next_line)
0306         if match_position2 > 0
0307             while strpart(match_line, match_position2 - 1, 1) == '#'
0308                 let old_position = match_position2
0309                 let match_position2 = match(match_line, g:need_brace_on_same_line, match_position2 + 1)
0310                 if match_position2 == -1
0311                     if strpart(match_line, old_position, 2) == 'if'
0312                         :execute "normal o#endif\<ESC>k$"
0313                     endif
0314                     return
0315                 endif
0316             endwhile
0317         endif
0318     endif
0319 
0320     if match_position1 > -1
0321         if match_line =~ '}\s*else\>'
0322             " make sure else is on the same line as the closing brace
0323             if getline('.') =~ '^\s*else'
0324                 if getline(line('.') - 1) =~ '}$'
0325                     :execute "normal kA \<ESC>J"
0326                 elseif getline(line('.') - 1) =~ '}\s*$'
0327                     :execute "normal kJ"
0328                 endif
0329             endif
0330         endif
0331         while getline('.') =~ '^\s*{$'
0332             " opening brace is on its own line: move it up
0333             :execute "normal kJ"
0334         endwhile
0335         if match_line =~ '{$'
0336             if getline('.') =~ '[^ ]{$'
0337                 :execute ':s/{$/ {/'
0338             endif
0339         else
0340             :execute ':s/$/ {/'
0341         endif
0342         call AddClosingBrace(match_line)
0343     elseif getline('.') =~ '^\s*{$'
0344         call AddClosingBrace('')
0345     elseif match_position2 > -1
0346         if match_line =~ '{$'
0347             :execute ':s/\s*{$//'
0348         endif
0349         :execute "normal o{"
0350         call AddClosingBrace(match_line)
0351     endif
0352     :execute "normal $"
0353 endfunction
0354 
0355 function! SmartParensOn()
0356     inoremap ( <C-R>=SmartParens( '(' )<CR>
0357     inoremap [ <C-R>=SmartParens( '[' )<CR>
0358     inoremap ] <C-R>=SmartParens( ']', '[' )<CR>
0359     inoremap ) <C-R>=SmartParens( ')', '(' )<CR>
0360 endfunction
0361 
0362 function! SmartParensOff()
0363     if strlen(mapcheck('[','i')) > 0
0364         iunmap (
0365         iunmap [
0366         iunmap ]
0367         iunmap )
0368     endif
0369 endfunction
0370 
0371 function! SmartTab()
0372     let col = col('.') - 1
0373     if !col || getline('.')[col-1] !~ '\k'
0374         return "\<Tab>"
0375     else
0376         return "\<C-P>"
0377     endif
0378 endfunction
0379 
0380 function! SmartParens( char, ... )
0381     if ! ( &syntax =~ '^\(c\|cpp\|java\)$' )
0382         return a:char
0383     endif
0384     let s = strpart( getline( '.' ), 0, col( '.' ) - 1 )
0385     if s =~ '//'
0386         return a:char
0387     endif
0388     let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' )
0389     let s = substitute( s, "'[^']*'", '', 'g' )
0390     let s = substitute( s, '"\(\\"\|[^"]\)*"', '', 'g' )
0391     if s =~ "\\([\"']\\|/\\*\\)"
0392         return a:char
0393     endif
0394     if a:0 > 0
0395         if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == a:1 . ' '
0396             return "\<BS>" . a:char
0397         endif
0398         if strpart( getline( '.' ), col( '.' ) - 2, 1 ) == ' '
0399             return a:char
0400         endif
0401         return ' ' . a:char
0402     endif
0403     if !exists("g:DisableSpaceBeforeParen")
0404         if a:char == '('
0405             if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == 'if' ||
0406               \strpart( getline( '.' ), col( '.' ) - 4, 3 ) == 'for' ||
0407               \strpart( getline( '.' ), col( '.' ) - 6, 5 ) == 'while' ||
0408               \strpart( getline( '.' ), col( '.' ) - 7, 6 ) == 'switch'
0409                 return ' ( '
0410             endif
0411         endif
0412     endif
0413     return a:char . ' '
0414 endfunction
0415 
0416 function! SpaceBetweenKeywordAndParens()
0417     if ! ( &syntax =~ '^\(c\|cpp\|java\)$' )
0418         return '('
0419     endif
0420     let s = strpart( getline( '.' ), 0, col( '.' ) - 1 )
0421     if s =~ '//'
0422         " text inside a comment
0423         return '('
0424     endif
0425     let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' )
0426     let s = substitute( s, "'[^']*'", '', 'g' )
0427     let s = substitute( s, '"\(\\"\|[^"]\)*"', '', 'g' )
0428     if s =~ "\\([\"']\\|/\\*\\)"
0429         " text inside a string
0430         return '('
0431     endif
0432     if a:0 > 0
0433         if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == a:1 . ' '
0434             return "\<BS>" . a:char
0435         endif
0436         if strpart( getline( '.' ), col( '.' ) - 2, 1 ) == ' '
0437             return a:char
0438         endif
0439         return ' ' . a:char
0440     endif
0441     if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == 'if' ||
0442         \strpart( getline( '.' ), col( '.' ) - 4, 3 ) == 'for' ||
0443         \strpart( getline( '.' ), col( '.' ) - 6, 5 ) == 'while' ||
0444         \strpart( getline( '.' ), col( '.' ) - 7, 6 ) == 'switch' ||
0445         \strpart( getline( '.' ), col( '.' ) - 8, 7 ) == 'foreach' ||
0446         \strpart( getline( '.' ), col( '.' ) - 8, 7 ) == 'forever'
0447         return ' ('
0448     endif
0449     return '('
0450 endfunction
0451 
0452 function! SwitchHeaderImpl()
0453     let privateheaders = '_p\.\([hH]\|hpp\|hxx\)$'
0454     let headers = '\.\([hH]\|hpp\|hxx\)$'
0455     let impl = '\.\([cC]\|cpp\|cc\|cxx\)$'
0456     let fn = expand( '%' )
0457     if fn =~ privateheaders
0458         let list = glob( substitute( fn, privateheaders, '.*', '' ) )
0459     elseif fn =~ headers
0460         let list = glob( substitute( fn, headers, '.*', '' ) )
0461     elseif fn =~ impl
0462         let list = glob( substitute( fn, impl, '.*', '' ) )
0463     endif
0464     while strlen( list ) > 0
0465         let file = substitute( list, "\n.*", '', '' )
0466         let list = substitute( list, "[^\n]*", '', '' )
0467         let list = substitute( list, "^\n", '', '' )
0468         if ( ( fn =~ headers || fn =~ privateheaders ) && file =~ impl ) || ( fn =~ impl && file =~ headers )
0469             call AskToSave()
0470             execute( "edit " . file )
0471             return
0472         endif
0473     endwhile
0474     if ( fn =~ headers )
0475         call AskToSave()
0476         if exists( "$implextension" )
0477             let file = substitute( fn, headers, '.' . $implextension, '' )
0478         else
0479             let file = substitute( fn, headers, '.cpp', '' )
0480         endif
0481         " check for modified state of current buffer and if modified ask:
0482         " save, discard, cancel
0483         execute( 'edit '.file )
0484         call append( 0, "#include \"".fn."\"" )
0485         call append( 2, "// vim: sw=4 sts=4 et tw=100" )
0486         execute( "set sw=4" )
0487         execute( "set sts=4" )
0488         execute( "set et" )
0489         "execute( "set tw=100" )
0490     elseif fn =~ impl
0491         call AskToSave()
0492         let file = substitute( fn, impl, '.h', '' )
0493         execute( "edit ".file )
0494     endif
0495 endfunction
0496 
0497 function! SwitchPrivateHeaderImpl()
0498     let privateheaders = '_p\.\([hH]\|hpp\|hxx\)$'
0499     let headers = '\.\([hH]\|hpp\|hxx\)$'
0500     let impl = '\.\([cC]\|cpp\|cc\|cxx\)$'
0501     let fn = expand( '%' )
0502     if fn =~ privateheaders
0503         let list = glob( substitute( fn, privateheaders, '.*', '' ) )
0504     elseif fn =~ headers
0505         let list = glob( substitute( fn, headers, '_p.*', '' ) )
0506     elseif fn =~ impl
0507         let list = glob( substitute( fn, impl, '_p.*', '' ) )
0508     endif
0509     while strlen( list ) > 0
0510         let file = substitute( list, "\n.*", '', '' )
0511         let list = substitute( list, "[^\n]*", '', '' )
0512         let list = substitute( list, "^\n", '', '' )
0513         if ( fn =~ privateheaders && file =~ impl ) || ( fn =~ impl && file =~ privateheaders ) || ( fn =~ headers && file =~ privateheaders )
0514             call AskToSave()
0515             execute( "edit " . file )
0516             return
0517         endif
0518     endwhile
0519     if ( fn =~ privateheaders )
0520         call AskToSave()
0521         if exists( "$implextension" )
0522             let file = substitute( fn, privateheaders, '.' . $implextension, '' )
0523         else
0524             let file = substitute( fn, privateheaders, '.cpp', '' )
0525         endif
0526         " check for modified state of current buffer and if modified ask:
0527         " save, discard, cancel
0528         execute( 'edit '.file )
0529         call append( 0, "#include \"".fn."\"" )
0530         call append( 2, "// vim: sw=4 ts=4 noet" )
0531         execute( "set sw=4" )
0532         execute( "set ts=4" )
0533     elseif fn =~ impl
0534         let file = substitute( fn, impl, '_p.h', '' )
0535         call CreatePrivateHeader( file )
0536     elseif fn =~ headers
0537         let file = substitute( fn, headers, '_p.h', '' )
0538         call CreatePrivateHeader( file )
0539     endif
0540 endfunction
0541 
0542 function! AskToSave()
0543     if &modified
0544         let yesorno = input("Save changes before switching file? [Y/n]")
0545         if yesorno == 'y' || yesorno == '' || yesorno == 'Y'
0546             :execute 'w'
0547             return 1
0548         else
0549             return 0
0550         endif
0551     endif
0552     return 1
0553 endfunction
0554 
0555 function! CreatePrivateHeader( privateHeader )
0556     let privateheaders = '_p\.\([hH]\|hpp\|hxx\)$'
0557     let headers = '\.\([hH]\|hpp\|hxx\)$'
0558     let impl = '\.\([cC]\|cpp\|cc\|cxx\)$'
0559     let fn = expand( '%' )
0560     if fn =~ headers
0561         let className = ClassNameFromHeader()
0562     elseif fn =~ impl
0563         let className = ClassNameFromImpl()
0564     endif
0565 
0566     if AskToSave() && fn =~ headers
0567         :normal gg
0568         " check whether a Q_DECLARE_PRIVATE is needed
0569         let dp = search( '\(^\|\s\+\)Q_DECLARE_PRIVATE\s*(\s*'.className.'\s*)' )
0570         if dp == 0 "nothing found
0571             call search( '^\s*class\s\+\([A-Za-z0-9]\+_EXPORT\s\+\)\?[A-Za-z_]\+\s*\(:\s*[,\t A-Za-z_]\+\)\?\s*\n\?\s*{' )
0572             call search( '{' )
0573             let @c = className
0574             if getline(line('.')+1) =~ 'Q_OBJECT'
0575                 :normal joQ_DECLARE_PRIVATE(c)
0576             else
0577                 :normal oQ_DECLARE_PRIVATE(c)
0578             endif
0579             :execute 'w'
0580         endif
0581     endif
0582     execute( "edit ".a:privateHeader )
0583     let privateClassName = className . 'Private'
0584     let header = substitute( a:privateHeader, privateheaders, '.h', '' )
0585 
0586     call IncludeGuard()
0587     " FIXME: find out what license to use
0588     call LicenseHeader( "LGPL" )
0589     let @h = header
0590     let @p = privateClassName
0591     let @c = className
0592     :normal Gkko
#include "h"

class p
Q_DECLARE_PUBLIC(c)
protected:
c *q_ptr;
0593 endfunction
0594 
0595 function! ClassNameFromHeader()
0596     :normal gg
0597     call search( '^\s*class\s\+\([A-Za-z0-9]\+_EXPORT\s\+\)\?[A-Za-z_]\+\s*\(:\s*[,\t A-Za-z_]\+\)\?\s*\n\?\s*{' )
0598     "\zs and \ze mark start and end of the matching
0599     return matchstr( getline('.'), '\s\+\zs\w\+\ze\s*\(:\|{\|$\)' )
0600 endfunction
0601 
0602 function! ClassNameFromImpl()
0603     :normal gg
0604     call search( '\s*\([A-Za-z_]\+\)::\1\s*(' )
0605     :normal "cye
0606     return @c
0607 endfunction
0608 
0609 function! IncludeGuard()
0610     let guard = toupper( substitute( expand( '%' ), '[\./]', '_', 'g' ) )
0611     call append( '^', '#define ' . guard )
0612     +
0613     call append( '^', '#ifndef ' . guard )
0614     call append( '$', '#endif // ' . guard )
0615     +
0616 endfunction
0617 
0618 function! LicenseHeader( license )
0619     let filename = $HOME . "/" . a:license . "HEADER"
0620     execute ":0r " . filename
0621 "   call append( 0, system( "cat " . filename ) )
0622 endfunction
0623 
0624 function! SmartInclude()
0625     let next = nr2char( getchar( 0 ) )
0626     if next == '"'
0627         return "#include \".h\"\<Left>\<Left>\<Left>"
0628     endif
0629     if next == '>'
0630         return "#include <>\<Left>"
0631     endif
0632     return "#include <.h>\<Left>\<Left>\<Left>"
0633 endfunction
0634 
0635 function! MapIdentHeader( ident )
0636     let header = tolower(substitute(a:ident, '::', '/', 'g')).'.h'
0637     if a:ident =~ 'Private$'
0638         let header = substitute(header, 'private', '_p', '')
0639     endif
0640     " always prefer the headers in the same directory
0641     let check = header
0642     let slash = 1
0643     while slash != -1
0644         if filereadable( check )
0645             return '"' . check . '"'
0646         endif
0647         let slash = match( check, '/' )
0648         let check = strpart( check, slash + 1 )
0649     endwhile
0650     let check = tolower(substitute(a:ident, '::', '/', 'g')).'_p.h'
0651     let slash = 1
0652     while slash != -1
0653         if filereadable(check)
0654             return '"' . check . '"'
0655         endif
0656         let slash = match(check, '/')
0657         let check = strpart(check, slash + 1)
0658     endwhile
0659 
0660     " Qt stuff
0661     if a:ident =~ '^Q[A-Z]'
0662         " let's try to find the module
0663         let module = ''
0664         if $QTDIR != ''
0665             if filereadable($QTDIR.'/include/QtCore/'.a:ident)
0666                 let module = 'QtCore/'
0667             elseif filereadable($QTDIR.'/include/QtGui/'.a:ident)
0668                 let module = 'QtGui/'
0669             elseif filereadable($QTDIR.'/include/Qt3Support/'.a:ident)
0670                 let module = 'Qt3Support/'
0671             elseif filereadable($QTDIR.'/include/QtAssistant/'.a:ident)
0672                 let module = 'QtAssistant/'
0673             elseif filereadable($QTDIR.'/include/QtDBus/'.a:ident)
0674                 let module = 'QtDBus/'
0675             elseif filereadable($QTDIR.'/include/QtDesigner/'.a:ident)
0676                 let module = 'QtDesigner/'
0677             elseif filereadable($QTDIR.'/include/QtNetwork/'.a:ident)
0678                 let module = 'QtNetwork/'
0679             elseif filereadable($QTDIR.'/include/QtOpenGL/'.a:ident)
0680                 let module = 'QtOpenGL/'
0681             elseif filereadable($QTDIR.'/include/QtSql/'.a:ident)
0682                 let module = 'QtSql/'
0683             elseif filereadable($QTDIR.'/include/QtSvg/'.a:ident)
0684                 let module = 'QtSvg/'
0685             elseif filereadable($QTDIR.'/include/QtTest/'.a:ident)
0686                 let module = 'QtTest/'
0687             elseif filereadable($QTDIR.'/include/QtUiTools/'.a:ident)
0688                 let module = 'QtUiTools/'
0689             elseif filereadable($QTDIR.'/include/QtXml/'.a:ident)
0690                 let module = 'QtXml/'
0691             endif
0692         endif
0693         return '<'.module.a:ident.'>'
0694     elseif a:ident == 'qDebug' ||
0695           \a:ident == 'qWarning' ||
0696           \a:ident == 'qCritical' ||
0697           \a:ident == 'qFatal'
0698         return '<QtCore/QtDebug>'
0699     elseif a:ident == 'Q_EXPORT_PLUGIN2'
0700         return '<QtCore/QtPlugin>'
0701     elseif a:ident =~ 'Q_DECLARE_INTERFACE'
0702         return '<QtCore/QObject>'
0703     elseif a:ident =~ '^QT_VERSION' ||
0704           \a:ident =~ '^Q_\(W\|O\)S_' ||
0705           \a:ident =~ '^Q_CC_' ||
0706           \a:ident =~ '^Q_.*STRUCTOR_FUNCTION$' ||
0707           \a:ident =~ '^qu\?int' ||
0708           \a:ident =~ '^Q_.*_RESOURCE$' ||
0709           \a:ident == 'qreal' ||
0710           \a:ident == 'qAbs' ||
0711           \a:ident == 'qRound' ||
0712           \a:ident == 'qRound64' ||
0713           \a:ident == 'qMin' ||
0714           \a:ident == 'qMax' ||
0715           \a:ident == 'qBound' ||
0716           \a:ident == 'qVersion' ||
0717           \a:ident == 'qSharedBuild' ||
0718           \a:ident == 'Q_UNUSED' ||
0719           \a:ident == 'Q_ASSERT' ||
0720           \a:ident == 'qInstallMsgHandler' ||
0721           \a:ident == 'Q_GLOBAL_STATIC' ||
0722           \a:ident == 'Q_GLOBAL_STATIC_WITH_ARGS' ||
0723           \a:ident == 'qFuzzyCompare' ||
0724           \a:ident == 'qIsNull' ||
0725           \a:ident == 'qSwap' ||
0726           \a:ident =~ 'Q_DECLARE_\(FLAGS\|OPERATORS_FOR_FLAGS\|PRIVATE\|PUBLIC\)' ||
0727           \a:ident == 'Q_D' ||
0728           \a:ident == 'Q_Q' ||
0729           \a:ident == 'Q_DISABLE_COPY' ||
0730           \a:ident == 'qsrand' ||
0731           \a:ident == 'qrand'
0732         return '<QtCore/QtGlobal>'
0733 
0734     " Phonon stuff
0735     elseif a:ident =~ '^Phonon::[A-Z]'
0736         if a:ident =~ '^Phonon::\(NoDisc\|Cd\|Dvd\|Vcd\|.\+MetaData\|.*State\|.*Category\|.\+Error\)'
0737             return '<Phonon/Global>'
0738         endif
0739         return '<'.substitute(a:ident, '::', '/', 'g').'>'
0740     endif
0741 
0742     " KDE stuff
0743     let kdeincdir = substitute(system('kde4-config --prefix'), '[\n\r]*', '', 'g').'/include/KDE/'
0744     let classname = substitute(a:ident, '^.*:', '', '')
0745     let pathfn = expand('%:p:h')
0746     if filereadable(kdeincdir.classname) && !pathfn =~ 'kdelibs'
0747         return '<'.classname.'>'
0748     elseif filereadable(kdeincdir.'Phonon/'.classname)
0749         return '<Phonon/'.classname.'>'
0750     elseif filereadable(kdeincdir.'Solid/'.classname)
0751         return '<Solid/'.classname.'>'
0752     elseif filereadable(kdeincdir.'KIO/'.classname)
0753         return '<KIO/'.classname.'>'
0754     elseif filereadable(kdeincdir.'KParts/'.classname)
0755         return '<KParts/'.classname.'>'
0756     elseif a:ident == 'K_GLOBAL_STATIC'
0757         return '<KGlobal>'
0758     elseif a:ident == 'K_EXPORT_PLUGIN'
0759         return '<KPluginLoader>'
0760     elseif a:ident =~ 'K_PLUGIN_FACTORY'
0761         return '<KPluginFactory>'
0762     elseif a:ident == 'K\(Double\|Int\)\(NumInput\|SpinBox\)'
0763         return '<knuminput.h>'
0764     elseif a:ident == 'KSharedConfig'
0765         return '<kconfig.h>'
0766     elseif a:ident == 'KConfigGroup'
0767         return '<kconfiggroup.h>'
0768     elseif a:ident == 'KListViewItem'
0769         return '<klistview.h>'
0770     elseif a:ident =~ 'kd\(Debug\|Warning\|Error\|Fatal\|Backtrace\)'
0771         return '<kdebug.h>'
0772     elseif a:ident == 'kapp'
0773         return '<kapplication.h>'
0774     elseif a:ident == 'i18n' ||
0775           \a:ident == 'I18N_NOOP'
0776         return '<klocale.h>'
0777     elseif a:ident == 'locate' ||
0778           \a:ident == 'locateLocal'
0779         return '<kstandarddirs.h>'
0780     elseif a:ident =~ '\(Small\|Desktop\|Bar\|MainBar\|User\)Icon\(Set\)\?' ||
0781           \a:ident == 'IconSize'
0782         return '<kiconloader.h>'
0783 
0784     " Standard Library stuff
0785     elseif a:ident =~ '\(std::\)\?\(cout\|cerr\|endl\)'
0786         return '<iostream>'
0787     elseif a:ident =~ '\(std::\)\?is\(alnum\|alpha\|ascii\|blank\|graph\|lower\|print\|punct\|space\|upper\|xdigit\)'
0788         return '<cctype>'
0789     elseif a:ident == 'printf'
0790         return '<cstdio>'
0791     endif
0792 
0793     let check = header
0794     while 1
0795         if filereadable( check )
0796             return '"' . check . '"'
0797         endif
0798         let slash = match( check, '/' )
0799         if slash == -1
0800             return '<' . header . '>'
0801         endif
0802         let check = strpart( check, slash + 1 )
0803     endwhile
0804 endfunction
0805 
0806 " This is a rather dirty hack, but seems to work somehow :-) (malte)
0807 function! AddHeader()
0808     let s = getline( '.' )
0809     let i = col( '.' ) - 1
0810     while i > 0 && strpart( s, i, 1 ) !~ '[A-Za-z0-9_:]'
0811         let i = i - 1
0812     endwhile
0813     while i > 0 && strpart( s, i, 1 ) =~ '[A-Za-z0-9_:]'
0814         let i = i - 1
0815     endwhile
0816     let start = match( s, '[A-Za-z0-9_]\+\(::[A-Z][A-Za-z0-9_]*\)*', i )
0817     let end = matchend( s, '[A-Za-z0-9_]\+\(::[A-Z][A-Za-z0-9_]*\)*', i )
0818 "    if end > col( '.' )
0819 "        let end = matchend( s, '[A-Za-z0-9_]\+', i )
0820 "    endif
0821     let ident = strpart( s, start, end - start )
0822     let header = MapIdentHeader(ident)
0823     let include = '#include '.header
0824 
0825     let line = 1
0826     let incomment = 0
0827     let appendpos = 0
0828     let codestart = 0
0829     let similarpos = 0
0830     let similarity = 0
0831     while line <= line( '$' )
0832         let s = getline( line )
0833         if incomment == 1
0834             let end = matchend( s, '\*/' )
0835             if end == -1
0836                 let line = line + 1
0837                 continue
0838             else
0839                 let s = strpart( s, end )
0840                 let incomment = 0
0841             endif
0842         endif
0843         let s = substitute( s, '//.*', '', '' )
0844         let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' )
0845         if s =~ '/\*'
0846             let incomment = 1
0847         elseif s =~ '^' . include
0848             break
0849         elseif s =~ '^#include' && s !~ '\.moc"'
0850             let appendpos = line
0851             if s =~ '^#include '.header[0:similarity+1]
0852                 let similarpos = line
0853                 let similarity = similarity + 1
0854                 while s =~ '^#include '.header[0:similarity+1]
0855                     let similarity = similarity + 1
0856                 endwhile
0857                 if s[9:strlen(s)-2] > header[0:strlen(header)-2]
0858                     let similarpos = similarpos - 1
0859                     let similarity = 100 "this include belongs one line higher (assuming the order of includes already is alphabetically)
0860                 endif
0861             endif
0862         elseif codestart == 0 && s !~ '^$'
0863             let codestart = line
0864         endif
0865         let line = line + 1
0866     endwhile
0867     if similarpos > 0
0868         let appendpos = similarpos
0869     endif
0870     if line == line( '$' ) + 1
0871         if appendpos == 0
0872             call append( codestart - 1, include )
0873             call append( codestart, '' )
0874         else
0875             call append( appendpos, include )
0876         endif
0877     endif
0878 endfunction
0879 
0880 function! AddForward()
0881     let s = getline( '.' )
0882     let i = col( '.' ) - 1
0883     while i > 0 && strpart( s, i, 1 ) !~ '[A-Za-z0-9_:]'
0884         let i = i - 1
0885     endwhile
0886     while i > 0 && strpart( s, i, 1 ) =~ '[A-Za-z0-9_:]'
0887         let i = i - 1
0888     endwhile
0889     let start = match( s, '[A-Za-z0-9_]\+\(::[A-Za-z0-9_]\+\)*', i )
0890     let end = matchend( s, '[A-Za-z0-9_]\+\(::[A-Za-z0-9_]\+\)*', i )
0891     if end > col( '.' )
0892         let end = matchend( s, '[A-Za-z0-9_]\+', i )
0893     endif
0894     let ident = strpart( s, start, end - start )
0895     let forward = 'class ' . ident . ';'
0896 
0897     let line = 1
0898     let incomment = 0
0899     let appendpos = 0
0900     let codestart = 0
0901     while line <= line( '$' )
0902         let s = getline( line )
0903         if incomment == 1
0904             let end = matchend( s, '\*/' )
0905             if end == -1
0906                 let line = line + 1
0907                 continue
0908             else
0909                 let s = strpart( s, end )
0910                 let incomment = 0
0911             endif
0912         endif
0913         let s = substitute( s, '//.*', '', '' )
0914         let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' )
0915         if s =~ '/\*'
0916             let incomment = 1
0917         elseif s =~ '^' . forward
0918             break
0919         elseif s =~ '^\s*class [A-za-z0-9_]\+;' || (s =~ '^#include' && s !~ '\.moc"')
0920             let appendpos = line
0921         elseif codestart == 0 && s !~ '^$'
0922             let codestart = line
0923         endif
0924         let line = line + 1
0925     endwhile
0926     if line == line( '$' ) + 1
0927         if appendpos == 0
0928             call append( codestart - 1, forward )
0929             call append( codestart, '' )
0930         else
0931             call append( appendpos, forward )
0932         endif
0933     endif
0934 endfunction
0935 
0936 function! RunDiff()
0937     echo 'Diffing....'
0938     read! cvs diff -bB -I \\\#include | egrep -v '(^Index:|^=+$|^RCS file:|^retrieving revision|^diff -u|^[+-]{3})'
0939 endfunction
0940 
0941 function! CreateChangeLogEntry()
0942     let currentBuffer = expand( "%" )
0943 
0944     if exists( "g:EMAIL" )
0945         let mail = g:EMAIL
0946     elseif exists( "$EMAIL" )
0947         let mail = $EMAIL
0948     else
0949         let mail = inputdialog( "Enter Name/Email for Changelog entry: " ) 
0950     if mail == ""
0951         echo "Aborted ChangeLog edit..."
0952         return
0953     endif
0954     let g:EMAIL = mail
0955     endif
0956 
0957     if bufname( "ChangeLog" ) != "" && bufwinnr( bufname( "ChangeLog" ) ) != -1
0958     execute bufwinnr( bufname( "ChangeLog" ) ) . " wincmd w"
0959     else
0960         execute "split ChangeLog"
0961     endif
0962 
0963     let lastEntry = getline( nextnonblank( 1 ) )
0964     let newEntry = strftime("%Y-%m-%d") . "  " . mail
0965 
0966     if lastEntry != newEntry 
0967         call append( 0, "" )
0968         call append( 0, "" )
0969         call append( 0, newEntry )
0970     endif
0971 
0972     " like emacs, prepend the current buffer name to the entry. but unlike
0973     " emacs I have no idea how to figure out the current function name :(
0974     " (Simon)
0975     if currentBuffer != ""
0976         let newLine = "\t* " . currentBuffer . ": "
0977     else
0978         let newLine = "\t* "
0979     endif
0980 
0981     call append( 2, newLine )
0982 
0983     execute "normal 3G$"
0984 endfunction
0985 
0986 function! AddQtSyntax()
0987     if expand( "<amatch>" ) == "cpp"
0988         syn keyword qtKeywords     signals slots emit Q_SLOTS Q_SIGNALS
0989         syn keyword qtMacros       Q_OBJECT Q_WIDGET Q_PROPERTY Q_ENUMS Q_OVERRIDE Q_CLASSINFO Q_SETS SIGNAL SLOT Q_DECLARE_PUBLIC Q_DECLARE_PRIVATE Q_D Q_Q Q_DISABLE_COPY Q_DECLARE_METATYPE Q_PRIVATE_SLOT Q_FLAGS Q_INTERFACES Q_DECLARE_INTERFACE Q_EXPORT_PLUGIN2 Q_GADGET Q_SCRIPTABLE Q_INVOKABLE METHOD Q_ARG Q_RETURN_ARG Q_GLOBAL_STATIC Q_GLOBAL_STATIC_WITH_ARGS
0990         syn keyword qtCast         qt_cast qobject_cast qvariant_cast qstyleoption_cast qgraphicsitem_cast
0991         syn keyword qtTypedef      uchar uint ushort ulong Q_INT8 Q_UINT8 Q_INT16 Q_UINT16 Q_INT32 Q_UINT32 Q_LONG Q_ULONG Q_INT64 Q_UINT64 Q_LLONG Q_ULLONG pchar puchar pcchar qint8 quint8 qint16 quint16 qint32 quint32 qint64 quint64 qlonglong qulonglong qreal
0992         syn keyword kdeMacros      ASYNC PHONON_ABSTRACTBASE PHONON_OBJECT PHONON_HEIR PHONON_ABSTRACTBASE_IMPL PHONON_OBJECT_IMPL PHONON_HEIR_IMPL PHONON_PRIVATECLASS PHONON_PRIVATEABSTRACTCLASS K_DECLARE_PRIVATE K_D K_EXPORT_PLUGIN K_PLUGIN_FACTORY K_PLUGIN_FACTORY_DEFINITION K_PLUGIN_FACTORY_DECLARATION K_GLOBAL_STATIC K_GLOBAL_STATIC_WITH_ARGS
0993         syn keyword cRepeat        foreach
0994         syn keyword cRepeat        forever
0995 
0996         hi def link qtKeywords          Statement
0997         hi def link qtMacros            Type
0998         hi def link qtCast              Statement
0999         hi def link qtTypedef           Type
1000         hi def link kdeMacros           Type
1001     endif
1002 endfunction
1003 
1004 function! UpdateMocFiles()
1005     if &syntax == "cpp"
1006         let i = 1
1007         while i < 80
1008             let s = getline( i )
1009             if s =~ '^#include ".*\.moc"'
1010                 let s = substitute( s, '.*"\(.*\)\.moc"', '\1.h', '' )
1011                 if stridx( &complete, s ) == -1
1012                     let &complete = &complete . ',k' . s
1013                 endif
1014                 break
1015             endif
1016             let i = i + 1
1017         endwhile
1018     endif
1019 endfunction
1020 
1021 autocmd Syntax * call AddQtSyntax()
1022 autocmd CursorHold * call UpdateMocFiles()
1023 autocmd BufNewFile,BufRead * call SetCodingStyle()
1024 
1025 " vim: sw=4 sts=4 et