15e3dae8bSBram Moolenaar" Vim filetype plugin
25e3dae8bSBram Moolenaar" Language:	Cucumber
35e3dae8bSBram Moolenaar" Maintainer:	Tim Pope <[email protected]>
4*89bcfda6SBram Moolenaar" Last Change:	2016 Aug 29
55e3dae8bSBram Moolenaar
65e3dae8bSBram Moolenaar" Only do this when not done yet for this buffer
75e3dae8bSBram Moolenaarif (exists("b:did_ftplugin"))
85e3dae8bSBram Moolenaar  finish
95e3dae8bSBram Moolenaarendif
105e3dae8bSBram Moolenaarlet b:did_ftplugin = 1
115e3dae8bSBram Moolenaar
12543b7ef7SBram Moolenaarlet s:keepcpo= &cpo
13543b7ef7SBram Moolenaarset cpo&vim
14543b7ef7SBram Moolenaar
155e3dae8bSBram Moolenaarsetlocal formatoptions-=t formatoptions+=croql
165e3dae8bSBram Moolenaarsetlocal comments=:# commentstring=#\ %s
175e3dae8bSBram Moolenaarsetlocal omnifunc=CucumberComplete
185e3dae8bSBram Moolenaar
195e3dae8bSBram Moolenaarlet b:undo_ftplugin = "setl fo< com< cms< ofu<"
205e3dae8bSBram Moolenaar
215e3dae8bSBram Moolenaarlet b:cucumber_root = expand('%:p:h:s?.*[\/]\%(features\|stories\)\zs[\/].*??')
22*89bcfda6SBram Moolenaarif !exists("b:cucumber_steps_glob")
23*89bcfda6SBram Moolenaar  let b:cucumber_steps_glob = b:cucumber_root.'/**/*.rb'
24*89bcfda6SBram Moolenaarendif
255e3dae8bSBram Moolenaar
265e3dae8bSBram Moolenaarif !exists("g:no_plugin_maps") && !exists("g:no_cucumber_maps")
27*89bcfda6SBram Moolenaar  cnoremap <SID>foldopen <Bar>if &foldopen =~# 'tag'<Bar>exe 'norm! zv'<Bar>endif
28*89bcfda6SBram Moolenaar  nnoremap <silent> <script> <buffer> [<C-D>      :<C-U>exe <SID>jump('edit',v:count)<SID>foldopen<CR>
29*89bcfda6SBram Moolenaar  nnoremap <silent> <script> <buffer> ]<C-D>      :<C-U>exe <SID>jump('edit',v:count)<SID>foldopen<CR>
30*89bcfda6SBram Moolenaar  nnoremap <silent> <script> <buffer> <C-W>d      :<C-U>exe <SID>jump('split',v:count)<SID>foldopen<CR>
31*89bcfda6SBram Moolenaar  nnoremap <silent> <script> <buffer> <C-W><C-D>  :<C-U>exe <SID>jump('split',v:count)<SID>foldopen<CR>
32*89bcfda6SBram Moolenaar  nnoremap <silent> <script> <buffer> [d          :<C-U>exe <SID>jump('pedit',v:count)<CR>
33*89bcfda6SBram Moolenaar  nnoremap <silent> <script> <buffer> ]d          :<C-U>exe <SID>jump('pedit',v:count)<CR>
34543b7ef7SBram Moolenaar  let b:undo_ftplugin .=
35543b7ef7SBram Moolenaar        \ "|sil! nunmap <buffer> [<C-D>" .
36543b7ef7SBram Moolenaar        \ "|sil! nunmap <buffer> ]<C-D>" .
37543b7ef7SBram Moolenaar        \ "|sil! nunmap <buffer> <C-W>d" .
38543b7ef7SBram Moolenaar        \ "|sil! nunmap <buffer> <C-W><C-D>" .
39543b7ef7SBram Moolenaar        \ "|sil! nunmap <buffer> [d" .
40543b7ef7SBram Moolenaar        \ "|sil! nunmap <buffer> ]d"
415e3dae8bSBram Moolenaarendif
425e3dae8bSBram Moolenaar
435e3dae8bSBram Moolenaarfunction! s:jump(command,count)
445e3dae8bSBram Moolenaar  let steps = s:steps('.')
455e3dae8bSBram Moolenaar  if len(steps) == 0 || len(steps) < a:count
465e3dae8bSBram Moolenaar    return 'echoerr "No matching step found"'
475e3dae8bSBram Moolenaar  elseif len(steps) > 1 && !a:count
485e3dae8bSBram Moolenaar    return 'echoerr "Multiple matching steps found"'
495e3dae8bSBram Moolenaar  else
505e3dae8bSBram Moolenaar    let c = a:count ? a:count-1 : 0
515e3dae8bSBram Moolenaar    return a:command.' +'.steps[c][1].' '.escape(steps[c][0],' %#')
525e3dae8bSBram Moolenaar  endif
535e3dae8bSBram Moolenaarendfunction
545e3dae8bSBram Moolenaar
555e3dae8bSBram Moolenaarfunction! s:allsteps()
56543b7ef7SBram Moolenaar  let step_pattern = '\C^\s*\K\k*\>\s*(\=\s*\zs\S.\{-\}\ze\s*)\=\s*\%(do\|{\)\s*\%(|[^|]*|\s*\)\=\%($\|#\)'
575e3dae8bSBram Moolenaar  let steps = []
58*89bcfda6SBram Moolenaar  for file in split(glob(b:cucumber_steps_glob),"\n")
595e3dae8bSBram Moolenaar    let lines = readfile(file)
605e3dae8bSBram Moolenaar    let num = 0
615e3dae8bSBram Moolenaar    for line in lines
625e3dae8bSBram Moolenaar      let num += 1
635e3dae8bSBram Moolenaar      if line =~ step_pattern
645e3dae8bSBram Moolenaar        let type = matchstr(line,'\w\+')
655e3dae8bSBram Moolenaar        let steps += [[file,num,type,matchstr(line,step_pattern)]]
665e3dae8bSBram Moolenaar      endif
675e3dae8bSBram Moolenaar    endfor
685e3dae8bSBram Moolenaar  endfor
695e3dae8bSBram Moolenaar  return steps
705e3dae8bSBram Moolenaarendfunction
715e3dae8bSBram Moolenaar
725e3dae8bSBram Moolenaarfunction! s:steps(lnum)
73543b7ef7SBram Moolenaar  let c = match(getline(a:lnum), '\S') + 1
745e3dae8bSBram Moolenaar  while synIDattr(synID(a:lnum,c,1),'name') !~# '^$\|Region$'
755e3dae8bSBram Moolenaar    let c = c + 1
765e3dae8bSBram Moolenaar  endwhile
775e3dae8bSBram Moolenaar  let step = matchstr(getline(a:lnum)[c-1 : -1],'^\s*\zs.\{-\}\ze\s*$')
785e3dae8bSBram Moolenaar  return filter(s:allsteps(),'s:stepmatch(v:val[3],step)')
795e3dae8bSBram Moolenaarendfunction
805e3dae8bSBram Moolenaar
815e3dae8bSBram Moolenaarfunction! s:stepmatch(receiver,target)
825e3dae8bSBram Moolenaar  if a:receiver =~ '^[''"].*[''"]$'
835e3dae8bSBram Moolenaar    let pattern = '^'.escape(substitute(a:receiver[1:-2],'$\w\+','(.*)','g'),'/').'$'
845e3dae8bSBram Moolenaar  elseif a:receiver =~ '^/.*/$'
855e3dae8bSBram Moolenaar    let pattern = a:receiver[1:-2]
865e3dae8bSBram Moolenaar  elseif a:receiver =~ '^%r..*.$'
875e3dae8bSBram Moolenaar    let pattern = escape(a:receiver[3:-2],'/')
885e3dae8bSBram Moolenaar  else
895e3dae8bSBram Moolenaar    return 0
905e3dae8bSBram Moolenaar  endif
915e3dae8bSBram Moolenaar  try
925e3dae8bSBram Moolenaar    let vimpattern = substitute(substitute(pattern,'\\\@<!(?:','%(','g'),'\\\@<!\*?','{-}','g')
935e3dae8bSBram Moolenaar    if a:target =~# '\v'.vimpattern
945e3dae8bSBram Moolenaar      return 1
955e3dae8bSBram Moolenaar    endif
965e3dae8bSBram Moolenaar  catch
975e3dae8bSBram Moolenaar  endtry
986af737fdSBram Moolenaar  if has("ruby") && pattern !~ '\\\@<!#{'
995e3dae8bSBram Moolenaar    ruby VIM.command("return #{if (begin; Kernel.eval('/'+VIM.evaluate('pattern')+'/'); rescue SyntaxError; end) === VIM.evaluate('a:target') then 1 else 0 end}")
1005e3dae8bSBram Moolenaar  else
1015e3dae8bSBram Moolenaar    return 0
1025e3dae8bSBram Moolenaar  endif
1035e3dae8bSBram Moolenaarendfunction
1045e3dae8bSBram Moolenaar
1055e3dae8bSBram Moolenaarfunction! s:bsub(target,pattern,replacement)
1065e3dae8bSBram Moolenaar  return  substitute(a:target,'\C\\\@<!'.a:pattern,a:replacement,'g')
1075e3dae8bSBram Moolenaarendfunction
1085e3dae8bSBram Moolenaar
1095e3dae8bSBram Moolenaarfunction! CucumberComplete(findstart,base) abort
1105e3dae8bSBram Moolenaar  let indent = indent('.')
1115e3dae8bSBram Moolenaar  let group = synIDattr(synID(line('.'),indent+1,1),'name')
1125e3dae8bSBram Moolenaar  let type = matchstr(group,'\Ccucumber\zs\%(Given\|When\|Then\)')
1135e3dae8bSBram Moolenaar  let e = matchend(getline('.'),'^\s*\S\+\s')
1145e3dae8bSBram Moolenaar  if type == '' || col('.') < col('$') || e < 0
1155e3dae8bSBram Moolenaar    return -1
1165e3dae8bSBram Moolenaar  endif
1175e3dae8bSBram Moolenaar  if a:findstart
1185e3dae8bSBram Moolenaar    return e
1195e3dae8bSBram Moolenaar  endif
1205e3dae8bSBram Moolenaar  let steps = []
1215e3dae8bSBram Moolenaar  for step in s:allsteps()
1225e3dae8bSBram Moolenaar    if step[2] ==# type
1235e3dae8bSBram Moolenaar      if step[3] =~ '^[''"]'
1245e3dae8bSBram Moolenaar        let steps += [step[3][1:-2]]
1255e3dae8bSBram Moolenaar      elseif step[3] =~ '^/\^.*\$/$'
1265e3dae8bSBram Moolenaar        let pattern = step[3][2:-3]
1275e3dae8bSBram Moolenaar        let pattern = substitute(pattern,'\C^(?:|I )','I ','')
1285e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'\\[Sw]','w')
1295e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'\\d','1')
1305e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'\\[sWD]',' ')
1315e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'\[\^\\\="\]','_')
1325e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'[[:alnum:]. _-][?*]?\=','')
1335e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'\[\([^^]\).\{-\}\]','\1')
1345e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'+?\=','')
1355e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'(\([[:alnum:]. -]\{-\}\))','\1')
1365e3dae8bSBram Moolenaar        let pattern = s:bsub(pattern,'\\\([[:punct:]]\)','\1')
1375e3dae8bSBram Moolenaar        if pattern !~ '[\\()*?]'
1385e3dae8bSBram Moolenaar          let steps += [pattern]
1395e3dae8bSBram Moolenaar        endif
1405e3dae8bSBram Moolenaar      endif
1415e3dae8bSBram Moolenaar    endif
1425e3dae8bSBram Moolenaar  endfor
1435e3dae8bSBram Moolenaar  call filter(steps,'strpart(v:val,0,strlen(a:base)) ==# a:base')
1445e3dae8bSBram Moolenaar  return sort(steps)
1455e3dae8bSBram Moolenaarendfunction
1465e3dae8bSBram Moolenaar
147543b7ef7SBram Moolenaarlet &cpo = s:keepcpo
148543b7ef7SBram Moolenaarunlet s:keepcpo
149543b7ef7SBram Moolenaar
1505e3dae8bSBram Moolenaar" vim:set sts=2 sw=2:
151