neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

ruby.vim (17984B)


      1 " Vim filetype plugin
      2 " Language:		Ruby
      3 " Maintainer:		Tim Pope <vimNOSPAM@tpope.org>
      4 " URL:			https://github.com/vim-ruby/vim-ruby
      5 " Last Change:		2023 Dec 31
      6 "			2024 Jan 14 by Vim Project (browsefilter)
      7 
      8 if (exists("b:did_ftplugin"))
      9  finish
     10 endif
     11 let b:did_ftplugin = 1
     12 
     13 let s:cpo_save = &cpo
     14 set cpo&vim
     15 
     16 if has("gui_running") && !has("gui_win32")
     17  setlocal keywordprg=ri\ -T\ -f\ bs
     18 else
     19  setlocal keywordprg=ri
     20 endif
     21 
     22 " Matchit support
     23 if exists("loaded_matchit") && !exists("b:match_words")
     24  let b:match_ignorecase = 0
     25 
     26  let b:match_words =
     27 \ '{\|\<\%(if\|unless\|case\|while\|until\|for\|do\|class\|module\|def\|=\@<!begin\)\>=\@!' .
     28 \ ':' .
     29 \ '\<\%(else\|elsif\|ensure\|when\|rescue\|break\|redo\|next\|retry\)\>' .
     30 \ ':' .
     31        \ '}\|\%(^\|[^.\:@$=]\)\@<=\<end\:\@!\>' .
     32        \ ',^=begin\>:^=end\>,' .
     33 \ ',\[:\],(:)'
     34 
     35  let b:match_skip =
     36 \ "synIDattr(synID(line('.'),col('.'),0),'name') =~ '" .
     37 \ "\\<ruby\\%(String\\|.\+Delimiter\\|Character\\|.\+Escape\\|" .
     38        \ "Regexp\\|Interpolation\\|Comment\\|Documentation\\|" .
     39 \ "ConditionalModifier\\|RepeatModifier\\|RescueModifier\\|OptionalDo\\|" .
     40 \ "MethodName\\|BlockArgument\\|KeywordAsMethod\\|ClassVariable\\|" .
     41 \ "InstanceVariable\\|GlobalVariable\\|Symbol\\)\\>'"
     42 endif
     43 
     44 setlocal formatoptions-=t formatoptions+=croql
     45 
     46 setlocal include=^\\s*\\<\\(load\\>\\\|require\\>\\\|autoload\\s*:\\=[\"']\\=\\h\\w*[\"']\\=,\\)
     47 setlocal suffixesadd=.rb
     48 
     49 if exists("&ofu") && has("ruby")
     50  setlocal omnifunc=rubycomplete#Complete
     51 endif
     52 
     53 " TODO:
     54 "setlocal define=^\\s*def
     55 
     56 setlocal comments=b:#
     57 setlocal commentstring=#\ %s
     58 
     59 if !exists('g:ruby_version_paths')
     60  let g:ruby_version_paths = {}
     61 endif
     62 
     63 let s:path_split = has('win32') ? ';' : ':'
     64 
     65 function! s:query_path(root) abort
     66  " Disabled by default for security reasons.
     67  if !get(g:, 'ruby_exec', get(g:, 'plugin_exec', 0)) || empty(a:root)
     68    return map(split($RUBYLIB, s:path_split), 'v:val ==# "." ? "" : v:val')
     69  endif
     70  let code = "print $:.join %q{,}"
     71  if &shellxquote == "'"
     72    let args = ' --disable-gems -e "' . code . '"'
     73  else
     74    let args = " --disable-gems -e '" . code . "'"
     75  endif
     76 
     77  let cd = haslocaldir() ? 'lcd' : exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd'
     78  let cwd = fnameescape(getcwd())
     79  try
     80    exe cd fnameescape(a:root)
     81    for dir in split($PATH, s:path_split)
     82      if dir !=# '.' && executable(dir . '/ruby') == 1
     83 let exepath = dir . '/ruby'
     84 break
     85      endif
     86    endfor
     87    if exists('l:exepath')
     88      let path = split(system(exepath . args),',')
     89      if v:shell_error
     90 let path = []
     91      endif
     92    else
     93      let path = []
     94    endif
     95    exe cd cwd
     96    return path
     97  finally
     98    exe cd cwd
     99  endtry
    100 endfunction
    101 
    102 function! s:build_path(path) abort
    103  let path = join(map(copy(a:path), 'v:val ==# "." ? "" : v:val'), ',')
    104  if &g:path =~# '\v^%(\.,)=%(/%(usr|emx)/include,)=,$'
    105    let path = path . ',.,,'
    106  elseif &g:path =~# ',\.,,$'
    107    let path = &g:path[0:-4] . path . ',.,,'
    108  elseif &g:path =~# ',,$'
    109    let path = &g:path[0:-2] . path . ',,'
    110  else
    111    let path = substitute(&g:path, '[^,]\zs$', ',', '') . path
    112  endif
    113  return path
    114 endfunction
    115 
    116 if !exists('b:ruby_version') && !exists('g:ruby_path') && isdirectory(expand('%:p:h'))
    117  let s:version_file = findfile('.ruby-version', '.;')
    118  if !empty(s:version_file) && filereadable(s:version_file)
    119    let b:ruby_version = get(readfile(s:version_file, '', 1), '')
    120    if !has_key(g:ruby_version_paths, b:ruby_version)
    121      let g:ruby_version_paths[b:ruby_version] = s:query_path(fnamemodify(s:version_file, ':p:h'))
    122    endif
    123  endif
    124 endif
    125 
    126 if exists("g:ruby_path")
    127  let s:ruby_path = type(g:ruby_path) == type([]) ? join(g:ruby_path, ',') : g:ruby_path
    128 elseif has_key(g:ruby_version_paths, get(b:, 'ruby_version', ''))
    129  let s:ruby_paths = g:ruby_version_paths[b:ruby_version]
    130  let s:ruby_path = s:build_path(s:ruby_paths)
    131 else
    132  if !exists('g:ruby_default_path')
    133    if has("ruby") && has("win32")
    134      ruby ::VIM::command( 'let g:ruby_default_path = split("%s",",")' % $:.join(%q{,}) )
    135    else
    136      let g:ruby_default_path = s:query_path($HOME)
    137    endif
    138  endif
    139  let s:ruby_paths = g:ruby_default_path
    140  let s:ruby_path = s:build_path(s:ruby_paths)
    141 endif
    142 
    143 if stridx(&l:path, s:ruby_path) == -1
    144  let &l:path = s:ruby_path
    145 endif
    146 if exists('s:ruby_paths') && stridx(&l:tags, join(map(copy(s:ruby_paths),'v:val."/tags"'),',')) == -1
    147  let &l:tags = &tags . ',' . join(map(copy(s:ruby_paths),'v:val."/tags"'),',')
    148 endif
    149 
    150 if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
    151  let b:browsefilter = "Ruby Source Files (*.rb)\t*.rb\n"
    152  if has("win32")
    153    let b:browsefilter .= "All Files (*.*)\t*\n"
    154  else
    155    let b:browsefilter .= "All Files (*)\t*\n"
    156  endif
    157 endif
    158 
    159 let b:undo_ftplugin = "setl inc= sua= path= tags= fo< com< cms< kp="
    160      \."| unlet! b:browsefilter b:match_ignorecase b:match_words b:match_skip"
    161      \."| if exists('&ofu') && has('ruby') | setl ofu< | endif"
    162 
    163 if get(g:, 'ruby_recommended_style', 1)
    164  setlocal shiftwidth=2 softtabstop=2 expandtab
    165  let b:undo_ftplugin .= ' | setl sw< sts< et<'
    166 endif
    167 
    168 " To activate, :set ballooneval
    169 if exists('+balloonexpr') && get(g:, 'ruby_balloonexpr')
    170  setlocal balloonexpr=RubyBalloonexpr()
    171  let b:undo_ftplugin .= "| setl bexpr="
    172 endif
    173 
    174 function! s:map(mode, flags, map) abort
    175  let from = matchstr(a:map, '\S\+')
    176  if empty(mapcheck(from, a:mode))
    177    exe a:mode.'map' '<buffer>' a:flags a:map
    178    let b:undo_ftplugin .= '|sil! '.a:mode.'unmap <buffer> '.from
    179  endif
    180 endfunction
    181 
    182 cmap <buffer><script><expr> <Plug><ctag> substitute(RubyCursorTag(),'^$',"\022\027",'')
    183 cmap <buffer><script><expr> <Plug><cfile> substitute(RubyCursorFile(),'^$',"\022\006",'')
    184 let b:undo_ftplugin .= "| sil! cunmap <buffer> <Plug><ctag>| sil! cunmap <buffer> <Plug><cfile>"
    185 
    186 if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
    187  nmap <buffer><script> <SID>:  :<C-U>
    188  nmap <buffer><script> <SID>c: :<C-U><C-R>=v:count ? v:count : ''<CR>
    189  cmap <buffer> <SID><cfile> <Plug><cfile>
    190  cmap <buffer> <SID><ctag>  <Plug><ctag>
    191 
    192  nnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'b','n')<CR>
    193  nnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'','n')<CR>
    194  nnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'b','n')<CR>
    195  nnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'','n')<CR>
    196  xnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'b','v')<CR>
    197  xnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'','v')<CR>
    198  xnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'b','v')<CR>
    199  xnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'','v')<CR>
    200 
    201  nnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'b','n')<CR>
    202  nnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'','n')<CR>
    203  nnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'b','n')<CR>
    204  nnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'','n')<CR>
    205  xnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'b','v')<CR>
    206  xnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'','v')<CR>
    207  xnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'b','v')<CR>
    208  xnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'','v')<CR>
    209 
    210  let b:undo_ftplugin = b:undo_ftplugin
    211        \."| sil! exe 'unmap <buffer> [[' | sil! exe 'unmap <buffer> ]]' | sil! exe 'unmap <buffer> []' | sil! exe 'unmap <buffer> ]['"
    212        \."| sil! exe 'unmap <buffer> [m' | sil! exe 'unmap <buffer> ]m' | sil! exe 'unmap <buffer> [M' | sil! exe 'unmap <buffer> ]M'"
    213 
    214  if maparg('im','x') == '' && maparg('im','o') == '' && maparg('am','x') == '' && maparg('am','o') == ''
    215    onoremap <silent> <buffer> im :<C-U>call <SID>wrap_i('[m',']M')<CR>
    216    onoremap <silent> <buffer> am :<C-U>call <SID>wrap_a('[m',']M')<CR>
    217    xnoremap <silent> <buffer> im :<C-U>call <SID>wrap_i('[m',']M')<CR>
    218    xnoremap <silent> <buffer> am :<C-U>call <SID>wrap_a('[m',']M')<CR>
    219    let b:undo_ftplugin = b:undo_ftplugin
    220          \."| sil! exe 'ounmap <buffer> im' | sil! exe 'ounmap <buffer> am'"
    221          \."| sil! exe 'xunmap <buffer> im' | sil! exe 'xunmap <buffer> am'"
    222  endif
    223 
    224  if maparg('iM','x') == '' && maparg('iM','o') == '' && maparg('aM','x') == '' && maparg('aM','o') == ''
    225    onoremap <silent> <buffer> iM :<C-U>call <SID>wrap_i('[[','][')<CR>
    226    onoremap <silent> <buffer> aM :<C-U>call <SID>wrap_a('[[','][')<CR>
    227    xnoremap <silent> <buffer> iM :<C-U>call <SID>wrap_i('[[','][')<CR>
    228    xnoremap <silent> <buffer> aM :<C-U>call <SID>wrap_a('[[','][')<CR>
    229    let b:undo_ftplugin = b:undo_ftplugin
    230          \."| sil! exe 'ounmap <buffer> iM' | sil! exe 'ounmap <buffer> aM'"
    231          \."| sil! exe 'xunmap <buffer> iM' | sil! exe 'xunmap <buffer> aM'"
    232  endif
    233 
    234  call s:map('c', '', '<C-R><C-F> <Plug><cfile>')
    235 
    236  cmap <buffer><script><expr> <SID>tagzv &foldopen =~# 'tag' ? '<Bar>norm! zv' : ''
    237  call s:map('n', '<script><silent>', '<C-]>       <SID>:exe  v:count1."tag <SID><ctag>"<SID>tagzv<CR>')
    238  call s:map('n', '<script><silent>', 'g<C-]>      <SID>:exe         "tjump <SID><ctag>"<SID>tagzv<CR>')
    239  call s:map('n', '<script><silent>', 'g]          <SID>:exe       "tselect <SID><ctag>"<SID>tagzv<CR>')
    240  call s:map('n', '<script><silent>', '<C-W>]      <SID>:exe v:count1."stag <SID><ctag>"<SID>tagzv<CR>')
    241  call s:map('n', '<script><silent>', '<C-W><C-]>  <SID>:exe v:count1."stag <SID><ctag>"<SID>tagzv<CR>')
    242  call s:map('n', '<script><silent>', '<C-W>g<C-]> <SID>:exe        "stjump <SID><ctag>"<SID>tagzv<CR>')
    243  call s:map('n', '<script><silent>', '<C-W>g]     <SID>:exe      "stselect <SID><ctag>"<SID>tagzv<CR>')
    244  call s:map('n', '<script><silent>', '<C-W>}      <SID>:exe v:count1."ptag <SID><ctag>"<CR>')
    245  call s:map('n', '<script><silent>', '<C-W>g}     <SID>:exe        "ptjump <SID><ctag>"<CR>')
    246 
    247  call s:map('n', '<script><silent>', 'gf           <SID>c:find <SID><cfile><CR>')
    248  call s:map('n', '<script><silent>', '<C-W>f      <SID>c:sfind <SID><cfile><CR>')
    249  call s:map('n', '<script><silent>', '<C-W><C-F>  <SID>c:sfind <SID><cfile><CR>')
    250  call s:map('n', '<script><silent>', '<C-W>gf   <SID>c:tabfind <SID><cfile><CR>')
    251 endif
    252 
    253 let &cpo = s:cpo_save
    254 unlet s:cpo_save
    255 
    256 if exists("g:did_ruby_ftplugin_functions")
    257  finish
    258 endif
    259 let g:did_ruby_ftplugin_functions = 1
    260 
    261 function! RubyBalloonexpr() abort
    262  if !exists('s:ri_found')
    263    let s:ri_found = executable('ri')
    264  endif
    265  if s:ri_found
    266    let line = getline(v:beval_lnum)
    267    let b = matchstr(strpart(line,0,v:beval_col),'\%(\w\|[:.]\)*$')
    268    let a = substitute(matchstr(strpart(line,v:beval_col),'^\w*\%([?!]\|\s*=\)\?'),'\s\+','','g')
    269    let str = b.a
    270    let before = strpart(line,0,v:beval_col-strlen(b))
    271    let after  = strpart(line,v:beval_col+strlen(a))
    272    if str =~ '^\.'
    273      let str = substitute(str,'^\.','#','g')
    274      if before =~ '\]\s*$'
    275        let str = 'Array'.str
    276      elseif before =~ '}\s*$'
    277        " False positives from blocks here
    278        let str = 'Hash'.str
    279      elseif before =~ "[\"'`]\\s*$" || before =~ '\$\d\+\s*$'
    280        let str = 'String'.str
    281      elseif before =~ '\$\d\+\.\d\+\s*$'
    282        let str = 'Float'.str
    283      elseif before =~ '\$\d\+\s*$'
    284        let str = 'Integer'.str
    285      elseif before =~ '/\s*$'
    286        let str = 'Regexp'.str
    287      else
    288        let str = substitute(str,'^#','.','')
    289      endif
    290    endif
    291    let str = substitute(str,'.*\.\s*to_f\s*\.\s*','Float#','')
    292    let str = substitute(str,'.*\.\s*to_i\%(nt\)\=\s*\.\s*','Integer#','')
    293    let str = substitute(str,'.*\.\s*to_s\%(tr\)\=\s*\.\s*','String#','')
    294    let str = substitute(str,'.*\.\s*to_sym\s*\.\s*','Symbol#','')
    295    let str = substitute(str,'.*\.\s*to_a\%(ry\)\=\s*\.\s*','Array#','')
    296    let str = substitute(str,'.*\.\s*to_proc\s*\.\s*','Proc#','')
    297    if str !~ '^\w'
    298      return ''
    299    endif
    300    silent! let res = substitute(system("ri -f rdoc -T \"".str.'"'),'\n$','','')
    301    if res =~ '^Nothing known about' || res =~ '^Bad argument:' || res =~ '^More than one method'
    302      return ''
    303    endif
    304    return res
    305  else
    306    return ""
    307  endif
    308 endfunction
    309 
    310 function! s:searchsyn(pattern, syn, flags, mode) abort
    311  let cnt = v:count1
    312  norm! m'
    313  if a:mode ==# 'v'
    314    norm! gv
    315  endif
    316  let i = 0
    317  call map(a:syn, 'hlID(v:val)')
    318  while i < cnt
    319    let i = i + 1
    320    let line = line('.')
    321    let col  = col('.')
    322    let pos = search(a:pattern,'W'.a:flags)
    323    while pos != 0 && index(a:syn, s:synid()) < 0
    324      let pos = search(a:pattern,'W'.a:flags)
    325    endwhile
    326    if pos == 0
    327      call cursor(line,col)
    328      return
    329    endif
    330  endwhile
    331 endfunction
    332 
    333 function! s:synid() abort
    334  return synID(line('.'),col('.'),0)
    335 endfunction
    336 
    337 function! s:wrap_i(back,forward) abort
    338  execute 'norm! k'
    339  execute 'norm '.a:forward
    340  let line = line('.')
    341  execute 'norm '.a:back
    342  if line('.') == line - 1
    343    return s:wrap_a(a:back,a:forward)
    344  endif
    345  execute 'norm! jV'
    346  execute 'norm '.a:forward
    347  execute 'norm! k'
    348 endfunction
    349 
    350 function! s:wrap_a(back,forward) abort
    351  execute 'norm '.a:forward
    352  if line('.') < line('$') && getline(line('.')+1) ==# ''
    353    let after = 1
    354  endif
    355  execute 'norm '.a:back
    356  while getline(line('.')-1) =~# '^\s*#' && line('.')
    357    -
    358  endwhile
    359  if exists('after')
    360    execute 'norm! V'
    361    execute 'norm '.a:forward
    362    execute 'norm! j'
    363  elseif line('.') > 1 && getline(line('.')-1) =~# '^\s*$'
    364    execute 'norm! kV'
    365    execute 'norm '.a:forward
    366  else
    367    execute 'norm! V'
    368    execute 'norm '.a:forward
    369  endif
    370 endfunction
    371 
    372 function! RubyCursorIdentifier() abort
    373  let asciicode    = '\%(\w\|[]})\"'."'".']\)\@<!\%(?\%(\\M-\\C-\|\\C-\\M-\|\\M-\\c\|\\c\\M-\|\\c\|\\C-\|\\M-\)\=\%(\\\o\{1,3}\|\\x\x\{1,2}\|\\\=\S\)\)'
    374  let number       = '\%(\%(\w\|[]})\"'."'".']\s*\)\@<!-\)\=\%(\<[[:digit:]_]\+\%(\.[[:digit:]_]\+\)\=\%([Ee][[:digit:]_]\+\)\=\>\|\<0[xXbBoOdD][[:xdigit:]_]\+\>\)\|'.asciicode
    375  let operator     = '\%(\[\]\|<<\|<=>\|[!<>]=\=\|===\=\|[!=]\~\|>>\|\*\*\|\.\.\.\=\|=>\|[~^&|*/%+-]\)'
    376  let method       = '\%(\.[_a-zA-Z]\w*\s*=>\@!\|\<[_a-zA-Z]\w*\>[?!]\=\)'
    377  let global       = '$\%([!$&"'."'".'*+,./:;<=>?@\`~]\|-\=\w\+\>\)'
    378  let symbolizable = '\%(\%(@@\=\)\w\+\>\|'.global.'\|'.method.'\|'.operator.'\)'
    379  let pattern      = '\C\s*\%('.number.'\|\%(:\@<!:\)\='.symbolizable.'\)'
    380  let [lnum, col]  = searchpos(pattern,'bcn',line('.'))
    381  let raw          = matchstr(getline('.')[col-1 : ],pattern)
    382  let stripped     = substitute(substitute(raw,'\s\+=$','=',''),'^\s*[:.]\=','','')
    383  return stripped == '' ? expand("<cword>") : stripped
    384 endfunction
    385 
    386 function! RubyCursorTag() abort
    387  return substitute(RubyCursorIdentifier(), '^[$@]*', '', '')
    388 endfunction
    389 
    390 function! RubyCursorFile() abort
    391  let isfname = &isfname
    392  try
    393    set isfname+=:
    394    let cfile = expand('<cfile>')
    395  finally
    396    let isfname = &isfname
    397  endtry
    398  let pre = matchstr(strpart(getline('.'), 0, col('.')-1), '.*\f\@<!')
    399  let post = matchstr(strpart(getline('.'), col('.')), '\f\@!.*')
    400  if s:synid() ==# hlID('rubyConstant')
    401    let cfile = substitute(cfile,'\.\w\+[?!=]\=$','','')
    402    let cfile = substitute(cfile,'^::','','')
    403    let cfile = substitute(cfile,'::','/','g')
    404    let cfile = substitute(cfile,'\(\u\+\)\(\u\l\)','\1_\2', 'g')
    405    let cfile = substitute(cfile,'\(\l\|\d\)\(\u\)','\1_\2', 'g')
    406    return tolower(cfile) . '.rb'
    407  elseif getline('.') =~# '^\s*require_relative\s*\(["'']\).*\1\s*$'
    408    let cfile = expand('%:p:h') . '/' . matchstr(getline('.'),'\(["'']\)\zs.\{-\}\ze\1')
    409    let cfile .= cfile !~# '\.rb$' ? '.rb' : ''
    410  elseif getline('.') =~# '^\s*\%(require[( ]\|load[( ]\|autoload[( ]:\w\+,\)\s*\%(::\)\=File\.expand_path(\(["'']\)\.\./.*\1,\s*__FILE__)\s*$'
    411    let target = matchstr(getline('.'),'\(["'']\)\.\.\zs/.\{-\}\ze\1')
    412    let cfile = expand('%:p:h') . target
    413    let cfile .= cfile !~# '\.rb$' ? '.rb' : ''
    414  elseif getline('.') =~# '^\s*\%(require \|load \|autoload :\w\+,\)\s*\(["'']\).*\1\s*$'
    415    let cfile = matchstr(getline('.'),'\(["'']\)\zs.\{-\}\ze\1')
    416    let cfile .= cfile !~# '\.rb$' ? '.rb' : ''
    417  elseif pre.post =~# '\<File.expand_path[( ].*[''"]\{2\}, *__FILE__\>' && cfile =~# '^\.\.'
    418    let cfile = expand('%:p:h') . strpart(cfile, 2)
    419  else
    420    return substitute(cfile, '\C\v^(.*):(\d+)%(:in)=$', '+\2 \1', '')
    421  endif
    422  let cwdpat = '^\M' . substitute(getcwd(), '[\/]', '\\[\\/]', 'g').'\ze\[\/]'
    423  let cfile = substitute(cfile, cwdpat, '.', '')
    424  if fnameescape(cfile) !=# cfile
    425    return '+ '.fnameescape(cfile)
    426  else
    427    return cfile
    428  endif
    429 endfunction
    430 
    431 "
    432 " Instructions for enabling "matchit" support:
    433 "
    434 " 1. Look for the latest "matchit" plugin at
    435 "
    436 "         http://www.vim.org/scripts/script.php?script_id=39
    437 "
    438 "    It is also packaged with Vim, in the $VIMRUNTIME/macros directory.
    439 "
    440 " 2. Copy "matchit.txt" into a "doc" directory (e.g. $HOME/.vim/doc).
    441 "
    442 " 3. Copy "matchit.vim" into a "plugin" directory (e.g. $HOME/.vim/plugin).
    443 "
    444 " 4. Ensure this file (ftplugin/ruby.vim) is installed.
    445 "
    446 " 5. Ensure you have this line in your $HOME/.vimrc:
    447 "         filetype plugin on
    448 "
    449 " 6. Restart Vim and create the matchit documentation:
    450 "
    451 "         :helptags ~/.vim/doc
    452 "
    453 "    Now you can do ":help matchit", and you should be able to use "%" on Ruby
    454 "    keywords.  Try ":echo b:match_words" to be sure.
    455 "
    456 " Thanks to Mark J. Reed for the instructions.  See ":help vimrc" for the
    457 " locations of plugin directories, etc., as there are several options, and it
    458 " differs on Windows.  Email gsinclair@soyabean.com.au if you need help.
    459 "
    460 
    461 " vim: nowrap sw=2 sts=2 ts=8: