From 003b429a8671dbb00d9c7e7e9f40d7aedfa87b8d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Nov 2025 18:07:33 +0800 Subject: [PATCH] vim-patch:9.1.1892: Not possible to know once Vim is done with sourcing vimrc (#36429) Problem: A plugin does not know when startup scripts were already triggered. This is useful to determine if a function is called inside vimrc or after (like when sourcing 'plugin/' files). Solution: Add the v:vim_did_init variable (Evgeni Chasnovski) closes: vim/vim#18668 https://github.com/vim/vim/commit/294bce21ee837aab209a1008d0efc3e305cf188f Nvim has two more steps between sourcing startup scripts and loading plugins. Set this variable after these two steps. Co-authored-by: Evgeni Chasnovski --- runtime/doc/news.txt | 1 + runtime/doc/repeat.txt | 6 ++++ runtime/doc/starting.txt | 18 ++++++------ runtime/doc/vvars.txt | 6 ++++ runtime/lua/vim/_meta/vvars.lua | 6 ++++ src/nvim/eval/vars.c | 1 + src/nvim/eval_defs.h | 1 + src/nvim/main.c | 2 ++ src/nvim/vvars.lua | 8 ++++++ test/old/testdir/test_startup.vim | 47 +++++++++++++++++++++++-------- 10 files changed, 76 insertions(+), 20 deletions(-) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 5452990b68..03f3966400 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -367,6 +367,7 @@ VIMSCRIPT • |getcompletiontype()| gets command-line completion type for any string. • |prompt_getinput()| gets current user-input in prompt-buffer. • |wildtrigger()| triggers command-line expansion. +• |v:vim_did_init| is set after sourcing |init.vim| but before |load-plugins|. ============================================================================== CHANGED FEATURES *news-changed* diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index b94af96360..817f664211 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -301,6 +301,12 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. each directory is inserted before others), after loading the ftdetect scripts. + To programmatically decide if `!` is needed during + startup, check |v:vim_did_init|: use `!` if 0 (to not + duplicate |load-plugins| step), no `!` otherwise (to + force load plugin files as otherwise they won't be + loaded automatically). + *:packl* *:packloadall* :packl[oadall][!] Load all packages in the "start" directory under each entry in 'packpath'. diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 512e48d170..6672a20fcc 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -517,7 +517,9 @@ accordingly, proceeding as follows: < Skipped if ":syntax off" was called or if the "-u NONE" command line argument was given. -10. Load the plugin scripts. *load-plugins* +10. Set the |v:vim_did_init| variable to 1. + +11. Load the plugin scripts. *load-plugins* This does the same as the command: > :runtime! plugin/**/*.{vim,lua} < The result is that all directories in 'runtimepath' will be searched @@ -547,21 +549,21 @@ accordingly, proceeding as follows: if packages have been found, but that should not add a directory ending in "after". -11. Set 'shellpipe' and 'shellredir' +12. 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. This means that Nvim will figure out the values of 'shellpipe' and 'shellredir' for you, unless you have set them yourself. -12. Set 'updatecount' to zero, if "-n" command argument used. +13. Set 'updatecount' to zero, if "-n" command argument used. -13. Set binary options if the |-b| flag was given. +14. Set binary options if the |-b| flag was given. -14. Read the |shada-file|. +15. Read the |shada-file|. -15. Read the quickfix file if the |-q| flag was given, or exit on failure. +16. Read the quickfix file if the |-q| flag was given, or exit on failure. -16. Open all windows +17. Open all windows When the |-o| flag was given, windows will be opened (but not displayed yet). When the |-p| flag was given, tab pages will be created (but not @@ -571,7 +573,7 @@ accordingly, proceeding as follows: Buffers for all windows will be loaded, without triggering |BufAdd| autocommands. -17. Execute startup commands +18. Execute startup commands If a |-t| flag was given, the tag is jumped to. Commands given with |-c| and |+cmd| are executed. The starting flag is reset, has("vim_starting") will now return zero. diff --git a/runtime/doc/vvars.txt b/runtime/doc/vvars.txt index 07f0d99e75..3db2f5c176 100644 --- a/runtime/doc/vvars.txt +++ b/runtime/doc/vvars.txt @@ -744,6 +744,12 @@ v:versionlong *v:vim_did_enter* *vim_did_enter-variable* v:vim_did_enter 0 during startup, 1 just before |VimEnter|. + Read-only. + + *v:vim_did_init* *vim_did_init-variable* +v:vim_did_init + 0 during initialization, 1 after sourcing |vimrc| and just + before |load-plugins|. Read-only. *v:virtnum* *virtnum-variable* diff --git a/runtime/lua/vim/_meta/vvars.lua b/runtime/lua/vim/_meta/vvars.lua index fc629edc30..2b18d21f78 100644 --- a/runtime/lua/vim/_meta/vvars.lua +++ b/runtime/lua/vim/_meta/vvars.lua @@ -793,6 +793,12 @@ vim.v.versionlong = ... --- @type integer vim.v.vim_did_enter = ... +--- 0 during initialization, 1 after sourcing `vimrc` and just +--- before `load-plugins`. +--- Read-only. +--- @type integer +vim.v.vim_did_init = ... + --- Virtual line number for the 'statuscolumn' expression. --- Negative when drawing the status column for virtual lines, zero --- when drawing an actual buffer line, and positive when drawing diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index bb6e58acee..61de5cc954 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -203,6 +203,7 @@ static struct vimvar { VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO), VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO), VV(VV_STACKTRACE, "stacktrace", VAR_LIST, VV_RO), + VV(VV_VIM_DID_INIT, "vim_did_init", VAR_NUMBER, VV_RO), // Neovim VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO), VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO), diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h index 07b01f0c93..ce66d07699 100644 --- a/src/nvim/eval_defs.h +++ b/src/nvim/eval_defs.h @@ -123,6 +123,7 @@ typedef enum { VV_EXITING, VV_MAXCOL, VV_STACKTRACE, + VV_VIM_DID_INIT, // Nvim VV_STDERR, VV_MSGPACK_TYPES, diff --git a/src/nvim/main.c b/src/nvim/main.c index a3da291bae..71ba002d76 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -466,6 +466,8 @@ int main(int argc, char **argv) syn_maybe_enable(); } + set_vim_var_nr(VV_VIM_DID_INIT, 1); + // Read all the plugin files. load_plugins(); diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index 6ebd268062..64d3d0e9cc 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -901,6 +901,14 @@ M.vars = { Read-only. ]=], }, + vim_did_init = { + type = 'integer', + desc = [=[ + 0 during initialization, 1 after sourcing |vimrc| and just + before |load-plugins|. + Read-only. + ]=], + }, virtnum = { type = 'integer', desc = [=[ diff --git a/test/old/testdir/test_startup.vim b/test/old/testdir/test_startup.vim index 7e94a5c743..974f8ce942 100644 --- a/test/old/testdir/test_startup.vim +++ b/test/old/testdir/test_startup.vim @@ -22,9 +22,7 @@ endfunc " 2. packages " 3. plugins in after directories func Test_after_comes_later() - if !has('packages') - return - endif + CheckFeature packages let before =<< trim [CODE] set nocp viminfo+=nviminfo set guioptions+=M @@ -46,14 +44,14 @@ func Test_after_comes_later() quit [CODE] - call mkdir('Xhere/plugin', 'p') + call mkdir('Xhere/plugin', 'pR') call writefile(['let g:sequence .= "here "'], 'Xhere/plugin/here.vim') - call mkdir('Xanother/plugin', 'p') + call mkdir('Xanother/plugin', 'pR') call writefile(['let g:sequence .= "another "'], 'Xanother/plugin/another.vim') call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p') call writefile(['let g:sequence .= "pack "'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim') - call mkdir('Xdir/after/plugin', 'p') + call mkdir('Xdir/after/plugin', 'pR') call writefile(['let g:sequence .= "after "'], 'Xdir/after/plugin/later.vim') if RunVim(before, after, '') @@ -75,15 +73,40 @@ func Test_after_comes_later() call delete('Xtestout') call delete('Xsequence') - call delete('Xhere', 'rf') - call delete('Xanother', 'rf') - call delete('Xdir', 'rf') +endfunc + +func Test_vim_did_init() + let before =<< trim [CODE] + set nocp viminfo+=nviminfo + set guioptions+=M + set loadplugins + set rtp=Xhere + set nomore + [CODE] + + let after =<< trim [CODE] + redir! > Xtestout + echo g:var_vimrc + echo g:var_plugin + redir END + quit + [CODE] + + call writefile(['let g:var_vimrc=v:vim_did_init'], 'Xvimrc', 'D') + call mkdir('Xhere/plugin', 'pR') + call writefile(['let g:var_plugin=v:vim_did_init'], 'Xhere/plugin/here.vim') + + if RunVim(before, after, '-u Xvimrc') + let lines = readfile('Xtestout') + call assert_equal('0', lines[1]) + call assert_equal('1', lines[2]) + endif + + call delete('Xtestout') endfunc func Test_pack_in_rtp_when_plugins_run() - if !has('packages') - return - endif + CheckFeature packages let before =<< trim [CODE] set nocp viminfo+=nviminfo set guioptions+=M