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