diff --git a/plug.vim b/plug.vim index d81f466..7df3371 100644 --- a/plug.vim +++ b/plug.vim @@ -403,6 +403,7 @@ function! s:prepare() else vertical topleft new nnoremap q :if b:plug_preview==1pcendifq + nnoremap R :silent! call retry() nnoremap D :PlugDiff nnoremap S :PlugStatus nnoremap ]] :silent! call section('') @@ -437,9 +438,22 @@ function! s:finish(pull) call setline(4, getline(4) . 'Done!') normal! gg redraw - if a:pull - echo "Press 'D' to see the updated changes." + let msgs = [] + if !empty(s:prev_update.errors) + call add(msgs, "Press 'R' to retry.") endif + if a:pull + call add(msgs, "Press 'D' to see the updated changes.") + endif + echo join(msgs, ' ') +endfunction + +function! s:retry() + if empty(s:prev_update.errors) + return + endif + call s:update_impl(s:prev_update.pull, + \ extend(copy(s:prev_update.errors), [s:prev_update.threads])) endfunction function! s:is_managed(name) @@ -473,6 +487,7 @@ function! s:update_impl(pull, args) abort redraw let len = len(g:plugs) + let s:prev_update = { 'errors': [], 'pull': a:pull, 'threads': threads } if has('ruby') && threads > 1 try let imd = &imd @@ -566,6 +581,9 @@ function! s:update_serial(pull, todo) let error = v:shell_error != 0 endif let bar .= error ? 'x' : '=' + if error + call add(s:prev_update.errors, name) + endif call append(3, s:format_message(!error, name, result)) call s:update_progress(a:pull, len(done), bar, total) endfor @@ -640,7 +658,10 @@ function! s:update_parallel(pull, todo, threads) bar += type ? '=' : 'x' unless ing b = case type when :install then '+' when :update then '*' - when true, nil then '-' else 'x' end + when true, nil then '-' else + VIM::command("call add(s:prev_update.errors, '#{name}')") + 'x' + end result = if type || type.nil? ["#{b} #{name}: #{result.lines.to_a.last}"] diff --git a/test/workflow.vader b/test/workflow.vader index 4e4ccdf..16226af 100644 --- a/test/workflow.vader +++ b/test/workflow.vader @@ -27,6 +27,12 @@ Execute (Initialize test environment): g/^$/d endfunction + function! AssertExpect(bang, pat, cnt) + let op = a:bang ? '==' : '=~' + AssertEqual a:cnt, len(filter(getline(1, '$'), "v:val ".op." '".a:pat."'")) + endfunction + command! -nargs=+ -bang AssertExpect call AssertExpect('' == '!', ) + let g:vimrc_reloaded = 0 let vimrc = tempname() call writefile(['let g:vimrc_reloaded += 1'], vimrc) @@ -112,12 +118,12 @@ Execute (Plug command with dictionary option): Execute (PlugStatus before installation): PlugStatus - AssertEqual 4, len(filter(getline(1, '$'), 'v:val =~ "Not found"')) + AssertExpect 'Not found', 4 q Execute (PlugClean before installation): PlugClean - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "Already clean"')) + AssertExpect 'Already clean', 1 q Execute (plug#end() updates &rtp): @@ -139,12 +145,13 @@ Execute (Plugin available after installation): Execute (PlugClean after installation): PlugClean - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "Already clean"')) + AssertExpect 'Already clean', 1 q Execute (PlugStatus after installation): PlugStatus - AssertEqual 4, len(filter(getline(1, '$'), 'v:val =~ "OK"')) + Log getline(1, '$') + AssertExpect 'OK', 4 q Execute (Change tag of goyo.vim): @@ -215,8 +222,8 @@ Expect: Execute (PlugClean! to remove seoul256.vim): PlugClean! " Three removed, emoji left - AssertEqual 3, len(filter(getline(1, '$'), 'v:val =~ "^- "')) - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "Removed"')) + AssertExpect '^- ', 3 + AssertExpect 'Removed', 1 Assert empty(globpath(&rtp, 'colors/seoul256.vim')) Assert !empty(globpath(&rtp, 'autoload/emoji.vim')) q @@ -242,15 +249,15 @@ Expect: Execute (PlugClean! to remove vim-emoji): PlugClean! - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "^- "')) - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "Removed"')) + AssertExpect '^- ', 1 + AssertExpect 'Removed', 1 Assert empty(globpath(&rtp, 'colors/seoul256.vim')) Assert empty(globpath(&rtp, 'autoload/emoji.vim')) q Execute (PlugUpdate to install both again): PlugUpdate - AssertEqual 2, len(filter(getline(1, '$'), 'v:val =~ "^- [^:]*:"')) + AssertExpect '^- [^:]*:', 2 AssertEqual 3, g:vimrc_reloaded Assert !empty(globpath(&rtp, 'colors/seoul256.vim')), 'seoul256.vim should be found' Assert !empty(globpath(&rtp, 'autoload/emoji.vim')), 'vim-emoji should be found' @@ -258,7 +265,7 @@ Execute (PlugUpdate to install both again): Execute (PlugUpdate only to find out plugins are up-to-date, D key to check): PlugUpdate - AssertEqual 2, len(filter(getline(1, '$'), 'v:val =~ "Already up-to-date"')) + AssertExpect 'Already up-to-date', 2 AssertEqual 4, g:vimrc_reloaded normal D AssertEqual 'No updates.', getline(1) @@ -365,9 +372,9 @@ Execute (Check commands): Execute (Partial PlugInstall): PlugInstall vim-fnr vim-easy-align - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "vim-pseudocl"')) + AssertExpect 'vim-pseudocl', 1 PlugInstall vim-fnr vim-easy-align 1 - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "vim-pseudocl"')) + AssertExpect 'vim-pseudocl', 1 q Execute (Check dependent plugin): @@ -438,26 +445,26 @@ Execute (Plug block for following tests): Execute (PlugInstall will only install vim-easy-align): PlugInstall Log getline(1, '$') - AssertEqual 0, len(filter(getline(1, '$'), 'v:val =~ "fzf"')) + AssertExpect 'fzf', 0 q Execute (PlugUpdate will only update vim-easy-align): PlugUpdate Log getline(1, '$') - AssertEqual 0, len(filter(getline(1, '$'), 'v:val =~ "fzf"')) + AssertExpect 'fzf', 0 q Execute (PlugClean should not care about unmanaged plugins): PlugClean Log getline(1, '$') - AssertEqual 0, len(filter(getline(1, '$'), 'v:val =~ "fzf"')) + AssertExpect 'fzf', 0 q Execute (PlugStatus should point out that the plugin is missing): PlugStatus Log getline(1, '$') - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "x fzf"')) - AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "Not found"')) + AssertExpect 'x fzf', 1 + AssertExpect 'Not found', 1 q Execute (Deploy unmanaged plugin): @@ -467,14 +474,14 @@ Execute (Deploy unmanaged plugin): Execute (PlugUpdate still should not care): PlugUpdate Log getline(1, '$') - AssertEqual 0, len(filter(getline(1, '$'), 'v:val =~ "fzf"')) + AssertExpect 'fzf', 0 q Execute (PlugStatus with no error): PlugStatus Log getline(1, '$') - AssertEqual 0, len(filter(getline(1, '$'), 'v:val =~ "x fzf"')) - AssertEqual 0, len(filter(getline(1, '$'), 'v:val =~ "Not found"')) + AssertExpect 'x fzf', 0 + AssertExpect 'Not found', 0 q Execute (Check &rtp after SomeCommand): @@ -494,7 +501,7 @@ Execute (Common parent): PlugInstall Log getline(1, '$') - AssertEqual 1, len(filter(getline(1, '$'), 'v:val == "[===]"')) + AssertExpect! '[===]', 1 q ********************************************************************** @@ -527,6 +534,48 @@ Execute (But you can still install it if the name is given as the argument): AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "vim-easy-align"')) q +********************************************************************** +~ Retry +********************************************************************** + +Execute (Retry failed tasks): + call plug#begin() + Plug 'junegunn/vim-easy-align' + Plug 'junegunn/aaaaaaaaaaaaaa' + call plug#end() + + PlugInstall + Log getline(1, '$') + AssertExpect 'x aaa', 1 + AssertExpect '- vim-easy-align', 1 + normal R + Log getline(1, '$') + AssertExpect 'x aaa', 1 + AssertExpect '- vim-easy-align', 0 + AssertExpect! '[x]', 1 + q + + call plug#begin() + Plug 'junegunn/vim-easy-align' + Plug 'junegunn/aaaaaaaaaaaaaa' + Plug 'junegunn/bbbbbbbbbbbbbb' + Plug 'junegunn/cccccccccccccc' + call plug#end() + + " Ruby installer + PlugUpdate + normal R + AssertExpect '- vim-easy-align', 0 + AssertExpect! '[xxx]', 1 + q + + " Vim installer + PlugUpdate 1 + normal R + AssertExpect '- vim-easy-align', 0 + AssertExpect! '[xxx]', 1 + q + Execute (Cleanup): call system('rm -rf '.temp_plugged) call rename('fzf', 'fzf-staged') @@ -536,5 +585,7 @@ Execute (Cleanup): unlet g:vimrc_reloaded unlet temp_plugged vader plug basertp save_rtp repo lnum fzf delf PlugStatusSorted + delf AssertExpect + delc AssertExpect Restore