diff options
-rw-r--r-- | src/nvim/ex_cmds2.c | 22 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 33 | ||||
-rw-r--r-- | test/old/testdir/test_autocmd.vim | 59 |
4 files changed, 102 insertions, 13 deletions
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 6d190df939..4d71285447 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -38,6 +38,7 @@ #include "nvim/move.h" #include "nvim/normal.h" #include "nvim/option.h" +#include "nvim/optionstr.h" #include "nvim/os/os_defs.h" #include "nvim/path.h" #include "nvim/pos.h" @@ -467,7 +468,6 @@ void ex_listdo(exarg_T *eap) | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) { int next_fnum = 0; - char *p_shm_save; int i = 0; // start at the eap->line1 argument/window/buffer wp = firstwin; @@ -514,7 +514,9 @@ void ex_listdo(exarg_T *eap) if (qf_size == 0 || (size_t)eap->line1 > qf_size) { buf = NULL; } else { + save_clear_shm_value(); ex_cc(eap); + restore_shm_value(); buf = curbuf; i = (int)eap->line1 - 1; @@ -541,11 +543,9 @@ void ex_listdo(exarg_T *eap) if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) { // Clear 'shm' to avoid that the file message overwrites // any output from the command. - p_shm_save = xstrdup(p_shm); - set_option_value_give_err("shm", 0L, "", 0); + save_clear_shm_value(); do_argfile(eap, i); - set_option_value_give_err("shm", 0L, p_shm_save, 0); - xfree(p_shm_save); + restore_shm_value(); } if (curwin->w_arg_idx != i) { break; @@ -610,11 +610,9 @@ void ex_listdo(exarg_T *eap) // Go to the next buffer. Clear 'shm' to avoid that the file // message overwrites any output from the command. - p_shm_save = xstrdup(p_shm); - set_option_value_give_err("shm", 0L, "", 0); + save_clear_shm_value(); goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); - set_option_value_give_err("shm", 0L, p_shm_save, 0); - xfree(p_shm_save); + restore_shm_value(); // If autocommands took us elsewhere, quit here. if (curbuf->b_fnum != next_fnum) { @@ -633,11 +631,9 @@ void ex_listdo(exarg_T *eap) // Clear 'shm' to avoid that the file message overwrites // any output from the command. - p_shm_save = xstrdup(p_shm); - set_option_value_give_err("shm", 0L, "", 0); + save_clear_shm_value(); ex_cnext(eap); - set_option_value_give_err("shm", 0L, p_shm_save, 0); - xfree(p_shm_save); + restore_shm_value(); // If jumping to the next quickfix entry fails, quit here. if (qf_get_cur_idx(eap) == qf_idx) { diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index b7ea8cd2c2..66d5b7280a 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -260,6 +260,7 @@ enum { SHM_RECORDING = 'q', ///< Short recording message. SHM_FILEINFO = 'F', ///< No file info messages. SHM_SEARCHCOUNT = 'S', ///< Search stats: '[1/10]' + SHM_LEN = 30, ///< Max length of all flags together plus a NUL character. }; /// Represented by 'a' flag. #define SHM_ALL_ABBREVIATIONS ((char[]) { \ diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 3372c7b6c6..6c6190cb08 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -67,6 +67,8 @@ static const char e_backupext_and_patchmode_are_equal[] = N_("E589: 'backupext' and 'patchmode' are equal"); static const char e_showbreak_contains_unprintable_or_wide_character[] = N_("E595: 'showbreak' contains unprintable or wide character"); +static const char e_internal_error_shortmess_too_long[] + = N_("E1336: Internal error: shortmess too long"); static char *(p_ambw_values[]) = { "single", "double", NULL }; static char *(p_bg_values[]) = { "light", "dark", NULL }; @@ -1941,6 +1943,37 @@ int check_ff_value(char *p) return check_opt_strings(p, p_ff_values, false); } +static char shm_buf[SHM_LEN]; +static int set_shm_recursive = 0; + +/// Save the acutal shortmess Flags and clear them +/// temporarily to avoid that file messages +/// overwrites any output from the following commands. +/// +/// Caller must make sure to first call save_clear_shm_value() and then +/// restore_shm_value() exactly the same number of times. +void save_clear_shm_value(void) +{ + if (strlen(p_shm) >= SHM_LEN) { + iemsg(e_internal_error_shortmess_too_long); + return; + } + + if (++set_shm_recursive == 1) { + STRCPY(shm_buf, p_shm); + set_option_value_give_err("shm", 0L, "", 0); + } +} + +/// Restore the shortmess Flags set from the save_clear_shm_value() function. +void restore_shm_value(void) +{ + if (--set_shm_recursive == 0) { + set_option_value_give_err("shm", 0L, shm_buf, 0); + memset(shm_buf, 0, SHM_LEN); + } +} + static const char e_conflicts_with_value_of_listchars[] = N_("E834: Conflicts with value of 'listchars'"); static const char e_conflicts_with_value_of_fillchars[] diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index ec671369f5..f91792e36e 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -56,6 +56,9 @@ if has('timers') endfunc func Test_cursorhold_insert() + " depends on timing + let g:test_is_flaky = 1 + " Need to move the cursor. call feedkeys("ggG", "xt") @@ -3623,5 +3626,61 @@ func Test_autocmd_nested_setbufvar() %bwipe! endfunc +func SetupVimTest_shm() + let g:bwe = [] + let g:brp = [] + set shortmess+=F + messages clear + + let dirname='XVimTestSHM' + call mkdir(dirname, 'R') + call writefile(['test'], dirname .. '/1') + call writefile(['test'], dirname .. '/2') + call writefile(['test'], dirname .. '/3') + + augroup test + autocmd! + autocmd BufWinEnter * call add(g:bwe, $'BufWinEnter: {expand('<amatch>')}') + autocmd BufReadPost * call add(g:brp, $'BufReadPost: {expand('<amatch>')}') + augroup END + + call setqflist([ + \ {'filename': dirname .. '/1', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0}, + \ {'filename': dirname .. '/2', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0}, + \ {'filename': dirname .. '/3', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0} + \ ]) + cdo! substitute/test/TEST + + " clean up + noa enew! + set shortmess&vim + augroup test + autocmd! + augroup END + augroup! test +endfunc + +func Test_autocmd_shortmess() + CheckNotMSWindows + + call SetupVimTest_shm() + let output = execute(':mess')->split('\n') + + let info = copy(output)->filter({idx, val -> val =~# '\d of 3'} ) + let bytes = copy(output)->filter({idx, val -> val =~# 'bytes'} ) + + " We test the following here: + " BufReadPost should have been triggered 3 times, once per file + " BufWinEnter should have been triggered 3 times, once per file + " FileInfoMessage should have been shown 3 times, regardless of shm option + " "(x of 3)" message from :cnext has been shown 3 times + + call assert_equal(3, g:brp->len()) + call assert_equal(3, g:bwe->len()) + call assert_equal(3, info->len()) + call assert_equal(3, bytes->len()) + + delfunc SetupVimTest_shm +endfunc " vim: shiftwidth=2 sts=2 expandtab |