mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
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
5bf6c2117f
This commit is contained in:
parent
e005b8d2eb
commit
b08667d4f0
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user