Patch 8.2.3555
Problem:    ModeChanged is not triggered on every mode change.
Solution:   Also trigger on minor mode changes. (Maguns Gross, closes #8999)
Files:      runtime/doc/autocmd.txt, src/autocmd.c, src/insexpand.c,
            src/misc1.c, src/normal.c, src/terminal.c,
            src/testdir/test_edit.vim


*** ../vim-8.2.3554/runtime/doc/autocmd.txt     2021-09-12 12:39:04.319467418 
+0100
--- runtime/doc/autocmd.txt     2021-10-22 18:49:38.117786968 +0100
***************
*** 927,944 ****
                                                        *ModeChanged*
  ModeChanged                   After changing the mode. The pattern is
                                matched against `'old_mode:new_mode'`, for
!                               example match against `i:*` to simulate
!                               |InsertLeave|.
                                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()|.
                                When ModeChanged is triggered, old_mode will
                                have the value of new_mode when the event was
                                last triggered.
                                Usage example to use relative line numbers
!                               when entering visual mode: >
!       :autocmd ModeChanged *:v set relativenumber
  <                                                     *OptionSet*
  OptionSet                     After setting an option.  The pattern is
                                matched against the long option name.
--- 930,952 ----
                                                        *ModeChanged*
  ModeChanged                   After changing the mode. The pattern is
                                matched against `'old_mode:new_mode'`, for
!                               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()| 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: >
!       :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.
*** ../vim-8.2.3554/src/autocmd.c       2021-10-02 11:23:01.566500862 +0100
--- src/autocmd.c       2021-10-22 18:51:58.903728134 +0100
***************
*** 1218,1223 ****
--- 1218,1240 ----
                    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;
*** ../vim-8.2.3554/src/insexpand.c     2021-10-17 14:13:04.836665895 +0100
--- src/insexpand.c     2021-10-22 18:49:38.117786968 +0100
***************
*** 243,248 ****
--- 243,250 ----
        // 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,2155 ****
--- 2152,2159 ----
        // 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,2492 ****
--- 2491,2497 ----
      // 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,3260 ****
--- 3260,3267 ----
        if (compl_curr_match == NULL)
            compl_curr_match = compl_old_match;
      }
+     trigger_modechanged();
+ 
      return i;
  }
  
*** ../vim-8.2.3554/src/misc1.c 2021-10-21 18:01:10.101023157 +0100
--- src/misc1.c 2021-10-22 18:53:08.824685050 +0100
***************
*** 2670,2681 ****
      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);
      (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);
--- 2670,2686 ----
      if (!has_modechanged())
        return;
  
      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,2696 ****
      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);
  #endif
  }
--- 2693,2701 ----
      apply_autocmds(EVENT_MODECHANGED, pat, NULL, FALSE, curbuf);
      STRCPY(last_mode, 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
  }
*** ../vim-8.2.3554/src/normal.c        2021-10-17 17:20:20.399745698 +0100
--- src/normal.c        2021-10-22 18:49:38.121787024 +0100
***************
*** 527,532 ****
--- 527,533 ----
  # endif
      }
  #endif
+     trigger_modechanged();
  
      // When not finishing an operator and no register name typed, reset the
      // count.
***************
*** 1221,1226 ****
--- 1222,1228 ----
      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,1283 ****
--- 1280,1286 ----
        if (restart_VIsual_select == 1)
        {
            VIsual_select = TRUE;
+           trigger_modechanged();
            showmode();
            restart_VIsual_select = 0;
        }
***************
*** 1386,1392 ****
  #endif
  
      VIsual_active = FALSE;
-     trigger_modechanged();
      setmouse();
      mouse_dragging = 0;
  
--- 1389,1394 ----
***************
*** 1403,1408 ****
--- 1405,1411 ----
      may_clear_cmdline();
  
      adjust_cursor_eol();
+     trigger_modechanged();
  }
  
  /*
***************
*** 3439,3444 ****
--- 3442,3448 ----
      if (VIsual_active)        // toggle Selection/Visual mode
      {
        VIsual_select = !VIsual_select;
+       trigger_modechanged();
        showmode();
      }
      else if (!checkclearop(cap->oap))
***************
*** 3501,3506 ****
--- 3505,3511 ----
      if (VIsual_active && VIsual_select)
      {
        VIsual_select = FALSE;
+       trigger_modechanged();
        showmode();
        restart_VIsual_select = 2;      // restart Select mode later
      }
*** ../vim-8.2.3554/src/terminal.c      2021-10-17 17:20:20.399745698 +0100
--- src/terminal.c      2021-10-22 18:49:38.121787024 +0100
***************
*** 1995,2000 ****
--- 1995,2001 ----
  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);
*** ../vim-8.2.3554/src/testdir/test_edit.vim   2021-10-17 14:13:04.836665895 
+0100
--- src/testdir/test_edit.vim   2021-10-22 18:49:38.121787024 +0100
***************
*** 1959,1970 ****
  
  " 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']
    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"))
--- 1959,1966 ----
  
  " Test for ModeChanged pattern
  func Test_mode_changes()
    let g:index = 0
!   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,1985 ****
    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)
    call assert_equal(len(g:mode_seq) - 1, g:index)
  
    let g:n_to_i = 0
--- 1969,1983 ----
    endfunc
  
    au ModeChanged * :call TestMode()
!   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,2019 ****
    call assert_equal(2, g:i_to_any)
    call assert_equal(3, g:nori_to_any)
  
    au! ModeChanged
    delfunc TestMode
    unlet! g:mode_seq
    unlet! g:index
!   delfunc DoIt
!   unlet! g:count
  endfunc
  
  " vim: shiftwidth=2 sts=2 expandtab
--- 2006,2037 ----
    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
!   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
*** ../vim-8.2.3554/src/version.c       2021-10-22 15:55:27.782135449 +0100
--- src/version.c       2021-10-22 18:51:32.783369530 +0100
***************
*** 759,760 ****
--- 759,762 ----
  {   /* Add new patch number below this line */
+ /**/
+     3555,
  /**/

-- 
If evolution theories are correct, humans will soon grow a third
hand for operating the mouse.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20211022175711.5C7ABC80054%40moolenaar.net.

Raspunde prin e-mail lui