vim-patch:7.4.1480

Problem:    Cannot add a pack direcory without loading a plugin.
Solution:   Add the :packadd command.

91715873d1
This commit is contained in:
James McCoy
2016-04-28 20:47:27 -04:00
parent d43ac790f2
commit 67d8e58631
5 changed files with 121 additions and 46 deletions

View File

@@ -398,7 +398,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
@@ -428,6 +428,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

View File

@@ -1854,6 +1854,12 @@ return {
addr_type=ADDR_LINES, addr_type=ADDR_LINES,
func='ex_print', func='ex_print',
}, },
{
command='packadd',
flags=bit.bor(BANG, FILE1, TRLBAR, SBOXOK, CMDWIN),
addr_type=ADDR_LINES,
func='ex_packadd',
},
{ {
command='pclose', command='pclose',
flags=bit.bor(BANG, TRLBAR), flags=bit.bor(BANG, TRLBAR),

View File

@@ -2277,14 +2277,19 @@ static void source_callback(char_u *fname, void *cookie)
/// 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 source_runtime(char_u *name, int all) int 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);
} }
static int do_in_path(char_u *path, char_u *name, bool all, #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 flags,
DoInRuntimepathCB callback, void *cookie) DoInRuntimepathCB callback, void *cookie)
{ {
char_u *tail; char_u *tail;
@@ -2307,7 +2312,7 @@ static int do_in_path(char_u *path, char_u *name, bool all,
// Loop over all entries in 'runtimepath'. // Loop over all entries in 'runtimepath'.
char_u *rtp = rtp_copy; char_u *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, ",");
if (name == NULL) { if (name == NULL) {
@@ -2321,7 +2326,7 @@ static int do_in_path(char_u *path, char_u *name, bool all,
// Loop over all patterns in "name" // Loop over all patterns in "name"
char_u *np = name; char_u *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[].
assert(MAXPATHL >= (tail - buf)); assert(MAXPATHL >= (tail - buf));
copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)),
@@ -2335,11 +2340,12 @@ static int do_in_path(char_u *path, char_u *name, bool all,
// 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
for (i = 0; i < num_files; i++) { : EW_FILE) == OK) {
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;
} }
} }
@@ -2372,7 +2378,7 @@ static int do_in_path(char_u *path, char_u *name, bool all,
int do_in_runtimepath(char_u *name, bool all, DoInRuntimepathCB callback, int do_in_runtimepath(char_u *name, bool all, DoInRuntimepathCB callback,
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);
} }
// Source filetype detection scripts, if filetype.vim was already done. // Source filetype detection scripts, if filetype.vim was already done.
@@ -2384,47 +2390,61 @@ static void may_do_filetypes(char_u *pat)
// when it loads. // when it loads.
if (cmd != NULL && eval_to_number(cmd) > 0) { if (cmd != NULL && eval_to_number(cmd) > 0) {
do_cmdline_cmd("augroup filetypedetect"); do_cmdline_cmd("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("augroup END"); do_cmdline_cmd("augroup END");
} }
xfree(cmd); xfree(cmd);
} }
static void source_pack_plugin(char_u *fname, void *cookie) static void 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;
char_u *new_rtp; char_u *new_rtp;
char_u *ffname = (char_u *)fix_fname((char *)fname);
bool 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'
char_u c = *p6; char_u 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; c = *p2;
if (strstr((char *)p_rtp, (char *)fname) == NULL) { *p2 = NUL;
}
if (strstr((char *)p_rtp, (char *)ffname) == NULL) {
// directory not in 'runtimepath', add it // directory not in 'runtimepath', add it
size_t oldlen = STRLEN(p_rtp); size_t oldlen = STRLEN(p_rtp);
size_t addlen = STRLEN(fname); size_t addlen = STRLEN(ffname);
new_rtp = try_malloc(oldlen + addlen + 1); new_rtp = try_malloc(oldlen + addlen + 1);
if (new_rtp == NULL) { if (new_rtp == NULL) {
*p2 = c; *p2 = c;
@@ -2433,7 +2453,7 @@ static void source_pack_plugin(char_u *fname, void *cookie)
uintptr_t keep = (uintptr_t)(p - p_rtp); uintptr_t keep = (uintptr_t)(p - p_rtp);
memmove(new_rtp, p_rtp, keep); memmove(new_rtp, p_rtp, keep);
new_rtp[keep] = ','; new_rtp[keep] = ',';
memmove(new_rtp + keep + 1, fname, addlen + 1); memmove(new_rtp + keep + 1, ffname, addlen + 1);
if (p_rtp[keep] != NUL) { if (p_rtp[keep] != NUL) {
memmove(new_rtp + keep + 1 + addlen, p_rtp + keep, memmove(new_rtp + keep + 1 + addlen, p_rtp + keep,
oldlen - keep + 1); oldlen - keep + 1);
@@ -2441,16 +2461,18 @@ static void source_pack_plugin(char_u *fname, void *cookie)
set_option_value((char_u *)"rtp", 0L, new_rtp, 0); set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
xfree(new_rtp); xfree(new_rtp);
} }
*p2 = c; xfree(ffname);
(void)do_source(fname, false, DOSO_NONE); if (load_file) {
(void)do_source(fname, false, DOSO_NONE);
}
} }
// Source the plugins in the package directories. // Source the plugins in the package directories.
void source_packages(void) void source_packages(void)
{ {
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");
} }
@@ -2463,7 +2485,7 @@ void ex_loadplugin(exarg_T *eap)
size_t len = STRLEN(ftpat) + STRLEN(eap->arg); size_t len = STRLEN(ftpat) + STRLEN(eap->arg);
char *pat = xmallocz(len); char *pat = xmallocz(len);
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);
@@ -2471,6 +2493,18 @@ void ex_loadplugin(exarg_T *eap)
xfree(pat); xfree(pat);
} }
/// ":packadd {name}"
void ex_packadd(exarg_T *eap)
{
static const char *plugpat = "pack/*/opt/%s";
size_t len = STRLEN(plugpat) + STRLEN(eap->arg);
char *pat = (char *)xmallocz(len);
vim_snprintf(pat, len, plugpat, eap->arg);
do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR, add_pack_plugin, NULL);
xfree(pat);
}
/// ":options" /// ":options"
void ex_options(exarg_T *eap) void ex_options(exarg_T *eap)
{ {

View File

@@ -215,7 +215,7 @@ static int included_patches[] = {
// 1483 NA // 1483 NA
// 1482 NA // 1482 NA
// 1481 NA // 1481 NA
// 1480, 1480,
1479, 1479,
1478, 1478,
// 1477, // 1477,

View File

@@ -13,34 +13,67 @@ describe('loadplugin', function()
clear() clear()
source([=[ source([=[
func SetUp()
let s:topdir = expand('%:p: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() func Test_loadplugin()
let topdir = expand('%:p:h') . '/Xdir' call mkdir(s:plugdir . '/plugin', 'p')
exe 'set packpath=' . topdir call mkdir(s:plugdir . '/ftdetect', 'p')
let plugdir = topdir . '/pack/mine/opt/mytest' set rtp&
call mkdir(plugdir . '/plugin', 'p') let rtp = &rtp
call mkdir(plugdir . '/ftdetect', 'p')
filetype on filetype on
try
exe 'split ' . plugdir . '/plugin/test.vim'
call setline(1, 'let g:plugin_works = 42')
wq
exe 'split ' . plugdir . '/ftdetect/test.vim' exe 'split ' . s:plugdir . '/plugin/test.vim'
call setline(1, 'let g:ftdetect_works = 17') call setline(1, 'let g:plugin_works = 42')
wq wq
loadplugin mytest exe 'split ' . s:plugdir . '/ftdetect/test.vim'
call assert_true(42, g:plugin_works) call setline(1, 'let g:ftdetect_works = 17')
call assert_true(17, g:ftdetect_works) wq
finally
call delete(topdir, 'rf') loadplugin mytest
endtry
call assert_true(42, g:plugin_works)
call assert_true(17, g:ftdetect_works)
call assert_true(len(&rtp) > len(rtp))
call assert_true(&rtp =~ (s:plugdir . '\($\|,\)'))
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 =~ (s:plugdir . '\($\|,\)'))
" check the path is not added twice
let new_rtp = &rtp
packadd mytest
call assert_equal(new_rtp, &rtp)
endfunc endfunc
]=]) ]=])
call('SetUp')
end)
teardown(function()
call('TearDown')
end) end)
it('is working', function() it('is working', function()
call('Test_loadplugin') call('Test_loadplugin')
expected_empty() expected_empty()
end) end)
it('works with packadd', function()
call('Test_packadd')
expected_empty()
end)
end) end)