plug.vim 10 KB

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