diff src/misc1.c @ 26155:f2392648af3e v8.2.3609

patch 8.2.3609: internal error when ModeChanged is triggered recursively Commit: https://github.com/vim/vim/commit/3075a45592fe76f2febb6321632a23e352efe949 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Nov 17 15:51:52 2021 +0000 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.
author Bram Moolenaar <Bram@vim.org>
date Wed, 17 Nov 2021 17:00:05 +0100
parents 6b39ab99e367
children 3f842f7b5278
line wrap: on
line diff
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -2654,18 +2654,52 @@ path_with_url(char_u *fname)
     return path_is_url(p);
 }
 
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the dictionary of v:event.
+ * Save and clear the value in case it already has items.
+ */
+    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)
+{
+    dict_free_contents(v_event);
+    if (sve->sve_did_save)
+	v_event->dv_hashtab = sve->sve_hashtab;
+    else
+	hash_init(&v_event->dv_hashtab);
+}
+#endif
+
 /*
  * Fires a ModeChanged autocmd
  */
     void
 trigger_modechanged()
 {
-#if defined(FEAT_EVAL) || defined(PROTO)
+#ifdef FEAT_EVAL
     dict_T	    *v_event;
     typval_T	    rettv;
     typval_T	    tv[2];
     char_u	    *pat_pre;
     char_u	    *pat;
+    save_v_event_T  save_v_event;
 
     if (!has_modechanged())
 	return;
@@ -2680,7 +2714,7 @@ trigger_modechanged()
 	return;
     }
 
-    v_event = get_vim_var_dict(VV_EVENT);
+    v_event = get_v_event(&save_v_event);
     (void)dict_add_string(v_event, "new_mode", rettv.vval.v_string);
     (void)dict_add_string(v_event, "old_mode", last_mode);
     dict_set_items_ro(v_event);
@@ -2694,8 +2728,7 @@ trigger_modechanged()
     STRCPY(last_mode, rettv.vval.v_string);
 
     vim_free(pat);
-    dict_free_contents(v_event);
-    hash_init(&v_event->dv_hashtab);
+    restore_v_event(v_event, &save_v_event);
     vim_free(rettv.vval.v_string);
 #endif
 }