Mercurial > vim
view runtime/autoload/rubycomplete.vim @ 877:af98ef7f5a39 v7.0.003
updated for version 7.0-003
author | vimboss |
---|---|
date | Sat, 13 May 2006 10:11:39 +0000 |
parents | d58e3db4a7d1 |
children | e63691e7c504 |
line wrap: on
line source
" Vim completion script " Language: Ruby " Maintainer: Mark Guzman <segfault@hasno.info> " Info: $Id$ " URL: http://vim-ruby.rubyforge.org " Anon CVS: See above site " Release Coordinator: Doug Kearns <dougkearns@gmail.com> " ---------------------------------------------------------------------------- " " Ruby IRB/Complete author: Keiju ISHITSUKA(keiju@ishitsuka.com) " ---------------------------------------------------------------------------- " {{{ requirement checks 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 " }}} requirement checks if !exists("g:rubycomplete_rails") let g:rubycomplete_rails = 0 endif if !exists("g:rubycomplete_classes_in_global") let g:rubycomplete_classes_in_global = 0 endif " {{{ vim-side support functions 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('.') let [lnum,lcol] = searchpos('^\s*#\s*@var\s*'.a:v.'\>\s\+[^ \t]\+\s*$','nb',stopline) if lnum != 0 && lcol != 0 call setpos('.',pos) let str = getline(lnum) let vtp = substitute(str,'^\s*#\s*@var\s*'.a:v.'\>\s\+\([^ \t]\+\)\s*$','\1','') return vtp endif call setpos('.',pos) if g:rubycomplete_rails == 1 && g:rubycomplete_rails_loaded == 1 let ctors = '\(now\|new\|open\|get_instance\|find\|create\)' else let ctors = '\(now\|new\|open\|get_instance\)' endif let [lnum,lcol] = searchpos(''.a:v.'\>\s*[+\-*/]*=\s*\([^ \t]\+.' . ctors .'\>\|[\[{"''/]\|%r{\|[A-Za-z0-9@:\-()]\+...\?\)','nb',stopline) if lnum != 0 && lcol != 0 let str = matchstr(getline(lnum),'=\s*\([^ \t]\+.' . ctors . '\>\|[\[{"''/]\|%r{\|[A-Za-z0-9@:\-()]\+...\?\)',lcol) let str = substitute(str,'^=\s*','','') call setpos('.',pos) if str == '"' || str == '''' return 'String' elseif str == '[' return 'Array' elseif str == '{' return 'Hash' elseif str == '/' || str == '%r{' return 'Regexp' elseif strlen(str) >= 4 && stridx(str,'..') != -1 return 'Range' elseif strlen(str) > 4 let l = stridx(str,'.') return str[0:l-1] end return '' endif call setpos('.',pos) return '' endfunction "}}} vim-side support functions function! rubycomplete#Complete(findstart, base) "findstart = 1 when we need to get the text length if a:findstart let line = getline('.') let idx = col('.') while idx > 0 let idx -= 1 let c = line[idx-1] if c =~ '\w' continue elseif ! c =~ '\.' idx = -1 break else break endif endwhile 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:rubycomplete_completions endif endfunction function! s:DefRuby() ruby << RUBYEOF # {{{ ruby completion RailsWords = [ "has_many", "has_one", "belongs_to", ] ReservedWords = [ "BEGIN", "END", "alias", "and", "begin", "break", "case", "class", "def", "defined", "do", "else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "next", "nil", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", "until", "when", "while", "yield", ] Operators = [ "%", "&", "*", "**", "+", "-", "/", "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>", "[]", "[]=", "^", ] 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 end end 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 mixre = /.*\n\s*include\s*(.*)\s*\n/.match( classdef ) load_buffer_module( $2 ) if mixre != nil eval classdef end def load_buffer_module(name) classdef = get_buffer_entity(name, 'GetBufferRubyModule("%s")') return if classdef == nil eval classdef end def get_buffer_entity(name, vimfun) return nil if /(\"|\')+/.match( name ) 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 def get_var_type( receiver ) if /(\"|\')+/.match( receiver ) "String" else VIM::evaluate("GetRubyVarType('%s')" % receiver) end end def get_buffer_classes() # this will be a little expensive. allow_aggressive_load = VIM::evaluate('g:rubycomplete_classes_in_global') return [] if allow_aggressive_load != '1' buf = VIM::Buffer.current eob = buf.length ret = [] rg = 1..eob rg.each do |x| if /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/.match( buf[x] ) ret.push $1 end end return ret end 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 return if pok == nil bootfile = pok + "/boot.rb" envfile = pok + "/environment.rb" if File.exists?( bootfile ) && File.exists?( envfile ) begin require bootfile require envfile require 'console_app' require 'console_with_helpers' VIM::command('let g:rubycomplete_rails_loaded = 1') rescue print "Error loading rails environment" end end end def get_rails_helpers allow_rails = VIM::evaluate('g:rubycomplete_rails') rails_loaded = VIM::evaluate('g:rubycomplete_rails_loaded') return [] if allow_rails != '1' || rails_loaded != '1' return RailsWords end def get_completions(base) load_requires load_rails input = VIM::Buffer.current.line cpos = VIM::Window.current.cursor[1] - 1 input = input[0..cpos] if cpos != 0 input += base rip = input.rindex(/\s/,cpos) if rip input = input[rip..input.length] end asn = /^.*(\+|\-|\*|=|\(|\[)=?(\s*[A-Za-z0-9_:@.-]*)(\s*(\{|\+|\-|\*|\%|\/)?\s*).*/ if asn.match(input) input = $2 end input.strip! message = nil receiver = nil candidates = [] case input when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp receiver = $1 message = Regexp.quote($2) candidates = Regexp.instance_methods(true) when /^([^\]]*\])\.([^.]*)$/ # Array receiver = $1 message = Regexp.quote($2) candidates = Array.instance_methods(true) when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash receiver = $1 message = Regexp.quote($2) candidates = Proc.instance_methods(true) | Hash.instance_methods(true) when /^(:[^:.]*)$/ # Symbol if Symbol.respond_to?(:all_symbols) receiver = $1 candidates = Symbol.all_symbols.collect{|s| s.id2name} candidates.delete_if { |c| c.match( /'/ ) } 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) when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric receiver = $1 message = Regexp.quote($4) begin candidates = eval(receiver).methods rescue Exception candidates end when /^(\$[^.]*)$/ #global candidates = global_variables.grep(Regexp.new(Regexp.quote($1))) when /^((\.?[^.]+)+)\.([^.]*)$/ # variable receiver = $1 message = Regexp.quote($3) load_buffer_class( receiver ) cv = eval("self.class.constants") vartype = get_var_type( receiver ) if vartype != '' load_buffer_class( vartype ) begin candidates = eval("#{vartype}.instance_methods") 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") rescue Exception candidates = [] end 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) } end when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/ message = $1 candidates = Range.instance_methods(true) when /^\[(\s*[A-Za-z0-9:^@.%\/+*\(\)\[\]\{\}.\'\"],?)*\].([^.]*)/ message = $2 candidates = Array.instance_methods(true) when /^\.([^.]*)$/ # unknown(maybe String) message = Regexp.quote($1) candidates = String.instance_methods(true) 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 ) begin candidates = eval( "#{receiver}.instance_methods" ) candidates += get_rails_helpers rescue Exception found = nil end end end if inclass == nil || found == nil candidates = eval("self.class.constants") candidates += get_buffer_classes message = receiver = input end end candidates.delete_if { |x| x == nil } candidates.uniq! candidates.sort! candidates = candidates.grep(/^#{Regexp.quote(message)}/) if message != nil outp = "" 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("call extend(g:rubycomplete_completions, [%s])" % outp) outp = "" end end # }}} ruby completion RUBYEOF endfunction let g:rubycomplete_rails_loaded = 0 call s:DefRuby() " vim:tw=78:sw=4:ts=8:et:ft=vim:norl: