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 <zeert...@outlook.com>
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 <zeert...@outlook.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/autocmd.c b/src/autocmd.c
index 8a7e6072a..9632c74d4 100644
--- 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
index 243593a52..58e9718e3 100644
--- 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
index 8c27986b4..0e071d87b 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -3920,7 +3920,7 @@ f_deepcopy(typval_T *argvars, typval_T *rettv)
     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
index 864f89d43..2a5d842fc 100644
--- 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
index 981d270dc..cc42e52a5 100644
--- 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
index 53bfbeadf..07e05fc80 100644
--- 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, int reload_options)
            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, int reload_options)
        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
index f04f19dd2..29ad7edd4 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -796,20 +796,6 @@ EXTERN int autocmd_no_enter INIT(= FALSE); // Buf/WinEnter 
autocmds disabled
 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
index 8123a2a2c..c594301a9 100644
--- 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
index e5f4946b4..45f126ff6 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -4332,7 +4332,7 @@ do_filetype_autocmd(char_u **varp, int opt_flags, int 
value_changed)
     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
index 0bf4cfe6b..2e5b69373 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -4964,12 +4964,12 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T 
*old_last, int qf_winid)
                                                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
index 0d3f60acb..2218de703 100644
--- 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
index bf9087111..e69a3f60e 100644
--- 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 <script>
+      redir! > XftSwapExists.out
+        set readonly? filetype?
+      redir END
+      qall!
+    endfunc
+
+    autocmd SwapExists * ++nested call SwapExists()
+    autocmd SafeState * ++nested ++once call SafeState()
+  END
+  call writefile(lines, 'XftSwapExists.vim', 'D')
+
+  new XftSwapExists.vim
+  if RunVim('', '', ' -S XftSwapExists.vim')
+    call assert_equal(
+          \ ['', '  readonly', '  filetype=vim'],
+          \ readfile('XftSwapExists.out'))
+    call delete('XftSwapExists.out')
+  endif
+
+  bwipe!
+endfunc
+
+" Test that file is not marked as modified when SwapExists autocommand sets
+" 'modified' in another buffer.
+func Test_SwapExists_set_other_buf_modified()
+  let lines =<< trim END
+    set nocompatible directory=.
+
+    let g:buf = bufnr()
+    new
+
+    func SwapExists()
+      let v:swapchoice = 'o'
+      call setbufvar(g:buf, '&modified', 1)
+    endfunc
+
+    func SafeState()
+      edit <script>
+      redir! > XmodSwapExists.out
+        set readonly? modified?
+      redir END
+      qall!
+    endfunc
+
+    autocmd SwapExists * ++nested call SwapExists()
+    autocmd SafeState * ++nested ++once call SafeState()
+  END
+  call writefile(lines, 'XmodSwapExists.vim', 'D')
+
+  new XmodSwapExists.vim
+  if RunVim('', '', ' -S XmodSwapExists.vim')
+    call assert_equal(
+          \ ['', '  readonly', 'nomodified'],
+          \ readfile('XmodSwapExists.out'))
+    call delete('XmodSwapExists.out')
+  endif
+
+  bwipe!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index db942bc3a..e7187447c 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    231,
 /**/
     230,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1rqyIr-000IvF-Ca%40256bit.org.

Raspunde prin e-mail lui