45 Commits
0.4.0 ... 0.5.2

Author SHA1 Message Date
Junegunn Choi
93628b1c3d Forced run of post-update hooks using bang commands
PlugInstall! / PlugUpdate!
2014-08-02 12:13:52 +09:00
Junegunn Choi
01e126469b Remove duplicate expression and escape helptags directory 2014-08-02 02:52:56 +09:00
Junegunn Choi
a7477f04b7 Update README 2014-08-02 01:12:01 +09:00
Junegunn Choi
0fdb56ba72 Update README 2014-08-02 01:00:59 +09:00
Junegunn Choi
d89949f16c Update README.md 2014-08-01 23:46:50 +09:00
Junegunn Choi
19b8221c14 Update README 2014-08-01 23:37:19 +09:00
Junegunn Choi
336fadd236 Remove FAQ/Troubleshooting section and add link to wiki page 2014-08-01 23:33:26 +09:00
Junegunn Choi
a216e38a59 Merge pull request #44 from FriedSock/test_refactoring
Force use of bash for Vader tests.
2014-08-01 23:26:26 +09:00
Jack Bracewell
d930594686 Force use of bash for Vader tests.
If not using a bash compatible shell (like fish), then this will be
set as the default Vim shell. Leading to half the tests failing with
E484: CAN’T OPEN FILE
2014-08-01 15:16:21 +01:00
Junegunn Choi
f4261711ae Update README 2014-08-01 02:01:31 +09:00
Junegunn Choi
61b77bc8e8 Fix many subtle issues regarding on-demand loading etc.
- On-demand loading
    - Fix loading of unwanted files (e.g. colors/*.vim, syntax/*.vim, etc.)
- Filetyp-based on-demand loading
    - Load `after/ftdetect` as well
    - Make sure indent files are loaded by invoking
      `doautocmd filetypeindent FileType`
- Ensure plugin loaded when it was added after Vim started
- Do not reload $MYVIMRC after installtion/update
    - Instead simply call plug#end()
2014-07-31 16:34:41 +09:00
Junegunn Choi
fe7c7e7b40 Minor tweaks 2014-07-31 03:04:59 +09:00
Junegunn Choi
25afdf138c Refactoring
- Remove dead code
- Extract method
2014-07-31 01:01:59 +09:00
Junegunn Choi
b36fd34da0 Ensure files under after are loaded when first installed 2014-07-31 00:17:21 +09:00
Junegunn Choi
7e55690f19 Update examples 2014-07-30 20:00:21 +09:00
Junegunn Choi
30ef53d832 Remove support for experiemental dependency resolution (#43)
🎉
2014-07-30 19:52:19 +09:00
Junegunn Choi
f58d090bb2 Add dir option: managed plugins outside g:plug_home 2014-07-30 19:20:51 +09:00
Junegunn Choi
eeef77e9c8 Merge branch 'vheon-refactoring' into refactoring 2014-07-29 23:37:47 +09:00
Andrea Cedraro
6af2cd8946 Inline substitute inside s:dirpath() 2014-07-29 14:21:11 +02:00
Junegunn Choi
878cdd5309 Unmap / and ? from vim-oblique after test 2014-07-29 19:18:33 +09:00
Junegunn Choi
9bb2da53a0 Replace s:extract_name with a single fnamemodify call 2014-07-29 19:17:12 +09:00
Junegunn Choi
58c06ed77e Use single-quotes whenever possible for consistency 2014-07-29 19:07:09 +09:00
Junegunn Choi
2e691c6feb Define a separate version of s:is_local_plug for Windows 2014-07-29 10:09:05 +09:00
Junegunn Choi
a18087610a Use fnamemodify instead of split hackery
Simpler and faster
2014-07-29 02:42:53 +09:00
Junegunn Choi
276106d987 Performance tuning: reduce the number of s:parse_options calls 2014-07-29 02:11:59 +09:00
Junegunn Choi
d499fc311a Use dot operator instead of get()
The reason I used get() instead of concise dot operator when accessing
`frozen` and `local` properties of plugin spec was to avoid errors when
a user "PlugUpgrade" from an old version of vim-plug whose g:plugs does
not have those properties. Added the code to patch the old version of
g:plugs so that we can safely use dot operators.
2014-07-29 01:51:32 +09:00
Junegunn Choi
c4b4aa8f07 Code cleanup: reuse s:trim() when possible 2014-07-29 00:19:29 +09:00
Junegunn Choi
d690f8d576 Change error reporting method
As suggested by @vheon:
https://github.com/junegunn/vim-plug/pull/40#issuecomment-50278543
2014-07-28 19:56:59 +09:00
Junegunn Choi
8738341ad0 Performance tuning: reduce the number of globpath calls 2014-07-28 19:45:40 +09:00
Junegunn Choi
5ab2024fbb Performace tuning: inlining some function calls 2014-07-28 19:41:05 +09:00
Junegunn Choi
300176ba9f Avoid echoerr inside catch block 2014-07-28 01:27:30 +09:00
Andrea Cedraro
da7d6bd58b Refactor s:add function 2014-07-27 17:38:57 +02:00
Junegunn Choi
b651558c63 Update README 2014-07-27 12:00:36 +09:00
Junegunn Choi
2d815ad2f0 Escape angle brackets in README 2014-07-27 11:58:12 +09:00
Junegunn Choi
3af4079179 Fix typo 2014-07-27 11:55:06 +09:00
Junegunn Choi
e6a594f1ad Change post-hook function to take a dictionary for more control 2014-07-27 11:28:53 +09:00
Junegunn Choi
e741d02ad0 Fix elapsed time to include the time spent in post-update hook 2014-07-27 11:15:13 +09:00
Junegunn Choi
b2208640d4 Update documentation 2014-07-27 11:06:47 +09:00
Junegunn Choi
aa49c38586 Don't need <Plug> map (#38) 2014-07-27 03:16:44 +09:00
Junegunn Choi
b6b10ac17e Print progress of post-update hooks using :! (#38) 2014-07-27 03:07:37 +09:00
Junegunn Choi
706f7e00ea Merge pull request #39 from vheon/fix-type-parameter-clarity
Replace return value of type() with call to the function
2014-07-27 02:22:31 +09:00
Andrea Cedraro
6ff1031339 Replace return value of type() with named values 2014-07-26 19:14:46 +02:00
Junegunn Choi
0936877399 Don't check for the need for post-update hook when interrupted 2014-07-27 00:42:23 +09:00
Junegunn Choi
d956e16f15 Minor refactoring 2014-07-26 22:58:34 +09:00
Junegunn Choi
f98c8456fa Post-update hook (do option) 2014-07-26 22:49:18 +09:00
4 changed files with 606 additions and 369 deletions

148
README.md
View File

@@ -1,26 +1,22 @@
![vim-plug](https://raw.github.com/junegunn/vim-plug/master/plug.png) ![vim-plug](https://raw.github.com/junegunn/vim-plug/master/plug.png)
![travis-ci](https://travis-ci.org/junegunn/vim-plug.svg?branch=master) ![travis-ci](https://travis-ci.org/junegunn/vim-plug.svg?branch=master)
A single-file Vim plugin manager. A minimalist Vim plugin manager.
Somewhere between [Pathogen](https://github.com/tpope/vim-pathogen) and
[Vundle](https://github.com/gmarik/vundle), but with faster parallel installer.
![](https://raw.github.com/junegunn/i/master/vim-plug/installer.gif) ![](https://raw.github.com/junegunn/i/master/vim-plug/installer.gif)
### Pros. ### Pros.
- Easier to setup - Easier to setup: Single file. No boilerplate code required.
- Parallel installation/update (requires - Easier to use: Concise, intuitive syntax
[+ruby](http://junegunn.kr/2013/09/installing-vim-with-ruby-support/)) - [Super-fast](https://raw.github.com/junegunn/i/master/vim-plug/40-in-4.gif)
- Smallest possible feature set parallel installation/update (requires
- Branch/tag support [+ruby](https://github.com/junegunn/vim-plug/wiki/ruby))
- On-demand loading - On-demand loading to achieve
- Dependency resolution using `Plugfile` (experimental) [fast startup time](http://junegunn.kr/images/vim-startup-time.png)
- Post-update hooks
### Cons. - Can choose a specific branch or tag for each plugin
- Support for externally managed plugins
- Everything else
### Usage ### Usage
@@ -51,8 +47,11 @@ Plug 'https://github.com/junegunn/vim-github-dashboard.git'
" Plugin options " Plugin options
Plug 'nsf/gocode', { 'tag': 'go.weekly.2012-03-13', 'rtp': 'vim' } Plug 'nsf/gocode', { 'tag': 'go.weekly.2012-03-13', 'rtp': 'vim' }
" Locally-managed plugin " Plugin outside ~/.vim/plugged with post-update hook
Plug '~/.fzf' Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': 'yes \| ./install' }
" Unmanaged plugin (manually installed and updated)
Plug '~/my-prototype-plugin'
call plug#end() call plug#end()
``` ```
@@ -76,7 +75,9 @@ Reload .vimrc and `:PlugInstall` to install plugins.
| -------------- | -------------------------------------------------------------------- | | -------------- | -------------------------------------------------------------------- |
| `branch`/`tag` | Branch or tag of the repository to use | | `branch`/`tag` | Branch or tag of the repository to use |
| `rtp` | Subdirectory that contains Vim plugin | | `rtp` | Subdirectory that contains Vim plugin |
| `on` | On-demand loading: Commands or <Plug>-mappings | | `dir` | Custom directory for the plugin |
| `do` | Post-update hook (string or funcref) |
| `on` | On-demand loading: Commands or `<Plug>`-mappings |
| `for` | On-demand loading: File types | | `for` | On-demand loading: File types |
| `frozen` | Do not install/update plugin unless explicitly given as the argument | | `frozen` | Do not install/update plugin unless explicitly given as the argument |
@@ -119,71 +120,62 @@ Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
Plug 'junegunn/vader.vim', { 'on': 'Vader', 'for': 'vader' } Plug 'junegunn/vader.vim', { 'on': 'Vader', 'for': 'vader' }
``` ```
### Dependency resolution ### Post-update hooks
See [Dependency There are some plugins that require extra steps after installation or update.
Resolution](https://github.com/junegunn/vim-plug/wiki/Dependency-Resolution). In that case, use `do` option to describe the task to be performed.
```vim
Plug 'Valloric/YouCompleteMe', { 'do': './install.sh' }
```
If you need more control, you can pass a reference to a Vim function that
takes a single argument.
```vim
function! BuildYCM(info)
" info is a dictionary with 3 fields
" - name: name of the plugin
" - status: 'installed', 'updated', or 'unchanged'
" - force: set on PlugInstall! or PlugUpdate!
if a:info.status == 'installed' || a:info.force
!./install.sh
endif
endfunction
Plug 'Valloric/YouCompleteMe', { 'do': function('BuildYCM') }
```
Both forms of post-update hook are executed inside the directory of the plugin
and only run when the repository has changed, but you can force it to run
unconditionally with the bang-versions of the commands: `PlugInstall!` and
`PlugUpdate!`.
Make sure to escape BARs when you write `do` option inline as they are
mistakenly recognized as command separator for Plug command.
```vim
Plug 'junegunn/fzf', { 'do': 'yes \| ./install' }
```
But you can avoid the escaping if you extract the inline specification using a
variable (or any Vimscript expression) as follows:
```vim
let g:fzf_install = 'yes | ./install'
Plug 'junegunn/fzf', { 'do': g:fzf_install }
```
### FAQ/Troubleshooting
See [FAQ/Troubleshooting](https://github.com/junegunn/vim-plug/wiki/faq).
### Articles ### Articles
- [Writing my own Vim plugin manager](http://junegunn.kr/2013/09/writing-my-own-vim-plugin-manager) - [Writing my own Vim plugin manager](http://junegunn.kr/2013/09/writing-my-own-vim-plugin-manager)
- [Thoughts on Vim plugin dependency](http://junegunn.kr/2013/09/thoughts-on-vim-plugin-dependency) - [Vim plugins and startup time](http://junegunn.kr/2014/07/vim-plugins-and-startup-time)
- ~~[Thoughts on Vim plugin dependency](http://junegunn.kr/2013/09/thoughts-on-vim-plugin-dependency)~~
### FAQ/Troubleshooting - *Support for Plugfile has been removed since 0.5.0*
#### Plugins are not installed/updated in parallel
Your Vim does not support Ruby interface. `:echo has('ruby')` should print 1.
In order to setup Vim with Ruby support, you may refer to [this
article](http://junegunn.kr/2013/09/installing-vim-with-ruby-support).
#### *Vim: Caught deadly signal SEGV*
If your Vim crashes with the above message, first check if its Ruby interface is
working correctly with the following command:
```vim
:ruby puts RUBY_VERSION
```
If Vim crashes even with this command, it is likely that Ruby interface is
broken, and you have to rebuild Vim with a working version of Ruby.
(`brew remove vim && brew install vim` or `./configure && make ...`)
If you're on OS X, one possibility is that you had installed Vim with
[Homebrew](http://brew.sh/) while using a Ruby installed with
[RVM](http://rvm.io/) or [rbenv](https://github.com/sstephenson/rbenv) and later
removed that version of Ruby.
[Please let me know](https://github.com/junegunn/vim-plug/issues) if you can't
resolve the problem. In the meantime, you can set `g:plug_threads` to 1, so that
Ruby installer is not used at all.
#### Errors on fish shell
If vim-plug doesn't work correctly on fish shell, you might need to add `set
shell=/bin/sh` to your .vimrc.
Refer to the following links for the details:
- http://badsimplicity.com/vim-fish-e484-cant-open-file-tmpvrdnvqe0-error/
- https://github.com/junegunn/vim-plug/issues/12
#### Freezing plugin version with commit hash
vim-plug does not allow you to freeze the version of a plugin with its commit
hash. This is by design. I don't believe a user of a plugin should be looking
at its individual commits. Instead, one should be choosing the right version
using release tags or versioned branches (e.g. 1.2.3, stable, devel, etc.)
```vim
Plug 'junegunn/vim-easy-align', '2.9.2'
```
If the repository doesn't come with such tags or branches, you should think of
it as "unstable" or "in development", and always use its latest revision.
If you really must choose a certain untagged revision, consider forking the
repository.
### License ### License

429
plug.vim
View File

@@ -9,19 +9,32 @@
" "
" Edit your .vimrc " Edit your .vimrc
" "
" call plug#begin() " call plug#begin('~/.vim/plugged')
" "
" " Make sure you use single quotes
" Plug 'junegunn/seoul256.vim' " Plug 'junegunn/seoul256.vim'
" Plug 'junegunn/vim-easy-align' " Plug 'junegunn/vim-easy-align'
" Plug 'junegunn/goyo.vim', { 'on': 'Goyo' } "
" " Plug 'user/repo1', 'branch_or_tag' " " On-demand loading
" " Plug 'user/repo2', { 'rtp': 'vim/plugin/dir', 'branch': 'branch_or_tag' } " Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' }
" " ... " Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
"
" " Using git URL
" Plug 'https://github.com/junegunn/vim-github-dashboard.git'
"
" " Plugin options
" Plug 'nsf/gocode', { 'tag': 'go.weekly.2012-03-13', 'rtp': 'vim' }
"
" " Plugin outside ~/.vim/plugged with post-update hook
" Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': 'yes \| ./install' }
"
" " Unmanaged plugin (manually installed and updated)
" Plug '~/my-prototype-plugin'
" "
" call plug#end() " call plug#end()
" "
" Then :PlugInstall to install plugins. (default: ~/.vim/plugged) " Then reload .vimrc and :PlugInstall to install plugins.
" You can change the location of the plugins with plug#begin(path) call. " Visit https://github.com/junegunn/vim-plug for more information.
" "
" "
" Copyright (c) 2014 Junegunn Choi " Copyright (c) 2014 Junegunn Choi
@@ -56,11 +69,17 @@ let s:cpo_save = &cpo
set cpo&vim set cpo&vim
let s:plug_source = 'https://raw.github.com/junegunn/vim-plug/master/plug.vim' let s:plug_source = 'https://raw.github.com/junegunn/vim-plug/master/plug.vim'
let s:plug_file = 'Plugfile'
let s:plug_buf = -1 let s:plug_buf = -1
let s:mac_gui = has('gui_macvim') && has('gui_running') let s:mac_gui = has('gui_macvim') && has('gui_running')
let s:is_win = has('win32') || has('win64') let s:is_win = has('win32') || has('win64')
let s:me = expand('<sfile>:p') let s:me = expand('<sfile>:p')
let s:base_spec = { 'branch': 'master', 'frozen': 0 }
let s:TYPE = {
\ 'string': type(''),
\ 'list': type([]),
\ 'dict': type({}),
\ 'funcref': type(function('call'))
\ }
function! plug#begin(...) function! plug#begin(...)
if a:0 > 0 if a:0 > 0
@@ -70,21 +89,18 @@ function! plug#begin(...)
elseif !empty(&rtp) elseif !empty(&rtp)
let home = s:path(split(&rtp, ',')[0]) . '/plugged' let home = s:path(split(&rtp, ',')[0]) . '/plugged'
else else
echoerr "Unable to determine plug home. Try calling plug#begin() with a path argument." return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')
return 0
endif endif
if !isdirectory(home) if !isdirectory(home)
try try
call mkdir(home, 'p') call mkdir(home, 'p')
catch catch
echoerr 'Invalid plug directory: '. home return s:err('Invalid plug directory: '. home)
return 0
endtry endtry
endif endif
if !executable('git') if !executable('git')
echoerr "`git' executable not found. vim-plug requires git." return s:err('`git` executable not found. vim-plug requires git.')
return 0
endif endif
let g:plug_home = home let g:plug_home = home
@@ -92,11 +108,11 @@ function! plug#begin(...)
" we want to keep track of the order plugins where registered. " we want to keep track of the order plugins where registered.
let g:plugs_order = [] let g:plugs_order = []
command! -nargs=+ -bar Plug call s:add(1, <args>) command! -nargs=+ -bar Plug call s:add(<args>)
command! -nargs=* -complete=customlist,s:names PlugInstall call s:install(<f-args>) command! -nargs=* -bang -complete=customlist,s:names PlugInstall call s:install(!empty('<bang>'), <f-args>)
command! -nargs=* -complete=customlist,s:names PlugUpdate call s:update(<f-args>) command! -nargs=* -bang -complete=customlist,s:names PlugUpdate call s:update(!empty('<bang>'), <f-args>)
command! -nargs=0 -bang PlugClean call s:clean('<bang>' == '!') command! -nargs=0 -bang PlugClean call s:clean('<bang>' == '!')
command! -nargs=0 PlugUpgrade if s:upgrade() | execute "source ". s:me | endif command! -nargs=0 PlugUpgrade if s:upgrade() | call s:upgrade_specs() | execute 'source '. s:me | endif
command! -nargs=0 PlugStatus call s:status() command! -nargs=0 PlugStatus call s:status()
command! -nargs=0 PlugDiff call s:diff() command! -nargs=0 PlugDiff call s:diff()
@@ -104,18 +120,22 @@ function! plug#begin(...)
endfunction endfunction
function! s:to_a(v) function! s:to_a(v)
return type(a:v) == 3 ? a:v : [a:v] return type(a:v) == s:TYPE.list ? a:v : [a:v]
endfunction
function! s:source(from, ...)
for pattern in a:000
for vim in split(globpath(a:from, pattern), '\n')
execute 'source '.vim
endfor
endfor
endfunction endfunction
function! plug#end() function! plug#end()
let reload = !has('vim_starting')
if !exists('g:plugs') if !exists('g:plugs')
echoerr 'Call plug#begin() first' return s:err('Call plug#begin() first')
return
endif endif
let keys = keys(g:plugs)
while !empty(keys)
let keys = keys(s:extend(keys))
endwhile
if exists('#PlugLOD') if exists('#PlugLOD')
augroup PlugLOD augroup PlugLOD
@@ -133,34 +153,35 @@ function! plug#end()
for name in reverse(copy(g:plugs_order)) for name in reverse(copy(g:plugs_order))
let plug = g:plugs[name] let plug = g:plugs[name]
if !has_key(plug, 'on') && !has_key(plug, 'for') if !has_key(plug, 'on') && !has_key(plug, 'for')
call s:add_rtp(s:rtp(plug)) let rtp = s:rtp(plug)
call s:add_rtp(rtp)
if reload
call s:source(rtp, 'plugin/**/*.vim', 'after/plugin/**/*.vim')
endif
continue continue
endif endif
if has_key(plug, 'on') if has_key(plug, 'on')
let commands = s:to_a(plug.on) for cmd in s:to_a(plug.on)
for cmd in commands
if cmd =~ '^<Plug>.\+' if cmd =~ '^<Plug>.\+'
if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i'))
for [mode, map_prefix, key_prefix] in for [mode, map_prefix, key_prefix] in
\ [['i', "<C-O>", ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] \ [['i', '<C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']]
execute printf( execute printf(
\ "%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, '%s')<CR>", \ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, "%s")<CR>',
\ mode, cmd, map_prefix, string(cmd), string(name), key_prefix) \ mode, cmd, map_prefix, string(cmd), string(name), key_prefix)
endfor endfor
endif endif
elseif !exists(':'.cmd) elseif !exists(':'.cmd)
execute printf( execute printf(
\ "command! -nargs=* -range -bang %s call s:lod_cmd(%s, '<bang>', <line1>, <line2>, <q-args>, %s)", \ 'command! -nargs=* -range -bang %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)',
\ cmd, string(cmd), string(name)) \ cmd, string(cmd), string(name))
endif endif
endfor endfor
endif endif
if has_key(plug, 'for') if has_key(plug, 'for')
for vim in split(globpath(s:rtp(plug), 'ftdetect/**/*.vim'), '\n') call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim')
execute 'source '.vim
endfor
for key in s:to_a(plug.for) for key in s:to_a(plug.for)
if !has_key(lod, key) if !has_key(lod, key)
let lod[key] = [] let lod[key] = []
@@ -181,42 +202,60 @@ function! plug#end()
syntax on syntax on
endfunction endfunction
function! s:trim(str)
return substitute(a:str, '[\/]\+$', '', '')
endfunction
if s:is_win if s:is_win
function! s:rtp(spec) function! s:rtp(spec)
let rtp = s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
return substitute(rtp, '\\*$', '', '')
endfunction endfunction
function! s:path(path) function! s:path(path)
return substitute(substitute(a:path, '/', '\', 'g'), '[/\\]*$', '', '') return s:trim(substitute(a:path, '/', '\', 'g'))
endfunction endfunction
function! s:dirpath(path) function! s:dirpath(path)
return s:path(a:path) . '\' return s:path(a:path) . '\'
endfunction endfunction
function! s:is_local_plug(repo)
return a:repo =~? '^[a-z]:'
endfunction
else else
function! s:rtp(spec) function! s:rtp(spec)
return s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) return s:dirpath(a:spec.dir . get(a:spec, 'rtp', ''))
endfunction endfunction
function! s:path(path) function! s:path(path)
return substitute(a:path, '[/\\]*$', '', '') return s:trim(a:path)
endfunction endfunction
function! s:dirpath(path) function! s:dirpath(path)
return s:path(a:path) . '/' return substitute(a:path, '[/\\]*$', '/', '')
endfunction
function! s:is_local_plug(repo)
return a:repo[0] =~ '[/$~]'
endfunction endfunction
endif endif
function! s:err(msg)
echohl ErrorMsg
echom a:msg
echohl None
return 0
endfunction
function! s:esc(path) function! s:esc(path)
return substitute(a:path, ' ', '\\ ', 'g') return substitute(a:path, ' ', '\\ ', 'g')
endfunction endfunction
function! s:add_rtp(rtp) function! s:add_rtp(rtp)
execute "set rtp^=".s:esc(a:rtp) execute 'set rtp^='.s:esc(a:rtp)
let after = globpath(a:rtp, 'after') let after = globpath(a:rtp, 'after')
if isdirectory(after) if isdirectory(after)
execute "set rtp+=".s:esc(after) execute 'set rtp+='.s:esc(after)
endif endif
endfunction endfunction
@@ -235,32 +274,31 @@ function! s:lod(plug, types)
let rtp = s:rtp(a:plug) let rtp = s:rtp(a:plug)
call s:add_rtp(rtp) call s:add_rtp(rtp)
for dir in a:types for dir in a:types
for vim in split(globpath(rtp, dir.'/**/*.vim'), '\n') call s:source(rtp, dir.'/**/*.vim')
execute 'source '.vim
endfor
endfor endfor
endfunction endfunction
function! s:lod_ft(pat, names) function! s:lod_ft(pat, names)
for name in a:names for name in a:names
call s:lod(g:plugs[name], ['plugin', 'after']) call s:lod(g:plugs[name], ['plugin', 'after/plugin'])
endfor endfor
call s:reorg_rtp() call s:reorg_rtp()
execute 'autocmd! PlugLOD FileType ' . a:pat execute 'autocmd! PlugLOD FileType ' . a:pat
silent! doautocmd filetypeplugin FileType silent! doautocmd filetypeplugin FileType
silent! doautocmd filetypeindent FileType
endfunction endfunction
function! s:lod_cmd(cmd, bang, l1, l2, args, name) function! s:lod_cmd(cmd, bang, l1, l2, args, name)
execute 'delc '.a:cmd execute 'delc '.a:cmd
call s:lod(g:plugs[a:name], ['plugin', 'ftdetect', 'after']) call s:lod(g:plugs[a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
call s:reorg_rtp() call s:reorg_rtp()
execute printf("%s%s%s %s", (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
endfunction endfunction
function! s:lod_map(map, name, prefix) function! s:lod_map(map, name, prefix)
execute 'unmap '.a:map execute 'unmap '.a:map
execute 'iunmap '.a:map execute 'iunmap '.a:map
call s:lod(g:plugs[a:name], ['plugin', 'ftdetect', 'after']) call s:lod(g:plugs[a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
call s:reorg_rtp() call s:reorg_rtp()
let extra = '' let extra = ''
while 1 while 1
@@ -273,75 +311,75 @@ function! s:lod_map(map, name, prefix)
call feedkeys(a:prefix . substitute(a:map, '^<Plug>', "\<Plug>", '') . extra) call feedkeys(a:prefix . substitute(a:map, '^<Plug>', "\<Plug>", '') . extra)
endfunction endfunction
function! s:add(force, ...) function! s:add(repo, ...)
let opts = { 'branch': 'master', 'frozen': 0 } if a:0 > 1
if a:0 == 1 return s:err('Invalid number of arguments (1..2)')
let plugin = a:1 endif
elseif a:0 == 2
let plugin = a:1 try
if type(a:2) == 1 let repo = s:trim(a:repo)
let opts.branch = a:2 let name = fnamemodify(repo, ':t:s?\.git$??')
elseif type(a:2) == 4 let spec = extend(s:infer_properties(name, repo),
call extend(opts, a:2) \ a:0 == 1 ? s:parse_options(a:1) : s:base_spec)
let g:plugs[name] = spec
let g:plugs_order += [name]
catch
return s:err(v:exception)
endtry
endfunction
function! s:parse_options(arg)
let opts = copy(s:base_spec)
let type = type(a:arg)
if type == s:TYPE.string
let opts.branch = a:arg
elseif type == s:TYPE.dict
call extend(opts, a:arg)
if has_key(opts, 'tag') if has_key(opts, 'tag')
let opts.branch = remove(opts, 'tag') let opts.branch = remove(opts, 'tag')
endif endif
else if has_key(opts, 'dir')
echoerr "Invalid argument type (expected: string or dictionary)" let opts.dir = s:dirpath(expand(opts.dir))
return
endif endif
else else
echoerr "Invalid number of arguments (1..2)" throw 'Invalid argument type (expected: string or dictionary)'
return
endif endif
return opts
let plugin = substitute(plugin, '[/\\]*$', '', '')
let name = substitute(split(plugin, '/')[-1], '\.git$', '', '')
if !a:force && has_key(g:plugs, name)
let s:extended[name] = g:plugs[name]
return
endif
if plugin[0] =~ '[/$~]' || plugin =~? '^[a-z]:'
let spec = extend(opts, { 'dir': s:dirpath(expand(plugin)) })
else
if plugin =~ ':'
let uri = plugin
else
if plugin !~ '/'
let plugin = 'vim-scripts/'. plugin
endif
let uri = 'https://git:@github.com/' . plugin . '.git'
endif
let dir = s:dirpath( fnamemodify(join([g:plug_home, name], '/'), ':p') )
let spec = extend(opts, { 'dir': dir, 'uri': uri })
endif
let g:plugs[name] = spec
if !a:force
let s:extended[name] = spec
endif
let g:plugs_order += [name]
endfunction endfunction
function! s:install(...) function! s:infer_properties(name, repo)
call s:update_impl(0, a:000) let repo = a:repo
if s:is_local_plug(repo)
return { 'dir': s:dirpath(expand(repo)) }
else
if repo =~ ':'
let uri = repo
else
if repo !~ '/'
let repo = 'vim-scripts/'. repo
endif
let uri = 'https://git:@github.com/' . repo . '.git'
endif
let dir = s:dirpath( fnamemodify(join([g:plug_home, a:name], '/'), ':p') )
return { 'dir': dir, 'uri': uri }
endif
endfunction endfunction
function! s:update(...) function! s:install(force, ...)
call s:update_impl(1, a:000) call s:update_impl(0, a:force, a:000)
endfunction endfunction
function! s:apply() function! s:update(force, ...)
call s:update_impl(1, a:force, a:000)
endfunction
function! s:helptags()
for spec in values(g:plugs) for spec in values(g:plugs)
let docd = join([spec.dir, 'doc'], '/') let docd = join([spec.dir, 'doc'], '/')
if isdirectory(docd) if isdirectory(docd)
silent! execute "helptags ". join([spec.dir, 'doc'], '/') silent! execute 'helptags '. s:esc(docd)
endif endif
endfor endfor
runtime! plugin/*.vim
runtime! after/*.vim
silent! source $MYVIMRC
endfunction endfunction
function! s:syntax() function! s:syntax()
@@ -354,7 +392,8 @@ function! s:syntax()
syn match plugDash /^-/ syn match plugDash /^-/
syn match plugPlus /^+/ syn match plugPlus /^+/
syn match plugStar /^*/ syn match plugStar /^*/
syn match plugName /\(^- \)\@<=[^:]*/ syn match plugMessage /\(^- \)\@<=.*/
syn match plugName /\(^- \)\@<=[^ ]*:/
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
@@ -372,6 +411,7 @@ function! s:syntax()
hi def link plugPlus Constant hi def link plugPlus Constant
hi def link plugStar Boolean hi def link plugStar Boolean
hi def link plugMessage Function
hi def link plugName Label hi def link plugName Label
hi def link plugInstall Function hi def link plugInstall Function
hi def link plugUpdate Type hi def link plugUpdate Type
@@ -424,19 +464,59 @@ function! s:assign_name()
let name = prefix let name = prefix
let idx = 2 let idx = 2
while bufexists(name) while bufexists(name)
let name = printf("%s (%s)", prefix, idx) let name = printf('%s (%s)', prefix, idx)
let idx = idx + 1 let idx = idx + 1
endwhile endwhile
silent! execute "f ".fnameescape(name) silent! execute 'f '.fnameescape(name)
endfunction
function! s:do(pull, force, todo)
for [name, spec] in items(a:todo)
if !isdirectory(spec.dir)
continue
endif
execute 'cd '.s:esc(spec.dir)
let installed = has_key(s:prev_update.new, name)
let updated = installed ? 0 :
\ (a:pull && !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"')))
if a:force || installed || updated
call append(3, '- Post-update hook for '. name .' ... ')
let type = type(spec.do)
if type == s:TYPE.string
try
" FIXME: Escaping is incomplete. We could use shellescape with eval,
" but it won't work on Windows.
let g:_plug_do = '!'.escape(spec.do, '#!%')
execute "normal! :execute g:_plug_do\<cr>\<cr>"
finally
let result = v:shell_error ? ('Exit status: '.v:shell_error) : 'Done!'
unlet g:_plug_do
endtry
elseif type == s:TYPE.funcref
try
let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
call spec.do({ 'name': name, 'status': status, 'force': a:force })
let result = 'Done!'
catch
let result = 'Error: ' . v:exception
endtry
else
let result = 'Error: Invalid type!'
endif
call setline(4, getline(4) . result)
endif
cd -
endfor
endfunction endfunction
function! s:finish(pull) function! s:finish(pull)
call append(3, '- Finishing ... ') call append(3, '- Finishing ... ')
redraw redraw
call s:apply() call s:helptags()
call s:syntax() call plug#end()
call setline(4, getline(4) . 'Done!') call setline(4, getline(4) . 'Done!')
normal! gg normal! gg
call s:syntax()
redraw redraw
let msgs = [] let msgs = []
if !empty(s:prev_update.errors) if !empty(s:prev_update.errors)
@@ -452,7 +532,7 @@ function! s:retry()
if empty(s:prev_update.errors) if empty(s:prev_update.errors)
return return
endif endif
call s:update_impl(s:prev_update.pull, call s:update_impl(s:prev_update.pull, s:prev_update.force,
\ extend(copy(s:prev_update.errors), [s:prev_update.threads])) \ extend(copy(s:prev_update.errors), [s:prev_update.threads]))
endfunction endfunction
@@ -464,13 +544,14 @@ function! s:names(...)
return filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)') return filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')
endfunction endfunction
function! s:update_impl(pull, args) abort function! s:update_impl(pull, force, args) abort
let st = reltime()
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', 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, '!get(v:val, "frozen", 0)') : let todo = empty(args) ? filter(managed, '!v:val.frozen') :
\ filter(managed, 'index(args, v:key) >= 0') \ filter(managed, 'index(args, v:key) >= 0')
if empty(todo) if empty(todo)
@@ -486,8 +567,10 @@ function! s:update_impl(pull, args) abort
normal! 2G normal! 2G
redraw redraw
let len = len(g:plugs) if !isdirectory(g:plug_home)
let s:prev_update = { 'errors': [], 'pull': a:pull, 'threads': threads } call mkdir(g:plug_home, 'p')
endif
let s:prev_update = { 'errors': [], 'pull': a:pull, 'force': a:force, 'new': {}, 'threads': threads }
if has('ruby') && threads > 1 if has('ruby') && threads > 1
try try
let imd = &imd let imd = &imd
@@ -517,45 +600,26 @@ function! s:update_impl(pull, args) abort
else else
call s:update_serial(a:pull, todo) call s:update_serial(a:pull, todo)
endif endif
if len(g:plugs) > len call s:do(a:pull, a:force, filter(copy(todo), 'has_key(v:val, "do")'))
call plug#end()
endif
call s:finish(a:pull) call s:finish(a:pull)
endfunction call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(st)))[0] . ' sec.')
function! s:extend(names)
let s:extended = {}
try
command! -nargs=+ Plug call s:add(0, <args>)
for name in a:names
let plugfile = globpath(s:rtp(g:plugs[name]), s:plug_file)
if filereadable(plugfile)
execute "source ". s:esc(plugfile)
endif
endfor
finally
command! -nargs=+ Plug call s:add(1, <args>)
endtry
return s:extended
endfunction endfunction
function! s:update_progress(pull, cnt, bar, total) function! s:update_progress(pull, cnt, bar, total)
call setline(1, (a:pull ? 'Updating' : 'Installing'). call setline(1, (a:pull ? 'Updating' : 'Installing').
\ " plugins (".a:cnt."/".a:total.")") \ ' plugins ('.a:cnt.'/'.a:total.')')
call s:progress_bar(2, a:bar, a:total) call s:progress_bar(2, a:bar, a:total)
normal! 2G normal! 2G
redraw redraw
endfunction endfunction
function! s:update_serial(pull, todo) function! s:update_serial(pull, todo)
let st = reltime()
let base = g:plug_home let base = g:plug_home
let todo = copy(a:todo) let todo = copy(a:todo)
let total = len(todo) let total = len(todo)
let done = {} let done = {}
let bar = '' let bar = ''
while !empty(todo)
for [name, spec] in items(todo) for [name, spec] in items(todo)
let done[name] = 1 let done[name] = 1
if isdirectory(spec.dir) if isdirectory(spec.dir)
@@ -573,16 +637,14 @@ function! s:update_serial(pull, todo)
endif endif
cd - cd -
else else
if !isdirectory(base)
call mkdir(base, 'p')
endif
let result = s:system( let result = s:system(
\ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1', \ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1',
\ s:shellesc(spec.uri), \ s:shellesc(spec.uri),
\ s:shellesc(spec.branch), \ s:shellesc(spec.branch),
\ s:shellesc(substitute(spec.dir, '[\/]\+$', '', '')), \ s:shellesc(s:trim(spec.dir)),
\ s:shellesc(spec.dir))) \ s:shellesc(spec.dir)))
let error = v:shell_error != 0 let error = v:shell_error != 0
if !error | let s:prev_update.new[name] = 1 | endif
endif endif
let bar .= error ? 'x' : '=' let bar .= error ? 'x' : '='
if error if error
@@ -591,18 +653,6 @@ function! s:update_serial(pull, todo)
call append(3, s:format_message(!error, name, result)) call append(3, s:format_message(!error, name, result))
call s:update_progress(a:pull, len(done), bar, total) call s:update_progress(a:pull, len(done), bar, total)
endfor endfor
let extended = s:extend(keys(todo))
if !empty(extended)
let todo = filter(extended, '!has_key(done, v:key)')
let total += len(todo)
call s:update_progress(a:pull, len(done), bar, total)
else
break
endif
endwhile
call setline(1, "Updated. Elapsed time: " . split(reltimestr(reltime(st)))[0] . ' sec.')
endfunction endfunction
function! s:update_parallel(pull, todo, threads) function! s:update_parallel(pull, todo, threads)
@@ -628,16 +678,28 @@ function! s:update_parallel(pull, todo, threads)
%["#{arg.gsub('"', '\"')}"] %["#{arg.gsub('"', '\"')}"]
end end
require 'set' def killall pid
pids = [pid]
unless `which pgrep`.empty?
children = pids
until children.empty?
children = children.map { |pid|
`pgrep -P #{pid}`.lines.map { |l| l.chomp }
}.flatten
pids += children
end
end
pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
end
require 'thread' require 'thread'
require 'fileutils' require 'fileutils'
require 'timeout' require 'timeout'
running = true running = true
st = Time.now
iswin = VIM::evaluate('s:is_win').to_i == 1 iswin = VIM::evaluate('s:is_win').to_i == 1
pull = VIM::evaluate('a:pull').to_i == 1 pull = VIM::evaluate('a:pull').to_i == 1
base = VIM::evaluate('g:plug_home') base = VIM::evaluate('g:plug_home')
all = VIM::evaluate('copy(a:todo)') all = VIM::evaluate('a:todo')
limit = VIM::evaluate('get(g:, "plug_timeout", 60)') limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1
nthr = VIM::evaluate('a:threads').to_i nthr = VIM::evaluate('a:threads').to_i
@@ -712,17 +774,7 @@ function! s:update_parallel(pull, todo, threads)
[$? == 0, data.chomp] [$? == 0, data.chomp]
rescue Timeout::Error, Interrupt => e rescue Timeout::Error, Interrupt => e
if fd && !fd.closed? if fd && !fd.closed?
pids = [fd.pid] killall fd.pid
unless `which pgrep`.empty?
children = pids
until children.empty?
children = children.map { |pid|
`pgrep -P #{pid}`.lines.map { |l| l.chomp }
}.flatten
pids += children
end
end
pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
fd.close fd.close
end end
if e.is_a?(Timeout::Error) && tried < tries if e.is_a?(Timeout::Error) && tried < tries
@@ -760,12 +812,8 @@ function! s:update_parallel(pull, todo, threads)
end end
} if VIM::evaluate('s:mac_gui') == 1 } if VIM::evaluate('s:mac_gui') == 1
processed = Set.new
progress = iswin ? '' : '--progress' progress = iswin ? '' : '--progress'
until all.empty? [all.length, nthr].min.times do
names = all.keys
processed.merge names
[names.length, nthr].min.times do
mtx.synchronize do mtx.synchronize do
threads << Thread.new { threads << Thread.new {
while pair = take1.call while pair = take1.call
@@ -773,8 +821,9 @@ function! s:update_parallel(pull, todo, threads)
dir, uri, branch = pair.last.values_at *%w[dir uri branch] dir, uri, branch = pair.last.values_at *%w[dir uri branch]
branch = esc branch branch = esc branch
subm = "git submodule update --init --recursive 2>&1" subm = "git submodule update --init --recursive 2>&1"
exists = File.directory? dir
ok, result = ok, result =
if File.directory? dir if exists
dir = esc dir dir = esc dir
ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil
current_uri = data.lines.to_a.last current_uri = data.lines.to_a.last
@@ -797,28 +846,20 @@ function! s:update_parallel(pull, todo, threads)
end end
end end
else else
FileUtils.mkdir_p(base)
d = esc dir.sub(%r{[\\/]+$}, '') d = esc dir.sub(%r{[\\/]+$}, '')
log.call name, 'Installing ...', :install log.call name, 'Installing ...', :install
bt.call "(git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && #{subm})", name, :install bt.call "(git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && #{subm})", name, :install
end end
mtx.synchronize { VIM::command("let s:prev_update.new['#{name}'] = 1") } if !exists && ok
log.call name, result, ok log.call name, result, ok
end end
} if running } if running
end end
end end
threads.each { |t| t.join rescue nil } threads.each { |t| t.join rescue nil }
mtx.synchronize { threads.clear }
extended = Hash[(VIM::evaluate("s:extend(#{names.inspect})") || {}).reject { |k, _|
processed.include? k
}]
tot += extended.length
all.merge!(extended)
logh.call logh.call
end
refresh.kill if refresh refresh.kill if refresh
watcher.kill watcher.kill
$curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
EOF EOF
endfunction endfunction
@@ -862,16 +903,16 @@ function! s:git_valid(spec, check_branch, cd)
let ret = 1 let ret = 1
let msg = 'OK' let msg = 'OK'
if isdirectory(a:spec.dir) if isdirectory(a:spec.dir)
if a:cd | execute "cd " . s:esc(a:spec.dir) | endif if a:cd | execute 'cd ' . s:esc(a:spec.dir) | endif
let result = split(s:system("git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"), '\n') let result = split(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url'), '\n')
let remote = result[-1] let remote = result[-1]
if v:shell_error if v:shell_error
let msg = join([remote, "PlugClean required."], "\n") let msg = join([remote, 'PlugClean required.'], "\n")
let ret = 0 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 msg = join(['Invalid URI: '.remote,
\ 'Expected: '.a:spec.uri, \ 'Expected: '.a:spec.uri,
\ "PlugClean required."], "\n") \ 'PlugClean required.'], "\n")
let ret = 0 let ret = 0
elseif a:check_branch elseif a:check_branch
let branch = result[0] let branch = result[0]
@@ -936,7 +977,7 @@ function! s:clean(force)
call append(line('$'), 'Already clean.') call append(line('$'), 'Already clean.')
else else
call inputsave() call inputsave()
let yes = a:force || (input("Proceed? (Y/N) ") =~? '^y') let yes = a:force || (input('Proceed? (Y/N) ') =~? '^y')
call inputrestore() call inputrestore()
if yes if yes
for dir in todo for dir in todo
@@ -956,23 +997,22 @@ function! s:upgrade()
if executable('curl') if executable('curl')
let mee = s:shellesc(s:me) let mee = s:shellesc(s:me)
let new = s:shellesc(s:me . '.new') let new = s:shellesc(s:me . '.new')
echo "Downloading ". s:plug_source echo 'Downloading '. s:plug_source
redraw redraw
let mv = s:is_win ? 'move /Y' : 'mv -f' let mv = s:is_win ? 'move /Y' : 'mv -f'
let cp = s:is_win ? 'copy /Y' : 'cp -f' let cp = s:is_win ? 'copy /Y' : 'cp -f'
call system(printf( call system(printf(
\ "curl -fLo %s %s && ".cp." %s %s.old && ".mv." %s %s", \ 'curl -fLo %s %s && '.cp.' %s %s.old && '.mv.' %s %s',
\ new, s:plug_source, mee, mee, new, mee)) \ new, s:plug_source, mee, mee, new, mee))
if v:shell_error == 0 if v:shell_error == 0
unlet g:loaded_plug unlet g:loaded_plug
echo "Downloaded ". s:plug_source echo 'Downloaded '. s:plug_source
return 1 return 1
else else
echoerr "Error upgrading vim-plug" return s:err('Error upgrading vim-plug')
return 0
endif endif
elseif has('ruby') elseif has('ruby')
echo "Downloading ". s:plug_source echo 'Downloading '. s:plug_source
ruby << EOF ruby << EOF
require 'open-uri' require 'open-uri'
require 'fileutils' require 'fileutils'
@@ -986,14 +1026,19 @@ function! s:upgrade()
File.rename new, me File.rename new, me
EOF EOF
unlet g:loaded_plug unlet g:loaded_plug
echo "Downloaded ". s:plug_source echo 'Downloaded '. s:plug_source
return 1 return 1
else else
echoerr "curl executable or ruby support not found" return s:err('curl executable or ruby support not found')
return 0
endif endif
endfunction endfunction
function! s:upgrade_specs()
for spec in values(g:plugs)
let spec.frozen = get(spec, 'frozen', 0)
endfor
endfunction
function! s:status() function! s:status()
call s:prepare() call s:prepare()
call append(0, 'Checking plugins') call append(0, 'Checking plugins')
@@ -1082,7 +1127,7 @@ function! s:diff()
endif endif
execute 'cd '.s:esc(v.dir) execute 'cd '.s:esc(v.dir)
let diff = system('git log --pretty=format:"%h %s (%cr)" "HEAD@{0}...HEAD@{1}"') let diff = system('git log --pretty=format:"%h %s (%cr)" "HEAD...HEAD@{1}"')
if !v:shell_error && !empty(diff) if !v:shell_error && !empty(diff)
call append(1, '') call append(1, '')
call append(2, '- '.k.':') call append(2, '- '.k.':')

View File

@@ -14,8 +14,26 @@ if [ ! -d fzf-staged ]; then
git clone https://github.com/junegunn/fzf.git fzf-staged git clone https://github.com/junegunn/fzf.git fzf-staged
fi fi
make_dirs() {
mkdir -p "$1"
cd "$1"
mkdir -p autoload colors ftdetect ftplugin indent plugin syntax
for d in *; do
cat > $d/xxx.vim << EOF
" echom expand('<sfile>')
let g:xxx = get(g:, 'xxx', [])
call add(g:xxx, '${1:4}/$d')
EOF
done
cd - > /dev/null
}
make_dirs xxx/
make_dirs xxx/after
cat > /tmp/mini-vimrc << VIMRC cat > /tmp/mini-vimrc << VIMRC
set rtp+=vader.vim set rtp+=vader.vim
set shell=/bin/bash
source $PLUG_SRC source $PLUG_SRC
VIMRC VIMRC

View File

@@ -1,5 +1,5 @@
Execute (Initialize test environment): Execute (Initialize test environment):
Save &rtp, g:plugs, g:plug_home, $MYVIMRC Save &rtp, g:plugs, g:plug_home
let first_rtp = split(&rtp, ',')[0] let first_rtp = split(&rtp, ',')[0]
let last_rtp = split(&rtp, ',')[-1] let last_rtp = split(&rtp, ',')[-1]
@@ -33,18 +33,11 @@ Execute (Initialize test environment):
endfunction endfunction
command! -nargs=+ -bang AssertExpect call AssertExpect('<bang>' == '!', <args>) command! -nargs=+ -bang AssertExpect call AssertExpect('<bang>' == '!', <args>)
let g:vimrc_reloaded = 0
let vimrc = tempname()
call writefile(['let g:vimrc_reloaded += 1'], vimrc)
let $MYVIMRC = vimrc
Execute (plug#end() before plug#begin() should fail): Execute (plug#end() before plug#begin() should fail):
try redir => out
call plug#end() AssertEqual 0, plug#end()
Assert 0, 'should not reach here' redir END
catch Assert stridx(out, 'Call plug#begin() first') >= 0
Assert stridx(v:exception, 'Call plug#begin() first') >= 0
endtry
Execute (plug#begin() without path argument): Execute (plug#begin() without path argument):
call plug#begin() call plug#begin()
@@ -54,12 +47,10 @@ Execute (plug#begin() without path argument):
Execute (plug#begin() without path argument with empty &rtp): Execute (plug#begin() without path argument with empty &rtp):
let save_rtp = &rtp let save_rtp = &rtp
set rtp= set rtp=
try redir => out
call plug#begin() AssertEqual 0, plug#begin()
Assert 0, 'should not reach here' redir END
catch Assert stridx(out, 'Unable to determine plug home') >= 0
Assert stridx(v:exception, 'Unable to determine plug home') >= 0, 'Got: '.v:exception
endtry
let &rtp = save_rtp let &rtp = save_rtp
Execute (plug#begin(path)): Execute (plug#begin(path)):
@@ -137,7 +128,6 @@ Execute (Yet, plugins are not available):
Execute (PlugInstall): Execute (PlugInstall):
PlugInstall PlugInstall
AssertEqual 1, g:vimrc_reloaded
q q
Execute (Plugin available after installation): Execute (Plugin available after installation):
@@ -171,7 +161,6 @@ Expect:
Execute (PlugUpdate to set the right branch): Execute (PlugUpdate to set the right branch):
PlugUpdate PlugUpdate
call PlugStatusSorted() call PlugStatusSorted()
AssertEqual 2, g:vimrc_reloaded
Expect: Expect:
- goyo.vim: OK - goyo.vim: OK
@@ -258,7 +247,6 @@ Execute (PlugClean! to remove vim-emoji):
Execute (PlugUpdate to install both again): Execute (PlugUpdate to install both again):
PlugUpdate PlugUpdate
AssertExpect '^- [^:]*:', 2 AssertExpect '^- [^:]*:', 2
AssertEqual 3, g:vimrc_reloaded
Assert !empty(globpath(&rtp, 'colors/seoul256.vim')), 'seoul256.vim should be found' Assert !empty(globpath(&rtp, 'colors/seoul256.vim')), 'seoul256.vim should be found'
Assert !empty(globpath(&rtp, 'autoload/emoji.vim')), 'vim-emoji should be found' Assert !empty(globpath(&rtp, 'autoload/emoji.vim')), 'vim-emoji should be found'
q q
@@ -266,7 +254,6 @@ Execute (PlugUpdate to install both again):
Execute (PlugUpdate only to find out plugins are up-to-date, D key to check): 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
AssertEqual 4, g:vimrc_reloaded
normal D normal D
AssertEqual 'No updates.', getline(1) AssertEqual 'No updates.', getline(1)
q q
@@ -361,7 +348,8 @@ Execute (Trying to execute on-demand commands when plugin is not installed):
Execute (New set of plugins): Execute (New set of plugins):
call plug#begin() call plug#begin()
Plug 'junegunn/vim-fnr' " Depends on vim-pseudocl Plug 'junegunn/vim-fnr'
Plug 'junegunn/vim-pseudocl'
Plug 'junegunn/vim-easy-align', { 'on': 'EasyAlign' } Plug 'junegunn/vim-easy-align', { 'on': 'EasyAlign' }
Plug 'junegunn/vim-redis', { 'for': 'redis' } Plug 'junegunn/vim-redis', { 'for': 'redis' }
call plug#end() call plug#end()
@@ -372,31 +360,36 @@ Execute (Check commands):
Execute (Partial PlugInstall): Execute (Partial PlugInstall):
PlugInstall vim-fnr vim-easy-align PlugInstall vim-fnr vim-easy-align
AssertExpect 'vim-pseudocl', 1 AssertExpect 'vim-fnr', 1
PlugInstall vim-fnr vim-easy-align 1
AssertExpect 'vim-pseudocl', 1
q q
Execute (Check dependent plugin): PlugInstall vim-fnr vim-easy-align 1
Assert &rtp =~ 'pseudocl', &rtp AssertExpect 'vim-fnr', 1
AssertExpect 'vim-easy-align', 1
AssertEqual first_rtp, split(&rtp, ',')[0] AssertEqual first_rtp, split(&rtp, ',')[0]
AssertEqual last_rtp, split(&rtp, ',')[-1] AssertEqual last_rtp, split(&rtp, ',')[-1]
q
Given (Unaligned code): Given (Unaligned code):
a=1 a=1
aa=2 aa=2
Execute (Check installed plugins): Execute (Check installed plugins):
if has('vim_starting')
Log 'Vader is run from commandline'
runtime! plugin/**/*.vim
endif
Assert exists(':FNR'), 'FNR command should be found' Assert exists(':FNR'), 'FNR command should be found'
Assert exists(':EasyAlign'), 'EasyAlign command should be found'
Assert !exists(':RedisExecute'), 'RedisExecute command still should not be found' Assert !exists(':RedisExecute'), 'RedisExecute command still should not be found'
Assert exists(':EasyAlign'), 'EasyAlign command should be found'
%EasyAlign= %EasyAlign=
Expect (Aligned code): Expect (Aligned code):
a = 1 a = 1
aa = 2 aa = 2
Given (nothing): Given:
Execute (Partial PlugUpdate): Execute (Partial PlugUpdate):
PlugUpdate vim-redis PlugUpdate vim-redis
q q
@@ -576,16 +569,205 @@ Execute (Retry failed tasks):
AssertExpect! '[xxx]', 1 AssertExpect! '[xxx]', 1
q q
Execute (Cleanup): **********************************************************************
call system('rm -rf '.temp_plugged) ~ Post-update hook (`do` option)
call rename('fzf', 'fzf-staged') **********************************************************************
unlet g:plugs Execute (Cleanup):
unlet g:plug_home call plug#begin()
unlet g:vimrc_reloaded call plug#end()
unlet temp_plugged vader plug basertp save_rtp repo lnum fzf PlugClean!
delf PlugStatusSorted
delf AssertExpect Execute (On install):
delc AssertExpect call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': 'touch installed' }
Plug 'junegunn/vim-pseudocl'
call plug#end()
PlugInstall
q
Assert filereadable(g:plugs['vim-easy-align'].dir.'/installed'),
\ 'vim-easy-align/installed should exist'
Assert !filereadable(g:plugs['vim-pseudocl'].dir.'/installed'),
\ 'vim-pseudocl/installed should not exist'
Execute (On update):
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': 'touch updated' }
Plug 'junegunn/vim-pseudocl', { 'do': 'touch updated' }
call plug#end()
" Reset for updates
call system('cd '.g:plugs['vim-pseudocl'].dir.' && git reset --hard HEAD^')
PlugUpdate
Log getline(1, '$')
q
Assert !filereadable(g:plugs['vim-easy-align'].dir.'/updated'),
\ 'vim-easy-align/updated should not exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/updated'),
\ 'vim-pseudocl/updated should exist'
Execute (When already installed):
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': 'touch installed2' }
Plug 'junegunn/vim-pseudocl', { 'do': 'touch installed2' }
call plug#end()
PlugInstall
q
Assert !filereadable(g:plugs['vim-easy-align'].dir.'/installed2'),
\ 'vim-easy-align/installed2 should not exist'
Assert !filereadable(g:plugs['vim-pseudocl'].dir.'/installed2'),
\ 'vim-pseudocl/installed2 should not exist'
Execute (PlugInstall!):
PlugInstall!
q
Assert filereadable(g:plugs['vim-easy-align'].dir.'/installed2'),
\ 'vim-easy-align/installed2 should exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/installed2'),
\ 'vim-pseudocl/installed2 should exist'
Execute (When already updated):
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': 'touch updated2' }
Plug 'junegunn/vim-pseudocl', { 'do': 'touch updated2' }
call plug#end()
PlugUpdate
q
Assert !filereadable(g:plugs['vim-easy-align'].dir.'/updated2'),
\ 'vim-easy-align/updated2 should not exist'
Assert !filereadable(g:plugs['vim-pseudocl'].dir.'/updated2'),
\ 'vim-pseudocl/updated2 should not exist'
Execute (PlugUpdate!):
PlugUpdate!
q
Assert filereadable(g:plugs['vim-easy-align'].dir.'/updated2'),
\ 'vim-easy-align/updated2 should exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/updated2'),
\ 'vim-pseudocl/updated2 should exist'
Execute (Using Funcref):
function! PlugUpdated(info)
call system('touch '. a:info.name . a:info.status . a:info.force . len(a:info))
endfunction
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'do': function('PlugUpdated') }
Plug 'junegunn/vim-pseudocl', { 'do': function('PlugUpdated') }
call plug#end()
call system('cd '.g:plugs['vim-easy-align'].dir.' && git reset --hard HEAD^')
call system('rm -rf '.g:plugs['vim-pseudocl'].dir)
PlugUpdate
Log getline(1, '$')
q
Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignupdated03'),
\ 'vim-easy-align/vim-easy-alignupdated03 should exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclinstalled03'),
\ 'vim-pseudocl/vim-pseudoclinstalled03 should exist'
call system('rm -rf '.g:plugs['vim-pseudocl'].dir)
PlugInstall!
q
Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignunchanged13'),
\ 'vim-easy-align/vim-easy-alignunchanged13 should exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclinstalled13'),
\ 'vim-pseudocl/vim-pseudoclinstalled13 should exist'
call system('cd '.g:plugs['vim-easy-align'].dir.' && git reset --hard HEAD^')
PlugUpdate!
q
Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignupdated13'),
\ 'vim-easy-align/vim-easy-alignupdated13 should exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclunchanged13'),
\ 'vim-pseudocl/vim-pseudoclunchanged13 should exist'
**********************************************************************
~ Overriding `dir`
**********************************************************************
Execute (Using custom dir):
Assert isdirectory(g:plugs['vim-easy-align'].dir)
call system('rm -rf '.$TMPDIR.'easy-align')
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'dir': $TMPDIR.'easy-align' }
call plug#end()
AssertEqual $TMPDIR.'easy-align/', g:plugs['vim-easy-align'].dir
PlugClean!
Assert !isdirectory(g:plugs['vim-easy-align'].dir)
q
PlugInstall
q
Assert isdirectory(g:plugs['vim-easy-align'].dir)
**********************************************************************
~ On-demand loading load order
**********************************************************************
Before (Clear global vars):
let g:xxx = []
set rtp-=$PWD/xxx/
set rtp-=$PWD/xxx/after
Execute (Immediate loading):
call plug#begin()
Plug '$PWD/xxx'
call plug#end()
" FIXME:
" Different result when Vader is run from commandline with `-c` option
Log g:xxx
if has('vim_starting')
AssertEqual ['/ftdetect', 'after/ftdetect'], g:xxx
else
AssertEqual ['/plugin', 'after/plugin', '/ftdetect', 'after/ftdetect'], g:xxx
endif
Execute (Command-based on-demand loading):
call plug#begin()
Plug '$PWD/xxx', { 'on': 'XXX' }
call plug#end()
AssertEqual [], g:xxx
silent! XXX
AssertEqual ['/ftdetect', 'after/ftdetect', '/plugin', 'after/plugin'], g:xxx
setf xxx
AssertEqual ['/ftdetect', 'after/ftdetect', '/plugin', 'after/plugin', '/ftplugin', 'after/ftplugin', '/indent', 'after/indent', '/syntax', 'after/syntax'], g:xxx
Execute (Filetype-based on-demand loading):
call plug#begin()
Plug '$PWD/xxx', { 'for': 'xxx' }
call plug#end()
AssertEqual ['/ftdetect', 'after/ftdetect'], g:xxx
setf xxx
AssertEqual ['/ftdetect', 'after/ftdetect', '/plugin', 'after/plugin', '/ftplugin', 'after/ftplugin', '/indent', 'after/indent', '/syntax', 'after/syntax'], g:xxx
Before:
Execute (Cleanup):
silent! call system('rm -rf '.temp_plugged)
silent! call rename('fzf', 'fzf-staged')
silent! unlet g:plugs
silent! unlet g:plug_home
silent! unlet temp_plugged vader plug basertp save_rtp repo lnum fzf out
silent! delf PlugStatusSorted
silent! delf AssertExpect
silent! delf PlugUpdated
silent! delc AssertExpect
silent! unmap /
silent! unmap ?
Restore Restore