Просмотр исходного кода

Fix git detection bug, git prompt colour issues

Git version detection was falling over when development versions of git
were used. We now make sure we only take the first 3 version numbers,
and not the patch number/development hash.

Git prompt colours are reset after the end of the prompt to ensure that
background colours do not spill into following elements.

Also:

- Update vim-plug.
- Standardise folder naming for dotfiles backups. There are different
  default formats between the GNU and BSD versions of `date`.
Weiyi Lou 10 лет назад
Родитель
Сommit
fb05ca71bc
4 измененных файлов с 87 добавлено и 48 удалено
  1. 1 1
      setup.sh
  2. 82 45
      vim/autoload/plug.vim
  3. 1 1
      zsh/custom/cinaeco.zsh-theme
  4. 3 1
      zsh/custom/git.zsh

+ 1 - 1
setup.sh

@@ -18,7 +18,7 @@ linkup() {
 # }}}
 # }}}
 
 
 # Prepare folders
 # Prepare folders
-backup_dir=~/.dotfilesbackup/$(date)
+backup_dir=~/.dotfilesbackup/$(date "+%Y-%m-%d-%H%M%S")
 mkdir -p "$backup_dir" ~/.ssh ${XDG_CONFIG_HOME:=$HOME/.config}
 mkdir -p "$backup_dir" ~/.ssh ${XDG_CONFIG_HOME:=$HOME/.config}
 echo "Prepared folders."
 echo "Prepared folders."
 
 

+ 82 - 45
vim/autoload/plug.vim

@@ -24,11 +24,14 @@
 "   " Using git URL
 "   " Using git URL
 "   Plug 'https://github.com/junegunn/vim-github-dashboard.git'
 "   Plug 'https://github.com/junegunn/vim-github-dashboard.git'
 "
 "
+"   " Using a non-master branch
+"   Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }
+
 "   " Plugin options
 "   " Plugin options
 "   Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }
 "   Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }
 "
 "
 "   " Plugin outside ~/.vim/plugged with post-update hook
 "   " Plugin outside ~/.vim/plugged with post-update hook
-"   Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': 'yes \| ./install' }
+"   Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
 "
 "
 "   " Unmanaged plugin (manually installed and updated)
 "   " Unmanaged plugin (manually installed and updated)
 "   Plug '~/my-prototype-plugin'
 "   Plug '~/my-prototype-plugin'
@@ -172,11 +175,14 @@ function! plug#end()
             call s:assoc(lod.map, cmd, name)
             call s:assoc(lod.map, cmd, name)
           endif
           endif
           call add(s:triggers[name].map, cmd)
           call add(s:triggers[name].map, cmd)
-        elseif cmd =~ '^[A-Z]'
+        elseif cmd =~# '^[A-Z]'
           if exists(':'.cmd) != 2
           if exists(':'.cmd) != 2
             call s:assoc(lod.cmd, cmd, name)
             call s:assoc(lod.cmd, cmd, name)
           endif
           endif
           call add(s:triggers[name].cmd, cmd)
           call add(s:triggers[name].cmd, cmd)
+        else
+          call s:err('Invalid `on` option: '.cmd.
+          \ '. Should start with an uppercase letter or `<Plug>`.')
         endif
         endif
       endfor
       endfor
     endif
     endif
@@ -294,7 +300,7 @@ endif
 
 
 function! s:err(msg)
 function! s:err(msg)
   echohl ErrorMsg
   echohl ErrorMsg
-  echom a:msg
+  echom '[vim-plug] '.a:msg
   echohl None
   echohl None
   return 0
   return 0
 endfunction
 endfunction
@@ -605,7 +611,7 @@ function! s:prepare()
     silent %d _
     silent %d _
   else
   else
     call s:new_window()
     call s:new_window()
-    nnoremap <silent> <buffer> q  :if b:plug_preview==1<bar>pc<bar>endif<bar>echo<bar>q<cr>
+    nnoremap <silent> <buffer> q  :if b:plug_preview==1<bar>pc<bar>endif<bar>bd<cr>
     nnoremap <silent> <buffer> R  :silent! call <SID>retry()<cr>
     nnoremap <silent> <buffer> R  :silent! call <SID>retry()<cr>
     nnoremap <silent> <buffer> D  :PlugDiff<cr>
     nnoremap <silent> <buffer> D  :PlugDiff<cr>
     nnoremap <silent> <buffer> S  :PlugStatus<cr>
     nnoremap <silent> <buffer> S  :PlugStatus<cr>
@@ -650,6 +656,7 @@ function! s:do(pull, force, todo)
     if a:force || installed || updated
     if a:force || installed || updated
       execute 'cd' s:esc(spec.dir)
       execute 'cd' s:esc(spec.dir)
       call append(3, '- Post-update hook for '. name .' ... ')
       call append(3, '- Post-update hook for '. name .' ... ')
+      let error = ''
       let type = type(spec.do)
       let type = type(spec.do)
       if type == s:TYPE.string
       if type == s:TYPE.string
         try
         try
@@ -658,26 +665,60 @@ function! s:do(pull, force, todo)
           let g:_plug_do = '!'.escape(spec.do, '#!%')
           let g:_plug_do = '!'.escape(spec.do, '#!%')
           execute "normal! :execute g:_plug_do\<cr>\<cr>"
           execute "normal! :execute g:_plug_do\<cr>\<cr>"
         finally
         finally
-          let result = v:shell_error ? ('Exit status: '.v:shell_error) : 'Done!'
+          if v:shell_error
+            let error = 'Exit status: ' . v:shell_error
+          endif
           unlet g:_plug_do
           unlet g:_plug_do
         endtry
         endtry
       elseif type == s:TYPE.funcref
       elseif type == s:TYPE.funcref
         try
         try
           let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
           let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
           call spec.do({ 'name': name, 'status': status, 'force': a:force })
           call spec.do({ 'name': name, 'status': status, 'force': a:force })
-          let result = 'Done!'
         catch
         catch
-          let result = 'Error: ' . v:exception
+          let error = v:exception
         endtry
         endtry
       else
       else
-        let result = 'Error: Invalid type!'
+        let error = 'Invalid hook type'
       endif
       endif
-      call setline(4, getline(4) . result)
+      call setline(4, empty(error) ? (getline(4) . 'OK')
+                                 \ : ('x' . getline(4)[1:] . error))
       cd -
       cd -
     endif
     endif
   endfor
   endfor
 endfunction
 endfunction
 
 
+function! s:hash_match(a, b)
+  return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0
+endfunction
+
+function! s:checkout(plugs)
+  for [name, spec] in items(a:plugs)
+    let sha = spec.commit
+    call append(3, '- Checking out '.sha[:6].' of '.name.' ... ')
+    redraw
+
+    let error = []
+    let output = s:lines(s:system('git rev-parse HEAD', spec.dir))
+    if v:shell_error
+      let error = output
+    elseif !s:hash_match(sha, output[0])
+      let output = s:lines(s:system(
+            \ 'git fetch --depth 999999 && git checkout '.sha, spec.dir))
+      if v:shell_error
+        let error = output
+      endif
+    endif
+    if empty(error)
+      call setline(4, getline(4) . 'OK')
+    else
+      call setline(4, 'x'.getline(4)[1:] . 'Error')
+      for line in reverse(error)
+        call append(4, '    '.line)
+      endfor
+    endif
+  endfor
+endfunction
+
 function! s:finish(pull)
 function! s:finish(pull)
   let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen'))
   let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen'))
   if new_frozen
   if new_frozen
@@ -832,6 +873,7 @@ function! s:update_finish()
     let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt
     let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt
   endif
   endif
   if s:switch_in()
   if s:switch_in()
+    call s:checkout(filter(copy(s:update.all), 'has_key(v:val, "commit")'))
     call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'has_key(v:val, "do")'))
     call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'has_key(v:val, "do")'))
     call s:finish(s:update.pull)
     call s:finish(s:update.pull)
     call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.')
     call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.')
@@ -986,8 +1028,8 @@ while 1 " Without TCO, Vim stack is bound to explode
   let merge = s:shellesc(has_tag ? spec.tag : 'origin/'.spec.branch)
   let merge = s:shellesc(has_tag ? spec.tag : 'origin/'.spec.branch)
 
 
   if !new
   if !new
-    let [valid, msg] = s:git_valid(spec, 0)
-    if valid
+    let error = s:git_validate(spec, 0)
+    if empty(error)
       if pull
       if pull
         let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : ''
         let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : ''
         call s:spawn(name,
         call s:spawn(name,
@@ -997,7 +1039,7 @@ while 1 " Without TCO, Vim stack is bound to explode
         let s:jobs[name] = { 'running': 0, 'result': 'Already installed', 'error': 0 }
         let s:jobs[name] = { 'running': 0, 'result': 'Already installed', 'error': 0 }
       endif
       endif
     else
     else
-      let s:jobs[name] = { 'running': 0, 'result': msg, 'error': 1 }
+      let s:jobs[name] = { 'running': 0, 'result': error, 'error': 1 }
     endif
     endif
   else
   else
     call s:spawn(name,
     call s:spawn(name,
@@ -1019,7 +1061,7 @@ endwhile
 endfunction
 endfunction
 
 
 function! s:update_python()
 function! s:update_python()
-let py_exe = has('python3') ? 'python3' : 'python'
+let py_exe = has('python') ? 'python' : 'python3'
 execute py_exe "<< EOF"
 execute py_exe "<< EOF"
 """ Due to use of signals this function is POSIX only. """
 """ Due to use of signals this function is POSIX only. """
 import datetime
 import datetime
@@ -1048,14 +1090,9 @@ G_CLONE_OPT = vim.eval('s:clone_opt')
 G_PROGRESS = vim.eval('s:progress_opt(1)')
 G_PROGRESS = vim.eval('s:progress_opt(1)')
 G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads'))
 G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads'))
 G_STOP = thr.Event()
 G_STOP = thr.Event()
-G_THREADS = {}
 
 
 class PlugError(Exception):
 class PlugError(Exception):
-  def __init__(self, msg):
-    self._msg = msg
-  @property
-  def msg(self):
-    return self._msg
+  pass
 class CmdTimedOut(PlugError):
 class CmdTimedOut(PlugError):
   pass
   pass
 class CmdFailed(PlugError):
 class CmdFailed(PlugError):
@@ -1246,7 +1283,7 @@ class Plugin(object):
         with self.lock:
         with self.lock:
           thread_vim_command("let s:update.new['{0}'] = 1".format(self.name))
           thread_vim_command("let s:update.new['{0}'] = 1".format(self.name))
     except PlugError as exc:
     except PlugError as exc:
-      self.write(Action.ERROR, self.name, exc.msg)
+      self.write(Action.ERROR, self.name, [str(exc)])
     except KeyboardInterrupt:
     except KeyboardInterrupt:
       G_STOP.set()
       G_STOP.set()
       self.write(Action.ERROR, self.name, ['Interrupted!'])
       self.write(Action.ERROR, self.name, ['Interrupted!'])
@@ -1329,10 +1366,6 @@ class PlugThread(thr.Thread):
         work_q.task_done()
         work_q.task_done()
     except queue.Empty:
     except queue.Empty:
       pass
       pass
-    finally:
-      global G_THREADS
-      with lock:
-        del G_THREADS[thr.current_thread().name]
 
 
 class RefreshThread(thr.Thread):
 class RefreshThread(thr.Thread):
   def __init__(self, lock):
   def __init__(self, lock):
@@ -1386,17 +1419,16 @@ def main():
   for work in plugs.items():
   for work in plugs.items():
     work_q.put(work)
     work_q.put(work)
 
 
-  global G_THREADS
+  start_cnt = thr.active_count()
   for num in range(nthreads):
   for num in range(nthreads):
     tname = 'PlugT-{0:02}'.format(num)
     tname = 'PlugT-{0:02}'.format(num)
     thread = PlugThread(tname, (buf_q, work_q, lock))
     thread = PlugThread(tname, (buf_q, work_q, lock))
     thread.start()
     thread.start()
-    G_THREADS[tname] = thread
   if mac_gui:
   if mac_gui:
     rthread = RefreshThread(lock)
     rthread = RefreshThread(lock)
     rthread.start()
     rthread.start()
 
 
-  while not buf_q.empty() or len(G_THREADS) != 0:
+  while not buf_q.empty() or thr.active_count() != start_cnt:
     try:
     try:
       action, name, msg = buf_q.get(True, 0.25)
       action, name, msg = buf_q.get(True, 0.25)
       buf.write(action, name, msg)
       buf.write(action, name, msg)
@@ -1677,42 +1709,46 @@ function! s:system_chomp(...)
   return v:shell_error ? '' : substitute(ret, '\n$', '', '')
   return v:shell_error ? '' : substitute(ret, '\n$', '', '')
 endfunction
 endfunction
 
 
-function! s:git_valid(spec, check_branch)
-  let ret = 1
-  let msg = 'OK'
+function! s:git_validate(spec, check_branch)
+  let err = ''
   if isdirectory(a:spec.dir)
   if isdirectory(a:spec.dir)
     let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url', a:spec.dir))
     let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url', a:spec.dir))
     let remote = result[-1]
     let remote = result[-1]
     if v:shell_error
     if v:shell_error
-      let msg = join([remote, 'PlugClean required.'], "\n")
-      let ret = 0
+      let err = join([remote, 'PlugClean required.'], "\n")
     elseif !s:compare_git_uri(remote, a:spec.uri)
     elseif !s:compare_git_uri(remote, a:spec.uri)
-      let msg = join(['Invalid URI: '.remote,
+      let err = join(['Invalid URI: '.remote,
                     \ 'Expected:    '.a:spec.uri,
                     \ 'Expected:    '.a:spec.uri,
                     \ 'PlugClean required.'], "\n")
                     \ 'PlugClean required.'], "\n")
-      let ret = 0
+    elseif a:check_branch && has_key(a:spec, 'commit')
+      let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir))
+      let sha = result[-1]
+      if v:shell_error
+        let err = join(add(result, 'PlugClean required.'), "\n")
+      elseif !s:hash_match(sha, a:spec.commit)
+        let err = join([printf('Invalid HEAD (expected: %s, actual: %s)',
+                              \ a:spec.commit[:6], sha[:6]),
+                      \ 'PlugUpdate required.'], "\n")
+      endif
     elseif a:check_branch
     elseif a:check_branch
       let branch = result[0]
       let branch = result[0]
       " Check tag
       " Check tag
       if has_key(a:spec, 'tag')
       if has_key(a:spec, 'tag')
         let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
         let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
         if a:spec.tag !=# tag
         if a:spec.tag !=# tag
-          let msg = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',
+          let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',
                 \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
                 \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
-          let ret = 0
         endif
         endif
       " Check branch
       " Check branch
       elseif a:spec.branch !=# branch
       elseif a:spec.branch !=# branch
-        let msg = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
+        let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
               \ branch, a:spec.branch)
               \ branch, a:spec.branch)
-        let ret = 0
       endif
       endif
     endif
     endif
   else
   else
-    let msg = 'Not found'
-    let ret = 0
+    let err = 'Not found'
   endif
   endif
-  return [ret, msg]
+  return err
 endfunction
 endfunction
 
 
 function! s:rm_rf(dir)
 function! s:rm_rf(dir)
@@ -1730,7 +1766,7 @@ function! s:clean(force)
   let dirs = []
   let dirs = []
   let [cnt, total] = [0, len(g:plugs)]
   let [cnt, total] = [0, len(g:plugs)]
   for [name, spec] in items(g:plugs)
   for [name, spec] in items(g:plugs)
-    if !s:is_managed(name) || s:git_valid(spec, 0)[0]
+    if !s:is_managed(name) || empty(s:git_validate(spec, 0))
       call add(dirs, spec.dir)
       call add(dirs, spec.dir)
     endif
     endif
     let cnt += 1
     let cnt += 1
@@ -1823,7 +1859,8 @@ function! s:status()
   for [name, spec] in items(g:plugs)
   for [name, spec] in items(g:plugs)
     if has_key(spec, 'uri')
     if has_key(spec, 'uri')
       if isdirectory(spec.dir)
       if isdirectory(spec.dir)
-        let [valid, msg] = s:git_valid(spec, 1)
+        let err = s:git_validate(spec, 1)
+        let [valid, msg] = [empty(err), empty(err) ? 'OK' : err]
       else
       else
         let [valid, msg] = [0, 'Not found. Try PlugInstall.']
         let [valid, msg] = [0, 'Not found. Try PlugInstall.']
       endif
       endif
@@ -1939,7 +1976,7 @@ function! s:diff()
   redraw
   redraw
 
 
   let cnt = 0
   let cnt = 0
-  for [k, v] in items(g:plugs)
+  for [k, v] in filter(items(g:plugs), '!has_key(v:val[1], "commit")')
     if !isdirectory(v.dir) || !s:is_managed(k)
     if !isdirectory(v.dir) || !s:is_managed(k)
       continue
       continue
     endif
     endif
@@ -1998,7 +2035,7 @@ function! s:snapshot(...) abort
   redraw
   redraw
 
 
   let dirs = sort(map(values(filter(copy(g:plugs),
   let dirs = sort(map(values(filter(copy(g:plugs),
-        \'has_key(v:val, "uri") && isdirectory(v:val.dir)')), 'v:val.dir'))
+        \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)')), 'v:val.dir'))
   let anchor = line('$') - 1
   let anchor = line('$') - 1
   for dir in reverse(dirs)
   for dir in reverse(dirs)
     let sha = s:system_chomp('git rev-parse --short HEAD', dir)
     let sha = s:system_chomp('git rev-parse --short HEAD', dir)

+ 1 - 1
zsh/custom/cinaeco.zsh-theme

@@ -128,7 +128,7 @@ function git_prompt_status() {
     [[ $X == 'R' ]] && X_SET="$X_SET$ZSH_THEME_GIT_INDEX_RENAMED" && continue
     [[ $X == 'R' ]] && X_SET="$X_SET$ZSH_THEME_GIT_INDEX_RENAMED" && continue
     [[ $X == 'C' ]] && X_SET="$X_SET$ZSH_THEME_GIT_INDEX_COPIED" && continue
     [[ $X == 'C' ]] && X_SET="$X_SET$ZSH_THEME_GIT_INDEX_COPIED" && continue
   done
   done
-  local STATUS=" %{$FG[070]%}$X_SET%{$FG[124]%}$Y_SET%{$FG[220]%}$UN_SET$END"
+  local STATUS=" %{$FG[070]%}$X_SET%{$FG[124]%}$Y_SET%{$FG[220]%}$UN_SET$END%{$reset_color%}"
   echo $STATUS
   echo $STATUS
 }
 }
 
 

+ 3 - 1
zsh/custom/git.zsh

@@ -12,8 +12,10 @@ function git_compare_version() {
     t again'
     t again'
   )
   )
   # Sanitise installed version to 3 digits as well.
   # Sanitise installed version to 3 digits as well.
+  # The raw version string takes the form 'git version 1.2.3...'
   INSTALLED=$(git --version 2> /dev/null)
   INSTALLED=$(git --version 2> /dev/null)
-  INSTALLED=${INSTALLED//[git version |.]/}
+  INSTALLED=${INSTALLED:12:5}
+  INSTALLED=${INSTALLED//./}
 
 
   if [[ $INSTALLED -gt $INPUT ]]; then
   if [[ $INSTALLED -gt $INPUT ]]; then
     echo 1
     echo 1