aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMagnus Groß <magnus.gross@rwth-aachen.de>2021-09-29 16:36:48 +0200
committerMagnus Groß <magnus.gross@rwth-aachen.de>2021-11-18 11:23:18 +0100
commit69bd1e4e36fa3e3f604740c92b15b13141520822 (patch)
treebcff79c6cef4d64707ce1819d18c466872304bcc /src
parent36538417f027758ee50faf50c5e4dcc6cb73431d (diff)
downloadrneovim-69bd1e4e36fa3e3f604740c92b15b13141520822.tar.gz
rneovim-69bd1e4e36fa3e3f604740c92b15b13141520822.tar.bz2
rneovim-69bd1e4e36fa3e3f604740c92b15b13141520822.zip
vim-patch:8.2.3430: no generic way to trigger an autocommand on mode change
Problem: No generic way to trigger an autocommand on mode change. Solution: Add the ModeChanged autocommand event. (Magnus Gross, closes vim/vim#8856) https://github.com/vim/vim/commit/f1e8876fa2359b572d262772747405d3616db670 N/A patches for version.c: vim-patch:8.2.3434: function prototype for trigger_modechanged() is incomplete Problem: Function prototype for trigger_modechanged() is incomplete. Solution: Add "void". https://github.com/vim/vim/commit/28e591dd5080bbcd0f468f9d9597cedb716e28c9 Fixes #4399. Fixes #7416.
Diffstat (limited to 'src')
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/autocmd.c13
-rw-r--r--src/nvim/edit.c3
-rw-r--r--src/nvim/ex_docmd.c1
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/globals.h1
-rw-r--r--src/nvim/memory.c1
-rw-r--r--src/nvim/misc1.c29
-rw-r--r--src/nvim/normal.c3
-rw-r--r--src/nvim/state.c2
-rw-r--r--src/nvim/testdir/test_edit.vim34
-rw-r--r--src/nvim/vim.h2
12 files changed, 85 insertions, 7 deletions
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 6be51c504c..bd30966acf 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -69,6 +69,7 @@ return {
'InsertLeave', -- just after leaving Insert mode
'InsertLeavePre', -- just before leaving Insert mode
'MenuPopup', -- just before popup menu is displayed
+ 'ModeChanged', -- after changing the mode
'OptionSet', -- after setting any option
'QuickFixCmdPost', -- after :make, :grep etc.
'QuickFixCmdPre', -- before :make, :grep etc.
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 2d0c0f3fd5..ae81b6a808 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -1440,7 +1440,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
// invalid.
if (fname_io == NULL) {
if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
- || event == EVENT_OPTIONSET) {
+ || event == EVENT_OPTIONSET || event == EVENT_MODECHANGED) {
autocmd_fname = NULL;
} else if (fname != NULL && !ends_excmd(*fname)) {
autocmd_fname = fname;
@@ -1494,11 +1494,12 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|| event == EVENT_CMDWINLEAVE || event == EVENT_CMDUNDEFINED
|| event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
|| event == EVENT_DIRCHANGED || event == EVENT_FILETYPE
- || event == EVENT_FUNCUNDEFINED || event == EVENT_OPTIONSET
- || event == EVENT_QUICKFIXCMDPOST || event == EVENT_QUICKFIXCMDPRE
- || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING
- || event == EVENT_SYNTAX || event == EVENT_SIGNAL
- || event == EVENT_TABCLOSED || event == EVENT_WINCLOSED) {
+ || event == EVENT_FUNCUNDEFINED || event == EVENT_MODECHANGED
+ || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST
+ || event == EVENT_QUICKFIXCMDPRE || event == EVENT_REMOTEREPLY
+ || event == EVENT_SPELLFILEMISSING || event == EVENT_SYNTAX
+ || event == EVENT_SIGNAL || event == EVENT_TABCLOSED
+ || event == EVENT_WINCLOSED) {
fname = vim_strsave(fname);
} else {
fname = (char_u *)FullName_save((char *)fname, false);
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 7a24ee1b32..cbb93c88ee 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -385,6 +385,7 @@ static void insert_enter(InsertState *s)
State = INSERT;
}
+ trigger_modechanged();
stop_insert_mode = false;
// Need to recompute the cursor position, it might move when the cursor is
@@ -7965,6 +7966,7 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
State = NORMAL;
+ trigger_modechanged();
// need to position cursor again (e.g. when on a TAB )
changed_cline_bef_curs();
@@ -8066,6 +8068,7 @@ static void ins_insert(int replaceState)
} else {
State = replaceState | (State & LANGMAP);
}
+ trigger_modechanged();
AppendCharToRedobuff(K_INS);
showmode();
ui_cursor_shape(); // may show different cursor shape
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e622a2a68f..03d85ea888 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -196,6 +196,7 @@ void do_exmode(void)
exmode_active = true;
State = NORMAL;
+ trigger_modechanged();
// When using ":global /pat/ visual" and then "Q" we return to continue
// the :global command.
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 0716b5445d..09f379d0b9 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -906,6 +906,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
}
tl_ret = true;
}
+ trigger_modechanged();
state_enter(&s->state);
@@ -6547,6 +6548,7 @@ static int open_cmdwin(void)
cmdmsg_rl = save_cmdmsg_rl;
State = save_State;
+ trigger_modechanged();
setmouse();
return cmdwin_result;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index e2d3378402..9f0f19024b 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -727,6 +727,7 @@ EXTERN bool listcmd_busy INIT(= false); // set when :argdo, :windo or
// :bufdo is executing
EXTERN bool need_start_insertmode INIT(= false);
// start insert mode soon
+EXTERN char *last_mode INIT(= NULL);
EXTERN char_u *last_cmdline INIT(= NULL); // last command line (for ":)
EXTERN char_u *repeat_cmdline INIT(= NULL); // command line for "."
EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 547a9015b7..85140e4c64 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -632,6 +632,7 @@ void free_all_mem(void)
clear_sb_text(true); // free any scrollback text
// Free some global vars.
+ xfree(last_mode);
xfree(last_cmdline);
xfree(new_last_cmdline);
set_keep_msg(NULL, 0);
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 5ecd4ca431..4c495ee9db 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -1059,3 +1059,32 @@ void add_time(char_u *buf, size_t buflen, time_t tt)
seconds);
}
}
+
+/// Fires a ModeChanged autocmd.
+void trigger_modechanged(void)
+{
+ if (!has_event(EVENT_MODECHANGED)) {
+ return;
+ }
+
+ dict_T *v_event = get_vim_var_dict(VV_EVENT);
+
+ char *mode = get_mode();
+ if (last_mode == NULL) {
+ last_mode = (char *)vim_strsave((char_u *)"n");
+ }
+ tv_dict_add_str(v_event, S_LEN("new_mode"), mode);
+ tv_dict_add_str(v_event, S_LEN("old_mode"), last_mode);
+
+ char_u *pat_pre = concat_str((char_u *)last_mode, (char_u *)":");
+ char_u *pat = concat_str(pat_pre, (char_u *)mode);
+ xfree(pat_pre);
+
+ apply_autocmds(EVENT_MODECHANGED, pat, NULL, false, curbuf);
+ xfree(last_mode);
+ last_mode = mode;
+
+ xfree(pat);
+ tv_dict_free_contents(v_event);
+ hash_init(&v_event->dv_hashtab);
+}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 1effeefd32..81e8251361 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -3050,6 +3050,7 @@ static int get_mouse_class(char_u *p)
void end_visual_mode(void)
{
VIsual_active = false;
+ trigger_modechanged();
setmouse();
mouse_dragging = 0;
@@ -6680,6 +6681,7 @@ static void nv_visual(cmdarg_T *cap)
// or char/line mode
VIsual_mode = cap->cmdchar;
showmode();
+ trigger_modechanged();
}
redraw_curbuf_later(INVERTED); // update the inversion
} else { // start Visual mode
@@ -6782,6 +6784,7 @@ static void n_start_visual_mode(int c)
VIsual_mode = c;
VIsual_active = true;
VIsual_reselect = true;
+ trigger_modechanged();
// Corner case: the 0 position in a tab may change when going into
// virtualedit. Recalculate curwin->w_cursor to avoid bad highlighting.
//
diff --git a/src/nvim/state.c b/src/nvim/state.c
index 4eb0073873..71db25664f 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -136,7 +136,7 @@ int get_real_state(void)
/// @returns[allocated] mode string
char *get_mode(void)
{
- char *buf = xcalloc(4, sizeof(char));
+ char *buf = xcalloc(MODE_MAX_LENGTH, sizeof(char));
if (VIsual_active) {
if (VIsual_select) {
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 23ad8dbfc5..75e30502b8 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1644,4 +1644,38 @@ func Test_read_invalid()
set encoding=utf-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']
+ 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"))
+ call assert_equal(mode(), get(v:event, "new_mode"))
+ let g:index += 1
+ 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)
+
+ au! ModeChanged
+ delfunc TestMode
+ unlet! g:mode_seq
+ unlet! g:index
+ delfunc DoIt
+ unlet! g:count
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 726670f082..e3539c1a57 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -72,6 +72,8 @@ enum { NUMBUFLEN = 65, };
#define TERM_FOCUS 0x2000 // Terminal focus mode
#define CMDPREVIEW 0x4000 // Showing 'inccommand' command "live" preview.
+#define MODE_MAX_LENGTH 4 // max mode length returned in mode()
+
// all mode bits used for mapping
#define MAP_ALL_MODES (0x3f | SELECTMODE | TERM_FOCUS)