plug.vim 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  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#begin()
  13. "
  14. " Plug 'junegunn/seoul256.vim'
  15. " Plug 'junegunn/vim-easy-align'
  16. " Plug 'junegunn/goyo.vim', { 'on': 'Goyo' }
  17. " " Plug 'user/repo1', 'branch_or_tag'
  18. " " Plug 'user/repo2', { 'rtp': 'vim/plugin/dir', 'branch': 'branch_or_tag' }
  19. " " ...
  20. "
  21. " call plug#end()
  22. "
  23. " Then :PlugInstall to install plugins. (default: ~/.vim/plugged)
  24. " You can change the location of the plugins with plug#begin(path) call.
  25. "
  26. "
  27. " Copyright (c) 2013 Junegunn Choi
  28. "
  29. " MIT License
  30. "
  31. " Permission is hereby granted, free of charge, to any person obtaining
  32. " a copy of this software and associated documentation files (the
  33. " "Software"), to deal in the Software without restriction, including
  34. " without limitation the rights to use, copy, modify, merge, publish,
  35. " distribute, sublicense, and/or sell copies of the Software, and to
  36. " permit persons to whom the Software is furnished to do so, subject to
  37. " the following conditions:
  38. "
  39. " The above copyright notice and this permission notice shall be
  40. " included in all copies or substantial portions of the Software.
  41. "
  42. " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  43. " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  44. " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  45. " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  46. " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  47. " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  48. " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  49. if exists('g:loaded_plug')
  50. finish
  51. endif
  52. let g:loaded_plug = 1
  53. let s:cpo_save = &cpo
  54. set cpo&vim
  55. let s:plug_source = 'https://raw.github.com/junegunn/vim-plug/master/plug.vim'
  56. let s:plug_file = 'Plugfile'
  57. let s:plug_win = 0
  58. let s:is_win = has('win32') || has('win64')
  59. let s:me = expand('<sfile>:p')
  60. function! plug#begin(...)
  61. if a:0 > 0
  62. let home = s:path(fnamemodify(a:1, ':p'))
  63. elseif exists('g:plug_home')
  64. let home = s:path(g:plug_home)
  65. elseif !empty(&rtp)
  66. let home = s:path(split(&rtp, ',')[0]) . '/plugged'
  67. else
  68. echoerr "Unable to determine plug home. Try calling plug#begin() with a path argument."
  69. return
  70. endif
  71. if !isdirectory(home)
  72. try
  73. call mkdir(home, 'p')
  74. catch
  75. echoerr 'Invalid plug directory: '. home
  76. return 0
  77. endtry
  78. endif
  79. if !executable('git')
  80. echoerr "`git' executable not found. vim-plug requires git."
  81. return 0
  82. endif
  83. let g:plug_home = home
  84. let g:plugs = {}
  85. command! -nargs=+ Plug call s:add(1, <args>)
  86. command! -nargs=* PlugInstall call s:install(<f-args>)
  87. command! -nargs=* PlugUpdate call s:update(<f-args>)
  88. command! -nargs=0 -bang PlugClean call s:clean('<bang>' == '!')
  89. command! -nargs=0 PlugUpgrade if s:upgrade() | execute "source ". s:me | endif
  90. command! -nargs=0 PlugStatus call s:status()
  91. return 1
  92. endfunction
  93. function! plug#end()
  94. if !exists('g:plugs')
  95. echoerr 'Call plug#begin() first'
  96. return
  97. endif
  98. let keys = keys(g:plugs)
  99. while !empty(keys)
  100. let keys = keys(s:extend(keys))
  101. endwhile
  102. filetype off
  103. for plug in values(g:plugs)
  104. if has_key(plug, 'on')
  105. let commands = type(plug.on) == 1 ? [plug.on] : plug.on
  106. for cmd in commands
  107. if cmd =~ '^<Plug>.\+'
  108. if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i'))
  109. for [mode, prefix] in [['i', "<C-O>"], ['', '']]
  110. execute printf(
  111. \ "%snoremap <silent> %s %s:call <SID>lod_map(%s, %s)<CR>",
  112. \ mode, cmd, prefix, string(cmd), string(plug))
  113. endfor
  114. endif
  115. elseif !exists(':'.cmd)
  116. execute printf(
  117. \ "command! -nargs=* -bang %s call s:lod_cmd(%s, '<bang>', <q-args>, %s)",
  118. \ cmd, string(cmd), string(plug))
  119. endif
  120. endfor
  121. else
  122. call s:add_rtp(s:rtp(plug))
  123. endif
  124. endfor
  125. filetype plugin indent on
  126. syntax on
  127. endfunction
  128. function! s:rtp(spec)
  129. let rtp = s:dirpath(a:spec.dir . get(a:spec, 'rtp', ''))
  130. if s:is_win
  131. let rtp = substitute(rtp, '\\*$', '', '')
  132. endif
  133. return rtp
  134. endfunction
  135. function! s:esc(path)
  136. return substitute(a:path, ' ', '\\ ', 'g')
  137. endfunction
  138. function! s:add_rtp(rtp)
  139. execute "set rtp^=".s:esc(a:rtp)
  140. if isdirectory(a:rtp.'after')
  141. execute "set rtp+=".s:esc(a:rtp.'after')
  142. endif
  143. endfunction
  144. function! s:lod(plug)
  145. let rtp = s:rtp(a:plug)
  146. call s:add_rtp(rtp)
  147. for dir in ['plugin', 'after']
  148. for vim in split(globpath(rtp, dir.'/*.vim'), '\n')
  149. execute 'source '.vim
  150. endfor
  151. endfor
  152. endfunction
  153. function! s:lod_cmd(cmd, bang, args, plug)
  154. execute 'delc '.a:cmd
  155. call s:lod(a:plug)
  156. execute printf("%s%s %s", a:cmd, a:bang, a:args)
  157. endfunction
  158. function! s:lod_map(map, plug)
  159. execute 'unmap '.a:map
  160. execute 'iunmap '.a:map
  161. call s:lod(a:plug)
  162. let extra = ''
  163. while 1
  164. let c = getchar(0)
  165. if c == 0
  166. break
  167. endif
  168. let extra .= nr2char(c)
  169. endwhile
  170. call feedkeys(substitute(a:map, '^<Plug>', "\<Plug>", '') . extra)
  171. endfunction
  172. function! s:add(...)
  173. let force = a:1
  174. let opts = { 'branch': 'master' }
  175. if a:0 == 2
  176. let plugin = a:2
  177. elseif a:0 == 3
  178. let plugin = a:2
  179. if type(a:3) == 1
  180. let opts.branch = a:3
  181. elseif type(a:3) == 4
  182. call extend(opts, a:3)
  183. else
  184. echoerr "Invalid argument type (expected: string or dictionary)"
  185. return
  186. endif
  187. else
  188. echoerr "Invalid number of arguments (1..2)"
  189. return
  190. endif
  191. if plugin =~ ':'
  192. let uri = plugin
  193. else
  194. if plugin !~ '/'
  195. let plugin = 'vim-scripts/'. plugin
  196. endif
  197. let uri = 'https://git:@github.com/' . plugin . '.git'
  198. endif
  199. let name = substitute(split(plugin, '/')[-1], '\.git$', '', '')
  200. if !force && has_key(g:plugs, name) | return | endif
  201. let dir = s:dirpath( fnamemodify(join([g:plug_home, name], '/'), ':p') )
  202. let spec = extend(opts, { 'dir': dir, 'uri': uri })
  203. let g:plugs[name] = spec
  204. endfunction
  205. function! s:install(...)
  206. call s:update_impl(0, a:000)
  207. endfunction
  208. function! s:update(...)
  209. call s:update_impl(1, a:000)
  210. endfunction
  211. function! s:apply()
  212. for spec in values(g:plugs)
  213. let docd = join([spec.dir, 'doc'], '/')
  214. if isdirectory(docd)
  215. execute "helptags ". join([spec.dir, 'doc'], '/')
  216. endif
  217. endfor
  218. runtime! plugin/*.vim
  219. runtime! after/*.vim
  220. silent! source $MYVIMRC
  221. endfunction
  222. function! s:syntax()
  223. syntax clear
  224. syntax region plug1 start=/\%1l/ end=/\%2l/ contains=ALL
  225. syntax region plug2 start=/\%2l/ end=/\%3l/ contains=ALL
  226. syn match plugNumber /[0-9]\+[0-9.]*/ containedin=plug1 contained
  227. syn match plugBracket /[[\]]/ containedin=plug2 contained
  228. syn match plugX /x/ containedin=plug2 contained
  229. syn match plugDash /^-/
  230. syn match plugName /\(^- \)\@<=[^:]*/
  231. syn match plugError /^x.*/
  232. syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
  233. hi def link plug1 Title
  234. hi def link plug2 Repeat
  235. hi def link plugX Exception
  236. hi def link plugBracket Structure
  237. hi def link plugNumber Number
  238. hi def link plugDash Special
  239. hi def link plugName Label
  240. hi def link plugError Error
  241. endfunction
  242. function! s:lpad(str, len)
  243. return a:str . repeat(' ', a:len - len(a:str))
  244. endfunction
  245. function! s:lastline(msg)
  246. let lines = split(a:msg, '\n')
  247. return get(lines, -1, '')
  248. endfunction
  249. function! s:prepare()
  250. execute s:plug_win . 'wincmd w'
  251. if exists('b:plug')
  252. %d
  253. else
  254. vertical topleft new
  255. noremap <silent> <buffer> q :q<cr>
  256. let b:plug = 1
  257. let s:plug_win = winnr()
  258. call s:assign_name()
  259. endif
  260. setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline
  261. setf vim-plug
  262. call s:syntax()
  263. endfunction
  264. function! s:assign_name()
  265. " Assign buffer name
  266. let prefix = '[Plugins]'
  267. let name = prefix
  268. let idx = 2
  269. while bufexists(name)
  270. let name = printf("%s (%s)", prefix, idx)
  271. let idx = idx + 1
  272. endwhile
  273. silent! execute "f ".fnameescape(name)
  274. endfunction
  275. function! s:finish()
  276. call append(3, '- Finishing ... ')
  277. redraw
  278. call s:apply()
  279. call s:syntax()
  280. call setline(4, getline(4) . 'Done!')
  281. normal! gg
  282. endfunction
  283. function! s:update_impl(pull, args)
  284. let threads = len(a:args) > 0 ? a:args[0] : get(g:, 'plug_threads', 16)
  285. call s:prepare()
  286. call append(0, a:pull ? 'Updating plugins' : 'Installing plugins')
  287. call append(1, '['. s:lpad('', len(g:plugs)) .']')
  288. normal! 2G
  289. redraw
  290. if has('ruby') && threads > 1
  291. call s:update_parallel(a:pull, threads)
  292. else
  293. call s:update_serial(a:pull)
  294. endif
  295. call s:finish()
  296. endfunction
  297. function! s:extend(names)
  298. let prev = copy(g:plugs)
  299. try
  300. command! -nargs=+ Plug call s:add(0, <args>)
  301. for name in a:names
  302. let plugfile = s:rtp(g:plugs[name]) . s:plug_file
  303. if filereadable(plugfile)
  304. execute "source ". s:esc(plugfile)
  305. endif
  306. endfor
  307. finally
  308. command! -nargs=+ Plug call s:add(1, <args>)
  309. endtry
  310. return filter(copy(g:plugs), '!has_key(prev, v:key)')
  311. endfunction
  312. function! s:update_progress(pull, cnt, bar, total)
  313. call setline(1, (a:pull ? 'Updating' : 'Installing').
  314. \ " plugins (".a:cnt."/".a:total.")")
  315. call s:progress_bar(2, a:bar, a:total)
  316. normal! 2G
  317. redraw
  318. endfunction
  319. function! s:update_serial(pull)
  320. let st = reltime()
  321. let base = g:plug_home
  322. let todo = copy(g:plugs)
  323. let total = len(todo)
  324. let done = {}
  325. let bar = ''
  326. while !empty(todo)
  327. for [name, spec] in items(todo)
  328. let done[name] = 1
  329. if isdirectory(spec.dir)
  330. execute 'cd '.s:esc(spec.dir)
  331. let [valid, msg] = s:git_valid(spec, 0, 0)
  332. if valid
  333. let result = a:pull ?
  334. \ s:system(
  335. \ printf('git checkout -q %s 2>&1 && git pull origin %s 2>&1',
  336. \ s:shellesc(spec.branch), s:shellesc(spec.branch))) : 'Already installed'
  337. let error = a:pull ? v:shell_error != 0 : 0
  338. else
  339. let result = msg
  340. let error = 1
  341. endif
  342. else
  343. if !isdirectory(base)
  344. call mkdir(base, 'p')
  345. endif
  346. execute 'cd '.base
  347. let result = s:system(
  348. \ printf('git clone --recursive %s -b %s %s 2>&1',
  349. \ s:shellesc(spec.uri),
  350. \ s:shellesc(spec.branch),
  351. \ s:shellesc(substitute(spec.dir, '[\/]\+$', '', ''))))
  352. let error = v:shell_error != 0
  353. endif
  354. cd -
  355. let bar .= error ? 'x' : '='
  356. call append(3, s:format_message(!error, name, result))
  357. call s:update_progress(a:pull, len(done), bar, total)
  358. endfor
  359. if !empty(s:extend(keys(todo)))
  360. let todo = filter(copy(g:plugs), '!has_key(done, v:key)')
  361. let total += len(todo)
  362. call s:update_progress(a:pull, len(done), bar, total)
  363. else
  364. break
  365. endif
  366. endwhile
  367. call setline(1, "Updated. Elapsed time: " . split(reltimestr(reltime(st)))[0] . ' sec.')
  368. endfunction
  369. function! s:update_parallel(pull, threads)
  370. ruby << EOF
  371. def esc arg
  372. %["#{arg.gsub('"', '\"')}"]
  373. end
  374. st = Time.now
  375. require 'thread'
  376. require 'fileutils'
  377. require 'timeout'
  378. running = true
  379. iswin = VIM::evaluate('s:is_win').to_i == 1
  380. pull = VIM::evaluate('a:pull').to_i == 1
  381. base = VIM::evaluate('g:plug_home')
  382. all = VIM::evaluate('copy(g:plugs)')
  383. limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
  384. nthr = VIM::evaluate('a:threads').to_i
  385. cd = iswin ? 'cd /d' : 'cd'
  386. done = {}
  387. tot = 0
  388. bar = ''
  389. skip = 'Already installed'
  390. mtx = Mutex.new
  391. take1 = proc { mtx.synchronize { running && all.shift } }
  392. logh = proc {
  393. cnt = done.length
  394. tot = VIM::evaluate('len(g:plugs)') || tot
  395. $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
  396. $curbuf[2] = '[' + bar.ljust(tot) + ']'
  397. VIM::command('normal! 2G')
  398. VIM::command('redraw') unless iswin
  399. }
  400. log = proc { |name, result, ok|
  401. mtx.synchronize do
  402. bar += ok ? '=' : 'x'
  403. done[name] = true
  404. result =
  405. if ok
  406. ["- #{name}: #{result.lines.to_a.last.strip}"]
  407. elsif result =~ /^Interrupted|^Timeout/
  408. ["x #{name}: #{result}"]
  409. else
  410. ["x #{name}"] + result.lines.map { |l| " " << l }
  411. end
  412. result.each_with_index do |line, offset|
  413. $curbuf.append 3 + offset, line.chomp
  414. end
  415. logh.call
  416. end
  417. }
  418. bt = proc { |cmd|
  419. begin
  420. fd = nil
  421. Timeout::timeout(limit) do
  422. if iswin
  423. tmp = VIM::evaluate('tempname()')
  424. system("#{cmd} > #{tmp}")
  425. data = File.read(tmp).chomp
  426. File.unlink tmp rescue nil
  427. else
  428. fd = IO.popen(cmd)
  429. data = fd.read.chomp
  430. fd.close
  431. end
  432. [$? == 0, data]
  433. end
  434. rescue Timeout::Error, Interrupt => e
  435. if fd && !fd.closed?
  436. pids = [fd.pid]
  437. unless `which pgrep`.empty?
  438. children = pids
  439. until children.empty?
  440. children = children.map { |pid|
  441. `pgrep -P #{pid}`.lines.map(&:chomp)
  442. }.flatten
  443. pids += children
  444. end
  445. end
  446. pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
  447. fd.close
  448. end
  449. [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
  450. end
  451. }
  452. main = Thread.current
  453. threads = []
  454. watcher = Thread.new {
  455. while VIM::evaluate('getchar(1)')
  456. sleep 0.1
  457. end
  458. mtx.synchronize do
  459. running = false
  460. threads.each { |t| t.raise Interrupt }
  461. end
  462. threads.each { |t| t.join rescue nil }
  463. main.kill
  464. }
  465. until all.empty?
  466. names = all.keys
  467. [names.length, nthr].min.times do
  468. mtx.synchronize do
  469. threads << Thread.new {
  470. while pair = take1.call
  471. name = pair.first
  472. dir, uri, branch = pair.last.values_at *%w[dir uri branch]
  473. branch = esc branch
  474. ok, result =
  475. if File.directory? dir
  476. dir = esc dir
  477. ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"
  478. current_uri = data.lines.to_a.last
  479. if !ret
  480. if data =~ /^Interrupted|^Timeout/
  481. [false, data]
  482. else
  483. [false, [data.chomp, "PlugClean required."].join($/)]
  484. end
  485. elsif current_uri.sub(/git:@/, '') != uri.sub(/git:@/, '')
  486. [false, ["Invalid URI: #{current_uri}",
  487. "Expected: #{uri}",
  488. "PlugClean required."].join($/)]
  489. else
  490. if pull
  491. bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && git pull origin #{branch} 2>&1"
  492. else
  493. [true, skip]
  494. end
  495. end
  496. else
  497. FileUtils.mkdir_p(base)
  498. d = esc dir.sub(%r{[\\/]+$}, '')
  499. bt.call "#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{d} 2>&1"
  500. end
  501. log.call name, result, ok
  502. end
  503. } if running
  504. end
  505. end
  506. threads.each(&:join)
  507. mtx.synchronize { threads.clear }
  508. all.merge!(VIM::evaluate("s:extend(#{names.inspect})") || {})
  509. logh.call
  510. end
  511. watcher.kill
  512. $curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
  513. EOF
  514. endfunction
  515. function! s:path(path)
  516. return substitute(s:is_win ? substitute(a:path, '/', '\', 'g') : a:path,
  517. \ '[/\\]*$', '', '')
  518. endfunction
  519. function! s:dirpath(path)
  520. let path = s:path(a:path)
  521. if s:is_win
  522. return path !~ '\\$' ? path.'\' : path
  523. else
  524. return path !~ '/$' ? path.'/' : path
  525. endif
  526. endfunction
  527. function! s:shellesc(arg)
  528. return '"'.substitute(a:arg, '"', '\\"', 'g').'"'
  529. endfunction
  530. function! s:glob_dir(path)
  531. return map(filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)'), 's:dirpath(v:val)')
  532. endfunction
  533. function! s:progress_bar(line, bar, total)
  534. call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')
  535. endfunction
  536. function! s:compare_git_uri(a, b)
  537. let a = substitute(a:a, 'git:@', '', '')
  538. let b = substitute(a:b, 'git:@', '', '')
  539. return a ==# b
  540. endfunction
  541. function! s:format_message(ok, name, message)
  542. if a:ok
  543. return [printf('- %s: %s', a:name, s:lastline(a:message))]
  544. else
  545. let lines = map(split(a:message, '\n'), '" ".v:val')
  546. return extend([printf('x %s:', a:name)], lines)
  547. endif
  548. endfunction
  549. function! s:system(cmd)
  550. return system(s:is_win ? '('.a:cmd.')' : a:cmd)
  551. endfunction
  552. function! s:git_valid(spec, check_branch, cd)
  553. let ret = 1
  554. let msg = 'OK'
  555. if isdirectory(a:spec.dir)
  556. if a:cd | execute "cd " . s:esc(a:spec.dir) | endif
  557. let result = split(s:system("git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"), '\n')
  558. let remote = result[-1]
  559. if v:shell_error != 0
  560. let msg = join([remote, "PlugClean required."], "\n")
  561. let ret = 0
  562. elseif !s:compare_git_uri(remote, a:spec.uri)
  563. let msg = join(['Invalid URI: '.remote,
  564. \ 'Expected: '.a:spec.uri,
  565. \ "PlugClean required."], "\n")
  566. let ret = 0
  567. elseif a:check_branch
  568. let branch = result[0]
  569. if a:spec.branch != branch
  570. let msg = 'Invalid branch: '.branch.'. Try PlugUpdate.'
  571. let ret = 0
  572. endif
  573. endif
  574. if a:cd | cd - | endif
  575. else
  576. let msg = 'Not found'
  577. let ret = 0
  578. endif
  579. return [ret, msg]
  580. endfunction
  581. function! s:clean(force)
  582. call s:prepare()
  583. call append(0, 'Searching for unused plugins in '.g:plug_home)
  584. call append(1, '')
  585. " List of valid directories
  586. let dirs = []
  587. let [cnt, total] = [0, len(g:plugs)]
  588. for spec in values(g:plugs)
  589. if s:git_valid(spec, 0, 1)[0]
  590. call add(dirs, spec.dir)
  591. endif
  592. let cnt += 1
  593. call s:progress_bar(2, repeat('=', cnt), total)
  594. redraw
  595. endfor
  596. let allowed = {}
  597. for dir in dirs
  598. let allowed[dir] = 1
  599. for child in s:glob_dir(dir)
  600. let allowed[child] = 1
  601. endfor
  602. endfor
  603. let todo = []
  604. let found = sort(s:glob_dir(g:plug_home))
  605. while !empty(found)
  606. let f = remove(found, 0)
  607. if !has_key(allowed, f) && isdirectory(f)
  608. call add(todo, f)
  609. call append(line('$'), '- ' . f)
  610. let found = filter(found, 'stridx(v:val, f) != 0')
  611. end
  612. endwhile
  613. normal! G
  614. redraw
  615. if empty(todo)
  616. call append(line('$'), 'Already clean.')
  617. else
  618. call inputsave()
  619. let yes = a:force || (input("Proceed? (Y/N) ") =~? '^y')
  620. call inputrestore()
  621. if yes
  622. for dir in todo
  623. if isdirectory(dir)
  624. call system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(dir))
  625. endif
  626. endfor
  627. call append(line('$'), 'Removed.')
  628. else
  629. call append(line('$'), 'Cancelled.')
  630. endif
  631. endif
  632. normal! G
  633. endfunction
  634. function! s:upgrade()
  635. if executable('curl')
  636. let mee = s:shellesc(s:me)
  637. let new = s:shellesc(s:me . '.new')
  638. echo "Downloading ". s:plug_source
  639. redraw
  640. let mv = s:is_win ? 'move /Y' : 'mv -f'
  641. let cp = s:is_win ? 'copy /Y' : 'cp -f'
  642. call system(printf(
  643. \ "curl -fLo %s %s && ".cp." %s %s.old && ".mv." %s %s",
  644. \ new, s:plug_source, mee, mee, new, mee))
  645. if v:shell_error == 0
  646. unlet g:loaded_plug
  647. echo "Downloaded ". s:plug_source
  648. return 1
  649. else
  650. echoerr "Error upgrading vim-plug"
  651. return 0
  652. endif
  653. elseif has('ruby')
  654. echo "Downloading ". s:plug_source
  655. ruby << EOF
  656. require 'open-uri'
  657. require 'fileutils'
  658. me = VIM::evaluate('s:me')
  659. old = me + '.old'
  660. new = me + '.new'
  661. File.open(new, 'w') do |f|
  662. f << open(VIM::evaluate('s:plug_source')).read
  663. end
  664. FileUtils.cp me, old
  665. File.rename new, me
  666. EOF
  667. unlet g:loaded_plug
  668. echo "Downloaded ". s:plug_source
  669. return 1
  670. else
  671. echoerr "curl executable or ruby support not found"
  672. return 0
  673. endif
  674. endfunction
  675. function! s:status()
  676. call s:prepare()
  677. call append(0, 'Checking plugins')
  678. let ecnt = 0
  679. for [name, spec] in items(g:plugs)
  680. if isdirectory(spec.dir)
  681. let [valid, msg] = s:git_valid(spec, 1, 1)
  682. else
  683. let [valid, msg] = [0, 'Not found. Try PlugInstall.']
  684. endif
  685. let ecnt += !valid
  686. call append(2, s:format_message(valid, name, msg))
  687. call cursor(3, 1)
  688. redraw
  689. endfor
  690. call setline(1, 'Finished. '.ecnt.' error(s).')
  691. normal! gg
  692. endfunction
  693. let &cpo = s:cpo_save
  694. unlet s:cpo_save