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*4d8f4761SBram Moolenaar" Last Change:		2020 Apr 12
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
562ed639abSBram Moolenaar" {{{ regex patterns
572ed639abSBram Moolenaar
582ed639abSBram Moolenaar" Regex that defines the start-match for the 'end' keyword.
592ed639abSBram Moolenaarlet s:end_start_regex =
602ed639abSBram Moolenaar      \ '\C\%(^\s*\|[=,*/%+\-|;{]\|<<\|>>\|:\s\)\s*\zs' .
612ed639abSBram Moolenaar      \ '\<\%(module\|class\|if\|for\|while\|until\|case\|unless\|begin' .
622ed639abSBram Moolenaar      \   '\|\%(\K\k*[!?]\?\s\+\)\=def\):\@!\>' .
632ed639abSBram Moolenaar      \ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>'
642ed639abSBram Moolenaar
652ed639abSBram Moolenaar" Regex that defines the middle-match for the 'end' keyword.
662ed639abSBram Moolenaarlet s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|elsif\):\@!\>'
672ed639abSBram Moolenaar
682ed639abSBram Moolenaar" Regex that defines the end-match for the 'end' keyword.
692ed639abSBram Moolenaarlet s:end_end_regex = '\%(^\|[^.:@$]\)\@<=\<end:\@!\>'
702ed639abSBram Moolenaar
712ed639abSBram Moolenaar" }}} regex patterns
722ed639abSBram Moolenaar
73eb3593b3SBram Moolenaar" {{{ vim-side support functions
749964e468SBram Moolenaarlet s:rubycomplete_debug = 0
759964e468SBram Moolenaar
769964e468SBram Moolenaarfunction! s:dprint(msg)
779964e468SBram Moolenaar    if s:rubycomplete_debug == 1
789964e468SBram Moolenaar        echom a:msg
799964e468SBram Moolenaar    endif
809964e468SBram Moolenaarendfunction
819964e468SBram Moolenaar
829964e468SBram Moolenaarfunction! s:GetBufferRubyModule(name, ...)
839964e468SBram Moolenaar    if a:0 == 1
849964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "module", a:1)
859964e468SBram Moolenaar    else
869964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "module")
879964e468SBram Moolenaar    endif
88fc1421ebSBram Moolenaar    return snum . '..' . enum
89fc1421ebSBram Moolenaarendfunction
90fc1421ebSBram Moolenaar
919964e468SBram Moolenaarfunction! s:GetBufferRubyClass(name, ...)
929964e468SBram Moolenaar    if a:0 >= 1
939964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "class", a:1)
949964e468SBram Moolenaar    else
959964e468SBram Moolenaar        let [snum,enum] = s:GetBufferRubyEntity(a:name, "class")
969964e468SBram Moolenaar    endif
97fc1421ebSBram Moolenaar    return snum . '..' . enum
98fc1421ebSBram Moolenaarendfunction
99fc1421ebSBram Moolenaar
1009964e468SBram Moolenaarfunction! s:GetBufferRubySingletonMethods(name)
101fc1421ebSBram Moolenaarendfunction
102fc1421ebSBram Moolenaar
1039964e468SBram Moolenaarfunction! s:GetBufferRubyEntity( name, type, ... )
1049964e468SBram Moolenaar    let lastpos = getpos(".")
1059964e468SBram Moolenaar    let lastline = lastpos
1069964e468SBram Moolenaar    if (a:0 >= 1)
1079964e468SBram Moolenaar        let lastline = [ 0, a:1, 0, 0 ]
1089964e468SBram Moolenaar        call cursor( a:1, 0 )
1099964e468SBram Moolenaar    endif
1109964e468SBram Moolenaar
111fc1421ebSBram Moolenaar    let stopline = 1
1129964e468SBram Moolenaar
11389bcfda6SBram Moolenaar    let crex = '^\s*\<' . a:type . '\>\s*\<' . escape(a:name, '*') . '\>\s*\(<\s*.*\s*\)\?'
1149964e468SBram Moolenaar    let [lnum,lcol] = searchpos( crex, 'w' )
1159964e468SBram Moolenaar    "let [lnum,lcol] = searchpairpos( crex . '\zs', '', '\(end\|}\)', 'w' )
1169964e468SBram Moolenaar
117fc1421ebSBram Moolenaar    if lnum == 0 && lcol == 0
1189964e468SBram Moolenaar        call cursor(lastpos[1], lastpos[2])
119fc1421ebSBram Moolenaar        return [0,0]
120fc1421ebSBram Moolenaar    endif
121fc1421ebSBram Moolenaar
1229964e468SBram Moolenaar    let curpos = getpos(".")
1232ed639abSBram Moolenaar    let [enum,ecol] = searchpairpos( s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'W' )
1249964e468SBram Moolenaar    call cursor(lastpos[1], lastpos[2])
1259964e468SBram Moolenaar
126fc1421ebSBram Moolenaar    if lnum > enum
1279964e468SBram Moolenaar        return [0,0]
128fc1421ebSBram Moolenaar    endif
129fc1421ebSBram Moolenaar    " we found a the class def
130fc1421ebSBram Moolenaar    return [lnum,enum]
131fc1421ebSBram Moolenaarendfunction
132fc1421ebSBram Moolenaar
1339964e468SBram Moolenaarfunction! s:IsInClassDef()
1349964e468SBram Moolenaar    return s:IsPosInClassDef( line('.') )
1359964e468SBram Moolenaarendfunction
136fc1421ebSBram Moolenaar
1379964e468SBram Moolenaarfunction! s:IsPosInClassDef(pos)
1389964e468SBram Moolenaar    let [snum,enum] = s:GetBufferRubyEntity( '.*', "class" )
1399964e468SBram Moolenaar    let ret = 'nil'
1409964e468SBram Moolenaar
1419964e468SBram Moolenaar    if snum < a:pos && a:pos < enum
142fc1421ebSBram Moolenaar        let ret = snum . '..' . enum
143fc1421ebSBram Moolenaar    endif
144fc1421ebSBram Moolenaar
145fc1421ebSBram Moolenaar    return ret
146fc1421ebSBram Moolenaarendfunction
147fc1421ebSBram Moolenaar
1482ed639abSBram Moolenaarfunction! s:IsInComment(pos)
1492ed639abSBram Moolenaar    let stack = synstack(a:pos[0], a:pos[1])
1502ed639abSBram Moolenaar    if !empty(stack)
1512ed639abSBram Moolenaar        return synIDattr(stack[0], 'name') =~ 'ruby\%(.*Comment\|Documentation\)'
1522ed639abSBram Moolenaar    else
1532ed639abSBram Moolenaar        return 0
1542ed639abSBram Moolenaar    endif
1552ed639abSBram Moolenaarendfunction
1562ed639abSBram Moolenaar
1579964e468SBram Moolenaarfunction! s:GetRubyVarType(v)
158c6249bb2SBram Moolenaar    let stopline = 1
159c6249bb2SBram Moolenaar    let vtp = ''
1602ed639abSBram Moolenaar    let curpos = getpos('.')
161ec7944aaSBram Moolenaar    let sstr = '^\s*#\s*@var\s*'.escape(a:v, '*').'\>\s\+[^ \t]\+\s*$'
1629964e468SBram Moolenaar    let [lnum,lcol] = searchpos(sstr,'nb',stopline)
163c6249bb2SBram Moolenaar    if lnum != 0 && lcol != 0
1642ed639abSBram Moolenaar        call setpos('.',curpos)
165c6249bb2SBram Moolenaar        let str = getline(lnum)
1669964e468SBram Moolenaar        let vtp = substitute(str,sstr,'\1','')
167c6249bb2SBram Moolenaar        return vtp
168c6249bb2SBram Moolenaar    endif
1692ed639abSBram Moolenaar    call setpos('.',curpos)
1709964e468SBram Moolenaar    let ctors = '\(now\|new\|open\|get_instance'
1719964e468SBram Moolenaar    if exists('g:rubycomplete_rails') && g:rubycomplete_rails == 1 && s:rubycomplete_rails_loaded == 1
1729964e468SBram Moolenaar        let ctors = ctors.'\|find\|create'
173551dbcc9SBram Moolenaar    else
174551dbcc9SBram Moolenaar    endif
1759964e468SBram Moolenaar    let ctors = ctors.'\)'
176551dbcc9SBram Moolenaar
1779964e468SBram Moolenaar    let fstr = '=\s*\([^ \t]\+.' . ctors .'\>\|[\[{"''/]\|%[xwQqr][(\[{@]\|[A-Za-z0-9@:\-()\.]\+...\?\|lambda\|&\)'
17889bcfda6SBram Moolenaar    let sstr = ''.escape(a:v, '*').'\>\s*[+\-*/]*'.fstr
1792ed639abSBram Moolenaar    let pos = searchpos(sstr,'bW')
1802ed639abSBram Moolenaar    while pos != [0,0] && s:IsInComment(pos)
1812ed639abSBram Moolenaar        let pos = searchpos(sstr,'bW')
1822ed639abSBram Moolenaar    endwhile
1832ed639abSBram Moolenaar    if pos != [0,0]
1842ed639abSBram Moolenaar        let [lnum, col] = pos
1852ed639abSBram Moolenaar        let str = matchstr(getline(lnum),fstr,col)
186c6249bb2SBram Moolenaar        let str = substitute(str,'^=\s*','','')
1879964e468SBram Moolenaar
188c6249bb2SBram Moolenaar        call setpos('.',pos)
1899964e468SBram Moolenaar        if str == '"' || str == '''' || stridx(tolower(str), '%q[') != -1
190c6249bb2SBram Moolenaar            return 'String'
1919964e468SBram Moolenaar        elseif str == '[' || stridx(str, '%w[') != -1
192c6249bb2SBram Moolenaar            return 'Array'
193c6249bb2SBram Moolenaar        elseif str == '{'
194c6249bb2SBram Moolenaar            return 'Hash'
195fc1421ebSBram Moolenaar        elseif str == '/' || str == '%r{'
196fc1421ebSBram Moolenaar            return 'Regexp'
197d8fc5c0bSBram Moolenaar        elseif strlen(str) >= 4 && stridx(str,'..') != -1
198d8fc5c0bSBram Moolenaar            return 'Range'
1999964e468SBram Moolenaar        elseif stridx(str, 'lambda') != -1 || str == '&'
2009964e468SBram Moolenaar            return 'Proc'
201c6249bb2SBram Moolenaar        elseif strlen(str) > 4
202c6249bb2SBram Moolenaar            let l = stridx(str,'.')
203c6249bb2SBram Moolenaar            return str[0:l-1]
204c6249bb2SBram Moolenaar        end
205c6249bb2SBram Moolenaar        return ''
206c6249bb2SBram Moolenaar    endif
2072ed639abSBram Moolenaar    call setpos('.',curpos)
208c6249bb2SBram Moolenaar    return ''
209fc1421ebSBram Moolenaarendfunction
210c6249bb2SBram Moolenaar
211eb3593b3SBram Moolenaar"}}} vim-side support functions
212eb3593b3SBram Moolenaar
2139964e468SBram Moolenaar"{{{ vim-side completion function
2149964e468SBram Moolenaarfunction! rubycomplete#Init()
2159964e468SBram Moolenaar    execute "ruby VimRubyCompletion.preload_rails"
2169964e468SBram Moolenaarendfunction
2179964e468SBram Moolenaar
218c6249bb2SBram Moolenaarfunction! rubycomplete#Complete(findstart, base)
219c6249bb2SBram Moolenaar     "findstart = 1 when we need to get the text length
220c6249bb2SBram Moolenaar    if a:findstart
221c6249bb2SBram Moolenaar        let line = getline('.')
222c6249bb2SBram Moolenaar        let idx = col('.')
223c6249bb2SBram Moolenaar        while idx > 0
224c6249bb2SBram Moolenaar            let idx -= 1
225c6249bb2SBram Moolenaar            let c = line[idx-1]
226c6249bb2SBram Moolenaar            if c =~ '\w'
227c6249bb2SBram Moolenaar                continue
228c6249bb2SBram Moolenaar            elseif ! c =~ '\.'
2294575876dSBram Moolenaar                let idx = -1
230c6249bb2SBram Moolenaar                break
231c6249bb2SBram Moolenaar            else
232c6249bb2SBram Moolenaar                break
233c6249bb2SBram Moolenaar            endif
234c6249bb2SBram Moolenaar        endwhile
235c6249bb2SBram Moolenaar
236c6249bb2SBram Moolenaar        return idx
237c6249bb2SBram Moolenaar    "findstart = 0 when we need to return the list of completions
238c6249bb2SBram Moolenaar    else
239fc1421ebSBram Moolenaar        let g:rubycomplete_completions = []
2409964e468SBram Moolenaar        execute "ruby VimRubyCompletion.get_completions('" . a:base . "')"
241fc1421ebSBram Moolenaar        return g:rubycomplete_completions
242c6249bb2SBram Moolenaar    endif
243c6249bb2SBram Moolenaarendfunction
2449964e468SBram Moolenaar"}}} vim-side completion function
245c6249bb2SBram Moolenaar
2469964e468SBram Moolenaar"{{{ ruby-side code
247c6249bb2SBram Moolenaarfunction! s:DefRuby()
248c6249bb2SBram Moolenaarruby << RUBYEOF
249eb3593b3SBram Moolenaar# {{{ ruby completion
250fc1421ebSBram Moolenaar
2519964e468SBram Moolenaarbegin
2529964e468SBram Moolenaar    require 'rubygems' # let's assume this is safe...?
2539964e468SBram Moolenaarrescue Exception
2549964e468SBram Moolenaar    #ignore?
2559964e468SBram Moolenaarend
2569964e468SBram Moolenaarclass VimRubyCompletion
2579964e468SBram Moolenaar# {{{ constants
2589964e468SBram Moolenaar  @@debug = false
2599964e468SBram Moolenaar  @@ReservedWords = [
260c6249bb2SBram Moolenaar        "BEGIN", "END",
261c6249bb2SBram Moolenaar        "alias", "and",
262c6249bb2SBram Moolenaar        "begin", "break",
263c6249bb2SBram Moolenaar        "case", "class",
264c6249bb2SBram Moolenaar        "def", "defined", "do",
265c6249bb2SBram Moolenaar        "else", "elsif", "end", "ensure",
266c6249bb2SBram Moolenaar        "false", "for",
267c6249bb2SBram Moolenaar        "if", "in",
268c6249bb2SBram Moolenaar        "module",
269c6249bb2SBram Moolenaar        "next", "nil", "not",
270c6249bb2SBram Moolenaar        "or",
271c6249bb2SBram Moolenaar        "redo", "rescue", "retry", "return",
272c6249bb2SBram Moolenaar        "self", "super",
273c6249bb2SBram Moolenaar        "then", "true",
274c6249bb2SBram Moolenaar        "undef", "unless", "until",
275c6249bb2SBram Moolenaar        "when", "while",
276c6249bb2SBram Moolenaar        "yield",
277c6249bb2SBram Moolenaar      ]
278c6249bb2SBram Moolenaar
2799964e468SBram Moolenaar  @@Operators = [ "%", "&", "*", "**", "+",  "-",  "/",
280c6249bb2SBram Moolenaar        "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
281c6249bb2SBram Moolenaar        "[]", "[]=", "^", ]
2829964e468SBram Moolenaar# }}} constants
283c6249bb2SBram Moolenaar
2849964e468SBram Moolenaar# {{{ buffer analysis magic
285c6249bb2SBram Moolenaar  def load_requires
286d09091d4SBram Moolenaar
287d09091d4SBram Moolenaar    custom_paths = VIM::evaluate("get(g:, 'rubycomplete_load_paths', [])")
288d09091d4SBram Moolenaar
289d09091d4SBram Moolenaar    if !custom_paths.empty?
290d09091d4SBram Moolenaar      $LOAD_PATH.concat(custom_paths).uniq!
291d09091d4SBram Moolenaar    end
292d09091d4SBram Moolenaar
293eb3593b3SBram Moolenaar    buf = VIM::Buffer.current
294eb3593b3SBram Moolenaar    enum = buf.line_number
295c6249bb2SBram Moolenaar    nums = Range.new( 1, enum )
296c6249bb2SBram Moolenaar    nums.each do |x|
297d09091d4SBram Moolenaar
298eb3593b3SBram Moolenaar      ln = buf[x]
299c6249bb2SBram Moolenaar      begin
300d09091d4SBram Moolenaar        if /.*require_relative\s*(.*)$/.match( ln )
301d09091d4SBram Moolenaar          eval( "require %s" % File.expand_path($1) )
302d09091d4SBram Moolenaar        elsif /.*require\s*(["'].*?["'])/.match( ln )
303d09091d4SBram Moolenaar          eval( "require %s" % $1 )
304d09091d4SBram Moolenaar        end
305d09091d4SBram Moolenaar      rescue Exception => e
306d09091d4SBram Moolenaar        dprint e.inspect
307c6249bb2SBram Moolenaar      end
308c6249bb2SBram Moolenaar    end
309c6249bb2SBram Moolenaar  end
310c6249bb2SBram Moolenaar
31189bcfda6SBram Moolenaar  def load_gems
31289bcfda6SBram Moolenaar    fpath = VIM::evaluate("get(g:, 'rubycomplete_gemfile_path', 'Gemfile')")
31389bcfda6SBram Moolenaar    return unless File.file?(fpath) && File.readable?(fpath)
31489bcfda6SBram Moolenaar    want_bundler = VIM::evaluate("get(g:, 'rubycomplete_use_bundler')")
31589bcfda6SBram Moolenaar    parse_file = !want_bundler
31689bcfda6SBram Moolenaar    begin
31789bcfda6SBram Moolenaar      require 'bundler'
31889bcfda6SBram Moolenaar      Bundler.setup
31989bcfda6SBram Moolenaar      Bundler.require
32089bcfda6SBram Moolenaar    rescue Exception
32189bcfda6SBram Moolenaar      parse_file = true
32289bcfda6SBram Moolenaar    end
32389bcfda6SBram Moolenaar    if parse_file
32489bcfda6SBram Moolenaar      File.new(fpath).each_line do |line|
32589bcfda6SBram Moolenaar        begin
32689bcfda6SBram Moolenaar          require $1 if /\s*gem\s*['"]([^'"]+)/.match(line)
32789bcfda6SBram Moolenaar        rescue Exception
32889bcfda6SBram Moolenaar        end
32989bcfda6SBram Moolenaar      end
33089bcfda6SBram Moolenaar    end
33189bcfda6SBram Moolenaar  end
33289bcfda6SBram Moolenaar
333fc1421ebSBram Moolenaar  def load_buffer_class(name)
3349964e468SBram Moolenaar    dprint "load_buffer_class(%s) START" % name
3359964e468SBram Moolenaar    classdef = get_buffer_entity(name, 's:GetBufferRubyClass("%s")')
336fc1421ebSBram Moolenaar    return if classdef == nil
337fc1421ebSBram Moolenaar
338fc1421ebSBram Moolenaar    pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef )
3399964e468SBram Moolenaar    load_buffer_class( $2 ) if pare != nil  && $2 != name # load parent class if needed
340fc1421ebSBram Moolenaar
341ec7944aaSBram Moolenaar    mixre = /.*\n\s*(include|prepend)\s*(.*)\s*\n/.match( classdef )
3429964e468SBram Moolenaar    load_buffer_module( $2 ) if mixre != nil && $2 != name # load mixins if needed
343fc1421ebSBram Moolenaar
3449964e468SBram Moolenaar    begin
345fc1421ebSBram Moolenaar      eval classdef
3469964e468SBram Moolenaar    rescue Exception
3479964e468SBram Moolenaar      VIM::evaluate( "s:ErrMsg( 'Problem loading class \"%s\", was it already completed?' )" % name )
3489964e468SBram Moolenaar    end
3499964e468SBram Moolenaar    dprint "load_buffer_class(%s) END" % name
350fc1421ebSBram Moolenaar  end
351fc1421ebSBram Moolenaar
352fc1421ebSBram Moolenaar  def load_buffer_module(name)
3539964e468SBram Moolenaar    dprint "load_buffer_module(%s) START" % name
3549964e468SBram Moolenaar    classdef = get_buffer_entity(name, 's:GetBufferRubyModule("%s")')
355fc1421ebSBram Moolenaar    return if classdef == nil
356fc1421ebSBram Moolenaar
3579964e468SBram Moolenaar    begin
358fc1421ebSBram Moolenaar      eval classdef
3599964e468SBram Moolenaar    rescue Exception
3609964e468SBram Moolenaar      VIM::evaluate( "s:ErrMsg( 'Problem loading module \"%s\", was it already completed?' )" % name )
3619964e468SBram Moolenaar    end
3629964e468SBram Moolenaar    dprint "load_buffer_module(%s) END" % name
363fc1421ebSBram Moolenaar  end
364fc1421ebSBram Moolenaar
365fc1421ebSBram Moolenaar  def get_buffer_entity(name, vimfun)
3669964e468SBram Moolenaar    loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
367c236c16dSBram Moolenaar    return nil if loading_allowed.to_i.zero?
368d8fc5c0bSBram Moolenaar    return nil if /(\"|\')+/.match( name )
369eb3593b3SBram Moolenaar    buf = VIM::Buffer.current
370fc1421ebSBram Moolenaar    nums = eval( VIM::evaluate( vimfun % name ) )
371fc1421ebSBram Moolenaar    return nil if nums == nil
372fc1421ebSBram Moolenaar    return nil if nums.min == nums.max && nums.min == 0
373fc1421ebSBram Moolenaar
3749964e468SBram Moolenaar    dprint "get_buffer_entity START"
3759964e468SBram Moolenaar    visited = []
3769964e468SBram Moolenaar    clscnt = 0
3779964e468SBram Moolenaar    bufname = VIM::Buffer.current.name
378fc1421ebSBram Moolenaar    classdef = ""
3799964e468SBram Moolenaar    cur_line = VIM::Buffer.current.line_number
3809964e468SBram Moolenaar    while (nums != nil && !(nums.min == 0 && nums.max == 0) )
3819964e468SBram Moolenaar      dprint "visited: %s" % visited.to_s
3829964e468SBram Moolenaar      break if visited.index( nums )
3839964e468SBram Moolenaar      visited << nums
3849964e468SBram Moolenaar
385fc1421ebSBram Moolenaar      nums.each do |x|
386fc1421ebSBram Moolenaar        if x != cur_line
3879964e468SBram Moolenaar          next if x == 0
388eb3593b3SBram Moolenaar          ln = buf[x]
389d09091d4SBram Moolenaar          is_const = false
390d09091d4SBram 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)
391d09091d4SBram Moolenaar            clscnt += 1 if /class|module/.match($1)
392d09091d4SBram Moolenaar            # We must make sure to load each constant only once to avoid errors
393d09091d4SBram Moolenaar            if is_const
394d09091d4SBram Moolenaar                ln.gsub!(/\s*?[|]{0,2}=\s*?/, '||=')
395d09091d4SBram Moolenaar            end
3961d68952aSBram Moolenaar            #dprint "\$1$1
397fc1421ebSBram Moolenaar            classdef += "%s\n" % ln
3989964e468SBram Moolenaar            classdef += "end\n" if /def\s+/.match(ln)
3999964e468SBram Moolenaar            dprint ln
4009964e468SBram Moolenaar          end
401fc1421ebSBram Moolenaar        end
402fc1421ebSBram Moolenaar      end
403fc1421ebSBram Moolenaar
4049964e468SBram Moolenaar      nm = "%s(::.*)*\", %s, \"" % [ name, nums.last ]
4059964e468SBram Moolenaar      nums = eval( VIM::evaluate( vimfun % nm ) )
4069964e468SBram Moolenaar      dprint "nm: \"%s\"" % nm
4079964e468SBram Moolenaar      dprint "vimfun: %s" % (vimfun % nm)
4089964e468SBram Moolenaar      dprint "got nums: %s" % nums.to_s
4099964e468SBram Moolenaar    end
4109964e468SBram Moolenaar    if classdef.length > 1
4119964e468SBram Moolenaar        classdef += "end\n"*clscnt
4129964e468SBram Moolenaar        # classdef = "class %s\n%s\nend\n" % [ bufname.gsub( /\/|\\/, "_" ), classdef ]
4139964e468SBram Moolenaar    end
4149964e468SBram Moolenaar
4159964e468SBram Moolenaar    dprint "get_buffer_entity END"
4169964e468SBram Moolenaar    dprint "classdef====start"
4179964e468SBram Moolenaar    lns = classdef.split( "\n" )
4189964e468SBram Moolenaar    lns.each { |x| dprint x }
4199964e468SBram Moolenaar    dprint "classdef====end"
420fc1421ebSBram Moolenaar    return classdef
421fc1421ebSBram Moolenaar  end
422fc1421ebSBram Moolenaar
423d8fc5c0bSBram Moolenaar  def get_var_type( receiver )
424d8fc5c0bSBram Moolenaar    if /(\"|\')+/.match( receiver )
425d8fc5c0bSBram Moolenaar      "String"
426d8fc5c0bSBram Moolenaar    else
4279964e468SBram Moolenaar      VIM::evaluate("s:GetRubyVarType('%s')" % receiver)
428d8fc5c0bSBram Moolenaar    end
429d8fc5c0bSBram Moolenaar  end
430d8fc5c0bSBram Moolenaar
4319964e468SBram Moolenaar  def dprint( txt )
4329964e468SBram Moolenaar    print txt if @@debug
4339964e468SBram Moolenaar  end
4349964e468SBram Moolenaar
435ec7944aaSBram Moolenaar  def escape_vim_singlequote_string(str)
436ec7944aaSBram Moolenaar    str.to_s.gsub(/'/,"\\'")
437ec7944aaSBram Moolenaar  end
438ec7944aaSBram Moolenaar
4399964e468SBram Moolenaar  def get_buffer_entity_list( type )
440eb3593b3SBram Moolenaar    # this will be a little expensive.
4419964e468SBram Moolenaar    loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
4429964e468SBram Moolenaar    allow_aggressive_load = VIM::evaluate("exists('g:rubycomplete_classes_in_global') && g:rubycomplete_classes_in_global")
443c236c16dSBram Moolenaar    return [] if allow_aggressive_load.to_i.zero? || loading_allowed.to_i.zero?
444eb3593b3SBram Moolenaar
445eb3593b3SBram Moolenaar    buf = VIM::Buffer.current
446eb3593b3SBram Moolenaar    eob = buf.length
447eb3593b3SBram Moolenaar    ret = []
448eb3593b3SBram Moolenaar    rg = 1..eob
4499964e468SBram Moolenaar    re = eval( "/^\s*%s\s*([A-Za-z0-9_:-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/" % type )
450eb3593b3SBram Moolenaar
451eb3593b3SBram Moolenaar    rg.each do |x|
4529964e468SBram Moolenaar      if re.match( buf[x] )
4539964e468SBram Moolenaar        next if type == "def" && eval( VIM::evaluate("s:IsPosInClassDef(%s)" % x) ) != nil
454eb3593b3SBram Moolenaar        ret.push $1
455eb3593b3SBram Moolenaar      end
456eb3593b3SBram Moolenaar    end
457eb3593b3SBram Moolenaar
458eb3593b3SBram Moolenaar    return ret
459eb3593b3SBram Moolenaar  end
460eb3593b3SBram Moolenaar
4619964e468SBram Moolenaar  def get_buffer_modules
4629964e468SBram Moolenaar    return get_buffer_entity_list( "modules" )
4639964e468SBram Moolenaar  end
4649964e468SBram Moolenaar
4659964e468SBram Moolenaar  def get_buffer_methods
4669964e468SBram Moolenaar    return get_buffer_entity_list( "def" )
4679964e468SBram Moolenaar  end
4689964e468SBram Moolenaar
4699964e468SBram Moolenaar  def get_buffer_classes
4709964e468SBram Moolenaar    return get_buffer_entity_list( "class" )
4719964e468SBram Moolenaar  end
4729964e468SBram Moolenaar
4739964e468SBram Moolenaar  def load_rails
4749964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
475c236c16dSBram Moolenaar    return if allow_rails.to_i.zero?
476fc1421ebSBram Moolenaar
477fc1421ebSBram Moolenaar    buf_path = VIM::evaluate('expand("%:p")')
478fc1421ebSBram Moolenaar    file_name = VIM::evaluate('expand("%:t")')
4799964e468SBram Moolenaar    vim_dir = VIM::evaluate('getcwd()')
4809964e468SBram Moolenaar    file_dir = buf_path.gsub( file_name, '' )
4819964e468SBram Moolenaar    file_dir.gsub!( /\\/, "/" )
4829964e468SBram Moolenaar    vim_dir.gsub!( /\\/, "/" )
4839964e468SBram Moolenaar    vim_dir << "/"
4849964e468SBram Moolenaar    dirs = [ vim_dir, file_dir ]
4859964e468SBram Moolenaar    sdirs = [ "", "./", "../", "../../", "../../../", "../../../../" ]
4869964e468SBram Moolenaar    rails_base = nil
487fc1421ebSBram Moolenaar
4889964e468SBram Moolenaar    dirs.each do |dir|
4899964e468SBram Moolenaar      sdirs.each do |sub|
4909964e468SBram Moolenaar        trail = "%s%s" % [ dir, sub ]
4919964e468SBram Moolenaar        tcfg = "%sconfig" % trail
4929964e468SBram Moolenaar
4939964e468SBram Moolenaar        if File.exists?( tcfg )
4949964e468SBram Moolenaar          rails_base = trail
495fc1421ebSBram Moolenaar          break
496fc1421ebSBram Moolenaar        end
497fc1421ebSBram Moolenaar      end
4989964e468SBram Moolenaar      break if rails_base
4999964e468SBram Moolenaar    end
500eb3593b3SBram Moolenaar
5019964e468SBram Moolenaar    return if rails_base == nil
5029964e468SBram Moolenaar    $:.push rails_base unless $:.index( rails_base )
503551dbcc9SBram Moolenaar
504*4d8f4761SBram Moolenaar    bootfile = rails_base + "config/boot.rb"
505*4d8f4761SBram Moolenaar    envfile = rails_base + "config/environment.rb"
506551dbcc9SBram Moolenaar    if File.exists?( bootfile ) && File.exists?( envfile )
507551dbcc9SBram Moolenaar      begin
508eb3593b3SBram Moolenaar        require bootfile
509551dbcc9SBram Moolenaar        require envfile
5109964e468SBram Moolenaar        begin
511551dbcc9SBram Moolenaar          require 'console_app'
512551dbcc9SBram Moolenaar          require 'console_with_helpers'
5139964e468SBram Moolenaar        rescue Exception
5149964e468SBram Moolenaar          dprint "Rails 1.1+ Error %s" % $!
5159964e468SBram Moolenaar          # assume 1.0
5169964e468SBram Moolenaar        end
5179964e468SBram Moolenaar        #eval( "Rails::Initializer.run" ) #not necessary?
5189964e468SBram Moolenaar        VIM::command('let s:rubycomplete_rails_loaded = 1')
5199964e468SBram Moolenaar        dprint "rails loaded"
5209964e468SBram Moolenaar      rescue Exception
5219964e468SBram Moolenaar        dprint "Rails Error %s" % $!
5229964e468SBram Moolenaar        VIM::evaluate( "s:ErrMsg('Error loading rails environment')" )
523551dbcc9SBram Moolenaar      end
524eb3593b3SBram Moolenaar    end
525fc1421ebSBram Moolenaar  end
526fc1421ebSBram Moolenaar
527fc1421ebSBram Moolenaar  def get_rails_helpers
5289964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
5299964e468SBram Moolenaar    rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
530c236c16dSBram Moolenaar    return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
5319964e468SBram Moolenaar
5329964e468SBram Moolenaar    buf_path = VIM::evaluate('expand("%:p")')
5339964e468SBram Moolenaar    buf_path.gsub!( /\\/, "/" )
5349964e468SBram Moolenaar    path_elm = buf_path.split( "/" )
5359964e468SBram Moolenaar    dprint "buf_path: %s" % buf_path
5369964e468SBram Moolenaar    types = [ "app", "db", "lib", "test", "components", "script" ]
5379964e468SBram Moolenaar
5389964e468SBram Moolenaar    i = nil
5399964e468SBram Moolenaar    ret = []
5409964e468SBram Moolenaar    type = nil
5419964e468SBram Moolenaar    types.each do |t|
5429964e468SBram Moolenaar      i = path_elm.index( t )
5439964e468SBram Moolenaar      break if i
5449964e468SBram Moolenaar    end
5459964e468SBram Moolenaar    type = path_elm[i]
5469964e468SBram Moolenaar    type.downcase!
5479964e468SBram Moolenaar
5489964e468SBram Moolenaar    dprint "type: %s" % type
5499964e468SBram Moolenaar    case type
5509964e468SBram Moolenaar      when "app"
5519964e468SBram Moolenaar        i += 1
5529964e468SBram Moolenaar        subtype = path_elm[i]
5539964e468SBram Moolenaar        subtype.downcase!
5549964e468SBram Moolenaar
5559964e468SBram Moolenaar        dprint "subtype: %s" % subtype
5569964e468SBram Moolenaar        case subtype
5579964e468SBram Moolenaar          when "views"
5589964e468SBram Moolenaar            ret += ActionView::Base.instance_methods
5599964e468SBram Moolenaar            ret += ActionView::Base.methods
5609964e468SBram Moolenaar          when "controllers"
5619964e468SBram Moolenaar            ret += ActionController::Base.instance_methods
5629964e468SBram Moolenaar            ret += ActionController::Base.methods
5639964e468SBram Moolenaar          when "models"
5649964e468SBram Moolenaar            ret += ActiveRecord::Base.instance_methods
5659964e468SBram Moolenaar            ret += ActiveRecord::Base.methods
5669964e468SBram Moolenaar        end
5679964e468SBram Moolenaar
5689964e468SBram Moolenaar      when "db"
5699964e468SBram Moolenaar        ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods
5709964e468SBram Moolenaar        ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods
5719964e468SBram Moolenaar    end
5729964e468SBram Moolenaar
5739964e468SBram Moolenaar    return ret
5749964e468SBram Moolenaar  end
5759964e468SBram Moolenaar
5769964e468SBram Moolenaar  def add_rails_columns( cls )
5779964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
5789964e468SBram Moolenaar    rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
579c236c16dSBram Moolenaar    return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
5809964e468SBram Moolenaar
5819964e468SBram Moolenaar    begin
5829964e468SBram Moolenaar        eval( "#{cls}.establish_connection" )
5839964e468SBram Moolenaar        return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" )
5849964e468SBram Moolenaar        col = eval( "#{cls}.column_names" )
5859964e468SBram Moolenaar        return col if col
5869964e468SBram Moolenaar    rescue
5879964e468SBram Moolenaar        dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ]
5889964e468SBram Moolenaar        return []
5899964e468SBram Moolenaar    end
5909964e468SBram Moolenaar    return []
5919964e468SBram Moolenaar  end
5929964e468SBram Moolenaar
5939964e468SBram Moolenaar  def clean_sel(sel, msg)
594ec7944aaSBram Moolenaar    ret = sel.reject{|x|x.nil?}.uniq
595ec7944aaSBram Moolenaar    ret = ret.grep(/^#{Regexp.quote(msg)}/) if msg != nil
596ec7944aaSBram Moolenaar    ret
5979964e468SBram Moolenaar  end
5989964e468SBram Moolenaar
5999964e468SBram Moolenaar  def get_rails_view_methods
6009964e468SBram Moolenaar    allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
6019964e468SBram Moolenaar    rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
602c236c16dSBram Moolenaar    return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
6039964e468SBram Moolenaar
6049964e468SBram Moolenaar    buf_path = VIM::evaluate('expand("%:p")')
6059964e468SBram Moolenaar    buf_path.gsub!( /\\/, "/" )
6069964e468SBram Moolenaar    pelm = buf_path.split( "/" )
6079964e468SBram Moolenaar    idx = pelm.index( "views" )
6089964e468SBram Moolenaar
6099964e468SBram Moolenaar    return [] unless idx
6109964e468SBram Moolenaar    idx += 1
6119964e468SBram Moolenaar
6129964e468SBram Moolenaar    clspl = pelm[idx].camelize.pluralize
6139964e468SBram Moolenaar    cls = clspl.singularize
6149964e468SBram Moolenaar
6159964e468SBram Moolenaar    ret = []
6169964e468SBram Moolenaar    begin
6179964e468SBram Moolenaar      ret += eval( "#{cls}.instance_methods" )
6189964e468SBram Moolenaar      ret += eval( "#{clspl}Helper.instance_methods" )
6199964e468SBram Moolenaar    rescue Exception
6209964e468SBram Moolenaar      dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ]
6219964e468SBram Moolenaar    end
6229964e468SBram Moolenaar
6239964e468SBram Moolenaar    return ret
6249964e468SBram Moolenaar  end
6259964e468SBram Moolenaar# }}} buffer analysis magic
6269964e468SBram Moolenaar
6279964e468SBram Moolenaar# {{{ main completion code
6289964e468SBram Moolenaar  def self.preload_rails
6299964e468SBram Moolenaar    a = VimRubyCompletion.new
630d09091d4SBram Moolenaar    if VIM::evaluate("has('nvim')") == 0
631d09091d4SBram Moolenaar      require 'thread'
6329964e468SBram Moolenaar      Thread.new(a) do |b|
6339964e468SBram Moolenaar        begin
6349964e468SBram Moolenaar        b.load_rails
6359964e468SBram Moolenaar        rescue
6369964e468SBram Moolenaar        end
6379964e468SBram Moolenaar      end
638d09091d4SBram Moolenaar    end
6399964e468SBram Moolenaar    a.load_rails
6409964e468SBram Moolenaar  rescue
6419964e468SBram Moolenaar  end
6429964e468SBram Moolenaar
6439964e468SBram Moolenaar  def self.get_completions(base)
6449964e468SBram Moolenaar    b = VimRubyCompletion.new
6459964e468SBram Moolenaar    b.get_completions base
646fc1421ebSBram Moolenaar  end
647fc1421ebSBram Moolenaar
648c6249bb2SBram Moolenaar  def get_completions(base)
6499964e468SBram Moolenaar    loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
650c236c16dSBram Moolenaar    if loading_allowed.to_i == 1
651c6249bb2SBram Moolenaar      load_requires
652fc1421ebSBram Moolenaar      load_rails
6539964e468SBram Moolenaar    end
654fc1421ebSBram Moolenaar
65589bcfda6SBram Moolenaar    want_gems = VIM::evaluate("get(g:, 'rubycomplete_load_gemfile')")
65689bcfda6SBram Moolenaar    load_gems unless want_gems.to_i.zero?
65789bcfda6SBram Moolenaar
658fc1421ebSBram Moolenaar    input = VIM::Buffer.current.line
659d8fc5c0bSBram Moolenaar    cpos = VIM::Window.current.cursor[1] - 1
6609964e468SBram Moolenaar    input = input[0..cpos]
661d8fc5c0bSBram Moolenaar    input += base
6629964e468SBram Moolenaar    input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters
6639964e468SBram Moolenaar    input.sub!(/self\./, '')
6649964e468SBram Moolenaar    input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '')
665c6249bb2SBram Moolenaar
6669964e468SBram Moolenaar    dprint 'input %s' % input
667d8fc5c0bSBram Moolenaar    message = nil
668d8fc5c0bSBram Moolenaar    receiver = nil
6699964e468SBram Moolenaar    methods = []
6709964e468SBram Moolenaar    variables = []
6719964e468SBram Moolenaar    classes = []
6729964e468SBram Moolenaar    constants = []
673c6249bb2SBram Moolenaar
674c6249bb2SBram Moolenaar    case input
675d8fc5c0bSBram Moolenaar      when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp
676c6249bb2SBram Moolenaar        receiver = $1
677c6249bb2SBram Moolenaar        message = Regexp.quote($2)
6789964e468SBram Moolenaar        methods = Regexp.instance_methods(true)
679c6249bb2SBram Moolenaar
680d8fc5c0bSBram Moolenaar      when /^([^\]]*\])\.([^.]*)$/ # Array
681c6249bb2SBram Moolenaar        receiver = $1
682c6249bb2SBram Moolenaar        message = Regexp.quote($2)
6839964e468SBram Moolenaar        methods = Array.instance_methods(true)
684c6249bb2SBram Moolenaar
685d8fc5c0bSBram Moolenaar      when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash
686c6249bb2SBram Moolenaar        receiver = $1
687c6249bb2SBram Moolenaar        message = Regexp.quote($2)
6889964e468SBram Moolenaar        methods = Proc.instance_methods(true) | Hash.instance_methods(true)
689c6249bb2SBram Moolenaar
690d8fc5c0bSBram Moolenaar      when /^(:[^:.]*)$/ # Symbol
6919964e468SBram Moolenaar        dprint "symbol"
692c6249bb2SBram Moolenaar        if Symbol.respond_to?(:all_symbols)
693d8fc5c0bSBram Moolenaar          receiver = $1
6949964e468SBram Moolenaar          message = $1.sub( /:/, '' )
6959964e468SBram Moolenaar          methods = Symbol.all_symbols.collect{|s| s.id2name}
6969964e468SBram Moolenaar          methods.delete_if { |c| c.match( /'/ ) }
697c6249bb2SBram Moolenaar        end
698c6249bb2SBram Moolenaar
6992ed639abSBram Moolenaar      when /^::([A-Z][^:\.\(]*)?$/ # Absolute Constant or class methods
7009964e468SBram Moolenaar        dprint "const or cls"
701c6249bb2SBram Moolenaar        receiver = $1
7022ed639abSBram Moolenaar        methods = Object.constants.collect{ |c| c.to_s }.grep(/^#{receiver}/)
703c6249bb2SBram Moolenaar
7041d68952aSBram Moolenaar      when /^(((::)?[A-Z][^:.\(]*)+?)::?([^:.]*)$/ # Constant or class methods
705c6249bb2SBram Moolenaar        receiver = $1
706c6249bb2SBram Moolenaar        message = Regexp.quote($4)
7079964e468SBram Moolenaar        dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ]
7089964e468SBram Moolenaar        load_buffer_class( receiver )
709d09091d4SBram Moolenaar        load_buffer_module( receiver )
710c6249bb2SBram Moolenaar        begin
7112ed639abSBram Moolenaar          constants = eval("#{receiver}.constants").collect{ |c| c.to_s }.grep(/^#{message}/)
7122ed639abSBram Moolenaar          methods = eval("#{receiver}.methods").collect{ |m| m.to_s }.grep(/^#{message}/)
713c6249bb2SBram Moolenaar        rescue Exception
7149964e468SBram Moolenaar          dprint "exception: %s" % $!
7152ed639abSBram Moolenaar          constants = []
7169964e468SBram Moolenaar          methods = []
717c6249bb2SBram Moolenaar        end
718c6249bb2SBram Moolenaar
719d8fc5c0bSBram Moolenaar      when /^(:[^:.]+)\.([^.]*)$/ # Symbol
7209964e468SBram Moolenaar        dprint "symbol"
721c6249bb2SBram Moolenaar        receiver = $1
722c6249bb2SBram Moolenaar        message = Regexp.quote($2)
7239964e468SBram Moolenaar        methods = Symbol.instance_methods(true)
724c6249bb2SBram Moolenaar
725d8fc5c0bSBram Moolenaar      when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric
7269964e468SBram Moolenaar        dprint "numeric"
727c6249bb2SBram Moolenaar        receiver = $1
728c6249bb2SBram Moolenaar        message = Regexp.quote($4)
729c6249bb2SBram Moolenaar        begin
7309964e468SBram Moolenaar          methods = eval(receiver).methods
731c6249bb2SBram Moolenaar        rescue Exception
7329964e468SBram Moolenaar          methods = []
733c6249bb2SBram Moolenaar        end
734c6249bb2SBram Moolenaar
735d8fc5c0bSBram Moolenaar      when /^(\$[^.]*)$/ #global
7369964e468SBram Moolenaar        dprint "global"
7379964e468SBram Moolenaar        methods = global_variables.grep(Regexp.new(Regexp.quote($1)))
738c6249bb2SBram Moolenaar
7391d68952aSBram Moolenaar      when /^((\.?[^.]+)+?)\.([^.]*)$/ # variable
7409964e468SBram Moolenaar        dprint "variable"
741c6249bb2SBram Moolenaar        receiver = $1
742c6249bb2SBram Moolenaar        message = Regexp.quote($3)
743fc1421ebSBram Moolenaar        load_buffer_class( receiver )
744c6249bb2SBram Moolenaar
745c6249bb2SBram Moolenaar        cv = eval("self.class.constants")
746d8fc5c0bSBram Moolenaar        vartype = get_var_type( receiver )
7479964e468SBram Moolenaar        dprint "vartype: %s" % vartype
74889bcfda6SBram Moolenaar
74989bcfda6SBram Moolenaar        invalid_vartype = ['', "gets"]
75089bcfda6SBram Moolenaar        if !invalid_vartype.include?(vartype)
751fc1421ebSBram Moolenaar          load_buffer_class( vartype )
752fc1421ebSBram Moolenaar
753fc1421ebSBram Moolenaar          begin
7549964e468SBram Moolenaar            methods = eval("#{vartype}.instance_methods")
7559964e468SBram Moolenaar            variables = eval("#{vartype}.instance_variables")
756fc1421ebSBram Moolenaar          rescue Exception
7579964e468SBram Moolenaar            dprint "load_buffer_class err: %s" % $!
758fc1421ebSBram Moolenaar          end
759c6249bb2SBram Moolenaar        elsif (cv).include?(receiver)
760c6249bb2SBram Moolenaar          # foo.func and foo is local var.
7619964e468SBram Moolenaar          methods = eval("#{receiver}.methods")
7629964e468SBram Moolenaar          vartype = receiver
763c6249bb2SBram Moolenaar        elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
7649964e468SBram Moolenaar          vartype = receiver
765c6249bb2SBram Moolenaar          # Foo::Bar.func
766c6249bb2SBram Moolenaar          begin
7679964e468SBram Moolenaar            methods = eval("#{receiver}.methods")
768c6249bb2SBram Moolenaar          rescue Exception
769c6249bb2SBram Moolenaar          end
770c6249bb2SBram Moolenaar        else
771c6249bb2SBram Moolenaar          # func1.func2
772c6249bb2SBram Moolenaar          ObjectSpace.each_object(Module){|m|
773c6249bb2SBram Moolenaar            next if m.name != "IRB::Context" and
774c6249bb2SBram Moolenaar              /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
7759964e468SBram Moolenaar            methods.concat m.instance_methods(false)
776c6249bb2SBram Moolenaar          }
777c6249bb2SBram Moolenaar        end
77889bcfda6SBram Moolenaar        variables += add_rails_columns( "#{vartype}" ) if vartype && !invalid_vartype.include?(vartype)
779c6249bb2SBram Moolenaar
780d8fc5c0bSBram Moolenaar      when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/
781d8fc5c0bSBram Moolenaar        message = $1
7829964e468SBram Moolenaar        methods = Range.instance_methods(true)
783c6249bb2SBram Moolenaar
784d8fc5c0bSBram Moolenaar      when /^\.([^.]*)$/ # unknown(maybe String)
785c6249bb2SBram Moolenaar        message = Regexp.quote($1)
7869964e468SBram Moolenaar        methods = String.instance_methods(true)
787c6249bb2SBram Moolenaar
788c6249bb2SBram Moolenaar    else
7899964e468SBram Moolenaar      dprint "default/other"
7909964e468SBram Moolenaar      inclass = eval( VIM::evaluate("s:IsInClassDef()") )
791c6249bb2SBram Moolenaar
792fc1421ebSBram Moolenaar      if inclass != nil
7939964e468SBram Moolenaar        dprint "inclass"
794fc1421ebSBram Moolenaar        classdef = "%s\n" % VIM::Buffer.current[ inclass.min ]
795fc1421ebSBram Moolenaar        found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef )
796fc1421ebSBram Moolenaar
797fc1421ebSBram Moolenaar        if found != nil
798fc1421ebSBram Moolenaar          receiver = $1
799fc1421ebSBram Moolenaar          message = input
800fc1421ebSBram Moolenaar          load_buffer_class( receiver )
801eb3593b3SBram Moolenaar          begin
8029964e468SBram Moolenaar            methods = eval( "#{receiver}.instance_methods" )
8039964e468SBram Moolenaar            variables += add_rails_columns( "#{receiver}" )
804eb3593b3SBram Moolenaar          rescue Exception
805eb3593b3SBram Moolenaar            found = nil
806eb3593b3SBram Moolenaar          end
807fc1421ebSBram Moolenaar        end
808fc1421ebSBram Moolenaar      end
809fc1421ebSBram Moolenaar
810fc1421ebSBram Moolenaar      if inclass == nil || found == nil
8119964e468SBram Moolenaar        dprint "inclass == nil"
8129964e468SBram Moolenaar        methods = get_buffer_methods
8139964e468SBram Moolenaar        methods += get_rails_view_methods
8149964e468SBram Moolenaar
8159964e468SBram Moolenaar        cls_const = Class.constants
8169964e468SBram Moolenaar        constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) }
8179964e468SBram Moolenaar        classes = eval("self.class.constants") - constants
8189964e468SBram Moolenaar        classes += get_buffer_classes
8199964e468SBram Moolenaar        classes += get_buffer_modules
8209964e468SBram Moolenaar
8219964e468SBram Moolenaar        include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace")
8229964e468SBram Moolenaar        ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1"
823d8fc5c0bSBram Moolenaar        message = receiver = input
824d8fc5c0bSBram Moolenaar      end
8259964e468SBram Moolenaar
8269964e468SBram Moolenaar      methods += get_rails_helpers
8279964e468SBram Moolenaar      methods += Kernel.public_methods
828d8fc5c0bSBram Moolenaar    end
829d8fc5c0bSBram Moolenaar
8309964e468SBram Moolenaar    include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object")
8319964e468SBram Moolenaar    methods = clean_sel( methods, message )
8329964e468SBram Moolenaar    methods = (methods-Object.instance_methods) if include_object == "0"
8339964e468SBram Moolenaar    rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods
8349964e468SBram Moolenaar    methods = (methods-rbcmeth)
8359964e468SBram Moolenaar
8369964e468SBram Moolenaar    variables = clean_sel( variables, message )
8379964e468SBram Moolenaar    classes = clean_sel( classes, message ) - ["VimRubyCompletion"]
8389964e468SBram Moolenaar    constants = clean_sel( constants, message )
8399964e468SBram Moolenaar
8409964e468SBram Moolenaar    valid = []
841ec7944aaSBram Moolenaar    valid += methods.collect { |m| { :name => m.to_s, :type => 'm' } }
842ec7944aaSBram Moolenaar    valid += variables.collect { |v| { :name => v.to_s, :type => 'v' } }
843ec7944aaSBram Moolenaar    valid += classes.collect { |c| { :name => c.to_s, :type => 't' } }
844ec7944aaSBram Moolenaar    valid += constants.collect { |d| { :name => d.to_s, :type => 'd' } }
8459964e468SBram Moolenaar    valid.sort! { |x,y| x[:name] <=> y[:name] }
846c6249bb2SBram Moolenaar
847c6249bb2SBram Moolenaar    outp = ""
848fc1421ebSBram Moolenaar
849fc1421ebSBram Moolenaar    rg = 0..valid.length
850fc1421ebSBram Moolenaar    rg.step(150) do |x|
851fc1421ebSBram Moolenaar      stpos = 0+x
852fc1421ebSBram Moolenaar      enpos = 150+x
853ec7944aaSBram 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)} }
854c6249bb2SBram Moolenaar      outp.sub!(/,$/, '')
855fc1421ebSBram Moolenaar
856fc1421ebSBram Moolenaar      VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp)
857fc1421ebSBram Moolenaar      outp = ""
858fc1421ebSBram Moolenaar    end
859c6249bb2SBram Moolenaar  end
8609964e468SBram Moolenaar# }}} main completion code
861c6249bb2SBram Moolenaar
8629964e468SBram Moolenaarend # VimRubyCompletion
863eb3593b3SBram Moolenaar# }}} ruby completion
864c6249bb2SBram MoolenaarRUBYEOF
865c6249bb2SBram Moolenaarendfunction
866c6249bb2SBram Moolenaar
8679964e468SBram Moolenaarlet s:rubycomplete_rails_loaded = 0
868fc1421ebSBram Moolenaar
869c6249bb2SBram Moolenaarcall s:DefRuby()
8709964e468SBram Moolenaar"}}} ruby-side code
8719964e468SBram Moolenaar
8729964e468SBram Moolenaar" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl:
873