# HG changeset patch # User Christian Brabandt # Date 1491588004 -7200 # Node ID 77f3b7316d8ba66232d0cfb4d465c06ea52eda35 # Parent c9adf54ef624ef39dd3712a7caee58404af0f6b4 patch 8.0.0548: saving the redo buffer only works one time commit https://github.com/vim/vim/commit/d4863aa99e0527e9505c79cbeafc68a6832200bf Author: Bram Moolenaar Date: Fri Apr 7 19:50:12 2017 +0200 patch 8.0.0548: saving the redo buffer only works one time 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 #1619) diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -9316,6 +9316,7 @@ apply_autocmds_group( proftime_T wait_time; #endif int did_save_redobuff = FALSE; + save_redo_T save_redo; /* * Quickly return if there are no autocommands for this event or @@ -9521,7 +9522,7 @@ apply_autocmds_group( if (!ins_compl_active()) #endif { - saveRedobuff(); + saveRedobuff(&save_redo); did_save_redobuff = TRUE; } did_filetype = keep_filetype; @@ -9624,7 +9625,7 @@ apply_autocmds_group( { restore_search_patterns(); if (did_save_redobuff) - restoreRedobuff(); + restoreRedobuff(&save_redo); did_filetype = FALSE; while (au_pending_free_buf != NULL) { diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -42,10 +42,6 @@ static buffheader_T redobuff = {{NULL, {NUL}}, NULL, 0, 0}; static buffheader_T old_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO) -static buffheader_T save_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -static buffheader_T save_old_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -#endif static buffheader_T recordbuff = {{NULL, {NUL}}, NULL, 0, 0}; static int typeahead_char = 0; /* typeahead char that's not flushed */ @@ -521,27 +517,22 @@ 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) +saveRedobuff(save_redo_T *save_redo) { char_u *s; - if (save_level++ == 0) + 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. */ + s = get_buffcont(&save_redo->sr_redobuff, FALSE); + if (s != NULL) { - 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. */ - s = get_buffcont(&save_redobuff, FALSE); - if (s != NULL) - { - add_buff(&redobuff, s, -1L); - vim_free(s); - } + add_buff(&redobuff, s, -1L); + vim_free(s); } } @@ -550,15 +541,12 @@ saveRedobuff(void) * Used after executing autocommands and user functions. */ void -restoreRedobuff(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; } #endif diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -8,8 +8,8 @@ void typeahead_noflush(int c); void flush_buffers(int flush_typeahead); void ResetRedobuff(void); void CancelRedo(void); -void saveRedobuff(void); -void restoreRedobuff(void); +void saveRedobuff(save_redo_T *save_redo); +void restoreRedobuff(save_redo_T *save_redo); void AppendToRedobuff(char_u *s); void AppendToRedobuffLit(char_u *str, int len); void AppendCharToRedobuff(int c); diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -515,6 +515,12 @@ struct buffheader int bh_space; /* space in bh_curr for appending */ }; +typedef struct +{ + buffheader_T sr_redobuff; + buffheader_T sr_old_redobuff; +} save_redo_T; + /* * used for completion on the command line */ diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -756,3 +756,31 @@ func Test_setbufvar_options() call win_gotoid(dum1_id) bwipe! endfunc + +func Test_redo_in_nested_functions() + nnoremap g. :set opfunc=Operatorg@ + 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 diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1408,6 +1408,7 @@ call_func( else { int did_save_redo = FALSE; + save_redo_T save_redo; /* * Call the user function. @@ -1419,7 +1420,7 @@ call_func( if (!ins_compl_active()) #endif { - saveRedobuff(); + saveRedobuff(&save_redo); did_save_redo = TRUE; } ++fp->uf_calls; @@ -1431,7 +1432,7 @@ call_func( * now. */ func_clear_free(fp, FALSE); if (did_save_redo) - restoreRedobuff(); + restoreRedobuff(&save_redo); restore_search_patterns(); error = ERROR_NONE; } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 548, +/**/ 547, /**/ 546,