diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3188124..2162ffc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ Issues Before submitting an issue, be sure to check the following places for answers. -1. Vundle docs at [`:h vundle`](https://github.com/gmarik/vundle/blob/master/doc/vundle.txt). +1. Vundle docs at [`:h vundle`](https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt). 2. The [FAQ](https://github.com/gmarik/Vundle.vim/search). @@ -53,9 +53,9 @@ Vimrc: set nocompatible syntax on filetype off -set rtp+=~/.vim/bundle/vundle/ +set rtp+=~/.vim/bundle/Vundle.vim/ call vundle#rc() -Bundle 'gmarik/vundle' +Bundle 'gmarik/Vundle.vim' Bundle 'relevant/plugin' filetype plugin indent on diff --git a/README.md b/README.md index 95c5ec0..05096b0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## [Help Maintain Vundle](https://github.com/gmarik/Vundle.vim/issues/241) +## [Help Maintain Vundle](https://github.com/gmarik/Vundle.vim/issues/383) ## About @@ -20,7 +20,9 @@ [Vundle] is undergoing an [interface change], please stay up to date to get latest changes. -![Vundle-installer](http://25.media.tumblr.com/tumblr_m8m96w06G81r39828o1_1280.png) +[![Gitter-chat](https://badges.gitter.im/gmarik/Vundle.vim.png)](https://gitter.im/gmarik/Vundle.vim) for discussion and support. + +![Vundle-installer](http://i.imgur.com/Rueh7Cc.png) ## Quick Start @@ -30,10 +32,11 @@ Curl is required for search. If you are using Windows, go directly to [Windows setup]. If you run into any issues, please consult the [FAQ]. + See [Tips] for some advanced configurations. 2. Set up [Vundle]: - `$ git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle` + `$ git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim` 3. Configure Plugins: @@ -44,34 +47,33 @@ filetype off " required " set the runtime path to include Vundle and initialize - set rtp+=~/.vim/bundle/vundle/ - call vundle#rc() + set rtp+=~/.vim/bundle/Vundle.vim + call vundle#begin() " alternatively, pass a path where Vundle should install plugins - "let path = '~/some/path/here' - "call vundle#rc(path) + "call vundle#begin('~/some/path/here') " let Vundle manage Vundle, required - Plugin 'gmarik/vundle' + Plugin 'gmarik/Vundle.vim' " The following are examples of different formats supported. - " Keep Plugin commands between here and filetype plugin indent on. - " scripts on GitHub repos + " Keep Plugin commands between vundle#begin/end. + " plugin on GitHub repo Plugin 'tpope/vim-fugitive' - Plugin 'Lokaltog/vim-easymotion' - Plugin 'tpope/vim-rails.git' - " The sparkup vim script is in a subdirectory of this repo called vim. - " Pass the path to set the runtimepath properly. - Plugin 'rstacruz/sparkup', {'rtp': 'vim/'} - " scripts from http://vim-scripts.org/vim/scripts.html + " plugin from http://vim-scripts.org/vim/scripts.html Plugin 'L9' - Plugin 'FuzzyFinder' - " scripts not on GitHub + " plugin not on GitHub Plugin 'git://git.wincent.com/command-t.git' " git repos on your local machine (i.e. when working on your own plugin) Plugin 'file:///home/gmarik/path/to/plugin' - " ... + " The sparkup vim script is in a subdirectory of this repo called vim. + " Pass the path to set the runtimepath properly. + Plugin 'rstacruz/sparkup', {'rtp': 'vim/'} + " Avoid a name conflict with L9 + Plugin 'user/L9', {'name': 'newL9'} - filetype plugin indent on " required + " All of your Plugins must be added before the following line + call vundle#end() " required + filetype plugin indent on " required " To ignore plugin indent changes, instead use: "filetype plugin on " @@ -82,27 +84,30 @@ " :PluginClean(!) - confirm (or auto-approve) removal of unused plugins " " see :h vundle for more details or wiki for FAQ - " NOTE: comments after Plugin commands are not allowed. - " Put your stuff after this line + " Put your non-Plugin stuff after this line ``` 4. Install Plugins: - Launch `vim` and run `:PluginInstall` + Launch `vim` and run `:PluginInstall` To install from command line: `vim +PluginInstall +qall` ## Docs -See the [`:h vundle`](https://github.com/gmarik/vundle/blob/master/doc/vundle.txt) Vimdoc for more details. +See the [`:h vundle`](https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt) Vimdoc for more details. + +## Changelog + +See the [changelog](https://github.com/gmarik/Vundle.vim/blob/master/changelog.md). ## People Using Vundle -see [Examples](https://github.com/gmarik/vundle/wiki/Examples) +see [Examples](https://github.com/gmarik/Vundle.vim/wiki/Examples) ## Contributors -see [Vundle contributors](https://github.com/gmarik/vundle/graphs/contributors) +see [Vundle contributors](https://github.com/gmarik/Vundle.vim/graphs/contributors) *Thank you!* @@ -132,9 +137,10 @@ see [Vundle contributors](https://github.com/gmarik/vundle/graphs/contributors) * search by description as well * make it rock! -[Vundle]:http://github.com/gmarik/vundle -[Windows setup]:https://github.com/gmarik/vundle/wiki/Vundle-for-Windows -[FAQ]:https://github.com/gmarik/vundle/wiki +[Vundle]:http://github.com/gmarik/Vundle.vim +[Windows setup]:https://github.com/gmarik/Vundle.vim/wiki/Vundle-for-Windows +[FAQ]:https://github.com/gmarik/Vundle.vim/wiki +[Tips]:https://github.com/gmarik/Vundle.vim/wiki/Tips-and-Tricks [Vim]:http://www.vim.org [Git]:http://git-scm.com [`git clone`]:http://gitref.org/creating/#clone @@ -143,10 +149,10 @@ see [Vundle contributors](https://github.com/gmarik/vundle/graphs/contributors) [help tags]:http://vimdoc.sourceforge.net/htmldoc/helphelp.html#:helptags [runtime path]:http://vimdoc.sourceforge.net/htmldoc/options.html#%27runtimepath%27 -[configure]:https://github.com/gmarik/vundle/blob/master/doc/vundle.txt#L122-L205 -[install]:https://github.com/gmarik/vundle/blob/master/doc/vundle.txt#L207-L226 -[update]:https://github.com/gmarik/vundle/blob/master/doc/vundle.txt#L228-L237 -[search]:https://github.com/gmarik/vundle/blob/master/doc/vundle.txt#L239-L267 -[clean]:https://github.com/gmarik/vundle/blob/master/doc/vundle.txt#L276-L289 -[interactive mode]:https://github.com/gmarik/vundle/blob/master/doc/vundle.txt#L292-L331 -[interface change]:https://github.com/gmarik/vundle/blob/master/doc/vundle.txt#L345-L369 +[configure]:https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt#L126-L233 +[install]:https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt#L234-L254 +[update]:https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt#L255-L265 +[search]:https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt#L266-L295 +[clean]:https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt#L303-L318 +[interactive mode]:https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt#L319-L360 +[interface change]:https://github.com/gmarik/Vundle.vim/blob/master/doc/vundle.txt#L372-L396 diff --git a/autoload/vundle.vim b/autoload/vundle.vim index 16eebca..2657121 100644 --- a/autoload/vundle.vim +++ b/autoload/vundle.vim @@ -1,7 +1,7 @@ " Vundle is a shortcut for Vim Bundle and Is a simple plugin manager for Vim " Author: gmarik -" HomePage: http://github.com/gmarik/vundle -" Readme: http://github.com/gmarik/vundle/blob/master/README.md +" HomePage: http://github.com/gmarik/Vundle.vim +" Readme: http://github.com/gmarik/Vundle.vim/blob/master/README.md " Version: 0.9 " Plugin Commands @@ -14,9 +14,6 @@ com! -nargs=? -bang -complete=custom,vundle#scripts#complete PluginInstall com! -nargs=? -bang -complete=custom,vundle#scripts#complete PluginSearch \ call vundle#scripts#all('!' == '', ) -com! -nargs=? -bang -complete=custom,vundle#scripts#complete Plugins -\ call vundle#scripts#all('!' == '', ) - com! -nargs=0 -bang PluginList \ call vundle#installer#list('!' == '') @@ -36,27 +33,32 @@ com! -nargs=? -bang VundleClean Plugi com! -nargs=0 VundleDocs PluginDocs com! VundleUpdate PluginInstall! -" deprecated +" Deprecated Commands com! -nargs=+ Bundle call vundle#config#bundle() com! -nargs=? -bang -complete=custom,vundle#scripts#complete BundleInstall PluginInstall com! -nargs=? -bang -complete=custom,vundle#scripts#complete BundleSearch PluginSearch -com! -nargs=? -bang -complete=custom,vundle#scripts#complete Bundles Plugins com! -nargs=0 -bang BundleList PluginList com! -nargs=? -bang BundleClean PluginClean com! -nargs=0 BundleDocs PluginDocs com! BundleUpdate PluginInstall! +" Set up the signs used in the installer window. (See :help signs) if (has('signs')) -sign define Vu_error text=! texthl=Error -sign define Vu_active text=> texthl=Comment -sign define Vu_todate text=. texthl=Comment -sign define Vu_new text=+ texthl=Comment -sign define Vu_updated text=* texthl=Comment -sign define Vu_deleted text=- texthl=Comment -sign define Vu_helptags text=* texthl=Comment + sign define Vu_error text=! texthl=Error + sign define Vu_active text=> texthl=Comment + sign define Vu_todate text=. texthl=Comment + sign define Vu_new text=+ texthl=Comment + sign define Vu_updated text=* texthl=Comment + sign define Vu_deleted text=- texthl=Comment + sign define Vu_helptags text=* texthl=Comment + sign define Vu_pinned text== texthl=Comment endif - +" Set up Vundle. This function has to be called from the users vimrc file. +" This will force Vim to source this file as a side effect which wil define +" the :Plugin command. After calling this function the user can use the +" :Plugin command in the vimrc. It is not possible to do this automatically +" because when loading the vimrc file no plugins where loaded yet. func! vundle#rc(...) abort let g:bundle_dir = len(a:000) > 0 ? expand(a:1, 1) : expand('$HOME/.vim/bundle', 1) let g:updated_bundles = [] @@ -64,3 +66,18 @@ func! vundle#rc(...) abort let g:vundle_changelog = ['Updated Plugins:'] call vundle#config#init() endf + +" Alternative to vundle#rc, offers speed up by modifying rtp only when end() +" called later. +func! vundle#begin(...) abort + let g:vundle_lazy_load = 1 + call call('vundle#rc', a:000) +endf + +" Finishes putting plugins on the rtp. +func! vundle#end(...) abort + unlet g:vundle_lazy_load + call vundle#config#activate_bundles() +endf + +" vim: set expandtab sts=2 ts=2 sw=2 tw=78 norl: diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index 7bcf647..561f468 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -1,17 +1,57 @@ +" --------------------------------------------------------------------------- +" Add a plugin to the runtimepath. +" +" arg -- a string specifying the plugin +" ... -- a dictionary of options for the plugin +" return -- the return value from vundle#config#init_bundle() +" --------------------------------------------------------------------------- func! vundle#config#bundle(arg, ...) let bundle = vundle#config#init_bundle(a:arg, a:000) - call s:rtp_rm_a() - call add(g:bundles, bundle) - call s:rtp_add_a() + if !s:check_bundle_name(bundle) + return + endif + if exists('g:vundle_lazy_load') && g:vundle_lazy_load + call add(g:bundles, bundle) + else + call s:rtp_rm_a() + call add(g:bundles, bundle) + call s:rtp_add_a() + call s:rtp_add_defaults() + endif return bundle endf + +" --------------------------------------------------------------------------- +" When lazy bundle load is used (begin/end functions), add all configured +" bundles to runtimepath and reorder appropriately. +" --------------------------------------------------------------------------- +func! vundle#config#activate_bundles() + call s:rtp_add_a() + call s:rtp_add_defaults() +endf + + +" --------------------------------------------------------------------------- +" Initialize Vundle. +" +" Start a new bundles list and make sure the runtimepath does not contain +" directories from a previous call. In theory, this should only be called +" once. +" --------------------------------------------------------------------------- func! vundle#config#init() if !exists('g:bundles') | let g:bundles = [] | endif call s:rtp_rm_a() let g:bundles = [] + let g:bundle_names = {} endf + +" --------------------------------------------------------------------------- +" Add a list of bundles to the runtimepath and source them. +" +" bundles -- a list of bundle objects +" --------------------------------------------------------------------------- func! vundle#config#require(bundles) abort for b in a:bundles call s:rtp_add(b.rtpath) @@ -21,8 +61,17 @@ func! vundle#config#require(bundles) abort exec 'runtime! '.b.name.'/after/*.vim' call s:rtp_rm(g:bundle_dir) endfor + call s:rtp_add_defaults() endf + +" --------------------------------------------------------------------------- +" Create a bundle object from a bundle specification. +" +" name -- the bundle specification as a string +" opts -- the options dictionary from then bundle definition +" return -- an initialized bundle object +" --------------------------------------------------------------------------- func! vundle#config#init_bundle(name, opts) if a:name != substitute(a:name, '^\s*\(.\{-}\)\s*$', '\1', '') echo "Spurious leading and/or trailing whitespace found in plugin spec '" . a:name . "'" @@ -33,6 +82,35 @@ func! vundle#config#init_bundle(name, opts) return b endf + +" --------------------------------------------------------------------------- +" Check if the current bundle name has already been used in this running +" instance and show an error to that effect. +" +" bundle -- a bundle object whose name is to be checked +" return -- 0 if the bundle's name has been seen before, 1 otherwise +" --------------------------------------------------------------------------- +funct! s:check_bundle_name(bundle) + if has_key(g:bundle_names, a:bundle.name) + echoerr 'Vundle error: Name collision for Plugin ' . a:bundle.name_spec . + \ '. Plugin ' . g:bundle_names[a:bundle.name] . + \ ' previously used the name "' . a:bundle.name . '"' . + \ '. Skipping Plugin ' . a:bundle.name_spec . '.' + return 0 + endif + let g:bundle_names[a:bundle.name] = a:bundle.name_spec + return 1 +endf + + +" --------------------------------------------------------------------------- +" Parse the options which can be supplied with the bundle specification. +" Corresponding documentation: vundle-plugins-configure +" +" opts -- a dictionary with the user supplied options for the bundle +" return -- a dictionary with the user supplied options for the bundle, this +" will be merged with a s:bundle object into one dictionary. +" --------------------------------------------------------------------------- func! s:parse_options(opts) " TODO: improve this if len(a:opts) != 1 | return {} | endif @@ -44,6 +122,16 @@ func! s:parse_options(opts) endif endf + +" --------------------------------------------------------------------------- +" Parse the plugin specification. Corresponding documentation: +" vundle-plugins-uris +" +" arg -- the string supplied to identify the plugin +" return -- a dictionary with the folder name (key 'name') and the uri (key +" 'uri') for cloning the plugin and the original argument (key +" 'name_spec') +" --------------------------------------------------------------------------- func! s:parse_name(arg) let arg = a:arg let git_proto = exists('g:vundle_default_git_proto') ? g:vundle_default_git_proto : 'https' @@ -67,6 +155,32 @@ func! s:parse_name(arg) return {'name': name, 'uri': uri, 'name_spec': arg } endf + +" --------------------------------------------------------------------------- +" Modify the runtimepath, after all bundles have been added, so that the +" directories that were in the default runtimepath appear first in the list +" (with their 'after' directories last). +" --------------------------------------------------------------------------- +func! s:rtp_add_defaults() + let current = &rtp + set rtp&vim + let default = &rtp + let &rtp = current + for item in reverse(split(default, ',')) + exec 'set rtp-=' . item + if fnamemodify(item, ":t") == 'after' + exec 'set rtp+=' . item + else + exec 'set rtp^=' . item + endif + endfor +endf + + +" --------------------------------------------------------------------------- +" Remove all paths for the plugins which are managed by Vundle from the +" runtimepath. +" --------------------------------------------------------------------------- func! s:rtp_rm_a() let paths = map(copy(g:bundles), 'v:val.rtpath') let prepends = join(paths, ',') @@ -75,6 +189,11 @@ func! s:rtp_rm_a() exec 'set rtp-='.fnameescape(appends) endf + +" --------------------------------------------------------------------------- +" Add all paths for the plugins which are managed by Vundle to the +" runtimepath. +" --------------------------------------------------------------------------- func! s:rtp_add_a() let paths = map(copy(g:bundles), 'v:val.rtpath') let prepends = join(paths, ',') @@ -83,27 +202,79 @@ func! s:rtp_add_a() exec 'set rtp+='.fnameescape(appends) endf + +" --------------------------------------------------------------------------- +" Remove a directory and the corresponding 'after' directory from runtimepath. +" +" dir -- the directory name to be removed as a string. The corresponding +" 'after' directory will also be removed. +" --------------------------------------------------------------------------- func! s:rtp_rm(dir) abort exec 'set rtp-='.fnameescape(expand(a:dir, 1)) exec 'set rtp-='.fnameescape(expand(a:dir.'/after', 1)) endf + +" --------------------------------------------------------------------------- +" Add a directory and the corresponding 'after' directory to runtimepath. +" +" dir -- the directory name to be added as a string. The corresponding +" 'after' directory will also be added. +" --------------------------------------------------------------------------- func! s:rtp_add(dir) abort exec 'set rtp^='.fnameescape(expand(a:dir, 1)) exec 'set rtp+='.fnameescape(expand(a:dir.'/after', 1)) endf + +" --------------------------------------------------------------------------- +" Expand and simplify a path. +" +" path -- the path to expand as a string +" return -- the expanded and simplified path +" --------------------------------------------------------------------------- func! s:expand_path(path) abort return simplify(expand(a:path, 1)) endf + +" --------------------------------------------------------------------------- +" Find the actual path inside a bundle directory to be added to the +" runtimepath. It might be provided by the user with the 'rtp' option. +" Corresponding documentation: vundle-plugins-configure +" +" opts -- a bundle dict +" return -- expanded path to the corresponding plugin directory +" --------------------------------------------------------------------------- func! s:rtpath(opts) return has_key(a:opts, 'rtp') ? s:expand_path(a:opts.path().'/'.a:opts.rtp) : a:opts.path() endf + +" --------------------------------------------------------------------------- +" a bundle 'object' +" --------------------------------------------------------------------------- let s:bundle = {} + +" --------------------------------------------------------------------------- +" Return the absolute path to the directory inside the bundle directory +" (prefix) where thr bundle will be cloned. +" +" return -- the target location to clone this bundle to +" --------------------------------------------------------------------------- func! s:bundle.path() return s:expand_path(g:bundle_dir.'/'.self.name) endf + +" --------------------------------------------------------------------------- +" Determine if the bundle has the pinned attribute set in the config +" +" return -- 1 if the bundle is pinned, 0 otherwise +" --------------------------------------------------------------------------- +func! s:bundle.is_pinned() + return get(self, 'pinned') +endf + +" vim: set expandtab sts=2 ts=2 sw=2 tw=78 norl: diff --git a/autoload/vundle/installer.vim b/autoload/vundle/installer.vim index bc2f41d..dd8247b 100644 --- a/autoload/vundle/installer.vim +++ b/autoload/vundle/installer.vim @@ -1,3 +1,10 @@ +" --------------------------------------------------------------------------- +" Try to clone all new bundles given (or all bundles in g:bundles by default) +" to g:bundle_dir. If a:bang is 1 it will also update all plugins (git pull). +" +" bang -- 1 or 0 +" ... -- any number of bundle specifications (separate arguments) +" --------------------------------------------------------------------------- func! vundle#installer#new(bang, ...) abort let bundles = (a:1 == '') ? \ g:bundles : @@ -6,12 +13,23 @@ func! vundle#installer#new(bang, ...) abort let names = vundle#scripts#bundle_names(map(copy(bundles), 'v:val.name_spec')) call vundle#scripts#view('Installer',['" Installing plugins to '.expand(g:bundle_dir, 1)], names + ['Helptags']) + " This calls 'add' as a normal mode command. This is a buffer local mapping + " defined in vundle#scripts#view(). The mapping will call a buffer local + " command InstallPlugin which in turn will call vundle#installer#run() with + " vundle#installer#install(). call s:process(a:bang, (a:bang ? 'add!' : 'add')) call vundle#config#require(bundles) endf +" --------------------------------------------------------------------------- +" Iterate over all lines in a Vundle window and execute the given command for +" every line. Used by the installation and cleaning functions. +" +" bang -- not used (FIXME) +" cmd -- the (normal mode) command to execute for every line as a string +" --------------------------------------------------------------------------- func! s:process(bang, cmd) let msg = '' @@ -43,6 +61,16 @@ func! s:process(bang, cmd) echo 'Done! '.msg endf + +" --------------------------------------------------------------------------- +" Call another function in the different Vundle windows. +" +" func_name -- the function to call +" name -- the bundle name to call func_name for (string) +" ... -- the argument to be used when calling func_name (only the first +" optional argument will be used) +" return -- the status returned by the call to func_name +" --------------------------------------------------------------------------- func! vundle#installer#run(func_name, name, ...) abort let n = a:name @@ -67,6 +95,8 @@ func! vundle#installer#run(func_name, name, ...) abort echo n.' deleted' elseif 'helptags' == status echo n.' regenerated' + elseif 'pinned' == status + echo n.' pinned' elseif 'error' == status echohl Error echo 'Error processing '.n @@ -81,6 +111,13 @@ func! vundle#installer#run(func_name, name, ...) abort return status endf + +" --------------------------------------------------------------------------- +" Put a sign on the current line, indicating the status of the installation +" step. +" +" status -- string describing the status +" --------------------------------------------------------------------------- func! s:sign(status) if (!has('signs')) return @@ -89,6 +126,14 @@ func! s:sign(status) exe ":sign place ".line('.')." line=".line('.')." name=Vu_". a:status ." buffer=" . bufnr("%") endf + +" --------------------------------------------------------------------------- +" Install a plugin, then add it to the runtimepath and source it. +" +" bang -- 1 or 0, passed directly to vundle#installer#install() +" name -- the name of a bundle (string) +" return -- the return value from vundle#installer#install() +" --------------------------------------------------------------------------- func! vundle#installer#install_and_require(bang, name) abort let result = vundle#installer#install(a:bang, a:name) let b = vundle#config#bundle(a:name, {}) @@ -97,6 +142,14 @@ func! vundle#installer#install_and_require(bang, name) abort return result endf + +" --------------------------------------------------------------------------- +" Install or update a bundle given by its name. +" +" bang -- 1 or 0, passed directly to s:sync() +" name -- the name of a bundle (string) +" return -- the return value from s:sync() +" --------------------------------------------------------------------------- func! vundle#installer#install(bang, name) abort if !isdirectory(g:bundle_dir) | call mkdir(g:bundle_dir, 'p') | endif @@ -112,6 +165,12 @@ func! vundle#installer#install(bang, name) abort return s:sync(a:bang, b) endf + +" --------------------------------------------------------------------------- +" Call :helptags for all bundles in g:bundles. +" +" return -- 'error' if an error occurred, else return 'helptags' +" --------------------------------------------------------------------------- func! vundle#installer#docs() abort let error_count = vundle#installer#helptags(g:bundles) if error_count > 0 @@ -120,6 +179,14 @@ func! vundle#installer#docs() abort return 'helptags' endf + +" --------------------------------------------------------------------------- +" Call :helptags for a list of bundles. +" +" bundles -- a list of bundle dictionaries for which :helptags should be +" called. +" return -- the number of directories where :helptags failed +" --------------------------------------------------------------------------- func! vundle#installer#helptags(bundles) abort let bundle_dirs = map(copy(a:bundles),'v:val.rtpath') let help_dirs = filter(bundle_dirs, 's:has_doc(v:val)') @@ -135,6 +202,13 @@ func! vundle#installer#helptags(bundles) abort return len(errors) endf + +" --------------------------------------------------------------------------- +" List all installed plugins. +" Corresponding documentation: vundle-plugins-list +" +" bang -- not used +" --------------------------------------------------------------------------- func! vundle#installer#list(bang) abort let bundles = vundle#scripts#bundle_names(map(copy(g:bundles), 'v:val.name_spec')) call vundle#scripts#view('list', ['" My Plugins'], bundles) @@ -143,6 +217,13 @@ func! vundle#installer#list(bang) abort endf +" --------------------------------------------------------------------------- +" List and remove all directories in the bundle directory which are not +" activated (added to the bundle list). +" +" bang -- 0 if the user should be asked to confirm every deletion, 1 if they +" should be removed unconditionally +" --------------------------------------------------------------------------- func! vundle#installer#clean(bang) abort let bundle_dirs = map(copy(g:bundles), 'v:val.path()') let all_dirs = (v:version > 702 || (v:version == 702 && has("patch51"))) @@ -174,6 +255,14 @@ func! vundle#installer#clean(bang) abort endf +" --------------------------------------------------------------------------- +" Delete to directory for a plugin. +" +" bang -- not used +" dir_name -- the bundle directory to be deleted (as a string) +" return -- 'error' if an error occurred, 'deleted' if the plugin folder was +" successfully deleted +" --------------------------------------------------------------------------- func! vundle#installer#delete(bang, dir_name) abort let cmd = ((has('win32') || has('win64')) && empty(matchstr(&shell, 'sh'))) ? @@ -187,8 +276,8 @@ func! vundle#installer#delete(bang, dir_name) abort call s:log('') call s:log('Plugin '.a:dir_name) - call s:log('$ '.cmd) - call s:log('> '.out) + call s:log(cmd, '$ ') + call s:log(out, '> ') if 0 != v:shell_error return 'error' @@ -197,6 +286,13 @@ func! vundle#installer#delete(bang, dir_name) abort endif endf + +" --------------------------------------------------------------------------- +" Check if a bundled plugin has any documentation. +" +" rtp -- a path (string) where the plugin is installed +" return -- 1 if some documentation was found, 0 otherwise +" --------------------------------------------------------------------------- func! s:has_doc(rtp) abort return isdirectory(a:rtp.'/doc') \ && (!filereadable(a:rtp.'/doc/tags') || filewritable(a:rtp.'/doc/tags')) @@ -205,6 +301,13 @@ func! s:has_doc(rtp) abort \ : !(empty(glob(a:rtp.'/doc/*.txt')) && empty(glob(a:rtp.'/doc/*.??x'))) endf + +" --------------------------------------------------------------------------- +" Update the helptags for a plugin. +" +" rtp -- the path to the plugin's root directory (string) +" return -- 1 if :helptags succeeded, 0 otherwise +" --------------------------------------------------------------------------- func! s:helptags(rtp) abort " it is important to keep trailing slash here let doc_path = resolve(a:rtp . '/doc/') @@ -218,27 +321,123 @@ func! s:helptags(rtp) abort return 1 endf -func! s:sync(bang, bundle) abort + +" --------------------------------------------------------------------------- +" Get the URL for the remote called 'origin' on the repository that +" corresponds to a given bundle. +" +" bundle -- a bundle object to check the repository for +" return -- the URL for the origin remote (string) +" --------------------------------------------------------------------------- +func! s:get_current_origin_url(bundle) abort + let cmd = 'cd '.vundle#installer#shellesc(a:bundle.path()).' && git config --get remote.origin.url' + let cmd = g:shellesc_cd(cmd) + let out = s:strip(s:system(cmd)) + return out +endf + + +" --------------------------------------------------------------------------- +" Get a short sha of the HEAD of the repository for a given bundle +" +" bundle -- a bundle object +" return -- A 15 character log sha for the current HEAD +" --------------------------------------------------------------------------- +func! s:get_current_sha(bundle) + let cmd = 'cd '.vundle#installer#shellesc(a:bundle.path()).' && git rev-parse HEAD' + let cmd = g:shellesc_cd(cmd) + let out = s:system(cmd)[0:15] + return out +endf + + +" --------------------------------------------------------------------------- +" Create the appropriate sync command to run according to the current state of +" the local repository (clone, pull, reset, etc). +" +" In the case of a pull (update), also return the current sha, so that we can +" later check that there has been an upgrade. +" +" bang -- 0 if only new plugins should be installed, 1 if existing plugins +" should be updated +" bundle -- a bundle object to create the sync command for +" return -- A list containing the command to run and the sha for the current +" HEAD +" --------------------------------------------------------------------------- +func! s:make_sync_command(bang, bundle) abort let git_dir = expand(a:bundle.path().'/.git/', 1) if isdirectory(git_dir) || filereadable(expand(a:bundle.path().'/.git', 1)) - if !(a:bang) | return 'todate' | endif - let cmd = 'cd '.vundle#installer#shellesc(a:bundle.path()).' && git pull && git submodule update --init --recursive' + let current_origin_url = s:get_current_origin_url(a:bundle) + if current_origin_url != a:bundle.uri + call s:log('Plugin URI change detected for Plugin ' . a:bundle.name) + call s:log('> Plugin ' . a:bundle.name . ' old URI: ' . current_origin_url) + call s:log('> Plugin ' . a:bundle.name . ' new URI: ' . a:bundle.uri) + " Directory names match but the origin remotes are not the same + let cmd_parts = [ + \ 'cd '.vundle#installer#shellesc(a:bundle.path()) , + \ 'git remote set-url origin ' . vundle#installer#shellesc(a:bundle.uri), + \ 'git fetch', + \ 'git reset --hard origin/HEAD', + \ 'git submodule update --init --recursive', + \ ] + let cmd = join(cmd_parts, ' && ') + let cmd = g:shellesc_cd(cmd) + let initial_sha = '' + return [cmd, initial_sha] + endif + + if !(a:bang) + " The repo exists, and no !, so leave as it is. + return ['', ''] + endif + + let cmd_parts = [ + \ 'cd '.vundle#installer#shellesc(a:bundle.path()), + \ 'git pull', + \ 'git submodule update --init --recursive', + \ ] + let cmd = join(cmd_parts, ' && ') let cmd = g:shellesc_cd(cmd) - let get_current_sha = 'cd '.vundle#installer#shellesc(a:bundle.path()).' && git rev-parse HEAD' - let get_current_sha = g:shellesc_cd(get_current_sha) - let initial_sha = s:system(get_current_sha)[0:15] + let initial_sha = s:get_current_sha(a:bundle) else let cmd = 'git clone --recursive '.vundle#installer#shellesc(a:bundle.uri).' '.vundle#installer#shellesc(a:bundle.path()) let initial_sha = '' endif + return [cmd, initial_sha] +endf + + +" --------------------------------------------------------------------------- +" Install or update a given bundle object with git. +" +" bang -- 0 if only new plugins should be installed, 1 if existing plugins +" should be updated +" bundle -- a bundle object (dictionary) +" return -- a string indicating the status of the bundle installation: +" - todate : Nothing was updated or the repository was up to date +" - new : The plugin was newly installed +" - updated : Some changes where pulled via git +" - error : An error occurred in the shell command +" - pinned : The bundle is marked as pinned +" --------------------------------------------------------------------------- +func! s:sync(bang, bundle) abort + " Do not sync if this bundle is pinned + if a:bundle.is_pinned() + return 'pinned' + endif + + let [ cmd, initial_sha ] = s:make_sync_command(a:bang, a:bundle) + if empty(cmd) + return 'todate' + endif let out = s:system(cmd) call s:log('') call s:log('Plugin '.a:bundle.name_spec) - call s:log('$ '.cmd) - call s:log('> '.out) + call s:log(cmd, '$ ') + call s:log(out, '> ') if 0 != v:shell_error return 'error' @@ -248,7 +447,7 @@ func! s:sync(bang, bundle) abort return 'new' endif - let updated_sha = s:system(get_current_sha)[0:15] + let updated_sha = s:get_current_sha(a:bundle) if initial_sha == updated_sha return 'todate' @@ -258,6 +457,14 @@ func! s:sync(bang, bundle) abort return 'updated' endf + +" --------------------------------------------------------------------------- +" Escape special characters in a string to be able to use it as a shell +" command with system(). +" +" cmd -- the string holding the shell command +" return -- a string with the relevant characters escaped +" --------------------------------------------------------------------------- func! vundle#installer#shellesc(cmd) abort if ((has('win32') || has('win64')) && empty(matchstr(&shell, 'sh'))) return '"' . substitute(a:cmd, '"', '\\"', 'g') . '"' @@ -265,6 +472,13 @@ func! vundle#installer#shellesc(cmd) abort return shellescape(a:cmd) endf + +" --------------------------------------------------------------------------- +" Fix a cd shell command to be used on Windows. +" +" cmd -- the command to be fixed (string) +" return -- the fixed command (string) +" --------------------------------------------------------------------------- func! g:shellesc_cd(cmd) abort if ((has('win32') || has('win64')) && empty(matchstr(&shell, 'sh'))) let cmd = substitute(a:cmd, '^cd ','cd /d ','') " add /d switch to change drives @@ -274,12 +488,47 @@ func! g:shellesc_cd(cmd) abort endif endf + +" --------------------------------------------------------------------------- +" Make a system call. This can be used to change the way system calls +" are made during developing, without searching the whole code base for +" actual system() calls. +" +" cmd -- the command passed to system() (string) +" return -- the return value from system() +" --------------------------------------------------------------------------- func! s:system(cmd) abort return system(a:cmd) endf -func! s:log(str) abort - let fmt = '%y%m%d %H:%M:%S' - call add(g:vundle_log, '['.strftime(fmt).'] '.a:str) + +" --------------------------------------------------------------------------- +" Add a log message to Vundle's internal logging variable. +" +" str -- the log message (string) +" prefix -- optional prefix for multi-line entries (string) +" return -- a:str +" --------------------------------------------------------------------------- +func! s:log(str, ...) abort + let prefix = a:0 > 0 ? a:1 : '' + let fmt = '%Y-%m-%d %H:%M:%S' + let lines = split(a:str, '\n', 1) + let time = strftime(fmt) + for line in lines + call add(g:vundle_log, '['. time .'] '. prefix . line) + endfor return a:str endf + + +" --------------------------------------------------------------------------- +" Remove leading and trailing whitespace from a string +" +" str -- The string to rid of trailing and leading spaces +" return -- A string stripped of side spaces +" --------------------------------------------------------------------------- +func! s:strip(str) + return substitute(a:str, '\%^\_s*\(.\{-}\)\_s*\%$', '\1', '') +endf + +" vim: set expandtab sts=2 ts=2 sw=2 tw=78 norl: diff --git a/autoload/vundle/scripts.vim b/autoload/vundle/scripts.vim index 5c43547..2129903 100644 --- a/autoload/vundle/scripts.vim +++ b/autoload/vundle/scripts.vim @@ -1,3 +1,11 @@ +" --------------------------------------------------------------------------- +" Search the database from vim-script.org for a matching plugin. If no +" argument is given, list all plugins. This function is used by the :Plugins +" and :PluginSearch commands. +" +" bang -- if 1 refresh the script name cache, if 0 don't +" ... -- a plugin name to search for +" --------------------------------------------------------------------------- func! vundle#scripts#all(bang, ...) let b:match = '' let info = ['"Keymap: i - Install plugin; c - Cleanup; s - Search; R - Reload list'] @@ -13,15 +21,31 @@ func! vundle#scripts#all(bang, ...) echo len(matches).' plugins found' endf + +" --------------------------------------------------------------------------- +" Repeat the search for bundles. +" --------------------------------------------------------------------------- func! vundle#scripts#reload() abort silent exec ':PluginSearch! '.(exists('b:match') ? b:match : '') redraw endf + +" --------------------------------------------------------------------------- +" Complete names for bundles in the command line. +" +" a, c, d -- see :h command-completion-custom +" return -- all valid plugin names from vim-scripts.org as completion +" candidates, see also :h command-completion-custom +" --------------------------------------------------------------------------- func! vundle#scripts#complete(a,c,d) return join(s:load_scripts(0),"\n") endf + +" --------------------------------------------------------------------------- +" View the logfile after an update or installation. +" --------------------------------------------------------------------------- func! s:view_log() if !exists('g:vundle_log_file') let g:vundle_log_file = tempname() @@ -33,6 +57,11 @@ func! s:view_log() wincmd P | wincmd H endf + +" --------------------------------------------------------------------------- +" Parse the output from git log after an update to create a change log for the +" user. +" --------------------------------------------------------------------------- func! s:create_changelog() abort for bundle_data in g:updated_bundles let initial_sha = bundle_data[0] @@ -61,6 +90,10 @@ func! s:create_changelog() abort endfor endf + +" --------------------------------------------------------------------------- +" View the change log after an update or installation. +" --------------------------------------------------------------------------- func! s:view_changelog() call s:create_changelog() @@ -74,10 +107,27 @@ func! s:view_changelog() wincmd P | wincmd H endf + +" --------------------------------------------------------------------------- +" Create a list of 'Plugin ...' lines from a list of bundle names. +" +" names -- a list of names (strings) of plugins +" return -- a list of 'Plugin ...' lines suitable to be written to a buffer +" --------------------------------------------------------------------------- func! vundle#scripts#bundle_names(names) return map(copy(a:names), ' printf("Plugin ' ."'%s'".'", v:val) ') endf + +" --------------------------------------------------------------------------- +" Open a buffer to display information to the user. Several special commands +" are defined in the new buffer. +" +" title -- a title for the new buffer +" headers -- a list of header lines to be displayed at the top of the buffer +" results -- the main information to be displayed in the buffer (list of +" strings) +" --------------------------------------------------------------------------- func! vundle#scripts#view(title, headers, results) if exists('g:vundle_view') && bufloaded(g:vundle_view) exec g:vundle_view.'bd!' @@ -148,6 +198,13 @@ func! vundle#scripts#view(title, headers, results) exec ':'.(len(a:headers) + 1) endf + +" --------------------------------------------------------------------------- +" Load the plugin database from vim-scripts.org . +" +" to -- the filename (string) to save the database to +" return -- 0 on success, 1 if an error occurred +" --------------------------------------------------------------------------- func! s:fetch_scripts(to) let scripts_dir = fnamemodify(expand(a:to, 1), ":h") if !isdirectory(scripts_dir) @@ -178,6 +235,15 @@ func! s:fetch_scripts(to) return 0 endf + +" --------------------------------------------------------------------------- +" Load the plugin database and return a list of all plugins. +" +" bang -- if 1 download the redatabase, else only download if it is not +" readable on disk (i.e. does not exist) +" return -- a list of strings, these are the names (valid bundle +" specifications) of all plugins from vim-scripts.org +" --------------------------------------------------------------------------- func! s:load_scripts(bang) let f = expand(g:bundle_dir.'/.vundle/script-names.vim-scripts.org.json', 1) if a:bang || !filereadable(f) @@ -187,3 +253,5 @@ func! s:load_scripts(bang) endif return eval(readfile(f, 'b')[0]) endf + +" vim: set expandtab sts=2 ts=2 sw=2 tw=78 norl: diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..a537da7 --- /dev/null +++ b/changelog.md @@ -0,0 +1,14 @@ +Change Log +========== +F = Feature, B = Bug Fix, D = Doc Change + +### Version 0.10 +- F: #415 Support plugin pinning (for non-git repos & preventing updates) +- F: #440 Detect plugin name collisions +- F: #418 Deferred rtp manipulation (speeds up start) +- B: #418 Leave default rtp directories (i.e. ~/.vim) where they should be +- B: #429 Fix newline character in log +- B: #440 Detect changed remotes & update repos +- D: #435 Image update in README.md +- D: #419 Add function documentation +- D: #436 Rename vundle to Vundle.vim, add modelines, quickstart update diff --git a/doc/vundle.txt b/doc/vundle.txt index a6c35e2..8f310cd 100644 --- a/doc/vundle.txt +++ b/doc/vundle.txt @@ -62,7 +62,7 @@ more information. 2. Setup Vundle: > - git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle + git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim < 3. Configure bundles: @@ -73,37 +73,44 @@ more information. filetype off " required " set the runtime path to include Vundle and initialize - set rtp+=~/.vim/bundle/vundle/ - call vundle#rc() - " alternatively, pass a path where Vundle should install bundles - "let path = '~/some/path/here' - "call vundle#rc(path) + set rtp+=~/.vim/bundle/Vundle.vim + call vundle#begin() + " alternatively, pass a path where Vundle should install plugins + "call vundle#begin('~/some/path/here') " let Vundle manage Vundle, required - Plugin 'gmarik/vundle' + Plugin 'gmarik/Vundle.vim' " The following are examples of different formats supported. - " Keep bundle commands between here and filetype plugin indent on. - " plugins on GitHub repos + " Keep Plugin commands between vundle#begin/end. + " plugin on GitHub repo Plugin 'tpope/vim-fugitive' - Plugin 'Lokaltog/vim-easymotion' - Plugin 'tpope/vim-rails.git' - " The sparkup vim script is in a subdirectory of this repo called vim. - " Pass the path to set the runtimepath properly. - Plugin 'rstacruz/sparkup', {'rtp': 'vim/'} - " plugins from http://vim-scripts.org/vim/scripts.html + " plugin from http://vim-scripts.org/vim/scripts.html Plugin 'L9' - Plugin 'FuzzyFinder' - " plugins not on GitHub + " plugin not on GitHub Plugin 'git://git.wincent.com/command-t.git' " git repos on your local machine (i.e. when working on your own plugin) Plugin 'file:///home/gmarik/path/to/plugin' - " ... + " The sparkup vim script is in a subdirectory of this repo called vim. + " Pass the path to set the runtimepath properly. + Plugin 'rstacruz/sparkup', {'rtp': 'vim/'} + " Avoid a name conflict with L9 + Plugin 'user/L9', {'name': 'newL9'} - filetype plugin indent on " required + " All of your Plugins must be added before the following line + call vundle#end() " required + filetype plugin indent on " required " To ignore plugin indent changes, instead use: "filetype plugin on - " Put your stuff after this line + " + " Brief help + " :PluginList - list configured plugins + " :PluginInstall(!) - install (update) plugins + " :PluginSearch(!) foo - search (or refresh cache first) for foo + " :PluginClean(!) - confirm (or auto-approve) removal of unused plugins + " + " see :h vundle for more details or wiki for FAQ + " Put your non-Plugin stuff after this line 4. Install configured bundles: @@ -166,6 +173,26 @@ This can be used to prevent name collisions between plugins that Vundle would otherwise try to clone into the same directory. It also provides an additional level of customisation. +The 'pinned' option +------------------- + +A flag that, when set to a value of 1, tells Vundle not to perform any git +operations on the plugin, while still adding the existing plugin under the +`bundles` directories to the |runtimepath|. + +For example: +> + Plugin 'mylocalplugin', {'pinned': 1} + +This allows the users to include, with Vundle, plugins tracked with version +control systems other than git, but the user is responsible for cloning and +keeping up to date. It also allows the users to stay in the current version of +a plugin that might have previously been updated by Vundle. + +Please note that the URI will be treated the same as for any other plugins, so +only the last part of it will be added to the |runtimepath|. The user is +advised to use this flag only with single word URIs to avoid confusion. + 3.2 SUPPORTED URIS ~ *vundle-plugins-uris* @@ -185,7 +212,7 @@ GitHub is used when a user/repo is passed to `Plugin`. Vim Scripts ----------- -Any single word without a '/' is assumed to be from Vim Scripts. +Any single word without a slash '/' is assumed to be from Vim Scripts. > Plugin 'ctrlp.vim' => https://github.com/vim-scripts/ctrlp.vim @@ -361,11 +388,10 @@ KEY | DESCRIPTION BundleSearch(!) | PluginSearch(!), VundleSearch(!) BundleClean | PluginClean(!), VundleClean(!) BundleList | PluginList - Bundles | Plugins Note: The Bundle commands will be deprecated. You may continue using them, but they may not get all future updates. For instance, we have enabled comments on Plugin lines but not Bundle, since it requires a change in command declaration. -vim:tw=78:ts=8:ft=help:norl: +" vim: set expandtab sts=2 ts=2 sw=2 tw=78 ft=help norl: diff --git a/test/minirc.vim b/test/minirc.vim index 352d9bc..3c24395 100644 --- a/test/minirc.vim +++ b/test/minirc.vim @@ -1,8 +1,8 @@ set nocompatible syntax on filetype off -set rtp+=~/.vim/bundle/vundle/ +set rtp+=~/.vim/bundle/Vundle.vim/ call vundle#rc() -Bundle 'gmarik/vundle' +Bundle 'gmarik/Vundle.vim' filetype plugin indent on diff --git a/test/vimrc b/test/vimrc index 13dd2e2..d8455a7 100644 --- a/test/vimrc +++ b/test/vimrc @@ -4,13 +4,13 @@ set nocompatible set nowrap let bundle_dir = '/tmp/vundle-test/bundles/' -" let src = 'http://github.com/gmarik/vundle.git' +" let src = 'http://github.com/gmarik/vundle.git' " Vundle Options " let g:vundle_default_git_proto = 'git' silent execute '!mkdir -p '.bundle_dir -silent execute '!ln -f -s ~/.vim/bundle/vundle '.bundle_dir +silent execute '!ln -f -s ~/.vim/bundle/Vundle.vim '.bundle_dir filetype off syntax on @@ -18,7 +18,7 @@ syntax on runtime macros/matchit.vim " This test should be executed in "test" directory -exec 'set rtp^='.bundle_dir.'vundle/' +exec 'set rtp^='.bundle_dir.'Vundle.vim/' call vundle#rc(bundle_dir) @@ -58,6 +58,13 @@ Bundle 'vim-scripts/RubySinatra' " syntax issue #203 Bundle 'jimenezrick/vimerl' +" Static bundle: Same name as a valid vim-scripts bundle +Bundle 'latte', {'pinned' : 1} +if !isdirectory(expand(bundle_dir) . '/latte') + call mkdir(expand(bundle_dir) . '/latte', 'p') +endif + + filetype plugin indent on " Automatically detect file types. set wildignore+=doc " should not break helptags @@ -71,3 +78,4 @@ set wildignore+=*/.git/* au VimEnter * BundleInstall " e test/files/erlang.erl +" vim: set expandtab sts=2 ts=2 sw=2 tw=78: