blob: 86baa0d272cbe8037148a8718b1360089e789ad7 [file] [log] [blame]
Bram Moolenaarc6249bb2006-04-15 20:25:09 +00001" Vim completion script
Bram Moolenaard8fc5c02006-04-29 21:55:22 +00002" Language: Ruby
3" Maintainer: Mark Guzman <segfault@hasno.info>
Bram Moolenaar5c736222010-01-06 20:54:52 +01004" Info: $Id: rubycomplete.vim,v 1.41 2008/06/30 06:50:45 segy Exp $
Bram Moolenaard8fc5c02006-04-29 21:55:22 +00005" URL: http://vim-ruby.rubyforge.org
6" Anon CVS: See above site
7" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
Bram Moolenaar9964e462007-05-05 17:54:07 +00008" Maintainer Version: 0.8
Bram Moolenaarc6249bb2006-04-15 20:25:09 +00009" ----------------------------------------------------------------------------
10"
11" Ruby IRB/Complete author: Keiju ISHITSUKA(keiju@ishitsuka.com)
12" ----------------------------------------------------------------------------
13
Bram Moolenaareb3593b2006-04-22 22:33:57 +000014" {{{ requirement checks
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000015if !has('ruby')
Bram Moolenaar9964e462007-05-05 17:54:07 +000016 s:ErrMsg( "Error: Rubycomplete requires vim compiled with +ruby" )
17 s:ErrMsg( "Error: falling back to syntax completion" )
18 " lets fall back to syntax completion
19 setlocal omnifunc=syntaxcomplete#Complete
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000020 finish
21endif
22
23if version < 700
Bram Moolenaar9964e462007-05-05 17:54:07 +000024 s:ErrMsg( "Error: Required vim >= 7.0" )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000025 finish
26endif
Bram Moolenaareb3593b2006-04-22 22:33:57 +000027" }}} requirement checks
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000028
Bram Moolenaar9964e462007-05-05 17:54:07 +000029" {{{ configuration failsafe initialization
Bram Moolenaareb3593b2006-04-22 22:33:57 +000030if !exists("g:rubycomplete_rails")
31 let g:rubycomplete_rails = 0
32endif
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000033
Bram Moolenaareb3593b2006-04-22 22:33:57 +000034if !exists("g:rubycomplete_classes_in_global")
35 let g:rubycomplete_classes_in_global = 0
36endif
37
Bram Moolenaar9964e462007-05-05 17:54:07 +000038if !exists("g:rubycomplete_buffer_loading")
Bram Moolenaara7241f52008-06-24 20:39:31 +000039 let g:rubycomplete_buffer_loading = 0
Bram Moolenaar9964e462007-05-05 17:54:07 +000040endif
41
42if !exists("g:rubycomplete_include_object")
43 let g:rubycomplete_include_object = 0
44endif
45
46if !exists("g:rubycomplete_include_objectspace")
47 let g:rubycomplete_include_objectspace = 0
48endif
49" }}} configuration failsafe initialization
50
Bram Moolenaareb3593b2006-04-22 22:33:57 +000051" {{{ vim-side support functions
Bram Moolenaar9964e462007-05-05 17:54:07 +000052let s:rubycomplete_debug = 0
53
54function! s:ErrMsg(msg)
55 echohl ErrorMsg
56 echo a:msg
57 echohl None
58endfunction
59
60function! s:dprint(msg)
61 if s:rubycomplete_debug == 1
62 echom a:msg
63 endif
64endfunction
65
66function! s:GetBufferRubyModule(name, ...)
67 if a:0 == 1
68 let [snum,enum] = s:GetBufferRubyEntity(a:name, "module", a:1)
69 else
70 let [snum,enum] = s:GetBufferRubyEntity(a:name, "module")
71 endif
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000072 return snum . '..' . enum
73endfunction
74
Bram Moolenaar9964e462007-05-05 17:54:07 +000075function! s:GetBufferRubyClass(name, ...)
76 if a:0 >= 1
77 let [snum,enum] = s:GetBufferRubyEntity(a:name, "class", a:1)
78 else
79 let [snum,enum] = s:GetBufferRubyEntity(a:name, "class")
80 endif
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000081 return snum . '..' . enum
82endfunction
83
Bram Moolenaar9964e462007-05-05 17:54:07 +000084function! s:GetBufferRubySingletonMethods(name)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000085endfunction
86
Bram Moolenaar9964e462007-05-05 17:54:07 +000087function! s:GetBufferRubyEntity( name, type, ... )
88 let lastpos = getpos(".")
89 let lastline = lastpos
90 if (a:0 >= 1)
91 let lastline = [ 0, a:1, 0, 0 ]
92 call cursor( a:1, 0 )
93 endif
94
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000095 let stopline = 1
Bram Moolenaar9964e462007-05-05 17:54:07 +000096
97 let crex = '^\s*\<' . a:type . '\>\s*\<' . a:name . '\>\s*\(<\s*.*\s*\)\?'
98 let [lnum,lcol] = searchpos( crex, 'w' )
99 "let [lnum,lcol] = searchpairpos( crex . '\zs', '', '\(end\|}\)', 'w' )
100
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000101 if lnum == 0 && lcol == 0
Bram Moolenaar9964e462007-05-05 17:54:07 +0000102 call cursor(lastpos[1], lastpos[2])
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000103 return [0,0]
104 endif
105
Bram Moolenaar9964e462007-05-05 17:54:07 +0000106 let curpos = getpos(".")
107 let [enum,ecol] = searchpairpos( crex, '', '\(end\|}\)', 'wr' )
108 call cursor(lastpos[1], lastpos[2])
109
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000110 if lnum > enum
Bram Moolenaar9964e462007-05-05 17:54:07 +0000111 return [0,0]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000112 endif
113 " we found a the class def
114 return [lnum,enum]
115endfunction
116
Bram Moolenaar9964e462007-05-05 17:54:07 +0000117function! s:IsInClassDef()
118 return s:IsPosInClassDef( line('.') )
119endfunction
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000120
Bram Moolenaar9964e462007-05-05 17:54:07 +0000121function! s:IsPosInClassDef(pos)
122 let [snum,enum] = s:GetBufferRubyEntity( '.*', "class" )
123 let ret = 'nil'
124
125 if snum < a:pos && a:pos < enum
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000126 let ret = snum . '..' . enum
127 endif
128
129 return ret
130endfunction
131
Bram Moolenaar9964e462007-05-05 17:54:07 +0000132function! s:GetRubyVarType(v)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000133 let stopline = 1
134 let vtp = ''
135 let pos = getpos('.')
Bram Moolenaar9964e462007-05-05 17:54:07 +0000136 let sstr = '^\s*#\s*@var\s*'.a:v.'\>\s\+[^ \t]\+\s*$'
137 let [lnum,lcol] = searchpos(sstr,'nb',stopline)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000138 if lnum != 0 && lcol != 0
139 call setpos('.',pos)
140 let str = getline(lnum)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000141 let vtp = substitute(str,sstr,'\1','')
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000142 return vtp
143 endif
144 call setpos('.',pos)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000145 let ctors = '\(now\|new\|open\|get_instance'
146 if exists('g:rubycomplete_rails') && g:rubycomplete_rails == 1 && s:rubycomplete_rails_loaded == 1
147 let ctors = ctors.'\|find\|create'
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000148 else
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000149 endif
Bram Moolenaar9964e462007-05-05 17:54:07 +0000150 let ctors = ctors.'\)'
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000151
Bram Moolenaar9964e462007-05-05 17:54:07 +0000152 let fstr = '=\s*\([^ \t]\+.' . ctors .'\>\|[\[{"''/]\|%[xwQqr][(\[{@]\|[A-Za-z0-9@:\-()\.]\+...\?\|lambda\|&\)'
153 let sstr = ''.a:v.'\>\s*[+\-*/]*'.fstr
154 let [lnum,lcol] = searchpos(sstr,'nb',stopline)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000155 if lnum != 0 && lcol != 0
Bram Moolenaar9964e462007-05-05 17:54:07 +0000156 let str = matchstr(getline(lnum),fstr,lcol)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000157 let str = substitute(str,'^=\s*','','')
Bram Moolenaar9964e462007-05-05 17:54:07 +0000158
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000159 call setpos('.',pos)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000160 if str == '"' || str == '''' || stridx(tolower(str), '%q[') != -1
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000161 return 'String'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000162 elseif str == '[' || stridx(str, '%w[') != -1
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000163 return 'Array'
164 elseif str == '{'
165 return 'Hash'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000166 elseif str == '/' || str == '%r{'
167 return 'Regexp'
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000168 elseif strlen(str) >= 4 && stridx(str,'..') != -1
169 return 'Range'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000170 elseif stridx(str, 'lambda') != -1 || str == '&'
171 return 'Proc'
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000172 elseif strlen(str) > 4
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000173 let l = stridx(str,'.')
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000174 return str[0:l-1]
175 end
176 return ''
177 endif
178 call setpos('.',pos)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000179 return ''
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000180endfunction
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000181
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000182"}}} vim-side support functions
183
Bram Moolenaar9964e462007-05-05 17:54:07 +0000184"{{{ vim-side completion function
185function! rubycomplete#Init()
186 execute "ruby VimRubyCompletion.preload_rails"
187endfunction
188
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000189function! rubycomplete#Complete(findstart, base)
190 "findstart = 1 when we need to get the text length
191 if a:findstart
192 let line = getline('.')
193 let idx = col('.')
194 while idx > 0
195 let idx -= 1
196 let c = line[idx-1]
197 if c =~ '\w'
198 continue
199 elseif ! c =~ '\.'
200 idx = -1
201 break
202 else
203 break
204 endif
205 endwhile
206
207 return idx
208 "findstart = 0 when we need to return the list of completions
209 else
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000210 let g:rubycomplete_completions = []
Bram Moolenaar9964e462007-05-05 17:54:07 +0000211 execute "ruby VimRubyCompletion.get_completions('" . a:base . "')"
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000212 return g:rubycomplete_completions
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000213 endif
214endfunction
Bram Moolenaar9964e462007-05-05 17:54:07 +0000215"}}} vim-side completion function
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000216
Bram Moolenaar9964e462007-05-05 17:54:07 +0000217"{{{ ruby-side code
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000218function! s:DefRuby()
219ruby << RUBYEOF
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000220# {{{ ruby completion
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000221
Bram Moolenaar9964e462007-05-05 17:54:07 +0000222begin
223 require 'rubygems' # let's assume this is safe...?
224rescue Exception
225 #ignore?
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000226end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000227class VimRubyCompletion
228# {{{ constants
229 @@debug = false
230 @@ReservedWords = [
231 "BEGIN", "END",
232 "alias", "and",
233 "begin", "break",
234 "case", "class",
235 "def", "defined", "do",
236 "else", "elsif", "end", "ensure",
237 "false", "for",
238 "if", "in",
239 "module",
240 "next", "nil", "not",
241 "or",
242 "redo", "rescue", "retry", "return",
243 "self", "super",
244 "then", "true",
245 "undef", "unless", "until",
246 "when", "while",
247 "yield",
248 ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000249
Bram Moolenaar9964e462007-05-05 17:54:07 +0000250 @@Operators = [ "%", "&", "*", "**", "+", "-", "/",
251 "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
252 "[]", "[]=", "^", ]
253# }}} constants
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000254
Bram Moolenaar9964e462007-05-05 17:54:07 +0000255# {{{ buffer analysis magic
256 def load_requires
257 buf = VIM::Buffer.current
258 enum = buf.line_number
259 nums = Range.new( 1, enum )
260 nums.each do |x|
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000261 ln = buf[x]
Bram Moolenaar9964e462007-05-05 17:54:07 +0000262 begin
263 eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln )
264 rescue Exception
265 #ignore?
266 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000267 end
268 end
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000269
Bram Moolenaar9964e462007-05-05 17:54:07 +0000270 def load_buffer_class(name)
271 dprint "load_buffer_class(%s) START" % name
272 classdef = get_buffer_entity(name, 's:GetBufferRubyClass("%s")')
273 return if classdef == nil
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000274
Bram Moolenaar9964e462007-05-05 17:54:07 +0000275 pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef )
276 load_buffer_class( $2 ) if pare != nil && $2 != name # load parent class if needed
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000277
Bram Moolenaar9964e462007-05-05 17:54:07 +0000278 mixre = /.*\n\s*include\s*(.*)\s*\n/.match( classdef )
279 load_buffer_module( $2 ) if mixre != nil && $2 != name # load mixins if needed
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000280
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000281 begin
Bram Moolenaar9964e462007-05-05 17:54:07 +0000282 eval classdef
283 rescue Exception
284 VIM::evaluate( "s:ErrMsg( 'Problem loading class \"%s\", was it already completed?' )" % name )
285 end
286 dprint "load_buffer_class(%s) END" % name
287 end
288
289 def load_buffer_module(name)
290 dprint "load_buffer_module(%s) START" % name
291 classdef = get_buffer_entity(name, 's:GetBufferRubyModule("%s")')
292 return if classdef == nil
293
294 begin
295 eval classdef
296 rescue Exception
297 VIM::evaluate( "s:ErrMsg( 'Problem loading module \"%s\", was it already completed?' )" % name )
298 end
299 dprint "load_buffer_module(%s) END" % name
300 end
301
302 def get_buffer_entity(name, vimfun)
303 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000304 return nil if loading_allowed.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000305 return nil if /(\"|\')+/.match( name )
306 buf = VIM::Buffer.current
307 nums = eval( VIM::evaluate( vimfun % name ) )
308 return nil if nums == nil
309 return nil if nums.min == nums.max && nums.min == 0
310
311 dprint "get_buffer_entity START"
312 visited = []
313 clscnt = 0
314 bufname = VIM::Buffer.current.name
315 classdef = ""
316 cur_line = VIM::Buffer.current.line_number
317 while (nums != nil && !(nums.min == 0 && nums.max == 0) )
318 dprint "visited: %s" % visited.to_s
319 break if visited.index( nums )
320 visited << nums
321
322 nums.each do |x|
323 if x != cur_line
324 next if x == 0
325 ln = buf[x]
326 if /^\s*(module|class|def|include)\s+/.match(ln)
327 clscnt += 1 if $1 == "class"
328 #dprint "\$1: %s" % $1
329 classdef += "%s\n" % ln
330 classdef += "end\n" if /def\s+/.match(ln)
331 dprint ln
332 end
333 end
334 end
335
336 nm = "%s(::.*)*\", %s, \"" % [ name, nums.last ]
337 nums = eval( VIM::evaluate( vimfun % nm ) )
338 dprint "nm: \"%s\"" % nm
339 dprint "vimfun: %s" % (vimfun % nm)
340 dprint "got nums: %s" % nums.to_s
341 end
342 if classdef.length > 1
343 classdef += "end\n"*clscnt
344 # classdef = "class %s\n%s\nend\n" % [ bufname.gsub( /\/|\\/, "_" ), classdef ]
345 end
346
347 dprint "get_buffer_entity END"
348 dprint "classdef====start"
349 lns = classdef.split( "\n" )
350 lns.each { |x| dprint x }
351 dprint "classdef====end"
352 return classdef
353 end
354
355 def get_var_type( receiver )
356 if /(\"|\')+/.match( receiver )
357 "String"
358 else
359 VIM::evaluate("s:GetRubyVarType('%s')" % receiver)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000360 end
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000361 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000362
Bram Moolenaar9964e462007-05-05 17:54:07 +0000363 def dprint( txt )
364 print txt if @@debug
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000365 end
366
Bram Moolenaar9964e462007-05-05 17:54:07 +0000367 def get_buffer_entity_list( type )
368 # this will be a little expensive.
369 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
370 allow_aggressive_load = VIM::evaluate("exists('g:rubycomplete_classes_in_global') && g:rubycomplete_classes_in_global")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000371 return [] if allow_aggressive_load.to_i.zero? || loading_allowed.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000372
373 buf = VIM::Buffer.current
374 eob = buf.length
375 ret = []
376 rg = 1..eob
377 re = eval( "/^\s*%s\s*([A-Za-z0-9_:-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/" % type )
378
379 rg.each do |x|
380 if re.match( buf[x] )
381 next if type == "def" && eval( VIM::evaluate("s:IsPosInClassDef(%s)" % x) ) != nil
382 ret.push $1
383 end
384 end
385
386 return ret
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000387 end
388
Bram Moolenaar9964e462007-05-05 17:54:07 +0000389 def get_buffer_modules
390 return get_buffer_entity_list( "modules" )
391 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000392
Bram Moolenaar9964e462007-05-05 17:54:07 +0000393 def get_buffer_methods
394 return get_buffer_entity_list( "def" )
395 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000396
Bram Moolenaar9964e462007-05-05 17:54:07 +0000397 def get_buffer_classes
398 return get_buffer_entity_list( "class" )
399 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000400
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000401
Bram Moolenaar9964e462007-05-05 17:54:07 +0000402 def load_rails
403 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000404 return if allow_rails.to_i.zero?
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000405
Bram Moolenaar9964e462007-05-05 17:54:07 +0000406 buf_path = VIM::evaluate('expand("%:p")')
407 file_name = VIM::evaluate('expand("%:t")')
408 vim_dir = VIM::evaluate('getcwd()')
409 file_dir = buf_path.gsub( file_name, '' )
410 file_dir.gsub!( /\\/, "/" )
411 vim_dir.gsub!( /\\/, "/" )
412 vim_dir << "/"
413 dirs = [ vim_dir, file_dir ]
414 sdirs = [ "", "./", "../", "../../", "../../../", "../../../../" ]
415 rails_base = nil
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000416
Bram Moolenaar9964e462007-05-05 17:54:07 +0000417 dirs.each do |dir|
418 sdirs.each do |sub|
419 trail = "%s%s" % [ dir, sub ]
420 tcfg = "%sconfig" % trail
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000421
Bram Moolenaar9964e462007-05-05 17:54:07 +0000422 if File.exists?( tcfg )
423 rails_base = trail
424 break
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000425 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000426 end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000427 break if rails_base
428 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000429
Bram Moolenaar9964e462007-05-05 17:54:07 +0000430 return if rails_base == nil
431 $:.push rails_base unless $:.index( rails_base )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000432
Bram Moolenaar9964e462007-05-05 17:54:07 +0000433 rails_config = rails_base + "config/"
434 rails_lib = rails_base + "lib/"
435 $:.push rails_config unless $:.index( rails_config )
436 $:.push rails_lib unless $:.index( rails_lib )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000437
Bram Moolenaar9964e462007-05-05 17:54:07 +0000438 bootfile = rails_config + "boot.rb"
439 envfile = rails_config + "environment.rb"
440 if File.exists?( bootfile ) && File.exists?( envfile )
441 begin
442 require bootfile
443 require envfile
444 begin
445 require 'console_app'
446 require 'console_with_helpers'
447 rescue Exception
448 dprint "Rails 1.1+ Error %s" % $!
449 # assume 1.0
450 end
451 #eval( "Rails::Initializer.run" ) #not necessary?
452 VIM::command('let s:rubycomplete_rails_loaded = 1')
453 dprint "rails loaded"
454 rescue Exception
455 dprint "Rails Error %s" % $!
456 VIM::evaluate( "s:ErrMsg('Error loading rails environment')" )
457 end
458 end
459 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000460
Bram Moolenaar9964e462007-05-05 17:54:07 +0000461 def get_rails_helpers
462 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
463 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000464 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000465
Bram Moolenaar9964e462007-05-05 17:54:07 +0000466 buf_path = VIM::evaluate('expand("%:p")')
467 buf_path.gsub!( /\\/, "/" )
468 path_elm = buf_path.split( "/" )
469 dprint "buf_path: %s" % buf_path
470 types = [ "app", "db", "lib", "test", "components", "script" ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000471
Bram Moolenaar9964e462007-05-05 17:54:07 +0000472 i = nil
473 ret = []
474 type = nil
475 types.each do |t|
476 i = path_elm.index( t )
477 break if i
478 end
479 type = path_elm[i]
480 type.downcase!
481
482 dprint "type: %s" % type
483 case type
484 when "app"
485 i += 1
486 subtype = path_elm[i]
487 subtype.downcase!
488
489 dprint "subtype: %s" % subtype
490 case subtype
491 when "views"
492 ret += ActionView::Base.instance_methods
493 ret += ActionView::Base.methods
494 when "controllers"
495 ret += ActionController::Base.instance_methods
496 ret += ActionController::Base.methods
497 when "models"
498 ret += ActiveRecord::Base.instance_methods
499 ret += ActiveRecord::Base.methods
500 end
501
502 when "db"
503 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods
504 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods
505 end
506
507
508 return ret
509 end
510
511 def add_rails_columns( cls )
512 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
513 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000514 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000515
516 begin
517 eval( "#{cls}.establish_connection" )
518 return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" )
519 col = eval( "#{cls}.column_names" )
520 return col if col
521 rescue
522 dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ]
523 return []
524 end
525 return []
526 end
527
528 def clean_sel(sel, msg)
529 sel.delete_if { |x| x == nil }
530 sel.uniq!
531 sel.grep(/^#{Regexp.quote(msg)}/) if msg != nil
532 end
533
534 def get_rails_view_methods
535 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
536 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000537 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000538
539 buf_path = VIM::evaluate('expand("%:p")')
540 buf_path.gsub!( /\\/, "/" )
541 pelm = buf_path.split( "/" )
542 idx = pelm.index( "views" )
543
544 return [] unless idx
545 idx += 1
546
547 clspl = pelm[idx].camelize.pluralize
548 cls = clspl.singularize
549
550 ret = []
551 begin
552 ret += eval( "#{cls}.instance_methods" )
553 ret += eval( "#{clspl}Helper.instance_methods" )
554 rescue Exception
555 dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ]
556 end
557
558 return ret
559 end
560# }}} buffer analysis magic
561
562# {{{ main completion code
563 def self.preload_rails
564 a = VimRubyCompletion.new
565 require 'Thread'
566 Thread.new(a) do |b|
567 begin
568 b.load_rails
569 rescue
570 end
571 end
572 a.load_rails
573 rescue
574 end
575
576 def self.get_completions(base)
577 b = VimRubyCompletion.new
578 b.get_completions base
579 end
580
581 def get_completions(base)
582 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000583 if loading_allowed.to_i == 1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000584 load_requires
585 load_rails
586 end
587
588 input = VIM::Buffer.current.line
589 cpos = VIM::Window.current.cursor[1] - 1
590 input = input[0..cpos]
591 input += base
592 input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters
593 input.sub!(/self\./, '')
594 input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '')
595
596 dprint 'input %s' % input
597 message = nil
598 receiver = nil
599 methods = []
600 variables = []
601 classes = []
602 constants = []
603
604 case input
605 when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000606 receiver = $1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000607 message = Regexp.quote($2)
608 methods = Regexp.instance_methods(true)
609
610 when /^([^\]]*\])\.([^.]*)$/ # Array
611 receiver = $1
612 message = Regexp.quote($2)
613 methods = Array.instance_methods(true)
614
615 when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash
616 receiver = $1
617 message = Regexp.quote($2)
618 methods = Proc.instance_methods(true) | Hash.instance_methods(true)
619
620 when /^(:[^:.]*)$/ # Symbol
621 dprint "symbol"
622 if Symbol.respond_to?(:all_symbols)
623 receiver = $1
624 message = $1.sub( /:/, '' )
625 methods = Symbol.all_symbols.collect{|s| s.id2name}
626 methods.delete_if { |c| c.match( /'/ ) }
627 end
628
629 when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods
630 dprint "const or cls"
631 receiver = $1
632 methods = Object.constants
633 methods.grep(/^#{receiver}/).collect{|e| "::" + e}
634
635 when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/ # Constant or class methods
636 receiver = $1
637 message = Regexp.quote($4)
638 dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000639 load_buffer_class( receiver )
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000640 begin
Bram Moolenaar9964e462007-05-05 17:54:07 +0000641 classes = eval("#{receiver}.constants")
642 #methods = eval("#{receiver}.methods")
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000643 rescue Exception
Bram Moolenaar9964e462007-05-05 17:54:07 +0000644 dprint "exception: %s" % $!
645 methods = []
646 end
647 methods.grep(/^#{message}/).collect{|e| receiver + "::" + e}
648
649 when /^(:[^:.]+)\.([^.]*)$/ # Symbol
650 dprint "symbol"
651 receiver = $1
652 message = Regexp.quote($2)
653 methods = Symbol.instance_methods(true)
654
655 when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric
656 dprint "numeric"
657 receiver = $1
658 message = Regexp.quote($4)
659 begin
660 methods = eval(receiver).methods
661 rescue Exception
662 methods = []
663 end
664
665 when /^(\$[^.]*)$/ #global
666 dprint "global"
667 methods = global_variables.grep(Regexp.new(Regexp.quote($1)))
668
669 when /^((\.?[^.]+)+)\.([^.]*)$/ # variable
670 dprint "variable"
671 receiver = $1
672 message = Regexp.quote($3)
673 load_buffer_class( receiver )
674
675 cv = eval("self.class.constants")
676 vartype = get_var_type( receiver )
677 dprint "vartype: %s" % vartype
678 if vartype != ''
679 load_buffer_class( vartype )
680
681 begin
682 methods = eval("#{vartype}.instance_methods")
683 variables = eval("#{vartype}.instance_variables")
684 rescue Exception
685 dprint "load_buffer_class err: %s" % $!
686 end
687 elsif (cv).include?(receiver)
688 # foo.func and foo is local var.
689 methods = eval("#{receiver}.methods")
690 vartype = receiver
691 elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
692 vartype = receiver
693 # Foo::Bar.func
694 begin
695 methods = eval("#{receiver}.methods")
696 rescue Exception
697 end
698 else
699 # func1.func2
700 ObjectSpace.each_object(Module){|m|
701 next if m.name != "IRB::Context" and
702 /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
703 methods.concat m.instance_methods(false)
704 }
705 end
706 variables += add_rails_columns( "#{vartype}" ) if vartype && vartype.length > 0
707
708 when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/
709 message = $1
710 methods = Range.instance_methods(true)
711
712 when /^\.([^.]*)$/ # unknown(maybe String)
713 message = Regexp.quote($1)
714 methods = String.instance_methods(true)
715
716 else
717 dprint "default/other"
718 inclass = eval( VIM::evaluate("s:IsInClassDef()") )
719
720 if inclass != nil
721 dprint "inclass"
722 classdef = "%s\n" % VIM::Buffer.current[ inclass.min ]
723 found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef )
724
725 if found != nil
726 receiver = $1
727 message = input
728 load_buffer_class( receiver )
729 begin
730 methods = eval( "#{receiver}.instance_methods" )
731 variables += add_rails_columns( "#{receiver}" )
732 rescue Exception
733 found = nil
734 end
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000735 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000736 end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000737
738 if inclass == nil || found == nil
739 dprint "inclass == nil"
740 methods = get_buffer_methods
741 methods += get_rails_view_methods
742
743 cls_const = Class.constants
744 constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) }
745 classes = eval("self.class.constants") - constants
746 classes += get_buffer_classes
747 classes += get_buffer_modules
748
749 include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace")
750 ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1"
751 message = receiver = input
752 end
753
754 methods += get_rails_helpers
755 methods += Kernel.public_methods
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000756 end
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000757
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000758
Bram Moolenaar9964e462007-05-05 17:54:07 +0000759 include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object")
760 methods = clean_sel( methods, message )
761 methods = (methods-Object.instance_methods) if include_object == "0"
762 rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods
763 methods = (methods-rbcmeth)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000764
Bram Moolenaar9964e462007-05-05 17:54:07 +0000765 variables = clean_sel( variables, message )
766 classes = clean_sel( classes, message ) - ["VimRubyCompletion"]
767 constants = clean_sel( constants, message )
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000768
Bram Moolenaar9964e462007-05-05 17:54:07 +0000769 valid = []
770 valid += methods.collect { |m| { :name => m, :type => 'm' } }
771 valid += variables.collect { |v| { :name => v, :type => 'v' } }
772 valid += classes.collect { |c| { :name => c, :type => 't' } }
773 valid += constants.collect { |d| { :name => d, :type => 'd' } }
774 valid.sort! { |x,y| x[:name] <=> y[:name] }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000775
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000776 outp = ""
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000777
Bram Moolenaar9964e462007-05-05 17:54:07 +0000778 rg = 0..valid.length
779 rg.step(150) do |x|
780 stpos = 0+x
781 enpos = 150+x
782 valid[stpos..enpos].each { |c| outp += "{'word':'%s','item':'%s','kind':'%s'}," % [ c[:name], c[:name], c[:type] ] }
783 outp.sub!(/,$/, '')
784
785 VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp)
786 outp = ""
787 end
788 end
789# }}} main completion code
790
791end # VimRubyCompletion
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000792# }}} ruby completion
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000793RUBYEOF
794endfunction
795
Bram Moolenaar9964e462007-05-05 17:54:07 +0000796let s:rubycomplete_rails_loaded = 0
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000797
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000798call s:DefRuby()
Bram Moolenaar9964e462007-05-05 17:54:07 +0000799"}}} ruby-side code
800
801
802" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl: