To: vim_dev@googlegroups.com Subject: Patch 8.2.4723 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///