Merge #8877 from janlazo/vim-8.0.1441

This commit is contained in:
Justin M. Keyes 2018-08-21 09:33:09 +02:00 committed by GitHub
commit 3807520001
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 176 additions and 117 deletions

View File

@ -7577,10 +7577,11 @@ static void ex_bang(exarg_T *eap)
*/ */
static void ex_undo(exarg_T *eap) static void ex_undo(exarg_T *eap)
{ {
if (eap->addr_count == 1) /* :undo 123 */ if (eap->addr_count == 1) { // :undo 123
undo_time(eap->line2, FALSE, FALSE, TRUE); undo_time(eap->line2, false, false, true);
else } else {
u_undo(1); u_undo(1);
}
} }
static void ex_wundo(exarg_T *eap) static void ex_wundo(exarg_T *eap)
@ -7613,8 +7614,8 @@ static void ex_redo(exarg_T *eap)
static void ex_later(exarg_T *eap) static void ex_later(exarg_T *eap)
{ {
long count = 0; long count = 0;
int sec = FALSE; bool sec = false;
int file = FALSE; bool file = false;
char_u *p = eap->arg; char_u *p = eap->arg;
if (*p == NUL) if (*p == NUL)
@ -7622,11 +7623,11 @@ static void ex_later(exarg_T *eap)
else if (isdigit(*p)) { else if (isdigit(*p)) {
count = getdigits_long(&p); count = getdigits_long(&p);
switch (*p) { switch (*p) {
case 's': ++p; sec = TRUE; break; case 's': ++p; sec = true; break;
case 'm': ++p; sec = TRUE; count *= 60; break; case 'm': ++p; sec = true; count *= 60; break;
case 'h': ++p; sec = TRUE; count *= 60 * 60; break; case 'h': ++p; sec = true; count *= 60 * 60; break;
case 'd': ++p; sec = TRUE; count *= 24 * 60 * 60; break; case 'd': ++p; sec = true; count *= 24 * 60 * 60; break;
case 'f': ++p; file = TRUE; break; case 'f': ++p; file = true; break;
} }
} }
@ -7634,7 +7635,7 @@ static void ex_later(exarg_T *eap)
EMSG2(_(e_invarg2), eap->arg); EMSG2(_(e_invarg2), eap->arg);
else else
undo_time(eap->cmdidx == CMD_earlier ? -count : count, undo_time(eap->cmdidx == CMD_earlier ? -count : count,
sec, file, FALSE); sec, file, false);
} }
/* /*

View File

@ -390,3 +390,47 @@ funct Test_undofile()
set undodir& set undodir&
endfunc endfunc
func Test_undo_0()
new
set ul=100
normal i1
undo
normal i2
undo
normal i3
undo 0
let d = undotree()
call assert_equal('', getline(1))
call assert_equal(0, d.seq_cur)
redo
let d = undotree()
call assert_equal('3', getline(1))
call assert_equal(3, d.seq_cur)
undo 2
undo 0
let d = undotree()
call assert_equal('', getline(1))
call assert_equal(0, d.seq_cur)
redo
let d = undotree()
call assert_equal('2', getline(1))
call assert_equal(2, d.seq_cur)
undo 1
undo 0
let d = undotree()
call assert_equal('', getline(1))
call assert_equal(0, d.seq_cur)
redo
let d = undotree()
call assert_equal('1', getline(1))
call assert_equal(1, d.seq_cur)
bwipe!
endfunc

View File

@ -122,7 +122,7 @@ static long u_newcount, u_oldcount;
* When 'u' flag included in 'cpoptions', we behave like vi. Need to remember * When 'u' flag included in 'cpoptions', we behave like vi. Need to remember
* the action that "u" should do. * the action that "u" should do.
*/ */
static int undo_undoes = FALSE; static bool undo_undoes = false;
static int lastmark = 0; static int lastmark = 0;
@ -591,7 +591,7 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
uep->ue_next = curbuf->b_u_newhead->uh_entry; uep->ue_next = curbuf->b_u_newhead->uh_entry;
curbuf->b_u_newhead->uh_entry = uep; curbuf->b_u_newhead->uh_entry = uep;
curbuf->b_u_synced = false; curbuf->b_u_synced = false;
undo_undoes = FALSE; undo_undoes = false;
#ifdef U_DEBUG #ifdef U_DEBUG
u_check(FALSE); u_check(FALSE);
@ -1675,10 +1675,11 @@ void u_undo(int count)
count = 1; count = 1;
} }
if (vim_strchr(p_cpo, CPO_UNDO) == NULL) if (vim_strchr(p_cpo, CPO_UNDO) == NULL) {
undo_undoes = TRUE; undo_undoes = true;
else } else {
undo_undoes = !undo_undoes; undo_undoes = !undo_undoes;
}
u_doit(count, false, true); u_doit(count, false, true);
} }
@ -1804,31 +1805,29 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event)
u_undo_end(undo_undoes, false, quiet); u_undo_end(undo_undoes, false, quiet);
} }
/* // Undo or redo over the timeline.
* Undo or redo over the timeline. // When "step" is negative go back in time, otherwise goes forward in time.
* When "step" is negative go back in time, otherwise goes forward in time. // When "sec" is false make "step" steps, when "sec" is true use "step" as
* When "sec" is FALSE make "step" steps, when "sec" is TRUE use "step" as // seconds.
* seconds. // When "file" is true use "step" as a number of file writes.
* When "file" is TRUE use "step" as a number of file writes. // When "absolute" is true use "step" as the sequence number to jump to.
* When "absolute" is TRUE use "step" as the sequence number to jump to. // "sec" must be false then.
* "sec" must be FALSE then. void undo_time(long step, bool sec, bool file, bool absolute)
*/
void undo_time(long step, int sec, int file, int absolute)
{ {
long target; long target;
long closest; long closest;
long closest_start; long closest_start;
long closest_seq = 0; long closest_seq = 0;
long val; long val;
u_header_T *uhp; u_header_T *uhp = NULL;
u_header_T *last; u_header_T *last;
int mark; int mark;
int nomark; int nomark;
int round; int round;
int dosec = sec; bool dosec = sec;
int dofile = file; bool dofile = file;
int above = FALSE; bool above = false;
int did_undo = TRUE; bool did_undo = true;
/* First make sure the current undoable change is synced. */ /* First make sure the current undoable change is synced. */
if (curbuf->b_u_synced == false) if (curbuf->b_u_synced == false)
@ -1842,13 +1841,7 @@ void undo_time(long step, int sec, int file, int absolute)
/* "target" is the node below which we want to be. /* "target" is the node below which we want to be.
* Init "closest" to a value we can't reach. */ * Init "closest" to a value we can't reach. */
if (absolute) { if (absolute) {
if (step == 0) { target = step;
// target 0 does not exist, got to 1 and above it.
target = 1;
above = true;
} else {
target = step;
}
closest = -1; closest = -1;
} else { } else {
if (dosec) { if (dosec) {
@ -1873,7 +1866,7 @@ void undo_time(long step, int sec, int file, int absolute)
if (target <= 0) if (target <= 0)
/* Go to before first write: before the oldest change. Use /* Go to before first write: before the oldest change. Use
* the sequence number for that. */ * the sequence number for that. */
dofile = FALSE; dofile = false;
} else { } else {
/* Moving forward to a newer write. */ /* Moving forward to a newer write. */
target = curbuf->b_u_save_nr_cur + step; target = curbuf->b_u_save_nr_cur + step;
@ -1881,7 +1874,7 @@ void undo_time(long step, int sec, int file, int absolute)
/* Go to after last write: after the latest change. Use /* Go to after last write: after the latest change. Use
* the sequence number for that. */ * the sequence number for that. */
target = curbuf->b_u_seq_last + 1; target = curbuf->b_u_seq_last + 1;
dofile = FALSE; dofile = false;
} }
} }
} else } else
@ -1906,6 +1899,11 @@ void undo_time(long step, int sec, int file, int absolute)
closest_start = closest; closest_start = closest;
closest_seq = curbuf->b_u_seq_cur; closest_seq = curbuf->b_u_seq_cur;
// When "target" is 0; Back to origin.
if (target == 0) {
goto found;
}
/* /*
* May do this twice: * May do this twice:
* 1. Search for "target", update "closest" to the best match found. * 1. Search for "target", update "closest" to the best match found.
@ -2015,17 +2013,17 @@ void undo_time(long step, int sec, int file, int absolute)
} }
target = closest_seq; target = closest_seq;
dosec = FALSE; dosec = false;
dofile = FALSE; dofile = false;
if (step < 0) if (step < 0) {
above = TRUE; /* stop above the header */ above = true; // stop above the header
}
} }
/* If we found it: Follow the path to go to where we want to be. */ found:
if (uhp != NULL) { // If we found it: Follow the path to go to where we want to be.
/* if (uhp != NULL || target == 0) {
* First go up the tree as much as needed. // First go up the tree as much as needed.
*/
while (!got_int) { while (!got_int) {
/* Do the change warning now, for the same reason as above. */ /* Do the change warning now, for the same reason as above. */
change_warning(0); change_warning(0);
@ -2035,83 +2033,97 @@ void undo_time(long step, int sec, int file, int absolute)
uhp = curbuf->b_u_newhead; uhp = curbuf->b_u_newhead;
else else
uhp = uhp->uh_next.ptr; uhp = uhp->uh_next.ptr;
if (uhp == NULL || uhp->uh_walk != mark if (uhp == NULL
|| (uhp->uh_seq == target && !above)) || (target > 0 && uhp->uh_walk != mark)
|| (uhp->uh_seq == target && !above)) {
break; break;
}
curbuf->b_u_curhead = uhp; curbuf->b_u_curhead = uhp;
u_undoredo(true, true); u_undoredo(true, true);
uhp->uh_walk = nomark; // don't go back down here if (target > 0) {
uhp->uh_walk = nomark; // don't go back down here
}
} }
/* // When back to origin, redo is not needed.
* And now go down the tree (redo), branching off where needed. if (target > 0) {
*/ // And now go down the tree (redo), branching off where needed.
while (!got_int) { while (!got_int) {
/* Do the change warning now, for the same reason as above. */ // Do the change warning now, for the same reason as above.
change_warning(0); change_warning(0);
uhp = curbuf->b_u_curhead; uhp = curbuf->b_u_curhead;
if (uhp == NULL) if (uhp == NULL) {
break; break;
}
/* Go back to the first branch with a mark. */ // Go back to the first branch with a mark.
while (uhp->uh_alt_prev.ptr != NULL while (uhp->uh_alt_prev.ptr != NULL
&& uhp->uh_alt_prev.ptr->uh_walk == mark) && uhp->uh_alt_prev.ptr->uh_walk == mark) {
uhp = uhp->uh_alt_prev.ptr;
/* Find the last branch with a mark, that's the one. */
last = uhp;
while (last->uh_alt_next.ptr != NULL
&& last->uh_alt_next.ptr->uh_walk == mark)
last = last->uh_alt_next.ptr;
if (last != uhp) {
/* Make the used branch the first entry in the list of
* alternatives to make "u" and CTRL-R take this branch. */
while (uhp->uh_alt_prev.ptr != NULL)
uhp = uhp->uh_alt_prev.ptr; uhp = uhp->uh_alt_prev.ptr;
if (last->uh_alt_next.ptr != NULL) }
last->uh_alt_next.ptr->uh_alt_prev.ptr =
last->uh_alt_prev.ptr;
last->uh_alt_prev.ptr->uh_alt_next.ptr = last->uh_alt_next.ptr;
last->uh_alt_prev.ptr = NULL;
last->uh_alt_next.ptr = uhp;
uhp->uh_alt_prev.ptr = last;
if (curbuf->b_u_oldhead == uhp) // Find the last branch with a mark, that's the one.
curbuf->b_u_oldhead = last; last = uhp;
uhp = last; while (last->uh_alt_next.ptr != NULL
if (uhp->uh_next.ptr != NULL) && last->uh_alt_next.ptr->uh_walk == mark) {
uhp->uh_next.ptr->uh_prev.ptr = uhp; last = last->uh_alt_next.ptr;
} }
curbuf->b_u_curhead = uhp; if (last != uhp) {
// Make the used branch the first entry in the list of
// alternatives to make "u" and CTRL-R take this branch.
while (uhp->uh_alt_prev.ptr != NULL) {
uhp = uhp->uh_alt_prev.ptr;
}
if (last->uh_alt_next.ptr != NULL) {
last->uh_alt_next.ptr->uh_alt_prev.ptr = last->uh_alt_prev.ptr;
}
last->uh_alt_prev.ptr->uh_alt_next.ptr = last->uh_alt_next.ptr;
last->uh_alt_prev.ptr = NULL;
last->uh_alt_next.ptr = uhp;
uhp->uh_alt_prev.ptr = last;
if (uhp->uh_walk != mark) if (curbuf->b_u_oldhead == uhp) {
break; /* must have reached the target */ curbuf->b_u_oldhead = last;
}
uhp = last;
if (uhp->uh_next.ptr != NULL) {
uhp->uh_next.ptr->uh_prev.ptr = uhp;
}
}
curbuf->b_u_curhead = uhp;
/* Stop when going backwards in time and didn't find the exact if (uhp->uh_walk != mark) {
* header we were looking for. */ break; // must have reached the target
if (uhp->uh_seq == target && above) { }
curbuf->b_u_seq_cur = target - 1;
break;
}
u_undoredo(false, true); // Stop when going backwards in time and didn't find the exact
// header we were looking for.
if (uhp->uh_seq == target && above) {
curbuf->b_u_seq_cur = target - 1;
break;
}
/* Advance "curhead" to below the header we last used. If it u_undoredo(false, true);
* becomes NULL then we need to set "newhead" to this leaf. */
if (uhp->uh_prev.ptr == NULL)
curbuf->b_u_newhead = uhp;
curbuf->b_u_curhead = uhp->uh_prev.ptr;
did_undo = FALSE;
if (uhp->uh_seq == target) /* found it! */ // Advance "curhead" to below the header we last used. If it
break; // becomes NULL then we need to set "newhead" to this leaf.
if (uhp->uh_prev.ptr == NULL) {
curbuf->b_u_newhead = uhp;
}
curbuf->b_u_curhead = uhp->uh_prev.ptr;
did_undo = false;
uhp = uhp->uh_prev.ptr; if (uhp->uh_seq == target) { // found it!
if (uhp == NULL || uhp->uh_walk != mark) { break;
// Need to redo more but can't find it... }
internal_error("undo_time()");
break; uhp = uhp->uh_prev.ptr;
if (uhp == NULL || uhp->uh_walk != mark) {
// Need to redo more but can't find it...
internal_error("undo_time()");
break;
}
} }
} }
} }
@ -2375,8 +2387,8 @@ static void u_undoredo(int undo, bool do_buf_event)
/// Otherwise, report the number of changes (this may be incorrect /// Otherwise, report the number of changes (this may be incorrect
/// in some cases, but it's better than nothing). /// in some cases, but it's better than nothing).
static void u_undo_end( static void u_undo_end(
int did_undo, ///< just did an undo bool did_undo, ///< just did an undo
int absolute, ///< used ":undo N" bool absolute, ///< used ":undo N"
bool quiet) bool quiet)
{ {
char *msgstr; char *msgstr;
@ -2416,13 +2428,15 @@ static void u_undo_end(
/* For ":undo N" we prefer a "after #N" message. */ /* For ":undo N" we prefer a "after #N" message. */
if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL) { if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL) {
uhp = curbuf->b_u_curhead->uh_next.ptr; uhp = curbuf->b_u_curhead->uh_next.ptr;
did_undo = FALSE; did_undo = false;
} else if (did_undo) } else if (did_undo) {
uhp = curbuf->b_u_curhead; uhp = curbuf->b_u_curhead;
else } else {
uhp = curbuf->b_u_curhead->uh_next.ptr; uhp = curbuf->b_u_curhead->uh_next.ptr;
} else }
} else {
uhp = curbuf->b_u_newhead; uhp = curbuf->b_u_newhead;
}
if (uhp == NULL) if (uhp == NULL)
*msgbuf = NUL; *msgbuf = NUL;