blob: 440dfd42e9e5efbec1249522c04a0a1e32f51b50 [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 Moolenaarec7944a2013-06-12 21:29:15 +02004" URL: https://github.com/vim-ruby/vim-ruby
Bram Moolenaard8fc5c02006-04-29 21:55:22 +00005" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
Bram Moolenaar1d689522010-05-28 20:54:39 +02006" Maintainer Version: 0.8.1
Bram Moolenaarc6249bb2006-04-15 20:25:09 +00007" ----------------------------------------------------------------------------
8"
9" Ruby IRB/Complete author: Keiju ISHITSUKA(keiju@ishitsuka.com)
10" ----------------------------------------------------------------------------
11
Bram Moolenaareb3593b2006-04-22 22:33:57 +000012" {{{ requirement checks
Bram Moolenaarec7944a2013-06-12 21:29:15 +020013
14function! s:ErrMsg(msg)
15 echohl ErrorMsg
16 echo a:msg
17 echohl None
18endfunction
19
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000020if !has('ruby')
Bram Moolenaarec7944a2013-06-12 21:29:15 +020021 call s:ErrMsg( "Error: Rubycomplete requires vim compiled with +ruby" )
22 call s:ErrMsg( "Error: falling back to syntax completion" )
Bram Moolenaar9964e462007-05-05 17:54:07 +000023 " lets fall back to syntax completion
24 setlocal omnifunc=syntaxcomplete#Complete
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000025 finish
26endif
27
28if version < 700
Bram Moolenaarec7944a2013-06-12 21:29:15 +020029 call s:ErrMsg( "Error: Required vim >= 7.0" )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000030 finish
31endif
Bram Moolenaareb3593b2006-04-22 22:33:57 +000032" }}} requirement checks
Bram Moolenaarc6249bb2006-04-15 20:25:09 +000033
Bram Moolenaar9964e462007-05-05 17:54:07 +000034" {{{ configuration failsafe initialization
Bram Moolenaareb3593b2006-04-22 22:33:57 +000035if !exists("g:rubycomplete_rails")
36 let g:rubycomplete_rails = 0
37endif
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000038
Bram Moolenaareb3593b2006-04-22 22:33:57 +000039if !exists("g:rubycomplete_classes_in_global")
40 let g:rubycomplete_classes_in_global = 0
41endif
42
Bram Moolenaar9964e462007-05-05 17:54:07 +000043if !exists("g:rubycomplete_buffer_loading")
Bram Moolenaara7241f52008-06-24 20:39:31 +000044 let g:rubycomplete_buffer_loading = 0
Bram Moolenaar9964e462007-05-05 17:54:07 +000045endif
46
47if !exists("g:rubycomplete_include_object")
48 let g:rubycomplete_include_object = 0
49endif
50
51if !exists("g:rubycomplete_include_objectspace")
52 let g:rubycomplete_include_objectspace = 0
53endif
54" }}} configuration failsafe initialization
55
Bram Moolenaareb3593b2006-04-22 22:33:57 +000056" {{{ vim-side support functions
Bram Moolenaar9964e462007-05-05 17:54:07 +000057let s:rubycomplete_debug = 0
58
Bram Moolenaar9964e462007-05-05 17:54:07 +000059function! s:dprint(msg)
60 if s:rubycomplete_debug == 1
61 echom a:msg
62 endif
63endfunction
64
65function! s:GetBufferRubyModule(name, ...)
66 if a:0 == 1
67 let [snum,enum] = s:GetBufferRubyEntity(a:name, "module", a:1)
68 else
69 let [snum,enum] = s:GetBufferRubyEntity(a:name, "module")
70 endif
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000071 return snum . '..' . enum
72endfunction
73
Bram Moolenaar9964e462007-05-05 17:54:07 +000074function! s:GetBufferRubyClass(name, ...)
75 if a:0 >= 1
76 let [snum,enum] = s:GetBufferRubyEntity(a:name, "class", a:1)
77 else
78 let [snum,enum] = s:GetBufferRubyEntity(a:name, "class")
79 endif
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000080 return snum . '..' . enum
81endfunction
82
Bram Moolenaar9964e462007-05-05 17:54:07 +000083function! s:GetBufferRubySingletonMethods(name)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000084endfunction
85
Bram Moolenaar9964e462007-05-05 17:54:07 +000086function! s:GetBufferRubyEntity( name, type, ... )
87 let lastpos = getpos(".")
88 let lastline = lastpos
89 if (a:0 >= 1)
90 let lastline = [ 0, a:1, 0, 0 ]
91 call cursor( a:1, 0 )
92 endif
93
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000094 let stopline = 1
Bram Moolenaar9964e462007-05-05 17:54:07 +000095
Bram Moolenaar89bcfda2016-08-30 23:26:57 +020096 let crex = '^\s*\<' . a:type . '\>\s*\<' . escape(a:name, '*') . '\>\s*\(<\s*.*\s*\)\?'
Bram Moolenaar9964e462007-05-05 17:54:07 +000097 let [lnum,lcol] = searchpos( crex, 'w' )
98 "let [lnum,lcol] = searchpairpos( crex . '\zs', '', '\(end\|}\)', 'w' )
99
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000100 if lnum == 0 && lcol == 0
Bram Moolenaar9964e462007-05-05 17:54:07 +0000101 call cursor(lastpos[1], lastpos[2])
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000102 return [0,0]
103 endif
104
Bram Moolenaar9964e462007-05-05 17:54:07 +0000105 let curpos = getpos(".")
106 let [enum,ecol] = searchpairpos( crex, '', '\(end\|}\)', 'wr' )
107 call cursor(lastpos[1], lastpos[2])
108
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000109 if lnum > enum
Bram Moolenaar9964e462007-05-05 17:54:07 +0000110 return [0,0]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000111 endif
112 " we found a the class def
113 return [lnum,enum]
114endfunction
115
Bram Moolenaar9964e462007-05-05 17:54:07 +0000116function! s:IsInClassDef()
117 return s:IsPosInClassDef( line('.') )
118endfunction
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000119
Bram Moolenaar9964e462007-05-05 17:54:07 +0000120function! s:IsPosInClassDef(pos)
121 let [snum,enum] = s:GetBufferRubyEntity( '.*', "class" )
122 let ret = 'nil'
123
124 if snum < a:pos && a:pos < enum
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000125 let ret = snum . '..' . enum
126 endif
127
128 return ret
129endfunction
130
Bram Moolenaar9964e462007-05-05 17:54:07 +0000131function! s:GetRubyVarType(v)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000132 let stopline = 1
133 let vtp = ''
134 let pos = getpos('.')
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200135 let sstr = '^\s*#\s*@var\s*'.escape(a:v, '*').'\>\s\+[^ \t]\+\s*$'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000136 let [lnum,lcol] = searchpos(sstr,'nb',stopline)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000137 if lnum != 0 && lcol != 0
138 call setpos('.',pos)
139 let str = getline(lnum)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000140 let vtp = substitute(str,sstr,'\1','')
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000141 return vtp
142 endif
143 call setpos('.',pos)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000144 let ctors = '\(now\|new\|open\|get_instance'
145 if exists('g:rubycomplete_rails') && g:rubycomplete_rails == 1 && s:rubycomplete_rails_loaded == 1
146 let ctors = ctors.'\|find\|create'
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000147 else
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000148 endif
Bram Moolenaar9964e462007-05-05 17:54:07 +0000149 let ctors = ctors.'\)'
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000150
Bram Moolenaar9964e462007-05-05 17:54:07 +0000151 let fstr = '=\s*\([^ \t]\+.' . ctors .'\>\|[\[{"''/]\|%[xwQqr][(\[{@]\|[A-Za-z0-9@:\-()\.]\+...\?\|lambda\|&\)'
Bram Moolenaar89bcfda2016-08-30 23:26:57 +0200152 let sstr = ''.escape(a:v, '*').'\>\s*[+\-*/]*'.fstr
Bram Moolenaar9964e462007-05-05 17:54:07 +0000153 let [lnum,lcol] = searchpos(sstr,'nb',stopline)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000154 if lnum != 0 && lcol != 0
Bram Moolenaar9964e462007-05-05 17:54:07 +0000155 let str = matchstr(getline(lnum),fstr,lcol)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000156 let str = substitute(str,'^=\s*','','')
Bram Moolenaar9964e462007-05-05 17:54:07 +0000157
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000158 call setpos('.',pos)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000159 if str == '"' || str == '''' || stridx(tolower(str), '%q[') != -1
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000160 return 'String'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000161 elseif str == '[' || stridx(str, '%w[') != -1
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000162 return 'Array'
163 elseif str == '{'
164 return 'Hash'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000165 elseif str == '/' || str == '%r{'
166 return 'Regexp'
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000167 elseif strlen(str) >= 4 && stridx(str,'..') != -1
168 return 'Range'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000169 elseif stridx(str, 'lambda') != -1 || str == '&'
170 return 'Proc'
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000171 elseif strlen(str) > 4
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000172 let l = stridx(str,'.')
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000173 return str[0:l-1]
174 end
175 return ''
176 endif
177 call setpos('.',pos)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000178 return ''
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000179endfunction
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000180
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000181"}}} vim-side support functions
182
Bram Moolenaar9964e462007-05-05 17:54:07 +0000183"{{{ vim-side completion function
184function! rubycomplete#Init()
185 execute "ruby VimRubyCompletion.preload_rails"
186endfunction
187
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000188function! rubycomplete#Complete(findstart, base)
189 "findstart = 1 when we need to get the text length
190 if a:findstart
191 let line = getline('.')
192 let idx = col('.')
193 while idx > 0
194 let idx -= 1
195 let c = line[idx-1]
196 if c =~ '\w'
197 continue
198 elseif ! c =~ '\.'
199 idx = -1
200 break
201 else
202 break
203 endif
204 endwhile
205
206 return idx
207 "findstart = 0 when we need to return the list of completions
208 else
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000209 let g:rubycomplete_completions = []
Bram Moolenaar9964e462007-05-05 17:54:07 +0000210 execute "ruby VimRubyCompletion.get_completions('" . a:base . "')"
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000211 return g:rubycomplete_completions
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000212 endif
213endfunction
Bram Moolenaar9964e462007-05-05 17:54:07 +0000214"}}} vim-side completion function
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000215
Bram Moolenaar9964e462007-05-05 17:54:07 +0000216"{{{ ruby-side code
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000217function! s:DefRuby()
218ruby << RUBYEOF
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000219# {{{ ruby completion
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000220
Bram Moolenaar9964e462007-05-05 17:54:07 +0000221begin
222 require 'rubygems' # let's assume this is safe...?
223rescue Exception
224 #ignore?
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000225end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000226class VimRubyCompletion
227# {{{ constants
228 @@debug = false
229 @@ReservedWords = [
230 "BEGIN", "END",
231 "alias", "and",
232 "begin", "break",
233 "case", "class",
234 "def", "defined", "do",
235 "else", "elsif", "end", "ensure",
236 "false", "for",
237 "if", "in",
238 "module",
239 "next", "nil", "not",
240 "or",
241 "redo", "rescue", "retry", "return",
242 "self", "super",
243 "then", "true",
244 "undef", "unless", "until",
245 "when", "while",
246 "yield",
247 ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000248
Bram Moolenaar9964e462007-05-05 17:54:07 +0000249 @@Operators = [ "%", "&", "*", "**", "+", "-", "/",
250 "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
251 "[]", "[]=", "^", ]
252# }}} constants
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000253
Bram Moolenaar9964e462007-05-05 17:54:07 +0000254# {{{ buffer analysis magic
255 def load_requires
256 buf = VIM::Buffer.current
257 enum = buf.line_number
258 nums = Range.new( 1, enum )
259 nums.each do |x|
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000260 ln = buf[x]
Bram Moolenaar9964e462007-05-05 17:54:07 +0000261 begin
262 eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln )
263 rescue Exception
264 #ignore?
265 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000266 end
267 end
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000268
Bram Moolenaar89bcfda2016-08-30 23:26:57 +0200269 def load_gems
270 fpath = VIM::evaluate("get(g:, 'rubycomplete_gemfile_path', 'Gemfile')")
271 return unless File.file?(fpath) && File.readable?(fpath)
272 want_bundler = VIM::evaluate("get(g:, 'rubycomplete_use_bundler')")
273 parse_file = !want_bundler
274 begin
275 require 'bundler'
276 Bundler.setup
277 Bundler.require
278 rescue Exception
279 parse_file = true
280 end
281 if parse_file
282 File.new(fpath).each_line do |line|
283 begin
284 require $1 if /\s*gem\s*['"]([^'"]+)/.match(line)
285 rescue Exception
286 end
287 end
288 end
289 end
290
Bram Moolenaar9964e462007-05-05 17:54:07 +0000291 def load_buffer_class(name)
292 dprint "load_buffer_class(%s) START" % name
293 classdef = get_buffer_entity(name, 's:GetBufferRubyClass("%s")')
294 return if classdef == nil
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000295
Bram Moolenaar9964e462007-05-05 17:54:07 +0000296 pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef )
297 load_buffer_class( $2 ) if pare != nil && $2 != name # load parent class if needed
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000298
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200299 mixre = /.*\n\s*(include|prepend)\s*(.*)\s*\n/.match( classdef )
Bram Moolenaar9964e462007-05-05 17:54:07 +0000300 load_buffer_module( $2 ) if mixre != nil && $2 != name # load mixins if needed
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000301
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000302 begin
Bram Moolenaar9964e462007-05-05 17:54:07 +0000303 eval classdef
304 rescue Exception
305 VIM::evaluate( "s:ErrMsg( 'Problem loading class \"%s\", was it already completed?' )" % name )
306 end
307 dprint "load_buffer_class(%s) END" % name
308 end
309
310 def load_buffer_module(name)
311 dprint "load_buffer_module(%s) START" % name
312 classdef = get_buffer_entity(name, 's:GetBufferRubyModule("%s")')
313 return if classdef == nil
314
315 begin
316 eval classdef
317 rescue Exception
318 VIM::evaluate( "s:ErrMsg( 'Problem loading module \"%s\", was it already completed?' )" % name )
319 end
320 dprint "load_buffer_module(%s) END" % name
321 end
322
323 def get_buffer_entity(name, vimfun)
324 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000325 return nil if loading_allowed.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000326 return nil if /(\"|\')+/.match( name )
327 buf = VIM::Buffer.current
328 nums = eval( VIM::evaluate( vimfun % name ) )
329 return nil if nums == nil
330 return nil if nums.min == nums.max && nums.min == 0
331
332 dprint "get_buffer_entity START"
333 visited = []
334 clscnt = 0
335 bufname = VIM::Buffer.current.name
336 classdef = ""
337 cur_line = VIM::Buffer.current.line_number
338 while (nums != nil && !(nums.min == 0 && nums.max == 0) )
339 dprint "visited: %s" % visited.to_s
340 break if visited.index( nums )
341 visited << nums
342
343 nums.each do |x|
344 if x != cur_line
345 next if x == 0
346 ln = buf[x]
347 if /^\s*(module|class|def|include)\s+/.match(ln)
348 clscnt += 1 if $1 == "class"
Bram Moolenaar1d689522010-05-28 20:54:39 +0200349 #dprint "\$1$1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000350 classdef += "%s\n" % ln
351 classdef += "end\n" if /def\s+/.match(ln)
352 dprint ln
353 end
354 end
355 end
356
357 nm = "%s(::.*)*\", %s, \"" % [ name, nums.last ]
358 nums = eval( VIM::evaluate( vimfun % nm ) )
359 dprint "nm: \"%s\"" % nm
360 dprint "vimfun: %s" % (vimfun % nm)
361 dprint "got nums: %s" % nums.to_s
362 end
363 if classdef.length > 1
364 classdef += "end\n"*clscnt
365 # classdef = "class %s\n%s\nend\n" % [ bufname.gsub( /\/|\\/, "_" ), classdef ]
366 end
367
368 dprint "get_buffer_entity END"
369 dprint "classdef====start"
370 lns = classdef.split( "\n" )
371 lns.each { |x| dprint x }
372 dprint "classdef====end"
373 return classdef
374 end
375
376 def get_var_type( receiver )
377 if /(\"|\')+/.match( receiver )
378 "String"
379 else
380 VIM::evaluate("s:GetRubyVarType('%s')" % receiver)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000381 end
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000382 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000383
Bram Moolenaar9964e462007-05-05 17:54:07 +0000384 def dprint( txt )
385 print txt if @@debug
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000386 end
387
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200388 def escape_vim_singlequote_string(str)
389 str.to_s.gsub(/'/,"\\'")
390 end
391
Bram Moolenaar9964e462007-05-05 17:54:07 +0000392 def get_buffer_entity_list( type )
393 # this will be a little expensive.
394 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
395 allow_aggressive_load = VIM::evaluate("exists('g:rubycomplete_classes_in_global') && g:rubycomplete_classes_in_global")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000396 return [] if allow_aggressive_load.to_i.zero? || loading_allowed.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000397
398 buf = VIM::Buffer.current
399 eob = buf.length
400 ret = []
401 rg = 1..eob
402 re = eval( "/^\s*%s\s*([A-Za-z0-9_:-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/" % type )
403
404 rg.each do |x|
405 if re.match( buf[x] )
406 next if type == "def" && eval( VIM::evaluate("s:IsPosInClassDef(%s)" % x) ) != nil
407 ret.push $1
408 end
409 end
410
411 return ret
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000412 end
413
Bram Moolenaar9964e462007-05-05 17:54:07 +0000414 def get_buffer_modules
415 return get_buffer_entity_list( "modules" )
416 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000417
Bram Moolenaar9964e462007-05-05 17:54:07 +0000418 def get_buffer_methods
419 return get_buffer_entity_list( "def" )
420 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000421
Bram Moolenaar9964e462007-05-05 17:54:07 +0000422 def get_buffer_classes
423 return get_buffer_entity_list( "class" )
424 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000425
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000426
Bram Moolenaar9964e462007-05-05 17:54:07 +0000427 def load_rails
428 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000429 return if allow_rails.to_i.zero?
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000430
Bram Moolenaar9964e462007-05-05 17:54:07 +0000431 buf_path = VIM::evaluate('expand("%:p")')
432 file_name = VIM::evaluate('expand("%:t")')
433 vim_dir = VIM::evaluate('getcwd()')
434 file_dir = buf_path.gsub( file_name, '' )
435 file_dir.gsub!( /\\/, "/" )
436 vim_dir.gsub!( /\\/, "/" )
437 vim_dir << "/"
438 dirs = [ vim_dir, file_dir ]
439 sdirs = [ "", "./", "../", "../../", "../../../", "../../../../" ]
440 rails_base = nil
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000441
Bram Moolenaar9964e462007-05-05 17:54:07 +0000442 dirs.each do |dir|
443 sdirs.each do |sub|
444 trail = "%s%s" % [ dir, sub ]
445 tcfg = "%sconfig" % trail
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000446
Bram Moolenaar9964e462007-05-05 17:54:07 +0000447 if File.exists?( tcfg )
448 rails_base = trail
449 break
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000450 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000451 end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000452 break if rails_base
453 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000454
Bram Moolenaar9964e462007-05-05 17:54:07 +0000455 return if rails_base == nil
456 $:.push rails_base unless $:.index( rails_base )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000457
Bram Moolenaar9964e462007-05-05 17:54:07 +0000458 rails_config = rails_base + "config/"
459 rails_lib = rails_base + "lib/"
460 $:.push rails_config unless $:.index( rails_config )
461 $:.push rails_lib unless $:.index( rails_lib )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000462
Bram Moolenaar9964e462007-05-05 17:54:07 +0000463 bootfile = rails_config + "boot.rb"
464 envfile = rails_config + "environment.rb"
465 if File.exists?( bootfile ) && File.exists?( envfile )
466 begin
467 require bootfile
468 require envfile
469 begin
470 require 'console_app'
471 require 'console_with_helpers'
472 rescue Exception
473 dprint "Rails 1.1+ Error %s" % $!
474 # assume 1.0
475 end
476 #eval( "Rails::Initializer.run" ) #not necessary?
477 VIM::command('let s:rubycomplete_rails_loaded = 1')
478 dprint "rails loaded"
479 rescue Exception
480 dprint "Rails Error %s" % $!
481 VIM::evaluate( "s:ErrMsg('Error loading rails environment')" )
482 end
483 end
484 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000485
Bram Moolenaar9964e462007-05-05 17:54:07 +0000486 def get_rails_helpers
487 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
488 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000489 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000490
Bram Moolenaar9964e462007-05-05 17:54:07 +0000491 buf_path = VIM::evaluate('expand("%:p")')
492 buf_path.gsub!( /\\/, "/" )
493 path_elm = buf_path.split( "/" )
494 dprint "buf_path: %s" % buf_path
495 types = [ "app", "db", "lib", "test", "components", "script" ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000496
Bram Moolenaar9964e462007-05-05 17:54:07 +0000497 i = nil
498 ret = []
499 type = nil
500 types.each do |t|
501 i = path_elm.index( t )
502 break if i
503 end
504 type = path_elm[i]
505 type.downcase!
506
507 dprint "type: %s" % type
508 case type
509 when "app"
510 i += 1
511 subtype = path_elm[i]
512 subtype.downcase!
513
514 dprint "subtype: %s" % subtype
515 case subtype
516 when "views"
517 ret += ActionView::Base.instance_methods
518 ret += ActionView::Base.methods
519 when "controllers"
520 ret += ActionController::Base.instance_methods
521 ret += ActionController::Base.methods
522 when "models"
523 ret += ActiveRecord::Base.instance_methods
524 ret += ActiveRecord::Base.methods
525 end
526
527 when "db"
528 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods
529 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods
530 end
531
532
533 return ret
534 end
535
536 def add_rails_columns( cls )
537 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
538 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000539 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000540
541 begin
542 eval( "#{cls}.establish_connection" )
543 return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" )
544 col = eval( "#{cls}.column_names" )
545 return col if col
546 rescue
547 dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ]
548 return []
549 end
550 return []
551 end
552
553 def clean_sel(sel, msg)
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200554 ret = sel.reject{|x|x.nil?}.uniq
555 ret = ret.grep(/^#{Regexp.quote(msg)}/) if msg != nil
556 ret
Bram Moolenaar9964e462007-05-05 17:54:07 +0000557 end
558
559 def get_rails_view_methods
560 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
561 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000562 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000563
564 buf_path = VIM::evaluate('expand("%:p")')
565 buf_path.gsub!( /\\/, "/" )
566 pelm = buf_path.split( "/" )
567 idx = pelm.index( "views" )
568
569 return [] unless idx
570 idx += 1
571
572 clspl = pelm[idx].camelize.pluralize
573 cls = clspl.singularize
574
575 ret = []
576 begin
577 ret += eval( "#{cls}.instance_methods" )
578 ret += eval( "#{clspl}Helper.instance_methods" )
579 rescue Exception
580 dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ]
581 end
582
583 return ret
584 end
585# }}} buffer analysis magic
586
587# {{{ main completion code
588 def self.preload_rails
589 a = VimRubyCompletion.new
590 require 'Thread'
591 Thread.new(a) do |b|
592 begin
593 b.load_rails
594 rescue
595 end
596 end
597 a.load_rails
598 rescue
599 end
600
601 def self.get_completions(base)
602 b = VimRubyCompletion.new
603 b.get_completions base
604 end
605
606 def get_completions(base)
607 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000608 if loading_allowed.to_i == 1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000609 load_requires
610 load_rails
611 end
612
Bram Moolenaar89bcfda2016-08-30 23:26:57 +0200613 want_gems = VIM::evaluate("get(g:, 'rubycomplete_load_gemfile')")
614 load_gems unless want_gems.to_i.zero?
615
616
Bram Moolenaar9964e462007-05-05 17:54:07 +0000617 input = VIM::Buffer.current.line
618 cpos = VIM::Window.current.cursor[1] - 1
619 input = input[0..cpos]
620 input += base
621 input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters
622 input.sub!(/self\./, '')
623 input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '')
624
625 dprint 'input %s' % input
626 message = nil
627 receiver = nil
628 methods = []
629 variables = []
630 classes = []
631 constants = []
632
633 case input
634 when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000635 receiver = $1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000636 message = Regexp.quote($2)
637 methods = Regexp.instance_methods(true)
638
639 when /^([^\]]*\])\.([^.]*)$/ # Array
640 receiver = $1
641 message = Regexp.quote($2)
642 methods = Array.instance_methods(true)
643
644 when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash
645 receiver = $1
646 message = Regexp.quote($2)
647 methods = Proc.instance_methods(true) | Hash.instance_methods(true)
648
649 when /^(:[^:.]*)$/ # Symbol
650 dprint "symbol"
651 if Symbol.respond_to?(:all_symbols)
652 receiver = $1
653 message = $1.sub( /:/, '' )
654 methods = Symbol.all_symbols.collect{|s| s.id2name}
655 methods.delete_if { |c| c.match( /'/ ) }
656 end
657
658 when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods
659 dprint "const or cls"
660 receiver = $1
661 methods = Object.constants
662 methods.grep(/^#{receiver}/).collect{|e| "::" + e}
663
Bram Moolenaar1d689522010-05-28 20:54:39 +0200664 when /^(((::)?[A-Z][^:.\(]*)+?)::?([^:.]*)$/ # Constant or class methods
Bram Moolenaar9964e462007-05-05 17:54:07 +0000665 receiver = $1
666 message = Regexp.quote($4)
667 dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000668 load_buffer_class( receiver )
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000669 begin
Bram Moolenaar9964e462007-05-05 17:54:07 +0000670 classes = eval("#{receiver}.constants")
671 #methods = eval("#{receiver}.methods")
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000672 rescue Exception
Bram Moolenaar9964e462007-05-05 17:54:07 +0000673 dprint "exception: %s" % $!
674 methods = []
675 end
676 methods.grep(/^#{message}/).collect{|e| receiver + "::" + e}
677
678 when /^(:[^:.]+)\.([^.]*)$/ # Symbol
679 dprint "symbol"
680 receiver = $1
681 message = Regexp.quote($2)
682 methods = Symbol.instance_methods(true)
683
684 when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric
685 dprint "numeric"
686 receiver = $1
687 message = Regexp.quote($4)
688 begin
689 methods = eval(receiver).methods
690 rescue Exception
691 methods = []
692 end
693
694 when /^(\$[^.]*)$/ #global
695 dprint "global"
696 methods = global_variables.grep(Regexp.new(Regexp.quote($1)))
697
Bram Moolenaar1d689522010-05-28 20:54:39 +0200698 when /^((\.?[^.]+)+?)\.([^.]*)$/ # variable
Bram Moolenaar9964e462007-05-05 17:54:07 +0000699 dprint "variable"
700 receiver = $1
701 message = Regexp.quote($3)
702 load_buffer_class( receiver )
703
704 cv = eval("self.class.constants")
705 vartype = get_var_type( receiver )
706 dprint "vartype: %s" % vartype
Bram Moolenaar89bcfda2016-08-30 23:26:57 +0200707
708 invalid_vartype = ['', "gets"]
709 if !invalid_vartype.include?(vartype)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000710 load_buffer_class( vartype )
711
712 begin
713 methods = eval("#{vartype}.instance_methods")
714 variables = eval("#{vartype}.instance_variables")
715 rescue Exception
716 dprint "load_buffer_class err: %s" % $!
717 end
718 elsif (cv).include?(receiver)
719 # foo.func and foo is local var.
720 methods = eval("#{receiver}.methods")
721 vartype = receiver
722 elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
723 vartype = receiver
724 # Foo::Bar.func
725 begin
726 methods = eval("#{receiver}.methods")
727 rescue Exception
728 end
729 else
730 # func1.func2
731 ObjectSpace.each_object(Module){|m|
732 next if m.name != "IRB::Context" and
733 /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
734 methods.concat m.instance_methods(false)
735 }
736 end
Bram Moolenaar89bcfda2016-08-30 23:26:57 +0200737 variables += add_rails_columns( "#{vartype}" ) if vartype && !invalid_vartype.include?(vartype)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000738
739 when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/
740 message = $1
741 methods = Range.instance_methods(true)
742
743 when /^\.([^.]*)$/ # unknown(maybe String)
744 message = Regexp.quote($1)
745 methods = String.instance_methods(true)
746
747 else
748 dprint "default/other"
749 inclass = eval( VIM::evaluate("s:IsInClassDef()") )
750
751 if inclass != nil
752 dprint "inclass"
753 classdef = "%s\n" % VIM::Buffer.current[ inclass.min ]
754 found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef )
755
756 if found != nil
757 receiver = $1
758 message = input
759 load_buffer_class( receiver )
760 begin
761 methods = eval( "#{receiver}.instance_methods" )
762 variables += add_rails_columns( "#{receiver}" )
763 rescue Exception
764 found = nil
765 end
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000766 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000767 end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000768
769 if inclass == nil || found == nil
770 dprint "inclass == nil"
771 methods = get_buffer_methods
772 methods += get_rails_view_methods
773
774 cls_const = Class.constants
775 constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) }
776 classes = eval("self.class.constants") - constants
777 classes += get_buffer_classes
778 classes += get_buffer_modules
779
780 include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace")
781 ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1"
782 message = receiver = input
783 end
784
785 methods += get_rails_helpers
786 methods += Kernel.public_methods
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000787 end
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000788
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000789
Bram Moolenaar9964e462007-05-05 17:54:07 +0000790 include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object")
791 methods = clean_sel( methods, message )
792 methods = (methods-Object.instance_methods) if include_object == "0"
793 rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods
794 methods = (methods-rbcmeth)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000795
Bram Moolenaar9964e462007-05-05 17:54:07 +0000796 variables = clean_sel( variables, message )
797 classes = clean_sel( classes, message ) - ["VimRubyCompletion"]
798 constants = clean_sel( constants, message )
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000799
Bram Moolenaar9964e462007-05-05 17:54:07 +0000800 valid = []
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200801 valid += methods.collect { |m| { :name => m.to_s, :type => 'm' } }
802 valid += variables.collect { |v| { :name => v.to_s, :type => 'v' } }
803 valid += classes.collect { |c| { :name => c.to_s, :type => 't' } }
804 valid += constants.collect { |d| { :name => d.to_s, :type => 'd' } }
Bram Moolenaar9964e462007-05-05 17:54:07 +0000805 valid.sort! { |x,y| x[:name] <=> y[:name] }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000806
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000807 outp = ""
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000808
Bram Moolenaar9964e462007-05-05 17:54:07 +0000809 rg = 0..valid.length
810 rg.step(150) do |x|
811 stpos = 0+x
812 enpos = 150+x
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200813 valid[stpos..enpos].each { |c| outp += "{'word':'%s','item':'%s','kind':'%s'}," % [ c[:name], c[:name], c[:type] ].map{|x|escape_vim_singlequote_string(x)} }
Bram Moolenaar9964e462007-05-05 17:54:07 +0000814 outp.sub!(/,$/, '')
815
816 VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp)
817 outp = ""
818 end
819 end
820# }}} main completion code
821
822end # VimRubyCompletion
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000823# }}} ruby completion
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000824RUBYEOF
825endfunction
826
Bram Moolenaar9964e462007-05-05 17:54:07 +0000827let s:rubycomplete_rails_loaded = 0
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000828
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000829call s:DefRuby()
Bram Moolenaar9964e462007-05-05 17:54:07 +0000830"}}} ruby-side code
831
832
833" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl: