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.c119
1 files changed, 69 insertions, 50 deletions
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 035613c7fd..97018f6c02 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -91,7 +91,9 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/buffer_updates.h"
+#include "nvim/pos.h" // MAXLNUM
#include "nvim/mark.h"
+#include "nvim/extmark.h"
#include "nvim/memline.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
@@ -106,6 +108,7 @@
#include "nvim/types.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
+#include "nvim/lib/kvec.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "undo.c.generated.h"
@@ -222,9 +225,6 @@ int u_save_cursor(void)
*/
int u_save(linenr_T top, linenr_T bot)
{
- if (undo_off)
- return OK;
-
if (top >= bot || bot > (curbuf->b_ml.ml_line_count + 1)) {
return FAIL; /* rely on caller to do error messages */
}
@@ -243,10 +243,7 @@ int u_save(linenr_T top, linenr_T bot)
*/
int u_savesub(linenr_T lnum)
{
- if (undo_off)
- return OK;
-
- return u_savecommon(lnum - 1, lnum + 1, lnum + 1, FALSE);
+ return u_savecommon(lnum - 1, lnum + 1, lnum + 1, false);
}
/*
@@ -257,10 +254,7 @@ int u_savesub(linenr_T lnum)
*/
int u_inssub(linenr_T lnum)
{
- if (undo_off)
- return OK;
-
- return u_savecommon(lnum - 1, lnum, lnum + 1, FALSE);
+ return u_savecommon(lnum - 1, lnum, lnum + 1, false);
}
/*
@@ -272,9 +266,6 @@ int u_inssub(linenr_T lnum)
*/
int u_savedel(linenr_T lnum, long nlines)
{
- if (undo_off)
- return OK;
-
return u_savecommon(lnum - 1, lnum + nlines,
nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, FALSE);
}
@@ -384,6 +375,7 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
* up the undo info when out of memory.
*/
uhp = xmalloc(sizeof(u_header_T));
+ kv_init(uhp->uh_extmark);
#ifdef U_DEBUG
uhp->uh_magic = UH_MAGIC;
#endif
@@ -1065,7 +1057,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
if (file_name == NULL) {
if (p_verbose > 0) {
verbose_enter();
- smsg(_("Cannot write undo file in any directory in 'undodir'"));
+ smsg("%s", _("Cannot write undo file in any directory in 'undodir'"));
verbose_leave();
}
return;
@@ -2249,10 +2241,10 @@ static void u_undoredo(int undo, bool do_buf_event)
xfree((char_u *)uep->ue_array);
}
- /* adjust marks */
+ // Adjust marks
if (oldsize != newsize) {
mark_adjust(top + 1, top + oldsize, (long)MAXLNUM,
- (long)newsize - (long)oldsize, false);
+ (long)newsize - (long)oldsize, kExtmarkNOOP);
if (curbuf->b_op_start.lnum > top + oldsize) {
curbuf->b_op_start.lnum += newsize - oldsize;
}
@@ -2285,6 +2277,23 @@ static void u_undoredo(int undo, bool do_buf_event)
newlist = uep;
}
+ // Adjust Extmarks
+ ExtmarkUndoObject undo_info;
+ if (undo) {
+ for (i = (int)kv_size(curhead->uh_extmark) - 1; i > -1; i--) {
+ undo_info = kv_A(curhead->uh_extmark, i);
+ extmark_apply_undo(undo_info, undo);
+ }
+ // redo
+ } else {
+ for (i = 0; i < (int)kv_size(curhead->uh_extmark); i++) {
+ undo_info = kv_A(curhead->uh_extmark, i);
+ extmark_apply_undo(undo_info, undo);
+ }
+ }
+ // finish Adjusting extmarks
+
+
curhead->uh_entry = newlist;
curhead->uh_flags = new_flags;
if ((old_flags & UH_EMPTYBUF) && BUFEMPTY()) {
@@ -2432,10 +2441,11 @@ static void u_undo_end(
uhp = curbuf->b_u_newhead;
}
- if (uhp == NULL)
+ if (uhp == NULL) {
*msgbuf = NUL;
- else
- u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
+ } else {
+ add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
+ }
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
@@ -2500,8 +2510,8 @@ void ex_undolist(exarg_T *eap)
&& uhp->uh_walk != mark) {
vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ",
uhp->uh_seq, changes);
- u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
- uhp->uh_time);
+ add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
+ uhp->uh_time);
if (uhp->uh_save_nr > 0) {
while (STRLEN(IObuff) < 33)
STRCAT(IObuff, " ");
@@ -2566,30 +2576,6 @@ void ex_undolist(exarg_T *eap)
}
/*
- * Put the timestamp of an undo header in "buf[buflen]" in a nice format.
- */
-static void u_add_time(char_u *buf, size_t buflen, time_t tt)
-{
- struct tm curtime;
-
- if (time(NULL) - tt >= 100) {
- os_localtime_r(&tt, &curtime);
- if (time(NULL) - tt < (60L * 60L * 12L))
- /* within 12 hours */
- (void)strftime((char *)buf, buflen, "%H:%M:%S", &curtime);
- else
- /* longer ago */
- (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", &curtime);
- } else {
- int64_t seconds = time(NULL) - tt;
- vim_snprintf((char *)buf, buflen,
- NGETTEXT("%" PRId64 " second ago",
- "%" PRId64 " seconds ago", (uint32_t)seconds),
- seconds);
- }
-}
-
-/*
* ":undojoin": continue adding to the last entry list
*/
void ex_undojoin(exarg_T *eap)
@@ -2828,6 +2814,8 @@ u_freeentries(
u_freeentry(uep, uep->ue_size);
}
+ kv_destroy(uhp->uh_extmark);
+
#ifdef U_DEBUG
uhp->uh_magic = 0;
#endif
@@ -2902,9 +2890,6 @@ void u_undoline(void)
colnr_T t;
char_u *oldp;
- if (undo_off)
- return;
-
if (curbuf->b_u_line_ptr == NULL
|| curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count) {
beep_flush();
@@ -2963,7 +2948,10 @@ static char_u *u_save_line(linenr_T lnum)
bool bufIsChanged(buf_T *buf)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- return !bt_dontwrite(buf) && (buf->b_changed || file_ff_differs(buf, true));
+ // In a "prompt" buffer we do respect 'modified', so that we can control
+ // closing the window by setting or resetting that option.
+ return (!bt_dontwrite(buf) || bt_prompt(buf))
+ && (buf->b_changed || file_ff_differs(buf, true));
}
// Return true if any buffer has changes. Also buffers that are not written.
@@ -3022,3 +3010,34 @@ list_T *u_eval_tree(const u_header_T *const first_uhp)
return list;
}
+
+// Given the buffer, Return the undo header. If none is set, set one first.
+// NULL will be returned if e.g undolevels = -1 (undo disabled)
+u_header_T *u_force_get_undo_header(buf_T *buf)
+{
+ u_header_T *uhp = NULL;
+ if (buf->b_u_curhead != NULL) {
+ uhp = buf->b_u_curhead;
+ } else if (buf->b_u_newhead) {
+ uhp = buf->b_u_newhead;
+ }
+ // Create the first undo header for the buffer
+ if (!uhp) {
+ // Undo is normally invoked in change code, which already has swapped
+ // curbuf.
+ buf_T *save_curbuf = curbuf;
+ curbuf = buf;
+ // Args are tricky: this means replace empty range by empty range..
+ u_savecommon(0, 1, 1, true);
+ curbuf = save_curbuf;
+
+ uhp = buf->b_u_curhead;
+ if (!uhp) {
+ uhp = buf->b_u_newhead;
+ if (get_undolevel() > 0 && !uhp) {
+ abort();
+ }
+ }
+ }
+ return uhp;
+}