plug.vim 21 KB

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