aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/undo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/undo.c')
-rw-r--r--src/nvim/undo.c118
1 files changed, 81 insertions, 37 deletions
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index f16b4264d7..4b267a1627 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -99,6 +99,7 @@
#include "nvim/quickfix.h"
#include "nvim/screen.h"
#include "nvim/sha256.h"
+#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/types.h"
#include "nvim/os/os.h"
@@ -690,7 +691,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
int ret;
char *failed_dir;
if ((ret = os_mkdir_recurse(dir_name, 0755, &failed_dir)) != 0) {
- EMSG3(_("E926: Unable to create directory \"%s\" for undo file: %s"),
+ EMSG3(_("E5003: Unable to create directory \"%s\" for undo file: %s"),
failed_dir, os_strerror(ret));
xfree(failed_dir);
} else {
@@ -712,7 +713,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
// When reading check if the file exists.
if (undo_file_name != NULL
- && (!reading || os_file_exists((char_u *)undo_file_name))) {
+ && (!reading || os_path_exists((char_u *)undo_file_name))) {
break;
}
xfree(undo_file_name);
@@ -1094,7 +1095,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
/* If the undo file already exists, verify that it actually is an undo
* file, and delete it. */
- if (os_file_exists((char_u *)file_name)) {
+ if (os_path_exists((char_u *)file_name)) {
if (name == NULL || !forceit) {
/* Check we can read it and it's an undo file. */
fd = os_open(file_name, O_RDONLY, 0);
@@ -1668,7 +1669,7 @@ void u_undo(int count)
undo_undoes = TRUE;
else
undo_undoes = !undo_undoes;
- u_doit(count);
+ u_doit(count, false);
}
/*
@@ -1677,15 +1678,58 @@ void u_undo(int count)
*/
void u_redo(int count)
{
- if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
- undo_undoes = FALSE;
- u_doit(count);
+ if (vim_strchr(p_cpo, CPO_UNDO) == NULL) {
+ undo_undoes = false;
+ }
+
+ u_doit(count, false);
}
-/*
- * Undo or redo, depending on 'undo_undoes', 'count' times.
- */
-static void u_doit(int startcount)
+/// Undo and remove the branch from the undo tree.
+/// Also moves the cursor (as a "normal" undo would).
+bool u_undo_and_forget(int count)
+{
+ if (curbuf->b_u_synced == false) {
+ u_sync(true);
+ count = 1;
+ }
+ undo_undoes = true;
+ u_doit(count, true);
+
+ if (curbuf->b_u_curhead == NULL) {
+ // nothing was undone.
+ return false;
+ }
+
+ // Delete the current redo header
+ // set the redo header to the next alternative branch (if any)
+ // otherwise we will be in the leaf state
+ u_header_T *to_forget = curbuf->b_u_curhead;
+ curbuf->b_u_newhead = to_forget->uh_next.ptr;
+ curbuf->b_u_curhead = to_forget->uh_alt_next.ptr;
+ if (curbuf->b_u_curhead) {
+ to_forget->uh_alt_next.ptr = NULL;
+ curbuf->b_u_curhead->uh_alt_prev.ptr = to_forget->uh_alt_prev.ptr;
+ curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_next.ptr ?
+ curbuf->b_u_curhead->uh_next.ptr->uh_seq : 0;
+ } else if (curbuf->b_u_newhead) {
+ curbuf->b_u_seq_cur = curbuf->b_u_newhead->uh_seq;
+ }
+ if (to_forget->uh_alt_prev.ptr) {
+ to_forget->uh_alt_prev.ptr->uh_alt_next.ptr = curbuf->b_u_curhead;
+ }
+ if (curbuf->b_u_newhead) {
+ curbuf->b_u_newhead->uh_prev.ptr = curbuf->b_u_curhead;
+ }
+ if (curbuf->b_u_seq_last == to_forget->uh_seq) {
+ curbuf->b_u_seq_last--;
+ }
+ u_freebranch(curbuf, to_forget, NULL);
+ return true;
+}
+
+/// Undo or redo, depending on `undo_undoes`, `count` times.
+static void u_doit(int startcount, bool quiet)
{
int count = startcount;
@@ -1721,7 +1765,7 @@ static void u_doit(int startcount)
break;
}
- u_undoredo(TRUE);
+ u_undoredo(true);
} else {
if (curbuf->b_u_curhead == NULL || get_undolevel() <= 0) {
beep_flush(); /* nothing to redo */
@@ -1741,7 +1785,7 @@ static void u_doit(int startcount)
curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev.ptr;
}
}
- u_undo_end(undo_undoes, FALSE);
+ u_undo_end(undo_undoes, false, quiet);
}
/*
@@ -2054,7 +2098,7 @@ void undo_time(long step, int sec, int file, int absolute)
}
}
}
- u_undo_end(did_undo, absolute);
+ u_undo_end(did_undo, absolute, false);
}
/*
@@ -2278,7 +2322,8 @@ static void u_undoredo(int undo)
if (undo)
/* We are below the previous undo. However, to make ":earlier 1s"
* work we compute this as being just above the just undone change. */
- --curbuf->b_u_seq_cur;
+ curbuf->b_u_seq_cur = curhead->uh_next.ptr ?
+ curhead->uh_next.ptr->uh_seq : 0;
/* Remember where we are for ":earlier 1f" and ":later 1f". */
if (curhead->uh_save_nr != 0) {
@@ -2298,16 +2343,13 @@ static void u_undoredo(int undo)
#endif
}
-/*
- * If we deleted or added lines, report the number of less/more lines.
- * 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" */
-)
+/// If we deleted or added lines, report the number of less/more lines.
+/// 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 quiet)
{
char *msgstr;
u_header_T *uhp;
@@ -2316,9 +2358,11 @@ u_undo_end (
if ((fdo_flags & FDO_UNDO) && KeyTyped)
foldOpenCursor();
- if (global_busy /* no messages now, wait until global is finished */
- || !messaging()) /* 'lazyredraw' set, don't do messages now */
+ if (quiet
+ || global_busy // no messages until global is finished
+ || !messaging()) { // 'lazyredraw' set, don't do messages now
return;
+ }
if (curbuf->b_ml.ml_flags & ML_EMPTY)
--u_newcount;
@@ -2507,20 +2551,20 @@ static void u_add_time(char_u *buf, size_t buflen, time_t tt)
*/
void ex_undojoin(exarg_T *eap)
{
- if (curbuf->b_u_newhead == NULL)
- return; /* nothing changed before */
+ if (curbuf->b_u_newhead == NULL) {
+ return; // nothing changed before
+ }
if (curbuf->b_u_curhead != NULL) {
EMSG(_("E790: undojoin is not allowed after undo"));
return;
}
- if (!curbuf->b_u_synced)
- return; /* already unsynced */
- if (get_undolevel() < 0)
- return; /* no entries, nothing to do */
- else {
- /* Go back to the last entry */
- curbuf->b_u_curhead = curbuf->b_u_newhead;
- curbuf->b_u_synced = false; /* no entries, nothing to do */
+ if (!curbuf->b_u_synced) {
+ return; // already unsynced
+ }
+ if (get_undolevel() < 0) {
+ return; // no entries, nothing to do
+ } else {
+ curbuf->b_u_synced = false; // Append next change to last entry
}
}