mirror of
https://github.com/neovim/neovim.git
synced 2024-12-26 14:11:15 -07:00
Merge #8877 from janlazo/vim-8.0.1441
This commit is contained in:
commit
3807520001
@ -7577,10 +7577,11 @@ static void ex_bang(exarg_T *eap)
|
||||
*/
|
||||
static void ex_undo(exarg_T *eap)
|
||||
{
|
||||
if (eap->addr_count == 1) /* :undo 123 */
|
||||
undo_time(eap->line2, FALSE, FALSE, TRUE);
|
||||
else
|
||||
if (eap->addr_count == 1) { // :undo 123
|
||||
undo_time(eap->line2, false, false, true);
|
||||
} else {
|
||||
u_undo(1);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
long count = 0;
|
||||
int sec = FALSE;
|
||||
int file = FALSE;
|
||||
bool sec = false;
|
||||
bool file = false;
|
||||
char_u *p = eap->arg;
|
||||
|
||||
if (*p == NUL)
|
||||
@ -7622,11 +7623,11 @@ static void ex_later(exarg_T *eap)
|
||||
else if (isdigit(*p)) {
|
||||
count = getdigits_long(&p);
|
||||
switch (*p) {
|
||||
case 's': ++p; sec = TRUE; break;
|
||||
case 'm': ++p; sec = TRUE; count *= 60; break;
|
||||
case 'h': ++p; sec = TRUE; count *= 60 * 60; break;
|
||||
case 'd': ++p; sec = TRUE; count *= 24 * 60 * 60; break;
|
||||
case 'f': ++p; file = TRUE; break;
|
||||
case 's': ++p; sec = true; break;
|
||||
case 'm': ++p; sec = true; count *= 60; break;
|
||||
case 'h': ++p; sec = true; count *= 60 * 60; break;
|
||||
case 'd': ++p; sec = true; count *= 24 * 60 * 60; break;
|
||||
case 'f': ++p; file = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7634,7 +7635,7 @@ static void ex_later(exarg_T *eap)
|
||||
EMSG2(_(e_invarg2), eap->arg);
|
||||
else
|
||||
undo_time(eap->cmdidx == CMD_earlier ? -count : count,
|
||||
sec, file, FALSE);
|
||||
sec, file, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -390,3 +390,47 @@ funct Test_undofile()
|
||||
|
||||
set undodir&
|
||||
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
|
||||
|
226
src/nvim/undo.c
226
src/nvim/undo.c
@ -122,7 +122,7 @@ static long u_newcount, u_oldcount;
|
||||
* When 'u' flag included in 'cpoptions', we behave like vi. Need to remember
|
||||
* the action that "u" should do.
|
||||
*/
|
||||
static int undo_undoes = FALSE;
|
||||
static bool undo_undoes = false;
|
||||
|
||||
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;
|
||||
curbuf->b_u_newhead->uh_entry = uep;
|
||||
curbuf->b_u_synced = false;
|
||||
undo_undoes = FALSE;
|
||||
undo_undoes = false;
|
||||
|
||||
#ifdef U_DEBUG
|
||||
u_check(FALSE);
|
||||
@ -1675,10 +1675,11 @@ void u_undo(int count)
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
|
||||
undo_undoes = TRUE;
|
||||
else
|
||||
if (vim_strchr(p_cpo, CPO_UNDO) == NULL) {
|
||||
undo_undoes = true;
|
||||
} else {
|
||||
undo_undoes = !undo_undoes;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Undo or redo over the timeline.
|
||||
* 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
|
||||
* seconds.
|
||||
* 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.
|
||||
* "sec" must be FALSE then.
|
||||
*/
|
||||
void undo_time(long step, int sec, int file, int absolute)
|
||||
// Undo or redo over the timeline.
|
||||
// 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
|
||||
// seconds.
|
||||
// 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.
|
||||
// "sec" must be false then.
|
||||
void undo_time(long step, bool sec, bool file, bool absolute)
|
||||
{
|
||||
long target;
|
||||
long closest;
|
||||
long closest_start;
|
||||
long closest_seq = 0;
|
||||
long val;
|
||||
u_header_T *uhp;
|
||||
u_header_T *uhp = NULL;
|
||||
u_header_T *last;
|
||||
int mark;
|
||||
int nomark;
|
||||
int round;
|
||||
int dosec = sec;
|
||||
int dofile = file;
|
||||
int above = FALSE;
|
||||
int did_undo = TRUE;
|
||||
bool dosec = sec;
|
||||
bool dofile = file;
|
||||
bool above = false;
|
||||
bool did_undo = true;
|
||||
|
||||
/* First make sure the current undoable change is synced. */
|
||||
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.
|
||||
* Init "closest" to a value we can't reach. */
|
||||
if (absolute) {
|
||||
if (step == 0) {
|
||||
// target 0 does not exist, got to 1 and above it.
|
||||
target = 1;
|
||||
above = true;
|
||||
} else {
|
||||
target = step;
|
||||
}
|
||||
target = step;
|
||||
closest = -1;
|
||||
} else {
|
||||
if (dosec) {
|
||||
@ -1873,7 +1866,7 @@ void undo_time(long step, int sec, int file, int absolute)
|
||||
if (target <= 0)
|
||||
/* Go to before first write: before the oldest change. Use
|
||||
* the sequence number for that. */
|
||||
dofile = FALSE;
|
||||
dofile = false;
|
||||
} else {
|
||||
/* Moving forward to a newer write. */
|
||||
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
|
||||
* the sequence number for that. */
|
||||
target = curbuf->b_u_seq_last + 1;
|
||||
dofile = FALSE;
|
||||
dofile = false;
|
||||
}
|
||||
}
|
||||
} else
|
||||
@ -1906,6 +1899,11 @@ void undo_time(long step, int sec, int file, int absolute)
|
||||
closest_start = closest;
|
||||
closest_seq = curbuf->b_u_seq_cur;
|
||||
|
||||
// When "target" is 0; Back to origin.
|
||||
if (target == 0) {
|
||||
goto found;
|
||||
}
|
||||
|
||||
/*
|
||||
* May do this twice:
|
||||
* 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;
|
||||
dosec = FALSE;
|
||||
dofile = FALSE;
|
||||
if (step < 0)
|
||||
above = TRUE; /* stop above the header */
|
||||
dosec = false;
|
||||
dofile = false;
|
||||
if (step < 0) {
|
||||
above = true; // stop above the header
|
||||
}
|
||||
}
|
||||
|
||||
/* If we found it: Follow the path to go to where we want to be. */
|
||||
if (uhp != NULL) {
|
||||
/*
|
||||
* First go up the tree as much as needed.
|
||||
*/
|
||||
found:
|
||||
// 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.
|
||||
while (!got_int) {
|
||||
/* Do the change warning now, for the same reason as above. */
|
||||
change_warning(0);
|
||||
@ -2035,83 +2033,97 @@ void undo_time(long step, int sec, int file, int absolute)
|
||||
uhp = curbuf->b_u_newhead;
|
||||
else
|
||||
uhp = uhp->uh_next.ptr;
|
||||
if (uhp == NULL || uhp->uh_walk != mark
|
||||
|| (uhp->uh_seq == target && !above))
|
||||
if (uhp == NULL
|
||||
|| (target > 0 && uhp->uh_walk != mark)
|
||||
|| (uhp->uh_seq == target && !above)) {
|
||||
break;
|
||||
}
|
||||
curbuf->b_u_curhead = uhp;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* And now go down the tree (redo), branching off where needed.
|
||||
*/
|
||||
while (!got_int) {
|
||||
/* Do the change warning now, for the same reason as above. */
|
||||
change_warning(0);
|
||||
// When back to origin, redo is not needed.
|
||||
if (target > 0) {
|
||||
// And now go down the tree (redo), branching off where needed.
|
||||
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;
|
||||
uhp = curbuf->b_u_curhead;
|
||||
if (uhp == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Go back to the first branch with a mark. */
|
||||
while (uhp->uh_alt_prev.ptr != NULL
|
||||
&& 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)
|
||||
// Go back to the first branch with a mark.
|
||||
while (uhp->uh_alt_prev.ptr != NULL
|
||||
&& uhp->uh_alt_prev.ptr->uh_walk == mark) {
|
||||
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)
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
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)
|
||||
break; /* must have reached the target */
|
||||
if (curbuf->b_u_oldhead == uhp) {
|
||||
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
|
||||
* header we were looking for. */
|
||||
if (uhp->uh_seq == target && above) {
|
||||
curbuf->b_u_seq_cur = target - 1;
|
||||
break;
|
||||
}
|
||||
if (uhp->uh_walk != mark) {
|
||||
break; // must have reached the target
|
||||
}
|
||||
|
||||
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
|
||||
* 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;
|
||||
u_undoredo(false, true);
|
||||
|
||||
if (uhp->uh_seq == target) /* found it! */
|
||||
break;
|
||||
// Advance "curhead" to below the header we last used. If it
|
||||
// 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 == NULL || uhp->uh_walk != mark) {
|
||||
// Need to redo more but can't find it...
|
||||
internal_error("undo_time()");
|
||||
break;
|
||||
if (uhp->uh_seq == target) { // found it!
|
||||
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
|
||||
/// in some cases, but it's better than nothing).
|
||||
static void u_undo_end(
|
||||
int did_undo, ///< just did an undo
|
||||
int absolute, ///< used ":undo N"
|
||||
bool did_undo, ///< just did an undo
|
||||
bool absolute, ///< used ":undo N"
|
||||
bool quiet)
|
||||
{
|
||||
char *msgstr;
|
||||
@ -2416,13 +2428,15 @@ static void u_undo_end(
|
||||
/* For ":undo N" we prefer a "after #N" message. */
|
||||
if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL) {
|
||||
uhp = curbuf->b_u_curhead->uh_next.ptr;
|
||||
did_undo = FALSE;
|
||||
} else if (did_undo)
|
||||
did_undo = false;
|
||||
} else if (did_undo) {
|
||||
uhp = curbuf->b_u_curhead;
|
||||
else
|
||||
} else {
|
||||
uhp = curbuf->b_u_curhead->uh_next.ptr;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
uhp = curbuf->b_u_newhead;
|
||||
}
|
||||
|
||||
if (uhp == NULL)
|
||||
*msgbuf = NUL;
|
||||
|
Loading…
Reference in New Issue
Block a user