Browse Source

Allow pressing 'q' to abort the running tasks, then 'R' to retry (#1289)

If you press 'q' while `PlugInstall` or `PlugUpdate` is in progress,
the current version of vim-plug immediately closes its window and aborts
all the running processes.

This commit enhances the 'q' map so that it doesn't close the window,
but instead displays the aborted tasks so that the user can press 'R' to
retry the tasks.

Fix #1285
Junegunn Choi 1 year ago
parent
commit
d80f495fab
2 changed files with 44 additions and 11 deletions
  1. 1 1
      README.md
  2. 43 10
      plug.vim

+ 1 - 1
README.md

@@ -315,7 +315,7 @@ vim.cmd('silent! colorscheme seoul256')
 - `S` - `PlugStatus`
 - `S` - `PlugStatus`
 - `R` - Retry failed update or installation tasks
 - `R` - Retry failed update or installation tasks
 - `U` - Update plugins in the selected range
 - `U` - Update plugins in the selected range
-- `q` - Close the window
+- `q` - Abort the running tasks or close the window
 - `:PlugStatus`
 - `:PlugStatus`
     - `L` - Load plugin
     - `L` - Load plugin
 - `:PlugDiff`
 - `:PlugDiff`

+ 43 - 10
plug.vim

@@ -783,10 +783,11 @@ endfunction
 function! s:syntax()
 function! s:syntax()
   syntax clear
   syntax clear
   syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber
   syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber
-  syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX
+  syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX,plugAbort
   syn match plugNumber /[0-9]\+[0-9.]*/ contained
   syn match plugNumber /[0-9]\+[0-9.]*/ contained
   syn match plugBracket /[[\]]/ contained
   syn match plugBracket /[[\]]/ contained
   syn match plugX /x/ contained
   syn match plugX /x/ contained
+  syn match plugAbort /\~/ contained
   syn match plugDash /^-\{1}\ /
   syn match plugDash /^-\{1}\ /
   syn match plugPlus /^+/
   syn match plugPlus /^+/
   syn match plugStar /^*/
   syn match plugStar /^*/
@@ -811,6 +812,7 @@ function! s:syntax()
   hi def link plug2       Repeat
   hi def link plug2       Repeat
   hi def link plugH2      Type
   hi def link plugH2      Type
   hi def link plugX       Exception
   hi def link plugX       Exception
+  hi def link plugAbort   Ignore
   hi def link plugBracket Structure
   hi def link plugBracket Structure
   hi def link plugNumber  Number
   hi def link plugNumber  Number
 
 
@@ -908,7 +910,7 @@ function! s:prepare(...)
     endif
     endif
   endfor
   endfor
 
 
-  call s:job_abort()
+  call s:job_abort(0)
   if s:switch_in()
   if s:switch_in()
     if b:plug_preview == 1
     if b:plug_preview == 1
       pc
       pc
@@ -944,6 +946,8 @@ function! s:close_pane()
   if b:plug_preview == 1
   if b:plug_preview == 1
     pc
     pc
     let b:plug_preview = -1
     let b:plug_preview = -1
+  elseif exists('s:jobs') && !empty(s:jobs)
+    call s:job_abort(1)
   else
   else
     bd
     bd
   endif
   endif
@@ -1326,7 +1330,12 @@ function! s:update_finish()
   endif
   endif
 endfunction
 endfunction
 
 
-function! s:job_abort()
+function! s:mark_aborted(name, message)
+  let attrs = { 'running': 0, 'error': 1, 'abort': 1, 'lines': [a:message] }
+  let s:jobs[a:name] = extend(get(s:jobs, a:name, {}), attrs)
+endfunction
+
+function! s:job_abort(cancel)
   if (!s:nvim && !s:vim8) || !exists('s:jobs')
   if (!s:nvim && !s:vim8) || !exists('s:jobs')
     return
     return
   endif
   endif
@@ -1340,8 +1349,18 @@ function! s:job_abort()
     if j.new
     if j.new
       call s:rm_rf(g:plugs[name].dir)
       call s:rm_rf(g:plugs[name].dir)
     endif
     endif
+    if a:cancel
+      call s:mark_aborted(name, 'Aborted')
+    endif
   endfor
   endfor
-  let s:jobs = {}
+
+  if a:cancel
+    for todo in values(s:update.todo)
+      let todo.abort = 1
+    endfor
+  else
+    let s:jobs = {}
+  endif
 endfunction
 endfunction
 
 
 function! s:last_non_empty_line(lines)
 function! s:last_non_empty_line(lines)
@@ -1355,6 +1374,16 @@ function! s:last_non_empty_line(lines)
   return ''
   return ''
 endfunction
 endfunction
 
 
+function! s:bullet_for(job, ...)
+  if a:job.running
+    return a:job.new ? '+' : '*'
+  endif
+  if get(a:job, 'abort', 0)
+    return '~'
+  endif
+  return a:job.error ? 'x' : get(a:000, 0, '-')
+endfunction
+
 function! s:job_out_cb(self, data) abort
 function! s:job_out_cb(self, data) abort
   let self = a:self
   let self = a:self
   let data = remove(self.lines, -1) . a:data
   let data = remove(self.lines, -1) . a:data
@@ -1363,10 +1392,9 @@ function! s:job_out_cb(self, data) abort
   " To reduce the number of buffer updates
   " To reduce the number of buffer updates
   let self.tick = get(self, 'tick', -1) + 1
   let self.tick = get(self, 'tick', -1) + 1
   if !self.running || self.tick % len(s:jobs) == 0
   if !self.running || self.tick % len(s:jobs) == 0
-    let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-')
     let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines)
     let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines)
     if len(result)
     if len(result)
-      call s:log(bullet, self.name, result)
+      call s:log(s:bullet_for(self), self.name, result)
     endif
     endif
   endif
   endif
 endfunction
 endfunction
@@ -1380,7 +1408,7 @@ endfunction
 
 
 function! s:job_cb(fn, job, ch, data)
 function! s:job_cb(fn, job, ch, data)
   if !s:plug_window_exists() " plug window closed
   if !s:plug_window_exists() " plug window closed
-    return s:job_abort()
+    return s:job_abort(0)
   endif
   endif
   call call(a:fn, [a:job, a:data])
   call call(a:fn, [a:job, a:data])
 endfunction
 endfunction
@@ -1452,17 +1480,16 @@ function! s:reap(name)
   endif
   endif
 
 
   let more = len(get(job, 'queue', []))
   let more = len(get(job, 'queue', []))
-  let bullet = job.error ? 'x' : more ? (job.new ? '+' : '*') : '-'
   let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines)
   let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines)
   if len(result)
   if len(result)
-    call s:log(bullet, a:name, result)
+    call s:log(s:bullet_for(job), a:name, result)
   endif
   endif
 
 
   if !job.error && more
   if !job.error && more
     let job.spec.queue = job.queue
     let job.spec.queue = job.queue
     let s:update.todo[a:name] = job.spec
     let s:update.todo[a:name] = job.spec
   else
   else
-    let s:update.bar .= job.error ? 'x' : '='
+    let s:update.bar .= s:bullet_for(job, '=')
     call s:bar()
     call s:bar()
   endif
   endif
 endfunction
 endfunction
@@ -1541,6 +1568,12 @@ while 1 " Without TCO, Vim stack is bound to explode
 
 
   let name = keys(s:update.todo)[0]
   let name = keys(s:update.todo)[0]
   let spec = remove(s:update.todo, name)
   let spec = remove(s:update.todo, name)
+  if get(spec, 'abort', 0)
+    call s:mark_aborted(name, 'Skipped')
+    call s:reap(name)
+    continue
+  endif
+
   let queue = get(spec, 'queue', [])
   let queue = get(spec, 'queue', [])
   let new = empty(globpath(spec.dir, '.git', 1))
   let new = empty(globpath(spec.dir, '.git', 1))