1c6249bb2SBram Moolenaar" Vim completion script
2c6249bb2SBram Moolenaar" Language:		Ruby
3fc1421ebSBram Moolenaar" Maintainer:		Mark Guzman <[email protected]>
4ec7944aaSBram Moolenaar" URL:			https://github.com/vim-ruby/vim-ruby
5c6249bb2SBram Moolenaar" Release Coordinator:	Doug Kearns <[email protected]>
6*d09091d4SBram Moolenaar" Last Change:		2019 Jan 06
7c6249bb2SBram Moolenaar" ----------------------------------------------------------------------------
8c6249bb2SBram Moolenaar"
9c6249bb2SBram Moolenaar" Ruby IRB/Complete author: Keiju ISHITSUKA([email protected])
10c6249bb2SBram Moolenaar" ----------------------------------------------------------------------------
11c6249bb2SBram Moolenaar
12eb3593b3SBram Moolenaar" {{{ requirement checks
13ec7944aaSBram Moolenaar
14ec7944aaSBram Moolenaarfunction! s:ErrMsg(msg)
15ec7944aaSBram Moolenaar    echohl ErrorMsg
16ec7944aaSBram Moolenaar    echo a:msg
17ec7944aaSBram Moolenaar    echohl None
18ec7944aaSBram Moolenaarendfunction
19ec7944aaSBram Moolenaar
20c6249bb2SBram Moolenaarif !has('ruby')
21ec7944aaSBram Moolenaar    call s:ErrMsg( "Error: Rubycomplete requires vim compiled with +ruby" )
22ec7944aaSBram Moolenaar    call s:ErrMsg( "Error: falling back to syntax completion" )
239964e468SBram Moolenaar    " lets fall back to syntax completion
249964e468SBram Moolenaar    setlocal omnifunc=syntaxcomplete#Complete
25c6249bb2SBram Moolenaar    finish
26c6249bb2SBram Moolenaarendif
27c6249bb2SBram Moolenaar
28c6249bb2SBram Moolenaarif version < 700
29ec7944aaSBram Moolenaar    call s:ErrMsg( "Error: Required vim >= 7.0" )
30c6249bb2SBram Moolenaar    finish
31c6249bb2SBram Moolenaarendif
32eb3593b3SBram Moolenaar" }}} requirement checks
33c6249bb2SBram Moolenaar
349964e468SBram Moolenaar" {{{ configuration failsafe initialization
35eb3593b3SBram Moolenaarif !exists("g:rubycomplete_rails")
36eb3593b3SBram Moolenaar    let g:rubycomplete_rails = 0
37eb3593b3SBram Moolenaarendif
38fc1421ebSBram Moolenaar
39eb3593b3SBram Moolenaarif !exists("g:rubycomplete_classes_in_global")
40eb3593b3SBram Moolenaar    let g:rubycomplete_classes_in_global = 0
41eb3593b3SBram Moolenaarendif
42eb3593b3SBram Moolenaar
439964e468SBram Moolenaarif !exists("g:rubycomplete_buffer_loading")
44a7241f5fSBram Moolenaar    let g:rubycomplete_buffer_loading = 0
459964e468SBram Moolenaarendif
469964e468SBram Moolenaar
479964e468SBram Moolenaarif !exists("g:rubycomplete_include_object")
489964e468SBram Moolenaar    let g:rubycomplete_include_object = 0
499964e468SBram Moolenaarendif
509964e468SBram Moolenaar
519964e468SBram Moolenaarif !exists("g:rubycomplete_include_objectspace")
529964e468SBram Moolenaar    let g:rubycomplete_include_objectspace = 0
539964e468SBram Moolenaarendif
549964e468SBram Moolenaar" }}} configuration failsafe initialization
559964e468SBram Moolenaar
56eb3593b3SBram Moolenaar" {{{ vim-side support functions
579964e468SBram Moolenaarlet s:rubycomplete_debug = 0
589964e468SBram Moolenaar
599964e468SBram Moolenaarfunction! s:dprint(msg)
609964e468SBram Moolenaar    if s:rubycomplete_debug == 1
619964e468SBram Moolenaar        echom a:msg
629964e468SBram Moolenaar    endif
639964e468SBram Moolenaarendfunction
649964e468SBram Moolenaar
659964e468SBram Moolenaarfunction! s:GetBufferRubyModule(name, ...)
669964e468SBram Moolenaar    if a:0 == 1
679964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "module", a:1)
689964e468SBram Moolenaar    else
699964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "module")
709964e468SBram Moolenaar    endif
71fc1421ebSBram Moolenaar    return snum . '..' . enum
72fc1421ebSBram Moolenaarendfunction
73fc1421ebSBram Moolenaar
749964e468SBram Moolenaarfunction! s:GetBufferRubyClass(name, ...)
759964e468SBram Moolenaar    if a:0 >= 1
769964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "class", a:1)
779964e468SBram Moolenaar    else
789964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "class")
799964e468SBram Moolenaar    endif
80fc1421ebSBram Moolenaar    return snum . '..' . enum
81fc1421ebSBram Moolenaarendfunction
82fc1421ebSBram Moolenaar
839964e468SBram Moolenaarfunction! s:GetBufferRubySingletonMethods(name)
84fc1421ebSBram Moolenaarendfunction
85fc1421ebSBram Moolenaar
869964e468SBram Moolenaarfunction! s:GetBufferRubyEntity( name, type, ... )
879964e468SBram Moolenaar    let lastpos = getpos(".")
889964e468SBram Moolenaar    let lastline = lastpos
899964e468SBram Moolenaar    if (a:0 >= 1)
909964e468SBram Moolenaar        let lastline = [ 0, a:1, 0, 0 ]
919964e468SBram Moolenaar        call cursor( a:1, 0 )
929964e468SBram Moolenaar    endif
939964e468SBram Moolenaar
94fc1421ebSBram Moolenaar    let stopline = 1
959964e468SBram Moolenaar
9689bcfda6SBram Moolenaar    let crex = '^\s*\<' . a:type . '\>\s*\<' . escape(a:name, '*') . '\>\s*\(<\s*.*\s*\)\?'
979964e468SBram Moolenaar    let [lnum,lcol] = searchpos( crex, 'w' )
989964e468SBram Moolenaar    "let [lnum,lcol] = searchpairpos( crex . '\zs', '', '\(end\|}\)', 'w' )
999964e468SBram Moolenaar
100fc1421ebSBram Moolenaar    if lnum == 0 && lcol == 0
1019964e468SBram Moolenaar        call cursor(lastpos[1], lastpos[2])
102fc1421ebSBram Moolenaar        return [0,0]
103fc1421ebSBram Moolenaar    endif
104fc1421ebSBram Moolenaar
1059964e468SBram Moolenaar    let curpos = getpos(".")
106*d09091d4SBram Moolenaar    let [enum,ecol] = searchpairpos( crex, '', '\(end\|}\)', 'W' )
1079964e468SBram Moolenaar    call cursor(lastpos[1], lastpos[2])
1089964e468SBram Moolenaar
109fc1421ebSBram Moolenaar    if lnum > enum
1109964e468SBram Moolenaar        return [0,0]
111fc1421ebSBram Moolenaar    endif
112fc1421ebSBram Moolenaar    " we found a the class def
113fc1421ebSBram Moolenaar    return [lnum,enum]
114fc1421ebSBram Moolenaarendfunction
115fc1421ebSBram Moolenaar
1169964e468SBram Moolenaarfunction! s:IsInClassDef()
1179964e468SBram Moolenaar    return s:IsPosInClassDef( line('.') )
1189964e468SBram Moolenaarendfunction
119fc1421ebSBram Moolenaar
1209964e468SBram Moolenaarfunction! s:IsPosInClassDef(pos)
1219964e468SBram Moolenaar    let [snum,enum] = s:GetBufferRubyEntity( '.*', "class" )
1229964e468SBram Moolenaar    let ret = 'nil'
1239964e468SBram Moolenaar
1249964e468SBram Moolenaar    if snum < a:pos && a:pos < enum
125fc1421ebSBram Moolenaar        let ret = snum . '..' . enum
126fc1421ebSBram Moolenaar    endif
127fc1421ebSBram Moolenaar
128fc1421ebSBram Moolenaar    return ret
129fc1421ebSBram Moolenaarendfunction
130fc1421ebSBram Moolenaar
1319964e468SBram Moolenaarfunction! s:GetRubyVarType(v)
132c6249bb2SBram Moolenaar    let stopline = 1
133c6249bb2SBram Moolenaar    let vtp = ''
134c6249bb2SBram Moolenaar    let pos = getpos('.')
135ec7944aaSBram Moolenaar    let sstr = '^\s*#\s*@var\s*'.escape(a:v, '*').'\>\s\+[^ \t]\+\s*$'
1369964e468SBram Moolenaar    let [lnum,lcol] = searchpos(sstr,'nb',stopline)
137c6249bb2SBram Moolenaar    if lnum != 0 && lcol != 0
138c6249bb2SBram Moolenaar        call setpos('.',pos)
139c6249bb2SBram Moolenaar        let str = getline(lnum)
1409964e468SBram Moolenaar        let vtp = substitute(str,sstr,'\1','')
141c6249bb2SBram Moolenaar        return vtp
142c6249bb2SBram Moolenaar    endif
143c6249bb2SBram Moolenaar    call setpos('.',pos)
1449964e468SBram Moolenaar    let ctors = '\(now\|new\|open\|get_instance'
1459964e468SBram Moolenaar    if exists('g:rubycomplete_rails') && g:rubycomplete_rails == 1 && s:rubycomplete_rails_loaded == 1
1469964e468SBram Moolenaar        let ctors = ctors.'\|find\|create'
147551dbcc9SBram Moolenaar    else
148551dbcc9SBram Moolenaar    endif
1499964e468SBram Moolenaar    let ctors = ctors.'\)'
150551dbcc9SBram Moolenaar
1519964e468SBram Moolenaar    let fstr = '=\s*\([^ \t]\+.' . ctors .'\>\|[\[{"''/]\|%[xwQqr][(\[{@]\|[A-Za-z0-9@:\-()\.]\+...\?\|lambda\|&\)'
15289bcfda6SBram Moolenaar    let sstr = ''.escape(a:v, '*').'\>\s*[+\-*/]*'.fstr
1539964e468SBram Moolenaar    let [lnum,lcol] = searchpos(sstr,'nb',stopline)
154c6249bb2SBram Moolenaar    if lnum != 0 && lcol != 0
1559964e468SBram Moolenaar        let str = matchstr(getline(lnum),fstr,lcol)
156c6249bb2SBram Moolenaar        let str = substitute(str,'^=\s*','','')
1579964e468SBram Moolenaar
158c6249bb2SBram Moolenaar        call setpos('.',pos)
1599964e468SBram Moolenaar        if str == '"' || str == '''' || stridx(tolower(str), '%q[') != -1
160c6249bb2SBram Moolenaar            return 'String'
1619964e468SBram Moolenaar        elseif str == '[' || stridx(str, '%w[') != -1
162c6249bb2SBram Moolenaar            return 'Array'
163c6249bb2SBram Moolenaar        elseif str == '{'
164c6249bb2SBram Moolenaar            return 'Hash'
165fc1421ebSBram Moolenaar        elseif str == '/' || str == '%r{'
166fc1421ebSBram Moolenaar            return 'Regexp'
167d8fc5c0bSBram Moolenaar        elseif strlen(str) >= 4 && stridx(str,'..') != -1
168d8fc5c0bSBram Moolenaar            return 'Range'
1699964e468SBram Moolenaar        elseif stridx(str, 'lambda') != -1 || str == '&'
1709964e468SBram Moolenaar            return 'Proc'
171c6249bb2SBram Moolenaar        elseif strlen(str) > 4
172c6249bb2SBram Moolenaar            let l = stridx(str,'.')
173c6249bb2SBram Moolenaar            return str[0:l-1]
174c6249bb2SBram Moolenaar        end
175c6249bb2SBram Moolenaar        return ''
176c6249bb2SBram Moolenaar    endif
177c6249bb2SBram Moolenaar    call setpos('.',pos)
178c6249bb2SBram Moolenaar    return ''
179fc1421ebSBram Moolenaarendfunction
180c6249bb2SBram Moolenaar
181eb3593b3SBram Moolenaar"}}} vim-side support functions
182eb3593b3SBram Moolenaar
1839964e468SBram Moolenaar"{{{ vim-side completion function
1849964e468SBram Moolenaarfunction! rubycomplete#Init()
1859964e468SBram Moolenaar    execute "ruby VimRubyCompletion.preload_rails"
1869964e468SBram Moolenaarendfunction
1879964e468SBram Moolenaar
188c6249bb2SBram Moolenaarfunction! rubycomplete#Complete(findstart, base)
189c6249bb2SBram Moolenaar     "findstart = 1 when we need to get the text length
190c6249bb2SBram Moolenaar    if a:findstart
191c6249bb2SBram Moolenaar        let line = getline('.')
192c6249bb2SBram Moolenaar        let idx = col('.')
193c6249bb2SBram Moolenaar        while idx > 0
194c6249bb2SBram Moolenaar            let idx -= 1
195c6249bb2SBram Moolenaar            let c = line[idx-1]
196c6249bb2SBram Moolenaar            if c =~ '\w'
197c6249bb2SBram Moolenaar                continue
198c6249bb2SBram Moolenaar            elseif ! c =~ '\.'
1994575876dSBram Moolenaar                let idx = -1
200c6249bb2SBram Moolenaar                break
201c6249bb2SBram Moolenaar            else
202c6249bb2SBram Moolenaar                break
203c6249bb2SBram Moolenaar            endif
204c6249bb2SBram Moolenaar        endwhile
205c6249bb2SBram Moolenaar
206c6249bb2SBram Moolenaar        return idx
207c6249bb2SBram Moolenaar    "findstart = 0 when we need to return the list of completions
208c6249bb2SBram Moolenaar    else
209fc1421ebSBram Moolenaar        let g:rubycomplete_completions = []
2109964e468SBram Moolenaar        execute "ruby VimRubyCompletion.get_completions('" . a:base . "')"
211fc1421ebSBram Moolenaar        return g:rubycomplete_completions
212c6249bb2SBram Moolenaar    endif
213c6249bb2SBram Moolenaarendfunction
2149964e468SBram Moolenaar"}}} vim-side completion function
215c6249bb2SBram Moolenaar
2169964e468SBram Moolenaar"{{{ ruby-side code
217c6249bb2SBram Moolenaarfunction! s:DefRuby()
218c6249bb2SBram Moolenaarruby << RUBYEOF
219eb3593b3SBram Moolenaar# {{{ ruby completion
220fc1421ebSBram Moolenaar
2219964e468SBram Moolenaarbegin
2229964e468SBram Moolenaar    require 'rubygems' # let's assume this is safe...?
2239964e468SBram Moolenaarrescue Exception
2249964e468SBram Moolenaar    #ignore?
2259964e468SBram Moolenaarend
2269964e468SBram Moolenaarclass VimRubyCompletion
2279964e468SBram Moolenaar# {{{ constants
2289964e468SBram Moolenaar  @@debug = false
2299964e468SBram Moolenaar  @@ReservedWords = [
230c6249bb2SBram Moolenaar        "BEGIN", "END",
231c6249bb2SBram Moolenaar        "alias", "and",
232c6249bb2SBram Moolenaar        "begin", "break",
233c6249bb2SBram Moolenaar        "case", "class",
234c6249bb2SBram Moolenaar        "def", "defined", "do",
235c6249bb2SBram Moolenaar        "else", "elsif", "end", "ensure",
236c6249bb2SBram Moolenaar        "false", "for",
237c6249bb2SBram Moolenaar        "if", "in",
238c6249bb2SBram Moolenaar        "module",
239c6249bb2SBram Moolenaar        "next", "nil", "not",
240c6249bb2SBram Moolenaar        "or",
241c6249bb2SBram Moolenaar        "redo", "rescue", "retry", "return",
242c6249bb2SBram Moolenaar        "self", "super",
243c6249bb2SBram Moolenaar        "then", "true",
244c6249bb2SBram Moolenaar        "undef", "unless", "until",
245c6249bb2SBram Moolenaar        "when", "while",
246c6249bb2SBram Moolenaar        "yield",
247c6249bb2SBram Moolenaar      ]
248c6249bb2SBram Moolenaar
2499964e468SBram Moolenaar  @@Operators = [ "%", "&", "*", "**", "+",  "-",  "/",
250c6249bb2SBram Moolenaar        "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
251c6249bb2SBram Moolenaar        "[]", "[]=", "^", ]
2529964e468SBram Moolenaar# }}} constants
253c6249bb2SBram Moolenaar
2549964e468SBram Moolenaar# {{{ buffer analysis magic
255c6249bb2SBram Moolenaar  def load_requires
256*d09091d4SBram Moolenaar
257*d09091d4SBram Moolenaar    custom_paths = VIM::evaluate("get(g:, 'rubycomplete_load_paths', [])")
258*d09091d4SBram Moolenaar
259*d09091d4SBram Moolenaar    if !custom_paths.empty?
260*d09091d4SBram Moolenaar      $LOAD_PATH.concat(custom_paths).uniq!
261*d09091d4SBram Moolenaar    end
262*d09091d4SBram Moolenaar
263eb3593b3SBram Moolenaar    buf = VIM::Buffer.current
264eb3593b3SBram Moolenaar    enum = buf.line_number
265c6249bb2SBram Moolenaar    nums = Range.new( 1, enum )
266c6249bb2SBram Moolenaar    nums.each do |x|
267*d09091d4SBram Moolenaar
268eb3593b3SBram Moolenaar      ln = buf[x]
269c6249bb2SBram Moolenaar      begin
270*d09091d4SBram Moolenaar        if /.*require_relative\s*(.*)$/.match( ln )
271*d09091d4SBram Moolenaar          eval( "require %s" % File.expand_path($1) )
272*d09091d4SBram Moolenaar        elsif /.*require\s*(["'].*?["'])/.match( ln )
273*d09091d4SBram Moolenaar          eval( "require %s" % $1 )
274*d09091d4SBram Moolenaar        end
275*d09091d4SBram Moolenaar      rescue Exception => e
276*d09091d4SBram Moolenaar        dprint e.inspect
277c6249bb2SBram Moolenaar      end
278c6249bb2SBram Moolenaar    end
279c6249bb2SBram Moolenaar  end
280c6249bb2SBram Moolenaar
28189bcfda6SBram Moolenaar  def load_gems
28289bcfda6SBram Moolenaar    fpath = VIM::evaluate("get(g:, 'rubycomplete_gemfile_path', 'Gemfile')")
28389bcfda6SBram Moolenaar    return unless File.file?(fpath) && File.readable?(fpath)
28489bcfda6SBram Moolenaar    want_bundler = VIM::evaluate("get(g:, 'rubycomplete_use_bundler')")
28589bcfda6SBram Moolenaar    parse_file = !want_bundler
28689bcfda6SBram Moolenaar    begin
28789bcfda6SBram Moolenaar      require 'bundler'
28889bcfda6SBram Moolenaar      Bundler.setup
28989bcfda6SBram Moolenaar      Bundler.require
29089bcfda6SBram Moolenaar    rescue Exception
29189bcfda6SBram Moolenaar      parse_file = true
29289bcfda6SBram Moolenaar    end
29389bcfda6SBram Moolenaar    if parse_file
29489bcfda6SBram Moolenaar      File.new(fpath).each_line do |line|
29589bcfda6SBram Moolenaar        begin
29689bcfda6SBram Moolenaar          require $1 if /\s*gem\s*['"]([^'"]+)/.match(line)
29789bcfda6SBram Moolenaar        rescue Exception
29889bcfda6SBram Moolenaar        end
29989bcfda6SBram Moolenaar      end
30089bcfda6SBram Moolenaar    end
30189bcfda6SBram Moolenaar  end
30289bcfda6SBram Moolenaar
303fc1421ebSBram Moolenaar  def load_buffer_class(name)
3049964e468SBram Moolenaar    dprint "load_buffer_class(%s) START" % name
3059964e468SBram Moolenaar    classdef = get_buffer_entity(name, 's:GetBufferRubyClass("%s")')
306fc1421ebSBram Moolenaar    return if classdef == nil
307fc1421ebSBram Moolenaar
308fc1421ebSBram Moolenaar    pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef )
3099964e468SBram Moolenaar    load_buffer_class( $2 ) if pare != nil  && $2 != name # load parent class if needed
310fc1421ebSBram Moolenaar
311ec7944aaSBram Moolenaar    mixre = /.*\n\s*(include|prepend)\s*(.*)\s*\n/.match( classdef )
3129964e468SBram Moolenaar    load_buffer_module( $2 ) if mixre != nil && $2 != name # load mixins if needed
313fc1421ebSBram Moolenaar
3149964e468SBram Moolenaar    begin
315fc1421ebSBram Moolenaar      eval classdef
3169964e468SBram Moolenaar    rescue Exception
3179964e468SBram Moolenaar      VIM::evaluate( "s:ErrMsg( 'Problem loading class \"%s\", was it already completed?' )" % name )
3189964e468SBram Moolenaar    end
3199964e468SBram Moolenaar    dprint "load_buffer_class(%s) END" % name
320fc1421ebSBram Moolenaar  end
321fc1421ebSBram Moolenaar
322fc1421ebSBram Moolenaar  def load_buffer_module(name)
3239964e468SBram Moolenaar    dprint "load_buffer_module(%s) START" % name
3249964e468SBram Moolenaar    classdef = get_buffer_entity(name, 's:GetBufferRubyModule("%s")')
325fc1421ebSBram Moolenaar    return if classdef == nil
326fc1421ebSBram Moolenaar
3279964e468SBram Moolenaar    begin
328fc1421ebSBram Moolenaar      eval classdef
3299964e468SBram Moolenaar    rescue Exception
3309964e468SBram Moolenaar      VIM::evaluate( "s:ErrMsg( 'Problem loading module \"%s\", was it already completed?' )" % name )
3319964e468SBram Moolenaar    end
3329964e468SBram Moolenaar    dprint "load_buffer_module(%s) END" % name
333fc1421ebSBram Moolenaar  end
334fc1421ebSBram Moolenaar
335fc1421ebSBram Moolenaar  def get_buffer_entity(name, vimfun)
3369964e468SBram Moolenaar    loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
337c236c16dSBram Moolenaar    return nil if loading_allowed.to_i.zero?
338d8fc5c0bSBram Moolenaar    return nil if /(\"|\')+/.match( name )
339eb3593b3SBram Moolenaar    buf = VIM::Buffer.current
340fc1421ebSBram Moolenaar    nums = eval( VIM::evaluate( vimfun % name ) )
341fc1421ebSBram Moolenaar    return nil if nums == nil
342fc1421ebSBram Moolenaar    return nil if nums.min == nums.max && nums.min == 0
343fc1421ebSBram Moolenaar
3449964e468SBram Moolenaar    dprint "get_buffer_entity START"
3459964e468SBram Moolenaar    visited = []
3469964e468SBram Moolenaar    clscnt = 0
3479964e468SBram Moolenaar    bufname = VIM::Buffer.current.name
348fc1421ebSBram Moolenaar    classdef = ""
3499964e468SBram Moolenaar    cur_line = VIM::Buffer.current.line_number
3509964e468SBram Moolenaar    while (nums != nil && !(nums.min == 0 && nums.max == 0) )
3519964e468SBram Moolenaar      dprint "visited: %s" % visited.to_s
3529964e468SBram Moolenaar      break if visited.index( nums )
3539964e468SBram Moolenaar      visited << nums
3549964e468SBram Moolenaar
355fc1421ebSBram Moolenaar      nums.each do |x|
356fc1421ebSBram Moolenaar        if x != cur_line
3579964e468SBram Moolenaar          next if x == 0
358eb3593b3SBram Moolenaar          ln = buf[x]
359*d09091d4SBram Moolenaar          is_const = false
360*d09091d4SBram Moolenaar          if /^\s*(module|class|def|include)\s+/.match(ln) || is_const = /^\s*?[A-Z]([A-z]|[1-9])*\s*?[|]{0,2}=\s*?.+\s*?/.match(ln)
361*d09091d4SBram Moolenaar            clscnt += 1 if /class|module/.match($1)
362*d09091d4SBram Moolenaar            # We must make sure to load each constant only once to avoid errors
363*d09091d4SBram Moolenaar            if is_const
364*d09091d4SBram Moolenaar                ln.gsub!(/\s*?[|]{0,2}=\s*?/, '||=')
365*d09091d4SBram Moolenaar            end
3661d68952aSBram Moolenaar            #dprint "\$1$1
367fc1421ebSBram Moolenaar            classdef += "%s\n" % ln
3689964e468SBram Moolenaar            classdef += "end\n" if /def\s+/.match(ln)
3699964e468SBram Moolenaar            dprint ln
3709964e468SBram Moolenaar          end
371fc1421ebSBram Moolenaar        end
372fc1421ebSBram Moolenaar      end
373fc1421ebSBram Moolenaar
3749964e468SBram Moolenaar      nm = "%s(::.*)*\", %s, \"" % [ name, nums.last ]
3759964e468SBram Moolenaar      nums = eval( VIM::evaluate( vimfun % nm ) )
3769964e468SBram Moolenaar      dprint "nm: \"%s\"" % nm
3779964e468SBram Moolenaar      dprint "vimfun: %s" % (vimfun % nm)
3789964e468SBram Moolenaar      dprint "got nums: %s" % nums.to_s
3799964e468SBram Moolenaar    end
3809964e468SBram Moolenaar    if classdef.length > 1
3819964e468SBram Moolenaar        classdef += "end\n"*clscnt
3829964e468SBram Moolenaar        # classdef = "class %s\n%s\nend\n" % [ bufname.gsub( /\/|\\/, "_" ), classdef ]
3839964e468SBram Moolenaar    end
3849964e468SBram Moolenaar
3859964e468SBram Moolenaar    dprint "get_buffer_entity END"
3869964e468SBram Moolenaar    dprint "classdef====start"
3879964e468SBram Moolenaar    lns = classdef.split( "\n" )
3889964e468SBram Moolenaar    lns.each { |x| dprint x }
3899964e468SBram Moolenaar    dprint "classdef====end"
390fc1421ebSBram Moolenaar    return classdef
391fc1421ebSBram Moolenaar  end
392fc1421ebSBram Moolenaar
393d8fc5c0bSBram Moolenaar  def get_var_type( receiver )
394d8fc5c0bSBram Moolenaar    if /(\"|\')+/.match( receiver )
395d8fc5c0bSBram Moolenaar      "String"
396d8fc5c0bSBram Moolenaar    else
3979964e468SBram Moolenaar      VIM::evaluate("s:GetRubyVarType('%s')" % receiver)
398d8fc5c0bSBram Moolenaar    end
399d8fc5c0bSBram Moolenaar  end
400d8fc5c0bSBram Moolenaar
4019964e468SBram Moolenaar  def dprint( txt )
4029964e468SBram Moolenaar    print txt if @@debug
4039964e468SBram Moolenaar  end
4049964e468SBram Moolenaar
405ec7944aaSBram Moolenaar  def escape_vim_singlequote_string(str)
406ec7944aaSBram Moolenaar    str.to_s.gsub(/'/,"\\'")
407ec7944aaSBram Moolenaar  end
408ec7944aaSBram Moolenaar
4099964e468SBram Moolenaar  def get_buffer_entity_list( type )
410eb3593b3SBram Moolenaar    # this will be a little expensive.
4119964e468SBram Moolenaar    loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
4129964e468SBram Moolenaar    allow_aggressive_load = VIM::evaluate("exists('g:rubycomplete_classes_in_global') && g:rubycomplete_classes_in_global")
413c236c16dSBram Moolenaar    return [] if allow_aggressive_load.to_i.zero? || loading_allowed.to_i.zero?
414eb3593b3SBram Moolenaar
415eb3593b3SBram Moolenaar    buf = VIM::Buffer.current
416eb3593b3SBram Moolenaar    eob = buf.length
417eb3593b3SBram Moolenaar    ret = []
418eb3593b3SBram Moolenaar    rg = 1..eob
4199964e468SBram Moolenaar    re = eval( "/^\s*%s\s*([A-Za-z0-9_:-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/" % type )
420eb3593b3SBram Moolenaar
421eb3593b3SBram Moolenaar    rg.each do |x|
4229964e468SBram Moolenaar      if re.match( buf[x] )
4239964e468SBram Moolenaar        next if type == "def" && eval( VIM::evaluate("s:IsPosInClassDef(%s)" % x) ) != nil
424eb3593b3SBram Moolenaar        ret.push $1
425eb3593b3SBram Moolenaar      end
426eb3593b3SBram Moolenaar    end
427eb3593b3SBram Moolenaar
428eb3593b3SBram Moolenaar    return ret
429eb3593b3SBram Moolenaar  end
430eb3593b3SBram Moolenaar
4319964e468SBram Moolenaar  def get_buffer_modules
4329964e468SBram Moolenaar    return get_buffer_entity_list( "modules" )
4339964e468SBram Moolenaar  end
4349964e468SBram Moolenaar
4359964e468SBram Moolenaar  def get_buffer_methods
4369964e468SBram Moolenaar    return get_buffer_entity_list( "def" )
4379964e468SBram Moolenaar  end
4389964e468SBram Moolenaar
4399964e468SBram Moolenaar  def get_buffer_classes
4409964e468SBram Moolenaar    return get_buffer_entity_list( "class" )
4419964e468SBram Moolenaar  end
4429964e468SBram Moolenaar
4439964e468SBram Moolenaar  def load_rails
4449964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
445c236c16dSBram Moolenaar    return if allow_rails.to_i.zero?
446fc1421ebSBram Moolenaar
447fc1421ebSBram Moolenaar    buf_path = VIM::evaluate('expand("%:p")')
448fc1421ebSBram Moolenaar    file_name = VIM::evaluate('expand("%:t")')
4499964e468SBram Moolenaar    vim_dir = VIM::evaluate('getcwd()')
4509964e468SBram Moolenaar    file_dir = buf_path.gsub( file_name, '' )
4519964e468SBram Moolenaar    file_dir.gsub!( /\\/, "/" )
4529964e468SBram Moolenaar    vim_dir.gsub!( /\\/, "/" )
4539964e468SBram Moolenaar    vim_dir << "/"
4549964e468SBram Moolenaar    dirs = [ vim_dir, file_dir ]
4559964e468SBram Moolenaar    sdirs = [ "", "./", "../", "../../", "../../../", "../../../../" ]
4569964e468SBram Moolenaar    rails_base = nil
457fc1421ebSBram Moolenaar
4589964e468SBram Moolenaar    dirs.each do |dir|
4599964e468SBram Moolenaar      sdirs.each do |sub|
4609964e468SBram Moolenaar        trail = "%s%s" % [ dir, sub ]
4619964e468SBram Moolenaar        tcfg = "%sconfig" % trail
4629964e468SBram Moolenaar
4639964e468SBram Moolenaar        if File.exists?( tcfg )
4649964e468SBram Moolenaar          rails_base = trail
465fc1421ebSBram Moolenaar          break
466fc1421ebSBram Moolenaar        end
467fc1421ebSBram Moolenaar      end
4689964e468SBram Moolenaar      break if rails_base
4699964e468SBram Moolenaar    end
470eb3593b3SBram Moolenaar
4719964e468SBram Moolenaar    return if rails_base == nil
4729964e468SBram Moolenaar    $:.push rails_base unless $:.index( rails_base )
473551dbcc9SBram Moolenaar
4749964e468SBram Moolenaar    rails_config = rails_base + "config/"
4759964e468SBram Moolenaar    rails_lib = rails_base + "lib/"
4769964e468SBram Moolenaar    $:.push rails_config unless $:.index( rails_config )
4779964e468SBram Moolenaar    $:.push rails_lib unless $:.index( rails_lib )
4789964e468SBram Moolenaar
4799964e468SBram Moolenaar    bootfile = rails_config + "boot.rb"
4809964e468SBram Moolenaar    envfile = rails_config + "environment.rb"
481551dbcc9SBram Moolenaar    if File.exists?( bootfile ) && File.exists?( envfile )
482551dbcc9SBram Moolenaar      begin
483eb3593b3SBram Moolenaar        require bootfile
484551dbcc9SBram Moolenaar        require envfile
4859964e468SBram Moolenaar        begin
486551dbcc9SBram Moolenaar          require 'console_app'
487551dbcc9SBram Moolenaar          require 'console_with_helpers'
4889964e468SBram Moolenaar        rescue Exception
4899964e468SBram Moolenaar          dprint "Rails 1.1+ Error %s" % $!
4909964e468SBram Moolenaar          # assume 1.0
4919964e468SBram Moolenaar        end
4929964e468SBram Moolenaar        #eval( "Rails::Initializer.run" ) #not necessary?
4939964e468SBram Moolenaar        VIM::command('let s:rubycomplete_rails_loaded = 1')
4949964e468SBram Moolenaar        dprint "rails loaded"
4959964e468SBram Moolenaar      rescue Exception
4969964e468SBram Moolenaar        dprint "Rails Error %s" % $!
4979964e468SBram Moolenaar        VIM::evaluate( "s:ErrMsg('Error loading rails environment')" )
498551dbcc9SBram Moolenaar      end
499eb3593b3SBram Moolenaar    end
500fc1421ebSBram Moolenaar  end
501fc1421ebSBram Moolenaar
502fc1421ebSBram Moolenaar  def get_rails_helpers
5039964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
5049964e468SBram Moolenaar    rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
505c236c16dSBram Moolenaar    return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
5069964e468SBram Moolenaar
5079964e468SBram Moolenaar    buf_path = VIM::evaluate('expand("%:p")')
5089964e468SBram Moolenaar    buf_path.gsub!( /\\/, "/" )
5099964e468SBram Moolenaar    path_elm = buf_path.split( "/" )
5109964e468SBram Moolenaar    dprint "buf_path: %s" % buf_path
5119964e468SBram Moolenaar    types = [ "app", "db", "lib", "test", "components", "script" ]
5129964e468SBram Moolenaar
5139964e468SBram Moolenaar    i = nil
5149964e468SBram Moolenaar    ret = []
5159964e468SBram Moolenaar    type = nil
5169964e468SBram Moolenaar    types.each do |t|
5179964e468SBram Moolenaar      i = path_elm.index( t )
5189964e468SBram Moolenaar      break if i
5199964e468SBram Moolenaar    end
5209964e468SBram Moolenaar    type = path_elm[i]
5219964e468SBram Moolenaar    type.downcase!
5229964e468SBram Moolenaar
5239964e468SBram Moolenaar    dprint "type: %s" % type
5249964e468SBram Moolenaar    case type
5259964e468SBram Moolenaar      when "app"
5269964e468SBram Moolenaar        i += 1
5279964e468SBram Moolenaar        subtype = path_elm[i]
5289964e468SBram Moolenaar        subtype.downcase!
5299964e468SBram Moolenaar
5309964e468SBram Moolenaar        dprint "subtype: %s" % subtype
5319964e468SBram Moolenaar        case subtype
5329964e468SBram Moolenaar          when "views"
5339964e468SBram Moolenaar            ret += ActionView::Base.instance_methods
5349964e468SBram Moolenaar            ret += ActionView::Base.methods
5359964e468SBram Moolenaar          when "controllers"
5369964e468SBram Moolenaar            ret += ActionController::Base.instance_methods
5379964e468SBram Moolenaar            ret += ActionController::Base.methods
5389964e468SBram Moolenaar          when "models"
5399964e468SBram Moolenaar            ret += ActiveRecord::Base.instance_methods
5409964e468SBram Moolenaar            ret += ActiveRecord::Base.methods
5419964e468SBram Moolenaar        end
5429964e468SBram Moolenaar
5439964e468SBram Moolenaar      when "db"
5449964e468SBram Moolenaar        ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods
5459964e468SBram Moolenaar        ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods
5469964e468SBram Moolenaar    end
5479964e468SBram Moolenaar
5489964e468SBram Moolenaar    return ret
5499964e468SBram Moolenaar  end
5509964e468SBram Moolenaar
5519964e468SBram Moolenaar  def add_rails_columns( cls )
5529964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
5539964e468SBram Moolenaar    rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
554c236c16dSBram Moolenaar    return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
5559964e468SBram Moolenaar
5569964e468SBram Moolenaar    begin
5579964e468SBram Moolenaar        eval( "#{cls}.establish_connection" )
5589964e468SBram Moolenaar        return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" )
5599964e468SBram Moolenaar        col = eval( "#{cls}.column_names" )
5609964e468SBram Moolenaar        return col if col
5619964e468SBram Moolenaar    rescue
5629964e468SBram Moolenaar        dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ]
5639964e468SBram Moolenaar        return []
5649964e468SBram Moolenaar    end
5659964e468SBram Moolenaar    return []
5669964e468SBram Moolenaar  end
5679964e468SBram Moolenaar
5689964e468SBram Moolenaar  def clean_sel(sel, msg)
569ec7944aaSBram Moolenaar    ret = sel.reject{|x|x.nil?}.uniq
570ec7944aaSBram Moolenaar    ret = ret.grep(/^#{Regexp.quote(msg)}/) if msg != nil
571ec7944aaSBram Moolenaar    ret
5729964e468SBram Moolenaar  end
5739964e468SBram Moolenaar
5749964e468SBram Moolenaar  def get_rails_view_methods
5759964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
5769964e468SBram Moolenaar    rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
577c236c16dSBram Moolenaar    return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
5789964e468SBram Moolenaar
5799964e468SBram Moolenaar    buf_path = VIM::evaluate('expand("%:p")')
5809964e468SBram Moolenaar    buf_path.gsub!( /\\/, "/" )
5819964e468SBram Moolenaar    pelm = buf_path.split( "/" )
5829964e468SBram Moolenaar    idx = pelm.index( "views" )
5839964e468SBram Moolenaar
5849964e468SBram Moolenaar    return [] unless idx
5859964e468SBram Moolenaar    idx += 1
5869964e468SBram Moolenaar
5879964e468SBram Moolenaar    clspl = pelm[idx].camelize.pluralize
5889964e468SBram Moolenaar    cls = clspl.singularize
5899964e468SBram Moolenaar
5909964e468SBram Moolenaar    ret = []
5919964e468SBram Moolenaar    begin
5929964e468SBram Moolenaar      ret += eval( "#{cls}.instance_methods" )
5939964e468SBram Moolenaar      ret += eval( "#{clspl}Helper.instance_methods" )
5949964e468SBram Moolenaar    rescue Exception
5959964e468SBram Moolenaar      dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ]
5969964e468SBram Moolenaar    end
5979964e468SBram Moolenaar
5989964e468SBram Moolenaar    return ret
5999964e468SBram Moolenaar  end
6009964e468SBram Moolenaar# }}} buffer analysis magic
6019964e468SBram Moolenaar
6029964e468SBram Moolenaar# {{{ main completion code
6039964e468SBram Moolenaar  def self.preload_rails
6049964e468SBram Moolenaar    a = VimRubyCompletion.new
605*d09091d4SBram Moolenaar    if VIM::evaluate("has('nvim')") == 0
606*d09091d4SBram Moolenaar      require 'thread'
6079964e468SBram Moolenaar      Thread.new(a) do |b|
6089964e468SBram Moolenaar        begin
6099964e468SBram Moolenaar        b.load_rails
6109964e468SBram Moolenaar        rescue
6119964e468SBram Moolenaar        end
6129964e468SBram Moolenaar      end
613*d09091d4SBram Moolenaar    end
6149964e468SBram Moolenaar    a.load_rails
6159964e468SBram Moolenaar  rescue
6169964e468SBram Moolenaar  end
6179964e468SBram Moolenaar
6189964e468SBram Moolenaar  def self.get_completions(base)
6199964e468SBram Moolenaar    b = VimRubyCompletion.new
6209964e468SBram Moolenaar    b.get_completions base
621fc1421ebSBram Moolenaar  end
622fc1421ebSBram Moolenaar
623c6249bb2SBram Moolenaar  def get_completions(base)
6249964e468SBram Moolenaar    loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
625c236c16dSBram Moolenaar    if loading_allowed.to_i == 1
626c6249bb2SBram Moolenaar      load_requires
627fc1421ebSBram Moolenaar      load_rails
6289964e468SBram Moolenaar    end
629fc1421ebSBram Moolenaar
63089bcfda6SBram Moolenaar    want_gems = VIM::evaluate("get(g:, 'rubycomplete_load_gemfile')")
63189bcfda6SBram Moolenaar    load_gems unless want_gems.to_i.zero?
63289bcfda6SBram Moolenaar
633fc1421ebSBram Moolenaar    input = VIM::Buffer.current.line
634d8fc5c0bSBram Moolenaar    cpos = VIM::Window.current.cursor[1] - 1
6359964e468SBram Moolenaar    input = input[0..cpos]
636d8fc5c0bSBram Moolenaar    input += base
6379964e468SBram Moolenaar    input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters
6389964e468SBram Moolenaar    input.sub!(/self\./, '')
6399964e468SBram Moolenaar    input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '')
640c6249bb2SBram Moolenaar
6419964e468SBram Moolenaar    dprint 'input %s' % input
642d8fc5c0bSBram Moolenaar    message = nil
643d8fc5c0bSBram Moolenaar    receiver = nil
6449964e468SBram Moolenaar    methods = []
6459964e468SBram Moolenaar    variables = []
6469964e468SBram Moolenaar    classes = []
6479964e468SBram Moolenaar    constants = []
648c6249bb2SBram Moolenaar
649c6249bb2SBram Moolenaar    case input
650d8fc5c0bSBram Moolenaar      when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp
651c6249bb2SBram Moolenaar        receiver = $1
652c6249bb2SBram Moolenaar        message = Regexp.quote($2)
6539964e468SBram Moolenaar        methods = Regexp.instance_methods(true)
654c6249bb2SBram Moolenaar
655d8fc5c0bSBram Moolenaar      when /^([^\]]*\])\.([^.]*)$/ # Array
656c6249bb2SBram Moolenaar        receiver = $1
657c6249bb2SBram Moolenaar        message = Regexp.quote($2)
6589964e468SBram Moolenaar        methods = Array.instance_methods(true)
659c6249bb2SBram Moolenaar
660d8fc5c0bSBram Moolenaar      when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash
661c6249bb2SBram Moolenaar        receiver = $1
662c6249bb2SBram Moolenaar        message = Regexp.quote($2)
6639964e468SBram Moolenaar        methods = Proc.instance_methods(true) | Hash.instance_methods(true)
664c6249bb2SBram Moolenaar
665d8fc5c0bSBram Moolenaar      when /^(:[^:.]*)$/ # Symbol
6669964e468SBram Moolenaar        dprint "symbol"
667c6249bb2SBram Moolenaar        if Symbol.respond_to?(:all_symbols)
668d8fc5c0bSBram Moolenaar          receiver = $1
6699964e468SBram Moolenaar          message = $1.sub( /:/, '' )
6709964e468SBram Moolenaar          methods = Symbol.all_symbols.collect{|s| s.id2name}
6719964e468SBram Moolenaar          methods.delete_if { |c| c.match( /'/ ) }
672c6249bb2SBram Moolenaar        end
673c6249bb2SBram Moolenaar
674d8fc5c0bSBram Moolenaar      when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods
6759964e468SBram Moolenaar        dprint "const or cls"
676c6249bb2SBram Moolenaar        receiver = $1
6779964e468SBram Moolenaar        methods = Object.constants
6789964e468SBram Moolenaar        methods.grep(/^#{receiver}/).collect{|e| "::" + e}
679c6249bb2SBram Moolenaar
6801d68952aSBram Moolenaar      when /^(((::)?[A-Z][^:.\(]*)+?)::?([^:.]*)$/ # Constant or class methods
681c6249bb2SBram Moolenaar        receiver = $1
682c6249bb2SBram Moolenaar        message = Regexp.quote($4)
6839964e468SBram Moolenaar        dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ]
6849964e468SBram Moolenaar        load_buffer_class( receiver )
685*d09091d4SBram Moolenaar        load_buffer_module( receiver )
686c6249bb2SBram Moolenaar        begin
6879964e468SBram Moolenaar          classes = eval("#{receiver}.constants")
6889964e468SBram Moolenaar          #methods = eval("#{receiver}.methods")
689c6249bb2SBram Moolenaar        rescue Exception
6909964e468SBram Moolenaar          dprint "exception: %s" % $!
6919964e468SBram Moolenaar          methods = []
692c6249bb2SBram Moolenaar        end
6939964e468SBram Moolenaar        methods.grep(/^#{message}/).collect{|e| receiver + "::" + e}
694c6249bb2SBram Moolenaar
695d8fc5c0bSBram Moolenaar      when /^(:[^:.]+)\.([^.]*)$/ # Symbol
6969964e468SBram Moolenaar        dprint "symbol"
697c6249bb2SBram Moolenaar        receiver = $1
698c6249bb2SBram Moolenaar        message = Regexp.quote($2)
6999964e468SBram Moolenaar        methods = Symbol.instance_methods(true)
700c6249bb2SBram Moolenaar
701d8fc5c0bSBram Moolenaar      when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric
7029964e468SBram Moolenaar        dprint "numeric"
703c6249bb2SBram Moolenaar        receiver = $1
704c6249bb2SBram Moolenaar        message = Regexp.quote($4)
705c6249bb2SBram Moolenaar        begin
7069964e468SBram Moolenaar          methods = eval(receiver).methods
707c6249bb2SBram Moolenaar        rescue Exception
7089964e468SBram Moolenaar          methods = []
709c6249bb2SBram Moolenaar        end
710c6249bb2SBram Moolenaar
711d8fc5c0bSBram Moolenaar      when /^(\$[^.]*)$/ #global
7129964e468SBram Moolenaar        dprint "global"
7139964e468SBram Moolenaar        methods = global_variables.grep(Regexp.new(Regexp.quote($1)))
714c6249bb2SBram Moolenaar
7151d68952aSBram Moolenaar      when /^((\.?[^.]+)+?)\.([^.]*)$/ # variable
7169964e468SBram Moolenaar        dprint "variable"
717c6249bb2SBram Moolenaar        receiver = $1
718c6249bb2SBram Moolenaar        message = Regexp.quote($3)
719fc1421ebSBram Moolenaar        load_buffer_class( receiver )
720c6249bb2SBram Moolenaar
721c6249bb2SBram Moolenaar        cv = eval("self.class.constants")
722d8fc5c0bSBram Moolenaar        vartype = get_var_type( receiver )
7239964e468SBram Moolenaar        dprint "vartype: %s" % vartype
72489bcfda6SBram Moolenaar
72589bcfda6SBram Moolenaar        invalid_vartype = ['', "gets"]
72689bcfda6SBram Moolenaar        if !invalid_vartype.include?(vartype)
727fc1421ebSBram Moolenaar          load_buffer_class( vartype )
728fc1421ebSBram Moolenaar
729fc1421ebSBram Moolenaar          begin
7309964e468SBram Moolenaar            methods = eval("#{vartype}.instance_methods")
7319964e468SBram Moolenaar            variables = eval("#{vartype}.instance_variables")
732fc1421ebSBram Moolenaar          rescue Exception
7339964e468SBram Moolenaar            dprint "load_buffer_class err: %s" % $!
734fc1421ebSBram Moolenaar          end
735c6249bb2SBram Moolenaar        elsif (cv).include?(receiver)
736c6249bb2SBram Moolenaar          # foo.func and foo is local var.
7379964e468SBram Moolenaar          methods = eval("#{receiver}.methods")
7389964e468SBram Moolenaar          vartype = receiver
739c6249bb2SBram Moolenaar        elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
7409964e468SBram Moolenaar          vartype = receiver
741c6249bb2SBram Moolenaar          # Foo::Bar.func
742c6249bb2SBram Moolenaar          begin
7439964e468SBram Moolenaar            methods = eval("#{receiver}.methods")
744c6249bb2SBram Moolenaar          rescue Exception
745c6249bb2SBram Moolenaar          end
746c6249bb2SBram Moolenaar        else
747c6249bb2SBram Moolenaar          # func1.func2
748c6249bb2SBram Moolenaar          ObjectSpace.each_object(Module){|m|
749c6249bb2SBram Moolenaar            next if m.name != "IRB::Context" and
750c6249bb2SBram Moolenaar              /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
7519964e468SBram Moolenaar            methods.concat m.instance_methods(false)
752c6249bb2SBram Moolenaar          }
753c6249bb2SBram Moolenaar        end
75489bcfda6SBram Moolenaar        variables += add_rails_columns( "#{vartype}" ) if vartype && !invalid_vartype.include?(vartype)
755c6249bb2SBram Moolenaar
756d8fc5c0bSBram Moolenaar      when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/
757d8fc5c0bSBram Moolenaar        message = $1
7589964e468SBram Moolenaar        methods = Range.instance_methods(true)
759c6249bb2SBram Moolenaar
760d8fc5c0bSBram Moolenaar      when /^\.([^.]*)$/ # unknown(maybe String)
761c6249bb2SBram Moolenaar        message = Regexp.quote($1)
7629964e468SBram Moolenaar        methods = String.instance_methods(true)
763c6249bb2SBram Moolenaar
764c6249bb2SBram Moolenaar    else
7659964e468SBram Moolenaar      dprint "default/other"
7669964e468SBram Moolenaar      inclass = eval( VIM::evaluate("s:IsInClassDef()") )
767c6249bb2SBram Moolenaar
768fc1421ebSBram Moolenaar      if inclass != nil
7699964e468SBram Moolenaar        dprint "inclass"
770fc1421ebSBram Moolenaar        classdef = "%s\n" % VIM::Buffer.current[ inclass.min ]
771fc1421ebSBram Moolenaar        found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef )
772fc1421ebSBram Moolenaar
773fc1421ebSBram Moolenaar        if found != nil
774fc1421ebSBram Moolenaar          receiver = $1
775fc1421ebSBram Moolenaar          message = input
776fc1421ebSBram Moolenaar          load_buffer_class( receiver )
777eb3593b3SBram Moolenaar          begin
7789964e468SBram Moolenaar            methods = eval( "#{receiver}.instance_methods" )
7799964e468SBram Moolenaar            variables += add_rails_columns( "#{receiver}" )
780eb3593b3SBram Moolenaar          rescue Exception
781eb3593b3SBram Moolenaar            found = nil
782eb3593b3SBram Moolenaar          end
783fc1421ebSBram Moolenaar        end
784fc1421ebSBram Moolenaar      end
785fc1421ebSBram Moolenaar
786fc1421ebSBram Moolenaar      if inclass == nil || found == nil
7879964e468SBram Moolenaar        dprint "inclass == nil"
7889964e468SBram Moolenaar        methods = get_buffer_methods
7899964e468SBram Moolenaar        methods += get_rails_view_methods
7909964e468SBram Moolenaar
7919964e468SBram Moolenaar        cls_const = Class.constants
7929964e468SBram Moolenaar        constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) }
7939964e468SBram Moolenaar        classes = eval("self.class.constants") - constants
7949964e468SBram Moolenaar        classes += get_buffer_classes
7959964e468SBram Moolenaar        classes += get_buffer_modules
7969964e468SBram Moolenaar
7979964e468SBram Moolenaar        include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace")
7989964e468SBram Moolenaar        ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1"
799d8fc5c0bSBram Moolenaar        message = receiver = input
800d8fc5c0bSBram Moolenaar      end
8019964e468SBram Moolenaar
8029964e468SBram Moolenaar      methods += get_rails_helpers
8039964e468SBram Moolenaar      methods += Kernel.public_methods
804d8fc5c0bSBram Moolenaar    end
805d8fc5c0bSBram Moolenaar
8069964e468SBram Moolenaar    include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object")
8079964e468SBram Moolenaar    methods = clean_sel( methods, message )
8089964e468SBram Moolenaar    methods = (methods-Object.instance_methods) if include_object == "0"
8099964e468SBram Moolenaar    rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods
8109964e468SBram Moolenaar    methods = (methods-rbcmeth)
8119964e468SBram Moolenaar
8129964e468SBram Moolenaar    variables = clean_sel( variables, message )
8139964e468SBram Moolenaar    classes = clean_sel( classes, message ) - ["VimRubyCompletion"]
8149964e468SBram Moolenaar    constants = clean_sel( constants, message )
8159964e468SBram Moolenaar
8169964e468SBram Moolenaar    valid = []
817ec7944aaSBram Moolenaar    valid += methods.collect { |m| { :name => m.to_s, :type => 'm' } }
818ec7944aaSBram Moolenaar    valid += variables.collect { |v| { :name => v.to_s, :type => 'v' } }
819ec7944aaSBram Moolenaar    valid += classes.collect { |c| { :name => c.to_s, :type => 't' } }
820ec7944aaSBram Moolenaar    valid += constants.collect { |d| { :name => d.to_s, :type => 'd' } }
8219964e468SBram Moolenaar    valid.sort! { |x,y| x[:name] <=> y[:name] }
822c6249bb2SBram Moolenaar
823c6249bb2SBram Moolenaar    outp = ""
824fc1421ebSBram Moolenaar
825fc1421ebSBram Moolenaar    rg = 0..valid.length
826fc1421ebSBram Moolenaar    rg.step(150) do |x|
827fc1421ebSBram Moolenaar      stpos = 0+x
828fc1421ebSBram Moolenaar      enpos = 150+x
829ec7944aaSBram Moolenaar      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)} }
830c6249bb2SBram Moolenaar      outp.sub!(/,$/, '')
831fc1421ebSBram Moolenaar
832fc1421ebSBram Moolenaar      VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp)
833fc1421ebSBram Moolenaar      outp = ""
834fc1421ebSBram Moolenaar    end
835c6249bb2SBram Moolenaar  end
8369964e468SBram Moolenaar# }}} main completion code
837c6249bb2SBram Moolenaar
8389964e468SBram Moolenaarend # VimRubyCompletion
839eb3593b3SBram Moolenaar# }}} ruby completion
840c6249bb2SBram MoolenaarRUBYEOF
841c6249bb2SBram Moolenaarendfunction
842c6249bb2SBram Moolenaar
8439964e468SBram Moolenaarlet s:rubycomplete_rails_loaded = 0
844fc1421ebSBram Moolenaar
845c6249bb2SBram Moolenaarcall s:DefRuby()
8469964e468SBram Moolenaar"}}} ruby-side code
8479964e468SBram Moolenaar
8489964e468SBram Moolenaar" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl:
849