1" Vim filetype plugin 2" Language: Cucumber 3" Maintainer: Tim Pope <vimNOSPAM@tpope.org> 4" Last Change: 2010 Aug 09 5 6" Only do this when not done yet for this buffer 7if (exists("b:did_ftplugin")) 8 finish 9endif 10let b:did_ftplugin = 1 11 12setlocal formatoptions-=t formatoptions+=croql 13setlocal comments=:# commentstring=#\ %s 14setlocal omnifunc=CucumberComplete 15 16let b:undo_ftplugin = "setl fo< com< cms< ofu<" 17 18let b:cucumber_root = expand('%:p:h:s?.*[\/]\%(features\|stories\)\zs[\/].*??') 19 20if !exists("g:no_plugin_maps") && !exists("g:no_cucumber_maps") 21 nmap <silent><buffer> <C-]> :<C-U>exe <SID>jump('edit',v:count)<CR> 22 nmap <silent><buffer> <C-W>] :<C-U>exe <SID>jump('split',v:count)<CR> 23 nmap <silent><buffer> <C-W><C-]> :<C-U>exe <SID>jump('split',v:count)<CR> 24 nmap <silent><buffer> <C-W>} :<C-U>exe <SID>jump('pedit',v:count)<CR> 25 let b:undo_ftplugin .= "| sil! iunmap! <C-]>| sil! iunmap! <C-W>]| sil! iunmap! <C-W><C-]>| sil! iunmap! <C-W>}" 26endif 27 28function! s:jump(command,count) 29 let steps = s:steps('.') 30 if len(steps) == 0 || len(steps) < a:count 31 return 'echoerr "No matching step found"' 32 elseif len(steps) > 1 && !a:count 33 return 'echoerr "Multiple matching steps found"' 34 else 35 let c = a:count ? a:count-1 : 0 36 return a:command.' +'.steps[c][1].' '.escape(steps[c][0],' %#') 37 endif 38endfunction 39 40function! s:allsteps() 41 let step_pattern = '\C^\s*\K\k*\>\s*\zs\S.\{-\}\ze\s*\%(do\|{\)\s*\%(|[^|]*|\s*\)\=\%($\|#\)' 42 let steps = [] 43 for file in split(glob(b:cucumber_root.'/**/*.rb'),"\n") 44 let lines = readfile(file) 45 let num = 0 46 for line in lines 47 let num += 1 48 if line =~ step_pattern 49 let type = matchstr(line,'\w\+') 50 let steps += [[file,num,type,matchstr(line,step_pattern)]] 51 endif 52 endfor 53 endfor 54 return steps 55endfunction 56 57function! s:steps(lnum) 58 let c = indent(a:lnum) + 1 59 while synIDattr(synID(a:lnum,c,1),'name') !~# '^$\|Region$' 60 let c = c + 1 61 endwhile 62 let step = matchstr(getline(a:lnum)[c-1 : -1],'^\s*\zs.\{-\}\ze\s*$') 63 return filter(s:allsteps(),'s:stepmatch(v:val[3],step)') 64endfunction 65 66function! s:stepmatch(receiver,target) 67 if a:receiver =~ '^[''"].*[''"]$' 68 let pattern = '^'.escape(substitute(a:receiver[1:-2],'$\w\+','(.*)','g'),'/').'$' 69 elseif a:receiver =~ '^/.*/$' 70 let pattern = a:receiver[1:-2] 71 elseif a:receiver =~ '^%r..*.$' 72 let pattern = escape(a:receiver[3:-2],'/') 73 else 74 return 0 75 endif 76 try 77 let vimpattern = substitute(substitute(pattern,'\\\@<!(?:','%(','g'),'\\\@<!\*?','{-}','g') 78 if a:target =~# '\v'.vimpattern 79 return 1 80 endif 81 catch 82 endtry 83 if has("ruby") && pattern !~ '\\\@<!#{' 84 ruby VIM.command("return #{if (begin; Kernel.eval('/'+VIM.evaluate('pattern')+'/'); rescue SyntaxError; end) === VIM.evaluate('a:target') then 1 else 0 end}") 85 else 86 return 0 87 endif 88endfunction 89 90function! s:bsub(target,pattern,replacement) 91 return substitute(a:target,'\C\\\@<!'.a:pattern,a:replacement,'g') 92endfunction 93 94function! CucumberComplete(findstart,base) abort 95 let indent = indent('.') 96 let group = synIDattr(synID(line('.'),indent+1,1),'name') 97 let type = matchstr(group,'\Ccucumber\zs\%(Given\|When\|Then\)') 98 let e = matchend(getline('.'),'^\s*\S\+\s') 99 if type == '' || col('.') < col('$') || e < 0 100 return -1 101 endif 102 if a:findstart 103 return e 104 endif 105 let steps = [] 106 for step in s:allsteps() 107 if step[2] ==# type 108 if step[3] =~ '^[''"]' 109 let steps += [step[3][1:-2]] 110 elseif step[3] =~ '^/\^.*\$/$' 111 let pattern = step[3][2:-3] 112 let pattern = substitute(pattern,'\C^(?:|I )','I ','') 113 let pattern = s:bsub(pattern,'\\[Sw]','w') 114 let pattern = s:bsub(pattern,'\\d','1') 115 let pattern = s:bsub(pattern,'\\[sWD]',' ') 116 let pattern = s:bsub(pattern,'\[\^\\\="\]','_') 117 let pattern = s:bsub(pattern,'[[:alnum:]. _-][?*]?\=','') 118 let pattern = s:bsub(pattern,'\[\([^^]\).\{-\}\]','\1') 119 let pattern = s:bsub(pattern,'+?\=','') 120 let pattern = s:bsub(pattern,'(\([[:alnum:]. -]\{-\}\))','\1') 121 let pattern = s:bsub(pattern,'\\\([[:punct:]]\)','\1') 122 if pattern !~ '[\\()*?]' 123 let steps += [pattern] 124 endif 125 endif 126 endif 127 endfor 128 call filter(steps,'strpart(v:val,0,strlen(a:base)) ==# a:base') 129 return sort(steps) 130endfunction 131 132" vim:set sts=2 sw=2: 133