diff options
-rw-r--r-- | src/nvim/buffer_defs.h | 6 | ||||
-rw-r--r-- | src/nvim/eval.c | 5 | ||||
-rw-r--r-- | src/nvim/fileio.c | 5 | ||||
-rw-r--r-- | src/nvim/getchar.c | 58 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 28 |
5 files changed, 63 insertions, 39 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 97e443547c..057f99e341 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -143,6 +143,12 @@ struct buffheader { size_t bh_space; // space in bh_curr for appending }; +typedef struct +{ + buffheader_T sr_redobuff; + buffheader_T sr_old_redobuff; +} save_redo_T; + /* * Structure that contains all options that are local to a window. * Used twice in a window: for the current buffer and for all buffers. diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d0e312475c..86ed9052aa 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -21174,6 +21174,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, proftime_T wait_start; proftime_T call_start; bool did_save_redo = false; + save_redo_T save_redo; /* If depth of calling is getting too high, don't execute the function */ if (depth >= p_mfd) { @@ -21186,7 +21187,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, // Save search patterns and redo buffer. save_search_patterns(); if (!ins_compl_active()) { - saveRedobuff(); + saveRedobuff(&save_redo); did_save_redo = true; } ++fp->uf_calls; @@ -21501,7 +21502,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, } // restore search patterns and redo buffer if (did_save_redo) { - restoreRedobuff(); + restoreRedobuff(&save_redo); } restore_search_patterns(); } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 5ddb3952de..0858436db3 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -6696,6 +6696,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, static int filechangeshell_busy = FALSE; proftime_T wait_time; bool did_save_redobuff = false; + save_redo_T save_redo; // Quickly return if there are no autocommands for this event or // autocommands are blocked. @@ -6876,7 +6877,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, if (!autocmd_busy) { save_search_patterns(); if (!ins_compl_active()) { - saveRedobuff(); + saveRedobuff(&save_redo); did_save_redobuff = true; } did_filetype = keep_filetype; @@ -6965,7 +6966,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, if (!autocmd_busy) { restore_search_patterns(); if (did_save_redobuff) { - restoreRedobuff(); + restoreRedobuff(&save_redo); } did_filetype = FALSE; while (au_pending_free_buf != NULL) { diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index a77c467fe5..563608dd1d 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -78,11 +78,9 @@ FileDescriptor *scriptin[NSCRIPT] = { NULL }; #define MINIMAL_SIZE 20 /* minimal size for b_str */ -static buffheader_T redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -static buffheader_T old_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -static buffheader_T save_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -static buffheader_T save_old_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -static buffheader_T recordbuff = {{NULL, {NUL}}, NULL, 0, 0}; +static buffheader_T redobuff = { { NULL, { NUL } }, NULL, 0, 0 }; +static buffheader_T old_redobuff = { { NULL, { NUL } }, NULL, 0, 0 }; +static buffheader_T recordbuff = { { NULL, { NUL } }, NULL, 0, 0 }; // First read ahead buffer. Used for translated commands. static buffheader_T readbuf1 = {{NULL, {NUL}}, NULL, 0, 0}; @@ -480,41 +478,31 @@ void CancelRedo(void) } } -/* - * Save redobuff and old_redobuff to save_redobuff and save_old_redobuff. - * Used before executing autocommands and user functions. - */ -static int save_level = 0; - -void saveRedobuff(void) +/// Save redobuff and old_redobuff to save_redobuff and save_old_redobuff. +/// Used before executing autocommands and user functions. +void saveRedobuff(save_redo_T *save_redo) { - if (save_level++ == 0) { - save_redobuff = redobuff; - redobuff.bh_first.b_next = NULL; - save_old_redobuff = old_redobuff; - old_redobuff.bh_first.b_next = NULL; - - // Make a copy, so that ":normal ." in a function works. - char *const s = (char *)get_buffcont(&save_redobuff, false); - if (s != NULL) { - add_buff(&redobuff, s, -1L); - xfree(s); - } + save_redo->sr_redobuff = redobuff; + redobuff.bh_first.b_next = NULL; + save_redo->sr_old_redobuff = old_redobuff; + old_redobuff.bh_first.b_next = NULL; + + // Make a copy, so that ":normal ." in a function works. + char *const s = (char *)get_buffcont(&save_redo->sr_redobuff, false); + if (s != NULL) { + add_buff(&redobuff, s, -1L); + xfree(s); } } -/* - * Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff. - * Used after executing autocommands and user functions. - */ -void restoreRedobuff(void) +/// Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff. +/// Used after executing autocommands and user functions. +void restoreRedobuff(save_redo_T *save_redo) { - if (--save_level == 0) { - free_buff(&redobuff); - redobuff = save_redobuff; - free_buff(&old_redobuff); - old_redobuff = save_old_redobuff; - } + free_buff(&redobuff); + redobuff = save_redo->sr_redobuff; + free_buff(&old_redobuff); + old_redobuff = save_redo->sr_old_redobuff; } /* diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 3028f72fec..c59134908c 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -795,3 +795,31 @@ func Test_shellescape() let &shell = save_shell endfunc + +func Test_redo_in_nested_functions() + nnoremap g. :set opfunc=Operator<CR>g@ + function Operator( type, ... ) + let @x = 'XXX' + execute 'normal! g`[' . (a:type ==# 'line' ? 'V' : 'v') . 'g`]' . '"xp' + endfunction + + function! Apply() + 5,6normal! . + endfunction + + new + call setline(1, repeat(['some "quoted" text', 'more "quoted" text'], 3)) + 1normal g.i" + call assert_equal('some "XXX" text', getline(1)) + 3,4normal . + call assert_equal('some "XXX" text', getline(3)) + call assert_equal('more "XXX" text', getline(4)) + call Apply() + call assert_equal('some "XXX" text', getline(5)) + call assert_equal('more "XXX" text', getline(6)) + bwipe! + + nunmap g. + delfunc Operator + delfunc Apply +endfunc |