blob: 0a745b98c990d4167c44716a9e71c61f533ac42e [file] [log] [blame]
Bram Moolenaarc6249bb2006-04-15 20:25:09 +00001" Vim completion script
2" Language: Ruby
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00003" Maintainer: Mark Guzman <segfault@hasno.info>
Bram Moolenaarc6249bb2006-04-15 20:25:09 +00004" Info: $Id$
5" URL: http://vim-ruby.rubyforge.org
6" Anon CVS: See above site
7" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
8" ----------------------------------------------------------------------------
9"
10" Ruby IRB/Complete author: Keiju ISHITSUKA(keiju@ishitsuka.com)
11" ----------------------------------------------------------------------------
12
13if !has('ruby')
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000014 echohl ErrorMsg
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000015 echo "Error: Required vim compiled with +ruby"
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000016 echohl None
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000017 finish
18endif
19
20if version < 700
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000021 echohl ErrorMsg
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000022 echo "Error: Required vim >= 7.0"
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000023 echohl None
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000024 finish
25endif
26
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000027
28function! GetBufferRubyModule(name)
29 let [snum,enum] = GetBufferRubyEntity(a:name, "module")
30 return snum . '..' . enum
31endfunction
32
33function! GetBufferRubyClass(name)
34 let [snum,enum] = GetBufferRubyEntity(a:name, "class")
35 return snum . '..' . enum
36endfunction
37
38function! GetBufferRubySingletonMethods(name)
39endfunction
40
41function! GetBufferRubyEntity( name, type )
42 let stopline = 1
43 let crex = '^\s*' . a:type . '\s*' . a:name . '\s*\(<\s*.*\s*\)\?\n*\(\(\s\|#\).*\n*\)*\n*\s*end$'
44 let [lnum,lcol] = searchpos( crex, 'nbw')
45 if lnum == 0 && lcol == 0
46 return [0,0]
47 endif
48
49 let [enum,ecol] = searchpos( crex, 'nebw')
50 if lnum > enum
51 let realdef = getline( lnum )
52 let crexb = '^' . realdef . '\n*\(\(\s\|#\).*\n*\)*\n*\s*end$'
53 let [enum,ecol] = searchpos( crexb, 'necw' )
54 endif
55 " we found a the class def
56 return [lnum,enum]
57endfunction
58
59function! IsInClassDef()
60 let [snum,enum] = GetBufferRubyEntity( '.*', "class" )
61 let ret = 'nil'
62 let pos = line('.')
63
64 if snum < pos && pos < enum
65 let ret = snum . '..' . enum
66 endif
67
68 return ret
69endfunction
70
71function! GetRubyVarType(v)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000072 let stopline = 1
73 let vtp = ''
74 let pos = getpos('.')
75 let [lnum,lcol] = searchpos('^\s*#\s*@var\s*'.a:v.'\>\s\+[^ \t]\+\s*$','nb',stopline)
76 if lnum != 0 && lcol != 0
77 call setpos('.',pos)
78 let str = getline(lnum)
79 let vtp = substitute(str,'^\s*#\s*@var\s*'.a:v.'\>\s\+\([^ \t]\+\)\s*$','\1','')
80 return vtp
81 endif
82 call setpos('.',pos)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000083 let [lnum,lcol] = searchpos(''.a:v.'\>\s*[+\-*/]*=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"''/]\|%r{\)','nb',stopline)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000084 if lnum != 0 && lcol != 0
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000085 let str = matchstr(getline(lnum),'=\s*\([^ \t]\+.\(now\|new\|open\|get_instance\)\>\|[\[{"''/]\|%r{\)',lcol)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000086 let str = substitute(str,'^=\s*','','')
87 call setpos('.',pos)
88 if str == '"' || str == ''''
89 return 'String'
90 elseif str == '['
91 return 'Array'
92 elseif str == '{'
93 return 'Hash'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000094 elseif str == '/' || str == '%r{'
95 return 'Regexp'
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000096 elseif strlen(str) > 4
97 let l = stridx(str,'.')
98 return str[0:l-1]
99 end
100 return ''
101 endif
102 call setpos('.',pos)
103 return ''
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000104endfunction
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000105
106function! rubycomplete#Complete(findstart, base)
107 "findstart = 1 when we need to get the text length
108 if a:findstart
109 let line = getline('.')
110 let idx = col('.')
111 while idx > 0
112 let idx -= 1
113 let c = line[idx-1]
114 if c =~ '\w'
115 continue
116 elseif ! c =~ '\.'
117 idx = -1
118 break
119 else
120 break
121 endif
122 endwhile
123
124 return idx
125 "findstart = 0 when we need to return the list of completions
126 else
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000127 let g:rubycomplete_completions = []
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000128 execute "ruby get_completions('" . a:base . "')"
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000129 return g:rubycomplete_completions
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000130 endif
131endfunction
132
133
134function! s:DefRuby()
135ruby << RUBYEOF
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000136RailsWords = [
137 "has_many", "has_one",
138 "belongs_to",
139 ]
140
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000141ReservedWords = [
142 "BEGIN", "END",
143 "alias", "and",
144 "begin", "break",
145 "case", "class",
146 "def", "defined", "do",
147 "else", "elsif", "end", "ensure",
148 "false", "for",
149 "if", "in",
150 "module",
151 "next", "nil", "not",
152 "or",
153 "redo", "rescue", "retry", "return",
154 "self", "super",
155 "then", "true",
156 "undef", "unless", "until",
157 "when", "while",
158 "yield",
159 ]
160
161Operators = [ "%", "&", "*", "**", "+", "-", "/",
162 "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
163 "[]", "[]=", "^", ]
164
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000165
166def load_requires
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000167 @buf = VIM::Buffer.current
168 enum = @buf.line_number
169 nums = Range.new( 1, enum )
170 nums.each do |x|
171 ln = @buf[x]
172 begin
173 eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln )
174 rescue Exception
175 #ignore?
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000176 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000177 end
178end
179
180def load_buffer_class(name)
181 classdef = get_buffer_entity(name, 'GetBufferRubyClass("%s")')
182 return if classdef == nil
183
184 pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef )
185 load_buffer_class( $2 ) if pare != nil
186
187 mixre = /.*\n\s*include\s*(.*)\s*\n/.match( classdef )
188 load_buffer_module( $2 ) if mixre != nil
189
190 eval classdef
191end
192
193def load_buffer_module(name)
194 classdef = get_buffer_entity(name, 'GetBufferRubyModule("%s")')
195 return if classdef == nil
196
197 eval classdef
198end
199
200def get_buffer_entity(name, vimfun)
201 @buf = VIM::Buffer.current
202 nums = eval( VIM::evaluate( vimfun % name ) )
203 return nil if nums == nil
204 return nil if nums.min == nums.max && nums.min == 0
205
206 cur_line = VIM::Buffer.current.line_number
207 classdef = ""
208 nums.each do |x|
209 if x != cur_line
210 ln = @buf[x]
211 classdef += "%s\n" % ln
212 end
213 end
214
215 return classdef
216end
217
218def load_rails()
219 allow_rails = VIM::evaluate('g:rubycomplete_rails')
220 return if allow_rails != '1'
221
222 buf_path = VIM::evaluate('expand("%:p")')
223 file_name = VIM::evaluate('expand("%:t")')
224 path = buf_path.gsub( file_name, '' )
225 path.gsub!( /\\/, "/" )
226 pup = [ "../", "../../", "../../../", "../../../../" ]
227 pok = nil
228
229 pup.each do |sup|
230 tpok = "%s%sconfig" % [ path, sup ]
231 if File.exists?( tpok )
232 pok = tpok
233 break
234 end
235 end
236 bootfile = pok + "/boot.rb"
237 require bootfile if pok != nil && File.exists?( bootfile )
238end
239
240def get_rails_helpers
241 allow_rails = VIM::evaluate('g:rubycomplete_rails')
242 return [] if allow_rails != '1'
243 return RailsWords
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000244end
245
246def get_completions(base)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000247 load_requires
248 load_rails
249
250 input = VIM::evaluate('expand("<cWORD>")')
251 input += base
252 input.lstrip!
253 if input.length == 0
254 input = VIM::Buffer.current.line
255 input.strip!
256 end
257 message = nil
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000258
259
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000260 case input
261 when /^(\/[^\/]*\/)\.([^.]*)$/
262 # Regexp
263 receiver = $1
264 message = Regexp.quote($2)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000265
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000266 candidates = Regexp.instance_methods(true)
267 select_message(receiver, message, candidates)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000268
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000269 when /^([^\]]*\])\.([^.]*)$/
270 # Array
271 receiver = $1
272 message = Regexp.quote($2)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000273
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000274 candidates = Array.instance_methods(true)
275 select_message(receiver, message, candidates)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000276
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000277 when /^([^\}]*\})\.([^.]*)$/
278 # Proc or Hash
279 receiver = $1
280 message = Regexp.quote($2)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000281
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000282 candidates = Proc.instance_methods(true) | Hash.instance_methods(true)
283 select_message(receiver, message, candidates)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000284
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000285 when /^(:[^:.]*)$/
286 # Symbol
287 if Symbol.respond_to?(:all_symbols)
288 sym = $1
289 candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
290 candidates.grep(/^#{sym}/)
291 candidates.delete_if do |c|
292 c.match( /'/ )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000293 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000294 candidates.uniq!
295 candidates.sort!
296 else
297 []
298 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000299
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000300 when /^::([A-Z][^:\.\(]*)$/
301 # Absolute Constant or class methods
302 receiver = $1
303 candidates = Object.constants
304 candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000305
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000306 when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/
307 # Constant or class methods
308 receiver = $1
309 message = Regexp.quote($4)
310 begin
311 candidates = eval("#{receiver}.constants | #{receiver}.methods")
312 rescue Exception
313 candidates = []
314 end
315 candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000316
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000317 when /^(:[^:.]+)\.([^.]*)$/
318 # Symbol
319 receiver = $1
320 message = Regexp.quote($2)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000321
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000322 candidates = Symbol.instance_methods(true)
323 select_message(receiver, message, candidates)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000324
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000325 when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/
326 # Numeric
327 receiver = $1
328 message = Regexp.quote($4)
329
330 begin
331 candidates = eval(receiver).methods
332 rescue Exception
333 candidates
334 end
335 select_message(receiver, message, candidates)
336
337 when /^(\$[^.]*)$/
338 candidates = global_variables.grep(Regexp.new(Regexp.quote($1)))
339
340# when /^(\$?(\.?[^.]+)+)\.([^.]*)$/
341 when /^((\.?[^.]+)+)\.([^.]*)$/
342 # variable
343 receiver = $1
344 message = Regexp.quote($3)
345 load_buffer_class( receiver )
346
347 cv = eval("self.class.constants")
348
349 vartype = VIM::evaluate("GetRubyVarType('%s')" % receiver)
350 if vartype != ''
351 load_buffer_class( vartype )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000352
353 begin
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000354 candidates = eval("#{vartype}.instance_methods")
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000355 rescue Exception
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000356 candidates = []
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000357 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000358 elsif (cv).include?(receiver)
359 # foo.func and foo is local var.
360 candidates = eval("#{receiver}.methods")
361 elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
362 # Foo::Bar.func
363 begin
364 candidates = eval("#{receiver}.methods")
365 rescue Exception
366 candidates = []
367 end
368 else
369 # func1.func2
370 candidates = []
371 ObjectSpace.each_object(Module){|m|
372 next if m.name != "IRB::Context" and
373 /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
374 candidates.concat m.instance_methods(false)
375 }
376 candidates.sort!
377 candidates.uniq!
378 end
379 #identify_type( receiver )
380 select_message(receiver, message, candidates)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000381
382 #when /^((\.?[^.]+)+)\.([^.]*)\(\s*\)*$/
383 #function call
384 #obj = $1
385 #func = $3
386
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000387 when /^\.([^.]*)$/
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000388 # unknown(maybe String)
389
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000390 receiver = ""
391 message = Regexp.quote($1)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000392
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000393 candidates = String.instance_methods(true)
394 select_message(receiver, message, candidates)
395
396 else
397 inclass = eval( VIM::evaluate("IsInClassDef()") )
398
399 if inclass != nil
400 classdef = "%s\n" % VIM::Buffer.current[ inclass.min ]
401 found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef )
402
403 if found != nil
404 receiver = $1
405 message = input
406 load_buffer_class( receiver )
407 candidates = eval( "#{receiver}.instance_methods" )
408 candidates += get_rails_helpers
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000409 select_message(receiver, message, candidates)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000410 end
411 end
412
413 if inclass == nil || found == nil
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000414 candidates = eval("self.class.constants")
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000415 (candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/)
416 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000417 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000418
419 #print candidates
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000420 if message != nil && message.length > 0
421 rexp = '^%s' % message.downcase
422 candidates.delete_if do |c|
423 c.downcase.match( rexp )
424 $~ == nil
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000425 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000426 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000427
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000428 outp = ""
429
430 # tags = VIM::evaluate("taglist('^%s$')" %
431 valid = (candidates-Object.instance_methods)
432
433 rg = 0..valid.length
434 rg.step(150) do |x|
435 stpos = 0+x
436 enpos = 150+x
437 valid[stpos..enpos].each { |c| outp += "{'word':'%s','item':'%s'}," % [ c, c ] }
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000438 outp.sub!(/,$/, '')
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000439
440 VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp)
441 outp = ""
442 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000443end
444
445
446def select_message(receiver, message, candidates)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000447 #tags = VIM::evaluate("taglist('%s')" % receiver)
448 #print tags
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000449 candidates.grep(/^#{message}/).collect do |e|
450 case e
451 when /^[a-zA-Z_]/
452 receiver + "." + e
453 when /^[0-9]/
454 when *Operators
455 #receiver + " " + e
456 end
457 end
458 candidates.delete_if { |x| x == nil }
459 candidates.uniq!
460 candidates.sort!
461end
462RUBYEOF
463endfunction
464
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000465
466let g:rubycomplete_rails = 0
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000467call s:DefRuby()
468" vim: set et ts=4: