aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/buffer_defs.h6
-rw-r--r--src/nvim/eval.c5
-rw-r--r--src/nvim/fileio.c5
-rw-r--r--src/nvim/getchar.c58
-rw-r--r--src/nvim/testdir/test_functions.vim28
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