" Vimball Archiver by Charles E. Campbell, Jr., Ph.D. UseVimball finish ftplugin/vim_ftpdev.vim [[[1 721 " Title: Vim filetype plugin file " Author: Marcin Szamotulski " Email: mszamot [AT] gmail [DOT] com " License: vim-license, see ':help license' " Copyright: © Marcin Szamotulski, 2012 " GetLatestVimScript: 3322 2 :AutoInstall: FTPDEV " " Todo: gd (search in current scope) and gD (search for global definition). " Copyright Statement: {{{1 " This file is a part of Automatic Tex Plugin for Vim. " " Automatic Tex Plugin for Vim is free software: you can redistribute it " and/or modify it under the terms of the GNU General Public License as " published by the Free Software Foundation, either version 3 of the " License, or (at your option) any later version. " " Automatic Tex Plugin for Vim is distributed in the hope that it will be " useful, but WITHOUT ANY WARRANTY; without even the implied warranty of " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU " General Public License for more details. " " You should have received a copy of the GNU General Public License along " with Automatic Tex Plugin for Vim. If not, see . " " This licence applies to all files shipped with Automatic Tex Plugin. "{{{1 GLOBAL VARIABLES let s:vim_dirs = [ "ftplugin", "plugin", "autoload", "compiler", "syntax", \ "indent", "colors", "doc", "keymap", "lang", "macros", "print", \ "spell", "tools", "tutor", ] if !exists("g:ftplugin_dir") let dir_path = '' for dir in s:vim_dirs let dir_path = fnamemodify(finddir(dir, expand("%:p:h").';'), ':p') if !empty(dir_path) break endif endfor if !empty(dir_path) let g:ftplugin_dir = fnamemodify(dir_path, ':h:h') else let g:ftplugin_dir = expand("%:p:h") endif endif fun! FTPDEV_GetInstallDir() " lcd to g:ftplugin_dir, we want path to be relative to this directory. exe 'lcd '.fnameescape(g:ftplugin_dir) " Check only vim files: let files = map(filter(split(globpath('.', '**'), '\n'), 'fnamemodify(v:val, ":e") == "vim"'), 'v:val[2:]') lcd - " Good files to check are those in s:vim_dirs: " i.e. in plugin, ftplugin, ... directories. let gfiles = [] for file in files if file =~ '^\%('.join(s:vim_dirs, '\|').'\)\>' call add(gfiles, file) endif endfor if len(gfiles) let files = gfiles endif " ipath - install path let ipath = '' for file in files " Find each file in 'runtimepath' let ipath = globpath(&rtp, file) if !empty(ipath) break endif endfor " Get the install path, count the directory level of file and strip that " many directories from the corresponing ipath. This should be the install " path. let idx = 0 while file != "." let idx += 1 let file = fnamemodify(file, ':h') endwhile let ipath = fnamemodify(ipath, repeat(':h', idx)) return ipath endfun if !exists("g:ftplugin_installdir") let dir = FTPDEV_GetInstallDir() if !empty(dir) let g:ftplugin_installdir = dir else let g:ftplugin_installdir = split(&rtp, ',')[0] endif endif if !exists("g:ftplugin_notinstall") let g:ftplugin_notinstall=['Makefile', '\.tar\%(\.bz2\|\.gz\)\?$', '\.vba$', '.*\.vmb$'] endif if exists("g:ftplugin_ResetPath") && g:ftplugin_ResetPath == 1 au! BufEnter *.vim exe "setl path=".substitute(g:ftplugin_dir.",".join(filter(split(globpath(g:ftplugin_dir, '**'), "\n"), "isdirectory(v:val)"), ","), " ", '\\\\\\\ ', 'g') else func! FTPDEV_AddPath() let path=map(split(&path, ','), "fnamemodify(v:val, ':p')") if index(path,fnamemodify(g:ftplugin_dir, ":p")) == -1 && g:ftplugin_dir != "" let add = join(filter(split(globpath(g:ftplugin_dir, '**'), "\n"), "isdirectory(v:val)"), ",") let add = substitute(add, " ", '\\\\\\\ ', 'g') exe "setl path+=".add endif endfun exe "au! BufEnter ".g:ftplugin_dir."* call FTPDEV_AddPath()" exe "au! VimEnter * call FTPDEV_AddPath()" endif try "1}}} " Vim Settings: " vim scripts written on windows works on Linux only if the EOF are dos or unix. setl fileformats=unix,dos " FUNCTIONS AND COMMANDS AND MAPS: fun! PyGrep(what, files) " {{{1 python << EOF import vim import re import json what = vim.eval('a:what') files = vim.eval('a:files') if what == 'function': pat = re.compile('\s*(?:silent!?)?\s*(?:fu|fun|func|funct|functio|function)!?\s') elif what == 'command': pat = re.compile('\s*(?:silent!?)?\s*(?:com|comm|comma|comman|command)!?\s') elif what == 'variable': pat = re.compile('\s*let\s') elif what == 'maplhs': pat = re.compile('\s*[cilnosvx!]?(?:nore)?(?:m|ma|map)\s' ) elif what == 'maprhs': pat = re.compile('\s*[cilnosvx!]?(?:nore)?(?:m|ma|map)' ) loclist = [] for filename in files: if vim.eval("bufloaded('%s')" % filename) == '1': for buf in vim.buffers: if buf.name == filename: buf_nr = buf.number break else: buf_nr = 0 with open(filename) as fo: buf = fo.read().splitlines() lnr = 0 buf_len = len(buf) while lnr < buf_len: lnr += 1 line = buf[lnr-1] if line.startswith('py'): # Skip over :python << EOF, :perl << EOF until EOF: eof = re.match('(?:py|pyt|pyth|pytho|python|pe|per|perl)\s*<<\s*(\w+)',line).group(1) while not line.startswith(eof): lnr +=1 if lnr == buf_len: break line = buf[lnr-1] if lnr == buf_len: break lnr += 1 line = buf[lnr-1] match = re.match(pat, line) if match: loclist.append({ "bufnr" : buf_nr, "filename" : filename, "lnum" : lnr, "text" : line }) vim.command("let loclist=%s" % json.dumps(loclist)) EOF return loclist endfun fun! Goto(what,bang,...) "{{{1 let pattern = (a:0 >= 1 ? \ (a:1 =~ '.*\ze\s\+\d\+$' ? matchstr(a:1, '.*\ze\s\+\d\+$') : a:1) \ : 'no_arg') let line = (a:0 >= 1 ? \ (a:1 =~ '.*\ze\s\+\d\+$' ? matchstr(a:1, '.*\s\+\zs\d\+$') : 0) \ : 0) " Go to a:2 lines below let grep_flag = ( a:bang == "!" ? 'j' : '' ) if a:what == 'function' if !has("python") let pattern = '^\s*\%(silent!\=\)\=\s*fu\%[nction]!\=\s\+\%(s:\|<\csid>\|\f\+\#\)\=' . ( a:0 >= 1 ? pattern : '' ) else let cpat = '^\s*\%(silent!\=\)\=\s*fu\%[nction]!\=\s\+\%(s:\|<\csid>\)\=\zs[^(]*' let pattern = ( a:0 >= 1 ? pattern : '' ) endif elseif a:what == 'command' if !has("python") let pattern = '^\s*\%(silent!\=\)\=\s*com\%[mand]!\=\%(\s*-buffer\s*\|\s*-nargs=[01*?+]\s*\|\s*-complete=\S\+\s*\|\s*-bang\s*\|\s*-range=\=[\d%]*\s*\|\s*-count=\d\+\s*\|\s*-bar\s*\|\s*-register\s*\)*\s*'.( a:0 >= 1 ? pattern : '' ) else let cpat = '^\s*\%(silent!\=\)\=\s*com\%[mand]!\=\%(\s*-buffer\s*\|\s*-nargs=[01*?+]\s*\|\s*-complete=\S\+\s*\|\s*-bang\s*\|\s*-range=\=[\d%]*\s*\|\s*-count=\d\+\s*\|\s*-bar\s*\|\s*-register\s*\)*\s*\zs\S*' let pattern = ( a:0 >= 1 ? pattern : '' ) endif elseif a:what == 'variable' if !has("python") let pattern = '^\s*let\s\+' . ( a:0 >= 1 ? pattern : '' ) else let cpat = '^\s*let\s\+\zs[^\s=]*' let pattern = ( a:0 >= 1 ? pattern : '' ) endif elseif a:what == 'maplhs' let cpat = '^\s*[cilnosvx!]\?\%(nore\)\?m\%[ap]\>\s\+\%(\%(\|\|\|\)\s*\)*\(\)\?\zs\S*' let pattern = ( a:0 >= 1 ? pattern : '' ) if !has("python") let pattern = '^\s*[cilnosvx!]\?\%(nore\)\?m\%[ap]\>\s\+\%(\%(\|\|\|\)\s*\)*\(\)\?'.pattern endif elseif a:what == 'maprhs' let cpat = '^\s*[cilnosvx!]\?\%(nore\)\?m\%[ap]\>\s\+\%(\%(\|\|\|\)\s*\)*\s\+\<\S\+\>\s\+\%(\)\?\zs.*' let pattern = ( a:0 >= 1 ? pattern : '' ) if !has("python") let pattern = '^\s*[cilnosvx!]\?\%(nore\)\?m\%[ap]\>\s\+\%(\%(\|\|\|\)\s*\)*\s\+\<\S\+\>\s\+\%(\)\?'.pattern endif else let pattern = '^\s*[ci]\=\%(\%(nore\|un\)a\%[bbrev]\|ab\%[breviate]\)' . ( a:0 >= 1 ? pattern : '' ) endif let files = map(split(globpath(g:ftplugin_dir, '**/*vim'), "\n"), "fnameescape(v:val)") let filename = join(files) if has("python") call map(files, 'fnamemodify(v:val, ":p")') if !exists("s:loclist") let loclist = PyGrep(a:what, files) else let loclist = s:loclist unlet s:loclist endif let nloclist = [] for loc in loclist let loc['m_text'] = matchstr(loc['text'], cpat) call add(nloclist, loc) endfor let loclist = nloclist call filter(loclist, 'v:val["m_text"] =~ pattern') call setloclist(0, loclist) try ll let error = 0 catch /E42/ let error = 1 endtry else let error = 0 if !exists("s:loclist") try exe 'silent! lvimgrep /'.pattern.'/' . grep_flag . ' ' . filename catch /E480:/ echoerr 'E480: No match: ' . pattern let error = 1 endtry endif endif if len(getloclist(".")) >= 2 llist endif if !error exe 'silent! normal zv' if a:what == 'function' exe 'normal zt' endif endif " Goto lines below if line exe "normal ".line."j" endif endfun catch /E127/ endtry " Completion is not working for a very simple reason: we are edditing a vim " script which might not be sourced. com! -buffer -bang -nargs=? -complete=customlist,FuncCompl Function :call Goto('function', , ) try fun! FuncCompl(A,B,C) "{{{1 let files = map(split(globpath(g:ftplugin_dir, '**/*vim'), "\n"), "fnameescape(v:val)") let filename = join(files) if has("python") let loclist = PyGrep('function', files) let s:loclist = deepcopy(loclist) else let saved_loclist=getloclist(0) try exe 'lvimgrep /^\s*fun\%[ction]/gj '.filename catch /E480:/ endtry let loclist = getloclist(0) let s:loclist = deepcopy(loclist) call setloclist(0, saved_loclist) endif call map(loclist, 'get(v:val, "text", "")') call map(loclist, 'matchstr(v:val, ''^\s*fun\%[ction]!\=\s*\(<\csid>\|\cs:\)\=\zs.*\ze\s*('')') call filter(loclist, "v:val =~ a:A") if !has("python") call map(loclist, 'v:val.''\>''') else call map(loclist, '"^".v:val."\\>"') endif return loclist endfun catch /E127/ endtry try fun! CommandCompl(A,B,C) "{{{1 let files = map(split(globpath(g:ftplugin_dir, '**/*vim'), "\n"), "fnameescape(v:val)") let filename = join(files) if has("python") let loclist = PyGrep('command', files) let s:loclist = deepcopy(loclist) else let saved_loclist=getloclist(0) try exe 'lvimgrep /^\s*com\%[mand]/gj '.filename catch /E480:/ endtry let loclist = getloclist(0) call setloclist(0, saved_loclist) endif call map(loclist, 'get(v:val, "text", "")') call map(loclist, 'matchstr(v:val, ''^\s*com\%[mand]!\=\(\s*-buffer\s*\|\s*-nargs=[01*?+]\s*\|\s*-complete=\S\+\s*\|\s*-bang\s*\|\s*-range=\=[\d%]*\s*\|\s*-count=\d\+\s*\|\s*-bar\s*\|\s*-register\s*\)*\s*\zs\w*\>\ze'')') if !has("python") call map(loclist, 'v:val.''\>''') else call map(loclist, '"^".v:val."\\>"') endif return join(loclist, "\n") endfun catch /E127/ endtry try fun! MapRhsCompl(A,B,C) "{{{1 let files = map(split(globpath(g:ftplugin_dir, '**/*vim'), "\n"), "fnameescape(v:val)") let filename = join(files) if has("python") let loclist = PyGrep('maprhs', files) let s:loclist = deepcopy(loclist) else let saved_loclist=getloclist(0) try exe 'lvimgrep /^\s*[cilnosvx!]\=\%(nore\)\=m\%[ap]\>/gj '.filename catch /E480:/ endtry let loclist = getloclist(0) call setloclist(0, saved_loclist) endif call map(loclist, 'get(v:val, "text", "")') call map(loclist, 'matchstr(v:val, ''^\s*[cilnosvx!]\=\%(nore\)\=m\%[ap]\>\s\+\%(\%(\|\|\|\)\s*\)*\(\)\=\zs.*'')') call map(loclist, 'matchstr(v:val, ''\S\+\s\+\%(\)\?\zs.*'')') call filter(loclist, 'v:val =~ a:A') call map(loclist, 'escape(v:val, "[]")') return loclist endfun catch /E127/ endtry try fun! MapLhsCompl(A,B,C) "{{{1 let files = map(split(globpath(g:ftplugin_dir, '**/*vim'), "\n"), "fnameescape(v:val)") let filename = join(files) if has("python") let loclist = PyGrep('maplhs', files) let s:loclist = deepcopy(loclist) else let saved_loclist=getloclist(0) try exe 'lvimgrep /^\s*[cilnosvx!]\=\%(nore\)\=m\%[ap]\>/gj '.filename catch /E480:/ endtry let loclist = getloclist(0) call setloclist(0, saved_loclist) endif call map(loclist, 'get(v:val, "text", "")') call map(loclist, 'matchstr(v:val, ''^\s*[cilnosvx!]\=\%(nore\)\=m\%[ap]\>\s\+\%(\%(\|\|\|\)\s*\)*\(\)\=\zs\S*\ze'')') call map(loclist, 'escape(v:val, "[]")') return join(loclist, "\n") endfun catch /E127/ endtry "}}}1 com! -buffer -bang -nargs=? -complete=custom,CommandCompl Command :call Goto('command', , ) com! -buffer -bang -nargs=? Variable :call Goto('variable', , ) com! -buffer -bang -nargs=? -complete=custom,MapLhsCompl MapLhs :call Goto('maplhs', , ) com! -buffer -bang -nargs=? -complete=customlist,MapRhsCompl MapRhs :call Goto('maprhs', , ) " Search in current function fun! SearchInFunction(pattern, flag) "{{{1 let [ cline, ccol ] = [ line("."), col(".") ] if a:flag =~# 'b\|w' || &wrapscan let begin = searchpairpos('^\s*fun\%[ction]\>', '', '^\s*endfun\%[ction]\>', 'bWn') endif if a:flag !~# 'b' || a:flag =~# 'w' || &wrapscan let end = searchpairpos('^\s*fun\%[ction]\>', '', '^\s*endfun\%[ction]\>', 'Wn') endif if a:flag !~# 'b' let pos = searchpos('\(' . a:pattern . ( a:pattern =~ '\\v' ? '|^\s*endfun%[ction]>)' : '\|^\s*endfun\%[ction]\>\)' ), 'W') else let pos = searchpos('\(' . a:pattern . ( a:pattern =~ '\\v' ? '|^\s*endfun%[ction]>)' : '\|^\s*endfun\%[ction]\>\)' ), 'Wb') endif let msg="" if a:flag =~# 'w' || &wrapscan if a:flag !~# 'b' && pos == end let msg="search hit BOTTOM, continuing at TOP" call cursor(begin) call search('^\s*fun\%[ction]\zs', '') let pos = searchpos('\(' . a:pattern . ( a:pattern =~ '\\v' ? '|^\s*endfun%[ction]>)' : '\|^\s*endfun\%[ction]\>\)' ), 'W') elseif a:flag =~# 'b' && pos == begin let msg="search hit TOP, continuing at BOTTOM" call cursor(end) let pos = searchpos('\(' . a:pattern . ( a:pattern =~ '\\v' ? '|^\s*endfun%[ction]>)' : '\|^\s*endfun\%[ction]\>\)' ), 'Wb') endif if pos == end || pos == begin let msg="Pattern: " . a:pattern . " not found." call cursor(cline, ccol) endif else if pos == end || pos == begin let msg="Pattern: " . a:pattern . " not found." call cursor(cline, ccol) endif endif if msg != "" echohl WarningMsg redraw exe "echomsg '".msg."'" echohl Normal endif endfun fun! GetSearchArgs(Arg,flags) "{{{1 if a:Arg =~ '^\/' let pattern = matchstr(a:Arg, '^\/\zs.*\ze\/') let flag = matchstr(a:Arg, '\/.*\/\s*\zs['.a:flags.']*\ze\s*$') elseif a:Arg =~ '^\i' && a:Arg !~ '^\w' let pattern = matchstr(a:Arg, '^\(\i\)\zs.*\ze\1') let flag = matchstr(a:Arg, '\(\i\).*\1\s*\zs['.a:flags.']*\ze\s*$') else let pattern = matchstr(a:Arg, '^\zs\S*\ze') let flag = matchstr(a:Arg, '^\S*\s*\zs['.a:flags.']*\ze\s*$') endif return [ pattern, flag ] endfun fun! Search(Arg) "{{{1 let [ pattern, flag ] = GetSearchArgs(a:Arg, 'bcenpswW') let @/ = pattern call histadd("search", pattern) if pattern == "" echohl ErrorMsg redraw echomsg "Enclose the pattern with /.../" echohl Normal return endif call SearchInFunction(pattern, flag) endfun "}}}1 com! -buffer -nargs=* S :call Search() | let v:searchforward = ( GetSearchArgs(, 'bcenpswW')[1] =~# 'b' ? 0 : 1 ) nmap :call SearchInFunction(@/,'') nmap :call SearchInFunction(@/,'b') nmap gn :call SearchInFunction(@/,( v:searchforward ? '' : 'b')) nmap gN :call SearchInFunction(@/,(!v:searchforward ? '' : 'b')) fun! PluginDir(...) "{{{1 if a:0 == 0 echo g:ftplugin_dir else let g:ftplugin_dir=a:1 endif endfun "}}}1 com! -nargs=? -complete=file PluginDir :call PluginDir() try fun! Pgrep(vimgrep_arg) "{{{1 let filename = join(filter(map(split(globpath(g:ftplugin_dir, '**/*'), "\n"), "fnameescape(v:val)"),"!isdirectory(v:val)")) try execute "lvimgrep " . a:vimgrep_arg . " " . filename catch /E480:/ echohl ErrorMsg redraw echo "E480: No match: ".a:vimgrep_arg echohl Normal endtry endfun catch /E127:/ endtry com! -nargs=1 Pgrep :call Pgrep() fun! ListFunctions(bang) "{{{1 try lvimgrep /^\s*fun\%[ction]/gj % catch /E480:/ echohl ErrorMsg redraw echo "E480: No match: ".a:vimgrep_arg echohl Normal endtry let loclist = getloclist(0) call map(loclist, 'get(v:val, "text", "")') call map(loclist, 'matchstr(v:val, ''^\s*fun\%[ction]!\=\s*\zs.*\ze\s*('')') if a:bang == "!" call sort(loclist) endif return join(PrintTable(loclist, 2), "\n") endfun com! -bang ListFunctions :echo ListFunctions() fun! ListCommands(bang) "{{{1 try lvimgrep /^\s*com\%[mmand]/gj % catch /E480:/ echohl ErrorMsg redraw echo "E480: No match: ".a:vimgrep_arg echohl Normal endtry let loclist = getloclist(0) call map(loclist, 'get(v:val, "text", "")') call map(loclist, 'substitute(v:val, ''^\s*'', '''', '''')') if a:bang == "!" call sort(loclist) endif let cmds = [] for raw_cmd in loclist let pattern = '^\s*com\%[mand]!\=\%(\s*-buffer\s*\|\s*-nargs=[01*?+]\s*\|\s*-complete=\S\+\s*\|\s*-bang\s*\|\s*-range=\=[\d%]*\s*\|\s*-count=\d\+\s*\|\s*-bar\s*\|\s*-register\s*\)*\s*\zs\w*\ze' call add(cmds, matchstr(raw_cmd, pattern)) endfor return join(cmds, "\n") endfun com! -bang ListCommands :echo ListCommands() nmap ]# :call searchpair('^[^"]*\<\zsif\>', '^[^"]*\<\zselse\%(if\)\=\>', '^[^"]*\<\zsendif\>') nmap [# :call searchpair('^[^"]*\<\zsif\>', '^[^"]*\<\zselse\%(if\)\=\>', '^[^"]*\<\zsendif\>', 'b') fun! Install(bang) "{{{1 if g:ftplugin_dir = g:ftplugin_installdir return endif exe 'lcd '.fnameescape(g:ftplugin_dir) if a:bang == "" " Note: this returns non zero list if the buffer is loaded " ':h getbufline()' let file_name = expand('%:.') let file = getbufline('%', '1', '$') let install_path = substitute(g:ftplugin_installdir, '\/\s*$', '', '').'/'.file_name call writefile(file, install_path) echom 'File installed to: "'.install_path.'".' else let install_path = substitute(g:ftplugin_installdir, '\/\s*$', '', '') let file_list = filter(split(globpath(g:ftplugin_dir, '**'), "\n"), "!isdirectory(v:val) && !Match(g:ftplugin_notinstall, fnamemodify(v:val, ':.'))") for file in file_list if bufloaded(file) let file_list = getbufline(file, '1', '$') else let file_list = readfile(file) endif let file_name = fnamemodify(file, ':.') echo 'Installing: "'.file_name.'" to "'.install_path.'/'.file_name.'"' try call writefile(file_list, install_path.'/'.file_name) catch /E482/ let dir = fnamemodify(install_path.'/'.file_name, ':h') echohl WarningMsg echom 'Making directory "'.dir.'"' echohl None call mkdir(dir, 'p') call writefile(file_list, install_path.'/'.file_name) endtry endfor endif lcd - endfun fun! Match(pattern_list, element) "{{{2 let match = 0 for pattern in a:pattern_list if a:element =~ pattern || a:element == pattern let match = 1 break endif endfor return match endfun "}}}2 com! -bang Install :call Install() fun! Evaluate(mode) "{{{1 let saved_pos = getpos(".") let saved_reg = @e if a:mode == "n" if strpart(getline(line(".")), col(".")-1) =~ '[bg]:' let end_pos = searchpos('[bg]:\w*\zs\>', 'cW') else let end_pos = searchpos('\ze\>', 'cW') endif let end_pos[1] -= 1 call cursor(saved_pos[1], saved_pos[2]) normal! v call cursor(end_pos) normal! "ey let expr = @e elseif a:mode ==? 'v' let beg_pos = getpos("'<") let end_pos = getpos("'>") call cursor(beg_pos[1], beg_pos[2]) normal! v call cursor(end_pos[1], end_pos[2]) normal! "ey let expr= @e endif let @e = saved_reg try echo expr."=".string({expr}) catch /E121:/ echomsg "variable ".expr." undefined" endtry endfun com! -buffer -range Eval :call Evaluate(mode()) "}}}1 " Print table tools: fun! FormatListinColumns(list,s) "{{{1 " take a list and reformat it into many columns " a:s is the number of spaces between columns " for example of usage see atplib#PrintTable let max_len=max(map(copy(a:list), 'len(v:val)')) " let g:list=a:list " let g:max_len=max_len+a:s let new_list=[] let k=&l:columns/(max_len+a:s) " let g:k=k let len=len(a:list) let column_len=len/k for i in range(0, column_len) let entry=[] for j in range(0,k) call add(entry, get(a:list, i+j*(column_len+1), "")) endfor call add(new_list,entry) endfor return new_list endfun fun! PrintTable(list, spaces) "{{{1 " Take list format it with atplib#FormatListinColumns and then with " atplib#Table (which makes columns of equal width) " a:list - list to print " a:spaces - nr of spaces between columns let list = atplib#FormatListinColumns(a:list, a:spaces) let nr_of_columns = max(map(copy(list), 'len(v:val)')) let spaces_list = ( nr_of_columns == 1 ? [0] : map(range(1,nr_of_columns-1), 'a:spaces') ) let g:spaces_list = spaces_list let g:nr_of_columns=nr_of_columns return atplib#Table(list, spaces_list) endfun fun! LocalDeclaration(variable) "{{{1 python << EOF import vim import re var = vim.eval('a:variable') buf = vim.current.buffer idx = vim.current.window.cursor[0]-1 col = vim.current.window.cursor[1] var_pat = re.compile(r'^(\s*let\s*)%s\b' % var) endfun_pat = re.compile(r'^\s*(?:endf|endfu|endfun|endfunc|endfunct|endfuncti|endfunctio|endfunction)\b') fun_pat = re.compile(r'^\s*(?:fu|fun|func|funct|functi|functio|function)\b') def jump(idx): # {{{2 global buf while idx >= 0: idx -= 1 line = buf[idx] if re.match(fun_pat, line): idx = -1 return (-1, -1) if re.match(endfun_pat, line): idx -= 1 line = buf[idx] m = re.match(fun_pat, line) while not m and idx >= 0: idx -= 1 line = buf[idx] m = re.match(fun_pat, line) if re.match(var_pat, line): col = line.index(var) return (idx, col) else: return (-1, -1) # }}}2 (n_idx, n_col) = jump(idx) while n_idx != -1: (idx, col) = (n_idx, n_col) (n_idx, n_col) = jump(idx) vim.command("let lnr=%s" % (idx+1)) vim.command("let col=%s" % (col+1)) EOF let g:lnr = lnr let g:col = col if lnr call setpos(".", [0, lnr, col, 0]) endif endfun if has("python") nnoremap gd :call LocalDeclaration(expand("")) endif doc/ftpdev.txt [[[1 236 *ftpdev.txt* For Vim version 7 Last change: 27 IX 2012 A help file for {F}ile {T}ype {P}lugin {DEV}elopemnt (ver. 5.6) by Marcin Szamotulski mszamot [AT] gmail [DOT] com ---------------------------------------- This file type plugin provides some additional functions and commands which help writing and vim plugins. Especially big ones. Here is the list of available commands and maps with some explanation: ====== NEWS *ftpdev-news* > version 6 < The core functionality of |ftpdev-:Function|, |ftpdev-:Command|, |ftpdev-:MapLhs| and |ftpdev-:MapRhs| was rewritten in Python. If your Vim has Python interface (:echo has("+python")) then these commands will be much faster. For |ftpdev-:MapLhs| and |ftpdev-:MapRhs| if your vim is compiled with Python interface then the pattern matches can use '^' to match the begining of the lhs or rhs of the map (the '' is not included in the lhs/rhs). |g:ftplugin_dir| and |g:ftplugin_installdir| should work out of the box. |g:ftplugin_installdir| will work if one file of the project is already installed in the 'runtimepath' (and it is distinguished on under 'runtimepath'). |ftpdev-:Install| will print where it puts files and will make missing directories. It will exit silently if both |g:ftplugin_dir| and |g:ftplugin_installdir| are set to the same value. This is useful when you set |ftpdev-:Install| through an autocommand and then edit files under the 'runtimepath'. You can folow development of this plugin on GitHub: https://github.com/coot/vim_ftpdev NEW FEATURE: ~ gd - jump to local declaration: it finds the first declaration of the variable under the cursor. The declaration is search in the current function scope and outside all nested function definitions. Thus when you are outside a function whole script is searched backward from the cursor position, omitting all functions. > version 5.4 < gn and gN changed into ]# and [# what is more in a vim way. See |ftpdev-]#| and |ftpdev-[#|. :Edit, :Split, ... commands removed. Instead the |path| option is set so you can use |:find|, |:sfind|, ... commands. ====== CONFIGURATION *ftpdev-configure* *ftpdev-g:ftplugin_dir* There is one variable which needs to be configured > g:ftplugin_dir < This is the directory which will be searched for files. If you set this to your ~/.vim/ftplugin directory where you have lots of scripts this plugin might be a bit slow. Each plugin that I develop has its own directory (you probably use some version control system as I do) then this variable is set in my vimrc file via an autocommand: > au BufEnter /plugin_dev_dir/* let g:ftplugin= < *ftpdev-:PluginDir* :PluginDir {dir} This sets value of the variable |ftpdev-g:ftplugin_dir| to {dir}. It has dir type completion. *ftpdev-g:ftplugin_ResetPath* |g:ftplugin_ResetPath| is set to 1 it will set |path|=g:ftplugin_dir, if not set or equal 0 it will add g:ftplugin_dir to |path| (only if the path already does not contain it). This makes the use of |edit|, |split|, |vsplit|, |diffsplit| a lot nicer. *ftpdev-g:ftplugin_notinstall* g:ftplugin_notinstall=['Makefile', '.*\.tar\.\%(bz2\|gz\)$', '.*\.vba$'] This is list of patterns or file names relative to |g:ftplugin_dir| which will not be installed by the |ftpdev-:Install| command. *ftpdev-g:ftplugin_installdir* g:ftplugin_installdir=split(&runtimepath,",")[0] Directory name where to |ftpdev-:Install| files. TIP ~ It might be good idea to put in your vimrc file: > au BufEnter {path_to_project_dir}/* source ~/.vim/ftplugin/vim_ftdev.vim or 's:' even if the function name has it. The bang is present |lvimgrep| is supplied with the j switch, i.e. the location list will be filled with matches without jumping to the first match. There is a completion for {fname}s. If [line] is non zero, go [lines] below. This is especially useful when you are debugging a script and you got en error in function {fname} at line [line]. :ListFunctions *ftpdev-:ListFunctions* List functions in defined in the current buffer. :Command[!] {cname} [line] *ftpdev-:Command* This finds command which name matches {fname} vim pattern under the |ftpdev-g:ftplugin_dir| {cname} has the same syntax as {fname}. The bang works as in |ftpdev-:Function| There is a completion for {cname}s. The [line] argument is the same as in |ftpdev-:Function|. :ListCommands *ftpdev-:ListCommands* List commands in defined in the current buffer. :Variable[!] {vname} [line] *ftpdev-:Variable* This finds variable definition matching {vname}. {vname} has to contain the g: b: s: t: prefix if the variable has it. The bang works as in |ftpdev-:Function| The [line] argument is the same as in |ftpdev-:Function|. :MapLhs[!] {maplhs} [line] *ftpdev-:MapLhs* This finds maps which lhs matches {maplhs} vim pattern. The bang works as in |ftpdev-:Function| The [line] argument is the same as in |ftpdev-:Function|. If Vim has Python interface then you can use '^' in {maplhs} pattern to match the start of the map name (' is not included into the map name). If Vim has not Python interface the {maplhs} always matches at the begining, thus if you want to match anywhere use '.*' at the begining of {maplhs} :MapRhs[!] {maprhs} [line] *ftpdev-:MapRhs* This finds maps which rhs matches {maprhs} vim pattern. The bang works as in |ftpdev-:Function| The [line] argument is the same as in |ftpdev-:Function|. {maprhs} works in the same way as {maplhs} argument of |atp-:MapLhs| command (read there about the difference when Vim has Python interface). Note: [todo] some completions might not work (especially complex right hand side maps, Goto function should check for == in this case). *ftpdev-]#* *ftpdev-[#* *ftpdev-:S* :S /{pattern}/ map ]# map [# This function make a search of {pattern} in the current function (it can wrap around the end of function. The argument {pattern} is a vim pattern passed to |vimgrep|. Mixing |\v| and |\m| in a pattern is not supported. The pattern is added to search history and copied to the @/ register, thus you can re use it with |n| and |N| commands to search globally or gn and gN to search in the scope of current function. Note that you can first search with the vim standard |/| or |?| and then use |ftpdev-gn| and |ftpdev-gN|. *ftpdev-:Eval* :Eval Probably in your plugin there are debug |global-variables|. Then position the cursor on the begining of this variable :Eval will show you its value (if its defined). You can also use visual mode to select an expression, but the limitation is that every variable must be defined (thus it must be a global variable). *ftpdev-:Pgrep* :Pgrep /{pattern}/[j][g] This makes |lvimgrep| in all files under |ftpdev-g:ftplugin_dir|. The argument syntax is the same as for |lvimgrep|. This note is just for completeness: Vim has its own vim.vim ftplugin which defines: ]] (next beginning of a function), ][ (next end of a function), [[ (previous beginning of a function), [] (previous end of a function). nmap Gn *ftpdev-Gn* nmap GN *ftpdev-GN* Go to next/previous if/else/elseif/endif pair (this, unlike |n| and |N| vim maps, doesn't depend on v:searchforward). These maps are defined by: > nmap Gn :call searchpair('^[^"]*\<\zsif\>', '^[^"]*\<\zselse\%(if\)\=\>', '^[^"]*\<\zsendif\>') nmap GN :call searchpair('^[^"]*\<\zsif\>', '^[^"]*\<\zselse\%(if\)\=\>', '^[^"]*\<\zsendif\>', 'b') < You can also use the |matchit| plugin. Just configure |b:match_words| variable. INSTALLING PLUGIN TO THE RUNTIME PATH ~ :Install[!] *ftpdev-:Install* Without bang "!": it will copy the current buffer to the location under |g:ftplugin_installdir| be default it is first path that appear in 'runtimepath' vim option. With bang "!": it will install all the files found under |g:ftplugin_dir| except the files in the (file/pattern) list |g:ftplugin_notinstall|. You can use this command in an autocommand for certain files: > au BufWritePost :Install < If a directory tree is missing |ftpdev-:Install| will make it on the fly. If |g:ftplugin_dir| and |g:ftplugin_installdir| are equal the command silently returns. This is useful when you set :Install through an autocommand and edit files under the 'runtimepath'. Happy vimming :) vim:tw=75:ts=8:ft=help:norl:ft=help