vim-patch:7.4.2164 (#6326)

Problem:    It is not possible to use plugins in an "after" directory to tune
            the behavior of a package.
Solution:   First load plugins from non-after directories, then packages and
            finally plugins in after directories.
            Reset 'loadplugins' before executing --cmd arguments.

66459b7c98

vim-patch:7.4.2172
vim-patch:7.4.2169
vim-patch:7.4.2177
vim-patch:7.4.2178
vim-patch:7.4.2184
vim-patch:8.0.0050
vim-patch:8.0.0105
vim-patch:8.0.0400
vim-patch:8.0.0405

Closes #6034
This commit is contained in:
Justin M. Keyes 2017-03-21 17:07:00 +01:00 committed by GitHub
parent 5657bb9ea6
commit 6baa669c10
8 changed files with 457 additions and 12 deletions

View File

@ -457,6 +457,8 @@ accordingly. Vim proceeds in this order:
searched for the "plugin" sub-directory and all files ending in ".vim"
will be sourced (in alphabetical order per directory), also in
subdirectories.
However, directories in 'runtimepath' ending in "after" are skipped
here and only loaded after packages, see below.
Loading plugins won't be done when:
- The 'loadplugins' option was reset in a vimrc file.
- The |--noplugin| command line argument is used.
@ -464,13 +466,18 @@ accordingly. Vim proceeds in this order:
- When Vim was compiled without the |+eval| feature.
Note that using "-c 'set noloadplugins'" doesn't work, because the
commands from the command line have not been executed yet. You can
use "--cmd 'set noloadplugins'" |--cmd|.
use "--cmd 'set noloadplugins'" or "--cmd 'set loadplugins'" |--cmd|.
Packages are loaded. These are plugins, as above, but found in the
"start" directory of each entry in 'packpath'. Every plugin directory
found is added in 'runtimepath' and then the plugins are sourced. See
|packages|.
The plugins scripts are loaded, as above, but now only the directories
ending in "after" are used. Note that 'runtimepath' will have changed
if packages have been found, but that should not add a directory
ending in "after".
7. 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.

View File

@ -2361,12 +2361,25 @@ int do_in_path(char_u *path, char_u *name, int flags,
while (*rtp != NUL && ((flags & DIP_ALL) || !did_one)) {
// Copy the path from 'runtimepath' to buf[].
copy_option_part(&rtp, buf, MAXPATHL, ",");
size_t buflen = STRLEN(buf);
// Skip after or non-after directories.
if (flags & (DIP_NOAFTER | DIP_AFTER)) {
bool is_after = buflen >= 5
&& STRCMP(buf + buflen - 5, "after") == 0;
if ((is_after && (flags & DIP_NOAFTER))
|| (!is_after && (flags & DIP_AFTER))) {
continue;
}
}
if (name == NULL) {
(*callback)(buf, (void *)&cookie);
if (!did_one) {
did_one = (cookie == NULL);
}
} else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL) {
} else if (buflen + STRLEN(name) + 2 < MAXPATHL) {
add_pathsep((char *)buf);
tail = buf + STRLEN(buf);
@ -2597,6 +2610,7 @@ static bool did_source_packages = false;
// ":packloadall"
// Find plugins in the package directories and source them.
// "eap" is NULL when invoked during startup.
void ex_packloadall(exarg_T *eap)
{
if (!did_source_packages || (eap != NULL && eap->forceit)) {

View File

@ -326,6 +326,12 @@ int main(int argc, char **argv)
do_cmdline_cmd("augroup END");
#undef PROTO
// Reset 'loadplugins' for "-u NONE" before "--cmd" arguments.
// Allows for setting 'loadplugins' there.
if (params.use_vimrc != NULL && strcmp(params.use_vimrc, "NONE") == 0) {
p_lpl = false;
}
/* Execute --cmd arguments. */
exe_pre_commands(&params);
@ -1268,11 +1274,14 @@ static void set_window_layout(mparm_T *paramp)
static void load_plugins(void)
{
if (p_lpl) {
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL); // NOLINT
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_NOAFTER); // NOLINT
TIME_MSG("loading plugins");
ex_packloadall(NULL);
TIME_MSG("loading packages");
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_AFTER);
TIME_MSG("loading after plugins");
}
}
@ -1708,8 +1717,6 @@ static void source_startup_scripts(const mparm_T *const parmp)
if (parmp->use_vimrc != NULL) {
if (strcmp(parmp->use_vimrc, "NONE") == 0
|| strcmp(parmp->use_vimrc, "NORC") == 0) {
if (parmp->use_vimrc[2] == 'N')
p_lpl = false; // don't load plugins either
} else {
if (do_source((char_u *)parmp->use_vimrc, FALSE, DOSO_NONE) != OK)
EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc);

View File

@ -4,8 +4,9 @@ set noruler
set noshowcmd
set belloff=
" Make sure 'runtimepath' does not include $HOME.
" Make sure 'runtimepath' and 'packpath' does not include $HOME.
set rtp=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
let &packpath = &rtp
" Make sure $HOME does not get read or written.
let $HOME = '/does/not/exist'

214
src/nvim/testdir/shared.vim Normal file
View File

@ -0,0 +1,214 @@
" Functions shared by several tests.
" Get the name of the Python executable.
" Also keeps it in s:python.
func PythonProg()
" This test requires the Python command to run the test server.
" This most likely only works on Unix and Windows.
if has('unix')
" We also need the job feature or the pkill command to make sure the server
" can be stopped.
if !(executable('python') && (has('job') || executable('pkill')))
return ''
endif
let s:python = 'python'
elseif has('win32')
" Use Python Launcher for Windows (py.exe) if available.
if executable('py.exe')
let s:python = 'py.exe'
elseif executable('python.exe')
let s:python = 'python.exe'
else
return ''
endif
else
return ''
endif
return s:python
endfunc
" Run "cmd". Returns the job if using a job.
func RunCommand(cmd)
let job = 0
if has('job')
let job = job_start(a:cmd, {"stoponexit": "hup"})
call job_setoptions(job, {"stoponexit": "kill"})
elseif has('win32')
exe 'silent !start cmd /c start "test_channel" ' . a:cmd
else
exe 'silent !' . a:cmd . '&'
endif
return job
endfunc
" Read the port number from the Xportnr file.
func GetPort()
let l = []
for i in range(200)
try
let l = readfile("Xportnr")
catch
endtry
if len(l) >= 1
break
endif
sleep 10m
endfor
call delete("Xportnr")
if len(l) == 0
" Can't make the connection, give up.
return 0
endif
return l[0]
endfunc
" Run a Python server for "cmd" and call "testfunc".
" Always kills the server before returning.
func RunServer(cmd, testfunc, args)
" The Python program writes the port number in Xportnr.
call delete("Xportnr")
if len(a:args) == 1
let arg = ' ' . a:args[0]
else
let arg = ''
endif
let pycmd = s:python . " " . a:cmd . arg
try
let g:currentJob = RunCommand(pycmd)
" Wait for up to 2 seconds for the port number to be there.
let port = GetPort()
if port == 0
call assert_false(1, "Can't start " . a:cmd)
return
endif
call call(function(a:testfunc), [port])
catch
call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint)
finally
call s:kill_server(a:cmd)
endtry
endfunc
func s:kill_server(cmd)
if has('job')
if exists('g:currentJob')
call job_stop(g:currentJob)
unlet g:currentJob
endif
elseif has('win32')
let cmd = substitute(a:cmd, ".py", '', '')
call system('taskkill /IM ' . s:python . ' /T /F /FI "WINDOWTITLE eq ' . cmd . '"')
else
call system("pkill -f " . a:cmd)
endif
endfunc
" Wait for up to a second for "expr" to become true.
" Return time slept in milliseconds. With the +reltime feature this can be
" more than the actual waiting time. Without +reltime it can also be less.
func WaitFor(expr)
" using reltime() is more accurate, but not always available
if has('reltime')
let start = reltime()
else
let slept = 0
endif
for i in range(100)
try
if eval(a:expr)
if has('reltime')
return float2nr(reltimefloat(reltime(start)) * 1000)
endif
return slept
endif
catch
endtry
if !has('reltime')
let slept += 10
endif
sleep 10m
endfor
return 1000
endfunc
" Wait for up to a given milliseconds.
" With the +timers feature this waits for key-input by getchar(), Resume()
" feeds key-input and resumes process. Return time waited in milliseconds.
" Without +timers it uses simply :sleep.
func Standby(msec)
if has('timers')
let start = reltime()
let g:_standby_timer = timer_start(a:msec, function('s:feedkeys'))
call getchar()
return float2nr(reltimefloat(reltime(start)) * 1000)
else
execute 'sleep ' a:msec . 'm'
return a:msec
endif
endfunc
func Resume()
if exists('g:_standby_timer')
call timer_stop(g:_standby_timer)
call s:feedkeys(0)
unlet g:_standby_timer
endif
endfunc
func s:feedkeys(timer)
call feedkeys('x', 'nt')
endfunc
" Get the command to run Vim, with -u NONE and --headless arguments.
" Returns an empty string on error.
func GetVimCommand()
let cmd = v:progpath
let cmd = substitute(cmd, '-u \f\+', '-u NONE', '')
if cmd !~ '-u NONE'
let cmd = cmd . ' -u NONE'
endif
let cmd .= ' --headless -i NONE'
let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '')
return cmd
endfunc
" Run Vim, using the "vimcmd" file and "-u NORC".
" "before" is a list of Vim commands to be executed before loading plugins.
" "after" is a list of Vim commands to be executed after loading plugins.
" Plugins are not loaded, unless 'loadplugins' is set in "before".
" Return 1 if Vim could be executed.
func RunVim(before, after, arguments)
return RunVimPiped(a:before, a:after, a:arguments, '')
endfunc
func RunVimPiped(before, after, arguments, pipecmd)
let $NVIM_LOG_FILE='Xnvim.log'
let cmd = GetVimCommand()
if cmd == ''
return 0
endif
let args = ''
if len(a:before) > 0
call writefile(a:before, 'Xbefore.vim')
let args .= ' --cmd "so Xbefore.vim"'
endif
if len(a:after) > 0
call writefile(a:after, 'Xafter.vim')
let args .= ' -S Xafter.vim'
endif
exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments
if len(a:before) > 0
call delete('Xbefore.vim')
endif
if len(a:after) > 0
call delete('Xafter.vim')
endif
return 1
endfunc

View File

@ -0,0 +1,200 @@
" Tests for startup.
source shared.vim
" Check that loading startup.vim works.
func Test_startup_script()
throw 'skipped: Nvim does not need defaults.vim'
set compatible
source $VIMRUNTIME/defaults.vim
call assert_equal(0, &compatible)
endfunc
" Verify the order in which plugins are loaded:
" 1. plugins in non-after directories
" 2. packages
" 3. plugins in after directories
func Test_after_comes_later()
if !has('packages')
return
endif
let before = [
\ 'set nocp viminfo+=nviminfo',
\ 'set guioptions+=M',
\ 'let $HOME = "/does/not/exist"',
\ 'set loadplugins',
\ 'set rtp=Xhere,Xafter',
\ 'set packpath=Xhere,Xafter',
\ 'set nomore',
\ ]
let after = [
\ 'redir! > Xtestout',
\ 'scriptnames',
\ 'redir END',
\ 'quit',
\ ]
call mkdir('Xhere/plugin', 'p')
call writefile(['let done = 1'], 'Xhere/plugin/here.vim')
call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p')
call writefile(['let done = 1'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
call mkdir('Xafter/plugin', 'p')
call writefile(['let done = 1'], 'Xafter/plugin/later.vim')
if RunVim(before, after, '')
let lines = readfile('Xtestout')
let expected = ['Xbefore.vim', 'here.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
let found = []
for line in lines
for one in expected
if line =~ one
call add(found, one)
endif
endfor
endfor
call assert_equal(expected, found)
endif
call delete('Xtestout')
call delete('Xhere', 'rf')
call delete('Xafter', 'rf')
endfunc
func Test_help_arg()
if !has('unix') && has('gui')
" this doesn't work with gvim on MS-Windows
return
endif
if RunVim([], [], '--help >Xtestout')
let lines = readfile('Xtestout')
call assert_true(len(lines) > 20)
call assert_match('Usage:', lines[0])
" check if couple of lines are there
let found = []
for line in lines
if line =~ '-R.*Readonly mode'
call add(found, 'Readonly mode')
endif
" Watch out for a second --version line in the Gnome version.
if line =~ '--version.*Print version information and exit'
call add(found, "--version")
endif
endfor
call assert_equal(['--version'], found)
endif
call delete('Xtestout')
endfunc
func Test_compatible_args()
throw "skipped: Nvim is always 'nocompatible'"
let after = [
\ 'call writefile([string(&compatible)], "Xtestout")',
\ 'set viminfo+=nviminfo',
\ 'quit',
\ ]
if RunVim([], after, '-C')
let lines = readfile('Xtestout')
call assert_equal('1', lines[0])
endif
if RunVim([], after, '-N')
let lines = readfile('Xtestout')
call assert_equal('0', lines[0])
endif
call delete('Xtestout')
endfunc
func Test_file_args()
let after = [
\ 'call writefile(argv(), "Xtestout")',
\ 'qall',
\ ]
if RunVim([], after, '')
let lines = readfile('Xtestout')
call assert_equal(0, len(lines))
endif
if RunVim([], after, 'one')
let lines = readfile('Xtestout')
call assert_equal(1, len(lines))
call assert_equal('one', lines[0])
endif
if RunVim([], after, 'one two three')
let lines = readfile('Xtestout')
call assert_equal(3, len(lines))
call assert_equal('one', lines[0])
call assert_equal('two', lines[1])
call assert_equal('three', lines[2])
endif
if RunVim([], after, 'one -c echo two')
let lines = readfile('Xtestout')
call assert_equal(2, len(lines))
call assert_equal('one', lines[0])
call assert_equal('two', lines[1])
endif
if RunVim([], after, 'one -- -c echo two')
let lines = readfile('Xtestout')
call assert_equal(4, len(lines))
call assert_equal('one', lines[0])
call assert_equal('-c', lines[1])
call assert_equal('echo', lines[2])
call assert_equal('two', lines[3])
endif
call delete('Xtestout')
endfunc
func Test_startuptime()
if !has('startuptime')
return
endif
let after = ['qall']
if RunVim([], after, '--startuptime Xtestout one')
let lines = readfile('Xtestout')
let expected = ['parsing arguments', 'inits 3', 'opening buffers']
let found = []
for line in lines
for exp in expected
if line =~ exp
call add(found, exp)
endif
endfor
endfor
call assert_equal(expected, found)
endif
call delete('Xtestout')
endfunc
func Test_read_stdin()
let after = [
\ 'write Xtestout',
\ 'quit!',
\ ]
if RunVimPiped([], after, '-', 'echo something | ')
let lines = readfile('Xtestout')
" MS-Windows adds a space after the word
call assert_equal(['something'], split(lines[0]))
endif
call delete('Xtestout')
endfunc
func Test_progpath()
" Tests normally run with "./vim" or "../vim", these must have been expanded
" to a full path.
if has('unix')
call assert_equal('/', v:progpath[0])
elseif has('win32')
call assert_equal(':', v:progpath[1])
call assert_match('[/\\]', v:progpath[2])
endif
" Only expect "vim" to appear in v:progname.
call assert_match('vim\c', v:progname)
endfunc

View File

@ -257,27 +257,27 @@ static int included_patches[] = {
2187,
// 2186 NA
2185,
// 2184,
2184,
2183,
// 2182 NA
// 2181,
// 2180,
// 2179,
// 2178,
// 2177,
2178,
2177,
// 2176 NA
2175,
2174,
// 2173,
// 2172,
2172,
// 2171,
// 2170,
// 2169,
2169,
// 2168 NA
// 2167 NA
// 2166 NA
// 2165,
// 2164,
2164,
2163,
2162,
// 2161,

View File

@ -325,6 +325,8 @@ enum {
#define DIP_START 0x08 // also use "start" directory in 'packpath'
#define DIP_OPT 0x10 // also use "opt" directory in 'packpath'
#define DIP_NORTP 0x20 // do not use 'runtimepath'
#define DIP_NOAFTER 0x40 // skip "after" directories
#define DIP_AFTER 0x80 // only use "after" directories
// Lowest number used for window ID. Cannot have this many windows per tab.
#define LOWEST_WIN_ID 1000