vim-easymotion/autoload/vital/_easymotion.vim

291 lines
7.8 KiB
VimL
Raw Normal View History

2014-01-29 00:29:23 -05:00
let s:self_version = expand('<sfile>:t:r')
2015-02-23 11:19:17 -05:00
let s:self_file = expand('<sfile>')
let s:base_dir = expand('<sfile>:h')
2014-01-29 00:29:23 -05:00
let s:loaded = {}
2015-06-28 10:01:55 -04:00
let s:cache_module_path = {}
let s:cache_sid = {}
let s:_unify_path_cache = {}
2014-01-29 00:29:23 -05:00
function! s:plugin_name() abort
let info_file = get(split(glob(s:base_dir . '/*.vital', 1), "\n"), 0, '')
return fnamemodify(info_file, ':t:r')
endfunction
function! s:vital_files() abort
if !exists('s:vital_files')
let s:vital_files =
\ map(
\ s:plugin_name() ==# 'vital'
\ ? s:_global_vital_files()
\ : s:_self_vital_files(),
\ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")')
endif
return copy(s:vital_files)
endfunction
2014-11-23 12:07:19 -05:00
function! s:import(name, ...) abort
2014-01-29 00:29:23 -05:00
let target = {}
let functions = []
for a in a:000
if type(a) == type({})
let target = a
elseif type(a) == type([])
let functions = a
endif
unlet a
endfor
let module = s:_import(a:name)
if empty(functions)
call extend(target, module, 'keep')
else
for f in functions
if has_key(module, f) && !has_key(target, f)
let target[f] = module[f]
endif
endfor
endif
return target
endfunction
2014-11-23 12:07:19 -05:00
function! s:load(...) dict abort
2014-01-29 00:29:23 -05:00
for arg in a:000
let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg]
let target = split(join(as, ''), '\W\+')
let dict = self
2015-06-28 10:01:55 -04:00
let dict_type = type({})
while !empty(target)
2014-01-29 00:29:23 -05:00
let ns = remove(target, 0)
if !has_key(dict, ns)
let dict[ns] = {}
endif
2015-06-28 10:01:55 -04:00
if type(dict[ns]) == dict_type
2014-01-29 00:29:23 -05:00
let dict = dict[ns]
else
unlet dict
break
endif
endwhile
if exists('dict')
call extend(dict, s:_import(name))
endif
unlet arg
endfor
return self
endfunction
2014-11-23 12:07:19 -05:00
function! s:unload() abort
2014-01-29 00:29:23 -05:00
let s:loaded = {}
2015-06-28 10:01:55 -04:00
let s:cache_sid = {}
let s:cache_module_path = {}
unlet! s:vital_files
2014-01-29 00:29:23 -05:00
endfunction
2014-11-23 12:07:19 -05:00
function! s:exists(name) abort
2014-06-06 12:35:19 -04:00
return s:_get_module_path(a:name) !=# ''
endfunction
2014-11-23 12:07:19 -05:00
function! s:search(pattern) abort
let paths = s:_extract_files(a:pattern, s:vital_files())
2014-06-06 12:35:19 -04:00
let modules = sort(map(paths, 's:_file2module(v:val)'))
return s:_uniq(modules)
endfunction
2014-11-23 12:07:19 -05:00
function! s:_import(name) abort
2014-01-29 00:29:23 -05:00
if type(a:name) == type(0)
return s:_build_module(a:name)
endif
let path = s:_get_module_path(a:name)
if path ==# ''
throw 'vital: module not found: ' . a:name
endif
2014-07-15 11:43:16 -04:00
let sid = s:_get_sid_by_script(path)
2014-01-29 00:29:23 -05:00
if !sid
try
execute 'source' fnameescape(path)
catch /^Vim\%((\a\+)\)\?:E484/
throw 'vital: module not found: ' . a:name
catch /^Vim\%((\a\+)\)\?:E127/
" Ignore.
endtry
2014-07-15 11:43:16 -04:00
let sid = s:_get_sid_by_script(path)
2014-01-29 00:29:23 -05:00
endif
return s:_build_module(sid)
endfunction
2014-11-23 12:07:19 -05:00
function! s:_get_module_path(name) abort
2015-06-28 10:01:55 -04:00
let key = a:name . '_'
if has_key(s:cache_module_path, key)
return s:cache_module_path[key]
endif
2014-01-29 00:29:23 -05:00
if s:_is_absolute_path(a:name) && filereadable(a:name)
2014-07-15 11:43:16 -04:00
return a:name
2014-01-29 00:29:23 -05:00
endif
if a:name =~# '\v^\u\w*%(\.\u\w*)*$'
let paths = s:_extract_files(a:name, s:vital_files())
2014-01-29 00:29:23 -05:00
else
throw 'vital: Invalid module name: ' . a:name
endif
call filter(paths, 'filereadable(expand(v:val, 1))')
2014-06-06 12:35:19 -04:00
let path = get(paths, 0, '')
2015-06-28 10:01:55 -04:00
let s:cache_module_path[key] = path
return path
2014-01-29 00:29:23 -05:00
endfunction
2014-11-23 12:07:19 -05:00
function! s:_get_sid_by_script(path) abort
2015-06-28 10:01:55 -04:00
if has_key(s:cache_sid, a:path)
return s:cache_sid[a:path]
endif
2014-07-15 11:43:16 -04:00
let path = s:_unify_path(a:path)
let p = 'stridx(v:val, s:self_version) > 0 || stridx(v:val, "__latest__") > 0'
for line in filter(split(s:_redir('scriptnames'), "\n"), p)
2014-01-29 00:29:23 -05:00
let list = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$')
2014-07-15 11:43:16 -04:00
if !empty(list) && s:_unify_path(list[2]) ==# path
2015-06-28 10:01:55 -04:00
let s:cache_sid[a:path] = list[1] - 0
return s:cache_sid[a:path]
2014-01-29 00:29:23 -05:00
endif
endfor
2014-07-15 11:43:16 -04:00
return 0
2014-01-29 00:29:23 -05:00
endfunction
2014-11-23 12:07:19 -05:00
function! s:_file2module(file) abort
2015-06-28 10:01:55 -04:00
let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?')
2014-06-06 12:35:19 -04:00
let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$')
return join(split(tail, '[\\/]\+'), '.')
endfunction
2014-01-29 00:29:23 -05:00
if filereadable(expand('<sfile>:r') . '.VIM')
2014-07-15 11:43:16 -04:00
" resolve() is slow, so we cache results.
" Note: On windows, vim can't expand path names from 8.3 formats.
" So if getting full path via <sfile> and $HOME was set as 8.3 format,
" vital load duplicated scripts. Below's :~ avoid this issue.
2014-11-23 12:07:19 -05:00
function! s:_unify_path(path) abort
2014-07-15 11:43:16 -04:00
if has_key(s:_unify_path_cache, a:path)
return s:_unify_path_cache[a:path]
endif
let value = tolower(fnamemodify(resolve(fnamemodify(
2015-06-28 10:01:55 -04:00
\ a:path, ':p')), ':~:gs?[\\/]?/?'))
2014-07-15 11:43:16 -04:00
let s:_unify_path_cache[a:path] = value
return value
2014-01-29 00:29:23 -05:00
endfunction
else
2014-11-23 12:07:19 -05:00
function! s:_unify_path(path) abort
2015-06-28 10:01:55 -04:00
return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?'))
2014-01-29 00:29:23 -05:00
endfunction
endif
function! s:_self_vital_files() abort
let base = s:base_dir . '/*/**/*.vim'
return split(glob(base, 1), "\n")
endfunction
2014-06-06 12:35:19 -04:00
function! s:_global_vital_files() abort
let pattern = 'autoload/vital/__latest__/**/*.vim'
return split(globpath(&runtimepath, pattern, 1), "\n")
endfunction
function! s:_extract_files(pattern, files) abort
let tr = {'.': '/', '*': '[^/]*', '**': '.*'}
let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g')
let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target)
return filter(a:files, 'v:val =~# regexp')
2014-07-15 11:43:16 -04:00
endfunction
2014-01-29 00:29:23 -05:00
" Copy from System.Filepath
if has('win16') || has('win32') || has('win64')
2014-11-23 12:07:19 -05:00
function! s:_is_absolute_path(path) abort
2014-01-29 00:29:23 -05:00
return a:path =~? '^[a-z]:[/\\]'
endfunction
else
2014-11-23 12:07:19 -05:00
function! s:_is_absolute_path(path) abort
2014-01-29 00:29:23 -05:00
return a:path[0] ==# '/'
endfunction
endif
2014-11-23 12:07:19 -05:00
function! s:_build_module(sid) abort
2014-01-29 00:29:23 -05:00
if has_key(s:loaded, a:sid)
return copy(s:loaded[a:sid])
endif
let functions = s:_get_functions(a:sid)
let prefix = '<SNR>' . a:sid . '_'
let module = {}
for func in functions
let module[func] = function(prefix . func)
endfor
if has_key(module, '_vital_created')
call module._vital_created(module)
endif
let export_module = filter(copy(module), 'v:key =~# "^\\a"')
" Cache module before calling module.vital_debug() to avoid cyclic
" dependences but remove the cache if module._vital_loaded() fails.
let s:loaded[a:sid] = get(g:, 'vital_debug', 0) ? module : export_module
2014-01-29 00:29:23 -05:00
if has_key(module, '_vital_loaded')
try
let V = vital#{s:self_version}#new()
call module._vital_loaded(V)
catch
unlet s:loaded[a:sid]
throw 'vital: fail to call ._vital_loaded(): ' . v:exception
endtry
2014-01-29 00:29:23 -05:00
endif
return copy(s:loaded[a:sid])
2014-01-29 00:29:23 -05:00
endfunction
if exists('+regexpengine')
2014-11-23 12:07:19 -05:00
function! s:_get_functions(sid) abort
2014-01-29 00:29:23 -05:00
let funcs = s:_redir(printf("function /\\%%#=2^\<SNR>%d_", a:sid))
let map_pat = '<SNR>' . a:sid . '_\zs\w\+'
return map(split(funcs, "\n"), 'matchstr(v:val, map_pat)')
endfunction
else
2014-11-23 12:07:19 -05:00
function! s:_get_functions(sid) abort
2014-01-29 00:29:23 -05:00
let prefix = '<SNR>' . a:sid . '_'
let funcs = s:_redir('function')
let filter_pat = '^\s*function ' . prefix
let map_pat = prefix . '\zs\w\+'
return map(filter(split(funcs, "\n"),
\ 'stridx(v:val, prefix) > 0 && v:val =~# filter_pat'),
\ 'matchstr(v:val, map_pat)')
endfunction
endif
2014-06-06 12:35:19 -04:00
if exists('*uniq')
2014-11-23 12:07:19 -05:00
function! s:_uniq(list) abort
2014-06-06 12:35:19 -04:00
return uniq(a:list)
endfunction
else
2014-11-23 12:07:19 -05:00
function! s:_uniq(list) abort
2014-06-06 12:35:19 -04:00
let i = len(a:list) - 1
while 0 < i
if a:list[i] ==# a:list[i - 1]
call remove(a:list, i)
let i -= 2
else
let i -= 1
endif
endwhile
return a:list
endfunction
endif
2014-11-23 12:07:19 -05:00
function! s:_redir(cmd) abort
2014-01-29 00:29:23 -05:00
let [save_verbose, save_verbosefile] = [&verbose, &verbosefile]
set verbose=0 verbosefile=
redir => res
silent! execute a:cmd
redir END
let [&verbose, &verbosefile] = [save_verbose, save_verbosefile]
return res
endfunction
2014-11-23 12:07:19 -05:00
function! vital#{s:self_version}#new() abort
let sid = s:_get_sid_by_script(s:self_file)
return s:_build_module(sid)
2014-01-29 00:29:23 -05:00
endfunction