plug.vim 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255
  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.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  9. "
  10. " Edit your .vimrc
  11. "
  12. " call plug#begin('~/.vim/plugged')
  13. "
  14. " " Make sure you use single quotes
  15. " Plug 'junegunn/seoul256.vim'
  16. " Plug 'junegunn/vim-easy-align'
  17. "
  18. " " On-demand loading
  19. " Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' }
  20. " Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
  21. "
  22. " " Using git URL
  23. " Plug 'https://github.com/junegunn/vim-github-dashboard.git'
  24. "
  25. " " Plugin options
  26. " Plug 'nsf/gocode', { 'tag': 'go.weekly.2012-03-13', 'rtp': 'vim' }
  27. "
  28. " " Plugin outside ~/.vim/plugged with post-update hook
  29. " Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': 'yes \| ./install' }
  30. "
  31. " " Unmanaged plugin (manually installed and updated)
  32. " Plug '~/my-prototype-plugin'
  33. "
  34. " call plug#end()
  35. "
  36. " Then reload .vimrc and :PlugInstall to install plugins.
  37. " Visit https://github.com/junegunn/vim-plug for more information.
  38. "
  39. "
  40. " Copyright (c) 2014 Junegunn Choi
  41. "
  42. " MIT License
  43. "
  44. " Permission is hereby granted, free of charge, to any person obtaining
  45. " a copy of this software and associated documentation files (the
  46. " "Software"), to deal in the Software without restriction, including
  47. " without limitation the rights to use, copy, modify, merge, publish,
  48. " distribute, sublicense, and/or sell copies of the Software, and to
  49. " permit persons to whom the Software is furnished to do so, subject to
  50. " the following conditions:
  51. "
  52. " The above copyright notice and this permission notice shall be
  53. " included in all copies or substantial portions of the Software.
  54. "
  55. " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  56. " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  57. " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  58. " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  59. " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  60. " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  61. " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  62. if exists('g:loaded_plug')
  63. finish
  64. endif
  65. let g:loaded_plug = 1
  66. let s:cpo_save = &cpo
  67. set cpo&vim
  68. let s:plug_source = 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
  69. let s:plug_buf = get(s:, 'plug_buf', -1)
  70. let s:mac_gui = has('gui_macvim') && has('gui_running')
  71. let s:is_win = has('win32') || has('win64')
  72. let s:me = resolve(expand('<sfile>:p'))
  73. let s:base_spec = { 'branch': 'master', 'frozen': 0 }
  74. let s:TYPE = {
  75. \ 'string': type(''),
  76. \ 'list': type([]),
  77. \ 'dict': type({}),
  78. \ 'funcref': type(function('call'))
  79. \ }
  80. let s:loaded = get(s:, 'loaded', {})
  81. function! plug#begin(...)
  82. if a:0 > 0
  83. let home = s:path(fnamemodify(a:1, ':p'))
  84. elseif exists('g:plug_home')
  85. let home = s:path(g:plug_home)
  86. elseif !empty(&rtp)
  87. let home = s:path(split(&rtp, ',')[0]) . '/plugged'
  88. else
  89. return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')
  90. endif
  91. let g:plug_home = home
  92. let g:plugs = {}
  93. " we want to keep track of the order plugins where registered.
  94. let g:plugs_order = []
  95. call s:define_commands()
  96. return 1
  97. endfunction
  98. function! s:define_commands()
  99. command! -nargs=+ -bar Plug call s:add(<args>)
  100. if !executable('git')
  101. return s:err('`git` executable not found. vim-plug requires git.')
  102. endif
  103. command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install('<bang>' == '!', <f-args>)
  104. command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update('<bang>' == '!', <f-args>)
  105. command! -nargs=0 -bar -bang PlugClean call s:clean('<bang>' == '!')
  106. command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:me | endif
  107. command! -nargs=0 -bar PlugStatus call s:status()
  108. command! -nargs=0 -bar PlugDiff call s:diff()
  109. endfunction
  110. function! s:to_a(v)
  111. return type(a:v) == s:TYPE.list ? a:v : [a:v]
  112. endfunction
  113. function! s:source(from, ...)
  114. for pattern in a:000
  115. for vim in split(globpath(a:from, pattern), '\n')
  116. execute 'source' vim
  117. endfor
  118. endfor
  119. endfunction
  120. function! plug#end()
  121. let reload = !has('vim_starting')
  122. if !exists('g:plugs')
  123. return s:err('Call plug#begin() first')
  124. endif
  125. if exists('#PlugLOD')
  126. augroup PlugLOD
  127. autocmd!
  128. augroup END
  129. augroup! PlugLOD
  130. endif
  131. let lod = {}
  132. filetype off
  133. " we want to make sure the plugin directories are added to rtp in the same
  134. " order that they are registered with the Plug command. since the s:add_rtp
  135. " function uses ^= to add plugin directories to the front of the rtp, we
  136. " need to loop through the plugins in reverse
  137. for name in reverse(copy(g:plugs_order))
  138. let plug = g:plugs[name]
  139. if get(s:loaded, plug.dir, 0) || !has_key(plug, 'on') && !has_key(plug, 'for')
  140. let rtp = s:add_rtp(plug)
  141. if reload
  142. call s:source(rtp, 'plugin/**/*.vim', 'after/plugin/**/*.vim')
  143. endif
  144. continue
  145. endif
  146. if has_key(plug, 'on')
  147. for cmd in s:to_a(plug.on)
  148. if cmd =~ '^<Plug>.\+'
  149. if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i'))
  150. for [mode, map_prefix, key_prefix] in
  151. \ [['i', '<C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']]
  152. execute printf(
  153. \ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, "%s")<CR>',
  154. \ mode, cmd, map_prefix, string(cmd), string(name), key_prefix)
  155. endfor
  156. endif
  157. elseif !exists(':'.cmd)
  158. execute printf(
  159. \ 'command! -nargs=* -range -bang %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)',
  160. \ cmd, string(cmd), string(name))
  161. endif
  162. endfor
  163. endif
  164. if has_key(plug, 'for')
  165. let types = s:to_a(plug.for)
  166. if !empty(types)
  167. call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim')
  168. endif
  169. for key in types
  170. if !has_key(lod, key)
  171. let lod[key] = []
  172. endif
  173. call add(lod[key], name)
  174. endfor
  175. endif
  176. endfor
  177. for [key, names] in items(lod)
  178. augroup PlugLOD
  179. execute printf('autocmd FileType %s call <SID>lod_ft(%s, %s)',
  180. \ key, string(key), string(reverse(names)))
  181. augroup END
  182. endfor
  183. call s:reorg_rtp()
  184. filetype plugin indent on
  185. syntax enable
  186. endfunction
  187. function! s:trim(str)
  188. return substitute(a:str, '[\/]\+$', '', '')
  189. endfunction
  190. if s:is_win
  191. function! s:rtp(spec)
  192. return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
  193. endfunction
  194. function! s:path(path)
  195. return s:trim(substitute(a:path, '/', '\', 'g'))
  196. endfunction
  197. function! s:dirpath(path)
  198. return s:path(a:path) . '\'
  199. endfunction
  200. function! s:is_local_plug(repo)
  201. return a:repo =~? '^[a-z]:'
  202. endfunction
  203. else
  204. function! s:rtp(spec)
  205. return s:dirpath(a:spec.dir . get(a:spec, 'rtp', ''))
  206. endfunction
  207. function! s:path(path)
  208. return s:trim(a:path)
  209. endfunction
  210. function! s:dirpath(path)
  211. return substitute(a:path, '[/\\]*$', '/', '')
  212. endfunction
  213. function! s:is_local_plug(repo)
  214. return a:repo[0] =~ '[/$~]'
  215. endfunction
  216. endif
  217. function! s:err(msg)
  218. echohl ErrorMsg
  219. echom a:msg
  220. echohl None
  221. return 0
  222. endfunction
  223. function! s:esc(path)
  224. return substitute(a:path, ' ', '\\ ', 'g')
  225. endfunction
  226. function! s:add_rtp(plug)
  227. let rtp = s:rtp(a:plug)
  228. execute 'set rtp^='.s:esc(rtp)
  229. let after = globpath(rtp, 'after')
  230. if isdirectory(after)
  231. execute 'set rtp+='.s:esc(after)
  232. endif
  233. let s:loaded[a:plug.dir] = 1
  234. return rtp
  235. endfunction
  236. function! s:reorg_rtp()
  237. if !empty(s:first_rtp)
  238. execute 'set rtp-='.s:first_rtp
  239. execute 'set rtp^='.s:first_rtp
  240. endif
  241. if s:last_rtp !=# s:first_rtp
  242. execute 'set rtp-='.s:last_rtp
  243. execute 'set rtp+='.s:last_rtp
  244. endif
  245. endfunction
  246. function! plug#load(...)
  247. if a:0 == 0
  248. return s:err('Argument missing: plugin name(s) required')
  249. endif
  250. if !exists('g:plugs')
  251. return s:err('plug#begin was not called')
  252. endif
  253. let unknowns = filter(copy(a:000), '!has_key(g:plugs, v:val)')
  254. if !empty(unknowns)
  255. let s = len(unknowns) > 1 ? 's' : ''
  256. return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', ')))
  257. end
  258. for name in a:000
  259. call s:lod(g:plugs[name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
  260. endfor
  261. call s:reorg_rtp()
  262. silent! doautocmd BufRead
  263. return 1
  264. endfunction
  265. function! s:lod(plug, types)
  266. let rtp = s:add_rtp(a:plug)
  267. for dir in a:types
  268. call s:source(rtp, dir.'/**/*.vim')
  269. endfor
  270. endfunction
  271. function! s:lod_ft(pat, names)
  272. for name in a:names
  273. call s:lod(g:plugs[name], ['plugin', 'after/plugin'])
  274. endfor
  275. call s:reorg_rtp()
  276. execute 'autocmd! PlugLOD FileType' a:pat
  277. silent! doautocmd filetypeplugin FileType
  278. silent! doautocmd filetypeindent FileType
  279. endfunction
  280. function! s:lod_cmd(cmd, bang, l1, l2, args, name)
  281. execute 'delc' a:cmd
  282. call s:lod(g:plugs[a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
  283. call s:reorg_rtp()
  284. execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
  285. endfunction
  286. function! s:lod_map(map, name, prefix)
  287. execute 'unmap' a:map
  288. execute 'iunmap' a:map
  289. call s:lod(g:plugs[a:name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
  290. call s:reorg_rtp()
  291. let extra = ''
  292. while 1
  293. let c = getchar(0)
  294. if c == 0
  295. break
  296. endif
  297. let extra .= nr2char(c)
  298. endwhile
  299. call feedkeys(a:prefix . substitute(a:map, '^<Plug>', "\<Plug>", '') . extra)
  300. endfunction
  301. function! s:add(repo, ...)
  302. if a:0 > 1
  303. return s:err('Invalid number of arguments (1..2)')
  304. endif
  305. try
  306. let repo = s:trim(a:repo)
  307. let name = fnamemodify(repo, ':t:s?\.git$??')
  308. let spec = extend(s:infer_properties(name, repo),
  309. \ a:0 == 1 ? s:parse_options(a:1) : s:base_spec)
  310. let g:plugs[name] = spec
  311. let g:plugs_order += [name]
  312. let s:loaded[spec.dir] = 0
  313. catch
  314. return s:err(v:exception)
  315. endtry
  316. endfunction
  317. function! s:parse_options(arg)
  318. let opts = copy(s:base_spec)
  319. let type = type(a:arg)
  320. if type == s:TYPE.string
  321. let opts.branch = a:arg
  322. elseif type == s:TYPE.dict
  323. call extend(opts, a:arg)
  324. if has_key(opts, 'tag')
  325. let opts.branch = remove(opts, 'tag')
  326. endif
  327. if has_key(opts, 'dir')
  328. let opts.dir = s:dirpath(expand(opts.dir))
  329. endif
  330. else
  331. throw 'Invalid argument type (expected: string or dictionary)'
  332. endif
  333. return opts
  334. endfunction
  335. function! s:infer_properties(name, repo)
  336. let repo = a:repo
  337. if s:is_local_plug(repo)
  338. return { 'dir': s:dirpath(expand(repo)) }
  339. else
  340. if repo =~ ':'
  341. let uri = repo
  342. else
  343. if repo !~ '/'
  344. let repo = 'vim-scripts/'. repo
  345. endif
  346. let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git')
  347. let uri = printf(fmt, repo)
  348. endif
  349. let dir = s:dirpath( fnamemodify(join([g:plug_home, a:name], '/'), ':p') )
  350. return { 'dir': dir, 'uri': uri }
  351. endif
  352. endfunction
  353. function! s:install(force, ...)
  354. call s:update_impl(0, a:force, a:000)
  355. endfunction
  356. function! s:update(force, ...)
  357. call s:update_impl(1, a:force, a:000)
  358. endfunction
  359. function! plug#helptags()
  360. if !exists('g:plugs')
  361. return s:err('plug#begin was not called')
  362. endif
  363. for spec in values(g:plugs)
  364. let docd = join([spec.dir, 'doc'], '/')
  365. if isdirectory(docd)
  366. silent! execute 'helptags' s:esc(docd)
  367. endif
  368. endfor
  369. return 1
  370. endfunction
  371. function! s:syntax()
  372. syntax clear
  373. syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber
  374. syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX
  375. syn match plugNumber /[0-9]\+[0-9.]*/ contained
  376. syn match plugBracket /[[\]]/ contained
  377. syn match plugX /x/ contained
  378. syn match plugDash /^-/
  379. syn match plugPlus /^+/
  380. syn match plugStar /^*/
  381. syn match plugMessage /\(^- \)\@<=.*/
  382. syn match plugName /\(^- \)\@<=[^ ]*:/
  383. syn match plugInstall /\(^+ \)\@<=[^:]*/
  384. syn match plugUpdate /\(^* \)\@<=[^:]*/
  385. syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha
  386. syn match plugSha /\(^ \)\@<=[0-9a-z]\{7}/ contained
  387. syn match plugRelDate /([^)]*)$/ contained
  388. syn match plugNotLoaded /(not loaded)$/
  389. syn match plugError /^x.*/
  390. syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
  391. hi def link plug1 Title
  392. hi def link plug2 Repeat
  393. hi def link plugX Exception
  394. hi def link plugBracket Structure
  395. hi def link plugNumber Number
  396. hi def link plugDash Special
  397. hi def link plugPlus Constant
  398. hi def link plugStar Boolean
  399. hi def link plugMessage Function
  400. hi def link plugName Label
  401. hi def link plugInstall Function
  402. hi def link plugUpdate Type
  403. hi def link plugError Error
  404. hi def link plugRelDate Comment
  405. hi def link plugSha Identifier
  406. hi def link plugNotLoaded Comment
  407. endfunction
  408. function! s:lpad(str, len)
  409. return a:str . repeat(' ', a:len - len(a:str))
  410. endfunction
  411. function! s:lastline(msg)
  412. let lines = split(a:msg, '\n')
  413. return get(lines, -1, '')
  414. endfunction
  415. function! s:new_window()
  416. execute get(g:, 'plug_window', 'vertical topleft new')
  417. endfunction
  418. function! s:prepare()
  419. if bufexists(s:plug_buf)
  420. let winnr = bufwinnr(s:plug_buf)
  421. if winnr < 0
  422. call s:new_window()
  423. execute 'buffer' s:plug_buf
  424. else
  425. execute winnr . 'wincmd w'
  426. endif
  427. setlocal modifiable
  428. silent %d _
  429. else
  430. call s:new_window()
  431. nnoremap <silent> <buffer> q :if b:plug_preview==1<bar>pc<bar>endif<bar>q<cr>
  432. nnoremap <silent> <buffer> R :silent! call <SID>retry()<cr>
  433. nnoremap <silent> <buffer> D :PlugDiff<cr>
  434. nnoremap <silent> <buffer> S :PlugStatus<cr>
  435. nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr>
  436. nnoremap <silent> <buffer> [[ :silent! call <SID>section('b')<cr>
  437. let b:plug_preview = -1
  438. let s:plug_buf = winbufnr(0)
  439. call s:assign_name()
  440. endif
  441. silent! unmap <buffer> <cr>
  442. silent! unmap <buffer> L
  443. silent! unmap <buffer> X
  444. setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline modifiable
  445. setf vim-plug
  446. call s:syntax()
  447. endfunction
  448. function! s:assign_name()
  449. " Assign buffer name
  450. let prefix = '[Plugins]'
  451. let name = prefix
  452. let idx = 2
  453. while bufexists(name)
  454. let name = printf('%s (%s)', prefix, idx)
  455. let idx = idx + 1
  456. endwhile
  457. silent! execute 'f' fnameescape(name)
  458. endfunction
  459. function! s:do(pull, force, todo)
  460. for [name, spec] in items(a:todo)
  461. if !isdirectory(spec.dir)
  462. continue
  463. endif
  464. execute 'cd' s:esc(spec.dir)
  465. let installed = has_key(s:prev_update.new, name)
  466. let updated = installed ? 0 :
  467. \ (a:pull && !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"')))
  468. if a:force || installed || updated
  469. call append(3, '- Post-update hook for '. name .' ... ')
  470. let type = type(spec.do)
  471. if type == s:TYPE.string
  472. try
  473. " FIXME: Escaping is incomplete. We could use shellescape with eval,
  474. " but it won't work on Windows.
  475. let g:_plug_do = '!'.escape(spec.do, '#!%')
  476. execute "normal! :execute g:_plug_do\<cr>\<cr>"
  477. finally
  478. let result = v:shell_error ? ('Exit status: '.v:shell_error) : 'Done!'
  479. unlet g:_plug_do
  480. endtry
  481. elseif type == s:TYPE.funcref
  482. try
  483. let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
  484. call spec.do({ 'name': name, 'status': status, 'force': a:force })
  485. let result = 'Done!'
  486. catch
  487. let result = 'Error: ' . v:exception
  488. endtry
  489. else
  490. let result = 'Error: Invalid type!'
  491. endif
  492. call setline(4, getline(4) . result)
  493. endif
  494. cd -
  495. endfor
  496. endfunction
  497. function! s:finish(pull)
  498. call append(3, '- Finishing ... ')
  499. redraw
  500. call plug#helptags()
  501. call plug#end()
  502. call setline(4, getline(4) . 'Done!')
  503. normal! gg
  504. call s:syntax()
  505. redraw
  506. let msgs = []
  507. if !empty(s:prev_update.errors)
  508. call add(msgs, "Press 'R' to retry.")
  509. endif
  510. if a:pull && !empty(filter(getline(5, '$'),
  511. \ "v:val =~ '^- ' && stridx(v:val, 'Already up-to-date') < 0"))
  512. call add(msgs, "Press 'D' to see the updated changes.")
  513. endif
  514. echo join(msgs, ' ')
  515. endfunction
  516. function! s:retry()
  517. if empty(s:prev_update.errors)
  518. return
  519. endif
  520. call s:update_impl(s:prev_update.pull, s:prev_update.force,
  521. \ extend(copy(s:prev_update.errors), [s:prev_update.threads]))
  522. endfunction
  523. function! s:is_managed(name)
  524. return has_key(g:plugs[a:name], 'uri')
  525. endfunction
  526. function! s:names(...)
  527. return filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')
  528. endfunction
  529. function! s:update_impl(pull, force, args) abort
  530. let st = reltime()
  531. let args = copy(a:args)
  532. let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ?
  533. \ remove(args, -1) : get(g:, 'plug_threads', 16)
  534. let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
  535. let todo = empty(args) ? filter(managed, '!v:val.frozen') :
  536. \ filter(managed, 'index(args, v:key) >= 0')
  537. if empty(todo)
  538. echohl WarningMsg
  539. echo 'No plugin to '. (a:pull ? 'update' : 'install') . '.'
  540. echohl None
  541. return
  542. endif
  543. if !isdirectory(g:plug_home)
  544. try
  545. call mkdir(g:plug_home, 'p')
  546. catch
  547. return s:err(printf('Invalid plug directory: %s.'
  548. \ 'Try to call plug#begin with a valid directory', g:plug_home))
  549. endtry
  550. endif
  551. call s:prepare()
  552. call append(0, a:pull ? 'Updating plugins' : 'Installing plugins')
  553. call append(1, '['. s:lpad('', len(todo)) .']')
  554. normal! 2G
  555. redraw
  556. let s:prev_update = { 'errors': [], 'pull': a:pull, 'force': a:force, 'new': {}, 'threads': threads }
  557. if has('ruby') && threads > 1
  558. try
  559. let imd = &imd
  560. if s:mac_gui
  561. set noimd
  562. endif
  563. call s:update_parallel(a:pull, todo, threads)
  564. catch
  565. let lines = getline(4, '$')
  566. let printed = {}
  567. silent 4,$d
  568. for line in lines
  569. let name = get(matchlist(line, '^. \([^:]\+\):'), 1, '')
  570. if empty(name) || !has_key(printed, name)
  571. call append('$', line)
  572. if !empty(name)
  573. let printed[name] = 1
  574. if line[0] == 'x' && index(s:prev_update.errors, name) < 0
  575. call add(s:prev_update.errors, name)
  576. end
  577. endif
  578. endif
  579. endfor
  580. finally
  581. let &imd = imd
  582. endtry
  583. else
  584. call s:update_serial(a:pull, todo)
  585. endif
  586. call s:do(a:pull, a:force, filter(copy(todo), 'has_key(v:val, "do")'))
  587. call s:finish(a:pull)
  588. call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(st)))[0] . ' sec.')
  589. endfunction
  590. function! s:update_progress(pull, cnt, bar, total)
  591. call setline(1, (a:pull ? 'Updating' : 'Installing').
  592. \ ' plugins ('.a:cnt.'/'.a:total.')')
  593. call s:progress_bar(2, a:bar, a:total)
  594. normal! 2G
  595. redraw
  596. endfunction
  597. function! s:update_serial(pull, todo)
  598. let base = g:plug_home
  599. let todo = copy(a:todo)
  600. let total = len(todo)
  601. let done = {}
  602. let bar = ''
  603. for [name, spec] in items(todo)
  604. let done[name] = 1
  605. if isdirectory(spec.dir)
  606. execute 'cd' s:esc(spec.dir)
  607. let [valid, msg] = s:git_valid(spec, 0, 0)
  608. if valid
  609. let result = a:pull ?
  610. \ s:system(
  611. \ printf('git checkout -q %s 2>&1 && git pull --no-rebase origin %s 2>&1 && git submodule update --init --recursive 2>&1',
  612. \ s:shellesc(spec.branch), s:shellesc(spec.branch))) : 'Already installed'
  613. let error = a:pull ? v:shell_error != 0 : 0
  614. else
  615. let result = msg
  616. let error = 1
  617. endif
  618. cd -
  619. else
  620. let result = s:system(
  621. \ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1',
  622. \ s:shellesc(spec.uri),
  623. \ s:shellesc(spec.branch),
  624. \ s:shellesc(s:trim(spec.dir)),
  625. \ s:shellesc(spec.dir)))
  626. let error = v:shell_error != 0
  627. if !error | let s:prev_update.new[name] = 1 | endif
  628. endif
  629. let bar .= error ? 'x' : '='
  630. if error
  631. call add(s:prev_update.errors, name)
  632. endif
  633. call append(3, s:format_message(!error, name, result))
  634. call s:update_progress(a:pull, len(done), bar, total)
  635. endfor
  636. endfunction
  637. function! s:update_parallel(pull, todo, threads)
  638. ruby << EOF
  639. module PlugStream
  640. SEP = ["\r", "\n", nil]
  641. def get_line
  642. buffer = ''
  643. loop do
  644. char = readchar rescue return
  645. if SEP.include? char.chr
  646. buffer << $/
  647. break
  648. else
  649. buffer << char
  650. end
  651. end
  652. buffer
  653. end
  654. end unless defined?(PlugStream)
  655. def esc arg
  656. %["#{arg.gsub('"', '\"')}"]
  657. end
  658. def killall pid
  659. pids = [pid]
  660. unless `which pgrep`.empty?
  661. children = pids
  662. until children.empty?
  663. children = children.map { |pid|
  664. `pgrep -P #{pid}`.lines.map { |l| l.chomp }
  665. }.flatten
  666. pids += children
  667. end
  668. end
  669. pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
  670. end
  671. require 'thread'
  672. require 'fileutils'
  673. require 'timeout'
  674. running = true
  675. iswin = VIM::evaluate('s:is_win').to_i == 1
  676. pull = VIM::evaluate('a:pull').to_i == 1
  677. base = VIM::evaluate('g:plug_home')
  678. all = VIM::evaluate('a:todo')
  679. limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
  680. tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1
  681. nthr = VIM::evaluate('a:threads').to_i
  682. maxy = VIM::evaluate('winheight(".")').to_i
  683. cd = iswin ? 'cd /d' : 'cd'
  684. tot = VIM::evaluate('len(a:todo)') || 0
  685. bar = ''
  686. skip = 'Already installed'
  687. mtx = Mutex.new
  688. take1 = proc { mtx.synchronize { running && all.shift } }
  689. logh = proc {
  690. cnt = bar.length
  691. $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
  692. $curbuf[2] = '[' + bar.ljust(tot) + ']'
  693. VIM::command('normal! 2G')
  694. VIM::command('redraw') unless iswin
  695. }
  696. where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }
  697. log = proc { |name, result, type|
  698. mtx.synchronize do
  699. ing = ![true, false].include?(type)
  700. bar += type ? '=' : 'x' unless ing
  701. b = case type
  702. when :install then '+' when :update then '*'
  703. when true, nil then '-' else
  704. VIM::command("call add(s:prev_update.errors, '#{name}')")
  705. 'x'
  706. end
  707. result =
  708. if type || type.nil?
  709. ["#{b} #{name}: #{result.lines.to_a.last}"]
  710. elsif result =~ /^Interrupted|^Timeout/
  711. ["#{b} #{name}: #{result}"]
  712. else
  713. ["#{b} #{name}"] + result.lines.map { |l| " " << l }
  714. end
  715. if lnum = where.call(name)
  716. $curbuf.delete lnum
  717. lnum = 4 if ing && lnum > maxy
  718. end
  719. result.each_with_index do |line, offset|
  720. $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp)
  721. end
  722. logh.call
  723. end
  724. }
  725. bt = proc { |cmd, name, type, cleanup|
  726. tried = timeout = 0
  727. begin
  728. tried += 1
  729. timeout += limit
  730. fd = nil
  731. data = ''
  732. if iswin
  733. Timeout::timeout(timeout) do
  734. tmp = VIM::evaluate('tempname()')
  735. system("#{cmd} > #{tmp}")
  736. data = File.read(tmp).chomp
  737. File.unlink tmp rescue nil
  738. end
  739. else
  740. fd = IO.popen(cmd).extend(PlugStream)
  741. first_line = true
  742. log_prob = 1.0 / nthr
  743. while line = Timeout::timeout(timeout) { fd.get_line }
  744. data << line
  745. log.call name, line.chomp, type if name && (first_line || rand < log_prob)
  746. first_line = false
  747. end
  748. fd.close
  749. end
  750. [$? == 0, data.chomp]
  751. rescue Timeout::Error, Interrupt => e
  752. if fd && !fd.closed?
  753. killall fd.pid
  754. fd.close
  755. end
  756. cleanup.call if cleanup
  757. if e.is_a?(Timeout::Error) && tried < tries
  758. 3.downto(1) do |countdown|
  759. s = countdown > 1 ? 's' : ''
  760. log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type
  761. sleep 1
  762. end
  763. log.call name, 'Retrying ...', type
  764. retry
  765. end
  766. [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
  767. end
  768. }
  769. main = Thread.current
  770. threads = []
  771. watcher = Thread.new {
  772. while VIM::evaluate('getchar(1)')
  773. sleep 0.1
  774. end
  775. mtx.synchronize do
  776. running = false
  777. threads.each { |t| t.raise Interrupt }
  778. end
  779. threads.each { |t| t.join rescue nil }
  780. main.kill
  781. }
  782. refresh = Thread.new {
  783. while true
  784. mtx.synchronize do
  785. break unless running
  786. VIM::command('noautocmd normal! a')
  787. end
  788. sleep 0.2
  789. end
  790. } if VIM::evaluate('s:mac_gui') == 1
  791. progress = iswin ? '' : '--progress'
  792. [all.length, nthr].min.times do
  793. mtx.synchronize do
  794. threads << Thread.new {
  795. while pair = take1.call
  796. name = pair.first
  797. dir, uri, branch = pair.last.values_at *%w[dir uri branch]
  798. branch = esc branch
  799. subm = "git submodule update --init --recursive 2>&1"
  800. exists = File.directory? dir
  801. ok, result =
  802. if exists
  803. dir = esc dir
  804. ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"
  805. current_uri = data.lines.to_a.last
  806. if !ret
  807. if data =~ /^Interrupted|^Timeout/
  808. [false, data]
  809. else
  810. [false, [data.chomp, "PlugClean required."].join($/)]
  811. end
  812. elsif current_uri.sub(/git::?@/, '') != uri.sub(/git::?@/, '')
  813. [false, ["Invalid URI: #{current_uri}",
  814. "Expected: #{uri}",
  815. "PlugClean required."].join($/)]
  816. else
  817. if pull
  818. log.call name, 'Updating ...', :update
  819. bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && (git pull --no-rebase origin #{branch} #{progress} 2>&1 && #{subm})", name, :update
  820. else
  821. [true, skip]
  822. end
  823. end
  824. else
  825. d = esc dir.sub(%r{[\\/]+$}, '')
  826. log.call name, 'Installing ...', :install
  827. bt.call "(git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && #{subm})", name, :install, proc {
  828. FileUtils.rm_rf dir
  829. }
  830. end
  831. mtx.synchronize { VIM::command("let s:prev_update.new['#{name}'] = 1") } if !exists && ok
  832. log.call name, result, ok
  833. end
  834. } if running
  835. end
  836. end
  837. threads.each { |t| t.join rescue nil }
  838. logh.call
  839. refresh.kill if refresh
  840. watcher.kill
  841. EOF
  842. endfunction
  843. function! s:shellesc(arg)
  844. return '"'.substitute(a:arg, '"', '\\"', 'g').'"'
  845. endfunction
  846. function! s:glob_dir(path)
  847. return map(filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)'), 's:dirpath(v:val)')
  848. endfunction
  849. function! s:progress_bar(line, bar, total)
  850. call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')
  851. endfunction
  852. function! s:compare_git_uri(a, b)
  853. let a = substitute(a:a, 'git:\{1,2}@', '', '')
  854. let b = substitute(a:b, 'git:\{1,2}@', '', '')
  855. return a ==# b
  856. endfunction
  857. function! s:format_message(ok, name, message)
  858. if a:ok
  859. return [printf('- %s: %s', a:name, s:lastline(a:message))]
  860. else
  861. let lines = map(split(a:message, '\n'), '" ".v:val')
  862. return extend([printf('x %s:', a:name)], lines)
  863. endif
  864. endfunction
  865. function! s:system(cmd)
  866. return system(s:is_win ? '('.a:cmd.')' : a:cmd)
  867. endfunction
  868. function! s:system_chomp(str)
  869. let ret = s:system(a:str)
  870. return v:shell_error ? '' : substitute(ret, '\n$', '', '')
  871. endfunction
  872. function! s:git_valid(spec, check_branch, cd)
  873. let ret = 1
  874. let msg = 'OK'
  875. if isdirectory(a:spec.dir)
  876. if a:cd | execute 'cd' s:esc(a:spec.dir) | endif
  877. let result = split(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url'), '\n')
  878. let remote = result[-1]
  879. if v:shell_error
  880. let msg = join([remote, 'PlugClean required.'], "\n")
  881. let ret = 0
  882. elseif !s:compare_git_uri(remote, a:spec.uri)
  883. let msg = join(['Invalid URI: '.remote,
  884. \ 'Expected: '.a:spec.uri,
  885. \ 'PlugClean required.'], "\n")
  886. let ret = 0
  887. elseif a:check_branch
  888. let branch = result[0]
  889. if a:spec.branch !=# branch
  890. let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1')
  891. if a:spec.branch !=# tag
  892. let msg = printf('Invalid branch/tag: %s (expected: %s). Try PlugUpdate.',
  893. \ (empty(tag) ? branch : tag), a:spec.branch)
  894. let ret = 0
  895. endif
  896. endif
  897. endif
  898. if a:cd | cd - | endif
  899. else
  900. let msg = 'Not found'
  901. let ret = 0
  902. endif
  903. return [ret, msg]
  904. endfunction
  905. function! s:clean(force)
  906. call s:prepare()
  907. call append(0, 'Searching for unused plugins in '.g:plug_home)
  908. call append(1, '')
  909. " List of valid directories
  910. let dirs = []
  911. let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
  912. let [cnt, total] = [0, len(managed)]
  913. for spec in values(managed)
  914. if s:git_valid(spec, 0, 1)[0]
  915. call add(dirs, spec.dir)
  916. endif
  917. let cnt += 1
  918. call s:progress_bar(2, repeat('=', cnt), total)
  919. normal! 2G
  920. redraw
  921. endfor
  922. let allowed = {}
  923. for dir in dirs
  924. let allowed[dir] = 1
  925. for child in s:glob_dir(dir)
  926. let allowed[child] = 1
  927. endfor
  928. endfor
  929. let todo = []
  930. let found = sort(s:glob_dir(g:plug_home))
  931. while !empty(found)
  932. let f = remove(found, 0)
  933. if !has_key(allowed, f) && isdirectory(f)
  934. call add(todo, f)
  935. call append(line('$'), '- ' . f)
  936. let found = filter(found, 'stridx(v:val, f) != 0')
  937. end
  938. endwhile
  939. normal! G
  940. redraw
  941. if empty(todo)
  942. call append(line('$'), 'Already clean.')
  943. else
  944. call inputsave()
  945. let yes = a:force || (input('Proceed? (Y/N) ') =~? '^y')
  946. call inputrestore()
  947. if yes
  948. for dir in todo
  949. if isdirectory(dir)
  950. call system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(dir))
  951. endif
  952. endfor
  953. call append(line('$'), 'Removed.')
  954. else
  955. call append(line('$'), 'Cancelled.')
  956. endif
  957. endif
  958. normal! G
  959. endfunction
  960. function! s:upgrade()
  961. let new = s:me . '.new'
  962. echo 'Downloading '. s:plug_source
  963. redraw
  964. try
  965. if executable('curl')
  966. let output = system(printf('curl -fLo %s %s', s:shellesc(new), s:plug_source))
  967. if v:shell_error
  968. throw get(split(output, '\n'), -1, v:shell_error)
  969. endif
  970. elseif has('ruby')
  971. ruby << EOF
  972. require 'open-uri'
  973. File.open(VIM::evaluate('new'), 'w') do |f|
  974. f << open(VIM::evaluate('s:plug_source')).read
  975. end
  976. EOF
  977. else
  978. return s:err('curl executable or ruby support not found')
  979. endif
  980. catch
  981. return s:err('Error upgrading vim-plug: '. v:exception)
  982. endtry
  983. if readfile(s:me) ==# readfile(new)
  984. echo 'vim-plug is up-to-date'
  985. silent! call delete(new)
  986. return 0
  987. else
  988. call rename(s:me, s:me . '.old')
  989. call rename(new, s:me)
  990. unlet g:loaded_plug
  991. echo 'vim-plug is upgraded'
  992. return 1
  993. endif
  994. endfunction
  995. function! s:upgrade_specs()
  996. for spec in values(g:plugs)
  997. let spec.frozen = get(spec, 'frozen', 0)
  998. endfor
  999. endfunction
  1000. function! s:status()
  1001. call s:prepare()
  1002. call append(0, 'Checking plugins')
  1003. call append(1, '')
  1004. let ecnt = 0
  1005. let unloaded = 0
  1006. let [cnt, total] = [0, len(g:plugs)]
  1007. for [name, spec] in items(g:plugs)
  1008. if has_key(spec, 'uri')
  1009. if isdirectory(spec.dir)
  1010. let [valid, msg] = s:git_valid(spec, 1, 1)
  1011. else
  1012. let [valid, msg] = [0, 'Not found. Try PlugInstall.']
  1013. endif
  1014. else
  1015. if isdirectory(spec.dir)
  1016. let [valid, msg] = [1, 'OK']
  1017. else
  1018. let [valid, msg] = [0, 'Not found.']
  1019. endif
  1020. endif
  1021. let cnt += 1
  1022. let ecnt += !valid
  1023. " `s:loaded` entry can be missing if PlugUpgraded
  1024. if valid && get(s:loaded, spec.dir, -1) == 0
  1025. let unloaded = 1
  1026. let msg .= ' (not loaded)'
  1027. endif
  1028. call s:progress_bar(2, repeat('=', cnt), total)
  1029. call append(3, s:format_message(valid, name, msg))
  1030. normal! 2G
  1031. redraw
  1032. endfor
  1033. call setline(1, 'Finished. '.ecnt.' error(s).')
  1034. normal! gg
  1035. setlocal nomodifiable
  1036. if unloaded
  1037. echo "Press 'L' on each line to load plugin"
  1038. nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
  1039. xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
  1040. end
  1041. endfunction
  1042. function! s:status_load(lnum)
  1043. let line = getline(a:lnum)
  1044. let matches = matchlist(line, '^- \([^:]*\):.*(not loaded)$')
  1045. if !empty(matches)
  1046. let name = matches[1]
  1047. call plug#load(name)
  1048. setlocal modifiable
  1049. call setline(a:lnum, substitute(line, ' (not loaded)$', '', ''))
  1050. setlocal nomodifiable
  1051. endif
  1052. endfunction
  1053. function! s:is_preview_window_open()
  1054. silent! wincmd P
  1055. if &previewwindow
  1056. wincmd p
  1057. return 1
  1058. endif
  1059. return 0
  1060. endfunction
  1061. function! s:find_name(lnum)
  1062. for lnum in reverse(range(1, a:lnum))
  1063. let line = getline(lnum)
  1064. if empty(line)
  1065. return ''
  1066. endif
  1067. let name = matchstr(line, '\(^- \)\@<=[^:]\+')
  1068. if !empty(name)
  1069. return name
  1070. endif
  1071. endfor
  1072. return ''
  1073. endfunction
  1074. function! s:preview_commit()
  1075. if b:plug_preview < 0
  1076. let b:plug_preview = !s:is_preview_window_open()
  1077. endif
  1078. let sha = matchstr(getline('.'), '\(^ \)\@<=[0-9a-z]\{7}')
  1079. if empty(sha)
  1080. return
  1081. endif
  1082. let name = s:find_name(line('.'))
  1083. if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir)
  1084. return
  1085. endif
  1086. execute 'pedit' sha
  1087. wincmd P
  1088. setlocal filetype=git buftype=nofile nobuflisted
  1089. execute 'cd' s:esc(g:plugs[name].dir)
  1090. execute 'silent read !git show' sha
  1091. cd -
  1092. normal! gg"_dd
  1093. wincmd p
  1094. endfunction
  1095. function! s:section(flags)
  1096. call search('\(^- \)\@<=.', a:flags)
  1097. endfunction
  1098. function! s:diff()
  1099. call s:prepare()
  1100. call append(0, 'Collecting updated changes ...')
  1101. normal! gg
  1102. redraw
  1103. let cnt = 0
  1104. for [k, v] in items(g:plugs)
  1105. if !isdirectory(v.dir) || !s:is_managed(k)
  1106. continue
  1107. endif
  1108. execute 'cd' s:esc(v.dir)
  1109. let diff = system('git log --pretty=format:"%h %s (%cr)" "HEAD...HEAD@{1}"')
  1110. if !v:shell_error && !empty(diff)
  1111. call append(1, '')
  1112. call append(2, '- '.k.':')
  1113. call append(3, map(split(diff, '\n'), '" ". v:val'))
  1114. let cnt += 1
  1115. normal! gg
  1116. redraw
  1117. endif
  1118. cd -
  1119. endfor
  1120. call setline(1, cnt == 0 ? 'No updates.' : 'Last update:')
  1121. nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr>
  1122. nnoremap <silent> <buffer> X :call <SID>revert()<cr>
  1123. normal! gg
  1124. setlocal nomodifiable
  1125. if cnt > 0
  1126. echo "Press 'X' on each block to revert the update"
  1127. endif
  1128. endfunction
  1129. function! s:revert()
  1130. let name = s:find_name(line('.'))
  1131. if empty(name) || !has_key(g:plugs, name) ||
  1132. \ input(printf('Revert the update of %s? (Y/N) ', name)) !~? '^y'
  1133. return
  1134. endif
  1135. execute 'cd' s:esc(g:plugs[name].dir)
  1136. call system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch))
  1137. cd -
  1138. setlocal modifiable
  1139. normal! "_dap
  1140. setlocal nomodifiable
  1141. echo 'Reverted.'
  1142. endfunction
  1143. let s:first_rtp = s:esc(get(split(&rtp, ','), 0, ''))
  1144. let s:last_rtp = s:esc(get(split(&rtp, ','), -1, ''))
  1145. if exists('g:plugs')
  1146. let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs))
  1147. call s:upgrade_specs()
  1148. call s:define_commands()
  1149. endif
  1150. let &cpo = s:cpo_save
  1151. unlet s:cpo_save