Преглед на файлове

Update plugins

Sclarki user on github appears to no longer exist (or, perhaps less
likely, has been renamed to MidnaPeach?), hence repositories for
Neonwave and Surarken no longer exist, and these are now pointed to
alternatives.
cinaeco преди 7 години
родител
ревизия
3f36ee8e96
променени са 7 файла, в които са добавени 126 реда и са изтрити 307 реда
  1. 1 1
      docs/man/man1/z.1
  2. 1 1
      shell/common/coloured-man-pages.sh
  3. 25 23
      shell/common/z.sh
  4. 0 25
      shell/zsh/completions/_ack
  5. 1 217
      shell/zsh/completions/_ag
  6. 95 37
      vim/autoload/plug.vim
  7. 3 3
      vim/plugins.vim

+ 1 - 1
docs/man/man1/z.1

@@ -155,7 +155,7 @@ directory trees to exclude from tracking. \fB$HOME\fR is always excluded.
 Directories must be full paths without trailing slashes.
 .P
 The environment variable \fB$_Z_OWNER\fR can be set to your username, to
-allow usage of \fBz\fR when your sudo enviroment keeps \fB$HOME\fR set.
+allow usage of \fBz\fR when your sudo environment keeps \fB$HOME\fR set.
 .SH
 FILES
 Data is stored in \fB$HOME/.z\fR. This can be overridden by setting the

+ 1 - 1
shell/common/coloured-man-pages.sh

@@ -16,7 +16,7 @@ EOF
 	fi
 fi
 
-man() {
+function man() {
 	env \
 		LESS_TERMCAP_mb=$(printf "\e[1;31m") \
 		LESS_TERMCAP_md=$(printf "\e[1;31m") \

+ 25 - 23
shell/common/z.sh

@@ -1,4 +1,4 @@
-# Copyright (c) 2009 rupa deadwyler under the WTFPL license
+# Copyright (c) 2009 rupa deadwyler. Licensed under the WTFPL license, Version 2
 
 # maintains a jump-list of the directories you actually use
 #
@@ -31,15 +31,19 @@ _z() {
 
     local datafile="${_Z_DATA:-$HOME/.z}"
 
+    # if symlink, dereference
+    [ -h "$datafile" ] && datafile=$(readlink "$datafile")
+
     # bail if we don't own ~/.z and $_Z_OWNER not set
     [ -z "$_Z_OWNER" -a -f "$datafile" -a ! -O "$datafile" ] && return
 
     _z_dirs () {
-      while read line; do
-        # only count directories
-        [ -d "${line%%\|*}" ] && echo $line
-      done < "$datafile"
-      return 0
+        local line
+        while read line; do
+            # only count directories
+            [ -d "${line%%\|*}" ] && echo "$line"
+        done < "$datafile"
+        return 0
     }
 
     # add entries
@@ -57,7 +61,7 @@ _z() {
 
         # maintain the data file
         local tempfile="$datafile.$RANDOM"
-        awk < <(_z_dirs 2>/dev/null) -v path="$*" -v now="$(date +%s)" -F"|" '
+        _z_dirs | awk -v path="$*" -v now="$(date +%s)" -F"|" '
             BEGIN {
                 rank[path] = 1
                 time[path] = now
@@ -90,17 +94,15 @@ _z() {
 
     # tab completion
     elif [ "$1" = "--complete" -a -s "$datafile" ]; then
-        while read line; do
-            [ -d "${line%%\|*}" ] && echo $line
-        done < "$datafile" | awk -v q="$2" -F"|" '
+        _z_dirs | awk -v q="$2" -F"|" '
             BEGIN {
-                if( q == tolower(q) ) imatch = 1
                 q = substr(q, 3)
-                gsub(" ", ".*", q)
+                if( q == tolower(q) ) imatch = 1
+                gsub(/ /, ".*", q)
             }
             {
                 if( imatch ) {
-                    if( tolower($1) ~ tolower(q) ) print $1
+                    if( tolower($1) ~ q ) print $1
                 } else if( $1 ~ q ) print $1
             }
         ' 2>/dev/null
@@ -141,19 +143,21 @@ _z() {
                 if( dx < 604800 ) return rank / 2
                 return rank / 4
             }
-            function output(files, out, common) {
+            function output(matches, best_match, common) {
                 # list or return the desired directory
                 if( list ) {
                     cmd = "sort -n >&2"
-                    for( x in files ) {
-                        if( files[x] ) printf "%-10s %s\n", files[x], x | cmd
+                    for( x in matches ) {
+                        if( matches[x] ) {
+                            printf "%-10s %s\n", matches[x], x | cmd
+                        }
                     }
                     if( common ) {
                         printf "%-10s %s\n", "common:", common > "/dev/stderr"
                     }
                 } else {
-                    if( common ) out = common
-                    print out
+                    if( common ) best_match = common
+                    print best_match
                 }
             }
             function common(matches) {
@@ -164,11 +168,9 @@ _z() {
                     }
                 }
                 if( short == "/" ) return
-                # use a copy to escape special characters, as we want to return
-                # the original. yeah, this escaping is awful.
-                clean_short = short
-                gsub(/\[\(\)\[\]\|\]/, "\\\\&", clean_short)
-                for( x in matches ) if( matches[x] && x !~ clean_short ) return
+                for( x in matches ) if( matches[x] && index(x, short) != 1 ) {
+                    return
+                }
                 return short
             }
             BEGIN {

+ 0 - 25
shell/zsh/completions/_ack

@@ -1,30 +1,5 @@
 #compdef ack ack2 ack-grep ack-standalone
 # ------------------------------------------------------------------------------
-# Copyright (c) 2011 Github zsh-users - http://github.com/zsh-users
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above copyright
-#       notice, this list of conditions and the following disclaimer in the
-#       documentation and/or other materials provided with the distribution.
-#     * Neither the name of the zsh-users nor the
-#       names of its contributors may be used to endorse or promote products
-#       derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL ZSH-USERS BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# ------------------------------------------------------------------------------
 # Description
 # -----------
 #

+ 1 - 217
shell/zsh/completions/_ag

@@ -1,217 +1 @@
-#compdef ag
-# ------------------------------------------------------------------------------
-# Copyright (c) 2015 Github zsh-users - http://github.com/zsh-users
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above copyright
-#       notice, this list of conditions and the following disclaimer in the
-#       documentation and/or other materials provided with the distribution.
-#     * Neither the name of the zsh-users nor the
-#       names of its contributors may be used to endorse or promote products
-#       derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL ZSH-USERS BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# ------------------------------------------------------------------------------
-# Description
-# -----------
-#
-#  Completion script for ag (https://github.com/ggreer/the_silver_searcher)
-#
-# ------------------------------------------------------------------------------
-# Authors
-# -------
-#
-#  * Akira Maeda <https://github.com/glidenote>
-#
-# ------------------------------------------------------------------------------
-# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
-# vim: ft=zsh sw=2 ts=2 et
-# ------------------------------------------------------------------------------
-_ag_version() {
-  local version
-  version=( $($words[1] --version) )
-  version=${version[@]:2:1}
-  version=( "${(@s/./)version}" )
-  echo "${version[2]}"
-}
-
-# Dynamically build the file type completion
-# Modifies the global $AG_OPTS array
-_ag_add_file_types() {
-  local typ exts
-  for i in $($words[1] --list-file-types); do
-    if [[ "${i:0:2}" = '--' ]]; then
-      if [[ "${typ}x" != "x" ]]; then
-        AG_OPTS+="${typ}[${exts}]"
-      fi
-      typ=$i
-      exts=
-    else
-      exts+=$i
-    fi
-  done
-  AG_OPTS+="${typ}[${exts}]"
-}
-
-# Add version appropriate options above base
-# Modifies the global $AG_OPTS array
-_ag_add_version_opts() {
-  local minor=$(_ag_version)
-
-  if [[ $minor -gt 21 ]];then
-    _ag_add_file_types
-    AG_OPTS+=(
-      '(- 1 *)--list-file-types[list supported filetypes to search]'
-      '--silent[suppress all log messages, including errors]'
-    )
-  fi
-
-  if [[ $minor -gt 22 ]];then
-    AG_OPTS+=(
-      '(-z --search-zip)'{-z,--search-zip}'[search contents of compressed files]'
-    )
-  fi
-
-  if [[ $minor -le 24 ]];then
-    AG_OPTS+=(
-      '(-s --case-sensitive)'{-s,--case-sensitive}'[match case sensitively]'
-      '(--noheading --heading)'{--noheading,--heading}'[print file names above matching contents]'
-    )
-  fi
-  if [[ $minor -gt 24 ]];then
-    AG_OPTS+=(
-      '(-s --case-sensitive)'{-s,--case-sensitive}'[Match case sensitively. Default on.]'
-      '(-H --noheading --heading)'{-H,--noheading,--heading}'[print file names above matching contents]'
-      '--vimgrep[output results like vim''s, :vimgrep /pattern/g would (report every match on the line)]'
-    )
-  fi
-
-  if [[ $minor -gt 26 ]];then
-    AG_OPTS+=(
-      '(-0 --null --print0)'{-0,--null,--print0}'[separate the filenames with \\0, rather than \\n]'
-    )
-  fi
-
-  if [[ $minor -le 27 ]];then
-    AG_OPTS+=(
-      '--depth[Search up to NUM directories deep. Default is 25.]:number'
-    )
-  fi
-  if [[ $minor -gt 27 ]];then
-    AG_OPTS+=(
-      '(-c --count)'{-c,--count}'[only print the number of matches in each file]'
-      '--depth[Search up to NUM directories deep, -1 for unlimited. Default is 25.]:number'
-      '(-F --fixed-strings)'{-F,--fixed-strings}'[alias for --literal for compatibility with grep]'
-    )
-  fi
-
-  if [[ $minor -le 28 ]];then
-    AG_OPTS+=(
-      '(--no-numbers)--no-numbers[don´t show line numbers]'
-    )
-  fi
-  if [[ $minor -gt 28 ]];then
-    AG_OPTS+=(
-      '(--nofilename --filename)'{--nofilename,--filename}'[Print file names. Default on, except when searching a single file.]'
-      '(--nonumbers --numbers)'{--nonumbers,--numbers}'[Print line numbers. Default is to omit line numbers when searching streams]'
-      '(-o --only-matching)'{-o,--only-matching}'[print only the matching part of the lines]'
-    )
-  fi
-}
-
-_ag() {
-  local curcontext="$curcontext" state line cmds update_policy ret=1
-
-  zstyle -s ":completion:${curcontext}:" cache-policy update_policy
-  [[ -z "$update_policy" ]] && zstyle ":completion:${curcontext}:" cache-policy _ag_types_caching_policy
-
-  # Don't complete if command doesn't exist
-  [[ ${+commands[${words[1]}]} -eq 0 ]] && return 0
-
-  if ( [[ ${+AG_OPTS} -eq 0 ]] || _cache_invalid "_AG_OPTS" ) && ! _retrieve_cache "_AG_OPTS"; then
-    # Base opts starts at ag version 0.20
-    AG_OPTS=(
-      '(- 1 *)--help[print a short help statement]'
-      '(- 1 *)--man[print the manual page]'
-      '(- 1 *)--version[display version and copyright information]'
-      '--ackmate[output results in a format parseable by AckMate]'
-      '(-A --after)'{-A,--after}'[Print NUM lines before match. Default is 2]:number'
-      '(-t --all-text -a --all-types -u --unrestricted)'{-t,--all-text}"[search all text files, excluding hidden ones]"
-      '(-a --all-types -t --all-text -u --unrestricted)'{-a,--all-types}"[search all text files, excluding hidden ones and not obeying ignore files (.agignore, .gitignore...)]"
-      '(-B --before)'{-B,--before}'[Print NUM lines after match. Defaults is 2]:number'
-      '(--nobreak --break)'{--nobreak,--break}'[Print a newline between matches in different files. Default on.]'
-      '(--color --nocolor)--color[Print color codes in results. Default on.]'
-      '(--nocolor --color --color-line-number --color-match --color-path)--nocolor[Do not print color codes in results. Default on.]'
-      '(--nocolor)--color-line-number[Color codes for line numbers. Default is 1;33.]'
-      '(--nocolor)--color-match[Color codes for result match numbers. Default is 30;43.]'
-      '(--nocolor)--color-path[Color codes for path names. Default is 1;32.]'
-      '--column[print column numbers in results]'
-      '(-C --context)'{-C,--context}'[Print NUM lines before and after matches. Default is 2.]:number'
-      '(-D --debug)'{-D,--debug}'[enable debug logging]'
-      '(-G --file-search-regex)'{-G,--file-search-regex}'[only search file names matching PATTERN]:pattern'
-      '(-l --files-with-matches)'{-l,--files-with-matches}'[only print filenames containing matches, not matching lines]'
-      '(-L --files-without-matches)'{-L,--files-without-matches}"[only print filenames that don't contain matches]"
-      '(-f --follow)'{-f,--follow}'[follow symlinks]'
-      '(-g)-g[print filenames that match PATTERN]:pattern'
-      '(--nogroup --group)'{--nogroup,--group}'[same as --\[no\]break --\[no\]heading]'
-      '--hidden[search hidden files, still obeys ignore files.]'
-      '*--ignore[Ignore files/directories matching this pattern. Literal file and directory names are also allowed.]:files:_files'
-      '(-i --ignore-case)'{-i,--ignore-case}'[match case insensitively]:pattern'
-      '*--ignore-dir[alias for --ignore for compatibility with ack]:files:_files'
-      '(-v --invert-match)'{-v,--invert-match}'[invert match]'
-      '(-Q --literal)'{-Q,--literal}'[match PATTERN literally, no regular expression]'
-      '(-m --max-count)'{-m,--max-count}'[Skip the rest of a file after NUM matches. Default is 10,000.]:number'
-      '(--pager --nopager)'{--pager,--nopager}'[Display results with PAGER. Disabled by default.]:pager program:_command_names'
-      '(--passthrough)--passthrough[when searching a stream, print all lines even if they don''t match]'
-      '(-p --path-to-agignore)'{-p,--path-to-agignore}'[provide a path to a specific .agignore file]:files:_files'
-      '--print-long-lines[print matches on very long lines, > 2k characters by default]'
-      '--search-binary[search binary files]'
-      '(-U --skip-vcs-ignores)'{-U,--skip-vcs-ignores}'[ignore VCS ignore files (.gitigore, .hgignore, svn:ignore), but still use .agignore]'
-      '(-S --smart-case)'{-S,--smart-case}'[match case sensitively if PATTERN contains any uppercase letters, else match case insensitively]'
-      '--stats[print stats (files scanned, time taken, etc)]'
-      '(-u --unrestricted -t --all-text -a --all-types)'{-u,--unrestricted}'[search ALL files, includes: hidden, binary & ignored files (.agignore, .gitignore...)]'
-      '(-w --word-regexp)'{-w,--word-regexp}'[only match whole words]'
-    )
-    _ag_add_version_opts
-    AG_OPTS+=(
-      '*: :_files'
-    )
-    [[ $#AG_OPTS -gt 0 ]] && _store_cache '_AG_OPTS' AG_OPTS
-  fi
-
-  _arguments -C -s -S ${AG_OPTS} && ret=0
-  unset AG_OPTS
-
-  case $state in
-    # placeholder
-  esac
-
-  return ret
-}
-
-_ag_types_caching_policy() {
-  # Rebuild if .agignore more recent than cache.
-  [[ -f $HOME/.agignore && $$HOME/.agignore -nt "$1" ]] && return 0
-
-  # Rebuild if cache is older than one week.
-  local -a oldp
-  oldp=( "$1"(Nmw+1) )
-  (( $#oldp )) && return 0
-
-  return 1
-}
-
-_ag "$@"
+404: Not Found

+ 95 - 37
vim/autoload/plug.vim

@@ -97,7 +97,7 @@ let s:plug_tab = get(s:, 'plug_tab', -1)
 let s:plug_buf = get(s:, 'plug_buf', -1)
 let s:mac_gui = has('gui_macvim') && has('gui_running')
 let s:is_win = has('win32') || has('win64')
-let s:nvim = has('nvim') && exists('*jobwait') && !s:is_win
+let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win)
 let s:vim8 = has('patch-8.0.0039') && exists('*job_start')
 let s:me = resolve(expand('<sfile>:p'))
 let s:base_spec = { 'branch': 'master', 'frozen': 0 }
@@ -121,6 +121,9 @@ function! plug#begin(...)
   else
     return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')
   endif
+  if fnamemodify(home, ':t') ==# 'plugin' && fnamemodify(home, ':h') ==# s:first_rtp
+    return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.')
+  endif
 
   let g:plug_home = home
   let g:plugs = {}
@@ -442,16 +445,21 @@ function! plug#load(...)
   if !exists('g:plugs')
     return s:err('plug#begin was not called')
   endif
-  let unknowns = filter(copy(a:000), '!has_key(g:plugs, v:val)')
+  let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000
+  let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)')
   if !empty(unknowns)
     let s = len(unknowns) > 1 ? 's' : ''
     return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', ')))
   end
-  for name in a:000
-    call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
-  endfor
-  call s:dobufread(a:000)
-  return 1
+  let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)')
+  if !empty(unloaded)
+    for name in unloaded
+      call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
+    endfor
+    call s:dobufread(unloaded)
+    return 1
+  end
+  return 0
 endfunction
 
 function! s:remove_triggers(name)
@@ -575,7 +583,7 @@ function! s:infer_properties(name, repo)
       let uri = repo
     else
       if repo !~ '/'
-        let repo = 'vim-scripts/'. repo
+        throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo)
       endif
       let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git')
       let uri = printf(fmt, repo)
@@ -597,7 +605,7 @@ function! plug#helptags()
     return s:err('plug#begin was not called')
   endif
   for spec in values(g:plugs)
-    let docd = join([spec.dir, 'doc'], '/')
+    let docd = join([s:rtp(spec), 'doc'], '/')
     if isdirectory(docd)
       silent! execute 'helptags' s:esc(docd)
     endif
@@ -621,10 +629,10 @@ function! s:syntax()
   syn match plugTag /(tag: [^)]\+)/
   syn match plugInstall /\(^+ \)\@<=[^:]*/
   syn match plugUpdate /\(^* \)\@<=[^:]*/
-  syn match plugCommit /^  \X*[0-9a-f]\{7} .*/ contains=plugRelDate,plugEdge,plugTag
+  syn match plugCommit /^  \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag
   syn match plugEdge /^  \X\+$/
   syn match plugEdge /^  \X*/ contained nextgroup=plugSha
-  syn match plugSha /[0-9a-f]\{7}/ contained
+  syn match plugSha /[0-9a-f]\{7,9}/ contained
   syn match plugRelDate /([^)]*)$/ contained
   syn match plugNotLoaded /(not loaded)$/
   syn match plugError /^x.*/
@@ -774,8 +782,10 @@ function! s:assign_name()
 endfunction
 
 function! s:chsh(swap)
-  let prev = [&shell, &shellredir]
-  if !s:is_win && a:swap
+  let prev = [&shell, &shellcmdflag, &shellredir]
+  if s:is_win
+    set shell=cmd.exe shellcmdflag=/c shellredir=>%s\ 2>&1
+  elseif a:swap
     set shell=sh shellredir=>%s\ 2>&1
   endif
   return prev
@@ -783,15 +793,23 @@ endfunction
 
 function! s:bang(cmd, ...)
   try
-    let [sh, shrd] = s:chsh(a:0)
+    let [sh, shellcmdflag, shrd] = s:chsh(a:0)
     " FIXME: Escaping is incomplete. We could use shellescape with eval,
     "        but it won't work on Windows.
     let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd
-    let g:_plug_bang = '!'.escape(cmd, '#!%')
+    if s:is_win
+      let batchfile = tempname().'.bat'
+      call writefile(['@echo off', cmd], batchfile)
+      let cmd = batchfile
+    endif
+    let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%')
     execute "normal! :execute g:_plug_bang\<cr>\<cr>"
   finally
     unlet g:_plug_bang
-    let [&shell, &shellredir] = [sh, shrd]
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win
+      call delete(batchfile)
+    endif
   endtry
   return v:shell_error ? 'Exit status: ' . v:shell_error : ''
 endfunction
@@ -868,7 +886,7 @@ function! s:checkout(spec)
   let output = s:system('git rev-parse HEAD', a:spec.dir)
   if !v:shell_error && !s:hash_match(sha, s:lines(output)[0])
     let output = s:system(
-          \ 'git fetch --depth 999999 && git checkout '.s:esc(sha), a:spec.dir)
+          \ 'git fetch --depth 999999 && git checkout '.s:esc(sha).' --', a:spec.dir)
   endif
   return output
 endfunction
@@ -986,6 +1004,10 @@ function! s:update_impl(pull, force, args) abort
   let s:clone_opt = get(g:, 'plug_shallow', 1) ?
         \ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : ''
 
+  if has('win32unix')
+    let s:clone_opt .= ' -c core.eol=lf -c core.autocrlf=input'
+  endif
+
   " Python version requirement (>= 2.7)
   if python && !has('python3') && !ruby && !use_job && s:update.threads > 1
     redir => pyv
@@ -1059,7 +1081,7 @@ function! s:update_finish()
       elseif has_key(spec, 'tag')
         let tag = spec.tag
         if tag =~ '\*'
-          let tags = s:lines(s:system('git tag --list '.string(tag).' --sort -version:refname 2>&1', spec.dir))
+          let tags = s:lines(s:system('git tag --list '.s:shellesc(tag).' --sort -version:refname 2>&1', spec.dir))
           if !v:shell_error && !empty(tags)
             let tag = tags[0]
             call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag))
@@ -1067,11 +1089,11 @@ function! s:update_finish()
           endif
         endif
         call s:log4(name, 'Checking out '.tag)
-        let out = s:system('git checkout -q '.s:esc(tag).' 2>&1', spec.dir)
+        let out = s:system('git checkout -q '.s:esc(tag).' -- 2>&1', spec.dir)
       else
         let branch = s:esc(get(spec, 'branch', 'master'))
         call s:log4(name, 'Merging origin/'.branch)
-        let out = s:system('git checkout -q '.branch.' 2>&1'
+        let out = s:system('git checkout -q '.branch.' -- 2>&1'
               \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only origin/'.branch.' 2>&1')), spec.dir)
       endif
       if !v:shell_error && filereadable(spec.dir.'/.gitmodules') &&
@@ -1169,10 +1191,15 @@ endfunction
 
 function! s:spawn(name, cmd, opts)
   let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''],
+            \ 'batchfile': (s:is_win && (s:nvim || s:vim8)) ? tempname().'.bat' : '',
             \ 'new': get(a:opts, 'new', 0) }
   let s:jobs[a:name] = job
-  let argv = add(s:is_win ? ['cmd', '/c'] : ['sh', '-c'],
-               \ has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd)
+  let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd
+  if !empty(job.batchfile)
+    call writefile(['@echo off', cmd], job.batchfile)
+    let cmd = job.batchfile
+  endif
+  let argv = add(s:is_win ? ['cmd', '/c'] : ['sh', '-c'], cmd)
 
   if s:nvim
     call extend(job, {
@@ -1202,8 +1229,7 @@ function! s:spawn(name, cmd, opts)
       let job.lines   = ['Failed to start job']
     endif
   else
-    let params = has_key(a:opts, 'dir') ? [a:cmd, a:opts.dir] : [a:cmd]
-    let job.lines = s:lines(call('s:system', params))
+    let job.lines = s:lines(call('s:system', [cmd]))
     let job.error = v:shell_error != 0
     let job.running = 0
   endif
@@ -1223,6 +1249,9 @@ function! s:reap(name)
   call s:log(bullet, a:name, empty(result) ? 'OK' : result)
   call s:bar()
 
+  if has_key(job, 'batchfile') && !empty(job.batchfile)
+    call delete(job.batchfile)
+  endif
   call remove(s:jobs, a:name)
 endfunction
 
@@ -1940,8 +1969,19 @@ function! s:update_ruby()
 EOF
 endfunction
 
+function! s:shellesc_cmd(arg)
+  let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g')
+  let escaped = substitute(escaped, '%', '%%', 'g')
+  let escaped = substitute(escaped, '"', '\\^&', 'g')
+  let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g')
+  return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"'
+endfunction
+
 function! s:shellesc(arg)
-  return '"'.escape(a:arg, '"').'"'
+  if &shell =~# 'cmd.exe$'
+    return s:shellesc_cmd(a:arg)
+  endif
+  return shellescape(a:arg)
 endfunction
 
 function! s:glob_dir(path)
@@ -1979,11 +2019,19 @@ endfunction
 
 function! s:system(cmd, ...)
   try
-    let [sh, shrd] = s:chsh(1)
+    let [sh, shellcmdflag, shrd] = s:chsh(1)
     let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd
+    if s:is_win
+      let batchfile = tempname().'.bat'
+      call writefile(['@echo off', cmd], batchfile)
+      let cmd = batchfile
+    endif
     return system(s:is_win ? '('.cmd.')' : cmd)
   finally
-    let [&shell, &shellredir] = [sh, shrd]
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win
+      call delete(batchfile)
+    endif
   endtry
 endfunction
 
@@ -2018,7 +2066,7 @@ function! s:git_validate(spec, check_branch)
       " Check tag
       if has_key(a:spec, 'tag')
         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 && a:spec.tag !~ '\*'
           let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',
                 \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
         endif
@@ -2198,15 +2246,16 @@ function! s:status()
   let unloaded = 0
   let [cnt, total] = [0, len(g:plugs)]
   for [name, spec] in items(g:plugs)
+    let is_dir = isdirectory(spec.dir)
     if has_key(spec, 'uri')
-      if isdirectory(spec.dir)
+      if is_dir
         let [err, _] = s:git_validate(spec, 1)
         let [valid, msg] = [empty(err), empty(err) ? 'OK' : err]
       else
         let [valid, msg] = [0, 'Not found. Try PlugInstall.']
       endif
     else
-      if isdirectory(spec.dir)
+      if is_dir
         let [valid, msg] = [1, 'OK']
       else
         let [valid, msg] = [0, 'Not found.']
@@ -2215,7 +2264,7 @@ function! s:status()
     let cnt += 1
     let ecnt += !valid
     " `s:loaded` entry can be missing if PlugUpgraded
-    if valid && get(s:loaded, name, -1) == 0
+    if is_dir && get(s:loaded, name, -1) == 0
       let unloaded = 1
       let msg .= ' (not loaded)'
     endif
@@ -2285,7 +2334,7 @@ function! s:preview_commit()
     let b:plug_preview = !s:is_preview_window_open()
   endif
 
-  let sha = matchstr(getline('.'), '^  \X*\zs[0-9a-f]\{7}')
+  let sha = matchstr(getline('.'), '^  \X*\zs[0-9a-f]\{7,9}')
   if empty(sha)
     return
   endif
@@ -2304,10 +2353,19 @@ function! s:preview_commit()
   endif
   setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable
   try
-    let [sh, shrd] = s:chsh(1)
-    execute 'silent %!cd' s:shellesc(g:plugs[name].dir) '&& git show --no-color --pretty=medium' sha
+    let [sh, shellcmdflag, shrd] = s:chsh(1)
+    let cmd = 'cd '.s:shellesc(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha
+    if s:is_win
+      let batchfile = tempname().'.bat'
+      call writefile(['@echo off', cmd], batchfile)
+      let cmd = batchfile
+    endif
+    execute 'silent %!' cmd
   finally
-    let [&shell, &shellredir] = [sh, shrd]
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win
+      call delete(batchfile)
+    endif
   endtry
   setlocal nomodifiable
   nnoremap <silent> <buffer> q :q<cr>
@@ -2349,7 +2407,7 @@ function! s:diff()
     call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
     for [k, v] in plugs
       let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..'
-      let diff = s:system_chomp('git log --graph --color=never --pretty=format:"%x01%h%x01%d%x01%s%x01%cr" '.s:shellesc(range), v.dir)
+      let diff = s:system_chomp('git log --graph --color=never '.join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 's:shellesc(v:val)')), v.dir)
       if !empty(diff)
         let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
         call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
@@ -2390,7 +2448,7 @@ function! s:revert()
     return
   endif
 
-  call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch), g:plugs[name].dir)
+  call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch).' --', g:plugs[name].dir)
   setlocal modifiable
   normal! "_dap
   setlocal nomodifiable

+ 3 - 3
vim/plugins.vim

@@ -12,10 +12,10 @@ silent! call plug#begin('~/dotfiles/vim/plugged')
 
 " General {{{
 Plug 'Raimondi/delimitMate'
+Plug 'adelarsq/vim-matchit'
 Plug 'dkprice/vim-easygrep'
 Plug 'haya14busa/vim-asterisk'
 Plug 'junegunn/vim-easy-align'
-Plug 'matchit.zip'
 Plug 'mbbill/undotree'
 Plug 'scrooloose/nerdcommenter'
 Plug 'terryma/vim-multiple-cursors'
@@ -34,9 +34,9 @@ endif
 
 " Visual {{{
 Plug 'AlessandroYorba/Alduin'
-Plug 'Sclarki/airline-surarken'
-Plug 'Sclarki/neonwave.vim'
+Plug 'MidnaPeach/neonwave.vim'
 Plug 'altercation/vim-colors-solarized'
+Plug 'cinaeco/airline-surarken'
 Plug 'junegunn/goyo.vim'
 Plug 'junegunn/limelight.vim'
 Plug 'vim-airline/vim-airline'