plug.vim 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256
  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|
  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. if e.is_a?(Timeout::Error) && tried < tries
  757. 3.downto(1) do |countdown|
  758. s = countdown > 1 ? 's' : ''
  759. log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type
  760. sleep 1
  761. end
  762. log.call name, 'Retrying ...', type
  763. retry
  764. end
  765. [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
  766. end
  767. }
  768. main = Thread.current
  769. threads = []
  770. watcher = Thread.new {
  771. while VIM::evaluate('getchar(1)')
  772. sleep 0.1
  773. end
  774. mtx.synchronize do
  775. running = false
  776. threads.each { |t| t.raise Interrupt }
  777. end
  778. threads.each { |t| t.join rescue nil }
  779. main.kill
  780. }
  781. refresh = Thread.new {
  782. while true
  783. mtx.synchronize do
  784. break unless running
  785. VIM::command('noautocmd normal! a')
  786. end
  787. sleep 0.2
  788. end
  789. } if VIM::evaluate('s:mac_gui') == 1
  790. progress = iswin ? '' : '--progress'
  791. [all.length, nthr].min.times do
  792. mtx.synchronize do
  793. threads << Thread.new {
  794. while pair = take1.call
  795. name = pair.first
  796. dir, uri, branch = pair.last.values_at *%w[dir uri branch]
  797. branch = esc branch
  798. subm = "git submodule update --init --recursive 2>&1"
  799. exists = File.directory? dir
  800. ok, result =
  801. if exists
  802. dir = esc dir
  803. ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil
  804. current_uri = data.lines.to_a.last
  805. if !ret
  806. if data =~ /^Interrupted|^Timeout/
  807. [false, data]
  808. else
  809. [false, [data.chomp, "PlugClean required."].join($/)]
  810. end
  811. elsif current_uri.sub(/git::?@/, '') != uri.sub(/git::?@/, '')
  812. [false, ["Invalid URI: #{current_uri}",
  813. "Expected: #{uri}",
  814. "PlugClean required."].join($/)]
  815. else
  816. if pull
  817. log.call name, 'Updating ...', :update
  818. bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && (git pull --no-rebase origin #{branch} #{progress} 2>&1 && #{subm})", name, :update
  819. else
  820. [true, skip]
  821. end
  822. end
  823. else
  824. d = esc dir.sub(%r{[\\/]+$}, '')
  825. log.call name, 'Installing ...', :install
  826. bt.call "(git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && #{subm})", name, :install
  827. end
  828. mtx.synchronize { VIM::command("let s:prev_update.new['#{name}'] = 1") } if !exists && ok
  829. log.call name, result, ok
  830. end
  831. } if running
  832. end
  833. end
  834. threads.each { |t| t.join rescue nil }
  835. logh.call
  836. refresh.kill if refresh
  837. watcher.kill
  838. EOF
  839. endfunction
  840. function! s:shellesc(arg)
  841. return '"'.substitute(a:arg, '"', '\\"', 'g').'"'
  842. endfunction
  843. function! s:glob_dir(path)
  844. return map(filter(split(globpath(a:path, '**'), '\n'), 'isdirectory(v:val)'), 's:dirpath(v:val)')
  845. endfunction
  846. function! s:progress_bar(line, bar, total)
  847. call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')
  848. endfunction
  849. function! s:compare_git_uri(a, b)
  850. let a = substitute(a:a, 'git:\{1,2}@', '', '')
  851. let b = substitute(a:b, 'git:\{1,2}@', '', '')
  852. return a ==# b
  853. endfunction
  854. function! s:format_message(ok, name, message)
  855. if a:ok
  856. return [printf('- %s: %s', a:name, s:lastline(a:message))]
  857. else
  858. let lines = map(split(a:message, '\n'), '" ".v:val')
  859. return extend([printf('x %s:', a:name)], lines)
  860. endif
  861. endfunction
  862. function! s:system(cmd)
  863. return system(s:is_win ? '('.a:cmd.')' : a:cmd)
  864. endfunction
  865. function! s:system_chomp(str)
  866. let ret = s:system(a:str)
  867. return v:shell_error ? '' : substitute(ret, '\n$', '', '')
  868. endfunction
  869. function! s:git_valid(spec, check_branch, cd)
  870. let ret = 1
  871. let msg = 'OK'
  872. if isdirectory(a:spec.dir)
  873. if a:cd | execute 'cd' s:esc(a:spec.dir) | endif
  874. let result = split(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url'), '\n')
  875. let remote = result[-1]
  876. if v:shell_error
  877. let msg = join([remote, 'PlugClean required.'], "\n")
  878. let ret = 0
  879. elseif !s:compare_git_uri(remote, a:spec.uri)
  880. let msg = join(['Invalid URI: '.remote,
  881. \ 'Expected: '.a:spec.uri,
  882. \ 'PlugClean required.'], "\n")
  883. let ret = 0
  884. elseif a:check_branch
  885. let branch = result[0]
  886. if a:spec.branch !=# branch
  887. let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1')
  888. if a:spec.branch !=# tag
  889. let msg = printf('Invalid branch/tag: %s (expected: %s). Try PlugUpdate.',
  890. \ (empty(tag) ? branch : tag), a:spec.branch)
  891. let ret = 0
  892. endif
  893. endif
  894. endif
  895. if a:cd | cd - | endif
  896. else
  897. let msg = 'Not found'
  898. let ret = 0
  899. endif
  900. return [ret, msg]
  901. endfunction
  902. function! s:clean(force)
  903. call s:prepare()
  904. call append(0, 'Searching for unused plugins in '.g:plug_home)
  905. call append(1, '')
  906. " List of valid directories
  907. let dirs = []
  908. let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
  909. let [cnt, total] = [0, len(managed)]
  910. for spec in values(managed)
  911. if s:git_valid(spec, 0, 1)[0]
  912. call add(dirs, spec.dir)
  913. endif
  914. let cnt += 1
  915. call s:progress_bar(2, repeat('=', cnt), total)
  916. normal! 2G
  917. redraw
  918. endfor
  919. let allowed = {}
  920. for dir in dirs
  921. let allowed[dir] = 1
  922. for child in s:glob_dir(dir)
  923. let allowed[child] = 1
  924. endfor
  925. endfor
  926. let todo = []
  927. let found = sort(s:glob_dir(g:plug_home))
  928. while !empty(found)
  929. let f = remove(found, 0)
  930. if !has_key(allowed, f) && isdirectory(f)
  931. call add(todo, f)
  932. call append(line('$'), '- ' . f)
  933. let found = filter(found, 'stridx(v:val, f) != 0')
  934. end
  935. endwhile
  936. normal! G
  937. redraw
  938. if empty(todo)
  939. call append(line('$'), 'Already clean.')
  940. else
  941. call inputsave()
  942. let yes = a:force || (input('Proceed? (Y/N) ') =~? '^y')
  943. call inputrestore()
  944. if yes
  945. for dir in todo
  946. if isdirectory(dir)
  947. call system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(dir))
  948. endif
  949. endfor
  950. call append(line('$'), 'Removed.')
  951. else
  952. call append(line('$'), 'Cancelled.')
  953. endif
  954. endif
  955. normal! G
  956. endfunction
  957. function! s:upgrade()
  958. if executable('curl')
  959. let mee = s:shellesc(s:me)
  960. let new = s:shellesc(s:me . '.new')
  961. echo 'Downloading '. s:plug_source
  962. redraw
  963. let mv = s:is_win ? 'move /Y' : 'mv -f'
  964. let cp = s:is_win ? 'copy /Y' : 'cp -f'
  965. call system(printf(
  966. \ 'curl -fLo %s %s && '.cp.' %s %s.old && '.mv.' %s %s',
  967. \ new, s:plug_source, mee, mee, new, mee))
  968. if v:shell_error
  969. return s:err('Error upgrading vim-plug')
  970. endif
  971. elseif has('ruby')
  972. echo 'Downloading '. s:plug_source
  973. try
  974. ruby << EOF
  975. require 'open-uri'
  976. require 'fileutils'
  977. me = VIM::evaluate('s:me')
  978. old = me + '.old'
  979. new = me + '.new'
  980. File.open(new, 'w') do |f|
  981. f << open(VIM::evaluate('s:plug_source')).read
  982. end
  983. FileUtils.cp me, old
  984. File.rename new, me
  985. EOF
  986. catch
  987. return s:err('Error upgrading vim-plug')
  988. endtry
  989. else
  990. return s:err('curl executable or ruby support not found')
  991. endif
  992. unlet g:loaded_plug
  993. echo 'Downloaded '. s:plug_source
  994. return 1
  995. endfunction
  996. function! s:upgrade_specs()
  997. for spec in values(g:plugs)
  998. let spec.frozen = get(spec, 'frozen', 0)
  999. endfor
  1000. endfunction
  1001. function! s:status()
  1002. call s:prepare()
  1003. call append(0, 'Checking plugins')
  1004. call append(1, '')
  1005. let ecnt = 0
  1006. let unloaded = 0
  1007. let [cnt, total] = [0, len(g:plugs)]
  1008. for [name, spec] in items(g:plugs)
  1009. if has_key(spec, 'uri')
  1010. if isdirectory(spec.dir)
  1011. let [valid, msg] = s:git_valid(spec, 1, 1)
  1012. else
  1013. let [valid, msg] = [0, 'Not found. Try PlugInstall.']
  1014. endif
  1015. else
  1016. if isdirectory(spec.dir)
  1017. let [valid, msg] = [1, 'OK']
  1018. else
  1019. let [valid, msg] = [0, 'Not found.']
  1020. endif
  1021. endif
  1022. let cnt += 1
  1023. let ecnt += !valid
  1024. " `s:loaded` entry can be missing if PlugUpgraded
  1025. if valid && get(s:loaded, spec.dir, -1) == 0
  1026. let unloaded = 1
  1027. let msg .= ' (not loaded)'
  1028. endif
  1029. call s:progress_bar(2, repeat('=', cnt), total)
  1030. call append(3, s:format_message(valid, name, msg))
  1031. normal! 2G
  1032. redraw
  1033. endfor
  1034. call setline(1, 'Finished. '.ecnt.' error(s).')
  1035. normal! gg
  1036. setlocal nomodifiable
  1037. if unloaded
  1038. echo "Press 'L' on each line to load plugin"
  1039. nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
  1040. xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
  1041. end
  1042. endfunction
  1043. function! s:status_load(lnum)
  1044. let line = getline(a:lnum)
  1045. let matches = matchlist(line, '^- \([^:]*\):.*(not loaded)$')
  1046. if !empty(matches)
  1047. let name = matches[1]
  1048. call plug#load(name)
  1049. setlocal modifiable
  1050. call setline(a:lnum, substitute(line, ' (not loaded)$', '', ''))
  1051. setlocal nomodifiable
  1052. endif
  1053. endfunction
  1054. function! s:is_preview_window_open()
  1055. silent! wincmd P
  1056. if &previewwindow
  1057. wincmd p
  1058. return 1
  1059. endif
  1060. return 0
  1061. endfunction
  1062. function! s:find_name(lnum)
  1063. for lnum in reverse(range(1, a:lnum))
  1064. let line = getline(lnum)
  1065. if empty(line)
  1066. return ''
  1067. endif
  1068. let name = matchstr(line, '\(^- \)\@<=[^:]\+')
  1069. if !empty(name)
  1070. return name
  1071. endif
  1072. endfor
  1073. return ''
  1074. endfunction
  1075. function! s:preview_commit()
  1076. if b:plug_preview < 0
  1077. let b:plug_preview = !s:is_preview_window_open()
  1078. endif
  1079. let sha = matchstr(getline('.'), '\(^ \)\@<=[0-9a-z]\{7}')
  1080. if empty(sha)
  1081. return
  1082. endif
  1083. let name = s:find_name(line('.'))
  1084. if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir)
  1085. return
  1086. endif
  1087. execute 'pedit' sha
  1088. wincmd P
  1089. setlocal filetype=git buftype=nofile nobuflisted
  1090. execute 'cd' s:esc(g:plugs[name].dir)
  1091. execute 'silent read !git show' sha
  1092. cd -
  1093. normal! gg"_dd
  1094. wincmd p
  1095. endfunction
  1096. function! s:section(flags)
  1097. call search('\(^- \)\@<=.', a:flags)
  1098. endfunction
  1099. function! s:diff()
  1100. call s:prepare()
  1101. call append(0, 'Collecting updated changes ...')
  1102. normal! gg
  1103. redraw
  1104. let cnt = 0
  1105. for [k, v] in items(g:plugs)
  1106. if !isdirectory(v.dir) || !s:is_managed(k)
  1107. continue
  1108. endif
  1109. execute 'cd' s:esc(v.dir)
  1110. let diff = system('git log --pretty=format:"%h %s (%cr)" "HEAD...HEAD@{1}"')
  1111. if !v:shell_error && !empty(diff)
  1112. call append(1, '')
  1113. call append(2, '- '.k.':')
  1114. call append(3, map(split(diff, '\n'), '" ". v:val'))
  1115. let cnt += 1
  1116. normal! gg
  1117. redraw
  1118. endif
  1119. cd -
  1120. endfor
  1121. call setline(1, cnt == 0 ? 'No updates.' : 'Last update:')
  1122. nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr>
  1123. nnoremap <silent> <buffer> X :call <SID>revert()<cr>
  1124. normal! gg
  1125. setlocal nomodifiable
  1126. if cnt > 0
  1127. echo "Press 'X' on each block to revert the update"
  1128. endif
  1129. endfunction
  1130. function! s:revert()
  1131. let name = s:find_name(line('.'))
  1132. if empty(name) || !has_key(g:plugs, name) ||
  1133. \ input(printf('Revert the update of %s? (Y/N) ', name)) !~? '^y'
  1134. return
  1135. endif
  1136. execute 'cd' s:esc(g:plugs[name].dir)
  1137. call system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch))
  1138. cd -
  1139. setlocal modifiable
  1140. normal! "_dap
  1141. setlocal nomodifiable
  1142. echo 'Reverted.'
  1143. endfunction
  1144. let s:first_rtp = s:esc(get(split(&rtp, ','), 0, ''))
  1145. let s:last_rtp = s:esc(get(split(&rtp, ','), -1, ''))
  1146. if exists('g:plugs')
  1147. let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs))
  1148. call s:upgrade_specs()
  1149. call s:define_commands()
  1150. endif
  1151. let &cpo = s:cpo_save
  1152. unlet s:cpo_save