Permalink
5133 lines (4741 sloc) 183 KB
" autoload/rails.vim
" Author: Tim Pope <http://tpo.pe/>
" Install this file as autoload/rails.vim.
if exists('g:autoloaded_rails') || &cp
finish
endif
let g:autoloaded_rails = '5.2'
" Utility Functions {{{1
let s:app_prototype = {}
let s:file_prototype = {}
let s:buffer_prototype = {}
let s:readable_prototype = {}
function! s:add_methods(namespace, method_names)
for name in a:method_names
let s:{a:namespace}_prototype[name] = s:function('s:'.a:namespace.'_'.name)
endfor
endfunction
function! s:function(name)
return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
endfunction
function! s:sub(str,pat,rep)
return substitute(a:str,'\v\C'.a:pat,a:rep,'')
endfunction
function! s:gsub(str,pat,rep)
return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
endfunction
function! s:startswith(string,prefix)
return strpart(a:string, 0, strlen(a:prefix)) ==# a:prefix
endfunction
function! s:endswith(string,suffix)
return strpart(a:string, len(a:string) - len(a:suffix), len(a:suffix)) ==# a:suffix
endfunction
function! s:uniq(list) abort
let i = 0
let seen = {}
while i < len(a:list)
if (a:list[i] ==# '' && exists('empty')) || has_key(seen,a:list[i])
call remove(a:list,i)
elseif a:list[i] ==# ''
let i += 1
let empty = 1
else
let seen[a:list[i]] = 1
let i += 1
endif
endwhile
return a:list
endfunction
function! s:getlist(arg, key)
let value = get(a:arg, a:key, [])
return type(value) == type([]) ? copy(value) : [value]
endfunction
function! s:split(arg, ...)
return type(a:arg) == type([]) ? copy(a:arg) : split(a:arg, a:0 ? a:1 : "\n")
endfunction
function! rails#lencmp(i1, i2) abort
return len(a:i1) - len(a:i2)
endfunc
function! s:escarg(p)
return s:gsub(a:p,'[ !%#]','\\&')
endfunction
function! s:esccmd(p)
return s:gsub(a:p,'[!%#]','\\&')
endfunction
function! s:rquote(str)
if a:str =~ '^[A-Za-z0-9_/.:-]\+$'
return a:str
elseif &shell =~? 'cmd'
return '"'.s:gsub(s:gsub(a:str, '"', '""'), '\%', '"%"').'"'
else
return shellescape(a:str)
endif
endfunction
function! s:fnameescape(file) abort
if exists('*fnameescape')
return fnameescape(a:file)
else
return escape(a:file," \t\n*?[{`$\\%#'\"|!<")
endif
endfunction
function! s:sname()
return fnamemodify(s:file,':t:r')
endfunction
function! s:pop_command()
if exists("s:command_stack") && len(s:command_stack) > 0
exe remove(s:command_stack,-1)
endif
endfunction
function! s:push_chdir(...)
if !exists("s:command_stack") | let s:command_stack = [] | endif
if exists("b:rails_root") && (a:0 ? getcwd() !=# rails#app().path() : !s:startswith(getcwd(), rails#app().path()))
let chdir = exists("*haslocaldir") && haslocaldir() ? "lchdir " : "chdir "
call add(s:command_stack,chdir.s:escarg(getcwd()))
exe chdir.s:escarg(rails#app().path())
else
call add(s:command_stack,"")
endif
endfunction
function! s:app_path(...) dict
if a:0 && a:1 =~# '\%(^\|^\w*:\)[\/]'
return a:1
else
return join([self.root]+a:000,'/')
endif
endfunction
function! s:app_has_path(path) dict
return getftime(self.path(a:path)) != -1
endfunction
function! s:app_has_file(file) dict
return filereadable(self.path(a:file))
endfunction
function! s:app_find_file(name, ...) dict abort
let trim = strlen(self.path())+1
if a:0
let path = s:pathjoin(map(s:pathsplit(a:1),'self.path(v:val)'))
else
let path = s:pathjoin([self.path()])
endif
let suffixesadd = s:pathjoin(get(a:000,1,&suffixesadd))
let default = get(a:000,2,'')
let oldsuffixesadd = &l:suffixesadd
try
let &suffixesadd = suffixesadd
" Versions before 7.1.256 returned directories from findfile
if type(default) == type(0) && (v:version < 702 || default == -1)
let all = findfile(a:name,path,-1)
if v:version < 702
call filter(all,'!isdirectory(v:val)')
endif
call map(all,'s:gsub(strpart(fnamemodify(v:val,":p"),trim),"\\\\","/")')
return default < 0 ? all : get(all,default-1,'')
elseif type(default) == type(0)
let found = findfile(a:name,path,default)
else
let i = 1
let found = findfile(a:name,path)
while v:version < 702 && found != "" && isdirectory(found)
let i += 1
let found = findfile(a:name,path,i)
endwhile
endif
return found == "" ? default : s:gsub(strpart(fnamemodify(found,':p'),trim),'\\','/')
finally
let &l:suffixesadd = oldsuffixesadd
endtry
endfunction
call s:add_methods('app',['path','has_path','has_file','find_file'])
" Split a path into a list.
function! s:pathsplit(path) abort
if type(a:path) == type([]) | return copy(a:path) | endif
return split(s:gsub(a:path, '\\ ', ' '), ',')
endfunction
" Convert a list to a path.
function! s:pathjoin(...) abort
let i = 0
let path = ""
while i < a:0
if type(a:000[i]) == type([])
let path .= "," . escape(join(a:000[i], ','), ' ')
else
let path .= "," . a:000[i]
endif
let i += 1
endwhile
return substitute(path,'^,','','')
endfunction
function! s:readable_end_of(lnum) dict abort
if a:lnum == 0
return 0
endif
let cline = self.getline(a:lnum)
let spc = matchstr(cline,'^\s*')
let endpat = '\<end\>'
if matchstr(self.getline(a:lnum+1),'^'.spc) && !matchstr(self.getline(a:lnum+1),'^'.spc.endpat) && matchstr(cline,endpat)
return a:lnum
endif
let endl = a:lnum
while endl <= self.line_count()
let endl += 1
if self.getline(endl) =~ '^'.spc.endpat
return endl
elseif self.getline(endl) =~ '^=begin\>'
while self.getline(endl) !~ '^=end\>' && endl <= self.line_count()
let endl += 1
endwhile
let endl += 1
elseif self.getline(endl) !~ '^'.spc && self.getline(endl) !~ '^\s*\%(#.*\)\=$'
return 0
endif
endwhile
return 0
endfunction
function! s:endof(lnum)
return rails#buffer().end_of(a:lnum)
endfunction
function! s:readable_last_opening_line(start,pattern,limit) dict abort
let line = a:start
while line > a:limit && self.getline(line) !~ a:pattern
let line -= 1
endwhile
if self.name() =~# '\.\%(rb\|rake\)$'
let lend = self.end_of(line)
else
let lend = -1
endif
if line > a:limit && (lend < 0 || lend >= a:start)
return line
else
return -1
endif
endfunction
function! s:lastopeningline(pattern,limit,start)
return rails#buffer().last_opening_line(a:start,a:pattern,a:limit)
endfunction
function! s:readable_define_pattern() dict abort
if self.name() =~ '\.yml\%(\.example\)\=$'
return '^\%(\h\k*:\)\@='
endif
let define = '^\s*def\s\+\(self\.\)\='
if self.name() =~# '\.rake$'
let define .= "\\\|^\\s*\\%(task\\\|file\\)\\s\\+[:'\"]"
endif
if self.name() =~# '/schema\.rb$'
let define .= "\\\|^\\s*create_table\\s\\+[:'\"]"
endif
if self.name() =~# '/\.erb$'
let define .= '\|\<id=["'']\='
endif
if self.name() =~# '/\.haml$'
let define .= '\|^\s*\%(%\w*\)\=\%(\.[[:alnum:]_-]\+\)*#'
endif
if self.type_name('test')
let define .= '\|^\s*test\s*[''"]'
endif
return define
endfunction
function! s:readable_last_method_line(start) dict abort
return self.last_opening_line(a:start,self.define_pattern(),0)
endfunction
function! s:lastmethodline(start)
return rails#buffer().last_method_line(a:start)
endfunction
function! s:readable_last_method(start) dict abort
let lnum = self.last_method_line(a:start)
let line = self.getline(lnum)
if line =~# '^\s*test\s*\([''"]\).*\1'
let string = matchstr(line,'^\s*\w\+\s*\([''"]\)\zs.*\ze\1')
return 'test_'.s:gsub(string,' +','_')
elseif lnum
return s:sub(matchstr(line,'\%('.self.define_pattern().'\)\zs\h\%(\k\|[:.]\)*[?!=]\='),':$','')
else
return ""
endif
endfunction
function! s:lastmethod(...)
return rails#buffer().last_method(a:0 ? a:1 : line("."))
endfunction
function! s:readable_format(start) dict abort
let format = matchstr(self.getline(a:start), '\%(:formats *=>\|\<formats:\) *\[\= *[:''"]\zs\w\+')
if format !=# ''
return format
endif
if self.type_name('view')
let format = fnamemodify(self.path(),':r:e')
if format == ''
return get({'rhtml': 'html', 'rxml': 'xml', 'rjs': 'js', 'haml': 'html'},fnamemodify(self.path(),':e'),'')
else
return format
endif
endif
let rline = self.last_opening_line(a:start,'\C^\s*\%(mail\>.*\|respond_to\)\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|',self.last_method_line(a:start))
if rline
let variable = matchstr(self.getline(rline),'\C^\s*\%(mail\>.*\|respond_to\)\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|')
let line = a:start
while line > rline
let match = matchstr(self.getline(line),'\C^\s*'.variable.'\s*\.\s*\zs\h\k*')
if match != ''
return match
endif
let line -= 1
endwhile
endif
return self.type_name('mailer') ? 'text' : 'html'
endfunction
function! s:format()
return rails#buffer().format(line('.'))
endfunction
call s:add_methods('readable',['end_of','last_opening_line','last_method_line','last_method','format','define_pattern'])
function! s:readable_find_affinity() dict abort
let f = self.name()
let all = self.app().projections()
for pattern in reverse(sort(filter(keys(all), 'v:val =~# "^[^*{}]*\\*[^*{}]*$"'), s:function('rails#lencmp')))
if !has_key(all[pattern], 'affinity')
continue
endif
let [prefix, suffix; _] = split(pattern, '\*', 1)
if s:startswith(f, prefix) && s:endswith(f, suffix)
let root = f[strlen(prefix) : -strlen(suffix)-1]
return [all[pattern].affinity, root]
endif
endfor
return ['', '']
endfunction
function! s:controller(...)
return rails#buffer().controller_name(a:0 ? a:1 : 0)
endfunction
function! s:readable_controller_name(...) dict abort
let f = self.name()
if has_key(self,'getvar') && self.getvar('rails_controller') != ''
return self.getvar('rails_controller')
endif
let [affinity, root] = self.find_affinity()
if affinity ==# 'controller'
return root
elseif affinity ==# 'resource'
return rails#pluralize(root)
endif
if f =~ '\<app/views/layouts/'
return s:sub(f,'.*<app/views/layouts/(.{-})\..*','\1')
elseif f =~ '\<app/views/'
return s:sub(f,'.*<app/views/(.{-})/\w+%(\.[[:alnum:]_+]+)=\.\w+$','\1')
elseif f =~ '\<app/helpers/.*_helper\.rb$'
return s:sub(f,'.*<app/helpers/(.{-})_helper\.rb$','\1')
elseif f =~ '\<app/controllers/.*\.rb$'
return s:sub(f,'.*<app/controllers/(.{-})%(_controller)=\.rb$','\1')
elseif f =~ '\<app/mailers/.*\.rb$'
return s:sub(f,'.*<app/mailers/(.{-})\.rb$','\1')
elseif f =~ '\<app/apis/.*_api\.rb$'
return s:sub(f,'.*<app/apis/(.{-})_api\.rb$','\1')
elseif f =~ '\<app/jobs/.*\.rb$'
return s:sub(f,'.*<app/jobs/(.{-})%(_job)=\.rb$','\1')
elseif f =~ '\<test/\%(functional\|controllers\)/.*_test\.rb$'
return s:sub(f,'.*<test/%(functional|controllers)/(.{-})%(_controller)=_test\.rb$','\1')
elseif f =~ '\<test/\%(unit/\)\?helpers/.*_helper_test\.rb$'
return s:sub(f,'.*<test/%(unit/)?helpers/(.{-})_helper_test\.rb$','\1')
elseif f =~ '\<spec/controllers/.*_spec\.rb$'
return s:sub(f,'.*<spec/controllers/(.{-})%(_controller)=_spec\.rb$','\1')
elseif f =~ '\<spec/jobs/.*_spec\.rb$'
return s:sub(f,'.*<spec/jobs/(.{-})%(_job)=_spec\.rb$','\1')
elseif f =~ '\<spec/helpers/.*_helper_spec\.rb$'
return s:sub(f,'.*<spec/helpers/(.{-})_helper_spec\.rb$','\1')
elseif f =~ '\<spec/views/.*/\w\+_view_spec\.rb$'
return s:sub(f,'.*<spec/views/(.{-})/\w+_view_spec\.rb$','\1')
elseif f =~ '\<app/models/.*\.rb$' && self.type_name('mailer')
return s:sub(f,'.*<app/models/(.{-})\.rb$','\1')
elseif f =~ '\<\%(public\|app/assets\)/stylesheets/.*\.css\%(\.\w\+\)\=$'
return s:sub(f,'.*<%(public|app/assets)/stylesheets/(.{-})\.css%(\.\w+)=$','\1')
elseif f =~ '\<\%(public\|app/assets\)/javascripts/.*\.js\%(\.\w\+\)\=$'
return s:sub(f,'.*<%(public|app/assets)/javascripts/(.{-})\.js%(\.\w+)=$','\1')
elseif a:0 && a:1
return rails#pluralize(self.model_name())
endif
return ""
endfunction
function! s:model(...)
return rails#buffer().model_name(a:0 ? a:1 : 0)
endfunction
function! s:readable_model_name(...) dict abort
let f = self.name()
if has_key(self,'getvar') && self.getvar('rails_model') != ''
return self.getvar('rails_model')
endif
let [affinity, root] = self.find_affinity()
if affinity ==# 'model'
return root
elseif affinity ==# 'collection'
return rails#singularize(root)
endif
if f =~ '\<app/models/.*_observer.rb$'
return s:sub(f,'.*<app/models/(.*)_observer\.rb$','\1')
elseif f =~ '\<app/models/.*\.rb$'
return s:sub(f,'.*<app/models/(.*)\.rb$','\1')
elseif f =~ '\<test/\%(unit\|models\)/.*_observer_test\.rb$'
return s:sub(f,'.*<test/unit/(.*)_observer_test\.rb$','\1')
elseif f =~ '\<test/\%(unit\|models\)/.*_test\.rb$'
return s:sub(f,'.*<test/%(unit|models)/(.*)_test\.rb$','\1')
elseif f =~ '\<spec/models/.*_spec\.rb$'
return s:sub(f,'.*<spec/models/(.*)_spec\.rb$','\1')
elseif f =~ '\<\%(test\|spec\)/blueprints/.*\.rb$'
return s:sub(f,'.*<%(test|spec)/blueprints/(.{-})%(_blueprint)=\.rb$','\1')
elseif f =~ '\<\%(test\|spec\)/exemplars/.*_exemplar\.rb$'
return s:sub(f,'.*<%(test|spec)/exemplars/(.*)_exemplar\.rb$','\1')
elseif f =~ '\<\%(test/\|spec/\)\=factories/.*_factory\.rb$'
return s:sub(f,'.*<%(test/|spec/)=factories/(.{-})_factory.rb$','\1')
elseif f =~ '\<\%(test/\|spec/\)\=fabricators/.*\.rb$'
return s:sub(f,'.*<%(test/|spec/)=fabricators/(.{-})_fabricator.rb$','\1')
elseif f =~ '\<\%(test\|spec\)/\%(fixtures\|factories\|fabricators\)/.*\.\w\+$'
return rails#singularize(s:sub(f,'.*<%(test|spec)/\w+/(.*)\.\w+$','\1'))
elseif a:0 && a:1
return rails#singularize(self.controller_name())
endif
return ""
endfunction
call s:add_methods('readable', ['find_affinity', 'controller_name', 'model_name'])
function! s:readfile(path,...)
let nr = bufnr('^'.a:path.'$')
if nr < 0 && exists('+shellslash') && ! &shellslash
let nr = bufnr('^'.s:gsub(a:path,'/','\\').'$')
endif
if bufloaded(nr)
return getbufline(nr,1,a:0 ? a:1 : '$')
elseif !filereadable(a:path)
return []
elseif a:0
return readfile(a:path,'',a:1)
else
return readfile(a:path)
endif
endfunction
function! s:file_lines() dict abort
let ftime = getftime(self.path())
if ftime > get(self,'last_lines_ftime',0)
let self.last_lines = s:readfile(self.path())
let self.last_lines_ftime = ftime
endif
return get(self,'last_lines',[])
endfunction
function! s:file_getline(lnum,...) dict abort
if a:0
return self.lines()[a:lnum-1 : a:1-1]
else
return self.lines()[a:lnum-1]
endif
endfunction
function! s:buffer_lines() dict abort
return self.getline(1,'$')
endfunction
function! s:buffer_getline(...) dict abort
if a:0 == 1
return get(call('getbufline',[self.number()]+a:000),0,'')
else
return call('getbufline',[self.number()]+a:000)
endif
endfunction
function! s:readable_line_count() dict abort
return len(self.lines())
endfunction
function! s:environment()
if exists('$RAILS_ENV')
return $RAILS_ENV
elseif exists('$RACK_ENV')
return $RACK_ENV
else
return "development"
endif
endfunction
function! s:Complete_environments(...)
return s:completion_filter(rails#app().environments(),a:0 ? a:1 : "")
endfunction
function! s:warn(str)
echohl WarningMsg
echomsg a:str
echohl None
" Sometimes required to flush output
echo ""
let v:warningmsg = a:str
endfunction
function! s:error(str)
echohl ErrorMsg
echomsg a:str
echohl None
let v:errmsg = a:str
return ''
endfunction
function! s:debug(str)
if exists("g:rails_debug") && g:rails_debug
echohl Debug
echomsg a:str
echohl None
endif
endfunction
function! s:buffer_getvar(varname) dict abort
return getbufvar(self.number(),a:varname)
endfunction
function! s:buffer_setvar(varname, val) dict abort
return setbufvar(self.number(),a:varname,a:val)
endfunction
call s:add_methods('buffer',['getvar','setvar'])
" }}}1
" Public Interface {{{1
function! rails#underscore(str)
let str = s:gsub(a:str,'::','/')
let str = s:gsub(str,'(\u+)(\u\l)','\1_\2')
let str = s:gsub(str,'(\l|\d)(\u)','\1_\2')
let str = tolower(str)
return str
endfunction
function! rails#camelize(str)
let str = s:gsub(a:str,'/(.=)','::\u\1')
let str = s:gsub(str,'%([_-]|<)(.)','\u\1')
return str
endfunction
function! rails#singularize(word)
" Probably not worth it to be as comprehensive as Rails but we can
" still hit the common cases.
let word = a:word
if word =~? '\.js$' || word == ''
return word
endif
let word = s:sub(word,'eople$','ersons')
let word = s:sub(word,'%([Mm]ov|[aeio])@<!ies$','ys')
let word = s:sub(word,'xe[ns]$','xs')
let word = s:sub(word,'ves$','fs')
let word = s:sub(word,'ss%(es)=$','sss')
let word = s:sub(word,'s$','')
let word = s:sub(word,'%([nrt]ch|tatus|lias)\zse$','')
let word = s:sub(word,'%(nd|rt)\zsice$','ex')
return word
endfunction
function! rails#pluralize(word)
let word = a:word
if word == ''
return word
endif
let word = s:sub(word,'[aeio]@<!y$','ie')
let word = s:sub(word,'%(nd|rt)@<=ex$','ice')
let word = s:sub(word,'%([sxz]|[cs]h)$','&e')
let word = s:sub(word,'f@<!f$','ve')
let word .= 's'
let word = s:sub(word,'ersons$','eople')
return word
endfunction
function! rails#app(...) abort
let root = s:sub(a:0 ? a:1 : get(b:, 'rails_root', ''), '[\/]$', '')
if !empty(root)
if !has_key(s:apps, root) && filereadable(root . '/config/environment.rb')
let s:apps[root] = deepcopy(s:app_prototype)
let s:apps[root].root = root
let s:apps[root]._root = root
endif
return get(s:apps, root, {})
endif
return {}
endfunction
function! rails#buffer(...)
return extend(extend({'#': bufnr(a:0 ? a:1 : '%')},s:buffer_prototype,'keep'),s:readable_prototype,'keep')
endfunction
function! s:buffer_app() dict abort
if self.getvar('rails_root') != ''
return rails#app(self.getvar('rails_root'))
else
throw 'Not in a Rails app'
endif
endfunction
function! s:readable_app() dict abort
return self._app
endfunction
function! RailsRevision()
return 1000*matchstr(g:autoloaded_rails,'^\d\+')+matchstr(g:autoloaded_rails,'[1-9]\d*$')
endfunction
function! RailsRoot()
if exists("b:rails_root")
return b:rails_root
else
return ""
endif
endfunction
function! s:app_file(name) dict abort
return extend(extend({'_app': self, '_name': a:name}, s:file_prototype,'keep'),s:readable_prototype,'keep')
endfunction
function! s:readable_relative() dict abort
return self.name()
endfunction
function! s:readable_absolute() dict abort
return self.path()
endfunction
function! s:readable_spec() dict abort
return self.path()
endfunction
function! s:file_path() dict abort
return self.app().path(self._name)
endfunction
function! s:file_name() dict abort
return self._name
endfunction
function! s:buffer_number() dict abort
return self['#']
endfunction
function! s:buffer_path() dict abort
return s:gsub(fnamemodify(bufname(self.number()),':p'),'\\ @!','/')
endfunction
function! s:buffer_name() dict abort
let app = self.app()
let f = s:gsub(resolve(fnamemodify(bufname(self.number()),':p')),'\\ @!','/')
let f = s:sub(f,'/$','')
let sep = matchstr(f,'^[^\\/]\{3,\}\zs[\\/]')
if sep != ""
let f = getcwd().sep.f
endif
if s:startswith(tolower(f),s:gsub(tolower(app.path()),'\\ @!','/')) || f == ""
return strpart(f,strlen(app.path())+1)
else
if !exists("s:path_warn") && &verbose
let s:path_warn = 1
call s:warn("File ".f." does not appear to be under the Rails root ".self.app().path().". Please report to the rails.vim author!")
endif
return f
endif
endfunction
function! RailsFilePath()
if !exists("b:rails_root")
return ""
else
return rails#buffer().name()
endif
endfunction
function! RailsFile()
return RailsFilePath()
endfunction
function! RailsFileType()
if !exists("b:rails_root")
return ""
else
return rails#buffer().type_name()
endif
endfunction
function! s:readable_calculate_file_type() dict abort
let f = self.name()
let e = fnamemodify(f,':e')
let r = "-"
let full_path = self.path()
let nr = bufnr('^'.full_path.'$')
if nr < 0 && exists('+shellslash') && ! &shellslash
let nr = bufnr('^'.s:gsub(full_path,'/','\\').'$')
endif
if f == ""
let r = f
elseif nr > 0 && getbufvar(nr,'rails_file_type') != ''
return getbufvar(nr,'rails_file_type')
elseif f =~ '_controller\.rb$' || f =~ '\<app/controllers/.*\.rb$'
if join(s:readfile(full_path,50),"\n") =~ '\<wsdl_service_name\>'
let r = "controller-api"
else
let r = "controller"
endif
elseif f =~ '\<app/apis/.*_api\.rb'
let r = "api"
elseif f =~ '\<test/test_helper\.rb$'
let r = "test"
elseif f =~ '\<spec/spec_helper\.rb$'
let r = "spec"
elseif f =~ '_helper\.rb$'
let r = "helper"
elseif f =~ '\<app/mailers/.*\.rb'
let r = "mailer"
elseif f =~ '\<app/jobs/.*\.rb'
let r = "job"
elseif f =~ '\<app/models/'
let top = "\n".join(s:readfile(full_path,50),"\n")
let class = matchstr(top,"\n".'class\s\+\S\+\s*<\s*\<\zs\S\+\>')
let type = tolower(matchstr(class, '^Application\zs[A-Z]\w*$\|^Acti\w\w\zs[A-Z]\w*\ze::Base'))
if type ==# 'mailer' || f =~ '_mailer\.rb$'
let r = 'mailer'
elseif class ==# 'ActiveRecord::Observer'
let r = 'model-observer'
elseif !empty(type)
let r = 'model-'.type
elseif top =~ '\<\%(self\.\%(table_name\|primary_key\)\|has_one\|has_many\|belongs_to\)\>'
let r = 'model-record'
else
let r = 'model'
endif
elseif f =~ '\<app/views/.*/_\w\+\%(\.[[:alnum:]_+]\+\)\=\.\w\+$'
let r = "view-partial-" . e
elseif f =~ '\<app/views/layouts\>.*\.'
let r = "view-layout-" . e
elseif f =~ '\<app/views\>.*\.'
let r = "view-" . e
elseif f =~ '\<test/\%(unit\|models\|helpers\|jobs\)/.*_test\.rb$'
let r = "test-unit"
elseif f =~ '\<test/\%(functional\|controllers\)/.*_test\.rb$'
let r = "test-functional"
elseif f =~ '\<test/integration/.*_test\.rb$'
let r = "test-integration"
elseif f =~ '\<test/lib/.*_test\.rb$'
let r = "test-lib"
elseif f =~ '\<test/\w*s/.*_test\.rb$'
let r = s:sub(f,'.*<test/(\w*)s/.*','test-\1')
elseif f =~ '\<test/.*_test\.rb'
let r = "test"
elseif f =~ '\<spec/lib/.*_spec\.rb$'
let r = 'spec-lib'
elseif f =~ '\<lib/.*\.rb$'
let r = 'lib'
elseif f =~ '\<spec/\w*s/.*_spec\.rb$'
let r = s:sub(f,'.*<spec/(\w*)s/.*','spec-\1')
elseif f =~ '\<features/.*\.feature$'
let r = 'cucumber-feature'
elseif f =~ '\<features/step_definitions/.*_steps\.rb$'
let r = 'cucumber-steps'
elseif f =~ '\<features/.*\.rb$'
let r = 'cucumber'
elseif f =~ '\<spec/.*\.feature$'
let r = 'spec-feature'
elseif f =~ '\<\%(test\|spec\)/fixtures\>'
if e == "yml"
let r = "fixtures-yaml"
else
let r = "fixtures" . (e == "" ? "" : "-" . e)
endif
elseif f =~ '\<\%(test\|spec\)/\%(factories\|fabricators\)\>'
let r = "fixtures-replacement"
elseif f =~ '\<spec/.*_spec\.rb'
let r = "spec"
elseif f =~ '\<spec/support/.*\.rb'
let r = "spec"
elseif f =~ '\<db/migrate\>'
let r = "db-migration"
elseif f=~ '\<db/schema\.rb$'
let r = "db-schema"
elseif f =~ '\.rake$' || f =~ '\<\%(Rake\|Cap\)file$' || f =~ '\<config/deploy\.rb$' || f =~ '\<config/deploy/.*\.rb$'
let r = "task"
elseif f =~ '\<log/.*\.log$'
let r = "log"
elseif e == "css" || e =~ "s[ac]ss" || e == "less"
let r = "stylesheet-".e
elseif e == "js"
let r = "javascript"
elseif e == "coffee"
let r = "javascript-coffee"
elseif e == "html"
let r = e
elseif f =~ '\<config/routes\>.*\.rb$'
let r = "config-routes"
elseif f =~ '\<config/'
let r = "config"
endif
return r
endfunction
function! s:buffer_type_name(...) dict abort
let type = getbufvar(self.number(),'rails_cached_file_type')
if type == ''
let type = self.calculate_file_type()
endif
return call('s:match_type',[type == '-' ? '' : type] + a:000)
endfunction
function! s:readable_type_name(...) dict abort
let type = self.calculate_file_type()
return call('s:match_type',[type == '-' ? '' : type] + a:000)
endfunction
function! s:match_type(type,...)
if a:0
return !empty(filter(copy(a:000),'a:type =~# "^".v:val."\\%(-\\|$\\)"'))
else
return a:type
endif
endfunction
function! s:app_environments() dict
if self.cache.needs('environments')
call self.cache.set('environments',self.relglob('config/environments/','**/*','.rb'))
endif
return copy(self.cache.get('environments'))
endfunction
function! s:app_default_locale() dict abort
if self.cache.needs('default_locale')
let candidates = map(filter(
\ s:readfile(self.path('config/application.rb')) + s:readfile(self.path('config/environment.rb')),
\ 'v:val =~ "^ *config.i18n.default_locale = :[\"'']\\=[A-Za-z-]\\+[\"'']\\= *$"'
\ ), 'matchstr(v:val,"[A-Za-z-]\\+\\ze[\"'']\\= *$")')
call self.cache.set('default_locale', get(candidates, 0, 'en'))
endif
return self.cache.get('default_locale')
endfunction
function! s:app_stylesheet_suffix() dict abort
if self.cache.needs('stylesheet_suffix')
let default = self.has_gem('sass-rails') ? '.css.scss' : '.css'
let candidates = map(filter(
\ s:readfile(self.path('config/application.rb')),
\ 'v:val =~ "^ *config.sass.preferred_syntax *= *:[A-Za-z-]\\+ *$"'
\ ), '".".matchstr(v:val,"[A-Za-z-]\\+\\ze *$")')
call self.cache.set('stylesheet_suffix', get(candidates, 0, default))
endif
return self.cache.get('stylesheet_suffix')
endfunction
function! s:app_has(feature) dict
let map = {
\'test': 'test/',
\'spec': 'spec/',
\'bundler': 'Gemfile|gems.locked',
\'rails2': 'script/about',
\'rails3': 'config/application.rb',
\'rails5': 'app/assets/config/manifest.js|config/initializers/application_controller_renderer.rb',
\'cucumber': 'features/',
\'turnip': 'spec/acceptance/',
\'sass': 'public/stylesheets/sass/',
\'lesscss': 'app/stylesheets/',
\'coffee': 'app/scripts/'}
if self.cache.needs('features')
call self.cache.set('features',{})
endif
let features = self.cache.get('features')
if !has_key(features,a:feature)
let path = get(map,a:feature,a:feature.'/')
let features[a:feature] =
\ !empty(filter(split(path, '|'), 'self.has_path(v:val)'))
endif
return features[a:feature]
endfunction
" Returns the subset of ['test', 'spec'] present on the app.
function! s:app_test_suites() dict
return filter(['test','spec'],'self.has(v:val)')
endfunction
call s:add_methods('app',['default_locale','environments','file','has','stylesheet_suffix','test_suites'])
call s:add_methods('file',['path','name','lines','getline'])
call s:add_methods('buffer',['app','number','path','name','lines','getline','type_name'])
call s:add_methods('readable',['app','relative','absolute','spec','calculate_file_type','type_name','line_count'])
" }}}1
" Ruby Execution {{{1
function! s:app_ruby_command(cmd) dict abort
return 'ruby '.a:cmd
endfunction
function! s:app_ruby_script_command(cmd) dict abort
if has('win32')
return self.ruby_command(a:cmd)
else
return a:cmd
endif
endfunction
function! s:app_static_rails_command(cmd) dict abort
if self.has_path('bin/rails')
let cmd = 'bin/rails '.a:cmd
elseif self.has_path('script/rails')
let cmd = 'script/rails '.a:cmd
elseif !self.has('rails3')
let cmd = 'script/'.a:cmd
elseif self.has('bundler')
return 'bundle exec rails ' . a:cmd
else
return 'rails '.a:cmd
endif
return self.ruby_script_command(cmd)
endfunction
function! s:app_prepare_rails_command(cmd) dict abort
if self.has_path('.zeus.sock') && a:cmd =~# '^\%(console\|dbconsole\|destroy\|generate\|server\|runner\)\>'
return 'zeus '.a:cmd
endif
return self.static_rails_command(a:cmd)
endfunction
function! s:app_start_rails_command(cmd, ...) dict abort
let cmd = s:esccmd(self.prepare_rails_command(a:cmd))
let title = s:sub(a:cmd, '\s.*', '')
let title = get({
\ 'g': 'generate',
\ 'd': 'destroy',
\ 'c': 'console',
\ 'db': 'dbconsole',
\ 's': 'server',
\ 'r': 'runner',
\ }, title, title)
call s:push_chdir(1)
try
if exists(':Start') == 2
let title = escape(fnamemodify(self.path(), ':t').' '.title, ' ')
exe 'Start'.(a:0 && a:1 ? '!' : '').' -title='.title.' '.cmd
elseif has("win32")
exe "!start ".cmd
else
exe "!".cmd
endif
finally
call s:pop_command()
endtry
return ''
endfunction
function! s:app_execute_rails_command(cmd) dict abort
call s:push_chdir(1)
try
exe '!'.s:esccmd(self.prepare_rails_command(a:cmd))
finally
call s:pop_command()
endtry
return ''
endfunction
function! s:app_eval(ruby,...) dict abort
let def = a:0 ? a:1 : ""
if !executable("ruby")
return def
endif
let args = "-r./config/boot -r ".s:rquote(self.path("config/environment"))." -e ".s:rquote(a:ruby)
let cmd = self.ruby_command(args)
call s:push_chdir(1)
try
silent! let results = system(cmd)
finally
call s:pop_command()
endtry
return v:shell_error == 0 ? results : def
endfunction
call s:add_methods('app', ['ruby_command','ruby_script_command','static_rails_command','prepare_rails_command','execute_rails_command','start_rails_command','eval'])
" }}}1
" Commands {{{1
function! s:BufCommands()
call s:BufNavCommands()
call s:BufScriptWrappers()
command! -buffer -bar -nargs=+ Rnavcommand :call s:Navcommand(<bang>0,<f-args>)
command! -buffer -bar -nargs=* -bang Rabbrev :call s:Abbrev(<bang>0,<f-args>)
command! -buffer -bar -nargs=? -bang -count -complete=customlist,rails#complete_rake Rake :call s:Rake(<bang>0,!<count> && <line1> ? -1 : <count>,<q-args>)
command! -buffer -bar -nargs=? -bang -range -complete=customlist,s:Complete_preview Rpreview :call s:Preview(<bang>0,<line1>,<q-args>)
command! -buffer -bar -nargs=? -bang -range -complete=customlist,s:Complete_preview Rbrowse :call s:Preview(<bang>0,<line1>,<q-args>)
command! -buffer -bar -nargs=? -bang -range -complete=customlist,s:Complete_preview Preview :call s:Preview(<bang>0,<line1>,<q-args>)
command! -buffer -bar -nargs=? -bang -complete=customlist,s:Complete_environments Rlog :call s:Log(<bang>0,<q-args>)
command! -buffer -bar -nargs=* -bang Rset :call s:Set(<bang>0,<f-args>)
command! -buffer -bar -nargs=0 Rtags :execute rails#app().tags_command()
command! -buffer -bar -nargs=0 Ctags :execute rails#app().tags_command()
command! -buffer -bar -nargs=0 -bang Rrefresh :if <bang>0|unlet! g:autoloaded_rails|source `=s:file`|endif|call s:Refresh(<bang>0)
if exists("g:loaded_dbext")
command! -buffer -bar -nargs=? -complete=customlist,s:Complete_environments Rdbext :call s:BufDatabase(2,<q-args>)|let b:dbext_buffer_defaulted = 1
endif
let ext = expand("%:e")
if RailsFilePath() =~ '\<app/views/'
" TODO: complete controller names with trailing slashes here
command! -buffer -bar -bang -nargs=? -range -complete=customlist,s:controllerList Rextract :<line1>,<line2>call s:Extract(<bang>0,<f-args>)
command! -buffer -bar -bang -nargs=? -range -complete=customlist,s:controllerList Extract :<line1>,<line2>call s:Extract(<bang>0,<f-args>)
elseif rails#buffer().name() =~# '^app/helpers/.*\.rb$'
command! -buffer -bar -bang -nargs=1 -range Rextract :<line1>,<line2>call s:RubyExtract(<bang>0, 'app/helpers', [], s:sub(<f-args>, '_helper$|Helper$|$', '_helper'))
command! -buffer -bar -bang -nargs=1 -range Extract :<line1>,<line2>call s:RubyExtract(<bang>0, 'app/helpers', [], s:sub(<f-args>, '_helper$|Helper$|$', '_helper'))
elseif rails#buffer().name() =~# '^app/\w\+/.*\.rb$'
command! -buffer -bar -bang -nargs=1 -range Rextract :<line1>,<line2>call s:RubyExtract(<bang>0, matchstr(rails#buffer().name(), '^app/\w\+/').'concerns', [' extend ActiveSupport::Concern', ''], <f-args>)
command! -buffer -bar -bang -nargs=1 -range Extract :<line1>,<line2>call s:RubyExtract(<bang>0, matchstr(rails#buffer().name(), '^app/\w\+/').'concerns', [' extend ActiveSupport::Concern', ''], <f-args>)
endif
if RailsFilePath() =~ '\<db/migrate/.*\.rb$'
command! -buffer -bar Rinvert :call s:Invert(<bang>0)
endif
endfunction
function! s:Log(bang,arg)
let lf = rails#app().path('log/' . (empty(a:arg) ? s:environment() : a:arg) . '.log')
if a:bang
exe 'cgetfile' s:fnameescape(lf)
clast
else
if exists(":Tail") == 2
exe 'Tail' s:fnameescape(lf)
else
exe 'pedit' s:fnameescape(lf)
endif
endif
endfunction
function! rails#new_app_command(bang,...) abort
if !a:0 || a:1 !=# 'new'
return 'echoerr '.string('Usage: rails new <path>')
endif
let args = copy(a:000)
if &shellpipe !~# 'tee' && index(args, '--skip') < 0 && index(args, '--force') < 0
let args += ['--skip']
endif
let temp = tempname()
try
if &shellpipe =~# '%s'
let pipe = s:sub(&shellpipe, '\%s', temp)
else
let pipe = &shellpipe . ' ' . temp
endif
exe '!rails' join(map(copy(args),'s:rquote(v:val)'),' ') pipe
catch /^Vim:Interrupt/
endtry
if isdirectory(expand(args[1]))
let old_errorformat = &l:errorformat
let chdir = exists("*haslocaldir") && haslocaldir() ? 'lchdir' : 'chdir'
let cwd = getcwd()
try
exe chdir s:fnameescape(expand(args[1]))
let &l:errorformat = s:efm_generate
exe 'cgetfile' temp
return 'cfirst'
finally
let &l:errorformat = old_errorformat
exe chdir s:fnameescape(cwd)
endtry
endif
return ''
endfunction
function! s:app_tags_command() dict abort
if exists("g:Tlist_Ctags_Cmd")
let cmd = g:Tlist_Ctags_Cmd
elseif executable("exuberant-ctags")
let cmd = "exuberant-ctags"
elseif executable("ctags-exuberant")
let cmd = "ctags-exuberant"
elseif executable("exctags")
let cmd = "exctags"
elseif executable("ctags")
let cmd = "ctags"
elseif executable("ctags.exe")
let cmd = "ctags.exe"
else
call s:error("ctags not found")
return ''
endif
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
let cwd = getcwd()
try
execute cd fnameescape(self.path())
if self.has_path('.ctags')
let args = []
else
let args = s:split(get(g:, 'rails_ctags_arguments', '--languages=ruby'))
endif
exe '!'.cmd.' -R '.join(args,' ')
finally
execute cd fnameescape(cwd)
endtry
return ''
endfunction
call s:add_methods('app',['tags_command'])
function! s:Refresh(bang)
if exists("g:rubycomplete_rails") && g:rubycomplete_rails && has("ruby") && exists('g:rubycomplete_completions')
silent! ruby ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
silent! ruby if defined?(ActiveSupport::Dependencies); ActiveSupport::Dependencies.clear; elsif defined?(Dependencies); Dependencies.clear; end
if a:bang
silent! ruby ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
endif
endif
let _ = rails#app().cache.clear()
silent doautocmd User BufLeaveRails
if a:bang
for key in keys(s:apps)
if type(s:apps[key]) == type({})
call s:apps[key].cache.clear()
endif
call extend(s:apps[key],filter(copy(s:app_prototype),'type(v:val) == type(function("tr"))'),'force')
endfor
endif
let i = 1
let max = bufnr('$')
while i <= max
let rr = getbufvar(i,"rails_root")
if rr != ""
call setbufvar(i,"rails_refresh",1)
endif
let i += 1
endwhile
silent doautocmd User BufEnterRails
endfunction
function! s:RefreshBuffer()
if exists("b:rails_refresh") && b:rails_refresh
let b:rails_refresh = 0
let &filetype = &filetype
unlet! b:rails_refresh
endif
endfunction
" }}}1
" Rake {{{1
function! s:qf_pre() abort
let dir = substitute(matchstr(','.&l:errorformat, ',chdir \zs\%(\\.\|[^,]\)*'), '\\,' ,',', 'g')
let cwd = getcwd()
if !empty(dir) && dir !=# cwd
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
execute 'lcd' fnameescape(dir)
let s:qf_post = cd . ' ' . fnameescape(cwd)
endif
endfunction
augroup railsPluginMake
autocmd!
autocmd QuickFixCmdPre *make* call s:qf_pre()
autocmd QuickFixCmdPost *make*
\ if exists('s:qf_post') | execute remove(s:, 'qf_post') | endif
augroup END
function! s:app_rake_tasks() dict abort
if self.cache.needs('rake_tasks')
call s:push_chdir()
try
let output = system(self.rake_command().' -T')
let lines = split(output, "\n")
finally
call s:pop_command()
endtry
if v:shell_error != 0
return []
endif
call map(lines,'matchstr(v:val,"^rake\\s\\+\\zs[^][ ]\\+")')
call filter(lines,'v:val != ""')
call self.cache.set('rake_tasks',s:uniq(['default'] + lines))
endif
return self.cache.get('rake_tasks')
endfunction
call s:add_methods('app', ['rake_tasks'])
function! s:make(bang, args, ...)
if exists(':Make') == 2
exe 'Make'.(a:bang ? '! ' : ' ').a:args
else
exe 'make! '.a:args
let qf = &l:buftype ==# 'quickfix'
if !a:bang
exe (a:0 ? a:1 : 'cwindow')
if !qf && &l:buftype ==# 'quickfix'
wincmd p
endif
endif
endif
endfunction
function! s:Rake(bang, lnum, arg) abort
let self = rails#app()
let lnum = a:lnum < 0 ? 0 : a:lnum
let old_makeprg = &l:makeprg
let old_errorformat = &l:errorformat
let old_compiler = get(b:, 'current_compiler', '')
try
compiler rails
let b:current_compiler = 'rake'
let &l:makeprg = rails#app().rake_command()
let &l:errorformat .= ',chdir '.escape(self.path(), ',')
let arg = a:arg
if arg == ''
let arg = rails#buffer().default_rake_task(lnum)
endif
if !has_key(self,'options') | let self.options = {} | endif
if arg == '-'
let arg = get(self.options,'last_rake_task','')
endif
let self.options['last_rake_task'] = arg
if arg =~# '^notes\>'
let &l:errorformat = '%-P%f:,\ \ *\ [%\ %#%l]\ [%t%*[^]]] %m,\ \ *\ [%[\ ]%#%l] %m,%-Q'
call s:make(a:bang, arg)
elseif arg =~# '^\%(stats\|routes\|secret\|middleware\|time:zones\|db:\%(charset\|collation\|fixtures:identify\>.*\|migrate:status\|version\)\)\%([: ]\|$\)'
let &l:errorformat = '%D(in\ %f),%+G%.%#'
call s:make(a:bang, arg, 'copen')
else
call s:make(a:bang, arg)
endif
finally
let &l:errorformat = old_errorformat
let &l:makeprg = old_makeprg
let b:current_compiler = old_compiler
if empty(b:current_compiler)
unlet b:current_compiler
endif
endtry
endfunction
function! s:readable_test_file_candidates() dict abort
let f = self.name()
let projected = self.projected('test')
if self.type_name('view')
let tests = [
\ fnamemodify(f,':s?\<app/?spec/?')."_spec.rb",
\ fnamemodify(f,':r:s?\<app/?spec/?')."_spec.rb",
\ fnamemodify(f,':r:r:s?\<app/?spec/?')."_spec.rb",
\ s:sub(s:sub(f,'<app/views/','test/controllers/'),'/[^/]*$','_controller_test.rb'),
\ s:sub(s:sub(f,'<app/views/','test/functional/'),'/[^/]*$','_controller_test.rb')]
elseif self.type_name('controller-api')
let tests = [
\ s:sub(s:sub(f,'/controllers/','/apis/'),'_controller\.rb$','_api.rb')]
elseif self.type_name('api')
let tests = [
\ s:sub(s:sub(f,'/apis/','/controllers/'),'_api\.rb$','_controller.rb')]
elseif self.type_name('lib')
let tests = [
\ s:sub(f,'<lib/(.*)\.rb$','test/lib/\1_test.rb'),
\ s:sub(f,'<lib/(.*)\.rb$','test/unit/\1_test.rb'),
\ s:sub(f,'<lib/(.*)\.rb$','spec/lib/\1_spec.rb')]
elseif self.type_name('fixtures') && f =~# '\<spec/'
let tests = [
\ 'spec/models/' . self.model_name() . '_spec.rb']
elseif self.type_name('fixtures')
let tests = [
\ 'test/models/' . self.model_name() . '_test.rb',
\ 'test/unit/' . self.model_name() . '_test.rb']
elseif f =~# '\<app/.*/.*\.rb'
let file = fnamemodify(f,":r")
let test_file = s:sub(file,'<app/','test/') . '_test.rb'
let spec_file = s:sub(file,'<app/','spec/') . '_spec.rb'
let old_test_file = s:sub(s:sub(s:sub(s:sub(test_file,
\ '<test/helpers/', 'test/unit/helpers/'),
\ '<test/models/', 'test/unit/'),
\ '<test/mailers/', 'test/functional/'),
\ '<test/controllers/', 'test/functional/')
let tests = s:uniq([test_file, old_test_file, spec_file])
elseif f =~# '\<\(test\|spec\)/\%(\1_helper\.rb$\|support\>\)' || f =~# '\%(\<spec/\|\<test/\)\@<!\<features/.*\.rb$'
let tests = [matchstr(f, '.*\<\%(test\|spec\|features\)\>')]
elseif self.type_name('test', 'spec', 'cucumber')
let tests = [f]
else
let tests = []
endif
if !self.app().has('test')
call filter(tests, 'v:val !~# "^test/"')
endif
if !self.app().has('spec')
call filter(tests, 'v:val !~# "^spec/"')
endif
if !self.app().has('cucumber')
call filter(tests, 'v:val !~# "^cucumber/"')
endif
return projected + tests
endfunction
function! s:readable_test_file() dict abort
let candidates = self.test_file_candidates()
for file in candidates
if self.app().has_path(file)
return file
endif
endfor
return get(candidates, 0, '')
endfunction
function! s:readable_default_rake_task(...) dict abort
let app = self.app()
let lnum = a:0 ? (a:1 < 0 ? 0 : a:1) : 0
let taskpat = '\C# rake\s\+\zs.\{-\}\ze\%(\s\s\|#\|$\)'
if self.getvar('&buftype') == 'quickfix'
return '-'
elseif self.getline(lnum) =~# '# rake \S'
return matchstr(self.getline(lnum),'\C# rake \zs.*')
elseif self.getline(self.last_method_line(lnum)-1) =~# taskpat
return matchstr(self.getline(self.last_method_line(lnum)-1), taskpat)
elseif self.getline(self.last_method_line(lnum)) =~# taskpat
return matchstr(self.getline(self.last_method_line(lnum)), taskpat)
elseif self.getline(1) =~# taskpat && !lnum
return matchstr(self.getline(1), taskpat)
endif
let placeholders = {}
if lnum
let placeholders.l = lnum
let placeholders.lnum = lnum
let placeholders.line = lnum
let last = self.last_method(lnum)
if !empty(last)
let placeholders.d = last
let placeholders.define = last
endif
endif
let tasks = self.projected('task', placeholders)
if !empty(tasks)
return tasks[0]
endif
if self.type_name('config-routes')
return 'routes'
elseif self.type_name('fixtures-yaml') && lnum
return "db:fixtures:identify LABEL=".self.last_method(lnum)
elseif self.type_name('fixtures') && lnum == 0
return "db:fixtures:load FIXTURES=".s:sub(fnamemodify(self.name(),':r'),'^.{-}/fixtures/','')
elseif self.type_name('task')
let mnum = self.last_method_line(lnum)
let line = getline(mnum)
" We can't grab the namespace so only run tasks at the start of the line
if line =~# '^\%(task\|file\)\>'
let task = self.last_method(lnum)
else
let task = matchstr(self.getline(1),'\C# rake \zs.*')
endif
return s:sub(task, '^$', '--tasks')
elseif self.type_name('db-migration')
let ver = matchstr(self.name(),'\<db/migrate/0*\zs\d*\ze_')
if !empty(ver)
let method = self.last_method(lnum)
if method == "down" || lnum == 1
return "db:migrate:down VERSION=".ver
elseif method == "up" || lnum == line('$')
return "db:migrate:up VERSION=".ver
else
return "db:migrate:redo VERSION=".ver
endif
else
return 'db:migrate'
endif
elseif self.name() =~# '\<db/seeds\.rb$'
return 'db:seed'
elseif self.name() =~# '\<db/\|\<config/database\.'
return 'db:migrate:status'
elseif self.name() =~# '\<config\.ru$'
return 'middleware'
elseif self.name() =~# '\<README'
return 'about'
elseif self.type_name('controller') && lnum
return 'routes CONTROLLER='.self.controller_name()
else
let test = self.test_file()
let with_line = test
if test ==# self.name()
let with_line .= (lnum > 0 ? ':'.lnum : '')
endif
if empty(test)
return '--tasks'
elseif test =~# '^test\>' && self.app().has('rails5')
return 'test '.s:rquote(with_line)
elseif test =~# '^test\>'
let opts = ''
if test ==# self.name()
let method = self.app().file(test).last_method(lnum)
if method =~ '^test_'
let opts = ' TESTOPTS=-n'.method
endif
endif
if test =~# '^test/\%(unit\|models\|jobs\)\>'
return 'test:units TEST='.s:rquote(test).opts
elseif test =~# '^test/\%(functional\|controllers\)\>'
return 'test:functionals TEST='.s:rquote(test).opts
elseif test =~# '^test/integration\>'
return 'test:integration TEST='.s:rquote(test).opts
elseif test ==# 'test'
return 'test'
else
return 'test:units TEST='.s:rquote(test).opts
endif
elseif test =~# '^spec\>'
return 'spec SPEC='.s:rquote(with_line)
elseif test =~# '^features\>'
return 'cucumber FEATURE='.s:rquote(with_line)
else
let task = matchstr(test, '^\w*')
return task . ' ' . toupper(task) . '=' . s:rquote(with_line)
endif
endif
endfunction
function! s:app_rake_command(...) dict abort
if get(a:, 1, '') !=# 'static' && self.has_path('.zeus.sock') && executable('zeus')
return 'zeus rake'
elseif self.has_path('bin/rake')
return self.ruby_script_command('bin/rake')
elseif self.has('bundler')
return 'bundle exec rake'
else
return 'rake'
endif
endfunction
function! rails#complete_rake(A,L,P)
return s:completion_filter(rails#app().rake_tasks(), a:A, ':')
endfunction
call s:add_methods('readable', ['test_file_candidates', 'test_file', 'default_rake_task'])
call s:add_methods('app', ['rake_command'])
" }}}1
" Preview {{{1
function! s:initOpenURL() abort
if exists(":OpenURL") != 2
if exists(":Browse") == 2
command -bar -nargs=1 OpenURL Browse <args>
elseif has("gui_mac") || has("gui_macvim") || exists("$SECURITYSESSIONID")
command -bar -nargs=1 OpenURL exe '!open' shellescape(<q-args>, 1)
elseif has("gui_win32")
command -bar -nargs=1 OpenURL exe '!start cmd /cstart /b' shellescape(<q-args>, 1)
elseif executable("xdg-open")
command -bar -nargs=1 OpenURL exe '!xdg-open' shellescape(<q-args>, 1) '&'
elseif executable("sensible-browser")
command -bar -nargs=1 OpenURL exe '!sensible-browser' shellescape(<q-args>, 1)
elseif executable('launchy')
command -bar -nargs=1 OpenURL exe '!launchy' shellescape(<q-args>, 1)
elseif executable('git')
command -bar -nargs=1 OpenURL exe '!git web--browse' shellescape(<q-args>, 1)
endif
endif
endfunction
function! s:scanlineforuris(line)
let url = matchstr(a:line,"\\v\\C%(%(GET|PUT|POST|DELETE)\\s+|\\w+://[^/]*)/[^ \n\r\t<>\"]*[^] .,;\n\r\t<>\":]")
if url =~ '\C^\u\+\s\+'
let method = matchstr(url,'^\u\+')
let url = matchstr(url,'\s\+\zs.*')
if method !=? "GET"
let url .= (url =~ '?' ? '&' : '?') . '_method='.tolower(method)
endif
endif
if url != ""
return [url]
else
return []
endif
endfunction
function! s:readable_preview_urls(lnum) dict abort
let urls = []
let start = self.last_method_line(a:lnum) - 1
while start > 0 && self.getline(start) =~ '^\s*\%(\%(-\=\|<%\)#.*\)\=$'
let urls = s:scanlineforuris(self.getline(start)) + urls
let start -= 1
endwhile
let start = 1
while start < self.line_count() && self.getline(start) =~ '^\s*\%(\%(-\=\|<%\)#.*\)\=$'
let urls += s:scanlineforuris(self.getline(start))
let start += 1
endwhile
if has_key(self,'getvar') && self.getvar('rails_preview') != ''
let urls += [self.getvar('rails_preview')]
endif
if self.name() =~ '^public/stylesheets/sass/'
let urls = urls + [s:sub(s:sub(self.name(),'^public/stylesheets/sass/','/stylesheets/'),'\.s[ac]ss$','.css')]
elseif self.name() =~ '^public/'
let urls = urls + [s:sub(self.name(),'^public','')]
elseif self.name() =~ '^app/assets/stylesheets/'
let urls = urls + ['/assets/application.css']
elseif self.name() =~ '^app/assets/javascripts/'
let urls = urls + ['/assets/application.js']
elseif self.name() =~ '^app/stylesheets/'
let urls = urls + [s:sub(s:sub(self.name(),'^app/stylesheets/','/stylesheets/'),'\.less$','.css')]
elseif self.name() =~ '^app/scripts/'
let urls = urls + [s:sub(s:sub(self.name(),'^app/scripts/','/javascripts/'),'\.coffee$','.js')]
elseif self.controller_name() != '' && self.controller_name() != 'application'
if self.type_name('controller') && self.last_method(a:lnum) != ''
let handler = self.controller_name().'#'.self.last_method(a:lnum)
elseif self.type_name('controller','view-layout','view-partial')
let handler = self.controller_name().'#index'
elseif self.type_name('view')
let handler = self.controller_name().'#'.fnamemodify(self.name(),':t:r:r')
endif
if exists('handler')
call self.app().route_names()
for route in values(self.app().cache.get('named_routes'))
if route.method ==# 'GET' && route.handler ==# handler
let urls += [s:gsub(s:gsub(route.path, '\([^()]*\)', ''), ':\w+', '1')]
endif
endfor
endif
endif
return urls
endfunction
call s:add_methods('readable', ['preview_urls'])
function! s:app_server_pid() dict abort
for type in ['server', 'unicorn']
let pidfile = self.path('tmp/pids/'.type.'.pid')
if filereadable(pidfile)
let pid = get(readfile(pidfile, 'b', 1), 0, 0)
if pid
return pid
endif
endif
endfor
endfunction
function! s:app_server_binding() dict abort
let pid = self.server_pid()
if pid
if self.cache.has('server')
let old = self.cache.get('server')
else
let old = {'pid': 0, 'binding': ''}
endif
if !empty(old.binding) && pid == old.pid
return old.binding
endif
let binding = rails#get_binding_for(pid)
call self.cache.set('server', {'pid': pid, 'binding': binding})
if !empty(binding)
return binding
endif
endif
for app in s:split(glob("~/.pow/*"))
if resolve(app) ==# resolve(self.path())
return fnamemodify(app, ':t').'.dev'
endif
endfor
return ''
endfunction
call s:add_methods('app', ['server_pid', 'server_binding'])
function! s:Preview(bang, lnum, uri) abort
let binding = rails#app().server_binding()
if empty(binding)
let binding = '0.0.0.0:3000'
endif
let binding = s:sub(binding, '^0\.0\.0\.0>|^127\.0\.0\.1>', 'localhost')
let binding = s:sub(binding, '^\[::\]', '[::1]')
let uri = empty(a:uri) ? get(rails#buffer().preview_urls(a:lnum),0,'') : a:uri
if uri =~ '://'
"
elseif uri =~# '^[[:alnum:]-]\+\.'
let uri = 'http://'.s:sub(uri, '^[^/]*\zs', matchstr(root, ':\d\+$'))
elseif uri =~# '^[[:alnum:]-]\+\%(/\|$\)'
let domain = s:sub(binding, '^localhost>', 'lvh.me')
let uri = 'http://'.s:sub(uri, '^[^/]*\zs', '.'.domain)
else
let uri = 'http://'.binding.'/'.s:sub(uri,'^/','')
endif
call s:initOpenURL()
if (exists(':OpenURL') == 2) && !a:bang
exe 'OpenURL '.uri
else
" Work around bug where URLs ending in / get handled as FTP
let url = uri.(uri =~ '/$' ? '?' : '')
silent exe 'pedit '.url
let root = rails#app().path()
wincmd w
let b:rails_root = root
if &filetype ==# ''
if uri =~ '\.css$'
setlocal filetype=css
elseif uri =~ '\.js$'
setlocal filetype=javascript
elseif getline(1) =~ '^\s*<'
setlocal filetype=xhtml
endif
endif
call rails#buffer_setup()
map <buffer> <silent> q :bwipe<CR>
wincmd p
if !a:bang
call s:warn("Define a :OpenURL command to use a browser")
endif
endif
endfunction
function! s:Complete_preview(A,L,P)
return rails#buffer().preview_urls(a:L =~ '^\d' ? matchstr(a:L,'^\d\+') : line('.'))
endfunction
" }}}1
" Script Wrappers {{{1
function! s:BufScriptWrappers()
command! -buffer -bang -bar -nargs=? -complete=customlist,s:Complete_script Rscript :execute 'Rails<bang>' empty(<q-args>) ? 'console' : <q-args>
command! -buffer -bang -bar -nargs=* -complete=customlist,s:Complete_environments Console :Rails<bang> console <args>
command! -buffer -bang -bar -nargs=? -count -complete=customlist,s:Complete_script Rails :execute s:Rails(<bang>0, !<count> && <line1> ? -1 : <count>, <q-args>)
command! -buffer -bang -bar -nargs=* -complete=customlist,s:Complete_generate Rgenerate :execute rails#app().generator_command(<bang>0,'generate',<f-args>)
command! -buffer -bang -bar -nargs=* -complete=customlist,s:Complete_generate Generate :execute rails#app().generator_command(<bang>0,'generate',<f-args>)
command! -buffer -bar -nargs=* -complete=customlist,s:Complete_destroy Rdestroy :execute rails#app().generator_command(1,'destroy',<f-args>)
command! -buffer -bar -nargs=* -complete=customlist,s:Complete_destroy Destroy :execute rails#app().generator_command(1,'destroy',<f-args>)
command! -buffer -bar -nargs=? -bang -complete=customlist,s:Complete_server Rserver :execute rails#app().server_command(<bang>0, 1, <q-args>)
command! -buffer -bar -nargs=? -bang -complete=customlist,s:Complete_server Server :execute rails#app().server_command(0, <bang>0, <q-args>)
command! -buffer -bang -nargs=? -range=0 -complete=customlist,s:Complete_edit Rrunner :execute rails#buffer().runner_command(<bang>0, <count>?<line1>:0, <q-args>)
command! -buffer -bang -nargs=? -range=0 -complete=customlist,s:Complete_edit Runner :execute rails#buffer().runner_command(<bang>0, <count>?<line1>:0, <q-args>)
command! -buffer -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rp :execute rails#app().output_command(<count>==<line2>?<count>:-1, 'p begin '.<q-args>.' end')
command! -buffer -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rpp :execute rails#app().output_command(<count>==<line2>?<count>:-1, 'require %{pp}; pp begin '.<q-args>.' end')
endfunction
function! s:app_generators() dict abort
if self.cache.needs('generators')
let paths = [self.path('vendor/plugins/*'), self.path('lib'), expand("~/.rails")]
if !empty(self.gems())
let gems = values(self.gems())
let paths += map(copy(gems), 'v:val . "/lib/rails"')
let paths += map(gems, 'v:val . "/lib"')
let builtin = []
else
let builtin = ['assets', 'controller', 'generator', 'helper', 'integration_test', 'jbuilder', 'jbuilder_scaffold_controller', 'mailer', 'migration', 'model', 'resource', 'scaffold', 'scaffold_controller', 'task', 'job']
endif
let generators = s:split(globpath(s:pathjoin(paths), 'generators/**/*_generator.rb'))
call map(generators, 's:sub(v:val,"^.*[\\\\/]generators[\\\\/]\\ze.","")')
call map(generators, 's:sub(v:val,"[\\\\/][^\\\\/]*_generator\.rb$","")')
call map(generators, 'tr(v:val, "/", ":")')
let builtin += map(filter(copy(generators), 'v:val =~# "^rails:"'), 'v:val[6:-1]')
call filter(generators,'v:val !~# "^rails:"')
call self.cache.set('generators',s:uniq(builtin + generators))
endif
return self.cache.get('generators')
endfunction
function! s:Rails(bang, count, arg) abort
if !empty(a:arg)
let str = a:arg
elseif rails#buffer().type_name('spec', 'cucumber')
return rails#buffer().runner_command(a:bang, a:count, '')
elseif rails#buffer().type_name('test') && !rails#app().has('rails5')
return rails#buffer().runner_command(a:bang, a:count, '')
elseif rails#buffer().name() =~# '^\%(app\|config\|db\|lib\|log\|README\|Rakefile\|test\|spec\|features\)'
let str = rails#buffer().default_rake_task(a:count)
if str ==# '--tasks'
let str = ''
else
let rake = 1
endif
else
let str = ''
endif
if str =~# '^\%(c\|console\|db\|dbconsole\|s\|server\)\S\@!' && str !~# ' -d\| --daemon\| --help'
return rails#app().start_rails_command(str, a:bang)
else
let [mp, efm, cc] = [&l:mp, &l:efm, get(b:, 'current_compiler', '')]
try
compiler rails
if exists('rake') && !rails#app().has('rails5')
let &l:makeprg = rails#app().rake_command()
else
let &l:makeprg = rails#app().prepare_rails_command('$*')
endif
let &l:errorformat .= ',chdir '.escape(rails#app().path(), ',')
call s:make(a:bang, str)
finally
let [&l:mp, &l:efm, b:current_compiler] = [mp, efm, cc]
if empty(cc) | unlet! b:current_compiler | endif
endtry
return ''
endif
endfunction
function! s:readable_runner_command(bang, count, arg) dict abort
let old_makeprg = &l:makeprg
let old_errorformat = &l:errorformat
let old_compiler = get(b:, 'current_compiler', '')
try
if !empty(a:arg)
let arg = a:arg
elseif a:count
let arg = self.name()
else
let arg = self.test_file()
if empty(arg)
let arg = self.name()
endif
endif
let extra = ''
if a:count > 0
let extra = ':'.a:count
endif
let file = arg ==# self.name() ? self : self.app().file(arg)
if arg =~# '^test/.*_test\.rb$'
let compiler = 'rubyunit'
if a:count > 0
let method = file.last_method(a:count)
if method =~ '^test_'
let extra = ' -n'.method
else
let extra = ''
endif
endif
elseif arg =~# '^spec\%(/.*\%(_spec\.rb\|\.feature\)\)\=$'
let compiler = 'rspec'
elseif arg =~# '^features\%(/.*\.feature\)\=$'
let compiler = 'cucumber'
else
let compiler = 'ruby'
endif
let compiler = get(file.projected('compiler'), 0, compiler)
if compiler ==# 'testrb' || compiler ==# 'minitest'
let compiler = 'rubyunit'
elseif empty(findfile('compiler/'.compiler.'.vim', escape(&rtp, ' ')))
let compiler = 'ruby'
endif
execute 'compiler '.compiler
if compiler ==# 'ruby'
let &l:makeprg = self.app().prepare_rails_command('runner')
let extra = ''
elseif &makeprg =~# '^\%(testrb\|rspec\|cucumber\)\>' && self.app().has_path('.zeus.sock')
let &l:makeprg = 'zeus ' . &l:makeprg
elseif compiler ==# 'rubyunit'
let &l:makeprg = 'ruby -Itest'
elseif self.app().has_path('bin/' . &l:makeprg)
let &l:makeprg = self.app().ruby_script_command('bin/' . &l:makeprg)
elseif &l:makeprg !~# '^bundle\>' && self.app().has('bundler')
let &l:makeprg = 'bundle exec ' . &l:makeprg
endif
let &l:errorformat .= ',chdir '.escape(self.app().path(), ',')
call s:make(a:bang, arg . extra)
return ''
finally
let &l:errorformat = old_errorformat
let &l:makeprg = old_makeprg
let b:current_compiler = old_compiler
if empty(b:current_compiler)
unlet b:current_compiler
endif
endtry
return ''
endfunction
call s:add_methods('readable', ['runner_command'])
function! s:app_output_command(count, code) dict
let str = self.prepare_rails_command('runner '.s:rquote(a:code))
call s:push_chdir(1)
try
let res = s:sub(system(str),'\n$','')
finally
call s:pop_command()
endtry
if a:count < 0
echo res
else
exe a:count.'put =res'
endif
return ''
endfunction
function! rails#get_binding_for(pid) abort
if empty(a:pid)
return ''
endif
if has('win32')
let output = system('netstat -anop tcp')
let binding = matchstr(output, '\n\s*TCP\s\+\zs\S\+\ze\s\+\S\+\s\+LISTENING\s\+'.a:pid.'\>')
return s:sub(binding, '^([^[]*:.*):', '[\1]:')
endif
if executable('lsof')
let lsof = 'lsof'
elseif executable('/usr/sbin/lsof')
let lsof = '/usr/sbin/lsof'
endif
if exists('lsof')
let output = system(lsof.' -an -i4tcp -sTCP:LISTEN -p'.a:pid)
let binding = matchstr(output, '\S\+:\d\+\ze\s\+(LISTEN)\n')
let binding = s:sub(binding, '^\*', '0.0.0.0')
if empty(binding)
let output = system(lsof.' -an -i6tcp -sTCP:LISTEN -p'.a:pid)
let binding = matchstr(output, '\S\+:\d\+\ze\s\+(LISTEN)\n')
let binding = s:sub(binding, '^\*', '[::]')
endif
return binding
endif
if executable('netstat')
let output = system('netstat -antp')
let binding = matchstr(output, '\S\+:\d\+\ze\s\+\S\+\s\+LISTEN\s\+'.a:pid.'/')
return s:sub(binding, '^([^[]*:.*):', '[\1]:')
endif
return ''
endfunction
function! s:app_server_command(kill, bg, arg) dict abort
let arg = empty(a:arg) ? '' : ' '.a:arg
let flags = ' -d\| --daemon\| --help'
if a:kill || a:arg =~# '^ *[!-]$' || (a:bg && arg =~# flags)
let pid = self.server_pid()
if pid
echo "Killing server with pid ".pid
if !has("win32")
call system("ruby -e 'Process.kill(:TERM,".pid.")'")
sleep 100m
endif
call system("ruby -e 'Process.kill(9,".pid.")'")
sleep 100m
else
echo "No server running"
endif
if a:arg =~# '^ *[-!]$'
return
endif
endif
if exists(':Start') == 0 && !has('win32') && arg !~# flags
let arg .= ' -d'
endif
if a:arg =~# flags
call self.execute_rails_command('server '.a:arg)
else
call self.start_rails_command('server '.a:arg, a:bg)
endif
return ''
endfunction
function! s:color_efm(pre, before, after)
return a:pre . '%\e%\S%\+ %#' . a:before . '%\e[0m %#' . a:after . ',' .
\ a:pre . '%\s %#'.a:before.' %#'.a:after . ','
endfunction
let s:efm_generate =
\ s:color_efm('%-G', 'invoke', '%f') .
\ s:color_efm('%-G', 'conflict', '%f') .
\ s:color_efm('%-G', 'run', '%f') .
\ s:color_efm('%-G', '%\w%\+', ' ') .
\ 'Overwrite%.%#%\S%\+ %#%m%\e[0m %#%f,' .
\ s:color_efm('', '%m%\>', '%f') .
\ '%-G%.%#'
function! s:app_generator_command(bang,...) dict
call self.cache.clear('user_classes')
call self.cache.clear('features')
let cmd = join(map(copy(a:000),'s:rquote(v:val)'),' ')
let old_makeprg = &l:makeprg
let old_errorformat = &l:errorformat
try
let &l:makeprg = self.prepare_rails_command(cmd)
let &l:errorformat = s:efm_generate . ',chdir '.escape(self.path(), ',')
noautocmd make!
finally
let &l:errorformat = old_errorformat
let &l:makeprg = old_makeprg
endtry
if a:bang || empty(getqflist())
return ''
else
return 'cfirst'
endif
endfunction
call s:add_methods('app', ['generators','output_command','server_command','generator_command'])
function! s:Complete_script(ArgLead, CmdLine, P) abort
return rails#complete_rails(a:ArgLead, a:CmdLine, a:P, rails#app())
endfunction
function! rails#complete_rails(ArgLead, CmdLine, P, ...) abort
if a:0
let app = a:1
else
let manifest = findfile('config/environment.rb', escape(getcwd(), ' ,;').';')
let app = empty(manifest) ? {} : rails#app(fnamemodify(manifest, ':p:h:h'))
endif
let cmd = s:sub(a:CmdLine,'^\u\w*\s+','')
if cmd =~# '^new\s\+'
return split(glob(a:ArgLead.'*/'), "\n")
elseif empty(app)
return s:completion_filter(['new'], a:ArgLead)
elseif cmd =~# '^\w*$'
let cmds = ['generate', 'console', 'server', 'dbconsole', 'destroy', 'plugin', 'runner']
if app.has('rails5')
call extend(cmds, app.rake_tasks())
endif
return s:completion_filter(cmds, a:ArgLead)
elseif cmd =~# '^\%([rt]\|runner\|test\|test:db\)\s\+'
return s:completion_filter(app.relglob('', s:fuzzyglob(a:ArgLead)), a:ArgLead)
elseif cmd =~# '^\%([gd]\|generate\|destroy\)\s\+'.a:ArgLead.'$'
return s:completion_filter(app.generators(),a:ArgLead)
elseif cmd =~# '^\%([gd]\|generate\|destroy\)\s\+\w\+\s\+'.a:ArgLead.'$'
let target = matchstr(cmd,'^\w\+\s\+\%(\w\+:\)\=\zs\w\+\ze\s\+')
if target =~# '^\w*controller$'
return filter(s:controllerList(a:ArgLead,"",""),'v:val !=# "application"')
elseif target ==# 'generator'
return s:completion_filter(map(app.relglob('lib/generators/','*'),'s:sub(v:val,"/$","")'), a:ArgLead)
elseif target ==# 'helper'
return s:autocamelize(app.relglob('app/helpers/','**/*','_helper.rb'),a:ArgLead)
elseif target ==# 'integration_test' || target ==# 'integration_spec' || target ==# 'feature'
return s:autocamelize(
\ app.relglob('test/integration/','**/*','_test.rb') +
\ app.relglob('spec/features/', '**/*', '_spec.rb') +
\ app.relglob('spec/requests/', '**/*', '_spec.rb') +
\ app.relglob('features/', '**/*', '.feature'), a:ArgLead)
elseif target ==# 'migration' || target ==# 'session_migration'
return s:migrationList(a:ArgLead,"","")
elseif target ==# 'mailer'
return s:mailerList(a:ArgLead,"","")
return s:completion_filter(app.relglob("app/mailers/","**/*",".rb"),a:ArgLead)
elseif target =~# '^\w*\%(model\|resource\)$' || target =~# '\w*scaffold\%(_controller\)\=$'
return s:completion_filter(app.relglob('app/models/','**/*','.rb'), a:ArgLead)
else
return []
endif
elseif cmd =~# '^\%([gd]\|generate\|destroy\)\s\+scaffold\s\+\w\+\s\+'.a:ArgLead.'$'
return filter(s:controllerList(a:ArgLead,"",""),'v:val !=# "application"')
return s:completion_filter(app.environments())
elseif cmd =~# '^\%(c\|console\)\s\+\(--\=\w\+\s\+\)\='.a:ArgLead."$"
return s:completion_filter(app.environments()+["-s","--sandbox"],a:ArgLead)
elseif cmd =~# '^\%(db\|dbconsole\)\s\+\(--\=\w\+\s\+\)\='.a:ArgLead."$"
return s:completion_filter(app.environments()+["-p","--include-password"],a:ArgLead)
elseif cmd =~# '^\%(s\|server\)\s\+.*-e\s\+'.a:ArgLead."$"
return s:completion_filter(app.environments(),a:ArgLead)
elseif cmd =~# '^\%(s\|server\)\s\+'
if a:ArgLead =~# '^--environment='
return s:completion_filter(map(copy(app.environments()),'"--environment=".v:val'),a:ArgLead)
else
return filter(["-p","-b","-c","-d","-u","-e","-P","-h","--port=","--binding=","--config=","--daemon","--debugger","--environment=","--pid=","--help"],'s:startswith(v:val,a:ArgLead)')
endif
endif
return ""
endfunction
function! s:CustomComplete(A,L,P,cmd)
let L = "Rscript ".a:cmd." ".s:sub(a:L,'^\h\w*\s+','')
let P = a:P - strlen(a:L) + strlen(L)
return s:Complete_script(a:A,L,P)
endfunction
function! s:Complete_server(A,L,P)
return s:CustomComplete(a:A,a:L,a:P,"server")
endfunction
function! s:Complete_console(A,L,P)
return s:CustomComplete(a:A,a:L,a:P,"console")
endfunction
function! s:Complete_generate(A,L,P)
return s:CustomComplete(a:A,a:L,a:P,"generate")
endfunction
function! s:Complete_destroy(A,L,P)
return s:CustomComplete(a:A,a:L,a:P,"destroy")
endfunction
function! s:Complete_ruby(A,L,P)
return s:completion_filter(rails#app().user_classes()+["ActiveRecord::Base"],a:A)
endfunction
" }}}1
" Navigation {{{1
function! s:BufNavCommands()
command! -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Cd :cd `=rails#app().path(<q-args>)`
command! -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Lcd :lcd `=rails#app().path(<q-args>)`
command! -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Rcd :cd `=rails#app().path(<q-args>)`
command! -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Rlcd :lcd `=rails#app().path(<q-args>)`
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related A :exe s:Alternate('E<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AE :exe s:Alternate('E<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AS :exe s:Alternate('S<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AV :exe s:Alternate('V<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AT :exe s:Alternate('T<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AD :exe s:Alternate('D<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AR :exe s:Alternate('D<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related R :exe s:Related('E<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RE :exe s:Related('E<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RS :exe s:Related('S<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RV :exe s:Related('V<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RT :exe s:Related('T<bang>',<line1>,<line2>,<count>,<f-args>)
command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RD :exe s:Related('D<bang>',<line1>,<line2>,<count>,<f-args>)
endfunction
function! s:jumpargs(file, jump) abort
let file = fnameescape(a:file)
if empty(a:jump)
return file
elseif a:jump ==# '!'
return '+AD ' . file
elseif a:jump =~# '^\d\+$'
return '+' . a:jump . ' ' . file
else
return '+A#' . a:jump . ' ' . file
endif
endfunction
function! s:jump(def, ...) abort
let def = s:sub(a:def,'^[#:]','')
let edit = s:editcmdfor(a:0 ? a:1 : '')
if edit !~# 'edit'
exe edit
endif
if def =~ '^\d\+$'
exe def
elseif def !~# '^$\|^!'
let ext = matchstr(def,'\.\zs.*')
let def = matchstr(def,'[^.]*')
let include = &l:include
try
setlocal include=
exe 'djump' def
catch /^Vim(djump):E387/
catch
let error = 1
finally
let &l:include = include
endtry
if !empty(ext) && expand('%:e') ==# 'rb' && !exists('error')
let rpat = '\C^\s*\%(mail\>.*\|respond_to\)\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|'
let end = s:endof(line('.'))
let rline = search(rpat,'',end)
if rline > 0
let variable = matchstr(getline(rline),rpat)
let success = search('\C^\s*'.variable.'\s*\.\s*\zs'.ext.'\>','',end)
if !success
try
setlocal include=
exe 'djump' def
catch
finally
let &l:include = include
endtry
endif
endif
endif
endif
return ''
endfunction
function! s:fuzzyglob(arg)
return s:gsub(s:gsub(a:arg,'[^/.]','[&]*'),'%(/|^)\.@!|\.','&*')
endfunction
function! s:Complete_find(ArgLead, CmdLine, CursorPos)
let paths = s:pathsplit(&l:path)
let seen = {}
for path in paths
if s:startswith(path,rails#app().path()) && path !~ '[][*]'
let path = path[strlen(rails#app().path()) + 1 : ]
for file in rails#app().relglob(path == '' ? '' : path.'/',s:fuzzyglob(rails#underscore(a:ArgLead)), a:ArgLead =~# '\u' ? '.rb' : '')
let seen[file] = 1
endfor
endif
endfor
return s:autocamelize(sort(keys(seen)),a:ArgLead)
endfunction
function! s:Complete_edit(ArgLead, CmdLine, CursorPos)
return s:completion_filter(rails#app().relglob("",s:fuzzyglob(a:ArgLead)),a:ArgLead)
endfunction
function! s:Complete_cd(ArgLead, CmdLine, CursorPos)
let all = rails#app().relglob("",a:ArgLead."*")
call filter(all,'v:val =~ "/$"')
return filter(all,'s:startswith(v:val,a:ArgLead)')
endfunction
function! rails#includeexpr(fname) abort
if mode() =~# '[iR]' || expand('<cfile>') !=# a:fname
return s:RailsIncludefind(a:fname)
else
return s:RailsIncludefind(a:fname, 1)
endif
endfunction
function! s:linepeak()
let line = getline(line("."))
let line = s:sub(line,'^(.{'.col(".").'}).*','\1')
let line = s:sub(line,'([:"'."'".']|\%[qQ]=[[({<])=\f*$','')
return line
endfunction
function! s:matchcursor(pat)
let line = getline(".")
let lastend = 0
while lastend >= 0
let beg = match(line,'\C'.a:pat,lastend)
let end = matchend(line,'\C'.a:pat,lastend)
if beg < col(".") && end >= col(".")
return matchstr(line,'\C'.a:pat,lastend)
endif
let lastend = end
endwhile
return ""
endfunction
function! s:findit(pat,repl)
let res = s:matchcursor(a:pat)
if res != ""
return substitute(res,'\C'.a:pat,a:repl,'')
else
return ""
endif
endfunction
function! s:findamethod(func,repl)
return s:findit('\s*\<\%('.a:func.'\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>.\=',a:repl)
endfunction
function! s:findasymbol(sym,repl)
return s:findit('\s*\%(:\%('.a:sym.'\)\s*=>\|\<'.a:sym.':\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>.\=',a:repl)
endfunction
function! s:findfromview(func,repl)
" ( ) ( ) ( \1 ) ( )
return s:findit('\s*\%(<%\)\==\=\s*\<\%('.a:func.'\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>['."'".'"]\=\s*\%(%>\s*\)\=',a:repl)
endfunction
function! s:findasset(path, ext, pre, post) abort
let asset = rails#app().resolve_asset(a:path, a:ext)
return len(asset) ? asset : rails#app().path(a:pre . a:path . a:post)
endfunction
function! s:cfile(...) abort
if filereadable(expand("<cfile>"))
return expand("<cfile>")
endif
" UGH
let buffer = rails#buffer()
let format = s:format()
let ssext = ['css', 'css.*', 'scss', 'sass']
if buffer.type_name('stylesheet')
let res = s:findit('^\s*\*=\s*require\s*["'']\=\([^"'' ]*\)', '\1')
if !empty(res)
return s:findasset(res, ssext, "app/assets/stylesheets/", ".css")
endif
let res = s:findit('^\s*@import\s*\%(url(\)\=["'']\=\([^"'' ]*\)', '\1')
if res != ""
let base = expand('%:p:h')
let rel = s:sub(res, '\ze[^/]*$', '_')
for ext in ['css', 'css.scss', 'css.sass', 'scss', 'sass']
for name in [res.'.'.ext, res.'.'.ext.'.erb', rel.'.'.ext, rel.'.'.ext.'.erb']
if filereadable(base.'/'.name)
return base.'/'.name
endif
endfor
endfor
let asset = rails#app().resolve_asset(res, ssext)
if empty(asset) && expand('%:e') =~# '^s[ac]ss$'
let asset = rails#app().resolve_asset(rel, ssext)
endif
return empty(asset) ? 'app/assets/stylesheets/'.res : asset
endif
endif
let jsext = ['js', 'js.*', 'jst', 'jst.*', 'coffee']
if buffer.type_name('javascript')
let res = s:findit('^\s*//=\s*require\s*["'']\=\([^"'' ]*\)', '\1')
if !empty(res)
return s:findasset(res, jsext, "app/assets/javascript/", ".js")
endif
return expand("<cfile>")
endif
let res = s:findit('\v\s*<require\s*\(=\s*File.dirname\(__FILE__\)\s*\+\s*[:'."'".'"](\f+)>.=',expand('%:h').'/\1')
if res != ""|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
let res = s:findit('\v<File.dirname\(__FILE__\)\s*\+\s*[:'."'".'"](\f+)>['."'".'"]=',expand('%:h').'\1')
if res != ""|return res|endif
let res = rails#underscore(s:findit('\v\s*<%(include|extend)\(=\s*<([[:alnum:]_:]+)>','\1'))
if res != ""|return res.".rb"|endif
let res = s:findamethod('require','\1')
if res != ""|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
let res = s:findamethod('belongs_to\|has_one\|embedded_in\|embeds_one\|composed_of\|validates_associated\|scaffold','\1.rb')
if res != ""|return res|endif
let res = rails#singularize(s:findamethod('has_many\|has_and_belongs_to_many\|embeds_many','\1'))
if res != ""|return res.".rb"|endif
let res = rails#singularize(s:findamethod('create_table\|change_table\|drop_table\|rename_table\|\%(add\|remove\)_\%(column\|index\|timestamps\|reference\|belongs_to\)\|rename_column\|remove_columns\|rename_index','\1'))
if res != ""|return res.".rb"|endif
let res = rails#singularize(s:findasymbol('through','\1'))
if res != ""|return res.".rb"|endif
let res = s:findamethod('fixtures','fixtures/\1')
if res != ""
return RailsFilePath() =~ '\<spec/' ? 'spec/'.res : res
endif
let res = s:findamethod('\%(\w\+\.\)\=resources','\1_controller.rb')
if res != ""|return res|endif
let res = s:findamethod('\%(\w\+\.\)\=resource','\1')
if res != ""|return rails#pluralize(res)."_controller.rb"|endif
let res = s:findasymbol('to','\1')
if res =~ '#'|return s:sub(res,'#','_controller.rb#')|endif
let res = s:findamethod('root\s*\%(:to\s*=>\|\<to:\)\s*','\1')
if res =~ '#'|return s:sub(res,'#','_controller.rb#')|endif
let res = s:findamethod('\%(match\|get\|put\|patch\|post\|delete\|redirect\)\s*(\=\s*[:''"][^''"]*[''"]\=\s*\%(\%(,\s*:to\s*\)\==>\|,\s*to:\)\s*','\1')
if res =~ '#'|return s:sub(res,'#','_controller.rb#')|endif
if !buffer.type_name('controller', 'mailer')
let res = s:sub(s:sub(s:findasymbol('layout','\1'),'^/',''),'[^/]+$','_&')
if res != ""|return s:findview(res)|endif
let res = s:sub(s:sub(s:findfromview('render\s*(\=\s*\%(:layout\s\+=>\|layout:\)\s*','\1'),'^/',''),'[^/]+$','_&')
if res != ""|return s:findview(res)|endif
endif
let res = s:findamethod('layout','\=s:findlayout(submatch(1))')
if res != ""|return res|endif
let res = s:findasymbol('layout','\=s:findlayout(submatch(1))')
if res != ""|return res|endif
let res = s:findamethod('helper','\1_helper.rb')
if res != ""|return res|endif
let res = s:findasymbol('controller','\1_controller.rb')
if res != ""|return res|endif
let res = s:findasymbol('action','\1')
if res != ""|return s:findview(res)|endif
let res = s:findasymbol('template','\1')
if res != ""|return s:findview(res)|endif
let res = s:sub(s:sub(s:findasymbol('partial','\1'),'^/',''),'[^/]+$','_&')
if res != ""|return s:findview(res)|endif
let res = s:sub(s:sub(s:findfromview('json\.(\=\s*\%(:partial\s\+=>\|partial!\)\s*','\1'),'^/',''),'[^/]+$','_&')
if res != ""|return s:findview(res)|endif
let res = s:sub(s:sub(s:findfromview('render\s*(\=\s*\%(:partial\s\+=>\|partial:\)\s*','\1'),'^/',''),'[^/]+$','_&')
if res != ""|return s:findview(res)|endif
let res = s:findamethod('render\>\s*\%(:\%(template\|action\)\s\+=>\|template:\|action:\)\s*','\1')
if res != ""|return s:findview(res)|endif
let res = s:sub(s:findfromview('render','\1'),'^/','')
if !buffer.type_name('controller', 'mailer')
let res = s:sub(res,'[^/]+$','_&')
endif
if res != ""|return s:findview(res)|endif
let res = s:findamethod('redirect_to\s*(\=\s*\%\(:action\s\+=>\|\<action:\)\s*','\1')
if res != ""|return res|endif
let res = s:findfromview('image[_-]\%(\|path\|url\)\|\%(path\|url\)_to_image','\1')
if res != ""
return s:findasset(res, [], 'public/images/', '')
endif
let res = s:findfromview('stylesheet[_-]\%(link_tag\|path\|url\)\|\%(path\|url\)_to_stylesheet','\1')
if res != ""
return s:findasset(res, ssext, 'public/stylesheets/', '.css')
endif
let res = s:sub(s:findfromview('javascript_\%(include_tag\|path\|url\)\|\%(path\|url\)_to_javascript','\1'),'/defaults>','/application')
if res != ""
return s:findasset(res, jsext, 'public/javascripts/', '.js')
endif
if buffer.type_name('controller', 'mailer')
let contr = s:controller()
let view = s:findit('\s*\<def\s\+\(\k\+\)\>(\=','/\1')
if view !=# ''
let res = rails#buffer().resolve_view(contr.view)
if res != ""|return res|endif
endif
endif
let old_isfname = &isfname
try
set isfname=@,48-57,/,-,_,:,#
" TODO: grab visual selection in visual mode
let cfile = expand("<cfile>")
finally
let &isfname = old_isfname
endtry
let res = s:RailsIncludefind(cfile,1)
return res
endfunction
function! rails#cfile(...) abort
let cfile = s:find('find', s:cfile())[5:-1]
return empty(cfile) && a:0 && a:1 is# 'delegate' ? "\<C-R>\<C-F>" : cfile
endfunction
function! s:app_named_route_file(route) dict abort
call self.route_names()
if self.cache.has("named_routes") && has_key(self.cache.get("named_routes"),a:route)
return s:sub(self.cache.get("named_routes")[a:route].handler, '#', '_controller.rb#')
endif
return ""
endfunction
function! s:app_route_names() dict abort
if self.cache.needs("named_routes")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
let cwd = getcwd()
let routes = {}
try
execute cd fnameescape(rails#app().path())
let output = system(self.rake_command().' routes')
finally
execute cd fnameescape(cwd)
endtry
for line in split(output, "\n")
let matches = matchlist(line, '^ \+\(\l\w*\) \{-\}\(\u*\) \+\(\S\+\) \+\(\w\+#\w\+\)')
if !empty(matches)
let [_, name, method, path, handler; __] = matches
let routes[name] = {'method': method, 'path': path, 'handler': handler}
endif
endfor
call self.cache.set("named_routes",routes)
endif
return keys(self.cache.get("named_routes"))
endfunction
call s:add_methods('app', ['route_names','named_route_file'])
function! s:RailsIncludefind(str,...) abort
if a:str ==# "ApplicationController" && rails#app().has_path('app/controllers/application.rb')
return 'application.rb'
endif
let str = a:str
if a:0 == 1
" Get the text before the filename under the cursor.
" We'll cheat and peak at this in a bit
let line = s:linepeak()
let line = s:sub(line,'([:"'."'".']|\%[qQ]=[[({<])=\f*$','')
else
let line = ""
endif
let str = s:sub(str,'^\s*','')
let str = s:sub(str,'\s*$','')
let str = s:sub(str,'^:=[:@]','')
let str = s:sub(str,':0x\x+$','') " For #<Object:0x...> style output
let str = s:gsub(str,"[\"']",'')
if line =~# '\<\(require\|load\)\s*(\s*$'
return str
elseif str =~# '^\l\w*#\w\+$'
return s:sub(str,'#','_controller.rb#')
endif
let str = rails#underscore(str)
let fpat = '\(\s*\%("\f*"\|:\f*\|'."'\\f*'".'\)\s*,\s*\)*'
if a:str =~# '\u' && &filetype !~# 'javascript\|coffee'
" Classes should always be in .rb files
let str .= '.rb'
elseif line =~# ':partial\s*=>\s*' || (line =~# ':layout\s*=>\s*' && !rails#buffer().type_name('controller', 'mailer'))
let str = s:sub(str,'[^/]+$','_&')
let str = s:findview(str)
elseif line =~# '\<layout\s*(\=\s*' || line =~# ':layout\s*=>\s*'
let str = s:findview(s:sub(str,'^/=','layouts/'))
elseif line =~# ':controller\s*=>\s*'
let str = str.'_controller.rb'
elseif line =~# '\<helper\s*(\=\s*'
let str = str.'_helper.rb'
elseif line =~# '\<fixtures\s*(\='.fpat
if RailsFilePath() =~# '\<spec/'
let str = s:sub(str,'^/@!','spec/fixtures/')
else
let str = s:sub(str,'^/@!','test/fixtures/')
endif
elseif line =~# '\<stylesheet_\(link_tag\|path\)\s*(\='.fpat
let str = s:sub(str,'^/@!','/stylesheets/')
if str != '' && fnamemodify(str, ':e') == ''
let str .= '.css'
endif
elseif line =~# '\<javascript_\(include_tag\|path\)\s*(\='.fpat
if str ==# "defaults"
let str = "application"
endif
let str = s:sub(str,'^/@!','/javascripts/')
if str != '' && fnamemodify(str, ':e') == ''
let str .= '.js'
endif
elseif line =~# '\<\(has_one\|belongs_to\)\s*(\=\s*'
let str = str.'.rb'
elseif line =~# '\<has_\(and_belongs_to_\)\=many\s*(\=\s*'
let str = rails#singularize(str).'.rb'
elseif line =~# '\<def\s\+' && expand("%:t") =~# '_controller\.rb'
let str = s:findview(str)
elseif str =~# '_\%(path\|url\)$' || (line =~# ':as\s*=>\s*$' && rails#buffer().type_name('config-routes'))
if line !~# ':as\s*=>\s*$'
let str = s:sub(str,'_%(path|url)$','')
let str = s:sub(str,'^hash_for_','')
endif
let file = rails#app().named_route_file(str)
if file == ""
let str = s:sub(str,'^formatted_','')
if str =~# '^\%(new\|edit\)_'
let str = s:sub(rails#pluralize(str),'^(new|edit)_(.*)','\2_controller.rb#\1')
elseif str ==# rails#singularize(str)
" If the word can't be singularized, it's probably a link to the show
" method. We should verify by checking for an argument, but that's
" difficult the way things here are currently structured.
let str = rails#pluralize(str).'_controller.rb#show'
else
let str = str.'_controller.rb#index'
endif
else
let str = file
endif
elseif str !~ '/'
" If we made it this far, we'll risk making it singular.
let str = rails#singularize(str)
let str = s:sub(str,'_id$','')
endif
if str =~ '^/' && !filereadable(str)
let str = s:sub(str,'^/','')
endif
if str =~# '^lib/' && !filereadable(str)
let str = s:sub(str,'^lib/','')
endif
return str
endfunction
" }}}1
" Projection Commands {{{1
function! s:app_commands() dict abort
let commands = {}
let all = self.projections()
for pattern in sort(keys(all), function('rails#lencmp'))
let projection = all[pattern]
for name in s:split(get(projection, 'command', get(projection, 'type', get(projection, 'name', ''))))
let command = {
\ 'pattern': pattern,
\ 'affinity': get(projection, 'affinity', '')}
if !has_key(commands, name)
let commands[name] = []
endif
call insert(commands[name], command)
endfor
endfor
call filter(commands, '!empty(v:val)')
return commands
endfunction
call s:add_methods('app', ['commands'])
function! s:addfilecmds(type)
let l = s:sub(a:type,'^.','\l&')
for prefix in ['E', 'S', 'V', 'T', 'D', 'R', 'RE', 'RS', 'RV', 'RT', 'RD']
let cplt = " -complete=customlist,".s:sid.l."List"
exe "command! -buffer -bar ".(prefix =~# 'D' ? '-range=0 ' : '')."-nargs=*".cplt." ".prefix.l." :execute s:".l.'Edit("'.(prefix =~# 'D' ? '<line1>' : '').s:sub(prefix, '^R', '').'<bang>",<f-args>)'
endfor
endfunction
function! s:BufProjectionCommands()
call s:addfilecmds("view")
call s:addfilecmds("migration")
call s:addfilecmds("schema")
call s:addfilecmds("layout")
call s:addfilecmds("fixtures")
call s:addfilecmds("locale")
if rails#app().has('spec')
call s:addfilecmds("spec")
endif
call s:addfilecmds("stylesheet")
call s:addfilecmds("javascript")
for [name, command] in items(rails#app().commands())
call s:define_navcommand(name, command)
endfor
endfunction
function! s:completion_filter(results, A, ...) abort
if exists('*projectionist#completion_filter')
return projectionist#completion_filter(a:results, a:A, a:0 ? a:1 : '/')
endif
let results = s:uniq(sort(type(a:results) == type("") ? split(a:results,"\n") : copy(a:results)))
call filter(results,'v:val !~# "\\~$"')
if a:A =~# '\*'
let regex = s:gsub(a:A,'\*','.*')
return filter(copy(results),'v:val =~# "^".regex')
endif
let filtered = filter(copy(results),'s:startswith(v:val,a:A)')
if !empty(filtered) | return filtered | endif
let prefix = s:sub(a:A,'(.*[/]|^)','&_')
let filtered = filter(copy(results),"s:startswith(v:val,prefix)")
if !empty(filtered) | return filtered | endif
let regex = s:gsub(a:A,'[^/]','[&].*')
let filtered = filter(copy(results),'v:val =~# "^".regex')
if !empty(filtered) | return filtered | endif
let regex = s:gsub(a:A,'.','[&].*')
let filtered = filter(copy(results),'v:val =~# regex')
return filtered
endfunction
function! s:autocamelize(files,test)
if a:test =~# '^\u'
return s:completion_filter(map(copy(a:files),'rails#camelize(v:val)'),a:test)
else
return s:completion_filter(a:files,a:test)
endif
endfunction
function! s:app_relglob(path,glob,...) dict
if exists("+shellslash") && ! &shellslash
let old_ss = &shellslash
let &shellslash = 1
endif
let path = a:path
if path !~ '^/' && path !~ '^\w:'
let path = self.path(path)
endif
let suffix = a:0 ? a:1 : ''
let full_paths = split(glob(path.a:glob.suffix),"\n")
let relative_paths = []
for entry in full_paths
if suffix == '' && isdirectory(entry) && entry !~ '/$'
let entry .= '/'
endif
let relative_paths += [entry[strlen(path) : -strlen(suffix)-1]]
endfor
if exists("old_ss")
let &shellslash = old_ss
endif
return relative_paths
endfunction
call s:add_methods('app', ['relglob'])
function! s:relglob(...)
return join(call(rails#app().relglob,a:000,rails#app()),"\n")
endfunction
function! s:controllerList(A,L,P)
let con = rails#app().relglob("app/controllers/","**/*",".rb")
call map(con,'s:sub(v:val,"_controller$","")')
return s:autocamelize(con,a:A)
endfunction
function! s:viewList(A,L,P)
let c = s:controller(1)
let top = rails#app().relglob("app/views/",s:fuzzyglob(a:A))
call filter(top,'v:val !~# "\\~$"')
if c != '' && a:A !~ '/'
let local = rails#app().relglob("app/views/".c."/","*.*[^~]")
return s:completion_filter(local+top,a:A)
endif
return s:completion_filter(top,a:A)
endfunction
function! s:layoutList(A,L,P)
return s:completion_filter(rails#app().relglob("app/views/layouts/","*"),a:A)
endfunction
function! s:stylesheetList(A,L,P)
let list = rails#app().relglob('app/assets/stylesheets/','**/*.*','')
call map(list,'s:sub(v:val,"\\..*$","")')
let list += rails#app().relglob('public/stylesheets/','**/*','.css')
if rails#app().has('sass')
call extend(list,rails#app().relglob('public/stylesheets/sass/','**/*','.s?ss'))
call s:uniq(list)
endif
return