summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2006-03-13 22:15:53 +0000
committerBram Moolenaar <Bram@vim.org>2006-03-13 22:15:53 +0000
commit1e60789f9b8e1b839b3bafe40183aa75a9a7db54 (patch)
tree91c6858978c02d803828463462f71fecc4693cda
parent019ff6825b54e31efc71faf3ce55cb78bac24d35 (diff)
downloadvim-git-1e60789f9b8e1b839b3bafe40183aa75a9a7db54.tar.gz
updated for version 7.0223
-rw-r--r--runtime/filetype.vim5
-rw-r--r--src/popupmenu.c7
-rw-r--r--src/structs.h10
-rw-r--r--src/undo.c403
-rw-r--r--src/version.h4
5 files changed, 379 insertions, 50 deletions
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index d07f8e904..86b4525ba 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1,7 +1,7 @@
" Vim support file to detect file types
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2006 Mar 05
+" Last Change: 2006 Mar 13
" Listen very carefully, I will say this only once
if exists("did_load_filetypes")
@@ -1780,6 +1780,9 @@ au BufNewFile,BufRead *.wml setf wml
" Winbatch
au BufNewFile,BufRead *.wbt setf winbatch
+" WSML
+au BufNewFile,BufRead *.wsml setf wsml
+
" WvDial
au BufNewFile,BufRead wvdial.conf,.wvdialrc setf wvdial
diff --git a/src/popupmenu.c b/src/popupmenu.c
index 752f1832d..1ca03726d 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -65,7 +65,12 @@ redo:
kind_width = 0;
extra_width = 0;
+ /* Pretend the pum is already there to avoid that must_redraw is set when
+ * 'cuc' is on. */
+ pum_array = (pumitem_T *)1;
validate_cursor_col();
+ pum_array = NULL;
+
row = curwin->w_cline_row + W_WINROW(curwin);
height = curwin->w_cline_height;
col = curwin->w_wcol + W_WINCOL(curwin) - curwin->w_leftcol;
@@ -137,7 +142,7 @@ redo:
}
if (array[i].pum_extra != NULL)
{
- w = vim_strsize(array[i].pum_extra + 1);
+ w = vim_strsize(array[i].pum_extra) + 1;
if (extra_width < w)
extra_width = w;
}
diff --git a/src/structs.h b/src/structs.h
index 518fee136..8f554fea0 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -280,8 +280,12 @@ struct u_entry
struct u_header
{
- u_header_T *uh_next; /* pointer to next header in list */
+ u_header_T *uh_next; /* pointer to next undo header in list */
u_header_T *uh_prev; /* pointer to previous header in list */
+ u_header_T *uh_alt_next; /* pointer to next header for alt. redo */
+ u_header_T *uh_alt_prev; /* pointer to previous header for alt. redo */
+ long uh_seq; /* sequence number, higher == newer undo */
+ int uh_walk; /* used by undo_time() */
u_entry_T *uh_entry; /* pointer to first entry */
u_entry_T *uh_getbot_entry; /* pointer to where ue_bot must be set */
pos_T uh_cursor; /* cursor position before saving */
@@ -293,6 +297,7 @@ struct u_header
#ifdef FEAT_VISUAL
visualinfo_T uh_visual; /* Visual areas before undo/after redo */
#endif
+ time_t uh_time; /* timestamp when the change was made */
};
/* values for uh_flags */
@@ -1248,6 +1253,9 @@ struct file_buffer
u_header_T *b_u_curhead; /* pointer to current header */
int b_u_numhead; /* current number of headers */
int b_u_synced; /* entry lists are synced */
+ long b_u_seq_last; /* last used undo sequence number plus 1 */
+ long b_u_seq_cur; /* undo sequence number of last header used
+ plus 1 */
/*
* variables for "U" command in undo.c
diff --git a/src/undo.c b/src/undo.c
index 0c7cbd751..f693d144f 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -41,6 +41,11 @@
* curbuf->b_u_curhead points to the header of the last undo (the next redo),
* or is NULL if nothing has been undone.
*
+ * For keeping alternate undo/redo branches the uh_alt field is used. Thus at
+ * each point in the list a branch may appear for an alternate to redo. The
+ * uh_seq field is numbered sequentially to be able to find a newer or older
+ * branch.
+ *
* All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the
* buffer is unloaded.
*/
@@ -57,7 +62,9 @@ static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T));
static void u_doit __ARGS((int count));
static void u_undoredo __ARGS((void));
static void u_undo_end __ARGS((void));
-static void u_freelist __ARGS((buf_T *buf, struct u_header *));
+static void u_freelist __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
+static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
+static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
static void u_freeentry __ARGS((u_entry_T *, long));
#ifdef U_USE_MALLOC
@@ -196,12 +203,13 @@ u_savecommon(top, bot, newbot)
linenr_T top, bot;
linenr_T newbot;
{
- linenr_T lnum;
- long i;
- struct u_header *uhp;
- u_entry_T *uep;
- u_entry_T *prev_uep;
- long size;
+ linenr_T lnum;
+ long i;
+ u_header_T *uhp;
+ u_header_T *old_curhead;
+ u_entry_T *uep;
+ u_entry_T *prev_uep;
+ long size;
/* When making changes is not allowed return FAIL. It's a crude way to
* make all change commands fail. */
@@ -250,36 +258,70 @@ u_savecommon(top, bot, newbot)
curbuf->b_new_change = TRUE;
#endif
+ if (p_ul >= 0)
+ {
+ /*
+ * Make a new header entry. Do this first so that we don't mess
+ * up the undo info when out of memory.
+ */
+ uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T));
+ if (uhp == NULL)
+ goto nomem;
+ }
+
/*
- * if we undid more than we redid, free the entry lists before and
- * including curbuf->b_u_curhead
+ * If we undid more than we redid, remove the entry lists before and
+ * including curbuf->b_u_curhead to the alternate branch.
*/
- while (curbuf->b_u_curhead != NULL)
- u_freelist(curbuf, curbuf->b_u_newhead);
+ old_curhead = curbuf->b_u_curhead;
+ if (old_curhead != NULL)
+ {
+ curbuf->b_u_newhead = old_curhead->uh_next;
+ curbuf->b_u_curhead = NULL;
+ }
/*
* free headers to keep the size right
*/
while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL)
- u_freelist(curbuf, curbuf->b_u_oldhead);
+ {
+ u_header_T *upfree = curbuf->b_u_oldhead;
+
+ /* If there is no branch only free one header. */
+ if (upfree->uh_alt_next == NULL)
+ u_freelist(curbuf, upfree, &old_curhead);
+ else
+ {
+ /* Free the oldest alternate branch as a whole. */
+ while (upfree->uh_alt_next != NULL)
+ upfree = upfree->uh_alt_next;
+ u_freebranch(curbuf, upfree, &old_curhead);
+ }
+ }
if (p_ul < 0) /* no undo at all */
{
+ if (old_curhead != NULL)
+ u_freebranch(curbuf, old_curhead, NULL);
curbuf->b_u_synced = FALSE;
return OK;
}
- /*
- * make a new header entry
- */
- uhp = (struct u_header *)U_ALLOC_LINE((unsigned)
- sizeof(struct u_header));
- if (uhp == NULL)
- goto nomem;
uhp->uh_prev = NULL;
uhp->uh_next = curbuf->b_u_newhead;
+ uhp->uh_alt_next = old_curhead;
+ if (old_curhead != NULL)
+ {
+ old_curhead->uh_alt_prev = uhp;
+ if (curbuf->b_u_oldhead == old_curhead)
+ curbuf->b_u_oldhead = uhp;
+ }
+ uhp->uh_alt_prev = NULL;
+ uhp->uh_seq = curbuf->b_u_seq_last++;
+ curbuf->b_u_seq_cur = curbuf->b_u_seq_last;
if (curbuf->b_u_newhead != NULL)
curbuf->b_u_newhead->uh_prev = uhp;
+ uhp->uh_walk = 0;
uhp->uh_entry = NULL;
uhp->uh_getbot_entry = NULL;
uhp->uh_cursor = curwin->w_cursor; /* save cursor pos. for undo */
@@ -289,6 +331,7 @@ u_savecommon(top, bot, newbot)
else
uhp->uh_cursor_vcol = -1;
#endif
+ uhp->uh_time = time(NULL);
/* save changed and buffer empty flag for undo */
uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
@@ -532,6 +575,7 @@ u_doit(count)
}
u_undoredo();
+ curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq;
}
else
{
@@ -542,12 +586,204 @@ u_doit(count)
}
u_undoredo();
- /* advance for next redo */
+ curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq + 1;
+
+ /* Advance for next redo. Set "newhead" when at the end of the
+ * redoable changes. */
+ if (curbuf->b_u_curhead->uh_prev == NULL)
+ curbuf->b_u_newhead = curbuf->b_u_curhead;
curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev;
}
}
+ u_undo_end();
+}
+
+static int lastmark = 0;
+
+/*
+ * Undo or redo over the timeline.
+ * When "step" is negative go back in time, otherwise goes forward in time.
+ */
+ void
+undo_time(step)
+ int step;
+{
+ long target;
+ long closest;
+ u_header_T *uhp;
+ u_header_T *last;
+ int mark;
+ int nomark;
+ int round;
+
+ u_newcount = 0;
+ u_oldcount = 0;
if (curbuf->b_ml.ml_flags & ML_EMPTY)
- --u_newcount;
+ u_oldcount = -1;
+
+ /* "target" is the node below which we want to be. When going forward
+ * the current one also counts, thus do one less. */
+ if (step < 0)
+ {
+ target = curbuf->b_u_seq_cur + step;
+ closest = -1;
+ }
+ else
+ {
+ target = curbuf->b_u_seq_cur + step - 1;
+ closest = curbuf->b_u_seq_last + 1;
+ }
+
+ /* May do this twice:
+ * 1. Search for "target", update "closest" to the best match found.
+ * 2. If "target" not found search for "closest". */
+ for (round = 1; round <= 2; ++round)
+ {
+ /* Find the path from the current state to where we want to go. The
+ * desired state can be anywhere in the undo tree, need to go all over
+ * it. We put "nomark" in uh_walk where we have been without success,
+ * "mark" where it could possibly be. */
+ mark = ++lastmark;
+ nomark = ++lastmark;
+
+ if (curbuf->b_u_curhead == NULL) /* at leaf of the tree */
+ uhp = curbuf->b_u_newhead;
+ else
+ uhp = curbuf->b_u_curhead;
+
+ while (uhp != NULL)
+ {
+ uhp->uh_walk = mark;
+ if (uhp->uh_seq == target) /* found it! */
+ break;
+
+ if (round == 1 && (step < 0
+ ? (uhp->uh_seq < target && uhp->uh_seq > closest)
+ : (uhp->uh_seq > target && uhp->uh_seq < closest)))
+ closest = uhp->uh_seq;
+
+ /* go down in the tree if we haven't been there */
+ if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != nomark
+ && uhp->uh_prev->uh_walk != mark)
+ uhp = uhp->uh_prev;
+
+ /* go to alternate branch if we haven't been there */
+ else if (uhp->uh_alt_next != NULL
+ && uhp->uh_alt_next->uh_walk != nomark
+ && uhp->uh_alt_next->uh_walk != mark)
+ uhp = uhp->uh_alt_next;
+
+ /* go up in the tree if we haven't been there and we are at the
+ * start of alternate branches */
+ else if (uhp->uh_next != NULL && uhp->uh_alt_prev == NULL
+ && uhp->uh_next->uh_walk != nomark
+ && uhp->uh_next->uh_walk != mark)
+ uhp = uhp->uh_next;
+
+ else
+ {
+ /* need to backtrack; mark this node as useless */
+ uhp->uh_walk = nomark;
+ if (uhp->uh_alt_prev != NULL)
+ uhp = uhp->uh_alt_prev;
+ else
+ uhp = uhp->uh_next;
+ }
+ }
+
+ if (uhp != NULL) /* found it */
+ break;
+ if (step < 0 && closest == -1)
+ {
+ MSG(_("Already at oldest change"));
+ return;
+ }
+ if (step > 0 && closest == curbuf->b_u_seq_last + 1)
+ {
+ MSG(_("Already at newest change"));
+ return;
+ }
+
+ target = closest;
+ }
+
+ /* 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.
+ */
+ for (;;)
+ {
+ uhp = curbuf->b_u_curhead;
+ if (uhp == NULL)
+ uhp = curbuf->b_u_newhead;
+ else
+ {
+ while (uhp->uh_alt_prev != NULL)
+ {
+ uhp->uh_walk = nomark;
+ uhp = uhp->uh_alt_prev;
+ }
+ uhp = uhp->uh_next;
+ }
+ if (uhp == NULL || uhp->uh_walk != mark)
+ break;
+ curbuf->b_u_curhead = uhp;
+ u_undoredo();
+ uhp->uh_walk = nomark; /* don't go back down here */
+ curbuf->b_u_seq_cur = uhp->uh_seq;
+ }
+
+ /*
+ * And now go down the tree, branching off where needed.
+ */
+ uhp = curbuf->b_u_curhead;
+ for (;;)
+ {
+ /* Find the last branch with a mark, that's the one. */
+ last = uhp;
+ while (last->uh_alt_next != NULL
+ && last->uh_alt_next->uh_walk == mark)
+ last = last->uh_alt_next;
+ if (last != uhp)
+ {
+ /* Make the used branch the first entry in the list of
+ * alternatives to make "u" and CTRL-R take this branch. */
+ if (last->uh_alt_next != NULL)
+ last->uh_alt_next->uh_alt_prev = last->uh_alt_prev;
+ last->uh_alt_prev->uh_alt_next = last->uh_alt_next;
+ last->uh_alt_prev = NULL;
+ last->uh_alt_next = uhp;
+ uhp->uh_alt_prev = last;
+
+ uhp = last;
+ }
+
+ if (uhp->uh_walk != mark)
+ break; /* must have reached the target */
+
+ curbuf->b_u_curhead = uhp;
+ u_undoredo();
+ curbuf->b_u_seq_cur = uhp->uh_seq + 1;
+
+ /* 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 == NULL)
+ curbuf->b_u_newhead = uhp;
+ curbuf->b_u_curhead = uhp->uh_prev;
+
+ if (uhp->uh_seq == target) /* found it! */
+ break;
+
+ uhp = uhp->uh_prev;
+ if (uhp == NULL || uhp->uh_walk != mark)
+ {
+ EMSG2(_(e_intern2), "undo_time()");
+ break;
+ }
+ }
+ }
u_undo_end();
}
@@ -808,19 +1044,45 @@ u_undoredo()
static void
u_undo_end()
{
- if ((u_oldcount -= u_newcount) != 0)
- msgmore(-u_oldcount);
- else if (u_newcount > p_report)
- {
- if (u_newcount == 1)
- MSG(_("1 change"));
- else
- smsg((char_u *)_("%ld changes"), u_newcount);
- }
+ long sec;
+ char *msg;
+
#ifdef FEAT_FOLDING
if ((fdo_flags & FDO_UNDO) && KeyTyped)
foldOpenCursor();
#endif
+
+ if (global_busy /* no messages now, wait until global is finished */
+ || !messaging()) /* 'lazyredraw' set, don't do messages now */
+ return;
+
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ --u_newcount;
+
+ u_oldcount -= u_newcount;
+ if (u_oldcount == -1)
+ msg = N_("more line");
+ else if (u_oldcount < 0)
+ msg = N_("more lines");
+ else if (u_oldcount == 1)
+ msg = N_("line less");
+ else if (u_oldcount > 1)
+ msg = N_("fewer lines");
+ else
+ {
+ u_oldcount = u_newcount;
+ if (u_newcount == 1)
+ msg = N_("change");
+ else
+ msg = N_("changes");
+ }
+
+ if (curbuf->b_u_curhead == 0)
+ sec = 0;
+ else
+ sec = time(NULL) - curbuf->b_u_curhead->uh_time;
+
+ smsg((char_u *)_("%ld %s; %ld seconds ago"), u_oldcount, _(msg), sec);
}
/*
@@ -874,7 +1136,7 @@ ex_undojoin(eap)
u_unchanged(buf)
buf_T *buf;
{
- struct u_header *uh;
+ u_header_T *uh;
for (uh = buf->b_u_newhead; uh; uh = uh->uh_next)
uh->uh_flags |= UH_CHANGED;
@@ -936,24 +1198,23 @@ u_getbot()
}
/*
- * u_freelist: free one entry list and adjust the pointers
+ * Free one header and its entry list and adjust the pointers.
*/
static void
-u_freelist(buf, uhp)
+u_freelist(buf, uhp, uhpp)
buf_T *buf;
- struct u_header *uhp;
+ u_header_T *uhp;
+ u_header_T **uhpp; /* if not NULL reset when freeing this header */
{
- u_entry_T *uep, *nuep;
-
- for (uep = uhp->uh_entry; uep != NULL; uep = nuep)
- {
- nuep = uep->ue_next;
- u_freeentry(uep, uep->ue_size);
- }
+ /* When there is an alternate redo list free that branch completely,
+ * because we can never go there. */
+ if (uhp->uh_alt_next != NULL)
+ u_freebranch(buf, uhp->uh_alt_next, uhpp);
- if (buf->b_u_curhead == uhp)
- buf->b_u_curhead = NULL;
+ if (uhp->uh_alt_prev != NULL)
+ uhp->uh_alt_prev->uh_alt_next = NULL;
+ /* Update the links in the list to remove the header. */
if (uhp->uh_next == NULL)
buf->b_u_oldhead = uhp->uh_prev;
else
@@ -964,6 +1225,58 @@ u_freelist(buf, uhp)
else
uhp->uh_prev->uh_next = uhp->uh_next;
+ u_freeentries(buf, uhp, uhpp);
+}
+
+/*
+ * Free an alternate branch and all following alternate branches.
+ */
+ static void
+u_freebranch(buf, uhp, uhpp)
+ buf_T *buf;
+ u_header_T *uhp;
+ u_header_T **uhpp; /* if not NULL reset when freeing this header */
+{
+ u_header_T *tofree, *next;
+
+ if (uhp->uh_alt_prev != NULL)
+ uhp->uh_alt_prev->uh_alt_next = NULL;
+
+ next = uhp;
+ while (next != NULL)
+ {
+ tofree = next;
+ if (tofree->uh_alt_next != NULL)
+ u_freebranch(buf, tofree->uh_alt_next, uhpp); /* recursive */
+ next = tofree->uh_prev;
+ u_freeentries(buf, tofree, uhpp);
+ }
+}
+
+/*
+ * Free all the undo entries for one header and the header itself.
+ * This means that "uhp" is invalid when returning.
+ */
+ static void
+u_freeentries(buf, uhp, uhpp)
+ buf_T *buf;
+ u_header_T *uhp;
+ u_header_T **uhpp; /* if not NULL reset when freeing this header */
+{
+ u_entry_T *uep, *nuep;
+
+ /* Check for pointers to the header that become invalid now. */
+ if (buf->b_u_curhead == uhp)
+ buf->b_u_curhead = NULL;
+ if (uhpp != NULL && uhp == *uhpp)
+ *uhpp = NULL;
+
+ for (uep = uhp->uh_entry; uep != NULL; uep = nuep)
+ {
+ nuep = uep->ue_next;
+ u_freeentry(uep, uep->ue_size);
+ }
+
U_FREE_LINE((char_u *)uhp);
--buf->b_u_numhead;
}
@@ -1101,8 +1414,8 @@ u_undoline()
u_blockfree(buf)
buf_T *buf;
{
- while (buf->b_u_newhead != NULL)
- u_freelist(buf, buf->b_u_newhead);
+ while (buf->b_u_oldhead != NULL)
+ u_freelist(buf, buf->b_u_oldhead, NULL);
U_FREE_LINE(buf->b_u_line_ptr);
}
diff --git a/src/version.h b/src/version.h
index 183269fc0..47dc1b4a7 100644
--- a/src/version.h
+++ b/src/version.h
@@ -36,5 +36,5 @@
#define VIM_VERSION_NODOT "vim70aa"
#define VIM_VERSION_SHORT "7.0aa"
#define VIM_VERSION_MEDIUM "7.0aa ALPHA"
-#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 12)"
-#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 12, compiled "
+#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 13)"
+#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 13, compiled "