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