plug.vim 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  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:add_rtp(rtp)
  136. execute "set rtp^=".a:rtp
  137. if isdirectory(a:rtp.'after')
  138. execute "set rtp+=".a:rtp.'after'
  139. endif
  140. endfunction
  141. function! s:lod(plug)
  142. let rtp = s:rtp(a:plug)
  143. call s:add_rtp(rtp)
  144. for dir in ['plugin', 'after']
  145. for vim in split(globpath(rtp, dir.'/*.vim'), '\n')
  146. execute 'source '.vim
  147. endfor
  148. endfor
  149. endfunction
  150. function! s:lod_cmd(cmd, bang, args, plug)
  151. execute 'delc '.a:cmd
  152. call s:lod(a:plug)
  153. execute printf("%s%s %s", a:cmd, a:bang, a:args)
  154. endfunction
  155. function! s:lod_map(map, plug)
  156. execute 'unmap '.a:map
  157. execute 'iunmap '.a:map
  158. call s:lod(a:plug)
  159. let extra = ''
  160. while 1
  161. let c = getchar(0)
  162. if c == 0
  163. break
  164. endif
  165. let extra .= nr2char(c)
  166. endwhile
  167. call feedkeys(substitute(a:map, '^<Plug>', "\<Plug>", '') . extra)
  168. endfunction
  169. function! s:add(...)
  170. let force = a:1
  171. let opts = { 'branch': 'master' }
  172. if a:0 == 2
  173. let plugin = a:2
  174. elseif a:0 == 3
  175. let plugin = a:2
  176. if type(a:3) == 1
  177. let opts.branch = a:3
  178. elseif type(a:3) == 4
  179. call extend(opts, a:3)
  180. else
  181. echoerr "Invalid argument type (expected: string or dictionary)"
  182. return
  183. endif
  184. else
  185. echoerr "Invalid number of arguments (1..2)"
  186. return
  187. endif
  188. if plugin =~ ':'
  189. let uri = plugin
  190. else
  191. if plugin !~ '/'
  192. let plugin = 'vim-scripts/'. plugin
  193. endif
  194. let uri = 'https://git:@github.com/' . plugin . '.git'
  195. endif
  196. let name = substitute(split(plugin, '/')[-1], '\.git$', '', '')
  197. if !force && has_key(g:plugs, name) | return | endif
  198. let dir = s:dirpath( fnamemodify(join([g:plug_home, name], '/'), ':p') )
  199. let spec = extend(opts, { 'dir': dir, 'uri': uri })
  200. let g:plugs[name] = spec
  201. endfunction
  202. function! s:install(...)
  203. call s:update_impl(0, a:000)
  204. endfunction
  205. function! s:update(...)
  206. call s:update_impl(1, a:000)
  207. endfunction
  208. function! s:apply()
  209. for spec in values(g:plugs)
  210. let docd = join([spec.dir, 'doc'], '/')
  211. if isdirectory(docd)
  212. execute "helptags ". join([spec.dir, 'doc'], '/')
  213. endif
  214. endfor
  215. runtime! plugin/*.vim
  216. runtime! after/*.vim
  217. silent! source $MYVIMRC
  218. endfunction
  219. function! s:syntax()
  220. syntax clear
  221. syntax region plug1 start=/\%1l/ end=/\%2l/ contains=ALL
  222. syntax region plug2 start=/\%2l/ end=/\%3l/ contains=ALL
  223. syn match plugNumber /[0-9]\+[0-9.]*/ containedin=plug1 contained
  224. syn match plugBracket /[[\]]/ containedin=plug2 contained
  225. syn match plugX /x/ containedin=plug2 contained
  226. syn match plugDash /^-/
  227. syn match plugName /\(^- \)\@<=[^:]*/
  228. syn match plugError /^x.*/
  229. syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
  230. hi def link plug1 Title
  231. hi def link plug2 Repeat
  232. hi def link plugX Exception
  233. hi def link plugBracket Structure
  234. hi def link plugNumber Number
  235. hi def link plugDash Special
  236. hi def link plugName Label
  237. hi def link plugError Error
  238. endfunction
  239. function! s:lpad(str, len)
  240. return a:str . repeat(' ', a:len - len(a:str))
  241. endfunction
  242. function! s:lastline(msg)
  243. let lines = split(a:msg, '\n')
  244. return get(lines, -1, '')
  245. endfunction
  246. function! s:prepare()
  247. execute s:plug_win . 'wincmd w'
  248. if exists('b:plug')
  249. %d
  250. else
  251. vertical topleft new
  252. noremap <silent> <buffer> q :q<cr>
  253. let b:plug = 1
  254. let s:plug_win = winnr()
  255. call s:assign_name()
  256. endif
  257. setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline
  258. setf vim-plug
  259. call s:syntax()
  260. endfunction
  261. function! s:assign_name()
  262. " Assign buffer name
  263. let prefix = '[Plugins]'
  264. let name = prefix
  265. let idx = 2
  266. while bufexists(name)
  267. let name = printf("%s (%s)", prefix, idx)
  268. let idx = idx + 1
  269. endwhile
  270. silent! execute "f ".fnameescape(name)
  271. endfunction
  272. function! s:finish()
  273. call append(3, '- Finishing ... ')
  274. redraw
  275. call s:apply()
  276. call s:syntax()
  277. call setline(4, getline(4) . 'Done!')
  278. normal! gg
  279. endfunction
  280. function! s:update_impl(pull, args)
  281. let threads = len(a:args) > 0 ? a:args[0] : get(g:, 'plug_threads', 16)
  282. call s:prepare()
  283. call append(0, a:pull ? 'Updating plugins' : 'Installing plugins')
  284. call append(1, '['. s:lpad('', len(g:plugs)) .']')
  285. normal! 2G
  286. redraw
  287. if has('ruby') && threads > 1
  288. call s:update_parallel(a:pull, threads)
  289. else
  290. call s:update_serial(a:pull)
  291. endif
  292. call s:finish()
  293. endfunction
  294. function! s:extend(names)
  295. let prev = copy(g:plugs)
  296. try
  297. command! -nargs=+ Plug call s:add(0, <args>)
  298. for name in a:names
  299. let plugfile = s:rtp(g:plugs[name]) . s:plug_file
  300. if filereadable(plugfile)
  301. execute "source ". plugfile
  302. endif
  303. endfor
  304. finally
  305. command! -nargs=+ Plug call s:add(1, <args>)
  306. endtry
  307. return filter(copy(g:plugs), '!has_key(prev, v:key)')
  308. endfunction
  309. function! s:update_progress(pull, cnt, bar, total)
  310. call setline(1, (a:pull ? 'Updating' : 'Installing').
  311. \ " plugins (".a:cnt."/".a:total.")")
  312. call s:progress_bar(2, a:bar, a:total)
  313. normal! 2G
  314. redraw
  315. endfunction
  316. function! s:update_serial(pull)
  317. let st = reltime()
  318. let base = g:plug_home
  319. let todo = copy(g:plugs)
  320. let total = len(todo)
  321. let done = {}
  322. let bar = ''
  323. while !empty(todo)
  324. for [name, spec] in items(todo)
  325. let done[name] = 1
  326. if isdirectory(spec.dir)
  327. execute 'cd '.spec.dir
  328. let [valid, msg] = s:git_valid(spec, 0, 0)
  329. if valid
  330. let result = a:pull ?
  331. \ system(
  332. \ printf('git checkout -q %s 2>&1 && git pull origin %s 2>&1',
  333. \ spec.branch, spec.branch)) : 'Already installed'
  334. let error = a:pull ? v:shell_error != 0 : 0
  335. else
  336. let result = msg
  337. let error = 1
  338. endif
  339. else
  340. if !isdirectory(base)
  341. call mkdir(base, 'p')
  342. endif
  343. execute 'cd '.base
  344. let d = shellescape(substitute(spec.dir, '[\/]\+$', '', ''))
  345. let result = system(
  346. \ printf('git clone --recursive %s -b %s %s 2>&1',
  347. \ shellescape(spec.uri), shellescape(spec.branch), d))
  348. let error = v:shell_error != 0
  349. endif
  350. cd -
  351. let bar .= error ? 'x' : '='
  352. call append(3, s:format_message(!error, name, result))
  353. call s:update_progress(a:pull, len(done), bar, total)
  354. endfor
  355. if !empty(s:extend(keys(todo)))
  356. let todo = filter(copy(g:plugs), '!has_key(done, v:key)')
  357. let total += len(todo)
  358. call s:update_progress(a:pull, len(done), bar, total)
  359. else
  360. break
  361. endif
  362. endwhile
  363. call setline(1, "Updated. Elapsed time: " . split(reltimestr(reltime(st)))[0] . ' sec.')
  364. endfunction
  365. function! s:update_parallel(pull, threads)
  366. ruby << EOF
  367. st = Time.now
  368. require 'thread'
  369. require 'fileutils'
  370. require 'timeout'
  371. running = true
  372. iswin = VIM::evaluate('s:is_win').to_i == 1
  373. pull = VIM::evaluate('a:pull').to_i == 1
  374. base = VIM::evaluate('g:plug_home')
  375. all = VIM::evaluate('copy(g:plugs)')
  376. limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
  377. nthr = VIM::evaluate('a:threads').to_i
  378. cd = iswin ? 'cd /d' : 'cd'
  379. done = {}
  380. tot = 0
  381. bar = ''
  382. skip = 'Already installed'
  383. mtx = Mutex.new
  384. take1 = proc { mtx.synchronize { running && all.shift } }
  385. logh = proc {
  386. cnt = done.length
  387. tot = VIM::evaluate('len(g:plugs)') || tot
  388. $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
  389. $curbuf[2] = '[' + bar.ljust(tot) + ']'
  390. VIM::command('normal! 2G')
  391. VIM::command('redraw') unless iswin
  392. }
  393. log = proc { |name, result, ok|
  394. mtx.synchronize do
  395. bar += ok ? '=' : 'x'
  396. done[name] = true
  397. result =
  398. if ok
  399. ["- #{name}: #{result.lines.to_a.last.strip}"]
  400. elsif result =~ /^Interrupted|^Timeout/
  401. ["x #{name}: #{result}"]
  402. else
  403. ["x #{name}"] + result.lines.map { |l| " " << l }
  404. end
  405. result.each_with_index do |line, offset|
  406. $curbuf.append 3 + offset, line.chomp
  407. end
  408. logh.call
  409. end
  410. }
  411. bt = proc { |cmd|
  412. begin
  413. fd = nil
  414. Timeout::timeout(limit) do
  415. if iswin
  416. tmp = VIM::evaluate('tempname()')
  417. system("#{cmd} > #{tmp}")
  418. data = File.read(tmp).chomp
  419. File.unlink tmp rescue nil
  420. else
  421. fd = IO.popen(cmd)
  422. data = fd.read.chomp
  423. fd.close
  424. end
  425. [$? == 0, data]
  426. end
  427. rescue Timeout::Error, Interrupt => e
  428. if fd && !fd.closed?
  429. pids = [fd.pid]
  430. unless `which pgrep`.empty?
  431. children = pids
  432. until children.empty?
  433. children = children.map { |pid|
  434. `pgrep -P #{pid}`.lines.map(&:chomp)
  435. }.flatten
  436. pids += children
  437. end
  438. end
  439. pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
  440. fd.close
  441. end
  442. [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
  443. end
  444. }
  445. main = Thread.current
  446. threads = []
  447. watcher = Thread.new {
  448. while VIM::evaluate('getchar(1)')
  449. sleep 0.1
  450. end
  451. mtx.synchronize do
  452. running = false
  453. threads.each { |t| t.raise Interrupt }
  454. end
  455. threads.each { |t| t.join rescue nil }
  456. main.kill
  457. }
  458. until all.empty?
  459. names = all.keys
  460. [names.length, nthr].min.times do
  461. mtx.synchronize do
  462. threads << Thread.new {
  463. while pair = take1.call
  464. name = pair.first
  465. dir, uri, branch = pair.last.values_at *%w[dir uri branch]
  466. ok, result =
  467. if File.directory? dir
  468. ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"
  469. current_uri = data.lines.to_a.last
  470. if !ret
  471. if data =~ /^Interrupted|^Timeout/
  472. [false, data]
  473. else
  474. [false, [data.chomp, "PlugClean required."].join($/)]
  475. end
  476. elsif current_uri.sub(/git:@/, '') != uri.sub(/git:@/, '')
  477. [false, ["Invalid URI: #{current_uri}",
  478. "Expected: #{uri}",
  479. "PlugClean required."].join($/)]
  480. else
  481. if pull
  482. bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && git pull origin #{branch} 2>&1"
  483. else
  484. [true, skip]
  485. end
  486. end
  487. else
  488. FileUtils.mkdir_p(base)
  489. d = dir.sub(%r{[\\/]+$}, '')
  490. bt.call "#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{d} 2>&1"
  491. end
  492. log.call name, result, ok
  493. end
  494. } if running
  495. end
  496. end
  497. threads.each(&:join)
  498. mtx.synchronize { threads.clear }
  499. all.merge!(VIM::evaluate("s:extend(#{names.inspect})") || {})
  500. logh.call
  501. end
  502. watcher.kill
  503. $curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
  504. EOF
  505. endfunction
  506. function! s:path(path)
  507. return substitute(s:is_win ? substitute(a:path, '/', '\', 'g') : a:path,
  508. \ '[/\\]*$', '', '')
  509. endfunction
  510. function! s:dirpath(path)
  511. let path = s:path(a:path)
  512. if s:is_win
  513. return path !~ '\\$' ? path.'\' : path
  514. else
  515. return path !~ '/$' ? path.'/' : path
  516. endif
  517. endfunction
  518. function! s:glob_dir(path)
  519. return map(filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)'), 's:dirpath(v:val)')
  520. endfunction
  521. function! s:progress_bar(line, bar, total)
  522. call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')
  523. endfunction
  524. function! s:compare_git_uri(a, b)
  525. let a = substitute(a:a, 'git:@', '', '')
  526. let b = substitute(a:b, 'git:@', '', '')
  527. return a ==# b
  528. endfunction
  529. function! s:format_message(ok, name, message)
  530. if a:ok
  531. return [printf('- %s: %s', a:name, s:lastline(a:message))]
  532. else
  533. let lines = map(split(a:message, '\n'), '" ".v:val')
  534. return extend([printf('x %s:', a:name)], lines)
  535. endif
  536. endfunction
  537. function! s:git_valid(spec, check_branch, cd)
  538. let ret = 1
  539. let msg = 'OK'
  540. if isdirectory(a:spec.dir)
  541. if a:cd | execute "cd " . a:spec.dir | endif
  542. let result = split(system("git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"), '\n')
  543. let remote = result[-1]
  544. if v:shell_error != 0
  545. let msg = join([remote, "PlugClean required."], "\n")
  546. let ret = 0
  547. elseif !s:compare_git_uri(remote, a:spec.uri)
  548. let msg = join(['Invalid URI: '.remote,
  549. \ 'Expected: '.a:spec.uri,
  550. \ "PlugClean required."], "\n")
  551. let ret = 0
  552. elseif a:check_branch
  553. let branch = result[0]
  554. if a:spec.branch != branch
  555. let msg = 'Invalid branch: '.branch.'. Try PlugUpdate.'
  556. let ret = 0
  557. endif
  558. endif
  559. if a:cd | cd - | endif
  560. else
  561. let msg = 'Not found'
  562. let ret = 0
  563. endif
  564. return [ret, msg]
  565. endfunction
  566. function! s:clean(force)
  567. call s:prepare()
  568. call append(0, 'Searching for unused plugins in '.g:plug_home)
  569. call append(1, '')
  570. " List of valid directories
  571. let dirs = []
  572. let [cnt, total] = [0, len(g:plugs)]
  573. for spec in values(g:plugs)
  574. if s:git_valid(spec, 0, 1)[0]
  575. call add(dirs, spec.dir)
  576. endif
  577. let cnt += 1
  578. call s:progress_bar(2, repeat('=', cnt), total)
  579. redraw
  580. endfor
  581. let allowed = {}
  582. for dir in dirs
  583. let allowed[dir] = 1
  584. for child in s:glob_dir(dir)
  585. let allowed[child] = 1
  586. endfor
  587. endfor
  588. let todo = []
  589. let found = sort(s:glob_dir(g:plug_home))
  590. while !empty(found)
  591. let f = remove(found, 0)
  592. if !has_key(allowed, f) && isdirectory(f)
  593. call add(todo, f)
  594. call append(line('$'), '- ' . f)
  595. let found = filter(found, 'stridx(v:val, f) != 0')
  596. end
  597. endwhile
  598. normal! G
  599. redraw
  600. if empty(todo)
  601. call append(line('$'), 'Already clean.')
  602. else
  603. call inputsave()
  604. let yes = a:force || (input("Proceed? (Y/N) ") =~? '^y')
  605. call inputrestore()
  606. if yes
  607. for dir in todo
  608. if isdirectory(dir)
  609. call system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . dir)
  610. endif
  611. endfor
  612. call append(line('$'), 'Removed.')
  613. else
  614. call append(line('$'), 'Cancelled.')
  615. endif
  616. endif
  617. normal! G
  618. endfunction
  619. function! s:upgrade()
  620. if executable('curl')
  621. let mee = shellescape(s:me)
  622. let new = shellescape(s:me . '.new')
  623. echo "Downloading ". s:plug_source
  624. redraw
  625. let mv = s:is_win ? 'move /Y' : 'mv -f'
  626. let cp = s:is_win ? 'copy /Y' : 'cp -f'
  627. call system(printf(
  628. \ "curl -fLo %s %s && ".cp." %s %s.old && ".mv." %s %s",
  629. \ new, s:plug_source, mee, mee, new, mee))
  630. if v:shell_error == 0
  631. unlet g:loaded_plug
  632. echo "Downloaded ". s:plug_source
  633. return 1
  634. else
  635. echoerr "Error upgrading vim-plug"
  636. return 0
  637. endif
  638. elseif has('ruby')
  639. echo "Downloading ". s:plug_source
  640. ruby << EOF
  641. require 'open-uri'
  642. require 'fileutils'
  643. me = VIM::evaluate('s:me')
  644. old = me + '.old'
  645. new = me + '.new'
  646. File.open(new, 'w') do |f|
  647. f << open(VIM::evaluate('s:plug_source')).read
  648. end
  649. FileUtils.cp me, old
  650. File.rename new, me
  651. EOF
  652. unlet g:loaded_plug
  653. echo "Downloaded ". s:plug_source
  654. return 1
  655. else
  656. echoerr "curl executable or ruby support not found"
  657. return 0
  658. endif
  659. endfunction
  660. function! s:status()
  661. call s:prepare()
  662. call append(0, 'Checking plugins')
  663. let ecnt = 0
  664. for [name, spec] in items(g:plugs)
  665. if isdirectory(spec.dir)
  666. let [valid, msg] = s:git_valid(spec, 1, 1)
  667. else
  668. let [valid, msg] = [0, 'Not found. Try PlugInstall.']
  669. endif
  670. let ecnt += !valid
  671. call append(2, s:format_message(valid, name, msg))
  672. call cursor(3, 1)
  673. redraw
  674. endfor
  675. call setline(1, 'Finished. '.ecnt.' error(s).')
  676. normal! gg
  677. endfunction
  678. let &cpo = s:cpo_save
  679. unlet s:cpo_save