changeset 8376:e448f2a5d45b v7.4.1480

commit https://github.com/vim/vim/commit/91715873d19a1859c08eeded7848113596e2f2bd Author: Bram Moolenaar <Bram@vim.org> Date: Thu Mar 3 17:13:03 2016 +0100 patch 7.4.1480 Problem: Cannot add a pack direcory without loading a plugin. Solution: Add the :packadd command.
author Christian Brabandt <cb@256bit.org>
date Thu, 03 Mar 2016 17:15:05 +0100
parents 3d5a49fe23bf
children c938f8e269c5
files runtime/doc/repeat.txt src/ex_cmds.h src/ex_cmds2.c src/proto/ex_cmds2.pro src/testdir/test_loadplugin.vim src/version.c
diffstat 6 files changed, 122 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -413,7 +413,7 @@ A Vim package is a directory that contai
 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
+- A package can be a git, mercurial, etc. repository.  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
@@ -443,6 +443,8 @@ In the example Vim will find "my/ever/al
 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'.
 
+Vim will also load ftdetect files, like with |:loadplugin|.
+
 							*load-plugin*
 To load an optional plugin from a pack use the `:loadplugin` command: >
 	:loadplugin mydebug
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1014,6 +1014,9 @@ EX(CMD_ownsyntax,	"ownsyntax",	ex_ownsyn
 EX(CMD_print,		"print",	ex_print,
 			RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK,
 			ADDR_LINES),
+EX(CMD_packadd,		"packadd",	ex_packadd,
+			BANG|FILE1|TRLBAR|SBOXOK|CMDWIN,
+			ADDR_LINES),
 EX(CMD_pclose,		"pclose",	ex_pclose,
 			BANG|TRLBAR,
 			ADDR_LINES),
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -2918,7 +2918,9 @@ source_callback(char_u *fname, void *coo
 /*
  * Source the file "name" from all directories in 'runtimepath'.
  * "name" can contain wildcards.
- * When "all" is TRUE, source all files, otherwise only the first one.
+ * When "flags" has DIP_ALL: source all files, otherwise only the first one.
+ * When "flags" has DIP_DIR: find directories instead of files.
+ *
  * return FAIL when no file could be sourced, OK otherwise.
  */
     int
@@ -2927,11 +2929,14 @@ source_runtime(char_u *name, int all)
     return do_in_runtimepath(name, all, source_callback, NULL);
 }
 
+#define DIP_ALL	1	/* all matches, not just the first one */
+#define DIP_DIR	2	/* find directories instead of files. */
+
     static int
 do_in_path(
     char_u	*path,
     char_u	*name,
-    int		all,
+    int		flags,
     void	(*callback)(char_u *fname, void *ck),
     void	*cookie)
 {
@@ -2968,7 +2973,7 @@ do_in_path(
 
 	/* Loop over all entries in 'runtimepath'. */
 	rtp = rtp_copy;
-	while (*rtp != NUL && (all || !did_one))
+	while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
 	{
 	    /* Copy the path from 'runtimepath' to buf[]. */
 	    copy_option_part(&rtp, buf, MAXPATHL, ",");
@@ -2985,7 +2990,7 @@ do_in_path(
 
 		/* Loop over all patterns in "name" */
 		np = name;
-		while (*np != NUL && (all || !did_one))
+		while (*np != NUL && ((flags & DIP_ALL) || !did_one))
 		{
 		    /* Append the pattern from "name" to buf[]. */
 		    copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
@@ -3000,13 +3005,13 @@ do_in_path(
 
 		    /* Expand wildcards, invoke the callback for each match. */
 		    if (gen_expand_wildcards(1, &buf, &num_files, &files,
-							       EW_FILE) == OK)
+				  (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
 		    {
 			for (i = 0; i < num_files; ++i)
 			{
 			    (*callback)(files[i], cookie);
 			    did_one = TRUE;
-			    if (!all)
+			    if (!(flags & DIP_ALL))
 				break;
 			}
 			FreeWild(num_files, files);
@@ -3049,7 +3054,7 @@ do_in_runtimepath(
     void	(*callback)(char_u *fname, void *ck),
     void	*cookie)
 {
-    return do_in_path(p_rtp, name, all, callback, cookie);
+    return do_in_path(p_rtp, name, all ? DIP_ALL : 0, callback, cookie);
 }
 
 /*
@@ -3065,53 +3070,66 @@ may_do_filetypes(char_u *pat)
     if (cmd != NULL && eval_to_number(cmd) > 0)
     {
 	do_cmdline_cmd((char_u *)"augroup filetypedetect");
-	do_in_path(p_pp, pat, TRUE, source_callback, NULL);
+	do_in_path(p_pp, pat, DIP_ALL, source_callback, NULL);
 	do_cmdline_cmd((char_u *)"augroup END");
     }
     vim_free(cmd);
 }
 
     static void
-source_pack_plugin(char_u *fname, void *cookie UNUSED)
+add_pack_plugin(char_u *fname, void *cookie)
 {
-    char_u *p6, *p5, *p4, *p3, *p2, *p1, *p;
-    int c;
-    char_u *new_rtp;
-    int keep;
-    int oldlen;
-    int addlen;
-
-    p6 = p5 = p4 = p3 = p2 = p1 = get_past_head(fname);
+    char_u  *p6, *p5, *p4, *p3, *p2, *p1, *p;
+    int	    c;
+    char_u  *new_rtp;
+    int	    keep;
+    int	    oldlen;
+    int	    addlen;
+    char_u  *ffname = fix_fname(fname);
+    int	    load_file = cookie != NULL;
+
+    if (ffname == NULL)
+	return;
+    p6 = p5 = p4 = p3 = p2 = p1 = get_past_head(ffname);
     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:
+    /* now we have, load_file == TRUE:
      * rtp/pack/name/ever/name/plugin/name.vim
      *    p6   p5   p4   p3   p2     p1
+     *
+     * with load_file == FALSE:
+     * rtp/pack/name/ever/name
+     *    p4   p3   p2   p1
      */
+    if (load_file)
+	p4 = p6;
 
     /* find the part up to "pack" in 'runtimepath' */
-    c = *p6;
-    *p6 = NUL;
-    p = (char_u *)strstr((char *)p_rtp, (char *)fname);
+    c = *p4;
+    *p4 = NUL;
+    p = (char_u *)strstr((char *)p_rtp, (char *)ffname);
     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)
+	p += STRLEN(ffname);
+    *p4 = c;
+
+    if (load_file)
+    {
+	c = *p2;
+	*p2 = NUL;
+    }
+    if (strstr((char *)p_rtp, (char *)ffname) == NULL)
     {
 	/* directory not in 'runtimepath', add it */
 	oldlen = (int)STRLEN(p_rtp);
-	addlen = (int)STRLEN(fname);
+	addlen = (int)STRLEN(ffname);
 	new_rtp = alloc(oldlen + addlen + 2);
 	if (new_rtp == NULL)
 	{
@@ -3121,16 +3139,17 @@ source_pack_plugin(char_u *fname, void *
 	keep = (int)(p - p_rtp);
 	mch_memmove(new_rtp, p_rtp, keep);
 	new_rtp[keep] = ',';
-	mch_memmove(new_rtp + keep + 1, fname, addlen + 1);
+	mch_memmove(new_rtp + keep + 1, ffname, addlen + 1);
 	if (p_rtp[keep] != NUL)
 	    mch_memmove(new_rtp + keep + 1 + addlen, p_rtp + keep,
 							   oldlen - keep + 1);
 	set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
 	vim_free(new_rtp);
     }
-    *p2 = c;
-
-    (void)do_source(fname, FALSE, DOSO_NONE);
+    vim_free(ffname);
+
+    if (load_file)
+	(void)do_source(fname, FALSE, DOSO_NONE);
 }
 
 /*
@@ -3140,7 +3159,7 @@ source_pack_plugin(char_u *fname, void *
 source_packages()
 {
     do_in_path(p_pp, (char_u *)"pack/*/ever/*/plugin/*.vim",
-					      TRUE, source_pack_plugin, NULL);
+					      DIP_ALL, add_pack_plugin, p_pp);
     may_do_filetypes((char_u *)"pack/*/ever/*/ftdetect/*.vim");
 }
 
@@ -3160,7 +3179,7 @@ ex_loadplugin(exarg_T *eap)
     if (pat == NULL)
 	return;
     vim_snprintf(pat, len, plugpat, eap->arg);
-    do_in_path(p_pp, (char_u *)pat, TRUE, source_pack_plugin, NULL);
+    do_in_path(p_pp, (char_u *)pat, DIP_ALL, add_pack_plugin, p_pp);
 
     vim_snprintf(pat, len, ftpat, eap->arg);
     may_do_filetypes((char_u *)pat);
@@ -3168,6 +3187,25 @@ ex_loadplugin(exarg_T *eap)
     vim_free(pat);
 }
 
+/*
+ * ":packadd {name}"
+ */
+    void
+ex_packadd(exarg_T *eap)
+{
+    static char *plugpat = "pack/*/opt/%s";
+    int		len;
+    char	*pat;
+
+    len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
+    pat = (char *)alloc(len);
+    if (pat == NULL)
+	return;
+    vim_snprintf(pat, len, plugpat, eap->arg);
+    do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR, add_pack_plugin, NULL);
+    vim_free(pat);
+}
+
 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
 /*
  * ":options"
--- a/src/proto/ex_cmds2.pro
+++ b/src/proto/ex_cmds2.pro
@@ -64,6 +64,7 @@ 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_packadd(exarg_T *eap);
 void ex_options(exarg_T *eap);
 void ex_source(exarg_T *eap);
 linenr_T *source_breakpoint(void *cookie);
--- a/src/testdir/test_loadplugin.vim
+++ b/src/testdir/test_loadplugin.vim
@@ -1,25 +1,48 @@
 " Tests for :loadplugin
 
+func SetUp()
+  let s:topdir = expand('%:h') . '/Xdir'
+  exe 'set packpath=' . s:topdir
+  let s:plugdir = s:topdir . '/pack/mine/opt/mytest'
+endfunc
+
+func TearDown()
+  call delete(s:topdir, 'rf')
+endfunc
+
 func Test_loadplugin()
-  let topdir = expand('%:h') . '/Xdir'
-  exe 'set packpath=' . topdir
-  let plugdir = topdir . '/pack/mine/opt/mytest'
-  call mkdir(plugdir . '/plugin', 'p')
-  call mkdir(plugdir . '/ftdetect', 'p')
+  call mkdir(s:plugdir . '/plugin', 'p')
+  call mkdir(s:plugdir . '/ftdetect', 'p')
+  set rtp&
+  let rtp = &rtp
   filetype on
-  try
-    exe 'split ' . plugdir . '/plugin/test.vim'
-    call setline(1, 'let g:plugin_works = 42')
-    wq
+
+  exe 'split ' . s:plugdir . '/plugin/test.vim'
+  call setline(1, 'let g:plugin_works = 42')
+  wq
+
+  exe 'split ' . s:plugdir . '/ftdetect/test.vim'
+  call setline(1, 'let g:ftdetect_works = 17')
+  wq
+
+  loadplugin mytest
 
-    exe 'split ' . plugdir . '/ftdetect/test.vim'
-    call setline(1, 'let g:ftdetect_works = 17')
-    wq
+  call assert_equal(42, g:plugin_works)
+  call assert_equal(17, g:ftdetect_works)
+  call assert_true(len(&rtp) > len(rtp))
+  call assert_true(&rtp =~ 'testdir/Xdir/pack/mine/opt/mytest\($\|,\)')
+endfunc
 
-    loadplugin mytest
-    call assert_true(42, g:plugin_works)
-    call assert_true(17, g:ftdetect_works)
-  finally
-    call delete(topdir, 'rf')
-  endtry
+func Test_packadd()
+  call mkdir(s:plugdir . '/syntax', 'p')
+  set rtp&
+  let rtp = &rtp
+  packadd mytest
+  call assert_true(len(&rtp) > len(rtp))
+  call assert_true(&rtp =~ 'testdir/Xdir/pack/mine/opt/mytest\($\|,\)')
+
+  " check the path is not added twice
+  let new_rtp = &rtp
+  packadd mytest
+  call assert_equal(new_rtp, &rtp)
 endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -744,6 +744,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1480,
+/**/
     1479,
 /**/
     1478,