this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Autoinstall vim-plug on new machines

+7 -2330
-2330
nvim/autoload/plug.vim
··· 1 - " vim-plug: Vim plugin manager 2 - " ============================ 3 - " 4 - " Download plug.vim and put it in ~/.vim/autoload 5 - " 6 - " curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ 7 - " https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim 8 - " 9 - " Edit your .vimrc 10 - " 11 - " call plug#begin('~/.vim/plugged') 12 - " 13 - " " Make sure you use single quotes 14 - " 15 - " " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align 16 - " Plug 'junegunn/vim-easy-align' 17 - " 18 - " " Any valid git URL is allowed 19 - " Plug 'https://github.com/junegunn/vim-github-dashboard.git' 20 - " 21 - " " Group dependencies, vim-snippets depends on ultisnips 22 - " Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets' 23 - " 24 - " " On-demand loading 25 - " Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } 26 - " Plug 'tpope/vim-fireplace', { 'for': 'clojure' } 27 - " 28 - " " Using a non-master branch 29 - " Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' } 30 - " 31 - " " Using a tagged release; wildcard allowed (requires git 1.9.2 or above) 32 - " Plug 'fatih/vim-go', { 'tag': '*' } 33 - " 34 - " " Plugin options 35 - " Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' } 36 - " 37 - " " Plugin outside ~/.vim/plugged with post-update hook 38 - " Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } 39 - " 40 - " " Unmanaged plugin (manually installed and updated) 41 - " Plug '~/my-prototype-plugin' 42 - " 43 - " " Add plugins to &runtimepath 44 - " call plug#end() 45 - " 46 - " Then reload .vimrc and :PlugInstall to install plugins. 47 - " 48 - " Plug options: 49 - " 50 - "| Option | Description | 51 - "| ----------------------- | ------------------------------------------------ | 52 - "| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use | 53 - "| `rtp` | Subdirectory that contains Vim plugin | 54 - "| `dir` | Custom directory for the plugin | 55 - "| `as` | Use different name for the plugin | 56 - "| `do` | Post-update hook (string or funcref) | 57 - "| `on` | On-demand loading: Commands or `<Plug>`-mappings | 58 - "| `for` | On-demand loading: File types | 59 - "| `frozen` | Do not update unless explicitly specified | 60 - " 61 - " More information: https://github.com/junegunn/vim-plug 62 - " 63 - " 64 - " Copyright (c) 2016 Junegunn Choi 65 - " 66 - " MIT License 67 - " 68 - " Permission is hereby granted, free of charge, to any person obtaining 69 - " a copy of this software and associated documentation files (the 70 - " "Software"), to deal in the Software without restriction, including 71 - " without limitation the rights to use, copy, modify, merge, publish, 72 - " distribute, sublicense, and/or sell copies of the Software, and to 73 - " permit persons to whom the Software is furnished to do so, subject to 74 - " the following conditions: 75 - " 76 - " The above copyright notice and this permission notice shall be 77 - " included in all copies or substantial portions of the Software. 78 - " 79 - " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 80 - " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 81 - " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 82 - " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 83 - " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 84 - " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 85 - " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 86 - 87 - if exists('g:loaded_plug') 88 - finish 89 - endif 90 - let g:loaded_plug = 1 91 - 92 - let s:cpo_save = &cpo 93 - set cpo&vim 94 - 95 - let s:plug_src = 'https://github.com/junegunn/vim-plug.git' 96 - let s:plug_tab = get(s:, 'plug_tab', -1) 97 - let s:plug_buf = get(s:, 'plug_buf', -1) 98 - let s:mac_gui = has('gui_macvim') && has('gui_running') 99 - let s:is_win = has('win32') || has('win64') 100 - let s:nvim = has('nvim') && exists('*jobwait') && !s:is_win 101 - let s:me = resolve(expand('<sfile>:p')) 102 - let s:base_spec = { 'branch': 'master', 'frozen': 0 } 103 - let s:TYPE = { 104 - \ 'string': type(''), 105 - \ 'list': type([]), 106 - \ 'dict': type({}), 107 - \ 'funcref': type(function('call')) 108 - \ } 109 - let s:loaded = get(s:, 'loaded', {}) 110 - let s:triggers = get(s:, 'triggers', {}) 111 - 112 - function! plug#begin(...) 113 - if a:0 > 0 114 - let s:plug_home_org = a:1 115 - let home = s:path(fnamemodify(expand(a:1), ':p')) 116 - elseif exists('g:plug_home') 117 - let home = s:path(g:plug_home) 118 - elseif !empty(&rtp) 119 - let home = s:path(split(&rtp, ',')[0]) . '/plugged' 120 - else 121 - return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') 122 - endif 123 - 124 - let g:plug_home = home 125 - let g:plugs = {} 126 - let g:plugs_order = [] 127 - let s:triggers = {} 128 - 129 - call s:define_commands() 130 - return 1 131 - endfunction 132 - 133 - function! s:define_commands() 134 - command! -nargs=+ -bar Plug call plug#(<args>) 135 - if !executable('git') 136 - return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') 137 - endif 138 - command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>]) 139 - command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(<bang>0, [<f-args>]) 140 - command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0) 141 - command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif 142 - command! -nargs=0 -bar PlugStatus call s:status() 143 - command! -nargs=0 -bar PlugDiff call s:diff() 144 - command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(<bang>0, <f-args>) 145 - endfunction 146 - 147 - function! s:to_a(v) 148 - return type(a:v) == s:TYPE.list ? a:v : [a:v] 149 - endfunction 150 - 151 - function! s:to_s(v) 152 - return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" 153 - endfunction 154 - 155 - function! s:glob(from, pattern) 156 - return s:lines(globpath(a:from, a:pattern)) 157 - endfunction 158 - 159 - function! s:source(from, ...) 160 - let found = 0 161 - for pattern in a:000 162 - for vim in s:glob(a:from, pattern) 163 - execute 'source' s:esc(vim) 164 - let found = 1 165 - endfor 166 - endfor 167 - return found 168 - endfunction 169 - 170 - function! s:assoc(dict, key, val) 171 - let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) 172 - endfunction 173 - 174 - function! s:ask(message, ...) 175 - call inputsave() 176 - echohl WarningMsg 177 - let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) 178 - echohl None 179 - call inputrestore() 180 - echo "\r" 181 - return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 182 - endfunction 183 - 184 - function! s:ask_no_interrupt(...) 185 - try 186 - return call('s:ask', a:000) 187 - catch 188 - return 0 189 - endtry 190 - endfunction 191 - 192 - function! plug#end() 193 - if !exists('g:plugs') 194 - return s:err('Call plug#begin() first') 195 - endif 196 - 197 - if exists('#PlugLOD') 198 - augroup PlugLOD 199 - autocmd! 200 - augroup END 201 - augroup! PlugLOD 202 - endif 203 - let lod = { 'ft': {}, 'map': {}, 'cmd': {} } 204 - 205 - filetype off 206 - for name in g:plugs_order 207 - if !has_key(g:plugs, name) 208 - continue 209 - endif 210 - let plug = g:plugs[name] 211 - if get(s:loaded, name, 0) || !has_key(plug, 'on') && !has_key(plug, 'for') 212 - let s:loaded[name] = 1 213 - continue 214 - endif 215 - 216 - if has_key(plug, 'on') 217 - let s:triggers[name] = { 'map': [], 'cmd': [] } 218 - for cmd in s:to_a(plug.on) 219 - if cmd =~? '^<Plug>.\+' 220 - if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) 221 - call s:assoc(lod.map, cmd, name) 222 - endif 223 - call add(s:triggers[name].map, cmd) 224 - elseif cmd =~# '^[A-Z]' 225 - if exists(':'.cmd) != 2 226 - call s:assoc(lod.cmd, cmd, name) 227 - endif 228 - call add(s:triggers[name].cmd, cmd) 229 - else 230 - call s:err('Invalid `on` option: '.cmd. 231 - \ '. Should start with an uppercase letter or `<Plug>`.') 232 - endif 233 - endfor 234 - endif 235 - 236 - if has_key(plug, 'for') 237 - let types = s:to_a(plug.for) 238 - if !empty(types) 239 - augroup filetypedetect 240 - call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') 241 - augroup END 242 - endif 243 - for type in types 244 - call s:assoc(lod.ft, type, name) 245 - endfor 246 - endif 247 - endfor 248 - 249 - for [cmd, names] in items(lod.cmd) 250 - execute printf( 251 - \ 'command! -nargs=* -range -bang %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)', 252 - \ cmd, string(cmd), string(names)) 253 - endfor 254 - 255 - for [map, names] in items(lod.map) 256 - for [mode, map_prefix, key_prefix] in 257 - \ [['i', '<C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] 258 - execute printf( 259 - \ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, "%s")<CR>', 260 - \ mode, map, map_prefix, string(map), string(names), key_prefix) 261 - endfor 262 - endfor 263 - 264 - for [ft, names] in items(lod.ft) 265 - augroup PlugLOD 266 - execute printf('autocmd FileType %s call <SID>lod_ft(%s, %s)', 267 - \ ft, string(ft), string(names)) 268 - augroup END 269 - endfor 270 - 271 - call s:reorg_rtp() 272 - filetype plugin indent on 273 - if has('vim_starting') 274 - if has('syntax') && !exists('g:syntax_on') 275 - syntax enable 276 - end 277 - else 278 - call s:reload_plugins() 279 - endif 280 - endfunction 281 - 282 - function! s:loaded_names() 283 - return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') 284 - endfunction 285 - 286 - function! s:load_plugin(spec) 287 - call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') 288 - endfunction 289 - 290 - function! s:reload_plugins() 291 - for name in s:loaded_names() 292 - call s:load_plugin(g:plugs[name]) 293 - endfor 294 - endfunction 295 - 296 - function! s:trim(str) 297 - return substitute(a:str, '[\/]\+$', '', '') 298 - endfunction 299 - 300 - function! s:version_requirement(val, min) 301 - for idx in range(0, len(a:min) - 1) 302 - let v = get(a:val, idx, 0) 303 - if v < a:min[idx] | return 0 304 - elseif v > a:min[idx] | return 1 305 - endif 306 - endfor 307 - return 1 308 - endfunction 309 - 310 - function! s:git_version_requirement(...) 311 - if !exists('s:git_version') 312 - let s:git_version = map(split(split(s:system('git --version'))[-1], '\.'), 'str2nr(v:val)') 313 - endif 314 - return s:version_requirement(s:git_version, a:000) 315 - endfunction 316 - 317 - function! s:progress_opt(base) 318 - return a:base && !s:is_win && 319 - \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' 320 - endfunction 321 - 322 - if s:is_win 323 - function! s:rtp(spec) 324 - return s:path(a:spec.dir . get(a:spec, 'rtp', '')) 325 - endfunction 326 - 327 - function! s:path(path) 328 - return s:trim(substitute(a:path, '/', '\', 'g')) 329 - endfunction 330 - 331 - function! s:dirpath(path) 332 - return s:path(a:path) . '\' 333 - endfunction 334 - 335 - function! s:is_local_plug(repo) 336 - return a:repo =~? '^[a-z]:\|^[%~]' 337 - endfunction 338 - else 339 - function! s:rtp(spec) 340 - return s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) 341 - endfunction 342 - 343 - function! s:path(path) 344 - return s:trim(a:path) 345 - endfunction 346 - 347 - function! s:dirpath(path) 348 - return substitute(a:path, '[/\\]*$', '/', '') 349 - endfunction 350 - 351 - function! s:is_local_plug(repo) 352 - return a:repo[0] =~ '[/$~]' 353 - endfunction 354 - endif 355 - 356 - function! s:err(msg) 357 - echohl ErrorMsg 358 - echom '[vim-plug] '.a:msg 359 - echohl None 360 - endfunction 361 - 362 - function! s:warn(cmd, msg) 363 - echohl WarningMsg 364 - execute a:cmd 'a:msg' 365 - echohl None 366 - endfunction 367 - 368 - function! s:esc(path) 369 - return escape(a:path, ' ') 370 - endfunction 371 - 372 - function! s:escrtp(path) 373 - return escape(a:path, ' ,') 374 - endfunction 375 - 376 - function! s:remove_rtp() 377 - for name in s:loaded_names() 378 - let rtp = s:rtp(g:plugs[name]) 379 - execute 'set rtp-='.s:escrtp(rtp) 380 - let after = globpath(rtp, 'after') 381 - if isdirectory(after) 382 - execute 'set rtp-='.s:escrtp(after) 383 - endif 384 - endfor 385 - endfunction 386 - 387 - function! s:reorg_rtp() 388 - if !empty(s:first_rtp) 389 - execute 'set rtp-='.s:first_rtp 390 - execute 'set rtp-='.s:last_rtp 391 - endif 392 - 393 - " &rtp is modified from outside 394 - if exists('s:prtp') && s:prtp !=# &rtp 395 - call s:remove_rtp() 396 - unlet! s:middle 397 - endif 398 - 399 - let s:middle = get(s:, 'middle', &rtp) 400 - let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') 401 - let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), 'isdirectory(v:val)') 402 - let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') 403 - \ . ','.s:middle.',' 404 - \ . join(map(afters, 'escape(v:val, ",")'), ',') 405 - let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') 406 - let s:prtp = &rtp 407 - 408 - if !empty(s:first_rtp) 409 - execute 'set rtp^='.s:first_rtp 410 - execute 'set rtp+='.s:last_rtp 411 - endif 412 - endfunction 413 - 414 - function! s:doautocmd(...) 415 - if exists('#'.join(a:000, '#')) 416 - execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000) 417 - endif 418 - endfunction 419 - 420 - function! s:dobufread(names) 421 - for name in a:names 422 - let path = s:rtp(g:plugs[name]).'/**' 423 - for dir in ['ftdetect', 'ftplugin'] 424 - if len(finddir(dir, path)) 425 - return s:doautocmd('BufRead') 426 - endif 427 - endfor 428 - endfor 429 - endfunction 430 - 431 - function! plug#load(...) 432 - if a:0 == 0 433 - return s:err('Argument missing: plugin name(s) required') 434 - endif 435 - if !exists('g:plugs') 436 - return s:err('plug#begin was not called') 437 - endif 438 - let unknowns = filter(copy(a:000), '!has_key(g:plugs, v:val)') 439 - if !empty(unknowns) 440 - let s = len(unknowns) > 1 ? 's' : '' 441 - return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) 442 - end 443 - for name in a:000 444 - call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 445 - endfor 446 - call s:dobufread(a:000) 447 - return 1 448 - endfunction 449 - 450 - function! s:remove_triggers(name) 451 - if !has_key(s:triggers, a:name) 452 - return 453 - endif 454 - for cmd in s:triggers[a:name].cmd 455 - execute 'silent! delc' cmd 456 - endfor 457 - for map in s:triggers[a:name].map 458 - execute 'silent! unmap' map 459 - execute 'silent! iunmap' map 460 - endfor 461 - call remove(s:triggers, a:name) 462 - endfunction 463 - 464 - function! s:lod(names, types, ...) 465 - for name in a:names 466 - call s:remove_triggers(name) 467 - let s:loaded[name] = 1 468 - endfor 469 - call s:reorg_rtp() 470 - 471 - for name in a:names 472 - let rtp = s:rtp(g:plugs[name]) 473 - for dir in a:types 474 - call s:source(rtp, dir.'/**/*.vim') 475 - endfor 476 - if a:0 477 - if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) 478 - execute 'runtime' a:1 479 - endif 480 - call s:source(rtp, a:2) 481 - endif 482 - call s:doautocmd('User', name) 483 - endfor 484 - endfunction 485 - 486 - function! s:lod_ft(pat, names) 487 - let syn = 'syntax/'.a:pat.'.vim' 488 - call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) 489 - execute 'autocmd! PlugLOD FileType' a:pat 490 - call s:doautocmd('filetypeplugin', 'FileType') 491 - call s:doautocmd('filetypeindent', 'FileType') 492 - endfunction 493 - 494 - function! s:lod_cmd(cmd, bang, l1, l2, args, names) 495 - call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 496 - call s:dobufread(a:names) 497 - execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) 498 - endfunction 499 - 500 - function! s:lod_map(map, names, prefix) 501 - call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 502 - call s:dobufread(a:names) 503 - let extra = '' 504 - while 1 505 - let c = getchar(0) 506 - if c == 0 507 - break 508 - endif 509 - let extra .= nr2char(c) 510 - endwhile 511 - 512 - let prefix = v:count ? v:count : '' 513 - let prefix .= '"'.v:register.a:prefix 514 - if mode(1) == 'no' 515 - if v:operator == 'c' 516 - let prefix = "\<esc>" . prefix 517 - endif 518 - let prefix .= v:operator 519 - endif 520 - call feedkeys(prefix, 'n') 521 - call feedkeys(substitute(a:map, '^<Plug>', "\<Plug>", '') . extra) 522 - endfunction 523 - 524 - function! plug#(repo, ...) 525 - if a:0 > 1 526 - return s:err('Invalid number of arguments (1..2)') 527 - endif 528 - 529 - try 530 - let repo = s:trim(a:repo) 531 - let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec 532 - let name = get(opts, 'as', fnamemodify(repo, ':t:s?\.git$??')) 533 - let spec = extend(s:infer_properties(name, repo), opts) 534 - if !has_key(g:plugs, name) 535 - call add(g:plugs_order, name) 536 - endif 537 - let g:plugs[name] = spec 538 - let s:loaded[name] = get(s:loaded, name, 0) 539 - catch 540 - return s:err(v:exception) 541 - endtry 542 - endfunction 543 - 544 - function! s:parse_options(arg) 545 - let opts = copy(s:base_spec) 546 - let type = type(a:arg) 547 - if type == s:TYPE.string 548 - let opts.tag = a:arg 549 - elseif type == s:TYPE.dict 550 - call extend(opts, a:arg) 551 - if has_key(opts, 'dir') 552 - let opts.dir = s:dirpath(expand(opts.dir)) 553 - endif 554 - else 555 - throw 'Invalid argument type (expected: string or dictionary)' 556 - endif 557 - return opts 558 - endfunction 559 - 560 - function! s:infer_properties(name, repo) 561 - let repo = a:repo 562 - if s:is_local_plug(repo) 563 - return { 'dir': s:dirpath(expand(repo)) } 564 - else 565 - if repo =~ ':' 566 - let uri = repo 567 - else 568 - if repo !~ '/' 569 - let repo = 'vim-scripts/'. repo 570 - endif 571 - let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') 572 - let uri = printf(fmt, repo) 573 - endif 574 - let dir = s:dirpath( fnamemodify(join([g:plug_home, a:name], '/'), ':p') ) 575 - return { 'dir': dir, 'uri': uri } 576 - endif 577 - endfunction 578 - 579 - function! s:install(force, names) 580 - call s:update_impl(0, a:force, a:names) 581 - endfunction 582 - 583 - function! s:update(force, names) 584 - call s:update_impl(1, a:force, a:names) 585 - endfunction 586 - 587 - function! plug#helptags() 588 - if !exists('g:plugs') 589 - return s:err('plug#begin was not called') 590 - endif 591 - for spec in values(g:plugs) 592 - let docd = join([spec.dir, 'doc'], '/') 593 - if isdirectory(docd) 594 - silent! execute 'helptags' s:esc(docd) 595 - endif 596 - endfor 597 - return 1 598 - endfunction 599 - 600 - function! s:syntax() 601 - syntax clear 602 - syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber 603 - syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX 604 - syn match plugNumber /[0-9]\+[0-9.]*/ contained 605 - syn match plugBracket /[[\]]/ contained 606 - syn match plugX /x/ contained 607 - syn match plugDash /^-/ 608 - syn match plugPlus /^+/ 609 - syn match plugStar /^*/ 610 - syn match plugMessage /\(^- \)\@<=.*/ 611 - syn match plugName /\(^- \)\@<=[^ ]*:/ 612 - syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ 613 - syn match plugTag /(tag: [^)]\+)/ 614 - syn match plugInstall /\(^+ \)\@<=[^:]*/ 615 - syn match plugUpdate /\(^* \)\@<=[^:]*/ 616 - syn match plugCommit /^ \X*[0-9a-f]\{7} .*/ contains=plugRelDate,plugEdge,plugTag 617 - syn match plugEdge /^ \X\+$/ 618 - syn match plugEdge /^ \X*/ contained nextgroup=plugSha 619 - syn match plugSha /[0-9a-f]\{7}/ contained 620 - syn match plugRelDate /([^)]*)$/ contained 621 - syn match plugNotLoaded /(not loaded)$/ 622 - syn match plugError /^x.*/ 623 - syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ 624 - syn match plugH2 /^.*:\n-\+$/ 625 - syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean 626 - hi def link plug1 Title 627 - hi def link plug2 Repeat 628 - hi def link plugH2 Type 629 - hi def link plugX Exception 630 - hi def link plugBracket Structure 631 - hi def link plugNumber Number 632 - 633 - hi def link plugDash Special 634 - hi def link plugPlus Constant 635 - hi def link plugStar Boolean 636 - 637 - hi def link plugMessage Function 638 - hi def link plugName Label 639 - hi def link plugInstall Function 640 - hi def link plugUpdate Type 641 - 642 - hi def link plugError Error 643 - hi def link plugDeleted Ignore 644 - hi def link plugRelDate Comment 645 - hi def link plugEdge PreProc 646 - hi def link plugSha Identifier 647 - hi def link plugTag Constant 648 - 649 - hi def link plugNotLoaded Comment 650 - endfunction 651 - 652 - function! s:lpad(str, len) 653 - return a:str . repeat(' ', a:len - len(a:str)) 654 - endfunction 655 - 656 - function! s:lines(msg) 657 - return split(a:msg, "[\r\n]") 658 - endfunction 659 - 660 - function! s:lastline(msg) 661 - return get(s:lines(a:msg), -1, '') 662 - endfunction 663 - 664 - function! s:new_window() 665 - execute get(g:, 'plug_window', 'vertical topleft new') 666 - endfunction 667 - 668 - function! s:plug_window_exists() 669 - let buflist = tabpagebuflist(s:plug_tab) 670 - return !empty(buflist) && index(buflist, s:plug_buf) >= 0 671 - endfunction 672 - 673 - function! s:switch_in() 674 - if !s:plug_window_exists() 675 - return 0 676 - endif 677 - 678 - if winbufnr(0) != s:plug_buf 679 - let s:pos = [tabpagenr(), winnr(), winsaveview()] 680 - execute 'normal!' s:plug_tab.'gt' 681 - let winnr = bufwinnr(s:plug_buf) 682 - execute winnr.'wincmd w' 683 - call add(s:pos, winsaveview()) 684 - else 685 - let s:pos = [winsaveview()] 686 - endif 687 - 688 - setlocal modifiable 689 - return 1 690 - endfunction 691 - 692 - function! s:switch_out(...) 693 - call winrestview(s:pos[-1]) 694 - setlocal nomodifiable 695 - if a:0 > 0 696 - execute a:1 697 - endif 698 - 699 - if len(s:pos) > 1 700 - execute 'normal!' s:pos[0].'gt' 701 - execute s:pos[1] 'wincmd w' 702 - call winrestview(s:pos[2]) 703 - endif 704 - endfunction 705 - 706 - function! s:finish_bindings() 707 - nnoremap <silent> <buffer> R :call <SID>retry()<cr> 708 - nnoremap <silent> <buffer> D :PlugDiff<cr> 709 - nnoremap <silent> <buffer> S :PlugStatus<cr> 710 - nnoremap <silent> <buffer> U :call <SID>status_update()<cr> 711 - xnoremap <silent> <buffer> U :call <SID>status_update()<cr> 712 - nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr> 713 - nnoremap <silent> <buffer> [[ :silent! call <SID>section('b')<cr> 714 - endfunction 715 - 716 - function! s:prepare(...) 717 - if empty(getcwd()) 718 - throw 'Invalid current working directory. Cannot proceed.' 719 - endif 720 - 721 - for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] 722 - if exists(evar) 723 - throw evar.' detected. Cannot proceed.' 724 - endif 725 - endfor 726 - 727 - call s:job_abort() 728 - if s:switch_in() 729 - normal q 730 - endif 731 - 732 - call s:new_window() 733 - nnoremap <silent> <buffer> q :if b:plug_preview==1<bar>pc<bar>endif<bar>bd<cr> 734 - if a:0 == 0 735 - call s:finish_bindings() 736 - endif 737 - let b:plug_preview = -1 738 - let s:plug_tab = tabpagenr() 739 - let s:plug_buf = winbufnr(0) 740 - call s:assign_name() 741 - 742 - for k in ['<cr>', 'L', 'o', 'X', 'd', 'dd'] 743 - execute 'silent! unmap <buffer>' k 744 - endfor 745 - setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline modifiable 746 - setf vim-plug 747 - if exists('g:syntax_on') 748 - call s:syntax() 749 - endif 750 - endfunction 751 - 752 - function! s:assign_name() 753 - " Assign buffer name 754 - let prefix = '[Plugins]' 755 - let name = prefix 756 - let idx = 2 757 - while bufexists(name) 758 - let name = printf('%s (%s)', prefix, idx) 759 - let idx = idx + 1 760 - endwhile 761 - silent! execute 'f' fnameescape(name) 762 - endfunction 763 - 764 - function! s:chsh(swap) 765 - let prev = [&shell, &shellredir] 766 - if !s:is_win && a:swap 767 - set shell=sh shellredir=>%s\ 2>&1 768 - endif 769 - return prev 770 - endfunction 771 - 772 - function! s:bang(cmd, ...) 773 - try 774 - let [sh, shrd] = s:chsh(a:0) 775 - " FIXME: Escaping is incomplete. We could use shellescape with eval, 776 - " but it won't work on Windows. 777 - let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd 778 - let g:_plug_bang = '!'.escape(cmd, '#!%') 779 - execute "normal! :execute g:_plug_bang\<cr>\<cr>" 780 - finally 781 - unlet g:_plug_bang 782 - let [&shell, &shellredir] = [sh, shrd] 783 - endtry 784 - return v:shell_error ? 'Exit status: ' . v:shell_error : '' 785 - endfunction 786 - 787 - function! s:regress_bar() 788 - let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') 789 - call s:progress_bar(2, bar, len(bar)) 790 - endfunction 791 - 792 - function! s:is_updated(dir) 793 - return !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', a:dir)) 794 - endfunction 795 - 796 - function! s:do(pull, force, todo) 797 - for [name, spec] in items(a:todo) 798 - if !isdirectory(spec.dir) 799 - continue 800 - endif 801 - let installed = has_key(s:update.new, name) 802 - let updated = installed ? 0 : 803 - \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) 804 - if a:force || installed || updated 805 - execute 'cd' s:esc(spec.dir) 806 - call append(3, '- Post-update hook for '. name .' ... ') 807 - let error = '' 808 - let type = type(spec.do) 809 - if type == s:TYPE.string 810 - if spec.do[0] == ':' 811 - call s:load_plugin(spec) 812 - execute spec.do[1:] 813 - else 814 - let error = s:bang(spec.do) 815 - endif 816 - elseif type == s:TYPE.funcref 817 - try 818 - let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') 819 - call spec.do({ 'name': name, 'status': status, 'force': a:force }) 820 - catch 821 - let error = v:exception 822 - endtry 823 - else 824 - let error = 'Invalid hook type' 825 - endif 826 - call s:switch_in() 827 - call setline(4, empty(error) ? (getline(4) . 'OK') 828 - \ : ('x' . getline(4)[1:] . error)) 829 - if !empty(error) 830 - call add(s:update.errors, name) 831 - call s:regress_bar() 832 - endif 833 - cd - 834 - endif 835 - endfor 836 - endfunction 837 - 838 - function! s:hash_match(a, b) 839 - return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 840 - endfunction 841 - 842 - function! s:checkout(spec) 843 - let sha = a:spec.commit 844 - let output = s:system('git rev-parse HEAD', a:spec.dir) 845 - if !v:shell_error && !s:hash_match(sha, s:lines(output)[0]) 846 - let output = s:system( 847 - \ 'git fetch --depth 999999 && git checkout '.s:esc(sha), a:spec.dir) 848 - endif 849 - return output 850 - endfunction 851 - 852 - function! s:finish(pull) 853 - let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) 854 - if new_frozen 855 - let s = new_frozen > 1 ? 's' : '' 856 - call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) 857 - endif 858 - call append(3, '- Finishing ... ') | 4 859 - redraw 860 - call plug#helptags() 861 - call plug#end() 862 - call setline(4, getline(4) . 'Done!') 863 - redraw 864 - let msgs = [] 865 - if !empty(s:update.errors) 866 - call add(msgs, "Press 'R' to retry.") 867 - endif 868 - if a:pull && len(s:update.new) < len(filter(getline(5, '$'), 869 - \ "v:val =~ '^- ' && stridx(v:val, 'Already up-to-date') < 0")) 870 - call add(msgs, "Press 'D' to see the updated changes.") 871 - endif 872 - echo join(msgs, ' ') 873 - call s:finish_bindings() 874 - endfunction 875 - 876 - function! s:retry() 877 - if empty(s:update.errors) 878 - return 879 - endif 880 - echo 881 - call s:update_impl(s:update.pull, s:update.force, 882 - \ extend(copy(s:update.errors), [s:update.threads])) 883 - endfunction 884 - 885 - function! s:is_managed(name) 886 - return has_key(g:plugs[a:name], 'uri') 887 - endfunction 888 - 889 - function! s:names(...) 890 - return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) 891 - endfunction 892 - 893 - function! s:check_ruby() 894 - silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") 895 - if !exists('g:plug_ruby') 896 - redraw! 897 - return s:warn('echom', 'Warning: Ruby interface is broken') 898 - endif 899 - let ruby_version = split(g:plug_ruby, '\.') 900 - unlet g:plug_ruby 901 - return s:version_requirement(ruby_version, [1, 8, 7]) 902 - endfunction 903 - 904 - function! s:update_impl(pull, force, args) abort 905 - let args = copy(a:args) 906 - let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? 907 - \ remove(args, -1) : get(g:, 'plug_threads', 16) 908 - 909 - let managed = filter(copy(g:plugs), 's:is_managed(v:key)') 910 - let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : 911 - \ filter(managed, 'index(args, v:key) >= 0') 912 - 913 - if empty(todo) 914 - return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) 915 - endif 916 - 917 - if !s:is_win && s:git_version_requirement(2, 3) 918 - let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' 919 - let $GIT_TERMINAL_PROMPT = 0 920 - for plug in values(todo) 921 - let plug.uri = substitute(plug.uri, 922 - \ '^https://git::@github\.com', 'https://github.com', '') 923 - endfor 924 - endif 925 - 926 - if !isdirectory(g:plug_home) 927 - try 928 - call mkdir(g:plug_home, 'p') 929 - catch 930 - return s:err(printf('Invalid plug directory: %s. '. 931 - \ 'Try to call plug#begin with a valid directory', g:plug_home)) 932 - endtry 933 - endif 934 - 935 - if has('nvim') && !exists('*jobwait') && threads > 1 936 - call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') 937 - endif 938 - 939 - let python = (has('python') || has('python3')) && (!s:nvim || has('vim_starting')) 940 - let ruby = has('ruby') && !s:nvim && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && s:check_ruby() 941 - 942 - let s:update = { 943 - \ 'start': reltime(), 944 - \ 'all': todo, 945 - \ 'todo': copy(todo), 946 - \ 'errors': [], 947 - \ 'pull': a:pull, 948 - \ 'force': a:force, 949 - \ 'new': {}, 950 - \ 'threads': (python || ruby || s:nvim) ? min([len(todo), threads]) : 1, 951 - \ 'bar': '', 952 - \ 'fin': 0 953 - \ } 954 - 955 - call s:prepare(1) 956 - call append(0, ['', '']) 957 - normal! 2G 958 - silent! redraw 959 - 960 - let s:clone_opt = get(g:, 'plug_shallow', 1) ? 961 - \ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : '' 962 - 963 - " Python version requirement (>= 2.7) 964 - if python && !has('python3') && !ruby && !s:nvim && s:update.threads > 1 965 - redir => pyv 966 - silent python import platform; print platform.python_version() 967 - redir END 968 - let python = s:version_requirement( 969 - \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) 970 - endif 971 - 972 - if (python || ruby) && s:update.threads > 1 973 - try 974 - let imd = &imd 975 - if s:mac_gui 976 - set noimd 977 - endif 978 - if ruby 979 - call s:update_ruby() 980 - else 981 - call s:update_python() 982 - endif 983 - catch 984 - let lines = getline(4, '$') 985 - let printed = {} 986 - silent! 4,$d _ 987 - for line in lines 988 - let name = s:extract_name(line, '.', '') 989 - if empty(name) || !has_key(printed, name) 990 - call append('$', line) 991 - if !empty(name) 992 - let printed[name] = 1 993 - if line[0] == 'x' && index(s:update.errors, name) < 0 994 - call add(s:update.errors, name) 995 - end 996 - endif 997 - endif 998 - endfor 999 - finally 1000 - let &imd = imd 1001 - call s:update_finish() 1002 - endtry 1003 - else 1004 - call s:update_vim() 1005 - endif 1006 - endfunction 1007 - 1008 - function! s:log4(name, msg) 1009 - call setline(4, printf('- %s (%s)', a:msg, a:name)) 1010 - redraw 1011 - endfunction 1012 - 1013 - function! s:update_finish() 1014 - if exists('s:git_terminal_prompt') 1015 - let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt 1016 - endif 1017 - if s:switch_in() 1018 - call append(3, '- Updating ...') | 4 1019 - for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))')) 1020 - let pos = s:logpos(name) 1021 - if !pos 1022 - continue 1023 - endif 1024 - if has_key(spec, 'commit') 1025 - call s:log4(name, 'Checking out '.spec.commit) 1026 - let out = s:checkout(spec) 1027 - elseif has_key(spec, 'tag') 1028 - let tag = spec.tag 1029 - if tag =~ '\*' 1030 - let tags = s:lines(s:system('git tag --list '.string(tag).' --sort -version:refname 2>&1', spec.dir)) 1031 - if !v:shell_error && !empty(tags) 1032 - let tag = tags[0] 1033 - call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) 1034 - call append(3, '') 1035 - endif 1036 - endif 1037 - call s:log4(name, 'Checking out '.tag) 1038 - let out = s:system('git checkout -q '.s:esc(tag).' 2>&1', spec.dir) 1039 - else 1040 - let branch = s:esc(get(spec, 'branch', 'master')) 1041 - call s:log4(name, 'Merging origin/'.branch) 1042 - let out = s:system('git checkout -q '.branch.' 2>&1' 1043 - \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only origin/'.branch.' 2>&1')), spec.dir) 1044 - endif 1045 - if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && 1046 - \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) 1047 - call s:log4(name, 'Updating submodules. This may take a while.') 1048 - let out .= s:bang('git submodule update --init --recursive 2>&1', spec.dir) 1049 - endif 1050 - let msg = s:format_message(v:shell_error ? 'x': '-', name, out) 1051 - if v:shell_error 1052 - call add(s:update.errors, name) 1053 - call s:regress_bar() 1054 - silent execute pos 'd _' 1055 - call append(4, msg) | 4 1056 - elseif !empty(out) 1057 - call setline(pos, msg[0]) 1058 - endif 1059 - redraw 1060 - endfor 1061 - silent 4 d _ 1062 - call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")')) 1063 - call s:finish(s:update.pull) 1064 - call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') 1065 - call s:switch_out('normal! gg') 1066 - endif 1067 - endfunction 1068 - 1069 - function! s:job_abort() 1070 - if !s:nvim || !exists('s:jobs') 1071 - return 1072 - endif 1073 - 1074 - for [name, j] in items(s:jobs) 1075 - silent! call jobstop(j.jobid) 1076 - if j.new 1077 - call s:system('rm -rf ' . s:shellesc(g:plugs[name].dir)) 1078 - endif 1079 - endfor 1080 - let s:jobs = {} 1081 - endfunction 1082 - 1083 - " When a:event == 'stdout', data = list of strings 1084 - " When a:event == 'exit', data = returncode 1085 - function! s:job_handler(job_id, data, event) abort 1086 - if !s:plug_window_exists() " plug window closed 1087 - return s:job_abort() 1088 - endif 1089 - 1090 - if a:event == 'stdout' 1091 - let complete = empty(a:data[-1]) 1092 - let lines = map(filter(a:data, 'v:val =~ "[^\r\n]"'), 'split(v:val, "[\r\n]")[-1]') 1093 - call extend(self.lines, lines) 1094 - let self.result = join(self.lines, "\n") 1095 - if !complete 1096 - call remove(self.lines, -1) 1097 - endif 1098 - " To reduce the number of buffer updates 1099 - let self.tick = get(self, 'tick', -1) + 1 1100 - if self.tick % len(s:jobs) == 0 1101 - call s:log(self.new ? '+' : '*', self.name, self.result) 1102 - endif 1103 - elseif a:event == 'exit' 1104 - let self.running = 0 1105 - if a:data != 0 1106 - let self.error = 1 1107 - endif 1108 - call s:reap(self.name) 1109 - call s:tick() 1110 - endif 1111 - endfunction 1112 - 1113 - function! s:spawn(name, cmd, opts) 1114 - let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [], 'result': '', 1115 - \ 'new': get(a:opts, 'new', 0), 1116 - \ 'on_stdout': function('s:job_handler'), 1117 - \ 'on_exit' : function('s:job_handler'), 1118 - \ } 1119 - let s:jobs[a:name] = job 1120 - 1121 - if s:nvim 1122 - let argv = [ 'sh', '-c', 1123 - \ (has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd) ] 1124 - let jid = jobstart(argv, job) 1125 - if jid > 0 1126 - let job.jobid = jid 1127 - else 1128 - let job.running = 0 1129 - let job.error = 1 1130 - let job.result = jid < 0 ? 'sh is not executable' : 1131 - \ 'Invalid arguments (or job table is full)' 1132 - endif 1133 - else 1134 - let params = has_key(a:opts, 'dir') ? [a:cmd, a:opts.dir] : [a:cmd] 1135 - let job.result = call('s:system', params) 1136 - let job.error = v:shell_error != 0 1137 - let job.running = 0 1138 - endif 1139 - endfunction 1140 - 1141 - function! s:reap(name) 1142 - let job = s:jobs[a:name] 1143 - if job.error 1144 - call add(s:update.errors, a:name) 1145 - elseif get(job, 'new', 0) 1146 - let s:update.new[a:name] = 1 1147 - endif 1148 - let s:update.bar .= job.error ? 'x' : '=' 1149 - 1150 - call s:log(job.error ? 'x' : '-', a:name, empty(job.result) ? 'OK' : job.result) 1151 - call s:bar() 1152 - 1153 - call remove(s:jobs, a:name) 1154 - endfunction 1155 - 1156 - function! s:bar() 1157 - if s:switch_in() 1158 - let total = len(s:update.all) 1159 - call setline(1, (s:update.pull ? 'Updating' : 'Installing'). 1160 - \ ' plugins ('.len(s:update.bar).'/'.total.')') 1161 - call s:progress_bar(2, s:update.bar, total) 1162 - call s:switch_out() 1163 - endif 1164 - endfunction 1165 - 1166 - function! s:logpos(name) 1167 - for i in range(4, line('$')) 1168 - if getline(i) =~# '^[-+x*] '.a:name.':' 1169 - return i 1170 - endif 1171 - endfor 1172 - endfunction 1173 - 1174 - function! s:log(bullet, name, lines) 1175 - if s:switch_in() 1176 - let pos = s:logpos(a:name) 1177 - if pos > 0 1178 - silent execute pos 'd _' 1179 - if pos > winheight('.') 1180 - let pos = 4 1181 - endif 1182 - else 1183 - let pos = 4 1184 - endif 1185 - call append(pos - 1, s:format_message(a:bullet, a:name, a:lines)) 1186 - call s:switch_out() 1187 - endif 1188 - endfunction 1189 - 1190 - function! s:update_vim() 1191 - let s:jobs = {} 1192 - 1193 - call s:bar() 1194 - call s:tick() 1195 - endfunction 1196 - 1197 - function! s:tick() 1198 - let pull = s:update.pull 1199 - let prog = s:progress_opt(s:nvim) 1200 - while 1 " Without TCO, Vim stack is bound to explode 1201 - if empty(s:update.todo) 1202 - if empty(s:jobs) && !s:update.fin 1203 - let s:update.fin = 1 1204 - call s:update_finish() 1205 - endif 1206 - return 1207 - endif 1208 - 1209 - let name = keys(s:update.todo)[0] 1210 - let spec = remove(s:update.todo, name) 1211 - let new = !isdirectory(spec.dir) 1212 - 1213 - call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') 1214 - redraw 1215 - 1216 - let has_tag = has_key(spec, 'tag') 1217 - if !new 1218 - let [error, _] = s:git_validate(spec, 0) 1219 - if empty(error) 1220 - if pull 1221 - let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : '' 1222 - call s:spawn(name, printf('git fetch %s %s 2>&1', fetch_opt, prog), { 'dir': spec.dir }) 1223 - else 1224 - let s:jobs[name] = { 'running': 0, 'result': 'Already installed', 'error': 0 } 1225 - endif 1226 - else 1227 - let s:jobs[name] = { 'running': 0, 'result': error, 'error': 1 } 1228 - endif 1229 - else 1230 - call s:spawn(name, 1231 - \ printf('git clone %s %s %s %s 2>&1', 1232 - \ has_tag ? '' : s:clone_opt, 1233 - \ prog, 1234 - \ s:shellesc(spec.uri), 1235 - \ s:shellesc(s:trim(spec.dir))), { 'new': 1 }) 1236 - endif 1237 - 1238 - if !s:jobs[name].running 1239 - call s:reap(name) 1240 - endif 1241 - if len(s:jobs) >= s:update.threads 1242 - break 1243 - endif 1244 - endwhile 1245 - endfunction 1246 - 1247 - function! s:update_python() 1248 - let py_exe = has('python') ? 'python' : 'python3' 1249 - execute py_exe "<< EOF" 1250 - import datetime 1251 - import functools 1252 - import os 1253 - try: 1254 - import queue 1255 - except ImportError: 1256 - import Queue as queue 1257 - import random 1258 - import re 1259 - import shutil 1260 - import signal 1261 - import subprocess 1262 - import tempfile 1263 - import threading as thr 1264 - import time 1265 - import traceback 1266 - import vim 1267 - 1268 - G_NVIM = vim.eval("has('nvim')") == '1' 1269 - G_PULL = vim.eval('s:update.pull') == '1' 1270 - G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 1271 - G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) 1272 - G_CLONE_OPT = vim.eval('s:clone_opt') 1273 - G_PROGRESS = vim.eval('s:progress_opt(1)') 1274 - G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) 1275 - G_STOP = thr.Event() 1276 - G_IS_WIN = vim.eval('s:is_win') == '1' 1277 - 1278 - class PlugError(Exception): 1279 - def __init__(self, msg): 1280 - self.msg = msg 1281 - class CmdTimedOut(PlugError): 1282 - pass 1283 - class CmdFailed(PlugError): 1284 - pass 1285 - class InvalidURI(PlugError): 1286 - pass 1287 - class Action(object): 1288 - INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] 1289 - 1290 - class Buffer(object): 1291 - def __init__(self, lock, num_plugs, is_pull): 1292 - self.bar = '' 1293 - self.event = 'Updating' if is_pull else 'Installing' 1294 - self.lock = lock 1295 - self.maxy = int(vim.eval('winheight(".")')) 1296 - self.num_plugs = num_plugs 1297 - 1298 - def __where(self, name): 1299 - """ Find first line with name in current buffer. Return line num. """ 1300 - found, lnum = False, 0 1301 - matcher = re.compile('^[-+x*] {0}:'.format(name)) 1302 - for line in vim.current.buffer: 1303 - if matcher.search(line) is not None: 1304 - found = True 1305 - break 1306 - lnum += 1 1307 - 1308 - if not found: 1309 - lnum = -1 1310 - return lnum 1311 - 1312 - def header(self): 1313 - curbuf = vim.current.buffer 1314 - curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) 1315 - 1316 - num_spaces = self.num_plugs - len(self.bar) 1317 - curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') 1318 - 1319 - with self.lock: 1320 - vim.command('normal! 2G') 1321 - vim.command('redraw') 1322 - 1323 - def write(self, action, name, lines): 1324 - first, rest = lines[0], lines[1:] 1325 - msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] 1326 - msg.extend([' ' + line for line in rest]) 1327 - 1328 - try: 1329 - if action == Action.ERROR: 1330 - self.bar += 'x' 1331 - vim.command("call add(s:update.errors, '{0}')".format(name)) 1332 - elif action == Action.DONE: 1333 - self.bar += '=' 1334 - 1335 - curbuf = vim.current.buffer 1336 - lnum = self.__where(name) 1337 - if lnum != -1: # Found matching line num 1338 - del curbuf[lnum] 1339 - if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): 1340 - lnum = 3 1341 - else: 1342 - lnum = 3 1343 - curbuf.append(msg, lnum) 1344 - 1345 - self.header() 1346 - except vim.error: 1347 - pass 1348 - 1349 - class Command(object): 1350 - CD = 'cd /d' if G_IS_WIN else 'cd' 1351 - 1352 - def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): 1353 - self.cmd = cmd 1354 - if cmd_dir: 1355 - self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) 1356 - self.timeout = timeout 1357 - self.callback = cb if cb else (lambda msg: None) 1358 - self.clean = clean if clean else (lambda: None) 1359 - self.proc = None 1360 - 1361 - @property 1362 - def alive(self): 1363 - """ Returns true only if command still running. """ 1364 - return self.proc and self.proc.poll() is None 1365 - 1366 - def execute(self, ntries=3): 1367 - """ Execute the command with ntries if CmdTimedOut. 1368 - Returns the output of the command if no Exception. 1369 - """ 1370 - attempt, finished, limit = 0, False, self.timeout 1371 - 1372 - while not finished: 1373 - try: 1374 - attempt += 1 1375 - result = self.try_command() 1376 - finished = True 1377 - return result 1378 - except CmdTimedOut: 1379 - if attempt != ntries: 1380 - self.notify_retry() 1381 - self.timeout += limit 1382 - else: 1383 - raise 1384 - 1385 - def notify_retry(self): 1386 - """ Retry required for command, notify user. """ 1387 - for count in range(3, 0, -1): 1388 - if G_STOP.is_set(): 1389 - raise KeyboardInterrupt 1390 - msg = 'Timeout. Will retry in {0} second{1} ...'.format( 1391 - count, 's' if count != 1 else '') 1392 - self.callback([msg]) 1393 - time.sleep(1) 1394 - self.callback(['Retrying ...']) 1395 - 1396 - def try_command(self): 1397 - """ Execute a cmd & poll for callback. Returns list of output. 1398 - Raises CmdFailed -> return code for Popen isn't 0 1399 - Raises CmdTimedOut -> command exceeded timeout without new output 1400 - """ 1401 - first_line = True 1402 - 1403 - try: 1404 - tfile = tempfile.NamedTemporaryFile(mode='w+b') 1405 - preexec_fn = not G_IS_WIN and os.setsid or None 1406 - self.proc = subprocess.Popen(self.cmd, stdout=tfile, 1407 - stderr=subprocess.STDOUT, 1408 - stdin=subprocess.PIPE, shell=True, 1409 - preexec_fn=preexec_fn) 1410 - thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) 1411 - thrd.start() 1412 - 1413 - thread_not_started = True 1414 - while thread_not_started: 1415 - try: 1416 - thrd.join(0.1) 1417 - thread_not_started = False 1418 - except RuntimeError: 1419 - pass 1420 - 1421 - while self.alive: 1422 - if G_STOP.is_set(): 1423 - raise KeyboardInterrupt 1424 - 1425 - if first_line or random.random() < G_LOG_PROB: 1426 - first_line = False 1427 - line = '' if G_IS_WIN else nonblock_read(tfile.name) 1428 - if line: 1429 - self.callback([line]) 1430 - 1431 - time_diff = time.time() - os.path.getmtime(tfile.name) 1432 - if time_diff > self.timeout: 1433 - raise CmdTimedOut(['Timeout!']) 1434 - 1435 - thrd.join(0.5) 1436 - 1437 - tfile.seek(0) 1438 - result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] 1439 - 1440 - if self.proc.returncode != 0: 1441 - raise CmdFailed([''] + result) 1442 - 1443 - return result 1444 - except: 1445 - self.terminate() 1446 - raise 1447 - 1448 - def terminate(self): 1449 - """ Terminate process and cleanup. """ 1450 - if self.alive: 1451 - if G_IS_WIN: 1452 - os.kill(self.proc.pid, signal.SIGINT) 1453 - else: 1454 - os.killpg(self.proc.pid, signal.SIGTERM) 1455 - self.clean() 1456 - 1457 - class Plugin(object): 1458 - def __init__(self, name, args, buf_q, lock): 1459 - self.name = name 1460 - self.args = args 1461 - self.buf_q = buf_q 1462 - self.lock = lock 1463 - self.tag = args.get('tag', 0) 1464 - 1465 - def manage(self): 1466 - try: 1467 - if os.path.exists(self.args['dir']): 1468 - self.update() 1469 - else: 1470 - self.install() 1471 - with self.lock: 1472 - thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) 1473 - except PlugError as exc: 1474 - self.write(Action.ERROR, self.name, exc.msg) 1475 - except KeyboardInterrupt: 1476 - G_STOP.set() 1477 - self.write(Action.ERROR, self.name, ['Interrupted!']) 1478 - except: 1479 - # Any exception except those above print stack trace 1480 - msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) 1481 - self.write(Action.ERROR, self.name, msg.split('\n')) 1482 - raise 1483 - 1484 - def install(self): 1485 - target = self.args['dir'] 1486 - if target[-1] == '\\': 1487 - target = target[0:-1] 1488 - 1489 - def clean(target): 1490 - def _clean(): 1491 - try: 1492 - shutil.rmtree(target) 1493 - except OSError: 1494 - pass 1495 - return _clean 1496 - 1497 - self.write(Action.INSTALL, self.name, ['Installing ...']) 1498 - callback = functools.partial(self.write, Action.INSTALL, self.name) 1499 - cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( 1500 - '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], 1501 - esc(target)) 1502 - com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) 1503 - result = com.execute(G_RETRIES) 1504 - self.write(Action.DONE, self.name, result[-1:]) 1505 - 1506 - def repo_uri(self): 1507 - cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' 1508 - command = Command(cmd, self.args['dir'], G_TIMEOUT,) 1509 - result = command.execute(G_RETRIES) 1510 - return result[-1] 1511 - 1512 - def update(self): 1513 - match = re.compile(r'git::?@') 1514 - actual_uri = re.sub(match, '', self.repo_uri()) 1515 - expect_uri = re.sub(match, '', self.args['uri']) 1516 - if actual_uri != expect_uri: 1517 - msg = ['', 1518 - 'Invalid URI: {0}'.format(actual_uri), 1519 - 'Expected {0}'.format(expect_uri), 1520 - 'PlugClean required.'] 1521 - raise InvalidURI(msg) 1522 - 1523 - if G_PULL: 1524 - self.write(Action.UPDATE, self.name, ['Updating ...']) 1525 - callback = functools.partial(self.write, Action.UPDATE, self.name) 1526 - fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' 1527 - cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) 1528 - com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) 1529 - result = com.execute(G_RETRIES) 1530 - self.write(Action.DONE, self.name, result[-1:]) 1531 - else: 1532 - self.write(Action.DONE, self.name, ['Already installed']) 1533 - 1534 - def write(self, action, name, msg): 1535 - self.buf_q.put((action, name, msg)) 1536 - 1537 - class PlugThread(thr.Thread): 1538 - def __init__(self, tname, args): 1539 - super(PlugThread, self).__init__() 1540 - self.tname = tname 1541 - self.args = args 1542 - 1543 - def run(self): 1544 - thr.current_thread().name = self.tname 1545 - buf_q, work_q, lock = self.args 1546 - 1547 - try: 1548 - while not G_STOP.is_set(): 1549 - name, args = work_q.get_nowait() 1550 - plug = Plugin(name, args, buf_q, lock) 1551 - plug.manage() 1552 - work_q.task_done() 1553 - except queue.Empty: 1554 - pass 1555 - 1556 - class RefreshThread(thr.Thread): 1557 - def __init__(self, lock): 1558 - super(RefreshThread, self).__init__() 1559 - self.lock = lock 1560 - self.running = True 1561 - 1562 - def run(self): 1563 - while self.running: 1564 - with self.lock: 1565 - thread_vim_command('noautocmd normal! a') 1566 - time.sleep(0.33) 1567 - 1568 - def stop(self): 1569 - self.running = False 1570 - 1571 - if G_NVIM: 1572 - def thread_vim_command(cmd): 1573 - vim.session.threadsafe_call(lambda: vim.command(cmd)) 1574 - else: 1575 - def thread_vim_command(cmd): 1576 - vim.command(cmd) 1577 - 1578 - def esc(name): 1579 - return '"' + name.replace('"', '\"') + '"' 1580 - 1581 - def nonblock_read(fname): 1582 - """ Read a file with nonblock flag. Return the last line. """ 1583 - fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) 1584 - buf = os.read(fread, 100000).decode('utf-8', 'replace') 1585 - os.close(fread) 1586 - 1587 - line = buf.rstrip('\r\n') 1588 - left = max(line.rfind('\r'), line.rfind('\n')) 1589 - if left != -1: 1590 - left += 1 1591 - line = line[left:] 1592 - 1593 - return line 1594 - 1595 - def main(): 1596 - thr.current_thread().name = 'main' 1597 - nthreads = int(vim.eval('s:update.threads')) 1598 - plugs = vim.eval('s:update.todo') 1599 - mac_gui = vim.eval('s:mac_gui') == '1' 1600 - 1601 - lock = thr.Lock() 1602 - buf = Buffer(lock, len(plugs), G_PULL) 1603 - buf_q, work_q = queue.Queue(), queue.Queue() 1604 - for work in plugs.items(): 1605 - work_q.put(work) 1606 - 1607 - start_cnt = thr.active_count() 1608 - for num in range(nthreads): 1609 - tname = 'PlugT-{0:02}'.format(num) 1610 - thread = PlugThread(tname, (buf_q, work_q, lock)) 1611 - thread.start() 1612 - if mac_gui: 1613 - rthread = RefreshThread(lock) 1614 - rthread.start() 1615 - 1616 - while not buf_q.empty() or thr.active_count() != start_cnt: 1617 - try: 1618 - action, name, msg = buf_q.get(True, 0.25) 1619 - buf.write(action, name, ['OK'] if not msg else msg) 1620 - buf_q.task_done() 1621 - except queue.Empty: 1622 - pass 1623 - except KeyboardInterrupt: 1624 - G_STOP.set() 1625 - 1626 - if mac_gui: 1627 - rthread.stop() 1628 - rthread.join() 1629 - 1630 - main() 1631 - EOF 1632 - endfunction 1633 - 1634 - function! s:update_ruby() 1635 - ruby << EOF 1636 - module PlugStream 1637 - SEP = ["\r", "\n", nil] 1638 - def get_line 1639 - buffer = '' 1640 - loop do 1641 - char = readchar rescue return 1642 - if SEP.include? char.chr 1643 - buffer << $/ 1644 - break 1645 - else 1646 - buffer << char 1647 - end 1648 - end 1649 - buffer 1650 - end 1651 - end unless defined?(PlugStream) 1652 - 1653 - def esc arg 1654 - %["#{arg.gsub('"', '\"')}"] 1655 - end 1656 - 1657 - def killall pid 1658 - pids = [pid] 1659 - if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM 1660 - pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } 1661 - else 1662 - unless `which pgrep 2> /dev/null`.empty? 1663 - children = pids 1664 - until children.empty? 1665 - children = children.map { |pid| 1666 - `pgrep -P #{pid}`.lines.map { |l| l.chomp } 1667 - }.flatten 1668 - pids += children 1669 - end 1670 - end 1671 - pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } 1672 - end 1673 - end 1674 - 1675 - require 'thread' 1676 - require 'fileutils' 1677 - require 'timeout' 1678 - running = true 1679 - iswin = VIM::evaluate('s:is_win').to_i == 1 1680 - pull = VIM::evaluate('s:update.pull').to_i == 1 1681 - base = VIM::evaluate('g:plug_home') 1682 - all = VIM::evaluate('s:update.todo') 1683 - limit = VIM::evaluate('get(g:, "plug_timeout", 60)') 1684 - tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 1685 - nthr = VIM::evaluate('s:update.threads').to_i 1686 - maxy = VIM::evaluate('winheight(".")').to_i 1687 - cd = iswin ? 'cd /d' : 'cd' 1688 - tot = VIM::evaluate('len(s:update.todo)') || 0 1689 - bar = '' 1690 - skip = 'Already installed' 1691 - mtx = Mutex.new 1692 - take1 = proc { mtx.synchronize { running && all.shift } } 1693 - logh = proc { 1694 - cnt = bar.length 1695 - $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" 1696 - $curbuf[2] = '[' + bar.ljust(tot) + ']' 1697 - VIM::command('normal! 2G') 1698 - VIM::command('redraw') 1699 - } 1700 - where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } 1701 - log = proc { |name, result, type| 1702 - mtx.synchronize do 1703 - ing = ![true, false].include?(type) 1704 - bar += type ? '=' : 'x' unless ing 1705 - b = case type 1706 - when :install then '+' when :update then '*' 1707 - when true, nil then '-' else 1708 - VIM::command("call add(s:update.errors, '#{name}')") 1709 - 'x' 1710 - end 1711 - result = 1712 - if type || type.nil? 1713 - ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] 1714 - elsif result =~ /^Interrupted|^Timeout/ 1715 - ["#{b} #{name}: #{result}"] 1716 - else 1717 - ["#{b} #{name}"] + result.lines.map { |l| " " << l } 1718 - end 1719 - if lnum = where.call(name) 1720 - $curbuf.delete lnum 1721 - lnum = 4 if ing && lnum > maxy 1722 - end 1723 - result.each_with_index do |line, offset| 1724 - $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) 1725 - end 1726 - logh.call 1727 - end 1728 - } 1729 - bt = proc { |cmd, name, type, cleanup| 1730 - tried = timeout = 0 1731 - begin 1732 - tried += 1 1733 - timeout += limit 1734 - fd = nil 1735 - data = '' 1736 - if iswin 1737 - Timeout::timeout(timeout) do 1738 - tmp = VIM::evaluate('tempname()') 1739 - system("(#{cmd}) > #{tmp}") 1740 - data = File.read(tmp).chomp 1741 - File.unlink tmp rescue nil 1742 - end 1743 - else 1744 - fd = IO.popen(cmd).extend(PlugStream) 1745 - first_line = true 1746 - log_prob = 1.0 / nthr 1747 - while line = Timeout::timeout(timeout) { fd.get_line } 1748 - data << line 1749 - log.call name, line.chomp, type if name && (first_line || rand < log_prob) 1750 - first_line = false 1751 - end 1752 - fd.close 1753 - end 1754 - [$? == 0, data.chomp] 1755 - rescue Timeout::Error, Interrupt => e 1756 - if fd && !fd.closed? 1757 - killall fd.pid 1758 - fd.close 1759 - end 1760 - cleanup.call if cleanup 1761 - if e.is_a?(Timeout::Error) && tried < tries 1762 - 3.downto(1) do |countdown| 1763 - s = countdown > 1 ? 's' : '' 1764 - log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type 1765 - sleep 1 1766 - end 1767 - log.call name, 'Retrying ...', type 1768 - retry 1769 - end 1770 - [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] 1771 - end 1772 - } 1773 - main = Thread.current 1774 - threads = [] 1775 - watcher = Thread.new { 1776 - while VIM::evaluate('getchar(1)') 1777 - sleep 0.1 1778 - end 1779 - mtx.synchronize do 1780 - running = false 1781 - threads.each { |t| t.raise Interrupt } 1782 - end 1783 - threads.each { |t| t.join rescue nil } 1784 - main.kill 1785 - } 1786 - refresh = Thread.new { 1787 - while true 1788 - mtx.synchronize do 1789 - break unless running 1790 - VIM::command('noautocmd normal! a') 1791 - end 1792 - sleep 0.2 1793 - end 1794 - } if VIM::evaluate('s:mac_gui') == 1 1795 - 1796 - clone_opt = VIM::evaluate('s:clone_opt') 1797 - progress = VIM::evaluate('s:progress_opt(1)') 1798 - nthr.times do 1799 - mtx.synchronize do 1800 - threads << Thread.new { 1801 - while pair = take1.call 1802 - name = pair.first 1803 - dir, uri, tag = pair.last.values_at *%w[dir uri tag] 1804 - exists = File.directory? dir 1805 - ok, result = 1806 - if exists 1807 - chdir = "#{cd} #{iswin ? dir : esc(dir)}" 1808 - ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil 1809 - current_uri = data.lines.to_a.last 1810 - if !ret 1811 - if data =~ /^Interrupted|^Timeout/ 1812 - [false, data] 1813 - else 1814 - [false, [data.chomp, "PlugClean required."].join($/)] 1815 - end 1816 - elsif current_uri.sub(/git::?@/, '') != uri.sub(/git::?@/, '') 1817 - [false, ["Invalid URI: #{current_uri}", 1818 - "Expected: #{uri}", 1819 - "PlugClean required."].join($/)] 1820 - else 1821 - if pull 1822 - log.call name, 'Updating ...', :update 1823 - fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' 1824 - bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil 1825 - else 1826 - [true, skip] 1827 - end 1828 - end 1829 - else 1830 - d = esc dir.sub(%r{[\\/]+$}, '') 1831 - log.call name, 'Installing ...', :install 1832 - bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { 1833 - FileUtils.rm_rf dir 1834 - } 1835 - end 1836 - mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok 1837 - log.call name, result, ok 1838 - end 1839 - } if running 1840 - end 1841 - end 1842 - threads.each { |t| t.join rescue nil } 1843 - logh.call 1844 - refresh.kill if refresh 1845 - watcher.kill 1846 - EOF 1847 - endfunction 1848 - 1849 - function! s:shellesc(arg) 1850 - return '"'.escape(a:arg, '"').'"' 1851 - endfunction 1852 - 1853 - function! s:glob_dir(path) 1854 - return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') 1855 - endfunction 1856 - 1857 - function! s:progress_bar(line, bar, total) 1858 - call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') 1859 - endfunction 1860 - 1861 - function! s:compare_git_uri(a, b) 1862 - let a = substitute(a:a, 'git:\{1,2}@', '', '') 1863 - let b = substitute(a:b, 'git:\{1,2}@', '', '') 1864 - return a ==# b 1865 - endfunction 1866 - 1867 - function! s:format_message(bullet, name, message) 1868 - if a:bullet != 'x' 1869 - return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] 1870 - else 1871 - let lines = map(s:lines(a:message), '" ".v:val') 1872 - return extend([printf('x %s:', a:name)], lines) 1873 - endif 1874 - endfunction 1875 - 1876 - function! s:with_cd(cmd, dir) 1877 - return printf('cd%s %s && %s', s:is_win ? ' /d' : '', s:shellesc(a:dir), a:cmd) 1878 - endfunction 1879 - 1880 - function! s:system(cmd, ...) 1881 - try 1882 - let [sh, shrd] = s:chsh(1) 1883 - let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd 1884 - return system(s:is_win ? '('.cmd.')' : cmd) 1885 - finally 1886 - let [&shell, &shellredir] = [sh, shrd] 1887 - endtry 1888 - endfunction 1889 - 1890 - function! s:system_chomp(...) 1891 - let ret = call('s:system', a:000) 1892 - return v:shell_error ? '' : substitute(ret, '\n$', '', '') 1893 - endfunction 1894 - 1895 - function! s:git_validate(spec, check_branch) 1896 - let err = '' 1897 - if isdirectory(a:spec.dir) 1898 - let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url', a:spec.dir)) 1899 - let remote = result[-1] 1900 - if v:shell_error 1901 - let err = join([remote, 'PlugClean required.'], "\n") 1902 - elseif !s:compare_git_uri(remote, a:spec.uri) 1903 - let err = join(['Invalid URI: '.remote, 1904 - \ 'Expected: '.a:spec.uri, 1905 - \ 'PlugClean required.'], "\n") 1906 - elseif a:check_branch && has_key(a:spec, 'commit') 1907 - let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir)) 1908 - let sha = result[-1] 1909 - if v:shell_error 1910 - let err = join(add(result, 'PlugClean required.'), "\n") 1911 - elseif !s:hash_match(sha, a:spec.commit) 1912 - let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', 1913 - \ a:spec.commit[:6], sha[:6]), 1914 - \ 'PlugUpdate required.'], "\n") 1915 - endif 1916 - elseif a:check_branch 1917 - let branch = result[0] 1918 - " Check tag 1919 - if has_key(a:spec, 'tag') 1920 - let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) 1921 - if a:spec.tag !=# tag 1922 - let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', 1923 - \ (empty(tag) ? 'N/A' : tag), a:spec.tag) 1924 - endif 1925 - " Check branch 1926 - elseif a:spec.branch !=# branch 1927 - let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', 1928 - \ branch, a:spec.branch) 1929 - endif 1930 - if empty(err) 1931 - let commits = len(s:lines(s:system(printf('git rev-list origin/%s..HEAD', a:spec.branch), a:spec.dir))) 1932 - if !v:shell_error && commits 1933 - let err = join([printf('Diverged from origin/%s by %d commit(s).', a:spec.branch, commits), 1934 - \ 'Reinstall after PlugClean.'], "\n") 1935 - endif 1936 - endif 1937 - endif 1938 - else 1939 - let err = 'Not found' 1940 - endif 1941 - return [err, err =~# 'PlugClean'] 1942 - endfunction 1943 - 1944 - function! s:rm_rf(dir) 1945 - if isdirectory(a:dir) 1946 - call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(a:dir)) 1947 - endif 1948 - endfunction 1949 - 1950 - function! s:clean(force) 1951 - call s:prepare() 1952 - call append(0, 'Searching for invalid plugins in '.g:plug_home) 1953 - call append(1, '') 1954 - 1955 - " List of valid directories 1956 - let dirs = [] 1957 - let errs = {} 1958 - let [cnt, total] = [0, len(g:plugs)] 1959 - for [name, spec] in items(g:plugs) 1960 - if !s:is_managed(name) 1961 - call add(dirs, spec.dir) 1962 - else 1963 - let [err, clean] = s:git_validate(spec, 1) 1964 - if clean 1965 - let errs[spec.dir] = s:lines(err)[0] 1966 - else 1967 - call add(dirs, spec.dir) 1968 - endif 1969 - endif 1970 - let cnt += 1 1971 - call s:progress_bar(2, repeat('=', cnt), total) 1972 - normal! 2G 1973 - redraw 1974 - endfor 1975 - 1976 - let allowed = {} 1977 - for dir in dirs 1978 - let allowed[s:dirpath(fnamemodify(dir, ':h:h'))] = 1 1979 - let allowed[dir] = 1 1980 - for child in s:glob_dir(dir) 1981 - let allowed[child] = 1 1982 - endfor 1983 - endfor 1984 - 1985 - let todo = [] 1986 - let found = sort(s:glob_dir(g:plug_home)) 1987 - while !empty(found) 1988 - let f = remove(found, 0) 1989 - if !has_key(allowed, f) && isdirectory(f) 1990 - call add(todo, f) 1991 - call append(line('$'), '- ' . f) 1992 - if has_key(errs, f) 1993 - call append(line('$'), ' ' . errs[f]) 1994 - endif 1995 - let found = filter(found, 'stridx(v:val, f) != 0') 1996 - end 1997 - endwhile 1998 - 1999 - 4 2000 - redraw 2001 - if empty(todo) 2002 - call append(line('$'), 'Already clean.') 2003 - else 2004 - let s:clean_count = 0 2005 - call append(3, ['Directories to delete:', '']) 2006 - redraw! 2007 - if a:force || s:ask_no_interrupt('Delete all directories?') 2008 - call s:delete([6, line('$')], 1) 2009 - else 2010 - call setline(4, 'Cancelled.') 2011 - nnoremap <silent> <buffer> d :set opfunc=<sid>delete_op<cr>g@ 2012 - nmap <silent> <buffer> dd d_ 2013 - xnoremap <silent> <buffer> d :<c-u>call <sid>delete_op(visualmode(), 1)<cr> 2014 - echo 'Delete the lines (d{motion}) to delete the corresponding directories' 2015 - endif 2016 - endif 2017 - 4 2018 - setlocal nomodifiable 2019 - endfunction 2020 - 2021 - function! s:delete_op(type, ...) 2022 - call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) 2023 - endfunction 2024 - 2025 - function! s:delete(range, force) 2026 - let [l1, l2] = a:range 2027 - let force = a:force 2028 - while l1 <= l2 2029 - let line = getline(l1) 2030 - if line =~ '^- ' && isdirectory(line[2:]) 2031 - execute l1 2032 - redraw! 2033 - let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) 2034 - let force = force || answer > 1 2035 - if answer 2036 - call s:rm_rf(line[2:]) 2037 - setlocal modifiable 2038 - call setline(l1, '~'.line[1:]) 2039 - let s:clean_count += 1 2040 - call setline(4, printf('Removed %d directories.', s:clean_count)) 2041 - setlocal nomodifiable 2042 - endif 2043 - endif 2044 - let l1 += 1 2045 - endwhile 2046 - endfunction 2047 - 2048 - function! s:upgrade() 2049 - echo 'Downloading the latest version of vim-plug' 2050 - redraw 2051 - let tmp = tempname() 2052 - let new = tmp . '/plug.vim' 2053 - 2054 - try 2055 - let out = s:system(printf('git clone --depth 1 %s %s', s:plug_src, tmp)) 2056 - if v:shell_error 2057 - return s:err('Error upgrading vim-plug: '. out) 2058 - endif 2059 - 2060 - if readfile(s:me) ==# readfile(new) 2061 - echo 'vim-plug is already up-to-date' 2062 - return 0 2063 - else 2064 - call rename(s:me, s:me . '.old') 2065 - call rename(new, s:me) 2066 - unlet g:loaded_plug 2067 - echo 'vim-plug has been upgraded' 2068 - return 1 2069 - endif 2070 - finally 2071 - silent! call s:rm_rf(tmp) 2072 - endtry 2073 - endfunction 2074 - 2075 - function! s:upgrade_specs() 2076 - for spec in values(g:plugs) 2077 - let spec.frozen = get(spec, 'frozen', 0) 2078 - endfor 2079 - endfunction 2080 - 2081 - function! s:status() 2082 - call s:prepare() 2083 - call append(0, 'Checking plugins') 2084 - call append(1, '') 2085 - 2086 - let ecnt = 0 2087 - let unloaded = 0 2088 - let [cnt, total] = [0, len(g:plugs)] 2089 - for [name, spec] in items(g:plugs) 2090 - if has_key(spec, 'uri') 2091 - if isdirectory(spec.dir) 2092 - let [err, _] = s:git_validate(spec, 1) 2093 - let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] 2094 - else 2095 - let [valid, msg] = [0, 'Not found. Try PlugInstall.'] 2096 - endif 2097 - else 2098 - if isdirectory(spec.dir) 2099 - let [valid, msg] = [1, 'OK'] 2100 - else 2101 - let [valid, msg] = [0, 'Not found.'] 2102 - endif 2103 - endif 2104 - let cnt += 1 2105 - let ecnt += !valid 2106 - " `s:loaded` entry can be missing if PlugUpgraded 2107 - if valid && get(s:loaded, name, -1) == 0 2108 - let unloaded = 1 2109 - let msg .= ' (not loaded)' 2110 - endif 2111 - call s:progress_bar(2, repeat('=', cnt), total) 2112 - call append(3, s:format_message(valid ? '-' : 'x', name, msg)) 2113 - normal! 2G 2114 - redraw 2115 - endfor 2116 - call setline(1, 'Finished. '.ecnt.' error(s).') 2117 - normal! gg 2118 - setlocal nomodifiable 2119 - if unloaded 2120 - echo "Press 'L' on each line to load plugin, or 'U' to update" 2121 - nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr> 2122 - xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr> 2123 - end 2124 - endfunction 2125 - 2126 - function! s:extract_name(str, prefix, suffix) 2127 - return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') 2128 - endfunction 2129 - 2130 - function! s:status_load(lnum) 2131 - let line = getline(a:lnum) 2132 - let name = s:extract_name(line, '-', '(not loaded)') 2133 - if !empty(name) 2134 - call plug#load(name) 2135 - setlocal modifiable 2136 - call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) 2137 - setlocal nomodifiable 2138 - endif 2139 - endfunction 2140 - 2141 - function! s:status_update() range 2142 - let lines = getline(a:firstline, a:lastline) 2143 - let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') 2144 - if !empty(names) 2145 - echo 2146 - execute 'PlugUpdate' join(names) 2147 - endif 2148 - endfunction 2149 - 2150 - function! s:is_preview_window_open() 2151 - silent! wincmd P 2152 - if &previewwindow 2153 - wincmd p 2154 - return 1 2155 - endif 2156 - endfunction 2157 - 2158 - function! s:find_name(lnum) 2159 - for lnum in reverse(range(1, a:lnum)) 2160 - let line = getline(lnum) 2161 - if empty(line) 2162 - return '' 2163 - endif 2164 - let name = s:extract_name(line, '-', '') 2165 - if !empty(name) 2166 - return name 2167 - endif 2168 - endfor 2169 - return '' 2170 - endfunction 2171 - 2172 - function! s:preview_commit() 2173 - if b:plug_preview < 0 2174 - let b:plug_preview = !s:is_preview_window_open() 2175 - endif 2176 - 2177 - let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7}') 2178 - if empty(sha) 2179 - return 2180 - endif 2181 - 2182 - let name = s:find_name(line('.')) 2183 - if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) 2184 - return 2185 - endif 2186 - 2187 - if exists('g:plug_pwindow') && !s:is_preview_window_open() 2188 - execute g:plug_pwindow 2189 - execute 'e' sha 2190 - else 2191 - execute 'pedit' sha 2192 - wincmd P 2193 - endif 2194 - setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable 2195 - execute 'silent %!cd' s:shellesc(g:plugs[name].dir) '&& git show --no-color --pretty=medium' sha 2196 - setlocal nomodifiable 2197 - nnoremap <silent> <buffer> q :q<cr> 2198 - wincmd p 2199 - endfunction 2200 - 2201 - function! s:section(flags) 2202 - call search('\(^[x-] \)\@<=[^:]\+:', a:flags) 2203 - endfunction 2204 - 2205 - function! s:format_git_log(line) 2206 - let indent = ' ' 2207 - let tokens = split(a:line, nr2char(1)) 2208 - if len(tokens) != 5 2209 - return indent.substitute(a:line, '\s*$', '', '') 2210 - endif 2211 - let [graph, sha, refs, subject, date] = tokens 2212 - let tag = matchstr(refs, 'tag: [^,)]\+') 2213 - let tag = empty(tag) ? ' ' : ' ('.tag.') ' 2214 - return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) 2215 - endfunction 2216 - 2217 - function! s:append_ul(lnum, text) 2218 - call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) 2219 - endfunction 2220 - 2221 - function! s:diff() 2222 - call s:prepare() 2223 - call append(0, ['Collecting changes ...', '']) 2224 - let cnts = [0, 0] 2225 - let bar = '' 2226 - let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') 2227 - call s:progress_bar(2, bar, len(total)) 2228 - for origin in [1, 0] 2229 - let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) 2230 - if empty(plugs) 2231 - continue 2232 - endif 2233 - call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') 2234 - for [k, v] in plugs 2235 - let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..' 2236 - let diff = s:system_chomp('git log --graph --color=never --pretty=format:"%x01%h%x01%d%x01%s%x01%cr" '.s:shellesc(range), v.dir) 2237 - if !empty(diff) 2238 - let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' 2239 - call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) 2240 - let cnts[origin] += 1 2241 - endif 2242 - let bar .= '=' 2243 - call s:progress_bar(2, bar, len(total)) 2244 - normal! 2G 2245 - redraw 2246 - endfor 2247 - if !cnts[origin] 2248 - call append(5, ['', 'N/A']) 2249 - endif 2250 - endfor 2251 - call setline(1, printf('%d plugin(s) updated.', cnts[0]) 2252 - \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) 2253 - 2254 - if cnts[0] || cnts[1] 2255 - nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr> 2256 - nnoremap <silent> <buffer> o :silent! call <SID>preview_commit()<cr> 2257 - endif 2258 - if cnts[0] 2259 - nnoremap <silent> <buffer> X :call <SID>revert()<cr> 2260 - echo "Press 'X' on each block to revert the update" 2261 - endif 2262 - normal! gg 2263 - setlocal nomodifiable 2264 - endfunction 2265 - 2266 - function! s:revert() 2267 - if search('^Pending updates', 'bnW') 2268 - return 2269 - endif 2270 - 2271 - let name = s:find_name(line('.')) 2272 - if empty(name) || !has_key(g:plugs, name) || 2273 - \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' 2274 - return 2275 - endif 2276 - 2277 - call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch), g:plugs[name].dir) 2278 - setlocal modifiable 2279 - normal! "_dap 2280 - setlocal nomodifiable 2281 - echo 'Reverted' 2282 - endfunction 2283 - 2284 - function! s:snapshot(force, ...) abort 2285 - call s:prepare() 2286 - setf vim 2287 - call append(0, ['" Generated by vim-plug', 2288 - \ '" '.strftime("%c"), 2289 - \ '" :source this file in vim to restore the snapshot', 2290 - \ '" or execute: vim -S snapshot.vim', 2291 - \ '', '', 'PlugUpdate!']) 2292 - 1 2293 - let anchor = line('$') - 3 2294 - let names = sort(keys(filter(copy(g:plugs), 2295 - \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) 2296 - for name in reverse(names) 2297 - let sha = s:system_chomp('git rev-parse --short HEAD', g:plugs[name].dir) 2298 - if !empty(sha) 2299 - call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) 2300 - redraw 2301 - endif 2302 - endfor 2303 - 2304 - if a:0 > 0 2305 - let fn = expand(a:1) 2306 - if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) 2307 - return 2308 - endif 2309 - call writefile(getline(1, '$'), fn) 2310 - echo 'Saved as '.a:1 2311 - silent execute 'e' s:esc(fn) 2312 - setf vim 2313 - endif 2314 - endfunction 2315 - 2316 - function! s:split_rtp() 2317 - return split(&rtp, '\\\@<!,') 2318 - endfunction 2319 - 2320 - let s:first_rtp = s:escrtp(get(s:split_rtp(), 0, '')) 2321 - let s:last_rtp = s:escrtp(get(s:split_rtp(), -1, '')) 2322 - 2323 - if exists('g:plugs') 2324 - let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs)) 2325 - call s:upgrade_specs() 2326 - call s:define_commands() 2327 - endif 2328 - 2329 - let &cpo = s:cpo_save 2330 - unlet s:cpo_save
+7
nvim/init.vim
··· 4 4 let $EDITOR="nvr" 5 5 6 6 " Plugins {{{ 7 + let s:plugins = filereadable(expand("~/.config/nvim/autoload/plug.vim", 1)) 8 + if !s:plugins 9 + silent call mkdir(expand("~/.config/nvim/autoload", 1), 'p') 10 + exe '!curl -fLo '.expand("~/.config/nvim/autoload/plug.vim", 1) 11 + \ .' https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' 12 + endif 13 + 7 14 call plug#begin('~/.local/nvim/plugins') 8 15 9 16 " Visual