diff options
author | Magnus Groß <magnus.gross@rwth-aachen.de> | 2021-09-29 16:36:48 +0200 |
---|---|---|
committer | Magnus Groß <magnus.gross@rwth-aachen.de> | 2021-11-18 11:23:18 +0100 |
commit | 69bd1e4e36fa3e3f604740c92b15b13141520822 (patch) | |
tree | bcff79c6cef4d64707ce1819d18c466872304bcc /src | |
parent | 36538417f027758ee50faf50c5e4dcc6cb73431d (diff) | |
download | rneovim-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.lua | 1 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 13 | ||||
-rw-r--r-- | src/nvim/edit.c | 3 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 1 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/globals.h | 1 | ||||
-rw-r--r-- | src/nvim/memory.c | 1 | ||||
-rw-r--r-- | src/nvim/misc1.c | 29 | ||||
-rw-r--r-- | src/nvim/normal.c | 3 | ||||
-rw-r--r-- | src/nvim/state.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_edit.vim | 34 | ||||
-rw-r--r-- | src/nvim/vim.h | 2 |
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) |