summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-06-12 21:20:54 +0200
committerBram Moolenaar <Bram@vim.org>2016-06-12 21:20:54 +0200
commit2d35899721da0e9359a9fe1059554f8c4ea7f0c1 (patch)
treefcb24c8186d9b23277948cb097e1807830737781
parentcf089463492fab53b2a5d81517829d22f882f82e (diff)
patch 7.4.1925v7.4.1925
Problem: Viminfo does not merge file marks properly. Solution: Use a timestamp. Add the :clearjumps command.
-rw-r--r--src/ex_cmds.c14
-rw-r--r--src/ex_cmds.h3
-rw-r--r--src/ex_docmd.c1
-rw-r--r--src/mark.c265
-rw-r--r--src/proto/mark.pro4
-rw-r--r--src/structs.h5
-rw-r--r--src/testdir/test_viminfo.vim100
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h4
9 files changed, 380 insertions, 18 deletions
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index b3b920939d..519f40c167 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -1983,6 +1983,8 @@ write_viminfo(char_u *file, int forceit)
*/
if (*wp == 'a')
{
+ EMSG2(_("E929: Too many viminfo temp files, like %s!"),
+ tempname);
vim_free(tempname);
tempname = NULL;
break;
@@ -2164,9 +2166,13 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
{
if (flags & VIF_WANT_INFO)
{
- /* Registers are read and newer ones are used when writing. */
if (fp_out != NULL)
+ {
+ /* Registers and marks are read and kept separate from what
+ * this Vim is using. They are merged when writing. */
prepare_viminfo_registers();
+ prepare_viminfo_marks();
+ }
eof = read_viminfo_up_to_marks(&vir,
flags & VIF_FORCEIT, fp_out != NULL);
@@ -2200,6 +2206,7 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
write_viminfo_varlist(fp_out);
#endif
write_viminfo_filemarks(fp_out);
+ finish_viminfo_marks();
write_viminfo_bufferlist(fp_out);
write_viminfo_barlines(&vir, fp_out);
count = write_viminfo_marks(fp_out);
@@ -2778,6 +2785,11 @@ read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing)
handle_viminfo_register(&values, force);
break;
+ case BARTYPE_MARK:
+ barline_parse(virp, p, &values);
+ handle_viminfo_mark(&values, force);
+ break;
+
default:
/* copy unrecognized line (for future use) */
if (writing)
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index e2b30f2f69..5053e602e6 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -316,6 +316,9 @@ EX(CMD_clast, "clast", ex_cc,
EX(CMD_close, "close", ex_close,
BANG|RANGE|NOTADR|COUNT|TRLBAR|CMDWIN,
ADDR_WINDOWS),
+EX(CMD_clearjumps, "clearjumps", ex_clearjumps,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
EX(CMD_cmap, "cmap", ex_map,
EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
ADDR_LINES),
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 55c093fb09..ad4ba7c4e5 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -474,6 +474,7 @@ static void ex_folddo(exarg_T *eap);
#endif
#ifndef FEAT_JUMPLIST
# define ex_jumps ex_ni
+# define ex_clearjumps ex_ni
# define ex_changes ex_ni
#endif
diff --git a/src/mark.c b/src/mark.c
index 3465947730..34825a6574 100644
--- a/src/mark.c
+++ b/src/mark.c
@@ -106,24 +106,25 @@ setmark_pos(int c, pos_T *pos, int fnum)
return OK;
}
-#ifndef EBCDIC
- if (c > 'z') /* some islower() and isupper() cannot handle
- characters above 127 */
- return FAIL;
-#endif
- if (islower(c))
+ if (ASCII_ISLOWER(c))
{
i = c - 'a';
curbuf->b_namedm[i] = *pos;
return OK;
}
- if (isupper(c))
+ if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c))
{
- i = c - 'A';
+ if (VIM_ISDIGIT(c))
+ i = c - '0' + NMARKS;
+ else
+ i = c - 'A';
namedfm[i].fmark.mark = *pos;
namedfm[i].fmark.fnum = fnum;
vim_free(namedfm[i].fname);
namedfm[i].fname = NULL;
+#ifdef FEAT_VIMINFO
+ namedfm[i].time_set = vim_time();
+#endif
return OK;
}
return FAIL;
@@ -184,6 +185,9 @@ setpcmark(void)
fm->fmark.mark = curwin->w_pcmark;
fm->fmark.fnum = curbuf->b_fnum;
fm->fname = NULL;
+# ifdef FEAT_VIMINFO
+ fm->time_set = vim_time();
+# endif
#endif
}
@@ -634,6 +638,9 @@ clrallmarks(buf_T *buf)
{
namedfm[i].fmark.mark.lnum = 0;
namedfm[i].fname = NULL;
+#ifdef FEAT_VIMINFO
+ namedfm[i].time_set = 0;
+#endif
}
for (i = 0; i < NMARKS; i++)
@@ -849,6 +856,9 @@ ex_delmarks(exarg_T *eap)
namedfm[n].fmark.mark.lnum = 0;
vim_free(namedfm[n].fname);
namedfm[n].fname = NULL;
+#ifdef FEAT_VIMINFO
+ namedfm[n].time_set = 0;
+#endif
}
}
}
@@ -918,6 +928,14 @@ ex_jumps(exarg_T *eap UNUSED)
MSG_PUTS("\n>");
}
+ void
+ex_clearjumps(exarg_T *eap UNUSED)
+{
+ free_jumplist(curwin);
+ curwin->w_jumplistlen = 0;
+ curwin->w_jumplistidx = 0;
+}
+
/*
* print the changelist
*/
@@ -1400,11 +1418,199 @@ read_viminfo_filemark(vir_T *virp, int force)
vim_free(fm->fname);
fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line),
FALSE);
+ fm->time_set = 0;
}
}
return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
}
+static xfmark_T *vi_namedfm = NULL;
+#ifdef FEAT_JUMPLIST
+static xfmark_T *vi_jumplist = NULL;
+static int vi_jumplist_len = 0;
+#endif
+
+/*
+ * Prepare for reading viminfo marks when writing viminfo later.
+ */
+ void
+prepare_viminfo_marks(void)
+{
+ vi_namedfm = (xfmark_T *)alloc_clear((NMARKS + EXTRA_MARKS)
+ * (int)sizeof(xfmark_T));
+#ifdef FEAT_JUMPLIST
+ vi_jumplist = (xfmark_T *)alloc_clear(JUMPLISTSIZE
+ * (int)sizeof(xfmark_T));
+ vi_jumplist_len = 0;
+#endif
+}
+
+ void
+finish_viminfo_marks(void)
+{
+ int i;
+
+ if (vi_namedfm != NULL)
+ {
+ for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
+ vim_free(vi_namedfm[i].fname);
+ vim_free(vi_namedfm);
+ vi_namedfm = NULL;
+ }
+#ifdef FEAT_JUMPLIST
+ if (vi_jumplist != NULL)
+ {
+ for (i = 0; i < vi_jumplist_len; ++i)
+ vim_free(vi_jumplist[i].fname);
+ vim_free(vi_jumplist);
+ vi_jumplist = NULL;
+ }
+#endif
+}
+
+/*
+ * Accept a new style mark line from the viminfo, store it when it's new.
+ */
+ void
+handle_viminfo_mark(garray_T *values, int force)
+{
+ bval_T *vp = (bval_T *)values->ga_data;
+ int name;
+ linenr_T lnum;
+ colnr_T col;
+ time_t timestamp;
+ xfmark_T *fm = NULL;
+
+ /* Check the format:
+ * |{bartype},{name},{lnum},{col},{timestamp},{filename} */
+ if (values->ga_len < 5
+ || vp[0].bv_type != BVAL_NR
+ || vp[1].bv_type != BVAL_NR
+ || vp[2].bv_type != BVAL_NR
+ || vp[3].bv_type != BVAL_NR
+ || vp[4].bv_type != BVAL_STRING)
+ return;
+
+ name = vp[0].bv_nr;
+ if (name != '\'' && !VIM_ISDIGIT(name) && !ASCII_ISUPPER(name))
+ return;
+ lnum = vp[1].bv_nr;
+ col = vp[2].bv_nr;
+ if (lnum <= 0 || col < 0)
+ return;
+ timestamp = (time_t)vp[3].bv_nr;
+
+ if (name == '\'')
+ {
+#ifdef FEAT_JUMPLIST
+ if (vi_jumplist != NULL)
+ {
+ if (vi_jumplist_len < JUMPLISTSIZE)
+ fm = &vi_jumplist[vi_jumplist_len++];
+ }
+ else
+ {
+ int idx;
+ int i;
+
+ /* If we have a timestamp insert it in the right place. */
+ if (timestamp != 0)
+ {
+ for (idx = curwin->w_jumplistlen - 1; idx >= 0; --idx)
+ if (curwin->w_jumplist[idx].time_set < timestamp)
+ break;
+ }
+ else if (curwin->w_jumplistlen < JUMPLISTSIZE)
+ /* insert as oldest entry */
+ idx = 0;
+ else
+ idx = -1;
+
+ if (idx >= 0)
+ {
+ if (curwin->w_jumplistlen == JUMPLISTSIZE)
+ {
+ /* Drop the oldest entry. */
+ vim_free(curwin->w_jumplist[0].fname);
+ for (i = 0; i < idx; ++i)
+ curwin->w_jumplist[i] = curwin->w_jumplist[i + 1];
+ }
+ else
+ {
+ /* Move newer entries forward. */
+ ++idx;
+ for (i = curwin->w_jumplistlen; i > idx; --i)
+ curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
+ ++curwin->w_jumplistidx;
+ ++curwin->w_jumplistlen;
+ }
+ fm = &curwin->w_jumplist[idx];
+ fm->fmark.mark.lnum = 0;
+ fm->fname = NULL;
+ fm->time_set = 0;
+ }
+ }
+#endif
+ }
+ else
+ {
+ int idx;
+
+ if (VIM_ISDIGIT(name))
+ {
+ if (vi_namedfm != NULL)
+ idx = name - '0' + NMARKS;
+ else
+ {
+ int i;
+
+ /* Do not use the name from the viminfo file, insert in time
+ * order. */
+ for (idx = NMARKS; idx < NMARKS + EXTRA_MARKS; ++idx)
+ if (namedfm[idx].time_set < timestamp)
+ break;
+ if (idx == NMARKS + EXTRA_MARKS)
+ /* All existing entries are newer. */
+ return;
+ i = NMARKS + EXTRA_MARKS - 1;
+
+ vim_free(namedfm[i].fname);
+ for ( ; i > idx; --i)
+ namedfm[i] = namedfm[i - 1];
+ namedfm[idx].fname = NULL;
+ }
+ }
+ else
+ idx = name - 'A';
+ if (vi_namedfm != NULL)
+ fm = &vi_namedfm[idx];
+ else
+ fm = &namedfm[idx];
+ }
+
+ if (fm != NULL)
+ {
+ if (vi_namedfm != NULL || fm->time_set < timestamp || force)
+ {
+ fm->fmark.mark.lnum = lnum;
+ fm->fmark.mark.col = col;
+#ifdef FEAT_VIRTUALEDIT
+ fm->fmark.mark.coladd = 0;
+#endif
+ fm->fmark.fnum = 0;
+ vim_free(fm->fname);
+ if (vp[4].bv_allocated)
+ {
+ fm->fname = vp[4].bv_string;
+ vp[4].bv_string = NULL;
+ }
+ else
+ fm->fname = vim_strsave(vp[4].bv_string);
+ fm->time_set = timestamp;
+ }
+ }
+}
+
void
write_viminfo_filemarks(FILE *fp)
{
@@ -1412,17 +1618,30 @@ write_viminfo_filemarks(FILE *fp)
char_u *name;
buf_T *buf;
xfmark_T *fm;
+ int vi_idx;
+ int idx;
if (get_viminfo_parameter('f') == 0)
return;
fputs(_("\n# File marks:\n"), fp);
+ /* Write the filemarks 'A - 'Z */
+ for (i = 0; i < NMARKS; i++)
+ {
+ if (vi_namedfm != NULL && (vi_namedfm[i].time_set > namedfm[i].time_set
+ || namedfm[i].fmark.mark.lnum == 0))
+ fm = &vi_namedfm[i];
+ else
+ fm = &namedfm[i];
+ write_one_filemark(fp, fm, '\'', i + 'A');
+ }
+
/*
* Find a mark that is the same file and position as the cursor.
* That one, or else the last one is deleted.
* Move '0 to '1, '1 to '2, etc. until the matching one or '9
- * Set '0 mark to current cursor position.
+ * Set the '0 mark to current cursor position.
*/
if (curbuf->b_ffname != NULL && !removable(curbuf->b_ffname))
{
@@ -1442,18 +1661,30 @@ write_viminfo_filemarks(FILE *fp)
namedfm[NMARKS].fmark.mark = curwin->w_cursor;
namedfm[NMARKS].fmark.fnum = curbuf->b_fnum;
namedfm[NMARKS].fname = NULL;
+ namedfm[NMARKS].time_set = vim_time();
}
- /* Write the filemarks '0 - '9 and 'A - 'Z */
- for (i = 0; i < NMARKS + EXTRA_MARKS; i++)
- write_one_filemark(fp, &namedfm[i], '\'',
- i < NMARKS ? i + 'A' : i - NMARKS + '0');
+ /* Write the filemarks '0 - '9. Newest (highest timestamp) first. */
+ vi_idx = NMARKS;
+ idx = NMARKS;
+ for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
+ {
+ if (vi_namedfm != NULL
+ && vi_namedfm[vi_idx].fmark.mark.lnum != 0
+ && (vi_namedfm[vi_idx].time_set > namedfm[idx].time_set
+ || namedfm[idx].fmark.mark.lnum == 0))
+ fm = &vi_namedfm[vi_idx++];
+ else
+ fm = &namedfm[idx++];
+ write_one_filemark(fp, fm, '\'', i - NMARKS + '0');
+ }
#ifdef FEAT_JUMPLIST
/* Write the jumplist with -' */
fputs(_("\n# Jumplist (newest first):\n"), fp);
setpcmark(); /* add current cursor position */
cleanup_jumplist();
+ /* TODO: when vi_jumplist != NULL merge the two lists. */
for (fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
fm >= &curwin->w_jumplist[0]; --fm)
{
@@ -1486,6 +1717,14 @@ write_one_filemark(
fprintf(fp, "%c%c %ld %ld ", c1, c2, (long)fm->fmark.mark.lnum,
(long)fm->fmark.mark.col);
viminfo_writestring(fp, name);
+
+ /* Barline: |{bartype},{name},{lnum},{col},{timestamp},{filename}
+ * size up to filename: 8 + 3 * 20 */
+ fprintf(fp, "|%d,%d,%ld,%ld,%ld,", BARTYPE_MARK, c2,
+ (long)fm->fmark.mark.lnum, (long)fm->fmark.mark.col,
+ (long)fm->time_set);
+ barline_writestring(fp, name, LSIZE - 70);
+ putc('\n', fp);
}
if (fm->fmark.fnum != 0)
diff --git a/src/proto/mark.pro b/src/proto/mark.pro
index 9a3e9e9e0d..f24c0355eb 100644
--- a/src/proto/mark.pro
+++ b/src/proto/mark.pro
@@ -16,6 +16,7 @@ char_u *fm_getname(fmark_T *fmark, int lead_len);
void do_marks(exarg_T *eap);
void ex_delmarks(exarg_T *eap);
void ex_jumps(exarg_T *eap);
+void ex_clearjumps(exarg_T *eap);
void ex_changes(exarg_T *eap);
void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after);
void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount);
@@ -24,6 +25,9 @@ void free_jumplist(win_T *wp);
void set_last_cursor(win_T *win);
void free_all_marks(void);
int read_viminfo_filemark(vir_T *virp, int force);
+void prepare_viminfo_marks(void);
+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);
diff --git a/src/structs.h b/src/structs.h
index ac99e9158d..6075ee2e0a 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -84,7 +84,7 @@ typedef struct file_buffer buf_T; /* forward declaration */
# ifdef FEAT_XCLIPBOARD
# include <X11/Intrinsic.h>
# endif
-# define guicolor_T long_u /* avoid error in prototypes and
+# define guicolor_T long_u /* avoid error in prototypes and
* make FEAT_TERMGUICOLORS work */
# define INVALCOLOR ((guicolor_T)0x1ffffff)
#endif
@@ -112,6 +112,9 @@ typedef struct xfilemark
{
fmark_T fmark;
char_u *fname; /* file name, used when fnum == 0 */
+#ifdef FEAT_VIMINFO
+ time_t time_set;
+#endif
} xfmark_T;
/*
diff --git a/src/testdir/test_viminfo.vim b/src/testdir/test_viminfo.vim
index b68b8ce586..19be47dd16 100644
--- a/src/testdir/test_viminfo.vim
+++ b/src/testdir/test_viminfo.vim
@@ -17,9 +17,9 @@ function Test_read_and_write()
let lines = readfile('Xviminfo')
let done = 0
for line in lines
- if line[0] == '|' && line !~ '^|3,'
+ if line[0] == '|' && line !~ '^|[234],'
if done == 0
- call assert_equal('|1,3', line)
+ call assert_equal('|1,4', line)
elseif done == 1
call assert_equal('|copied as-is', line)
elseif done == 2
@@ -217,6 +217,102 @@ func Test_viminfo_registers()
call delete('Xviminfo')
endfunc
+func Test_viminfo_marks()
+ sp bufa
+ let bufa = bufnr('%')
+ sp bufb
+ let bufb = bufnr('%')
+
+ call test_settime(8)
+ call setpos("'A", [bufa, 1, 1, 0])
+ call test_settime(20)
+ call setpos("'B", [bufb, 9, 1, 0])
+ call setpos("'C", [bufa, 7, 1, 0])
+
+ delmark 0-9
+ call test_settime(25)
+ call setpos("'1", [bufb, 12, 1, 0])
+ call test_settime(35)
+ call setpos("'0", [bufa, 11, 1, 0])
+
+ call test_settime(45)
+ wviminfo Xviminfo
+
+ " Writing viminfo inserts the '0 mark.
+ call assert_equal([bufb, 1, 1, 0], getpos("'0"))
+ call assert_equal([bufa, 11, 1, 0], getpos("'1"))
+ call assert_equal([bufb, 12, 1, 0], getpos("'2"))
+
+ call test_settime(4)
+ call setpos("'A", [bufa, 9, 1, 0])
+ call test_settime(30)
+ call setpos("'B", [bufb, 2, 3, 0])
+ delmark C
+
+ delmark 0-9
+ call test_settime(30)
+ call setpos("'1", [bufb, 22, 1, 0])
+ call test_settime(55)
+ call setpos("'0", [bufa, 21, 1, 0])
+
+ rviminfo Xviminfo
+
+ call assert_equal([bufa, 1, 1, 0], getpos("'A"))
+ call assert_equal([bufb, 2, 3, 0], getpos("'B"))
+ call assert_equal([bufa, 7, 1, 0], getpos("'C"))
+
+ " numbered marks are merged
+ call assert_equal([bufa, 21, 1, 0], getpos("'0")) " time 55
+ call assert_equal([bufb, 1, 1, 0], getpos("'1")) " time 45
+ call assert_equal([bufa, 11, 1, 0], getpos("'2")) " time 35
+ call assert_equal([bufb, 22, 1, 0], getpos("'3")) " time 30
+ call assert_equal([bufb, 12, 1, 0], getpos("'4")) " time 25
+
+ call delete('Xviminfo')
+ exe 'bwipe ' . bufa
+ exe 'bwipe ' . bufb
+endfunc
+
+func Test_viminfo_jumplist()
+ split testbuf
+ clearjumps
+ call setline(1, ['time 05', 'time 10', 'time 15', 'time 20', 'time 30', 'last pos'])
+ call cursor(2, 1)
+ call test_settime(10)
+ exe "normal /20\r"
+ call test_settime(20)
+ exe "normal /30\r"
+ call test_settime(30)
+ exe "normal /last pos\r"
+ wviminfo Xviminfo
+
+ clearjumps
+ call cursor(1, 1)
+ call test_settime(5)
+ exe "normal /15\r"
+ call test_settime(15)
+ exe "normal /last pos\r"
+ call test_settime(40)
+ exe "normal ?30\r"
+ rviminfo Xviminfo
+
+ call assert_equal('time 30', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('last pos', getline('.'))
+ exe "normal \<C-O>"
+ " duplicate for 'time 30' was removed
+ call assert_equal('time 20', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 15', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 10', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 05', getline('.'))
+
+ bwipe!
+ call delete('Xviminfo')
+endfunc
+
func Test_viminfo_encoding()
if !has('multi_byte')
return
diff --git a/src/version.c b/src/version.c
index 01b9c4fcbf..9c821d492b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1925,
+/**/
1924,
/**/
1923,
diff --git a/src/vim.h b/src/vim.h
index 863c2e211e..7c933d5976 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1076,10 +1076,12 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
#define BARTYPE_VERSION 1
#define BARTYPE_HISTORY 2
#define BARTYPE_REGISTER 3
+#define BARTYPE_MARK 4
-#define VIMINFO_VERSION 3
+#define VIMINFO_VERSION 4
#define VIMINFO_VERSION_WITH_HISTORY 2
#define VIMINFO_VERSION_WITH_REGISTERS 3
+#define VIMINFO_VERSION_WITH_MARKS 4
typedef enum {
BVAL_NR,