34 Commits
0.4.1 ... 0.5.4

Author SHA1 Message Date
Junegunn Choi
f7ebba7b9e Improve PlugDiff: 'X' key to revert the update 2014-08-10 16:52:26 +09:00
Junegunn Choi
6272f5e289 Improve PlugStatus
- Display load status
- Load plugin with 'L' key

(This commit also allows not loading a plugin with `'for': []`. It used
to load ftdetect files.)
2014-08-10 13:46:46 +09:00
Junegunn Choi
f43067c7a5 Merge pull request #51 from junegunn/public-api
Add plug#helptags and plug#load (#48)
2014-08-09 23:44:59 +09:00
Junegunn Choi
e6cba28997 Fix error messages 2014-08-09 13:11:41 +09:00
Junegunn Choi
f1b8832a13 Add plug#load() (#48) 2014-08-09 12:59:20 +09:00
Junegunn Choi
d0c94a9b08 Add plug#helptags() 2014-08-09 12:58:16 +09:00
Junegunn Choi
3a2e406cd0 Merge pull request #47 from junegunn/fix-upgrade
Do not require reloading of .vimrc after PlugUpgrade
2014-08-05 19:09:17 +09:00
Junegunn Choi
84cdf61730 Do not require reloading of .vimrc after PlugUpgrade 2014-08-05 18:52:19 +09:00
Junegunn Choi
0aeea1db08 Update README.md 2014-08-05 15:32:28 +09:00
Junegunn Choi
8289477d18 Revert "Make sure update/install after PlugUpgrade work"
This reverts commit 19b12e2216.

No luck. The user still have to reload .vimrc anyway. Let's just make it
clear that a restart can be required after PlugUpgrade.
2014-08-05 01:50:03 +09:00
Junegunn Choi
19b12e2216 Make sure update/install after PlugUpgrade work
By not assuming `frozen` property exists. I tried to fix it with
s:upgrade_specs, but it has no effect if the old version of vim-plug
doesn't know about it.
2014-08-05 01:43:42 +09:00
Junegunn Choi
4c9ebe9c31 Add -bar option to commands 2014-08-05 01:31:19 +09:00
Junegunn Choi
74dcd13575 s:upgrade_specs should be called after reloading the source 2014-08-05 01:25:34 +09:00
Junegunn Choi
518f20652f Merge pull request #46 from vheon/fix-multiple-create-directory
Do not try to create g:plug_home more than once
2014-08-05 00:56:26 +09:00
Andrea Cedraro
665ec057d7 Do not try to create g:plug_home more than once 2014-08-04 17:43:34 +02:00
Junegunn Choi
bc212dca77 Merge pull request #45 from junegunn/travis-ci-rubies
Test against multiple versions of Ruby
2014-08-04 16:40:11 +09:00
Junegunn Choi
8da7b50fb2 Test against multiple versions of Ruby
As discussed in junegunn/vim-plug#31
2014-08-04 16:31:05 +09:00
Junegunn Choi
4ae2e879e1 Note on escaping double quotes in inline expression 2014-08-02 14:04:03 +09:00
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
5 changed files with 573 additions and 392 deletions

View File

@@ -1,4 +1,7 @@
language: vim language: ruby
rvm:
- 1.8.7
- 2.0.0
before_script: | before_script: |
hg clone https://code.google.com/p/vim/ hg clone https://code.google.com/p/vim/

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
@@ -29,7 +25,8 @@ and put it in ~/.vim/autoload
```sh ```sh
mkdir -p ~/.vim/autoload mkdir -p ~/.vim/autoload
curl -fLo ~/.vim/autoload/plug.vim https://raw.github.com/junegunn/vim-plug/master/plug.vim curl -fLo ~/.vim/autoload/plug.vim \
https://raw.github.com/junegunn/vim-plug/master/plug.vim
``` ```
Edit your .vimrc Edit your .vimrc
@@ -51,8 +48,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()
``` ```
@@ -61,14 +61,14 @@ Reload .vimrc and `:PlugInstall` to install plugins.
### Commands ### Commands
| Command | Description | | Command | Description |
| --------------------------------- | ------------------------------------------------------------------ | | ----------------------------------- | ------------------------------------------------------------------ |
| PlugInstall [name ...] [#threads] | Install plugins | | `PlugInstall [name ...] [#threads]` | Install plugins |
| PlugUpdate [name ...] [#threads] | Install or update plugins | | `PlugUpdate [name ...] [#threads]` | Install or update plugins |
| PlugClean[!] | Remove unused directories (bang version will clean without prompt) | | `PlugClean[!]` | Remove unused directories (bang version will clean without prompt) |
| PlugUpgrade | Upgrade vim-plug itself | | `PlugUpgrade` | Upgrade vim-plug itself |
| PlugStatus | Check the status of plugins | | `PlugStatus` | Check the status of plugins |
| PlugDiff | See the updated changes from the previous PlugUpdate | | `PlugDiff` | See the updated changes from the previous PlugUpdate |
### `Plug` options ### `Plug` options
@@ -96,6 +96,10 @@ Reload .vimrc and `:PlugInstall` to install plugins.
- `S` - `PlugStatus` - `S` - `PlugStatus`
- `R` - Retry failed update or installation tasks - `R` - Retry failed update or installation tasks
- `q` - Close the window - `q` - Close the window
- `:PlugStatus`
- `L` - Load plugin
- `:PlugDiff`
- `X` - Revert the update
### Example: A small [sensible](https://github.com/tpope/vim-sensible) Vim configuration ### Example: A small [sensible](https://github.com/tpope/vim-sensible) Vim configuration
@@ -121,7 +125,7 @@ Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
Plug 'junegunn/vader.vim', { 'on': 'Vader', 'for': 'vader' } Plug 'junegunn/vader.vim', { 'on': 'Vader', 'for': 'vader' }
``` ```
### Post-installation/update hooks ### Post-update hooks
There are some plugins that require extra steps after installation or update. There are some plugins that require extra steps after installation or update.
In that case, use `do` option to describe the task to be performed. In that case, use `do` option to describe the task to be performed.
@@ -135,10 +139,11 @@ takes a single argument.
```vim ```vim
function! BuildYCM(info) function! BuildYCM(info)
" info is a dictionary with two fields " info is a dictionary with 3 fields
" - name: name of the plugin " - name: name of the plugin
" - status: 'installed' or 'updated' " - status: 'installed', 'updated', or 'unchanged'
if a:info.status == 'installed' " - force: set on PlugInstall! or PlugUpdate!
if a:info.status == 'installed' || a:info.force
!./install.sh !./install.sh
endif endif
endfunction endfunction
@@ -146,10 +151,14 @@ endfunction
Plug 'Valloric/YouCompleteMe', { 'do': function('BuildYCM') } Plug 'Valloric/YouCompleteMe', { 'do': function('BuildYCM') }
``` ```
Both forms of post-update hook are executed inside the directory of the plugin. 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 Make sure to escape BARs and double-quotes when you write `do` option inline
mistakenly recognized as command separator for Plug command. as they are mistakenly recognized as command separator or the start of the
trailing comment.
```vim ```vim
Plug 'junegunn/fzf', { 'do': 'yes \| ./install' } Plug 'junegunn/fzf', { 'do': 'yes \| ./install' }
@@ -163,79 +172,16 @@ let g:fzf_install = 'yes | ./install'
Plug 'junegunn/fzf', { 'do': g:fzf_install } Plug 'junegunn/fzf', { 'do': g:fzf_install }
``` ```
### Dependency resolution ### FAQ/Troubleshooting
See [Dependency See [FAQ/Troubleshooting](https://github.com/junegunn/vim-plug/wiki/faq).
Resolution](https://github.com/junegunn/vim-plug/wiki/Dependency-Resolution).
### 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) - [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.
#### Migrating from other plugin managers
vim-plug does not require any extra statement other than `plug#begin()` and
`plug#end()`. You can remove `filetype off`, `filetype plugin indent on` and
`syntax on` from your .vimrc as they are automatically handled by
`plug#end()`.
### License ### License

540
plug.vim
View File

@@ -25,8 +25,11 @@
" " 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()
" "
@@ -66,18 +69,18 @@ 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 = get(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, 'local': 0 } let s:base_spec = { 'branch': 'master', 'frozen': 0 }
let s:TYPE = { let s:TYPE = {
\ 'string': type(''), \ 'string': type(''),
\ 'list': type([]), \ 'list': type([]),
\ 'dict': type({}), \ 'dict': type({}),
\ 'funcref': type(function('call')) \ 'funcref': type(function('call'))
\ } \ }
let s:loaded = get(s:, 'loaded', {})
function! plug#begin(...) function! plug#begin(...)
if a:0 > 0 if a:0 > 0
@@ -90,13 +93,6 @@ function! plug#begin(...)
return s:err('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.')
endif endif
if !isdirectory(home)
try
call mkdir(home, 'p')
catch
return s:err('Invalid plug directory: '. home)
endtry
endif
if !executable('git') if !executable('git')
return s:err('`git` executable not found. vim-plug requires git.') return s:err('`git` executable not found. vim-plug requires git.')
endif endif
@@ -106,31 +102,37 @@ 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>) call s:define_commands()
command! -nargs=* -complete=customlist,s:names PlugInstall call s:install(<f-args>)
command! -nargs=* -complete=customlist,s:names PlugUpdate call s:update(<f-args>)
command! -nargs=0 -bang PlugClean call s:clean('<bang>' == '!')
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 PlugDiff call s:diff()
return 1 return 1
endfunction endfunction
function! s:define_commands()
command! -nargs=+ -bar Plug call s:add(<args>)
command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install('<bang>' == '!', <f-args>)
command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update('<bang>' == '!', <f-args>)
command! -nargs=0 -bar -bang PlugClean call s:clean('<bang>' == '!')
command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source '. s:me | endif
command! -nargs=0 -bar PlugStatus call s:status()
command! -nargs=0 -bar PlugDiff call s:diff()
endfunction
function! s:to_a(v) function! s:to_a(v)
return type(a:v) == s:TYPE.list ? a:v : [a:v] return type(a:v) == s:TYPE.list ? a:v : [a:v]
endfunction 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
function! plug#end() function! plug#end()
let reload = !has('vim_starting')
if !exists('g:plugs') if !exists('g:plugs')
return s:err('Call plug#begin() first') return s:err('Call plug#begin() first')
endif endif
let keys = keys(g:plugs)
let plugfiles = s:find_plugfiles()
while !empty(keys)
" No need to look for Plugfiles more than once
let keys = keys(s:extend(keys, plugfiles))
endwhile
if exists('#PlugLOD') if exists('#PlugLOD')
augroup PlugLOD augroup PlugLOD
@@ -147,14 +149,16 @@ function! plug#end()
" need to loop through the plugins in reverse " need to loop through the plugins in reverse
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 get(s:loaded, plug.dir, 0) || !has_key(plug, 'on') && !has_key(plug, 'for')
call s:add_rtp(s:rtp(plug)) let rtp = s:add_rtp(plug)
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
@@ -173,10 +177,11 @@ function! plug#end()
endif endif
if has_key(plug, 'for') if has_key(plug, 'for')
for vim in split(globpath(s:rtp(plug), 'ftdetect/**/*.vim'), '\n') let types = s:to_a(plug.for)
execute 'source '.vim if !empty(types)
endfor call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim')
for key in s:to_a(plug.for) endif
for key in types
if !has_key(lod, key) if !has_key(lod, key)
let lod[key] = [] let lod[key] = []
endif endif
@@ -245,12 +250,15 @@ 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(plug)
execute 'set rtp^='.s:esc(a:rtp) let rtp = s:rtp(a:plug)
let after = globpath(a:rtp, 'after') execute 'set rtp^='.s:esc(rtp)
let after = globpath(rtp, 'after')
if isdirectory(after) if isdirectory(after)
execute 'set rtp+='.s:esc(after) execute 'set rtp+='.s:esc(after)
endif endif
let s:loaded[a:plug.dir] = 1
return rtp
endfunction endfunction
function! s:reorg_rtp() function! s:reorg_rtp()
@@ -264,28 +272,46 @@ function! s:reorg_rtp()
endif endif
endfunction endfunction
function! plug#load(...)
if a:0 == 0
return s:err('Argument missing: plugin name(s) required')
endif
if !exists('g:plugs')
return s:err('plug#begin was not called')
endif
let unknowns = filter(copy(a:000), '!has_key(g:plugs, v:val)')
if !empty(unknowns)
let s = len(unknowns) > 1 ? 's' : ''
return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', ')))
end
for name in a:000
call s:lod(g:plugs[name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
endfor
call s:reorg_rtp()
silent! doautocmd BufRead
return 1
endfunction
function! s:lod(plug, types) function! s:lod(plug, types)
let rtp = s:rtp(a:plug) let rtp = s:add_rtp(a:plug)
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
@@ -293,7 +319,7 @@ 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
@@ -306,7 +332,7 @@ 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, repo, ...) function! s:add(repo, ...)
if a:0 > 1 if a:0 > 1
return s:err('Invalid number of arguments (1..2)') return s:err('Invalid number of arguments (1..2)')
endif endif
@@ -314,19 +340,11 @@ function! s:add(force, repo, ...)
try try
let repo = s:trim(a:repo) let repo = s:trim(a:repo)
let name = fnamemodify(repo, ':t:s?\.git$??') let name = fnamemodify(repo, ':t:s?\.git$??')
if !a:force && has_key(g:plugs, name)
let s:extended[name] = g:plugs[name]
return
endif
let spec = extend(s:infer_properties(name, repo), let spec = extend(s:infer_properties(name, repo),
\ a:0 == 1 ? s:parse_options(a:1) : copy(s:base_spec)) \ a:0 == 1 ? s:parse_options(a:1) : s:base_spec)
if !a:force
let s:extended[name] = spec
endif
let g:plugs[name] = spec let g:plugs[name] = spec
let g:plugs_order += [name] let g:plugs_order += [name]
let s:loaded[spec.dir] = 0
catch catch
return s:err(v:exception) return s:err(v:exception)
endtry endtry
@@ -354,7 +372,7 @@ endfunction
function! s:infer_properties(name, repo) function! s:infer_properties(name, repo)
let repo = a:repo let repo = a:repo
if s:is_local_plug(repo) if s:is_local_plug(repo)
let properties = { 'dir': s:dirpath(expand(repo)), 'local': 1 } return { 'dir': s:dirpath(expand(repo)) }
else else
if repo =~ ':' if repo =~ ':'
let uri = repo let uri = repo
@@ -365,29 +383,29 @@ function! s:infer_properties(name, repo)
let uri = 'https://git:@github.com/' . repo . '.git' let uri = 'https://git:@github.com/' . repo . '.git'
endif endif
let dir = s:dirpath( fnamemodify(join([g:plug_home, a:name], '/'), ':p') ) let dir = s:dirpath( fnamemodify(join([g:plug_home, a:name], '/'), ':p') )
let properties = { 'dir': dir, 'uri': uri } return { 'dir': dir, 'uri': uri }
endif endif
return properties
endfunction endfunction
function! s:install(...) function! s:install(force, ...)
call s:update_impl(0, a:000) call s:update_impl(0, a:force, a:000)
endfunction endfunction
function! s:update(...) function! s:update(force, ...)
call s:update_impl(1, a:000) call s:update_impl(1, a:force, a:000)
endfunction endfunction
function! s:apply() function! plug#helptags()
if !exists('g:plugs')
return s:err('plug#begin was not called')
endif
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 return 1
runtime! after/*.vim
silent! source $MYVIMRC
endfunction endfunction
function! s:syntax() function! s:syntax()
@@ -407,6 +425,7 @@ function! s:syntax()
syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha
syn match plugSha /\(^ \)\@<=[0-9a-z]\{7}/ contained syn match plugSha /\(^ \)\@<=[0-9a-z]\{7}/ contained
syn match plugRelDate /([^)]*)$/ contained syn match plugRelDate /([^)]*)$/ contained
syn match plugNotLoaded /(not loaded)$/
syn match plugError /^x.*/ syn match plugError /^x.*/
syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
hi def link plug1 Title hi def link plug1 Title
@@ -427,6 +446,8 @@ function! s:syntax()
hi def link plugError Error hi def link plugError Error
hi def link plugRelDate Comment hi def link plugRelDate Comment
hi def link plugSha Identifier hi def link plugSha Identifier
hi def link plugNotLoaded Comment
endfunction endfunction
function! s:lpad(str, len) function! s:lpad(str, len)
@@ -447,6 +468,7 @@ function! s:prepare()
else else
execute winnr . 'wincmd w' execute winnr . 'wincmd w'
endif endif
setlocal modifiable
silent %d _ silent %d _
else else
vertical topleft new vertical topleft new
@@ -461,7 +483,9 @@ function! s:prepare()
call s:assign_name() call s:assign_name()
endif endif
silent! unmap <buffer> <cr> silent! unmap <buffer> <cr>
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline silent! unmap <buffer> L
silent! unmap <buffer> X
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline modifiable
setf vim-plug setf vim-plug
call s:syntax() call s:syntax()
endfunction endfunction
@@ -478,15 +502,16 @@ function! s:assign_name()
silent! execute 'f '.fnameescape(name) silent! execute 'f '.fnameescape(name)
endfunction endfunction
function! s:do(pull, todo) function! s:do(pull, force, todo)
for [name, spec] in items(a:todo) for [name, spec] in items(a:todo)
if !isdirectory(spec.dir) if !isdirectory(spec.dir)
continue continue
endif endif
execute 'cd '.s:esc(spec.dir) execute 'cd '.s:esc(spec.dir)
let installed = has_key(s:prev_update.new, name) let installed = has_key(s:prev_update.new, name)
if installed || (a:pull && let updated = installed ? 0 :
\ !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"'))) \ (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 .' ... ') call append(3, '- Post-update hook for '. name .' ... ')
let type = type(spec.do) let type = type(spec.do)
if type == s:TYPE.string if type == s:TYPE.string
@@ -501,7 +526,8 @@ function! s:do(pull, todo)
endtry endtry
elseif type == s:TYPE.funcref elseif type == s:TYPE.funcref
try try
call spec.do({ 'name': name, 'status': (installed ? 'installed' : 'updated') }) let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
call spec.do({ 'name': name, 'status': status, 'force': a:force })
let result = 'Done!' let result = 'Done!'
catch catch
let result = 'Error: ' . v:exception let result = 'Error: ' . v:exception
@@ -518,10 +544,11 @@ endfunction
function! s:finish(pull) function! s:finish(pull)
call append(3, '- Finishing ... ') call append(3, '- Finishing ... ')
redraw redraw
call s:apply() call plug#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)
@@ -537,7 +564,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
@@ -549,7 +576,7 @@ 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 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]*$') ?
@@ -566,17 +593,22 @@ function! s:update_impl(pull, args) abort
return return
endif endif
if !isdirectory(g:plug_home)
try
call mkdir(g:plug_home, 'p')
catch
return s:err(printf('Invalid plug directory: %s.'
\ 'Try to call plug#begin with a valid directory', g:plug_home))
endtry
endif
call s:prepare() call s:prepare()
call append(0, a:pull ? 'Updating plugins' : 'Installing plugins') call append(0, a:pull ? 'Updating plugins' : 'Installing plugins')
call append(1, '['. s:lpad('', len(todo)) .']') call append(1, '['. s:lpad('', len(todo)) .']')
normal! 2G normal! 2G
redraw redraw
if !isdirectory(g:plug_home) let s:prev_update = { 'errors': [], 'pull': a:pull, 'force': a:force, 'new': {}, 'threads': threads }
call mkdir(g:plug_home, 'p')
endif
let len = len(g:plugs)
let s:prev_update = { 'errors': [], 'pull': a:pull, 'new': {}, 'threads': threads }
if has('ruby') && threads > 1 if has('ruby') && threads > 1
try try
let imd = &imd let imd = &imd
@@ -606,44 +638,11 @@ 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
call s:do(a:pull, filter(copy(todo), 'has_key(v:val, "do")')) call s:do(a:pull, a:force, filter(copy(todo), 'has_key(v:val, "do")'))
if len(g:plugs) > len
call plug#end()
endif
call s:finish(a:pull) call s:finish(a:pull)
call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(st)))[0] . ' sec.') call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(st)))[0] . ' sec.')
endfunction endfunction
function! s:find_plugfiles()
let plugfiles = {}
for pf in split(globpath(g:plug_home, '*/'.s:plug_file), '\n')
let plugfiles[fnamemodify(pf, ':h:t')] = pf
endfor
return plugfiles
endfunction
function! s:extend(names, ...)
let s:extended = {}
let plugfiles = a:0 > 0 ? a:1 : s:find_plugfiles()
try
command! -nargs=+ Plug call s:add(0, <args>)
for name in a:names
let spec = g:plugs[name]
if spec.local
let plugfile = globpath(s:rtp(spec), s:plug_file)
if filereadable(plugfile)
execute 'source '. s:esc(plugfile)
endif
elseif has_key(plugfiles, name)
execute 'source '. s:esc(plugfiles[name])
endif
endfor
finally
command! -nargs=+ Plug call s:add(1, <args>)
endtry
return s:extended
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.')')
@@ -659,50 +658,39 @@ function! s:update_serial(pull, 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) execute 'cd '.s:esc(spec.dir)
execute 'cd '.s:esc(spec.dir) let [valid, msg] = s:git_valid(spec, 0, 0)
let [valid, msg] = s:git_valid(spec, 0, 0) if valid
if valid let result = a:pull ?
let result = a:pull ? \ s:system(
\ s:system( \ printf('git checkout -q %s 2>&1 && git pull origin %s 2>&1 && git submodule update --init --recursive 2>&1',
\ printf('git checkout -q %s 2>&1 && git pull origin %s 2>&1 && git submodule update --init --recursive 2>&1', \ s:shellesc(spec.branch), s:shellesc(spec.branch))) : 'Already installed'
\ s:shellesc(spec.branch), s:shellesc(spec.branch))) : 'Already installed' let error = a:pull ? v:shell_error != 0 : 0
let error = a:pull ? v:shell_error != 0 : 0
else
let result = msg
let error = 1
endif
cd -
else else
let result = s:system( let result = msg
\ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1', let error = 1
\ s:shellesc(spec.uri),
\ s:shellesc(spec.branch),
\ s:shellesc(s:trim(spec.dir)),
\ s:shellesc(spec.dir)))
let error = v:shell_error != 0
if !error | let s:prev_update.new[name] = 1 | endif
endif endif
let bar .= error ? 'x' : '=' cd -
if error
call add(s:prev_update.errors, name)
endif
call append(3, s:format_message(!error, name, result))
call s:update_progress(a:pull, len(done), bar, total)
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 else
break let result = s:system(
\ 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.branch),
\ s:shellesc(s:trim(spec.dir)),
\ s:shellesc(spec.dir)))
let error = v:shell_error != 0
if !error | let s:prev_update.new[name] = 1 | endif
endif endif
endwhile let bar .= error ? 'x' : '='
if error
call add(s:prev_update.errors, name)
endif
call append(3, s:format_message(!error, name, result))
call s:update_progress(a:pull, len(done), bar, total)
endfor
endfunction endfunction
function! s:update_parallel(pull, todo, threads) function! s:update_parallel(pull, todo, threads)
@@ -728,7 +716,20 @@ 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'
@@ -736,7 +737,7 @@ 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 tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1
nthr = VIM::evaluate('a:threads').to_i nthr = VIM::evaluate('a:threads').to_i
@@ -811,17 +812,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
@@ -859,63 +850,52 @@ 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 mtx.synchronize do
processed.merge names threads << Thread.new {
[names.length, nthr].min.times do while pair = take1.call
mtx.synchronize do name = pair.first
threads << Thread.new { dir, uri, branch = pair.last.values_at *%w[dir uri branch]
while pair = take1.call branch = esc branch
name = pair.first subm = "git submodule update --init --recursive 2>&1"
dir, uri, branch = pair.last.values_at *%w[dir uri branch] exists = File.directory? dir
branch = esc branch ok, result =
subm = "git submodule update --init --recursive 2>&1" if exists
exists = File.directory? dir dir = esc dir
ok, result = ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil
if exists current_uri = data.lines.to_a.last
dir = esc dir if !ret
ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil if data =~ /^Interrupted|^Timeout/
current_uri = data.lines.to_a.last [false, data]
if !ret
if data =~ /^Interrupted|^Timeout/
[false, data]
else
[false, [data.chomp, "PlugClean required."].join($/)]
end
elsif current_uri.sub(/git:@/, '') != uri.sub(/git:@/, '')
[false, ["Invalid URI: #{current_uri}",
"Expected: #{uri}",
"PlugClean required."].join($/)]
else else
if pull [false, [data.chomp, "PlugClean required."].join($/)]
log.call name, 'Updating ...', :update
bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && (git pull origin #{branch} #{progress} 2>&1 && #{subm})", name, :update
else
[true, skip]
end
end end
elsif current_uri.sub(/git:@/, '') != uri.sub(/git:@/, '')
[false, ["Invalid URI: #{current_uri}",
"Expected: #{uri}",
"PlugClean required."].join($/)]
else else
d = esc dir.sub(%r{[\\/]+$}, '') if pull
log.call name, 'Installing ...', :install log.call name, 'Updating ...', :update
bt.call "(git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && #{subm})", name, :install bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && (git pull origin #{branch} #{progress} 2>&1 && #{subm})", name, :update
else
[true, skip]
end
end end
mtx.synchronize { VIM::command("let s:prev_update.new['#{name}'] = 1") } if !exists && ok else
log.call name, result, ok d = esc dir.sub(%r{[\\/]+$}, '')
end log.call name, 'Installing ...', :install
} if running 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
end
} if running
end end
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
end end
threads.each { |t| t.join rescue nil }
logh.call
refresh.kill if refresh refresh.kill if refresh
watcher.kill watcher.kill
EOF EOF
@@ -1062,16 +1042,13 @@ function! s:upgrade()
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
unlet g:loaded_plug
echo 'Downloaded '. s:plug_source
return 1
else
return s:err('Error upgrading vim-plug') return s:err('Error upgrading vim-plug')
endif endif
elseif has('ruby') elseif has('ruby')
echo 'Downloading '. s:plug_source echo 'Downloading '. s:plug_source
ruby << EOF try
ruby << EOF
require 'open-uri' require 'open-uri'
require 'fileutils' require 'fileutils'
me = VIM::evaluate('s:me') me = VIM::evaluate('s:me')
@@ -1083,18 +1060,21 @@ function! s:upgrade()
FileUtils.cp me, old FileUtils.cp me, old
File.rename new, me File.rename new, me
EOF EOF
unlet g:loaded_plug catch
echo 'Downloaded '. s:plug_source return s:err('Error upgrading vim-plug')
return 1 endtry
else else
return s:err('curl executable or ruby support not found') return s:err('curl executable or ruby support not found')
endif endif
unlet g:loaded_plug
echo 'Downloaded '. s:plug_source
return 1
endfunction endfunction
function! s:upgrade_specs() function! s:upgrade_specs()
for spec in values(g:plugs) for spec in values(g:plugs)
let spec.frozen = get(spec, 'frozen', 0) let spec.frozen = get(spec, 'frozen', 0)
let spec.local = get(spec, 'local', 0)
endfor endfor
endfunction endfunction
@@ -1104,6 +1084,7 @@ function! s:status()
call append(1, '') call append(1, '')
let ecnt = 0 let ecnt = 0
let unloaded = 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 has_key(spec, 'uri')
@@ -1121,6 +1102,11 @@ function! s:status()
endif endif
let cnt += 1 let cnt += 1
let ecnt += !valid let ecnt += !valid
" `s:loaded` entry can be missing if PlugUpgraded
if valid && get(s:loaded, spec.dir, -1) == 0
let unloaded = 1
let msg .= ' (not loaded)'
endif
call s:progress_bar(2, repeat('=', cnt), total) call s:progress_bar(2, repeat('=', cnt), total)
call append(3, s:format_message(valid, name, msg)) call append(3, s:format_message(valid, name, msg))
normal! 2G normal! 2G
@@ -1128,6 +1114,24 @@ function! s:status()
endfor endfor
call setline(1, 'Finished. '.ecnt.' error(s).') call setline(1, 'Finished. '.ecnt.' error(s).')
normal! gg normal! gg
setlocal nomodifiable
if unloaded
echo "Press 'L' on each line to load plugin"
nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
end
endfunction
function! s:status_load(lnum)
let line = getline(a:lnum)
let matches = matchlist(line, '^- \([^:]*\):.*(not loaded)$')
if !empty(matches)
let name = matches[1]
call plug#load(name)
setlocal modifiable
call setline(a:lnum, substitute(line, ' (not loaded)$', '', ''))
setlocal nomodifiable
endif
endfunction endfunction
function! s:is_preview_window_open() function! s:is_preview_window_open()
@@ -1139,34 +1143,43 @@ function! s:is_preview_window_open()
return 0 return 0
endfunction endfunction
function! s:find_name(lnum)
for lnum in reverse(range(1, a:lnum))
let line = getline(lnum)
if empty(line)
return ''
endif
let name = matchstr(line, '\(^- \)\@<=[^:]\+')
if !empty(name)
return name
endif
endfor
return ''
endfunction
function! s:preview_commit() function! s:preview_commit()
if b:plug_preview < 0 if b:plug_preview < 0
let b:plug_preview = !s:is_preview_window_open() let b:plug_preview = !s:is_preview_window_open()
endif endif
let sha = matchstr(getline('.'), '\(^ \)\@<=[0-9a-z]\{7}') let sha = matchstr(getline('.'), '\(^ \)\@<=[0-9a-z]\{7}')
if !empty(sha) if empty(sha)
let lnum = line('.') return
while lnum > 1
let lnum -= 1
let line = getline(lnum)
let name = matchstr(line, '\(^- \)\@<=[^:]\+')
if !empty(name)
let dir = g:plugs[name].dir
if isdirectory(dir)
execute 'cd '.s:esc(dir)
execute 'pedit '.sha
wincmd P
setlocal filetype=git buftype=nofile nobuflisted
execute 'silent read !git show '.sha
normal! ggdd
wincmd p
cd -
endif
break
endif
endwhile
endif endif
let name = s:find_name(line('.'))
if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir)
return
endif
execute 'cd '.s:esc(g:plugs[name].dir)
execute 'pedit '.sha
wincmd P
setlocal filetype=git buftype=nofile nobuflisted
execute 'silent read !git show '.sha
normal! ggdd
wincmd p
cd -
endfunction endfunction
function! s:section(flags) function! s:section(flags)
@@ -1200,12 +1213,39 @@ function! s:diff()
call setline(1, cnt == 0 ? 'No updates.' : 'Last update:') call setline(1, cnt == 0 ? 'No updates.' : 'Last update:')
nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr> nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr>
nnoremap <silent> <buffer> X :call <SID>revert()<cr>
normal! gg normal! gg
setlocal nomodifiable
if cnt > 0
echo "Press 'X' on each block to revert the update"
endif
endfunction
function! s:revert()
let name = s:find_name(line('.'))
if empty(name) || !has_key(g:plugs, name) ||
\ input(printf('Revert the update of %s? (Y/N) ', name)) !~? '^y'
return
endif
execute 'cd '.s:esc(g:plugs[name].dir)
call system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch))
cd -
setlocal modifiable
normal! dap
setlocal nomodifiable
echo 'Reverted.'
endfunction endfunction
let s:first_rtp = s:esc(get(split(&rtp, ','), 0, '')) let s:first_rtp = s:esc(get(split(&rtp, ','), 0, ''))
let s:last_rtp = s:esc(get(split(&rtp, ','), -1, '')) let s:last_rtp = s:esc(get(split(&rtp, ','), -1, ''))
if exists('g:plugs')
let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs))
call s:upgrade_specs()
call s:define_commands()
endif
let &cpo = s:cpo_save let &cpo = s:cpo_save
unlet s:cpo_save unlet s:cpo_save

View File

@@ -14,8 +14,34 @@ 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:$2 = get(g:, '$2', [])
call add(g:$2, '${1:4}/$d')
EOF
done
cd - > /dev/null
}
make_dirs xxx/ xxx
make_dirs xxx/after xxx
mkdir xxx/doc
cat > xxx/doc/xxx.txt << DOC
hello *xxx*
DOC
make_dirs yyy/ yyy
make_dirs z1/ z1
make_dirs z2/ z2
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,10 +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 Execute (Print Ruby version):
let vimrc = tempname() redir => out
call writefile(['let g:vimrc_reloaded += 1'], vimrc) silent ruby puts RUBY_VERSION
let $MYVIMRC = vimrc redir END
Log substitute(out, '\n', '', 'g')
Execute (plug#end() before plug#begin() should fail): Execute (plug#end() before plug#begin() should fail):
redir => out redir => out
@@ -133,7 +134,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):
@@ -167,7 +167,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
@@ -254,7 +253,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
@@ -262,7 +260,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
@@ -310,6 +307,13 @@ Execute (Rollback recent updates, PlugUpdate, then PlugDiff):
AssertEqual lnum, line('.') AssertEqual lnum, line('.')
AssertEqual 3, col('.') AssertEqual 3, col('.')
" X key to revert the update
AssertExpect '^- ', 2
execute "normal Xn\<cr>"
AssertExpect '^- ', 2
execute "normal Xy\<cr>"
AssertExpect '^- ', 1
" q will close preview window as well " q will close preview window as well
normal q normal q
@@ -320,6 +324,7 @@ Execute (Rollback recent updates, PlugUpdate, then PlugDiff):
" q should not close preview window if it's already open " q should not close preview window if it's already open
pedit pedit
PlugDiff PlugDiff
AssertExpect '^- ', 1
execute "normal ]]j\<cr>" execute "normal ]]j\<cr>"
normal q normal q
@@ -333,8 +338,8 @@ Execute (Plug window in a new tab):
set buftype=nofile set buftype=nofile
PlugUpdate PlugUpdate
normal D normal D
AssertEqual 'No updates.', getline(1) AssertExpect '^- ', 1
q normal q
AssertEqual 'new-tab', expand('%') AssertEqual 'new-tab', expand('%')
q q
q q
@@ -357,7 +362,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()
@@ -368,24 +374,29 @@ 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):
@@ -509,15 +520,15 @@ Execute (Frozen plugin are not installed nor updated):
Plug 'junegunn/vim-easy-align', { 'frozen': 1 } Plug 'junegunn/vim-easy-align', { 'frozen': 1 }
call plug#end() call plug#end()
redir => output redir => out
silent PlugInstall silent PlugInstall
redir END redir END
Assert output =~ 'No plugin to install' Assert out =~ 'No plugin to install'
redir => output redir => out
silent PlugUpdate silent PlugUpdate
redir END redir END
Assert output =~ 'No plugin to update' Assert out =~ 'No plugin to update'
Execute (But you can still install it if the name is given as the argument): Execute (But you can still install it if the name is given as the argument):
PlugInstall vim-easy-align PlugInstall vim-easy-align
@@ -624,6 +635,14 @@ Execute (When already installed):
Assert !filereadable(g:plugs['vim-easy-align'].dir.'/installed2'), Assert !filereadable(g:plugs['vim-easy-align'].dir.'/installed2'),
\ 'vim-easy-align/installed2 should not exist' \ 'vim-easy-align/installed2 should not exist'
Assert !filereadable(g:plugs['vim-pseudocl'].dir.'/installed2'), 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' \ 'vim-pseudocl/installed2 should exist'
Execute (When already updated): Execute (When already updated):
@@ -637,11 +656,19 @@ Execute (When already updated):
Assert !filereadable(g:plugs['vim-easy-align'].dir.'/updated2'), Assert !filereadable(g:plugs['vim-easy-align'].dir.'/updated2'),
\ 'vim-easy-align/updated2 should not exist' \ 'vim-easy-align/updated2 should not exist'
Assert !filereadable(g:plugs['vim-pseudocl'].dir.'/updated2'), 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' \ 'vim-pseudocl/updated2 should exist'
Execute (Using Funcref): Execute (Using Funcref):
function! PlugUpdated(info) function! PlugUpdated(info)
call system('touch '. a:info.name . a:info.status . len(a:info)) call system('touch '. a:info.name . a:info.status . a:info.force . len(a:info))
endfunction endfunction
call plug#begin() call plug#begin()
@@ -655,11 +682,26 @@ Execute (Using Funcref):
PlugUpdate PlugUpdate
Log getline(1, '$') Log getline(1, '$')
q q
Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignupdated2'), Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignupdated03'),
\ 'vim-easy-align/vim-easy-alignupdated2 should exist' \ 'vim-easy-align/vim-easy-alignupdated03 should exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclinstalled2'), Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclinstalled03'),
\ 'vim-pseudocl/vim-pseudoclinstalled2 should exist' \ '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` ~ Overriding `dir`
@@ -668,6 +710,7 @@ Execute (Using Funcref):
Execute (Using custom dir): Execute (Using custom dir):
Assert isdirectory(g:plugs['vim-easy-align'].dir) Assert isdirectory(g:plugs['vim-easy-align'].dir)
call system('rm -rf '.$TMPDIR.'easy-align')
call plug#begin() call plug#begin()
Plug 'junegunn/vim-easy-align', { 'dir': $TMPDIR.'easy-align' } Plug 'junegunn/vim-easy-align', { 'dir': $TMPDIR.'easy-align' }
call plug#end() call plug#end()
@@ -681,19 +724,142 @@ Execute (Using custom dir):
q q
Assert isdirectory(g:plugs['vim-easy-align'].dir) Assert isdirectory(g:plugs['vim-easy-align'].dir)
Execute (Cleanup): **********************************************************************
call system('rm -rf '.temp_plugged) ~ On-demand loading load order
call rename('fzf', 'fzf-staged') **********************************************************************
Before (Clear global vars):
let g:xxx = []
set rtp-=$PWD/xxx/
set rtp-=$PWD/xxx/after
unlet g:plugs Execute (Immediate loading):
unlet g:plug_home call plug#begin()
unlet g:vimrc_reloaded Plug '$PWD/xxx'
unlet temp_plugged vader plug basertp save_rtp repo lnum fzf out call plug#end()
delf PlugStatusSorted
delf AssertExpect " FIXME:
delf PlugUpdated " Different result when Vader is run from commandline with `-c` option
delc AssertExpect Log g:xxx
unmap / if has('vim_starting')
unmap ? 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:
**********************************************************************
~ plug#helptags()
**********************************************************************
Execute (plug#helptags):
silent! call delete(expand('$PWD/xxx/doc/tags'))
Assert !filereadable(expand('$PWD/xxx/doc/tags'))
AssertEqual 1, plug#helptags()
Assert filereadable(expand('$PWD/xxx/doc/tags'))
**********************************************************************
~ Manual loading
**********************************************************************
Execute (plug#load - invalid arguments):
AssertEqual 0, plug#load()
AssertEqual 0, plug#load('non-existent-plugin')
AssertEqual 0, plug#load('non-existent-plugin', 'another-non-existent-plugin')
AssertEqual 1, plug#load('xxx')
AssertEqual 0, plug#load('xxx', 'non-existent-plugin')
AssertEqual 0, plug#load('non-existent-plugin', 'xxx')
Execute (on: []):
call plug#begin()
Plug 'junegunn/rust.vim', { 'on': [] }
call plug#end()
PlugInstall
q
Execute (PlugStatus reports (not loaded)):
PlugStatus
AssertExpect 'not loaded', 1
q
Execute (plug#load to load it):
tabnew test.rs
" Vader will switch tab to [Vader-workbench] after Log
" Log &filetype
AssertEqual 1, plug#load('rust.vim')
AssertEqual 'rust', &filetype
q
Execute (PlugStatus should not contain (not loaded)):
PlugStatus
AssertExpect 'not loaded', 0
q
Execute (Load plugin from PlugStatus screen with L key in normal mode):
call plug#begin()
Plug '$PWD/yyy', { 'on': [] }
call plug#end()
PlugStatus
AssertExpect 'not loaded', 1
Assert !exists('g:yyy'), 'yyy not loaded'
/not loaded
normal L
AssertExpect 'not loaded', 0
Assert exists('g:yyy'), 'yyy loaded'
q
Execute (Load plugin from PlugStatus screen with L key in visual mode):
call plug#begin()
Plug '$PWD/z1', { 'on': [] }
Plug '$PWD/z2', { 'for': [] }
call plug#end()
PlugStatus
AssertExpect 'not loaded', 2
Assert !exists('g:z1'), 'z1 not loaded'
Assert !exists('g:z2'), 'z2 not loaded'
normal ggVGL
AssertExpect 'not loaded', 0
Assert exists('g:z1'), 'z1 loaded'
Assert exists('g:z2'), 'z2 loaded'
q
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