1" Vim completion script 2" Language: Ruby 3" Maintainer: Mark Guzman <[email protected]> 4" URL: https://github.com/vim-ruby/vim-ruby 5" Release Coordinator: Doug Kearns <[email protected]> 6" Last Change: 2019 Feb 25 7" ---------------------------------------------------------------------------- 8" 9" Ruby IRB/Complete author: Keiju ISHITSUKA([email protected]) 10" ---------------------------------------------------------------------------- 11 12" {{{ requirement checks 13 14function! s:ErrMsg(msg) 15 echohl ErrorMsg 16 echo a:msg 17 echohl None 18endfunction 19 20if !has('ruby') 21 call s:ErrMsg( "Error: Rubycomplete requires vim compiled with +ruby" ) 22 call s:ErrMsg( "Error: falling back to syntax completion" ) 23 " lets fall back to syntax completion 24 setlocal omnifunc=syntaxcomplete#Complete 25 finish 26endif 27 28if version < 700 29 call s:ErrMsg( "Error: Required vim >= 7.0" ) 30 finish 31endif 32" }}} requirement checks 33 34" {{{ configuration failsafe initialization 35if !exists("g:rubycomplete_rails") 36 let g:rubycomplete_rails = 0 37endif 38 39if !exists("g:rubycomplete_classes_in_global") 40 let g:rubycomplete_classes_in_global = 0 41endif 42 43if !exists("g:rubycomplete_buffer_loading") 44 let g:rubycomplete_buffer_loading = 0 45endif 46 47if !exists("g:rubycomplete_include_object") 48 let g:rubycomplete_include_object = 0 49endif 50 51if !exists("g:rubycomplete_include_objectspace") 52 let g:rubycomplete_include_objectspace = 0 53endif 54" }}} configuration failsafe initialization 55 56" {{{ regex patterns 57 58" Regex that defines the start-match for the 'end' keyword. 59let s:end_start_regex = 60 \ '\C\%(^\s*\|[=,*/%+\-|;{]\|<<\|>>\|:\s\)\s*\zs' . 61 \ '\<\%(module\|class\|if\|for\|while\|until\|case\|unless\|begin' . 62 \ '\|\%(\K\k*[!?]\?\s\+\)\=def\):\@!\>' . 63 \ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>' 64 65" Regex that defines the middle-match for the 'end' keyword. 66let s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|elsif\):\@!\>' 67 68" Regex that defines the end-match for the 'end' keyword. 69let s:end_end_regex = '\%(^\|[^.:@$]\)\@<=\<end:\@!\>' 70 71" }}} regex patterns 72 73" {{{ vim-side support functions 74let s:rubycomplete_debug = 0 75 76function! s:dprint(msg) 77 if s:rubycomplete_debug == 1 78 echom a:msg 79 endif 80endfunction 81 82function! s:GetBufferRubyModule(name, ...) 83 if a:0 == 1 84 let [snum,enum] = s:GetBufferRubyEntity(a:name, "module", a:1) 85 else 86 let [snum,enum] = s:GetBufferRubyEntity(a:name, "module") 87 endif 88 return snum . '..' . enum 89endfunction 90 91function! s:GetBufferRubyClass(name, ...) 92 if a:0 >= 1 93 let [snum,enum] = s:GetBufferRubyEntity(a:name, "class", a:1) 94 else 95 let [snum,enum] = s:GetBufferRubyEntity(a:name, "class") 96 endif 97 return snum . '..' . enum 98endfunction 99 100function! s:GetBufferRubySingletonMethods(name) 101endfunction 102 103function! s:GetBufferRubyEntity( name, type, ... ) 104 let lastpos = getpos(".") 105 let lastline = lastpos 106 if (a:0 >= 1) 107 let lastline = [ 0, a:1, 0, 0 ] 108 call cursor( a:1, 0 ) 109 endif 110 111 let stopline = 1 112 113 let crex = '^\s*\<' . a:type . '\>\s*\<' . escape(a:name, '*') . '\>\s*\(<\s*.*\s*\)\?' 114 let [lnum,lcol] = searchpos( crex, 'w' ) 115 "let [lnum,lcol] = searchpairpos( crex . '\zs', '', '\(end\|}\)', 'w' ) 116 117 if lnum == 0 && lcol == 0 118 call cursor(lastpos[1], lastpos[2]) 119 return [0,0] 120 endif 121 122 let curpos = getpos(".") 123 let [enum,ecol] = searchpairpos( s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'W' ) 124 call cursor(lastpos[1], lastpos[2]) 125 126 if lnum > enum 127 return [0,0] 128 endif 129 " we found a the class def 130 return [lnum,enum] 131endfunction 132 133function! s:IsInClassDef() 134 return s:IsPosInClassDef( line('.') ) 135endfunction 136 137function! s:IsPosInClassDef(pos) 138 let [snum,enum] = s:GetBufferRubyEntity( '.*', "class" ) 139 let ret = 'nil' 140 141 if snum < a:pos && a:pos < enum 142 let ret = snum . '..' . enum 143 endif 144 145 return ret 146endfunction 147 148function! s:IsInComment(pos) 149 let stack = synstack(a:pos[0], a:pos[1]) 150 if !empty(stack) 151 return synIDattr(stack[0], 'name') =~ 'ruby\%(.*Comment\|Documentation\)' 152 else 153 return 0 154 endif 155endfunction 156 157function! s:GetRubyVarType(v) 158 let stopline = 1 159 let vtp = '' 160 let curpos = getpos('.') 161 let sstr = '^\s*#\s*@var\s*'.escape(a:v, '*').'\>\s\+[^ \t]\+\s*$' 162 let [lnum,lcol] = searchpos(sstr,'nb',stopline) 163 if lnum != 0 && lcol != 0 164 call setpos('.',curpos) 165 let str = getline(lnum) 166 let vtp = substitute(str,sstr,'\1','') 167 return vtp 168 endif 169 call setpos('.',curpos) 170 let ctors = '\(now\|new\|open\|get_instance' 171 if exists('g:rubycomplete_rails') && g:rubycomplete_rails == 1 && s:rubycomplete_rails_loaded == 1 172 let ctors = ctors.'\|find\|create' 173 else 174 endif 175 let ctors = ctors.'\)' 176 177 let fstr = '=\s*\([^ \t]\+.' . ctors .'\>\|[\[{"''/]\|%[xwQqr][(\[{@]\|[A-Za-z0-9@:\-()\.]\+...\?\|lambda\|&\)' 178 let sstr = ''.escape(a:v, '*').'\>\s*[+\-*/]*'.fstr 179 let pos = searchpos(sstr,'bW') 180 while pos != [0,0] && s:IsInComment(pos) 181 let pos = searchpos(sstr,'bW') 182 endwhile 183 if pos != [0,0] 184 let [lnum, col] = pos 185 let str = matchstr(getline(lnum),fstr,col) 186 let str = substitute(str,'^=\s*','','') 187 188 call setpos('.',pos) 189 if str == '"' || str == '''' || stridx(tolower(str), '%q[') != -1 190 return 'String' 191 elseif str == '[' || stridx(str, '%w[') != -1 192 return 'Array' 193 elseif str == '{' 194 return 'Hash' 195 elseif str == '/' || str == '%r{' 196 return 'Regexp' 197 elseif strlen(str) >= 4 && stridx(str,'..') != -1 198 return 'Range' 199 elseif stridx(str, 'lambda') != -1 || str == '&' 200 return 'Proc' 201 elseif strlen(str) > 4 202 let l = stridx(str,'.') 203 return str[0:l-1] 204 end 205 return '' 206 endif 207 call setpos('.',curpos) 208 return '' 209endfunction 210 211"}}} vim-side support functions 212 213"{{{ vim-side completion function 214function! rubycomplete#Init() 215 execute "ruby VimRubyCompletion.preload_rails" 216endfunction 217 218function! rubycomplete#Complete(findstart, base) 219 "findstart = 1 when we need to get the text length 220 if a:findstart 221 let line = getline('.') 222 let idx = col('.') 223 while idx > 0 224 let idx -= 1 225 let c = line[idx-1] 226 if c =~ '\w' 227 continue 228 elseif ! c =~ '\.' 229 let idx = -1 230 break 231 else 232 break 233 endif 234 endwhile 235 236 return idx 237 "findstart = 0 when we need to return the list of completions 238 else 239 let g:rubycomplete_completions = [] 240 execute "ruby VimRubyCompletion.get_completions('" . a:base . "')" 241 return g:rubycomplete_completions 242 endif 243endfunction 244"}}} vim-side completion function 245 246"{{{ ruby-side code 247function! s:DefRuby() 248ruby << RUBYEOF 249# {{{ ruby completion 250 251begin 252 require 'rubygems' # let's assume this is safe...? 253rescue Exception 254 #ignore? 255end 256class VimRubyCompletion 257# {{{ constants 258 @@debug = false 259 @@ReservedWords = [ 260 "BEGIN", "END", 261 "alias", "and", 262 "begin", "break", 263 "case", "class", 264 "def", "defined", "do", 265 "else", "elsif", "end", "ensure", 266 "false", "for", 267 "if", "in", 268 "module", 269 "next", "nil", "not", 270 "or", 271 "redo", "rescue", "retry", "return", 272 "self", "super", 273 "then", "true", 274 "undef", "unless", "until", 275 "when", "while", 276 "yield", 277 ] 278 279 @@Operators = [ "%", "&", "*", "**", "+", "-", "/", 280 "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>", 281 "[]", "[]=", "^", ] 282# }}} constants 283 284# {{{ buffer analysis magic 285 def load_requires 286 287 custom_paths = VIM::evaluate("get(g:, 'rubycomplete_load_paths', [])") 288 289 if !custom_paths.empty? 290 $LOAD_PATH.concat(custom_paths).uniq! 291 end 292 293 buf = VIM::Buffer.current 294 enum = buf.line_number 295 nums = Range.new( 1, enum ) 296 nums.each do |x| 297 298 ln = buf[x] 299 begin 300 if /.*require_relative\s*(.*)$/.match( ln ) 301 eval( "require %s" % File.expand_path($1) ) 302 elsif /.*require\s*(["'].*?["'])/.match( ln ) 303 eval( "require %s" % $1 ) 304 end 305 rescue Exception => e 306 dprint e.inspect 307 end 308 end 309 end 310 311 def load_gems 312 fpath = VIM::evaluate("get(g:, 'rubycomplete_gemfile_path', 'Gemfile')") 313 return unless File.file?(fpath) && File.readable?(fpath) 314 want_bundler = VIM::evaluate("get(g:, 'rubycomplete_use_bundler')") 315 parse_file = !want_bundler 316 begin 317 require 'bundler' 318 Bundler.setup 319 Bundler.require 320 rescue Exception 321 parse_file = true 322 end 323 if parse_file 324 File.new(fpath).each_line do |line| 325 begin 326 require $1 if /\s*gem\s*['"]([^'"]+)/.match(line) 327 rescue Exception 328 end 329 end 330 end 331 end 332 333 def load_buffer_class(name) 334 dprint "load_buffer_class(%s) START" % name 335 classdef = get_buffer_entity(name, 's:GetBufferRubyClass("%s")') 336 return if classdef == nil 337 338 pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef ) 339 load_buffer_class( $2 ) if pare != nil && $2 != name # load parent class if needed 340 341 mixre = /.*\n\s*(include|prepend)\s*(.*)\s*\n/.match( classdef ) 342 load_buffer_module( $2 ) if mixre != nil && $2 != name # load mixins if needed 343 344 begin 345 eval classdef 346 rescue Exception 347 VIM::evaluate( "s:ErrMsg( 'Problem loading class \"%s\", was it already completed?' )" % name ) 348 end 349 dprint "load_buffer_class(%s) END" % name 350 end 351 352 def load_buffer_module(name) 353 dprint "load_buffer_module(%s) START" % name 354 classdef = get_buffer_entity(name, 's:GetBufferRubyModule("%s")') 355 return if classdef == nil 356 357 begin 358 eval classdef 359 rescue Exception 360 VIM::evaluate( "s:ErrMsg( 'Problem loading module \"%s\", was it already completed?' )" % name ) 361 end 362 dprint "load_buffer_module(%s) END" % name 363 end 364 365 def get_buffer_entity(name, vimfun) 366 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading") 367 return nil if loading_allowed.to_i.zero? 368 return nil if /(\"|\')+/.match( name ) 369 buf = VIM::Buffer.current 370 nums = eval( VIM::evaluate( vimfun % name ) ) 371 return nil if nums == nil 372 return nil if nums.min == nums.max && nums.min == 0 373 374 dprint "get_buffer_entity START" 375 visited = [] 376 clscnt = 0 377 bufname = VIM::Buffer.current.name 378 classdef = "" 379 cur_line = VIM::Buffer.current.line_number 380 while (nums != nil && !(nums.min == 0 && nums.max == 0) ) 381 dprint "visited: %s" % visited.to_s 382 break if visited.index( nums ) 383 visited << nums 384 385 nums.each do |x| 386 if x != cur_line 387 next if x == 0 388 ln = buf[x] 389 is_const = false 390 if /^\s*(module|class|def|include)\s+/.match(ln) || is_const = /^\s*?[A-Z]([A-z]|[1-9])*\s*?[|]{0,2}=\s*?.+\s*?/.match(ln) 391 clscnt += 1 if /class|module/.match($1) 392 # We must make sure to load each constant only once to avoid errors 393 if is_const 394 ln.gsub!(/\s*?[|]{0,2}=\s*?/, '||=') 395 end 396 #dprint "\$1$1 397 classdef += "%s\n" % ln 398 classdef += "end\n" if /def\s+/.match(ln) 399 dprint ln 400 end 401 end 402 end 403 404 nm = "%s(::.*)*\", %s, \"" % [ name, nums.last ] 405 nums = eval( VIM::evaluate( vimfun % nm ) ) 406 dprint "nm: \"%s\"" % nm 407 dprint "vimfun: %s" % (vimfun % nm) 408 dprint "got nums: %s" % nums.to_s 409 end 410 if classdef.length > 1 411 classdef += "end\n"*clscnt 412 # classdef = "class %s\n%s\nend\n" % [ bufname.gsub( /\/|\\/, "_" ), classdef ] 413 end 414 415 dprint "get_buffer_entity END" 416 dprint "classdef====start" 417 lns = classdef.split( "\n" ) 418 lns.each { |x| dprint x } 419 dprint "classdef====end" 420 return classdef 421 end 422 423 def get_var_type( receiver ) 424 if /(\"|\')+/.match( receiver ) 425 "String" 426 else 427 VIM::evaluate("s:GetRubyVarType('%s')" % receiver) 428 end 429 end 430 431 def dprint( txt ) 432 print txt if @@debug 433 end 434 435 def escape_vim_singlequote_string(str) 436 str.to_s.gsub(/'/,"\\'") 437 end 438 439 def get_buffer_entity_list( type ) 440 # this will be a little expensive. 441 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading") 442 allow_aggressive_load = VIM::evaluate("exists('g:rubycomplete_classes_in_global') && g:rubycomplete_classes_in_global") 443 return [] if allow_aggressive_load.to_i.zero? || loading_allowed.to_i.zero? 444 445 buf = VIM::Buffer.current 446 eob = buf.length 447 ret = [] 448 rg = 1..eob 449 re = eval( "/^\s*%s\s*([A-Za-z0-9_:-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/" % type ) 450 451 rg.each do |x| 452 if re.match( buf[x] ) 453 next if type == "def" && eval( VIM::evaluate("s:IsPosInClassDef(%s)" % x) ) != nil 454 ret.push $1 455 end 456 end 457 458 return ret 459 end 460 461 def get_buffer_modules 462 return get_buffer_entity_list( "modules" ) 463 end 464 465 def get_buffer_methods 466 return get_buffer_entity_list( "def" ) 467 end 468 469 def get_buffer_classes 470 return get_buffer_entity_list( "class" ) 471 end 472 473 def load_rails 474 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails") 475 return if allow_rails.to_i.zero? 476 477 buf_path = VIM::evaluate('expand("%:p")') 478 file_name = VIM::evaluate('expand("%:t")') 479 vim_dir = VIM::evaluate('getcwd()') 480 file_dir = buf_path.gsub( file_name, '' ) 481 file_dir.gsub!( /\\/, "/" ) 482 vim_dir.gsub!( /\\/, "/" ) 483 vim_dir << "/" 484 dirs = [ vim_dir, file_dir ] 485 sdirs = [ "", "./", "../", "../../", "../../../", "../../../../" ] 486 rails_base = nil 487 488 dirs.each do |dir| 489 sdirs.each do |sub| 490 trail = "%s%s" % [ dir, sub ] 491 tcfg = "%sconfig" % trail 492 493 if File.exists?( tcfg ) 494 rails_base = trail 495 break 496 end 497 end 498 break if rails_base 499 end 500 501 return if rails_base == nil 502 $:.push rails_base unless $:.index( rails_base ) 503 504 rails_config = rails_base + "config/" 505 rails_lib = rails_base + "lib/" 506 $:.push rails_config unless $:.index( rails_config ) 507 $:.push rails_lib unless $:.index( rails_lib ) 508 509 bootfile = rails_config + "boot.rb" 510 envfile = rails_config + "environment.rb" 511 if File.exists?( bootfile ) && File.exists?( envfile ) 512 begin 513 require bootfile 514 require envfile 515 begin 516 require 'console_app' 517 require 'console_with_helpers' 518 rescue Exception 519 dprint "Rails 1.1+ Error %s" % $! 520 # assume 1.0 521 end 522 #eval( "Rails::Initializer.run" ) #not necessary? 523 VIM::command('let s:rubycomplete_rails_loaded = 1') 524 dprint "rails loaded" 525 rescue Exception 526 dprint "Rails Error %s" % $! 527 VIM::evaluate( "s:ErrMsg('Error loading rails environment')" ) 528 end 529 end 530 end 531 532 def get_rails_helpers 533 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails") 534 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded') 535 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero? 536 537 buf_path = VIM::evaluate('expand("%:p")') 538 buf_path.gsub!( /\\/, "/" ) 539 path_elm = buf_path.split( "/" ) 540 dprint "buf_path: %s" % buf_path 541 types = [ "app", "db", "lib", "test", "components", "script" ] 542 543 i = nil 544 ret = [] 545 type = nil 546 types.each do |t| 547 i = path_elm.index( t ) 548 break if i 549 end 550 type = path_elm[i] 551 type.downcase! 552 553 dprint "type: %s" % type 554 case type 555 when "app" 556 i += 1 557 subtype = path_elm[i] 558 subtype.downcase! 559 560 dprint "subtype: %s" % subtype 561 case subtype 562 when "views" 563 ret += ActionView::Base.instance_methods 564 ret += ActionView::Base.methods 565 when "controllers" 566 ret += ActionController::Base.instance_methods 567 ret += ActionController::Base.methods 568 when "models" 569 ret += ActiveRecord::Base.instance_methods 570 ret += ActiveRecord::Base.methods 571 end 572 573 when "db" 574 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods 575 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods 576 end 577 578 return ret 579 end 580 581 def add_rails_columns( cls ) 582 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails") 583 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded') 584 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero? 585 586 begin 587 eval( "#{cls}.establish_connection" ) 588 return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" ) 589 col = eval( "#{cls}.column_names" ) 590 return col if col 591 rescue 592 dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ] 593 return [] 594 end 595 return [] 596 end 597 598 def clean_sel(sel, msg) 599 ret = sel.reject{|x|x.nil?}.uniq 600 ret = ret.grep(/^#{Regexp.quote(msg)}/) if msg != nil 601 ret 602 end 603 604 def get_rails_view_methods 605 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails") 606 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded') 607 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero? 608 609 buf_path = VIM::evaluate('expand("%:p")') 610 buf_path.gsub!( /\\/, "/" ) 611 pelm = buf_path.split( "/" ) 612 idx = pelm.index( "views" ) 613 614 return [] unless idx 615 idx += 1 616 617 clspl = pelm[idx].camelize.pluralize 618 cls = clspl.singularize 619 620 ret = [] 621 begin 622 ret += eval( "#{cls}.instance_methods" ) 623 ret += eval( "#{clspl}Helper.instance_methods" ) 624 rescue Exception 625 dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ] 626 end 627 628 return ret 629 end 630# }}} buffer analysis magic 631 632# {{{ main completion code 633 def self.preload_rails 634 a = VimRubyCompletion.new 635 if VIM::evaluate("has('nvim')") == 0 636 require 'thread' 637 Thread.new(a) do |b| 638 begin 639 b.load_rails 640 rescue 641 end 642 end 643 end 644 a.load_rails 645 rescue 646 end 647 648 def self.get_completions(base) 649 b = VimRubyCompletion.new 650 b.get_completions base 651 end 652 653 def get_completions(base) 654 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading") 655 if loading_allowed.to_i == 1 656 load_requires 657 load_rails 658 end 659 660 want_gems = VIM::evaluate("get(g:, 'rubycomplete_load_gemfile')") 661 load_gems unless want_gems.to_i.zero? 662 663 input = VIM::Buffer.current.line 664 cpos = VIM::Window.current.cursor[1] - 1 665 input = input[0..cpos] 666 input += base 667 input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters 668 input.sub!(/self\./, '') 669 input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '') 670 671 dprint 'input %s' % input 672 message = nil 673 receiver = nil 674 methods = [] 675 variables = [] 676 classes = [] 677 constants = [] 678 679 case input 680 when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp 681 receiver = $1 682 message = Regexp.quote($2) 683 methods = Regexp.instance_methods(true) 684 685 when /^([^\]]*\])\.([^.]*)$/ # Array 686 receiver = $1 687 message = Regexp.quote($2) 688 methods = Array.instance_methods(true) 689 690 when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash 691 receiver = $1 692 message = Regexp.quote($2) 693 methods = Proc.instance_methods(true) | Hash.instance_methods(true) 694 695 when /^(:[^:.]*)$/ # Symbol 696 dprint "symbol" 697 if Symbol.respond_to?(:all_symbols) 698 receiver = $1 699 message = $1.sub( /:/, '' ) 700 methods = Symbol.all_symbols.collect{|s| s.id2name} 701 methods.delete_if { |c| c.match( /'/ ) } 702 end 703 704 when /^::([A-Z][^:\.\(]*)?$/ # Absolute Constant or class methods 705 dprint "const or cls" 706 receiver = $1 707 methods = Object.constants.collect{ |c| c.to_s }.grep(/^#{receiver}/) 708 709 when /^(((::)?[A-Z][^:.\(]*)+?)::?([^:.]*)$/ # Constant or class methods 710 receiver = $1 711 message = Regexp.quote($4) 712 dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ] 713 load_buffer_class( receiver ) 714 load_buffer_module( receiver ) 715 begin 716 constants = eval("#{receiver}.constants").collect{ |c| c.to_s }.grep(/^#{message}/) 717 methods = eval("#{receiver}.methods").collect{ |m| m.to_s }.grep(/^#{message}/) 718 rescue Exception 719 dprint "exception: %s" % $! 720 constants = [] 721 methods = [] 722 end 723 724 when /^(:[^:.]+)\.([^.]*)$/ # Symbol 725 dprint "symbol" 726 receiver = $1 727 message = Regexp.quote($2) 728 methods = Symbol.instance_methods(true) 729 730 when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric 731 dprint "numeric" 732 receiver = $1 733 message = Regexp.quote($4) 734 begin 735 methods = eval(receiver).methods 736 rescue Exception 737 methods = [] 738 end 739 740 when /^(\$[^.]*)$/ #global 741 dprint "global" 742 methods = global_variables.grep(Regexp.new(Regexp.quote($1))) 743 744 when /^((\.?[^.]+)+?)\.([^.]*)$/ # variable 745 dprint "variable" 746 receiver = $1 747 message = Regexp.quote($3) 748 load_buffer_class( receiver ) 749 750 cv = eval("self.class.constants") 751 vartype = get_var_type( receiver ) 752 dprint "vartype: %s" % vartype 753 754 invalid_vartype = ['', "gets"] 755 if !invalid_vartype.include?(vartype) 756 load_buffer_class( vartype ) 757 758 begin 759 methods = eval("#{vartype}.instance_methods") 760 variables = eval("#{vartype}.instance_variables") 761 rescue Exception 762 dprint "load_buffer_class err: %s" % $! 763 end 764 elsif (cv).include?(receiver) 765 # foo.func and foo is local var. 766 methods = eval("#{receiver}.methods") 767 vartype = receiver 768 elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver 769 vartype = receiver 770 # Foo::Bar.func 771 begin 772 methods = eval("#{receiver}.methods") 773 rescue Exception 774 end 775 else 776 # func1.func2 777 ObjectSpace.each_object(Module){|m| 778 next if m.name != "IRB::Context" and 779 /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name 780 methods.concat m.instance_methods(false) 781 } 782 end 783 variables += add_rails_columns( "#{vartype}" ) if vartype && !invalid_vartype.include?(vartype) 784 785 when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/ 786 message = $1 787 methods = Range.instance_methods(true) 788 789 when /^\.([^.]*)$/ # unknown(maybe String) 790 message = Regexp.quote($1) 791 methods = String.instance_methods(true) 792 793 else 794 dprint "default/other" 795 inclass = eval( VIM::evaluate("s:IsInClassDef()") ) 796 797 if inclass != nil 798 dprint "inclass" 799 classdef = "%s\n" % VIM::Buffer.current[ inclass.min ] 800 found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef ) 801 802 if found != nil 803 receiver = $1 804 message = input 805 load_buffer_class( receiver ) 806 begin 807 methods = eval( "#{receiver}.instance_methods" ) 808 variables += add_rails_columns( "#{receiver}" ) 809 rescue Exception 810 found = nil 811 end 812 end 813 end 814 815 if inclass == nil || found == nil 816 dprint "inclass == nil" 817 methods = get_buffer_methods 818 methods += get_rails_view_methods 819 820 cls_const = Class.constants 821 constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) } 822 classes = eval("self.class.constants") - constants 823 classes += get_buffer_classes 824 classes += get_buffer_modules 825 826 include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace") 827 ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1" 828 message = receiver = input 829 end 830 831 methods += get_rails_helpers 832 methods += Kernel.public_methods 833 end 834 835 include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object") 836 methods = clean_sel( methods, message ) 837 methods = (methods-Object.instance_methods) if include_object == "0" 838 rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods 839 methods = (methods-rbcmeth) 840 841 variables = clean_sel( variables, message ) 842 classes = clean_sel( classes, message ) - ["VimRubyCompletion"] 843 constants = clean_sel( constants, message ) 844 845 valid = [] 846 valid += methods.collect { |m| { :name => m.to_s, :type => 'm' } } 847 valid += variables.collect { |v| { :name => v.to_s, :type => 'v' } } 848 valid += classes.collect { |c| { :name => c.to_s, :type => 't' } } 849 valid += constants.collect { |d| { :name => d.to_s, :type => 'd' } } 850 valid.sort! { |x,y| x[:name] <=> y[:name] } 851 852 outp = "" 853 854 rg = 0..valid.length 855 rg.step(150) do |x| 856 stpos = 0+x 857 enpos = 150+x 858 valid[stpos..enpos].each { |c| outp += "{'word':'%s','item':'%s','kind':'%s'}," % [ c[:name], c[:name], c[:type] ].map{|x|escape_vim_singlequote_string(x)} } 859 outp.sub!(/,$/, '') 860 861 VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp) 862 outp = "" 863 end 864 end 865# }}} main completion code 866 867end # VimRubyCompletion 868# }}} ruby completion 869RUBYEOF 870endfunction 871 872let s:rubycomplete_rails_loaded = 0 873 874call s:DefRuby() 875"}}} ruby-side code 876 877" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl: 878