To: vim_dev@googlegroups.com Subject: Patch 9.0.0965 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0965 Problem: Using one window for executing autocommands is insufficient. Solution: Use up to five windows for executing autocommands. Files: src/globals.h, src/structs.h, src/autocmd.c, src/proto/autocmd.pro, src/main.c, src/eval.c, src/evalwindow.c, src/ex_docmd.c, src/screen.c, src/terminal.c, src/window.c, src/buffer.c, src/bufwrite.c, src/channel.c, src/diff.c, src/evalbuffer.c, src/evalvars.c, src/ex_cmds2.c, src/fileio.c, src/if_ruby.c, src/os_unix.c, src/os_win32.c, src/quickfix.c, src/term.c, src/if_perl.xs, src/if_py_both.h, src/testdir/test_autocmd.vim *** ../vim-9.0.0964/src/globals.h 2022-11-26 19:16:44.186717893 +0000 --- src/globals.h 2022-11-28 17:23:59.229580371 +0000 *************** *** 977,984 **** EXTERN win_T *curwin; // currently active window ! EXTERN win_T *aucmd_win; // window used in aucmd_prepbuf() ! EXTERN int aucmd_win_used INIT(= FALSE); // aucmd_win is being used #ifdef FEAT_PROP_POPUP EXTERN win_T *first_popupwin; // first global popup window --- 977,994 ---- EXTERN win_T *curwin; // currently active window ! // When executing autocommands for a buffer that is not in any window, a ! // special window is created to handle the side effects. When autocommands ! // nest we may need more than one. Allow for up to five, if more are needed ! // something crazy is happening. ! #define AUCMD_WIN_COUNT 5 ! ! typedef struct { ! win_T *auc_win; // window used in aucmd_prepbuf() ! int auc_win_used; // this auc_win is being used ! } aucmdwin_T; ! ! EXTERN aucmdwin_T aucmd_win[AUCMD_WIN_COUNT]; #ifdef FEAT_PROP_POPUP EXTERN win_T *first_popupwin; // first global popup window *** ../vim-9.0.0964/src/structs.h 2022-11-25 16:31:46.964606667 +0000 --- src/structs.h 2022-11-28 17:36:48.730226363 +0000 *************** *** 4160,4166 **** typedef struct { buf_T *save_curbuf; // saved curbuf ! int use_aucmd_win; // using aucmd_win int save_curwin_id; // ID of saved curwin int new_curwin_id; // ID of new curwin int save_prevwin_id; // ID of saved prevwin --- 4160,4166 ---- typedef struct { buf_T *save_curbuf; // saved curbuf ! int use_aucmd_win_idx; // index in aucmd_win[] if >= 0 int save_curwin_id; // ID of saved curwin int new_curwin_id; // ID of new curwin int save_prevwin_id; // ID of saved prevwin *** ../vim-9.0.0964/src/autocmd.c 2022-11-22 12:40:44.062427876 +0000 --- src/autocmd.c 2022-11-28 18:01:55.253554954 +0000 *************** *** 629,656 **** } } #if defined(EXITFREE) || defined(PROTO) void free_all_autocmds(void) { - int i; char_u *s; for (current_augroup = -1; current_augroup < augroups.ga_len; ++current_augroup) do_autocmd(NULL, (char_u *)"", TRUE); ! for (i = 0; i < augroups.ga_len; ++i) { s = ((char_u **)(augroups.ga_data))[i]; if (s != get_deleted_augroup()) vim_free(s); } ga_clear(&augroups); } #endif /* * Return the event number for event name "start". * Return NUM_EVENTS if the event name was not found. * Return a pointer to the next event name in "end". --- 629,680 ---- } } + void + autocmd_init(void) + { + CLEAR_FIELD(aucmd_win); + } + #if defined(EXITFREE) || defined(PROTO) void free_all_autocmds(void) { char_u *s; for (current_augroup = -1; current_augroup < augroups.ga_len; ++current_augroup) do_autocmd(NULL, (char_u *)"", TRUE); ! for (int i = 0; i < augroups.ga_len; ++i) { s = ((char_u **)(augroups.ga_data))[i]; if (s != get_deleted_augroup()) vim_free(s); } ga_clear(&augroups); + + for (int i = 0; i < AUCMD_WIN_COUNT; ++i) + if (aucmd_win[i].auc_win_used) + { + aucmd_win[i].auc_win_used = FALSE; + win_remove(aucmd_win[i].auc_win, NULL); + } } #endif /* + * Return TRUE if "win" is an active entry in aucmd_win[]. + */ + int + is_aucmd_win(win_T *win) + { + for (int i = 0; i < AUCMD_WIN_COUNT; ++i) + if (aucmd_win[i].auc_win_used && aucmd_win[i].auc_win == win) + return TRUE; + return FALSE; + } + + /* * Return the event number for event name "start". * Return NUM_EVENTS if the event name was not found. * Return a pointer to the next event name in "end". *************** *** 1438,1445 **** if (buf->b_ml.ml_mfp == NULL || buf == curbuf) continue; ! // find a window for this buffer and save some values aucmd_prepbuf(&aco, buf); set_bufref(&bufref, buf); // execute the autocommands for this buffer --- 1462,1477 ---- if (buf->b_ml.ml_mfp == NULL || buf == curbuf) continue; ! // Find a window for this buffer and save some values. aucmd_prepbuf(&aco, buf); + if (curbuf != buf) + { + // Failed to find a window for this buffer. Better not execute + // autocommands then. + retval = FAIL; + break; + } + set_bufref(&bufref, buf); // execute the autocommands for this buffer *************** *** 1449,1455 **** // Execute the modeline settings, but don't set window-local // options if we are using the current window for another // buffer. ! do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0); // restore the current window aucmd_restbuf(&aco); --- 1481,1487 ---- // Execute the modeline settings, but don't set window-local // options if we are using the current window for another // buffer. ! do_modelines(is_aucmd_win(curwin) ? OPT_NOWIN : 0); // restore the current window aucmd_restbuf(&aco); *************** *** 1490,1497 **** /* * Prepare for executing autocommands for (hidden) buffer "buf". * Search for a visible window containing the current buffer. If there isn't ! * one then use "aucmd_win". * Set "curbuf" and "curwin" to match "buf". */ void aucmd_prepbuf( --- 1522,1530 ---- /* * Prepare for executing autocommands for (hidden) buffer "buf". * Search for a visible window containing the current buffer. If there isn't ! * one then use an entry in "aucmd_win[]". * Set "curbuf" and "curwin" to match "buf". + * When this fails "curbuf" is not equal "buf". */ void aucmd_prepbuf( *************** *** 1512,1529 **** if (win->w_buffer == buf) break; ! // Allocate "aucmd_win" when needed. If this fails (out of memory) fall ! // back to using the current window. ! if (win == NULL && aucmd_win == NULL) ! { ! aucmd_win = win_alloc_popup_win(); ! if (aucmd_win == NULL) ! win = curwin; ! } ! if (win == NULL && aucmd_win_used) ! // Strange recursive autocommand, fall back to using the current ! // window. Expect a few side effects... ! win = curwin; aco->save_curwin_id = curwin->w_id; aco->save_curbuf = curbuf; --- 1545,1573 ---- if (win->w_buffer == buf) break; ! // Allocate a window when needed. ! win_T *auc_win = NULL; ! int auc_idx = AUCMD_WIN_COUNT; ! if (win == NULL) ! { ! for (auc_idx = 0; auc_idx < AUCMD_WIN_COUNT; ++auc_idx) ! if (!aucmd_win[auc_idx].auc_win_used) ! { ! auc_win = win_alloc_popup_win(); ! if (auc_win != NULL) ! { ! aucmd_win[auc_idx].auc_win = auc_win; ! aucmd_win[auc_idx].auc_win_used = TRUE; ! } ! break; ! } ! ! // If this fails (out of memory or using all AUCMD_WIN_COUNT ! // entries) then we can't reliable execute the autocmd, return with ! // "curbuf" unequal "buf". ! if (auc_win == NULL) ! return; ! } aco->save_curwin_id = curwin->w_id; aco->save_curbuf = curbuf; *************** *** 1533,1556 **** // There is a window for "buf" in the current tab page, make it the // curwin. This is preferred, it has the least side effects (esp. if // "buf" is curbuf). ! aco->use_aucmd_win = FALSE; curwin = win; } else { ! // There is no window for "buf", use "aucmd_win". To minimize the side // effects, insert it in the current tab page. // Anything related to a window (e.g., setting folds) may have // unexpected results. ! aco->use_aucmd_win = TRUE; ! aucmd_win_used = TRUE; ! win_init_popup_win(aucmd_win, buf); aco->globaldir = globaldir; globaldir = NULL; ! // Split the current window, put the aucmd_win in the upper half. // We don't want the BufEnter or WinEnter autocommands. block_autocmds(); make_snapshot(SNAP_AUCMD_IDX); --- 1577,1599 ---- // There is a window for "buf" in the current tab page, make it the // curwin. This is preferred, it has the least side effects (esp. if // "buf" is curbuf). ! aco->use_aucmd_win_idx = -1; curwin = win; } else { ! // There is no window for "buf", use "auc_win". To minimize the side // effects, insert it in the current tab page. // Anything related to a window (e.g., setting folds) may have // unexpected results. ! aco->use_aucmd_win_idx = auc_idx; ! win_init_popup_win(auc_win, buf); aco->globaldir = globaldir; globaldir = NULL; ! // Split the current window, put the auc_win in the upper half. // We don't want the BufEnter or WinEnter autocommands. block_autocmds(); make_snapshot(SNAP_AUCMD_IDX); *************** *** 1565,1571 **** // no redrawing and don't set the window title ++RedrawingDisabled; ! (void)win_split_ins(0, WSP_TOP, aucmd_win, 0); --RedrawingDisabled; (void)win_comp_pos(); // recompute window positions p_ea = save_ea; --- 1608,1614 ---- // no redrawing and don't set the window title ++RedrawingDisabled; ! (void)win_split_ins(0, WSP_TOP, auc_win, 0); --RedrawingDisabled; (void)win_comp_pos(); // recompute window positions p_ea = save_ea; *************** *** 1573,1579 **** p_acd = save_acd; #endif unblock_autocmds(); ! curwin = aucmd_win; } curbuf = buf; aco->new_curwin_id = curwin->w_id; --- 1616,1622 ---- p_acd = save_acd; #endif unblock_autocmds(); ! curwin = auc_win; } curbuf = buf; aco->new_curwin_id = curwin->w_id; *************** *** 1595,1618 **** int dummy; win_T *save_curwin; ! if (aco->use_aucmd_win) { --curbuf->b_nwindows; ! // Find "aucmd_win", it can't be closed, but it may be in another tab // page. Do not trigger autocommands here. block_autocmds(); ! if (curwin != aucmd_win) { tabpage_T *tp; win_T *wp; FOR_ALL_TAB_WINDOWS(tp, wp) { ! if (wp == aucmd_win) { if (tp != curtab) goto_tabpage_tp(tp, TRUE, TRUE); ! win_goto(aucmd_win); goto win_found; } } --- 1638,1663 ---- int dummy; win_T *save_curwin; ! if (aco->use_aucmd_win_idx >= 0) { + win_T *awp = aucmd_win[aco->use_aucmd_win_idx].auc_win; + --curbuf->b_nwindows; ! // Find "awp", it can't be closed, but it may be in another tab // page. Do not trigger autocommands here. block_autocmds(); ! if (curwin != awp) { tabpage_T *tp; win_T *wp; FOR_ALL_TAB_WINDOWS(tp, wp) { ! if (wp == awp) { if (tp != curtab) goto_tabpage_tp(tp, TRUE, TRUE); ! win_goto(awp); goto win_found; } } *************** *** 1622,1628 **** // Remove the window and frame from the tree of frames. (void)winframe_remove(curwin, &dummy, NULL); win_remove(curwin, NULL); ! aucmd_win_used = FALSE; last_status(FALSE); // may need to remove last status line if (!valid_tabpage_win(curtab)) --- 1667,1673 ---- // Remove the window and frame from the tree of frames. (void)winframe_remove(curwin, &dummy, NULL); win_remove(curwin, NULL); ! aucmd_win[aco->use_aucmd_win_idx].auc_win_used = FALSE; last_status(FALSE); // may need to remove last status line if (!valid_tabpage_win(curtab)) *************** *** 1646,1653 **** #endif prevwin = win_find_by_id(aco->save_prevwin_id); #ifdef FEAT_EVAL ! vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables ! hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab #endif vim_free(globaldir); globaldir = aco->globaldir; --- 1691,1698 ---- #endif prevwin = win_find_by_id(aco->save_prevwin_id); #ifdef FEAT_EVAL ! vars_clear(&awp->w_vars->dv_hashtab); // free all w: variables ! hash_init(&awp->w_vars->dv_hashtab); // re-use the hashtab #endif vim_free(globaldir); globaldir = aco->globaldir; *************** *** 1664,1674 **** #if defined(FEAT_GUI) if (gui.in_use) { ! // Hide the scrollbars from the aucmd_win and update. ! gui_mch_enable_scrollbar( ! &aucmd_win->w_scrollbars[SBAR_LEFT], FALSE); ! gui_mch_enable_scrollbar( ! &aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE); gui_may_update_scrollbars(); } #endif --- 1709,1717 ---- #if defined(FEAT_GUI) if (gui.in_use) { ! // Hide the scrollbars from the "awp" and update. ! gui_mch_enable_scrollbar(&awp->w_scrollbars[SBAR_LEFT], FALSE); ! gui_mch_enable_scrollbar(&awp->w_scrollbars[SBAR_RIGHT], FALSE); gui_may_update_scrollbars(); } #endif *** ../vim-9.0.0964/src/proto/autocmd.pro 2022-11-22 12:40:44.062427876 +0000 --- src/proto/autocmd.pro 2022-11-28 17:47:53.893838235 +0000 *************** *** 2,8 **** --- 2,10 ---- void aubuflocal_remove(buf_T *buf); int au_has_group(char_u *name); void do_augroup(char_u *arg, int del_group); + void autocmd_init(void); void free_all_autocmds(void); + int is_aucmd_win(win_T *win); int check_ei(void); char_u *au_event_disable(char *what); void au_event_restore(char_u *old_ei); *** ../vim-9.0.0964/src/main.c 2022-11-24 00:08:58.461010529 +0000 --- src/main.c 2022-11-28 17:12:18.551941151 +0000 *************** *** 123,128 **** --- 123,130 ---- #endif params.window_count = -1; + autocmd_init(); + #ifdef FEAT_RUBY { int ruby_stack_start; *** ../vim-9.0.0964/src/eval.c 2022-11-18 22:14:04.798988157 +0000 --- src/eval.c 2022-11-28 17:39:42.506319536 +0000 *************** *** 5084,5092 **** FOR_ALL_TAB_WINDOWS(tp, wp) abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID, NULL, NULL); ! if (aucmd_win != NULL) ! abort = abort || set_ref_in_item(&aucmd_win->w_winvar.di_tv, copyID, ! NULL, NULL); #ifdef FEAT_PROP_POPUP FOR_ALL_POPUPWINS(wp) abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID, --- 5084,5093 ---- FOR_ALL_TAB_WINDOWS(tp, wp) abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID, NULL, NULL); ! for (int i = 0; i < AUCMD_WIN_COUNT; ++i) ! if (aucmd_win[i].auc_win_used) ! abort = abort || set_ref_in_item( ! &aucmd_win[i].auc_win->w_winvar.di_tv, copyID, NULL, NULL); #ifdef FEAT_PROP_POPUP FOR_ALL_POPUPWINS(wp) abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID, *** ../vim-9.0.0964/src/evalwindow.c 2022-11-18 22:14:04.798988157 +0000 --- src/evalwindow.c 2022-11-28 17:40:20.758338784 +0000 *************** *** 1064,1070 **** return; } } ! if (wp == aucmd_win) rettv->vval.v_string = vim_strsave((char_u *)"autocmd"); #if defined(FEAT_QUICKFIX) else if (wp->w_p_pvw) --- 1064,1070 ---- return; } } ! if (is_aucmd_win(wp)) rettv->vval.v_string = vim_strsave((char_u *)"autocmd"); #if defined(FEAT_QUICKFIX) else if (wp->w_p_pvw) *** ../vim-9.0.0964/src/ex_docmd.c 2022-11-19 13:14:05.737367072 +0000 --- src/ex_docmd.c 2022-11-28 17:40:46.126326544 +0000 *************** *** 6050,6056 **** buf_T *buf = win->w_buffer; // Never close the autocommand window. ! if (win == aucmd_win) { emsg(_(e_cannot_close_autocmd_or_popup_window)); return; --- 6050,6056 ---- buf_T *buf = win->w_buffer; // Never close the autocommand window. ! if (is_aucmd_win(win)) { emsg(_(e_cannot_close_autocmd_or_popup_window)); return; *** ../vim-9.0.0964/src/screen.c 2022-11-24 00:08:58.465010528 +0000 --- src/screen.c 2022-11-28 17:54:21.485646564 +0000 *************** *** 2369,2375 **** u8char_T *new_ScreenLinesUC = NULL; u8char_T *new_ScreenLinesC[MAX_MCO]; schar_T *new_ScreenLines2 = NULL; - int i; sattr_T *new_ScreenAttrs; colnr_T *new_ScreenCols; unsigned *new_LineOffset; --- 2369,2374 ---- *************** *** 2438,2445 **** */ FOR_ALL_TAB_WINDOWS(tp, wp) win_free_lsize(wp); ! if (aucmd_win != NULL) ! win_free_lsize(aucmd_win); #ifdef FEAT_PROP_POPUP // global popup windows FOR_ALL_POPUPWINS(wp) --- 2437,2445 ---- */ FOR_ALL_TAB_WINDOWS(tp, wp) win_free_lsize(wp); ! for (int i = 0; i < AUCMD_WIN_COUNT; ++i) ! if (aucmd_win[i].auc_win_used) ! win_free_lsize(aucmd_win[i].auc_win); #ifdef FEAT_PROP_POPUP // global popup windows FOR_ALL_POPUPWINS(wp) *************** *** 2455,2461 **** if (enc_utf8) { new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns); ! for (i = 0; i < p_mco; ++i) new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T, (Rows + 1) * Columns); } --- 2455,2461 ---- if (enc_utf8) { new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns); ! for (int i = 0; i < p_mco; ++i) new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T, (Rows + 1) * Columns); } *************** *** 2482,2490 **** goto give_up; } } ! if (aucmd_win != NULL && aucmd_win->w_lines == NULL ! && win_alloc_lines(aucmd_win) == FAIL) ! outofmem = TRUE; #ifdef FEAT_PROP_POPUP // global popup windows FOR_ALL_POPUPWINS(wp) --- 2482,2495 ---- goto give_up; } } ! for (int i = 0; i < AUCMD_WIN_COUNT; ++i) ! if (aucmd_win[i].auc_win_used ! && aucmd_win[i].auc_win->w_lines == NULL ! && win_alloc_lines(aucmd_win[i].auc_win) == FAIL) ! { ! outofmem = TRUE; ! break; ! } #ifdef FEAT_PROP_POPUP // global popup windows FOR_ALL_POPUPWINS(wp) *************** *** 2505,2515 **** give_up: ! for (i = 0; i < p_mco; ++i) if (new_ScreenLinesC[i] == NULL) break; if (new_ScreenLines == NULL ! || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco)) || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL) || new_ScreenAttrs == NULL || new_ScreenCols == NULL --- 2510,2524 ---- give_up: ! int found_null = FALSE; ! for (int i = 0; i < p_mco; ++i) if (new_ScreenLinesC[i] == NULL) + { + found_null = TRUE; break; + } if (new_ScreenLines == NULL ! || (enc_utf8 && (new_ScreenLinesUC == NULL || found_null)) || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL) || new_ScreenAttrs == NULL || new_ScreenCols == NULL *************** *** 2534,2540 **** } VIM_CLEAR(new_ScreenLines); VIM_CLEAR(new_ScreenLinesUC); ! for (i = 0; i < p_mco; ++i) VIM_CLEAR(new_ScreenLinesC[i]); VIM_CLEAR(new_ScreenLines2); VIM_CLEAR(new_ScreenAttrs); --- 2543,2549 ---- } VIM_CLEAR(new_ScreenLines); VIM_CLEAR(new_ScreenLinesUC); ! for (int i = 0; i < p_mco; ++i) VIM_CLEAR(new_ScreenLinesC[i]); VIM_CLEAR(new_ScreenLines2); VIM_CLEAR(new_ScreenAttrs); *************** *** 2571,2577 **** { (void)vim_memset(new_ScreenLinesUC + new_row * Columns, 0, (size_t)Columns * sizeof(u8char_T)); ! for (i = 0; i < p_mco; ++i) (void)vim_memset(new_ScreenLinesC[i] + new_row * Columns, 0, (size_t)Columns * sizeof(u8char_T)); --- 2580,2586 ---- { (void)vim_memset(new_ScreenLinesUC + new_row * Columns, 0, (size_t)Columns * sizeof(u8char_T)); ! for (int i = 0; i < p_mco; ++i) (void)vim_memset(new_ScreenLinesC[i] + new_row * Columns, 0, (size_t)Columns * sizeof(u8char_T)); *************** *** 2603,2609 **** mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row], ScreenLinesUC + LineOffset[old_row], (size_t)len * sizeof(u8char_T)); ! for (i = 0; i < p_mco; ++i) mch_memmove(new_ScreenLinesC[i] + new_LineOffset[new_row], ScreenLinesC[i] + LineOffset[old_row], --- 2612,2618 ---- mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row], ScreenLinesUC + LineOffset[old_row], (size_t)len * sizeof(u8char_T)); ! for (int i = 0; i < p_mco; ++i) mch_memmove(new_ScreenLinesC[i] + new_LineOffset[new_row], ScreenLinesC[i] + LineOffset[old_row], *************** *** 2636,2642 **** // NOTE: this may result in all pointers to become NULL. ScreenLines = new_ScreenLines; ScreenLinesUC = new_ScreenLinesUC; ! for (i = 0; i < p_mco; ++i) ScreenLinesC[i] = new_ScreenLinesC[i]; Screen_mco = p_mco; ScreenLines2 = new_ScreenLines2; --- 2645,2651 ---- // NOTE: this may result in all pointers to become NULL. ScreenLines = new_ScreenLines; ScreenLinesUC = new_ScreenLinesUC; ! for (int i = 0; i < p_mco; ++i) ScreenLinesC[i] = new_ScreenLinesC[i]; Screen_mco = p_mco; ScreenLines2 = new_ScreenLines2; *** ../vim-9.0.0964/src/terminal.c 2022-11-25 16:31:46.968606662 +0000 --- src/terminal.c 2022-11-28 18:29:37.183398477 +0000 *************** *** 3560,3574 **** // ++close or term_finish == "close" ch_log(NULL, "terminal job finished, closing window"); aucmd_prepbuf(&aco, term->tl_buffer); ! // Avoid closing the window if we temporarily use it. ! if (curwin == aucmd_win) ! do_set_w_closing = TRUE; ! if (do_set_w_closing) ! curwin->w_closing = TRUE; ! do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE); ! if (do_set_w_closing) ! curwin->w_closing = FALSE; ! aucmd_restbuf(&aco); #ifdef FEAT_PROP_POPUP if (pwin != NULL) popup_close_with_retval(pwin, 0); --- 3560,3577 ---- // ++close or term_finish == "close" ch_log(NULL, "terminal job finished, closing window"); aucmd_prepbuf(&aco, term->tl_buffer); ! if (curbuf == term->tl_buffer) ! { ! // Avoid closing the window if we temporarily use it. ! if (is_aucmd_win(curwin)) ! do_set_w_closing = TRUE; ! if (do_set_w_closing) ! curwin->w_closing = TRUE; ! do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE); ! if (do_set_w_closing) ! curwin->w_closing = FALSE; ! aucmd_restbuf(&aco); ! } #ifdef FEAT_PROP_POPUP if (pwin != NULL) popup_close_with_retval(pwin, 0); *** ../vim-9.0.0964/src/window.c 2022-11-28 16:49:18.442868485 +0000 --- src/window.c 2022-11-28 17:47:21.633862191 +0000 *************** *** 1362,1368 **** win_equal(wp, TRUE, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : dir == 'h' ? 'b' : 'v'); ! else if (*p_spk != 'c' && wp != aucmd_win) win_fix_scroll(FALSE); // Don't change the window height/width to 'winheight' / 'winwidth' if a --- 1362,1368 ---- win_equal(wp, TRUE, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : dir == 'h' ? 'b' : 'v'); ! else if (*p_spk != 'c' && !is_aucmd_win(wp)) win_fix_scroll(FALSE); // Don't change the window height/width to 'winheight' / 'winwidth' if a *************** *** 1962,1968 **** win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current, topframe, dir, 0, tabline_height(), (int)Columns, topframe->fr_height); ! if (*p_spk != 'c' && next_curwin != aucmd_win) win_fix_scroll(TRUE); } --- 1962,1968 ---- win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current, topframe, dir, 0, tabline_height(), (int)Columns, topframe->fr_height); ! if (*p_spk != 'c' && !is_aucmd_win(next_curwin)) win_fix_scroll(TRUE); } *************** *** 2426,2432 **** /* * Return TRUE if the current window is the only window that exists (ignoring ! * "aucmd_win"). * Returns FALSE if there is a window, possibly in another tab page. */ static int --- 2426,2432 ---- /* * Return TRUE if the current window is the only window that exists (ignoring ! * "aucmd_win[]"). * Returns FALSE if there is a window, possibly in another tab page. */ static int *************** *** 2436,2442 **** } /* ! * Return TRUE if there is only one window other than "aucmd_win" in the * current tab page. */ int --- 2436,2442 ---- } /* ! * Return TRUE if there is only one window other than "aucmd_win[]" in the * current tab page. */ int *************** *** 2447,2453 **** FOR_ALL_WINDOWS(wp) { ! if (wp != aucmd_win) { if (seen_one) return FALSE; --- 2447,2453 ---- FOR_ALL_WINDOWS(wp) { ! if (!is_aucmd_win(wp)) { if (seen_one) return FALSE; *************** *** 2588,2594 **** emsg(_(e_cannot_close_autocmd_or_popup_window)); return FAIL; } ! if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window()) { emsg(_(e_cannot_close_window_only_autocmd_window_would_remain)); return FAIL; --- 2588,2594 ---- emsg(_(e_cannot_close_autocmd_or_popup_window)); return FAIL; } ! if ((is_aucmd_win(firstwin) || is_aucmd_win(lastwin)) && one_window()) { emsg(_(e_cannot_close_window_only_autocmd_window_would_remain)); return FAIL; *************** *** 3292,3302 **** while (first_tabpage->tp_next != NULL) tabpage_close(TRUE); ! if (aucmd_win != NULL) ! { ! (void)win_free_mem(aucmd_win, &dummy, NULL); ! aucmd_win = NULL; ! } while (firstwin != NULL) (void)win_free_mem(firstwin, &dummy, NULL); --- 3292,3303 ---- while (first_tabpage->tp_next != NULL) tabpage_close(TRUE); ! for (int i = 0; i < AUCMD_WIN_COUNT; ++i) ! if (aucmd_win[i].auc_win_used) ! { ! (void)win_free_mem(aucmd_win[i].auc_win, &dummy, NULL); ! aucmd_win[i].auc_win_used = FALSE; ! } while (firstwin != NULL) (void)win_free_mem(firstwin, &dummy, NULL); *************** *** 5663,5669 **** int win_unlisted(win_T *wp) { ! return wp == aucmd_win || WIN_IS_POPUP(wp); } #if defined(FEAT_PROP_POPUP) || defined(PROTO) --- 5664,5670 ---- int win_unlisted(win_T *wp) { ! return is_aucmd_win(wp) || WIN_IS_POPUP(wp); } #if defined(FEAT_PROP_POPUP) || defined(PROTO) *************** *** 7257,7263 **** # ifdef FEAT_QUICKFIX || wp->w_p_pvw # endif ! ) || wp == curwin) && wp != aucmd_win) ++count; return (count <= 1); } --- 7258,7264 ---- # ifdef FEAT_QUICKFIX || wp->w_p_pvw # endif ! ) || wp == curwin) && !is_aucmd_win(wp)) ++count; return (count <= 1); } *** ../vim-9.0.0964/src/buffer.c 2022-11-25 16:31:46.964606667 +0000 --- src/buffer.c 2022-11-28 18:07:18.013530353 +0000 *************** *** 150,160 **** { aco_save_T aco; aucmd_prepbuf(&aco, buf); ! if (swap_exists_action != SEA_READONLY) ! swap_exists_action = SEA_NONE; ! open_buffer(FALSE, NULL, 0); ! aucmd_restbuf(&aco); } } #endif --- 150,164 ---- { aco_save_T aco; + // Make sure the buffer is in a window. If not then skip it. aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) ! { ! if (swap_exists_action != SEA_READONLY) ! swap_exists_action = SEA_NONE; ! open_buffer(FALSE, NULL, 0); ! aucmd_restbuf(&aco); ! } } } #endif *************** *** 361,381 **** { aco_save_T aco; ! // Go to the buffer that was opened. aucmd_prepbuf(&aco, old_curbuf.br_buf); ! do_modelines(0); ! curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED); ! if ((flags & READ_NOWINENTER) == 0) #ifdef FEAT_EVAL ! apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, ! curbuf, &retval); #else ! apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf); #endif ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); } } --- 365,390 ---- { aco_save_T aco; ! // Go to the buffer that was opened, make sure it is in a window. ! // If not then skip it. aucmd_prepbuf(&aco, old_curbuf.br_buf); ! if (curbuf == old_curbuf.br_buf) ! { ! do_modelines(0); ! curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED); ! if ((flags & READ_NOWINENTER) == 0) #ifdef FEAT_EVAL ! apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, ! FALSE, curbuf, &retval); #else ! apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, ! FALSE, curbuf); #endif ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! } } } *************** *** 5942,5949 **** return TRUE; } ! // set curwin/curbuf to buf and save a few things aucmd_prepbuf(&aco, newbuf); if (ml_open(curbuf) == OK && readfile(buf->b_ffname, buf->b_fname, --- 5951,5964 ---- return TRUE; } ! // Set curwin/curbuf to buf and save a few things. aucmd_prepbuf(&aco, newbuf); + if (curbuf != newbuf) + { + // Failed to find a window for "newbuf". + wipe_buffer(newbuf, FALSE); + return TRUE; + } if (ml_open(curbuf) == OK && readfile(buf->b_ffname, buf->b_fname, *** ../vim-9.0.0964/src/bufwrite.c 2022-11-02 13:30:37.526314510 +0000 --- src/bufwrite.c 2022-11-28 18:12:05.305522374 +0000 *************** *** 802,809 **** if (fname == buf->b_sfname) buf_fname_s = TRUE; ! // set curwin/curbuf to buf and save a few things aucmd_prepbuf(&aco, buf); set_bufref(&bufref, buf); if (append) --- 802,816 ---- if (fname == buf->b_sfname) buf_fname_s = TRUE; ! // Set curwin/curbuf to buf and save a few things. aucmd_prepbuf(&aco, buf); + if (curbuf != buf) + { + // Could not find a window for "buf". Doing more might cause + // problems, better bail out. + return FAIL; + } + set_bufref(&bufref, buf); if (append) *************** *** 2592,2614 **** // Apply POST autocommands. // Careful: The autocommands may call buf_write() recursively! aucmd_prepbuf(&aco, buf); ! if (append) ! apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, ! FALSE, curbuf, eap); ! else if (filtering) ! apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, ! FALSE, curbuf, eap); ! else if (reset_changed && whole) ! apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, ! FALSE, curbuf, eap); ! else ! apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, ! FALSE, curbuf, eap); ! ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); #ifdef FEAT_EVAL if (aborting()) // autocmds may abort script processing --- 2599,2624 ---- // Apply POST autocommands. // Careful: The autocommands may call buf_write() recursively! + // Only do this when a window was found for "buf". aucmd_prepbuf(&aco, buf); + if (curbuf == buf) + { + if (append) + apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, + FALSE, curbuf, eap); + else if (filtering) + apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, + FALSE, curbuf, eap); + else if (reset_changed && whole) + apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, + FALSE, curbuf, eap); + else + apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, + FALSE, curbuf, eap); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! } #ifdef FEAT_EVAL if (aborting()) // autocmds may abort script processing *** ../vim-9.0.0964/src/channel.c 2022-10-16 21:43:03.386665520 +0100 --- src/channel.c 2022-11-28 18:13:21.517521630 +0000 *************** *** 2872,2879 **** buffer->b_p_ma = TRUE; ! // set curbuf to be our buf, temporarily aucmd_prepbuf(&aco, buffer); u_sync(TRUE); // ignore undo failure, undo is not very useful here --- 2872,2885 ---- buffer->b_p_ma = TRUE; ! // Set curbuf to "buffer", temporarily. aucmd_prepbuf(&aco, buffer); + if (curbuf != buffer) + { + // Could not find a window for this buffer, the following might cause + // trouble, better bail out. + return; + } u_sync(TRUE); // ignore undo failure, undo is not very useful here *** ../vim-9.0.0964/src/diff.c 2022-08-14 14:16:07.983582313 +0100 --- src/diff.c 2022-11-28 18:14:44.625513782 +0000 *************** *** 2786,2793 **** idx_to = idx_other; // Need to make the other buffer the current buffer to be able to make // changes in it. ! // set curwin/curbuf to buf and save a few things aucmd_prepbuf(&aco, curtab->tp_diffbuf[idx_other]); } // May give the warning for a changed buffer here, which can trigger the --- 2786,2797 ---- idx_to = idx_other; // Need to make the other buffer the current buffer to be able to make // changes in it. ! // Set curwin/curbuf to buf and save a few things. aucmd_prepbuf(&aco, curtab->tp_diffbuf[idx_other]); + if (curbuf != curtab->tp_diffbuf[idx_other]) + // Could not find a window for this buffer, the rest is likely to + // fail. + goto theend; } // May give the warning for a changed buffer here, which can trigger the *** ../vim-9.0.0964/src/evalbuffer.c 2022-11-27 19:45:45.706989832 +0000 --- src/evalbuffer.c 2022-11-28 18:18:26.628686202 +0000 *************** *** 136,141 **** --- 136,143 ---- * * Information is saved in "cob" and MUST be restored by calling * change_other_buffer_restore(). + * + * If this fails then "curbuf" will not be equal to "buf". */ static void change_other_buffer_prepare(cob_T *cob, buf_T *buf) *************** *** 156,162 **** // curwin->w_buffer differ from "curbuf", use the autocmd window. curbuf = curwin->w_buffer; aucmd_prepbuf(&cob->cob_aco, buf); ! cob->cob_using_aco = TRUE; } } --- 158,165 ---- // curwin->w_buffer differ from "curbuf", use the autocmd window. curbuf = curwin->w_buffer; aucmd_prepbuf(&cob->cob_aco, buf); ! if (curbuf == buf) ! cob->cob_using_aco = TRUE; } } *** ../vim-9.0.0964/src/evalvars.c 2022-11-25 16:31:46.964606667 +0000 --- src/evalvars.c 2022-11-28 18:19:23.640519052 +0000 *************** *** 4761,4773 **** { aco_save_T aco; ! // set curbuf to be our buf, temporarily aucmd_prepbuf(&aco, buf); ! set_option_from_tv(varname + 1, varp); ! ! // reset notion of buffer ! aucmd_restbuf(&aco); } else { --- 4761,4776 ---- { aco_save_T aco; ! // Set curbuf to be our buf, temporarily. aucmd_prepbuf(&aco, buf); + if (curbuf == buf) + { + // Only when it worked to set "curbuf". + set_option_from_tv(varname + 1, varp); ! // reset notion of buffer ! aucmd_restbuf(&aco); ! } } else { *** ../vim-9.0.0964/src/ex_cmds2.c 2022-10-09 18:53:29.024591198 +0100 --- src/ex_cmds2.c 2022-11-28 18:19:48.764450172 +0000 *************** *** 705,713 **** else { aucmd_prepbuf(&aco, buf); ! apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, TRUE, buf); ! aucmd_restbuf(&aco); } // start over, in case autocommands messed things up. --- 705,716 ---- else { aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) ! { ! apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, TRUE, buf); ! aucmd_restbuf(&aco); ! } } // start over, in case autocommands messed things up. *** ../vim-9.0.0964/src/fileio.c 2022-11-01 20:33:39.991400397 +0000 --- src/fileio.c 2022-11-28 18:20:53.384285260 +0000 *************** *** 4369,4376 **** int flags = READ_NEW; int prepped = OK; ! // set curwin/curbuf for "buf" and save some things aucmd_prepbuf(&aco, buf); // Unless reload_options is set, we only want to read the text from the // file, not reset the syntax highlighting, clear marks, diff status, etc. --- 4369,4382 ---- int flags = READ_NEW; int prepped = OK; ! // Set curwin/curbuf for "buf" and save some things. aucmd_prepbuf(&aco, buf); + if (curbuf != buf) + { + // Failed to find a window for "buf", it is dangerous to continue, + // better bail out. + return; + } // Unless reload_options is set, we only want to read the text from the // file, not reset the syntax highlighting, clear marks, diff status, etc. *** ../vim-9.0.0964/src/if_ruby.c 2022-11-25 16:31:46.968606662 +0000 --- src/if_ruby.c 2022-11-28 18:22:55.536015597 +0000 *************** *** 1371,1391 **** if (n > 0 && n <= buf->b_ml.ml_line_count && line != NULL) { ! // set curwin/curbuf for "buf" and save some things aucmd_prepbuf(&aco, buf); ! ! if (u_savesub(n) == OK) { ! ml_replace(n, (char_u *)line, TRUE); ! changed(); #ifdef SYNTAX_HL ! syn_changed(n); // recompute syntax hl. for this line #endif ! } ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! // Careful: autocommands may have made "buf" invalid! update_curbuf(UPD_NOT_VALID); } --- 1371,1394 ---- if (n > 0 && n <= buf->b_ml.ml_line_count && line != NULL) { ! // Set curwin/curbuf for "buf" and save some things. aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) { ! // Only when it worked to set "curbuf". ! if (u_savesub(n) == OK) ! { ! ml_replace(n, (char_u *)line, TRUE); ! changed(); #ifdef SYNTAX_HL ! syn_changed(n); // recompute syntax hl. for this line #endif ! } ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! // Careful: autocommands may have made "buf" invalid! ! } update_curbuf(UPD_NOT_VALID); } *************** *** 1415,1438 **** if (n > 0 && n <= buf->b_ml.ml_line_count) { ! // set curwin/curbuf for "buf" and save some things aucmd_prepbuf(&aco, buf); ! ! if (u_savedel(n, 1) == OK) { ! ml_delete(n); ! ! // Changes to non-active buffers should properly refresh ! // SegPhault - 01/09/05 ! deleted_lines_mark(n, 1L); ! ! changed(); } - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - // Careful: autocommands may have made "buf" invalid! - update_curbuf(UPD_NOT_VALID); } else --- 1418,1444 ---- if (n > 0 && n <= buf->b_ml.ml_line_count) { ! // Set curwin/curbuf for "buf" and save some things. aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) { ! // Only when it worked to set "curbuf". ! if (u_savedel(n, 1) == OK) ! { ! ml_delete(n); ! ! // Changes to non-active buffers should properly refresh ! // SegPhault - 01/09/05 ! deleted_lines_mark(n, 1L); ! ! changed(); ! } ! ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! // Careful: autocommands may have made "buf" invalid! } update_curbuf(UPD_NOT_VALID); } else *************** *** 1458,1479 **** { // set curwin/curbuf for "buf" and save some things aucmd_prepbuf(&aco, buf); ! ! if (u_inssub(n + 1) == OK) { ! ml_append(n, (char_u *) line, (colnr_T) 0, FALSE); ! ! // Changes to non-active buffers should properly refresh screen ! // SegPhault - 12/20/04 ! appended_lines_mark(n, 1L); ! ! changed(); } - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - // Careful: autocommands may have made "buf" invalid! - update_curbuf(UPD_NOT_VALID); } else --- 1464,1488 ---- { // set curwin/curbuf for "buf" and save some things aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) { ! // Only when it worked to set "curbuf". ! if (u_inssub(n + 1) == OK) ! { ! ml_append(n, (char_u *) line, (colnr_T) 0, FALSE); ! ! // Changes to non-active buffers should properly refresh screen ! // SegPhault - 12/20/04 ! appended_lines_mark(n, 1L); ! ! changed(); ! } ! ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! // Careful: autocommands may have made "buf" invalid! } update_curbuf(UPD_NOT_VALID); } else *** ../vim-9.0.0964/src/os_unix.c 2022-11-25 15:09:30.710402884 +0000 --- src/os_unix.c 2022-11-28 18:24:30.511837561 +0000 *************** *** 4490,4516 **** // Find a window to make "buf" curbuf. aucmd_prepbuf(&aco, buf); ! ! clear_oparg(&oa); ! while (term_use_loop()) { ! if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active) { ! // If terminal_loop() returns OK we got a key that is handled ! // in Normal model. We don't do redrawing anyway. ! if (terminal_loop(TRUE) == OK) normal_cmd(&oa, TRUE); } ! else ! normal_cmd(&oa, TRUE); ! } ! retval = job->jv_exitval; ! ch_log(NULL, "system command finished"); ! job_unref(job); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); // Only require pressing Enter when redrawing, to avoid that system() gets // the hit-enter prompt even though it didn't output anything. --- 4490,4519 ---- // Find a window to make "buf" curbuf. aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) { ! // Only when managed to find a window for "buf", ! clear_oparg(&oa); ! while (term_use_loop()) { ! if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active) ! { ! // If terminal_loop() returns OK we got a key that is handled ! // in Normal model. We don't do redrawing anyway. ! if (terminal_loop(TRUE) == OK) ! normal_cmd(&oa, TRUE); ! } ! else normal_cmd(&oa, TRUE); } ! retval = job->jv_exitval; ! ch_log(NULL, "system command finished"); ! job_unref(job); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! } // Only require pressing Enter when redrawing, to avoid that system() gets // the hit-enter prompt even though it didn't output anything. *** ../vim-9.0.0964/src/os_win32.c 2022-11-23 22:28:03.552026184 +0000 --- src/os_win32.c 2022-11-28 18:25:11.999767140 +0000 *************** *** 4878,4904 **** // Find a window to make "buf" curbuf. aucmd_prepbuf(&aco, buf); ! ! clear_oparg(&oa); ! while (term_use_loop()) { ! if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active) { ! // If terminal_loop() returns OK we got a key that is handled ! // in Normal model. We don't do redrawing anyway. ! if (terminal_loop(TRUE) == OK) normal_cmd(&oa, TRUE); } ! else ! normal_cmd(&oa, TRUE); ! } ! retval = job->jv_exitval; ! ch_log(NULL, "system command finished"); ! job_unref(job); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); wait_return(TRUE); do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE); --- 4878,4907 ---- // Find a window to make "buf" curbuf. aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) { ! // Only do this when a window was found for "buf". ! clear_oparg(&oa); ! while (term_use_loop()) { ! if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active) ! { ! // If terminal_loop() returns OK we got a key that is handled ! // in Normal model. We don't do redrawing anyway. ! if (terminal_loop(TRUE) == OK) ! normal_cmd(&oa, TRUE); ! } ! else normal_cmd(&oa, TRUE); } ! retval = job->jv_exitval; ! ch_log(NULL, "system command finished"); ! job_unref(job); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! } wait_return(TRUE); do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE); *** ../vim-9.0.0964/src/quickfix.c 2022-11-13 12:54:46.718898500 +0000 --- src/quickfix.c 2022-11-28 18:28:02.135516484 +0000 *************** *** 4598,4618 **** // autocommands may cause trouble incr_quickfix_busy(); if (old_last == NULL) // set curwin/curbuf to buf and save a few things aucmd_prepbuf(&aco, buf); ! qf_update_win_titlevar(qi); ! qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid); ! ++CHANGEDTICK(buf); ! if (old_last == NULL) ! { ! (void)qf_win_pos_update(qi, 0); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); } // Only redraw when added lines are visible. This avoids flickering --- 4598,4626 ---- // autocommands may cause trouble incr_quickfix_busy(); + int do_fill = TRUE; if (old_last == NULL) + { // set curwin/curbuf to buf and save a few things aucmd_prepbuf(&aco, buf); + if (curbuf != buf) + do_fill = FALSE; // failed to find a window for "buf" + } ! if (do_fill) ! { ! qf_update_win_titlevar(qi); ! qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid); ! ++CHANGEDTICK(buf); ! if (old_last == NULL) ! { ! (void)qf_win_pos_update(qi, 0); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! } } // Only redraw when added lines are visible. This avoids flickering *************** *** 6395,6406 **** // need to be done (again). But not the window-local // options! aucmd_prepbuf(&aco, buf); #if defined(FEAT_SYN_HL) ! apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, TRUE, buf); #endif ! do_modelines(OPT_NOWIN); ! aucmd_restbuf(&aco); } } } --- 6403,6417 ---- // need to be done (again). But not the window-local // options! aucmd_prepbuf(&aco, buf); + if (curbuf == buf) + { #if defined(FEAT_SYN_HL) ! apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, TRUE, buf); #endif ! do_modelines(OPT_NOWIN); ! aucmd_restbuf(&aco); ! } } } } *************** *** 6593,6632 **** // set curwin/curbuf to buf and save a few things aucmd_prepbuf(&aco, newbuf); ! // Need to set the filename for autocommands. ! (void)setfname(curbuf, fname, NULL, FALSE); ! ! // Create swap file now to avoid the ATTENTION message. ! check_need_swap(TRUE); ! // Remove the "dummy" flag, otherwise autocommands may not ! // work. ! curbuf->b_flags &= ~BF_DUMMY; ! ! newbuf_to_wipe.br_buf = NULL; ! readfile_result = readfile(fname, NULL, ! (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, ! NULL, READ_NEW | READ_DUMMY); ! --newbuf->b_locked; ! if (readfile_result == OK ! && !got_int ! && !(curbuf->b_flags & BF_NEW)) ! { ! failed = FALSE; ! if (curbuf != newbuf) { ! // Bloody autocommands changed the buffer! Can happen when ! // using netrw and editing a remote file. Use the current ! // buffer instead, delete the dummy one after restoring the ! // window stuff. ! set_bufref(&newbuf_to_wipe, newbuf); ! newbuf = curbuf; } } - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe)) wipe_buffer(newbuf_to_wipe.br_buf, FALSE); --- 6604,6646 ---- // set curwin/curbuf to buf and save a few things aucmd_prepbuf(&aco, newbuf); + if (curbuf == newbuf) + { + // Need to set the filename for autocommands. + (void)setfname(curbuf, fname, NULL, FALSE); ! // Create swap file now to avoid the ATTENTION message. ! check_need_swap(TRUE); ! // Remove the "dummy" flag, otherwise autocommands may not ! // work. ! curbuf->b_flags &= ~BF_DUMMY; ! ! newbuf_to_wipe.br_buf = NULL; ! readfile_result = readfile(fname, NULL, ! (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, ! NULL, READ_NEW | READ_DUMMY); ! --newbuf->b_locked; ! if (readfile_result == OK ! && !got_int ! && !(curbuf->b_flags & BF_NEW)) { ! failed = FALSE; ! if (curbuf != newbuf) ! { ! // Bloody autocommands changed the buffer! Can happen when ! // using netrw and editing a remote file. Use the current ! // buffer instead, delete the dummy one after restoring the ! // window stuff. ! set_bufref(&newbuf_to_wipe, newbuf); ! newbuf = curbuf; ! } } + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); } if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe)) wipe_buffer(newbuf_to_wipe.br_buf, FALSE); *** ../vim-9.0.0964/src/term.c 2022-11-26 19:16:44.186717893 +0000 --- src/term.c 2022-11-28 18:28:32.775476943 +0000 *************** *** 2232,2241 **** if (curbuf->b_ml.ml_mfp != NULL) { aucmd_prepbuf(&aco, buf); ! apply_autocmds(EVENT_TERMCHANGED, NULL, NULL, FALSE, curbuf); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); } } } --- 2232,2244 ---- if (curbuf->b_ml.ml_mfp != NULL) { aucmd_prepbuf(&aco, buf); ! if (curbuf == buf) ! { ! apply_autocmds(EVENT_TERMCHANGED, NULL, NULL, FALSE, curbuf); ! // restore curwin/curbuf and a few other things ! aucmd_restbuf(&aco); ! } } } } *** ../vim-9.0.0964/src/if_perl.xs 2022-11-14 15:31:04.041587447 +0000 --- src/if_perl.xs 2022-11-28 18:32:20.335223624 +0000 *************** *** 1869,1886 **** { aco_save_T aco; ! /* set curwin/curbuf for "vimbuf" and save some things */ aucmd_prepbuf(&aco, vimbuf); ! ! if (u_savesub(lnum) == OK) { ! ml_replace(lnum, (char_u *)line, TRUE); ! changed_bytes(lnum, 0); ! } ! /* restore curwin/curbuf and a few other things */ ! aucmd_restbuf(&aco); ! /* Careful: autocommands may have made "vimbuf" invalid! */ } } } --- 1869,1889 ---- { aco_save_T aco; ! /* Set curwin/curbuf for "vimbuf" and save some things. */ aucmd_prepbuf(&aco, vimbuf); ! if (curbuf == vimbuf) { ! /* Only when a window was found. */ ! if (u_savesub(lnum) == OK) ! { ! ml_replace(lnum, (char_u *)line, TRUE); ! changed_bytes(lnum, 0); ! } ! /* restore curwin/curbuf and a few other things */ ! aucmd_restbuf(&aco); ! /* Careful: autocommands may have made "vimbuf" invalid! */ ! } } } } *************** *** 1921,1938 **** /* set curwin/curbuf for "vimbuf" and save some things */ aucmd_prepbuf(&aco, vimbuf); ! ! if (u_savedel(lnum, 1) == OK) { ! ml_delete(lnum); ! check_cursor(); ! deleted_lines_mark(lnum, 1L); } - /* restore curwin/curbuf and a few other things */ - aucmd_restbuf(&aco); - /* Careful: autocommands may have made "vimbuf" invalid! */ - update_curbuf(UPD_VALID); } } --- 1924,1945 ---- /* set curwin/curbuf for "vimbuf" and save some things */ aucmd_prepbuf(&aco, vimbuf); ! if (curbuf == vimbuf) { ! /* Only when a window was found. */ ! if (u_savedel(lnum, 1) == OK) ! { ! ml_delete(lnum); ! check_cursor(); ! deleted_lines_mark(lnum, 1L); ! } ! ! /* restore curwin/curbuf and a few other things */ ! aucmd_restbuf(&aco); ! /* Careful: autocommands may have made "vimbuf" ! * invalid! */ } update_curbuf(UPD_VALID); } } *************** *** 1963,1978 **** /* set curwin/curbuf for "vimbuf" and save some things */ aucmd_prepbuf(&aco, vimbuf); ! ! if (u_inssub(lnum + 1) == OK) { ! ml_append(lnum, (char_u *)line, (colnr_T)0, FALSE); ! appended_lines_mark(lnum, 1L); ! } ! /* restore curwin/curbuf and a few other things */ ! aucmd_restbuf(&aco); ! /* Careful: autocommands may have made "vimbuf" invalid! */ update_curbuf(UPD_VALID); } --- 1970,1988 ---- /* set curwin/curbuf for "vimbuf" and save some things */ aucmd_prepbuf(&aco, vimbuf); ! if (curbuf == vimbuf) { ! /* Only when a window for "vimbuf" was found. */ ! if (u_inssub(lnum + 1) == OK) ! { ! ml_append(lnum, (char_u *)line, (colnr_T)0, FALSE); ! appended_lines_mark(lnum, 1L); ! } ! /* restore curwin/curbuf and a few other things */ ! aucmd_restbuf(&aco); ! /* Careful: autocommands may have made "vimbuf" invalid! */ ! } update_curbuf(UPD_VALID); } *** ../vim-9.0.0964/src/if_py_both.h 2022-11-25 16:31:46.968606662 +0000 --- src/if_py_both.h 2022-11-28 18:33:06.435179423 +0000 *************** *** 5283,5290 **** VimTryStart(); // Using aucmd_*: autocommands will be executed by rename_buffer aucmd_prepbuf(&aco, self->buf); ! ren_ret = rename_buffer(val); ! aucmd_restbuf(&aco); Py_XDECREF(todecref); if (VimTryEnd()) return -1; --- 5283,5293 ---- VimTryStart(); // Using aucmd_*: autocommands will be executed by rename_buffer aucmd_prepbuf(&aco, self->buf); ! if (curbuf == self->buf) ! { ! ren_ret = rename_buffer(val); ! aucmd_restbuf(&aco); ! } Py_XDECREF(todecref); if (VimTryEnd()) return -1; *** ../vim-9.0.0964/src/testdir/test_autocmd.vim 2022-11-25 16:31:46.972606656 +0000 --- src/testdir/test_autocmd.vim 2022-11-28 17:06:57.506202897 +0000 *************** *** 4068,4071 **** --- 4068,4094 ---- call delete('Xerr') endfunc + " This was crashing because there was only one window to execute autocommands + " in. + func Test_autocmd_nested_setbufvar() + CheckFeature python3 + + set hidden + edit Xaaa + edit Xbbb + call setline(1, 'bar') + enew + au BufWriteCmd Xbbb ++nested call setbufvar('Xaaa', '&ft', 'foo') | bw! Xaaa + au FileType foo call py3eval('vim.current.buffer.options["cindent"]') + wall + + au! BufWriteCmd + au! FileType foo + set nohidden + call delete('Xaaa') + call delete('Xbbb') + %bwipe! + endfunc + + " vim: shiftwidth=2 sts=2 expandtab *** ../vim-9.0.0964/src/version.c 2022-11-28 16:49:18.446868480 +0000 --- src/version.c 2022-11-28 17:03:08.590102217 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 965, /**/ -- Living in Hollywood is like living in a bowl of granola. What ain't fruits and nuts is flakes. /// 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 ///