62 Commits
0.3.6 ... 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
Junegunn Choi
5b2c03d3a8 R to retry interrupted tasks as well 2014-07-23 11:46:29 +09:00
Junegunn Choi
0b31be49cf Update README 2014-07-22 12:47:34 +09:00
Junegunn Choi
74fa6ab9df 'R' to retry failed update/installation tasks 2014-07-22 12:46:59 +09:00
Junegunn Choi
0d7e20c984 Merge pull request #37 from junegunn/retries
Retry in case of timeout
2014-07-21 23:13:43 +09:00
Junegunn Choi
e2714fb56e Retry in 3 seconds 2014-07-21 23:09:16 +09:00
Junegunn Choi
3b83a22ea4 Avoid InsertEnter/InsertLeave events in GUI MacVim workaround 2014-07-21 14:27:38 +09:00
Junegunn Choi
cd418369bc Use gui_macvim instead of mac (#36) 2014-07-21 11:42:27 +09:00
Junegunn Choi
279a334c8b Temporarily disable &imd on GUI MacVim (#36) 2014-07-21 11:35:48 +09:00
Junegunn Choi
9132e9d50d Workaround for screen freeze in MacVim GUI (#36) 2014-07-21 02:49:47 +09:00
Junegunn Choi
3323163e04 Retry in case of timeout (#35)
while gradually increasing the time limit
2014-07-20 02:14:15 +09:00
Junegunn Choi
e4671eaf9e Do not assume that frozen key exists
To avoid possible error after PlugUpgrade
2014-07-18 01:27:41 +09:00
Junegunn Choi
9afa356fb3 Exclude unmanaged plugins from PlugDiff output 2014-07-17 10:28:59 +09:00
Junegunn Choi
e04f696682 Ignore errors during :helptags
https://github.com/junegunn/vim-plug/issues/31#issuecomment-49058031
2014-07-17 02:20:00 +09:00
Junegunn Choi
4cb5fd04a6 Note on single quotes (#33) 2014-07-16 20:40:49 +09:00
Junegunn Choi
c16743e8fc License 2014-07-16 20:39:39 +09:00
Junegunn Choi
46a6e8441f Pin first and last path in &rtp (#34) 2014-07-16 20:26:42 +09:00
Junegunn Choi
466d1839b3 Add support for local plugins. Add frozen option (#32) 2014-07-16 19:52:58 +09:00
4 changed files with 945 additions and 398 deletions

194
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
@@ -37,28 +33,31 @@ Edit your .vimrc
```vim ```vim
call plug#begin('~/.vim/plugged') 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'
" On-demand loading
Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' }
Plug 'tpope/vim-fireplace', { 'for': 'clojure' } Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
" Plug 'user/repo1', 'branch_or_tag'
" Plug 'user/repo2', { 'rtp': 'vim/plugin/dir', 'branch': 'devel' } " Using git URL
" Plug 'git@github.com:junegunn/vim-github-dashboard.git' 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()
``` ```
Reload .vimrc and `:PlugInstall` to install plugins. Reload .vimrc and `:PlugInstall` to install plugins.
### Plugin directory
If you omit the path argument to `plug#begin()`, plugins are installed in
`plugged` directory under the first path in `runtimepath` at the point when
`plug#begin()` is called. This is usually `~/.vim/plugged` (or
`$HOME/vimfiles/plugged` on Windows) given that you didn't touch runtimepath
before the call.
### Commands ### Commands
| Command | Description | | Command | Description |
@@ -70,17 +69,31 @@ before the call.
| PlugStatus | Check the status of plugins | | PlugStatus | Check the status of plugins |
| PlugDiff | See the updated changes from the previous PlugUpdate | | PlugDiff | See the updated changes from the previous PlugUpdate |
### `Plug` options
| Option | Description |
| -------------- | -------------------------------------------------------------------- |
| `branch`/`tag` | Branch or tag of the repository to use |
| `rtp` | Subdirectory that contains Vim plugin |
| `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 |
| `frozen` | Do not install/update plugin unless explicitly given as the argument |
### Options for parallel installer ### Options for parallel installer
| Flag | Default | Description | | Flag | Default | Description |
| ---------------- | ------- | --------------------------------- | | ---------------- | ------- | ------------------------------------ |
| `g:plug_threads` | 16 | Default number of threads to use | | `g:plug_threads` | 16 | Default number of threads to use |
| `g:plug_timeout` | 60 | Time limit of each task in seconds | | `g:plug_timeout` | 60 | Time limit of each task in seconds |
| `g:plug_retries` | 2 | Number of retries in case of timeout |
### Keybindings ### Keybindings
- `D` - `PlugDiff` - `D` - `PlugDiff`
- `S` - `PlugStatus` - `S` - `PlugStatus`
- `R` - Retry failed update or installation tasks
- `q` - Close the window - `q` - Close the window
### Example: A small [sensible](https://github.com/tpope/vim-sensible) Vim configuration ### Example: A small [sensible](https://github.com/tpope/vim-sensible) Vim configuration
@@ -107,83 +120,64 @@ 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)~~
- *Support for Plugfile has been removed since 0.5.0*
### FAQ/Troubleshooting ### License
#### Plugins are not installed/updated in parallel MIT
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.
### Regarding feature request
You may submit a request for a new feature by [creating an
issue](https://github.com/junegunn/vim-plug/issues). However, please be minded
that this is an opinionated software and I want to keep the feature set as small
as possible. So I may not agree with you on the necessity of the suggested
feature. If that happens, I suggest the following options.
1. Check out [Vundle](https://github.com/gmarik/vundle) or
[NeoBundle](https://github.com/Shougo/neobundle.vim).
They offer broader feature sets.
2. Create a fork of this project and let it be your own plugin manager.
There's no need for us to have a single canonical branch.

526
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,10 +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: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
@@ -69,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
@@ -91,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()
@@ -103,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
@@ -132,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] = []
@@ -175,46 +197,76 @@ function! plug#end()
\ key, string(key), string(reverse(names))) \ key, string(key), string(reverse(names)))
augroup END augroup END
endfor endfor
call s:reorg_rtp()
filetype plugin indent on filetype plugin indent on
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
endfunction
function! s:reorg_rtp()
if !empty(s:first_rtp)
execute 'set rtp-='.s:first_rtp
execute 'set rtp^='.s:first_rtp
endif
if s:last_rtp !=# s:first_rtp
execute 'set rtp-='.s:last_rtp
execute 'set rtp+='.s:last_rtp
endif endif
endfunction endfunction
@@ -222,30 +274,32 @@ 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()
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'])
execute printf("%s%s%s %s", (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) call s:reorg_rtp()
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()
let extra = '' let extra = ''
while 1 while 1
let c = getchar(0) let c = getchar(0)
@@ -257,62 +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(...) function! s:add(repo, ...)
let force = a:1 if a:0 > 1
let opts = { 'branch': 'master' } return s:err('Invalid number of arguments (1..2)')
if a:0 == 2
let plugin = a:2
elseif a:0 == 3
let plugin = a:2
if type(a:3) == 1
let opts.branch = a:3
elseif type(a:3) == 4
call extend(opts, a:3)
else
echoerr "Invalid argument type (expected: string or dictionary)"
return
endif
else
echoerr "Invalid number of arguments (1..2)"
return
endif endif
let name = substitute(split(plugin, '/')[-1], '\.git$', '', '') try
if !force && has_key(g:plugs, name) | return | endif let repo = s:trim(a:repo)
let name = fnamemodify(repo, ':t:s?\.git$??')
if plugin =~ ':' let spec = extend(s:infer_properties(name, repo),
let uri = plugin \ a:0 == 1 ? s:parse_options(a:1) : s:base_spec)
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 })
let g:plugs[name] = spec let g:plugs[name] = spec
let g:plugs_order += [name] let g:plugs_order += [name]
catch
return s:err(v:exception)
endtry
endfunction endfunction
function! s:install(...) function! s:parse_options(arg)
call s:update_impl(0, a:000) 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')
let opts.branch = remove(opts, 'tag')
endif
if has_key(opts, 'dir')
let opts.dir = s:dirpath(expand(opts.dir))
endif
else
throw 'Invalid argument type (expected: string or dictionary)'
endif
return opts
endfunction endfunction
function! s:update(...) function! s:infer_properties(name, repo)
call s:update_impl(1, 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:apply() function! s:install(force, ...)
call s:update_impl(0, a:force, a:000)
endfunction
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)
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()
@@ -325,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
@@ -343,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
@@ -374,6 +443,7 @@ function! s:prepare()
else else
vertical topleft new vertical topleft new
nnoremap <silent> <buffer> q :if b:plug_preview==1<bar>pc<bar>endif<bar>q<cr> nnoremap <silent> <buffer> q :if b:plug_preview==1<bar>pc<bar>endif<bar>q<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>
nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr> nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr>
@@ -394,36 +464,95 @@ 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
if a:pull let msgs = []
echo "Press 'D' to see the updated changes." if !empty(s:prev_update.errors)
call add(msgs, "Press 'R' to retry.")
endif endif
if a:pull
call add(msgs, "Press 'D' to see the updated changes.")
endif
echo join(msgs, ' ')
endfunction
function! s:retry()
if empty(s:prev_update.errors)
return
endif
call s:update_impl(s:prev_update.pull, s:prev_update.force,
\ extend(copy(s:prev_update.errors), [s:prev_update.threads]))
endfunction
function! s:is_managed(name)
return has_key(g:plugs[a:name], 'uri')
endfunction endfunction
function! s:names(...) function! s:names(...)
return filter(keys(g:plugs), 'stridx(v:val, a:1) == 0') 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 todo = empty(args) ? g:plugs : let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
\ filter(copy(g:plugs), 'index(args, v:key) >= 0') let todo = empty(args) ? filter(managed, '!v:val.frozen') :
\ filter(managed, 'index(args, v:key) >= 0')
if empty(todo) if empty(todo)
echohl WarningMsg echohl WarningMsg
@@ -438,9 +567,16 @@ function! s:update_impl(pull, args) abort
normal! 2G normal! 2G
redraw redraw
let len = len(g:plugs) if !isdirectory(g:plug_home)
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
if s:mac_gui
set noimd
endif
call s:update_parallel(a:pull, todo, threads) call s:update_parallel(a:pull, todo, threads)
catch catch
let lines = getline(4, '$') let lines = getline(4, '$')
@@ -449,54 +585,41 @@ function! s:update_impl(pull, args) abort
for line in lines for line in lines
let name = get(matchlist(line, '^. \([^:]\+\):'), 1, '') let name = get(matchlist(line, '^. \([^:]\+\):'), 1, '')
if empty(name) || !has_key(printed, name) if empty(name) || !has_key(printed, name)
let printed[name] = 1
call append('$', line) call append('$', line)
if !empty(name)
let printed[name] = 1
if line[0] == 'x' && index(s:prev_update.errors, name) < 0
call add(s:prev_update.errors, name)
end
endif
endif endif
endfor endfor
echoerr v:exception finally
let &imd = imd
endtry endtry
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 prev = copy(g:plugs)
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 filter(copy(g:plugs), '!has_key(prev, v:key)')
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)
@@ -512,34 +635,24 @@ function! s:update_serial(pull, todo)
let result = msg let result = msg
let error = 1 let error = 1
endif endif
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
cd -
let bar .= error ? 'x' : '=' let bar .= error ? 'x' : '='
if error
call add(s:prev_update.errors, name)
endif
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
if !empty(s:extend(keys(todo)))
let todo = filter(copy(g:plugs), '!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)
@@ -565,7 +678,20 @@ function! s:update_parallel(pull, todo, threads)
%["#{arg.gsub('"', '\"')}"] %["#{arg.gsub('"', '\"')}"]
end end
st = Time.now 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'
@@ -573,19 +699,19 @@ function! s:update_parallel(pull, todo, threads)
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
nthr = VIM::evaluate('a:threads').to_i nthr = VIM::evaluate('a:threads').to_i
maxy = VIM::evaluate('winheight(".")').to_i maxy = VIM::evaluate('winheight(".")').to_i
cd = iswin ? 'cd /d' : 'cd' cd = iswin ? 'cd /d' : 'cd'
tot = 0 tot = VIM::evaluate('len(a:todo)') || 0
bar = '' bar = ''
skip = 'Already installed' skip = 'Already installed'
mtx = Mutex.new mtx = Mutex.new
take1 = proc { mtx.synchronize { running && all.shift } } take1 = proc { mtx.synchronize { running && all.shift } }
logh = proc { logh = proc {
cnt = $curbuf[2][1...-1].strip.length cnt = bar.length
tot = VIM::evaluate('len(a:todo)') || tot
$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')
@@ -598,7 +724,10 @@ function! s:update_parallel(pull, todo, threads)
bar += type ? '=' : 'x' unless ing bar += type ? '=' : 'x' unless ing
b = case type b = case type
when :install then '+' when :update then '*' when :install then '+' when :update then '*'
when true, nil then '-' else 'x' end when true, nil then '-' else
VIM::command("call add(s:prev_update.errors, '#{name}')")
'x'
end
result = result =
if type || type.nil? if type || type.nil?
["#{b} #{name}: #{result.lines.to_a.last}"] ["#{b} #{name}: #{result.lines.to_a.last}"]
@@ -618,11 +747,14 @@ function! s:update_parallel(pull, todo, threads)
end end
} }
bt = proc { |cmd, name, type| bt = proc { |cmd, name, type|
tried = timeout = 0
begin begin
tried += 1
timeout += limit
fd = nil fd = nil
data = '' data = ''
if iswin if iswin
Timeout::timeout(limit) do Timeout::timeout(timeout) do
tmp = VIM::evaluate('tempname()') tmp = VIM::evaluate('tempname()')
system("#{cmd} > #{tmp}") system("#{cmd} > #{tmp}")
data = File.read(tmp).chomp data = File.read(tmp).chomp
@@ -632,7 +764,7 @@ function! s:update_parallel(pull, todo, threads)
fd = IO.popen(cmd).extend(PlugStream) fd = IO.popen(cmd).extend(PlugStream)
first_line = true first_line = true
log_prob = 1.0 / nthr log_prob = 1.0 / nthr
while line = Timeout::timeout(limit) { fd.get_line } while line = Timeout::timeout(timeout) { fd.get_line }
data << line data << line
log.call name, line.chomp, type if name && (first_line || rand < log_prob) log.call name, line.chomp, type if name && (first_line || rand < log_prob)
first_line = false first_line = false
@@ -642,19 +774,18 @@ 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
3.downto(1) do |countdown|
s = countdown > 1 ? 's' : ''
log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type
sleep 1
end
log.call name, 'Retrying ...', type
retry
end
[false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
end end
} }
@@ -671,11 +802,18 @@ function! s:update_parallel(pull, todo, threads)
threads.each { |t| t.join rescue nil } threads.each { |t| t.join rescue nil }
main.kill main.kill
} }
refresh = Thread.new {
while true
mtx.synchronize do
break unless running
VIM::command('noautocmd normal! a')
end
sleep 0.2
end
} if VIM::evaluate('s:mac_gui') == 1
progress = iswin ? '' : '--progress' progress = iswin ? '' : '--progress'
until all.empty? [all.length, nthr].min.times do
names = all.keys
[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
@@ -683,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
@@ -707,23 +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 }
all.merge!(VIM::evaluate("s:extend(#{names.inspect})") || {})
logh.call logh.call
end refresh.kill if refresh
watcher.kill watcher.kill
$curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
EOF EOF
endfunction endfunction
@@ -767,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]
@@ -804,8 +940,9 @@ function! s:clean(force)
" List of valid directories " List of valid directories
let dirs = [] let dirs = []
let [cnt, total] = [0, len(g:plugs)] let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
for spec in values(g:plugs) let [cnt, total] = [0, len(managed)]
for spec in values(managed)
if s:git_valid(spec, 0, 1)[0] if s:git_valid(spec, 0, 1)[0]
call add(dirs, spec.dir) call add(dirs, spec.dir)
endif endif
@@ -840,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
@@ -860,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'
@@ -890,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')
@@ -906,11 +1047,19 @@ function! s:status()
let ecnt = 0 let ecnt = 0
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 has_key(spec, 'uri')
if isdirectory(spec.dir) if isdirectory(spec.dir)
let [valid, msg] = s:git_valid(spec, 1, 1) let [valid, msg] = s:git_valid(spec, 1, 1)
else else
let [valid, msg] = [0, 'Not found. Try PlugInstall.'] let [valid, msg] = [0, 'Not found. Try PlugInstall.']
endif endif
else
if isdirectory(spec.dir)
let [valid, msg] = [1, 'OK']
else
let [valid, msg] = [0, 'Not found.']
endif
endif
let cnt += 1 let cnt += 1
let ecnt += !valid let ecnt += !valid
call s:progress_bar(2, repeat('=', cnt), total) call s:progress_bar(2, repeat('=', cnt), total)
@@ -973,12 +1122,12 @@ function! s:diff()
let cnt = 0 let cnt = 0
for [k, v] in items(g:plugs) for [k, v] in items(g:plugs)
if !isdirectory(v.dir) if !isdirectory(v.dir) || !s:is_managed(k)
continue continue
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.':')
@@ -995,6 +1144,9 @@ function! s:diff()
normal! gg normal! gg
endfunction endfunction
let s:first_rtp = s:esc(get(split(&rtp, ','), 0, ''))
let s:last_rtp = s:esc(get(split(&rtp, ','), -1, ''))
let &cpo = s:cpo_save let &cpo = s:cpo_save
unlet s:cpo_save unlet s:cpo_save

View File

@@ -9,13 +9,37 @@ if [ ! -d vader.vim ]; then
git clone https://github.com/junegunn/vader.vim.git git clone https://github.com/junegunn/vader.vim.git
fi fi
rm -rf fzf
if [ ! -d fzf-staged ]; then
git clone https://github.com/junegunn/fzf.git fzf-staged
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
if [ "$1" = '!' ]; then if [ "$1" = '!' ]; then
/usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'Vader! workflow.vader' > /dev/null /usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'Vader! workflow.vader' > /dev/null &&
/usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'let g:plug_threads = 1 | Vader! workflow.vader' > /dev/null
else else
/usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'Vader workflow.vader' /usr/local/bin/vim -Nu /tmp/mini-vimrc -c 'Vader workflow.vader'
fi fi

View File

@@ -1,5 +1,8 @@
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 last_rtp = split(&rtp, ',')[-1]
let vader = fnamemodify(globpath(&rtp, 'autoload/vader.vim'), ':h:h') let vader = fnamemodify(globpath(&rtp, 'autoload/vader.vim'), ':h:h')
let plug = fnamemodify(globpath(&rtp, 'autoload/plug.vim'), ':h:h') let plug = fnamemodify(globpath(&rtp, 'autoload/plug.vim'), ':h:h')
@@ -24,18 +27,17 @@ Execute (Initialize test environment):
g/^$/d g/^$/d
endfunction endfunction
let g:vimrc_reloaded = 0 function! AssertExpect(bang, pat, cnt)
let vimrc = tempname() let op = a:bang ? '==' : '=~'
call writefile(['let g:vimrc_reloaded += 1'], vimrc) AssertEqual a:cnt, len(filter(getline(1, '$'), "v:val ".op." '".a:pat."'"))
let $MYVIMRC = vimrc endfunction
command! -nargs=+ -bang AssertExpect call AssertExpect('<bang>' == '!', <args>)
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()
@@ -45,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)):
@@ -68,15 +68,21 @@ Execute (Subsequent plug#begin() calls will reuse g:plug_home):
Execute (Test Plug command): Execute (Test Plug command):
" Git repo with branch " Git repo with branch
Plug 'junegunn/seoul256.vim', 'no-t_co' Plug 'junegunn/seoul256.vim', 'yes-t_co'
AssertEqual 'https://git:@github.com/junegunn/seoul256.vim.git', g:plugs['seoul256.vim'].uri AssertEqual 'https://git:@github.com/junegunn/seoul256.vim.git', g:plugs['seoul256.vim'].uri
AssertEqual join([temp_plugged, 'seoul256.vim/'], '/'), g:plugs['seoul256.vim'].dir AssertEqual join([temp_plugged, 'seoul256.vim/'], '/'), g:plugs['seoul256.vim'].dir
AssertEqual 'yes-t_co', g:plugs['seoul256.vim'].branch
Plug 'junegunn/seoul256.vim', { 'branch': 'no-t_co' } " Using branch option
AssertEqual 'no-t_co', g:plugs['seoul256.vim'].branch AssertEqual 'no-t_co', g:plugs['seoul256.vim'].branch
" Git repo with tag " Git repo with tag
Plug 'junegunn/goyo.vim', '1.5.3' Plug 'junegunn/goyo.vim', '1.5.2'
AssertEqual 'https://git:@github.com/junegunn/goyo.vim.git', g:plugs['goyo.vim'].uri AssertEqual 'https://git:@github.com/junegunn/goyo.vim.git', g:plugs['goyo.vim'].uri
AssertEqual join([temp_plugged, 'goyo.vim/'], '/'), g:plugs['goyo.vim'].dir AssertEqual join([temp_plugged, 'goyo.vim/'], '/'), g:plugs['goyo.vim'].dir
AssertEqual '1.5.2', g:plugs['goyo.vim'].branch
Plug 'junegunn/goyo.vim', { 'tag': '1.5.3' } " Using tag option
AssertEqual '1.5.3', g:plugs['goyo.vim'].branch AssertEqual '1.5.3', g:plugs['goyo.vim'].branch
" Git URI " Git URI
@@ -103,24 +109,25 @@ Execute (Plug command with dictionary option):
Execute (PlugStatus before installation): Execute (PlugStatus before installation):
PlugStatus PlugStatus
AssertEqual 4, len(filter(getline(1, line('$')), 'v:val =~ "Not found"')) AssertExpect 'Not found', 4
q q
Execute (PlugClean before installation): Execute (PlugClean before installation):
PlugClean PlugClean
AssertEqual 1, len(filter(getline(1, line('$')), 'v:val =~ "Already clean"')) AssertExpect 'Already clean', 1
q q
Execute (plug#end() updates &rtp): Execute (plug#end() updates &rtp):
call plug#end() call plug#end()
Assert len(&rtp) > len(basertp) Assert len(&rtp) > len(basertp)
AssertEqual first_rtp, split(&rtp, ',')[0]
AssertEqual last_rtp, split(&rtp, ',')[-1]
Execute (Yet, plugins are not available): Execute (Yet, plugins are not available):
Assert empty(globpath(&rtp, 'autoload/emoji.vim')) Assert empty(globpath(&rtp, 'autoload/emoji.vim'))
Execute (PlugInstall): Execute (PlugInstall):
PlugInstall PlugInstall
AssertEqual 1, g:vimrc_reloaded
q q
Execute (Plugin available after installation): Execute (Plugin available after installation):
@@ -128,12 +135,13 @@ Execute (Plugin available after installation):
Execute (PlugClean after installation): Execute (PlugClean after installation):
PlugClean PlugClean
AssertEqual 1, len(filter(getline(1, line('$')), 'v:val =~ "Already clean"')) AssertExpect 'Already clean', 1
q q
Execute (PlugStatus after installation): Execute (PlugStatus after installation):
PlugStatus PlugStatus
AssertEqual 4, len(filter(getline(1, line('$')), 'v:val =~ "OK"')) Log getline(1, '$')
AssertExpect 'OK', 4
q q
Execute (Change tag of goyo.vim): Execute (Change tag of goyo.vim):
@@ -153,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
@@ -204,8 +211,8 @@ Expect:
Execute (PlugClean! to remove seoul256.vim): Execute (PlugClean! to remove seoul256.vim):
PlugClean! PlugClean!
" Three removed, emoji left " Three removed, emoji left
AssertEqual 3, len(filter(getline(1, line('$')), 'v:val =~ "^- "')) AssertExpect '^- ', 3
AssertEqual 1, len(filter(getline(1, line('$')), 'v:val =~ "Removed"')) AssertExpect 'Removed', 1
Assert empty(globpath(&rtp, 'colors/seoul256.vim')) Assert empty(globpath(&rtp, 'colors/seoul256.vim'))
Assert !empty(globpath(&rtp, 'autoload/emoji.vim')) Assert !empty(globpath(&rtp, 'autoload/emoji.vim'))
q q
@@ -231,24 +238,22 @@ Expect:
Execute (PlugClean! to remove vim-emoji): Execute (PlugClean! to remove vim-emoji):
PlugClean! PlugClean!
AssertEqual 1, len(filter(getline(1, line('$')), 'v:val =~ "^- "')) AssertExpect '^- ', 1
AssertEqual 1, len(filter(getline(1, line('$')), 'v:val =~ "Removed"')) AssertExpect 'Removed', 1
Assert empty(globpath(&rtp, 'colors/seoul256.vim')) Assert empty(globpath(&rtp, 'colors/seoul256.vim'))
Assert empty(globpath(&rtp, 'autoload/emoji.vim')) Assert empty(globpath(&rtp, 'autoload/emoji.vim'))
q q
Execute (PlugUpdate to install both again): Execute (PlugUpdate to install both again):
PlugUpdate PlugUpdate
AssertEqual 2, len(filter(getline(1, line('$')), 'v:val =~ "^- [^:]*:"')) 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
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
AssertEqual 2, len(filter(getline(1, line('$')), 'v:val =~ "Already up-to-date"')) 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
@@ -343,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()
@@ -354,27 +360,36 @@ Execute (Check commands):
Execute (Partial PlugInstall): Execute (Partial PlugInstall):
PlugInstall vim-fnr vim-easy-align PlugInstall vim-fnr vim-easy-align
PlugInstall vim-fnr vim-easy-align 1 AssertExpect 'vim-fnr', 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 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
@@ -384,13 +399,375 @@ Execute (On-demand loading based on filetypes):
set ft=redis set ft=redis
Assert exists(':RedisExecute'), 'RedisExecute command is now found' Assert exists(':RedisExecute'), 'RedisExecute command is now found'
Execute (Cleanup): **********************************************************************
call system('rm -rf '.temp_plugged) ~ Local (unmanaged) plugins
**********************************************************************
unlet g:plugs Execute (Add unmanaged plugin):
unlet g:plug_home let fzf = fnamemodify(g:vader_file, ':h') . '/fzf'
unlet g:vimrc_reloaded Log fzf
unlet temp_plugged vader plug basertp save_rtp repo lnum
delf PlugStatusSorted call plug#begin()
Plug fzf, { 'on': 'SomeCommand' }
call plug#end()
" Check uri field
Assert !has_key(g:plugs.fzf, 'uri'), 'Should not have uri field'
" Check dir field
AssertEqual fzf.'/', g:plugs.fzf.dir
" Trailing slashes and backslashes should be stripped
for suffix in ['///', '/\/\/']
call plug#begin()
Plug fzf.suffix, { 'on': 'SomeCommand' }
call plug#end()
" Check dir field
AssertEqual fzf.'/', g:plugs.fzf.dir
endfor
Execute (Plug block for following tests):
call plug#begin()
Plug 'junegunn/vim-easy-align'
Plug fzf, { 'on': 'SomeCommand' }
call plug#end()
" Remove plugins from previous tests
PlugClean!
Execute (PlugInstall will only install vim-easy-align):
PlugInstall
Log getline(1, '$')
AssertExpect 'fzf', 0
q
Execute (PlugUpdate will only update vim-easy-align):
PlugUpdate
Log getline(1, '$')
AssertExpect 'fzf', 0
q
Execute (PlugClean should not care about unmanaged plugins):
PlugClean
Log getline(1, '$')
AssertExpect 'fzf', 0
q
Execute (PlugStatus should point out that the plugin is missing):
PlugStatus
Log getline(1, '$')
AssertExpect 'x fzf', 1
AssertExpect 'Not found', 1
q
Execute (Deploy unmanaged plugin):
Assert !exists(':FZF'), ':FZF command should not exist'
call rename('fzf-staged', 'fzf')
Execute (PlugUpdate still should not care):
PlugUpdate
Log getline(1, '$')
AssertExpect 'fzf', 0
q
Execute (PlugStatus with no error):
PlugStatus
Log getline(1, '$')
AssertExpect 'x fzf', 0
AssertExpect 'Not found', 0
q
Execute (Check &rtp after SomeCommand):
Log &rtp
Assert &rtp !~ 'fzf'
silent! SomeCommand
Assert &rtp =~ 'fzf'
AssertEqual first_rtp, split(&rtp, ',')[0]
AssertEqual last_rtp, split(&rtp, ',')[-1]
Execute (Common parent):
call plug#begin()
Plug 'junegunn/vim-pseudocl'
Plug 'junegunn/vim-fnr'
Plug 'junegunn/vim-oblique'
call plug#end()
PlugInstall
Log getline(1, '$')
AssertExpect! '[===]', 1
q
**********************************************************************
~ Frozen plugins
**********************************************************************
Execute (Frozen plugin are not installed nor updated):
call plug#begin()
Plug 'junegunn/vim-easy-align', { 'frozen': 1 }
call plug#end()
redir => output
silent PlugInstall
redir END
Assert output =~ 'No plugin to install'
redir => output
silent PlugUpdate
redir END
Assert output =~ 'No plugin to update'
Execute (But you can still install it if the name is given as the argument):
PlugInstall vim-easy-align
Log getline(1, '$')
AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "vim-easy-align"'))
q
PlugUpdate vim-easy-align
Log getline(1, '$')
AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ "vim-easy-align"'))
q
**********************************************************************
~ Retry
**********************************************************************
Execute (Retry failed tasks):
call plug#begin()
Plug 'junegunn/vim-easy-align'
Plug 'junegunn/aaaaaaaaaaaaaa'
call plug#end()
PlugInstall
Log getline(1, '$')
AssertExpect 'x aaa', 1
AssertExpect '- vim-easy-align', 1
normal R
Log getline(1, '$')
AssertExpect 'x aaa', 1
AssertExpect '- vim-easy-align', 0
AssertExpect! '[x]', 1
q
call plug#begin()
Plug 'junegunn/vim-easy-align'
Plug 'junegunn/aaaaaaaaaaaaaa'
Plug 'junegunn/bbbbbbbbbbbbbb'
Plug 'junegunn/cccccccccccccc'
call plug#end()
" Ruby installer
PlugUpdate
normal R
AssertExpect '- vim-easy-align', 0
AssertExpect! '[xxx]', 1
q
" Vim installer
PlugUpdate 1
normal R
AssertExpect '- vim-easy-align', 0
AssertExpect! '[xxx]', 1
q
**********************************************************************
~ Post-update hook (`do` option)
**********************************************************************
Execute (Cleanup):
call plug#begin()
call plug#end()
PlugClean!
Execute (On install):
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