]> granicus.if.org Git - vim/commitdiff
patch 8.2.3555: ModeChanged is not triggered on every mode change v8.2.3555
author=?UTF-8?q?Magnus=20Gro=C3=9F?= <magnus.gross@rwth-aachen.de>
Fri, 22 Oct 2021 17:56:39 +0000 (18:56 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 22 Oct 2021 17:56:39 +0000 (18:56 +0100)
Problem:    ModeChanged is not triggered on every mode change.
Solution:   Also trigger on minor mode changes. (Maguns Gross, closes #8999)

runtime/doc/autocmd.txt
src/autocmd.c
src/insexpand.c
src/misc1.c
src/normal.c
src/terminal.c
src/testdir/test_edit.vim
src/version.c

index bcc81ecdad9b8be3f5044b249d602078e408728b..6a4edf9039ce862c906abae4c02e3d8077e2dd7d 100644 (file)
@@ -930,18 +930,23 @@ MenuPopup                 Just before showing the popup menu (under the
                                                        *ModeChanged*
 ModeChanged                    After changing the mode. The pattern is
                                matched against `'old_mode:new_mode'`, for
-                               example match against `i:*` to simulate
-                               |InsertLeave|.
+                               example match against `*:c*` to simulate
+                               |CmdlineEnter|.
                                The following values of |v:event| are set:
                                   old_mode     The mode before it changed.
                                   new_mode     The new mode as also returned
-                                               by |mode()|.
+                                               by |mode()| called with a
+                                               non-zero argument.
                                When ModeChanged is triggered, old_mode will
                                have the value of new_mode when the event was
                                last triggered.
+                               This will be triggered on every minor mode
+                               change.
                                Usage example to use relative line numbers
                                when entering Visual mode: >
-       :autocmd ModeChanged *:v set relativenumber
+       :au ModeChanged [vV\x16]*:* let &l:rnu = mode() =~# '^[vV\x16]'
+       :au ModeChanged *:[vV\x16]* let &l:rnu = mode() =~# '^[vV\x16]'
+       :au WinEnter,WinLeave * let &l:rnu = mode() =~# '^[vV\x16]'
 <                                                      *OptionSet*
 OptionSet                      After setting an option.  The pattern is
                                matched against the long option name.
index bd1ed87419f8605ee178e36b34ccd2ab5c65d54f..1704cd4e3a5c98f7f43abe454a61d04b009716ce 100644 (file)
@@ -1218,6 +1218,23 @@ do_autocmd_event(
                    return FAIL;
                }
 
+#ifdef FEAT_EVAL
+               // need to initialize last_mode for the first ModeChanged
+               // autocmd
+               if (event == EVENT_MODECHANGED && !has_modechanged())
+               {
+                   typval_T rettv;
+                   typval_T tv[2];
+
+                   tv[0].v_type = VAR_NUMBER;
+                   tv[0].vval.v_number = 1;
+                   tv[1].v_type = VAR_UNKNOWN;
+                   f_mode(tv, &rettv);
+                   STRCPY(last_mode, rettv.vval.v_string);
+                   vim_free(rettv.vval.v_string);
+               }
+#endif
+
                if (is_buflocal)
                {
                    ap->buflocal_nr = buflocal_nr;
index 6d5e556c6629a103a1564d793389590567b989a0..c993d96701a17c86e5d2b9553f9ad323f8e04128 100644 (file)
@@ -243,6 +243,8 @@ ins_ctrl_x(void)
        // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X
        // CTRL-V look like CTRL-N
        ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
+
+    trigger_modechanged();
 }
 
 /*
@@ -2150,6 +2152,8 @@ ins_compl_prep(int c)
        // upon the (possibly failed) completion.
        ins_apply_autocmds(EVENT_COMPLETEDONE);
 
+    trigger_modechanged();
+
     // reset continue_* if we left expansion-mode, if we stay they'll be
     // (re)set properly in ins_complete()
     if (!vim_is_ctrl_x_key(c))
@@ -2487,6 +2491,7 @@ set_completion(colnr_T startcol, list_T *list)
     // Lazily show the popup menu, unless we got interrupted.
     if (!compl_interrupted)
        show_pum(save_w_wrow, save_w_leftcol);
+    trigger_modechanged();
     out_flush();
 }
 
@@ -3255,6 +3260,8 @@ ins_compl_get_exp(pos_T *ini)
        if (compl_curr_match == NULL)
            compl_curr_match = compl_old_match;
     }
+    trigger_modechanged();
+
     return i;
 }
 
index 109b7bb0cff3d8b353e907bf46bb4a3a0a847222..58f515dffb332fcc552feb4f744c84a0e3875dc6 100644 (file)
@@ -2670,12 +2670,17 @@ trigger_modechanged()
     if (!has_modechanged())
        return;
 
-    v_event = get_vim_var_dict(VV_EVENT);
-
     tv[0].v_type = VAR_NUMBER;
     tv[0].vval.v_number = 1;       // get full mode
     tv[1].v_type = VAR_UNKNOWN;
     f_mode(tv, &rettv);
+    if (STRCMP(rettv.vval.v_string, last_mode) == 0)
+    {
+       vim_free(rettv.vval.v_string);
+       return;
+    }
+
+    v_event = get_vim_var_dict(VV_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);
@@ -2688,9 +2693,9 @@ trigger_modechanged()
     apply_autocmds(EVENT_MODECHANGED, pat, NULL, FALSE, curbuf);
     STRCPY(last_mode, rettv.vval.v_string);
 
-    vim_free(rettv.vval.v_string);
     vim_free(pat);
     dict_free_contents(v_event);
     hash_init(&v_event->dv_hashtab);
+    vim_free(rettv.vval.v_string);
 #endif
 }
index eafd1fddb628fdf2412fd4669ebedaef8bf4d34f..e6b7a8a758d77d987a0bcdb5f3107d5bae767a52 100644 (file)
@@ -527,6 +527,7 @@ normal_cmd(
 # endif
     }
 #endif
+    trigger_modechanged();
 
     // When not finishing an operator and no register name typed, reset the
     // count.
@@ -1221,6 +1222,7 @@ normal_end:
     c = finish_op;
 #endif
     finish_op = FALSE;
+    trigger_modechanged();
 #ifdef CURSOR_SHAPE
     // Redraw the cursor with another shape, if we were in Operator-pending
     // mode or did a replace command.
@@ -1278,6 +1280,7 @@ normal_end:
        if (restart_VIsual_select == 1)
        {
            VIsual_select = TRUE;
+           trigger_modechanged();
            showmode();
            restart_VIsual_select = 0;
        }
@@ -1386,7 +1389,6 @@ end_visual_mode_keep_button()
 #endif
 
     VIsual_active = FALSE;
-    trigger_modechanged();
     setmouse();
     mouse_dragging = 0;
 
@@ -1403,6 +1405,7 @@ end_visual_mode_keep_button()
     may_clear_cmdline();
 
     adjust_cursor_eol();
+    trigger_modechanged();
 }
 
 /*
@@ -3439,6 +3442,7 @@ nv_ctrlg(cmdarg_T *cap)
     if (VIsual_active) // toggle Selection/Visual mode
     {
        VIsual_select = !VIsual_select;
+       trigger_modechanged();
        showmode();
     }
     else if (!checkclearop(cap->oap))
@@ -3501,6 +3505,7 @@ nv_ctrlo(cmdarg_T *cap)
     if (VIsual_active && VIsual_select)
     {
        VIsual_select = FALSE;
+       trigger_modechanged();
        showmode();
        restart_VIsual_select = 2;      // restart Select mode later
     }
index e9dd8ea166aab83655f86c50b68734dd37f9548d..bb3035bdfd15740031ae15f0a6ea7c8c6110d5c8 100644 (file)
@@ -1995,6 +1995,7 @@ term_check_timers(int next_due_arg, proftime_T *now)
 set_terminal_mode(term_T *term, int normal_mode)
 {
     term->tl_normal_mode = normal_mode;
+    trigger_modechanged();
     if (!normal_mode)
        handle_postponed_scrollback(term);
     VIM_CLEAR(term->tl_status_text);
index 8e4254be4f1ea93c45104559c79503ef33bfbbc5..f0f04f0491620370e3244d2d336a893952ce6617 100644 (file)
@@ -1959,12 +1959,8 @@ endfunc
 
 " Test for ModeChanged pattern
 func Test_mode_changes()
-  let g:count = 0
-  func! DoIt()
-    let g:count += 1
-  endfunc
   let g:index = 0
-  let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'n', 'V', 'v', 'n']
+  let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'i', 'ix', 'i', 'ic', 'i', 'n', 'no', 'n', 'V', 'v', 's', 'n']
   func! TestMode()
     call assert_equal(g:mode_seq[g:index], get(v:event, "old_mode"))
     call assert_equal(g:mode_seq[g:index + 1], get(v:event, "new_mode"))
@@ -1973,13 +1969,15 @@ func Test_mode_changes()
   endfunc
 
   au ModeChanged * :call TestMode()
-  au ModeChanged n:* :call DoIt()
-  call feedkeys("i\<esc>vV\<esc>", 'tnix')
-  call assert_equal(2, g:count)
-
-  au ModeChanged V:v :call DoIt()
-  call feedkeys("Vv\<esc>", 'tnix')
-  call assert_equal(4, g:count)
+  let g:n_to_any = 0
+  au ModeChanged n:* let g:n_to_any += 1
+  call feedkeys("i\<esc>vVca\<CR>\<C-X>\<C-L>\<esc>ggdG", 'tnix')
+
+  let g:V_to_v = 0
+  au ModeChanged V:v let g:V_to_v += 1
+  call feedkeys("Vv\<C-G>\<esc>", 'tnix')
+  call assert_equal(len(filter(g:mode_seq[1:], {idx, val -> val == 'n'})), g:n_to_any)
+  call assert_equal(1, g:V_to_v)
   call assert_equal(len(g:mode_seq) - 1, g:index)
 
   let g:n_to_i = 0
@@ -2008,12 +2006,32 @@ func Test_mode_changes()
   call assert_equal(2, g:i_to_any)
   call assert_equal(3, g:nori_to_any)
 
+  if has('terminal')
+    let g:mode_seq += ['c', 'n', 't', 'nt', 'c', 'nt', 'n']
+    call feedkeys(":term\<CR>\<C-W>N:bd!\<CR>", 'tnix')
+    call assert_equal(len(g:mode_seq) - 1, g:index)
+    call assert_equal(1, g:n_to_i)
+    call assert_equal(1, g:n_to_niI)
+    call assert_equal(1, g:niI_to_i)
+    call assert_equal(2, g:nany_to_i)
+    call assert_equal(1, g:i_to_n)
+    call assert_equal(2, g:i_to_any)
+    call assert_equal(5, g:nori_to_any)
+  endif
+
   au! ModeChanged
   delfunc TestMode
   unlet! g:mode_seq
   unlet! g:index
-  delfunc DoIt
-  unlet! g:count
+  unlet! g:n_to_any
+  unlet! g:V_to_v
+  unlet! g:n_to_i
+  unlet! g:n_to_niI
+  unlet! g:niI_to_i
+  unlet! g:nany_to_i
+  unlet! g:i_to_n
+  unlet! g:nori_to_any
+  unlet! g:i_to_any
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
index 16a290ba77dda2428c4e088d6bed59885a0a69c1..1c2231f145b611bd1b58ddf4eecfbf3d4c10a10b 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3555,
 /**/
     3554,
 /**/