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