mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 7.4.1480
Problem: Cannot add a pack direcory without loading a plugin. Solution: Add the :packadd command.
This commit is contained in:
@@ -413,7 +413,7 @@ A Vim package is a directory that contains one or more plugins. The
|
|||||||
advantages over normal plugins:
|
advantages over normal plugins:
|
||||||
- A package can be downloaded as an archive and unpacked in its own directory.
|
- A package can be downloaded as an archive and unpacked in its own directory.
|
||||||
That makes it easy to updated and/or remove.
|
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.
|
easy to update.
|
||||||
- A package can contain multiple plugins that depend on each other.
|
- A package can contain multiple plugins that depend on each other.
|
||||||
- A package can contain plugins that are automatically loaded on startup and
|
- A package can contain plugins that are automatically loaded on startup and
|
||||||
@@ -443,6 +443,8 @@ In the example Vim will find "my/ever/always/plugin/always.vim" and adds
|
|||||||
If the "always" plugin kicks in and sets the 'filetype' to "always", Vim will
|
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'.
|
find the syntax/always.vim file, because its directory is in 'runtimepath'.
|
||||||
|
|
||||||
|
Vim will also load ftdetect files, like with |:loadplugin|.
|
||||||
|
|
||||||
*load-plugin*
|
*load-plugin*
|
||||||
To load an optional plugin from a pack use the `:loadplugin` command: >
|
To load an optional plugin from a pack use the `:loadplugin` command: >
|
||||||
:loadplugin mydebug
|
:loadplugin mydebug
|
||||||
|
@@ -1014,6 +1014,9 @@ EX(CMD_ownsyntax, "ownsyntax", ex_ownsyntax,
|
|||||||
EX(CMD_print, "print", ex_print,
|
EX(CMD_print, "print", ex_print,
|
||||||
RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK,
|
RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK,
|
||||||
ADDR_LINES),
|
ADDR_LINES),
|
||||||
|
EX(CMD_packadd, "packadd", ex_packadd,
|
||||||
|
BANG|FILE1|TRLBAR|SBOXOK|CMDWIN,
|
||||||
|
ADDR_LINES),
|
||||||
EX(CMD_pclose, "pclose", ex_pclose,
|
EX(CMD_pclose, "pclose", ex_pclose,
|
||||||
BANG|TRLBAR,
|
BANG|TRLBAR,
|
||||||
ADDR_LINES),
|
ADDR_LINES),
|
||||||
|
100
src/ex_cmds2.c
100
src/ex_cmds2.c
@@ -2918,7 +2918,9 @@ source_callback(char_u *fname, void *cookie UNUSED)
|
|||||||
/*
|
/*
|
||||||
* Source the file "name" from all directories in 'runtimepath'.
|
* Source the file "name" from all directories in 'runtimepath'.
|
||||||
* "name" can contain wildcards.
|
* "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.
|
* return FAIL when no file could be sourced, OK otherwise.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
@@ -2927,11 +2929,14 @@ source_runtime(char_u *name, int all)
|
|||||||
return do_in_runtimepath(name, all, source_callback, NULL);
|
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
|
static int
|
||||||
do_in_path(
|
do_in_path(
|
||||||
char_u *path,
|
char_u *path,
|
||||||
char_u *name,
|
char_u *name,
|
||||||
int all,
|
int flags,
|
||||||
void (*callback)(char_u *fname, void *ck),
|
void (*callback)(char_u *fname, void *ck),
|
||||||
void *cookie)
|
void *cookie)
|
||||||
{
|
{
|
||||||
@@ -2968,7 +2973,7 @@ do_in_path(
|
|||||||
|
|
||||||
/* Loop over all entries in 'runtimepath'. */
|
/* Loop over all entries in 'runtimepath'. */
|
||||||
rtp = rtp_copy;
|
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 the path from 'runtimepath' to buf[]. */
|
||||||
copy_option_part(&rtp, buf, MAXPATHL, ",");
|
copy_option_part(&rtp, buf, MAXPATHL, ",");
|
||||||
@@ -2985,7 +2990,7 @@ do_in_path(
|
|||||||
|
|
||||||
/* Loop over all patterns in "name" */
|
/* Loop over all patterns in "name" */
|
||||||
np = name;
|
np = name;
|
||||||
while (*np != NUL && (all || !did_one))
|
while (*np != NUL && ((flags & DIP_ALL) || !did_one))
|
||||||
{
|
{
|
||||||
/* Append the pattern from "name" to buf[]. */
|
/* Append the pattern from "name" to buf[]. */
|
||||||
copy_option_part(&np, tail, (int)(MAXPATHL - (tail - 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. */
|
/* Expand wildcards, invoke the callback for each match. */
|
||||||
if (gen_expand_wildcards(1, &buf, &num_files, &files,
|
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)
|
for (i = 0; i < num_files; ++i)
|
||||||
{
|
{
|
||||||
(*callback)(files[i], cookie);
|
(*callback)(files[i], cookie);
|
||||||
did_one = TRUE;
|
did_one = TRUE;
|
||||||
if (!all)
|
if (!(flags & DIP_ALL))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
FreeWild(num_files, files);
|
FreeWild(num_files, files);
|
||||||
@@ -3049,7 +3054,7 @@ do_in_runtimepath(
|
|||||||
void (*callback)(char_u *fname, void *ck),
|
void (*callback)(char_u *fname, void *ck),
|
||||||
void *cookie)
|
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)
|
if (cmd != NULL && eval_to_number(cmd) > 0)
|
||||||
{
|
{
|
||||||
do_cmdline_cmd((char_u *)"augroup filetypedetect");
|
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");
|
do_cmdline_cmd((char_u *)"augroup END");
|
||||||
}
|
}
|
||||||
vim_free(cmd);
|
vim_free(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
char_u *p6, *p5, *p4, *p3, *p2, *p1, *p;
|
||||||
int c;
|
int c;
|
||||||
char_u *new_rtp;
|
char_u *new_rtp;
|
||||||
int keep;
|
int keep;
|
||||||
int oldlen;
|
int oldlen;
|
||||||
int addlen;
|
int addlen;
|
||||||
|
char_u *ffname = fix_fname(fname);
|
||||||
|
int load_file = cookie != NULL;
|
||||||
|
|
||||||
p6 = p5 = p4 = p3 = p2 = p1 = get_past_head(fname);
|
if (ffname == NULL)
|
||||||
|
return;
|
||||||
|
p6 = p5 = p4 = p3 = p2 = p1 = get_past_head(ffname);
|
||||||
for (p = p1; *p; mb_ptr_adv(p))
|
for (p = p1; *p; mb_ptr_adv(p))
|
||||||
if (vim_ispathsep_nocolon(*p))
|
if (vim_ispathsep_nocolon(*p))
|
||||||
{
|
{
|
||||||
p6 = p5; p5 = p4; p4 = p3; p3 = p2; p2 = p1; p1 = 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
|
* rtp/pack/name/ever/name/plugin/name.vim
|
||||||
* p6 p5 p4 p3 p2 p1
|
* 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' */
|
/* find the part up to "pack" in 'runtimepath' */
|
||||||
c = *p6;
|
c = *p4;
|
||||||
*p6 = NUL;
|
*p4 = NUL;
|
||||||
p = (char_u *)strstr((char *)p_rtp, (char *)fname);
|
p = (char_u *)strstr((char *)p_rtp, (char *)ffname);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
/* not found, append at the end */
|
/* not found, append at the end */
|
||||||
p = p_rtp + STRLEN(p_rtp);
|
p = p_rtp + STRLEN(p_rtp);
|
||||||
else
|
else
|
||||||
/* append after the matching directory. */
|
/* append after the matching directory. */
|
||||||
p += STRLEN(fname);
|
p += STRLEN(ffname);
|
||||||
*p6 = c;
|
*p4 = c;
|
||||||
|
|
||||||
c = *p2;
|
if (load_file)
|
||||||
*p2 = NUL;
|
{
|
||||||
if (strstr((char *)p_rtp, (char *)fname) == NULL)
|
c = *p2;
|
||||||
|
*p2 = NUL;
|
||||||
|
}
|
||||||
|
if (strstr((char *)p_rtp, (char *)ffname) == NULL)
|
||||||
{
|
{
|
||||||
/* directory not in 'runtimepath', add it */
|
/* directory not in 'runtimepath', add it */
|
||||||
oldlen = (int)STRLEN(p_rtp);
|
oldlen = (int)STRLEN(p_rtp);
|
||||||
addlen = (int)STRLEN(fname);
|
addlen = (int)STRLEN(ffname);
|
||||||
new_rtp = alloc(oldlen + addlen + 2);
|
new_rtp = alloc(oldlen + addlen + 2);
|
||||||
if (new_rtp == NULL)
|
if (new_rtp == NULL)
|
||||||
{
|
{
|
||||||
@@ -3121,16 +3139,17 @@ source_pack_plugin(char_u *fname, void *cookie UNUSED)
|
|||||||
keep = (int)(p - p_rtp);
|
keep = (int)(p - p_rtp);
|
||||||
mch_memmove(new_rtp, p_rtp, keep);
|
mch_memmove(new_rtp, p_rtp, keep);
|
||||||
new_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)
|
if (p_rtp[keep] != NUL)
|
||||||
mch_memmove(new_rtp + keep + 1 + addlen, p_rtp + keep,
|
mch_memmove(new_rtp + keep + 1 + addlen, p_rtp + keep,
|
||||||
oldlen - keep + 1);
|
oldlen - keep + 1);
|
||||||
set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
|
set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
|
||||||
vim_free(new_rtp);
|
vim_free(new_rtp);
|
||||||
}
|
}
|
||||||
*p2 = c;
|
vim_free(ffname);
|
||||||
|
|
||||||
(void)do_source(fname, FALSE, DOSO_NONE);
|
if (load_file)
|
||||||
|
(void)do_source(fname, FALSE, DOSO_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3140,7 +3159,7 @@ source_pack_plugin(char_u *fname, void *cookie UNUSED)
|
|||||||
source_packages()
|
source_packages()
|
||||||
{
|
{
|
||||||
do_in_path(p_pp, (char_u *)"pack/*/ever/*/plugin/*.vim",
|
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");
|
may_do_filetypes((char_u *)"pack/*/ever/*/ftdetect/*.vim");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3160,7 +3179,7 @@ ex_loadplugin(exarg_T *eap)
|
|||||||
if (pat == NULL)
|
if (pat == NULL)
|
||||||
return;
|
return;
|
||||||
vim_snprintf(pat, len, plugpat, eap->arg);
|
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);
|
vim_snprintf(pat, len, ftpat, eap->arg);
|
||||||
may_do_filetypes((char_u *)pat);
|
may_do_filetypes((char_u *)pat);
|
||||||
@@ -3168,6 +3187,25 @@ ex_loadplugin(exarg_T *eap)
|
|||||||
vim_free(pat);
|
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)
|
#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
|
||||||
/*
|
/*
|
||||||
* ":options"
|
* ":options"
|
||||||
|
@@ -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);
|
int do_in_runtimepath(char_u *name, int all, void (*callback)(char_u *fname, void *ck), void *cookie);
|
||||||
void source_packages(void);
|
void source_packages(void);
|
||||||
void ex_loadplugin(exarg_T *eap);
|
void ex_loadplugin(exarg_T *eap);
|
||||||
|
void ex_packadd(exarg_T *eap);
|
||||||
void ex_options(exarg_T *eap);
|
void ex_options(exarg_T *eap);
|
||||||
void ex_source(exarg_T *eap);
|
void ex_source(exarg_T *eap);
|
||||||
linenr_T *source_breakpoint(void *cookie);
|
linenr_T *source_breakpoint(void *cookie);
|
||||||
|
@@ -1,25 +1,48 @@
|
|||||||
" Tests for :loadplugin
|
" Tests for :loadplugin
|
||||||
|
|
||||||
func Test_loadplugin()
|
func SetUp()
|
||||||
let topdir = expand('%:h') . '/Xdir'
|
let s:topdir = expand('%:h') . '/Xdir'
|
||||||
exe 'set packpath=' . topdir
|
exe 'set packpath=' . s:topdir
|
||||||
let plugdir = topdir . '/pack/mine/opt/mytest'
|
let s:plugdir = s:topdir . '/pack/mine/opt/mytest'
|
||||||
call mkdir(plugdir . '/plugin', 'p')
|
endfunc
|
||||||
call mkdir(plugdir . '/ftdetect', 'p')
|
|
||||||
filetype on
|
func TearDown()
|
||||||
try
|
call delete(s:topdir, 'rf')
|
||||||
exe 'split ' . plugdir . '/plugin/test.vim'
|
endfunc
|
||||||
call setline(1, 'let g:plugin_works = 42')
|
|
||||||
wq
|
func Test_loadplugin()
|
||||||
|
call mkdir(s:plugdir . '/plugin', 'p')
|
||||||
exe 'split ' . plugdir . '/ftdetect/test.vim'
|
call mkdir(s:plugdir . '/ftdetect', 'p')
|
||||||
call setline(1, 'let g:ftdetect_works = 17')
|
set rtp&
|
||||||
wq
|
let rtp = &rtp
|
||||||
|
filetype on
|
||||||
loadplugin mytest
|
|
||||||
call assert_true(42, g:plugin_works)
|
exe 'split ' . s:plugdir . '/plugin/test.vim'
|
||||||
call assert_true(17, g:ftdetect_works)
|
call setline(1, 'let g:plugin_works = 42')
|
||||||
finally
|
wq
|
||||||
call delete(topdir, 'rf')
|
|
||||||
endtry
|
exe 'split ' . s:plugdir . '/ftdetect/test.vim'
|
||||||
|
call setline(1, 'let g:ftdetect_works = 17')
|
||||||
|
wq
|
||||||
|
|
||||||
|
loadplugin mytest
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
endfunc
|
||||||
|
@@ -743,6 +743,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1480,
|
||||||
/**/
|
/**/
|
||||||
1479,
|
1479,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user