plug.vim 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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. if isdirectory(dir.'after')
  95. execute "set rtp+=".dir.'after'
  96. endif
  97. let g:plug[plugin] = spec
  98. endfunction
  99. function! s:install(...)
  100. call s:update_impl(0, a:000)
  101. endfunction
  102. function! s:update(...)
  103. call s:update_impl(1, a:000)
  104. endfunction
  105. function! s:apply()
  106. for spec in values(g:plug)
  107. let docd = join([spec.dir, 'doc'], '/')
  108. if isdirectory(docd)
  109. execute "helptags ". join([spec.dir, 'doc'], '/')
  110. endif
  111. endfor
  112. runtime! plugin/*.vim
  113. runtime! after/*.vim
  114. silent! source $MYVIMRC
  115. endfunction
  116. function! s:syntax()
  117. syntax clear
  118. syntax region plug1 start=/\%1l/ end=/\%2l/ contains=ALL
  119. syntax region plug2 start=/\%2l/ end=/\%3l/ contains=ALL
  120. syn match plugNumber /[0-9]\+[0-9.]*/ containedin=plug1
  121. syn match plugBracket /[[\]]/ containedin=plug2
  122. syn match plugDash /^-/
  123. syn match plugName /\(^- \)\@<=[^:]*/
  124. syn match plugError /^- [^:]\+: (x).*/
  125. hi def link plug1 Title
  126. hi def link plug2 Repeat
  127. hi def link plugBracket Structure
  128. hi def link plugNumber Number
  129. hi def link plugDash Special
  130. hi def link plugName Label
  131. hi def link plugError Error
  132. endfunction
  133. function! s:lpad(str, len)
  134. return a:str . repeat(' ', a:len - len(a:str))
  135. endfunction
  136. function! s:system(cmd)
  137. return split(system(a:cmd), '\n')[-1]
  138. endfunction
  139. function! s:prepare()
  140. execute s:plug_win . 'wincmd w'
  141. if exists('b:plug')
  142. %d
  143. else
  144. vertical topleft new
  145. noremap <silent> <buffer> q :q<cr>
  146. let b:plug = 1
  147. let s:plug_win = winnr()
  148. call s:assign_name()
  149. endif
  150. setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline
  151. setf vim-plug
  152. call s:syntax()
  153. endfunction
  154. function! s:assign_name()
  155. " Assign buffer name
  156. let prefix = '[Plugins]'
  157. let name = prefix
  158. let idx = 2
  159. while bufexists(name)
  160. let name = printf("%s (%s)", prefix, idx)
  161. let idx = idx + 1
  162. endwhile
  163. silent! execute "f ".fnameescape(name)
  164. endfunction
  165. function! s:finish()
  166. call append(line('$'), '')
  167. call append(line('$'), 'Finishing ... ')
  168. redraw
  169. call s:apply()
  170. call s:syntax()
  171. call setline(line('$'), getline(line('$')) . 'Done!')
  172. normal! G
  173. endfunction
  174. function! s:update_impl(pull, args)
  175. if has('ruby') && get(g:, 'plug_parallel', 1)
  176. let threads = min(
  177. \ [len(g:plug), len(a:args) > 0 ? a:args[0] : get(g:, 'plug_threads', 16)])
  178. else
  179. let threads = 1
  180. endif
  181. call s:prepare()
  182. call append(0, 'Updating plugins')
  183. call append(1, '['. s:lpad('', len(g:plug)) .']')
  184. normal! 2G
  185. redraw
  186. if threads > 1
  187. call s:update_parallel(a:pull, threads)
  188. else
  189. call s:update_serial(a:pull)
  190. endif
  191. call s:finish()
  192. endfunction
  193. function! s:update_serial(pull)
  194. let st = reltime()
  195. let base = g:plug_home
  196. let cnt = 0
  197. let total = len(g:plug)
  198. for [name, spec] in items(g:plug)
  199. let cnt += 1
  200. let d = shellescape(spec.dir)
  201. if isdirectory(spec.dir)
  202. execute 'cd '.spec.dir
  203. let result = a:pull ? s:system('git pull 2>&1') : 'Already installed'
  204. let error = a:pull ? v:shell_error != 0 : 0
  205. else
  206. if !isdirectory(base)
  207. call mkdir(base, 'p')
  208. endif
  209. execute 'cd '.base
  210. let result = s:system(
  211. \ printf('git clone --recursive %s -b %s %s 2>&1',
  212. \ shellescape(spec.uri), shellescape(spec.branch), d))
  213. let error = v:shell_error != 0
  214. endif
  215. cd -
  216. if error
  217. let result = '(x) ' . result
  218. endif
  219. call setline(1, "Updating plugins (".cnt."/".total.")")
  220. call setline(2, '[' . s:lpad(repeat('=', cnt), total) . ']')
  221. call append(line('$'), '- ' . name . ': ' . result)
  222. normal! 2G
  223. redraw
  224. endfor
  225. call setline(1, "Updated. Elapsed time: " . split(reltimestr(reltime(st)))[0] . ' sec.')
  226. endfunction
  227. function! s:update_parallel(pull, threads)
  228. ruby << EOF
  229. require 'thread'
  230. require 'fileutils'
  231. st = Time.now
  232. cd = VIM::evaluate('s:is_win').to_i == 1 ? 'cd /d' : 'cd'
  233. pull = VIM::evaluate('a:pull').to_i == 1
  234. base = VIM::evaluate('g:plug_home')
  235. all = VIM::evaluate('g:plug')
  236. total = all.length
  237. cnt = 0
  238. skip = 'Already installed'
  239. mtx = Mutex.new
  240. take1 = proc { mtx.synchronize { all.shift } }
  241. log = proc { |name, result, ok|
  242. mtx.synchronize {
  243. result = '(x) ' + result unless ok
  244. result = "- #{name}: #{result}"
  245. $curbuf[1] = "Updating plugins (#{cnt += 1}/#{total})"
  246. $curbuf[2] = '[' + ('=' * cnt).ljust(total) + ']'
  247. $curbuf.append $curbuf.count, result
  248. VIM::command('normal! 2G')
  249. VIM::command('redraw')
  250. }
  251. }
  252. VIM::evaluate('a:threads').to_i.times.map { |i|
  253. Thread.new(i) do |ii|
  254. while pair = take1.call
  255. name, dir, uri, branch = pair.last.values_at *%w[name dir uri branch]
  256. result =
  257. if File.directory? dir
  258. pull ? `#{cd} #{dir} && git pull 2>&1` : skip
  259. else
  260. FileUtils.mkdir_p(base)
  261. `#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{dir} 2>&1`
  262. end.lines.to_a.last.strip
  263. log.call name, result, ($? == 0 || result == skip)
  264. end
  265. end
  266. }.each(&:join)
  267. $curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
  268. EOF
  269. endfunction
  270. function! s:path(path)
  271. return substitute(s:is_win ? substitute(a:path, '/', '\', 'g') : a:path,
  272. \ '[/\\]*$', '', '')
  273. endfunction
  274. function! s:glob_dir(path)
  275. return map(filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)'), 's:path(v:val)')
  276. endfunction
  277. function! s:clean()
  278. call s:prepare()
  279. call append(0, 'Removing unused plugins in '.g:plug_home)
  280. " List of files
  281. let dirs = map(values(g:plug), 's:path(v:val.dir)')
  282. let alldirs = dirs +
  283. \ map(copy(dirs), 'fnamemodify(v:val, ":h")') +
  284. \ map(copy(dirs), 'fnamemodify(v:val, ":h:h")')
  285. for dir in dirs
  286. let alldirs += s:glob_dir(dir)
  287. endfor
  288. let allowed = {}
  289. for dir in alldirs
  290. let allowed[dir] = 1
  291. endfor
  292. let todo = []
  293. let found = sort(s:glob_dir(g:plug_home))
  294. while !empty(found)
  295. let f = remove(found, 0)
  296. if !has_key(allowed, f) && isdirectory(f)
  297. call add(todo, f)
  298. call append(line('$'), '- ' . f)
  299. let found = filter(found, 'stridx(v:val, f) != 0')
  300. end
  301. endwhile
  302. normal! G
  303. redraw
  304. if empty(todo)
  305. call append(line('$'), 'Already clean.')
  306. else
  307. call inputsave()
  308. let yes = input("Proceed? (Y/N) ")
  309. call inputrestore()
  310. if yes =~? '^y'
  311. for dir in todo
  312. if isdirectory(dir)
  313. call system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . dir)
  314. endif
  315. endfor
  316. call append(line('$'), 'Removed.')
  317. else
  318. call append(line('$'), 'Cancelled.')
  319. endif
  320. endif
  321. normal! G
  322. endfunction
  323. function! s:upgrade()
  324. if executable('curl')
  325. let mee = shellescape(s:me)
  326. let new = shellescape(s:me . '.new')
  327. echo "Downloading ". s:plug_source
  328. redraw
  329. let mv = s:is_win ? 'move /Y' : 'mv -f'
  330. call system(printf(
  331. \ "curl -fLo %s %s && ".mv." %s %s.old && ".mv." %s %s",
  332. \ new, s:plug_source, mee, mee, new, mee))
  333. if v:shell_error == 0
  334. unlet g:loaded_plug
  335. echo "Downloaded ". s:plug_source
  336. return 1
  337. else
  338. echoerr "Error upgrading vim-plug"
  339. return 0
  340. endif
  341. else
  342. echoerr "`curl' not found"
  343. return 0
  344. endif
  345. endfunction