29 Commits
0.4.0 ... 0.4.1

Author SHA1 Message Date
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
3 changed files with 388 additions and 124 deletions

View File

@@ -76,7 +76,9 @@ Reload .vimrc and `:PlugInstall` to install plugins.
| -------------- | -------------------------------------------------------------------- | | -------------- | -------------------------------------------------------------------- |
| `branch`/`tag` | Branch or tag of the repository to use | | `branch`/`tag` | Branch or tag of the repository to use |
| `rtp` | Subdirectory that contains Vim plugin | | `rtp` | Subdirectory that contains Vim plugin |
| `on` | On-demand loading: Commands or <Plug>-mappings | | `dir` | Custom directory for the plugin |
| `do` | Post-update hook (string or funcref) |
| `on` | On-demand loading: Commands or `<Plug>`-mappings |
| `for` | On-demand loading: File types | | `for` | On-demand loading: File types |
| `frozen` | Do not install/update plugin unless explicitly given as the argument | | `frozen` | Do not install/update plugin unless explicitly given as the argument |
@@ -119,6 +121,48 @@ 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
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.
```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 two fields
" - name: name of the plugin
" - status: 'installed' or 'updated'
if a:info.status == 'installed'
!./install.sh
endif
endfunction
Plug 'Valloric/YouCompleteMe', { 'do': function('BuildYCM') }
```
Both forms of post-update hook are executed inside the directory of the plugin.
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 }
```
### Dependency resolution ### Dependency resolution
See [Dependency See [Dependency
@@ -128,6 +172,7 @@ Resolution](https://github.com/junegunn/vim-plug/wiki/Dependency-Resolution).
- [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) - [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)
### FAQ/Troubleshooting ### FAQ/Troubleshooting
@@ -185,6 +230,13 @@ it as "unstable" or "in development", and always use its latest revision.
If you really must choose a certain untagged revision, consider forking the If you really must choose a certain untagged revision, consider forking the
repository. 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
MIT MIT

310
plug.vim
View File

@@ -9,19 +9,29 @@
" "
" 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' }
"
" " Locally-managed plugin
" Plug '~/.fzf'
" "
" 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
@@ -61,6 +71,13 @@ 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:TYPE = {
\ 'string': type(''),
\ 'list': type([]),
\ 'dict': type({}),
\ 'funcref': type(function('call'))
\ }
function! plug#begin(...) function! plug#begin(...)
if a:0 > 0 if a:0 > 0
@@ -70,21 +87,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
@@ -96,7 +110,7 @@ function! plug#begin(...)
command! -nargs=* -complete=customlist,s:names PlugInstall call s:install(<f-args>) 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=* -complete=customlist,s:names PlugUpdate call s:update(<f-args>)
command! -nargs=0 -bang PlugClean call s:clean('<bang>' == '!') command! -nargs=0 -bang PlugClean call s:clean('<bang>' == '!')
command! -nargs=0 PlugUpgrade if s:upgrade() | execute "source ". s:me | endif command! -nargs=0 PlugUpgrade if s:upgrade() | call s:upgrade_specs() | execute 'source '. s:me | endif
command! -nargs=0 PlugStatus call s:status() command! -nargs=0 PlugStatus call s:status()
command! -nargs=0 PlugDiff call s:diff() command! -nargs=0 PlugDiff call s:diff()
@@ -104,17 +118,18 @@ 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 endfunction
function! plug#end() function! plug#end()
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) let keys = keys(g:plugs)
let plugfiles = s:find_plugfiles()
while !empty(keys) while !empty(keys)
let keys = keys(s:extend(keys)) " No need to look for Plugfiles more than once
let keys = keys(s:extend(keys, plugfiles))
endwhile endwhile
if exists('#PlugLOD') if exists('#PlugLOD')
@@ -143,15 +158,15 @@ function! plug#end()
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
@@ -181,42 +196,60 @@ function! plug#end()
syntax on syntax on
endfunction endfunction
function! s:trim(str)
return substitute(a:str, '[\/]\+$', '', '')
endfunction
if s:is_win if s:is_win
function! s:rtp(spec) function! s:rtp(spec)
let rtp = s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
return substitute(rtp, '\\*$', '', '')
endfunction endfunction
function! s:path(path) function! s:path(path)
return substitute(substitute(a:path, '/', '\', 'g'), '[/\\]*$', '', '') return s:trim(substitute(a:path, '/', '\', 'g'))
endfunction endfunction
function! s:dirpath(path) function! s:dirpath(path)
return s:path(a:path) . '\' return s:path(a:path) . '\'
endfunction endfunction
function! s:is_local_plug(repo)
return a:repo =~? '^[a-z]:'
endfunction
else else
function! s:rtp(spec) function! s:rtp(spec)
return s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) return s:dirpath(a:spec.dir . get(a:spec, 'rtp', ''))
endfunction endfunction
function! s:path(path) function! s:path(path)
return substitute(a:path, '[/\\]*$', '', '') return s:trim(a:path)
endfunction endfunction
function! s:dirpath(path) function! s:dirpath(path)
return s:path(a:path) . '/' return substitute(a:path, '[/\\]*$', '/', '')
endfunction
function! s:is_local_plug(repo)
return a:repo[0] =~ '[/$~]'
endfunction endfunction
endif endif
function! s:err(msg)
echohl ErrorMsg
echom a:msg
echohl None
return 0
endfunction
function! s:esc(path) function! s:esc(path)
return substitute(a:path, ' ', '\\ ', 'g') return substitute(a:path, ' ', '\\ ', 'g')
endfunction endfunction
function! s:add_rtp(rtp) function! s:add_rtp(rtp)
execute "set rtp^=".s:esc(a:rtp) execute 'set rtp^='.s:esc(a:rtp)
let after = globpath(a:rtp, 'after') let after = globpath(a:rtp, 'after')
if isdirectory(after) if isdirectory(after)
execute "set rtp+=".s:esc(after) execute 'set rtp+='.s:esc(after)
endif endif
endfunction endfunction
@@ -254,7 +287,7 @@ 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], ['plugin', 'ftdetect', 'after'])
call s:reorg_rtp() call s:reorg_rtp()
execute printf("%s%s%s %s", (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
endfunction endfunction
function! s:lod_map(map, name, prefix) function! s:lod_map(map, name, prefix)
@@ -273,55 +306,68 @@ function! s:lod_map(map, name, prefix)
call feedkeys(a:prefix . substitute(a:map, '^<Plug>', "\<Plug>", '') . extra) call feedkeys(a:prefix . substitute(a:map, '^<Plug>', "\<Plug>", '') . extra)
endfunction endfunction
function! s:add(force, ...) function! s:add(force, repo, ...)
let opts = { 'branch': 'master', 'frozen': 0 } if a:0 > 1
if a:0 == 1 return s:err('Invalid number of arguments (1..2)')
let plugin = a:1
elseif a:0 == 2
let plugin = a:1
if type(a:2) == 1
let opts.branch = a:2
elseif type(a:2) == 4
call extend(opts, a:2)
if has_key(opts, 'tag')
let opts.branch = remove(opts, 'tag')
endif
else
echoerr "Invalid argument type (expected: string or dictionary)"
return
endif
else
echoerr "Invalid number of arguments (1..2)"
return
endif endif
let plugin = substitute(plugin, '[/\\]*$', '', '') try
let name = substitute(split(plugin, '/')[-1], '\.git$', '', '') let repo = s:trim(a:repo)
let name = fnamemodify(repo, ':t:s?\.git$??')
if !a:force && has_key(g:plugs, name) if !a:force && has_key(g:plugs, name)
let s:extended[name] = g:plugs[name] let s:extended[name] = g:plugs[name]
return return
endif endif
if plugin[0] =~ '[/$~]' || plugin =~? '^[a-z]:' let spec = extend(s:infer_properties(name, repo),
let spec = extend(opts, { 'dir': s:dirpath(expand(plugin)) }) \ a:0 == 1 ? s:parse_options(a:1) : copy(s:base_spec))
else
if plugin =~ ':'
let uri = plugin
else
if plugin !~ '/'
let plugin = 'vim-scripts/'. plugin
endif
let uri = 'https://git:@github.com/' . plugin . '.git'
endif
let dir = s:dirpath( fnamemodify(join([g:plug_home, name], '/'), ':p') )
let spec = extend(opts, { 'dir': dir, 'uri': uri })
endif
let g:plugs[name] = spec
if !a:force if !a:force
let s:extended[name] = spec let s:extended[name] = spec
endif endif
let g:plugs[name] = spec
let g:plugs_order += [name] let g:plugs_order += [name]
catch
return s:err(v:exception)
endtry
endfunction
function! s:parse_options(arg)
let opts = copy(s:base_spec)
let type = type(a:arg)
if type == s:TYPE.string
let opts.branch = a:arg
elseif type == s:TYPE.dict
call extend(opts, a:arg)
if has_key(opts, 'tag')
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
function! s:infer_properties(name, repo)
let repo = a:repo
if s:is_local_plug(repo)
let properties = { 'dir': s:dirpath(expand(repo)), 'local': 1 }
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') )
let properties = { 'dir': dir, 'uri': uri }
endif
return properties
endfunction endfunction
function! s:install(...) function! s:install(...)
@@ -336,7 +382,7 @@ function! s:apply()
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 '. join([spec.dir, 'doc'], '/')
endif endif
endfor endfor
runtime! plugin/*.vim runtime! plugin/*.vim
@@ -354,7 +400,8 @@ function! s:syntax()
syn match plugDash /^-/ syn match plugDash /^-/
syn match plugPlus /^+/ syn match plugPlus /^+/
syn match plugStar /^*/ syn match plugStar /^*/
syn match plugName /\(^- \)\@<=[^:]*/ syn match plugMessage /\(^- \)\@<=.*/
syn match plugName /\(^- \)\@<=[^ ]*:/
syn match plugInstall /\(^+ \)\@<=[^:]*/ syn match plugInstall /\(^+ \)\@<=[^:]*/
syn match plugUpdate /\(^* \)\@<=[^:]*/ syn match plugUpdate /\(^* \)\@<=[^:]*/
syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha
@@ -372,6 +419,7 @@ function! s:syntax()
hi def link plugPlus Constant hi def link plugPlus Constant
hi def link plugStar Boolean hi def link plugStar Boolean
hi def link plugMessage Function
hi def link plugName Label hi def link plugName Label
hi def link plugInstall Function hi def link plugInstall Function
hi def link plugUpdate Type hi def link plugUpdate Type
@@ -424,10 +472,47 @@ 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, 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)
if installed || (a:pull &&
\ !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"')))
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
call spec.do({ 'name': name, 'status': (installed ? 'installed' : 'updated') })
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)
@@ -465,12 +550,13 @@ function! s:names(...)
endfunction endfunction
function! s:update_impl(pull, args) abort function! s:update_impl(pull, args) abort
let st = reltime()
let args = copy(a:args) let args = copy(a:args)
let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ?
\ remove(args, -1) : get(g:, 'plug_threads', 16) \ remove(args, -1) : get(g:, 'plug_threads', 16)
let managed = filter(copy(g:plugs), 's:is_managed(v:key)') let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
let todo = empty(args) ? filter(managed, '!get(v:val, "frozen", 0)') : let todo = empty(args) ? filter(managed, '!v:val.frozen') :
\ filter(managed, 'index(args, v:key) >= 0') \ filter(managed, 'index(args, v:key) >= 0')
if empty(todo) if empty(todo)
@@ -486,8 +572,11 @@ function! s:update_impl(pull, args) abort
normal! 2G normal! 2G
redraw redraw
if !isdirectory(g:plug_home)
call mkdir(g:plug_home, 'p')
endif
let len = len(g:plugs) let len = len(g:plugs)
let s:prev_update = { 'errors': [], 'pull': a:pull, 'threads': threads } 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
@@ -517,20 +606,36 @@ 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")'))
if len(g:plugs) > len if len(g:plugs) > len
call plug#end() call plug#end()
endif endif
call s:finish(a:pull) call s:finish(a:pull)
call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(st)))[0] . ' sec.')
endfunction endfunction
function! s:extend(names) 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 s:extended = {}
let plugfiles = a:0 > 0 ? a:1 : s:find_plugfiles()
try try
command! -nargs=+ Plug call s:add(0, <args>) command! -nargs=+ Plug call s:add(0, <args>)
for name in a:names for name in a:names
let plugfile = globpath(s:rtp(g:plugs[name]), s:plug_file) let spec = g:plugs[name]
if spec.local
let plugfile = globpath(s:rtp(spec), s:plug_file)
if filereadable(plugfile) if filereadable(plugfile)
execute "source ". s:esc(plugfile) execute 'source '. s:esc(plugfile)
endif
elseif has_key(plugfiles, name)
execute 'source '. s:esc(plugfiles[name])
endif endif
endfor endfor
finally finally
@@ -541,14 +646,13 @@ 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)
@@ -573,16 +677,14 @@ function! s:update_serial(pull, todo)
endif endif
cd - cd -
else else
if !isdirectory(base)
call mkdir(base, 'p')
endif
let result = s:system( let result = s:system(
\ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1', \ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1',
\ s:shellesc(spec.uri), \ s:shellesc(spec.uri),
\ s:shellesc(spec.branch), \ s:shellesc(spec.branch),
\ s:shellesc(substitute(spec.dir, '[\/]\+$', '', '')), \ s:shellesc(s:trim(spec.dir)),
\ s:shellesc(spec.dir))) \ s:shellesc(spec.dir)))
let error = v:shell_error != 0 let error = v:shell_error != 0
if !error | let s:prev_update.new[name] = 1 | endif
endif endif
let bar .= error ? 'x' : '=' let bar .= error ? 'x' : '='
if error if error
@@ -601,8 +703,6 @@ function! s:update_serial(pull, todo)
break break
endif endif
endwhile 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)
@@ -633,7 +733,6 @@ function! s:update_parallel(pull, todo, threads)
require 'fileutils' require 'fileutils'
require 'timeout' require 'timeout'
running = true running = true
st = Time.now
iswin = VIM::evaluate('s:is_win').to_i == 1 iswin = VIM::evaluate('s:is_win').to_i == 1
pull = VIM::evaluate('a:pull').to_i == 1 pull = VIM::evaluate('a:pull').to_i == 1
base = VIM::evaluate('g:plug_home') base = VIM::evaluate('g:plug_home')
@@ -773,8 +872,9 @@ function! s:update_parallel(pull, todo, threads)
dir, uri, branch = pair.last.values_at *%w[dir uri branch] dir, uri, branch = pair.last.values_at *%w[dir uri branch]
branch = esc branch branch = esc branch
subm = "git submodule update --init --recursive 2>&1" subm = "git submodule update --init --recursive 2>&1"
exists = File.directory? dir
ok, result = ok, result =
if File.directory? dir if exists
dir = esc dir dir = esc dir
ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil
current_uri = data.lines.to_a.last current_uri = data.lines.to_a.last
@@ -797,11 +897,11 @@ 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
@@ -818,7 +918,6 @@ function! s:update_parallel(pull, todo, threads)
end end
refresh.kill if refresh refresh.kill if refresh
watcher.kill watcher.kill
$curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
EOF EOF
endfunction endfunction
@@ -862,16 +961,16 @@ function! s:git_valid(spec, check_branch, cd)
let ret = 1 let ret = 1
let msg = 'OK' let msg = 'OK'
if isdirectory(a:spec.dir) if isdirectory(a:spec.dir)
if a:cd | execute "cd " . s:esc(a:spec.dir) | endif if a:cd | execute 'cd ' . s:esc(a:spec.dir) | endif
let result = split(s:system("git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"), '\n') let result = split(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url'), '\n')
let remote = result[-1] let remote = result[-1]
if v:shell_error if v:shell_error
let msg = join([remote, "PlugClean required."], "\n") let msg = join([remote, 'PlugClean required.'], "\n")
let ret = 0 let ret = 0
elseif !s:compare_git_uri(remote, a:spec.uri) elseif !s:compare_git_uri(remote, a:spec.uri)
let msg = join(['Invalid URI: '.remote, let msg = join(['Invalid URI: '.remote,
\ 'Expected: '.a:spec.uri, \ 'Expected: '.a:spec.uri,
\ "PlugClean required."], "\n") \ 'PlugClean required.'], "\n")
let ret = 0 let ret = 0
elseif a:check_branch elseif a:check_branch
let branch = result[0] let branch = result[0]
@@ -936,7 +1035,7 @@ function! s:clean(force)
call append(line('$'), 'Already clean.') call append(line('$'), 'Already clean.')
else else
call inputsave() call inputsave()
let yes = a:force || (input("Proceed? (Y/N) ") =~? '^y') let yes = a:force || (input('Proceed? (Y/N) ') =~? '^y')
call inputrestore() call inputrestore()
if yes if yes
for dir in todo for dir in todo
@@ -956,23 +1055,22 @@ function! s:upgrade()
if executable('curl') if executable('curl')
let mee = s:shellesc(s:me) let mee = s:shellesc(s:me)
let new = s:shellesc(s:me . '.new') let new = s:shellesc(s:me . '.new')
echo "Downloading ". s:plug_source echo 'Downloading '. s:plug_source
redraw redraw
let mv = s:is_win ? 'move /Y' : 'mv -f' let mv = s:is_win ? 'move /Y' : 'mv -f'
let cp = s:is_win ? 'copy /Y' : 'cp -f' let cp = s:is_win ? 'copy /Y' : 'cp -f'
call system(printf( call system(printf(
\ "curl -fLo %s %s && ".cp." %s %s.old && ".mv." %s %s", \ 'curl -fLo %s %s && '.cp.' %s %s.old && '.mv.' %s %s',
\ new, s:plug_source, mee, mee, new, mee)) \ new, s:plug_source, mee, mee, new, mee))
if v:shell_error == 0 if v:shell_error == 0
unlet g:loaded_plug unlet g:loaded_plug
echo "Downloaded ". s:plug_source echo 'Downloaded '. s:plug_source
return 1 return 1
else else
echoerr "Error upgrading vim-plug" return s:err('Error upgrading vim-plug')
return 0
endif endif
elseif has('ruby') elseif has('ruby')
echo "Downloading ". s:plug_source echo 'Downloading '. s:plug_source
ruby << EOF ruby << EOF
require 'open-uri' require 'open-uri'
require 'fileutils' require 'fileutils'
@@ -986,14 +1084,20 @@ 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)
let spec.local = get(spec, 'local', 0)
endfor
endfunction
function! s:status() function! s:status()
call s:prepare() call s:prepare()
call append(0, 'Checking plugins') call append(0, 'Checking plugins')
@@ -1082,7 +1186,7 @@ function! s:diff()
endif endif
execute 'cd '.s:esc(v.dir) execute 'cd '.s:esc(v.dir)
let diff = system('git log --pretty=format:"%h %s (%cr)" "HEAD@{0}...HEAD@{1}"') let diff = system('git log --pretty=format:"%h %s (%cr)" "HEAD...HEAD@{1}"')
if !v:shell_error && !empty(diff) if !v:shell_error && !empty(diff)
call append(1, '') call append(1, '')
call append(2, '- '.k.':') call append(2, '- '.k.':')

View File

@@ -39,12 +39,10 @@ Execute (Initialize test environment):
let $MYVIMRC = vimrc let $MYVIMRC = vimrc
Execute (plug#end() before plug#begin() should fail): Execute (plug#end() before plug#begin() should fail):
try redir => out
call plug#end() AssertEqual 0, plug#end()
Assert 0, 'should not reach here' redir END
catch Assert stridx(out, 'Call plug#begin() first') >= 0
Assert stridx(v:exception, 'Call plug#begin() first') >= 0
endtry
Execute (plug#begin() without path argument): Execute (plug#begin() without path argument):
call plug#begin() call plug#begin()
@@ -54,12 +52,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)):
@@ -396,7 +392,7 @@ Expect (Aligned code):
a = 1 a = 1
aa = 2 aa = 2
Given (nothing): Given:
Execute (Partial PlugUpdate): Execute (Partial PlugUpdate):
PlugUpdate vim-redis PlugUpdate vim-redis
q q
@@ -576,6 +572,115 @@ Execute (Retry failed tasks):
AssertExpect! '[xxx]', 1 AssertExpect! '[xxx]', 1
q 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 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 exist'
Execute (Using Funcref):
function! PlugUpdated(info)
call system('touch '. a:info.name . a:info.status . 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-alignupdated2'),
\ 'vim-easy-align/vim-easy-alignupdated2 should exist'
Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclinstalled2'),
\ 'vim-pseudocl/vim-pseudoclinstalled2 should exist'
**********************************************************************
~ Overriding `dir`
**********************************************************************
Execute (Using custom dir):
Assert isdirectory(g:plugs['vim-easy-align'].dir)
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)
Execute (Cleanup): Execute (Cleanup):
call system('rm -rf '.temp_plugged) call system('rm -rf '.temp_plugged)
call rename('fzf', 'fzf-staged') call rename('fzf', 'fzf-staged')
@@ -583,9 +688,12 @@ Execute (Cleanup):
unlet g:plugs unlet g:plugs
unlet g:plug_home unlet g:plug_home
unlet g:vimrc_reloaded unlet g:vimrc_reloaded
unlet temp_plugged vader plug basertp save_rtp repo lnum fzf unlet temp_plugged vader plug basertp save_rtp repo lnum fzf out
delf PlugStatusSorted delf PlugStatusSorted
delf AssertExpect delf AssertExpect
delf PlugUpdated
delc AssertExpect delc AssertExpect
unmap /
unmap ?
Restore Restore