changeset 8182:95d59081580f v7.4.1384

commit https://github.com/vim/vim/commit/f6fee0e2d4341c0c2f5339c1268e5877fafd07cf Author: Bram Moolenaar <Bram@vim.org> Date: Sun Feb 21 23:02:49 2016 +0100 patch 7.4.1384 Problem: It is not easy to use a set of plugins and their dependencies. Solution: Add packages, ":loadopt", 'packpath'.
author Christian Brabandt <cb@256bit.org>
date Sun, 21 Feb 2016 23:15:05 +0100
parents f478d4537f82
children d34c263b1fcc
files runtime/doc/options.txt runtime/doc/repeat.txt runtime/doc/starting.txt runtime/doc/tags runtime/optwin.vim src/eval.c src/ex_cmds.h src/ex_cmds2.c src/main.c src/option.c src/option.h src/proto/ex_cmds2.pro src/version.c
diffstat 13 files changed, 245 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt*	For Vim version 7.4.  Last change: 2016 Feb 20
+*options.txt*	For Vim version 7.4.  Last change: 2016 Feb 21
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -5409,6 +5409,13 @@ A jump table for the options with a shor
 	This option was supported on RISC OS, which has been removed.
 
 
+				*'packpath'* *'pp'*
+'packpath' 'pp'		string	(default: see 'runtimepath')
+			{not in Vi}
+			{not available without the |+packages| feature}
+	Directories used to find packages.  See |packages|.
+
+
 						*'paragraphs'* *'para'*
 'paragraphs' 'para'	string	(default "IPLPPPQPP TPHPLIPpLpItpplpipbp")
 			global
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -1,4 +1,4 @@
-*repeat.txt*    For Vim version 7.4.  Last change: 2016 Feb 12
+*repeat.txt*    For Vim version 7.4.  Last change: 2016 Feb 21
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -12,8 +12,9 @@ 1. Single repeats	|single-repeat|
 2. Multiple repeats	|multi-repeat|
 3. Complex repeats	|complex-repeat|
 4. Using Vim scripts	|using-scripts|
-5. Debugging scripts	|debug-scripts|
-6. Profiling		|profiling|
+5. Using Vim packages	|packages|
+6. Debugging scripts	|debug-scripts|
+7. Profiling		|profiling|
 
 ==============================================================================
 1. Single repeats					*single-repeat*
@@ -212,6 +213,22 @@ For writing a Vim script, see chapter 41
 			about each searched file.
 			{not in Vi}
 
+							*:loadp* *:loadplugin*
+:loadp[lugin] {name}	Search for an optional plugin directory and source the
+			plugin files found.  It is similar to: >
+				:runtime pack/*/opt/{name}/plugin/*.vim
+<			However, `:loadplugin` uses 'packpath' instead of
+			'runtimepath'.  And the directory found is added to
+			'runtimepath'.
+
+			Note that {name} is the directory name, not the name
+			of the .vim file.  If the "{name}/plugin" directory
+			contains more than one file they are all sourced.
+
+			Also see |load-plugin|.
+
+			{not available without the |+packages| feature}
+
 :scripte[ncoding] [encoding]		*:scripte* *:scriptencoding* *E167*
 			Specify the character encoding used in the script.
 			The following lines will be converted from [encoding]
@@ -388,7 +405,56 @@ Rationale:
 <	Therefore the unusual leading backslash is used.
 
 ==============================================================================
-5. Debugging scripts					*debug-scripts*
+5. Using Vim packages					*packages*
+
+A Vim package is a directory that contains one or more plugins.  The
+advantages over normal plugins:
+- A package can be downloaded as an archive and unpacked in its own directory.
+  That makes it easy to updated and/or remove.
+- A package can be a git, mercurial, etc. respository.  That makes it really
+  easy to update.
+- A package can contain multiple plugins that depend on each other.
+- A package can contain plugins that are automatically loaded on startup and
+  ones that are only loaded when needed with `:loadplugin`.
+
+Let's assume your Vim files are in the "~/.vim" directory and you want to add a
+package from a zip archive "/tmp/mypack.zip":
+	% mkdir -p ~/.vim/pack/my
+	% cd ~/.vim/pack/my
+	% unzip /tmp/mypack.zip
+
+The directory name "my" is arbitrary, you can pick anything you like.
+
+You would now have these files under ~/.vim:
+	pack/my/README.txt
+	pack/my/ever/always/plugin/always.vim
+	pack/my/ever/always/syntax/always.vim
+	pack/my/opt/mydebug/plugin/debugger.vim
+
+When Vim starts up it scans all directories in 'packpath' for plugins under the
+"ever" directory and loads them.  When found that directory is added to
+'runtimepath'.
+
+In the example Vim will find "my/ever/always/plugin/always.vim" and adds 
+"~/.vim/pack/my/ever/always" to 'runtimepath'.
+
+If the "always" plugin kicks in and sets the 'filetype' to "always", Vim will
+find the syntax/always.vim file, because its directory is in 'runtimepath'.
+
+							*load-plugin*
+To load an optional plugin from a pack use the `:loadplugin` command: >
+	:loadplugin mydebug
+This could be done inside always.vim, if some conditions are met.
+Or you could add this command to your |.vimrc|.
+
+It is perfectly normal for a package to only have files in the "opt"
+directory.  You then need to load each plugin when you want to use it.
+
+Loading packages will not happen if loading plugins is disabled, see
+|load-plugins|.
+
+==============================================================================
+6. Debugging scripts					*debug-scripts*
 
 Besides the obvious messages that you can add to your scripts to find out what
 they are doing, Vim offers a debug mode.  This allows you to step through a
@@ -613,7 +679,7 @@ OBSCURE
 		user, don't use typeahead for debug commands.
 
 ==============================================================================
-6. Profiling						*profile* *profiling*
+7. Profiling						*profile* *profiling*
 
 Profiling means that Vim measures the time that is spent on executing
 functions and/or scripts.  The |+profile| feature is required for this.
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -1,4 +1,4 @@
-*starting.txt*  For Vim version 7.4.  Last change: 2016 Feb 18
+*starting.txt*  For Vim version 7.4.  Last change: 2016 Feb 21
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -857,6 +857,10 @@ 4. Load the plugin scripts.					*load-pl
 	commands from the command line have not been executed yet.  You can
 	use "--cmd 'set noloadplugins'" |--cmd|.
 
+	Plugin packs are loaded.  These are plugins, as above, but found in
+	'packpath' directories.  Every plugin directory found is added in
+	'runtimepath'.  See |packages|.
+
 5. Set 'shellpipe' and 'shellredir'
 	The 'shellpipe' and 'shellredir' options are set according to the
 	value of the 'shell' option, unless they have been set before.
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -726,6 +726,7 @@
 'option'	intro.txt	/*'option'*
 'osfiletype'	options.txt	/*'osfiletype'*
 'pa'	options.txt	/*'pa'*
+'packpath'	options.txt	/*'packpath'*
 'para'	options.txt	/*'para'*
 'paragraphs'	options.txt	/*'paragraphs'*
 'paste'	options.txt	/*'paste'*
@@ -746,6 +747,7 @@
 'pmbcs'	options.txt	/*'pmbcs'*
 'pmbfn'	options.txt	/*'pmbfn'*
 'popt'	options.txt	/*'popt'*
+'pp'	options.txt	/*'pp'*
 'preserveindent'	options.txt	/*'preserveindent'*
 'previewheight'	options.txt	/*'previewheight'*
 'previewwindow'	options.txt	/*'previewwindow'*
@@ -3540,6 +3542,7 @@ CTRL-\_CTRL-N	intro.txt	/*CTRL-\\_CTRL-N
 CTRL-]	tagsrch.txt	/*CTRL-]*
 CTRL-^	editing.txt	/*CTRL-^*
 CTRL-{char}	intro.txt	/*CTRL-{char}*
+Channel	eval.txt	/*Channel*
 Chinese	mbyte.txt	/*Chinese*
 Cmd-event	autocmd.txt	/*Cmd-event*
 CmdUndefined	autocmd.txt	/*CmdUndefined*
@@ -4427,7 +4430,6 @@ E893	eval.txt	/*E893*
 E894	eval.txt	/*E894*
 E895	if_mzsch.txt	/*E895*
 E896	channel.txt	/*E896*
-E897	channel.txt	/*E897*
 E898	channel.txt	/*E898*
 E899	channel.txt	/*E899*
 E90	message.txt	/*E90*
@@ -4447,6 +4449,8 @@ E911	eval.txt	/*E911*
 E912	eval.txt	/*E912*
 E913	eval.txt	/*E913*
 E914	eval.txt	/*E914*
+E915	channel.txt	/*E915*
+E916	eval.txt	/*E916*
 E92	message.txt	/*E92*
 E93	windows.txt	/*E93*
 E94	windows.txt	/*E94*
@@ -4515,6 +4519,7 @@ InsertEnter	autocmd.txt	/*InsertEnter*
 InsertLeave	autocmd.txt	/*InsertLeave*
 J	change.txt	/*J*
 Japanese	mbyte.txt	/*Japanese*
+Job	eval.txt	/*Job*
 K	various.txt	/*K*
 KDE	gui_x11.txt	/*KDE*
 KVim	gui_x11.txt	/*KVim*
@@ -4659,6 +4664,7 @@ ShellCmdPost	autocmd.txt	/*ShellCmdPost*
 ShellFilterPost	autocmd.txt	/*ShellFilterPost*
 SourceCmd	autocmd.txt	/*SourceCmd*
 SourcePre	autocmd.txt	/*SourcePre*
+Special	eval.txt	/*Special*
 SpellFileMissing	autocmd.txt	/*SpellFileMissing*
 StdinReadPost	autocmd.txt	/*StdinReadPost*
 StdinReadPre	autocmd.txt	/*StdinReadPre*
@@ -5168,9 +5174,11 @@ cc	change.txt	/*cc*
 ceil()	eval.txt	/*ceil()*
 ch.vim	syntax.txt	/*ch.vim*
 ch_close()	eval.txt	/*ch_close()*
+ch_getjob()	eval.txt	/*ch_getjob()*
 ch_log()	eval.txt	/*ch_log()*
 ch_logfile()	eval.txt	/*ch_logfile()*
 ch_open()	eval.txt	/*ch_open()*
+ch_read()	eval.txt	/*ch_read()*
 ch_readraw()	eval.txt	/*ch_readraw()*
 ch_sendexpr()	eval.txt	/*ch_sendexpr()*
 ch_sendraw()	eval.txt	/*ch_sendraw()*
@@ -5203,6 +5211,7 @@ changetick	eval.txt	/*changetick*
 changing	change.txt	/*changing*
 channel	channel.txt	/*channel*
 channel-callback	channel.txt	/*channel-callback*
+channel-close	channel.txt	/*channel-close*
 channel-commands	channel.txt	/*channel-commands*
 channel-demo	channel.txt	/*channel-demo*
 channel-mode	channel.txt	/*channel-mode*
@@ -5273,6 +5282,7 @@ clipboard-html	options.txt	/*clipboard-h
 clipboard-unnamed	options.txt	/*clipboard-unnamed*
 clipboard-unnamedplus	options.txt	/*clipboard-unnamedplus*
 clojure-indent	indent.txt	/*clojure-indent*
+close-cb	channel.txt	/*close-cb*
 cmdarg-variable	eval.txt	/*cmdarg-variable*
 cmdbang-variable	eval.txt	/*cmdbang-variable*
 cmdline-arguments	vi_diff.txt	/*cmdline-arguments*
@@ -5639,6 +5649,8 @@ end	intro.txt	/*end*
 end-of-file	pattern.txt	/*end-of-file*
 enlightened-terminal	syntax.txt	/*enlightened-terminal*
 erlang.vim	syntax.txt	/*erlang.vim*
+err-cb	channel.txt	/*err-cb*
+err-timeout	channel.txt	/*err-timeout*
 errmsg-variable	eval.txt	/*errmsg-variable*
 error-file-format	quickfix.txt	/*error-file-format*
 error-messages	message.txt	/*error-messages*
@@ -6433,7 +6445,6 @@ gui-shell-win32	gui_w32.txt	/*gui-shell-
 gui-start	gui.txt	/*gui-start*
 gui-toolbar	gui.txt	/*gui-toolbar*
 gui-vert-scroll	gui.txt	/*gui-vert-scroll*
-gui-w16	gui_w16.txt	/*gui-w16*
 gui-w32	gui_w32.txt	/*gui-w32*
 gui-w32-cmdargs	gui_w32.txt	/*gui-w32-cmdargs*
 gui-w32-dialogs	gui_w32.txt	/*gui-w32-dialogs*
@@ -6455,7 +6466,6 @@ gui-x11-printing	gui_x11.txt	/*gui-x11-p
 gui-x11-start	gui_x11.txt	/*gui-x11-start*
 gui-x11-various	gui_x11.txt	/*gui-x11-various*
 gui.txt	gui.txt	/*gui.txt*
-gui_w16.txt	gui_w16.txt	/*gui_w16.txt*
 gui_w32.txt	gui_w32.txt	/*gui_w32.txt*
 gui_x11.txt	gui_x11.txt	/*gui_x11.txt*
 guifontwide_gtk2	options.txt	/*guifontwide_gtk2*
@@ -6832,6 +6842,7 @@ java.vim	syntax.txt	/*java.vim*
 javascript-cinoptions	indent.txt	/*javascript-cinoptions*
 javascript-indenting	indent.txt	/*javascript-indenting*
 job	channel.txt	/*job*
+job-callback	channel.txt	/*job-callback*
 job-channel-overview	channel.txt	/*job-channel-overview*
 job-close-cb	channel.txt	/*job-close-cb*
 job-control	channel.txt	/*job-control*
@@ -6839,15 +6850,16 @@ job-err-cb	channel.txt	/*job-err-cb*
 job-err-io	channel.txt	/*job-err-io*
 job-exit-cb	channel.txt	/*job-exit-cb*
 job-in-io	channel.txt	/*job-in-io*
-job-killonexit	channel.txt	/*job-killonexit*
 job-may-start	channel.txt	/*job-may-start*
 job-options	channel.txt	/*job-options*
 job-out-cb	channel.txt	/*job-out-cb*
 job-out-io	channel.txt	/*job-out-io*
 job-start	channel.txt	/*job-start*
 job-start-nochannel	channel.txt	/*job-start-nochannel*
+job-stoponexit	channel.txt	/*job-stoponexit*
 job-term	channel.txt	/*job-term*
 job_getchannel()	eval.txt	/*job_getchannel()*
+job_setoptions()	eval.txt	/*job_setoptions()*
 job_start()	eval.txt	/*job_start()*
 job_status()	eval.txt	/*job_status()*
 job_stop()	eval.txt	/*job_stop()*
@@ -7577,7 +7589,10 @@ os_unix.txt	os_unix.txt	/*os_unix.txt*
 os_vms.txt	os_vms.txt	/*os_vms.txt*
 os_win32.txt	os_win32.txt	/*os_win32.txt*
 other-features	vi_diff.txt	/*other-features*
+out-cb	channel.txt	/*out-cb*
+out-timeout	channel.txt	/*out-timeout*
 p	change.txt	/*p*
+packages	repeat.txt	/*packages*
 page-down	intro.txt	/*page-down*
 page-up	intro.txt	/*page-up*
 page_down	intro.txt	/*page_down*
@@ -8995,25 +9010,13 @@ w:	eval.txt	/*w:*
 w:current_syntax	syntax.txt	/*w:current_syntax*
 w:quickfix_title	quickfix.txt	/*w:quickfix_title*
 w:var	eval.txt	/*w:var*
+waittime	channel.txt	/*waittime*
 warningmsg-variable	eval.txt	/*warningmsg-variable*
 white-space	pattern.txt	/*white-space*
 whitespace	pattern.txt	/*whitespace*
 wildcard	editing.txt	/*wildcard*
 wildcards	editing.txt	/*wildcards*
 wildmenumode()	eval.txt	/*wildmenumode()*
-win16-!start	gui_w16.txt	/*win16-!start*
-win16-clipboard	gui_w16.txt	/*win16-clipboard*
-win16-colors	gui_w16.txt	/*win16-colors*
-win16-default-editor	gui_w16.txt	/*win16-default-editor*
-win16-dialogs	gui_w16.txt	/*win16-dialogs*
-win16-drag-n-drop	gui_w16.txt	/*win16-drag-n-drop*
-win16-gui	gui_w16.txt	/*win16-gui*
-win16-maximized	gui_w16.txt	/*win16-maximized*
-win16-printing	gui_w16.txt	/*win16-printing*
-win16-shell	gui_w16.txt	/*win16-shell*
-win16-start	gui_w16.txt	/*win16-start*
-win16-truetype	gui_w16.txt	/*win16-truetype*
-win16-various	gui_w16.txt	/*win16-various*
 win32	os_win32.txt	/*win32*
 win32-!start	gui_w32.txt	/*win32-!start*
 win32-PATH	os_win32.txt	/*win32-PATH*
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1,7 +1,7 @@
 " These commands create the option window.
 "
 " Maintainer:	Bram Moolenaar <Bram@vim.org>
-" Last Change:	2015 Nov 10
+" Last Change:	2016 Feb 21
 
 " If there already is an option window, jump to that one.
 if bufwinnr("option-window") > 0
@@ -228,6 +228,8 @@ else
 endif
 call append("$", "runtimepath\tlist of directories used for runtime files and plugins")
 call <SID>OptionG("rtp", &rtp)
+call append("$", "packpath\tlist of directories used for plugin packages")
+call <SID>OptionG("pp", &pp)
 call append("$", "helpfile\tname of the main help file")
 call <SID>OptionG("hf", &hf)
 
--- a/src/eval.c
+++ b/src/eval.c
@@ -13785,6 +13785,7 @@ f_has(typval_T *argvars, typval_T *rettv
 #ifdef FEAT_OLE
 	"ole",
 #endif
+	"packages",
 #ifdef FEAT_PATH_EXTRA
 	"path_extra",
 #endif
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -810,6 +810,9 @@ EX(CMD_loadview,	"loadview",	ex_loadview
 EX(CMD_loadkeymap,	"loadkeymap",	ex_loadkeymap,
 			CMDWIN,
 			ADDR_LINES),
+EX(CMD_loadplugin,	"loadplugin",	ex_loadplugin,
+			BANG|FILE1|TRLBAR|SBOXOK|CMDWIN,
+			ADDR_LINES),
 EX(CMD_lockmarks,	"lockmarks",	ex_wrongmodifier,
 			NEEDARG|EXTRA|NOTRLCOM,
 			ADDR_LINES),
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -2905,8 +2905,6 @@ ex_runtime(exarg_T *eap)
     source_runtime(eap->arg, eap->forceit);
 }
 
-static void source_callback(char_u *fname, void *cookie);
-
     static void
 source_callback(char_u *fname, void *cookie UNUSED)
 {
@@ -2925,19 +2923,9 @@ source_runtime(char_u *name, int all)
     return do_in_runtimepath(name, all, source_callback, NULL);
 }
 
-/*
- * Find "name" in 'runtimepath'.  When found, invoke the callback function for
- * it: callback(fname, "cookie")
- * When "all" is TRUE repeat for all matches, otherwise only the first one is
- * used.
- * Returns OK when at least one match found, FAIL otherwise.
- *
- * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
- * passed by reference in this case, setting it to NULL indicates that callback
- * has done its job.
- */
-    int
-do_in_runtimepath(
+    static int
+do_in_path(
+    char_u	*path,
     char_u	*name,
     int		all,
     void	(*callback)(char_u *fname, void *ck),
@@ -2962,7 +2950,7 @@ do_in_runtimepath(
 
     /* Make a copy of 'runtimepath'.  Invoking the callback may change the
      * value. */
-    rtp_copy = vim_strsave(p_rtp);
+    rtp_copy = vim_strsave(path);
     buf = alloc(MAXPATHL);
     if (buf != NULL && rtp_copy != NULL)
     {
@@ -2970,7 +2958,7 @@ do_in_runtimepath(
 	{
 	    verbose_enter();
 	    smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
-						 (char *)name, (char *)p_rtp);
+						 (char *)name, (char *)path);
 	    verbose_leave();
 	}
 
@@ -3039,6 +3027,120 @@ do_in_runtimepath(
     return did_one ? OK : FAIL;
 }
 
+/*
+ * Find "name" in 'runtimepath'.  When found, invoke the callback function for
+ * it: callback(fname, "cookie")
+ * When "all" is TRUE repeat for all matches, otherwise only the first one is
+ * used.
+ * Returns OK when at least one match found, FAIL otherwise.
+ *
+ * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
+ * passed by reference in this case, setting it to NULL indicates that callback
+ * has done its job.
+ */
+    int
+do_in_runtimepath(
+    char_u	*name,
+    int		all,
+    void	(*callback)(char_u *fname, void *ck),
+    void	*cookie)
+{
+    return do_in_path(p_rtp, name, all, callback, cookie);
+}
+
+    static void
+source_pack_plugin(char_u *fname, void *cookie UNUSED)
+{
+    char_u *p6, *p5, *p4, *p3, *p2, *p1, *p;
+    int c;
+    char_u *new_rtp;
+    int keep;
+    int oldlen;
+    int addlen;
+
+    p4 = p3 = p2 = p1 = get_past_head(fname);
+    for (p = p1; *p; mb_ptr_adv(p))
+    {
+	if (vim_ispathsep_nocolon(*p))
+	{
+	    p6 = p5; p5 = p4; p4 = p3; p3 = p2; p2 = p1; p1 = p;
+	}
+    }
+
+    /* now we have:
+     * rtp/pack/name/ever/name/plugin/name.vim
+     *    p6   p5   p4   p3   p2     p1
+     */
+
+    /* find the part up to "pack" in 'runtimepath' */
+    c = *p6;
+    *p6 = NUL;
+    p = (char_u *)strstr((char *)p_rtp, (char *)fname);
+    if (p == NULL)
+	/* not found, append at the end */
+	p = p_rtp + STRLEN(p_rtp);
+    else
+	/* append after the matching directory. */
+	p += STRLEN(fname);
+    *p6 = c;
+
+    c = *p2;
+    *p2 = NUL;
+    if (strstr((char *)p_rtp, (char *)fname) == NULL)
+    {
+	/* directory not in 'runtimepath', add it */
+	oldlen = STRLEN(p_rtp);
+	addlen = STRLEN(fname);
+	new_rtp = alloc(oldlen + addlen + 2);
+	if (new_rtp == NULL)
+	{
+	    *p2 = c;
+	    return;
+	}
+	keep = (int)(p - p_rtp);
+	mch_memmove(new_rtp, p_rtp, keep);
+	new_rtp[keep] = ',';
+	mch_memmove(new_rtp + keep + 1, fname, addlen + 1);
+	if (p_rtp[keep] != NUL)
+	    mch_memmove(new_rtp + keep + 1 + addlen, p_rtp + keep,
+							   oldlen - keep + 1);
+	free_string_option(p_rtp);
+	p_rtp = new_rtp;
+    }
+    *p2 = c;
+
+    (void)do_source(fname, FALSE, DOSO_NONE);
+}
+
+/*
+ * Source the plugins in the package directories.
+ */
+    void
+source_packages()
+{
+    do_in_path(p_pp, (char_u *)"pack/*/ever/*/plugin/*.vim",
+					      TRUE, source_pack_plugin, NULL);
+}
+
+/*
+ * ":loadplugin {name}"
+ */
+    void
+ex_loadplugin(exarg_T *eap)
+{
+    static char *pattern = "pack/*/opt/%s/plugin/*.vim";
+    int		len;
+    char	*pat;
+
+    len = STRLEN(pattern) + STRLEN(eap->arg);
+    pat = (char *)alloc(len);
+    if (pat == NULL)
+	return;
+    vim_snprintf(pat, len, pattern, eap->arg);
+    do_in_path(p_pp, (char_u *)pat, TRUE, source_pack_plugin, NULL);
+    vim_free(pat);
+}
+
 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
 /*
  * ":options"
--- a/src/main.c
+++ b/src/main.c
@@ -637,6 +637,9 @@ vim_main2(int argc UNUSED, char **argv U
 	source_runtime((char_u *)"plugin/**/*.vim", TRUE);
 # endif
 	TIME_MSG("loading plugins");
+
+	source_packages();
+	TIME_MSG("loading packages");
     }
 #endif
 
--- a/src/option.c
+++ b/src/option.c
@@ -1978,6 +1978,11 @@ static struct vimoption options[] =
     {"osfiletype",  "oft",  P_STRING|P_ALLOCED|P_VI_DEF,
 			    (char_u *)NULL, PV_NONE,
 			    {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
+    {"packpath",    "pp",   P_STRING|P_VI_DEF|P_EXPAND|P_ONECOMMA|P_NODUP
+								    |P_SECURE,
+			    (char_u *)&p_pp, PV_NONE,
+			    {(char_u *)DFLT_RUNTIMEPATH, (char_u *)0L}
+			    SCRIPTID_INIT},
     {"paragraphs",  "para", P_STRING|P_VI_DEF,
 			    (char_u *)&p_para, PV_NONE,
 			    {(char_u *)"IPLPPPQPP TPHPLIPpLpItpplpipbp",
@@ -11045,6 +11050,7 @@ set_context_in_set_cmd(
 	if (p == (char_u *)&p_bdir
 		|| p == (char_u *)&p_dir
 		|| p == (char_u *)&p_path
+		|| p == (char_u *)&p_pp
 		|| p == (char_u *)&p_rtp
 #ifdef FEAT_SEARCHPATH
 		|| p == (char_u *)&p_cdpath
--- a/src/option.h
+++ b/src/option.h
@@ -723,6 +723,7 @@ EXTERN int	p_ru;		/* 'ruler' */
 #ifdef FEAT_STL_OPT
 EXTERN char_u	*p_ruf;		/* 'rulerformat' */
 #endif
+EXTERN char_u	*p_pp;		/* 'packpath' */
 EXTERN char_u	*p_rtp;		/* 'runtimepath' */
 EXTERN long	p_sj;		/* 'scrolljump' */
 EXTERN long	p_so;		/* 'scrolloff' */
--- a/src/proto/ex_cmds2.pro
+++ b/src/proto/ex_cmds2.pro
@@ -62,6 +62,8 @@ void ex_compiler(exarg_T *eap);
 void ex_runtime(exarg_T *eap);
 int source_runtime(char_u *name, int all);
 int do_in_runtimepath(char_u *name, int all, void (*callback)(char_u *fname, void *ck), void *cookie);
+void source_packages(void);
+void ex_loadplugin(exarg_T *eap);
 void ex_options(exarg_T *eap);
 void ex_source(exarg_T *eap);
 linenr_T *source_breakpoint(void *cookie);
--- a/src/version.c
+++ b/src/version.c
@@ -462,6 +462,7 @@ static char *(features[]) =
 	"-ole",
 # endif
 #endif
+	"+packages",
 #ifdef FEAT_PATH_EXTRA
 	"+path_extra",
 #else
@@ -748,6 +749,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1384,
+/**/
     1383,
 /**/
     1382,