""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " Plugin Vim para programacion en C/C++. " " @autor: Daniel Lerch " @url: http://www.daniellerch.com " " Probado con exito en: Linux Fedora Core (FC3/FC4) """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " {{{ DOCUMENTACION: -------------------------------------------------------- " " INSTALACION: " Copiar cpp.vim en el directorio de pluggins de vim, por ejemplo en " /usr/share/vim/vimXX/plugin/ " " COMBINACIONES DE TECLAS: " Ctr+t: Salta a la definicion del tipo de la variable. " Ctr+f: Salta a la definicion de la funcion. " Ctr+l: Muestra la lista de miembros de la clase/estructura. " Ctr+c: Cierra la ventana del asistente. " " DEPENDENCIAS: " - ctags " - indent " - sed " - awk " - cat " - rm " - grep " - cut " " TODO: " - Soporte de herencia en el listado de tipos. " - Solo se solporta el operador sobrecargado [] en vectores, maps y similares. " " ------------------------------------------------------------------------ }}} " ---- CONFIGURACION --------------------------------------------------------- " {{{ " Lugares donde vim busca las cabeceras de C set path=.,/usr/include/c++/4.0.1,/usr/include/boost/,/usr/include/,/usr/include/mysql " Ficheros temporales utilizados let g:tf_assist = "~/.cpp.vim.assist.cpp" let g:tf_tags = "~/.cpp.vim.tags" let g:tf_code = "~/.cpp.vim.code" " Los tabulados y la identación son de X espacios set tabstop=3 set shiftwidth=3 " autoident set expandtab " deshabilitar con 'set noexpandtab' " Substituir tabulaciones por espacios "set expandtab " Para que vim permita plegar funciones con {{{ y }}} set fdm=marker " Muestra, durante un milisegundo, que parentesis se esta cerrando. set showmatch set matchtime=1 " Muestra la columna y la fila set ruler " Muestra la barra de estado set laststatus=2 " }}} " ---- COMBINACIONES DE TECLAS ----------------------------------------------- " {{{ " Modo insercion imap :call PSearch_Decl()a imap :call PSearch_Normal()a imap :call Cpp_List() imap :call Assistant_Close()a imap #i #include < imap usi using namespace " Modo normal nmap :call Assistant_ProcessEnter()a nmap :call Assistant_ProcessUpKey() nmap :call Assistant_ProcessDownKey() nmap :call Assistant_Close() " }}} " ---- COMANDOS -------------------------------------------------------------- " {{{ command! -nargs=0 TemplateDocComment call TemplateDocComment() command! -nargs=0 TemplateHeader call TemplateHeader() command! -nargs=0 TemplateMITLicense call TemplateMITLicense() " }}} " ---- FUNCIONES ------------------------------------------------------------- " {{{ Cpp_List(): Lista de opciones mediante el asistente function Cpp_List() let col_num = col('.')-1 let line = getline('.') " Requiere lista de metodos?: operadores . -> :: if line[col_num] == '.' || line[col_num] == '>' || line[col_num] == ':' call Cpp_ListMembers() elseif line[col_num] == '<' call Cpp_ListIncludes() endif endfunction " }}} " {{{ Cpp_GetBaseType(): Tipo de variable bajo el cursor function Cpp_GetBaseType() let type = "" let identif = "" let nline = line('.') let ncol = col('.') " Buscamos la declaracion de la variable :split normal gd " Ha funcionado gd? if nline == line('.') if ncol >= col('.') :quit call cursor(nline, ncol) return "" endif endif " Estamos en la declaracion, saltamos hacia atras buscando el tipo if stridx(getline('.'),'<')!=-1 && stridx(getline('.'),'>')!=-1 call search('[a-zA-Z_][a-zA-Z0-9_<>]*<.*>[ \*&]\+,\@!',"b") else call search('[a-zA-Z_][a-zA-Z0-9_<>]*[ \*&]\+,\@!',"b") endif let type = expand("") " Si es una plantilla obtenemos su tipo parametrizado let template = getline('.') let type_template = "" if stridx(template,'<')!=-1 && stridx(template,'>')!=-1 call search('[a-zA-Z_][a-zA-Z0-9_]*\s*>',"W") let type_template = expand("") :quit " Puede tratarse de un typedef try let ptt = '/typedef[ \t][a-zA-Z_][a-zA-Z0-9_<>]*[ \t]*'.type_template let ptt = ptt.'[ \t]*;/' exec "psearch ".ptt :wincmd w call search('[a-zA-Z_][a-zA-Z0-9_<>]*',"w") let type_template = expand("") :wincmd w :pclose catch endtry else :quit endif " Puede tratarse de un typedef try let pattern = '/typedef[ \t][a-zA-Z_][a-zA-Z0-9_<>]*[ \t]*'.type let pattern = pattern.'[ \t]*;/' exec "psearch ".pattern :wincmd w call search('[a-zA-Z_][a-zA-Z0-9_<>]*',"w") let type = expand("") :wincmd w :pclose catch endtry " Si es una plantilla, concatenamos su tipo if type_template != "" let type = type . ":".type_template endif " Dejar el cursor donde estaba call cursor(nline, ncol) return type endfunction " }}} " {{{ Cpp_GetType(): Tipo de variable encadenada function Cpp_GetType() " Guardamos la posicion actual let nline = line('.') let ncol = col('.') " Algunas variables utiles let fin = 0 let nparenth = 0 let is_string = 0 let col_num = col('.') let line_num = line('.') let line = getline('.') " Requiere lista de metodos?: operadores . -> :: if line[col_num] == '.' && line[col_num] != '>' && line[col_num] != ':' return endif if line[col_num] == '>' && line[col_num-1] != '-' return else let col_num = col_num - 1 endif if line[col_num] == ':' && line[col_num-1] != ':' let col_num = col_num - 1 return endif let col_num = col_num - 1 " Bucle de lectura con el objetivo de encontrar el inicio de la sentencia while fin == 0 " Lectura del caracter actual y desplazamiento hacia atras let c = line[col_num] let c_ant = line[col_num-1] if (c==';'||c=='='||c=='<'||(c=='>'&&(c_ant!='-'))||c=='+') &&is_string==0&&nparenth==0 " Colocamos el cursor al inicio de la sentencia call cursor(line_num, col_num) call search("[a-zA-Z_]","w") let fin = 1 elseif c=='"' if is_string == 1 let is_string = 0 else let is_string = 1 endif elseif c==')' if is_string==0 let nparenth = nparenth + 1 endif elseif c=='(' if is_string==0 let nparenth = nparenth - 1 endif endif " Fin de linea, continuamos con la linea anterior if col_num <= 0 let line_num = line_num - 1 let line = getline(line_num) let col_num = strlen(line) endif " Inicio del fichero if line_num == 0 return endif let col_num = col_num - 1 endwhile " El cursor esta situado al inicio de la sentencia, buscamos su tipo let type = Cpp_GetBaseType() if type == "" call cursor(nline, ncol) return endif let len = strlen(type) let pos = stridx(type, ':') let type_template = type if pos!=-1 let type_template = strpart(type, pos+1) let type = strpart(type, 0, pos) endif " Obtenemos la linea, ahora empezando en la misma sentencia y " finalizando cuando esta termina let line = strpart(getline(line(".")), col(".") - 1) if nline > line('.') let i = line('.')+1 while nline > i let line = line . getline(i) let i = i + 1 endwhile call cursor(nline, ncol) let line = line .strpart(getline(line(".")), 0, col('.')) endif call cursor(nline, ncol) " Bucle de busqueda del tipo deseado let fin = 0 let line = substitute(line, '->', ".", "g") let line = substitute(line, "::", ".", "g") let line = substitute(line, " ", "", "g") let len = stridx(line, '.') let identif = strpart(line,0,len) let first_time = 1 while fin == 0 let len = stridx(line,'.') if len != -1 let identif = strpart(line, 0, len) let pos_parent = stridx(identif,'(') if pos_parent != -1 let identif = strpart(identif, 0, pos_parent) endif let line = strpart(line, len+1) if identif != "" " Si contiene [ ] debemos buscar el tipo de la sobrecarga " del operador para modificar el tipo if stridx(identif,'[')!=-1 && stridx(identif,']')!=-1 let type = type_template else if first_time == 0 " Saltamos a la definicion del tipo let pattern = '/\(\(class\)\|\(struct\)\) '.type let pattern = pattern.'[;a-zA-Z_]\@!/' exec "silent! psearch ".pattern :wincmd w " Buscamos el tipo del identificador :exec "silent! psearch /[ \t^]".identif.".*(.*)/" :call search("[a-zA-Z_][a-zA-Z0-9_<>]*","b") :let type = expand("") :pclose else let first_time = 0 endif endif endif else let fin = 1 endif endwhile call cursor(nline, ncol) return type endfunction " }}} " {{{ Cpp_ListMembers(): Lista los metodos de una clase/estructura " " Soporte para herencia: (a hacer) " 1. Salto a la definicion de la clase (proceso normal) " 2. Localizar clases de las que se hereda " 3. Extraer los metodos de la clase (proceso normal) " 4. Bucle: para todas las clases de las que se hereda " -> saltar a la definicion de la clase " -> extraer los metodos de la misma y concatenarlos con g:tf_assist " 5. Ordenar g:tf_assist " function Cpp_ListMembers() call Assistant_Close() " Obtenemos el tipo let type = Cpp_GetType() if type == "" return endif " Saltamos a la definicion del tipo call PSearch_Decl() " Obtenemos el fichero donde buscar :wincmd w let file = bufname("%") :wincmd w :pclose " Borramos ficheros temporales anteriores call system("rm -f ".g:tf_tags." ".g:tf_assist) " Identamos el fichero fuente para que ctags no tenga problemas " con las lineas cortadas let cmd = "" let cmd = cmd."cat ".file."| indent -nhnl -nlp -l800 -o ".g:tf_code call system(cmd) " Generamos el fichero de tags let cmd = "" let cmd = cmd."ctags --sort=yes --language-force=c++ --extra=-q-f " let cmd = cmd."--fields=+aKfszn -f ".g:tf_tags." ".g:tf_code call system(cmd) " Generamos el fichero asistente let cmd = "" let cmd = cmd.'cat '.g:tf_tags let cmd = cmd.'| grep "\(kind:function\)\|\(kind:member\)" ' let cmd = cmd.'| grep "\(access:public\)\|\(access:protected\)" ' let cmd = cmd.'| sed -e "s/\t/ /g" ' let cmd = cmd.'| sed -e "s/ //g" ' let cmd = cmd.'| sed -e "s/ /@/" ' let cmd = cmd.'| sed -e "s/\/^ /@/g" ' let cmd = cmd.'| sed -e "s/\/^/@/g" ' let cmd = cmd.'| sed -e "s/\$\/;\" /@/g" ' let cmd = cmd.'| sed -e "s/ class:/@class:/g" ' let cmd = cmd.'| sed -e "s/ struct:/@struct:/g" ' let cmd = cmd.'| sed -e "s/ access:public/@+/" ' let cmd = cmd.'| sed -e "s/ access:protected/@#/" ' let cmd = cmd.'| grep ":'.type.'" ' let cmd = cmd."| awk -F'@' '{ print $1 \": [\" $6 \"] \" $3 }' " let cmd = cmd.'| grep "^[a-zA-Z_]" ' let cmd = cmd.'> '.g:tf_assist call system(cmd) " Abrimos el fichero asistente. exec ":split ".g:tf_assist :wincmd r :resize 8 :0 endfunction " }}} " {{{ Cpp_ListIncludes(): Lista las cabeceras disponibles function Cpp_ListIncludes() call system("find /usr/include/ -type f|sort|cut -c 14-100 > ".g:tf_assist) " Abrimos el fichero asistente. exec ":split ".g:tf_assist :wincmd r :resize 8 :0 endfunction " }}} " {{{ PSearch_Normal(): Llamada a 'psearch' del id bajo el cursor function PSearch_Normal() try let identifier = expand("") exec "silent! psearch ".identifier wincmd r wincmd w resize 8 wincmd w catch echo "PSearch_Normal(): ERROR patron no encontrado" endtry let file_1 = bufname("%") wincmd w let file_2 = bufname("%") wincmd w if file_1 == file_2 echo "PSearch_Normal(): ERROR patron no encontrado" :pclose endif endfunction " }}} " {{{ PSearch_Decl(): Busca la definicion del tipo function PSearch_Decl() " Obtenemos el tipo let identifier = Cpp_GetType() " Saltamos a la clase try let pattern = '/\(\(class\)\|\(struct\)\) '.identifier.'[;a-zA-Z_]\@!/' exec "silent! psearch ".pattern wincmd r wincmd w resize 8 wincmd w catch echo "PSearch(): ERROR patron no encontrado" endtry endfunction " }}} " {{{ Assistant_Close(): Cierra la ventana del asistente function Assistant_Close() let file = bufname("%") let filename = fnamemodify(file, ":t") :pclose if filename == fnamemodify(g:tf_assist, ":t") :quit! else :wincmd w let file = bufname("%") let filename = fnamemodify(file, ":t") if filename == fnamemodify(g:tf_assist, ":t") :quit! endif :wincmd w endif endfunction " }}} " {{{ Assistant_ProcessEnter(): Procesa tecla enter function Assistant_ProcessEnter() let file = bufname("%") let filename = fnamemodify(file, ":t") if filename == fnamemodify(g:tf_assist, ":t") let nline = line('.') call cursor(nline-1, 0) :normal ^ let line = getline('.') let pos = stridx(line, ':') if pos == -1 let pos = strlen(line) endif let line = strpart(line, 0, pos) :wincmd w exec "normal a".line endif endfunction " }}} " {{{ Assistant_ProcessUpKey(): Procesa tecla Up function Assistant_ProcessUpKey() let file = bufname("%") let filename = fnamemodify(file, ":t") if filename == fnamemodify(g:tf_assist, ":t") let nline = line('.') call cursor(nline, 0) let word = expand("") :highlight over_line term=bold ctermbg=grey guibg=grey exec ':match over_line /\%'.nline.'l/' endif endfunction " }}} " {{{ Assistant_ProcessDownKey(): Procesa tecla Down function Assistant_ProcessDownKey() let file = bufname("%") let filename = fnamemodify(file, ":t") if filename == fnamemodify(g:tf_assist, ":t") let nline = line('.') call cursor(nline, 0) let word = expand("") :highlight over_line term=bold ctermbg=grey guibg=grey exec ':match over_line /\%'.nline.'l/' endif endfunction " }}} " ---- PLANTILLAS ------------------------------------------------------------- " {{{ " Crea el codigo base de una archivo de cabecera function TemplateHeader() let file = bufname("%") let filename = fnamemodify(file, ":t") let fileroot = fnamemodify(file, ":t:r") let fileext = fnamemodify(file, ":t:e") let defname = "__" . toupper(fileroot) . "_" . toupper(fileext) . "__" let @z = "" let @z = @z. "#ifndef " . defname . "\n" let @z = @z. "#define " . defname. "\n\n" let @z = @z. "#ifdef __cplusplus\n" let @z = @z. "extern \"C\" {\n" let @z = @z. "#endif\n\n\n\n\n\n\n" let @z = @z. "#ifdef __cplusplus\n" let @z = @z. "}\n" let @z = @z. "#endif\n\n" let @z = @z. "#endif\n\n\n" put z endfunction " Crea el codigo base para un comentario de documentacion function TemplateDocComment() let @z = "" let @z = @z . "/**\n" let @z = @z . " * \n" let @z = @z . " * \n" let @z = @z . " * @param : \n" let @z = @z . " * @return : \n" let @z = @z . " */\n" put z endfunction " Crea el codigo base para un comentario de documentacion function TemplateMITLicense() let @z = "" let @z = @z."/*****************************************************************************\n" let @z = @z."* Copyright (c) 2005 Daniel Lerch Hostalot \n" let @z = @z."*\n" let @z = @z."* Permission is hereby granted, free of charge, to any person obtaining a\n" let @z = @z."* copy of this software and associated documentation files (the \"Software\"),\n" let @z = @z."* to deal in the Software without restriction, including without limitation\n" let @z = @z."* the rights to use, copy, modify, merge, publish, distribute, sublicense,\n" let @z = @z."* and/or sell copies of the Software, and to permit persons to whom the\n" let @z = @z."* Software is furnished to do so, subject to the following conditions:\n" let @z = @z."*\n" let @z = @z."* The above copyright notice and this permission notice shall be included in\n" let @z = @z."* all copies or substantial portions of the Software.\n" let @z = @z."*\n" let @z = @z."* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n" let @z = @z."* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" let @z = @z."* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n" let @z = @z."* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n" let @z = @z."* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n" let @z = @z."* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n" let @z = @z."* DEALINGS IN THE SOFTWARE.\n" let @z = @z."****************************************************************************/\n" put z endfunction " }}}