fix(filetype): avoid recursive FileType autocmds (#22813)

This commit is contained in:
Lewis Russell
2023-03-29 19:54:12 +01:00
committed by GitHub
parent 92005db760
commit 8b7fb668e4
3 changed files with 42 additions and 36 deletions

View File

@@ -111,15 +111,15 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err)
// Set curwin/curbuf to buf and save a few things.
aucmd_prepbuf(aco, ftbuf);
set_option_value("bufhidden", 0L, "hide", OPT_LOCAL);
set_option_value("buftype", 0L, "nofile", OPT_LOCAL);
set_option_value("swapfile", 0L, NULL, OPT_LOCAL);
set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline'
ftbuf->b_p_ft = xstrdup(filetype);
TRY_WRAP(err, {
apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf);
set_option_value("bufhidden", 0L, "hide", OPT_LOCAL);
set_option_value("buftype", 0L, "nofile", OPT_LOCAL);
set_option_value("swapfile", 0L, NULL, OPT_LOCAL);
set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline'
ftbuf->b_p_ft = xstrdup(filetype);
do_filetype_autocmd(ftbuf, false);
});
return ftbuf;

View File

@@ -2758,3 +2758,32 @@ void do_autocmd_focusgained(bool gained)
recursive = false;
}
void do_filetype_autocmd(buf_T *buf, bool force)
{
static bool recursive = false;
if (recursive && !force) {
return; // disallow recursion
}
char **varp = &buf->b_p_ft;
int secure_save = secure;
// Reset the secure flag, since the value of 'filetype' has
// been checked to be safe.
secure = 0;
recursive = true;
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, buf);
recursive = false;
// Just in case the old "buf" is now invalid
if (varp != &(buf->b_p_ft)) {
varp = NULL;
}
secure = secure_save;
}

View File

@@ -1529,34 +1529,6 @@ static void do_syntax_autocmd(buf_T *buf, bool value_changed)
syn_recursive--;
}
static void do_filetype_autocmd(buf_T *buf, char **varp, int opt_flags, bool value_changed)
{
// 'filetype' is set, trigger the FileType autocommand
// Skip this when called from a modeline and the filetype was
// already set to this value.
if (!(opt_flags & OPT_MODELINE) || value_changed) {
static int ft_recursive = 0;
int secure_save = secure;
// Reset the secure flag, since the value of 'filetype' has
// been checked to be safe.
secure = 0;
ft_recursive++;
did_filetype = true;
// Only pass true for "force" when the value changed or not
// used recursively, to avoid endless recurrence.
apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname,
value_changed || ft_recursive == 1, buf);
ft_recursive--;
// Just in case the old "buf" is now invalid
if (varp != &(buf->b_p_ft)) {
varp = NULL;
}
secure = secure_save;
}
}
static void do_spelllang_source(win_T *win)
{
char fname[200];
@@ -1884,7 +1856,12 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char
if (varp == &buf->b_p_syn) {
do_syntax_autocmd(buf, value_changed);
} else if (varp == &buf->b_p_ft) {
do_filetype_autocmd(buf, varp, opt_flags, value_changed);
// 'filetype' is set, trigger the FileType autocommand
// Skip this when called from a modeline
// Force autocmd when the filetype was changed
if (!(opt_flags & OPT_MODELINE) || value_changed) {
do_filetype_autocmd(buf, value_changed);
}
} else if (varp == &win->w_s->b_p_spl) {
do_spelllang_source(win);
}