summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author=?UTF-8?q?Magnus=20Gro=C3=9F?= <magnus.gross@rwth-aachen.de>2021-10-22 18:56:39 +0100
committerBram Moolenaar <Bram@vim.org>2021-10-22 18:56:39 +0100
commit25def2c8b8bd7b0c3d5f020207c717a880b05d50 (patch)
tree297dc3f2ad09266c34bdf4c518ff5ebcc588bb4d
parenta2ffb435209716dc7aeb4783333f6ea19f5d28a7 (diff)
downloadvim-git-25def2c8b8bd7b0c3d5f020207c717a880b05d50.tar.gz
patch 8.2.3555: ModeChanged is not triggered on every mode changev8.2.3555
Problem: ModeChanged is not triggered on every mode change. Solution: Also trigger on minor mode changes. (Maguns Gross, closes #8999)
-rw-r--r--runtime/doc/autocmd.txt13
-rw-r--r--src/autocmd.c17
-rw-r--r--src/insexpand.c7
-rw-r--r--src/misc1.c11
-rw-r--r--src/normal.c7
-rw-r--r--src/terminal.c1
-rw-r--r--src/testdir/test_edit.vim46
-rw-r--r--src/version.c2
8 files changed, 82 insertions, 22 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index bcc81ecda..6a4edf903 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -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.
diff --git a/src/autocmd.c b/src/autocmd.c
index bd1ed8741..1704cd4e3 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -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;
diff --git a/src/insexpand.c b/src/insexpand.c
index 6d5e556c6..c993d9670 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -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;
}
diff --git a/src/misc1.c b/src/misc1.c
index 109b7bb0c..58f515dff 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -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
}
diff --git a/src/normal.c b/src/normal.c
index eafd1fddb..e6b7a8a75 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -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
}
diff --git a/src/terminal.c b/src/terminal.c
index e9dd8ea16..bb3035bdf 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -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);
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
index 8e4254be4..f0f04f049 100644
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 16a290ba7..1c2231f14 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3555,
+/**/
3554,
/**/
3553,