]>
Commit | Line | Data |
---|---|---|
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 | |
7 | if (exists("b:did_ftplugin")) | |
8 | finish | |
9 | endif | |
10 | let b:did_ftplugin = 1 | |
11 | ||
12 | setlocal formatoptions-=t formatoptions+=croql | |
13 | setlocal comments=:# commentstring=#\ %s | |
14 | setlocal omnifunc=CucumberComplete | |
15 | ||
16 | let b:undo_ftplugin = "setl fo< com< cms< ofu<" | |
17 | ||
18 | let b:cucumber_root = expand('%:p:h:s?.*[\/]\%(features\|stories\)\zs[\/].*??') | |
19 | ||
20 | if !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! nunmap <buffer> <C-]>| sil! nunmap <buffer> <C-W>]| sil! nunmap <buffer> <C-W><C-]>| sil! nunmap <buffer> <C-W>}" | |
26 | endif | |
27 | ||
28 | function! 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 | |
38 | endfunction | |
39 | ||
40 | function! 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 | |
55 | endfunction | |
56 | ||
57 | function! 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)') | |
64 | endfunction | |
65 | ||
66 | function! 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 | |
88 | endfunction | |
89 | ||
90 | function! s:bsub(target,pattern,replacement) | |
91 | return substitute(a:target,'\C\\\@<!'.a:pattern,a:replacement,'g') | |
92 | endfunction | |
93 | ||
94 | function! 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) | |
130 | endfunction | |
131 | ||
132 | " vim:set sts=2 sw=2: |