diff options
Diffstat (limited to 'runtime/autoload/rubycomplete.vim')
-rw-r--r-- | runtime/autoload/rubycomplete.vim | 438 |
1 files changed, 299 insertions, 139 deletions
diff --git a/runtime/autoload/rubycomplete.vim b/runtime/autoload/rubycomplete.vim index 8def228edc..0a745b98c9 100644 --- a/runtime/autoload/rubycomplete.vim +++ b/runtime/autoload/rubycomplete.vim @@ -1,6 +1,6 @@ " Vim completion script " Language: Ruby -" Maintainer: Mark Guzman ( segfault AT hasno DOT info ) +" Maintainer: Mark Guzman <segfault@hasno.info> " Info: $Id$ " URL: http://vim-ruby.rubyforge.org " Anon CVS: See above site @@ -11,16 +11,64 @@ " ---------------------------------------------------------------------------- if !has('ruby') + echohl ErrorMsg echo "Error: Required vim compiled with +ruby" + echohl None finish endif if version < 700 + echohl ErrorMsg echo "Error: Required vim >= 7.0" + echohl None finish endif -func! GetRubyVarType(v) + +function! GetBufferRubyModule(name) + let [snum,enum] = GetBufferRubyEntity(a:name, "module") + return snum . '..' . enum +endfunction + +function! GetBufferRubyClass(name) + let [snum,enum] = GetBufferRubyEntity(a:name, "class") + return snum . '..' . enum +endfunction + +function! GetBufferRubySingletonMethods(name) +endfunction + +function! GetBufferRubyEntity( name, type ) + let stopline = 1 + let crex = '^\s*' . a:type . '\s*' . a:name . '\s*\(<\s*.*\s*\)\?\n*\(\(\s\|#\).*\n*\)*\n*\s*end$' + let [lnum,lcol] = searchpos( crex, 'nbw') + if lnum == 0 && lcol == 0 + return [0,0] + endif + + let [enum,ecol] = searchpos( crex, 'nebw') + if lnum > enum + let realdef = getline( lnum ) + let crexb = '^' . realdef . '\n*\(\(\s\|#\).*\n*\)*\n*\s*end$' + let [enum,ecol] = searchpos( crexb, 'necw' ) + endif + " we found a the class def + return [lnum,enum] +endfunction + +function! IsInClassDef() + let [snum,enum] = GetBufferRubyEntity( '.*', "class" ) + let ret = 'nil' + let pos = line('.') + + if snum < pos && pos < enum + let ret = snum . '..' . enum + endif + + return ret +endfunction + +function! GetRubyVarType(v) let stopline = 1 let vtp = '' let pos = getpos('.') @@ -32,9 +80,9 @@ func! GetRubyVarType(v) return vtp endif call setpos('.',pos) - let [lnum,lcol] = searchpos(''.a:v.'\>\s*[+\-*/]*=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"'']\)','nb',stopline) + let [lnum,lcol] = searchpos(''.a:v.'\>\s*[+\-*/]*=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"''/]\|%r{\)','nb',stopline) if lnum != 0 && lcol != 0 - let str = matchstr(getline(lnum),'=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"'']\)',lcol) + let str = matchstr(getline(lnum),'=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"''/]\|%r{\)',lcol) let str = substitute(str,'^=\s*','','') call setpos('.',pos) if str == '"' || str == '''' @@ -43,6 +91,8 @@ func! GetRubyVarType(v) return 'Array' elseif str == '{' return 'Hash' + elseif str == '/' || str == '%r{' + return 'Regexp' elseif strlen(str) > 4 let l = stridx(str,'.') return str[0:l-1] @@ -51,7 +101,7 @@ func! GetRubyVarType(v) endif call setpos('.',pos) return '' -endf +endfunction function! rubycomplete#Complete(findstart, base) "findstart = 1 when we need to get the text length @@ -74,14 +124,20 @@ function! rubycomplete#Complete(findstart, base) return idx "findstart = 0 when we need to return the list of completions else + let g:rubycomplete_completions = [] execute "ruby get_completions('" . a:base . "')" - return g:rbcomplete_completions + return g:rubycomplete_completions endif endfunction function! s:DefRuby() ruby << RUBYEOF +RailsWords = [ + "has_many", "has_one", + "belongs_to", + ] + ReservedWords = [ "BEGIN", "END", "alias", "and", @@ -106,188 +162,290 @@ Operators = [ "%", "&", "*", "**", "+", "-", "/", "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>", "[]", "[]=", "^", ] -def identify_type(var) - @buf = VIM::Buffer.current - enum = @buf.line_number - snum = (enum-10).abs - nums = Range.new( snum, enum ) - regxs = '/.*(%s)\s*=(.*)/' % var - regx = Regexp.new( regxs ) - nums.each do |x| - ln = @buf[x] - #print $~ if regx.match( ln ) - end -end def load_requires - @buf = VIM::Buffer.current - enum = @buf.line_number - nums = Range.new( 1, enum ) - nums.each do |x| - ln = @buf[x] - begin - eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln ) - rescue Exception - #ignore? - end + @buf = VIM::Buffer.current + enum = @buf.line_number + nums = Range.new( 1, enum ) + nums.each do |x| + ln = @buf[x] + begin + eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln ) + rescue Exception + #ignore? end + end end -def get_completions(base) - load_requires - input = VIM::evaluate('expand("<cWORD>")') - input += base - message = nil +def load_buffer_class(name) + classdef = get_buffer_entity(name, 'GetBufferRubyClass("%s")') + return if classdef == nil + pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef ) + load_buffer_class( $2 ) if pare != nil - case input - when /^(\/[^\/]*\/)\.([^.]*)$/ - # Regexp - receiver = $1 - message = Regexp.quote($2) + mixre = /.*\n\s*include\s*(.*)\s*\n/.match( classdef ) + load_buffer_module( $2 ) if mixre != nil - candidates = Regexp.instance_methods(true) - select_message(receiver, message, candidates) + eval classdef +end - when /^([^\]]*\])\.([^.]*)$/ - # Array - receiver = $1 - message = Regexp.quote($2) +def load_buffer_module(name) + classdef = get_buffer_entity(name, 'GetBufferRubyModule("%s")') + return if classdef == nil - candidates = Array.instance_methods(true) - select_message(receiver, message, candidates) + eval classdef +end - when /^([^\}]*\})\.([^.]*)$/ - # Proc or Hash - receiver = $1 - message = Regexp.quote($2) +def get_buffer_entity(name, vimfun) + @buf = VIM::Buffer.current + nums = eval( VIM::evaluate( vimfun % name ) ) + return nil if nums == nil + return nil if nums.min == nums.max && nums.min == 0 + + cur_line = VIM::Buffer.current.line_number + classdef = "" + nums.each do |x| + if x != cur_line + ln = @buf[x] + classdef += "%s\n" % ln + end + end + + return classdef +end - candidates = Proc.instance_methods(true) | Hash.instance_methods(true) - select_message(receiver, message, candidates) +def load_rails() + allow_rails = VIM::evaluate('g:rubycomplete_rails') + return if allow_rails != '1' + + buf_path = VIM::evaluate('expand("%:p")') + file_name = VIM::evaluate('expand("%:t")') + path = buf_path.gsub( file_name, '' ) + path.gsub!( /\\/, "/" ) + pup = [ "../", "../../", "../../../", "../../../../" ] + pok = nil + + pup.each do |sup| + tpok = "%s%sconfig" % [ path, sup ] + if File.exists?( tpok ) + pok = tpok + break + end + end + bootfile = pok + "/boot.rb" + require bootfile if pok != nil && File.exists?( bootfile ) +end - when /^(:[^:.]*)$/ - # Symbol - if Symbol.respond_to?(:all_symbols) - sym = $1 - candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name} - candidates.grep(/^#{sym}/) - else - [] - end +def get_rails_helpers + allow_rails = VIM::evaluate('g:rubycomplete_rails') + return [] if allow_rails != '1' + return RailsWords +end - when /^::([A-Z][^:\.\(]*)$/ - # Absolute Constant or class methods - receiver = $1 - candidates = Object.constants - candidates.grep(/^#{receiver}/).collect{|e| "::" + e} +def get_completions(base) + load_requires + load_rails + + input = VIM::evaluate('expand("<cWORD>")') + input += base + input.lstrip! + if input.length == 0 + input = VIM::Buffer.current.line + input.strip! + end + message = nil - when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/ - # Constant or class methods - receiver = $1 - message = Regexp.quote($4) - begin - candidates = eval("#{receiver}.constants | #{receiver}.methods") - rescue Exception - candidates = [] - end - candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e} - when /^(:[^:.]+)\.([^.]*)$/ - # Symbol - receiver = $1 - message = Regexp.quote($2) + case input + when /^(\/[^\/]*\/)\.([^.]*)$/ + # Regexp + receiver = $1 + message = Regexp.quote($2) - candidates = Symbol.instance_methods(true) - select_message(receiver, message, candidates) + candidates = Regexp.instance_methods(true) + select_message(receiver, message, candidates) - when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ - # Numeric - receiver = $1 - message = Regexp.quote($4) + when /^([^\]]*\])\.([^.]*)$/ + # Array + receiver = $1 + message = Regexp.quote($2) - begin - candidates = eval(receiver).methods - rescue Exception - candidates - end - select_message(receiver, message, candidates) + candidates = Array.instance_methods(true) + select_message(receiver, message, candidates) - when /^(\$[^.]*)$/ - candidates = global_variables.grep(Regexp.new(Regexp.quote($1))) + when /^([^\}]*\})\.([^.]*)$/ + # Proc or Hash + receiver = $1 + message = Regexp.quote($2) -# when /^(\$?(\.?[^.]+)+)\.([^.]*)$/ - when /^((\.?[^.]+)+)\.([^.]*)$/ - # variable - receiver = $1 - message = Regexp.quote($3) + candidates = Proc.instance_methods(true) | Hash.instance_methods(true) + select_message(receiver, message, candidates) - cv = eval("self.class.constants") + when /^(:[^:.]*)$/ + # Symbol + if Symbol.respond_to?(:all_symbols) + sym = $1 + candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name} + candidates.grep(/^#{sym}/) + candidates.delete_if do |c| + c.match( /'/ ) + end + candidates.uniq! + candidates.sort! + else + [] + end + + when /^::([A-Z][^:\.\(]*)$/ + # Absolute Constant or class methods + receiver = $1 + candidates = Object.constants + candidates.grep(/^#{receiver}/).collect{|e| "::" + e} + + when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/ + # Constant or class methods + receiver = $1 + message = Regexp.quote($4) + begin + candidates = eval("#{receiver}.constants | #{receiver}.methods") + rescue Exception + candidates = [] + end + candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e} + + when /^(:[^:.]+)\.([^.]*)$/ + # Symbol + receiver = $1 + message = Regexp.quote($2) + + candidates = Symbol.instance_methods(true) + select_message(receiver, message, candidates) + + when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ + # Numeric + receiver = $1 + message = Regexp.quote($4) + + begin + candidates = eval(receiver).methods + rescue Exception + candidates + end + select_message(receiver, message, candidates) + + when /^(\$[^.]*)$/ + candidates = global_variables.grep(Regexp.new(Regexp.quote($1))) + +# when /^(\$?(\.?[^.]+)+)\.([^.]*)$/ + when /^((\.?[^.]+)+)\.([^.]*)$/ + # variable + receiver = $1 + message = Regexp.quote($3) + load_buffer_class( receiver ) + + cv = eval("self.class.constants") + + vartype = VIM::evaluate("GetRubyVarType('%s')" % receiver) + if vartype != '' + load_buffer_class( vartype ) - vartype = VIM::evaluate("GetRubyVarType('%s')" % receiver) - if vartype != '' + begin candidates = eval("#{vartype}.instance_methods") - elsif (cv).include?(receiver) - # foo.func and foo is local var. + rescue Exception + candidates = [] + end + elsif (cv).include?(receiver) + # foo.func and foo is local var. + candidates = eval("#{receiver}.methods") + elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver + # Foo::Bar.func + begin candidates = eval("#{receiver}.methods") - elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver - # Foo::Bar.func - begin - candidates = eval("#{receiver}.methods") - rescue Exception - candidates = [] - end - else - # func1.func2 + rescue Exception candidates = [] - ObjectSpace.each_object(Module){|m| - next if m.name != "IRB::Context" and - /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name - candidates.concat m.instance_methods(false) - } - candidates.sort! - candidates.uniq! end - #identify_type( receiver ) - select_message(receiver, message, candidates) + else + # func1.func2 + candidates = [] + ObjectSpace.each_object(Module){|m| + next if m.name != "IRB::Context" and + /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name + candidates.concat m.instance_methods(false) + } + candidates.sort! + candidates.uniq! + end + #identify_type( receiver ) + select_message(receiver, message, candidates) #when /^((\.?[^.]+)+)\.([^.]*)\(\s*\)*$/ #function call #obj = $1 #func = $3 - when /^\.([^.]*)$/ + when /^\.([^.]*)$/ # unknown(maybe String) - receiver = "" - message = Regexp.quote($1) + receiver = "" + message = Regexp.quote($1) - candidates = String.instance_methods(true) - select_message(receiver, message, candidates) + candidates = String.instance_methods(true) + select_message(receiver, message, candidates) - else - candidates = eval("self.class.constants") + else + inclass = eval( VIM::evaluate("IsInClassDef()") ) + if inclass != nil + classdef = "%s\n" % VIM::Buffer.current[ inclass.min ] + found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef ) + + if found != nil + receiver = $1 + message = input + load_buffer_class( receiver ) + candidates = eval( "#{receiver}.instance_methods" ) + candidates += get_rails_helpers + select_message(receiver, message, candidates) + end + end + + if inclass == nil || found == nil + candidates = eval("self.class.constants") (candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/) end + end #print candidates - if message != nil && message.length > 0 - rexp = '^%s' % message.downcase - candidates.delete_if do |c| - c.downcase.match( rexp ) - $~ == nil - end + if message != nil && message.length > 0 + rexp = '^%s' % message.downcase + candidates.delete_if do |c| + c.downcase.match( rexp ) + $~ == nil end + end - outp = "" - # tags = VIM::evaluate("taglist('^%s$')" % - (candidates-Object.instance_methods).each { |c| outp += "{'word':'%s','item':'%s'}," % [ c, c ] } + outp = "" + + # tags = VIM::evaluate("taglist('^%s$')" % + valid = (candidates-Object.instance_methods) + + rg = 0..valid.length + rg.step(150) do |x| + stpos = 0+x + enpos = 150+x + valid[stpos..enpos].each { |c| outp += "{'word':'%s','item':'%s'}," % [ c, c ] } outp.sub!(/,$/, '') - VIM::command("let g:rbcomplete_completions = [%s]" % outp) + + VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp) + outp = "" + end end def select_message(receiver, message, candidates) + #tags = VIM::evaluate("taglist('%s')" % receiver) + #print tags candidates.grep(/^#{message}/).collect do |e| case e when /^[a-zA-Z_]/ @@ -304,5 +462,7 @@ end RUBYEOF endfunction + +let g:rubycomplete_rails = 0 call s:DefRuby() " vim: set et ts=4: |