diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-04-01 06:12:11 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-01 06:12:11 +0800 |
commit | b08667d4f00e434eac9874e4005ab8e1fd9d3e95 (patch) | |
tree | bf4b40e983294fbf96bdd6b9699cdb6526dd0fe6 | |
parent | e005b8d2eb0d5967d46cae604e3fac0ccae37555 (diff) | |
download | rneovim-b08667d4f00e434eac9874e4005ab8e1fd9d3e95.tar.gz rneovim-b08667d4f00e434eac9874e4005ab8e1fd9d3e95.tar.bz2 rneovim-b08667d4f00e434eac9874e4005ab8e1fd9d3e95.zip |
vim-patch:9.1.0231: Filetype may be undetected when SwapExists sets ft in other buf (#28136)
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: vim/vim#14344
https://github.com/vim/vim/commit/5bf6c2117fcef85fcf046c098dd3eb72a0147859
-rw-r--r-- | src/nvim/autocmd.c | 10 | ||||
-rw-r--r-- | src/nvim/autocmd.h | 11 | ||||
-rw-r--r-- | src/nvim/buffer.c | 6 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 13 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 4 | ||||
-rw-r--r-- | src/nvim/fileio.c | 8 | ||||
-rw-r--r-- | src/nvim/globals.h | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 2 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 4 | ||||
-rw-r--r-- | test/old/testdir/test_autocmd.vim | 77 |
12 files changed, 109 insertions, 32 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 00cfef23c7..c2cc8bd9b8 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1750,7 +1750,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force saveRedobuff(&save_redo); did_save_redobuff = true; } - did_filetype = keep_filetype; + curbuf->b_did_filetype = curbuf->b_keep_filetype; } // Note that we are applying autocmds. Some commands need to know. @@ -1760,7 +1760,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force // Remember that FileType was triggered. Used for did_filetype(). if (event == EVENT_FILETYPE) { - did_filetype = true; + curbuf->b_did_filetype = true; } char *tail = path_tail(fname); @@ -1864,7 +1864,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force 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; @@ -1901,7 +1901,7 @@ BYPASS_AU: } if (retval == OK && event == EVENT_FILETYPE) { - au_did_filetype = true; + curbuf->b_au_did_filetype = true; } return retval; @@ -2645,7 +2645,7 @@ void do_filetype_autocmd(buf_T *buf, bool force) secure = 0; ft_recursive++; - did_filetype = true; + buf->b_did_filetype = true; // Only pass true for "force" when it is true or // used recursively, to avoid endless recurrence. apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, force || ft_recursive == 1, buf); diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h index 8019cb7145..b298fbb6a1 100644 --- a/src/nvim/autocmd.h +++ b/src/nvim/autocmd.h @@ -15,14 +15,6 @@ #include "nvim/pos_defs.h" #include "nvim/types_defs.h" -// 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 bool au_did_filetype INIT( = false); - /// For CursorMoved event EXTERN win_T *last_cursormoved_win INIT( = NULL); /// For CursorMoved event, only used when last_cursormoved_win == curwin @@ -31,9 +23,6 @@ EXTERN pos_T last_cursormoved INIT( = { 0, 0, 0 }); EXTERN bool autocmd_busy INIT( = false); ///< Is apply_autocmds() busy? EXTERN int autocmd_no_enter INIT( = false); ///< Buf/WinEnter autocmds disabled EXTERN int autocmd_no_leave INIT( = false); ///< Buf/WinLeave autocmds disabled -EXTERN bool did_filetype INIT( = false); ///< FileType event found -/// value for did_filetype when starting to execute autocommands -EXTERN bool keep_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. diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 3c2d52e6ad..39d0d24d47 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -267,7 +267,7 @@ int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) // 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; @@ -350,7 +350,7 @@ int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) // the changed flag. Unless in readonly mode: "ls | nvim -R -". // 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" || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) { changed(curbuf); } else if (retval != FAIL && !read_stdin && !read_fifo) { @@ -1725,7 +1725,7 @@ void 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/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 7f7300706c..083508fe86 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -461,6 +461,19 @@ struct file_buffer { bool b_marks_read; // Have we read ShaDa marks yet? + bool b_modified_was_set; ///< did ":set modified" + bool b_did_filetype; ///< FileType event found + bool 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(). + bool b_au_did_filetype; + // The following only used in undo.c. u_header_T *b_u_oldhead; // pointer to oldest header u_header_T *b_u_newhead; // pointer to newest header; may not be valid diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 99da15ddd7..d3fe2c7e33 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1361,7 +1361,7 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, EvalFuncData fp /// "did_filetype()" function static void f_did_filetype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - rettv->vval.v_number = did_filetype; + rettv->vval.v_number = curbuf->b_did_filetype; } /// "diff_filler()" function diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index dd30cdbba4..6c997b9500 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2466,7 +2466,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // 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 // false false re-edit same file, buffer is re-used diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index ee738d9e92..318d2e4ff2 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7382,7 +7382,7 @@ void filetype_maybe_enable(void) /// ":setfiletype [FALLBACK] {name}" static void ex_setfiletype(exarg_T *eap) { - if (did_filetype) { + if (curbuf->b_did_filetype) { return; } @@ -7393,7 +7393,7 @@ static void ex_setfiletype(exarg_T *eap) set_option_value_give_err(kOptFiletype, CSTR_AS_OPTVAL(arg), OPT_LOCAL); if (arg != eap->arg) { - did_filetype = false; + curbuf->b_did_filetype = false; } } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 6b50b031a3..df9c4928c9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -234,7 +234,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, int using_b_fname; static char *msg_is_a_directory = N_("is a directory"); - 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 @@ -1854,7 +1854,7 @@ failed: } else if (newfile || (read_buffer && sfname != NULL)) { 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. apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, true, curbuf); @@ -3151,7 +3151,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) if (saved == OK) { 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 (readfile(buf->b_ffname, buf->b_fname, 0, 0, (linenr_T)MAXLNUM, &ea, flags, shortmess(SHM_FILEINFO)) != OK) { if (!aborting()) { @@ -3199,7 +3199,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) curwin->w_cursor = old_cursor; check_cursor(curwin); update_topline(curwin); - keep_filetype = false; + curbuf->b_keep_filetype = false; // Update folds unless they are defined manually. FOR_ALL_TAB_WINDOWS(tp, wp) { diff --git a/src/nvim/globals.h b/src/nvim/globals.h index bb9aca38b7..83fef1fe75 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -341,8 +341,6 @@ EXTERN bool did_check_timestamps INIT( = false); // did check timestamps // recently EXTERN int no_check_timestamps INIT( = 0); // Don't check timestamps -EXTERN int modified_was_set; // did ":set modified" - // Mouse coordinates, set by handle_mouse_event() EXTERN int mouse_grid; EXTERN int mouse_row; diff --git a/src/nvim/option.c b/src/nvim/option.c index 2c7922908c..799513e018 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2244,7 +2244,7 @@ static const char *did_set_modified(optset_T *args) save_file_ff(buf); // Buffer is unchanged } redraw_titles(); - modified_was_set = (int)args->os_newval.boolean; + buf->b_modified_was_set = (int)args->os_newval.boolean; return NULL; } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 9f431556e8..94e176bd94 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4274,10 +4274,10 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q set_option_value_give_err(kOptFiletype, STATIC_CSTR_AS_OPTVAL("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, "quickfix", NULL, false, curbuf); apply_autocmds(EVENT_BUFWINENTER, "quickfix", NULL, false, curbuf); - keep_filetype = false; + curbuf->b_keep_filetype = false; curbuf->b_ro_locked--; // make sure it will be redrawn diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 9dbd4ac521..61de6775fb 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -3977,4 +3977,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 |