From c20c90d86761c8e164ae51eb97b13b0f6d9c8adf Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Mon, 7 Apr 2014 00:59:23 +0200 Subject: [PATCH 1/9] Lazy loading plugins with begin/end block --- autoload/vundle.vim | 10 ++++++++++ autoload/vundle/config.vim | 14 +++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/autoload/vundle.vim b/autoload/vundle.vim index 16eebca..83d6c90 100644 --- a/autoload/vundle.vim +++ b/autoload/vundle.vim @@ -64,3 +64,13 @@ func! vundle#rc(...) abort let g:vundle_changelog = ['Updated Plugins:'] call vundle#config#init() endf + +func! vundle#begin(...) abort + let g:vundle_lazy_load = 1 + call call('vundle#rc', a:000) +endf + +func! vundle#end(...) abort + unlet g:vundle_lazy_load + call vundle#config#activate_bundles() +endf diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index 7bcf647..0e6b28c 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -1,11 +1,19 @@ 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 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() + endif return bundle endf +func! vundle#config#activate_bundles() + call s:rtp_add_a() +endf + func! vundle#config#init() if !exists('g:bundles') | let g:bundles = [] | endif call s:rtp_rm_a() From 1736243c0edea1209be4179b4206961a108a7d0c Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Mon, 7 Apr 2014 01:39:10 +0200 Subject: [PATCH 2/9] Handle default rtp values --- autoload/vundle/config.vim | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index 0e6b28c..a496752 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -1,17 +1,19 @@ func! vundle#config#bundle(arg, ...) let bundle = vundle#config#init_bundle(a:arg, a:000) if exists('g:vundle_lazy_load') && g:vundle_lazy_load - call add(g:bundles, bundle) + call add(g:bundles, bundle) else - call s:rtp_rm_a() - call add(g:bundles, bundle) - call s:rtp_add_a() + call s:rtp_rm_a() + call add(g:bundles, bundle) + call s:rtp_add_a() + call s:rtp_add_defaults() endif return bundle endf func! vundle#config#activate_bundles() call s:rtp_add_a() + call s:rtp_add_defaults() endf func! vundle#config#init() @@ -29,6 +31,7 @@ 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 func! vundle#config#init_bundle(name, opts) @@ -75,6 +78,22 @@ func! s:parse_name(arg) return {'name': name, 'uri': uri, 'name_spec': arg } endf +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 + + func! s:rtp_rm_a() let paths = map(copy(g:bundles), 'v:val.rtpath') let prepends = join(paths, ',') From 0152571eb570c5ac9e347dfb0c1aeb25ce28c950 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Mon, 7 Apr 2014 02:35:45 +0200 Subject: [PATCH 3/9] Add multiple lines separately to the log --- autoload/vundle/installer.vim | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/autoload/vundle/installer.vim b/autoload/vundle/installer.vim index bc2f41d..c96e078 100644 --- a/autoload/vundle/installer.vim +++ b/autoload/vundle/installer.vim @@ -187,8 +187,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' @@ -237,8 +237,8 @@ func! s:sync(bang, bundle) abort 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' @@ -278,8 +278,13 @@ 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) +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 From f3da68779ad06db096313fd9ddcbb8325157acb6 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Thu, 10 Nov 2011 23:50:31 +0000 Subject: [PATCH 4/9] Support plugin pinning New supported option called 'pinned' for the Plugin command. When set to 1, the plugin is added to rtp but no install/upgrade operation is performed. It not only allows vundle to do rtp management of plugins on VCS other than git, it also allows leaving plugins that had previously been managed by vundle in the current state, with no further updates. Fixes #24, #397 --- autoload/vundle.vim | 1 + autoload/vundle/config.vim | 4 ++++ autoload/vundle/installer.vim | 7 +++++++ doc/vundle.txt | 22 +++++++++++++++++++++- test/vimrc | 7 +++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/autoload/vundle.vim b/autoload/vundle.vim index 83d6c90..e41693d 100644 --- a/autoload/vundle.vim +++ b/autoload/vundle.vim @@ -54,6 +54,7 @@ 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 diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index a496752..785d43c 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -134,3 +134,7 @@ func! s:bundle.path() return s:expand_path(g:bundle_dir.'/'.self.name) endf +func! s:bundle.is_pinned() + return get(self, 'pinned') +endf + diff --git a/autoload/vundle/installer.vim b/autoload/vundle/installer.vim index c96e078..245dd74 100644 --- a/autoload/vundle/installer.vim +++ b/autoload/vundle/installer.vim @@ -67,6 +67,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 @@ -219,6 +221,11 @@ func! s:helptags(rtp) abort endf func! s:sync(bang, bundle) abort + " Do not sync if this bundle is pinned + if a:bundle.is_pinned() + return 'pinned' + endif + 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 diff --git a/doc/vundle.txt b/doc/vundle.txt index a6c35e2..3cffe91 100644 --- a/doc/vundle.txt +++ b/doc/vundle.txt @@ -166,6 +166,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 +205,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 diff --git a/test/vimrc b/test/vimrc index 13dd2e2..b4f2676 100644 --- a/test/vimrc +++ b/test/vimrc @@ -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 From b3b5f529b306b5084ad566eb2a62d3992aac5f07 Mon Sep 17 00:00:00 2001 From: Lucas Hoffmann Date: Sat, 29 Mar 2014 18:56:21 +0100 Subject: [PATCH 5/9] Add comments to document the code Also add some FIXME markers in places where the code needs more explanation. --- autoload/vundle.vim | 25 ++++---- autoload/vundle/config.vim | 66 +++++++++++++++++++++ autoload/vundle/installer.vim | 104 +++++++++++++++++++++++++++++++++- autoload/vundle/scripts.vim | 40 +++++++++++++ 4 files changed, 222 insertions(+), 13 deletions(-) diff --git a/autoload/vundle.vim b/autoload/vundle.vim index e41693d..adf93ad 100644 --- a/autoload/vundle.vim +++ b/autoload/vundle.vim @@ -36,7 +36,7 @@ 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 @@ -46,18 +46,23 @@ com! -nargs=? -bang BundleClean Plugi 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_pinned 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 = [] diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index 785d43c..4292095 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -1,3 +1,8 @@ +" 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) if exists('g:vundle_lazy_load') && g:vundle_lazy_load @@ -16,12 +21,19 @@ func! vundle#config#activate_bundles() call s:rtp_add_defaults() endf +" Initialize Vundle. +" +" return -- 0 (unconditionally) func! vundle#config#init() if !exists('g:bundles') | let g:bundles = [] | endif call s:rtp_rm_a() let g:bundles = [] endf +" Add a list of bundles to the runtimepath and source them. +" +" bundles -- a list of bundle objects +" return -- 0 (unconditionally) func! vundle#config#require(bundles) abort for b in a:bundles call s:rtp_add(b.rtpath) @@ -34,6 +46,11 @@ func! vundle#config#require(bundles) abort 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 . "'" @@ -44,6 +61,12 @@ func! vundle#config#init_bundle(name, opts) return b 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 @@ -55,6 +78,13 @@ 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' @@ -94,6 +124,10 @@ func! s:rtp_add_defaults() endf +" Remove all paths for the plugins which are managed by Vundle from the +" runtimepath. +" +" return -- 0 (unconditionally) func! s:rtp_rm_a() let paths = map(copy(g:bundles), 'v:val.rtpath') let prepends = join(paths, ',') @@ -102,6 +136,10 @@ 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. +" +" return -- 0 (unconditionally) func! s:rtp_add_a() let paths = map(copy(g:bundles), 'v:val.rtpath') let prepends = join(paths, ',') @@ -110,26 +148,54 @@ 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. +" return -- 0 (unconditionally) 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. +" return -- 0 (unconditionally) 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 = {} +" FIXME: This function is only called once and in most cases the return value +" is stored in the bundle object as obj.rtpath unmodfied. Is this necessary? +" +" 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 diff --git a/autoload/vundle/installer.vim b/autoload/vundle/installer.vim index 245dd74..ea1bde0 100644 --- a/autoload/vundle/installer.vim +++ b/autoload/vundle/installer.vim @@ -1,3 +1,9 @@ +" 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 (seperate arguments) +" return -- 0 (unconditionally) func! vundle#installer#new(bang, ...) abort let bundles = (a:1 == '') ? \ g:bundles : @@ -6,12 +12,22 @@ 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']) + " FIXME this tries to call '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(). This is very + " confusing and unclear. 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 +" return -- 0 (unconditionally) func! s:process(bang, cmd) let msg = '' @@ -43,6 +59,13 @@ 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 @@ -83,6 +106,11 @@ 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 +" return -- 0 (unconditionally) func! s:sign(status) if (!has('signs')) return @@ -91,6 +119,11 @@ 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, {}) @@ -99,6 +132,11 @@ 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 @@ -114,6 +152,9 @@ 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 @@ -122,6 +163,11 @@ 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)') @@ -137,6 +183,11 @@ func! vundle#installer#helptags(bundles) abort return len(errors) endf +" List all installed plugins. +" Corresponding documentation: vundle-plugins-list +" +" bang -- not used +" return -- 0 (unconditionally) 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) @@ -144,7 +195,12 @@ func! vundle#installer#list(bang) abort echo len(g:bundles).' plugins configured' 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 +" return -- 0 (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"))) @@ -175,7 +231,12 @@ func! vundle#installer#clean(bang) abort endif 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'))) ? @@ -199,6 +260,10 @@ 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')) @@ -207,6 +272,10 @@ 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/') @@ -220,6 +289,15 @@ func! s:helptags(rtp) abort return 1 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 (dict) +" return -- 'todate' if nothing was updated or the repository was up to date, +" 'new' when the plugin was newly installed, 'updated' if some +" changes where pulled via git, 'error' if an error occurred in the +" shell command func! s:sync(bang, bundle) abort " Do not sync if this bundle is pinned if a:bundle.is_pinned() @@ -265,6 +343,11 @@ 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') . '"' @@ -272,6 +355,10 @@ 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 @@ -281,10 +368,21 @@ 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 +" Add a log message to Vundle's internal logging variable. +" +" str -- the log message (string) +" prefix -- optional prefix for multiline 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' diff --git a/autoload/vundle/scripts.vim b/autoload/vundle/scripts.vim index 5c43547..6381391 100644 --- a/autoload/vundle/scripts.vim +++ b/autoload/vundle/scripts.vim @@ -1,3 +1,10 @@ +" Searches the database from vim-script.org for a matching plugin. If no +" argument is given all plugins are listed. 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 (FIXME what about multible arguments, it +" doesn't seem to work.) func! vundle#scripts#all(bang, ...) let b:match = '' let info = ['"Keymap: i - Install plugin; c - Cleanup; s - Search; R - Reload list'] @@ -13,15 +20,22 @@ 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 +47,10 @@ 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 +" tuser. +" +" return -- 0 (unconditionally) func! s:create_changelog() abort for bundle_data in g:updated_bundles let initial_sha = bundle_data[0] @@ -61,6 +79,7 @@ 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 +93,21 @@ 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 +178,10 @@ 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 +212,12 @@ 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) From 87e5a195207150eb2fc2374645e1bdd9d12412d2 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Thu, 10 Apr 2014 23:50:05 +0200 Subject: [PATCH 6/9] Complete function documentation - Complete the code documentation effort started by @lucc - Remove some judgemental comments :sparkles: - Remove comments pertaining to things that should be opened as issues - Boxed :exclamation: --- autoload/vundle/config.vim | 71 +++++++++++++++++++++++++++++------ autoload/vundle/installer.vim | 67 ++++++++++++++++++++++++++++----- autoload/vundle/scripts.vim | 42 +++++++++++++++++---- 3 files changed, 151 insertions(+), 29 deletions(-) diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index 4292095..309fb4e 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -1,8 +1,10 @@ +" --------------------------------------------------------------------------- " 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) if exists('g:vundle_lazy_load') && g:vundle_lazy_load @@ -16,24 +18,36 @@ func! vundle#config#bundle(arg, ...) 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. " -" return -- 0 (unconditionally) +" 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 = [] endf + +" --------------------------------------------------------------------------- " Add a list of bundles to the runtimepath and source them. " " bundles -- a list of bundle objects -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- func! vundle#config#require(bundles) abort for b in a:bundles call s:rtp_add(b.rtpath) @@ -46,11 +60,14 @@ func! vundle#config#require(bundles) abort 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 . "'" @@ -61,12 +78,15 @@ func! vundle#config#init_bundle(name, opts) return b 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 @@ -78,6 +98,8 @@ func! s:parse_options(opts) endif endf + +" --------------------------------------------------------------------------- " Parse the plugin specification. Corresponding documentation: " vundle-plugins-uris " @@ -85,6 +107,7 @@ endf " 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' @@ -108,6 +131,12 @@ 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 @@ -124,10 +153,10 @@ func! s:rtp_add_defaults() endf +" --------------------------------------------------------------------------- " Remove all paths for the plugins which are managed by Vundle from the " runtimepath. -" -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- func! s:rtp_rm_a() let paths = map(copy(g:bundles), 'v:val.rtpath') let prepends = join(paths, ',') @@ -136,10 +165,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. -" -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- func! s:rtp_add_a() let paths = map(copy(g:bundles), 'v:val.rtpath') let prepends = join(paths, ',') @@ -148,58 +178,77 @@ 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. -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- 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. -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- 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 = {} -" FIXME: This function is only called once and in most cases the return value -" is stored in the bundle object as obj.rtpath unmodfied. Is this necessary? -" + +" --------------------------------------------------------------------------- " 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 diff --git a/autoload/vundle/installer.vim b/autoload/vundle/installer.vim index ea1bde0..a9afd11 100644 --- a/autoload/vundle/installer.vim +++ b/autoload/vundle/installer.vim @@ -1,9 +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 (seperate arguments) -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- func! vundle#installer#new(bang, ...) abort let bundles = (a:1 == '') ? \ g:bundles : @@ -12,22 +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']) - " FIXME this tries to call '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(). This is very - " confusing and unclear. + " 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 -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- func! s:process(bang, cmd) let msg = '' @@ -59,6 +61,8 @@ func! s:process(bang, cmd) echo 'Done! '.msg endf + +" --------------------------------------------------------------------------- " Call another function in the different Vundle windows. " " func_name -- the function to call @@ -66,6 +70,7 @@ endf " ... -- 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 @@ -106,11 +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 -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- func! s:sign(status) if (!has('signs')) return @@ -119,11 +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, {}) @@ -132,11 +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 @@ -152,9 +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 @@ -163,11 +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)') @@ -183,11 +202,13 @@ func! vundle#installer#helptags(bundles) abort return len(errors) endf + +" --------------------------------------------------------------------------- " List all installed plugins. " Corresponding documentation: vundle-plugins-list " " bang -- not used -" return -- 0 (unconditionally) +" --------------------------------------------------------------------------- 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) @@ -195,12 +216,14 @@ func! vundle#installer#list(bang) abort echo len(g:bundles).' plugins configured' 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 -" return -- 0 (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"))) @@ -231,12 +254,15 @@ func! vundle#installer#clean(bang) abort endif 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'))) ? @@ -260,10 +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')) @@ -272,10 +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/') @@ -289,6 +321,8 @@ func! s:helptags(rtp) abort return 1 endf + +" --------------------------------------------------------------------------- " Install or update a given bundle object with git. " " bang -- 0 if only new plugins should be installed, 1 if existing plugins @@ -298,6 +332,7 @@ endf " 'new' when the plugin was newly installed, 'updated' if some " changes where pulled via git, 'error' if an error occurred in the " shell command +" --------------------------------------------------------------------------- func! s:sync(bang, bundle) abort " Do not sync if this bundle is pinned if a:bundle.is_pinned() @@ -343,11 +378,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') . '"' @@ -355,10 +393,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 @@ -368,21 +409,27 @@ 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 + +" --------------------------------------------------------------------------- " Add a log message to Vundle's internal logging variable. " " str -- the log message (string) " prefix -- optional prefix for multiline 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' diff --git a/autoload/vundle/scripts.vim b/autoload/vundle/scripts.vim index 6381391..40f91b9 100644 --- a/autoload/vundle/scripts.vim +++ b/autoload/vundle/scripts.vim @@ -1,10 +1,11 @@ -" Searches the database from vim-script.org for a matching plugin. If no -" argument is given all plugins are listed. This function is used by the -" :Plugins and :PluginSearch commands. +" --------------------------------------------------------------------------- +" 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 (FIXME what about multible arguments, it -" doesn't seem to work.) +" ... -- 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'] @@ -20,22 +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() @@ -47,10 +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 -" tuser. -" -" return -- 0 (unconditionally) +" user. +" --------------------------------------------------------------------------- func! s:create_changelog() abort for bundle_data in g:updated_bundles let initial_sha = bundle_data[0] @@ -79,7 +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() @@ -93,14 +107,19 @@ 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. " @@ -108,6 +127,7 @@ endf " 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!' @@ -178,10 +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) @@ -212,12 +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) From 50fe09cbd28afdb61879cb667730116f23a376f8 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Fri, 11 Apr 2014 00:13:32 +0200 Subject: [PATCH 7/9] Remove Plugins command It's a duplicate of the PluginSearch command. Fixes #428 --- autoload/vundle.vim | 4 ---- 1 file changed, 4 deletions(-) diff --git a/autoload/vundle.vim b/autoload/vundle.vim index adf93ad..781abc3 100644 --- a/autoload/vundle.vim +++ b/autoload/vundle.vim @@ -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('!' == '') @@ -40,7 +37,6 @@ com! VundleUpdate Plugi 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 From f5a208bef492ebde0e59f5e2a6b0f49ce2d40970 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Thu, 3 Apr 2014 08:25:29 +0200 Subject: [PATCH 8/9] Treat changed remotes as new plugins If one had this plugin: Plugin 'foo/bar' And now switches to another one with the same name: Plugin 'baz/bar' Recognise this scenario and replace the old plugin with the new one, rather than silently assuming they are the same. Fixes #367 #48 #183 #400 --- autoload/vundle/installer.vim | 110 +++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/autoload/vundle/installer.vim b/autoload/vundle/installer.vim index a9afd11..7972cfd 100644 --- a/autoload/vundle/installer.vim +++ b/autoload/vundle/installer.vim @@ -3,7 +3,7 @@ " 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 (seperate arguments) +" ... -- any number of bundle specifications (separate arguments) " --------------------------------------------------------------------------- func! vundle#installer#new(bang, ...) abort let bundles = (a:1 == '') ? @@ -323,27 +323,67 @@ endf " --------------------------------------------------------------------------- -" Install or update a given bundle object with git. +" 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 + + +" --------------------------------------------------------------------------- +" 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 (dict) -" return -- 'todate' if nothing was updated or the repository was up to date, -" 'new' when the plugin was newly installed, 'updated' if some -" changes where pulled via git, 'error' if an error occurred in the -" shell command +" 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:sync(bang, bundle) abort - " Do not sync if this bundle is pinned - if a:bundle.is_pinned() - return 'pinned' - endif - +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' @@ -353,6 +393,33 @@ func! s:sync(bang, bundle) abort 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('') @@ -427,7 +494,7 @@ endf " Add a log message to Vundle's internal logging variable. " " str -- the log message (string) -" prefix -- optional prefix for multiline entries (string) +" prefix -- optional prefix for multi-line entries (string) " return -- a:str " --------------------------------------------------------------------------- func! s:log(str, ...) abort @@ -440,3 +507,14 @@ func! s:log(str, ...) abort 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 From 0f936ef295c994f85b63e01c3b4828574acd73a0 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Tue, 15 Apr 2014 09:22:15 +0200 Subject: [PATCH 9/9] Check name collissions --- autoload/vundle/config.vim | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index 309fb4e..b04e5bf 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -7,6 +7,9 @@ " --------------------------------------------------------------------------- func! vundle#config#bundle(arg, ...) let bundle = vundle#config#init_bundle(a:arg, a:000) + if !s:check_bundle_name(bundle) + return + endif if exists('g:vundle_lazy_load') && g:vundle_lazy_load call add(g:bundles, bundle) else @@ -40,6 +43,7 @@ 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 @@ -79,6 +83,26 @@ func! vundle#config#init_bundle(name, opts) 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