blob: e1064c8a58d6ba62e133bcd6ff29de274dfdb0cc [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
96 let crex = '^\s*\<' . a:type . '\>\s*\<' . a:name . '\>\s*\(<\s*.*\s*\)\?'
97 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\|&\)'
152 let sstr = ''.a:v.'\>\s*[+\-*/]*'.fstr
153 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 Moolenaar9964e462007-05-05 17:54:07 +0000269 def load_buffer_class(name)
270 dprint "load_buffer_class(%s) START" % name
271 classdef = get_buffer_entity(name, 's:GetBufferRubyClass("%s")')
272 return if classdef == nil
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000273
Bram Moolenaar9964e462007-05-05 17:54:07 +0000274 pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef )
275 load_buffer_class( $2 ) if pare != nil && $2 != name # load parent class if needed
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000276
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200277 mixre = /.*\n\s*(include|prepend)\s*(.*)\s*\n/.match( classdef )
Bram Moolenaar9964e462007-05-05 17:54:07 +0000278 load_buffer_module( $2 ) if mixre != nil && $2 != name # load mixins if needed
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000279
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000280 begin
Bram Moolenaar9964e462007-05-05 17:54:07 +0000281 eval classdef
282 rescue Exception
283 VIM::evaluate( "s:ErrMsg( 'Problem loading class \"%s\", was it already completed?' )" % name )
284 end
285 dprint "load_buffer_class(%s) END" % name
286 end
287
288 def load_buffer_module(name)
289 dprint "load_buffer_module(%s) START" % name
290 classdef = get_buffer_entity(name, 's:GetBufferRubyModule("%s")')
291 return if classdef == nil
292
293 begin
294 eval classdef
295 rescue Exception
296 VIM::evaluate( "s:ErrMsg( 'Problem loading module \"%s\", was it already completed?' )" % name )
297 end
298 dprint "load_buffer_module(%s) END" % name
299 end
300
301 def get_buffer_entity(name, vimfun)
302 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000303 return nil if loading_allowed.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000304 return nil if /(\"|\')+/.match( name )
305 buf = VIM::Buffer.current
306 nums = eval( VIM::evaluate( vimfun % name ) )
307 return nil if nums == nil
308 return nil if nums.min == nums.max && nums.min == 0
309
310 dprint "get_buffer_entity START"
311 visited = []
312 clscnt = 0
313 bufname = VIM::Buffer.current.name
314 classdef = ""
315 cur_line = VIM::Buffer.current.line_number
316 while (nums != nil && !(nums.min == 0 && nums.max == 0) )
317 dprint "visited: %s" % visited.to_s
318 break if visited.index( nums )
319 visited << nums
320
321 nums.each do |x|
322 if x != cur_line
323 next if x == 0
324 ln = buf[x]
325 if /^\s*(module|class|def|include)\s+/.match(ln)
326 clscnt += 1 if $1 == "class"
Bram Moolenaar1d689522010-05-28 20:54:39 +0200327 #dprint "\$1$1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000328 classdef += "%s\n" % ln
329 classdef += "end\n" if /def\s+/.match(ln)
330 dprint ln
331 end
332 end
333 end
334
335 nm = "%s(::.*)*\", %s, \"" % [ name, nums.last ]
336 nums = eval( VIM::evaluate( vimfun % nm ) )
337 dprint "nm: \"%s\"" % nm
338 dprint "vimfun: %s" % (vimfun % nm)
339 dprint "got nums: %s" % nums.to_s
340 end
341 if classdef.length > 1
342 classdef += "end\n"*clscnt
343 # classdef = "class %s\n%s\nend\n" % [ bufname.gsub( /\/|\\/, "_" ), classdef ]
344 end
345
346 dprint "get_buffer_entity END"
347 dprint "classdef====start"
348 lns = classdef.split( "\n" )
349 lns.each { |x| dprint x }
350 dprint "classdef====end"
351 return classdef
352 end
353
354 def get_var_type( receiver )
355 if /(\"|\')+/.match( receiver )
356 "String"
357 else
358 VIM::evaluate("s:GetRubyVarType('%s')" % receiver)
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000359 end
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000360 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000361
Bram Moolenaar9964e462007-05-05 17:54:07 +0000362 def dprint( txt )
363 print txt if @@debug
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000364 end
365
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200366 def escape_vim_singlequote_string(str)
367 str.to_s.gsub(/'/,"\\'")
368 end
369
Bram Moolenaar9964e462007-05-05 17:54:07 +0000370 def get_buffer_entity_list( type )
371 # this will be a little expensive.
372 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
373 allow_aggressive_load = VIM::evaluate("exists('g:rubycomplete_classes_in_global') && g:rubycomplete_classes_in_global")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000374 return [] if allow_aggressive_load.to_i.zero? || loading_allowed.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000375
376 buf = VIM::Buffer.current
377 eob = buf.length
378 ret = []
379 rg = 1..eob
380 re = eval( "/^\s*%s\s*([A-Za-z0-9_:-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/" % type )
381
382 rg.each do |x|
383 if re.match( buf[x] )
384 next if type == "def" && eval( VIM::evaluate("s:IsPosInClassDef(%s)" % x) ) != nil
385 ret.push $1
386 end
387 end
388
389 return ret
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000390 end
391
Bram Moolenaar9964e462007-05-05 17:54:07 +0000392 def get_buffer_modules
393 return get_buffer_entity_list( "modules" )
394 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000395
Bram Moolenaar9964e462007-05-05 17:54:07 +0000396 def get_buffer_methods
397 return get_buffer_entity_list( "def" )
398 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000399
Bram Moolenaar9964e462007-05-05 17:54:07 +0000400 def get_buffer_classes
401 return get_buffer_entity_list( "class" )
402 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000403
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000404
Bram Moolenaar9964e462007-05-05 17:54:07 +0000405 def load_rails
406 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000407 return if allow_rails.to_i.zero?
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000408
Bram Moolenaar9964e462007-05-05 17:54:07 +0000409 buf_path = VIM::evaluate('expand("%:p")')
410 file_name = VIM::evaluate('expand("%:t")')
411 vim_dir = VIM::evaluate('getcwd()')
412 file_dir = buf_path.gsub( file_name, '' )
413 file_dir.gsub!( /\\/, "/" )
414 vim_dir.gsub!( /\\/, "/" )
415 vim_dir << "/"
416 dirs = [ vim_dir, file_dir ]
417 sdirs = [ "", "./", "../", "../../", "../../../", "../../../../" ]
418 rails_base = nil
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000419
Bram Moolenaar9964e462007-05-05 17:54:07 +0000420 dirs.each do |dir|
421 sdirs.each do |sub|
422 trail = "%s%s" % [ dir, sub ]
423 tcfg = "%sconfig" % trail
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000424
Bram Moolenaar9964e462007-05-05 17:54:07 +0000425 if File.exists?( tcfg )
426 rails_base = trail
427 break
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000428 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000429 end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000430 break if rails_base
431 end
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000432
Bram Moolenaar9964e462007-05-05 17:54:07 +0000433 return if rails_base == nil
434 $:.push rails_base unless $:.index( rails_base )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000435
Bram Moolenaar9964e462007-05-05 17:54:07 +0000436 rails_config = rails_base + "config/"
437 rails_lib = rails_base + "lib/"
438 $:.push rails_config unless $:.index( rails_config )
439 $:.push rails_lib unless $:.index( rails_lib )
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000440
Bram Moolenaar9964e462007-05-05 17:54:07 +0000441 bootfile = rails_config + "boot.rb"
442 envfile = rails_config + "environment.rb"
443 if File.exists?( bootfile ) && File.exists?( envfile )
444 begin
445 require bootfile
446 require envfile
447 begin
448 require 'console_app'
449 require 'console_with_helpers'
450 rescue Exception
451 dprint "Rails 1.1+ Error %s" % $!
452 # assume 1.0
453 end
454 #eval( "Rails::Initializer.run" ) #not necessary?
455 VIM::command('let s:rubycomplete_rails_loaded = 1')
456 dprint "rails loaded"
457 rescue Exception
458 dprint "Rails Error %s" % $!
459 VIM::evaluate( "s:ErrMsg('Error loading rails environment')" )
460 end
461 end
462 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000463
Bram Moolenaar9964e462007-05-05 17:54:07 +0000464 def get_rails_helpers
465 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
466 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000467 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000468
Bram Moolenaar9964e462007-05-05 17:54:07 +0000469 buf_path = VIM::evaluate('expand("%:p")')
470 buf_path.gsub!( /\\/, "/" )
471 path_elm = buf_path.split( "/" )
472 dprint "buf_path: %s" % buf_path
473 types = [ "app", "db", "lib", "test", "components", "script" ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000474
Bram Moolenaar9964e462007-05-05 17:54:07 +0000475 i = nil
476 ret = []
477 type = nil
478 types.each do |t|
479 i = path_elm.index( t )
480 break if i
481 end
482 type = path_elm[i]
483 type.downcase!
484
485 dprint "type: %s" % type
486 case type
487 when "app"
488 i += 1
489 subtype = path_elm[i]
490 subtype.downcase!
491
492 dprint "subtype: %s" % subtype
493 case subtype
494 when "views"
495 ret += ActionView::Base.instance_methods
496 ret += ActionView::Base.methods
497 when "controllers"
498 ret += ActionController::Base.instance_methods
499 ret += ActionController::Base.methods
500 when "models"
501 ret += ActiveRecord::Base.instance_methods
502 ret += ActiveRecord::Base.methods
503 end
504
505 when "db"
506 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods
507 ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods
508 end
509
510
511 return ret
512 end
513
514 def add_rails_columns( cls )
515 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
516 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000517 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000518
519 begin
520 eval( "#{cls}.establish_connection" )
521 return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" )
522 col = eval( "#{cls}.column_names" )
523 return col if col
524 rescue
525 dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ]
526 return []
527 end
528 return []
529 end
530
531 def clean_sel(sel, msg)
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200532 ret = sel.reject{|x|x.nil?}.uniq
533 ret = ret.grep(/^#{Regexp.quote(msg)}/) if msg != nil
534 ret
Bram Moolenaar9964e462007-05-05 17:54:07 +0000535 end
536
537 def get_rails_view_methods
538 allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
539 rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000540 return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000541
542 buf_path = VIM::evaluate('expand("%:p")')
543 buf_path.gsub!( /\\/, "/" )
544 pelm = buf_path.split( "/" )
545 idx = pelm.index( "views" )
546
547 return [] unless idx
548 idx += 1
549
550 clspl = pelm[idx].camelize.pluralize
551 cls = clspl.singularize
552
553 ret = []
554 begin
555 ret += eval( "#{cls}.instance_methods" )
556 ret += eval( "#{clspl}Helper.instance_methods" )
557 rescue Exception
558 dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ]
559 end
560
561 return ret
562 end
563# }}} buffer analysis magic
564
565# {{{ main completion code
566 def self.preload_rails
567 a = VimRubyCompletion.new
568 require 'Thread'
569 Thread.new(a) do |b|
570 begin
571 b.load_rails
572 rescue
573 end
574 end
575 a.load_rails
576 rescue
577 end
578
579 def self.get_completions(base)
580 b = VimRubyCompletion.new
581 b.get_completions base
582 end
583
584 def get_completions(base)
585 loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000586 if loading_allowed.to_i == 1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000587 load_requires
588 load_rails
589 end
590
591 input = VIM::Buffer.current.line
592 cpos = VIM::Window.current.cursor[1] - 1
593 input = input[0..cpos]
594 input += base
595 input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters
596 input.sub!(/self\./, '')
597 input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '')
598
599 dprint 'input %s' % input
600 message = nil
601 receiver = nil
602 methods = []
603 variables = []
604 classes = []
605 constants = []
606
607 case input
608 when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000609 receiver = $1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000610 message = Regexp.quote($2)
611 methods = Regexp.instance_methods(true)
612
613 when /^([^\]]*\])\.([^.]*)$/ # Array
614 receiver = $1
615 message = Regexp.quote($2)
616 methods = Array.instance_methods(true)
617
618 when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash
619 receiver = $1
620 message = Regexp.quote($2)
621 methods = Proc.instance_methods(true) | Hash.instance_methods(true)
622
623 when /^(:[^:.]*)$/ # Symbol
624 dprint "symbol"
625 if Symbol.respond_to?(:all_symbols)
626 receiver = $1
627 message = $1.sub( /:/, '' )
628 methods = Symbol.all_symbols.collect{|s| s.id2name}
629 methods.delete_if { |c| c.match( /'/ ) }
630 end
631
632 when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods
633 dprint "const or cls"
634 receiver = $1
635 methods = Object.constants
636 methods.grep(/^#{receiver}/).collect{|e| "::" + e}
637
Bram Moolenaar1d689522010-05-28 20:54:39 +0200638 when /^(((::)?[A-Z][^:.\(]*)+?)::?([^:.]*)$/ # Constant or class methods
Bram Moolenaar9964e462007-05-05 17:54:07 +0000639 receiver = $1
640 message = Regexp.quote($4)
641 dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000642 load_buffer_class( receiver )
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000643 begin
Bram Moolenaar9964e462007-05-05 17:54:07 +0000644 classes = eval("#{receiver}.constants")
645 #methods = eval("#{receiver}.methods")
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000646 rescue Exception
Bram Moolenaar9964e462007-05-05 17:54:07 +0000647 dprint "exception: %s" % $!
648 methods = []
649 end
650 methods.grep(/^#{message}/).collect{|e| receiver + "::" + e}
651
652 when /^(:[^:.]+)\.([^.]*)$/ # Symbol
653 dprint "symbol"
654 receiver = $1
655 message = Regexp.quote($2)
656 methods = Symbol.instance_methods(true)
657
658 when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric
659 dprint "numeric"
660 receiver = $1
661 message = Regexp.quote($4)
662 begin
663 methods = eval(receiver).methods
664 rescue Exception
665 methods = []
666 end
667
668 when /^(\$[^.]*)$/ #global
669 dprint "global"
670 methods = global_variables.grep(Regexp.new(Regexp.quote($1)))
671
Bram Moolenaar1d689522010-05-28 20:54:39 +0200672 when /^((\.?[^.]+)+?)\.([^.]*)$/ # variable
Bram Moolenaar9964e462007-05-05 17:54:07 +0000673 dprint "variable"
674 receiver = $1
675 message = Regexp.quote($3)
676 load_buffer_class( receiver )
677
678 cv = eval("self.class.constants")
679 vartype = get_var_type( receiver )
680 dprint "vartype: %s" % vartype
681 if vartype != ''
682 load_buffer_class( vartype )
683
684 begin
685 methods = eval("#{vartype}.instance_methods")
686 variables = eval("#{vartype}.instance_variables")
687 rescue Exception
688 dprint "load_buffer_class err: %s" % $!
689 end
690 elsif (cv).include?(receiver)
691 # foo.func and foo is local var.
692 methods = eval("#{receiver}.methods")
693 vartype = receiver
694 elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
695 vartype = receiver
696 # Foo::Bar.func
697 begin
698 methods = eval("#{receiver}.methods")
699 rescue Exception
700 end
701 else
702 # func1.func2
703 ObjectSpace.each_object(Module){|m|
704 next if m.name != "IRB::Context" and
705 /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
706 methods.concat m.instance_methods(false)
707 }
708 end
709 variables += add_rails_columns( "#{vartype}" ) if vartype && vartype.length > 0
710
711 when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/
712 message = $1
713 methods = Range.instance_methods(true)
714
715 when /^\.([^.]*)$/ # unknown(maybe String)
716 message = Regexp.quote($1)
717 methods = String.instance_methods(true)
718
719 else
720 dprint "default/other"
721 inclass = eval( VIM::evaluate("s:IsInClassDef()") )
722
723 if inclass != nil
724 dprint "inclass"
725 classdef = "%s\n" % VIM::Buffer.current[ inclass.min ]
726 found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef )
727
728 if found != nil
729 receiver = $1
730 message = input
731 load_buffer_class( receiver )
732 begin
733 methods = eval( "#{receiver}.instance_methods" )
734 variables += add_rails_columns( "#{receiver}" )
735 rescue Exception
736 found = nil
737 end
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000738 end
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000739 end
Bram Moolenaar9964e462007-05-05 17:54:07 +0000740
741 if inclass == nil || found == nil
742 dprint "inclass == nil"
743 methods = get_buffer_methods
744 methods += get_rails_view_methods
745
746 cls_const = Class.constants
747 constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) }
748 classes = eval("self.class.constants") - constants
749 classes += get_buffer_classes
750 classes += get_buffer_modules
751
752 include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace")
753 ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1"
754 message = receiver = input
755 end
756
757 methods += get_rails_helpers
758 methods += Kernel.public_methods
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000759 end
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000760
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000761
Bram Moolenaar9964e462007-05-05 17:54:07 +0000762 include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object")
763 methods = clean_sel( methods, message )
764 methods = (methods-Object.instance_methods) if include_object == "0"
765 rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods
766 methods = (methods-rbcmeth)
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000767
Bram Moolenaar9964e462007-05-05 17:54:07 +0000768 variables = clean_sel( variables, message )
769 classes = clean_sel( classes, message ) - ["VimRubyCompletion"]
770 constants = clean_sel( constants, message )
Bram Moolenaard8fc5c02006-04-29 21:55:22 +0000771
Bram Moolenaar9964e462007-05-05 17:54:07 +0000772 valid = []
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200773 valid += methods.collect { |m| { :name => m.to_s, :type => 'm' } }
774 valid += variables.collect { |v| { :name => v.to_s, :type => 'v' } }
775 valid += classes.collect { |c| { :name => c.to_s, :type => 't' } }
776 valid += constants.collect { |d| { :name => d.to_s, :type => 'd' } }
Bram Moolenaar9964e462007-05-05 17:54:07 +0000777 valid.sort! { |x,y| x[:name] <=> y[:name] }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000778
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000779 outp = ""
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000780
Bram Moolenaar9964e462007-05-05 17:54:07 +0000781 rg = 0..valid.length
782 rg.step(150) do |x|
783 stpos = 0+x
784 enpos = 150+x
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200785 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 +0000786 outp.sub!(/,$/, '')
787
788 VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp)
789 outp = ""
790 end
791 end
792# }}} main completion code
793
794end # VimRubyCompletion
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000795# }}} ruby completion
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000796RUBYEOF
797endfunction
798
Bram Moolenaar9964e462007-05-05 17:54:07 +0000799let s:rubycomplete_rails_loaded = 0
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000800
Bram Moolenaarc6249bb2006-04-15 20:25:09 +0000801call s:DefRuby()
Bram Moolenaar9964e462007-05-05 17:54:07 +0000802"}}} ruby-side code
803
804
805" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl: