To: vim_dev@googlegroups.com Subject: Patch 8.2.3591 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3591 Problem: No event is triggered when closing a window. Solution: Add the WinClosed event. (Naohiro Ono, closes #9110) Files: runtime/doc/autocmd.txt, src/autocmd.c, src/testdir/test_autocmd.vim, src/vim.h, src/window.c *** ../vim-8.2.3590/runtime/doc/autocmd.txt 2021-10-22 18:55:40.818752232 +0100 --- runtime/doc/autocmd.txt 2021-11-13 12:34:43.507586594 +0000 *************** *** 348,353 **** --- 348,354 ---- |WinNew| after creating a new window |TabNew| after creating a new tab page + |WinClosed| after closing a window |TabClosed| after closing a tab page |WinEnter| after entering another window |WinLeave| before leaving a window *************** *** 1276,1281 **** --- 1281,1292 ---- VimSuspend When the Vim instance is suspended. Only when CTRL-Z was typed inside Vim, not when the SIGSTOP or SIGTSTP signal was sent to Vim. + *WinClosed* + WinClosed After closing a window. The pattern is + matched against the |window-ID|. Both + and are set to the + |window-ID|. Non-recursive (event cannot + trigger itself). *WinEnter* WinEnter After entering another window. Not done for the first window, when Vim has just started. *** ../vim-8.2.3590/src/autocmd.c 2021-10-22 18:55:40.818752232 +0100 --- src/autocmd.c 2021-11-13 12:34:43.507586594 +0000 *************** *** 186,191 **** --- 186,192 ---- {"VimLeave", EVENT_VIMLEAVE}, {"VimLeavePre", EVENT_VIMLEAVEPRE}, {"WinNew", EVENT_WINNEW}, + {"WinClosed", EVENT_WINCLOSED}, {"WinEnter", EVENT_WINENTER}, {"WinLeave", EVENT_WINLEAVE}, {"VimResized", EVENT_VIMRESIZED}, *************** *** 2042,2048 **** || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST || event == EVENT_DIRCHANGED ! || event == EVENT_MODECHANGED) { fname = vim_strsave(fname); autocmd_fname_full = TRUE; // don't expand it later --- 2043,2050 ---- || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST || event == EVENT_DIRCHANGED ! || event == EVENT_MODECHANGED ! || event == EVENT_WINCLOSED) { fname = vim_strsave(fname); autocmd_fname_full = TRUE; // don't expand it later *** ../vim-8.2.3590/src/testdir/test_autocmd.vim 2021-10-21 10:50:36.636964245 +0100 --- src/testdir/test_autocmd.vim 2021-11-13 12:34:43.507586594 +0000 *************** *** 270,275 **** --- 270,276 ---- augroup testing au WinNew * call add(g:record, 'WinNew') + au WinClosed * call add(g:record, 'WinClosed') au WinEnter * call add(g:record, 'WinEnter') au WinLeave * call add(g:record, 'WinLeave') au TabNew * call add(g:record, 'TabNew') *************** *** 286,293 **** call assert_equal([ \ 'WinLeave', 'WinNew', 'WinEnter', \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', ! \ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter', ! \ 'WinLeave', 'WinEnter' \ ], g:record) let g:record = [] --- 287,294 ---- call assert_equal([ \ 'WinLeave', 'WinNew', 'WinEnter', \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', ! \ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter', ! \ 'WinLeave', 'WinClosed', 'WinEnter' \ ], g:record) let g:record = [] *************** *** 298,304 **** call assert_equal([ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', ! \ 'TabClosed' \ ], g:record) augroup testing --- 299,305 ---- call assert_equal([ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', ! \ 'WinClosed', 'TabClosed' \ ], g:record) augroup testing *************** *** 307,312 **** --- 308,352 ---- unlet g:record endfunc + func Test_WinClosed() + " Test that the pattern is matched against the closed window's ID, and both + " and are set to it. + new + let winid = win_getid() + let g:matched = v:false + augroup test-WinClosed + autocmd! + execute 'autocmd WinClosed' winid 'let g:matched = v:true' + autocmd WinClosed * let g:amatch = str2nr(expand('')) + autocmd WinClosed * let g:afile = str2nr(expand('')) + augroup END + close + call assert_true(g:matched) + call assert_equal(winid, g:amatch) + call assert_equal(winid, g:afile) + + " Test that WinClosed is non-recursive. + new + new + call assert_equal(3, winnr('$')) + let g:triggered = 0 + augroup test-WinClosed + autocmd! + autocmd WinClosed * let g:triggered += 1 + autocmd WinClosed * 2 wincmd c + augroup END + close + call assert_equal(1, winnr('$')) + call assert_equal(1, g:triggered) + + autocmd! test-WinClosed + augroup! test-WinClosed + unlet g:matched + unlet g:amatch + unlet g:afile + unlet g:triggered + endfunc + func s:AddAnAutocmd() augroup vimBarTest au BufReadCmd * echo 'hello' *** ../vim-8.2.3590/src/vim.h 2021-11-02 21:39:40.097064632 +0000 --- src/vim.h 2021-11-13 12:34:43.507586594 +0000 *************** *** 1379,1384 **** --- 1379,1385 ---- EVENT_WINENTER, // after entering a window EVENT_WINLEAVE, // before leaving a window EVENT_WINNEW, // when entering a new window + EVENT_WINCLOSED, // after closing a window EVENT_VIMSUSPEND, // before Vim is suspended EVENT_VIMRESUME, // after Vim is resumed *** ../vim-8.2.3590/src/window.c 2021-11-02 20:56:04.189640051 +0000 --- src/window.c 2021-11-13 12:34:43.511586582 +0000 *************** *** 19,24 **** --- 19,25 ---- static void win_rotate(int, int); static void win_totop(int size, int flags); static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height); + static void trigger_winclosed(win_T *win); static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp); static frame_T *win_altframe(win_T *win, tabpage_T *tp); static tabpage_T *alt_tabpage(void); *************** *** 2566,2571 **** --- 2567,2579 ---- if (popup_win_closed(win) && !win_valid(win)) return FAIL; #endif + + // Trigger WinClosed just before starting to free window-related resources. + trigger_winclosed(win); + // autocmd may have freed the window already. + if (!win_valid_any_tab(win)) + return OK; + win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, TRUE); if (only_one_window() && win_valid(win) && win->w_buffer == NULL *************** *** 2710,2715 **** --- 2718,2737 ---- return OK; } + static void + trigger_winclosed(win_T *win) + { + static int recursive = FALSE; + char_u winid[NUMBUFLEN]; + + if (recursive) + return; + recursive = TRUE; + vim_snprintf((char *)winid, sizeof(winid), "%i", win->w_id); + apply_autocmds(EVENT_WINCLOSED, winid, winid, FALSE, win->w_buffer); + recursive = FALSE; + } + /* * Close window "win" in tab page "tp", which is not the current tab page. * This may be the last window in that tab page and result in closing the tab, *************** *** 2731,2736 **** --- 2753,2764 ---- && win->w_buffer->b_locked > 0)) return; // window is already being closed + // Trigger WinClosed just before starting to free window-related resources. + trigger_winclosed(win); + // autocmd may have freed the window already. + if (!win_valid_any_tab(win)) + return; + if (win->w_buffer != NULL) // Close the link to the buffer. close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, *** ../vim-8.2.3590/src/version.c 2021-11-13 10:49:26.833952428 +0000 --- src/version.c 2021-11-13 12:36:17.439292966 +0000 *************** *** 759,760 **** --- 759,762 ---- { /* Add new patch number below this line */ + /**/ + 3591, /**/ -- Computers are not intelligent. They only think they are. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///