Mercurial > vim
diff src/undo.c @ 2189:cb94c42c0e1a v7.2.445
updated for version 7.2.445
Problem: Crash when using undo/redo and a FileChangedRO autocmd event that
reloads the buffer. (Dominique Pelle)
Solution: Do not allow autocommands while performing and undo or redo.
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Wed, 07 Jul 2010 18:20:28 +0200 |
parents | f838615313cd |
children | 073ff46fe397 |
line wrap: on
line diff
--- a/src/undo.c +++ b/src/undo.c @@ -185,7 +185,7 @@ u_check_tree(u_header_T *uhp, } } - void + static void u_check(int newhead_may_be_NULL) { seen_b_u_newhead = 0; @@ -320,6 +320,9 @@ undo_allowed() return TRUE; } +/* + * Common code for various ways to save text before a change. + */ static int u_savecommon(top, bot, newbot) linenr_T top, bot; @@ -374,7 +377,7 @@ u_savecommon(top, bot, newbot) size = bot - top - 1; /* - * if curbuf->b_u_synced == TRUE make a new header + * If curbuf->b_u_synced == TRUE make a new header. */ if (curbuf->b_u_synced) { @@ -709,6 +712,12 @@ u_doit(startcount) u_oldcount = -1; while (count--) { + /* Do the change warning now, so that it triggers FileChangedRO when + * needed. This may cause the file to be reloaded, that must happen + * before we do anything, because it may change curbuf->b_u_curhead + * and more. */ + change_warning(0); + if (undo_undoes) { if (curbuf->b_u_curhead == NULL) /* first undo */ @@ -952,8 +961,11 @@ undo_time(step, sec, absolute) /* * First go up the tree as much as needed. */ - for (;;) + while (!got_int) { + /* Do the change warning now, for the same reason as above. */ + change_warning(0); + uhp = curbuf->b_u_curhead; if (uhp == NULL) uhp = curbuf->b_u_newhead; @@ -970,9 +982,15 @@ undo_time(step, sec, absolute) /* * And now go down the tree (redo), branching off where needed. */ - uhp = curbuf->b_u_curhead; - while (uhp != NULL) + while (!got_int) { + /* Do the change warning now, for the same reason as above. */ + change_warning(0); + + uhp = curbuf->b_u_curhead; + if (uhp == NULL) + break; + /* Go back to the first branch with a mark. */ while (uhp->uh_alt_prev != NULL && uhp->uh_alt_prev->uh_walk == mark) @@ -1070,6 +1088,12 @@ u_undoredo(undo) int empty_buffer; /* buffer became empty */ u_header_T *curhead = curbuf->b_u_curhead; +#ifdef FEAT_AUTOCMD + /* Don't want autocommands using the undo structures here, they are + * invalid till the end. */ + block_autocmds(); +#endif + #ifdef U_DEBUG u_check(FALSE); #endif @@ -1099,6 +1123,9 @@ u_undoredo(undo) if (top > curbuf->b_ml.ml_line_count || top >= bot || bot > curbuf->b_ml.ml_line_count + 1) { +#ifdef FEAT_AUTOCMD + unblock_autocmds(); +#endif EMSG(_("E438: u_undo: line numbers wrong")); changed(); /* don't want UNCHANGED now */ return; @@ -1304,6 +1331,10 @@ u_undoredo(undo) /* The timestamp can be the same for multiple changes, just use the one of * the undone/redone change. */ curbuf->b_u_seq_time = curhead->uh_time; + +#ifdef FEAT_AUTOCMD + unblock_autocmds(); +#endif #ifdef U_DEBUG u_check(FALSE); #endif