vim-plug/plug.vim

422 lines
11 KiB
VimL
Raw Normal View History

2013-09-10 07:58:41 -07:00
" vim-plug: Vim plugin manager
" ============================
"
" Download plug.vim and put it in ~/.vim/autoload
"
" mkdir -p ~/.vim/autoload
2013-09-10 20:06:57 -07:00
" curl -fLo ~/.vim/autoload/plug.vim \
2013-09-10 07:58:41 -07:00
" https://raw.github.com/junegunn/vim-plug/master/plug.vim
"
" Edit your .vimrc
"
2013-09-16 01:37:09 -07:00
" call plug#begin()
2013-09-10 07:58:41 -07:00
"
" Plug 'junegunn/seoul256'
" Plug 'junegunn/vim-easy-align'
2013-09-10 07:58:41 -07:00
" " Plug 'user/repo', 'branch_or_tag'
" " ...
"
2013-09-16 01:37:09 -07:00
" call plug#end()
"
2013-09-10 07:58:41 -07:00
" Then :PlugInstall to install plugins. (default: ~/.vim/plugged)
2013-09-16 01:37:09 -07:00
" You can change the location of the plugins with plug#begin(path) call.
2013-09-10 07:58:41 -07:00
"
"
" Copyright (c) 2013 Junegunn Choi
"
" MIT License
"
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be
" included in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if exists('g:loaded_plug')
finish
endif
let g:loaded_plug = 1
2013-09-10 08:08:36 -07:00
let s:plug_source = 'https://raw.github.com/junegunn/vim-plug/master/plug.vim'
2013-09-10 07:58:41 -07:00
let s:plug_win = 0
let s:is_win = has('win32') || has('win64')
let s:me = expand('<sfile>:p')
2013-09-16 01:37:09 -07:00
function! plug#begin(...)
let home = a:0 > 0 ? fnamemodify(a:1, ':p') :
\ get(g:, 'plug_home', split(&rtp, ',')[0].'/plugged')
2013-09-10 07:58:41 -07:00
if !isdirectory(home)
try
call mkdir(home, 'p')
catch
echoerr 'Invalid plug directory: '. home
return
endtry
endif
if !executable('git')
echoerr "`git' executable not found. vim-plug requires git."
return
endif
let g:plug_home = home
let g:plugs = {}
2013-09-10 07:58:41 -07:00
command! -nargs=+ Plug call s:add(<args>)
command! -nargs=* PlugInstall call s:install(<f-args>)
command! -nargs=* PlugUpdate call s:update(<f-args>)
command! -nargs=0 PlugClean call s:clean()
command! -nargs=0 PlugUpgrade if s:upgrade() | execute "source ". s:me | endif
2013-09-10 07:58:41 -07:00
endfunction
2013-09-16 01:37:09 -07:00
function! plug#end()
set nocompatible
filetype off
for plug in values(g:plugs)
let dir = plug.dir
execute "set rtp^=".dir
if isdirectory(dir.'after')
execute "set rtp+=".dir.'after'
endif
endfor
filetype plugin indent on
syntax on
endfunction
2013-09-10 07:58:41 -07:00
function! s:add(...)
if a:0 == 1
let [plugin, branch] = [a:1, 'master']
elseif a:0 == 2
let [plugin, branch] = a:000
else
echoerr "Invalid number of arguments (1..2)"
return
endif
2013-09-16 20:35:10 -07:00
if plugin =~ ':'
let uri = plugin
else
if plugin !~ '/'
let plugin = 'vim-scripts/'. plugin
endif
let uri = 'https://git:@github.com/' . plugin . '.git'
2013-09-10 07:58:41 -07:00
endif
2013-09-16 20:35:10 -07:00
let name = substitute(split(plugin, '/')[-1], '\.git$', '', '')
let dir = fnamemodify(join([g:plug_home, name], '/'), ':p')
let spec = { 'dir': dir, 'uri': uri, 'branch': branch }
let g:plugs[name] = spec
2013-09-10 07:58:41 -07:00
endfunction
function! s:install(...)
call s:update_impl(0, a:000)
endfunction
function! s:update(...)
call s:update_impl(1, a:000)
endfunction
function! s:apply()
for spec in values(g:plugs)
2013-09-10 07:58:41 -07:00
let docd = join([spec.dir, 'doc'], '/')
if isdirectory(docd)
execute "helptags ". join([spec.dir, 'doc'], '/')
endif
endfor
runtime! plugin/*.vim
runtime! after/*.vim
2013-09-10 20:29:36 -07:00
silent! source $MYVIMRC
2013-09-10 07:58:41 -07:00
endfunction
function! s:syntax()
syntax clear
syntax region plug1 start=/\%1l/ end=/\%2l/ contains=ALL
syntax region plug2 start=/\%2l/ end=/\%3l/ contains=ALL
syn match plugNumber /[0-9]\+[0-9.]*/ containedin=plug1
syn match plugBracket /[[\]]/ containedin=plug2
syn match plugDash /^-/
syn match plugName /\(^- \)\@<=[^:]*/
syn match plugError /^- [^:]\+: (x).*/
2013-09-10 07:58:41 -07:00
hi def link plug1 Title
hi def link plug2 Repeat
hi def link plugBracket Structure
hi def link plugNumber Number
hi def link plugDash Special
hi def link plugName Label
hi def link plugError Error
2013-09-10 07:58:41 -07:00
endfunction
function! s:lpad(str, len)
return a:str . repeat(' ', a:len - len(a:str))
endfunction
function! s:system(cmd)
2013-09-16 20:35:10 -07:00
let lines = split(system(a:cmd), '\n')
return get(lines, -1, '')
2013-09-10 07:58:41 -07:00
endfunction
function! s:prepare()
execute s:plug_win . 'wincmd w'
if exists('b:plug')
%d
else
vertical topleft new
noremap <silent> <buffer> q :q<cr>
let b:plug = 1
let s:plug_win = winnr()
call s:assign_name()
endif
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline
setf vim-plug
call s:syntax()
endfunction
function! s:assign_name()
" Assign buffer name
let prefix = '[Plugins]'
let name = prefix
let idx = 2
while bufexists(name)
let name = printf("%s (%s)", prefix, idx)
let idx = idx + 1
endwhile
silent! execute "f ".fnameescape(name)
endfunction
function! s:finish()
call append(line('$'), '')
call append(line('$'), 'Finishing ... ')
redraw
call s:apply()
call s:syntax()
call setline(line('$'), getline(line('$')) . 'Done!')
normal! G
endfunction
function! s:update_impl(pull, args)
if has('ruby') && get(g:, 'plug_parallel', 1)
2013-09-10 20:06:57 -07:00
let threads = min(
\ [len(g:plugs), len(a:args) > 0 ? a:args[0] : get(g:, 'plug_threads', 16)])
2013-09-10 07:58:41 -07:00
else
let threads = 1
endif
call s:prepare()
call append(0, 'Updating plugins')
call append(1, '['. s:lpad('', len(g:plugs)) .']')
2013-09-10 07:58:41 -07:00
normal! 2G
redraw
if threads > 1
call s:update_parallel(a:pull, threads)
else
call s:update_serial(a:pull)
endif
call s:finish()
endfunction
function! s:update_serial(pull)
let st = reltime()
let base = g:plug_home
let cnt = 0
let total = len(g:plugs)
2013-09-10 07:58:41 -07:00
for [name, spec] in items(g:plugs)
2013-09-10 07:58:41 -07:00
let cnt += 1
let d = shellescape(spec.dir)
if isdirectory(spec.dir)
execute 'cd '.spec.dir
2013-09-16 20:35:10 -07:00
if s:git_valid(spec, 0)
let result = a:pull ?
\ s:system(
\ printf('git checkout -q %s && git pull origin %s 2>&1',
\ spec.branch, spec.branch)) : 'Already installed'
let error = a:pull ? v:shell_error != 0 : 0
else
let result = "PlugClean required. Invalid remote repository."
let error = 1
endif
2013-09-10 07:58:41 -07:00
else
if !isdirectory(base)
call mkdir(base, 'p')
endif
execute 'cd '.base
let result = s:system(
\ printf('git clone --recursive %s -b %s %s 2>&1',
\ shellescape(spec.uri), shellescape(spec.branch), d))
let error = v:shell_error != 0
endif
cd -
if error
let result = '(x) ' . result
endif
call setline(1, "Updating plugins (".cnt."/".total.")")
call setline(2, '[' . s:lpad(repeat('=', cnt), total) . ']')
call append(line('$'), '- ' . name . ': ' . result)
normal! 2G
redraw
endfor
call setline(1, "Updated. Elapsed time: " . split(reltimestr(reltime(st)))[0] . ' sec.')
endfunction
function! s:update_parallel(pull, threads)
ruby << EOF
2013-09-10 22:05:38 -07:00
require 'thread'
2013-09-10 07:58:41 -07:00
require 'fileutils'
st = Time.now
cd = VIM::evaluate('s:is_win').to_i == 1 ? 'cd /d' : 'cd'
pull = VIM::evaluate('a:pull').to_i == 1
base = VIM::evaluate('g:plug_home')
all = VIM::evaluate('g:plugs')
2013-09-10 07:58:41 -07:00
total = all.length
cnt = 0
skip = 'Already installed'
2013-09-10 20:06:57 -07:00
mtx = Mutex.new
take1 = proc { mtx.synchronize { all.shift } }
log = proc { |name, result, ok|
mtx.synchronize {
result = '(x) ' + result unless ok
result = "- #{name}: #{result}"
$curbuf[1] = "Updating plugins (#{cnt += 1}/#{total})"
$curbuf[2] = '[' + ('=' * cnt).ljust(total) + ']'
$curbuf.append $curbuf.count, result
VIM::command('normal! 2G')
VIM::command('redraw')
}
}
VIM::evaluate('a:threads').to_i.times.map { |i|
Thread.new(i) do |ii|
while pair = take1.call
2013-09-16 20:35:10 -07:00
name = pair.first
dir, uri, branch = pair.last.values_at *%w[dir uri branch]
ok, result =
2013-09-10 07:58:41 -07:00
if File.directory? dir
2013-09-16 20:35:10 -07:00
current_uri = `#{cd} #{dir} && git config remote.origin.url`.chomp
if $? == 0 && current_uri == uri
if pull
[true, `#{cd} #{dir} && git checkout -q #{branch} && git pull origin #{branch} 2>&1`]
else
[true, skip]
end
else
[false, "PlugClean required. Invalid remote repository."]
end
2013-09-10 07:58:41 -07:00
else
FileUtils.mkdir_p(base)
2013-09-16 20:35:10 -07:00
r = `#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{dir} 2>&1`
[$? == 0, r]
end
result = result.lines.to_a.last.strip
log.call name, result, ok
2013-09-10 07:58:41 -07:00
end
end
2013-09-10 20:06:57 -07:00
}.each(&:join)
2013-09-10 07:58:41 -07:00
$curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
EOF
endfunction
2013-09-10 20:29:36 -07:00
function! s:path(path)
return substitute(s:is_win ? substitute(a:path, '/', '\', 'g') : a:path,
\ '[/\\]*$', '', '')
endfunction
2013-09-10 07:58:41 -07:00
function! s:glob_dir(path)
2013-09-10 20:29:36 -07:00
return map(filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)'), 's:path(v:val)')
2013-09-10 07:58:41 -07:00
endfunction
2013-09-16 20:35:10 -07:00
function! s:git_valid(spec, cd)
if a:cd | execute "cd " . a:spec.dir | endif
let ret = s:system("git config remote.origin.url") == a:spec.uri
if a:cd | cd - | endif
return ret
endfunction
2013-09-10 07:58:41 -07:00
function! s:clean()
call s:prepare()
call append(0, 'Removing unused plugins in '.g:plug_home)
2013-09-16 20:35:10 -07:00
" List of valid directories
let dirs = map(filter(values(g:plugs), 's:git_valid(v:val, 1)'), 'v:val.dir')
2013-09-10 07:58:41 -07:00
let alldirs = dirs +
\ map(copy(dirs), 'fnamemodify(v:val, ":h")')
2013-09-10 07:58:41 -07:00
for dir in dirs
let alldirs += s:glob_dir(dir)
endfor
let allowed = {}
for dir in alldirs
let allowed[dir] = 1
endfor
let todo = []
let found = sort(s:glob_dir(g:plug_home))
while !empty(found)
let f = remove(found, 0)
if !has_key(allowed, f) && isdirectory(f)
call add(todo, f)
call append(line('$'), '- ' . f)
let found = filter(found, 'stridx(v:val, f) != 0')
end
endwhile
normal! G
redraw
if empty(todo)
call append(line('$'), 'Already clean.')
else
call inputsave()
let yes = input("Proceed? (Y/N) ")
call inputrestore()
if yes =~? '^y'
for dir in todo
if isdirectory(dir)
call system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . dir)
endif
endfor
call append(line('$'), 'Removed.')
else
call append(line('$'), 'Cancelled.')
endif
endif
normal! G
endfunction
function! s:upgrade()
if executable('curl')
let mee = shellescape(s:me)
let new = shellescape(s:me . '.new')
echo "Downloading ". s:plug_source
redraw
let mv = s:is_win ? 'move /Y' : 'mv -f'
call system(printf(
2013-09-10 20:06:57 -07:00
\ "curl -fLo %s %s && ".mv." %s %s.old && ".mv." %s %s",
2013-09-10 07:58:41 -07:00
\ new, s:plug_source, mee, mee, new, mee))
if v:shell_error == 0
unlet g:loaded_plug
echo "Downloaded ". s:plug_source
return 1
2013-09-10 07:58:41 -07:00
else
echoerr "Error upgrading vim-plug"
return 0
2013-09-10 07:58:41 -07:00
endif
else
echoerr "`curl' not found"
return 0
2013-09-10 07:58:41 -07:00
endif
endfunction