Patch 8.2.4723
Problem:    The ModeChanged autocmd event is inefficient.
Solution:   Avoid allocating memory. (closes #10134)  Rename
            trigger_modechanged() to may_trigger_modechanged().
Files:      src/misc1.c, src/proto/misc1.pro, src/edit.c, src/ex_docmd.c,
            src/ex_getln.c, src/insexpand.c, src/normal.c, src/terminal.c,
            src/autocmd.c


*** ../vim-8.2.4722/src/misc1.c 2022-01-28 15:28:00.208927722 +0000
--- src/misc1.c 2022-04-09 18:14:45.616902425 +0100
***************
*** 625,729 ****
  #if defined(FEAT_EVAL) || defined(PROTO)
  
  /*
!  * "mode()" function
   */
      void
! f_mode(typval_T *argvars, typval_T *rettv)
  {
!     char_u    buf[MODE_MAX_LENGTH];
! 
!     if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL)
!       return;
! 
!     CLEAR_FIELD(buf);
  
      if (time_for_testing == 93784)
      {
        // Testing the two-character code.
!       buf[0] = 'x';
!       buf[1] = '!';
      }
  #ifdef FEAT_TERMINAL
      else if (term_use_loop())
!       buf[0] = 't';
  #endif
      else if (VIsual_active)
      {
        if (VIsual_select)
!           buf[0] = VIsual_mode + 's' - 'v';
        else
        {
!           buf[0] = VIsual_mode;
            if (restart_VIsual_select)
!               buf[1] = 's';
        }
      }
      else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
                || State == CONFIRM)
      {
!       buf[0] = 'r';
        if (State == ASKMORE)
!           buf[1] = 'm';
        else if (State == CONFIRM)
!           buf[1] = '?';
      }
      else if (State == EXTERNCMD)
!       buf[0] = '!';
      else if (State & INSERT)
      {
        if (State & VREPLACE_FLAG)
        {
!           buf[0] = 'R';
!           buf[1] = 'v';
  
            if (ins_compl_active())
!               buf[2] = 'c';
            else if (ctrl_x_mode_not_defined_yet())
!               buf[2] = 'x';
        }
        else
        {
            if (State & REPLACE_FLAG)
!               buf[0] = 'R';
            else
!               buf[0] = 'i';
  
            if (ins_compl_active())
!               buf[1] = 'c';
            else if (ctrl_x_mode_not_defined_yet())
!               buf[1] = 'x';
        }
      }
      else if ((State & CMDLINE) || exmode_active)
      {
!       buf[0] = 'c';
        if (exmode_active == EXMODE_VIM)
!           buf[1] = 'v';
        else if (exmode_active == EXMODE_NORMAL)
!           buf[1] = 'e';
      }
      else
      {
!       buf[0] = 'n';
        if (finish_op)
        {
!           buf[1] = 'o';
            // to be able to detect force-linewise/blockwise/characterwise
            // operations
!           buf[2] = motion_force;
        }
        else if (restart_edit == 'I' || restart_edit == 'R'
                                                        || restart_edit == 'V')
        {
!           buf[1] = 'i';
!           buf[2] = restart_edit;
        }
  #ifdef FEAT_TERMINAL
        else if (term_in_normal_mode())
!           buf[1] = 't';
  #endif
      }
  
      // Clear out the minor mode when the argument is not a non-zero number or
      // non-empty string.
      if (!non_zero_arg(&argvars[0]))
--- 625,743 ----
  #if defined(FEAT_EVAL) || defined(PROTO)
  
  /*
!  * Returns the current mode as a string in "buf[MODE_MAX_LENGTH]", NUL
!  * terminated.
!  * The first character represents the major mode, the following ones the minor
!  * ones.
   */
      void
! get_mode(char_u *buf)
  {
!     int               i = 0;
  
      if (time_for_testing == 93784)
      {
        // Testing the two-character code.
!       buf[i++] = 'x';
!       buf[i++] = '!';
      }
  #ifdef FEAT_TERMINAL
      else if (term_use_loop())
!       buf[i++] = 't';
  #endif
      else if (VIsual_active)
      {
        if (VIsual_select)
!           buf[i++] = VIsual_mode + 's' - 'v';
        else
        {
!           buf[i++] = VIsual_mode;
            if (restart_VIsual_select)
!               buf[i++] = 's';
        }
      }
      else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
                || State == CONFIRM)
      {
!       buf[i++] = 'r';
        if (State == ASKMORE)
!           buf[i++] = 'm';
        else if (State == CONFIRM)
!           buf[i++] = '?';
      }
      else if (State == EXTERNCMD)
!       buf[i++] = '!';
      else if (State & INSERT)
      {
        if (State & VREPLACE_FLAG)
        {
!           buf[i++] = 'R';
!           buf[i++] = 'v';
  
            if (ins_compl_active())
!               buf[i++] = 'c';
            else if (ctrl_x_mode_not_defined_yet())
!               buf[i++] = 'x';
        }
        else
        {
            if (State & REPLACE_FLAG)
!               buf[i++] = 'R';
            else
!               buf[i++] = 'i';
  
            if (ins_compl_active())
!               buf[i++] = 'c';
            else if (ctrl_x_mode_not_defined_yet())
!               buf[i++] = 'x';
        }
      }
      else if ((State & CMDLINE) || exmode_active)
      {
!       buf[i++] = 'c';
        if (exmode_active == EXMODE_VIM)
!           buf[i++] = 'v';
        else if (exmode_active == EXMODE_NORMAL)
!           buf[i++] = 'e';
      }
      else
      {
!       buf[i++] = 'n';
        if (finish_op)
        {
!           buf[i++] = 'o';
            // to be able to detect force-linewise/blockwise/characterwise
            // operations
!           buf[i++] = motion_force;
        }
        else if (restart_edit == 'I' || restart_edit == 'R'
                                                        || restart_edit == 'V')
        {
!           buf[i++] = 'i';
!           buf[i++] = restart_edit;
        }
  #ifdef FEAT_TERMINAL
        else if (term_in_normal_mode())
!           buf[i++] = 't';
  #endif
      }
  
+     buf[i] = NUL;
+ }
+ 
+ /*
+  * "mode()" function
+  */
+     void
+ f_mode(typval_T *argvars, typval_T *rettv)
+ {
+     char_u    buf[MODE_MAX_LENGTH];
+ 
+     if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL)
+       return;
+ 
+     get_mode(buf);
+ 
      // Clear out the minor mode when the argument is not a non-zero number or
      // non-empty string.
      if (!non_zero_arg(&argvars[0]))
***************
*** 2691,2737 ****
  #endif
  
  /*
!  * Fires a ModeChanged autocmd
   */
      void
! trigger_modechanged()
  {
  #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;
  
!     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_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);
  
      // concatenate modes in format "old_mode:new_mode"
!     pat_pre = concat_str(last_mode, (char_u*)":");
!     pat = concat_str(pat_pre, rettv.vval.v_string);
!     vim_free(pat_pre);
  
!     apply_autocmds(EVENT_MODECHANGED, pat, NULL, FALSE, curbuf);
!     STRCPY(last_mode, rettv.vval.v_string);
  
-     vim_free(pat);
      restore_v_event(v_event, &save_v_event);
-     vim_free(rettv.vval.v_string);
  #endif
  }
--- 2705,2740 ----
  #endif
  
  /*
!  * Fires a ModeChanged autocmd event if appropriate.
   */
      void
! may_trigger_modechanged()
  {
  #ifdef FEAT_EVAL
      dict_T        *v_event;
      save_v_event_T  save_v_event;
+     char_u        curr_mode[MODE_MAX_LENGTH];
+     char_u        pattern_buf[2 * MODE_MAX_LENGTH];
  
      if (!has_modechanged())
        return;
  
!     get_mode(curr_mode);
!     if (STRCMP(curr_mode, last_mode) == 0)
        return;
  
      v_event = get_v_event(&save_v_event);
!     (void)dict_add_string(v_event, "new_mode", curr_mode);
      (void)dict_add_string(v_event, "old_mode", last_mode);
      dict_set_items_ro(v_event);
  
      // concatenate modes in format "old_mode:new_mode"
!     vim_snprintf((char *)pattern_buf, sizeof(pattern_buf), "%s:%s", last_mode,
!           curr_mode);
  
!     apply_autocmds(EVENT_MODECHANGED, pattern_buf, NULL, FALSE, curbuf);
!     STRCPY(last_mode, curr_mode);
  
      restore_v_event(v_event, &save_v_event);
  #endif
  }
*** ../vim-8.2.4722/src/proto/misc1.pro 2021-11-17 15:51:46.421992164 +0000
--- src/proto/misc1.pro 2022-04-09 18:14:48.676899515 +0100
***************
*** 14,19 ****
--- 14,20 ----
  char_u *skip_to_option_part(char_u *p);
  void check_status(buf_T *buf);
  int ask_yesno(char_u *str, int direct);
+ void get_mode(char_u *buf);
  void f_mode(typval_T *argvars, typval_T *rettv);
  void f_state(typval_T *argvars, typval_T *rettv);
  int get_keystroke(void);
***************
*** 49,53 ****
  int path_with_url(char_u *fname);
  dict_T *get_v_event(save_v_event_T *sve);
  void restore_v_event(dict_T *v_event, save_v_event_T *sve);
! void trigger_modechanged(void);
  /* vim: set ft=c : */
--- 50,54 ----
  int path_with_url(char_u *fname);
  dict_T *get_v_event(save_v_event_T *sve);
  void restore_v_event(dict_T *v_event, save_v_event_T *sve);
! void may_trigger_modechanged(void);
  /* vim: set ft=c : */
*** ../vim-8.2.4722/src/edit.c  2022-04-08 15:17:53.071952540 +0100
--- src/edit.c  2022-04-09 18:09:55.673180917 +0100
***************
*** 284,290 ****
      else
        State = INSERT;
  
!     trigger_modechanged();
      stop_insert_mode = FALSE;
  
  #ifdef FEAT_CONCEAL
--- 284,290 ----
      else
        State = INSERT;
  
!     may_trigger_modechanged();
      stop_insert_mode = FALSE;
  
  #ifdef FEAT_CONCEAL
***************
*** 3701,3707 ****
  #endif
  
      State = NORMAL;
!     trigger_modechanged();
      // need to position cursor again when on a TAB
      if (gchar_cursor() == TAB)
        curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
--- 3701,3707 ----
  #endif
  
      State = NORMAL;
!     may_trigger_modechanged();
      // need to position cursor again when on a TAB
      if (gchar_cursor() == TAB)
        curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
***************
*** 3838,3844 ****
        State = INSERT | (State & LANGMAP);
      else
        State = replaceState | (State & LANGMAP);
!     trigger_modechanged();
      AppendCharToRedobuff(K_INS);
      showmode();
  #ifdef CURSOR_SHAPE
--- 3838,3844 ----
        State = INSERT | (State & LANGMAP);
      else
        State = replaceState | (State & LANGMAP);
!     may_trigger_modechanged();
      AppendCharToRedobuff(K_INS);
      showmode();
  #ifdef CURSOR_SHAPE
*** ../vim-8.2.4722/src/ex_docmd.c      2022-04-07 18:06:03.342408480 +0100
--- src/ex_docmd.c      2022-04-09 18:09:59.821176881 +0100
***************
*** 477,483 ****
      else
        exmode_active = EXMODE_NORMAL;
      State = NORMAL;
!     trigger_modechanged();
  
      // When using ":global /pat/ visual" and then "Q" we return to continue
      // the :global command.
--- 477,483 ----
      else
        exmode_active = EXMODE_NORMAL;
      State = NORMAL;
!     may_trigger_modechanged();
  
      // When using ":global /pat/ visual" and then "Q" we return to continue
      // the :global command.
*** ../vim-8.2.4722/src/ex_getln.c      2022-03-17 13:03:05.967464752 +0000
--- src/ex_getln.c      2022-04-09 18:10:21.897155469 +0100
***************
*** 1714,1720 ****
      trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER);
  #ifdef FEAT_EVAL
      if (!debug_mode)
!       trigger_modechanged();
  #endif
  
      init_history();
--- 1714,1720 ----
      trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER);
  #ifdef FEAT_EVAL
      if (!debug_mode)
!       may_trigger_modechanged();
  #endif
  
      init_history();
***************
*** 2555,2561 ****
  
  #ifdef FEAT_EVAL
      if (!debug_mode)
!       trigger_modechanged();
  #endif
  
  #ifdef HAVE_INPUT_METHOD
--- 2555,2561 ----
  
  #ifdef FEAT_EVAL
      if (!debug_mode)
!       may_trigger_modechanged();
  #endif
  
  #ifdef HAVE_INPUT_METHOD
*** ../vim-8.2.4722/src/insexpand.c     2022-01-15 18:25:04.661419379 +0000
--- src/insexpand.c     2022-04-09 18:10:45.149132965 +0100
***************
*** 257,263 ****
        // CTRL-V look like CTRL-N
        ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
  
!     trigger_modechanged();
  }
  
  /*
--- 257,263 ----
        // CTRL-V look like CTRL-N
        ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
  
!     may_trigger_modechanged();
  }
  
  /*
***************
*** 2381,2387 ****
        // 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()
--- 2381,2387 ----
        // upon the (possibly failed) completion.
        ins_apply_autocmds(EVENT_COMPLETEDONE);
  
!     may_trigger_modechanged();
  
      // reset continue_* if we left expansion-mode, if we stay they'll be
      // (re)set properly in ins_complete()
***************
*** 2865,2871 ****
      // Lazily show the popup menu, unless we got interrupted.
      if (!compl_interrupted)
        show_pum(save_w_wrow, save_w_leftcol);
!     trigger_modechanged();
      out_flush();
  }
  
--- 2865,2871 ----
      // Lazily show the popup menu, unless we got interrupted.
      if (!compl_interrupted)
        show_pum(save_w_wrow, save_w_leftcol);
!     may_trigger_modechanged();
      out_flush();
  }
  
***************
*** 3818,3824 ****
        if (compl_curr_match == NULL)
            compl_curr_match = compl_old_match;
      }
!     trigger_modechanged();
  
      return i;
  }
--- 3818,3824 ----
        if (compl_curr_match == NULL)
            compl_curr_match = compl_old_match;
      }
!     may_trigger_modechanged();
  
      return i;
  }
*** ../vim-8.2.4722/src/normal.c        2022-03-27 19:26:29.334889006 +0100
--- src/normal.c        2022-04-09 18:11:38.701081295 +0100
***************
*** 689,695 ****
  # endif
      }
  #endif
!     trigger_modechanged();
  
      // When not finishing an operator and no register name typed, reset the
      // count.
--- 689,695 ----
  # endif
      }
  #endif
!     may_trigger_modechanged();
  
      // When not finishing an operator and no register name typed, reset the
      // count.
***************
*** 971,977 ****
      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.
--- 971,977 ----
      c = finish_op;
  #endif
      finish_op = FALSE;
!     may_trigger_modechanged();
  #ifdef CURSOR_SHAPE
      // Redraw the cursor with another shape, if we were in Operator-pending
      // mode or did a replace command.
***************
*** 1027,1033 ****
        if (restart_VIsual_select == 1)
        {
            VIsual_select = TRUE;
!           trigger_modechanged();
            showmode();
            restart_VIsual_select = 0;
            VIsual_select_reg = 0;
--- 1027,1033 ----
        if (restart_VIsual_select == 1)
        {
            VIsual_select = TRUE;
!           may_trigger_modechanged();
            showmode();
            restart_VIsual_select = 0;
            VIsual_select_reg = 0;
***************
*** 1151,1157 ****
      may_clear_cmdline();
  
      adjust_cursor_eol();
!     trigger_modechanged();
  }
  
  /*
--- 1151,1157 ----
      may_clear_cmdline();
  
      adjust_cursor_eol();
!     may_trigger_modechanged();
  }
  
  /*
***************
*** 3222,3228 ****
      if (VIsual_active)        // toggle Selection/Visual mode
      {
        VIsual_select = !VIsual_select;
!       trigger_modechanged();
        showmode();
      }
      else if (!checkclearop(cap->oap))
--- 3222,3228 ----
      if (VIsual_active)        // toggle Selection/Visual mode
      {
        VIsual_select = !VIsual_select;
!       may_trigger_modechanged();
        showmode();
      }
      else if (!checkclearop(cap->oap))
***************
*** 3285,3291 ****
      if (VIsual_active && VIsual_select)
      {
        VIsual_select = FALSE;
!       trigger_modechanged();
        showmode();
        restart_VIsual_select = 2;      // restart Select mode later
      }
--- 3285,3291 ----
      if (VIsual_active && VIsual_select)
      {
        VIsual_select = FALSE;
!       may_trigger_modechanged();
        showmode();
        restart_VIsual_select = 2;      // restart Select mode later
      }
***************
*** 5422,5428 ****
        {                                   //     or char/line mode
            VIsual_mode = cap->cmdchar;
            showmode();
!           trigger_modechanged();
        }
        redraw_curbuf_later(INVERTED);      // update the inversion
      }
--- 5422,5428 ----
        {                                   //     or char/line mode
            VIsual_mode = cap->cmdchar;
            showmode();
!           may_trigger_modechanged();
        }
        redraw_curbuf_later(INVERTED);      // update the inversion
      }
***************
*** 5549,5555 ****
      foldAdjustVisual();
  #endif
  
!     trigger_modechanged();
      setmouse();
  #ifdef FEAT_CONCEAL
      // Check if redraw is needed after changing the state.
--- 5549,5555 ----
      foldAdjustVisual();
  #endif
  
!     may_trigger_modechanged();
      setmouse();
  #ifdef FEAT_CONCEAL
      // Check if redraw is needed after changing the state.
*** ../vim-8.2.4722/src/terminal.c      2022-04-04 15:16:50.742014128 +0100
--- src/terminal.c      2022-04-09 18:11:44.737075473 +0100
***************
*** 2035,2041 ****
  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);
--- 2035,2041 ----
  set_terminal_mode(term_T *term, int normal_mode)
  {
      term->tl_normal_mode = normal_mode;
!     may_trigger_modechanged();
      if (!normal_mode)
        handle_postponed_scrollback(term);
      VIM_CLEAR(term->tl_status_text);
*** ../vim-8.2.4722/src/autocmd.c       2022-04-08 15:17:53.067952553 +0100
--- src/autocmd.c       2022-04-09 18:14:26.388920747 +0100
***************
*** 1240,1256 ****
                // 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
                // Initialize the fields checked by the WinScrolled trigger to
                // stop it from firing right after the first autocmd is defined.
--- 1240,1246 ----
                // need to initialize last_mode for the first ModeChanged
                // autocmd
                if (event == EVENT_MODECHANGED && !has_modechanged())
!                   get_mode(last_mode);
  #endif
                // Initialize the fields checked by the WinScrolled trigger to
                // stop it from firing right after the first autocmd is defined.
*** ../vim-8.2.4722/src/version.c       2022-04-09 17:58:45.089690780 +0100
--- src/version.c       2022-04-09 18:05:18.793422554 +0100
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     4723,
  /**/

-- 
ARTHUR: The swallow may fly south with the sun, or the house martin or the
        plover seek warmer hot lands in winter, yet these are not strangers to
        our land.
SOLDIER: Are you suggesting coconuts migrate?
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// 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/20220409171847.6C4531C0917%40moolenaar.net.

Raspunde prin e-mail lui