plug.vim 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. " vim-plug: Vim plugin manager
  2. " ============================
  3. "
  4. " Download plug.vim and put it in ~/.vim/autoload
  5. "
  6. " mkdir -p ~/.vim/autoload
  7. " curl -fLo ~/.vim/autoload/plug.vim \
  8. " https://raw.github.com/junegunn/vim-plug/master/plug.vim
  9. "
  10. " Edit your .vimrc
  11. "
  12. " call plug#init()
  13. "
  14. " Plug 'junegunn/seoul256'
  15. " " Plug 'user/repo', 'branch_or_tag'
  16. " " ...
  17. "
  18. " Then :PlugInstall to install plugins. (default: ~/.vim/plugged)
  19. " You can change the location of the plugins with plug#init(path) call.
  20. "
  21. "
  22. " Copyright (c) 2013 Junegunn Choi
  23. "
  24. " MIT License
  25. "
  26. " Permission is hereby granted, free of charge, to any person obtaining
  27. " a copy of this software and associated documentation files (the
  28. " "Software"), to deal in the Software without restriction, including
  29. " without limitation the rights to use, copy, modify, merge, publish,
  30. " distribute, sublicense, and/or sell copies of the Software, and to
  31. " permit persons to whom the Software is furnished to do so, subject to
  32. " the following conditions:
  33. "
  34. " The above copyright notice and this permission notice shall be
  35. " included in all copies or substantial portions of the Software.
  36. "
  37. " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  38. " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  39. " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  40. " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  41. " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  42. " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  43. " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  44. if exists('g:loaded_plug')
  45. finish
  46. endif
  47. let g:loaded_plug = 1
  48. let s:plug_source = 'https://raw.github.com/junegunn/vim-plug/master/plug.vim'
  49. let s:plug_win = 0
  50. let s:is_win = has('win32') || has('win64')
  51. let s:me = expand('<sfile>:p')
  52. function! plug#init(...)
  53. set nocompatible
  54. filetype off
  55. filetype plugin indent on
  56. let home = a:0 > 0 ? fnamemodify(a:1, ':p') : (split(&rtp, ',')[0].'/plugged')
  57. if !isdirectory(home)
  58. try
  59. call mkdir(home, 'p')
  60. catch
  61. echoerr 'Invalid plug directory: '. home
  62. return
  63. endtry
  64. endif
  65. if !executable('git')
  66. echoerr "`git' executable not found. vim-plug requires git."
  67. return
  68. endif
  69. let g:plug_home = home
  70. let g:plug = {}
  71. command! -nargs=+ Plug call s:add(<args>)
  72. command! -nargs=* PlugInstall call s:install(<f-args>)
  73. command! -nargs=* PlugUpdate call s:update(<f-args>)
  74. command! -nargs=0 PlugClean call s:clean()
  75. command! -nargs=0 PlugUpgrade if s:upgrade() | execute "source ". s:me | endif
  76. endfunction
  77. function! s:add(...)
  78. if a:0 == 1
  79. let [plugin, branch] = [a:1, 'master']
  80. elseif a:0 == 2
  81. let [plugin, branch] = a:000
  82. else
  83. echoerr "Invalid number of arguments (1..2)"
  84. return
  85. endif
  86. if plugin !~ '/'
  87. let plugin = 'vim-scripts/'. plugin
  88. endif
  89. let name = split(plugin, '/')[-1]
  90. let dir = fnamemodify(join([g:plug_home, plugin, branch], '/'), ':p')
  91. let uri = 'https://git:@github.com/' . plugin . '.git'
  92. let spec = { 'name': name, 'dir': dir, 'uri': uri, 'branch': branch }
  93. execute "set rtp+=".dir
  94. let g:plug[plugin] = spec
  95. endfunction
  96. function! s:install(...)
  97. call s:update_impl(0, a:000)
  98. endfunction
  99. function! s:update(...)
  100. call s:update_impl(1, a:000)
  101. endfunction
  102. function! s:apply()
  103. for spec in values(g:plug)
  104. let docd = join([spec.dir, 'doc'], '/')
  105. if isdirectory(docd)
  106. execute "helptags ". join([spec.dir, 'doc'], '/')
  107. endif
  108. endfor
  109. runtime! plugin/*.vim
  110. runtime! after/*.vim
  111. source $MYVIMRC
  112. endfunction
  113. function! s:syntax()
  114. syntax clear
  115. syntax region plug1 start=/\%1l/ end=/\%2l/ contains=ALL
  116. syntax region plug2 start=/\%2l/ end=/\%3l/ contains=ALL
  117. syn match plugNumber /[0-9]\+[0-9.]*/ containedin=plug1
  118. syn match plugBracket /[[\]]/ containedin=plug2
  119. syn match plugDash /^-/
  120. syn match plugName /\(^- \)\@<=[^:]*/
  121. syn match plugError /^- [^:]\+: (x).*/
  122. hi def link plug1 Title
  123. hi def link plug2 Repeat
  124. hi def link plugBracket Structure
  125. hi def link plugNumber Number
  126. hi def link plugDash Special
  127. hi def link plugName Label
  128. hi def link plugError Error
  129. endfunction
  130. function! s:lpad(str, len)
  131. return a:str . repeat(' ', a:len - len(a:str))
  132. endfunction
  133. function! s:system(cmd)
  134. return split(system(a:cmd), '\n')[-1]
  135. endfunction
  136. function! s:prepare()
  137. execute s:plug_win . 'wincmd w'
  138. if exists('b:plug')
  139. %d
  140. else
  141. vertical topleft new
  142. noremap <silent> <buffer> q :q<cr>
  143. let b:plug = 1
  144. let s:plug_win = winnr()
  145. call s:assign_name()
  146. endif
  147. setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline
  148. setf vim-plug
  149. call s:syntax()
  150. endfunction
  151. function! s:assign_name()
  152. " Assign buffer name
  153. let prefix = '[Plugins]'
  154. let name = prefix
  155. let idx = 2
  156. while bufexists(name)
  157. let name = printf("%s (%s)", prefix, idx)
  158. let idx = idx + 1
  159. endwhile
  160. silent! execute "f ".fnameescape(name)
  161. endfunction
  162. function! s:finish()
  163. call append(line('$'), '')
  164. call append(line('$'), 'Finishing ... ')
  165. redraw
  166. call s:apply()
  167. call s:syntax()
  168. call setline(line('$'), getline(line('$')) . 'Done!')
  169. normal! G
  170. endfunction
  171. function! s:update_impl(pull, args)
  172. if has('ruby') && get(g:, 'plug_parallel', 1)
  173. let threads = min(
  174. \ [len(g:plug), len(a:args) > 0 ? a:args[0] : get(g:, 'plug_threads', 16)])
  175. else
  176. let threads = 1
  177. endif
  178. call s:prepare()
  179. call append(0, 'Updating plugins')
  180. call append(1, '['. s:lpad('', len(g:plug)) .']')
  181. normal! 2G
  182. redraw
  183. if threads > 1
  184. call s:update_parallel(a:pull, threads)
  185. else
  186. call s:update_serial(a:pull)
  187. endif
  188. call s:finish()
  189. endfunction
  190. function! s:update_serial(pull)
  191. let st = reltime()
  192. let base = g:plug_home
  193. let cnt = 0
  194. let total = len(g:plug)
  195. for [name, spec] in items(g:plug)
  196. let cnt += 1
  197. let d = shellescape(spec.dir)
  198. if isdirectory(spec.dir)
  199. execute 'cd '.spec.dir
  200. let result = a:pull ? s:system('git pull 2>&1') : 'Already installed'
  201. let error = a:pull ? v:shell_error != 0 : 0
  202. else
  203. if !isdirectory(base)
  204. call mkdir(base, 'p')
  205. endif
  206. execute 'cd '.base
  207. let result = s:system(
  208. \ printf('git clone --recursive %s -b %s %s 2>&1',
  209. \ shellescape(spec.uri), shellescape(spec.branch), d))
  210. let error = v:shell_error != 0
  211. endif
  212. cd -
  213. if error
  214. let result = '(x) ' . result
  215. endif
  216. call setline(1, "Updating plugins (".cnt."/".total.")")
  217. call setline(2, '[' . s:lpad(repeat('=', cnt), total) . ']')
  218. call append(line('$'), '- ' . name . ': ' . result)
  219. normal! 2G
  220. redraw
  221. endfor
  222. call setline(1, "Updated. Elapsed time: " . split(reltimestr(reltime(st)))[0] . ' sec.')
  223. endfunction
  224. function! s:update_parallel(pull, threads)
  225. ruby << EOF
  226. require 'fileutils'
  227. st = Time.now
  228. cd = VIM::evaluate('s:is_win').to_i == 1 ? 'cd /d' : 'cd'
  229. pull = VIM::evaluate('a:pull').to_i == 1
  230. base = VIM::evaluate('g:plug_home')
  231. all = VIM::evaluate('g:plug')
  232. total = all.length
  233. cnt = 0
  234. skip = 'Already installed'
  235. mtx = Mutex.new
  236. take1 = proc { mtx.synchronize { all.shift } }
  237. log = proc { |name, result, ok|
  238. mtx.synchronize {
  239. result = '(x) ' + result unless ok
  240. result = "- #{name}: #{result}"
  241. $curbuf[1] = "Updating plugins (#{cnt += 1}/#{total})"
  242. $curbuf[2] = '[' + ('=' * cnt).ljust(total) + ']'
  243. $curbuf.append $curbuf.count, result
  244. VIM::command('normal! 2G')
  245. VIM::command('redraw')
  246. }
  247. }
  248. VIM::evaluate('a:threads').to_i.times.map { |i|
  249. Thread.new(i) do |ii|
  250. while pair = take1.call
  251. name, dir, uri, branch = pair.last.values_at *%w[name dir uri branch]
  252. result =
  253. if File.directory? dir
  254. pull ? `#{cd} #{dir} && git pull 2>&1` : skip
  255. else
  256. FileUtils.mkdir_p(base)
  257. `#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{dir} 2>&1`
  258. end.lines.to_a.last.strip
  259. log.call name, result, ($? == 0 || result == skip)
  260. end
  261. end
  262. }.each(&:join)
  263. $curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
  264. EOF
  265. endfunction
  266. function! s:glob_dir(path)
  267. return filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)')
  268. endfunction
  269. function! s:clean()
  270. call s:prepare()
  271. call append(0, 'Removing unused plugins in '.g:plug_home)
  272. " List of files
  273. let dirs = map(values(g:plug), 'substitute(v:val.dir, "/*$", "", "")')
  274. let alldirs = dirs +
  275. \ map(copy(dirs), 'fnamemodify(v:val, ":h")') +
  276. \ map(copy(dirs), 'fnamemodify(v:val, ":h:h")')
  277. for dir in dirs
  278. let alldirs += s:glob_dir(dir)
  279. endfor
  280. let allowed = {}
  281. for dir in alldirs
  282. let allowed[dir] = 1
  283. endfor
  284. let todo = []
  285. let found = sort(s:glob_dir(g:plug_home))
  286. while !empty(found)
  287. let f = remove(found, 0)
  288. if !has_key(allowed, f) && isdirectory(f)
  289. call add(todo, f)
  290. call append(line('$'), '- ' . f)
  291. let found = filter(found, 'stridx(v:val, f) != 0')
  292. end
  293. endwhile
  294. normal! G
  295. redraw
  296. if empty(todo)
  297. call append(line('$'), 'Already clean.')
  298. else
  299. call inputsave()
  300. let yes = input("Proceed? (Y/N) ")
  301. call inputrestore()
  302. if yes =~? '^y'
  303. for dir in todo
  304. if isdirectory(dir)
  305. call system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . dir)
  306. endif
  307. endfor
  308. call append(line('$'), 'Removed.')
  309. else
  310. call append(line('$'), 'Cancelled.')
  311. endif
  312. endif
  313. normal! G
  314. endfunction
  315. function! s:upgrade()
  316. if executable('curl')
  317. let mee = shellescape(s:me)
  318. let new = shellescape(s:me . '.new')
  319. echo "Downloading ". s:plug_source
  320. redraw
  321. let mv = s:is_win ? 'move /Y' : 'mv -f'
  322. call system(printf(
  323. \ "curl -fLo %s %s && ".mv." %s %s.old && ".mv." %s %s",
  324. \ new, s:plug_source, mee, mee, new, mee))
  325. if v:shell_error == 0
  326. unlet g:loaded_plug
  327. echo "Downloaded ". s:plug_source
  328. return 1
  329. else
  330. echoerr "Error upgrading vim-plug"
  331. return 0
  332. endif
  333. else
  334. echoerr "`curl' not found"
  335. return 0
  336. endif
  337. endfunction