├── .gitignore ├── after ├── ftplugin │ └── javascript.vim ├── test │ └── a.js └── autoload │ ├── update-nodejs-doc.js │ ├── nodejscomplete.vim │ └── nodejs-doc.vim ├── screenshot └── screenshot-1.jpg ├── vimconfig ├── plugins │ ├── incsearch.vim │ ├── gitgutter.vim │ ├── nerdcommenter.vim │ ├── flake8.vim │ ├── indentLine.vim │ ├── ctrlp.vim │ ├── deoplete.vim │ ├── vim-go.vim │ ├── syntastic.vim │ ├── nerdtree.vim │ └── airline.vim ├── keymap.vim └── general.vim ├── plug-snapshot ├── vimrc ├── readme.md ├── colors └── molokai.vim └── autoload └── plug.vim.old /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .DS_Store 3 | .netrwhist 4 | undodir/** 5 | bundle/** 6 | plugged/** 7 | -------------------------------------------------------------------------------- /after/ftplugin/javascript.vim: -------------------------------------------------------------------------------- 1 | if exists('&ofu') 2 | setlocal omnifunc=nodejscomplete#CompleteJS 3 | endif 4 | -------------------------------------------------------------------------------- /screenshot/screenshot-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SSARCandy/ssarcandy-vim/HEAD/screenshot/screenshot-1.jpg -------------------------------------------------------------------------------- /vimconfig/plugins/incsearch.vim: -------------------------------------------------------------------------------- 1 | " --------------- incsearch ---------------- 2 | map / (incsearch-forward) 3 | -------------------------------------------------------------------------------- /vimconfig/plugins/gitgutter.vim: -------------------------------------------------------------------------------- 1 | " -------------- gitgutter --------------- 2 | let g:gitgutter_max_signs = 1000 " default value" 3 | -------------------------------------------------------------------------------- /vimconfig/plugins/nerdcommenter.vim: -------------------------------------------------------------------------------- 1 | " ----------- NERDcommenter 2 | " Toggle comments (NERDcommenter) 3 | nmap \c 4 | vmap \c 5 | imap \c 6 | -------------------------------------------------------------------------------- /vimconfig/plugins/flake8.vim: -------------------------------------------------------------------------------- 1 | " ------------- flake8 ------------------------ 2 | let g:PyFlakeCheckers = 'pep8,mccabe,frosted' 3 | let g:PyFlakeOnWrite = 1 4 | let g:PyFlakeSigns = 1 5 | let g:PyFlakeMaxLineLength = 200 -------------------------------------------------------------------------------- /vimconfig/plugins/indentLine.vim: -------------------------------------------------------------------------------- 1 | 2 | 3 | " --------------- indentLine -------------- 4 | let g:indentLine_color_term = 239 " Vim 5 | let g:indentLine_color_gui = '#6e6e6e' " GVim 6 | " none X terminal 7 | let g:indentLine_color_tty_light = 7 " (default: 4) 8 | let g:indentLine_color_dark = 1 " (default: 2) 9 | let g:indentLine_char = '|' 10 | 11 | 12 | -------------------------------------------------------------------------------- /vimconfig/plugins/ctrlp.vim: -------------------------------------------------------------------------------- 1 | " -------------- ctrlp.vim ---------------- 2 | set wildignore+=*/tmp/*,*.so,*.swp,*.zip " MacOSX/Linux 3 | set wildignore+=*\\tmp\\*,*.swp,*.zip,*.exe " Windows 4 | 5 | let g:ctrlp_custom_ignore = { 6 | \ 'dir': '\v[\/](\.git|\.hg|\.svn|node_modules)$', 7 | \ 'file': '\v\.(exe|so|dll)$', 8 | \ 'link': 'some_bad_symbolic_links', 9 | \ } 10 | -------------------------------------------------------------------------------- /vimconfig/plugins/deoplete.vim: -------------------------------------------------------------------------------- 1 | " -------------- deoplete --------------- 2 | "Note: This option must set it in .vimrc(_vimrc). NOT IN .gvimrc(_gvimrc)! 3 | 4 | let g:deoplete#enable_yarp = 1 5 | let g:deoplete#enable_at_startup = 1 6 | let g:deoplete#file#enable_buffer_path=1 7 | 8 | " deoplete tab-complete 9 | inoremap pumvisible() ? "\" : "\" 10 | 11 | autocmd InsertEnter * call deoplete#enable() 12 | 13 | 14 | "call deoplete#enable() 15 | 16 | -------------------------------------------------------------------------------- /vimconfig/plugins/vim-go.vim: -------------------------------------------------------------------------------- 1 | " --------------- vim-go ------------------- 2 | au FileType go nmap r (go-run) 3 | au FileType go nmap b (go-build) 4 | au FileType go nmap t (go-test) 5 | au FileType go nmap c (go-coverage) 6 | au FileType go nmap ds (go-def-split) 7 | au FileType go nmap dv (go-def-vertical) 8 | au FileType go nmap dt (go-def-tab) 9 | au FileType go nmap gb (go-doc-browser) 10 | let g:go_fmt_autosave = 0 11 | 12 | -------------------------------------------------------------------------------- /vimconfig/plugins/syntastic.vim: -------------------------------------------------------------------------------- 1 | " -------------- syntastic -------------- 2 | set statusline+=%#warningmsg# 3 | set statusline+=%{SyntasticStatuslineFlag()} 4 | set statusline+=%* 5 | let g:syntastic_always_populate_loc_list = 1 6 | let g:syntastic_auto_loc_list = 0 7 | let g:syntastic_check_on_open = 0 8 | let g:syntastic_check_on_wq = 0 9 | let Tlist_Ctags_Cmd="/usr/local/Cellar/ctags/5.8_1/bin/ctags" 10 | let Tlist_Auto_Update = 1 11 | let Tlist_Use_Right_Window=1 12 | let g:syntastic_javascript_checkers = ['eslint'] " StrTrim(system('npm-which eslint')) 13 | 14 | 15 | -------------------------------------------------------------------------------- /vimconfig/plugins/nerdtree.vim: -------------------------------------------------------------------------------- 1 | " --------------- NERDTree ---------------- 2 | " Toggle NERDTree 3 | nmap :NERDTreeToggle 4 | 5 | autocmd StdinReadPre * let s:std_in=1 6 | autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif 7 | autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif 8 | "let NERDTreeShowHidden=1 9 | let NERDTreeMinimalUI = 1 " NERDTree 子窗口中不顯示冗餘幫助信息 10 | let NERDTreeAutoDeleteBuffer = 1 " 刪除文件時自動刪除文件對應buffer 11 | let NERDTreeQuitOnOpen = 0 " don't auto-quit nerdtree when open file 12 | -------------------------------------------------------------------------------- /vimconfig/keymap.vim: -------------------------------------------------------------------------------- 1 | " ====================== 2 | " == Key-map Settings == 3 | " ====================== 4 | 5 | " toggle fold-code at cursor 6 | nnoremap zz za 7 | 8 | " remap ZZ to save & close tab(buffer) 9 | nmap ZZ :update:Bd 10 | 11 | " remap \x to close split window 12 | nmap x :q 13 | 14 | " Save file 15 | nmap s :update 16 | 17 | " compile project (must have Makefile in current dir) 18 | nmap m :!rm -rf main:wa:make:cw 19 | 20 | 21 | 22 | " Open on github 23 | nnoremap o :!echo `git url`/blob/`git rev-parse --abbrev-ref HEAD`/%\#L=line('.') \| xargs open 24 | 25 | -------------------------------------------------------------------------------- /vimconfig/plugins/airline.vim: -------------------------------------------------------------------------------- 1 | " -------------- airline --------------- 2 | let g:airline_theme ='wombat' 3 | let g:airline#extensions#whitespace#enabled = 0 " disable whitespace warning 4 | let g:airline_section_x = '%{strftime("%m/%d %H:%M")}%' " show time at section x 5 | let g:airline#extensions#tabline#enabled = 1 " enable tabline 6 | let g:airline#extensions#tabline#left_sep = ' ' " set left separator 7 | let g:airline#extensions#tabline#left_alt_sep = '|' " set left separator which are not editting 8 | let g:airline#extensions#tabline#buffer_nr_show = 0 " show buffer number 9 | let g:airline#extensions#tabline#fnamemod = ':t' " set airline#tabline show only filename 10 | let g:airline_powerline_fonts = 1 " enable powerline-fonts 11 | set laststatus=2 " set status line 12 | set guifont=Literation_Mono_Powerline:h14 " enable powerline-fonts for macVim 13 | 14 | " air-line buffer switcher shortcut 15 | nmap :bn! 16 | nmap ` :bp! 17 | nmap d :Bd 18 | 19 | -------------------------------------------------------------------------------- /after/test/a.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | 4 | fs 5 | fs. 6 | fs.read 7 | fs[ 8 | fs[" 9 | fs['chmodSync']( 10 | 11 | 12 | 13 | var a = {hello: 'world'}, 14 | b = require('path'), 15 | // b = new A, 16 | // b = a; 17 | 18 | 19 | b. 20 | 21 | 22 | var emitter = new (require('events')).EventEmitter; 23 | emitter. 24 | 25 | var events = require('events'); 26 | var emitter = new events.EventEmitter(); 27 | var buffer = new Buffer; 28 | // var buffer = new global.Buffer; 29 | var tester = new A.B.C(); 30 | 31 | emitter. 32 | buffer. 33 | tester. 34 | events. 35 | 36 | 37 | cons 38 | 39 | 40 | 41 | { 42 | "globals": { 43 | "Buffer": { 44 | "classes": [ 45 | { 46 | ".self": [ 47 | { 48 | "word": "write", 49 | "info": "buf.write(string, [offset], [length], [encoding])", 50 | "kind": "f" 51 | } 52 | ] 53 | } 54 | ], 55 | "protos": [ 56 | ] 57 | } 58 | }, 59 | "modules": { 60 | "events" { 61 | "classes": [ 62 | ], 63 | "protos": [ 64 | ] 65 | } 66 | }, 67 | "vars": [ 68 | { 69 | "word": "__dirname", 70 | "kind": "v" 71 | } 72 | ] 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /plug-snapshot: -------------------------------------------------------------------------------- 1 | " Generated by vim-plug 2 | " Sat 24 Oct 2020 12:13:36 PM UTC 3 | " :source this file in vim to restore the snapshot 4 | " or execute: vim -S snapshot.vim 5 | 6 | silent! let g:plugs['ack.vim'].commit = 'eede042' 7 | silent! let g:plugs['ctrlp.vim'].commit = '7fa89fe' 8 | silent! let g:plugs['delimitMate'].commit = 'b571905' 9 | silent! let g:plugs['es.next.syntax.vim'].commit = '86ddf3c' 10 | silent! let g:plugs['flake8-vim'].commit = '96219c1' 11 | silent! let g:plugs['incsearch.vim'].commit = '213994f' 12 | silent! let g:plugs['indentLine'].commit = '942fea0' 13 | silent! let g:plugs['jedi-vim'].commit = '0dea756' 14 | silent! let g:plugs['neocomplete.vim'].commit = '9617d82' 15 | silent! let g:plugs['nerdcommenter'].commit = '6072532' 16 | silent! let g:plugs['nerdtree'].commit = '2817010' 17 | silent! let g:plugs['nerdtree-execute'].commit = '4e39f01' 18 | silent! let g:plugs['syntastic'].commit = '2124af8' 19 | silent! let g:plugs['tabular'].commit = '00e1e7f' 20 | silent! let g:plugs['taglist.vim'].commit = '53041fb' 21 | silent! let g:plugs['vim-airline'].commit = '7df411d' 22 | silent! let g:plugs['vim-airline-themes'].commit = '6026eb7' 23 | silent! let g:plugs['vim-autoformat'].commit = '92e9577' 24 | silent! let g:plugs['vim-bbye'].commit = 'a018cbc' 25 | silent! let g:plugs['vim-css-color'].commit = '417eaf8' 26 | silent! let g:plugs['vim-gitgutter'].commit = '77aa7ea' 27 | silent! let g:plugs['vim-go'].commit = '1425dec' 28 | silent! let g:plugs['vim-javascript'].commit = '871ab29' 29 | silent! let g:plugs['vim-jsx'].commit = 'eb656ed' 30 | silent! let g:plugs['vim-multiple-cursors'].commit = '51d0717' 31 | silent! let g:plugs['vim-nodejs-complete'].commit = '1e2f98f' 32 | silent! let g:plugs['vim-sleuth'].commit = '62c4f26' 33 | silent! let g:plugs['vim-snippets'].commit = '48b81d3' 34 | silent! let g:plugs['vimcdoc-tw'].commit = 'e18a899' 35 | silent! let g:plugs['yajs.vim'].commit = 'f9cfbe6' 36 | 37 | PlugUpdate! 38 | 39 | -------------------------------------------------------------------------------- /vimrc: -------------------------------------------------------------------------------- 1 | " =========================== 2 | " == vim config file == 3 | " == Created by SSARCandy == 4 | " =========================== 5 | 6 | call plug#begin('~/.vim/plugged') 7 | 8 | Plug 'mileszs/ack.vim' 9 | Plug 'moll/vim-bbye' 10 | Plug 'ctrlpvim/ctrlp.vim' 11 | Plug 'Raimondi/delimitMate' 12 | Plug 'othree/es.next.syntax.vim', {'for': ['js', 'javascript']} 13 | Plug 'haya14busa/incsearch.vim' 14 | Plug 'Yggdroot/indentLine' 15 | Plug 'scrooloose/nerdcommenter' 16 | Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } 17 | Plug 'scrooloose/syntastic' 18 | Plug 'godlygeek/tabular' 19 | Plug 'vim-scripts/taglist.vim', {'for': ['cpp', 'hpp', 'h', 'c']} 20 | Plug 'vim-airline/vim-airline' 21 | Plug 'vim-airline/vim-airline-themes' 22 | Plug 'Chiel92/vim-autoformat' 23 | Plug 'skammer/vim-css-color', {'for': ['css', 'less', 'sass']} 24 | Plug 'airblade/vim-gitgutter' 25 | Plug 'fatih/vim-go', {'for': ['go']} 26 | Plug 'pangloss/vim-javascript', {'for': ['js', 'javascript']} 27 | Plug 'terryma/vim-multiple-cursors' 28 | Plug 'myhere/vim-nodejs-complete', {'for': ['js', 'javascript']} 29 | Plug 'tpope/vim-sleuth' 30 | Plug 'honza/vim-snippets' 31 | Plug 'othree/yajs.vim' 32 | Plug 'ivalkeen/nerdtree-execute' 33 | Plug 'davidhalter/jedi-vim', {'for': ['py']} 34 | Plug 'andviro/flake8-vim', {'for': ['py']} 35 | Plug 'vim-tw/vimcdoc-tw' 36 | 37 | " deoplete related plugins 38 | Plug 'Shougo/deoplete.nvim' 39 | Plug 'roxma/nvim-yarp' 40 | Plug 'roxma/vim-hug-neovim-rpc' 41 | 42 | call plug#end() 43 | 44 | 45 | " == General Settings 46 | source ~/.vim/vimconfig/general.vim 47 | 48 | " == Key-map Settings 49 | source ~/.vim/vimconfig/keymap.vim 50 | 51 | " == Custom Settings of plugins 52 | source ~/.vim/vimconfig/plugins/airline.vim 53 | source ~/.vim/vimconfig/plugins/ctrlp.vim 54 | source ~/.vim/vimconfig/plugins/flake8.vim 55 | source ~/.vim/vimconfig/plugins/gitgutter.vim 56 | source ~/.vim/vimconfig/plugins/incsearch.vim 57 | source ~/.vim/vimconfig/plugins/indentLine.vim 58 | source ~/.vim/vimconfig/plugins/deoplete.vim 59 | source ~/.vim/vimconfig/plugins/nerdcommenter.vim 60 | source ~/.vim/vimconfig/plugins/nerdtree.vim 61 | source ~/.vim/vimconfig/plugins/syntastic.vim 62 | source ~/.vim/vimconfig/plugins/vim-go.vim 63 | -------------------------------------------------------------------------------- /vimconfig/general.vim: -------------------------------------------------------------------------------- 1 | " ====================== 2 | " == General Settings == 3 | " ====================== 4 | 5 | " --- General setting --- 6 | set shell=bash\ -i 7 | set nocompatible 8 | set secure 9 | set fileencodings=utf-8,cp936,big5,latin1 10 | set encoding=utf-8 11 | set helplang=tw " zh-tw for vim doc 12 | set viminfo='20,\"50 " Read/write a .viminfo file, don't store more than 50 lines of registers 13 | set history=50 " Keep 50 lines of command line history 14 | 15 | 16 | " --- Theme/apperance --- 17 | colorscheme molokai " Theme 18 | set background=dark " Theme background 19 | set cursorline " Highlight current line ('cursorcolumn' for highlight current column 20 | set showmode " Show current mode 21 | set incsearch " While typing a search pattern, show immediately where the so far typed pattern matches. 22 | set hlsearch " When there is a previous search pattern, highlight all its matches. 23 | set ruler " Show the cursor position all the time 24 | set list lcs=tab:\|\ " Indent hint with hard-tab" 25 | set showcmd " Show command 26 | set nowrap " No word-warp 27 | set nu 28 | set concealcursor= 29 | set guifont=Monaco:h14 30 | set showmatch 31 | syntax on 32 | highlight Comment ctermfg=DarkCyan 33 | highlight SpecialKey ctermfg=Yellow 34 | 35 | 36 | " --- Hide scrollbar --- 37 | set guioptions-=l 38 | set guioptions-=L 39 | set guioptions-=r 40 | set guioptions-=R 41 | 42 | 43 | " --- Editing setting --- 44 | set autoindent 45 | set noeol 46 | set backspace=2 " Allow backspacing over everything in insert mode 47 | set wildchar= " Such as in shell 48 | set smarttab 49 | set tabstop=4 50 | set shiftwidth=4 51 | set expandtab 52 | set mouse=a 53 | 54 | 55 | " --- Code fold setting --- 56 | set nofoldenable " Don't fold code on start 57 | set foldmethod=indent " Code fold method (INDENT or SYNTAX) 58 | set foldcolumn=1 59 | set foldnestmax=3 60 | 61 | 62 | filetype plugin indent on 63 | 64 | autocmd FileType python setlocal completeopt-=preview " Disable doc window in python 65 | autocmd FileType c,cpp,cc,java call C_family() 66 | autocmd FileType make setlocal noexpandtab 67 | 68 | au BufNewFile, BufRead *.ejs set filetype=html " treat *.ejs as html 69 | 70 | function C_family() 71 | set nosmartindent 72 | set cindent comments=sr:/*,mb:*,el:*/,:// cino=>s,e0,n0,f0,{0,}0,^-1s,:0,=s,g0,h1s,p2,t0,+2,(2,)20,*30 73 | set cinoptions=t0 74 | set formatoptions=tcqr 75 | let Tlist_Auto_Open=1 76 | 77 | " Autoformat triggered when ; } is typed. 78 | imap } }:Autoformat/}:let @/ = ""i 79 | 80 | nmap :Tlist 81 | endfunction 82 | 83 | 84 | 85 | " --- Presistent_undo --- 86 | " Put plugins and dictionaries in this dir (also on Windows) 87 | let vimDir = '$HOME/.vim' 88 | let &runtimepath.=','.vimDir 89 | 90 | " Keep undo history across sessions by storing it in a file 91 | if has('persistent_undo') 92 | let myUndoDir = expand(vimDir . '/undodir') 93 | call system('mkdir ' . vimDir) " Create dirs 94 | call system('mkdir ' . myUndoDir) " Create undo dir 95 | let &undodir = myUndoDir 96 | set undofile 97 | endif 98 | 99 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ssarcandy-vim 2 | 3 | My vim settings and plugins, compatible with [MacVim](http://macvim-dev.github.io/macvim/) in OSX. Requires vim 8.1+ 4 | 5 | ## Install 6 | 7 | I use [vim-plug](https://github.com/junegunn/vim-plug) for plugin managment. 8 | Installation is simple, just do following command in terminal: 9 | 10 | ```bash 11 | # Make sure that .vim/ isn't exist in your home dir 12 | $ git clone https://github.com/SSARCandy/ssarcandy-vim.git ~/.vim 13 | 14 | # Make soft link .vim/vimrc to ~/.vimrc 15 | $ ln -s .vim/vimrc ~/.vimrc 16 | 17 | # Install plugins 18 | $ vim -S ~/.vim/plug-snapshot 19 | ``` 20 | 21 | ## Screenshots 22 | ![](https://raw.githubusercontent.com/SSARCandy/ssarcandy-vim/master/screenshot/screenshot-1.jpg) 23 | 24 | ## Common problems 25 | 26 | - Q: airline glyphs cannot show normally. 27 | - A: see instruction of [airline fonts](https://github.com/vim-airline/vim-airline#integrating-with-powerline-fonts) 28 | - Q: neocomplete says need Lua supports 29 | - A: see [neocomplete README](https://github.com/Shougo/neocomplete.vim#requirements) 30 | - Q: ack.vim didn't work. 31 | - A: ack.vim required [ack](http://beyondgrep.com/install/) installed. 32 | - Q: vim-go not working 33 | - A: see vim-go [readme](https://github.com/fatih/vim-go#install) 34 | 35 | ## Plugin list 36 | 37 | - [mileszs/ack.vim](https://github.com/mileszs/ack.vim) 38 | - [moll/vim-bbye](https://github.com/moll/vim-bbye) 39 | - [ctrlpvim/ctrlp.vim](https://github.com/ctrlpvim/ctrlp.vim) 40 | - [Raimondi/delimitMate](https://github.com/Raimondi/delimitMate) 41 | - [othree/es.next.syntax.vim](https://github.com/othree/es.next.syntax.vim) 42 | - [haya14busa/incsearch.vim](https://github.com/haya14busa/incsearch.vim) 43 | - [Yggdroot/indentLine](https://github.com/Yggdroot/indentLine) 44 | - [Shougo/neocomplete.vim](https://github.com/Shougo/neocomplete.vim) 45 | - [scrooloose/nerdcommenter](https://github.com/scrooloose/nerdcommenter) 46 | - [scrooloose/nerdtree](https://github.com/scrooloose/nerdtree) 47 | - [scrooloose/syntastic](https://github.com/scrooloose/syntastic) 48 | - [godlygeek/tabular](https://github.com/godlygeek/tabular) 49 | - [vim-scripts/taglist.vim](https://github.com/vim-scripts/taglist.vim) 50 | - [vim-airline/vim-airline](https://github.com/vim-airline/vim-airline) 51 | - [vim-airline/vim-airline-themes](https://github.com/vim-airline/vim-airline-themes) 52 | - [Chiel92/vim-autoformat](https://github.com/Chiel92/vim-autoformat) 53 | - [skammer/vim-css-color](https://github.com/skammer/vim-css-color) 54 | - [airblade/vim-gitgutter](https://github.com/airblade/vim-gitgutter) 55 | - [fatih/vim-go](https://github.com/fatih/vim-go) 56 | - [pangloss/vim-javascript](https://github.com/pangloss/vim-javascript) 57 | - [mxw/vim-jsx](https://github.com/mxw/vim-jsx) 58 | - [terryma/vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors) 59 | - [myhere/vim-nodejs-complete](https://github.com/myhere/vim-nodejs-complete) 60 | - [tpope/vim-sleuth](https://github.com/tpope/vim-sleuth) 61 | - [honza/vim-snippets](https://github.com/honza/vim-snippets) 62 | - [othree/yajs.vim](https://github.com/othree/yajs.vim) 63 | - [chrisbra/csv.vim](https://github.com/chrisbra/csv.vim) 64 | - [ivalkeen/nerdtree-execute](https://github.com/ivalkeen/nerdtree-execute) 65 | - [davidhalter/jedi-vim](https://github.com/davidhalter/jedi-vim) 66 | - [andviro/flake8-vim](https://github.com/andviro/flake8-vim) 67 | - [sheerun/vim-polyglot](https://github.com/sheerun/vim-polyglot) 68 | - [vim-tw/vimcdoc-tw](https://github.com/vim-tw/vimcdoc-tw) 69 | 70 | ## Shortcuts 71 | 72 | | keys | mode | functions | note | 73 | |--------------|----------------|--------------------------|----------------------------------| 74 | |`\s` |NORMAL |save file (update) | | 75 | |`Tab` |NORMAL |goto next tab file | | 76 | |`` ` `` |NORMAL |goto previous tab file | | 77 | |`\d` |NORMAL |close current tab | will warning without saving | 78 | |`\x` |NORMAL |close current window | | 79 | |`ctrl + l` |NORMAL/INSERT |Toggle comments | | 80 | |`ctrl + m` |NORMAL |open NERDtree | | 81 | |`ctrl + ww` |NORMAL |switching windows | | 82 | | `\m` |NORMAL |compile | must have Makefile at current dir| 83 | | `:!./a.out` |NORMAL |execute | a.out is exe name | 84 | |`ctrl + t` |NORMAL |open Taglist | for c/cpp only | 85 | |`ctrl + p` |NORMAL |search file in working dir| | 86 | |`=` |NORMAL |align `=` and `:` | for js file only | 87 | |`q` |ERROR LIST |close jshint error list | for js file only | 88 | |`F9` |NORMAL/INSERT |show jshint next error | for js file only | 89 | |`F7` |NORMAL/INSERT |show jshint previous error| for js file only | 90 | 91 | -------------------------------------------------------------------------------- /after/autoload/update-nodejs-doc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * @author: Lin Zhang ( myhere.2009 AT gmail DOT com ) 5 | * @fileoverview: This script for auto-generate nodejs-doc.vim 6 | */ 7 | 8 | var util = require('util'), 9 | fs = require('fs'), 10 | path = require('path'), 11 | os = require('os'), 12 | emitter = new (require('events')).EventEmitter(); 13 | 14 | init(); 15 | 16 | function init() { 17 | initEvents(); 18 | 19 | initLoading(); 20 | 21 | getNodejsDoc(); 22 | } 23 | 24 | function initEvents() { 25 | // uncatched exception 26 | process.on('uncaughtException', function(err) { 27 | clearLoading(); 28 | 29 | console.error('Error: ' + err.stack); 30 | }); 31 | 32 | emitter.on('vimscript/done', function(message) { 33 | clearLoading(); 34 | console.log(message); 35 | console.log('Done!'); 36 | }); 37 | } 38 | 39 | function initLoading() { 40 | var chars = [ 41 | '-', 42 | '\\', 43 | '|', 44 | '/' 45 | ]; 46 | 47 | var index = 0, 48 | total = chars.length; 49 | 50 | initLoading.timer = setInterval(function() { 51 | index = ++index % total; 52 | 53 | var c = chars[index]; 54 | 55 | // clear console 56 | // @see: https://groups.google.com/forum/?fromgroups#!topic/nodejs/i-oqYFVty5I 57 | process.stdout.write('\033[2J\033[0;0H'); 58 | console.log('please wait:'); 59 | console.log(c); 60 | }, 200); 61 | } 62 | function clearLoading() { 63 | clearInterval(initLoading.timer); 64 | } 65 | 66 | function getNodejsDoc() { 67 | var http = require('http'); 68 | 69 | var req = http.get('http://nodejs.org/api/all.json', function(res){ 70 | var chunks = []; 71 | 72 | res.on('data', function(chunk) { 73 | chunks.push(chunk); 74 | }); 75 | 76 | res.on('end', function() { 77 | var buf = Buffer.concat(chunks), 78 | body = buf.toString('utf-8'); 79 | 80 | extract2VimScript(body); 81 | }); 82 | }).on('error', function(e) { 83 | console.error('problem with request: ' + e.message); 84 | }); 85 | } 86 | 87 | function extract2VimScript(body) { 88 | // for debug 89 | fs.writeFile('./nodejs-doc-all.json', body); 90 | var json = JSON.parse(body), 91 | vimObject; 92 | 93 | var _globals = sortModuleByName(mergeObject(getModsInfo(json.globals), 94 | getModsInfo(json.vars))), 95 | _modules = sortModuleByName(getModsInfo(json.modules)), 96 | _vars = (getVarInfo(json.vars)) 97 | .concat(getVarInfo(json.globals)) 98 | .sort(sortCompleteWord); 99 | 100 | _globals = copyGlobals(_globals, _modules); 101 | 102 | vimObject = { 103 | 'globals': _globals, 104 | 'modules': _modules, 105 | 'vars': _vars 106 | }; 107 | 108 | 109 | var filename = path.join(__dirname, 'nodejs-doc.vim'), 110 | comment = '" this file is auto created by "' + __filename + '", please do not edit it yourself!', 111 | content = 'let g:nodejs_complete_data = ' + JSON.stringify(vimObject), 112 | 113 | content = comment + os.EOL + content; 114 | 115 | fs.writeFile(filename, content, function(err) { 116 | emitter.emit('vimscript/done', 'write file to "' + filename + '" complete.'); 117 | }); 118 | 119 | // for debug 120 | fs.writeFileSync(filename + '.js', JSON.stringify(vimObject, null, 2)); 121 | } 122 | 123 | function getModsInfo(mods) { 124 | var ret = {}; 125 | if (!util.isArray(mods)) { 126 | return ret; 127 | } 128 | 129 | 130 | mods.forEach(function(mod) { 131 | var mod_name = getModName(mod), 132 | mod_props = getModProps(mod); 133 | 134 | // class 135 | var mod_classes = {}; 136 | var classes = mod.classes || []; 137 | classes.forEach(function(cls) { 138 | var names = getClassName(cls, mod_name); 139 | var cls_name = names.cls_name, 140 | _mod_name = names.mod_name; 141 | if (_mod_name && mod_name != _mod_name) { 142 | mod_name = names.mod_name; 143 | } 144 | 145 | mod_classes[cls_name] = getModProps(cls); 146 | }); 147 | 148 | if (mod_props.length == 0 && classes.length == 0) { 149 | } else { 150 | ret[mod_name] = { 151 | props: mod_props, 152 | classes: mod_classes 153 | } 154 | } 155 | }); 156 | 157 | return ret; 158 | } 159 | 160 | function getModProps(mod) { 161 | var is_legal_property_name = function(name) { 162 | name += ''; 163 | name = name.trim(); 164 | 165 | return (/^[$a-zA-Z_][$a-zA-Z0-9_]*$/i).test(name); 166 | }; 167 | 168 | var props = []; 169 | // properties 170 | var properties = mod.properties || []; 171 | properties.forEach(function(property) { 172 | var name = property.name; 173 | if (is_legal_property_name(name)) { 174 | var item = {}; 175 | item.word = name; 176 | item.kind = 'm'; 177 | item.info = ' '; 178 | 179 | props.push(item); 180 | } else { 181 | console.log('illegal name: ' + name); 182 | } 183 | }); 184 | 185 | // methods 186 | var methods = mod.methods || []; 187 | methods.forEach(function(method) { 188 | var name = method.name; 189 | if (is_legal_property_name(name)) { 190 | var item = {}; 191 | if (method.type == 'method') { 192 | item.word = name; 193 | item.info = method.textRaw; 194 | item.kind = 'f'; 195 | 196 | props.push(item); 197 | } 198 | } else { 199 | console.log('illegal name: ' + name); 200 | } 201 | }); 202 | 203 | // classes 204 | var classes = mod.classes || []; 205 | classes.forEach(function(cls) { 206 | var mod_name = getModName(mod); 207 | var names = getClassName(cls, mod_name); 208 | var name = names.cls_name; 209 | if (is_legal_property_name(name)) { 210 | var item = {}; 211 | item.word = names.cls_name; 212 | item.kind = 'f'; 213 | item.info = ' '; 214 | 215 | props.push(item); 216 | } else { 217 | console.log('illegal name: ' + name); 218 | } 219 | }); 220 | 221 | props = props.sort(sortCompleteWord); 222 | 223 | return props; 224 | } 225 | 226 | function getModName(mod) { 227 | // module name 228 | var mod_name = mod.name; 229 | // invalid module name like 'tls_(ssl)' 230 | // then guess the module name from textRaw 'TLS (SSL)' 231 | if ((/[^_a-z\d\$]/i).test(mod_name)) { 232 | var textRaw = mod.textRaw; 233 | var matched = textRaw.match(/^[_a-z\d\$]+/i); 234 | if (matched) { 235 | var mod_name_len = matched[0].length; 236 | mod_name = mod_name.substr(0, mod_name_len); 237 | } 238 | } 239 | 240 | return mod_name; 241 | } 242 | 243 | function getClassName(cls, mod_name) { 244 | var str = cls.name; 245 | var names = str.split('.'); 246 | 247 | var _mod_name = names[0], 248 | cls_name; 249 | 250 | if (names.length == 1) { 251 | cls_name = _mod_name; 252 | } 253 | else { 254 | // 修正 mod_name; events.EventEmitter 255 | if (_mod_name.toLowerCase() == mod_name.toLowerCase()) { 256 | mod_name = _mod_name; 257 | } 258 | cls_name = names.slice(1).join('.'); 259 | } 260 | 261 | return { 262 | mod_name: mod_name, 263 | cls_name: cls_name 264 | }; 265 | } 266 | 267 | function getVarInfo(vars) { 268 | var ret = []; 269 | if (!util.isArray(vars)) { 270 | return ret; 271 | } 272 | 273 | vars.forEach(function(_var) { 274 | // if var is a function 275 | if ((/\([^\(\)]*\)\s*$/).test(_var.textRaw)) { 276 | ret.push({ 277 | word: _var.name, 278 | info: _var.textRaw, 279 | kind: 'f' 280 | }); 281 | } else { 282 | ret.push({ 283 | word: _var.name, 284 | kind: 'v', 285 | info: ' ' 286 | }); 287 | } 288 | }); 289 | 290 | // sort 291 | ret = ret.sort(sortCompleteWord); 292 | 293 | return ret; 294 | } 295 | 296 | function copyGlobals(globals, modules) { 297 | var _Buffer = modules.buffer.classes.Buffer; 298 | 299 | globals.Buffer = { 300 | props: [], 301 | classes: { 302 | '.self': _Buffer 303 | } 304 | }; 305 | 306 | return globals; 307 | } 308 | 309 | 310 | // helpers 311 | /** 312 | * @param {Object} 313 | */ 314 | function sortModuleByName(mods) { 315 | var keys = Object.keys(mods); 316 | // sort 317 | keys.sort(); 318 | 319 | var ret = {}; 320 | keys.forEach(function(k) { 321 | ret[k] = mods[k]; 322 | }); 323 | 324 | return ret; 325 | } 326 | 327 | /** 328 | * @param {Object} 329 | * @param {Object} 330 | */ 331 | function sortCompleteWord(a, b) { 332 | var a_w = a.word.toLowerCase(), 333 | b_w = b.word.toLowerCase(); 334 | 335 | return a_w < b_w ? -1 : (a_w > b_w ? 1 : 0); 336 | } 337 | 338 | /** 339 | * @desc merge Object 340 | * @arguemnts: {Object} 341 | * 342 | * @return: return the new merged Object 343 | */ 344 | function mergeObject() { 345 | var ret = {}, 346 | args = Array.prototype.slice.call(arguments); 347 | 348 | args.forEach(function(obj) { 349 | for (var p in obj) { 350 | if (obj.hasOwnProperty(p)) { 351 | ret[p] = obj[p]; 352 | } 353 | } 354 | }); 355 | 356 | return ret; 357 | } 358 | -------------------------------------------------------------------------------- /colors/molokai.vim: -------------------------------------------------------------------------------- 1 | " Vim color file 2 | " 3 | " Author: Tomas Restrepo 4 | " https://github.com/tomasr/molokai 5 | " 6 | " Note: Based on the Monokai theme for TextMate 7 | " by Wimer Hazenberg and its darker variant 8 | " by Hamish Stuart Macpherson 9 | " 10 | 11 | hi clear 12 | 13 | if version > 580 14 | " no guarantees for version 5.8 and below, but this makes it stop 15 | " complaining 16 | hi clear 17 | if exists("syntax_on") 18 | syntax reset 19 | endif 20 | endif 21 | let g:colors_name="molokai" 22 | 23 | if exists("g:molokai_original") 24 | let s:molokai_original = g:molokai_original 25 | else 26 | let s:molokai_original = 0 27 | endif 28 | 29 | 30 | hi Boolean guifg=#AE81FF 31 | hi Character guifg=#E6DB74 32 | hi Number guifg=#AE81FF 33 | hi String guifg=#E6DB74 34 | hi Conditional guifg=#F92672 gui=bold 35 | hi Constant guifg=#AE81FF gui=bold 36 | hi Cursor guifg=#000000 guibg=#F8F8F0 37 | hi iCursor guifg=#000000 guibg=#F8F8F0 38 | hi Debug guifg=#BCA3A3 gui=bold 39 | hi Define guifg=#66D9EF 40 | hi Delimiter guifg=#8F8F8F 41 | hi DiffAdd guibg=#13354A 42 | hi DiffChange guifg=#89807D guibg=#4C4745 43 | hi DiffDelete guifg=#960050 guibg=#1E0010 44 | hi DiffText guibg=#4C4745 gui=italic,bold 45 | 46 | hi Directory guifg=#A6E22E gui=bold 47 | hi Error guifg=#E6DB74 guibg=#1E0010 48 | hi ErrorMsg guifg=#F92672 guibg=#232526 gui=bold 49 | hi Exception guifg=#A6E22E gui=bold 50 | hi Float guifg=#AE81FF 51 | hi FoldColumn guifg=#465457 guibg=#000000 52 | hi Folded guifg=#465457 guibg=#000000 53 | hi Function guifg=#A6E22E 54 | hi Identifier guifg=#FD971F 55 | hi Ignore guifg=#808080 guibg=bg 56 | hi IncSearch guifg=#C4BE89 guibg=#000000 57 | 58 | hi Keyword guifg=#F92672 gui=bold 59 | hi Label guifg=#E6DB74 gui=none 60 | hi Macro guifg=#C4BE89 gui=italic 61 | hi SpecialKey guifg=#66D9EF gui=italic 62 | 63 | hi MatchParen guifg=#000000 guibg=#FD971F gui=bold 64 | hi ModeMsg guifg=#E6DB74 65 | hi MoreMsg guifg=#E6DB74 66 | hi Operator guifg=#F92672 67 | 68 | " complete menu 69 | hi Pmenu guifg=#66D9EF guibg=#000000 70 | hi PmenuSel guibg=#808080 71 | hi PmenuSbar guibg=#080808 72 | hi PmenuThumb guifg=#66D9EF 73 | 74 | hi PreCondit guifg=#A6E22E gui=bold 75 | hi PreProc guifg=#A6E22E 76 | hi Question guifg=#66D9EF 77 | hi Repeat guifg=#F92672 gui=bold 78 | hi Search guifg=#000000 guibg=#FFE792 79 | " marks 80 | hi SignColumn guifg=#A6E22E guibg=#232526 81 | hi SpecialChar guifg=#F92672 gui=bold 82 | hi SpecialComment guifg=#7E8E91 gui=bold 83 | hi Special guifg=#66D9EF guibg=bg gui=italic 84 | if has("spell") 85 | hi SpellBad guisp=#FF0000 gui=undercurl 86 | hi SpellCap guisp=#7070F0 gui=undercurl 87 | hi SpellLocal guisp=#70F0F0 gui=undercurl 88 | hi SpellRare guisp=#FFFFFF gui=undercurl 89 | endif 90 | hi Statement guifg=#F92672 gui=bold 91 | hi StatusLine guifg=#455354 guibg=fg 92 | hi StatusLineNC guifg=#808080 guibg=#080808 93 | hi StorageClass guifg=#FD971F gui=italic 94 | hi Structure guifg=#66D9EF 95 | hi Tag guifg=#F92672 gui=italic 96 | hi Title guifg=#ef5939 97 | hi Todo guifg=#FFFFFF guibg=bg gui=bold 98 | 99 | hi Typedef guifg=#66D9EF 100 | hi Type guifg=#66D9EF gui=none 101 | hi Underlined guifg=#808080 gui=underline 102 | 103 | hi VertSplit guifg=#808080 guibg=#080808 gui=bold 104 | hi VisualNOS guibg=#403D3D 105 | hi Visual guibg=#403D3D 106 | hi WarningMsg guifg=#FFFFFF guibg=#333333 gui=bold 107 | hi WildMenu guifg=#66D9EF guibg=#000000 108 | 109 | hi TabLineFill guifg=#1B1D1E guibg=#1B1D1E 110 | hi TabLine guibg=#1B1D1E guifg=#808080 gui=none 111 | 112 | if s:molokai_original == 1 113 | hi Normal guifg=#F8F8F2 guibg=#272822 114 | hi Comment guifg=#75715E 115 | hi CursorLine guibg=#3E3D32 116 | hi CursorLineNr guifg=#FD971F gui=none 117 | hi CursorColumn guibg=#3E3D32 118 | hi ColorColumn guibg=#3B3A32 119 | hi LineNr guifg=#BCBCBC guibg=#3B3A32 120 | hi NonText guifg=#75715E 121 | hi SpecialKey guifg=#75715E 122 | else 123 | hi Normal guifg=#F8F8F2 guibg=#1B1D1E 124 | hi Comment guifg=#7E8E91 125 | hi CursorLine guibg=#293739 126 | hi CursorLineNr guifg=#FD971F gui=none 127 | hi CursorColumn guibg=#293739 128 | hi ColorColumn guibg=#232526 129 | hi LineNr guifg=#465457 guibg=#232526 130 | hi NonText guifg=#465457 131 | hi SpecialKey guifg=#465457 132 | end 133 | 134 | " 135 | " Support for 256-color terminal 136 | " 137 | if &t_Co > 255 138 | if s:molokai_original == 1 139 | hi Normal ctermbg=234 140 | hi CursorLine ctermbg=235 cterm=none 141 | hi CursorLineNr ctermfg=208 cterm=none 142 | else 143 | hi Normal ctermfg=252 ctermbg=233 144 | hi CursorLine ctermbg=234 cterm=none 145 | hi CursorLineNr ctermfg=208 cterm=none 146 | endif 147 | hi Boolean ctermfg=135 148 | hi Character ctermfg=144 149 | hi Number ctermfg=135 150 | hi String ctermfg=144 151 | hi Conditional ctermfg=161 cterm=bold 152 | hi Constant ctermfg=135 cterm=bold 153 | hi Cursor ctermfg=16 ctermbg=253 154 | hi Debug ctermfg=225 cterm=bold 155 | hi Define ctermfg=81 156 | hi Delimiter ctermfg=241 157 | 158 | hi DiffAdd ctermbg=24 159 | hi DiffChange ctermfg=181 ctermbg=239 160 | hi DiffDelete ctermfg=162 ctermbg=53 161 | hi DiffText ctermbg=102 cterm=bold 162 | 163 | hi Directory ctermfg=118 cterm=bold 164 | hi Error ctermfg=219 ctermbg=89 165 | hi ErrorMsg ctermfg=199 ctermbg=16 cterm=bold 166 | hi Exception ctermfg=118 cterm=bold 167 | hi Float ctermfg=135 168 | hi FoldColumn ctermfg=67 ctermbg=16 169 | hi Folded ctermfg=67 ctermbg=16 170 | hi Function ctermfg=118 171 | hi Identifier ctermfg=208 cterm=none 172 | hi Ignore ctermfg=244 ctermbg=232 173 | hi IncSearch ctermfg=193 ctermbg=16 174 | 175 | hi keyword ctermfg=161 cterm=bold 176 | hi Label ctermfg=229 cterm=none 177 | hi Macro ctermfg=193 178 | hi SpecialKey ctermfg=81 179 | 180 | hi MatchParen ctermfg=233 ctermbg=208 cterm=bold 181 | hi ModeMsg ctermfg=229 182 | hi MoreMsg ctermfg=229 183 | hi Operator ctermfg=161 184 | 185 | " complete menu 186 | hi Pmenu ctermfg=81 ctermbg=16 187 | hi PmenuSel ctermfg=255 ctermbg=242 188 | hi PmenuSbar ctermbg=232 189 | hi PmenuThumb ctermfg=81 190 | 191 | hi PreCondit ctermfg=118 cterm=bold 192 | hi PreProc ctermfg=118 193 | hi Question ctermfg=81 194 | hi Repeat ctermfg=161 cterm=bold 195 | hi Search ctermfg=0 ctermbg=222 cterm=NONE 196 | 197 | " marks column 198 | hi SignColumn ctermfg=118 ctermbg=235 199 | hi SpecialChar ctermfg=161 cterm=bold 200 | hi SpecialComment ctermfg=245 cterm=bold 201 | hi Special ctermfg=81 202 | if has("spell") 203 | hi SpellBad ctermbg=52 204 | hi SpellCap ctermbg=17 205 | hi SpellLocal ctermbg=17 206 | hi SpellRare ctermfg=none ctermbg=none cterm=reverse 207 | endif 208 | hi Statement ctermfg=161 cterm=bold 209 | hi StatusLine ctermfg=238 ctermbg=253 210 | hi StatusLineNC ctermfg=244 ctermbg=232 211 | hi StorageClass ctermfg=208 212 | hi Structure ctermfg=81 213 | hi Tag ctermfg=161 214 | hi Title ctermfg=166 215 | hi Todo ctermfg=231 ctermbg=232 cterm=bold 216 | 217 | hi Typedef ctermfg=81 218 | hi Type ctermfg=81 cterm=none 219 | hi Underlined ctermfg=244 cterm=underline 220 | 221 | hi VertSplit ctermfg=244 ctermbg=232 cterm=bold 222 | hi VisualNOS ctermbg=238 223 | hi Visual ctermbg=235 224 | hi WarningMsg ctermfg=231 ctermbg=238 cterm=bold 225 | hi WildMenu ctermfg=81 ctermbg=16 226 | 227 | hi Comment ctermfg=59 228 | hi CursorColumn ctermbg=236 229 | hi ColorColumn ctermbg=236 230 | hi LineNr ctermfg=250 ctermbg=236 231 | hi NonText ctermfg=59 232 | 233 | hi SpecialKey ctermfg=59 234 | 235 | if exists("g:rehash256") && g:rehash256 == 1 236 | hi Normal ctermfg=252 ctermbg=234 237 | hi CursorLine ctermbg=236 cterm=none 238 | hi CursorLineNr ctermfg=208 cterm=none 239 | 240 | hi Boolean ctermfg=141 241 | hi Character ctermfg=222 242 | hi Number ctermfg=141 243 | hi String ctermfg=222 244 | hi Conditional ctermfg=197 cterm=bold 245 | hi Constant ctermfg=141 cterm=bold 246 | 247 | hi DiffDelete ctermfg=125 ctermbg=233 248 | 249 | hi Directory ctermfg=154 cterm=bold 250 | hi Error ctermfg=222 ctermbg=233 251 | hi Exception ctermfg=154 cterm=bold 252 | hi Float ctermfg=141 253 | hi Function ctermfg=154 254 | hi Identifier ctermfg=208 255 | 256 | hi Keyword ctermfg=197 cterm=bold 257 | hi Operator ctermfg=197 258 | hi PreCondit ctermfg=154 cterm=bold 259 | hi PreProc ctermfg=154 260 | hi Repeat ctermfg=197 cterm=bold 261 | 262 | hi Statement ctermfg=197 cterm=bold 263 | hi Tag ctermfg=197 264 | hi Title ctermfg=203 265 | hi Visual ctermbg=238 266 | 267 | hi Comment ctermfg=244 268 | hi LineNr ctermfg=239 ctermbg=235 269 | hi NonText ctermfg=239 270 | hi SpecialKey ctermfg=239 271 | endif 272 | end 273 | 274 | " Must be at the end, because of ctermbg=234 bug. 275 | " https://groups.google.com/forum/#!msg/vim_dev/afPqwAFNdrU/nqh6tOM87QUJ 276 | set background=dark 277 | -------------------------------------------------------------------------------- /after/autoload/nodejscomplete.vim: -------------------------------------------------------------------------------- 1 | " Vim completion script 2 | " Language: Javascript(node) 3 | " Maintainer: Lin Zhang ( myhere.2009 AT gmail DOT com ) 4 | " Last Change: 2012-8-18 1:32:00 5 | 6 | " save current dir 7 | let s:nodejs_doc_file = expand(':p:h') . '/nodejs-doc.vim' 8 | 9 | let s:js_varname_reg = '[$a-zA-Z_][$a-zA-Z0-9_]*' 10 | 11 | let s:js_obj_declare_type = { 12 | \ 'global': 0, 13 | \ 'require': 1, 14 | \ 'constructor': 2 15 | \ } 16 | 17 | " settings 18 | " default setting 19 | let s:nodejs_complete_config = { 20 | \ 'js_compl_fn': 'javascriptcomplete#CompleteJS', 21 | \ 'max_node_compl_len': 15 22 | \} 23 | if exists('g:nodejs_complete_config') && type(g:nodejs_complete_config) == type({}) 24 | let g:nodejs_complete_config = extend(s:nodejs_complete_config, g:nodejs_complete_config) 25 | else 26 | let g:nodejs_complete_config = s:nodejs_complete_config 27 | endif 28 | unlet s:nodejs_complete_config 29 | 30 | function! nodejscomplete#CompleteJS(findstart, base)"{{{ 31 | if a:findstart 32 | try 33 | let JS_compl_fn = function(g:nodejs_complete_config.js_compl_fn) 34 | let start = call(JS_compl_fn, [a:findstart, a:base]) 35 | catch /.*/ 36 | echo '!!!!!!!!!!function [' . g:nodejs_complete_config.js_compl_fn . '] is not exists!' 37 | endtry 38 | 39 | "Decho 'start: ' . start 40 | " str[start: end] end 为负数时从末尾截取 41 | if start - 1 < 0 42 | let b:nodecompl_context = '' 43 | else 44 | let line = getline('.') 45 | let b:nodecompl_context = line[:start-1] 46 | endif 47 | return start 48 | else 49 | let posi = getpos('.') 50 | let result = s:getNodeComplete(a:base, b:nodecompl_context) 51 | " the function above will move the cursor 52 | " so we restore the cursor position 53 | " JS_compl_fn below may rely on the cursor position 54 | call setpos('.', posi) 55 | 56 | "Decho 'nodecomplete: ' . string(result) 57 | unlet b:nodecompl_context 58 | 59 | let nodejs_compl = result.complete 60 | " limit nodejs complete count 61 | if g:nodejs_complete_config.max_node_compl_len != 0 62 | let nodejs_compl = nodejs_compl[0 : g:nodejs_complete_config.max_node_compl_len - 1] 63 | endif 64 | 65 | if result.continue 66 | try 67 | let JS_compl_fn = function(g:nodejs_complete_config.js_compl_fn) 68 | let js_compl = call(JS_compl_fn, [a:findstart, a:base]) 69 | catch /.*/ 70 | echo '!!!!!!!!!!function [' . g:nodejs_complete_config.js_compl_fn . '] is not exists!' 71 | endtry 72 | 73 | "Decho 'js_compl: ' . string(js_compl) 74 | 75 | return nodejs_compl + js_compl 76 | else 77 | return nodejs_compl 78 | endif 79 | endif 80 | endfunction"}}} 81 | 82 | " get complete 83 | function! s:getNodeComplete(base, context)"{{{ 84 | "Decho 'base: ' . a:base 85 | "Decho 'context: ' . a:context 86 | 87 | " TODO: 排除 module.property.h 情况 88 | let mod_reg = '\(' . s:js_varname_reg . '\)\s*\(\.\|\[\s*["'']\?\)\s*$' 89 | let matched = matchlist(a:context, mod_reg) 90 | "Decho 'mod_reg: ' . mod_reg 91 | 92 | " 模块属性补全 93 | if len(matched) > 0 94 | let var_name = matched[1] 95 | let operator = matched[2] 96 | let position = [line('.'), len(a:context) - len(matched[0])] 97 | "Decho 'var_name: ' . var_name . ' ; operator: ' . operator 98 | let declare_info = s:getObjDeclareInfo(var_name, position) 99 | "Decho 'mod_info: ' . string(declare_info) . '; compl_prefix: ' . a:base 100 | 101 | let compl_list = s:getObjectComplete(declare_info.type, declare_info.value, 102 | \ a:base, operator) 103 | 104 | let ret = { 105 | \ 'complete': compl_list 106 | \ } 107 | if len(compl_list) == 0 108 | let ret.continue = 1 109 | else 110 | let ret.continue = 0 111 | endif 112 | " 全局补全 113 | else 114 | "Decho 'var complete' 115 | let ret = { 116 | \ 'continue': 1, 117 | \ 'complete': s:getVariableComplete(a:context, a:base) 118 | \ } 119 | endif 120 | 121 | return ret 122 | endfunction"}}} 123 | 124 | function! s:getObjDeclareInfo(var_name, position)"{{{ 125 | let position = s:fixPosition(a:position) 126 | "Decho 'position: ' . string(position) 127 | 128 | if position[0] <= 0 129 | return { 130 | \ 'type': s:js_obj_declare_type.global, 131 | \ 'value': a:var_name 132 | \} 133 | endif 134 | 135 | let decl_stmt_prefix_reg = '\<' . a:var_name . '\_s*=\_s*' 136 | " search backward, don't move the cursor, don't wrap 137 | call cursor(position[0], position[1]) 138 | let begin_position = searchpos(decl_stmt_prefix_reg, 'bnW') 139 | if begin_position[0] == 0 140 | return { 141 | \ 'type': s:js_obj_declare_type.global, 142 | \ 'value': a:var_name 143 | \} 144 | endif 145 | 146 | " make sure it's not in comments... 147 | if !s:isDeclaration(begin_position) 148 | return s:getObjDeclareInfo(a:var_name, begin_position) 149 | endif 150 | 151 | let lines = s:getLinesInRange(begin_position, position) 152 | "Decho 'lines: ' . string(lines) 153 | let code = join(lines, "\n") 154 | 155 | " require 156 | let require_stmt_reg = decl_stmt_prefix_reg . 157 | \ 'require\_s*(\_s*\([''"]\)\zs[^)''"]\+\ze\1\_s*)' 158 | let matched = matchstr(code, require_stmt_reg) 159 | if len(matched) 160 | return { 161 | \ 'type': s:js_obj_declare_type.require, 162 | \ 'value': matched 163 | \} 164 | endif 165 | 166 | " new 167 | let new_stmt_reg = decl_stmt_prefix_reg . 168 | \ 'new\_s\+\zs' . s:js_varname_reg . '\%(\_s*\.\_s*' . 169 | \ s:js_varname_reg . '\)*\ze' 170 | let matched = matchstr(code, new_stmt_reg) 171 | if len(matched) 172 | let parts = split(matched, '\.') 173 | return { 174 | \ 'type': s:js_obj_declare_type.constructor, 175 | \ 'value': [s:getObjDeclareInfo(parts[0], begin_position), join(parts[1:], '.')] 176 | \} 177 | endif 178 | 179 | " new 180 | " var emitter = new (require('events')).EventEmitter; 181 | let new_stmt_reg = decl_stmt_prefix_reg . 182 | \ 'new\_s\+' . 183 | \ '(\_s*require\_s*(\([''"]\)\(' . s:js_varname_reg . '\)\1\_s*)\_s*)' . 184 | \ '\_s*' . 185 | \ '\(\%(\.' . s:js_varname_reg . '\)\+\)' 186 | 187 | let matchedList = matchlist(code, new_stmt_reg) 188 | if (len(matchedList)) 189 | "Decho 'new stmt: ' . string(matchedList) 190 | let props = [matchedList[3][1:]] + matchedList[4:] 191 | "Decho 'props: ' . string(props) 192 | return { 193 | \ 'type': s:js_obj_declare_type.constructor, 194 | \ 'value': [ 195 | \ { 196 | \ 'type': s:js_obj_declare_type.require, 197 | \ 'value': matchedList[2] 198 | \ }, 199 | \ join(props, '') 200 | \ ] 201 | \} 202 | endif 203 | 204 | 205 | " assign 206 | let assign_stmt_reg = decl_stmt_prefix_reg . '\zs' . s:js_varname_reg . '\ze' 207 | let matched = matchstr(code, assign_stmt_reg) 208 | if len(matched) 209 | return s:getObjDeclareInfo(a:var_name, begin_position) 210 | endif 211 | 212 | " continure to search backward 213 | return s:getObjDeclareInfo(a:var_name, begin_position) 214 | endfunction"}}} 215 | 216 | function! s:isDeclaration(position)"{{{ 217 | let [line_num, col_num] = a:position 218 | " syntaxName @see: $VIMRUNTIME/syntax/javascript.vim 219 | let syntaxName = synIDattr(synID(line_num, col_num, 0), 'name') 220 | if syntaxName =~ '^javaScript\%(Comment\|LineComment\|String\|RegexpString\)' 221 | return 0 222 | else 223 | return 1 224 | endif 225 | endfunction"}}} 226 | 227 | " only complete nodejs's module info 228 | function! s:getObjectComplete(type, mod_name, prop_name, operator)"{{{ 229 | " new 230 | if a:type == s:js_obj_declare_type.constructor 231 | let list = s:getConstructedObjectComplete(a:mod_name) 232 | " require and global 233 | else 234 | let list = s:getNodeDocList(a:type, a:mod_name, 'props') 235 | endif 236 | 237 | if !len(list) 238 | return list 239 | else 240 | " no prop_name suplied 241 | if (len(a:prop_name) == 0) 242 | let ret = list 243 | else 244 | let ret = s:smartFilter(list, 'v:val["word"]', a:prop_name) 245 | endif 246 | 247 | let [prefix, suffix] = ['', ''] 248 | let matched = matchlist(a:operator, '\[\s*\(["'']\)\?') 249 | "Decho 'operator_matched: ' . string(matched) 250 | if len(matched) 251 | if len(matched[1]) 252 | let [prefix, suffix] = ['', matched[1] . ']'] 253 | else 254 | let [prefix, suffix] = ['''', ''']'] 255 | endif 256 | endif 257 | 258 | for item in ret 259 | let item.word = prefix . item.word . suffix 260 | endfor 261 | call s:addFunctionParen(ret) 262 | 263 | return ret 264 | endif 265 | endfunction"}}} 266 | 267 | function! s:getVariableComplete(context, var_name)"{{{ 268 | "Decho 'var_name: ' . a:var_name 269 | 270 | " complete require's arguments 271 | let matched = matchlist(a:context, 'require\s*(\s*\%(\([''"]\)\(\.\{1,2}.*\)\=\)\=$') 272 | if (len(matched) > 0) 273 | "Decho 'require complete: ' . string(matched) 274 | 275 | if (len(matched[2]) > 0) " complete -> require('./ 276 | let mod_names = s:getModuleInCurrentDir(a:context, a:var_name, matched) 277 | else 278 | let mod_names = s:getModuleNames() 279 | 280 | if (len(matched[1]) == 0) " complete -> require( 281 | call map(mod_names, '"''" . v:val . "'')"') 282 | elseif (len(a:var_name) == 0) " complete -> require(' 283 | call map(mod_names, 'v:val . "' . escape(matched[1], '"') . ')"') 284 | else " complete -> require('ti 285 | let mod_names = filter(mod_names, 'v:val =~# "^' . a:var_name . '"') 286 | call map(mod_names, 'v:val . "' . escape(matched[1], '"') . ')"') 287 | endif 288 | endif 289 | 290 | return mod_names 291 | endif 292 | 293 | " complete global variables 294 | let vars = [] 295 | if (len(a:var_name) == 0) 296 | return vars 297 | endif 298 | 299 | call s:loadNodeDocData() 300 | 301 | if (has_key(g:nodejs_complete_data, 'vars')) 302 | let vars = deepcopy(g:nodejs_complete_data.vars) 303 | endif 304 | 305 | let ret = s:smartFilter(vars, 'v:val["word"]', a:var_name) 306 | 307 | call s:addFunctionParen(ret) 308 | 309 | return ret 310 | endfunction"}}} 311 | 312 | function! s:getModuleInCurrentDir(context, var_name, matched)"{{{ 313 | let mod_names = [] 314 | let path = a:matched[2] . a:var_name 315 | 316 | " typed as require('.. 317 | " complete as require('../ 318 | " cause the latter one is more common 319 | let compl_prefix = '' 320 | if (path =~# '\.\.$') 321 | let compl_prefix = '/' 322 | let path = path . compl_prefix 323 | endif 324 | 325 | "Decho 'path: ' . path 326 | 327 | let current_dir = expand('%:p:h') 328 | let glob_path = current_dir . '/' . path . '*' 329 | let files = s:fuzglob(glob_path) 330 | "Decho 'glob: ' . glob_path 331 | "Decho 'current dir files: ' . string(files) 332 | for file in files 333 | " not '.' and '..' 334 | if ((isdirectory(file) ) || file =~? '\.json$\|\.js$') 335 | let mod_file = file 336 | " directory 337 | if (file !~? '\.json$\|\.js$') 338 | let mod_file = mod_file . '/' 339 | endif 340 | 341 | " get complete word 342 | let mod_file = substitute(mod_file, '\', '/', 'g') 343 | let start = len(glob_path) - 1 " substract character '*' 344 | let compl_infix = strpart(mod_file, start) 345 | "Decho 'idx: ' . start 346 | "Decho 'compl_infix: ' . compl_infix 347 | "Decho 'relative file: ' . mod_file 348 | 349 | let mod_name = compl_prefix . a:var_name . compl_infix 350 | " file module, not a directory 351 | if (compl_infix !~# '/$') 352 | let mod_name = mod_name . a:matched[1] . ')' 353 | endif 354 | 355 | "Decho 'mod_name: ' . mod_name 356 | call add(mod_names, mod_name) 357 | endif 358 | endfor 359 | 360 | "Decho 'relative path: ' . path 361 | 362 | return mod_names 363 | endfunction"}}} 364 | 365 | function! s:getModuleNames()"{{{ 366 | call s:loadNodeDocData() 367 | 368 | let mod_names = [] 369 | 370 | " build-in module name 371 | if (has_key(g:nodejs_complete_data, 'modules')) 372 | let mod_names = keys(g:nodejs_complete_data.modules) 373 | endif 374 | 375 | 376 | " find module in 'module_dir' folder 377 | if (!exists('b:npm_module_names')) 378 | let current_dir = expand('%:p:h') 379 | 380 | let b:npm_module_names = s:getModuleNamesInNode_modulesFolder(current_dir) 381 | endif 382 | 383 | let mod_names = mod_names + b:npm_module_names 384 | 385 | return sort(mod_names) 386 | endfunction"}}} 387 | 388 | function! s:getModuleNamesInNode_modulesFolder(current_dir)"{{{ 389 | " ensure platform coincidence 390 | let base_dir = substitute(a:current_dir, '\', '/', 'g') 391 | "Decho 'base_dir: ' . base_dir 392 | 393 | let ret = [] 394 | 395 | let parts = split(base_dir, '/', 1) 396 | "Decho 'parts: ' . string(parts) 397 | let idx = 0 398 | let len = len(parts) 399 | let sub_parts = [] 400 | while idx < len 401 | let sub_parts = add(sub_parts, parts[idx]) 402 | let module_dir = join(sub_parts, '/') . '/node_modules' 403 | "Decho 'directory: ' . module_dir 404 | 405 | if (isdirectory(module_dir)) 406 | let files = s:fuzglob(module_dir . '/*') 407 | "Decho 'node_module files: ' . string(files) 408 | for file in files 409 | if (isdirectory(file) || file =~? '\.json$\|\.js$') 410 | let mod_name = matchstr(file, '[^/\\]\+$') 411 | let ret = add(ret, mod_name) 412 | endif 413 | endfor 414 | endif 415 | 416 | let idx = idx + 1 417 | endwhile 418 | 419 | "Decho 'npm modules: ' . string(ret) 420 | 421 | return ret 422 | endfunction"}}} 423 | 424 | function! s:getConstructedObjectComplete(constructor_info)"{{{ 425 | "Decho 'getConstructedObjectComplete, constructor_info: ' . string(a:constructor_info) 426 | 427 | let ret = [] 428 | 429 | let [declare_info, class_name] = a:constructor_info 430 | let mod_name = declare_info.value 431 | " global 432 | if declare_info.type == s:js_obj_declare_type.global 433 | " Buffer 434 | if class_name == '' 435 | let class_name = '.self' 436 | endif 437 | " global.Buffer 438 | if mod_name == 'global' 439 | let mod_name = class_name 440 | let class_name = '.self' 441 | endif 442 | endif 443 | 444 | " global or require 445 | if declare_info.type == s:js_obj_declare_type.global || 446 | \ declare_info.type == s:js_obj_declare_type.require 447 | 448 | let ret = s:getNodeDocList(declare_info.type, mod_name, 'classes', class_name) 449 | endif 450 | 451 | return ret 452 | endfunction"}}} 453 | 454 | function! s:addFunctionParen(compl_list)"{{{ 455 | for item in a:compl_list 456 | if type(item) == 4 457 | if item.kind == 'f' 458 | let item.word = item.word . '(' 459 | endif 460 | endif 461 | endfor 462 | 463 | return a:compl_list 464 | endfunction"}}} 465 | 466 | function! s:loadNodeDocData()"{{{ 467 | " load node module data 468 | if (!exists('g:nodejs_complete_data')) 469 | " load data from external file 470 | let filename = s:nodejs_doc_file 471 | "Decho 'filename: ' . filename 472 | if (filereadable(filename)) 473 | execute 'so ' . filename 474 | "Decho string(g:nodejs_complete_data) 475 | else 476 | "Decho 'not readable: ' . filename 477 | endif 478 | endif 479 | endfunction"}}} 480 | 481 | " get infomation from g:nodejs_complete_data 482 | " @param mod_type {Enum} 483 | " @param mod_name {String} 484 | " @param type {Enum} 'props' | 'classes' 485 | " @param {String} if type == 'classes', then it exists and is class_name 486 | " else do not exist 487 | function! s:getNodeDocList(mod_type, mod_name, type, ...)"{{{ 488 | call s:loadNodeDocData() 489 | 490 | if a:mod_type == s:js_obj_declare_type.require 491 | let type = 'modules' 492 | else 493 | let type = 'globals' 494 | endif 495 | 496 | if (has_key(g:nodejs_complete_data[type], a:mod_name)) 497 | let mod = g:nodejs_complete_data[type][a:mod_name] 498 | else 499 | let mod = {} 500 | endif 501 | 502 | " class 503 | if a:0 != 0 504 | let class_name = a:1 505 | if (has_key(mod, a:type)) 506 | let classes = mod[a:type] 507 | else 508 | let classes = {} 509 | endif 510 | 511 | if (has_key(classes, a:1)) 512 | let ret = classes[class_name] 513 | else 514 | let ret = [] 515 | endif 516 | " property 517 | else 518 | if (has_key(mod, a:type)) 519 | let ret = mod[a:type] 520 | else 521 | let ret = [] 522 | endif 523 | endif 524 | 525 | return deepcopy(ret) 526 | endfunction"}}} 527 | 528 | " copied from FuzzyFinder/autoload/fuf.vim 529 | " returns list of paths. 530 | " An argument for glob() is normalized in order to avoid a bug on Windows. 531 | function! s:fuzglob(expr)"{{{ 532 | " Substitutes "\", because on Windows, "**\" doesn't include ".\", 533 | " but "**/" include "./". I don't know why. 534 | return split(glob(substitute(a:expr, '\', '/', 'g')), "\n") 535 | endfunction"}}} 536 | 537 | " when x <= 0, return [0, 0] 538 | " when y <= 0, move to previous line end 539 | function! s:fixPosition(position)"{{{ 540 | let [x, y] = a:position 541 | 542 | if x <= 0 543 | return [0, 0] 544 | endif 545 | 546 | if y <= 0 547 | let x -= 1 548 | let y = len(getline(x)) 549 | 550 | return s:fixPosition([x, y]) 551 | endif 552 | 553 | return [x, y] 554 | endfunction"}}} 555 | 556 | " return a List contains every line 557 | function! s:getLinesInRange(begin_position, end_position)"{{{ 558 | let [begin_x, begin_y] = a:begin_position 559 | let [end_x, end_y] = a:end_position 560 | 561 | let lines = [] 562 | if begin_x == end_x 563 | let line = getline(begin_x) 564 | call add(lines, line[begin_y - 1 : end_y - 1]) 565 | else 566 | let line = getline(begin_x) 567 | call add(lines, line[begin_y - 1 :]) 568 | 569 | let x = begin_x + 1 570 | while x < end_x 571 | let line = getline(x) 572 | call add(lines, line) 573 | let x += 1 574 | endwhile 575 | 576 | let line = getline(end_x) 577 | call add(lines, line[: end_y - 1]) 578 | endif 579 | 580 | return lines 581 | endfunction"}}} 582 | 583 | " filter items with exact match at first 584 | function! s:smartFilter(items, str, keyword)"{{{ 585 | let items = filter(a:items, a:str . ' =~ "' . a:keyword . '"') 586 | let [exact_ret, fuzzy_ret] = [[], []] 587 | for item in items 588 | if item.word =~ '^' . a:keyword 589 | call add(exact_ret, item) 590 | else 591 | call add(fuzzy_ret, item) 592 | endif 593 | endfor 594 | 595 | return exact_ret + fuzzy_ret 596 | endfunction"}}} 597 | 598 | " 599 | " use plugin Decho(https://github.com/vim-scripts/Decho) for debug 600 | " 601 | " turn off debug mode 602 | " :%s;^\(\s*\)\(Decho\);\1"\2;g | :w | so % 603 | " 604 | " turn on debug mode 605 | " :%s;^\(\s*\)"\(Decho\);\1\2;g | :w | so % 606 | " 607 | 608 | 609 | " vim:set foldmethod=marker: 610 | -------------------------------------------------------------------------------- /after/autoload/nodejs-doc.vim: -------------------------------------------------------------------------------- 1 | " this file is auto created by "c:\Documents and Settings\zhanglin\.vim\bundle\vim-nodejs-complete\after\autoload\update-nodejs-doc.js", please do not edit it yourself! 2 | let g:nodejs_complete_data = {"globals":{"console":{"props":[{"word":"assert","info":"console.assert(expression, [message])","kind":"f"},{"word":"dir","info":"console.dir(obj)","kind":"f"},{"word":"error","info":"console.error([data], [...])","kind":"f"},{"word":"info","info":"console.info([data], [...])","kind":"f"},{"word":"log","info":"console.log([data], [...])","kind":"f"},{"word":"time","info":"console.time(label)","kind":"f"},{"word":"timeEnd","info":"console.timeEnd(label)","kind":"f"},{"word":"trace","info":"console.trace(label)","kind":"f"},{"word":"warn","info":"console.warn([data], [...])","kind":"f"}],"classes":{}},"process":{"props":[{"word":"abort","info":"process.abort()","kind":"f"},{"word":"arch","kind":"m","info":" "},{"word":"argv","kind":"m","info":" "},{"word":"chdir","info":"process.chdir(directory)","kind":"f"},{"word":"config","kind":"m","info":" "},{"word":"cwd","info":"process.cwd()","kind":"f"},{"word":"env","kind":"m","info":" "},{"word":"execPath","kind":"m","info":" "},{"word":"exit","info":"process.exit([code])","kind":"f"},{"word":"getgid","info":"process.getgid()","kind":"f"},{"word":"getuid","info":"process.getuid()","kind":"f"},{"word":"hrtime","info":"process.hrtime()","kind":"f"},{"word":"kill","info":"process.kill(pid, [signal])","kind":"f"},{"word":"memoryUsage","info":"process.memoryUsage()","kind":"f"},{"word":"nextTick","info":"process.nextTick(callback)","kind":"f"},{"word":"pid","kind":"m","info":" "},{"word":"platform","kind":"m","info":" "},{"word":"setgid","info":"process.setgid(id)","kind":"f"},{"word":"setuid","info":"process.setuid(id)","kind":"f"},{"word":"stderr","kind":"m","info":" "},{"word":"stdin","kind":"m","info":" "},{"word":"stdout","kind":"m","info":" "},{"word":"title","kind":"m","info":" "},{"word":"umask","info":"process.umask([mask])","kind":"f"},{"word":"uptime","info":"process.uptime()","kind":"f"},{"word":"version","kind":"m","info":" "},{"word":"versions","kind":"m","info":" "}],"classes":{}},"require":{"props":[{"word":"cache","kind":"m","info":" "},{"word":"extensions","kind":"m","info":" "},{"word":"resolve","info":"require.resolve()","kind":"f"}],"classes":{}},"Buffer":{"props":[],"classes":{".self":[{"word":"copy","info":"buf.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd])","kind":"f"},{"word":"fill","info":"buf.fill(value, [offset], [end])","kind":"f"},{"word":"length","kind":"m","info":" "},{"word":"readDoubleBE","info":"buf.readDoubleBE(offset, [noAssert])","kind":"f"},{"word":"readDoubleLE","info":"buf.readDoubleLE(offset, [noAssert])","kind":"f"},{"word":"readFloatBE","info":"buf.readFloatBE(offset, [noAssert])","kind":"f"},{"word":"readFloatLE","info":"buf.readFloatLE(offset, [noAssert])","kind":"f"},{"word":"readInt16BE","info":"buf.readInt16BE(offset, [noAssert])","kind":"f"},{"word":"readInt16LE","info":"buf.readInt16LE(offset, [noAssert])","kind":"f"},{"word":"readInt32BE","info":"buf.readInt32BE(offset, [noAssert])","kind":"f"},{"word":"readInt32LE","info":"buf.readInt32LE(offset, [noAssert])","kind":"f"},{"word":"readInt8","info":"buf.readInt8(offset, [noAssert])","kind":"f"},{"word":"readUInt16BE","info":"buf.readUInt16BE(offset, [noAssert])","kind":"f"},{"word":"readUInt16LE","info":"buf.readUInt16LE(offset, [noAssert])","kind":"f"},{"word":"readUInt32BE","info":"buf.readUInt32BE(offset, [noAssert])","kind":"f"},{"word":"readUInt32LE","info":"buf.readUInt32LE(offset, [noAssert])","kind":"f"},{"word":"readUInt8","info":"buf.readUInt8(offset, [noAssert])","kind":"f"},{"word":"slice","info":"buf.slice([start], [end])","kind":"f"},{"word":"toString","info":"buf.toString([encoding], [start], [end])","kind":"f"},{"word":"write","info":"buf.write(string, [offset], [length], [encoding])","kind":"f"},{"word":"writeDoubleBE","info":"buf.writeDoubleBE(value, offset, [noAssert])","kind":"f"},{"word":"writeDoubleLE","info":"buf.writeDoubleLE(value, offset, [noAssert])","kind":"f"},{"word":"writeFloatBE","info":"buf.writeFloatBE(value, offset, [noAssert])","kind":"f"},{"word":"writeFloatLE","info":"buf.writeFloatLE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt16BE","info":"buf.writeInt16BE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt16LE","info":"buf.writeInt16LE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt32BE","info":"buf.writeInt32BE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt32LE","info":"buf.writeInt32LE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt8","info":"buf.writeInt8(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt16BE","info":"buf.writeUInt16BE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt16LE","info":"buf.writeUInt16LE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt32BE","info":"buf.writeUInt32BE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt32LE","info":"buf.writeUInt32LE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt8","info":"buf.writeUInt8(value, offset, [noAssert])","kind":"f"}]}}},"modules":{"assert":{"props":[{"word":"deepEqual","info":"assert.deepEqual(actual, expected, [message])","kind":"f"},{"word":"doesNotThrow","info":"assert.doesNotThrow(block, [error], [message])","kind":"f"},{"word":"equal","info":"assert.equal(actual, expected, [message])","kind":"f"},{"word":"fail","info":"assert.fail(actual, expected, message, operator)","kind":"f"},{"word":"ifError","info":"assert.ifError(value)","kind":"f"},{"word":"notDeepEqual","info":"assert.notDeepEqual(actual, expected, [message])","kind":"f"},{"word":"notEqual","info":"assert.notEqual(actual, expected, [message])","kind":"f"},{"word":"notStrictEqual","info":"assert.notStrictEqual(actual, expected, [message])","kind":"f"},{"word":"ok","info":"assert(value, message), assert.ok(value, [message])","kind":"f"},{"word":"strictEqual","info":"assert.strictEqual(actual, expected, [message])","kind":"f"},{"word":"throws","info":"assert.throws(block, [error], [message])","kind":"f"}],"classes":{}},"buffer":{"props":[{"word":"Buffer","kind":"f","info":" "},{"word":"INSPECT_MAX_BYTES","kind":"m","info":" "},{"word":"SlowBuffer","kind":"f","info":" "}],"classes":{"Buffer":[{"word":"copy","info":"buf.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd])","kind":"f"},{"word":"fill","info":"buf.fill(value, [offset], [end])","kind":"f"},{"word":"length","kind":"m","info":" "},{"word":"readDoubleBE","info":"buf.readDoubleBE(offset, [noAssert])","kind":"f"},{"word":"readDoubleLE","info":"buf.readDoubleLE(offset, [noAssert])","kind":"f"},{"word":"readFloatBE","info":"buf.readFloatBE(offset, [noAssert])","kind":"f"},{"word":"readFloatLE","info":"buf.readFloatLE(offset, [noAssert])","kind":"f"},{"word":"readInt16BE","info":"buf.readInt16BE(offset, [noAssert])","kind":"f"},{"word":"readInt16LE","info":"buf.readInt16LE(offset, [noAssert])","kind":"f"},{"word":"readInt32BE","info":"buf.readInt32BE(offset, [noAssert])","kind":"f"},{"word":"readInt32LE","info":"buf.readInt32LE(offset, [noAssert])","kind":"f"},{"word":"readInt8","info":"buf.readInt8(offset, [noAssert])","kind":"f"},{"word":"readUInt16BE","info":"buf.readUInt16BE(offset, [noAssert])","kind":"f"},{"word":"readUInt16LE","info":"buf.readUInt16LE(offset, [noAssert])","kind":"f"},{"word":"readUInt32BE","info":"buf.readUInt32BE(offset, [noAssert])","kind":"f"},{"word":"readUInt32LE","info":"buf.readUInt32LE(offset, [noAssert])","kind":"f"},{"word":"readUInt8","info":"buf.readUInt8(offset, [noAssert])","kind":"f"},{"word":"slice","info":"buf.slice([start], [end])","kind":"f"},{"word":"toString","info":"buf.toString([encoding], [start], [end])","kind":"f"},{"word":"write","info":"buf.write(string, [offset], [length], [encoding])","kind":"f"},{"word":"writeDoubleBE","info":"buf.writeDoubleBE(value, offset, [noAssert])","kind":"f"},{"word":"writeDoubleLE","info":"buf.writeDoubleLE(value, offset, [noAssert])","kind":"f"},{"word":"writeFloatBE","info":"buf.writeFloatBE(value, offset, [noAssert])","kind":"f"},{"word":"writeFloatLE","info":"buf.writeFloatLE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt16BE","info":"buf.writeInt16BE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt16LE","info":"buf.writeInt16LE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt32BE","info":"buf.writeInt32BE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt32LE","info":"buf.writeInt32LE(value, offset, [noAssert])","kind":"f"},{"word":"writeInt8","info":"buf.writeInt8(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt16BE","info":"buf.writeUInt16BE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt16LE","info":"buf.writeUInt16LE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt32BE","info":"buf.writeUInt32BE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt32LE","info":"buf.writeUInt32LE(value, offset, [noAssert])","kind":"f"},{"word":"writeUInt8","info":"buf.writeUInt8(value, offset, [noAssert])","kind":"f"}],"SlowBuffer":[]}},"child_process":{"props":[{"word":"ChildProcess","kind":"f","info":" "},{"word":"exec","info":"child_process.exec(command, [options], callback)","kind":"f"},{"word":"execFile","info":"child_process.execFile(file, args, options, callback)","kind":"f"},{"word":"fork","info":"child\\_process.fork(modulePath, [args], [options])","kind":"f"},{"word":"spawn","info":"child_process.spawn(command, [args], [options])","kind":"f"}],"classes":{"ChildProcess":[{"word":"disconnect","info":"child.disconnect()","kind":"f"},{"word":"kill","info":"child.kill([signal])","kind":"f"},{"word":"pid","kind":"m","info":" "},{"word":"send","info":"child.send(message, [sendHandle])","kind":"f"},{"word":"stderr","kind":"m","info":" "},{"word":"stdin","kind":"m","info":" "},{"word":"stdout","kind":"m","info":" "}]}},"cluster":{"props":[{"word":"disconnect","info":"cluster.disconnect([callback])","kind":"f"},{"word":"fork","info":"cluster.fork([env])","kind":"f"},{"word":"isMaster","kind":"m","info":" "},{"word":"isWorker","kind":"m","info":" "},{"word":"settings","kind":"m","info":" "},{"word":"setupMaster","info":"cluster.setupMaster([settings])","kind":"f"},{"word":"worker","kind":"m","info":" "},{"word":"Worker","kind":"f","info":" "},{"word":"workers","kind":"m","info":" "}],"classes":{"Worker":[{"word":"destroy","info":"worker.destroy()","kind":"f"},{"word":"disconnect","info":"worker.disconnect()","kind":"f"},{"word":"id","kind":"m","info":" "},{"word":"process","kind":"m","info":" "},{"word":"send","info":"worker.send(message, [sendHandle])","kind":"f"},{"word":"suicide","kind":"m","info":" "}]}},"crypto":{"props":[{"word":"Cipher","kind":"f","info":" "},{"word":"createCipher","info":"crypto.createCipher(algorithm, password)","kind":"f"},{"word":"createCipheriv","info":"crypto.createCipheriv(algorithm, key, iv)","kind":"f"},{"word":"createCredentials","info":"crypto.createCredentials(details)","kind":"f"},{"word":"createDecipher","info":"crypto.createDecipher(algorithm, password)","kind":"f"},{"word":"createDecipheriv","info":"crypto.createDecipheriv(algorithm, key, iv)","kind":"f"},{"word":"createDiffieHellman","info":"crypto.createDiffieHellman(prime, [encoding])","kind":"f"},{"word":"createDiffieHellman","info":"crypto.createDiffieHellman(prime_length)","kind":"f"},{"word":"createHash","info":"crypto.createHash(algorithm)","kind":"f"},{"word":"createHmac","info":"crypto.createHmac(algorithm, key)","kind":"f"},{"word":"createSign","info":"crypto.createSign(algorithm)","kind":"f"},{"word":"createVerify","info":"crypto.createVerify(algorithm)","kind":"f"},{"word":"Decipher","kind":"f","info":" "},{"word":"DiffieHellman","kind":"f","info":" "},{"word":"getDiffieHellman","info":"crypto.getDiffieHellman(group_name)","kind":"f"},{"word":"Hash","kind":"f","info":" "},{"word":"Hmac","kind":"f","info":" "},{"word":"pbkdf2","info":"crypto.pbkdf2(password, salt, iterations, keylen, callback)","kind":"f"},{"word":"randomBytes","info":"crypto.randomBytes(size, [callback])","kind":"f"},{"word":"Signer","kind":"f","info":" "},{"word":"Verify","kind":"f","info":" "}],"classes":{"Hash":[{"word":"digest","info":"hash.digest([encoding])","kind":"f"},{"word":"update","info":"hash.update(data, [input_encoding])","kind":"f"}],"Hmac":[{"word":"digest","info":"hmac.digest([encoding])","kind":"f"},{"word":"update","info":"hmac.update(data)","kind":"f"}],"Cipher":[{"word":"final","info":"cipher.final([output_encoding])","kind":"f"},{"word":"setAutoPadding","info":"cipher.setAutoPadding(auto_padding=true)","kind":"f"},{"word":"update","info":"cipher.update(data, [input_encoding], [output_encoding])","kind":"f"}],"Decipher":[{"word":"final","info":"decipher.final([output_encoding])","kind":"f"},{"word":"setAutoPadding","info":"decipher.setAutoPadding(auto_padding=true)","kind":"f"},{"word":"update","info":"decipher.update(data, [input_encoding], [output_encoding])","kind":"f"}],"Signer":[{"word":"sign","info":"signer.sign(private_key, [output_format])","kind":"f"},{"word":"update","info":"signer.update(data)","kind":"f"}],"Verify":[{"word":"update","info":"verifier.update(data)","kind":"f"},{"word":"verify","info":"verifier.verify(object, signature, [signature_format])","kind":"f"}],"DiffieHellman":[{"word":"computeSecret","info":"diffieHellman.computeSecret(other_public_key, [input_encoding], [output_encoding])","kind":"f"},{"word":"generateKeys","info":"diffieHellman.generateKeys([encoding])","kind":"f"},{"word":"getGenerator","info":"diffieHellman.getGenerator([encoding])","kind":"f"},{"word":"getPrime","info":"diffieHellman.getPrime([encoding])","kind":"f"},{"word":"getPrivateKey","info":"diffieHellman.getPrivateKey([encoding])","kind":"f"},{"word":"getPublicKey","info":"diffieHellman.getPublicKey([encoding])","kind":"f"},{"word":"setPrivateKey","info":"diffieHellman.setPrivateKey(public_key, [encoding])","kind":"f"},{"word":"setPublicKey","info":"diffieHellman.setPublicKey(public_key, [encoding])","kind":"f"}]}},"dgram":{"props":[{"word":"createSocket","info":"dgram.createSocket(type, [callback])","kind":"f"},{"word":"Socket","kind":"f","info":" "}],"classes":{"Socket":[{"word":"addMembership","info":"dgram.addMembership(multicastAddress, [multicastInterface])","kind":"f"},{"word":"address","info":"dgram.address()","kind":"f"},{"word":"bind","info":"dgram.bind(port, [address])","kind":"f"},{"word":"close","info":"dgram.close()","kind":"f"},{"word":"dropMembership","info":"dgram.dropMembership(multicastAddress, [multicastInterface])","kind":"f"},{"word":"send","info":"dgram.send(buf, offset, length, port, address, [callback])","kind":"f"},{"word":"setBroadcast","info":"dgram.setBroadcast(flag)","kind":"f"},{"word":"setMulticastLoopback","info":"dgram.setMulticastLoopback(flag)","kind":"f"},{"word":"setMulticastTTL","info":"dgram.setMulticastTTL(ttl)","kind":"f"},{"word":"setTTL","info":"dgram.setTTL(ttl)","kind":"f"}]}},"dns":{"props":[{"word":"lookup","info":"dns.lookup(domain, [family], callback)","kind":"f"},{"word":"resolve","info":"dns.resolve(domain, [rrtype], callback)","kind":"f"},{"word":"resolve4","info":"dns.resolve4(domain, callback)","kind":"f"},{"word":"resolve6","info":"dns.resolve6(domain, callback)","kind":"f"},{"word":"resolveCname","info":"dns.resolveCname(domain, callback)","kind":"f"},{"word":"resolveMx","info":"dns.resolveMx(domain, callback)","kind":"f"},{"word":"resolveNs","info":"dns.resolveNs(domain, callback)","kind":"f"},{"word":"resolveSrv","info":"dns.resolveSrv(domain, callback)","kind":"f"},{"word":"resolveTxt","info":"dns.resolveTxt(domain, callback)","kind":"f"},{"word":"reverse","info":"dns.reverse(ip, callback)","kind":"f"}],"classes":{}},"domain":{"props":[{"word":"create","info":"domain.create()","kind":"f"},{"word":"Domain","kind":"f","info":" "}],"classes":{"Domain":[{"word":"add","info":"domain.add(emitter)","kind":"f"},{"word":"bind","info":"domain.bind(callback)","kind":"f"},{"word":"dispose","info":"domain.dispose()","kind":"f"},{"word":"intercept","info":"domain.intercept(callback)","kind":"f"},{"word":"members","kind":"m","info":" "},{"word":"remove","info":"domain.remove(emitter)","kind":"f"},{"word":"run","info":"domain.run(fn)","kind":"f"}]}},"events":{"props":[{"word":"EventEmitter","kind":"f","info":" "}],"classes":{"EventEmitter":[{"word":"addListener","info":"emitter.addListener(event, listener)","kind":"f"},{"word":"emit","info":"emitter.emit(event, [arg1], [arg2], [...])","kind":"f"},{"word":"listeners","info":"emitter.listeners(event)","kind":"f"},{"word":"on","info":"emitter.on(event, listener)","kind":"f"},{"word":"once","info":"emitter.once(event, listener)","kind":"f"},{"word":"removeAllListeners","info":"emitter.removeAllListeners([event])","kind":"f"},{"word":"removeListener","info":"emitter.removeListener(event, listener)","kind":"f"},{"word":"setMaxListeners","info":"emitter.setMaxListeners(n)","kind":"f"}]}},"fs":{"props":[{"word":"appendFile","info":"fs.appendFile(filename, data, encoding='utf8', [callback])","kind":"f"},{"word":"appendFileSync","info":"fs.appendFileSync(filename, data, encoding='utf8')","kind":"f"},{"word":"chmod","info":"fs.chmod(path, mode, [callback])","kind":"f"},{"word":"chmodSync","info":"fs.chmodSync(path, mode)","kind":"f"},{"word":"chown","info":"fs.chown(path, uid, gid, [callback])","kind":"f"},{"word":"chownSync","info":"fs.chownSync(path, uid, gid)","kind":"f"},{"word":"close","info":"fs.close(fd, [callback])","kind":"f"},{"word":"closeSync","info":"fs.closeSync(fd)","kind":"f"},{"word":"createReadStream","info":"fs.createReadStream(path, [options])","kind":"f"},{"word":"createWriteStream","info":"fs.createWriteStream(path, [options])","kind":"f"},{"word":"exists","info":"fs.exists(path, [callback])","kind":"f"},{"word":"existsSync","info":"fs.existsSync(path)","kind":"f"},{"word":"fchmod","info":"fs.fchmod(fd, mode, [callback])","kind":"f"},{"word":"fchmodSync","info":"fs.fchmodSync(fd, mode)","kind":"f"},{"word":"fchown","info":"fs.fchown(fd, uid, gid, [callback])","kind":"f"},{"word":"fchownSync","info":"fs.fchownSync(fd, uid, gid)","kind":"f"},{"word":"fstat","info":"fs.fstat(fd, [callback])","kind":"f"},{"word":"fstatSync","info":"fs.fstatSync(fd)","kind":"f"},{"word":"FSWatcher","kind":"f","info":" "},{"word":"fsync","info":"fs.fsync(fd, [callback])","kind":"f"},{"word":"fsyncSync","info":"fs.fsyncSync(fd)","kind":"f"},{"word":"futimes","info":"fs.futimes(fd, atime, mtime, [callback])","kind":"f"},{"word":"futimesSync","info":"fs.futimesSync(fd, atime, mtime)","kind":"f"},{"word":"lchmod","info":"fs.lchmod(path, mode, [callback])","kind":"f"},{"word":"lchmodSync","info":"fs.lchmodSync(path, mode)","kind":"f"},{"word":"lchown","info":"fs.lchown(path, uid, gid, [callback])","kind":"f"},{"word":"lchownSync","info":"fs.lchownSync(path, uid, gid)","kind":"f"},{"word":"link","info":"fs.link(srcpath, dstpath, [callback])","kind":"f"},{"word":"linkSync","info":"fs.linkSync(srcpath, dstpath)","kind":"f"},{"word":"lstat","info":"fs.lstat(path, [callback])","kind":"f"},{"word":"lstatSync","info":"fs.lstatSync(path)","kind":"f"},{"word":"mkdir","info":"fs.mkdir(path, [mode], [callback])","kind":"f"},{"word":"mkdirSync","info":"fs.mkdirSync(path, [mode])","kind":"f"},{"word":"open","info":"fs.open(path, flags, [mode], [callback])","kind":"f"},{"word":"openSync","info":"fs.openSync(path, flags, [mode])","kind":"f"},{"word":"read","info":"fs.read(fd, buffer, offset, length, position, [callback])","kind":"f"},{"word":"readdir","info":"fs.readdir(path, [callback])","kind":"f"},{"word":"readdirSync","info":"fs.readdirSync(path)","kind":"f"},{"word":"readFile","info":"fs.readFile(filename, [encoding], [callback])","kind":"f"},{"word":"readFileSync","info":"fs.readFileSync(filename, [encoding])","kind":"f"},{"word":"readlink","info":"fs.readlink(path, [callback])","kind":"f"},{"word":"readlinkSync","info":"fs.readlinkSync(path)","kind":"f"},{"word":"ReadStream","kind":"f","info":" "},{"word":"readSync","info":"fs.readSync(fd, buffer, offset, length, position)","kind":"f"},{"word":"realpath","info":"fs.realpath(path, [cache], callback)","kind":"f"},{"word":"realpathSync","info":"fs.realpathSync(path, [cache])","kind":"f"},{"word":"rename","info":"fs.rename(oldPath, newPath, [callback])","kind":"f"},{"word":"renameSync","info":"fs.renameSync(oldPath, newPath)","kind":"f"},{"word":"rmdir","info":"fs.rmdir(path, [callback])","kind":"f"},{"word":"rmdirSync","info":"fs.rmdirSync(path)","kind":"f"},{"word":"stat","info":"fs.stat(path, [callback])","kind":"f"},{"word":"Stats","kind":"f","info":" "},{"word":"statSync","info":"fs.statSync(path)","kind":"f"},{"word":"symlink","info":"fs.symlink(srcpath, dstpath, [type], [callback])","kind":"f"},{"word":"symlinkSync","info":"fs.symlinkSync(srcpath, dstpath, [type])","kind":"f"},{"word":"truncate","info":"fs.truncate(fd, len, [callback])","kind":"f"},{"word":"truncateSync","info":"fs.truncateSync(fd, len)","kind":"f"},{"word":"unlink","info":"fs.unlink(path, [callback])","kind":"f"},{"word":"unlinkSync","info":"fs.unlinkSync(path)","kind":"f"},{"word":"unwatchFile","info":"fs.unwatchFile(filename, [listener])","kind":"f"},{"word":"utimes","info":"fs.utimes(path, atime, mtime, [callback])","kind":"f"},{"word":"utimesSync","info":"fs.utimesSync(path, atime, mtime)","kind":"f"},{"word":"watch","info":"fs.watch(filename, [options], [listener])","kind":"f"},{"word":"watchFile","info":"fs.watchFile(filename, [options], listener)","kind":"f"},{"word":"write","info":"fs.write(fd, buffer, offset, length, position, [callback])","kind":"f"},{"word":"writeFile","info":"fs.writeFile(filename, data, [encoding], [callback])","kind":"f"},{"word":"writeFileSync","info":"fs.writeFileSync(filename, data, [encoding])","kind":"f"},{"word":"WriteStream","kind":"m","info":" "},{"word":"writeSync","info":"fs.writeSync(fd, buffer, offset, length, position)","kind":"f"}],"classes":{"Stats":[],"ReadStream":[],"FSWatcher":[{"word":"close","info":"watcher.close()","kind":"f"}]}},"http":{"props":[{"word":"Agent","kind":"f","info":" "},{"word":"ClientRequest","kind":"f","info":" "},{"word":"ClientResponse","kind":"m","info":" "},{"word":"createClient","info":"http.createClient([port], [host])","kind":"f"},{"word":"createServer","info":"http.createServer([requestListener])","kind":"f"},{"word":"get","info":"http.get(options, callback)","kind":"f"},{"word":"globalAgent","kind":"m","info":" "},{"word":"request","info":"http.request(options, callback)","kind":"f"},{"word":"Server","kind":"f","info":" "},{"word":"ServerRequest","kind":"f","info":" "},{"word":"ServerResponse","kind":"f","info":" "},{"word":"STATUS_CODES","kind":"m","info":" "}],"classes":{"Server":[{"word":"close","info":"server.close([callback])","kind":"f"},{"word":"listen","info":"server.listen(port, [hostname], [backlog], [callback])","kind":"f"},{"word":"listen","info":"server.listen(path, [callback])","kind":"f"},{"word":"listen","info":"server.listen(handle, [callback])","kind":"f"},{"word":"maxHeadersCount","kind":"m","info":" "}],"ServerRequest":[{"word":"connection","kind":"m","info":" "},{"word":"headers","kind":"m","info":" "},{"word":"httpVersion","kind":"m","info":" "},{"word":"method","kind":"m","info":" "},{"word":"pause","info":"request.pause()","kind":"f"},{"word":"resume","info":"request.resume()","kind":"f"},{"word":"setEncoding","info":"request.setEncoding([encoding])","kind":"f"},{"word":"trailers","kind":"m","info":" "},{"word":"url","kind":"m","info":" "}],"ServerResponse":[{"word":"addTrailers","info":"response.addTrailers(headers)","kind":"f"},{"word":"end","info":"response.end([data], [encoding])","kind":"f"},{"word":"getHeader","info":"response.getHeader(name)","kind":"f"},{"word":"removeHeader","info":"response.removeHeader(name)","kind":"f"},{"word":"sendDate","kind":"m","info":" "},{"word":"setHeader","info":"response.setHeader(name, value)","kind":"f"},{"word":"statusCode","kind":"m","info":" "},{"word":"write","info":"response.write(chunk, [encoding])","kind":"f"},{"word":"writeContinue","info":"response.writeContinue()","kind":"f"},{"word":"writeHead","info":"response.writeHead(statusCode, [reasonPhrase], [headers])","kind":"f"}],"Agent":[{"word":"maxSockets","kind":"m","info":" "},{"word":"requests","kind":"m","info":" "},{"word":"sockets","kind":"m","info":" "}],"ClientRequest":[{"word":"abort","info":"request.abort()","kind":"f"},{"word":"end","info":"request.end([data], [encoding])","kind":"f"},{"word":"setNoDelay","info":"request.setNoDelay([noDelay])","kind":"f"},{"word":"setSocketKeepAlive","info":"request.setSocketKeepAlive([enable], [initialDelay])","kind":"f"},{"word":"setTimeout","info":"request.setTimeout(timeout, [callback])","kind":"f"},{"word":"write","info":"request.write(chunk, [encoding])","kind":"f"}]}},"https":{"props":[{"word":"Agent","kind":"f","info":" "},{"word":"createServer","info":"https.createServer(options, [requestListener])","kind":"f"},{"word":"get","info":"https.get(options, callback)","kind":"f"},{"word":"globalAgent","kind":"m","info":" "},{"word":"request","info":"https.request(options, callback)","kind":"f"},{"word":"Server","kind":"f","info":" "}],"classes":{"Server":[],"Agent":[]}},"net":{"props":[{"word":"connect","info":"net.connect(port, [host], [connectListener])","kind":"f"},{"word":"connect","info":"net.connect(path, [connectListener])","kind":"f"},{"word":"connect","info":"net.connect(options, [connectionListener])","kind":"f"},{"word":"createConnection","info":"net.createConnection(path, [connectListener])","kind":"f"},{"word":"createConnection","info":"net.createConnection(options, [connectionListener])","kind":"f"},{"word":"createConnection","info":"net.createConnection(port, [host], [connectListener])","kind":"f"},{"word":"createServer","info":"net.createServer([options], [connectionListener])","kind":"f"},{"word":"isIP","info":"net.isIP(input)","kind":"f"},{"word":"isIPv4","info":"net.isIPv4(input)","kind":"f"},{"word":"isIPv6","info":"net.isIPv6(input)","kind":"f"},{"word":"Server","kind":"f","info":" "},{"word":"Socket","kind":"f","info":" "}],"classes":{"Server":[{"word":"address","info":"server.address()","kind":"f"},{"word":"close","info":"server.close([callback])","kind":"f"},{"word":"connections","kind":"m","info":" "},{"word":"listen","info":"server.listen(port, [host], [backlog], [callback])","kind":"f"},{"word":"listen","info":"server.listen(path, [callback])","kind":"f"},{"word":"listen","info":"server.listen(handle, [callback])","kind":"f"},{"word":"maxConnections","kind":"m","info":" "}],"Socket":[{"word":"address","info":"socket.address()","kind":"f"},{"word":"bufferSize","kind":"m","info":" "},{"word":"bytesRead","kind":"m","info":" "},{"word":"bytesWritten","kind":"m","info":" "},{"word":"connect","info":"socket.connect(port, [host], [connectListener])","kind":"f"},{"word":"connect","info":"socket.connect(path, [connectListener])","kind":"f"},{"word":"destroy","info":"socket.destroy()","kind":"f"},{"word":"end","info":"socket.end([data], [encoding])","kind":"f"},{"word":"pause","info":"socket.pause()","kind":"f"},{"word":"remoteAddress","kind":"m","info":" "},{"word":"remotePort","kind":"m","info":" "},{"word":"resume","info":"socket.resume()","kind":"f"},{"word":"setEncoding","info":"socket.setEncoding([encoding])","kind":"f"},{"word":"setKeepAlive","info":"socket.setKeepAlive([enable], [initialDelay])","kind":"f"},{"word":"setNoDelay","info":"socket.setNoDelay([noDelay])","kind":"f"},{"word":"setTimeout","info":"socket.setTimeout(timeout, [callback])","kind":"f"},{"word":"Socket","info":"new net.Socket([options])","kind":"f"},{"word":"write","info":"socket.write(data, [encoding], [callback])","kind":"f"}]}},"os":{"props":[{"word":"arch","info":"os.arch()","kind":"f"},{"word":"cpus","info":"os.cpus()","kind":"f"},{"word":"EOL","kind":"m","info":" "},{"word":"freemem","info":"os.freemem()","kind":"f"},{"word":"hostname","info":"os.hostname()","kind":"f"},{"word":"loadavg","info":"os.loadavg()","kind":"f"},{"word":"networkInterfaces","info":"os.networkInterfaces()","kind":"f"},{"word":"platform","info":"os.platform()","kind":"f"},{"word":"release","info":"os.release()","kind":"f"},{"word":"tmpDir","info":"os.tmpDir()","kind":"f"},{"word":"totalmem","info":"os.totalmem()","kind":"f"},{"word":"type","info":"os.type()","kind":"f"},{"word":"uptime","info":"os.uptime()","kind":"f"}],"classes":{}},"path":{"props":[{"word":"basename","info":"path.basename(p, [ext])","kind":"f"},{"word":"dirname","info":"path.dirname(p)","kind":"f"},{"word":"extname","info":"path.extname(p)","kind":"f"},{"word":"join","info":"path.join([path1], [path2], [...])","kind":"f"},{"word":"normalize","info":"path.normalize(p)","kind":"f"},{"word":"relative","info":"path.relative(from, to)","kind":"f"},{"word":"resolve","info":"path.resolve([from ...], to)","kind":"f"},{"word":"sep","kind":"m","info":" "}],"classes":{}},"punycode":{"props":[{"word":"decode","info":"punycode.decode(string)","kind":"f"},{"word":"encode","info":"punycode.encode(string)","kind":"f"},{"word":"toASCII","info":"punycode.toASCII(domain)","kind":"f"},{"word":"toUnicode","info":"punycode.toUnicode(domain)","kind":"f"},{"word":"ucs2","kind":"m","info":" "},{"word":"version","kind":"m","info":" "}],"classes":{}},"querystring":{"props":[{"word":"escape","kind":"m","info":" "},{"word":"parse","info":"querystring.parse(str, [sep], [eq], [options])","kind":"f"},{"word":"stringify","info":"querystring.stringify(obj, [sep], [eq])","kind":"f"},{"word":"unescape","kind":"m","info":" "}],"classes":{}},"readline":{"props":[{"word":"createInterface","info":"readline.createInterface(options)","kind":"f"},{"word":"Interface","kind":"f","info":" "}],"classes":{"Interface":[{"word":"close","info":"rl.close()","kind":"f"},{"word":"pause","info":"rl.pause()","kind":"f"},{"word":"prompt","info":"rl.prompt([preserveCursor])","kind":"f"},{"word":"question","info":"rl.question(query, callback)","kind":"f"},{"word":"resume","info":"rl.resume()","kind":"f"},{"word":"setPrompt","info":"rl.setPrompt(prompt, length)","kind":"f"},{"word":"write","info":"rl.write(data, [key])","kind":"f"}]}},"repl":{"props":[{"word":"start","info":"repl.start(options)","kind":"f"}],"classes":{}},"stream":{"props":[],"classes":{"Readable Stream":[{"word":"destroy","info":"stream.destroy()","kind":"f"},{"word":"pause","info":"stream.pause()","kind":"f"},{"word":"pipe","info":"stream.pipe(destination, [options])","kind":"f"},{"word":"readable","kind":"m","info":" "},{"word":"resume","info":"stream.resume()","kind":"f"},{"word":"setEncoding","info":"stream.setEncoding([encoding])","kind":"f"}],"Writable Stream":[{"word":"destroy","info":"stream.destroy()","kind":"f"},{"word":"destroySoon","info":"stream.destroySoon()","kind":"f"},{"word":"end","info":"stream.end()","kind":"f"},{"word":"end","info":"stream.end(string, encoding)","kind":"f"},{"word":"end","info":"stream.end(buffer)","kind":"f"},{"word":"writable","kind":"m","info":" "},{"word":"write","info":"stream.write(string, [encoding])","kind":"f"},{"word":"write","info":"stream.write(buffer)","kind":"f"}]}},"stringdecoder":{"props":[{"word":"StringDecoder","kind":"f","info":" "}],"classes":{"StringDecoder":[{"word":"write","info":"StringDecoder.write(buffer)","kind":"f"}]}},"timers":{"props":[{"word":"clearInterval","info":"clearInterval(intervalId)","kind":"f"},{"word":"clearTimeout","info":"clearTimeout(timeoutId)","kind":"f"},{"word":"setInterval","info":"setInterval(callback, delay, [arg], [...])","kind":"f"},{"word":"setTimeout","info":"setTimeout(callback, delay, [arg], [...])","kind":"f"}],"classes":{}},"tls":{"props":[{"word":"CleartextStream","kind":"f","info":" "},{"word":"connect","info":"tls.connect(options, [callback])","kind":"f"},{"word":"connect","info":"tls.connect(port, [host], [options], [callback])","kind":"f"},{"word":"createSecurePair","info":"tls.createSecurePair([credentials], [isServer], [requestCert], [rejectUnauthorized])","kind":"f"},{"word":"createServer","info":"tls.createServer(options, [secureConnectionListener])","kind":"f"},{"word":"SecurePair","kind":"f","info":" "},{"word":"Server","kind":"f","info":" "}],"classes":{"SecurePair":[],"Server":[{"word":"addContext","info":"server.addContext(hostname, credentials)","kind":"f"},{"word":"address","info":"server.address()","kind":"f"},{"word":"close","info":"server.close()","kind":"f"},{"word":"connections","kind":"m","info":" "},{"word":"listen","info":"server.listen(port, [host], [callback])","kind":"f"},{"word":"maxConnections","kind":"m","info":" "}],"CleartextStream":[{"word":"address","info":"cleartextStream.address()","kind":"f"},{"word":"authorizationError","kind":"m","info":" "},{"word":"authorized","kind":"m","info":" "},{"word":"getCipher","info":"cleartextStream.getCipher()","kind":"f"},{"word":"getPeerCertificate","info":"cleartextStream.getPeerCertificate()","kind":"f"},{"word":"remoteAddress","kind":"m","info":" "},{"word":"remotePort","kind":"m","info":" "}]}},"tty":{"props":[{"word":"isatty","info":"tty.isatty(fd)","kind":"f"},{"word":"ReadStream","kind":"f","info":" "},{"word":"setRawMode","info":"tty.setRawMode(mode)","kind":"f"}],"classes":{"ReadStream":[{"word":"isRaw","kind":"m","info":" "},{"word":"setRawMode","info":"rs.setRawMode(mode)","kind":"f"}]}},"url":{"props":[{"word":"format","info":"url.format(urlObj)","kind":"f"},{"word":"parse","info":"url.parse(urlStr, [parseQueryString], [slashesDenoteHost])","kind":"f"},{"word":"resolve","info":"url.resolve(from, to)","kind":"f"}],"classes":{}},"util":{"props":[{"word":"debug","info":"util.debug(string)","kind":"f"},{"word":"error","info":"util.error([...])","kind":"f"},{"word":"format","info":"util.format(format, [...])","kind":"f"},{"word":"inherits","info":"util.inherits(constructor, superConstructor)","kind":"f"},{"word":"inspect","info":"util.inspect(object, [showHidden], [depth], [colors])","kind":"f"},{"word":"isArray","info":"util.isArray(object)","kind":"f"},{"word":"isDate","info":"util.isDate(object)","kind":"f"},{"word":"isError","info":"util.isError(object)","kind":"f"},{"word":"isRegExp","info":"util.isRegExp(object)","kind":"f"},{"word":"log","info":"util.log(string)","kind":"f"},{"word":"print","info":"util.print([...])","kind":"f"},{"word":"pump","info":"util.pump(readableStream, writableStream, [callback])","kind":"f"},{"word":"puts","info":"util.puts([...])","kind":"f"}],"classes":{}},"vm":{"props":[{"word":"createContext","info":"vm.createContext([initSandbox])","kind":"f"},{"word":"createScript","info":"vm.createScript(code, [filename])","kind":"f"},{"word":"runInContext","info":"vm.runInContext(code, context, [filename])","kind":"f"},{"word":"runInNewContext","info":"vm.runInNewContext(code, [sandbox], [filename])","kind":"f"},{"word":"runInThisContext","info":"vm.runInThisContext(code, [filename])","kind":"f"},{"word":"Script","kind":"f","info":" "}],"classes":{"Script":[{"word":"runInNewContext","info":"script.runInNewContext([sandbox])","kind":"f"},{"word":"runInThisContext","info":"script.runInThisContext()","kind":"f"}]}},"zlib":{"props":[{"word":"createDeflate","info":"zlib.createDeflate([options])","kind":"f"},{"word":"createDeflateRaw","info":"zlib.createDeflateRaw([options])","kind":"f"},{"word":"createGunzip","info":"zlib.createGunzip([options])","kind":"f"},{"word":"createGzip","info":"zlib.createGzip([options])","kind":"f"},{"word":"createInflate","info":"zlib.createInflate([options])","kind":"f"},{"word":"createInflateRaw","info":"zlib.createInflateRaw([options])","kind":"f"},{"word":"createUnzip","info":"zlib.createUnzip([options])","kind":"f"},{"word":"deflate","info":"zlib.deflate(buf, callback)","kind":"f"},{"word":"Deflate","kind":"f","info":" "},{"word":"deflateRaw","info":"zlib.deflateRaw(buf, callback)","kind":"f"},{"word":"DeflateRaw","kind":"f","info":" "},{"word":"gunzip","info":"zlib.gunzip(buf, callback)","kind":"f"},{"word":"Gunzip","kind":"f","info":" "},{"word":"Gzip","kind":"f","info":" "},{"word":"gzip","info":"zlib.gzip(buf, callback)","kind":"f"},{"word":"inflate","info":"zlib.inflate(buf, callback)","kind":"f"},{"word":"Inflate","kind":"f","info":" "},{"word":"inflateRaw","info":"zlib.inflateRaw(buf, callback)","kind":"f"},{"word":"InflateRaw","kind":"f","info":" "},{"word":"unzip","info":"zlib.unzip(buf, callback)","kind":"f"},{"word":"Unzip","kind":"f","info":" "}],"classes":{"Gzip":[],"Gunzip":[],"Deflate":[],"Inflate":[],"DeflateRaw":[],"InflateRaw":[],"Unzip":[]}}},"vars":[{"word":"__dirname","kind":"v","info":" "},{"word":"__filename","kind":"v","info":" "},{"word":"Buffer","kind":"v","info":" "},{"word":"clearInterval","info":"clearInterval(t)","kind":"f"},{"word":"console","kind":"v","info":" "},{"word":"console","kind":"v","info":" "},{"word":"exports","kind":"v","info":" "},{"word":"global","kind":"v","info":" "},{"word":"module","kind":"v","info":" "},{"word":"process","kind":"v","info":" "},{"word":"process","kind":"v","info":" "},{"word":"require","info":"require()","kind":"f"}]} -------------------------------------------------------------------------------- /autoload/plug.vim.old: -------------------------------------------------------------------------------- 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 | " " Multiple Plug commands can be written in a single line using | separators 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 | " " Initialize plugin system 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 ``-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) 2017 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') 100 | let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) 101 | let s:vim8 = has('patch-8.0.0039') && exists('*job_start') 102 | let s:me = resolve(expand(':p')) 103 | let s:base_spec = { 'branch': 'master', 'frozen': 0 } 104 | let s:TYPE = { 105 | \ 'string': type(''), 106 | \ 'list': type([]), 107 | \ 'dict': type({}), 108 | \ 'funcref': type(function('call')) 109 | \ } 110 | let s:loaded = get(s:, 'loaded', {}) 111 | let s:triggers = get(s:, 'triggers', {}) 112 | 113 | function! plug#begin(...) 114 | if a:0 > 0 115 | let s:plug_home_org = a:1 116 | let home = s:path(fnamemodify(expand(a:1), ':p')) 117 | elseif exists('g:plug_home') 118 | let home = s:path(g:plug_home) 119 | elseif !empty(&rtp) 120 | let home = s:path(split(&rtp, ',')[0]) . '/plugged' 121 | else 122 | return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') 123 | endif 124 | if fnamemodify(home, ':t') ==# 'plugin' && fnamemodify(home, ':h') ==# s:first_rtp 125 | return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.') 126 | endif 127 | 128 | let g:plug_home = home 129 | let g:plugs = {} 130 | let g:plugs_order = [] 131 | let s:triggers = {} 132 | 133 | call s:define_commands() 134 | return 1 135 | endfunction 136 | 137 | function! s:define_commands() 138 | command! -nargs=+ -bar Plug call plug#() 139 | if !executable('git') 140 | return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') 141 | endif 142 | command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(0, []) 143 | command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(0, []) 144 | command! -nargs=0 -bar -bang PlugClean call s:clean(0) 145 | command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif 146 | command! -nargs=0 -bar PlugStatus call s:status() 147 | command! -nargs=0 -bar PlugDiff call s:diff() 148 | command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(0, ) 149 | endfunction 150 | 151 | function! s:to_a(v) 152 | return type(a:v) == s:TYPE.list ? a:v : [a:v] 153 | endfunction 154 | 155 | function! s:to_s(v) 156 | return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" 157 | endfunction 158 | 159 | function! s:glob(from, pattern) 160 | return s:lines(globpath(a:from, a:pattern)) 161 | endfunction 162 | 163 | function! s:source(from, ...) 164 | let found = 0 165 | for pattern in a:000 166 | for vim in s:glob(a:from, pattern) 167 | execute 'source' s:esc(vim) 168 | let found = 1 169 | endfor 170 | endfor 171 | return found 172 | endfunction 173 | 174 | function! s:assoc(dict, key, val) 175 | let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) 176 | endfunction 177 | 178 | function! s:ask(message, ...) 179 | call inputsave() 180 | echohl WarningMsg 181 | let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) 182 | echohl None 183 | call inputrestore() 184 | echo "\r" 185 | return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 186 | endfunction 187 | 188 | function! s:ask_no_interrupt(...) 189 | try 190 | return call('s:ask', a:000) 191 | catch 192 | return 0 193 | endtry 194 | endfunction 195 | 196 | function! s:lazy(plug, opt) 197 | return has_key(a:plug, a:opt) && 198 | \ (empty(s:to_a(a:plug[a:opt])) || 199 | \ !isdirectory(a:plug.dir) || 200 | \ len(s:glob(s:rtp(a:plug), 'plugin')) || 201 | \ len(s:glob(s:rtp(a:plug), 'after/plugin'))) 202 | endfunction 203 | 204 | function! plug#end() 205 | if !exists('g:plugs') 206 | return s:err('Call plug#begin() first') 207 | endif 208 | 209 | if exists('#PlugLOD') 210 | augroup PlugLOD 211 | autocmd! 212 | augroup END 213 | augroup! PlugLOD 214 | endif 215 | let lod = { 'ft': {}, 'map': {}, 'cmd': {} } 216 | 217 | if exists('g:did_load_filetypes') 218 | filetype off 219 | endif 220 | for name in g:plugs_order 221 | if !has_key(g:plugs, name) 222 | continue 223 | endif 224 | let plug = g:plugs[name] 225 | if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for') 226 | let s:loaded[name] = 1 227 | continue 228 | endif 229 | 230 | if has_key(plug, 'on') 231 | let s:triggers[name] = { 'map': [], 'cmd': [] } 232 | for cmd in s:to_a(plug.on) 233 | if cmd =~? '^.\+' 234 | if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) 235 | call s:assoc(lod.map, cmd, name) 236 | endif 237 | call add(s:triggers[name].map, cmd) 238 | elseif cmd =~# '^[A-Z]' 239 | let cmd = substitute(cmd, '!*$', '', '') 240 | if exists(':'.cmd) != 2 241 | call s:assoc(lod.cmd, cmd, name) 242 | endif 243 | call add(s:triggers[name].cmd, cmd) 244 | else 245 | call s:err('Invalid `on` option: '.cmd. 246 | \ '. Should start with an uppercase letter or ``.') 247 | endif 248 | endfor 249 | endif 250 | 251 | if has_key(plug, 'for') 252 | let types = s:to_a(plug.for) 253 | if !empty(types) 254 | augroup filetypedetect 255 | call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') 256 | augroup END 257 | endif 258 | for type in types 259 | call s:assoc(lod.ft, type, name) 260 | endfor 261 | endif 262 | endfor 263 | 264 | for [cmd, names] in items(lod.cmd) 265 | execute printf( 266 | \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "", , , , %s)', 267 | \ cmd, string(cmd), string(names)) 268 | endfor 269 | 270 | for [map, names] in items(lod.map) 271 | for [mode, map_prefix, key_prefix] in 272 | \ [['i', '', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] 273 | execute printf( 274 | \ '%snoremap %s %s:call lod_map(%s, %s, %s, "%s")', 275 | \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix) 276 | endfor 277 | endfor 278 | 279 | for [ft, names] in items(lod.ft) 280 | augroup PlugLOD 281 | execute printf('autocmd FileType %s call lod_ft(%s, %s)', 282 | \ ft, string(ft), string(names)) 283 | augroup END 284 | endfor 285 | 286 | call s:reorg_rtp() 287 | filetype plugin indent on 288 | if has('vim_starting') 289 | if has('syntax') && !exists('g:syntax_on') 290 | syntax enable 291 | end 292 | else 293 | call s:reload_plugins() 294 | endif 295 | endfunction 296 | 297 | function! s:loaded_names() 298 | return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') 299 | endfunction 300 | 301 | function! s:load_plugin(spec) 302 | call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') 303 | endfunction 304 | 305 | function! s:reload_plugins() 306 | for name in s:loaded_names() 307 | call s:load_plugin(g:plugs[name]) 308 | endfor 309 | endfunction 310 | 311 | function! s:trim(str) 312 | return substitute(a:str, '[\/]\+$', '', '') 313 | endfunction 314 | 315 | function! s:version_requirement(val, min) 316 | for idx in range(0, len(a:min) - 1) 317 | let v = get(a:val, idx, 0) 318 | if v < a:min[idx] | return 0 319 | elseif v > a:min[idx] | return 1 320 | endif 321 | endfor 322 | return 1 323 | endfunction 324 | 325 | function! s:git_version_requirement(...) 326 | if !exists('s:git_version') 327 | let s:git_version = map(split(split(s:system('git --version'))[2], '\.'), 'str2nr(v:val)') 328 | endif 329 | return s:version_requirement(s:git_version, a:000) 330 | endfunction 331 | 332 | function! s:progress_opt(base) 333 | return a:base && !s:is_win && 334 | \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' 335 | endfunction 336 | 337 | if s:is_win 338 | function! s:rtp(spec) 339 | return s:path(a:spec.dir . get(a:spec, 'rtp', '')) 340 | endfunction 341 | 342 | function! s:path(path) 343 | return s:trim(substitute(a:path, '/', '\', 'g')) 344 | endfunction 345 | 346 | function! s:dirpath(path) 347 | return s:path(a:path) . '\' 348 | endfunction 349 | 350 | function! s:is_local_plug(repo) 351 | return a:repo =~? '^[a-z]:\|^[%~]' 352 | endfunction 353 | else 354 | function! s:rtp(spec) 355 | return s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) 356 | endfunction 357 | 358 | function! s:path(path) 359 | return s:trim(a:path) 360 | endfunction 361 | 362 | function! s:dirpath(path) 363 | return substitute(a:path, '[/\\]*$', '/', '') 364 | endfunction 365 | 366 | function! s:is_local_plug(repo) 367 | return a:repo[0] =~ '[/$~]' 368 | endfunction 369 | endif 370 | 371 | function! s:err(msg) 372 | echohl ErrorMsg 373 | echom '[vim-plug] '.a:msg 374 | echohl None 375 | endfunction 376 | 377 | function! s:warn(cmd, msg) 378 | echohl WarningMsg 379 | execute a:cmd 'a:msg' 380 | echohl None 381 | endfunction 382 | 383 | function! s:esc(path) 384 | return escape(a:path, ' ') 385 | endfunction 386 | 387 | function! s:escrtp(path) 388 | return escape(a:path, ' ,') 389 | endfunction 390 | 391 | function! s:remove_rtp() 392 | for name in s:loaded_names() 393 | let rtp = s:rtp(g:plugs[name]) 394 | execute 'set rtp-='.s:escrtp(rtp) 395 | let after = globpath(rtp, 'after') 396 | if isdirectory(after) 397 | execute 'set rtp-='.s:escrtp(after) 398 | endif 399 | endfor 400 | endfunction 401 | 402 | function! s:reorg_rtp() 403 | if !empty(s:first_rtp) 404 | execute 'set rtp-='.s:first_rtp 405 | execute 'set rtp-='.s:last_rtp 406 | endif 407 | 408 | " &rtp is modified from outside 409 | if exists('s:prtp') && s:prtp !=# &rtp 410 | call s:remove_rtp() 411 | unlet! s:middle 412 | endif 413 | 414 | let s:middle = get(s:, 'middle', &rtp) 415 | let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') 416 | let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)') 417 | let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') 418 | \ . ','.s:middle.',' 419 | \ . join(map(afters, 'escape(v:val, ",")'), ',') 420 | let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') 421 | let s:prtp = &rtp 422 | 423 | if !empty(s:first_rtp) 424 | execute 'set rtp^='.s:first_rtp 425 | execute 'set rtp+='.s:last_rtp 426 | endif 427 | endfunction 428 | 429 | function! s:doautocmd(...) 430 | if exists('#'.join(a:000, '#')) 431 | execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '' : '') join(a:000) 432 | endif 433 | endfunction 434 | 435 | function! s:dobufread(names) 436 | for name in a:names 437 | let path = s:rtp(g:plugs[name]).'/**' 438 | for dir in ['ftdetect', 'ftplugin'] 439 | if len(finddir(dir, path)) 440 | if exists('#BufRead') 441 | doautocmd BufRead 442 | endif 443 | return 444 | endif 445 | endfor 446 | endfor 447 | endfunction 448 | 449 | function! plug#load(...) 450 | if a:0 == 0 451 | return s:err('Argument missing: plugin name(s) required') 452 | endif 453 | if !exists('g:plugs') 454 | return s:err('plug#begin was not called') 455 | endif 456 | let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000 457 | let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)') 458 | if !empty(unknowns) 459 | let s = len(unknowns) > 1 ? 's' : '' 460 | return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) 461 | end 462 | let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)') 463 | if !empty(unloaded) 464 | for name in unloaded 465 | call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 466 | endfor 467 | call s:dobufread(unloaded) 468 | return 1 469 | end 470 | return 0 471 | endfunction 472 | 473 | function! s:remove_triggers(name) 474 | if !has_key(s:triggers, a:name) 475 | return 476 | endif 477 | for cmd in s:triggers[a:name].cmd 478 | execute 'silent! delc' cmd 479 | endfor 480 | for map in s:triggers[a:name].map 481 | execute 'silent! unmap' map 482 | execute 'silent! iunmap' map 483 | endfor 484 | call remove(s:triggers, a:name) 485 | endfunction 486 | 487 | function! s:lod(names, types, ...) 488 | for name in a:names 489 | call s:remove_triggers(name) 490 | let s:loaded[name] = 1 491 | endfor 492 | call s:reorg_rtp() 493 | 494 | for name in a:names 495 | let rtp = s:rtp(g:plugs[name]) 496 | for dir in a:types 497 | call s:source(rtp, dir.'/**/*.vim') 498 | endfor 499 | if a:0 500 | if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) 501 | execute 'runtime' a:1 502 | endif 503 | call s:source(rtp, a:2) 504 | endif 505 | call s:doautocmd('User', name) 506 | endfor 507 | endfunction 508 | 509 | function! s:lod_ft(pat, names) 510 | let syn = 'syntax/'.a:pat.'.vim' 511 | call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) 512 | execute 'autocmd! PlugLOD FileType' a:pat 513 | call s:doautocmd('filetypeplugin', 'FileType') 514 | call s:doautocmd('filetypeindent', 'FileType') 515 | endfunction 516 | 517 | function! s:lod_cmd(cmd, bang, l1, l2, args, names) 518 | call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 519 | call s:dobufread(a:names) 520 | execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) 521 | endfunction 522 | 523 | function! s:lod_map(map, names, with_prefix, prefix) 524 | call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 525 | call s:dobufread(a:names) 526 | let extra = '' 527 | while 1 528 | let c = getchar(0) 529 | if c == 0 530 | break 531 | endif 532 | let extra .= nr2char(c) 533 | endwhile 534 | 535 | if a:with_prefix 536 | let prefix = v:count ? v:count : '' 537 | let prefix .= '"'.v:register.a:prefix 538 | if mode(1) == 'no' 539 | if v:operator == 'c' 540 | let prefix = "\" . prefix 541 | endif 542 | let prefix .= v:operator 543 | endif 544 | call feedkeys(prefix, 'n') 545 | endif 546 | call feedkeys(substitute(a:map, '^', "\", '') . extra) 547 | endfunction 548 | 549 | function! plug#(repo, ...) 550 | if a:0 > 1 551 | return s:err('Invalid number of arguments (1..2)') 552 | endif 553 | 554 | try 555 | let repo = s:trim(a:repo) 556 | let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec 557 | let name = get(opts, 'as', fnamemodify(repo, ':t:s?\.git$??')) 558 | let spec = extend(s:infer_properties(name, repo), opts) 559 | if !has_key(g:plugs, name) 560 | call add(g:plugs_order, name) 561 | endif 562 | let g:plugs[name] = spec 563 | let s:loaded[name] = get(s:loaded, name, 0) 564 | catch 565 | return s:err(v:exception) 566 | endtry 567 | endfunction 568 | 569 | function! s:parse_options(arg) 570 | let opts = copy(s:base_spec) 571 | let type = type(a:arg) 572 | if type == s:TYPE.string 573 | let opts.tag = a:arg 574 | elseif type == s:TYPE.dict 575 | call extend(opts, a:arg) 576 | if has_key(opts, 'dir') 577 | let opts.dir = s:dirpath(expand(opts.dir)) 578 | endif 579 | else 580 | throw 'Invalid argument type (expected: string or dictionary)' 581 | endif 582 | return opts 583 | endfunction 584 | 585 | function! s:infer_properties(name, repo) 586 | let repo = a:repo 587 | if s:is_local_plug(repo) 588 | return { 'dir': s:dirpath(expand(repo)) } 589 | else 590 | if repo =~ ':' 591 | let uri = repo 592 | else 593 | if repo !~ '/' 594 | throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo) 595 | endif 596 | let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') 597 | let uri = printf(fmt, repo) 598 | endif 599 | return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri } 600 | endif 601 | endfunction 602 | 603 | function! s:install(force, names) 604 | call s:update_impl(0, a:force, a:names) 605 | endfunction 606 | 607 | function! s:update(force, names) 608 | call s:update_impl(1, a:force, a:names) 609 | endfunction 610 | 611 | function! plug#helptags() 612 | if !exists('g:plugs') 613 | return s:err('plug#begin was not called') 614 | endif 615 | for spec in values(g:plugs) 616 | let docd = join([s:rtp(spec), 'doc'], '/') 617 | if isdirectory(docd) 618 | silent! execute 'helptags' s:esc(docd) 619 | endif 620 | endfor 621 | return 1 622 | endfunction 623 | 624 | function! s:syntax() 625 | syntax clear 626 | syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber 627 | syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX 628 | syn match plugNumber /[0-9]\+[0-9.]*/ contained 629 | syn match plugBracket /[[\]]/ contained 630 | syn match plugX /x/ contained 631 | syn match plugDash /^-/ 632 | syn match plugPlus /^+/ 633 | syn match plugStar /^*/ 634 | syn match plugMessage /\(^- \)\@<=.*/ 635 | syn match plugName /\(^- \)\@<=[^ ]*:/ 636 | syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ 637 | syn match plugTag /(tag: [^)]\+)/ 638 | syn match plugInstall /\(^+ \)\@<=[^:]*/ 639 | syn match plugUpdate /\(^* \)\@<=[^:]*/ 640 | syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag 641 | syn match plugEdge /^ \X\+$/ 642 | syn match plugEdge /^ \X*/ contained nextgroup=plugSha 643 | syn match plugSha /[0-9a-f]\{7,9}/ contained 644 | syn match plugRelDate /([^)]*)$/ contained 645 | syn match plugNotLoaded /(not loaded)$/ 646 | syn match plugError /^x.*/ 647 | syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ 648 | syn match plugH2 /^.*:\n-\+$/ 649 | syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean 650 | hi def link plug1 Title 651 | hi def link plug2 Repeat 652 | hi def link plugH2 Type 653 | hi def link plugX Exception 654 | hi def link plugBracket Structure 655 | hi def link plugNumber Number 656 | 657 | hi def link plugDash Special 658 | hi def link plugPlus Constant 659 | hi def link plugStar Boolean 660 | 661 | hi def link plugMessage Function 662 | hi def link plugName Label 663 | hi def link plugInstall Function 664 | hi def link plugUpdate Type 665 | 666 | hi def link plugError Error 667 | hi def link plugDeleted Ignore 668 | hi def link plugRelDate Comment 669 | hi def link plugEdge PreProc 670 | hi def link plugSha Identifier 671 | hi def link plugTag Constant 672 | 673 | hi def link plugNotLoaded Comment 674 | endfunction 675 | 676 | function! s:lpad(str, len) 677 | return a:str . repeat(' ', a:len - len(a:str)) 678 | endfunction 679 | 680 | function! s:lines(msg) 681 | return split(a:msg, "[\r\n]") 682 | endfunction 683 | 684 | function! s:lastline(msg) 685 | return get(s:lines(a:msg), -1, '') 686 | endfunction 687 | 688 | function! s:new_window() 689 | execute get(g:, 'plug_window', 'vertical topleft new') 690 | endfunction 691 | 692 | function! s:plug_window_exists() 693 | let buflist = tabpagebuflist(s:plug_tab) 694 | return !empty(buflist) && index(buflist, s:plug_buf) >= 0 695 | endfunction 696 | 697 | function! s:switch_in() 698 | if !s:plug_window_exists() 699 | return 0 700 | endif 701 | 702 | if winbufnr(0) != s:plug_buf 703 | let s:pos = [tabpagenr(), winnr(), winsaveview()] 704 | execute 'normal!' s:plug_tab.'gt' 705 | let winnr = bufwinnr(s:plug_buf) 706 | execute winnr.'wincmd w' 707 | call add(s:pos, winsaveview()) 708 | else 709 | let s:pos = [winsaveview()] 710 | endif 711 | 712 | setlocal modifiable 713 | return 1 714 | endfunction 715 | 716 | function! s:switch_out(...) 717 | call winrestview(s:pos[-1]) 718 | setlocal nomodifiable 719 | if a:0 > 0 720 | execute a:1 721 | endif 722 | 723 | if len(s:pos) > 1 724 | execute 'normal!' s:pos[0].'gt' 725 | execute s:pos[1] 'wincmd w' 726 | call winrestview(s:pos[2]) 727 | endif 728 | endfunction 729 | 730 | function! s:finish_bindings() 731 | nnoremap R :call retry() 732 | nnoremap D :PlugDiff 733 | nnoremap S :PlugStatus 734 | nnoremap U :call status_update() 735 | xnoremap U :call status_update() 736 | nnoremap ]] :silent! call section('') 737 | nnoremap [[ :silent! call section('b') 738 | endfunction 739 | 740 | function! s:prepare(...) 741 | if empty(getcwd()) 742 | throw 'Invalid current working directory. Cannot proceed.' 743 | endif 744 | 745 | for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] 746 | if exists(evar) 747 | throw evar.' detected. Cannot proceed.' 748 | endif 749 | endfor 750 | 751 | call s:job_abort() 752 | if s:switch_in() 753 | if b:plug_preview == 1 754 | pc 755 | endif 756 | enew 757 | else 758 | call s:new_window() 759 | endif 760 | 761 | nnoremap q :if b:plug_preview==1pcendifbd 762 | if a:0 == 0 763 | call s:finish_bindings() 764 | endif 765 | let b:plug_preview = -1 766 | let s:plug_tab = tabpagenr() 767 | let s:plug_buf = winbufnr(0) 768 | call s:assign_name() 769 | 770 | for k in ['', 'L', 'o', 'X', 'd', 'dd'] 771 | execute 'silent! unmap ' k 772 | endfor 773 | setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell 774 | if exists('+colorcolumn') 775 | setlocal colorcolumn= 776 | endif 777 | setf vim-plug 778 | if exists('g:syntax_on') 779 | call s:syntax() 780 | endif 781 | endfunction 782 | 783 | function! s:assign_name() 784 | " Assign buffer name 785 | let prefix = '[Plugins]' 786 | let name = prefix 787 | let idx = 2 788 | while bufexists(name) 789 | let name = printf('%s (%s)', prefix, idx) 790 | let idx = idx + 1 791 | endwhile 792 | silent! execute 'f' fnameescape(name) 793 | endfunction 794 | 795 | function! s:chsh(swap) 796 | let prev = [&shell, &shellcmdflag, &shellredir] 797 | if s:is_win 798 | set shell=cmd.exe shellcmdflag=/c shellredir=>%s\ 2>&1 799 | elseif a:swap 800 | set shell=sh shellredir=>%s\ 2>&1 801 | endif 802 | return prev 803 | endfunction 804 | 805 | function! s:bang(cmd, ...) 806 | try 807 | let [sh, shellcmdflag, shrd] = s:chsh(a:0) 808 | " FIXME: Escaping is incomplete. We could use shellescape with eval, 809 | " but it won't work on Windows. 810 | let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd 811 | if s:is_win 812 | let batchfile = tempname().'.bat' 813 | call writefile(["@echo off\r", cmd . "\r"], batchfile) 814 | let cmd = batchfile 815 | endif 816 | let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%') 817 | execute "normal! :execute g:_plug_bang\\" 818 | finally 819 | unlet g:_plug_bang 820 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] 821 | if s:is_win 822 | call delete(batchfile) 823 | endif 824 | endtry 825 | return v:shell_error ? 'Exit status: ' . v:shell_error : '' 826 | endfunction 827 | 828 | function! s:regress_bar() 829 | let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') 830 | call s:progress_bar(2, bar, len(bar)) 831 | endfunction 832 | 833 | function! s:is_updated(dir) 834 | return !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', a:dir)) 835 | endfunction 836 | 837 | function! s:do(pull, force, todo) 838 | for [name, spec] in items(a:todo) 839 | if !isdirectory(spec.dir) 840 | continue 841 | endif 842 | let installed = has_key(s:update.new, name) 843 | let updated = installed ? 0 : 844 | \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) 845 | if a:force || installed || updated 846 | execute 'cd' s:esc(spec.dir) 847 | call append(3, '- Post-update hook for '. name .' ... ') 848 | let error = '' 849 | let type = type(spec.do) 850 | if type == s:TYPE.string 851 | if spec.do[0] == ':' 852 | if !get(s:loaded, name, 0) 853 | let s:loaded[name] = 1 854 | call s:reorg_rtp() 855 | endif 856 | call s:load_plugin(spec) 857 | try 858 | execute spec.do[1:] 859 | catch 860 | let error = v:exception 861 | endtry 862 | if !s:plug_window_exists() 863 | cd - 864 | throw 'Warning: vim-plug was terminated by the post-update hook of '.name 865 | endif 866 | else 867 | let error = s:bang(spec.do) 868 | endif 869 | elseif type == s:TYPE.funcref 870 | try 871 | let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') 872 | call spec.do({ 'name': name, 'status': status, 'force': a:force }) 873 | catch 874 | let error = v:exception 875 | endtry 876 | else 877 | let error = 'Invalid hook type' 878 | endif 879 | call s:switch_in() 880 | call setline(4, empty(error) ? (getline(4) . 'OK') 881 | \ : ('x' . getline(4)[1:] . error)) 882 | if !empty(error) 883 | call add(s:update.errors, name) 884 | call s:regress_bar() 885 | endif 886 | cd - 887 | endif 888 | endfor 889 | endfunction 890 | 891 | function! s:hash_match(a, b) 892 | return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 893 | endfunction 894 | 895 | function! s:checkout(spec) 896 | let sha = a:spec.commit 897 | let output = s:system('git rev-parse HEAD', a:spec.dir) 898 | if !v:shell_error && !s:hash_match(sha, s:lines(output)[0]) 899 | let output = s:system( 900 | \ 'git fetch --depth 999999 && git checkout '.s:esc(sha).' --', a:spec.dir) 901 | endif 902 | return output 903 | endfunction 904 | 905 | function! s:finish(pull) 906 | let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) 907 | if new_frozen 908 | let s = new_frozen > 1 ? 's' : '' 909 | call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) 910 | endif 911 | call append(3, '- Finishing ... ') | 4 912 | redraw 913 | call plug#helptags() 914 | call plug#end() 915 | call setline(4, getline(4) . 'Done!') 916 | redraw 917 | let msgs = [] 918 | if !empty(s:update.errors) 919 | call add(msgs, "Press 'R' to retry.") 920 | endif 921 | if a:pull && len(s:update.new) < len(filter(getline(5, '$'), 922 | \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'")) 923 | call add(msgs, "Press 'D' to see the updated changes.") 924 | endif 925 | echo join(msgs, ' ') 926 | call s:finish_bindings() 927 | endfunction 928 | 929 | function! s:retry() 930 | if empty(s:update.errors) 931 | return 932 | endif 933 | echo 934 | call s:update_impl(s:update.pull, s:update.force, 935 | \ extend(copy(s:update.errors), [s:update.threads])) 936 | endfunction 937 | 938 | function! s:is_managed(name) 939 | return has_key(g:plugs[a:name], 'uri') 940 | endfunction 941 | 942 | function! s:names(...) 943 | return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) 944 | endfunction 945 | 946 | function! s:check_ruby() 947 | silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") 948 | if !exists('g:plug_ruby') 949 | redraw! 950 | return s:warn('echom', 'Warning: Ruby interface is broken') 951 | endif 952 | let ruby_version = split(g:plug_ruby, '\.') 953 | unlet g:plug_ruby 954 | return s:version_requirement(ruby_version, [1, 8, 7]) 955 | endfunction 956 | 957 | function! s:update_impl(pull, force, args) abort 958 | let sync = index(a:args, '--sync') >= 0 || has('vim_starting') 959 | let args = filter(copy(a:args), 'v:val != "--sync"') 960 | let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? 961 | \ remove(args, -1) : get(g:, 'plug_threads', 16) 962 | 963 | let managed = filter(copy(g:plugs), 's:is_managed(v:key)') 964 | let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : 965 | \ filter(managed, 'index(args, v:key) >= 0') 966 | 967 | if empty(todo) 968 | return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) 969 | endif 970 | 971 | if !s:is_win && s:git_version_requirement(2, 3) 972 | let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' 973 | let $GIT_TERMINAL_PROMPT = 0 974 | for plug in values(todo) 975 | let plug.uri = substitute(plug.uri, 976 | \ '^https://git::@github\.com', 'https://github.com', '') 977 | endfor 978 | endif 979 | 980 | if !isdirectory(g:plug_home) 981 | try 982 | call mkdir(g:plug_home, 'p') 983 | catch 984 | return s:err(printf('Invalid plug directory: %s. '. 985 | \ 'Try to call plug#begin with a valid directory', g:plug_home)) 986 | endtry 987 | endif 988 | 989 | if has('nvim') && !exists('*jobwait') && threads > 1 990 | call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') 991 | endif 992 | 993 | let use_job = s:nvim || s:vim8 994 | let python = (has('python') || has('python3')) && !use_job 995 | let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby() 996 | 997 | let s:update = { 998 | \ 'start': reltime(), 999 | \ 'all': todo, 1000 | \ 'todo': copy(todo), 1001 | \ 'errors': [], 1002 | \ 'pull': a:pull, 1003 | \ 'force': a:force, 1004 | \ 'new': {}, 1005 | \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1, 1006 | \ 'bar': '', 1007 | \ 'fin': 0 1008 | \ } 1009 | 1010 | call s:prepare(1) 1011 | call append(0, ['', '']) 1012 | normal! 2G 1013 | silent! redraw 1014 | 1015 | let s:clone_opt = get(g:, 'plug_shallow', 1) ? 1016 | \ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : '' 1017 | 1018 | if has('win32unix') 1019 | let s:clone_opt .= ' -c core.eol=lf -c core.autocrlf=input' 1020 | endif 1021 | 1022 | let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : '' 1023 | 1024 | " Python version requirement (>= 2.7) 1025 | if python && !has('python3') && !ruby && !use_job && s:update.threads > 1 1026 | redir => pyv 1027 | silent python import platform; print platform.python_version() 1028 | redir END 1029 | let python = s:version_requirement( 1030 | \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) 1031 | endif 1032 | 1033 | if (python || ruby) && s:update.threads > 1 1034 | try 1035 | let imd = &imd 1036 | if s:mac_gui 1037 | set noimd 1038 | endif 1039 | if ruby 1040 | call s:update_ruby() 1041 | else 1042 | call s:update_python() 1043 | endif 1044 | catch 1045 | let lines = getline(4, '$') 1046 | let printed = {} 1047 | silent! 4,$d _ 1048 | for line in lines 1049 | let name = s:extract_name(line, '.', '') 1050 | if empty(name) || !has_key(printed, name) 1051 | call append('$', line) 1052 | if !empty(name) 1053 | let printed[name] = 1 1054 | if line[0] == 'x' && index(s:update.errors, name) < 0 1055 | call add(s:update.errors, name) 1056 | end 1057 | endif 1058 | endif 1059 | endfor 1060 | finally 1061 | let &imd = imd 1062 | call s:update_finish() 1063 | endtry 1064 | else 1065 | call s:update_vim() 1066 | while use_job && sync 1067 | sleep 100m 1068 | if s:update.fin 1069 | break 1070 | endif 1071 | endwhile 1072 | endif 1073 | endfunction 1074 | 1075 | function! s:log4(name, msg) 1076 | call setline(4, printf('- %s (%s)', a:msg, a:name)) 1077 | redraw 1078 | endfunction 1079 | 1080 | function! s:update_finish() 1081 | if exists('s:git_terminal_prompt') 1082 | let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt 1083 | endif 1084 | if s:switch_in() 1085 | call append(3, '- Updating ...') | 4 1086 | 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))')) 1087 | let [pos, _] = s:logpos(name) 1088 | if !pos 1089 | continue 1090 | endif 1091 | if has_key(spec, 'commit') 1092 | call s:log4(name, 'Checking out '.spec.commit) 1093 | let out = s:checkout(spec) 1094 | elseif has_key(spec, 'tag') 1095 | let tag = spec.tag 1096 | if tag =~ '\*' 1097 | let tags = s:lines(s:system('git tag --list '.s:shellesc(tag).' --sort -version:refname 2>&1', spec.dir)) 1098 | if !v:shell_error && !empty(tags) 1099 | let tag = tags[0] 1100 | call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) 1101 | call append(3, '') 1102 | endif 1103 | endif 1104 | call s:log4(name, 'Checking out '.tag) 1105 | let out = s:system('git checkout -q '.s:esc(tag).' -- 2>&1', spec.dir) 1106 | else 1107 | let branch = s:esc(get(spec, 'branch', 'master')) 1108 | call s:log4(name, 'Merging origin/'.branch) 1109 | let out = s:system('git checkout -q '.branch.' -- 2>&1' 1110 | \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only origin/'.branch.' 2>&1')), spec.dir) 1111 | endif 1112 | if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && 1113 | \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) 1114 | call s:log4(name, 'Updating submodules. This may take a while.') 1115 | let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir) 1116 | endif 1117 | let msg = s:format_message(v:shell_error ? 'x': '-', name, out) 1118 | if v:shell_error 1119 | call add(s:update.errors, name) 1120 | call s:regress_bar() 1121 | silent execute pos 'd _' 1122 | call append(4, msg) | 4 1123 | elseif !empty(out) 1124 | call setline(pos, msg[0]) 1125 | endif 1126 | redraw 1127 | endfor 1128 | silent 4 d _ 1129 | try 1130 | 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")')) 1131 | catch 1132 | call s:warn('echom', v:exception) 1133 | call s:warn('echo', '') 1134 | return 1135 | endtry 1136 | call s:finish(s:update.pull) 1137 | call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') 1138 | call s:switch_out('normal! gg') 1139 | endif 1140 | endfunction 1141 | 1142 | function! s:job_abort() 1143 | if (!s:nvim && !s:vim8) || !exists('s:jobs') 1144 | return 1145 | endif 1146 | 1147 | for [name, j] in items(s:jobs) 1148 | if s:nvim 1149 | silent! call jobstop(j.jobid) 1150 | elseif s:vim8 1151 | silent! call job_stop(j.jobid) 1152 | endif 1153 | if j.new 1154 | call s:system('rm -rf ' . s:shellesc(g:plugs[name].dir)) 1155 | endif 1156 | endfor 1157 | let s:jobs = {} 1158 | endfunction 1159 | 1160 | function! s:last_non_empty_line(lines) 1161 | let len = len(a:lines) 1162 | for idx in range(len) 1163 | let line = a:lines[len-idx-1] 1164 | if !empty(line) 1165 | return line 1166 | endif 1167 | endfor 1168 | return '' 1169 | endfunction 1170 | 1171 | function! s:job_out_cb(self, data) abort 1172 | let self = a:self 1173 | let data = remove(self.lines, -1) . a:data 1174 | let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]') 1175 | call extend(self.lines, lines) 1176 | " To reduce the number of buffer updates 1177 | let self.tick = get(self, 'tick', -1) + 1 1178 | if !self.running || self.tick % len(s:jobs) == 0 1179 | let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-') 1180 | let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines) 1181 | call s:log(bullet, self.name, result) 1182 | endif 1183 | endfunction 1184 | 1185 | function! s:job_exit_cb(self, data) abort 1186 | let a:self.running = 0 1187 | let a:self.error = a:data != 0 1188 | call s:reap(a:self.name) 1189 | call s:tick() 1190 | endfunction 1191 | 1192 | function! s:job_cb(fn, job, ch, data) 1193 | if !s:plug_window_exists() " plug window closed 1194 | return s:job_abort() 1195 | endif 1196 | call call(a:fn, [a:job, a:data]) 1197 | endfunction 1198 | 1199 | function! s:nvim_cb(job_id, data, event) dict abort 1200 | return a:event == 'stdout' ? 1201 | \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) : 1202 | \ s:job_cb('s:job_exit_cb', self, 0, a:data) 1203 | endfunction 1204 | 1205 | function! s:spawn(name, cmd, opts) 1206 | let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''], 1207 | \ 'batchfile': (s:is_win && (s:nvim || s:vim8)) ? tempname().'.bat' : '', 1208 | \ 'new': get(a:opts, 'new', 0) } 1209 | let s:jobs[a:name] = job 1210 | let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd 1211 | if !empty(job.batchfile) 1212 | call writefile(["@echo off\r", cmd . "\r"], job.batchfile) 1213 | let cmd = job.batchfile 1214 | endif 1215 | let argv = add(s:is_win ? ['cmd', '/c'] : ['sh', '-c'], cmd) 1216 | 1217 | if s:nvim 1218 | call extend(job, { 1219 | \ 'on_stdout': function('s:nvim_cb'), 1220 | \ 'on_exit': function('s:nvim_cb'), 1221 | \ }) 1222 | let jid = jobstart(argv, job) 1223 | if jid > 0 1224 | let job.jobid = jid 1225 | else 1226 | let job.running = 0 1227 | let job.error = 1 1228 | let job.lines = [jid < 0 ? argv[0].' is not executable' : 1229 | \ 'Invalid arguments (or job table is full)'] 1230 | endif 1231 | elseif s:vim8 1232 | let jid = job_start(s:is_win ? join(argv, ' ') : argv, { 1233 | \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]), 1234 | \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]), 1235 | \ 'out_mode': 'raw' 1236 | \}) 1237 | if job_status(jid) == 'run' 1238 | let job.jobid = jid 1239 | else 1240 | let job.running = 0 1241 | let job.error = 1 1242 | let job.lines = ['Failed to start job'] 1243 | endif 1244 | else 1245 | let job.lines = s:lines(call('s:system', [cmd])) 1246 | let job.error = v:shell_error != 0 1247 | let job.running = 0 1248 | endif 1249 | endfunction 1250 | 1251 | function! s:reap(name) 1252 | let job = s:jobs[a:name] 1253 | if job.error 1254 | call add(s:update.errors, a:name) 1255 | elseif get(job, 'new', 0) 1256 | let s:update.new[a:name] = 1 1257 | endif 1258 | let s:update.bar .= job.error ? 'x' : '=' 1259 | 1260 | let bullet = job.error ? 'x' : '-' 1261 | let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines) 1262 | call s:log(bullet, a:name, empty(result) ? 'OK' : result) 1263 | call s:bar() 1264 | 1265 | if has_key(job, 'batchfile') && !empty(job.batchfile) 1266 | call delete(job.batchfile) 1267 | endif 1268 | call remove(s:jobs, a:name) 1269 | endfunction 1270 | 1271 | function! s:bar() 1272 | if s:switch_in() 1273 | let total = len(s:update.all) 1274 | call setline(1, (s:update.pull ? 'Updating' : 'Installing'). 1275 | \ ' plugins ('.len(s:update.bar).'/'.total.')') 1276 | call s:progress_bar(2, s:update.bar, total) 1277 | call s:switch_out() 1278 | endif 1279 | endfunction 1280 | 1281 | function! s:logpos(name) 1282 | for i in range(4, line('$')) 1283 | if getline(i) =~# '^[-+x*] '.a:name.':' 1284 | for j in range(i + 1, line('$')) 1285 | if getline(j) !~ '^ ' 1286 | return [i, j - 1] 1287 | endif 1288 | endfor 1289 | return [i, i] 1290 | endif 1291 | endfor 1292 | return [0, 0] 1293 | endfunction 1294 | 1295 | function! s:log(bullet, name, lines) 1296 | if s:switch_in() 1297 | let [b, e] = s:logpos(a:name) 1298 | if b > 0 1299 | silent execute printf('%d,%d d _', b, e) 1300 | if b > winheight('.') 1301 | let b = 4 1302 | endif 1303 | else 1304 | let b = 4 1305 | endif 1306 | " FIXME For some reason, nomodifiable is set after :d in vim8 1307 | setlocal modifiable 1308 | call append(b - 1, s:format_message(a:bullet, a:name, a:lines)) 1309 | call s:switch_out() 1310 | endif 1311 | endfunction 1312 | 1313 | function! s:update_vim() 1314 | let s:jobs = {} 1315 | 1316 | call s:bar() 1317 | call s:tick() 1318 | endfunction 1319 | 1320 | function! s:tick() 1321 | let pull = s:update.pull 1322 | let prog = s:progress_opt(s:nvim || s:vim8) 1323 | while 1 " Without TCO, Vim stack is bound to explode 1324 | if empty(s:update.todo) 1325 | if empty(s:jobs) && !s:update.fin 1326 | call s:update_finish() 1327 | let s:update.fin = 1 1328 | endif 1329 | return 1330 | endif 1331 | 1332 | let name = keys(s:update.todo)[0] 1333 | let spec = remove(s:update.todo, name) 1334 | let new = empty(globpath(spec.dir, '.git', 1)) 1335 | 1336 | call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') 1337 | redraw 1338 | 1339 | let has_tag = has_key(spec, 'tag') 1340 | if !new 1341 | let [error, _] = s:git_validate(spec, 0) 1342 | if empty(error) 1343 | if pull 1344 | let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : '' 1345 | call s:spawn(name, printf('git fetch %s %s 2>&1', fetch_opt, prog), { 'dir': spec.dir }) 1346 | else 1347 | let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 } 1348 | endif 1349 | else 1350 | let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 } 1351 | endif 1352 | else 1353 | call s:spawn(name, 1354 | \ printf('git clone %s %s %s %s 2>&1', 1355 | \ has_tag ? '' : s:clone_opt, 1356 | \ prog, 1357 | \ s:shellesc(spec.uri), 1358 | \ s:shellesc(s:trim(spec.dir))), { 'new': 1 }) 1359 | endif 1360 | 1361 | if !s:jobs[name].running 1362 | call s:reap(name) 1363 | endif 1364 | if len(s:jobs) >= s:update.threads 1365 | break 1366 | endif 1367 | endwhile 1368 | endfunction 1369 | 1370 | function! s:update_python() 1371 | let py_exe = has('python') ? 'python' : 'python3' 1372 | execute py_exe "<< EOF" 1373 | import datetime 1374 | import functools 1375 | import os 1376 | try: 1377 | import queue 1378 | except ImportError: 1379 | import Queue as queue 1380 | import random 1381 | import re 1382 | import shutil 1383 | import signal 1384 | import subprocess 1385 | import tempfile 1386 | import threading as thr 1387 | import time 1388 | import traceback 1389 | import vim 1390 | 1391 | G_NVIM = vim.eval("has('nvim')") == '1' 1392 | G_PULL = vim.eval('s:update.pull') == '1' 1393 | G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 1394 | G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) 1395 | G_CLONE_OPT = vim.eval('s:clone_opt') 1396 | G_PROGRESS = vim.eval('s:progress_opt(1)') 1397 | G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) 1398 | G_STOP = thr.Event() 1399 | G_IS_WIN = vim.eval('s:is_win') == '1' 1400 | 1401 | class PlugError(Exception): 1402 | def __init__(self, msg): 1403 | self.msg = msg 1404 | class CmdTimedOut(PlugError): 1405 | pass 1406 | class CmdFailed(PlugError): 1407 | pass 1408 | class InvalidURI(PlugError): 1409 | pass 1410 | class Action(object): 1411 | INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] 1412 | 1413 | class Buffer(object): 1414 | def __init__(self, lock, num_plugs, is_pull): 1415 | self.bar = '' 1416 | self.event = 'Updating' if is_pull else 'Installing' 1417 | self.lock = lock 1418 | self.maxy = int(vim.eval('winheight(".")')) 1419 | self.num_plugs = num_plugs 1420 | 1421 | def __where(self, name): 1422 | """ Find first line with name in current buffer. Return line num. """ 1423 | found, lnum = False, 0 1424 | matcher = re.compile('^[-+x*] {0}:'.format(name)) 1425 | for line in vim.current.buffer: 1426 | if matcher.search(line) is not None: 1427 | found = True 1428 | break 1429 | lnum += 1 1430 | 1431 | if not found: 1432 | lnum = -1 1433 | return lnum 1434 | 1435 | def header(self): 1436 | curbuf = vim.current.buffer 1437 | curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) 1438 | 1439 | num_spaces = self.num_plugs - len(self.bar) 1440 | curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') 1441 | 1442 | with self.lock: 1443 | vim.command('normal! 2G') 1444 | vim.command('redraw') 1445 | 1446 | def write(self, action, name, lines): 1447 | first, rest = lines[0], lines[1:] 1448 | msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] 1449 | msg.extend([' ' + line for line in rest]) 1450 | 1451 | try: 1452 | if action == Action.ERROR: 1453 | self.bar += 'x' 1454 | vim.command("call add(s:update.errors, '{0}')".format(name)) 1455 | elif action == Action.DONE: 1456 | self.bar += '=' 1457 | 1458 | curbuf = vim.current.buffer 1459 | lnum = self.__where(name) 1460 | if lnum != -1: # Found matching line num 1461 | del curbuf[lnum] 1462 | if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): 1463 | lnum = 3 1464 | else: 1465 | lnum = 3 1466 | curbuf.append(msg, lnum) 1467 | 1468 | self.header() 1469 | except vim.error: 1470 | pass 1471 | 1472 | class Command(object): 1473 | CD = 'cd /d' if G_IS_WIN else 'cd' 1474 | 1475 | def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): 1476 | self.cmd = cmd 1477 | if cmd_dir: 1478 | self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) 1479 | self.timeout = timeout 1480 | self.callback = cb if cb else (lambda msg: None) 1481 | self.clean = clean if clean else (lambda: None) 1482 | self.proc = None 1483 | 1484 | @property 1485 | def alive(self): 1486 | """ Returns true only if command still running. """ 1487 | return self.proc and self.proc.poll() is None 1488 | 1489 | def execute(self, ntries=3): 1490 | """ Execute the command with ntries if CmdTimedOut. 1491 | Returns the output of the command if no Exception. 1492 | """ 1493 | attempt, finished, limit = 0, False, self.timeout 1494 | 1495 | while not finished: 1496 | try: 1497 | attempt += 1 1498 | result = self.try_command() 1499 | finished = True 1500 | return result 1501 | except CmdTimedOut: 1502 | if attempt != ntries: 1503 | self.notify_retry() 1504 | self.timeout += limit 1505 | else: 1506 | raise 1507 | 1508 | def notify_retry(self): 1509 | """ Retry required for command, notify user. """ 1510 | for count in range(3, 0, -1): 1511 | if G_STOP.is_set(): 1512 | raise KeyboardInterrupt 1513 | msg = 'Timeout. Will retry in {0} second{1} ...'.format( 1514 | count, 's' if count != 1 else '') 1515 | self.callback([msg]) 1516 | time.sleep(1) 1517 | self.callback(['Retrying ...']) 1518 | 1519 | def try_command(self): 1520 | """ Execute a cmd & poll for callback. Returns list of output. 1521 | Raises CmdFailed -> return code for Popen isn't 0 1522 | Raises CmdTimedOut -> command exceeded timeout without new output 1523 | """ 1524 | first_line = True 1525 | 1526 | try: 1527 | tfile = tempfile.NamedTemporaryFile(mode='w+b') 1528 | preexec_fn = not G_IS_WIN and os.setsid or None 1529 | self.proc = subprocess.Popen(self.cmd, stdout=tfile, 1530 | stderr=subprocess.STDOUT, 1531 | stdin=subprocess.PIPE, shell=True, 1532 | preexec_fn=preexec_fn) 1533 | thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) 1534 | thrd.start() 1535 | 1536 | thread_not_started = True 1537 | while thread_not_started: 1538 | try: 1539 | thrd.join(0.1) 1540 | thread_not_started = False 1541 | except RuntimeError: 1542 | pass 1543 | 1544 | while self.alive: 1545 | if G_STOP.is_set(): 1546 | raise KeyboardInterrupt 1547 | 1548 | if first_line or random.random() < G_LOG_PROB: 1549 | first_line = False 1550 | line = '' if G_IS_WIN else nonblock_read(tfile.name) 1551 | if line: 1552 | self.callback([line]) 1553 | 1554 | time_diff = time.time() - os.path.getmtime(tfile.name) 1555 | if time_diff > self.timeout: 1556 | raise CmdTimedOut(['Timeout!']) 1557 | 1558 | thrd.join(0.5) 1559 | 1560 | tfile.seek(0) 1561 | result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] 1562 | 1563 | if self.proc.returncode != 0: 1564 | raise CmdFailed([''] + result) 1565 | 1566 | return result 1567 | except: 1568 | self.terminate() 1569 | raise 1570 | 1571 | def terminate(self): 1572 | """ Terminate process and cleanup. """ 1573 | if self.alive: 1574 | if G_IS_WIN: 1575 | os.kill(self.proc.pid, signal.SIGINT) 1576 | else: 1577 | os.killpg(self.proc.pid, signal.SIGTERM) 1578 | self.clean() 1579 | 1580 | class Plugin(object): 1581 | def __init__(self, name, args, buf_q, lock): 1582 | self.name = name 1583 | self.args = args 1584 | self.buf_q = buf_q 1585 | self.lock = lock 1586 | self.tag = args.get('tag', 0) 1587 | 1588 | def manage(self): 1589 | try: 1590 | if os.path.exists(self.args['dir']): 1591 | self.update() 1592 | else: 1593 | self.install() 1594 | with self.lock: 1595 | thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) 1596 | except PlugError as exc: 1597 | self.write(Action.ERROR, self.name, exc.msg) 1598 | except KeyboardInterrupt: 1599 | G_STOP.set() 1600 | self.write(Action.ERROR, self.name, ['Interrupted!']) 1601 | except: 1602 | # Any exception except those above print stack trace 1603 | msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) 1604 | self.write(Action.ERROR, self.name, msg.split('\n')) 1605 | raise 1606 | 1607 | def install(self): 1608 | target = self.args['dir'] 1609 | if target[-1] == '\\': 1610 | target = target[0:-1] 1611 | 1612 | def clean(target): 1613 | def _clean(): 1614 | try: 1615 | shutil.rmtree(target) 1616 | except OSError: 1617 | pass 1618 | return _clean 1619 | 1620 | self.write(Action.INSTALL, self.name, ['Installing ...']) 1621 | callback = functools.partial(self.write, Action.INSTALL, self.name) 1622 | cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( 1623 | '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], 1624 | esc(target)) 1625 | com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) 1626 | result = com.execute(G_RETRIES) 1627 | self.write(Action.DONE, self.name, result[-1:]) 1628 | 1629 | def repo_uri(self): 1630 | cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' 1631 | command = Command(cmd, self.args['dir'], G_TIMEOUT,) 1632 | result = command.execute(G_RETRIES) 1633 | return result[-1] 1634 | 1635 | def update(self): 1636 | actual_uri = self.repo_uri() 1637 | expect_uri = self.args['uri'] 1638 | regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$') 1639 | ma = regex.match(actual_uri) 1640 | mb = regex.match(expect_uri) 1641 | if ma is None or mb is None or ma.groups() != mb.groups(): 1642 | msg = ['', 1643 | 'Invalid URI: {0}'.format(actual_uri), 1644 | 'Expected {0}'.format(expect_uri), 1645 | 'PlugClean required.'] 1646 | raise InvalidURI(msg) 1647 | 1648 | if G_PULL: 1649 | self.write(Action.UPDATE, self.name, ['Updating ...']) 1650 | callback = functools.partial(self.write, Action.UPDATE, self.name) 1651 | fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' 1652 | cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) 1653 | com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) 1654 | result = com.execute(G_RETRIES) 1655 | self.write(Action.DONE, self.name, result[-1:]) 1656 | else: 1657 | self.write(Action.DONE, self.name, ['Already installed']) 1658 | 1659 | def write(self, action, name, msg): 1660 | self.buf_q.put((action, name, msg)) 1661 | 1662 | class PlugThread(thr.Thread): 1663 | def __init__(self, tname, args): 1664 | super(PlugThread, self).__init__() 1665 | self.tname = tname 1666 | self.args = args 1667 | 1668 | def run(self): 1669 | thr.current_thread().name = self.tname 1670 | buf_q, work_q, lock = self.args 1671 | 1672 | try: 1673 | while not G_STOP.is_set(): 1674 | name, args = work_q.get_nowait() 1675 | plug = Plugin(name, args, buf_q, lock) 1676 | plug.manage() 1677 | work_q.task_done() 1678 | except queue.Empty: 1679 | pass 1680 | 1681 | class RefreshThread(thr.Thread): 1682 | def __init__(self, lock): 1683 | super(RefreshThread, self).__init__() 1684 | self.lock = lock 1685 | self.running = True 1686 | 1687 | def run(self): 1688 | while self.running: 1689 | with self.lock: 1690 | thread_vim_command('noautocmd normal! a') 1691 | time.sleep(0.33) 1692 | 1693 | def stop(self): 1694 | self.running = False 1695 | 1696 | if G_NVIM: 1697 | def thread_vim_command(cmd): 1698 | vim.session.threadsafe_call(lambda: vim.command(cmd)) 1699 | else: 1700 | def thread_vim_command(cmd): 1701 | vim.command(cmd) 1702 | 1703 | def esc(name): 1704 | return '"' + name.replace('"', '\"') + '"' 1705 | 1706 | def nonblock_read(fname): 1707 | """ Read a file with nonblock flag. Return the last line. """ 1708 | fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) 1709 | buf = os.read(fread, 100000).decode('utf-8', 'replace') 1710 | os.close(fread) 1711 | 1712 | line = buf.rstrip('\r\n') 1713 | left = max(line.rfind('\r'), line.rfind('\n')) 1714 | if left != -1: 1715 | left += 1 1716 | line = line[left:] 1717 | 1718 | return line 1719 | 1720 | def main(): 1721 | thr.current_thread().name = 'main' 1722 | nthreads = int(vim.eval('s:update.threads')) 1723 | plugs = vim.eval('s:update.todo') 1724 | mac_gui = vim.eval('s:mac_gui') == '1' 1725 | 1726 | lock = thr.Lock() 1727 | buf = Buffer(lock, len(plugs), G_PULL) 1728 | buf_q, work_q = queue.Queue(), queue.Queue() 1729 | for work in plugs.items(): 1730 | work_q.put(work) 1731 | 1732 | start_cnt = thr.active_count() 1733 | for num in range(nthreads): 1734 | tname = 'PlugT-{0:02}'.format(num) 1735 | thread = PlugThread(tname, (buf_q, work_q, lock)) 1736 | thread.start() 1737 | if mac_gui: 1738 | rthread = RefreshThread(lock) 1739 | rthread.start() 1740 | 1741 | while not buf_q.empty() or thr.active_count() != start_cnt: 1742 | try: 1743 | action, name, msg = buf_q.get(True, 0.25) 1744 | buf.write(action, name, ['OK'] if not msg else msg) 1745 | buf_q.task_done() 1746 | except queue.Empty: 1747 | pass 1748 | except KeyboardInterrupt: 1749 | G_STOP.set() 1750 | 1751 | if mac_gui: 1752 | rthread.stop() 1753 | rthread.join() 1754 | 1755 | main() 1756 | EOF 1757 | endfunction 1758 | 1759 | function! s:update_ruby() 1760 | ruby << EOF 1761 | module PlugStream 1762 | SEP = ["\r", "\n", nil] 1763 | def get_line 1764 | buffer = '' 1765 | loop do 1766 | char = readchar rescue return 1767 | if SEP.include? char.chr 1768 | buffer << $/ 1769 | break 1770 | else 1771 | buffer << char 1772 | end 1773 | end 1774 | buffer 1775 | end 1776 | end unless defined?(PlugStream) 1777 | 1778 | def esc arg 1779 | %["#{arg.gsub('"', '\"')}"] 1780 | end 1781 | 1782 | def killall pid 1783 | pids = [pid] 1784 | if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM 1785 | pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } 1786 | else 1787 | unless `which pgrep 2> /dev/null`.empty? 1788 | children = pids 1789 | until children.empty? 1790 | children = children.map { |pid| 1791 | `pgrep -P #{pid}`.lines.map { |l| l.chomp } 1792 | }.flatten 1793 | pids += children 1794 | end 1795 | end 1796 | pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } 1797 | end 1798 | end 1799 | 1800 | def compare_git_uri a, b 1801 | regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$} 1802 | regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1) 1803 | end 1804 | 1805 | require 'thread' 1806 | require 'fileutils' 1807 | require 'timeout' 1808 | running = true 1809 | iswin = VIM::evaluate('s:is_win').to_i == 1 1810 | pull = VIM::evaluate('s:update.pull').to_i == 1 1811 | base = VIM::evaluate('g:plug_home') 1812 | all = VIM::evaluate('s:update.todo') 1813 | limit = VIM::evaluate('get(g:, "plug_timeout", 60)') 1814 | tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 1815 | nthr = VIM::evaluate('s:update.threads').to_i 1816 | maxy = VIM::evaluate('winheight(".")').to_i 1817 | vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/ 1818 | cd = iswin ? 'cd /d' : 'cd' 1819 | tot = VIM::evaluate('len(s:update.todo)') || 0 1820 | bar = '' 1821 | skip = 'Already installed' 1822 | mtx = Mutex.new 1823 | take1 = proc { mtx.synchronize { running && all.shift } } 1824 | logh = proc { 1825 | cnt = bar.length 1826 | $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" 1827 | $curbuf[2] = '[' + bar.ljust(tot) + ']' 1828 | VIM::command('normal! 2G') 1829 | VIM::command('redraw') 1830 | } 1831 | where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } 1832 | log = proc { |name, result, type| 1833 | mtx.synchronize do 1834 | ing = ![true, false].include?(type) 1835 | bar += type ? '=' : 'x' unless ing 1836 | b = case type 1837 | when :install then '+' when :update then '*' 1838 | when true, nil then '-' else 1839 | VIM::command("call add(s:update.errors, '#{name}')") 1840 | 'x' 1841 | end 1842 | result = 1843 | if type || type.nil? 1844 | ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] 1845 | elsif result =~ /^Interrupted|^Timeout/ 1846 | ["#{b} #{name}: #{result}"] 1847 | else 1848 | ["#{b} #{name}"] + result.lines.map { |l| " " << l } 1849 | end 1850 | if lnum = where.call(name) 1851 | $curbuf.delete lnum 1852 | lnum = 4 if ing && lnum > maxy 1853 | end 1854 | result.each_with_index do |line, offset| 1855 | $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) 1856 | end 1857 | logh.call 1858 | end 1859 | } 1860 | bt = proc { |cmd, name, type, cleanup| 1861 | tried = timeout = 0 1862 | begin 1863 | tried += 1 1864 | timeout += limit 1865 | fd = nil 1866 | data = '' 1867 | if iswin 1868 | Timeout::timeout(timeout) do 1869 | tmp = VIM::evaluate('tempname()') 1870 | system("(#{cmd}) > #{tmp}") 1871 | data = File.read(tmp).chomp 1872 | File.unlink tmp rescue nil 1873 | end 1874 | else 1875 | fd = IO.popen(cmd).extend(PlugStream) 1876 | first_line = true 1877 | log_prob = 1.0 / nthr 1878 | while line = Timeout::timeout(timeout) { fd.get_line } 1879 | data << line 1880 | log.call name, line.chomp, type if name && (first_line || rand < log_prob) 1881 | first_line = false 1882 | end 1883 | fd.close 1884 | end 1885 | [$? == 0, data.chomp] 1886 | rescue Timeout::Error, Interrupt => e 1887 | if fd && !fd.closed? 1888 | killall fd.pid 1889 | fd.close 1890 | end 1891 | cleanup.call if cleanup 1892 | if e.is_a?(Timeout::Error) && tried < tries 1893 | 3.downto(1) do |countdown| 1894 | s = countdown > 1 ? 's' : '' 1895 | log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type 1896 | sleep 1 1897 | end 1898 | log.call name, 'Retrying ...', type 1899 | retry 1900 | end 1901 | [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] 1902 | end 1903 | } 1904 | main = Thread.current 1905 | threads = [] 1906 | watcher = Thread.new { 1907 | if vim7 1908 | while VIM::evaluate('getchar(1)') 1909 | sleep 0.1 1910 | end 1911 | else 1912 | require 'io/console' # >= Ruby 1.9 1913 | nil until IO.console.getch == 3.chr 1914 | end 1915 | mtx.synchronize do 1916 | running = false 1917 | threads.each { |t| t.raise Interrupt } unless vim7 1918 | end 1919 | threads.each { |t| t.join rescue nil } 1920 | main.kill 1921 | } 1922 | refresh = Thread.new { 1923 | while true 1924 | mtx.synchronize do 1925 | break unless running 1926 | VIM::command('noautocmd normal! a') 1927 | end 1928 | sleep 0.2 1929 | end 1930 | } if VIM::evaluate('s:mac_gui') == 1 1931 | 1932 | clone_opt = VIM::evaluate('s:clone_opt') 1933 | progress = VIM::evaluate('s:progress_opt(1)') 1934 | nthr.times do 1935 | mtx.synchronize do 1936 | threads << Thread.new { 1937 | while pair = take1.call 1938 | name = pair.first 1939 | dir, uri, tag = pair.last.values_at *%w[dir uri tag] 1940 | exists = File.directory? dir 1941 | ok, result = 1942 | if exists 1943 | chdir = "#{cd} #{iswin ? dir : esc(dir)}" 1944 | ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil 1945 | current_uri = data.lines.to_a.last 1946 | if !ret 1947 | if data =~ /^Interrupted|^Timeout/ 1948 | [false, data] 1949 | else 1950 | [false, [data.chomp, "PlugClean required."].join($/)] 1951 | end 1952 | elsif !compare_git_uri(current_uri, uri) 1953 | [false, ["Invalid URI: #{current_uri}", 1954 | "Expected: #{uri}", 1955 | "PlugClean required."].join($/)] 1956 | else 1957 | if pull 1958 | log.call name, 'Updating ...', :update 1959 | fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' 1960 | bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil 1961 | else 1962 | [true, skip] 1963 | end 1964 | end 1965 | else 1966 | d = esc dir.sub(%r{[\\/]+$}, '') 1967 | log.call name, 'Installing ...', :install 1968 | bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { 1969 | FileUtils.rm_rf dir 1970 | } 1971 | end 1972 | mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok 1973 | log.call name, result, ok 1974 | end 1975 | } if running 1976 | end 1977 | end 1978 | threads.each { |t| t.join rescue nil } 1979 | logh.call 1980 | refresh.kill if refresh 1981 | watcher.kill 1982 | EOF 1983 | endfunction 1984 | 1985 | function! s:shellesc_cmd(arg) 1986 | let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g') 1987 | let escaped = substitute(escaped, '%', '%%', 'g') 1988 | let escaped = substitute(escaped, '"', '\\^&', 'g') 1989 | let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g') 1990 | return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"' 1991 | endfunction 1992 | 1993 | function! s:shellesc(arg) 1994 | if &shell =~# 'cmd.exe$' 1995 | return s:shellesc_cmd(a:arg) 1996 | endif 1997 | return shellescape(a:arg) 1998 | endfunction 1999 | 2000 | function! s:glob_dir(path) 2001 | return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') 2002 | endfunction 2003 | 2004 | function! s:progress_bar(line, bar, total) 2005 | call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') 2006 | endfunction 2007 | 2008 | function! s:compare_git_uri(a, b) 2009 | " See `git help clone' 2010 | " https:// [user@] github.com[:port] / junegunn/vim-plug [.git] 2011 | " [git@] github.com[:port] : junegunn/vim-plug [.git] 2012 | " file:// / junegunn/vim-plug [/] 2013 | " / junegunn/vim-plug [/] 2014 | let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$' 2015 | let ma = matchlist(a:a, pat) 2016 | let mb = matchlist(a:b, pat) 2017 | return ma[1:2] ==# mb[1:2] 2018 | endfunction 2019 | 2020 | function! s:format_message(bullet, name, message) 2021 | if a:bullet != 'x' 2022 | return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] 2023 | else 2024 | let lines = map(s:lines(a:message), '" ".v:val') 2025 | return extend([printf('x %s:', a:name)], lines) 2026 | endif 2027 | endfunction 2028 | 2029 | function! s:with_cd(cmd, dir) 2030 | return printf('cd%s %s && %s', s:is_win ? ' /d' : '', s:shellesc(a:dir), a:cmd) 2031 | endfunction 2032 | 2033 | function! s:system(cmd, ...) 2034 | try 2035 | let [sh, shellcmdflag, shrd] = s:chsh(1) 2036 | let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd 2037 | if s:is_win 2038 | let batchfile = tempname().'.bat' 2039 | call writefile(["@echo off\r", cmd . "\r"], batchfile) 2040 | let cmd = batchfile 2041 | endif 2042 | return system(s:is_win ? '('.cmd.')' : cmd) 2043 | finally 2044 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] 2045 | if s:is_win 2046 | call delete(batchfile) 2047 | endif 2048 | endtry 2049 | endfunction 2050 | 2051 | function! s:system_chomp(...) 2052 | let ret = call('s:system', a:000) 2053 | return v:shell_error ? '' : substitute(ret, '\n$', '', '') 2054 | endfunction 2055 | 2056 | function! s:git_validate(spec, check_branch) 2057 | let err = '' 2058 | if isdirectory(a:spec.dir) 2059 | 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)) 2060 | let remote = result[-1] 2061 | if v:shell_error 2062 | let err = join([remote, 'PlugClean required.'], "\n") 2063 | elseif !s:compare_git_uri(remote, a:spec.uri) 2064 | let err = join(['Invalid URI: '.remote, 2065 | \ 'Expected: '.a:spec.uri, 2066 | \ 'PlugClean required.'], "\n") 2067 | elseif a:check_branch && has_key(a:spec, 'commit') 2068 | let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir)) 2069 | let sha = result[-1] 2070 | if v:shell_error 2071 | let err = join(add(result, 'PlugClean required.'), "\n") 2072 | elseif !s:hash_match(sha, a:spec.commit) 2073 | let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', 2074 | \ a:spec.commit[:6], sha[:6]), 2075 | \ 'PlugUpdate required.'], "\n") 2076 | endif 2077 | elseif a:check_branch 2078 | let branch = result[0] 2079 | " Check tag 2080 | if has_key(a:spec, 'tag') 2081 | let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) 2082 | if a:spec.tag !=# tag && a:spec.tag !~ '\*' 2083 | let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', 2084 | \ (empty(tag) ? 'N/A' : tag), a:spec.tag) 2085 | endif 2086 | " Check branch 2087 | elseif a:spec.branch !=# branch 2088 | let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', 2089 | \ branch, a:spec.branch) 2090 | endif 2091 | if empty(err) 2092 | let [ahead, behind] = split(s:lastline(s:system(printf( 2093 | \ 'git rev-list --count --left-right HEAD...origin/%s', 2094 | \ a:spec.branch), a:spec.dir)), '\t') 2095 | if !v:shell_error && ahead 2096 | if behind 2097 | " Only mention PlugClean if diverged, otherwise it's likely to be 2098 | " pushable (and probably not that messed up). 2099 | let err = printf( 2100 | \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n" 2101 | \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', a:spec.branch, ahead, behind) 2102 | else 2103 | let err = printf("Ahead of origin/%s by %d commit(s).\n" 2104 | \ .'Cannot update until local changes are pushed.', 2105 | \ a:spec.branch, ahead) 2106 | endif 2107 | endif 2108 | endif 2109 | endif 2110 | else 2111 | let err = 'Not found' 2112 | endif 2113 | return [err, err =~# 'PlugClean'] 2114 | endfunction 2115 | 2116 | function! s:rm_rf(dir) 2117 | if isdirectory(a:dir) 2118 | call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(a:dir)) 2119 | endif 2120 | endfunction 2121 | 2122 | function! s:clean(force) 2123 | call s:prepare() 2124 | call append(0, 'Searching for invalid plugins in '.g:plug_home) 2125 | call append(1, '') 2126 | 2127 | " List of valid directories 2128 | let dirs = [] 2129 | let errs = {} 2130 | let [cnt, total] = [0, len(g:plugs)] 2131 | for [name, spec] in items(g:plugs) 2132 | if !s:is_managed(name) 2133 | call add(dirs, spec.dir) 2134 | else 2135 | let [err, clean] = s:git_validate(spec, 1) 2136 | if clean 2137 | let errs[spec.dir] = s:lines(err)[0] 2138 | else 2139 | call add(dirs, spec.dir) 2140 | endif 2141 | endif 2142 | let cnt += 1 2143 | call s:progress_bar(2, repeat('=', cnt), total) 2144 | normal! 2G 2145 | redraw 2146 | endfor 2147 | 2148 | let allowed = {} 2149 | for dir in dirs 2150 | let allowed[s:dirpath(fnamemodify(dir, ':h:h'))] = 1 2151 | let allowed[dir] = 1 2152 | for child in s:glob_dir(dir) 2153 | let allowed[child] = 1 2154 | endfor 2155 | endfor 2156 | 2157 | let todo = [] 2158 | let found = sort(s:glob_dir(g:plug_home)) 2159 | while !empty(found) 2160 | let f = remove(found, 0) 2161 | if !has_key(allowed, f) && isdirectory(f) 2162 | call add(todo, f) 2163 | call append(line('$'), '- ' . f) 2164 | if has_key(errs, f) 2165 | call append(line('$'), ' ' . errs[f]) 2166 | endif 2167 | let found = filter(found, 'stridx(v:val, f) != 0') 2168 | end 2169 | endwhile 2170 | 2171 | 4 2172 | redraw 2173 | if empty(todo) 2174 | call append(line('$'), 'Already clean.') 2175 | else 2176 | let s:clean_count = 0 2177 | call append(3, ['Directories to delete:', '']) 2178 | redraw! 2179 | if a:force || s:ask_no_interrupt('Delete all directories?') 2180 | call s:delete([6, line('$')], 1) 2181 | else 2182 | call setline(4, 'Cancelled.') 2183 | nnoremap d :set opfunc=delete_opg@ 2184 | nmap dd d_ 2185 | xnoremap d :call delete_op(visualmode(), 1) 2186 | echo 'Delete the lines (d{motion}) to delete the corresponding directories' 2187 | endif 2188 | endif 2189 | 4 2190 | setlocal nomodifiable 2191 | endfunction 2192 | 2193 | function! s:delete_op(type, ...) 2194 | call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) 2195 | endfunction 2196 | 2197 | function! s:delete(range, force) 2198 | let [l1, l2] = a:range 2199 | let force = a:force 2200 | while l1 <= l2 2201 | let line = getline(l1) 2202 | if line =~ '^- ' && isdirectory(line[2:]) 2203 | execute l1 2204 | redraw! 2205 | let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) 2206 | let force = force || answer > 1 2207 | if answer 2208 | call s:rm_rf(line[2:]) 2209 | setlocal modifiable 2210 | call setline(l1, '~'.line[1:]) 2211 | let s:clean_count += 1 2212 | call setline(4, printf('Removed %d directories.', s:clean_count)) 2213 | setlocal nomodifiable 2214 | endif 2215 | endif 2216 | let l1 += 1 2217 | endwhile 2218 | endfunction 2219 | 2220 | function! s:upgrade() 2221 | echo 'Downloading the latest version of vim-plug' 2222 | redraw 2223 | let tmp = tempname() 2224 | let new = tmp . '/plug.vim' 2225 | 2226 | try 2227 | let out = s:system(printf('git clone --depth 1 %s %s', s:plug_src, tmp)) 2228 | if v:shell_error 2229 | return s:err('Error upgrading vim-plug: '. out) 2230 | endif 2231 | 2232 | if readfile(s:me) ==# readfile(new) 2233 | echo 'vim-plug is already up-to-date' 2234 | return 0 2235 | else 2236 | call rename(s:me, s:me . '.old') 2237 | call rename(new, s:me) 2238 | unlet g:loaded_plug 2239 | echo 'vim-plug has been upgraded' 2240 | return 1 2241 | endif 2242 | finally 2243 | silent! call s:rm_rf(tmp) 2244 | endtry 2245 | endfunction 2246 | 2247 | function! s:upgrade_specs() 2248 | for spec in values(g:plugs) 2249 | let spec.frozen = get(spec, 'frozen', 0) 2250 | endfor 2251 | endfunction 2252 | 2253 | function! s:status() 2254 | call s:prepare() 2255 | call append(0, 'Checking plugins') 2256 | call append(1, '') 2257 | 2258 | let ecnt = 0 2259 | let unloaded = 0 2260 | let [cnt, total] = [0, len(g:plugs)] 2261 | for [name, spec] in items(g:plugs) 2262 | let is_dir = isdirectory(spec.dir) 2263 | if has_key(spec, 'uri') 2264 | if is_dir 2265 | let [err, _] = s:git_validate(spec, 1) 2266 | let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] 2267 | else 2268 | let [valid, msg] = [0, 'Not found. Try PlugInstall.'] 2269 | endif 2270 | else 2271 | if is_dir 2272 | let [valid, msg] = [1, 'OK'] 2273 | else 2274 | let [valid, msg] = [0, 'Not found.'] 2275 | endif 2276 | endif 2277 | let cnt += 1 2278 | let ecnt += !valid 2279 | " `s:loaded` entry can be missing if PlugUpgraded 2280 | if is_dir && get(s:loaded, name, -1) == 0 2281 | let unloaded = 1 2282 | let msg .= ' (not loaded)' 2283 | endif 2284 | call s:progress_bar(2, repeat('=', cnt), total) 2285 | call append(3, s:format_message(valid ? '-' : 'x', name, msg)) 2286 | normal! 2G 2287 | redraw 2288 | endfor 2289 | call setline(1, 'Finished. '.ecnt.' error(s).') 2290 | normal! gg 2291 | setlocal nomodifiable 2292 | if unloaded 2293 | echo "Press 'L' on each line to load plugin, or 'U' to update" 2294 | nnoremap L :call status_load(line('.')) 2295 | xnoremap L :call status_load(line('.')) 2296 | end 2297 | endfunction 2298 | 2299 | function! s:extract_name(str, prefix, suffix) 2300 | return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') 2301 | endfunction 2302 | 2303 | function! s:status_load(lnum) 2304 | let line = getline(a:lnum) 2305 | let name = s:extract_name(line, '-', '(not loaded)') 2306 | if !empty(name) 2307 | call plug#load(name) 2308 | setlocal modifiable 2309 | call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) 2310 | setlocal nomodifiable 2311 | endif 2312 | endfunction 2313 | 2314 | function! s:status_update() range 2315 | let lines = getline(a:firstline, a:lastline) 2316 | let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') 2317 | if !empty(names) 2318 | echo 2319 | execute 'PlugUpdate' join(names) 2320 | endif 2321 | endfunction 2322 | 2323 | function! s:is_preview_window_open() 2324 | silent! wincmd P 2325 | if &previewwindow 2326 | wincmd p 2327 | return 1 2328 | endif 2329 | endfunction 2330 | 2331 | function! s:find_name(lnum) 2332 | for lnum in reverse(range(1, a:lnum)) 2333 | let line = getline(lnum) 2334 | if empty(line) 2335 | return '' 2336 | endif 2337 | let name = s:extract_name(line, '-', '') 2338 | if !empty(name) 2339 | return name 2340 | endif 2341 | endfor 2342 | return '' 2343 | endfunction 2344 | 2345 | function! s:preview_commit() 2346 | if b:plug_preview < 0 2347 | let b:plug_preview = !s:is_preview_window_open() 2348 | endif 2349 | 2350 | let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}') 2351 | if empty(sha) 2352 | return 2353 | endif 2354 | 2355 | let name = s:find_name(line('.')) 2356 | if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) 2357 | return 2358 | endif 2359 | 2360 | if exists('g:plug_pwindow') && !s:is_preview_window_open() 2361 | execute g:plug_pwindow 2362 | execute 'e' sha 2363 | else 2364 | execute 'pedit' sha 2365 | wincmd P 2366 | endif 2367 | setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable 2368 | try 2369 | let [sh, shellcmdflag, shrd] = s:chsh(1) 2370 | let cmd = 'cd '.s:shellesc(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha 2371 | if s:is_win 2372 | let batchfile = tempname().'.bat' 2373 | call writefile(["@echo off\r", cmd . "\r"], batchfile) 2374 | let cmd = batchfile 2375 | endif 2376 | execute 'silent %!' cmd 2377 | finally 2378 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] 2379 | if s:is_win 2380 | call delete(batchfile) 2381 | endif 2382 | endtry 2383 | setlocal nomodifiable 2384 | nnoremap q :q 2385 | wincmd p 2386 | endfunction 2387 | 2388 | function! s:section(flags) 2389 | call search('\(^[x-] \)\@<=[^:]\+:', a:flags) 2390 | endfunction 2391 | 2392 | function! s:format_git_log(line) 2393 | let indent = ' ' 2394 | let tokens = split(a:line, nr2char(1)) 2395 | if len(tokens) != 5 2396 | return indent.substitute(a:line, '\s*$', '', '') 2397 | endif 2398 | let [graph, sha, refs, subject, date] = tokens 2399 | let tag = matchstr(refs, 'tag: [^,)]\+') 2400 | let tag = empty(tag) ? ' ' : ' ('.tag.') ' 2401 | return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) 2402 | endfunction 2403 | 2404 | function! s:append_ul(lnum, text) 2405 | call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) 2406 | endfunction 2407 | 2408 | function! s:diff() 2409 | call s:prepare() 2410 | call append(0, ['Collecting changes ...', '']) 2411 | let cnts = [0, 0] 2412 | let bar = '' 2413 | let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') 2414 | call s:progress_bar(2, bar, len(total)) 2415 | for origin in [1, 0] 2416 | let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) 2417 | if empty(plugs) 2418 | continue 2419 | endif 2420 | call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') 2421 | for [k, v] in plugs 2422 | let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..' 2423 | let cmd = 'git log --graph --color=never '.join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 's:shellesc(v:val)')) 2424 | if has_key(v, 'rtp') 2425 | let cmd .= ' -- '.s:shellesc(v.rtp) 2426 | endif 2427 | let diff = s:system_chomp(cmd, v.dir) 2428 | if !empty(diff) 2429 | let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' 2430 | call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) 2431 | let cnts[origin] += 1 2432 | endif 2433 | let bar .= '=' 2434 | call s:progress_bar(2, bar, len(total)) 2435 | normal! 2G 2436 | redraw 2437 | endfor 2438 | if !cnts[origin] 2439 | call append(5, ['', 'N/A']) 2440 | endif 2441 | endfor 2442 | call setline(1, printf('%d plugin(s) updated.', cnts[0]) 2443 | \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) 2444 | 2445 | if cnts[0] || cnts[1] 2446 | nnoremap (plug-preview) :silent! call preview_commit() 2447 | if empty(maparg("\", 'n')) 2448 | nmap (plug-preview) 2449 | endif 2450 | if empty(maparg('o', 'n')) 2451 | nmap o (plug-preview) 2452 | endif 2453 | endif 2454 | if cnts[0] 2455 | nnoremap X :call revert() 2456 | echo "Press 'X' on each block to revert the update" 2457 | endif 2458 | normal! gg 2459 | setlocal nomodifiable 2460 | endfunction 2461 | 2462 | function! s:revert() 2463 | if search('^Pending updates', 'bnW') 2464 | return 2465 | endif 2466 | 2467 | let name = s:find_name(line('.')) 2468 | if empty(name) || !has_key(g:plugs, name) || 2469 | \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' 2470 | return 2471 | endif 2472 | 2473 | call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch).' --', g:plugs[name].dir) 2474 | setlocal modifiable 2475 | normal! "_dap 2476 | setlocal nomodifiable 2477 | echo 'Reverted' 2478 | endfunction 2479 | 2480 | function! s:snapshot(force, ...) abort 2481 | call s:prepare() 2482 | setf vim 2483 | call append(0, ['" Generated by vim-plug', 2484 | \ '" '.strftime("%c"), 2485 | \ '" :source this file in vim to restore the snapshot', 2486 | \ '" or execute: vim -S snapshot.vim', 2487 | \ '', '', 'PlugUpdate!']) 2488 | 1 2489 | let anchor = line('$') - 3 2490 | let names = sort(keys(filter(copy(g:plugs), 2491 | \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) 2492 | for name in reverse(names) 2493 | let sha = s:system_chomp('git rev-parse --short HEAD', g:plugs[name].dir) 2494 | if !empty(sha) 2495 | call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) 2496 | redraw 2497 | endif 2498 | endfor 2499 | 2500 | if a:0 > 0 2501 | let fn = expand(a:1) 2502 | if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) 2503 | return 2504 | endif 2505 | call writefile(getline(1, '$'), fn) 2506 | echo 'Saved as '.a:1 2507 | silent execute 'e' s:esc(fn) 2508 | setf vim 2509 | endif 2510 | endfunction 2511 | 2512 | function! s:split_rtp() 2513 | return split(&rtp, '\\\@