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