blob: 2ec1a5976fe2aabe2082cc61d04b8febe11aa368 [file] [log] [blame]
Bram Moolenaar5e3dae82010-03-02 16:19:40 +01001" Vim filetype plugin
2" Language: Cucumber
3" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02004" Last Change: 2013 Jun 01
Bram Moolenaar5e3dae82010-03-02 16:19:40 +01005
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
Bram Moolenaar543b7ef2013-06-01 14:50:56 +020012let s:keepcpo= &cpo
13set cpo&vim
14
Bram Moolenaar5e3dae82010-03-02 16:19:40 +010015setlocal formatoptions-=t formatoptions+=croql
16setlocal comments=:# commentstring=#\ %s
17setlocal omnifunc=CucumberComplete
18
19let b:undo_ftplugin = "setl fo< com< cms< ofu<"
20
21let b:cucumber_root = expand('%:p:h:s?.*[\/]\%(features\|stories\)\zs[\/].*??')
22
23if !exists("g:no_plugin_maps") && !exists("g:no_cucumber_maps")
Bram Moolenaar543b7ef2013-06-01 14:50:56 +020024 nnoremap <silent><buffer> <C-]> :<C-U>exe <SID>jump('edit',v:count)<CR>
25 nnoremap <silent><buffer> [<C-D> :<C-U>exe <SID>jump('edit',v:count)<CR>
26 nnoremap <silent><buffer> ]<C-D> :<C-U>exe <SID>jump('edit',v:count)<CR>
27 nnoremap <silent><buffer> <C-W>] :<C-U>exe <SID>jump('split',v:count)<CR>
28 nnoremap <silent><buffer> <C-W><C-]> :<C-U>exe <SID>jump('split',v:count)<CR>
29 nnoremap <silent><buffer> <C-W>d :<C-U>exe <SID>jump('split',v:count)<CR>
30 nnoremap <silent><buffer> <C-W><C-D> :<C-U>exe <SID>jump('split',v:count)<CR>
31 nnoremap <silent><buffer> <C-W>} :<C-U>exe <SID>jump('pedit',v:count)<CR>
32 nnoremap <silent><buffer> [d :<C-U>exe <SID>jump('pedit',v:count)<CR>
33 nnoremap <silent><buffer> ]d :<C-U>exe <SID>jump('pedit',v:count)<CR>
34 let b:undo_ftplugin .=
35 \ "|sil! nunmap <buffer> <C-]>" .
36 \ "|sil! nunmap <buffer> [<C-D>" .
37 \ "|sil! nunmap <buffer> ]<C-D>" .
38 \ "|sil! nunmap <buffer> <C-W>]" .
39 \ "|sil! nunmap <buffer> <C-W><C-]>" .
40 \ "|sil! nunmap <buffer> <C-W>d" .
41 \ "|sil! nunmap <buffer> <C-W><C-D>" .
42 \ "|sil! nunmap <buffer> <C-W>}" .
43 \ "|sil! nunmap <buffer> [d" .
44 \ "|sil! nunmap <buffer> ]d"
Bram Moolenaar5e3dae82010-03-02 16:19:40 +010045endif
46
47function! s:jump(command,count)
48 let steps = s:steps('.')
49 if len(steps) == 0 || len(steps) < a:count
50 return 'echoerr "No matching step found"'
51 elseif len(steps) > 1 && !a:count
52 return 'echoerr "Multiple matching steps found"'
53 else
54 let c = a:count ? a:count-1 : 0
55 return a:command.' +'.steps[c][1].' '.escape(steps[c][0],' %#')
56 endif
57endfunction
58
59function! s:allsteps()
Bram Moolenaar543b7ef2013-06-01 14:50:56 +020060 let step_pattern = '\C^\s*\K\k*\>\s*(\=\s*\zs\S.\{-\}\ze\s*)\=\s*\%(do\|{\)\s*\%(|[^|]*|\s*\)\=\%($\|#\)'
Bram Moolenaar5e3dae82010-03-02 16:19:40 +010061 let steps = []
62 for file in split(glob(b:cucumber_root.'/**/*.rb'),"\n")
63 let lines = readfile(file)
64 let num = 0
65 for line in lines
66 let num += 1
67 if line =~ step_pattern
68 let type = matchstr(line,'\w\+')
69 let steps += [[file,num,type,matchstr(line,step_pattern)]]
70 endif
71 endfor
72 endfor
73 return steps
74endfunction
75
76function! s:steps(lnum)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +020077 let c = match(getline(a:lnum), '\S') + 1
Bram Moolenaar5e3dae82010-03-02 16:19:40 +010078 while synIDattr(synID(a:lnum,c,1),'name') !~# '^$\|Region$'
79 let c = c + 1
80 endwhile
81 let step = matchstr(getline(a:lnum)[c-1 : -1],'^\s*\zs.\{-\}\ze\s*$')
82 return filter(s:allsteps(),'s:stepmatch(v:val[3],step)')
83endfunction
84
85function! s:stepmatch(receiver,target)
86 if a:receiver =~ '^[''"].*[''"]$'
87 let pattern = '^'.escape(substitute(a:receiver[1:-2],'$\w\+','(.*)','g'),'/').'$'
88 elseif a:receiver =~ '^/.*/$'
89 let pattern = a:receiver[1:-2]
90 elseif a:receiver =~ '^%r..*.$'
91 let pattern = escape(a:receiver[3:-2],'/')
92 else
93 return 0
94 endif
95 try
96 let vimpattern = substitute(substitute(pattern,'\\\@<!(?:','%(','g'),'\\\@<!\*?','{-}','g')
97 if a:target =~# '\v'.vimpattern
98 return 1
99 endif
100 catch
101 endtry
Bram Moolenaar6af737f2010-08-09 20:13:35 +0200102 if has("ruby") && pattern !~ '\\\@<!#{'
Bram Moolenaar5e3dae82010-03-02 16:19:40 +0100103 ruby VIM.command("return #{if (begin; Kernel.eval('/'+VIM.evaluate('pattern')+'/'); rescue SyntaxError; end) === VIM.evaluate('a:target') then 1 else 0 end}")
104 else
105 return 0
106 endif
107endfunction
108
109function! s:bsub(target,pattern,replacement)
110 return substitute(a:target,'\C\\\@<!'.a:pattern,a:replacement,'g')
111endfunction
112
113function! CucumberComplete(findstart,base) abort
114 let indent = indent('.')
115 let group = synIDattr(synID(line('.'),indent+1,1),'name')
116 let type = matchstr(group,'\Ccucumber\zs\%(Given\|When\|Then\)')
117 let e = matchend(getline('.'),'^\s*\S\+\s')
118 if type == '' || col('.') < col('$') || e < 0
119 return -1
120 endif
121 if a:findstart
122 return e
123 endif
124 let steps = []
125 for step in s:allsteps()
126 if step[2] ==# type
127 if step[3] =~ '^[''"]'
128 let steps += [step[3][1:-2]]
129 elseif step[3] =~ '^/\^.*\$/$'
130 let pattern = step[3][2:-3]
131 let pattern = substitute(pattern,'\C^(?:|I )','I ','')
132 let pattern = s:bsub(pattern,'\\[Sw]','w')
133 let pattern = s:bsub(pattern,'\\d','1')
134 let pattern = s:bsub(pattern,'\\[sWD]',' ')
135 let pattern = s:bsub(pattern,'\[\^\\\="\]','_')
136 let pattern = s:bsub(pattern,'[[:alnum:]. _-][?*]?\=','')
137 let pattern = s:bsub(pattern,'\[\([^^]\).\{-\}\]','\1')
138 let pattern = s:bsub(pattern,'+?\=','')
139 let pattern = s:bsub(pattern,'(\([[:alnum:]. -]\{-\}\))','\1')
140 let pattern = s:bsub(pattern,'\\\([[:punct:]]\)','\1')
141 if pattern !~ '[\\()*?]'
142 let steps += [pattern]
143 endif
144 endif
145 endif
146 endfor
147 call filter(steps,'strpart(v:val,0,strlen(a:base)) ==# a:base')
148 return sort(steps)
149endfunction
150
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200151let &cpo = s:keepcpo
152unlet s:keepcpo
153
Bram Moolenaar5e3dae82010-03-02 16:19:40 +0100154" vim:set sts=2 sw=2: