" vim-plug: Vim plugin manager " ============================ " " Download plug.vim and put it in ~/.vim/autoload " " mkdir -p ~/.vim/autoload " curl -fLo ~/.vim/autoload/plug.vim \ " https://raw.github.com/junegunn/vim-plug/master/plug.vim " " Edit your .vimrc " " call plug#begin() " " Plug 'junegunn/seoul256' " Plug 'junegunn/vim-easy-align' " " Plug 'user/repo', 'branch_or_tag' " " ... " " call plug#end() " " Then :PlugInstall to install plugins. (default: ~/.vim/plugged) " You can change the location of the plugins with plug#begin(path) call. " " " 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 let s:plug_source = 'https://raw.github.com/junegunn/vim-plug/master/plug.vim' let s:plug_file = 'Plugfile' let s:plug_win = 0 let s:is_win = has('win32') || has('win64') let s:me = expand(':p') function! plug#begin(...) let home = a:0 > 0 ? fnamemodify(a:1, ':p') : \ get(g:, 'plug_home', split(&rtp, ',')[0].'/plugged') 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 = {} command! -nargs=+ Plug call s:add(1, ) command! -nargs=* PlugInstall call s:install() command! -nargs=* PlugUpdate call s:update() command! -nargs=0 -bang PlugClean call s:clean('' == '!') command! -nargs=0 PlugUpgrade if s:upgrade() | execute "source ". s:me | endif command! -nargs=0 PlugStatus call s:status() endfunction function! plug#end() let keys = keys(g:plugs) while !empty(keys) let keys = keys(s:extend(keys)) endwhile 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 function! s:add(...) let force = a:1 if a:0 == 2 let [plugin, branch] = [a:2, 'master'] elseif a:0 == 3 let [plugin, branch] = [a:2, a:3] else echoerr "Invalid number of arguments (1..2)" return endif if plugin =~ ':' let uri = plugin else if plugin !~ '/' let plugin = 'vim-scripts/'. plugin endif let uri = 'https://git:@github.com/' . plugin . '.git' endif let name = substitute(split(plugin, '/')[-1], '\.git$', '', '') if !force && has_key(g:plugs, name) | return | endif let dir = fnamemodify(join([g:plug_home, name], '/'), ':p') let spec = { 'dir': dir, 'uri': uri, 'branch': branch } let g:plugs[name] = spec 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) let docd = join([spec.dir, 'doc'], '/') if isdirectory(docd) execute "helptags ". join([spec.dir, 'doc'], '/') endif endfor runtime! plugin/*.vim runtime! after/*.vim silent! source $MYVIMRC 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 contained syn match plugBracket /[[\]]/ containedin=plug2 contained syn match plugDash /^-/ syn match plugName /\(^- \)\@<=[^:]*/ syn match plugError /^- [^:]\+: (x).*/ 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 endfunction function! s:lpad(str, len) return a:str . repeat(' ', a:len - len(a:str)) endfunction function! s:system(cmd) let lines = split(system(a:cmd), '\n') return get(lines, -1, '') endfunction function! s:prepare() execute s:plug_win . 'wincmd w' if exists('b:plug') %d else vertical topleft new noremap q :q 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) let threads = len(a:args) > 0 ? a:args[0] : get(g:, 'plug_threads', 16) call s:prepare() call append(0, a:pull ? 'Updating plugins' : 'Installing plugins') call append(1, '['. s:lpad('', len(g:plugs)) .']') normal! 2G redraw if has('ruby') && threads > 1 call s:update_parallel(a:pull, threads) else call s:update_serial(a:pull) endif call s:finish() endfunction function! s:extend(names) let prev = copy(g:plugs) try command! -nargs=+ Plug call s:add(0, ) for name in a:names let spec = g:plugs[name] let plugfile = spec.dir . '/'. s:plug_file if filereadable(plugfile) execute "source ". plugfile endif endfor finally command! -nargs=+ Plug call s:add(1, ) endtry return filter(copy(g:plugs), '!has_key(prev, v:key)') endfunction function! s:update_progress(pull, cnt, total) call setline(1, (a:pull ? 'Updating' : 'Installing'). \ " plugins (".a:cnt."/".a:total.")") call s:progress_bar(2, a:cnt, a:total) normal! 2G redraw endfunction function! s:update_serial(pull) let st = reltime() let base = g:plug_home let todo = copy(g:plugs) let total = len(todo) let done = {} while !empty(todo) for [name, spec] in items(todo) let done[name] = 1 let d = shellescape(spec.dir) if isdirectory(spec.dir) execute 'cd '.spec.dir if s:git_valid(spec, 0) let result = a:pull ? \ s:system( \ printf('git checkout -q %s 2>&1 && 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." let error = 1 endif 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 append(3, '- ' . name . ': ' . result) call s:update_progress(a:pull, len(done), total) endfor if !empty(s:extend(keys(todo))) let todo = filter(copy(g:plugs), '!has_key(done, v:key)') let total += len(todo) call s:update_progress(a:pull, len(done), total) else break endif endwhile call setline(1, "Updated. Elapsed time: " . split(reltimestr(reltime(st)))[0] . ' sec.') endfunction function! s:update_parallel(pull, threads) ruby << EOF require 'thread' 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('copy(g:plugs)') done = {} skip = 'Already installed' mtx = Mutex.new take1 = proc { mtx.synchronize { all.shift } } logh = proc { cnt, tot = done.length, VIM::evaluate('len(g:plugs)') $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" $curbuf[2] = '[' + ('=' * cnt).ljust(tot) + ']' VIM::command('normal! 2G') VIM::command('redraw') } log = proc { |name, result, ok| mtx.synchronize do done[name] = true result = '(x) ' + result unless ok result = "- #{name}: #{result}" $curbuf.append 3, result logh.call end } until all.empty? names = all.keys [names.length, VIM::evaluate('a:threads').to_i].min.times.map { |i| Thread.new(i) do while pair = take1.call name = pair.first dir, uri, branch = pair.last.values_at *%w[dir uri branch] ok, result = if File.directory? dir current_uri = `#{cd} #{dir} && git config remote.origin.url`.chomp if $? == 0 && current_uri == uri if pull output = `#{cd} #{dir} && git checkout -q #{branch} 2>&1 && git pull origin #{branch} 2>&1` [$? == 0, output] else [true, skip] end else [false, "PlugClean required. Invalid remote."] end else FileUtils.mkdir_p(base) 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 end end }.each(&:join) all.merge! VIM::evaluate("s:extend(#{names.inspect})") logh.call end $curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec." EOF endfunction function! s:path(path) return substitute(s:is_win ? substitute(a:path, '/', '\', 'g') : a:path, \ '[/\\]*$', '', '') endfunction function! s:glob_dir(path) return map(filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)'), 's:path(v:val)') endfunction function! s:progress_bar(line, cnt, total) call setline(a:line, '[' . s:lpad(repeat('=', a:cnt), a:total) . ']') endfunction function! s:git_valid(spec, cd) if isdirectory(a:spec.dir) 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 else let ret = 0 endif return ret endfunction function! s:clean(force) call s:prepare() call append(0, 'Searching for unused plugins in '.g:plug_home) call append(1, '') " List of valid directories let dirs = [] let [cnt, total] = [0, len(g:plugs)] for spec in values(g:plugs) if s:git_valid(spec, 1) call add(dirs, spec.dir) endif let cnt += 1 call s:progress_bar(2, cnt, total) redraw endfor let alldirs = dirs + \ map(copy(dirs), 'fnamemodify(v:val, ":h")') 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 = a:force || (input("Proceed? (Y/N) ") =~? '^y') call inputrestore() if yes 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( \ "curl -fLo %s %s && ".mv." %s %s.old && ".mv." %s %s", \ new, s:plug_source, mee, mee, new, mee)) if v:shell_error == 0 unlet g:loaded_plug echo "Downloaded ". s:plug_source return 1 else echoerr "Error upgrading vim-plug" return 0 endif else echoerr "`curl' not found" return 0 endif endfunction function! s:status() call s:prepare() call append(0, 'Checking plugins') let errs = 0 for [name, spec] in items(g:plugs) let err = 'OK' if isdirectory(spec.dir) execute 'cd '.spec.dir if s:git_valid(spec, 0) let branch = s:system('git rev-parse --abbrev-ref HEAD') if spec.branch != branch let err = '(x) Invalid branch: '.branch.'. Try PlugUpdate.' endif else let err = '(x) Invalid remote. Try PlugClean.' endif cd - else let err = '(x) Not found. Try PlugInstall.' endif let errs += err != 'OK' call append(2, printf('- %s: %s', name, err)) call cursor(3, 1) redraw endfor call setline(1, 'Finished. '.errs.' error(s).') endfunction