patch 8.2.4723: the ModeChanged autocmd event is inefficient
Problem: The ModeChanged autocmd event is inefficient.
Solution: Avoid allocating memory. (closes #10134) Rename
trigger_modechanged() to may_trigger_modechanged().
diff --git a/src/autocmd.c b/src/autocmd.c
index a0065de..3b384f5 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -1240,17 +1240,7 @@
// 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);
- }
+ 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.
diff --git a/src/edit.c b/src/edit.c
index 1585f85..fad2a7b 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -284,7 +284,7 @@
else
State = INSERT;
- trigger_modechanged();
+ may_trigger_modechanged();
stop_insert_mode = FALSE;
#ifdef FEAT_CONCEAL
@@ -3701,7 +3701,7 @@
#endif
State = NORMAL;
- trigger_modechanged();
+ 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,7 +3838,7 @@
State = INSERT | (State & LANGMAP);
else
State = replaceState | (State & LANGMAP);
- trigger_modechanged();
+ may_trigger_modechanged();
AppendCharToRedobuff(K_INS);
showmode();
#ifdef CURSOR_SHAPE
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 0b88259..7e3cb7e 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -477,7 +477,7 @@
else
exmode_active = EXMODE_NORMAL;
State = NORMAL;
- trigger_modechanged();
+ may_trigger_modechanged();
// When using ":global /pat/ visual" and then "Q" we return to continue
// the :global command.
diff --git a/src/ex_getln.c b/src/ex_getln.c
index 4b14971..3cacf9d 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -1714,7 +1714,7 @@
trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER);
#ifdef FEAT_EVAL
if (!debug_mode)
- trigger_modechanged();
+ may_trigger_modechanged();
#endif
init_history();
@@ -2555,7 +2555,7 @@
#ifdef FEAT_EVAL
if (!debug_mode)
- trigger_modechanged();
+ may_trigger_modechanged();
#endif
#ifdef HAVE_INPUT_METHOD
diff --git a/src/insexpand.c b/src/insexpand.c
index b7b6c02..2c549f8 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -257,7 +257,7 @@
// CTRL-V look like CTRL-N
ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
- trigger_modechanged();
+ may_trigger_modechanged();
}
/*
@@ -2381,7 +2381,7 @@
// upon the (possibly failed) completion.
ins_apply_autocmds(EVENT_COMPLETEDONE);
- trigger_modechanged();
+ may_trigger_modechanged();
// reset continue_* if we left expansion-mode, if we stay they'll be
// (re)set properly in ins_complete()
@@ -2865,7 +2865,7 @@
// Lazily show the popup menu, unless we got interrupted.
if (!compl_interrupted)
show_pum(save_w_wrow, save_w_leftcol);
- trigger_modechanged();
+ may_trigger_modechanged();
out_flush();
}
@@ -3818,7 +3818,7 @@
if (compl_curr_match == NULL)
compl_curr_match = compl_old_match;
}
- trigger_modechanged();
+ may_trigger_modechanged();
return i;
}
diff --git a/src/misc1.c b/src/misc1.c
index 7fc625b..82dbbba 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -625,6 +625,107 @@
#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
@@ -635,94 +736,7 @@
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
- }
+ get_mode(buf);
// Clear out the minor mode when the argument is not a non-zero number or
// non-empty string.
@@ -2691,47 +2705,36 @@
#endif
/*
- * Fires a ModeChanged autocmd
+ * Fires a ModeChanged autocmd event if appropriate.
*/
void
-trigger_modechanged()
+may_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;
+ char_u curr_mode[MODE_MAX_LENGTH];
+ char_u pattern_buf[2 * MODE_MAX_LENGTH];
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);
+ 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", rettv.vval.v_string);
+ (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"
- pat_pre = concat_str(last_mode, (char_u*)":");
- pat = concat_str(pat_pre, rettv.vval.v_string);
- vim_free(pat_pre);
+ vim_snprintf((char *)pattern_buf, sizeof(pattern_buf), "%s:%s", last_mode,
+ curr_mode);
- apply_autocmds(EVENT_MODECHANGED, pat, NULL, FALSE, curbuf);
- STRCPY(last_mode, rettv.vval.v_string);
+ apply_autocmds(EVENT_MODECHANGED, pattern_buf, NULL, FALSE, curbuf);
+ STRCPY(last_mode, curr_mode);
- vim_free(pat);
restore_v_event(v_event, &save_v_event);
- vim_free(rettv.vval.v_string);
#endif
}
diff --git a/src/normal.c b/src/normal.c
index e39fb77..d7a2857 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -689,7 +689,7 @@
# endif
}
#endif
- trigger_modechanged();
+ may_trigger_modechanged();
// When not finishing an operator and no register name typed, reset the
// count.
@@ -971,7 +971,7 @@
c = finish_op;
#endif
finish_op = FALSE;
- trigger_modechanged();
+ 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,7 +1027,7 @@
if (restart_VIsual_select == 1)
{
VIsual_select = TRUE;
- trigger_modechanged();
+ may_trigger_modechanged();
showmode();
restart_VIsual_select = 0;
VIsual_select_reg = 0;
@@ -1151,7 +1151,7 @@
may_clear_cmdline();
adjust_cursor_eol();
- trigger_modechanged();
+ may_trigger_modechanged();
}
/*
@@ -3222,7 +3222,7 @@
if (VIsual_active) // toggle Selection/Visual mode
{
VIsual_select = !VIsual_select;
- trigger_modechanged();
+ may_trigger_modechanged();
showmode();
}
else if (!checkclearop(cap->oap))
@@ -3285,7 +3285,7 @@
if (VIsual_active && VIsual_select)
{
VIsual_select = FALSE;
- trigger_modechanged();
+ may_trigger_modechanged();
showmode();
restart_VIsual_select = 2; // restart Select mode later
}
@@ -5422,7 +5422,7 @@
{ // or char/line mode
VIsual_mode = cap->cmdchar;
showmode();
- trigger_modechanged();
+ may_trigger_modechanged();
}
redraw_curbuf_later(INVERTED); // update the inversion
}
@@ -5549,7 +5549,7 @@
foldAdjustVisual();
#endif
- trigger_modechanged();
+ may_trigger_modechanged();
setmouse();
#ifdef FEAT_CONCEAL
// Check if redraw is needed after changing the state.
diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro
index db60a6d..cc7e07a 100644
--- a/src/proto/misc1.pro
+++ b/src/proto/misc1.pro
@@ -14,6 +14,7 @@
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,5 +50,5 @@
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);
+void may_trigger_modechanged(void);
/* vim: set ft=c : */
diff --git a/src/terminal.c b/src/terminal.c
index 0849f2c..b6efb49 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -2035,7 +2035,7 @@
set_terminal_mode(term_T *term, int normal_mode)
{
term->tl_normal_mode = normal_mode;
- trigger_modechanged();
+ may_trigger_modechanged();
if (!normal_mode)
handle_postponed_scrollback(term);
VIM_CLEAR(term->tl_status_text);
diff --git a/src/version.c b/src/version.c
index 410fe2a..574bacb 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 4723,
+/**/
4722,
/**/
4721,