mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.2.3609: internal error when ModeChanged is triggered recursively
Problem: Internal error when ModeChanged is triggered when v:event is
already in use.
Solution: Save and restore v:event if needed.
3075a45592
In the vim codebase there is no occurrence of get_vim_var_dict(VV_EVENT)
after the above patch, so in order to hold the same invariant in the
neovim codebase we needed to replace more occurrences than the related
vim patch.
This commit is contained in:
parent
fdfd1eda43
commit
1fb101afe4
@ -8,6 +8,7 @@
|
||||
#include "nvim/ex_getln.h"
|
||||
#include "nvim/fileio.h"
|
||||
#include "nvim/main.h"
|
||||
#include "nvim/misc1.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/vim.h"
|
||||
@ -25,13 +26,14 @@ void do_autocmd_uienter(uint64_t chanid, bool attached)
|
||||
}
|
||||
recursive = true;
|
||||
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
save_v_event_T save_v_event;
|
||||
dict_T *dict = get_v_event(&save_v_event);
|
||||
assert(chanid < VARNUMBER_MAX);
|
||||
tv_dict_add_nr(dict, S_LEN("chan"), (varnumber_T)chanid);
|
||||
tv_dict_set_keys_readonly(dict);
|
||||
apply_autocmds(attached ? EVENT_UIENTER : EVENT_UILEAVE,
|
||||
NULL, NULL, false, curbuf);
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
|
||||
recursive = false;
|
||||
}
|
||||
|
@ -1116,6 +1116,12 @@ typedef struct {
|
||||
pos_T w_cursor_corr; // corrected cursor position
|
||||
} pos_save_T;
|
||||
|
||||
// Struct passed to get_v_event() and restore_v_event().
|
||||
typedef struct {
|
||||
bool sve_did_save;
|
||||
hashtab_T sve_hashtab;
|
||||
} save_v_event_T;
|
||||
|
||||
/// Indices into vimmenu_T->strings[] and vimmenu_T->noremap[] for each mode
|
||||
/// \addtogroup MENU_INDEX
|
||||
/// @{
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nvim/event/socket.h"
|
||||
#include "nvim/fileio.h"
|
||||
#include "nvim/lua/executor.h"
|
||||
#include "nvim/misc1.h"
|
||||
#include "nvim/msgpack_rpc/channel.h"
|
||||
#include "nvim/msgpack_rpc/server.h"
|
||||
#include "nvim/os/shell.h"
|
||||
@ -821,7 +822,8 @@ static void set_info_event(void **argv)
|
||||
Channel *chan = argv[0];
|
||||
event_T event = (event_T)(ptrdiff_t)argv[1];
|
||||
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
save_v_event_T save_v_event;
|
||||
dict_T *dict = get_v_event(&save_v_event);
|
||||
Dictionary info = channel_info(chan->id);
|
||||
typval_T retval;
|
||||
(void)object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
|
||||
@ -829,7 +831,7 @@ static void set_info_event(void **argv)
|
||||
|
||||
apply_autocmds(event, NULL, NULL, false, curbuf);
|
||||
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
api_free_dictionary(info);
|
||||
channel_decref(chan);
|
||||
}
|
||||
|
@ -2719,12 +2719,13 @@ static bool pum_enough_matches(void)
|
||||
static void trigger_complete_changed_event(int cur)
|
||||
{
|
||||
static bool recursive = false;
|
||||
save_v_event_T save_v_event;
|
||||
|
||||
if (recursive) {
|
||||
return;
|
||||
}
|
||||
|
||||
dict_T *v_event = get_vim_var_dict(VV_EVENT);
|
||||
dict_T *v_event = get_v_event(&save_v_event);
|
||||
if (cur < 0) {
|
||||
tv_dict_add_dict(v_event, S_LEN("completed_item"), tv_dict_alloc());
|
||||
} else {
|
||||
@ -2740,7 +2741,7 @@ static void trigger_complete_changed_event(int cur)
|
||||
textlock--;
|
||||
recursive = false;
|
||||
|
||||
tv_dict_clear(v_event);
|
||||
restore_v_event(v_event, &save_v_event);
|
||||
}
|
||||
|
||||
/// Show the popup menu for the list of matches.
|
||||
|
@ -880,7 +880,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
||||
TryState tstate;
|
||||
Error err = ERROR_INIT;
|
||||
bool tl_ret = true;
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
save_v_event_T save_v_event;
|
||||
dict_T *dict = get_v_event(&save_v_event);
|
||||
char firstcbuf[2];
|
||||
firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
|
||||
firstcbuf[1] = 0;
|
||||
@ -894,7 +895,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
||||
|
||||
apply_autocmds(EVENT_CMDLINEENTER, (char_u *)firstcbuf, (char_u *)firstcbuf,
|
||||
false, curbuf);
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
|
||||
|
||||
tl_ret = try_leave(&tstate, &err);
|
||||
@ -925,7 +926,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
||||
if (tv_dict_get_number(dict, "abort") != 0) {
|
||||
s->gotesc = 1;
|
||||
}
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
}
|
||||
|
||||
cmdmsg_rl = false;
|
||||
@ -2290,7 +2291,8 @@ static int command_line_changed(CommandLineState *s)
|
||||
if (has_event(EVENT_CMDLINECHANGED)) {
|
||||
TryState tstate;
|
||||
Error err = ERROR_INIT;
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
save_v_event_T save_v_event;
|
||||
dict_T *dict = get_v_event(&save_v_event);
|
||||
|
||||
char firstcbuf[2];
|
||||
firstcbuf[0] = (char)(s->firstc > 0 ? s->firstc : '-');
|
||||
@ -2304,7 +2306,7 @@ static int command_line_changed(CommandLineState *s)
|
||||
|
||||
apply_autocmds(EVENT_CMDLINECHANGED, (char_u *)firstcbuf,
|
||||
(char_u *)firstcbuf, false, curbuf);
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
|
||||
bool tl_ret = try_leave(&tstate, &err);
|
||||
if (!tl_ret && ERROR_SET(&err)) {
|
||||
|
@ -1603,7 +1603,8 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
|
||||
|
||||
recursive = true;
|
||||
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
save_v_event_T save_v_event;
|
||||
dict_T *dict = get_v_event(&save_v_event);
|
||||
char buf[8];
|
||||
|
||||
switch (scope) {
|
||||
@ -1648,7 +1649,7 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
|
||||
apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
|
||||
curbuf);
|
||||
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
|
||||
recursive = false;
|
||||
}
|
||||
|
@ -1060,6 +1060,31 @@ void add_time(char_u *buf, size_t buflen, time_t tt)
|
||||
}
|
||||
}
|
||||
|
||||
dict_T *get_v_event(save_v_event_T *sve)
|
||||
{
|
||||
dict_T *v_event = get_vim_var_dict(VV_EVENT);
|
||||
|
||||
if (v_event->dv_hashtab.ht_used > 0) {
|
||||
// recursive use of v:event, save, make empty and restore later
|
||||
sve->sve_did_save = true;
|
||||
sve->sve_hashtab = v_event->dv_hashtab;
|
||||
hash_init(&v_event->dv_hashtab);
|
||||
} else {
|
||||
sve->sve_did_save = false;
|
||||
}
|
||||
return v_event;
|
||||
}
|
||||
|
||||
void restore_v_event(dict_T *v_event, save_v_event_T *sve)
|
||||
{
|
||||
tv_dict_free_contents(v_event);
|
||||
if (sve->sve_did_save) {
|
||||
v_event->dv_hashtab = sve->sve_hashtab;
|
||||
} else {
|
||||
hash_init(&v_event->dv_hashtab);
|
||||
}
|
||||
}
|
||||
|
||||
/// Fires a ModeChanged autocmd.
|
||||
void trigger_modechanged(void)
|
||||
{
|
||||
@ -1073,7 +1098,8 @@ void trigger_modechanged(void)
|
||||
return;
|
||||
}
|
||||
|
||||
dict_T *v_event = get_vim_var_dict(VV_EVENT);
|
||||
save_v_event_T save_v_event;
|
||||
dict_T *v_event = get_v_event(&save_v_event);
|
||||
tv_dict_add_str(v_event, S_LEN("new_mode"), mode);
|
||||
tv_dict_add_str(v_event, S_LEN("old_mode"), last_mode);
|
||||
|
||||
@ -1086,6 +1112,5 @@ void trigger_modechanged(void)
|
||||
last_mode = mode;
|
||||
|
||||
xfree(pat);
|
||||
tv_dict_free_contents(v_event);
|
||||
hash_init(&v_event->dv_hashtab);
|
||||
restore_v_event(v_event, &save_v_event);
|
||||
}
|
||||
|
@ -2792,8 +2792,9 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
|
||||
|
||||
recursive = true;
|
||||
|
||||
save_v_event_T save_v_event;
|
||||
// Set the v:event dictionary with information about the yank.
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
dict_T *dict = get_v_event(&save_v_event);
|
||||
|
||||
// The yanked text contents.
|
||||
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
|
||||
@ -2830,7 +2831,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
|
||||
textlock++;
|
||||
apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, false, curbuf);
|
||||
textlock--;
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
|
||||
recursive = false;
|
||||
}
|
||||
|
@ -324,10 +324,11 @@ void terminal_close(Terminal *term, int status)
|
||||
}
|
||||
|
||||
if (buf && !is_autocmd_blocked()) {
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
save_v_event_T save_v_event;
|
||||
dict_T *dict = get_v_event(&save_v_event);
|
||||
tv_dict_add_nr(dict, S_LEN("status"), status);
|
||||
apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf);
|
||||
tv_dict_clear(dict);
|
||||
restore_v_event(dict, &save_v_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1721,4 +1721,10 @@ func Test_mode_changes()
|
||||
unlet! g:i_to_any
|
||||
endfunc
|
||||
|
||||
func Test_recursive_ModeChanged()
|
||||
au! ModeChanged * norm 0u
|
||||
sil! norm
|
||||
au!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
Loading…
Reference in New Issue
Block a user