56 Commits
0.7.2 ... 0.8.0

Author SHA1 Message Date
Junegunn Choi
77413875da Amend comment section 2015-12-23 13:17:34 +09:00
Junegunn Choi
f695463daf Merge pull request #366 from junegunn/diff-origin
PlugDiff to show pending updates as well
2015-12-23 13:16:27 +09:00
Junegunn Choi
e6f40479ee PlugDiff to show pending updates as well
Related: #348
2015-12-23 13:12:06 +09:00
Junegunn Choi
6843e5aeec Merge pull request #361 from junegunn/snapshot-in-vimscript
PlugSnapshot output in Vim script format (#360)
2015-12-17 23:34:37 +09:00
Junegunn Choi
0cfa683cd0 PlugSnapshot output in Vim script format (#360)
- The output file is no longer executable but a source-able vim script
- PlugSnapshot FILENAME to prompt the user if the file already exists
- Add PlugSnapshot! FILENAME variant to force overwrite existing file
- Apply -complete=file option to PlugSnapshot command
2015-12-17 16:06:19 +09:00
Junegunn Choi
e929534199 Fix #362 - Do not show future changes in PlugDiff 2015-12-16 22:56:57 +09:00
Junegunn Choi
52d7da3925 Fix #355 - PlugSnapshot to create scripts that disable shallow-clone 2015-12-14 23:16:50 +09:00
Jeremy Pallats/starcraft.man
cd26cd562e Merge pull request #357 from starcraftman/win_cd
Fix #353: Not Working On Windows
2015-12-13 14:26:22 -05:00
Jeremy Pallats/starcraft.man
24a71f9a91 Fix #353: Not Working On Windows
* First fix was only partial, allow drive letter changes.
2015-12-13 14:11:42 -05:00
Jeremy Pallats/starcraft.man
b836656556 Merge pull request #354 from starcraftman/trail_slash
Fix #353: Not Working On Windows
2015-12-13 13:31:59 -05:00
Jeremy Pallats/starcraft.man
7f598e5b58 Fix #353: Not Working On Windows
* Trailing slash appears to break clone command.
2015-12-13 13:10:06 -05:00
Junegunn Choi
87b426e381 Fix #350 - Tagged plugin should be unshallowed on update
Ruby installer failed to do so due to invalid escaping
2015-12-11 23:11:21 +09:00
Junegunn Choi
ba97f4458e Merge pull request #342 from mattn/windows 2015-12-10 01:04:05 +09:00
Yasuhiro Matsumoto
060c0e6d6c Enable multi-thread on windows
Specify PIPE as stdin for subprocess.Pipe for gvim.exe.
Also fixes some ruby implementation.

* windows doesn't have pgrep.
* windows can't handle SIGTERM.
* windows can't handle /dev/null
* redraw always
2015-12-10 01:00:42 +09:00
Jeremy Pallats/starcraft.man
80e5b3eab5 Merge pull request #345 from starcraftman/fix_msys
Merging fix for msys2.
2015-12-06 12:06:32 -05:00
Jeremy Pallats/starcraft.man
aae282e4f0 Fix msys2: prepend cd to commands 2015-12-06 11:50:37 -05:00
Junegunn Choi
7cdd4036de Fix nvim output format (#340) 2015-12-06 01:15:28 +09:00
Jeremy Pallats/starcraft.man
173bfea4c5 Merge pull request #337 from starcraftman/power_readme
Ensure CWD isn't a factor for powershell command.
2015-11-29 15:59:58 -05:00
Jeremy Pallats/starcraft.man
c233234bd9 Ensure CWD isn't a factor for powershell command. 2015-11-29 15:56:13 -05:00
Junegunn Choi
84faabe4cc Bind q to :bd
Close #336. Also remove unnecessary echo.
2015-11-29 22:12:55 +09:00
Junegunn Choi
6173ecc210 Merge pull request #334 from starcraftman/update_travis
Migrate travis to use new docker system.
2015-11-29 03:44:24 +09:00
Jeremy Pallats/starcraft.man
dbd045e995 Migrate travis to use new docker system.
* Travis now installs built vim into $DEPS.
* test/run now detects best vim to use.
* python: Fix small display issue with error messages.
2015-11-28 13:39:22 -05:00
Junegunn Choi
0611369d0d Update installation instruction (#329) 2015-11-28 14:00:19 +09:00
Jeremy Pallats/starcraft.man
d478351363 Merge pull request #329 from starcraftman/xanderdunn-patch-1
Add install directions for using neovim
2015-11-26 09:58:28 -05:00
Xander Dunn
8381041ac1 Add install directions for using neovim
Neovim's autoload directory path is now considerably different from vim's.
2015-11-26 09:50:35 -05:00
Jeremy Pallats/starcraft.man
93d9e434a2 Merge pull request #324 from starcraftman/fix_freeze
Fix #318: Freezes on PlugInstall
2015-11-24 18:47:56 -05:00
Jeremy Pallats/starcraft.man
c3bcd95459 Fix #318: Freezes on PlugInstall 2015-11-24 16:06:42 -05:00
Jeremy Pallats/starcraft.man
f820fb9f0d Merge pull request #319 from starcraftman/timjk-patch-1
Add windows install instructions
2015-11-20 21:17:31 -05:00
Tim Jackson-Kiely
072d28e86e Add windows install instructions 2015-11-20 21:03:34 -05:00
Junegunn Choi
8fb0efe4e5 Merge pull request #316 from junegunn/commit-hash
Add support for commit hashes
2015-11-20 15:54:36 +09:00
Junegunn Choi
e11e045577 Add support for commit hashes
Close #315
2015-11-20 03:38:58 +09:00
Junegunn Choi
e00be1b493 Enhance post-update hook output 2015-11-19 01:23:35 +09:00
Junegunn Choi
38e1e6335c Case-sensitive validation of on arguments (#314) 2015-11-15 22:43:25 +09:00
Junegunn Choi
0c710f75f4 Prepend [vim-plug] to error messages 2015-11-15 22:41:30 +09:00
Junegunn Choi
8292b3f31a Update usage examples 2015-11-08 22:41:37 +09:00
Junegunn Choi
26e4a77317 Merge pull request #307 from agauniyal/patch-1
Add a non-master branch example
2015-10-29 01:39:48 +09:00
Abhinav Gauniyal
dd28fc7368 Add a non-master branch example 2015-10-28 22:00:15 +05:30
Junegunn Choi
fb8a5f9246 Post-update hook should not run in case of an error 2015-10-22 13:23:35 +09:00
Jeremy Pallats/starcraft.man
eb29cc9b47 Merge pull request #285 from starcraftman/thrd_join
Join a thread instead of sleeping
2015-09-21 15:52:03 -04:00
Jeremy Pallats/starcraft.man
a93bdfc175 Merge pull request #286 from zackhsi/master
Update YouCompleteMe install script
2015-09-18 15:57:20 -04:00
Zack Hsi
ded1ab7562 Update YouCompleteMe install script
The install script has been changed from `install.sh` to `install.py`.

1b40d683be
2015-09-18 10:51:40 -07:00
Jeremy Pallats/starcraft.man
91fe6ad3e9 Join a thread instead of sleeping.
* Instead of having a fixed sleep duration, start a thread
that monitors the subprocess.
* Started thread is joined, if process finishes thread returns
before timeout.
* Should increase speed and reduce overhead on CPU.
2015-09-18 07:13:06 -04:00
Jeremy Pallats/starcraft.man
86e75e5d08 Merge pull request #283 from starcraftman/refactor_command
Refactor Python Command & .travis.yml
2015-09-12 14:12:21 -04:00
Jeremy Pallats/starcraft.man
7e1dc1bcc8 Refactor Python code & .travis.yml
* Refactor Command class for easier reading.
* Some other minor clean ups & method renames.
* Change travis to use `env` and `matrix` to select builds.
* Use case instead of ifs to select behaviour.
2015-09-12 14:04:34 -04:00
Jeremy Pallats/starcraft.man
58d39115f9 Merge pull request #281 from starcraftman/fix_travis_build
Fix #280: Travis Build - Vim Fails To Compile
2015-09-09 09:23:17 -04:00
Jeremy Pallats/starcraft.man
675b09dbfc Fix #280: Travis Build - Vim Fails To Compile
* Build broken by some gui_gtk link problem.
2015-09-09 09:17:15 -04:00
Jeremy Pallats/starcraft.man
a190f4e843 Merge pull request #273 from starcraftman/fix_after_syntax
Fix #272 PlugUpdate and delayed loading
2015-08-26 09:26:09 -04:00
Jeremy Pallats/starcraft.man
27289deb5c Fix #272 PlugUpdate and delayed loading
* Force syntax files sourcing on lod_ft.
2015-08-26 08:45:34 -04:00
Junegunn Choi
a6f3a020e3 Merge pull request #264 from starcraftman/fix_codec
Close #262 UnicodeDecodeError
2015-07-31 03:26:17 +09:00
Jeremy Pallats/starcraft.man
4e5b5b978e Close #262 UnicodeDecodeError
* Problem was default decoder being ascii.
2015-07-30 14:08:34 -04:00
Junegunn Choi
2653f4bdfd Make it clear that &runtimepath is updated on plug#end()
Close #260
2015-07-22 17:52:56 +09:00
Junegunn Choi
69d6c9d545 Need to set modifiable for reloading commit content (#255) 2015-07-09 01:25:35 +09:00
Junegunn Choi
51cf219213 Merge pull request #255 from sodapopcan/plug-diff-mappings
Make commit preview unmodifiable + map q for quit
2015-07-09 00:30:10 +09:00
Andrew Haust
6286337e5b Make commit preview unmodifiable + map q for quit 2015-07-07 14:53:38 -04:00
Junegunn Choi
23b508e5fd Merge pull request #242 from starcraftman/rem_glog
Remove GLog.
2015-06-11 01:51:56 +09:00
Jeremy Pallats/starcraft.man
c34b35d50e Remove GLog. 2015-06-09 20:40:05 -04:00
6 changed files with 635 additions and 307 deletions

View File

@@ -1,35 +1,51 @@
language: ruby language: ruby
rvm: sudo: false
- 1.8.7 env:
- 1.9.2 # Test with vim-nox package on ubuntu global:
- 1.9.3 # Test against python installer - DEPS=$HOME/deps
- 2.0.0 - PATH=$DEPS/bin:$PATH
- 2.1.0 # Test against python3 installer matrix:
include:
before_script: | - env: ENV=nox
sudo apt-get update -y rvm: 1.8.7
if [ $(ruby -e 'puts RUBY_VERSION') = 1.9.2 ]; then addons: { apt: { packages: [vim-nox] } }
sudo apt-get install -y vim-nox - env: ENV=python
sudo ln -s /usr/bin/vim /usr/local/bin/vim rvm: 1.8.7
else addons: { apt: { packages: [python2.7-dev] } }
git clone --depth 1 https://github.com/vim/vim - env: ENV=python3
cd vim rvm: 1.8.7
if [ $(ruby -e 'puts RUBY_VERSION') = 1.9.3 ]; then addons: { apt: { packages: [python3-dev] } }
sudo apt-get install -y python2.7-dev - env: ENV=ruby
./configure --with-features=huge --enable-pythoninterp rvm: 1.8.7
elif [ $(ruby -e 'puts RUBY_VERSION') = 2.1.0 ]; then - env: ENV=ruby
sudo apt-get install -y python3-dev rvm: 2.0.0
./configure --with-features=huge --enable-python3interp install: |
else
./configure --with-features=huge --enable-rubyinterp
fi
make
sudo make install
cd -
fi
git config --global user.email "you@example.com" git config --global user.email "you@example.com"
git config --global user.name "Your Name" git config --global user.name "Your Name"
script: | if [ "$ENV" == "nox" ]; then
test/run ! mkdir -p ${DEPS}/bin
ln -s /usr/bin/vim.nox ${DEPS}/bin/vim
return
fi
C_OPTS="--prefix=$DEPS --with-features=huge --disable-gui "
case "$ENV" in
python)
C_OPTS+=--enable-pythoninterp
;;
python3)
C_OPTS+=--enable-python3interp
;;
ruby)
C_OPTS+=--enable-rubyinterp
;;
esac
git clone --depth 1 https://github.com/vim/vim
cd vim
./configure $C_OPTS
make
make install
cd -
script: test/run !

View File

@@ -14,7 +14,7 @@ A minimalist Vim plugin manager.
- Creates shallow clones to minimize disk space usage and download time - Creates shallow clones to minimize disk space usage and download time
- On-demand loading for [faster startup time][startup-time] - On-demand loading for [faster startup time][startup-time]
- Can review and rollback updates - Can review and rollback updates
- Branch/tag support - Branch/tag/commit support
- Post-update hooks - Post-update hooks
- Support for externally managed plugins - Support for externally managed plugins
@@ -22,17 +22,43 @@ A minimalist Vim plugin manager.
[nv]: http://neovim.org/ [nv]: http://neovim.org/
[startup-time]: http://junegunn.kr/images/vim-startup-time.png [startup-time]: http://junegunn.kr/images/vim-startup-time.png
### Usage ### Installation
[Download plug.vim](https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim) [Download plug.vim](https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim)
and put it in ~/.vim/autoload and put it in the "autoload" directory.
###### Unix
```sh ```sh
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
``` ```
Edit your .vimrc ###### Neovim
```sh
curl -fLo ~/.config/nvim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
```
###### Windows
```powershell
md ~\vimfiles\autoload
$uri = 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
(New-Object Net.WebClient).DownloadFile($uri, (Resolve-Path ~\vimfiles\autoload\plug.vim))
```
### Usage
Add a vim-plug section to your .vimrc:
1. Begin the section with `plug#begin()`
1. List the plugins with `Plug` commands
1. `plug#end()` to add the plugins to `&runtimepath`
#### Example
```vim ```vim
call plug#begin('~/.vim/plugged') call plug#begin('~/.vim/plugged')
@@ -51,15 +77,19 @@ Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
" 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'
" Add plugins to &runtimepath
call plug#end() call plug#end()
``` ```
@@ -74,20 +104,20 @@ Reload .vimrc and `:PlugInstall` to install plugins.
| `PlugClean[!]` | Remove unused directories (bang version will clean without prompt) | | `PlugClean[!]` | Remove unused directories (bang version will clean without prompt) |
| `PlugUpgrade` | Upgrade vim-plug itself | | `PlugUpgrade` | Upgrade vim-plug itself |
| `PlugStatus` | Check the status of plugins | | `PlugStatus` | Check the status of plugins |
| `PlugDiff` | See the updated changes from the previous PlugUpdate | | `PlugDiff` | Examine changes from the previous update and the pending changes |
| `PlugSnapshot [output path]` | Generate script for restoring the current snapshot of the plugins | | `PlugSnapshot[!] [output path]` | Generate script for restoring the current snapshot of the plugins |
### `Plug` options ### `Plug` options
| Option | Description | | Option | Description |
| -------------- | ------------------------------------------------ | | ----------------------- | ------------------------------------------------ |
| `branch`/`tag` | Branch or tag of the repository to use | | `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use |
| `rtp` | Subdirectory that contains Vim plugin | | `rtp` | Subdirectory that contains Vim plugin |
| `dir` | Custom directory for the plugin | | `dir` | Custom directory for the plugin |
| `do` | Post-update hook (string or funcref) | | `do` | Post-update hook (string or funcref) |
| `on` | On-demand loading: Commands or `<Plug>`-mappings | | `on` | On-demand loading: Commands or `<Plug>`-mappings |
| `for` | On-demand loading: File types | | `for` | On-demand loading: File types |
| `frozen` | Do not update unless explicitly specified | | `frozen` | Do not update unless explicitly specified |
### Global options ### Global options
@@ -154,7 +184,7 @@ In that case, use `do` option to describe the task to be performed.
```vim ```vim
Plug 'Shougo/vimproc.vim', { 'do': 'make' } Plug 'Shougo/vimproc.vim', { 'do': 'make' }
Plug 'Valloric/YouCompleteMe', { 'do': './install.sh' } Plug 'Valloric/YouCompleteMe', { 'do': './install.py' }
``` ```
If you need more control, you can pass a reference to a Vim function that If you need more control, you can pass a reference to a Vim function that
@@ -167,7 +197,7 @@ function! BuildYCM(info)
" - status: 'installed', 'updated', or 'unchanged' " - status: 'installed', 'updated', or 'unchanged'
" - force: set on PlugInstall! or PlugUpdate! " - force: set on PlugInstall! or PlugUpdate!
if a:info.status == 'installed' || a:info.force if a:info.status == 'installed' || a:info.force
!./install.sh !./install.py
endif endif
endfunction endfunction

535
plug.vim
View File

@@ -24,15 +24,19 @@
" " 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'
" "
" " Add plugins to &runtimepath
" call plug#end() " call plug#end()
" "
" Then reload .vimrc and :PlugInstall to install plugins. " Then reload .vimrc and :PlugInstall to install plugins.
@@ -113,13 +117,13 @@ function! s:define_commands()
if !executable('git') if !executable('git')
return s:err('`git` executable not found. vim-plug requires git.') return s:err('`git` executable not found. vim-plug requires git.')
endif endif
command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install('<bang>' == '!', [<f-args>]) command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>])
command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update('<bang>' == '!', [<f-args>]) command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(<bang>0, [<f-args>])
command! -nargs=0 -bar -bang PlugClean call s:clean('<bang>' == '!') command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0)
command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif
command! -nargs=0 -bar PlugStatus call s:status() command! -nargs=0 -bar PlugStatus call s:status()
command! -nargs=0 -bar PlugDiff call s:diff() command! -nargs=0 -bar PlugDiff call s:diff()
command! -nargs=? -bar PlugSnapshot call s:snapshot(<f-args>) command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(<bang>0, <f-args>)
endfunction endfunction
function! s:to_a(v) function! s:to_a(v)
@@ -142,6 +146,16 @@ function! s:assoc(dict, key, val)
let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) let a:dict[a:key] = add(get(a:dict, a:key, []), a:val)
endfunction endfunction
function! s:ask(message)
call inputsave()
echohl WarningMsg
let proceed = input(a:message.' (y/N) ') =~? '^y'
echohl None
call inputrestore()
echo "\r"
return proceed
endfunction
function! plug#end() function! plug#end()
if !exists('g:plugs') if !exists('g:plugs')
return s:err('Call plug#begin() first') return s:err('Call plug#begin() first')
@@ -171,11 +185,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
@@ -293,7 +310,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
@@ -398,7 +415,7 @@ function! s:lod(names, types)
endfunction endfunction
function! s:lod_ft(pat, names) function! s:lod_ft(pat, names)
call s:lod(a:names, ['plugin', 'after/plugin']) call s:lod(a:names, ['plugin', 'after/plugin', 'syntax', 'after/syntax'])
execute 'autocmd! PlugLOD FileType' a:pat execute 'autocmd! PlugLOD FileType' a:pat
if exists('#filetypeplugin#FileType') if exists('#filetypeplugin#FileType')
doautocmd filetypeplugin FileType doautocmd filetypeplugin FileType
@@ -514,16 +531,20 @@ function! s:syntax()
syn match plugStar /^*/ syn match plugStar /^*/
syn match plugMessage /\(^- \)\@<=.*/ syn match plugMessage /\(^- \)\@<=.*/
syn match plugName /\(^- \)\@<=[^ ]*:/ syn match plugName /\(^- \)\@<=[^ ]*:/
syn match plugSha /\%(: \)\@<=[0-9a-z]\{4,}$/
syn match plugTag /(tag: [^)]\+)/
syn match plugInstall /\(^+ \)\@<=[^:]*/ syn match plugInstall /\(^+ \)\@<=[^:]*/
syn match plugUpdate /\(^* \)\@<=[^:]*/ syn match plugUpdate /\(^* \)\@<=[^:]*/
syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha,plugTag
syn match plugSha /\(^ \)\@<=[0-9a-z]\{7}/ contained syn match plugSha /\(^ \)\@<=[0-9a-z]\{7}/ contained
syn match plugRelDate /([^)]*)$/ contained syn match plugRelDate /([^)]*)$/ contained
syn match plugNotLoaded /(not loaded)$/ syn match plugNotLoaded /(not loaded)$/
syn match plugError /^x.*/ syn match plugError /^x.*/
syn match plugH2 /^.*:\n-\+$/
syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
hi def link plug1 Title hi def link plug1 Title
hi def link plug2 Repeat hi def link plug2 Repeat
hi def link plugH2 Type
hi def link plugX Exception hi def link plugX Exception
hi def link plugBracket Structure hi def link plugBracket Structure
hi def link plugNumber Number hi def link plugNumber Number
@@ -540,6 +561,7 @@ function! s:syntax()
hi def link plugError Error hi def link plugError Error
hi def link plugRelDate Comment hi def link plugRelDate Comment
hi def link plugSha Identifier hi def link plugSha Identifier
hi def link plugTag Constant
hi def link plugNotLoaded Comment hi def link plugNotLoaded Comment
endfunction endfunction
@@ -604,7 +626,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>
@@ -645,10 +667,11 @@ function! s:do(pull, force, todo)
endif endif
let installed = has_key(s:update.new, name) let installed = has_key(s:update.new, name)
let updated = installed ? 0 : let updated = installed ? 0 :
\ (a:pull && !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', spec.dir))) \ (a:pull && index(s:update.errors, name) < 0 && !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', spec.dir)))
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
@@ -657,26 +680,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
@@ -719,7 +776,7 @@ endfunction
function! s:update_impl(pull, force, args) abort function! s:update_impl(pull, force, args) abort
let args = copy(a:args) let args = copy(a:args)
let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ?
\ remove(args, -1) : get(g:, 'plug_threads', s:is_win ? 1 : 16) \ remove(args, -1) : get(g:, 'plug_threads', 16)
let managed = filter(copy(g:plugs), 's:is_managed(v:key)') let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') :
@@ -756,9 +813,8 @@ function! s:update_impl(pull, force, args) abort
echohl None echohl None
endif endif
let python = (has('python') || has('python3')) && !s:is_win && !has('win32unix') let python = (has('python') || has('python3')) && (!s:nvim || has('vim_starting'))
\ && (!s:nvim || has('vim_starting')) let ruby = has('ruby') && !s:nvim && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running'))
let ruby = has('ruby') && !s:nvim && (v:version >= 703 || v:version == 702 && has('patch374'))
let s:update = { let s:update = {
\ 'start': reltime(), \ 'start': reltime(),
@@ -831,6 +887,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.')
@@ -860,7 +917,13 @@ function! s:job_handler(job_id, data, event) abort
endif endif
if a:event == 'stdout' if a:event == 'stdout'
let self.result .= substitute(s:to_s(a:data), '[\r\n]', '', 'g') . "\n" let complete = empty(a:data[-1])
let lines = map(filter(a:data, 'len(v:val) > 0'), 'split(v:val, "[\r\n]")[-1]')
call extend(self.lines, lines)
let self.result = join(self.lines, "\n")
if !complete
call remove(self.lines, -1)
endif
" 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.tick % len(s:jobs) == 0 if self.tick % len(s:jobs) == 0
@@ -877,7 +940,7 @@ function! s:job_handler(job_id, data, event) abort
endfunction endfunction
function! s:spawn(name, cmd, opts) function! s:spawn(name, cmd, opts)
let job = { 'name': a:name, 'running': 1, 'error': 0, 'result': '', let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [], 'result': '',
\ 'new': get(a:opts, 'new', 0), \ 'new': get(a:opts, 'new', 0),
\ 'on_stdout': function('s:job_handler'), \ 'on_stdout': function('s:job_handler'),
\ 'on_exit' : function('s:job_handler'), \ 'on_exit' : function('s:job_handler'),
@@ -985,8 +1048,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) let error = s:git_validate(spec, 0)
if valid 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,
@@ -996,7 +1059,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,
@@ -1018,9 +1081,8 @@ 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. """
import datetime import datetime
import functools import functools
import os import os
@@ -1047,54 +1109,29 @@ 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 = {} G_IS_WIN = vim.eval('s:is_win') == '1'
class BaseExc(Exception): class PlugError(Exception):
def __init__(self, msg): def __init__(self, msg):
self._msg = msg self.msg = msg
@property class CmdTimedOut(PlugError):
def msg(self):
return self._msg
class CmdTimedOut(BaseExc):
pass pass
class CmdFailed(BaseExc): class CmdFailed(PlugError):
pass pass
class InvalidURI(BaseExc): class InvalidURI(PlugError):
pass pass
class Action(object): class Action(object):
INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-']
class GLog(object):
ON = None
LOGDIR = None
@classmethod
def write(cls, msg):
if cls.ON is None:
cls.ON = int(vim.eval('get(g:, "plug_log_on", 0)'))
cls.LOGDIR = os.path.expanduser(vim.eval('get(g:, "plug_logs", "~/plug_logs")'))
if cls.ON:
if not os.path.exists(cls.LOGDIR):
os.makedirs(cls.LOGDIR)
cls._write(msg)
@classmethod
def _write(cls, msg):
name = thr.current_thread().name
fname = cls.LOGDIR + os.path.sep + name
with open(fname, 'ab') as flog:
ltime = datetime.datetime.now().strftime("%H:%M:%S.%f")
msg = '[{0},{1}] {2}{3}'.format(name, ltime, msg, '\n')
flog.write(msg.encode())
class Buffer(object): class Buffer(object):
def __init__(self, lock, num_plugs, is_pull, is_win): def __init__(self, lock, num_plugs, is_pull):
self.bar = '' self.bar = ''
self.event = 'Updating' if is_pull else 'Installing' self.event = 'Updating' if is_pull else 'Installing'
self.is_win = is_win
self.lock = lock self.lock = lock
self.maxy = int(vim.eval('winheight(".")')) self.maxy = int(vim.eval('winheight(".")'))
self.num_plugs = num_plugs self.num_plugs = num_plugs
def _where(self, name): def __where(self, name):
""" Find first line with name in current buffer. Return line num. """ """ Find first line with name in current buffer. Return line num. """
found, lnum = False, 0 found, lnum = False, 0
matcher = re.compile('^[-+x*] {0}:'.format(name)) matcher = re.compile('^[-+x*] {0}:'.format(name))
@@ -1117,14 +1154,12 @@ class Buffer(object):
with self.lock: with self.lock:
vim.command('normal! 2G') vim.command('normal! 2G')
if not self.is_win: vim.command('redraw')
vim.command('redraw')
def write(self, action, name, lines): def write(self, action, name, lines):
first, rest = lines[0], lines[1:] first, rest = lines[0], lines[1:]
msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)]
padded_rest = [' ' + line for line in rest] msg.extend([' ' + line for line in rest])
msg.extend(padded_rest)
try: try:
if action == Action.ERROR: if action == Action.ERROR:
@@ -1134,7 +1169,7 @@ class Buffer(object):
self.bar += '=' self.bar += '='
curbuf = vim.current.buffer curbuf = vim.current.buffer
lnum = self._where(name) lnum = self.__where(name)
if lnum != -1: # Found matching line num if lnum != -1: # Found matching line num
del curbuf[lnum] del curbuf[lnum]
if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]):
@@ -1145,65 +1180,87 @@ class Buffer(object):
self.header() self.header()
except vim.error: except vim.error:
GLog.write('Buffer Update FAILED.') pass
class Command(object): class Command(object):
def __init__(self, cmd, cmd_dir=None, timeout=60, ntries=3, cb=None, clean=None): CD = 'cd /d' if G_IS_WIN else 'cd'
self.cmd = cmd
self.cmd_dir = cmd_dir
self.timeout = timeout
self.ntries = ntries
self.callback = cb if cb else (lambda msg: None)
self.clean = clean
def attempt_cmd(self): def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None):
""" Tries to run the command, returns result if no exceptions. """ self.cmd = cmd
attempt = 0 if cmd_dir:
finished = False self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd)
limit = self.timeout self.timeout = timeout
self.callback = cb if cb else (lambda msg: None)
self.clean = clean if clean else (lambda: None)
self.proc = None
@property
def alive(self):
""" Returns true only if command still running. """
return self.proc and self.proc.poll() is None
def execute(self, ntries=3):
""" Execute the command with ntries if CmdTimedOut.
Returns the output of the command if no Exception.
"""
attempt, finished, limit = 0, False, self.timeout
while not finished: while not finished:
try: try:
attempt += 1 attempt += 1
result = self.timeout_cmd() result = self.try_command()
finished = True finished = True
return result
except CmdTimedOut: except CmdTimedOut:
if attempt != self.ntries: if attempt != ntries:
for count in range(3, 0, -1): self.notify_retry()
if G_STOP.is_set():
raise KeyboardInterrupt
msg = 'Timeout. Will retry in {0} second{1} ...'.format(
count, 's' if count != 1 else '')
self.callback([msg])
time.sleep(1)
self.timeout += limit self.timeout += limit
self.callback(['Retrying ...'])
else: else:
raise raise
return result def notify_retry(self):
""" Retry required for command, notify user. """
for count in range(3, 0, -1):
if G_STOP.is_set():
raise KeyboardInterrupt
msg = 'Timeout. Will retry in {0} second{1} ...'.format(
count, 's' if count != 1 else '')
self.callback([msg])
time.sleep(1)
self.callback(['Retrying ...'])
def timeout_cmd(self): def try_command(self):
""" Execute a cmd & poll for callback. Returns list of output. """ Execute a cmd & poll for callback. Returns list of output.
Raises CmdFailed -> return code for Popen isn't 0 Raises CmdFailed -> return code for Popen isn't 0
Raises CmdTimedOut -> command exceeded timeout without new output Raises CmdTimedOut -> command exceeded timeout without new output
""" """
proc = None
first_line = True first_line = True
try:
tfile = tempfile.NamedTemporaryFile(mode='w+b', delete=False)
proc = subprocess.Popen(self.cmd, cwd=self.cmd_dir, stdout=tfile,
stderr=subprocess.STDOUT, shell=True, preexec_fn=os.setsid)
while proc.poll() is None:
# Yield this thread
time.sleep(0.2)
try:
tfile = tempfile.NamedTemporaryFile(mode='w+b')
preexec_fn = not G_IS_WIN and os.setsid or None
self.proc = subprocess.Popen(self.cmd, stdout=tfile,
stderr=subprocess.STDOUT,
stdin=subprocess.PIPE, shell=True,
preexec_fn=preexec_fn)
thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,))
thrd.start()
thread_not_started = True
while thread_not_started:
try:
thrd.join(0.1)
thread_not_started = False
except RuntimeError:
pass
while self.alive:
if G_STOP.is_set(): if G_STOP.is_set():
raise KeyboardInterrupt raise KeyboardInterrupt
if first_line or random.random() < G_LOG_PROB: if first_line or random.random() < G_LOG_PROB:
first_line = False first_line = False
line = nonblock_read(tfile.name) line = '' if G_IS_WIN else nonblock_read(tfile.name)
if line: if line:
self.callback([line]) self.callback([line])
@@ -1211,23 +1268,27 @@ class Command(object):
if time_diff > self.timeout: if time_diff > self.timeout:
raise CmdTimedOut(['Timeout!']) raise CmdTimedOut(['Timeout!'])
thrd.join(0.5)
tfile.seek(0) tfile.seek(0)
result = [line.decode().rstrip() for line in tfile] result = [line.decode('utf-8', 'replace').rstrip() for line in tfile]
if proc.returncode != 0: if self.proc.returncode != 0:
msg = [''] raise CmdFailed([''] + result)
msg.extend(result)
raise CmdFailed(msg) return result
except: except:
if proc and proc.poll() is None: self.terminate()
os.killpg(proc.pid, signal.SIGTERM)
if self.clean:
self.clean()
raise raise
finally:
os.remove(tfile.name)
return result def terminate(self):
""" Terminate process and cleanup. """
if self.alive:
if G_IS_WIN:
os.kill(self.proc.pid, signal.SIGINT)
else:
os.killpg(self.proc.pid, signal.SIGTERM)
self.clean()
class Plugin(object): class Plugin(object):
def __init__(self, name, args, buf_q, lock): def __init__(self, name, args, buf_q, lock):
@@ -1248,7 +1309,7 @@ class Plugin(object):
self.install() self.install()
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 (CmdTimedOut, CmdFailed, InvalidURI) as exc: except PlugError as exc:
self.write(Action.ERROR, self.name, exc.msg) self.write(Action.ERROR, self.name, exc.msg)
except KeyboardInterrupt: except KeyboardInterrupt:
G_STOP.set() G_STOP.set()
@@ -1261,6 +1322,8 @@ class Plugin(object):
def install(self): def install(self):
target = self.args['dir'] target = self.args['dir']
if target[-1] == '\\':
target = target[0:-1]
def clean(target): def clean(target):
def _clean(): def _clean():
@@ -1273,11 +1336,18 @@ class Plugin(object):
self.write(Action.INSTALL, self.name, ['Installing ...']) self.write(Action.INSTALL, self.name, ['Installing ...'])
callback = functools.partial(self.write, Action.INSTALL, self.name) callback = functools.partial(self.write, Action.INSTALL, self.name)
cmd = 'git clone {0} {1} --recursive {2} -b {3} {4} 2>&1'.format( cmd = 'git clone {0} {1} --recursive {2} -b {3} {4} 2>&1'.format(
'' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], self.checkout, esc(target)) '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'],
com = Command(cmd, None, G_TIMEOUT, G_RETRIES, callback, clean(target)) self.checkout, esc(target))
result = com.attempt_cmd() com = Command(cmd, None, G_TIMEOUT, callback, clean(target))
result = com.execute(G_RETRIES)
self.write(Action.DONE, self.name, result[-1:]) self.write(Action.DONE, self.name, result[-1:])
def repo_uri(self):
cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url'
command = Command(cmd, self.args['dir'], G_TIMEOUT,)
result = command.execute(G_RETRIES)
return result[-1]
def update(self): def update(self):
match = re.compile(r'git::?@') match = re.compile(r'git::?@')
actual_uri = re.sub(match, '', self.repo_uri()) actual_uri = re.sub(match, '', self.repo_uri())
@@ -1298,22 +1368,13 @@ class Plugin(object):
'git merge --ff-only {0}'.format(self.merge), 'git merge --ff-only {0}'.format(self.merge),
'git submodule update --init --recursive'] 'git submodule update --init --recursive']
cmd = ' 2>&1 && '.join(cmds) cmd = ' 2>&1 && '.join(cmds)
GLog.write(cmd) com = Command(cmd, self.args['dir'], G_TIMEOUT, callback)
com = Command(cmd, self.args['dir'], G_TIMEOUT, G_RETRIES, callback) result = com.execute(G_RETRIES)
result = com.attempt_cmd()
GLog.write(result)
self.write(Action.DONE, self.name, result[-1:]) self.write(Action.DONE, self.name, result[-1:])
else: else:
self.write(Action.DONE, self.name, ['Already installed']) self.write(Action.DONE, self.name, ['Already installed'])
def repo_uri(self):
cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url'
command = Command(cmd, self.args['dir'], G_TIMEOUT, G_RETRIES)
result = command.attempt_cmd()
return result[-1]
def write(self, action, name, msg): def write(self, action, name, msg):
GLog.write('{0} {1}: {2}'.format(action, name, '\n'.join(msg)))
self.buf_q.put((action, name, msg)) self.buf_q.put((action, name, msg))
class PlugThread(thr.Thread): class PlugThread(thr.Thread):
@@ -1329,16 +1390,11 @@ class PlugThread(thr.Thread):
try: try:
while not G_STOP.is_set(): while not G_STOP.is_set():
name, args = work_q.get_nowait() name, args = work_q.get_nowait()
GLog.write('{0}: Dir {1}'.format(name, args['dir']))
plug = Plugin(name, args, buf_q, lock) plug = Plugin(name, args, buf_q, lock)
plug.manage() plug.manage()
work_q.task_done() work_q.task_done()
except queue.Empty: except queue.Empty:
GLog.write('Queue now empty.') 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):
@@ -1350,7 +1406,7 @@ class RefreshThread(thr.Thread):
while self.running: while self.running:
with self.lock: with self.lock:
thread_vim_command('noautocmd normal! a') thread_vim_command('noautocmd normal! a')
time.sleep(0.2) time.sleep(0.33)
def stop(self): def stop(self):
self.running = False self.running = False
@@ -1368,7 +1424,7 @@ def esc(name):
def nonblock_read(fname): def nonblock_read(fname):
""" Read a file with nonblock flag. Return the last line. """ """ Read a file with nonblock flag. Return the last line. """
fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK)
buf = os.read(fread, 100000).decode() buf = os.read(fread, 100000).decode('utf-8', 'replace')
os.close(fread) os.close(fread)
line = buf.rstrip('\r\n') line = buf.rstrip('\r\n')
@@ -1381,37 +1437,26 @@ def nonblock_read(fname):
def main(): def main():
thr.current_thread().name = 'main' thr.current_thread().name = 'main'
GLog.write('')
if GLog.ON and os.path.exists(GLog.LOGDIR):
shutil.rmtree(GLog.LOGDIR)
nthreads = int(vim.eval('s:update.threads')) nthreads = int(vim.eval('s:update.threads'))
plugs = vim.eval('s:update.todo') plugs = vim.eval('s:update.todo')
mac_gui = vim.eval('s:mac_gui') == '1' mac_gui = vim.eval('s:mac_gui') == '1'
is_win = vim.eval('s:is_win') == '1'
GLog.write('Plugs: {0}'.format(plugs))
GLog.write('PULL: {0}, WIN: {1}, MAC: {2}'.format(G_PULL, is_win, mac_gui))
GLog.write('Num Threads: {0}'.format(nthreads))
lock = thr.Lock() lock = thr.Lock()
buf = Buffer(lock, len(plugs), G_PULL, is_win) buf = Buffer(lock, len(plugs), G_PULL)
buf_q, work_q = queue.Queue(), queue.Queue() buf_q, work_q = queue.Queue(), queue.Queue()
for work in plugs.items(): for work in plugs.items():
work_q.put(work) work_q.put(work)
GLog.write('Starting Threads') start_cnt = thr.active_count()
global G_THREADS
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()
GLog.write('Buffer Writing Loop') while not buf_q.empty() or thr.active_count() != start_cnt:
while not buf_q.empty() or len(G_THREADS) != 0:
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)
@@ -1424,7 +1469,6 @@ def main():
if mac_gui: if mac_gui:
rthread.stop() rthread.stop()
rthread.join() rthread.join()
GLog.write('Cleanly Exited Main')
main() main()
EOF EOF
@@ -1455,16 +1499,20 @@ function! s:update_ruby()
def killall pid def killall pid
pids = [pid] pids = [pid]
unless `which pgrep 2> /dev/null`.empty? if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
children = pids pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil }
until children.empty? else
children = children.map { |pid| unless `which pgrep 2> /dev/null`.empty?
`pgrep -P #{pid}`.lines.map { |l| l.chomp } children = pids
}.flatten until children.empty?
pids += children children = children.map { |pid|
`pgrep -P #{pid}`.lines.map { |l| l.chomp }
}.flatten
pids += children
end
end end
pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
end end
pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
end end
require 'thread' require 'thread'
@@ -1490,7 +1538,7 @@ function! s:update_ruby()
$curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
$curbuf[2] = '[' + bar.ljust(tot) + ']' $curbuf[2] = '[' + bar.ljust(tot) + ']'
VIM::command('normal! 2G') VIM::command('normal! 2G')
VIM::command('redraw') unless iswin VIM::command('redraw')
} }
where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }
log = proc { |name, result, type| log = proc { |name, result, type|
@@ -1602,8 +1650,8 @@ function! s:update_ruby()
exists = File.directory? dir exists = File.directory? dir
ok, result = ok, result =
if exists if exists
dir = iswin ? dir : esc(dir) chdir = "#{cd} #{iswin ? dir : esc(dir)}"
ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil, nil ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil, nil
current_uri = data.lines.to_a.last current_uri = data.lines.to_a.last
if !ret if !ret
if data =~ /^Interrupted|^Timeout/ if data =~ /^Interrupted|^Timeout/
@@ -1619,7 +1667,7 @@ function! s:update_ruby()
if pull if pull
log.call name, 'Updating ...', :update log.call name, 'Updating ...', :update
fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : ''
bt.call "#{cd} #{dir} && git fetch #{fetch_opt} #{progress} 2>&1 && git checkout -q #{checkout} 2>&1 && git merge --ff-only #{merge} 2>&1 && #{subm}", name, :update, nil bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1 && git checkout -q #{checkout} 2>&1 && git merge --ff-only #{merge} 2>&1 && #{subm}", name, :update, nil
else else
[true, skip] [true, skip]
end end
@@ -1693,42 +1741,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) function! s:git_validate(spec, check_branch)
let ret = 1 let err = ''
let msg = 'OK'
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 err = join([remote, 'PlugClean required.'], "\n")
let ret = 0
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 err = 'Not found'
let ret = 0
endif endif
return [ret, msg] return err
endfunction endfunction
function! s:rm_rf(dir) function! s:rm_rf(dir)
@@ -1746,7 +1798,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
@@ -1780,10 +1832,7 @@ function! s:clean(force)
if empty(todo) if empty(todo)
call append(line('$'), 'Already clean.') call append(line('$'), 'Already clean.')
else else
call inputsave() if a:force || s:ask('Proceed?')
let yes = a:force || (input('Proceed? (y/N) ') =~? '^y')
call inputrestore()
if yes
for dir in todo for dir in todo
call s:rm_rf(dir) call s:rm_rf(dir)
endfor endfor
@@ -1839,7 +1888,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
@@ -1936,9 +1986,11 @@ function! s:preview_commit()
execute 'pedit' sha execute 'pedit' sha
wincmd P wincmd P
setlocal filetype=git buftype=nofile nobuflisted setlocal filetype=git buftype=nofile nobuflisted modifiable
execute 'silent read !cd' s:shellesc(g:plugs[name].dir) '&& git show --pretty=medium' sha execute 'silent read !cd' s:shellesc(g:plugs[name].dir) '&& git show --pretty=medium' sha
normal! gg"_dd normal! gg"_dd
setlocal nomodifiable
nnoremap <silent> <buffer> q :q<cr>
wincmd p wincmd p
endfunction endfunction
@@ -1946,41 +1998,63 @@ function! s:section(flags)
call search('\(^[x-] \)\@<=[^:]\+:', a:flags) call search('\(^[x-] \)\@<=[^:]\+:', a:flags)
endfunction endfunction
function! s:format_git_log(line)
let [sha, refs, subject, date] = split(a:line, nr2char(1))
let tag = matchstr(refs, 'tag: [^,)]\+')
let tag = empty(tag) ? ' ' : ' ('.tag.') '
return printf(' %s%s%s (%s)', sha, tag, subject, date)
endfunction
function! s:append_ul(lnum, text)
call append(a:lnum, ['', a:text, repeat('-', len(a:text))])
endfunction
function! s:diff() function! s:diff()
call s:prepare() call s:prepare()
call append(0, 'Collecting updated changes ...') call append(0, ['Collecting changes ...', ''])
normal! gg let cnts = [0, 0]
redraw let bar = ''
let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)')
let cnt = 0 call s:progress_bar(2, bar, len(total))
for [k, v] in items(g:plugs) for origin in [1, 0]
if !isdirectory(v.dir) || !s:is_managed(k) call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
continue for [k, v] in reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))'))))
endif let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..'
let diff = s:system_chomp('git log --pretty=format:"%h%x01%d%x01%s%x01%cr" '.s:shellesc(range), v.dir)
let diff = s:system_chomp('git log --pretty=format:"%h %s (%cr)" "HEAD...HEAD@{1}"', v.dir) if !empty(diff)
if !empty(diff) let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
call append(1, '') call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
call append(2, '- '.k.':') let cnts[origin] += 1
call append(3, map(s:lines(diff), '" ". v:val')) endif
let cnt += 1 let bar .= '='
normal! gg call s:progress_bar(2, bar, len(total))
normal! 2G
redraw redraw
endfor
if !cnts[origin]
call append(5, ['', 'N/A'])
endif endif
endfor endfor
call setline(1, printf('%d plugin(s) updated.', cnts[0])
\ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : ''))
call setline(1, cnt == 0 ? 'No updates.' : 'Last update:') if cnts[0] || cnts[1]
nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr> nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr>
nnoremap <silent> <buffer> o :silent! call <SID>preview_commit()<cr> nnoremap <silent> <buffer> o :silent! call <SID>preview_commit()<cr>
nnoremap <silent> <buffer> X :call <SID>revert()<cr> endif
normal! gg if cnts[0]
setlocal nomodifiable nnoremap <silent> <buffer> X :call <SID>revert()<cr>
if cnt > 0
echo "Press 'X' on each block to revert the update" echo "Press 'X' on each block to revert the update"
endif endif
normal! gg
setlocal nomodifiable
endfunction endfunction
function! s:revert() function! s:revert()
if search('^Pending updates', 'bnW')
return
endif
let name = s:find_name(line('.')) let name = s:find_name(line('.'))
if empty(name) || !has_key(g:plugs, name) || if empty(name) || !has_key(g:plugs, name) ||
\ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y'
@@ -1994,42 +2068,35 @@ function! s:revert()
echo 'Reverted.' echo 'Reverted.'
endfunction endfunction
function! s:snapshot(...) abort function! s:snapshot(force, ...) abort
let home = get(s:, 'plug_home_org', g:plug_home)
let [type, var, header] = s:is_win ?
\ ['dosbatch', '%PLUG_HOME%',
\ ['@echo off', ':: Generated by vim-plug', ':: '.strftime("%c"), '',
\ ':: Make sure to PlugUpdate first', '', 'set PLUG_HOME='.home]] :
\ ['sh', '$PLUG_HOME',
\ ['#!/bin/sh', '# Generated by vim-plug', '# '.strftime("%c"), '',
\ 'vim +PlugUpdate +qa', '', 'PLUG_HOME='.s:esc(home)]]
call s:prepare() call s:prepare()
execute 'setf' type setf vim
call append(0, header) call append(0, ['" Generated by vim-plug',
call append('$', '') \ '" '.strftime("%c"),
\ '" :source this file in vim to restore the snapshot',
\ '" or execute: vim -S snapshot.vim',
\ '', '', 'PlugUpdate!'])
1 1
redraw let anchor = line('$') - 3
let names = sort(keys(filter(copy(g:plugs),
let dirs = sort(map(values(filter(copy(g:plugs), \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)')))
\'has_key(v:val, "uri") && isdirectory(v:val.dir)')), 'v:val.dir')) for name in reverse(names)
let anchor = line('$') - 1 let sha = s:system_chomp('git rev-parse --short HEAD', g:plugs[name].dir)
for dir in reverse(dirs)
let sha = s:system_chomp('git rev-parse --short HEAD', dir)
if !empty(sha) if !empty(sha)
call append(anchor, printf('cd %s && git reset --hard %s', call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha))
\ substitute(dir, '^\V'.escape(g:plug_home, '\'), var, ''), sha))
redraw redraw
endif endif
endfor endfor
if a:0 > 0 if a:0 > 0
let fn = expand(a:1) let fn = expand(a:1)
let fne = s:esc(fn) if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?'))
return
endif
call writefile(getline(1, '$'), fn) call writefile(getline(1, '$'), fn)
if !s:is_win | call s:system('chmod +x ' . fne) | endif echo 'Saved as '.a:1
echo 'Saved to '.a:1 silent execute 'e' s:esc(fn)
silent execute 'e' fne setf vim
endif endif
endfunction endfunction

View File

@@ -263,3 +263,26 @@ Execute (#236: Plugin removed from &rtp when .vimrc is reloaded):
Plug 'junegunn/vim-easy-align', { 'on': 'EasyAlign' } Plug 'junegunn/vim-easy-align', { 'on': 'EasyAlign' }
call plug#end() call plug#end()
Assert &rtp =~ '/vim-easy-align', 'Plugin should still be in &rtp' Assert &rtp =~ '/vim-easy-align', 'Plugin should still be in &rtp'
**********************************************************************
Execute (#350: Ruby installer failed to unshallow tagged plugin on update):
call plug#begin('/tmp/plugged')
call plug#end()
PlugClean!
" Shallow clone. We should have at least 2 plugins to enable parallel installer.
call plug#begin('/tmp/plugged')
Plug 'junegunn/vim-easy-align'
Plug 'junegunn/seoul256.vim'
call plug#end()
PlugUpdate
Assert filereadable(g:plugs['vim-easy-align'].dir.'/.git/shallow')
" Now unshallowed
call plug#begin('/tmp/plugged')
Plug 'junegunn/vim-easy-align', { 'tag': '2.9.0' }
Plug 'junegunn/seoul256.vim'
call plug#end()
PlugUpdate
Assert !filereadable(g:plugs['vim-easy-align'].dir.'/.git/shallow')
q

View File

@@ -18,7 +18,7 @@ clone() {
fi fi
} }
clone_repos() { clone_repos() (
cd /tmp cd /tmp
mkdir -p junegunn vim-scripts jg mkdir -p junegunn vim-scripts jg
for repo in vader.vim goyo.vim rust.vim seoul256.vim vim-easy-align vim-fnr \ for repo in vader.vim goyo.vim rust.vim seoul256.vim vim-easy-align vim-fnr \
@@ -31,11 +31,9 @@ clone_repos() {
clone junegunn/vim-emoji jg/vim-emoji clone junegunn/vim-emoji jg/vim-emoji
cd junegunn/seoul256.vim && git checkout no-t_co && git checkout master cd junegunn/seoul256.vim && git checkout no-t_co && git checkout master
)
cd "$BASE" make_dirs() (
}
make_dirs() {
rm -rf "$PLUG_FIXTURES/$1" rm -rf "$PLUG_FIXTURES/$1"
mkdir -p "$PLUG_FIXTURES/$1" mkdir -p "$PLUG_FIXTURES/$1"
cd "$PLUG_FIXTURES/$1" cd "$PLUG_FIXTURES/$1"
@@ -51,9 +49,13 @@ make_dirs() {
call add(g:total_order, s:name) call add(g:total_order, s:name)
EOF EOF
done done
)
cd "$BASE" gitinit() (
} cd "$PLUG_FIXTURES/$1"
git init
git commit -m 'commit' --allow-empty
)
prepare() { prepare() {
make_dirs xxx/ xxx make_dirs xxx/ xxx
@@ -62,9 +64,11 @@ prepare() {
cat > "$PLUG_FIXTURES/xxx/doc/xxx.txt" << DOC cat > "$PLUG_FIXTURES/xxx/doc/xxx.txt" << DOC
hello *xxx* hello *xxx*
DOC DOC
gitinit xxx
make_dirs yyy/ yyy make_dirs yyy/ yyy
make_dirs yyy/after yyy make_dirs yyy/after yyy
gitinit yyy
make_dirs z1/ z1 make_dirs z1/ z1
make_dirs z2/ z2 make_dirs z2/ z2
@@ -85,13 +89,26 @@ DOC
cd "$BASE" cd "$BASE"
} }
select_vim() {
local vim=/usr/bin/vim
if [ -n "$DEPS" ] && [ -e "${DEPS}/bin/vim" ]; then
vim="${DEPS}/bin/vim"
elif [ -e "/usr/local/bin/vim" ]; then
vim=/usr/local/bin/vim
fi
echo $vim
}
clone_repos clone_repos
prepare prepare
VIM=$(select_vim)
echo "Selected Vim: $VIM"
if [ "$1" = '!' ]; then if [ "$1" = '!' ]; then
/usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'Vader! test.vader' > /dev/null && $VIM -Nu /tmp/mini-vimrc -c 'Vader! test.vader' > /dev/null &&
prepare && prepare &&
/usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'let g:plug_threads = 1 | Vader! test.vader' > /dev/null $VIM -Nu /tmp/mini-vimrc -c 'let g:plug_threads = 1 | Vader! test.vader' > /dev/null
else else
/usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'Vader test.vader' $VIM -Nu /tmp/mini-vimrc -c 'Vader test.vader'
fi fi

View File

@@ -262,12 +262,16 @@ Execute (PlugUpdate only to find out plugins are up-to-date, D key to check):
PlugUpdate PlugUpdate
AssertExpect 'Already up-to-date', 2 AssertExpect 'Already up-to-date', 2
normal D normal D
AssertEqual 'No updates.', getline(1) AssertEqual '0 plugin(s) updated.', getline(1)
q q
Execute (PlugDiff - 'No updates.'): Execute (PlugDiff - 'No updates.'):
PlugDiff PlugDiff
AssertEqual 'No updates.', getline(1) Log getline(1, '$')
AssertEqual '0 plugin(s) updated.', getline(1)
Assert empty(mapcheck('o'))
Assert empty(mapcheck('X'))
Assert empty(mapcheck("\<cr>"))
q q
Execute (New commits on remote, PlugUpdate, then PlugDiff): Execute (New commits on remote, PlugUpdate, then PlugDiff):
@@ -281,7 +285,7 @@ Execute (New commits on remote, PlugUpdate, then PlugDiff):
" Now we have updates " Now we have updates
normal D normal D
AssertEqual 'Last update:', getline(1) AssertEqual '2 plugin(s) updated.', getline(1)
" Preview commit " Preview commit
silent! wincmd P silent! wincmd P
@@ -352,6 +356,75 @@ Execute (Reuse Plug window in another tab):
q q
unlet tabnr unlet tabnr
Execute (contd. PlugDiff should not show inverted history):
" Additional PlugUpdate to clear diff
PlugUpdate
PlugDiff
Log getline(1, '$')
" Checking out older revisions
for repo in values(g:plugs)
call system(printf('cd %s && git reset HEAD^ --hard', shellescape(repo.dir)))
endfor
unlet repo
" PlugDiff should not report the changes i.e. git log --left-only
PlugDiff
Log getline(1, '$')
AssertEqual '0 plugin(s) updated.', getline(1)
q
**********************************************************************
~ PlugDiff to see the pending changes
**********************************************************************
Execute (PlugDiff):
call plug#begin()
call plug#end()
PlugClean!
call plug#begin()
Plug 'file://'.expand('$PLUG_FIXTURES').'/xxx'
Plug 'file://'.expand('$PLUG_FIXTURES').'/yyy'
call plug#end()
PlugInstall
Log getline(1, '$')
call system('cd "$PLUG_FIXTURES/xxx" && git commit --allow-empty -m update-xxx && git tag -f xxx')
call system('cd "$PLUG_FIXTURES/yyy" && git tag -f yyy && git commit --allow-empty -m update-yyy && git tag -f zzz')
let g:plugs.yyy.tag = 'yyy'
PlugUpdate
Log getline(1, '$')
PlugDiff
" 1 plugin(s) updated. 1 plugin(s) have pending updates.
" [==]
"
" Last update:
" ------------
"
" - xxx:
" 166cfff (tag: xxx) update-xxx (1 second ago)
"
" Pending updates:
" ----------------
"
" - yyy: (tag: yyy)
" c0a064b (tag: zzz) update-yyy (1 second ago)
"
Log getline(1, '$')
AssertEqual 15, line('$')
AssertEqual '1 plugin(s) updated. 1 plugin(s) have pending updates.', getline(1)
AssertEqual '[==]', getline(2)
AssertEqual '- yyy: (tag: yyy)', getline(13)
Assert getline(8) =~ '(tag: xxx)'
Assert getline(14) =~ '(tag: zzz)'
Assert !empty(mapcheck('o'))
Assert !empty(mapcheck('X'))
Assert !empty(mapcheck("\<cr>"))
q
********************************************************************** **********************************************************************
~ On-demand loading / Partial installation/update ~ ~ On-demand loading / Partial installation/update ~
********************************************************************** **********************************************************************
@@ -756,6 +829,50 @@ Execute (Using Funcref):
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclunchanged13'), Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclunchanged13'),
\ 'vim-pseudocl/vim-pseudoclunchanged13 should exist' \ 'vim-pseudocl/vim-pseudoclunchanged13 should exist'
Execute (Post-update hook output; success and failure):
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': 'xxx-non-existent-command-xxx' }
Plug 'junegunn/vim-pseudocl', { 'do': 'true' }
call plug#end()
silent PlugInstall! 1
AssertEqual '- Post-update hook for vim-pseudocl ... OK', getline(5)
AssertEqual 'x Post-update hook for vim-easy-align ... Exit status: 127', getline(6)
q
Execute (Post-update hook output; invalid type or funcref):
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': 1 }
Plug 'junegunn/vim-pseudocl', { 'do': function('call') }
call plug#end()
silent PlugInstall! 1
AssertEqual 'x Post-update hook for vim-pseudocl ... Vim(call):E119: Not enough arguments for function: call', getline(5)
AssertEqual 'x Post-update hook for vim-easy-align ... Invalid hook type', getline(6)
q
Execute (Should not run when failed to update):
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': 'touch failed' }
Plug 'junegunn/vim-pseudocl', { 'do': 'touch not-failed' }
call plug#end()
" Invalid remote URL
call system(printf('cd %s && git remote set-url origin xxx', g:plugs['vim-easy-align'].dir))
" New commits on remote
call system('cd /tmp/junegunn/vim-easy-align && git commit --allow-empty -m "update"')
call system('cd /tmp/junegunn/vim-pseudocl && git commit --allow-empty -m "update"')
silent PlugUpdate
Log getline(1, '$')
q
Assert !filereadable(g:plugs['vim-easy-align'].dir.'/failed'),
\ 'vim-easy-align/failed should not exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/not-failed'),
\ 'vim-pseudocl/not-failed should exist'
********************************************************************** **********************************************************************
~ Overriding `dir` ~ Overriding `dir`
********************************************************************** **********************************************************************
@@ -823,7 +940,7 @@ Execute (Filetype-based on-demand loading):
AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx
setf xxx setf xxx
AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/ftplugin', 'xxx/after/ftplugin', 'xxx/indent', 'xxx/after/indent', 'xxx/syntax', 'xxx/after/syntax'], g:xxx AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/syntax', 'xxx/after/syntax', 'xxx/ftplugin', 'xxx/after/ftplugin', 'xxx/indent', 'xxx/after/indent', 'xxx/syntax', 'xxx/after/syntax'], g:xxx
Before: Before:
@@ -1096,17 +1213,22 @@ Execute (PlugSnapshot / #154 issues with paths containing spaces):
PlugInstall PlugInstall
call plug#load('vim-easy-align') " Should properly handle paths with spaces call plug#load('vim-easy-align') " Should properly handle paths with spaces
PlugSnapshot PlugSnapshot
AssertEqual '#!/bin/sh', getline(1) AssertEqual '" Generated by vim-plug', getline(1)
AssertEqual '# Generated by vim-plug', getline(2) AssertEqual 0, stridx(getline(6), "silent! let g:plugs['seoul256.vim'].commit = '")
AssertEqual 'vim +PlugUpdate +qa', getline(5) AssertEqual 0, stridx(getline(7), "silent! let g:plugs['vim-easy-align'].commit = '")
AssertEqual 'PLUG_HOME=$TMPDIR/plug\ with\ spaces', getline(7) AssertEqual 'vim', &filetype
AssertEqual 0, stridx(getline(9), 'cd $PLUG_HOME/seoul256.vim/ && git reset --hard')
AssertEqual 0, stridx(getline(10), 'cd $PLUG_HOME/vim-easy-align/ && git reset --hard')
AssertEqual 'sh', &filetype
execute 'PlugSnapshot' g:plug_home.'/snapshot.sh' call delete(g:plug_home.'/snapshot.vim')
AssertEqual 'sh', &filetype execute 'PlugSnapshot' escape(g:plug_home.'/snapshot.vim', ' ')
AssertEqual 'snapshot.sh', fnamemodify(expand('%'), ':t') AssertEqual 'vim', &filetype
AssertEqual 'snapshot.vim', fnamemodify(expand('%'), ':t')
q
Execute(PlugSnapshot! to overwrite existing file):
call writefile(['foobar'], g:plug_home.'/snapshot.vim')
AssertEqual 'foobar', readfile(g:plug_home.'/snapshot.vim')[0]
execute 'PlugSnapshot!' escape(g:plug_home.'/snapshot.vim', ' ')
AssertEqual '" Generated by vim-plug', readfile(g:plug_home.'/snapshot.vim')[0]
q q
********************************************************************** **********************************************************************
@@ -1166,3 +1288,56 @@ Execute (#221 Shallow-clone disabled by tag):
Assert !filereadable('.git/shallow') Assert !filereadable('.git/shallow')
cd - cd -
Execute (Commit hash support):
call plug#begin(g:temp_plugged)
Plug 'junegunn/goyo.vim', { 'commit': 'ffffffff' }
Plug 'junegunn/vim-emoji', { 'commit': '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a' }
call plug#end()
PlugUpdate
Log getline(1, '$')
AssertEqual ['x Checking out fffffff of goyo.vim ... Error',
\' error: pathspec ''ffffffff'' did not match any file(s) known to git.',
\'- Checking out 9db7fcf of vim-emoji ... OK'], getline(5, 7)
let hash = system(printf('cd %s && git rev-parse HEAD', g:plugs['vim-emoji'].dir))[:-2]
AssertEqual '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a', hash
" Validate error formatting
PlugStatus
Log getline(1, '$')
AssertEqual ['Finished. 1 error(s).',
\'[==]',
\'',
\'x goyo.vim:'], getline(1, 4)
Assert getline(5) =~ ' Invalid HEAD (expected: fffffff, actual: [0-9a-f]\{7})'
AssertEqual [' PlugUpdate required.',
\'- vim-emoji: OK'], getline(6, '$')
" PlugDiff should show pending updates for vim-emoji
PlugDiff
Log getline(1, '$')
AssertEqual '0 plugin(s) updated. 1 plugin(s) have pending updates.', getline(1)
Assert !empty(mapcheck('o'))
Assert empty(mapcheck('X'))
Assert !empty(mapcheck("\<cr>"))
" Nor in PlugSnapshot output
PlugSnapshot
Log getline(1, '$')
AssertEqual 8, line('$')
q
Execute (Commit hash support - cleared):
call plug#begin(g:temp_plugged)
Plug 'junegunn/goyo.vim'
Plug 'junegunn/vim-emoji'
call plug#end()
PlugInstall
let hash = system(printf('cd %s && git rev-parse HEAD', g:plugs['vim-emoji'].dir))[:-2]
AssertEqual '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a', hash
PlugUpdate
let hash = system(printf('cd %s && git rev-parse HEAD', g:plugs['vim-emoji'].dir))[:-2]
AssertNotEqual '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a', hash
q