summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-07-03 17:47:26 +0200
committerBram Moolenaar <Bram@vim.org>2016-07-03 17:47:26 +0200
commitab9c89b68dcbdb3fbda8c5a50dd90caca64f1bfd (patch)
tree2f0ec77daa7639d59485f19ea7e2e019cd1b5fb8
parentdec85cf75044ed94f611c825a7a0b0050a2597b9 (diff)
patch 7.4.1988v7.4.1988
Problem: When updating viminfo with file marks there is no time order. Solution: Remember the time when a buffer was last used, store marks for the most recently used buffers.
-rw-r--r--src/buffer.c3
-rw-r--r--src/ex_cmds.c26
-rw-r--r--src/main.c3
-rw-r--r--src/mark.c183
-rw-r--r--src/proto/mark.pro4
-rw-r--r--src/structs.h4
-rw-r--r--src/testdir/test_viminfo.vim30
-rw-r--r--src/version.c2
8 files changed, 213 insertions, 42 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 39a5bcb4d1..058e4d785b 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1619,6 +1619,9 @@ enter_buffer(buf_T *buf)
if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
(void)did_set_spelllang(curwin);
#endif
+#ifdef FEAT_VIMINFO
+ curbuf->b_last_used = vim_time();
+#endif
redraw_later(NOT_VALID);
}
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 72603d1bd2..5900c86d31 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -2148,10 +2148,11 @@ viminfo_filename(char_u *file)
static void
do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
{
- int count = 0;
int eof = FALSE;
vir_T vir;
int merge = FALSE;
+ int do_copy_marks = FALSE;
+ garray_T buflist;
if ((vir.vir_line = alloc(LSIZE)) == NULL)
return;
@@ -2183,7 +2184,11 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
while (!(eof = viminfo_readline(&vir))
&& vir.vir_line[0] != '>')
;
+
+ do_copy_marks = (flags &
+ (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT));
}
+
if (fp_out != NULL)
{
/* Write the info: */
@@ -2209,11 +2214,18 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
finish_viminfo_marks();
write_viminfo_bufferlist(fp_out);
write_viminfo_barlines(&vir, fp_out);
- count = write_viminfo_marks(fp_out);
+
+ if (do_copy_marks)
+ ga_init2(&buflist, sizeof(buf_T *), 50);
+ write_viminfo_marks(fp_out, do_copy_marks ? &buflist : NULL);
+ }
+
+ if (do_copy_marks)
+ {
+ copy_viminfo_marks(&vir, fp_out, &buflist, eof, flags);
+ if (fp_out != NULL)
+ ga_clear(&buflist);
}
- if (fp_in != NULL
- && (flags & (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT)))
- copy_viminfo_marks(&vir, fp_out, count, eof, flags);
vim_free(vir.vir_line);
#ifdef FEAT_MBYTE
@@ -4287,6 +4299,10 @@ do_ecmd(
msg_scrolled_ign = FALSE;
}
+#ifdef FEAT_VIMINFO
+ curbuf->b_last_used = vim_time();
+#endif
+
if (command != NULL)
do_cmdline(command, NULL, NULL, DOCMD_VERBOSE);
diff --git a/src/main.c b/src/main.c
index dcede31e45..42638e4485 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1273,6 +1273,9 @@ main_loop(
if (need_maketitle)
maketitle();
#endif
+#ifdef FEAT_VIMINFO
+ curbuf->b_last_used = vim_time();
+#endif
/* display message after redraw */
if (keep_msg != NULL)
{
diff --git a/src/mark.c b/src/mark.c
index 2e8fdd63f9..1e6b26a7ac 100644
--- a/src/mark.c
+++ b/src/mark.c
@@ -1799,16 +1799,54 @@ removable(char_u *name)
return retval;
}
-static void write_one_mark(FILE *fp_out, int c, pos_T *pos);
+ static void
+write_one_mark(FILE *fp_out, int c, pos_T *pos)
+{
+ if (pos->lnum != 0)
+ fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
+}
+
+
+ static void
+write_buffer_marks(buf_T *buf, FILE *fp_out)
+{
+ int i;
+ pos_T pos;
+
+ home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
+ fprintf(fp_out, "\n> ");
+ viminfo_writestring(fp_out, IObuff);
+
+ /* Write the last used timestamp as the lnum of the non-existing mark '*'.
+ * Older Vims will ignore it and/or copy it. */
+ pos.lnum = (linenr_T)buf->b_last_used;
+ pos.col = 0;
+ write_one_mark(fp_out, '*', &pos);
+
+ write_one_mark(fp_out, '"', &buf->b_last_cursor);
+ write_one_mark(fp_out, '^', &buf->b_last_insert);
+ write_one_mark(fp_out, '.', &buf->b_last_change);
+#ifdef FEAT_JUMPLIST
+ /* changelist positions are stored oldest first */
+ for (i = 0; i < buf->b_changelistlen; ++i)
+ {
+ /* skip duplicates */
+ if (i == 0 || !equalpos(buf->b_changelist[i - 1], buf->b_changelist[i]))
+ write_one_mark(fp_out, '+', &buf->b_changelist[i]);
+ }
+#endif
+ for (i = 0; i < NMARKS; i++)
+ write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
+}
/*
* Write all the named marks for all buffers.
- * Return the number of buffers for which marks have been written.
+ * When "buflist" is not NULL fill it with the buffers for which marks are to
+ * be written.
*/
- int
-write_viminfo_marks(FILE *fp_out)
+ void
+write_viminfo_marks(FILE *fp_out, garray_T *buflist)
{
- int count;
buf_T *buf;
int is_mark_set;
int i;
@@ -1826,7 +1864,6 @@ write_viminfo_marks(FILE *fp_out)
#endif
fputs(_("\n# History of marks within files (newest to oldest):\n"), fp_out);
- count = 0;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
{
/*
@@ -1850,42 +1887,35 @@ write_viminfo_marks(FILE *fp_out)
if (is_mark_set && buf->b_ffname != NULL
&& buf->b_ffname[0] != NUL && !removable(buf->b_ffname))
{
- home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
- fprintf(fp_out, "\n> ");
- viminfo_writestring(fp_out, IObuff);
- write_one_mark(fp_out, '"', &buf->b_last_cursor);
- write_one_mark(fp_out, '^', &buf->b_last_insert);
- write_one_mark(fp_out, '.', &buf->b_last_change);
-#ifdef FEAT_JUMPLIST
- /* changelist positions are stored oldest first */
- for (i = 0; i < buf->b_changelistlen; ++i)
- {
- /* skip duplicates */
- if (i == 0 || !equalpos(buf->b_changelist[i - 1],
- buf->b_changelist[i]))
- write_one_mark(fp_out, '+', &buf->b_changelist[i]);
- }
-#endif
- for (i = 0; i < NMARKS; i++)
- write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
- count++;
+ if (buflist == NULL)
+ write_buffer_marks(buf, fp_out);
+ else if (ga_grow(buflist, 1) == OK)
+ ((buf_T **)buflist->ga_data)[buflist->ga_len++] = buf;
}
}
}
-
- return count;
}
- static void
-write_one_mark(FILE *fp_out, int c, pos_T *pos)
+/*
+ * Compare functions for qsort() below, that compares b_last_used.
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+buf_compare(const void *s1, const void *s2)
{
- if (pos->lnum != 0)
- fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
+ buf_T *buf1 = *(buf_T **)s1;
+ buf_T *buf2 = *(buf_T **)s2;
+
+ if (buf1->b_last_used == buf2->b_last_used)
+ return 0;
+ return buf1->b_last_used > buf2->b_last_used ? -1 : 1;
}
/*
* Handle marks in the viminfo file:
- * fp_out != NULL: copy marks for buffers not in buffer list
+ * fp_out != NULL: copy marks, in time order with buffers in "buflist".
* fp_out == NULL && (flags & VIF_WANT_MARKS): read marks for curbuf only
* fp_out == NULL && (flags & VIF_GET_OLDFILES | VIF_FORCEIT): fill v:oldfiles
*/
@@ -1893,7 +1923,7 @@ write_one_mark(FILE *fp_out, int c, pos_T *pos)
copy_viminfo_marks(
vir_T *virp,
FILE *fp_out,
- int count,
+ garray_T *buflist,
int eof,
int flags)
{
@@ -1910,11 +1940,22 @@ copy_viminfo_marks(
#ifdef FEAT_EVAL
list_T *list = NULL;
#endif
+ int count = 0;
+ int buflist_used = 0;
+ buf_T *buflist_buf = NULL;
if ((name_buf = alloc(LSIZE)) == NULL)
return;
*name_buf = NUL;
+ if (fp_out != NULL && buflist->ga_len > 0)
+ {
+ /* Sort the list of buffers on b_last_used. */
+ qsort(buflist->ga_data, (size_t)buflist->ga_len,
+ sizeof(buf_T *), buf_compare);
+ buflist_buf = ((buf_T **)buflist->ga_data)[0];
+ }
+
#ifdef FEAT_EVAL
if (fp_out == NULL && (flags & (VIF_GET_OLDFILES | VIF_FORCEIT)))
{
@@ -1986,14 +2027,70 @@ copy_viminfo_marks(
}
/*
- * copy marks if the buffer has not been loaded
+ * Copy marks if the buffer has not been loaded.
*/
if (buf == NULL || !buf->b_marks_read)
{
- copy_marks_out = TRUE;
+ int did_read_line = FALSE;
+
+ if (buflist_buf != NULL)
+ {
+ /* Read the next line. If it has the "*" mark compare the
+ * time stamps. Write entries from "buflist" that are
+ * newer. */
+ if (!(eof = viminfo_readline(virp)) && line[0] == TAB)
+ {
+ did_read_line = TRUE;
+ if (line[1] == '*')
+ {
+ long ltime;
+
+ sscanf((char *)line + 2, "%ld ", &ltime);
+ while ((time_T)ltime < buflist_buf->b_last_used)
+ {
+ write_buffer_marks(buflist_buf, fp_out);
+ if (++count >= num_marked_files)
+ break;
+ if (++buflist_used == buflist->ga_len)
+ {
+ buflist_buf = NULL;
+ break;
+ }
+ buflist_buf =
+ ((buf_T **)buflist->ga_data)[buflist_used];
+ }
+ }
+ else
+ {
+ /* No timestamp, must be written by an older Vim.
+ * Assume all remaining buffers are older then
+ * ours. */
+ while (count < num_marked_files
+ && buflist_used < buflist->ga_len)
+ {
+ buflist_buf = ((buf_T **)buflist->ga_data)
+ [buflist_used++];
+ write_buffer_marks(buflist_buf, fp_out);
+ ++count;
+ }
+ buflist_buf = NULL;
+ }
+
+ if (count >= num_marked_files)
+ {
+ vim_free(str);
+ break;
+ }
+ }
+ }
+
fputs("\n> ", fp_out);
viminfo_writestring(fp_out, str);
+ if (did_read_line)
+ fputs((char *)line, fp_out);
+
count++;
+ copy_marks_out = TRUE;
}
}
vim_free(str);
@@ -2031,6 +2128,11 @@ copy_viminfo_marks(
curbuf->b_changelistlen - 1] = pos;
#endif
break;
+
+ /* Using the line number for the last-used
+ * timestamp. */
+ case '*': curbuf->b_last_used = pos.lnum; break;
+
default: if ((i = line[1] - 'a') >= 0 && i < NMARKS)
curbuf->b_namedm[i] = pos;
}
@@ -2039,6 +2141,7 @@ copy_viminfo_marks(
else if (copy_marks_out)
fputs((char *)line, fp_out);
}
+
if (load_marks)
{
#ifdef FEAT_JUMPLIST
@@ -2053,6 +2156,16 @@ copy_viminfo_marks(
break;
}
}
+
+ if (fp_out != NULL)
+ /* Write any remaining entries from buflist. */
+ while (count < num_marked_files && buflist_used < buflist->ga_len)
+ {
+ buflist_buf = ((buf_T **)buflist->ga_data)[buflist_used++];
+ write_buffer_marks(buflist_buf, fp_out);
+ ++count;
+ }
+
vim_free(name_buf);
}
#endif /* FEAT_VIMINFO */
diff --git a/src/proto/mark.pro b/src/proto/mark.pro
index f24c0355eb..90be1a566e 100644
--- a/src/proto/mark.pro
+++ b/src/proto/mark.pro
@@ -30,6 +30,6 @@ void finish_viminfo_marks(void);
void handle_viminfo_mark(garray_T *values, int force);
void write_viminfo_filemarks(FILE *fp);
int removable(char_u *name);
-int write_viminfo_marks(FILE *fp_out);
-void copy_viminfo_marks(vir_T *virp, FILE *fp_out, int count, int eof, int flags);
+void write_viminfo_marks(FILE *fp_out, garray_T *buflist);
+void copy_viminfo_marks(vir_T *virp, FILE *fp_out, garray_T *buflist, int eof, int flags);
/* vim: set ft=c : */
diff --git a/src/structs.h b/src/structs.h
index 9d19c3c89f..05f4617059 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1771,6 +1771,10 @@ struct file_buffer
long b_mtime_read; /* last change time when reading */
off_T b_orig_size; /* size of original file in bytes */
int b_orig_mode; /* mode of original file */
+#ifdef FEAT_VIMINFO
+ time_T b_last_used; /* time when the buffer was last used; used
+ * for viminfo */
+#endif
pos_T b_namedm[NMARKS]; /* current named marks (mark.c) */
diff --git a/src/testdir/test_viminfo.vim b/src/testdir/test_viminfo.vim
index 76b24403b3..4c4935b92e 100644
--- a/src/testdir/test_viminfo.vim
+++ b/src/testdir/test_viminfo.vim
@@ -395,3 +395,33 @@ func Test_viminfo_bad_syntax()
call delete('Xviminfo')
endfunc
+func Test_viminfo_file_marks()
+ silent! bwipe test_viminfo.vim
+ silent! bwipe Xviminfo
+
+ call test_settime(10)
+ edit ten
+ call test_settime(25)
+ edit again
+ call test_settime(30)
+ edit thirty
+ wviminfo Xviminfo
+
+ call test_settime(20)
+ edit twenty
+ call test_settime(35)
+ edit again
+ call test_settime(40)
+ edit fourty
+ wviminfo Xviminfo
+
+ sp Xviminfo
+ 1
+ for name in ['fourty', 'again', 'thirty', 'twenty', 'ten']
+ /^>
+ call assert_equal(name, substitute(getline('.'), '.*/', '', ''))
+ endfor
+ close
+
+ call delete('Xviminfo')
+endfunc
diff --git a/src/version.c b/src/version.c
index 0a720cd1ef..a89b83e1c5 100644
--- a/src/version.c
+++ b/src/version.c
@@ -759,6 +759,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1988,
+/**/
1987,
/**/
1986,