# HG changeset patch # User Christian Brabandt # Date 1711903505 -7200 # Node ID 159d598e67810cabddef08b34bd454554071eb00 # Parent 60194371609ead1f0d7734d446d276c3c2903280 patch 9.1.0231: Filetype may be undetected when SwapExists sets ft in other buf Commit: https://github.com/vim/vim/commit/5bf6c2117fcef85fcf046c098dd3eb72a0147859 Author: zeertzjq Date: Sun Mar 31 18:41:27 2024 +0200 patch 9.1.0231: Filetype may be undetected when SwapExists sets ft in other buf Problem: Filetype may be undetected when a SwapExists autocommand sets filetype in another buffer. Solution: Make filetype detection state buffer-specific. Also fix a similar problem for 'modified' (zeertzjq). closes: #14344 Signed-off-by: zeertzjq Signed-off-by: Christian Brabandt diff --git a/src/autocmd.c b/src/autocmd.c --- a/src/autocmd.c +++ b/src/autocmd.c @@ -2258,7 +2258,7 @@ apply_autocmds_group( saveRedobuff(&save_redo); did_save_redobuff = TRUE; } - did_filetype = keep_filetype; + curbuf->b_did_filetype = curbuf->b_keep_filetype; } /* @@ -2270,7 +2270,7 @@ apply_autocmds_group( // Remember that FileType was triggered. Used for did_filetype(). if (event == EVENT_FILETYPE) - did_filetype = TRUE; + curbuf->b_did_filetype = TRUE; tail = gettail(fname); @@ -2379,7 +2379,7 @@ apply_autocmds_group( restore_search_patterns(); if (did_save_redobuff) restoreRedobuff(&save_redo); - did_filetype = FALSE; + curbuf->b_did_filetype = FALSE; while (au_pending_free_buf != NULL) { buf_T *b = au_pending_free_buf->b_next; @@ -2421,7 +2421,7 @@ BYPASS_AU: aubuflocal_remove(buf); if (retval == OK && event == EVENT_FILETYPE) - au_did_filetype = TRUE; + curbuf->b_au_did_filetype = TRUE; return retval; } diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -225,7 +225,7 @@ open_buffer( // The autocommands in readfile() may change the buffer, but only AFTER // reading the file. set_bufref(&old_curbuf, curbuf); - modified_was_set = FALSE; + curbuf->b_modified_was_set = FALSE; // mark cursor position as being invalid curwin->w_valid = 0; @@ -322,7 +322,7 @@ open_buffer( // the changed flag. Unless in readonly mode: "ls | gview -". // When interrupted and 'cpoptions' contains 'i' set changed flag. if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL) - || modified_was_set // ":set modified" used in autocmd + || curbuf->b_modified_was_set // autocmd did ":set modified" #ifdef FEAT_EVAL || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL) #endif @@ -1944,7 +1944,7 @@ enter_buffer(buf_T *buf) // ":ball" used in an autocommand. If there already is a filetype we // might prefer to keep it. if (*curbuf->b_p_ft == NUL) - did_filetype = FALSE; + curbuf->b_did_filetype = FALSE; open_buffer(FALSE, NULL, 0); } diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -3920,7 +3920,7 @@ f_deepcopy(typval_T *argvars, typval_T * static void f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { - rettv->vval.v_number = did_filetype; + rettv->vval.v_number = curbuf->b_did_filetype; } /* diff --git a/src/ex_cmds.c b/src/ex_cmds.c --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -2961,7 +2961,7 @@ do_ecmd( // Since we are starting to edit a file, consider the filetype to be // unset. Helps for when an autocommand changes files and expects syntax // highlighting to work in the other file. - did_filetype = FALSE; + curbuf->b_did_filetype = FALSE; /* * other_file oldbuf diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -9898,7 +9898,7 @@ ex_filetype(exarg_T *eap) static void ex_setfiletype(exarg_T *eap) { - if (did_filetype) + if (curbuf->b_did_filetype) return; char_u *arg = eap->arg; @@ -9907,7 +9907,7 @@ ex_setfiletype(exarg_T *eap) set_option_value_give_err((char_u *)"filetype", 0L, arg, OPT_LOCAL); if (arg != eap->arg) - did_filetype = FALSE; + curbuf->b_did_filetype = FALSE; } static void diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -225,7 +225,7 @@ readfile( int may_need_lseek = FALSE; #endif - au_did_filetype = FALSE; // reset before triggering any autocommands + curbuf->b_au_did_filetype = FALSE; // reset before triggering any autocommands curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read @@ -2696,7 +2696,7 @@ failed: { apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname, FALSE, curbuf, eap); - if (!au_did_filetype && *curbuf->b_p_ft != NUL) + if (!curbuf->b_au_did_filetype && *curbuf->b_p_ft != NUL) /* * EVENT_FILETYPE was not triggered but the buffer already has a * filetype. Trigger EVENT_FILETYPE using the existing filetype. @@ -4492,7 +4492,7 @@ buf_reload(buf_T *buf, int orig_mode, in int old_msg_silent = msg_silent; curbuf->b_flags |= BF_CHECK_RO; // check for RO again - keep_filetype = TRUE; // don't detect 'filetype' + curbuf->b_keep_filetype = TRUE; // don't detect 'filetype' if (shortmess(SHM_FILEINFO)) msg_silent = 1; @@ -4549,7 +4549,7 @@ buf_reload(buf_T *buf, int orig_mode, in curwin->w_cursor = old_cursor; check_cursor(); update_topline(); - keep_filetype = FALSE; + curbuf->b_keep_filetype = FALSE; #ifdef FEAT_FOLDING { win_T *wp; diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -796,20 +796,6 @@ EXTERN int autocmd_no_enter INIT(= FALSE EXTERN int autocmd_no_leave INIT(= FALSE); // Buf/WinLeave autocmds disabled EXTERN int tabpage_move_disallowed INIT(= FALSE); // moving tabpages around disallowed -EXTERN int modified_was_set; // did ":set modified" -EXTERN int did_filetype INIT(= FALSE); // FileType event found -EXTERN int keep_filetype INIT(= FALSE); // value for did_filetype when - // starting to execute - // autocommands - -// Set by the apply_autocmds_group function if the given event is equal to -// EVENT_FILETYPE. Used by the readfile function in order to determine if -// EVENT_BUFREADPOST triggered the EVENT_FILETYPE. -// -// Relying on this value requires one to reset it prior calling -// apply_autocmds_group. -EXTERN int au_did_filetype INIT(= FALSE); - // When deleting the current buffer, another one must be loaded. If we know // which one is preferred, au_new_curbuf is set to it EXTERN bufref_T au_new_curbuf INIT3(NULL, 0, 0); diff --git a/src/option.c b/src/option.c --- a/src/option.c +++ b/src/option.c @@ -3678,7 +3678,7 @@ did_set_modified(optset_T *args) if (!args->os_newval.boolean) save_file_ff(curbuf); // Buffer is unchanged redraw_titles(); - modified_was_set = args->os_newval.boolean; + curbuf->b_modified_was_set = args->os_newval.boolean; return NULL; } diff --git a/src/optionstr.c b/src/optionstr.c --- a/src/optionstr.c +++ b/src/optionstr.c @@ -4332,7 +4332,7 @@ do_filetype_autocmd(char_u **varp, int o secure = 0; ++ft_recursive; - did_filetype = TRUE; + curbuf->b_did_filetype = TRUE; // Only pass TRUE for "force" when the value changed or not // used recursively, to avoid endless recurrence. apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, diff --git a/src/quickfix.c b/src/quickfix.c --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4964,12 +4964,12 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *bu 0L, (char_u *)"qf", OPT_LOCAL); curbuf->b_p_ma = FALSE; - keep_filetype = TRUE; // don't detect 'filetype' + curbuf->b_keep_filetype = TRUE; // don't detect 'filetype' apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, FALSE, curbuf); apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, FALSE, curbuf); - keep_filetype = FALSE; + curbuf->b_keep_filetype = FALSE; --curbuf_lock; // make sure it will be redrawn diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -3133,6 +3133,19 @@ struct file_buffer int b_marks_read; // Have we read viminfo marks yet? #endif + int b_modified_was_set; // did ":set modified" + int b_did_filetype; // FileType event found + int b_keep_filetype; // value for did_filetype when starting + // to execute autocommands + + // Set by the apply_autocmds_group function if the given event is equal to + // EVENT_FILETYPE. Used by the readfile function in order to determine if + // EVENT_BUFREADPOST triggered the EVENT_FILETYPE. + // + // Relying on this value requires one to reset it prior calling + // apply_autocmds_group(). + int b_au_did_filetype; + /* * The following only used in undo.c. */ diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -4550,4 +4550,81 @@ func Test_Changed_ChangedI_2() call delete('XTextChangedI3') endfunc +" Test that filetype detection still works when SwapExists autocommand sets +" filetype in another buffer. +func Test_SwapExists_set_other_buf_filetype() + let lines =<< trim END + set nocompatible directory=. + filetype on + + let g:buf = bufnr() + new + + func SwapExists() + let v:swapchoice = 'o' + call setbufvar(g:buf, '&filetype', 'text') + endfunc + + func SafeState() + edit