Bläddra i källkod

Real-time progress report

This commit is almost identical to the reverted
60b907c87f693e3e4ce2cc91aa10d9125cfe441e, but it tries to avoid high CPU load
by not printing every line.
Junegunn Choi 11 år sedan
förälder
incheckning
af89938633
2 ändrade filer med 84 tillägg och 24 borttagningar
  1. 83 23
      plug.vim
  2. 1 1
      test/workflow.vader

+ 83 - 23
plug.vim

@@ -323,7 +323,11 @@ function! s:syntax()
   syn match plugBracket /[[\]]/ contained
   syn match plugX /x/ contained
   syn match plugDash /^-/
+  syn match plugPlus /^+/
+  syn match plugStar /^*/
   syn match plugName /\(^- \)\@<=[^:]*/
+  syn match plugInstall /\(^+ \)\@<=[^:]*/
+  syn match plugUpdate /\(^* \)\@<=[^:]*/
   syn match plugCommit /^  [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha
   syn match plugSha /\(^  \)\@<=[0-9a-z]\{7}/ contained
   syn match plugRelDate /([^)]*)$/ contained
@@ -334,8 +338,15 @@ function! s:syntax()
   hi def link plugX       Exception
   hi def link plugBracket Structure
   hi def link plugNumber  Number
+
   hi def link plugDash    Special
+  hi def link plugPlus    Constant
+  hi def link plugStar    Boolean
+
   hi def link plugName    Label
+  hi def link plugInstall Function
+  hi def link plugUpdate  Type
+
   hi def link plugError   Error
   hi def link plugRelDate Comment
   hi def link plugSha     Identifier
@@ -429,7 +440,21 @@ function! s:update_impl(pull, args) abort
 
   let len = len(g:plugs)
   if has('ruby') && threads > 1
-    call s:update_parallel(a:pull, todo, threads)
+    try
+      call s:update_parallel(a:pull, todo, threads)
+    catch
+      let lines = getline(4, '$')
+      let printed = {}
+      silent 4,$d
+      for line in lines
+        let name = get(matchlist(line, '^. \([^:]\+\):'), 1, '')
+        if empty(name) || !has_key(printed, name)
+          let printed[name] = 1
+          call append('$', line)
+        endif
+      endfor
+      echoerr v:exception
+    endtry
   else
     call s:update_serial(a:pull, todo)
   endif
@@ -491,7 +516,6 @@ function! s:update_serial(pull, todo)
         if !isdirectory(base)
           call mkdir(base, 'p')
         endif
-        execute 'cd '.base
         let result = s:system(
               \ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1',
               \ s:shellesc(spec.uri),
@@ -520,6 +544,23 @@ endfunction
 
 function! s:update_parallel(pull, todo, threads)
   ruby << EOF
+  module PlugStream
+    SEP = ["\r", "\n", nil]
+    def get_line
+      buffer = ''
+      loop do
+        char = readchar rescue return
+        if SEP.include? char
+          buffer << $/
+          break
+        else
+          buffer << char
+        end
+      end
+      buffer
+    end
+  end unless defined?(PlugStream)
+
   def esc arg
     %["#{arg.gsub('"', '\"')}"]
   end
@@ -535,55 +576,70 @@ function! s:update_parallel(pull, todo, threads)
   all   = VIM::evaluate('copy(a:todo)')
   limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
   nthr  = VIM::evaluate('a:threads').to_i
+  maxy  = VIM::evaluate('winheight(".")').to_i
   cd    = iswin ? 'cd /d' : 'cd'
-  done  = {}
   tot   = 0
   bar   = ''
   skip  = 'Already installed'
   mtx   = Mutex.new
   take1 = proc { mtx.synchronize { running && all.shift } }
   logh  = proc {
-    cnt = done.length
+    cnt = $curbuf[2][1...-1].strip.length
     tot = VIM::evaluate('len(a:todo)') || tot
     $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
     $curbuf[2] = '[' + bar.ljust(tot) + ']'
     VIM::command('normal! 2G')
     VIM::command('redraw') unless iswin
   }
-  log = proc { |name, result, ok|
+  where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }
+  log   = proc { |name, result, type|
     mtx.synchronize do
-      bar += ok ? '=' : 'x'
-      done[name] = true
+      ing  = ![true, false].include?(type)
+      bar += type ? '=' : 'x' unless ing
+      b = case type
+          when :install  then '+' when :update then '*'
+          when true, nil then '-' else 'x' end
       result =
-        if ok
-          ["- #{name}: #{result.lines.to_a.last.strip}"]
+        if type || type.nil?
+          ["#{b} #{name}: #{result.lines.to_a.last}"]
         elsif result =~ /^Interrupted|^Timeout/
-          ["x #{name}: #{result}"]
+          ["#{b} #{name}: #{result}"]
         else
-          ["x #{name}"] + result.lines.map { |l| "    " << l }
+          ["#{b} #{name}"] + result.lines.map { |l| "    " << l }
         end
+      if lnum = where.call(name)
+        $curbuf.delete lnum
+        lnum = 4 if ing && lnum > maxy
+      end
       result.each_with_index do |line, offset|
-        $curbuf.append 3 + offset, line.chomp
+        $curbuf.append (lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp
       end
       logh.call
     end
   }
-  bt = proc { |cmd|
+  bt = proc { |cmd, name, type|
     begin
       fd = nil
-      Timeout::timeout(limit) do
-        if iswin
+      data = ''
+      if iswin
+        Timeout::timeout(limit) do
           tmp = VIM::evaluate('tempname()')
           system("#{cmd} > #{tmp}")
           data = File.read(tmp).chomp
           File.unlink tmp rescue nil
-        else
-          fd = IO.popen(cmd)
-          data = fd.read.chomp
-          fd.close
         end
-        [$? == 0, data]
+      else
+        fd = IO.popen(cmd).extend(PlugStream)
+        first_line = true
+        log_prob = 1.0 / nthr
+        while line = Timeout::timeout(limit) { fd.get_line }
+          data << line
+          log.call name, line.chomp, type if name && (first_line || rand < log_prob)
+          first_line = false
+        end
+        fd.close
       end
+      [$? == 0, data.chomp]
     rescue Timeout::Error, Interrupt => e
       if fd && !fd.closed?
         pids = [fd.pid]
@@ -616,6 +672,7 @@ function! s:update_parallel(pull, todo, threads)
     main.kill
   }
 
+  progress = iswin ? '' : '--progress'
   until all.empty?
     names = all.keys
     [names.length, nthr].min.times do
@@ -625,10 +682,11 @@ function! s:update_parallel(pull, todo, threads)
             name = pair.first
             dir, uri, branch = pair.last.values_at *%w[dir uri branch]
             branch = esc branch
+            subm = "git submodule update --init --recursive 2>&1"
             ok, result =
               if File.directory? dir
                 dir = esc dir
-                ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"
+                ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil
                 current_uri = data.lines.to_a.last
                 if !ret
                   if data =~ /^Interrupted|^Timeout/
@@ -642,7 +700,8 @@ function! s:update_parallel(pull, todo, threads)
                            "PlugClean required."].join($/)]
                 else
                   if pull
-                    bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && git pull origin #{branch} 2>&1 && git submodule update --init --recursive 2>&1"
+                    log.call name, 'Updating ...', :update
+                    bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && (git pull origin #{branch} #{progress} 2>&1 && #{subm})", name, :update
                   else
                     [true, skip]
                   end
@@ -650,7 +709,8 @@ function! s:update_parallel(pull, todo, threads)
               else
                 FileUtils.mkdir_p(base)
                 d = esc dir.sub(%r{[\\/]+$}, '')
-                bt.call "#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && git submodule update --init --recursive 2>&1"
+                log.call name, 'Installing ...', :install
+                bt.call "(git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && #{subm})", name, :install
               end
             log.call name, result, ok
           end

+ 1 - 1
test/workflow.vader

@@ -239,7 +239,7 @@ Execute (PlugClean! to remove vim-emoji):
 
 Execute (PlugUpdate to install both again):
   PlugUpdate
-  AssertEqual 2, len(filter(getline(1, line('$')), 'v:val =~ "Cloning into"'))
+  AssertEqual 2, len(filter(getline(1, line('$')), 'v:val =~ "^- [^:]*:"'))
   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'