|
1 | | -let s:self_version = expand('<sfile>:t:r') |
2 | | -let s:self_file = expand('<sfile>') |
3 | | -let s:base_dir = expand('<sfile>:h') |
| 1 | +let s:_plugin_name = expand('<sfile>:t:r') |
4 | 2 |
|
5 | | -let s:loaded = {} |
6 | | -let s:cache_module_path = {} |
7 | | -let s:cache_sid = {} |
8 | | - |
9 | | -let s:_unify_path_cache = {} |
10 | | - |
11 | | -function! s:plugin_name() abort |
12 | | - return s:self_version[1 :] |
13 | | -endfunction |
14 | | - |
15 | | -function! s:vital_files() abort |
16 | | - if !exists('s:vital_files') |
17 | | - let s:vital_files = |
18 | | - \ map( |
19 | | - \ s:plugin_name() ==# '_latest__' |
20 | | - \ ? s:_global_vital_files() |
21 | | - \ : s:_self_vital_files(), |
22 | | - \ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")') |
23 | | - endif |
24 | | - return copy(s:vital_files) |
25 | | -endfunction |
26 | | - |
27 | | -function! s:import(name, ...) abort |
28 | | - let target = {} |
29 | | - let functions = [] |
30 | | - for a in a:000 |
31 | | - if type(a) == type({}) |
32 | | - let target = a |
33 | | - elseif type(a) == type([]) |
34 | | - let functions = a |
35 | | - endif |
36 | | - unlet a |
37 | | - endfor |
38 | | - let module = s:_import(a:name) |
39 | | - if empty(functions) |
40 | | - call extend(target, module, 'keep') |
41 | | - else |
42 | | - for f in functions |
43 | | - if has_key(module, f) && !has_key(target, f) |
44 | | - let target[f] = module[f] |
45 | | - endif |
46 | | - endfor |
47 | | - endif |
48 | | - return target |
49 | | -endfunction |
50 | | - |
51 | | -function! s:load(...) dict abort |
52 | | - for arg in a:000 |
53 | | - let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg] |
54 | | - let target = split(join(as, ''), '\W\+') |
55 | | - let dict = self |
56 | | - let dict_type = type({}) |
57 | | - while !empty(target) |
58 | | - let ns = remove(target, 0) |
59 | | - if !has_key(dict, ns) |
60 | | - let dict[ns] = {} |
61 | | - endif |
62 | | - if type(dict[ns]) == dict_type |
63 | | - let dict = dict[ns] |
64 | | - else |
65 | | - unlet dict |
66 | | - break |
67 | | - endif |
68 | | - endwhile |
69 | | - |
70 | | - if exists('dict') |
71 | | - call extend(dict, s:_import(name)) |
72 | | - endif |
73 | | - unlet arg |
74 | | - endfor |
75 | | - return self |
76 | | -endfunction |
77 | | - |
78 | | -function! s:unload() abort |
79 | | - let s:loaded = {} |
80 | | - let s:cache_sid = {} |
81 | | - let s:cache_module_path = {} |
82 | | - unlet! s:vital_files |
83 | | -endfunction |
84 | | - |
85 | | -function! s:exists(name) abort |
86 | | - return s:_get_module_path(a:name) !=# '' |
87 | | -endfunction |
88 | | - |
89 | | -function! s:search(pattern) abort |
90 | | - let paths = s:_extract_files(a:pattern, s:vital_files()) |
91 | | - let modules = sort(map(paths, 's:_file2module(v:val)')) |
92 | | - return s:_uniq(modules) |
93 | | -endfunction |
94 | | - |
95 | | -function! s:_import(name) abort |
96 | | - if type(a:name) == type(0) |
97 | | - return s:_build_module(a:name) |
98 | | - endif |
99 | | - let path = s:_get_module_path(a:name) |
100 | | - if path ==# '' |
101 | | - throw 'vital: module not found: ' . a:name |
102 | | - endif |
103 | | - let sid = s:_get_sid_by_script(path) |
104 | | - if !sid |
105 | | - try |
106 | | - execute 'source' fnameescape(path) |
107 | | - catch /^Vim\%((\a\+)\)\?:E484/ |
108 | | - throw 'vital: module not found: ' . a:name |
109 | | - catch /^Vim\%((\a\+)\)\?:E127/ |
110 | | - " Ignore. |
111 | | - endtry |
112 | | - |
113 | | - let sid = s:_get_sid_by_script(path) |
114 | | - endif |
115 | | - return s:_build_module(sid) |
116 | | -endfunction |
117 | | - |
118 | | -function! s:_get_module_path(name) abort |
119 | | - let key = a:name . '_' |
120 | | - if has_key(s:cache_module_path, key) |
121 | | - return s:cache_module_path[key] |
122 | | - endif |
123 | | - if s:_is_absolute_path(a:name) && filereadable(a:name) |
124 | | - return a:name |
125 | | - endif |
126 | | - if a:name =~# '\v^\u\w*%(\.\u\w*)*$' |
127 | | - let paths = s:_extract_files(a:name, s:vital_files()) |
128 | | - else |
129 | | - throw 'vital: Invalid module name: ' . a:name |
130 | | - endif |
131 | | - |
132 | | - call filter(paths, 'filereadable(expand(v:val, 1))') |
133 | | - let path = get(paths, 0, '') |
134 | | - let s:cache_module_path[key] = path |
135 | | - return path |
136 | | -endfunction |
137 | | - |
138 | | -function! s:_get_sid_by_script(path) abort |
139 | | - if has_key(s:cache_sid, a:path) |
140 | | - return s:cache_sid[a:path] |
141 | | - endif |
142 | | - |
143 | | - let path = s:_unify_path(a:path) |
144 | | - let p = 'stridx(v:val, s:self_version) > 0 || stridx(v:val, "__latest__") > 0' |
145 | | - for line in filter(split(s:_redir('scriptnames'), "\n"), p) |
146 | | - let list = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$') |
147 | | - if !empty(list) && s:_unify_path(list[2]) ==# path |
148 | | - let s:cache_sid[a:path] = list[1] - 0 |
149 | | - return s:cache_sid[a:path] |
150 | | - endif |
151 | | - endfor |
152 | | - return 0 |
153 | | -endfunction |
154 | | - |
155 | | -function! s:_file2module(file) abort |
156 | | - let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?') |
157 | | - let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$') |
158 | | - return join(split(tail, '[\\/]\+'), '.') |
159 | | -endfunction |
160 | | - |
161 | | -if filereadable(expand('<sfile>:r') . '.VIM') |
162 | | - " resolve() is slow, so we cache results. |
163 | | - " Note: On windows, vim can't expand path names from 8.3 formats. |
164 | | - " So if getting full path via <sfile> and $HOME was set as 8.3 format, |
165 | | - " vital load duplicated scripts. Below's :~ avoid this issue. |
166 | | - function! s:_unify_path(path) abort |
167 | | - if has_key(s:_unify_path_cache, a:path) |
168 | | - return s:_unify_path_cache[a:path] |
169 | | - endif |
170 | | - let value = tolower(fnamemodify(resolve(fnamemodify( |
171 | | - \ a:path, ':p')), ':~:gs?[\\/]?/?')) |
172 | | - let s:_unify_path_cache[a:path] = value |
173 | | - return value |
174 | | - endfunction |
175 | | -else |
176 | | - function! s:_unify_path(path) abort |
177 | | - return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?')) |
178 | | - endfunction |
179 | | -endif |
180 | | - |
181 | | -function! s:_self_vital_files() abort |
182 | | - let base = s:base_dir . '/*/**/*.vim' |
183 | | - return split(glob(base, 1), "\n") |
184 | | -endfunction |
185 | | - |
186 | | -function! s:_global_vital_files() abort |
187 | | - let pattern = 'autoload/vital/__latest__/**/*.vim' |
188 | | - return split(globpath(&runtimepath, pattern, 1), "\n") |
189 | | -endfunction |
190 | | - |
191 | | -function! s:_extract_files(pattern, files) abort |
192 | | - let tr = {'.': '/', '*': '[^/]*', '**': '.*'} |
193 | | - let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g') |
194 | | - let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target) |
195 | | - return filter(a:files, 'v:val =~# regexp') |
196 | | -endfunction |
197 | | - |
198 | | -" Copy from System.Filepath |
199 | | -if has('win16') || has('win32') || has('win64') |
200 | | - function! s:_is_absolute_path(path) abort |
201 | | - return a:path =~? '^[a-z]:[/\\]' |
202 | | - endfunction |
203 | | -else |
204 | | - function! s:_is_absolute_path(path) abort |
205 | | - return a:path[0] ==# '/' |
206 | | - endfunction |
207 | | -endif |
208 | | - |
209 | | -function! s:_build_module(sid) abort |
210 | | - if has_key(s:loaded, a:sid) |
211 | | - return copy(s:loaded[a:sid]) |
212 | | - endif |
213 | | - let functions = s:_get_functions(a:sid) |
214 | | - |
215 | | - let prefix = '<SNR>' . a:sid . '_' |
216 | | - let module = {} |
217 | | - for func in functions |
218 | | - let module[func] = function(prefix . func) |
219 | | - endfor |
220 | | - if has_key(module, '_vital_created') |
221 | | - call module._vital_created(module) |
222 | | - endif |
223 | | - let export_module = filter(copy(module), 'v:key =~# "^\\a"') |
224 | | - " Cache module before calling module.vital_debug() to avoid cyclic |
225 | | - " dependences but remove the cache if module._vital_loaded() fails. |
226 | | - let s:loaded[a:sid] = get(g:, 'vital_debug', 0) ? module : export_module |
227 | | - if has_key(module, '_vital_loaded') |
228 | | - try |
229 | | - let V = vital#{s:self_version}#new() |
230 | | - call module._vital_loaded(V) |
231 | | - catch |
232 | | - unlet s:loaded[a:sid] |
233 | | - throw 'vital: fail to call ._vital_loaded(): ' . v:exception |
234 | | - endtry |
235 | | - endif |
236 | | - return copy(s:loaded[a:sid]) |
237 | | -endfunction |
238 | | - |
239 | | -if exists('+regexpengine') |
240 | | - function! s:_get_functions(sid) abort |
241 | | - let funcs = s:_redir(printf("function /\\%%#=2^\<SNR>%d_", a:sid)) |
242 | | - let map_pat = '<SNR>' . a:sid . '_\zs\w\+' |
243 | | - return map(split(funcs, "\n"), 'matchstr(v:val, map_pat)') |
244 | | - endfunction |
245 | | -else |
246 | | - function! s:_get_functions(sid) abort |
247 | | - let prefix = '<SNR>' . a:sid . '_' |
248 | | - let funcs = s:_redir('function') |
249 | | - let filter_pat = '^\s*function ' . prefix |
250 | | - let map_pat = prefix . '\zs\w\+' |
251 | | - return map(filter(split(funcs, "\n"), |
252 | | - \ 'stridx(v:val, prefix) > 0 && v:val =~# filter_pat'), |
253 | | - \ 'matchstr(v:val, map_pat)') |
254 | | - endfunction |
255 | | -endif |
256 | | - |
257 | | -if exists('*uniq') |
258 | | - function! s:_uniq(list) abort |
259 | | - return uniq(a:list) |
260 | | - endfunction |
261 | | -else |
262 | | - function! s:_uniq(list) abort |
263 | | - let i = len(a:list) - 1 |
264 | | - while 0 < i |
265 | | - if a:list[i] ==# a:list[i - 1] |
266 | | - call remove(a:list, i) |
267 | | - let i -= 2 |
268 | | - else |
269 | | - let i -= 1 |
270 | | - endif |
271 | | - endwhile |
272 | | - return a:list |
273 | | - endfunction |
274 | | -endif |
275 | | - |
276 | | -function! s:_redir(cmd) abort |
277 | | - let [save_verbose, save_verbosefile] = [&verbose, &verbosefile] |
278 | | - set verbose=0 verbosefile= |
279 | | - redir => res |
280 | | - silent! execute a:cmd |
281 | | - redir END |
282 | | - let [&verbose, &verbosefile] = [save_verbose, save_verbosefile] |
283 | | - return res |
284 | | -endfunction |
285 | | - |
286 | | -function! vital#{s:self_version}#new() abort |
287 | | - let sid = s:_get_sid_by_script(s:self_file) |
288 | | - return s:_build_module(sid) |
| 3 | +function! vital#{s:_plugin_name}#new() abort |
| 4 | + return vital#{s:_plugin_name[1:]}#of() |
289 | 5 | endfunction |
0 commit comments