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: 2020 Apr 12 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 bootfile = rails_base + "config/boot.rb" 505 envfile = rails_base + "config/environment.rb" 506 if File.exists?( bootfile ) && File.exists?( envfile ) 507 begin 508 require bootfile 509 require envfile 510 begin 511 require 'console_app' 512 require 'console_with_helpers' 513 rescue Exception 514 dprint "Rails 1.1+ Error %s" % $! 515 # assume 1.0 516 end 517 #eval( "Rails::Initializer.run" ) #not necessary? 518 VIM::command('let s:rubycomplete_rails_loaded = 1') 519 dprint "rails loaded" 520 rescue Exception 521 dprint "Rails Error %s" % $! 522 VIM::evaluate( "s:ErrMsg('Error loading rails environment')" ) 523 end 524 end 525 end 526 527 def get_rails_helpers 528 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails") 529 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded') 530 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero? 531 532 buf_path = VIM::evaluate('expand("%:p")') 533 buf_path.gsub!( /\\/, "/" ) 534 path_elm = buf_path.split( "/" ) 535 dprint "buf_path: %s" % buf_path 536 types = [ "app", "db", "lib", "test", "components", "script" ] 537 538 i = nil 539 ret = [] 540 type = nil 541 types.each do |t| 542 i = path_elm.index( t ) 543 break if i 544 end 545 type = path_elm[i] 546 type.downcase! 547 548 dprint "type: %s" % type 549 case type 550 when "app" 551 i += 1 552 subtype = path_elm[i] 553 subtype.downcase! 554 555 dprint "subtype: %s" % subtype 556 case subtype 557 when "views" 558 ret += ActionView::Base.instance_methods 559 ret += ActionView::Base.methods 560 when "controllers" 561 ret += ActionController::Base.instance_methods 562 ret += ActionController::Base.methods 563 when "models" 564 ret += ActiveRecord::Base.instance_methods 565 ret += ActiveRecord::Base.methods 566 end 567 568 when "db" 569 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods 570 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods 571 end 572 573 return ret 574 end 575 576 def add_rails_columns( cls ) 577 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails") 578 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded') 579 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero? 580 581 begin 582 eval( "#{cls}.establish_connection" ) 583 return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" ) 584 col = eval( "#{cls}.column_names" ) 585 return col if col 586 rescue 587 dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ] 588 return [] 589 end 590 return [] 591 end 592 593 def clean_sel(sel, msg) 594 ret = sel.reject{|x|x.nil?}.uniq 595 ret = ret.grep(/^#{Regexp.quote(msg)}/) if msg != nil 596 ret 597 end 598 599 def get_rails_view_methods 600 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails") 601 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded') 602 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero? 603 604 buf_path = VIM::evaluate('expand("%:p")') 605 buf_path.gsub!( /\\/, "/" ) 606 pelm = buf_path.split( "/" ) 607 idx = pelm.index( "views" ) 608 609 return [] unless idx 610 idx += 1 611 612 clspl = pelm[idx].camelize.pluralize 613 cls = clspl.singularize 614 615 ret = [] 616 begin 617 ret += eval( "#{cls}.instance_methods" ) 618 ret += eval( "#{clspl}Helper.instance_methods" ) 619 rescue Exception 620 dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ] 621 end 622 623 return ret 624 end 625# }}} buffer analysis magic 626 627# {{{ main completion code 628 def self.preload_rails 629 a = VimRubyCompletion.new 630 if VIM::evaluate("has('nvim')") == 0 631 require 'thread' 632 Thread.new(a) do |b| 633 begin 634 b.load_rails 635 rescue 636 end 637 end 638 end 639 a.load_rails 640 rescue 641 end 642 643 def self.get_completions(base) 644 b = VimRubyCompletion.new 645 b.get_completions base 646 end 647 648 def get_completions(base) 649 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading") 650 if loading_allowed.to_i == 1 651 load_requires 652 load_rails 653 end 654 655 want_gems = VIM::evaluate("get(g:, 'rubycomplete_load_gemfile')") 656 load_gems unless want_gems.to_i.zero? 657 658 input = VIM::Buffer.current.line 659 cpos = VIM::Window.current.cursor[1] - 1 660 input = input[0..cpos] 661 input += base 662 input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters 663 input.sub!(/self\./, '') 664 input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '') 665 666 dprint 'input %s' % input 667 message = nil 668 receiver = nil 669 methods = [] 670 variables = [] 671 classes = [] 672 constants = [] 673 674 case input 675 when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp 676 receiver = $1 677 message = Regexp.quote($2) 678 methods = Regexp.instance_methods(true) 679 680 when /^([^\]]*\])\.([^.]*)$/ # Array 681 receiver = $1 682 message = Regexp.quote($2) 683 methods = Array.instance_methods(true) 684 685 when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash 686 receiver = $1 687 message = Regexp.quote($2) 688 methods = Proc.instance_methods(true) | Hash.instance_methods(true) 689 690 when /^(:[^:.]*)$/ # Symbol 691 dprint "symbol" 692 if Symbol.respond_to?(:all_symbols) 693 receiver = $1 694 message = $1.sub( /:/, '' ) 695 methods = Symbol.all_symbols.collect{|s| s.id2name} 696 methods.delete_if { |c| c.match( /'/ ) } 697 end 698 699 when /^::([A-Z][^:\.\(]*)?$/ # Absolute Constant or class methods 700 dprint "const or cls" 701 receiver = $1 702 methods = Object.constants.collect{ |c| c.to_s }.grep(/^#{receiver}/) 703 704 when /^(((::)?[A-Z][^:.\(]*)+?)::?([^:.]*)$/ # Constant or class methods 705 receiver = $1 706 message = Regexp.quote($4) 707 dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ] 708 load_buffer_class( receiver ) 709 load_buffer_module( receiver ) 710 begin 711 constants = eval("#{receiver}.constants").collect{ |c| c.to_s }.grep(/^#{message}/) 712 methods = eval("#{receiver}.methods").collect{ |m| m.to_s }.grep(/^#{message}/) 713 rescue Exception 714 dprint "exception: %s" % $! 715 constants = [] 716 methods = [] 717 end 718 719 when /^(:[^:.]+)\.([^.]*)$/ # Symbol 720 dprint "symbol" 721 receiver = $1 722 message = Regexp.quote($2) 723 methods = Symbol.instance_methods(true) 724 725 when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric 726 dprint "numeric" 727 receiver = $1 728 message = Regexp.quote($4) 729 begin 730 methods = eval(receiver).methods 731 rescue Exception 732 methods = [] 733 end 734 735 when /^(\$[^.]*)$/ #global 736 dprint "global" 737 methods = global_variables.grep(Regexp.new(Regexp.quote($1))) 738 739 when /^((\.?[^.]+)+?)\.([^.]*)$/ # variable 740 dprint "variable" 741 receiver = $1 742 message = Regexp.quote($3) 743 load_buffer_class( receiver ) 744 745 cv = eval("self.class.constants") 746 vartype = get_var_type( receiver ) 747 dprint "vartype: %s" % vartype 748 749 invalid_vartype = ['', "gets"] 750 if !invalid_vartype.include?(vartype) 751 load_buffer_class( vartype ) 752 753 begin 754 methods = eval("#{vartype}.instance_methods") 755 variables = eval("#{vartype}.instance_variables") 756 rescue Exception 757 dprint "load_buffer_class err: %s" % $! 758 end 759 elsif (cv).include?(receiver) 760 # foo.func and foo is local var. 761 methods = eval("#{receiver}.methods") 762 vartype = receiver 763 elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver 764 vartype = receiver 765 # Foo::Bar.func 766 begin 767 methods = eval("#{receiver}.methods") 768 rescue Exception 769 end 770 else 771 # func1.func2 772 ObjectSpace.each_object(Module){|m| 773 next if m.name != "IRB::Context" and 774 /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name 775 methods.concat m.instance_methods(false) 776 } 777 end 778 variables += add_rails_columns( "#{vartype}" ) if vartype && !invalid_vartype.include?(vartype) 779 780 when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/ 781 message = $1 782 methods = Range.instance_methods(true) 783 784 when /^\.([^.]*)$/ # unknown(maybe String) 785 message = Regexp.quote($1) 786 methods = String.instance_methods(true) 787 788 else 789 dprint "default/other" 790 inclass = eval( VIM::evaluate("s:IsInClassDef()") ) 791 792 if inclass != nil 793 dprint "inclass" 794 classdef = "%s\n" % VIM::Buffer.current[ inclass.min ] 795 found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef ) 796 797 if found != nil 798 receiver = $1 799 message = input 800 load_buffer_class( receiver ) 801 begin 802 methods = eval( "#{receiver}.instance_methods" ) 803 variables += add_rails_columns( "#{receiver}" ) 804 rescue Exception 805 found = nil 806 end 807 end 808 end 809 810 if inclass == nil || found == nil 811 dprint "inclass == nil" 812 methods = get_buffer_methods 813 methods += get_rails_view_methods 814 815 cls_const = Class.constants 816 constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) } 817 classes = eval("self.class.constants") - constants 818 classes += get_buffer_classes 819 classes += get_buffer_modules 820 821 include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace") 822 ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1" 823 message = receiver = input 824 end 825 826 methods += get_rails_helpers 827 methods += Kernel.public_methods 828 end 829 830 include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object") 831 methods = clean_sel( methods, message ) 832 methods = (methods-Object.instance_methods) if include_object == "0" 833 rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods 834 methods = (methods-rbcmeth) 835 836 variables = clean_sel( variables, message ) 837 classes = clean_sel( classes, message ) - ["VimRubyCompletion"] 838 constants = clean_sel( constants, message ) 839 840 valid = [] 841 valid += methods.collect { |m| { :name => m.to_s, :type => 'm' } } 842 valid += variables.collect { |v| { :name => v.to_s, :type => 'v' } } 843 valid += classes.collect { |c| { :name => c.to_s, :type => 't' } } 844 valid += constants.collect { |d| { :name => d.to_s, :type => 'd' } } 845 valid.sort! { |x,y| x[:name] <=> y[:name] } 846 847 outp = "" 848 849 rg = 0..valid.length 850 rg.step(150) do |x| 851 stpos = 0+x 852 enpos = 150+x 853 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)} } 854 outp.sub!(/,$/, '') 855 856 VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp) 857 outp = "" 858 end 859 end 860# }}} main completion code 861 862end # VimRubyCompletion 863# }}} ruby completion 864RUBYEOF 865endfunction 866 867let s:rubycomplete_rails_loaded = 0 868 869call s:DefRuby() 870"}}} ruby-side code 871 872" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl: 873