1*c6249bb2SBram Moolenaar" Vim completion script
2*c6249bb2SBram Moolenaar" Language:				Ruby
3*c6249bb2SBram Moolenaar" Maintainer:			Mark Guzman ( segfault AT hasno DOT info )
4*c6249bb2SBram Moolenaar" Info:					$Id$
5*c6249bb2SBram Moolenaar" URL:					http://vim-ruby.rubyforge.org
6*c6249bb2SBram Moolenaar" Anon CVS:				See above site
7*c6249bb2SBram Moolenaar" Release Coordinator:	Doug Kearns <[email protected]>
8*c6249bb2SBram Moolenaar" ----------------------------------------------------------------------------
9*c6249bb2SBram Moolenaar"
10*c6249bb2SBram Moolenaar" Ruby IRB/Complete author: Keiju ISHITSUKA([email protected])
11*c6249bb2SBram Moolenaar" ----------------------------------------------------------------------------
12*c6249bb2SBram Moolenaar
13*c6249bb2SBram Moolenaarif !has('ruby')
14*c6249bb2SBram Moolenaar    echo "Error: Required vim compiled with +ruby"
15*c6249bb2SBram Moolenaar    finish
16*c6249bb2SBram Moolenaarendif
17*c6249bb2SBram Moolenaar
18*c6249bb2SBram Moolenaarif version < 700
19*c6249bb2SBram Moolenaar    echo "Error: Required vim >= 7.0"
20*c6249bb2SBram Moolenaar    finish
21*c6249bb2SBram Moolenaarendif
22*c6249bb2SBram Moolenaar
23*c6249bb2SBram Moolenaarfunc! GetRubyVarType(v)
24*c6249bb2SBram Moolenaar	let stopline = 1
25*c6249bb2SBram Moolenaar	let vtp = ''
26*c6249bb2SBram Moolenaar	let pos = getpos('.')
27*c6249bb2SBram Moolenaar	let [lnum,lcol] = searchpos('^\s*#\s*@var\s*'.a:v.'\>\s\+[^ \t]\+\s*$','nb',stopline)
28*c6249bb2SBram Moolenaar	if lnum != 0 && lcol != 0
29*c6249bb2SBram Moolenaar		call setpos('.',pos)
30*c6249bb2SBram Moolenaar		let str = getline(lnum)
31*c6249bb2SBram Moolenaar		let vtp = substitute(str,'^\s*#\s*@var\s*'.a:v.'\>\s\+\([^ \t]\+\)\s*$','\1','')
32*c6249bb2SBram Moolenaar		return vtp
33*c6249bb2SBram Moolenaar	endif
34*c6249bb2SBram Moolenaar	call setpos('.',pos)
35*c6249bb2SBram Moolenaar	let [lnum,lcol] = searchpos(''.a:v.'\>\s*[+\-*/]*=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"'']\)','nb',stopline)
36*c6249bb2SBram Moolenaar	if lnum != 0 && lcol != 0
37*c6249bb2SBram Moolenaar		let str = matchstr(getline(lnum),'=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"'']\)',lcol)
38*c6249bb2SBram Moolenaar		let str = substitute(str,'^=\s*','','')
39*c6249bb2SBram Moolenaar		call setpos('.',pos)
40*c6249bb2SBram Moolenaar		if str == '"' || str == ''''
41*c6249bb2SBram Moolenaar			return 'String'
42*c6249bb2SBram Moolenaar		elseif str == '['
43*c6249bb2SBram Moolenaar			return 'Array'
44*c6249bb2SBram Moolenaar		elseif str == '{'
45*c6249bb2SBram Moolenaar			return 'Hash'
46*c6249bb2SBram Moolenaar		elseif strlen(str) > 4
47*c6249bb2SBram Moolenaar            let l = stridx(str,'.')
48*c6249bb2SBram Moolenaar			return str[0:l-1]
49*c6249bb2SBram Moolenaar		end
50*c6249bb2SBram Moolenaar		return ''
51*c6249bb2SBram Moolenaar	endif
52*c6249bb2SBram Moolenaar	call setpos('.',pos)
53*c6249bb2SBram Moolenaar    return ''
54*c6249bb2SBram Moolenaarendf
55*c6249bb2SBram Moolenaar
56*c6249bb2SBram Moolenaarfunction! rubycomplete#Complete(findstart, base)
57*c6249bb2SBram Moolenaar     "findstart = 1 when we need to get the text length
58*c6249bb2SBram Moolenaar    if a:findstart
59*c6249bb2SBram Moolenaar        let line = getline('.')
60*c6249bb2SBram Moolenaar        let idx = col('.')
61*c6249bb2SBram Moolenaar        while idx > 0
62*c6249bb2SBram Moolenaar            let idx -= 1
63*c6249bb2SBram Moolenaar            let c = line[idx-1]
64*c6249bb2SBram Moolenaar            if c =~ '\w'
65*c6249bb2SBram Moolenaar                continue
66*c6249bb2SBram Moolenaar            elseif ! c =~ '\.'
67*c6249bb2SBram Moolenaar                idx = -1
68*c6249bb2SBram Moolenaar                break
69*c6249bb2SBram Moolenaar            else
70*c6249bb2SBram Moolenaar                break
71*c6249bb2SBram Moolenaar            endif
72*c6249bb2SBram Moolenaar        endwhile
73*c6249bb2SBram Moolenaar
74*c6249bb2SBram Moolenaar        return idx
75*c6249bb2SBram Moolenaar    "findstart = 0 when we need to return the list of completions
76*c6249bb2SBram Moolenaar    else
77*c6249bb2SBram Moolenaar        execute "ruby get_completions('" . a:base . "')"
78*c6249bb2SBram Moolenaar        return g:rbcomplete_completions
79*c6249bb2SBram Moolenaar    endif
80*c6249bb2SBram Moolenaarendfunction
81*c6249bb2SBram Moolenaar
82*c6249bb2SBram Moolenaar
83*c6249bb2SBram Moolenaarfunction! s:DefRuby()
84*c6249bb2SBram Moolenaarruby << RUBYEOF
85*c6249bb2SBram MoolenaarReservedWords = [
86*c6249bb2SBram Moolenaar      "BEGIN", "END",
87*c6249bb2SBram Moolenaar      "alias", "and",
88*c6249bb2SBram Moolenaar      "begin", "break",
89*c6249bb2SBram Moolenaar      "case", "class",
90*c6249bb2SBram Moolenaar      "def", "defined", "do",
91*c6249bb2SBram Moolenaar      "else", "elsif", "end", "ensure",
92*c6249bb2SBram Moolenaar      "false", "for",
93*c6249bb2SBram Moolenaar      "if", "in",
94*c6249bb2SBram Moolenaar      "module",
95*c6249bb2SBram Moolenaar      "next", "nil", "not",
96*c6249bb2SBram Moolenaar      "or",
97*c6249bb2SBram Moolenaar      "redo", "rescue", "retry", "return",
98*c6249bb2SBram Moolenaar      "self", "super",
99*c6249bb2SBram Moolenaar      "then", "true",
100*c6249bb2SBram Moolenaar      "undef", "unless", "until",
101*c6249bb2SBram Moolenaar      "when", "while",
102*c6249bb2SBram Moolenaar      "yield",
103*c6249bb2SBram Moolenaar    ]
104*c6249bb2SBram Moolenaar
105*c6249bb2SBram MoolenaarOperators = [ "%", "&", "*", "**", "+",  "-",  "/",
106*c6249bb2SBram Moolenaar      "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
107*c6249bb2SBram Moolenaar      "[]", "[]=", "^", ]
108*c6249bb2SBram Moolenaar
109*c6249bb2SBram Moolenaardef identify_type(var)
110*c6249bb2SBram Moolenaar    @buf = VIM::Buffer.current
111*c6249bb2SBram Moolenaar    enum = @buf.line_number
112*c6249bb2SBram Moolenaar    snum = (enum-10).abs
113*c6249bb2SBram Moolenaar    nums = Range.new( snum, enum )
114*c6249bb2SBram Moolenaar    regxs = '/.*(%s)\s*=(.*)/' % var
115*c6249bb2SBram Moolenaar    regx = Regexp.new( regxs )
116*c6249bb2SBram Moolenaar    nums.each do |x|
117*c6249bb2SBram Moolenaar        ln = @buf[x]
118*c6249bb2SBram Moolenaar        #print $~ if regx.match( ln )
119*c6249bb2SBram Moolenaar    end
120*c6249bb2SBram Moolenaarend
121*c6249bb2SBram Moolenaar
122*c6249bb2SBram Moolenaardef load_requires
123*c6249bb2SBram Moolenaar    @buf = VIM::Buffer.current
124*c6249bb2SBram Moolenaar    enum = @buf.line_number
125*c6249bb2SBram Moolenaar    nums = Range.new( 1, enum )
126*c6249bb2SBram Moolenaar    nums.each do |x|
127*c6249bb2SBram Moolenaar        ln = @buf[x]
128*c6249bb2SBram Moolenaar        begin
129*c6249bb2SBram Moolenaar            eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln )
130*c6249bb2SBram Moolenaar        rescue Exception
131*c6249bb2SBram Moolenaar            #ignore?
132*c6249bb2SBram Moolenaar        end
133*c6249bb2SBram Moolenaar    end
134*c6249bb2SBram Moolenaarend
135*c6249bb2SBram Moolenaar
136*c6249bb2SBram Moolenaardef get_completions(base)
137*c6249bb2SBram Moolenaar    load_requires
138*c6249bb2SBram Moolenaar    input = VIM::evaluate('expand("<cWORD>")')
139*c6249bb2SBram Moolenaar    input += base
140*c6249bb2SBram Moolenaar    message = nil
141*c6249bb2SBram Moolenaar
142*c6249bb2SBram Moolenaar
143*c6249bb2SBram Moolenaar    case input
144*c6249bb2SBram Moolenaar      when /^(\/[^\/]*\/)\.([^.]*)$/
145*c6249bb2SBram Moolenaar        # Regexp
146*c6249bb2SBram Moolenaar        receiver = $1
147*c6249bb2SBram Moolenaar        message = Regexp.quote($2)
148*c6249bb2SBram Moolenaar
149*c6249bb2SBram Moolenaar        candidates = Regexp.instance_methods(true)
150*c6249bb2SBram Moolenaar        select_message(receiver, message, candidates)
151*c6249bb2SBram Moolenaar
152*c6249bb2SBram Moolenaar      when /^([^\]]*\])\.([^.]*)$/
153*c6249bb2SBram Moolenaar        # Array
154*c6249bb2SBram Moolenaar        receiver = $1
155*c6249bb2SBram Moolenaar        message = Regexp.quote($2)
156*c6249bb2SBram Moolenaar
157*c6249bb2SBram Moolenaar        candidates = Array.instance_methods(true)
158*c6249bb2SBram Moolenaar        select_message(receiver, message, candidates)
159*c6249bb2SBram Moolenaar
160*c6249bb2SBram Moolenaar      when /^([^\}]*\})\.([^.]*)$/
161*c6249bb2SBram Moolenaar        # Proc or Hash
162*c6249bb2SBram Moolenaar        receiver = $1
163*c6249bb2SBram Moolenaar        message = Regexp.quote($2)
164*c6249bb2SBram Moolenaar
165*c6249bb2SBram Moolenaar        candidates = Proc.instance_methods(true) | Hash.instance_methods(true)
166*c6249bb2SBram Moolenaar        select_message(receiver, message, candidates)
167*c6249bb2SBram Moolenaar
168*c6249bb2SBram Moolenaar      when /^(:[^:.]*)$/
169*c6249bb2SBram Moolenaar        # Symbol
170*c6249bb2SBram Moolenaar        if Symbol.respond_to?(:all_symbols)
171*c6249bb2SBram Moolenaar          sym = $1
172*c6249bb2SBram Moolenaar          candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
173*c6249bb2SBram Moolenaar          candidates.grep(/^#{sym}/)
174*c6249bb2SBram Moolenaar        else
175*c6249bb2SBram Moolenaar          []
176*c6249bb2SBram Moolenaar        end
177*c6249bb2SBram Moolenaar
178*c6249bb2SBram Moolenaar      when /^::([A-Z][^:\.\(]*)$/
179*c6249bb2SBram Moolenaar        # Absolute Constant or class methods
180*c6249bb2SBram Moolenaar        receiver = $1
181*c6249bb2SBram Moolenaar        candidates = Object.constants
182*c6249bb2SBram Moolenaar        candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
183*c6249bb2SBram Moolenaar
184*c6249bb2SBram Moolenaar      when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/
185*c6249bb2SBram Moolenaar        # Constant or class methods
186*c6249bb2SBram Moolenaar        receiver = $1
187*c6249bb2SBram Moolenaar        message = Regexp.quote($4)
188*c6249bb2SBram Moolenaar        begin
189*c6249bb2SBram Moolenaar          candidates = eval("#{receiver}.constants | #{receiver}.methods")
190*c6249bb2SBram Moolenaar        rescue Exception
191*c6249bb2SBram Moolenaar          candidates = []
192*c6249bb2SBram Moolenaar        end
193*c6249bb2SBram Moolenaar        candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
194*c6249bb2SBram Moolenaar
195*c6249bb2SBram Moolenaar      when /^(:[^:.]+)\.([^.]*)$/
196*c6249bb2SBram Moolenaar        # Symbol
197*c6249bb2SBram Moolenaar        receiver = $1
198*c6249bb2SBram Moolenaar        message = Regexp.quote($2)
199*c6249bb2SBram Moolenaar
200*c6249bb2SBram Moolenaar        candidates = Symbol.instance_methods(true)
201*c6249bb2SBram Moolenaar        select_message(receiver, message, candidates)
202*c6249bb2SBram Moolenaar
203*c6249bb2SBram Moolenaar      when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/
204*c6249bb2SBram Moolenaar        # Numeric
205*c6249bb2SBram Moolenaar        receiver = $1
206*c6249bb2SBram Moolenaar        message = Regexp.quote($4)
207*c6249bb2SBram Moolenaar
208*c6249bb2SBram Moolenaar        begin
209*c6249bb2SBram Moolenaar          candidates = eval(receiver).methods
210*c6249bb2SBram Moolenaar        rescue Exception
211*c6249bb2SBram Moolenaar          candidates
212*c6249bb2SBram Moolenaar        end
213*c6249bb2SBram Moolenaar        select_message(receiver, message, candidates)
214*c6249bb2SBram Moolenaar
215*c6249bb2SBram Moolenaar      when /^(\$[^.]*)$/
216*c6249bb2SBram Moolenaar	      candidates = global_variables.grep(Regexp.new(Regexp.quote($1)))
217*c6249bb2SBram Moolenaar
218*c6249bb2SBram Moolenaar#      when /^(\$?(\.?[^.]+)+)\.([^.]*)$/
219*c6249bb2SBram Moolenaar      when /^((\.?[^.]+)+)\.([^.]*)$/
220*c6249bb2SBram Moolenaar        # variable
221*c6249bb2SBram Moolenaar        receiver = $1
222*c6249bb2SBram Moolenaar        message = Regexp.quote($3)
223*c6249bb2SBram Moolenaar
224*c6249bb2SBram Moolenaar        cv = eval("self.class.constants")
225*c6249bb2SBram Moolenaar
226*c6249bb2SBram Moolenaar        vartype = VIM::evaluate("GetRubyVarType('%s')" % receiver)
227*c6249bb2SBram Moolenaar        if vartype != ''
228*c6249bb2SBram Moolenaar          candidates = eval("#{vartype}.instance_methods")
229*c6249bb2SBram Moolenaar        elsif (cv).include?(receiver)
230*c6249bb2SBram Moolenaar          # foo.func and foo is local var.
231*c6249bb2SBram Moolenaar          candidates = eval("#{receiver}.methods")
232*c6249bb2SBram Moolenaar        elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
233*c6249bb2SBram Moolenaar          # Foo::Bar.func
234*c6249bb2SBram Moolenaar          begin
235*c6249bb2SBram Moolenaar            candidates = eval("#{receiver}.methods")
236*c6249bb2SBram Moolenaar          rescue Exception
237*c6249bb2SBram Moolenaar            candidates = []
238*c6249bb2SBram Moolenaar          end
239*c6249bb2SBram Moolenaar        else
240*c6249bb2SBram Moolenaar          # func1.func2
241*c6249bb2SBram Moolenaar          candidates = []
242*c6249bb2SBram Moolenaar          ObjectSpace.each_object(Module){|m|
243*c6249bb2SBram Moolenaar            next if m.name != "IRB::Context" and
244*c6249bb2SBram Moolenaar              /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
245*c6249bb2SBram Moolenaar            candidates.concat m.instance_methods(false)
246*c6249bb2SBram Moolenaar          }
247*c6249bb2SBram Moolenaar          candidates.sort!
248*c6249bb2SBram Moolenaar          candidates.uniq!
249*c6249bb2SBram Moolenaar        end
250*c6249bb2SBram Moolenaar        #identify_type( receiver )
251*c6249bb2SBram Moolenaar        select_message(receiver, message, candidates)
252*c6249bb2SBram Moolenaar
253*c6249bb2SBram Moolenaar    #when /^((\.?[^.]+)+)\.([^.]*)\(\s*\)*$/
254*c6249bb2SBram Moolenaar        #function call
255*c6249bb2SBram Moolenaar        #obj = $1
256*c6249bb2SBram Moolenaar        #func = $3
257*c6249bb2SBram Moolenaar
258*c6249bb2SBram Moolenaar      when /^\.([^.]*)$/
259*c6249bb2SBram Moolenaar	# unknown(maybe String)
260*c6249bb2SBram Moolenaar
261*c6249bb2SBram Moolenaar        receiver = ""
262*c6249bb2SBram Moolenaar        message = Regexp.quote($1)
263*c6249bb2SBram Moolenaar
264*c6249bb2SBram Moolenaar        candidates = String.instance_methods(true)
265*c6249bb2SBram Moolenaar        select_message(receiver, message, candidates)
266*c6249bb2SBram Moolenaar
267*c6249bb2SBram Moolenaar    else
268*c6249bb2SBram Moolenaar      candidates = eval("self.class.constants")
269*c6249bb2SBram Moolenaar
270*c6249bb2SBram Moolenaar      (candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/)
271*c6249bb2SBram Moolenaar    end
272*c6249bb2SBram Moolenaar
273*c6249bb2SBram Moolenaar    #print candidates
274*c6249bb2SBram Moolenaar    if message != nil && message.length > 0
275*c6249bb2SBram Moolenaar        rexp = '^%s' % message.downcase
276*c6249bb2SBram Moolenaar        candidates.delete_if do |c|
277*c6249bb2SBram Moolenaar            c.downcase.match( rexp )
278*c6249bb2SBram Moolenaar            $~ == nil
279*c6249bb2SBram Moolenaar        end
280*c6249bb2SBram Moolenaar    end
281*c6249bb2SBram Moolenaar
282*c6249bb2SBram Moolenaar    outp = ""
283*c6249bb2SBram Moolenaar    #    tags = VIM::evaluate("taglist('^%s$')" %
284*c6249bb2SBram Moolenaar    (candidates-Object.instance_methods).each { |c| outp += "{'word':'%s','item':'%s'}," % [ c, c ] }
285*c6249bb2SBram Moolenaar    outp.sub!(/,$/, '')
286*c6249bb2SBram Moolenaar    VIM::command("let g:rbcomplete_completions = [%s]" % outp)
287*c6249bb2SBram Moolenaarend
288*c6249bb2SBram Moolenaar
289*c6249bb2SBram Moolenaar
290*c6249bb2SBram Moolenaardef select_message(receiver, message, candidates)
291*c6249bb2SBram Moolenaar  candidates.grep(/^#{message}/).collect do |e|
292*c6249bb2SBram Moolenaar    case e
293*c6249bb2SBram Moolenaar      when /^[a-zA-Z_]/
294*c6249bb2SBram Moolenaar        receiver + "." + e
295*c6249bb2SBram Moolenaar      when /^[0-9]/
296*c6249bb2SBram Moolenaar      when *Operators
297*c6249bb2SBram Moolenaar        #receiver + " " + e
298*c6249bb2SBram Moolenaar    end
299*c6249bb2SBram Moolenaar  end
300*c6249bb2SBram Moolenaar  candidates.delete_if { |x| x == nil }
301*c6249bb2SBram Moolenaar  candidates.uniq!
302*c6249bb2SBram Moolenaar  candidates.sort!
303*c6249bb2SBram Moolenaarend
304*c6249bb2SBram MoolenaarRUBYEOF
305*c6249bb2SBram Moolenaarendfunction
306*c6249bb2SBram Moolenaar
307*c6249bb2SBram Moolenaarcall s:DefRuby()
308*c6249bb2SBram Moolenaar" vim: set et ts=4:
309