"============================================================================= " FILE: parse.vim " AUTHOR: Shougo Matsushita " License: MIT license "============================================================================= " Global options definition." let g:dein#enable_name_conversion = \ get(g:, 'dein#enable_name_conversion', v:false) let g:dein#default_options = \ get(g:, 'dein#default_options', {}) let s:git = dein#types#git#define() function! dein#parse#_add(repo, options, overwrite) abort let plugin = dein#parse#_dict(dein#parse#_init(a:repo, a:options)) let plugin_check = get(g:dein#_plugins, plugin.name, {}) let overwrite = get(a:options, 'overwrite', a:overwrite) if get(plugin_check, 'sourced', 0) " Skip already loaded plugin. return {} endif " Duplicated plugins check if !empty(plugin_check) if !overwrite if has('vim_starting') " Only warning when starting call dein#util#_error(printf( \ 'Plugin name "%s" is already defined.', plugin.name)) endif return {} endif " Overwrite " Note: reparse is needed. let options = extend(a:options, \ get(g:dein#_plugins[plugin.name], 'orig_opts', {}), 'keep') let plugin = dein#parse#_dict(dein#parse#_init(a:repo, options)) endif let g:dein#_plugins[plugin.name] = plugin if plugin.rtp !=# '' if plugin.lazy call s:parse_lazy(plugin) endif if has_key(plugin, 'hook_add') call dein#util#_call_hook('add', plugin) endif if has_key(plugin, 'ftplugin') call s:merge_ftplugin(plugin.ftplugin) endif endif return plugin endfunction function! dein#parse#_init(repo, options) abort let repo = dein#util#_expand(a:repo) let plugin = has_key(a:options, 'type') ? \ dein#util#_get_type(a:options.type).init(repo, a:options) : \ s:git.init(repo, a:options) if empty(plugin) let plugin = s:check_type(repo, a:options) endif call extend(plugin, a:options) if !empty(g:dein#default_options) call extend(plugin, g:dein#default_options, 'keep') endif let plugin.repo = repo if !empty(a:options) let plugin.orig_opts = deepcopy(a:options) endif return plugin endfunction function! dein#parse#_dict(plugin) abort let plugin = { \ 'rtp': '', \ 'sourced': 0, \ } call extend(plugin, a:plugin) if !has_key(plugin, 'name') let plugin.name = dein#parse#_name_conversion(plugin.repo) endif if !has_key(plugin, 'normalized_name') let plugin.normalized_name = substitute( \ fnamemodify(plugin.name, ':r'), \ '\c^\%(n\?vim\|dps\)[_-]\|[_-]n\?vim$', '', 'g') endif if !has_key(a:plugin, 'name') && g:dein#enable_name_conversion " Use normalized name. let plugin.name = plugin.normalized_name endif if !has_key(plugin, 'path') let plugin.path = (plugin.repo =~# '^/\|^\a:[/\\]') ? \ plugin.repo : dein#util#_get_base_path().'/repos/'.plugin.name endif let plugin.path = dein#util#_chomp(dein#util#_expand(plugin.path)) if get(plugin, 'rev', '') !=# '' " Add revision path let plugin.path .= '_' . substitute( \ plugin.rev, '[^[:alnum:].-]', '_', 'g') endif " Check relative path if (!has_key(a:plugin, 'rtp') || a:plugin.rtp !=# '') \ && plugin.rtp !~# '^\%([~/]\|\a\+:\)' let plugin.rtp = plugin.path.'/'.plugin.rtp endif if plugin.rtp[0:] ==# '~' let plugin.rtp = dein#util#_expand(plugin.rtp) endif let plugin.rtp = dein#util#_chomp(plugin.rtp) if g:dein#_is_sudo && !get(plugin, 'trusted', 0) let plugin.rtp = '' endif if has_key(plugin, 'script_type') " Add script_type. let plugin.path .= '/' . plugin.script_type endif if has_key(plugin, 'depends') && type(plugin.depends) != v:t_list let plugin.depends = [plugin.depends] endif " Deprecated check. for key in filter(['directory', 'base'], \ { _, val -> has_key(plugin, val) }) call dein#util#_error('plugin name = ' . plugin.name) call dein#util#_error(string(key) . ' is deprecated.') endfor if !has_key(plugin, 'lazy') let plugin.lazy = \ has_key(plugin, 'on_ft') \ || has_key(plugin, 'on_cmd') \ || has_key(plugin, 'on_func') \ || has_key(plugin, 'on_lua') \ || has_key(plugin, 'on_map') \ || has_key(plugin, 'on_path') \ || has_key(plugin, 'on_if') \ || has_key(plugin, 'on_event') \ || has_key(plugin, 'on_source') endif if !has_key(a:plugin, 'merged') let plugin.merged = !plugin.lazy \ && plugin.normalized_name !=# 'dein' \ && !has_key(plugin, 'local') \ && !has_key(plugin, 'build') \ && !has_key(plugin, 'if') \ && !has_key(plugin, 'hook_post_update') \ && stridx(plugin.rtp, dein#util#_get_base_path()) == 0 endif " Hooks for hook in filter([ \ 'hook_add', 'hook_source', \ 'hook_post_source', 'hook_post_update', \ ], { _, val -> has_key(plugin, val) \ && type(plugin[val]) == v:t_string }) let plugin[hook] = substitute(plugin[hook], '\n\s*\\', '', 'g') endfor return plugin endfunction function! dein#parse#_load_toml(filename, default) abort try let toml = dein#toml#parse_file(dein#util#_expand(a:filename)) catch /Text.TOML:/ call dein#util#_error('Invalid toml format: ' . a:filename) call dein#util#_error(v:exception) return 1 endtry if type(toml) != v:t_dict call dein#util#_error('Invalid toml file: ' . a:filename) return 1 endif " Parse. if has_key(toml, 'hook_add') let g:dein#_hook_add .= "\n" . substitute( \ toml.hook_add, '\n\s*\\', '', 'g') endif if has_key(toml, 'ftplugin') call s:merge_ftplugin(toml.ftplugin) endif if has_key(toml, 'multiple_plugins') for multi in toml.multiple_plugins if !has_key(multi, 'plugins') call dein#util#_error('Invalid multiple_plugins: ' . a:filename) return 1 endif call add(g:dein#_multiple_plugins, multi) endfor endif if has_key(toml, 'plugins') for plugin in toml.plugins if !has_key(plugin, 'repo') call dein#util#_error('No repository plugin data: ' . a:filename) return 1 endif let options = extend(plugin, a:default, 'keep') call dein#add(plugin.repo, options) endfor endif " Add to g:dein#_vimrcs call add(g:dein#_vimrcs, dein#util#_expand(a:filename)) endfunction function! dein#parse#_plugins2toml(plugins) abort let toml = [] let default = dein#parse#_dict(dein#parse#_init('', {})) let default.if = '' let default.frozen = 0 let default.local = 0 let default.depends = [] let default.on_ft = [] let default.on_cmd = [] let default.on_func = [] let default.on_lua = [] let default.on_map = [] let default.on_path = [] let default.on_source = [] let default.build = '' let default.hook_add = '' let default.hook_source = '' let default.hook_post_source = '' let default.hook_post_update = '' let skip_default = { \ 'type': 1, \ 'path': 1, \ 'rtp': 1, \ 'sourced': 1, \ 'orig_opts': 1, \ 'repo': 1, \ } for plugin in sort(a:plugins, \ { a, b -> a.repo ==# b.repo ? 0 : a.repo ># b.repo ? 1 : -1 }) let toml += ['[[plugins]]', \ 'repo = ' . string(plugin.repo)] for key in filter(sort(keys(default)), \ { _, val -> !has_key(skip_default, val) && has_key(plugin, val) \ && (type(plugin[val]) !=# type(default[val]) \ || plugin[val] !=# default[val]) }) let val = plugin[key] if key =~# '^hook_' call add(toml, key . " = '''") let toml += split(val, '\n') call add(toml, "'''") else call add(toml, key . ' = ' . string( \ (type(val) == v:t_list && len(val) == 1) ? val[0] : val)) endif unlet! val endfor call add(toml, '') endfor return toml endfunction function! dein#parse#_load_dict(dict, default) abort for [repo, options] in items(a:dict) call dein#add(repo, extend(copy(options), a:default, 'keep')) endfor endfunction function! dein#parse#_local(localdir, options, includes) abort let base = fnamemodify(dein#util#_expand(a:localdir), ':p') let directories = [] for glob in a:includes let directories += map(filter(glob(base . glob, v:true, v:true), \ { _, val -> isdirectory(val) }), \ { _, val -> substitute(dein#util#_substitute_path( \ fnamemodify(val, ':p')), '/$', '', '') }) endfor for dir in dein#util#_uniq(directories) let options = extend({ \ 'repo': dir, 'local': 1, 'path': dir, \ 'name': fnamemodify(dir, ':t') \ }, a:options) if has_key(g:dein#_plugins, options.name) call dein#config(options.name, options) else call dein#parse#_add(dir, options, v:true) endif endfor endfunction function! s:parse_lazy(plugin) abort " Auto convert2list. for key in filter([ \ 'on_ft', 'on_path', 'on_cmd', 'on_func', 'on_map', \ 'on_lua', 'on_source', 'on_event', \ ], { _, val -> has_key(a:plugin, val) \ && type(a:plugin[val]) != v:t_list \ && type(a:plugin[val]) != v:t_dict }) let a:plugin[key] = [a:plugin[key]] endfor if has_key(a:plugin, 'on_event') for event in a:plugin.on_event if !has_key(g:dein#_event_plugins, event) let g:dein#_event_plugins[event] = [a:plugin.name] else call add(g:dein#_event_plugins[event], a:plugin.name) let g:dein#_event_plugins[event] = dein#util#_uniq( \ g:dein#_event_plugins[event]) endif endfor endif if has_key(a:plugin, 'on_cmd') call s:generate_dummy_commands(a:plugin) endif if has_key(a:plugin, 'on_map') call s:generate_dummy_mappings(a:plugin) endif endfunction function! s:generate_dummy_commands(plugin) abort let a:plugin.dummy_commands = [] for name in a:plugin.on_cmd " Define dummy commands. let raw_cmd = 'command ' \ . '-complete=customlist,dein#autoload#_dummy_complete' \ . ' -bang -bar -range -nargs=* '. name \ . printf(" call dein#autoload#_on_cmd(%s, %s, , \ expand(''), expand(''), expand(''))", \ string(name), string(a:plugin.name)) call add(a:plugin.dummy_commands, [name, raw_cmd]) silent! execute raw_cmd endfor endfunction function! s:generate_dummy_mappings(plugin) abort let a:plugin.dummy_mappings = [] let items = type(a:plugin.on_map) == v:t_dict ? \ map(items(a:plugin.on_map), \ { _, val -> [split(val[0], '\zs'), \ dein#util#_convert2list(val[1])]}) : \ map(copy(a:plugin.on_map), \ { _, val -> type(val) == v:t_list ? \ [split(val[0], '\zs'), val[1:]] : [['n', 'x'], [val]] }) for [modes, mappings] in items if mappings ==# [''] " Use plugin name. let mappings = ['(' . a:plugin.normalized_name] if stridx(a:plugin.normalized_name, '-') >= 0 " The plugin mappings may use "_" instead of "-". call add(mappings, '(' . \ substitute(a:plugin.normalized_name, '-', '_', 'g')) endif endif for mapping in mappings " Define dummy mappings. let prefix = printf('dein#autoload#_on_map(%s, %s,', \ string(substitute(mapping, '<', '', 'g')), \ string(a:plugin.name)) for mode in modes let raw_map = mode.'noremap '.mapping \ . (mode ==# 'c' ? " \=" : \ mode ==# 'i' ? " \:call " : " :\call ") \ . prefix . string(mode) . ')' call add(a:plugin.dummy_mappings, [mode, mapping, raw_map]) silent! execute raw_map endfor endfor endfor endfunction function! s:merge_ftplugin(ftplugin) abort let pattern = '\n\s*\\\|\%(^\|\n\)\s*"[^\n]*' for [ft, val] in items(a:ftplugin) if !has_key(g:dein#_ftplugin, ft) let g:dein#_ftplugin[ft] = val else let g:dein#_ftplugin[ft] .= "\n" . val endif endfor call map(g:dein#_ftplugin, { _, val -> substitute(val, pattern, '', 'g') }) endfunction function! dein#parse#_get_types() abort if !exists('s:types') " Load types. let s:types = {} for type in filter(map(globpath(&runtimepath, \ 'autoload/dein/types/*.vim', v:true, v:true), \ { _, val -> dein#types#{fnamemodify(val, ':t:r')}#define() }), \ { _, val -> !empty(val) }) let s:types[type.name] = type endfor endif return s:types endfunction function! s:check_type(repo, options) abort let plugin = {} for type in values(dein#parse#_get_types()) let plugin = type.init(a:repo, a:options) if !empty(plugin) break endif endfor if empty(plugin) let plugin.type = 'none' let plugin.local = 1 let plugin.path = isdirectory(a:repo) ? a:repo : '' endif return plugin endfunction function! dein#parse#_name_conversion(path) abort return fnamemodify(get(split(a:path, ':'), -1, ''), \ ':s?/$??:t:s?\c\.git\s*$??') endfunction