From aa0e09d251610f9b17f0bf96a4f3485032c36e0f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 7 Nov 2016 22:48:39 +0100 Subject: 'inccommand': Preserve curbuf->b_u_newhead. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for undotree(). Helped-by: Björn Linse When "curhead" points to a valid head, the value of "newhead" is meaningless (and really should be set to null). The undo state for a buffer is _logically_ the enum: enum UndoState { CurrentHead(head), NewHead(head), EmptyTree } nvim _represents_ this as: whenever `curbuf->b_u_curhead` is nonnull it should be used as the current head, and `curbuf->b_u_newhead` is ignored. If the there is a current head, then this will be redoed on the next redo, and its parent will be undone on next undo. Only if `b_u_curhead` is NULL, `b_u_newhead` will be used as the head to undo (and it is not possible to redo). Also both can be NULL, to indicate an empty undotree. (To be fair, this only strictly true when calling undo.c from the outside, in some places _within_ a function in undo.c both values might be meaningful) Apparently `undotree()` breaks this non-abstraction, this _cosmetic_ issue can easily be fixed by `ex_substitute` also saving and restoring `b_u_newhead`, but is doesn't reflect any error really how `u_undo_and_forget` manipulates the _actual_ state of the undo tree. --- src/nvim/ex_cmds.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/nvim/ex_cmds.c') diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 6987bcfd89..0190db258f 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -6140,6 +6140,8 @@ void ex_substitute(exarg_T *eap) char_u *save_eap = eap->arg; save_search_patterns(); int save_changedtick = curbuf->b_changedtick; + time_t save_b_u_time_cur = curbuf->b_u_time_cur; + u_header_T *save_b_u_newhead = curbuf->b_u_newhead; long save_b_p_ul = curbuf->b_p_ul; curbuf->b_p_ul = LONG_MAX; // make sure we can undo all changes block_autocmds(); // disable events before show_sub() opens window/buffer @@ -6147,15 +6149,18 @@ void ex_substitute(exarg_T *eap) buf_T *preview_buf = do_sub(eap); - if (save_changedtick != curbuf->b_changedtick - && !u_undo_and_forget(1)) { - abort(); + if (save_changedtick != curbuf->b_changedtick) { + if (!u_undo_and_forget(1)) { abort(); } + // Restore newhead. It is meaningless when curhead is valid, but we must + // restore it so that undotree() is identical before/after the preview. + curbuf->b_u_newhead = save_b_u_newhead; + curbuf->b_u_time_cur = save_b_u_time_cur; + curbuf->b_changedtick = save_changedtick; } if (buf_valid(preview_buf)) { // XXX: Must do this *after* u_undo_and_forget(), why? close_windows(preview_buf, false); } - curbuf->b_changedtick = save_changedtick; curbuf->b_p_ul = save_b_p_ul; eap->arg = save_eap; restore_search_patterns(); -- cgit