diff --git a/plug.vim b/plug.vim index f371f62..9b3382d 100644 --- a/plug.vim +++ b/plug.vim @@ -142,17 +142,10 @@ function! plug#end() let lod = {} filetype off - " we want to make sure the plugin directories are added to rtp in the same - " order that they are registered with the Plug command. since the s:add_rtp - " function uses ^= to add plugin directories to the front of the rtp, we - " need to loop through the plugins in reverse - for name in reverse(copy(g:plugs_order)) + for name in g:plugs_order let plug = g:plugs[name] - if get(s:loaded, plug.dir, 0) || !has_key(plug, 'on') && !has_key(plug, 'for') - let rtp = s:add_rtp(plug) - if reload - call s:source(rtp, 'plugin/**/*.vim', 'after/plugin/**/*.vim') - endif + if get(s:loaded, name, 0) || !has_key(plug, 'on') && !has_key(plug, 'for') + let s:loaded[name] = 1 continue endif @@ -192,14 +185,28 @@ function! plug#end() for [key, names] in items(lod) augroup PlugLOD execute printf('autocmd FileType %s call lod_ft(%s, %s)', - \ key, string(key), string(reverse(names))) + \ key, string(key), string(names)) augroup END endfor + + if reload + call s:reload() + endif call s:reorg_rtp() filetype plugin indent on syntax enable endfunction +function! s:loaded_names() + return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') +endfunction + +function! s:reload() + for name in s:loaded_names() + call s:source(s:rtp(g:plugs[name]), 'plugin/**/*.vim', 'after/plugin/**/*.vim') + endfor +endfunction + function! s:trim(str) return substitute(a:str, '[\/]\+$', '', '') endfunction @@ -246,27 +253,46 @@ function! s:err(msg) endfunction function! s:esc(path) - return substitute(a:path, ' ', '\\ ', 'g') + return escape(a:path, ' ') endfunction -function! s:add_rtp(plug) - let rtp = s:rtp(a:plug) - execute 'set rtp^='.s:esc(rtp) - let after = globpath(rtp, 'after') - if isdirectory(after) - execute 'set rtp+='.s:esc(after) - endif - let s:loaded[a:plug.dir] = 1 - return rtp +function! s:escrtp(path) + return escape(a:path, ' ,') +endfunction + +function! s:remove_rtp() + for name in s:loaded_names() + let rtp = s:rtp(g:plugs[name]) + execute 'set rtp-='.s:escrtp(rtp) + let after = globpath(rtp, 'after') + if isdirectory(after) + execute 'set rtp-='.s:escrtp(after) + endif + endfor endfunction function! s:reorg_rtp() if !empty(s:first_rtp) execute 'set rtp-='.s:first_rtp - execute 'set rtp^='.s:first_rtp - endif - if s:last_rtp !=# s:first_rtp execute 'set rtp-='.s:last_rtp + endif + + " &rtp is modified from outside + if exists('s:prtp') && s:prtp !=# &rtp + call s:remove_rtp() + unlet! s:middle + endif + + let s:middle = get(s:, 'middle', &rtp) + let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') + let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), 'isdirectory(v:val)') + let &rtp = join(map(rtps, 's:escrtp(v:val)'), ',') + \ . substitute(','.s:middle.',', '^,,$', ',', '') + \ . join(map(afters, 's:escrtp(v:val)'), ',') + let s:prtp = &rtp + + if !empty(s:first_rtp) + execute 'set rtp^='.s:first_rtp execute 'set rtp+='.s:last_rtp endif endfunction @@ -284,25 +310,28 @@ function! plug#load(...) return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) end for name in a:000 - call s:lod(g:plugs[name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) endfor - call s:reorg_rtp() silent! doautocmd BufRead return 1 endfunction -function! s:lod(plug, types) - let rtp = s:add_rtp(a:plug) - for dir in a:types - call s:source(rtp, dir.'/**/*.vim') +function! s:lod(names, types) + for name in a:names + let s:loaded[name] = 1 + endfor + call s:reorg_rtp() + + for name in a:names + let rtp = s:rtp(g:plugs[name]) + for dir in a:types + call s:source(rtp, dir.'/**/*.vim') + endfor endfor endfunction function! s:lod_ft(pat, names) - for name in a:names - call s:lod(g:plugs[name], ['plugin', 'after/plugin']) - endfor - call s:reorg_rtp() + call s:lod(a:names, ['plugin', 'after/plugin']) execute 'autocmd! PlugLOD FileType' a:pat silent! doautocmd filetypeplugin FileType silent! doautocmd filetypeindent FileType @@ -310,16 +339,14 @@ endfunction function! s:lod_cmd(cmd, bang, l1, l2, args, name) execute 'delc' a:cmd - call s:lod(g:plugs[a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) - call s:reorg_rtp() + call s:lod([a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) endfunction function! s:lod_map(map, name, prefix) execute 'unmap' a:map execute 'iunmap' a:map - call s:lod(g:plugs[a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) - call s:reorg_rtp() + call s:lod([a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) let extra = '' while 1 let c = getchar(0) @@ -343,7 +370,7 @@ function! s:add(repo, ...) \ a:0 == 1 ? s:parse_options(a:1) : s:base_spec) let g:plugs[name] = spec let g:plugs_order += [name] - let s:loaded[spec.dir] = 0 + let s:loaded[name] = 0 catch return s:err(v:exception) endtry @@ -1109,7 +1136,7 @@ function! s:status() let cnt += 1 let ecnt += !valid " `s:loaded` entry can be missing if PlugUpgraded - if valid && get(s:loaded, spec.dir, -1) == 0 + if valid && get(s:loaded, name, -1) == 0 let unloaded = 1 let msg .= ' (not loaded)' endif @@ -1255,8 +1282,12 @@ function! s:revert() echo 'Reverted.' endfunction -let s:first_rtp = s:esc(get(split(&rtp, ','), 0, '')) -let s:last_rtp = s:esc(get(split(&rtp, ','), -1, '')) +function! s:split_rtp() + return split(&rtp, '\\\@ $d/xxx.vim << EOF " echom expand('') + let g:total_order = get(g:, 'total_order', []) let g:$2 = get(g:, '$2', []) - call add(g:$2, '${1:4}/$d') + let s:name = join(filter(['$2', '${1:4}', '$d'], '!empty(v:val)'), '/') + call add(g:$2, s:name) + call add(g:total_order, s:name) EOF done cd - > /dev/null @@ -30,12 +34,14 @@ EOF make_dirs xxx/ xxx make_dirs xxx/after xxx -mkdir xxx/doc +mkdir -p xxx/doc cat > xxx/doc/xxx.txt << DOC hello *xxx* DOC make_dirs yyy/ yyy +make_dirs yyy/after yyy + make_dirs z1/ z1 make_dirs z2/ z2 diff --git a/test/workflow.vader b/test/workflow.vader index 9d8e100..fad8eca 100644 --- a/test/workflow.vader +++ b/test/workflow.vader @@ -32,6 +32,12 @@ Execute (Initialize test environment): endfunction command! -nargs=+ -bang AssertExpect call AssertExpect('' == '!', ) + function! EnsureLoaded() + if has('vim_starting') + runtime! plugin/**/*.vim + endif + endfunction + Execute (Print Ruby version): redir => out silent ruby puts RUBY_VERSION @@ -388,10 +394,7 @@ Given (Unaligned code): aa=2 Execute (Check installed plugins): - if has('vim_starting') - Log 'Vader is run from commandline' - runtime! plugin/**/*.vim - endif + call EnsureLoaded() Assert exists(':FNR'), 'FNR command should be found' Assert !exists(':RedisExecute'), 'RedisExecute command still should not be found' @@ -740,9 +743,9 @@ Execute (Immediate loading): " Different result when Vader is run from commandline with `-c` option Log g:xxx if has('vim_starting') - AssertEqual ['/ftdetect', 'after/ftdetect'], g:xxx + AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx else - AssertEqual ['/plugin', 'after/plugin', '/ftdetect', 'after/ftdetect'], g:xxx + AssertEqual ['xxx/plugin', 'xxx/after/plugin', 'xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx endif Execute (Command-based on-demand loading): @@ -753,20 +756,20 @@ Execute (Command-based on-demand loading): AssertEqual [], g:xxx silent! XXX - AssertEqual ['/ftdetect', 'after/ftdetect', '/plugin', 'after/plugin'], g:xxx + AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin'], g:xxx setf xxx - AssertEqual ['/ftdetect', 'after/ftdetect', '/plugin', 'after/plugin', '/ftplugin', 'after/ftplugin', '/indent', 'after/indent', '/syntax', 'after/syntax'], g:xxx + AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/ftplugin', 'xxx/after/ftplugin', 'xxx/indent', 'xxx/after/indent', 'xxx/syntax', 'xxx/after/syntax'], g:xxx Execute (Filetype-based on-demand loading): call plug#begin() Plug '$PWD/xxx', { 'for': 'xxx' } call plug#end() - AssertEqual ['/ftdetect', 'after/ftdetect'], g:xxx + AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx setf xxx - AssertEqual ['/ftdetect', 'after/ftdetect', '/plugin', 'after/plugin', '/ftplugin', 'after/ftplugin', '/indent', 'after/indent', '/syntax', 'after/syntax'], g:xxx + AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/ftplugin', 'xxx/after/ftplugin', 'xxx/indent', 'xxx/after/indent', 'xxx/syntax', 'xxx/after/syntax'], g:xxx Before: @@ -937,21 +940,81 @@ Execute (Update plugins with U key in visual mode): AssertExpect! '[==]', 1 q +********************************************************************** Execute (plug#begin should expand env vars): AssertNotEqual '$HOME/.emacs/plugged', expand('$HOME/.emacs/plugged') call plug#begin('$HOME/.emacs/plugged') AssertEqual expand('$HOME/.emacs/plugged'), g:plug_home +********************************************************************** +Execute (Plug directory with comma): + call plug#begin(temp_plugged . '/p,l,u,g,g,e,d') + Plug 'junegunn/vim-emoji' + call plug#end() + Log &rtp + + PlugInstall + q + let found = filter(split(globpath(&rtp, 'README.md'), '\n'), 'v:val =~ ","') + Log found + AssertEqual 1, len(found) + +********************************************************************** +Execute (Strict load order): + let g:total_order = [] + call plug#begin() + Plug '$PWD/xxx' + Plug '$PWD/yyy', { 'for': ['xxx'] } + call plug#end() + call EnsureLoaded() + setf xxx + Log 'Case 1: ' . &rtp + AssertEqual ['yyy/ftdetect', 'yyy/after/ftdetect', 'xxx/ftdetect', 'xxx/after/ftdetect'], g:total_order[0:3] + Assert index(g:total_order, 'xxx/plugin') < index(g:total_order, 'yyy/plugin') + Assert index(g:total_order, 'xxx/after/plugin') < index(g:total_order, 'yyy/after/plugin') + let len = len(split(&rtp, ',')) + + let g:total_order = [] + call plug#begin() + Plug '$PWD/xxx', { 'for': ['xxx'] } + Plug '$PWD/yyy' + call plug#end() + call EnsureLoaded() + set rtp^=manually-prepended + set rtp+=manually-appended + setf xxx + Log 'Case 2: ' . &rtp + AssertEqual 'manually-prepended', split(&rtp, ',')[3] + AssertEqual 'manually-appended', split(&rtp, ',')[-4] + AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'yyy/ftdetect', 'yyy/after/ftdetect'], g:total_order[0:3] + Assert index(g:total_order, 'yyy/plugin') < index(g:total_order, 'xxx/plugin') + Assert index(g:total_order, 'yyy/after/plugin') < index(g:total_order, 'xxx/after/plugin') + AssertEqual len + 2, len(split(&rtp, ',')) + + let g:total_order = [] + call plug#begin() + Plug '$PWD/xxx', { 'for': ['xxx'] } + Plug '$PWD/yyy', { 'for': ['xxx'] } + call plug#end() + call EnsureLoaded() + setf xxx + Log 'Case 3: ' . &rtp + AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'yyy/ftdetect', 'yyy/after/ftdetect'], g:total_order[0:3] + Assert index(g:total_order, 'xxx/plugin') < index(g:total_order, 'yyy/plugin') + Assert index(g:total_order, 'xxx/after/plugin') < index(g:total_order, 'yyy/after/plugin') + AssertEqual len + 2, len(split(&rtp, ',')) + Execute (Cleanup): silent! call system('rm -rf '.temp_plugged) silent! call rename('fzf', 'fzf-staged') silent! unlet g:plugs silent! unlet g:plug_home silent! unlet g:plug_url_format - silent! unlet temp_plugged vader plug basertp save_rtp repo lnum fzf out tabnr + silent! unlet temp_plugged vader plug basertp save_rtp repo lnum fzf out tabnr found len silent! delf PlugStatusSorted silent! delf AssertExpect silent! delf PlugUpdated + silent! delf EnsureLoaded silent! delc AssertExpect silent! unmap / silent! unmap ?