diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 3f050b92f3..9276f9b315 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -2204,15 +2204,17 @@ nvim_create_autocmd({event}, {opts}) *nvim_create_autocmd()* triggered. Lua callback can return |lua-truthy| to delete the autocommand. Callback receives one argument, a table with keys: *event-args* - • buf: (`number`) + • buf: (`integer`) • data: (`any`) Arbitrary data passed from |nvim_exec_autocmds()| *event-data* • event: (`vim.api.keyset.events`) Name of the triggered event |autocmd-events| • file: (`string`) (not expanded to a full path) - • group: (`number?`) Group id, if any - • id: (`number`) Autocommand id + • group: (`integer?`) Group id, if any + • id: (`integer`) Autocommand id • match: (`string`) (expanded to a full path) + • win: (`integer`) id of the window for the event, see + |window-ID| • command (string?) Vim command executed on event. Not allowed with {callback}. • desc (`string?`) Description (for documentation and diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index ee5392a563..ebea5a46c9 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -238,6 +238,7 @@ API • |nvim_set_option_value()| returns the new option value. • |nvim_create_autocmd()| is now |api-fast|, so it can be called from a fast event context (e.g. |vim.uv| callbacks). +• |nvim_create_autocmd()| callback |event-args| provide `win`. BUILD diff --git a/runtime/lua/vim/_meta/api.gen.lua b/runtime/lua/vim/_meta/api.gen.lua index 1b1311c498..ed323861b1 100644 --- a/runtime/lua/vim/_meta/api.gen.lua +++ b/runtime/lua/vim/_meta/api.gen.lua @@ -969,13 +969,14 @@ function vim.api.nvim_create_augroup(name, opts) end --- - callback (`function|string?`) Lua function (or Vimscript function name, if string) --- called when the event(s) is triggered. Lua callback can return `lua-truthy` to delete --- the autocommand. Callback receives one argument, a table with keys: [event-args]() ---- - buf: (`number`) [] +--- - buf: (`integer`) [] --- - data: (`any`) Arbitrary data passed from [nvim_exec_autocmds()] [event-data]() --- - event: (`vim.api.keyset.events`) Name of the triggered event `autocmd-events` --- - file: (`string`) [] (not expanded to a full path) ---- - group: (`number?`) Group id, if any ---- - id: (`number`) Autocommand id +--- - group: (`integer?`) Group id, if any +--- - id: (`integer`) Autocommand id --- - match: (`string`) [] (expanded to a full path) +--- - win: (`integer`) id of the window for the event, see `window-ID` --- - command (string?) Vim command executed on event. Not allowed with {callback}. --- - desc (`string?`) Description (for documentation and troubleshooting). --- - group (`string|integer?`) Group name or id to match against. diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua index acc23be54e..c1d574707d 100644 --- a/runtime/lua/vim/_meta/api_keysets_extra.lua +++ b/runtime/lua/vim/_meta/api_keysets_extra.lua @@ -76,6 +76,7 @@ error('Cannot require a meta file') --- @field match string expanded value of --- @field buf integer expanded value of --- @field file string expanded value of +--- @field win integer id of the window for the event, see |window-ID| --- @field data? any arbitrary data passed from |nvim_exec_autocmds()| --- @class vim.api.keyset.create_user_command.command_args diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index f3b5aa780a..62fb5da9e4 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -373,13 +373,14 @@ cleanup: /// - callback (`function|string?`) Lua function (or Vimscript function name, if string) /// called when the event(s) is triggered. Lua callback can return |lua-truthy| to delete /// the autocommand. Callback receives one argument, a table with keys: [event-args]() -/// - buf: (`number`) [] +/// - buf: (`integer`) [] /// - data: (`any`) Arbitrary data passed from [nvim_exec_autocmds()] [event-data]() /// - event: (`vim.api.keyset.events`) Name of the triggered event |autocmd-events| /// - file: (`string`) [] (not expanded to a full path) -/// - group: (`number?`) Group id, if any -/// - id: (`number`) Autocommand id +/// - group: (`integer?`) Group id, if any +/// - id: (`integer`) Autocommand id /// - match: (`string`) [] (expanded to a full path) +/// - win: (`integer`) id of the window for the event, see |window-ID| /// - command (string?) Vim command executed on event. Not allowed with {callback}. /// - desc (`string?`) Description (for documentation and troubleshooting). /// - group (`string|integer?`) Group name or id to match against. @@ -764,8 +765,8 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Arena *arena, E FOREACH_ITEM(patterns, pat, { char *fname = !has_buf ? pat.data.string.data : NULL; - did_aucmd |= apply_autocmds_group(event_nr, fname, NULL, true, au_group, b, NULL, data, - has_buf); + did_aucmd |= apply_autocmds_group(event_nr, fname, NULL, true, au_group, b, curwin, NULL, + data, has_buf); }) }) diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index c7f3047a64..12ee0ccb61 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -299,7 +299,7 @@ Window nvim_open_win(Buffer buf, Boolean enter, Dict(win_config) *config, Error const bool result = ctx_switch(&switchwin, wp, tp, NULL, kCtxNoDisplay); assert(result); (void)result; - if (apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf)) { + if (apply_autocmds_win(EVENT_WINNEW, NULL, NULL, false, curbuf, wp)) { tp = win_find_tabpage(wp); } ctx_restore(&switchwin); diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 191dd3aa90..0b529f0757 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -88,6 +88,10 @@ static const char e_autocommand_nesting_too_deep[] // Code for automatic commands. static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands +/// Window handle for `ev.win`. Unlike autocmd_bufnr/_match this needn't be a +/// global: only au_callback() reads it. +static handle_T autocmd_winid = 0; + // ID for associating autocmds created via nvim_create_autocmd // Used to delete autocmds from nvim_del_autocmd static int next_augroup_id = 1; @@ -1165,7 +1169,7 @@ int do_doautocmd(char *arg_start, bool do_msg, bool *did_something) // Loop over the events. while (*arg && !ends_excmd(*arg) && !ascii_iswhite(*arg)) { if (apply_autocmds_group(event_name2nr(arg, &arg), fname, NULL, true, group, - curbuf, NULL, NULL, false)) { + curbuf, curwin, NULL, NULL, false)) { nothing_done = false; } } @@ -1311,9 +1315,11 @@ static void deferred_event(void **argv) } tv_dict_set_keys_readonly(v_event); + win_T *win = curwin; // before ctx_switch() may make the context window current + CtxSwitch aco = { 0 }; ctx_switch(&aco, NULL, NULL, buf, 0); - apply_autocmds_group(event, fname, fname_io, false, group, buf, eap, data, false); + apply_autocmds_group(event, fname, fname_io, false, group, buf, win, eap, data, false); ctx_restore(&aco); restore_v_event(v_event, &save_v_event); @@ -1359,6 +1365,8 @@ void aucmd_defer_modified(buf_T *buf, bool new_val) /// Execute autocommands for "event" and file name "fname". /// +/// `ev.win` is curwin; use apply_autocmds_win() for window-specific events. +/// /// @param event event that occurred /// @param fname filename, NULL or empty means use actual file name /// @param fname_io filename to use for on cmdline @@ -1368,7 +1376,20 @@ void aucmd_defer_modified(buf_T *buf, bool new_val) /// @return true if some commands were executed. bool apply_autocmds(event_T event, char *fname, char *fname_io, bool force, buf_T *buf) { - return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL, NULL, false); + return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, curwin, NULL, NULL, + false); +} + +/// Like apply_autocmds(), but with an explicit window for `ev.win`. +/// +/// @param win Window for `ev.win`, NULL for the current window. +/// +/// @return true if some commands were executed. +bool apply_autocmds_win(event_T event, char *fname, char *fname_io, bool force, buf_T *buf, + win_T *win) +{ + return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, win, NULL, NULL, + false); } /// Like apply_autocmds(), but with extra "eap" argument. This takes care of @@ -1385,7 +1406,8 @@ bool apply_autocmds(event_T event, char *fname, char *fname_io, bool force, buf_ bool apply_autocmds_exarg(event_T event, char *fname, char *fname_io, bool force, buf_T *buf, exarg_T *eap) { - return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, eap, NULL, false); + return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, curwin, eap, NULL, + false); } /// Like apply_autocmds(), but handles the caller's retval. If the script @@ -1408,8 +1430,8 @@ bool apply_autocmds_retval(event_T event, char *fname, char *fname_io, bool forc return false; } - bool did_cmd = apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL, NULL, - false); + bool did_cmd = apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, curwin, NULL, + NULL, false); if (did_cmd && aborting()) { *retval = FAIL; } @@ -1453,12 +1475,13 @@ bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT /// @param force Ignore autocmd_busy (force "++nested" behavior) /// @param group autocmd group ID or AUGROUP_ALL /// @param buf Buffer for +/// @param win Window for `ev.win`, NULL for the current window. /// @param eap Ex command arguments /// @param with_buf Run callbacks with "buf" as the current buffer /// /// @return true if some commands were executed. bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force, int group, - buf_T *buf, exarg_T *eap, Object *data, bool with_buf) + buf_T *buf, win_T *win, exarg_T *eap, Object *data, bool with_buf) { char *sfname = NULL; // short file name bool retval = false; @@ -1539,6 +1562,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force char *save_autocmd_fname = autocmd_fname; bool save_autocmd_fname_full = autocmd_fname_full; int save_autocmd_bufnr = autocmd_bufnr; + handle_T save_autocmd_winid = autocmd_winid; char *save_autocmd_match = autocmd_match; int save_autocmd_busy = autocmd_busy; int save_autocmd_nested = autocmd_nested; @@ -1640,6 +1664,10 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force goto BYPASS_AU; } + // Set the window handle for `ev.win`. After the last "goto BYPASS_AU", which + // skips the restore below, and before ctx_switch(). + autocmd_winid = win != NULL ? win->handle : (curwin != NULL ? curwin->handle : 0); + if (with_buf && buf != NULL && buf != curbuf) { ctx_switch(&aco, NULL, NULL, buf, 0); } @@ -1770,6 +1798,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force autocmd_fname = save_autocmd_fname; autocmd_fname_full = save_autocmd_fname_full; autocmd_bufnr = save_autocmd_bufnr; + autocmd_winid = save_autocmd_winid; autocmd_match = save_autocmd_match; current_sctx = save_current_sctx; restore_funccal(); @@ -1839,7 +1868,7 @@ void do_termresponse_autocmd(const String sequence, uint64_t channel_id) MAXSIZE_TEMP_DICT(data, 2); PUT_C(data, "sequence", STRING_OBJ(sequence)); PUT_C(data, "chan", INTEGER_OBJ((Integer)channel_id)); - apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, true, AUGROUP_ALL, NULL, NULL, + apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, true, AUGROUP_ALL, NULL, curwin, NULL, &DICT_OBJ(data), false); termresponse_changed = true; termresponse_chan_id = channel_id; @@ -1945,12 +1974,13 @@ static bool au_callback(const AutoCmd *ac, const AutoPatCmd *apc) { Callback callback = ac->handler_fn; if (callback.type == kCallbackLua) { - MAXSIZE_TEMP_DICT(data, 7); + MAXSIZE_TEMP_DICT(data, 8); PUT_C(data, "id", INTEGER_OBJ(ac->id)); PUT_C(data, "event", CSTR_AS_OBJ(event_nr2name(apc->event))); PUT_C(data, "file", CSTR_AS_OBJ(apc->afile_orig)); PUT_C(data, "match", CSTR_AS_OBJ(autocmd_match)); PUT_C(data, "buf", INTEGER_OBJ(autocmd_bufnr)); + PUT_C(data, "win", INTEGER_OBJ(autocmd_winid)); if (apc->data) { PUT_C(data, "data", *apc->data); diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 635262253a..252d752c08 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -636,8 +636,8 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i if (win_valid && win->w_buffer == buf && buf->b_nwindows == 1) { buf->b_locked++; buf->b_locked_split++; - if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, false, - buf) && !bufref_valid(&bufref)) { + if (apply_autocmds_win(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, false, + buf, win) && !bufref_valid(&bufref)) { // Autocommands deleted the buffer. emsg(_(e_auabort)); return false; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6bf91447e0..8925e24a78 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4725,7 +4725,7 @@ bool before_quit_autocmds(win_T *wp, bool quit_all, bool forceit) if (*get_vim_var_str(VV_EXITREASON) == NUL) { set_vim_var_string(VV_EXITREASON, S_LEN("quit")); } - apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, wp->w_buffer); + apply_autocmds_win(EVENT_QUITPRE, NULL, NULL, false, wp->w_buffer, wp); // Bail out when autocommands closed the window. // Refuse to quit when the buffer in the last window is being closed (can diff --git a/src/nvim/main.c b/src/nvim/main.c index d0be382c81..a266e59f27 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -795,7 +795,7 @@ void getout(int exitval) bufref_T bufref; set_bufref(&bufref, buf); - apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, false, buf); + apply_autocmds_win(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, false, buf, wp); if (bufref_valid(&bufref)) { buf_set_changedtick(buf, -1); // note that we did it already } diff --git a/src/nvim/message.c b/src/nvim/message.c index 7b2a238769..6a690ac1ef 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1184,7 +1184,7 @@ void do_autocmd_progress(MsgID msg_id, HlMessage msg, MessageData *msg_data) apply_autocmds_group(EVENT_PROGRESS, (msg_data && msg_data->source.size > 0) ? msg_data->source.data : "", NULL, true, - AUGROUP_ALL, NULL, NULL, &DICT_OBJ(data), false); + AUGROUP_ALL, NULL, curwin, NULL, &DICT_OBJ(data), false); kv_destroy(messages); } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 3724bde076..20289322ce 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -280,7 +280,7 @@ static void emit_termrequest(void **argv) VTERM_TERMINATOR_BEL ? STATIC_CSTR_AS_OBJ("\x07") : STATIC_CSTR_AS_OBJ("\x1b\\")); term->refcount++; - apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, true, AUGROUP_ALL, buf, NULL, + apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, true, AUGROUP_ALL, buf, curwin, NULL, &DICT_OBJ(data), false); term->refcount--; xfree(sequence); @@ -744,7 +744,7 @@ void terminal_close(Terminal **termpp, int status) PUT_C(data, "pos", INTEGER_OBJ(pos)); apply_autocmds_group(EVENT_TERMCLOSE, NULL, NULL, status >= 0, AUGROUP_ALL, - buf, NULL, &DICT_OBJ(data), false); + buf, curwin, NULL, &DICT_OBJ(data), false); restore_v_event(dict, &save_v_event); } diff --git a/src/nvim/window.c b/src/nvim/window.c index 9287c2fbae..fc95f0f82c 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3119,7 +3119,7 @@ static void do_autocmd_winclosed(win_T *win) recursive = true; char winid[NUMBUFLEN]; vim_snprintf(winid, sizeof(winid), "%d", win->handle); - apply_autocmds(EVENT_WINCLOSED, winid, winid, false, win->w_buffer); + apply_autocmds_win(EVENT_WINCLOSED, winid, winid, false, win->w_buffer, win); recursive = false; } @@ -6084,17 +6084,21 @@ void may_trigger_win_scrolled_resized(void) // Save window info before autocmds since they can free windows char resize_winid[NUMBUFLEN]; + win_T *resize_win = NULL; bufref_T resize_bufref; if (trigger_resize) { - vim_snprintf(resize_winid, sizeof(resize_winid), "%d", first_size_win->handle); - set_bufref(&resize_bufref, first_size_win->w_buffer); + resize_win = first_size_win; + vim_snprintf(resize_winid, sizeof(resize_winid), "%d", resize_win->handle); + set_bufref(&resize_bufref, resize_win->w_buffer); } char scroll_winid[NUMBUFLEN]; + win_T *scroll_win = NULL; bufref_T scroll_bufref; if (trigger_scroll) { - vim_snprintf(scroll_winid, sizeof(scroll_winid), "%d", first_scroll_win->handle); - set_bufref(&scroll_bufref, first_scroll_win->w_buffer); + scroll_win = first_scroll_win; + vim_snprintf(scroll_winid, sizeof(scroll_winid), "%d", scroll_win->handle); + set_bufref(&scroll_bufref, scroll_win->w_buffer); } // If both are to be triggered do WinResized first. @@ -6105,7 +6109,9 @@ void may_trigger_win_scrolled_resized(void) if (tv_dict_add_list(v_event, S_LEN("windows"), windows_list) == OK) { tv_dict_set_keys_readonly(v_event); buf_T *buf = bufref_valid(&resize_bufref) ? resize_bufref.br_buf : curbuf; - apply_autocmds(EVENT_WINRESIZED, resize_winid, resize_winid, false, buf); + // May have been freed by an earlier autocmd. + win_T *win = win_valid_any_tab(resize_win) ? resize_win : curwin; + apply_autocmds_win(EVENT_WINRESIZED, resize_winid, resize_winid, false, buf, win); } restore_v_event(v_event, &save_v_event); } @@ -6120,7 +6126,9 @@ void may_trigger_win_scrolled_resized(void) tv_dict_unref(scroll_dict); buf_T *buf = bufref_valid(&scroll_bufref) ? scroll_bufref.br_buf : curbuf; - apply_autocmds(EVENT_WINSCROLLED, scroll_winid, scroll_winid, false, buf); + // May have been freed by the WinResized autocmds above. + win_T *win = win_valid_any_tab(scroll_win) ? scroll_win : curwin; + apply_autocmds_win(EVENT_WINSCROLLED, scroll_winid, scroll_winid, false, buf, win); restore_v_event(v_event, &save_v_event); } diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index a4588dd314..049ac4f55d 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -370,6 +370,7 @@ describe('autocmd api', function() event = event, match = amatch, file = exec_pat, + win = api.nvim_get_current_win(), buf = 1, }, api.nvim_get_var('autocmd_args')) @@ -392,6 +393,7 @@ describe('autocmd api', function() event = event, match = amatch, file = exec_pat, + win = api.nvim_get_current_win(), buf = 1, }, api.nvim_get_var('autocmd_args')) end @@ -406,6 +408,134 @@ describe('autocmd api', function() end) end) + describe('ev.win #25844', function() + it('is the current window for events that are not about a window', function() + local win = api.nvim_get_current_win() + exec_lua(function() + vim.api.nvim_create_autocmd('BufAdd', { + callback = function(ev) + vim.g.ev_win = ev.win + end, + }) + end) + command('badd some_file') + eq(win, api.nvim_get_var('ev_win')) + end) + + it('WinClosed reports the closed window', function() + command('split') + local closed_win = api.nvim_get_current_win() + exec_lua(function() + vim.api.nvim_create_autocmd('WinClosed', { + callback = function(ev) + vim.g.ev_win = ev.win + vim.g.ev_match = ev.match + end, + }) + end) + command('quit') + eq(closed_win, api.nvim_get_var('ev_win')) + eq(tostring(closed_win), api.nvim_get_var('ev_match')) + end) + + it('WinNew reports the new window, not the focused one', function() + local origin_win = api.nvim_get_current_win() + local buf = api.nvim_create_buf(false, true) + exec_lua(function() + vim.api.nvim_create_autocmd('WinNew', { + callback = function(ev) + vim.g.ev_win = ev.win + end, + }) + end) + local new_win = api.nvim_open_win(buf, false, { + relative = 'editor', + row = 0, + col = 0, + width = 10, + height = 5, + }) + eq(origin_win, api.nvim_get_current_win()) + eq(new_win, api.nvim_get_var('ev_win')) + end) + + it('WinResized reports the resized window, not curwin', function() + local top_win = api.nvim_get_current_win() + command('botright split') + local bot_win = api.nvim_get_current_win() + neq(top_win, bot_win) + command('redraw') -- flush the WinResized caused by the split itself + exec_lua(function() + vim.api.nvim_create_autocmd('WinResized', { + callback = function(ev) + vim.g.ev_win = ev.win + vim.g.ev_match = ev.match + vim.g.ev_curwin = vim.api.nvim_get_current_win() + end, + }) + end) + command('resize 3') + command('redraw') + -- ev.win is the first window whose size changed, matching . + eq(top_win, api.nvim_get_var('ev_win')) + eq(tostring(top_win), api.nvim_get_var('ev_match')) + eq(bot_win, api.nvim_get_var('ev_curwin')) + end) + + it('WinScrolled reports the scrolled window, not curwin', function() + command('split') + local scrolled = api.nvim_get_current_win() + exec_lua(function() + local lines = {} + for i = 1, 30 do + lines[i] = 'line ' .. i + end + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + end) + command('wincmd w') + neq(scrolled, api.nvim_get_current_win()) + command('redraw') + exec_lua(function(scroll_win) + vim.api.nvim_create_autocmd('WinScrolled', { + callback = function(ev) + vim.g.ev_win = ev.win + vim.g.ev_match = ev.match + vim.g.ev_curwin = vim.api.nvim_get_current_win() + end, + }) + vim.api.nvim_win_call(scroll_win, function() + vim.cmd('normal! G') + end) + end, scrolled) + command('redraw') + eq(scrolled, api.nvim_get_var('ev_win')) + eq(tostring(scrolled), api.nvim_get_var('ev_match')) + neq(scrolled, api.nvim_get_var('ev_curwin')) + end) + + it('is restored after a nested autocmd', function() + command('edit a') + command('rightbelow vsplit b') + command('wincmd w') + local trigger_win = api.nvim_get_current_win() + exec_lua(function() + -- Fires BufLeave/WinLeave/WinEnter/BufEnter, each with its own ev.win. + vim.api.nvim_create_autocmd('ColorScheme', { + callback = function() + vim.cmd('wincmd w') + end, + }) + vim.api.nvim_create_autocmd('ColorScheme', { + callback = function(ev) + vim.g.ev_win = ev.win + end, + }) + end) + command('colorscheme blue') + eq(trigger_win, api.nvim_get_var('ev_win')) + end) + end) + it('can receive arbitrary data', function() local function test(data) eq(