From 7852993f4927c2d004d627bbe244dbbe09edb94f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Feb 2026 21:30:44 +0800 Subject: [PATCH] vim-patch:9.2.0061: Not possible to know when a session will be loaded (#38071) Problem: Not possible to know when a session will be loaded. Solution: Add the SessionLoadPre autocommand (Colin Kennedy). fixes: vim/vim#19084 closes: vim/vim#19306 https://github.com/vim/vim/commit/1c0d468d72e0220d4cb25936043ac35439a981b5 Co-authored-by: Colin Kennedy --- runtime/doc/autocmd.txt | 3 ++ runtime/doc/news.txt | 1 + runtime/doc/options.txt | 1 + runtime/doc/starting.txt | 4 +- runtime/lua/vim/_meta/api_keysets.lua | 1 + runtime/lua/vim/_meta/options.lua | 1 + src/nvim/auevents.lua | 1 + src/nvim/ex_session.c | 3 ++ test/old/testdir/test_autocmd.vim | 65 +++++++++++++++++++++++++++ 9 files changed, 78 insertions(+), 2 deletions(-) diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 2b5520a3e4..8abc4dcb84 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -961,6 +961,9 @@ SafeState When nothing is pending, going to wait for the check more with `state()`, e.g. whether the screen was scrolled for messages. + *SessionLoadPre* +SessionLoadPre Before loading the session file created using + the |:mksession| command. *SessionLoadPost* SessionLoadPost After loading the session file created using the |:mksession| command. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index eff4084f08..926bf4866a 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -240,6 +240,7 @@ EVENTS • Creating or updating a progress message with |nvim_echo()| triggers a |Progress| event. • |MarkSet| is triggered after a |mark| is set by the user (currently doesn't support implicit marks like |'[| or |'<|, …). +• |SessionLoadPre| is triggered before loading a |Session| file. • |TabClosedPre| is triggered before closing a |tabpage|. • New `terminator` parameter for |TermRequest| event. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 126c3730b6..5475840f44 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2553,6 +2553,7 @@ A jump table for the options with a short description can be found at |Q_op|. |RemoteReply|, |SafeState|, |SessionLoadPost|, + |SessionLoadPre|, |SessionWritePost|, |ShellCmdPost|, |Signal|, diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index d8f209452f..b46e8d8f06 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -852,8 +852,8 @@ This saves the current Session, and starts off the command to load another. A session includes all tab pages, unless "tabpages" was removed from 'sessionoptions'. |tab-page| -The |SessionLoadPost| autocmd event is triggered after a session file is -loaded/sourced. +The |SessionLoadPre| autocmd event is triggered before a session file is +loaded/sourced and |SessionLoadPost| autocmd event is triggered after. *SessionLoad-variable* While the session file is loading, the SessionLoad global variable is set to 1. Plugins can use this to postpone some work until the SessionLoadPost event diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua index ba7b92fff2..16a51f3b18 100644 --- a/runtime/lua/vim/_meta/api_keysets.lua +++ b/runtime/lua/vim/_meta/api_keysets.lua @@ -176,6 +176,7 @@ error('Cannot require a meta file') --- |'SafeState' --- |'SearchWrapped' --- |'SessionLoadPost' +--- |'SessionLoadPre' --- |'SessionWritePost' --- |'ShellCmdPost' --- |'ShellFilterPost' diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index c2283dbd84..e0747c0041 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -2231,6 +2231,7 @@ vim.go.ei = vim.go.eventignore --- `RemoteReply`, --- `SafeState`, --- `SessionLoadPost`, +--- `SessionLoadPre`, --- `SessionWritePost`, --- `ShellCmdPost`, --- `Signal`, diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index 39508eff09..f3e26720e1 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -97,6 +97,7 @@ return { SafeState = false, -- going to wait for a character SearchWrapped = true, -- after the search wrapped around SessionLoadPost = false, -- after loading a session file + SessionLoadPre = false, -- before loading a session file SessionWritePost = false, -- after writing a session file ShellCmdPost = false, -- after ":!cmd" ShellFilterPost = true, -- after ":1,2!cmd", ":w !cmd", ":r !cmd". diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 93ad8518d4..7af10d1a87 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -600,6 +600,9 @@ static int makeopens(FILE *fd, char *dirnow) // Begin by setting v:this_session, and then other sessionable variables. PUTLINE_FAIL("let v:this_session=expand(\":p\")"); + + PUTLINE_FAIL("doautoall SessionLoadPre"); + if (ssop_flags & kOptSsopFlagGlobals) { if (store_session_globals(fd) == FAIL) { return FAIL; diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 45dabcf4ce..c6bc608204 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -1135,6 +1135,71 @@ func Test_BufEnter() only endfunc +func Test_autocmd_SessLoadPre() + tabnew + set noswapfile + mksession! Session.vim + + call assert_false(exists('g:session_loaded_var')) + + let content =<< trim [CODE] + set nocp noswapfile + + func! Assert(cond, msg) + if !a:cond + echomsg "ASSERT_FAIL: " .. a:msg + else + echomsg "ASSERT_OK: " .. a:msg + endif + endfunc + + func! OnSessionLoadPre() + call Assert(!exists('g:session_loaded_var'), + \ 'SessionLoadPre: var NOT set') + endfunc + au SessionLoadPre * call OnSessionLoadPre() + + func! OnSessionLoadPost() + call Assert(exists('g:session_loaded_var'), + \ 'SessionLoadPost: var IS set') + echomsg "SessionLoadPost DONE" + endfunc + au SessionLoadPost * call OnSessionLoadPost() + + func! WriteErrors() + call writefile([execute("messages")], "XerrorsPost") + endfunc + au VimLeave * call WriteErrors() + [CODE] + + call writefile(content, 'Xvimrc', 'D') + + call writefile( + \ ['let g:session_loaded_var = 1'], + \ 'Sessionx.vim', + \ 'b' + \ ) + + " --- Run child Vim --- + call system( + \ GetVimCommand('Xvimrc') + \ .. ' --headless --noplugins -S Session.vim -c cq' + \ ) + + call WaitForAssert({-> assert_true(filereadable('XerrorsPost'))}) + + let errors = join(readfile('XerrorsPost'), "\n") + call assert_notmatch('ASSERT_FAIL', errors) + call assert_match('ASSERT_OK: SessionLoadPre: var NOT set', errors) + call assert_match('ASSERT_OK: SessionLoadPost: var IS set', errors) + call assert_match('SessionLoadPost DONE', errors) + + set swapfile + for file in ['Session.vim', 'Sessionx.vim', 'XerrorsPost'] + call delete(file) + endfor +endfunc + " Closing a window might cause an endless loop " E814 for older Vims func Test_autocmd_bufwipe_in_SessLoadPost()