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