mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
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 <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
8603270293
commit
5bf6c2117f
+4
-4
@@ -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;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+4
-4
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
231,
|
||||
/**/
|
||||
230,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user