vim-patch:8.0.0548: saving the redo buffer only works one time (#8629)

Problem:    Saving the redo buffer only works one time, resulting in the "."
            command not working well for a function call inside another
            function call. (Ingo Karkat)
Solution:   Save the redo buffer at every user function call. (closes vim/vim#1619)
d4863aa99e
This commit is contained in:
KunMing Xie
2018-06-25 04:16:57 +08:00
committed by Justin M. Keyes
parent 83be7cec98
commit 38fb835854
5 changed files with 62 additions and 38 deletions

View File

@@ -143,6 +143,12 @@ struct buffheader {
size_t bh_space; // space in bh_curr for appending 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. * Structure that contains all options that are local to a window.
* Used twice in a window: for the current buffer and for all buffers. * Used twice in a window: for the current buffer and for all buffers.

View File

@@ -21174,6 +21174,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
proftime_T wait_start; proftime_T wait_start;
proftime_T call_start; proftime_T call_start;
bool did_save_redo = false; 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 of calling is getting too high, don't execute the function */
if (depth >= p_mfd) { 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 and redo buffer.
save_search_patterns(); save_search_patterns();
if (!ins_compl_active()) { if (!ins_compl_active()) {
saveRedobuff(); saveRedobuff(&save_redo);
did_save_redo = true; did_save_redo = true;
} }
++fp->uf_calls; ++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 // restore search patterns and redo buffer
if (did_save_redo) { if (did_save_redo) {
restoreRedobuff(); restoreRedobuff(&save_redo);
} }
restore_search_patterns(); restore_search_patterns();
} }

View File

@@ -6696,6 +6696,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
static int filechangeshell_busy = FALSE; static int filechangeshell_busy = FALSE;
proftime_T wait_time; proftime_T wait_time;
bool did_save_redobuff = false; bool did_save_redobuff = false;
save_redo_T save_redo;
// Quickly return if there are no autocommands for this event or // Quickly return if there are no autocommands for this event or
// autocommands are blocked. // 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) { if (!autocmd_busy) {
save_search_patterns(); save_search_patterns();
if (!ins_compl_active()) { if (!ins_compl_active()) {
saveRedobuff(); saveRedobuff(&save_redo);
did_save_redobuff = true; did_save_redobuff = true;
} }
did_filetype = keep_filetype; 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) { if (!autocmd_busy) {
restore_search_patterns(); restore_search_patterns();
if (did_save_redobuff) { if (did_save_redobuff) {
restoreRedobuff(); restoreRedobuff(&save_redo);
} }
did_filetype = FALSE; did_filetype = FALSE;
while (au_pending_free_buf != NULL) { while (au_pending_free_buf != NULL) {

View File

@@ -78,11 +78,9 @@ FileDescriptor *scriptin[NSCRIPT] = { NULL };
#define MINIMAL_SIZE 20 /* minimal size for b_str */ #define MINIMAL_SIZE 20 /* minimal size for b_str */
static buffheader_T redobuff = {{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 old_redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
static buffheader_T save_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; static buffheader_T recordbuff = { { 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};
// First read ahead buffer. Used for translated commands. // First read ahead buffer. Used for translated commands.
static buffheader_T readbuf1 = {{NULL, {NUL}}, NULL, 0, 0}; 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.
* Save redobuff and old_redobuff to save_redobuff and save_old_redobuff. /// Used before executing autocommands and user functions.
* Used before executing autocommands and user functions. void saveRedobuff(save_redo_T *save_redo)
*/
static int save_level = 0;
void saveRedobuff(void)
{ {
if (save_level++ == 0) { save_redo->sr_redobuff = redobuff;
save_redobuff = redobuff;
redobuff.bh_first.b_next = NULL; redobuff.bh_first.b_next = NULL;
save_old_redobuff = old_redobuff; save_redo->sr_old_redobuff = old_redobuff;
old_redobuff.bh_first.b_next = NULL; old_redobuff.bh_first.b_next = NULL;
// Make a copy, so that ":normal ." in a function works. // Make a copy, so that ":normal ." in a function works.
char *const s = (char *)get_buffcont(&save_redobuff, false); char *const s = (char *)get_buffcont(&save_redo->sr_redobuff, false);
if (s != NULL) { if (s != NULL) {
add_buff(&redobuff, s, -1L); add_buff(&redobuff, s, -1L);
xfree(s); xfree(s);
} }
}
} }
/* /// Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff.
* Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff. /// Used after executing autocommands and user functions.
* Used after executing autocommands and user functions. void restoreRedobuff(save_redo_T *save_redo)
*/
void restoreRedobuff(void)
{ {
if (--save_level == 0) {
free_buff(&redobuff); free_buff(&redobuff);
redobuff = save_redobuff; redobuff = save_redo->sr_redobuff;
free_buff(&old_redobuff); free_buff(&old_redobuff);
old_redobuff = save_old_redobuff; old_redobuff = save_redo->sr_old_redobuff;
}
} }
/* /*

View File

@@ -795,3 +795,31 @@ func Test_shellescape()
let &shell = save_shell let &shell = save_shell
endfunc 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