1
0
forked from aniani/vim

patch 7.4.1925

Problem:    Viminfo does not merge file marks properly.
Solution:   Use a timestamp.  Add the :clearjumps command.
This commit is contained in:
Bram Moolenaar
2016-06-12 21:20:54 +02:00
parent cf08946349
commit 2d35899721
9 changed files with 380 additions and 18 deletions

View File

@@ -1983,6 +1983,8 @@ write_viminfo(char_u *file, int forceit)
*/ */
if (*wp == 'a') if (*wp == 'a')
{ {
EMSG2(_("E929: Too many viminfo temp files, like %s!"),
tempname);
vim_free(tempname); vim_free(tempname);
tempname = NULL; tempname = NULL;
break; break;
@@ -2164,9 +2166,13 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
{ {
if (flags & VIF_WANT_INFO) if (flags & VIF_WANT_INFO)
{ {
/* Registers are read and newer ones are used when writing. */
if (fp_out != NULL) 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_registers();
prepare_viminfo_marks();
}
eof = read_viminfo_up_to_marks(&vir, eof = read_viminfo_up_to_marks(&vir,
flags & VIF_FORCEIT, fp_out != NULL); 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); write_viminfo_varlist(fp_out);
#endif #endif
write_viminfo_filemarks(fp_out); write_viminfo_filemarks(fp_out);
finish_viminfo_marks();
write_viminfo_bufferlist(fp_out); write_viminfo_bufferlist(fp_out);
write_viminfo_barlines(&vir, fp_out); write_viminfo_barlines(&vir, fp_out);
count = write_viminfo_marks(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); handle_viminfo_register(&values, force);
break; break;
case BARTYPE_MARK:
barline_parse(virp, p, &values);
handle_viminfo_mark(&values, force);
break;
default: default:
/* copy unrecognized line (for future use) */ /* copy unrecognized line (for future use) */
if (writing) if (writing)

View File

@@ -316,6 +316,9 @@ EX(CMD_clast, "clast", ex_cc,
EX(CMD_close, "close", ex_close, EX(CMD_close, "close", ex_close,
BANG|RANGE|NOTADR|COUNT|TRLBAR|CMDWIN, BANG|RANGE|NOTADR|COUNT|TRLBAR|CMDWIN,
ADDR_WINDOWS), ADDR_WINDOWS),
EX(CMD_clearjumps, "clearjumps", ex_clearjumps,
TRLBAR|CMDWIN,
ADDR_LINES),
EX(CMD_cmap, "cmap", ex_map, EX(CMD_cmap, "cmap", ex_map,
EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN, EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
ADDR_LINES), ADDR_LINES),

View File

@@ -474,6 +474,7 @@ static void ex_folddo(exarg_T *eap);
#endif #endif
#ifndef FEAT_JUMPLIST #ifndef FEAT_JUMPLIST
# define ex_jumps ex_ni # define ex_jumps ex_ni
# define ex_clearjumps ex_ni
# define ex_changes ex_ni # define ex_changes ex_ni
#endif #endif

View File

@@ -106,24 +106,25 @@ setmark_pos(int c, pos_T *pos, int fnum)
return OK; return OK;
} }
#ifndef EBCDIC if (ASCII_ISLOWER(c))
if (c > 'z') /* some islower() and isupper() cannot handle
characters above 127 */
return FAIL;
#endif
if (islower(c))
{ {
i = c - 'a'; i = c - 'a';
curbuf->b_namedm[i] = *pos; curbuf->b_namedm[i] = *pos;
return OK; 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.mark = *pos;
namedfm[i].fmark.fnum = fnum; namedfm[i].fmark.fnum = fnum;
vim_free(namedfm[i].fname); vim_free(namedfm[i].fname);
namedfm[i].fname = NULL; namedfm[i].fname = NULL;
#ifdef FEAT_VIMINFO
namedfm[i].time_set = vim_time();
#endif
return OK; return OK;
} }
return FAIL; return FAIL;
@@ -184,6 +185,9 @@ setpcmark(void)
fm->fmark.mark = curwin->w_pcmark; fm->fmark.mark = curwin->w_pcmark;
fm->fmark.fnum = curbuf->b_fnum; fm->fmark.fnum = curbuf->b_fnum;
fm->fname = NULL; fm->fname = NULL;
# ifdef FEAT_VIMINFO
fm->time_set = vim_time();
# endif
#endif #endif
} }
@@ -634,6 +638,9 @@ clrallmarks(buf_T *buf)
{ {
namedfm[i].fmark.mark.lnum = 0; namedfm[i].fmark.mark.lnum = 0;
namedfm[i].fname = NULL; namedfm[i].fname = NULL;
#ifdef FEAT_VIMINFO
namedfm[i].time_set = 0;
#endif
} }
for (i = 0; i < NMARKS; i++) for (i = 0; i < NMARKS; i++)
@@ -849,6 +856,9 @@ ex_delmarks(exarg_T *eap)
namedfm[n].fmark.mark.lnum = 0; namedfm[n].fmark.mark.lnum = 0;
vim_free(namedfm[n].fname); vim_free(namedfm[n].fname);
namedfm[n].fname = NULL; 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>"); MSG_PUTS("\n>");
} }
void
ex_clearjumps(exarg_T *eap UNUSED)
{
free_jumplist(curwin);
curwin->w_jumplistlen = 0;
curwin->w_jumplistidx = 0;
}
/* /*
* print the changelist * print the changelist
*/ */
@@ -1400,11 +1418,199 @@ read_viminfo_filemark(vir_T *virp, int force)
vim_free(fm->fname); vim_free(fm->fname);
fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line), fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line),
FALSE); FALSE);
fm->time_set = 0;
} }
} }
return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd); 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 void
write_viminfo_filemarks(FILE *fp) write_viminfo_filemarks(FILE *fp)
{ {
@@ -1412,17 +1618,30 @@ write_viminfo_filemarks(FILE *fp)
char_u *name; char_u *name;
buf_T *buf; buf_T *buf;
xfmark_T *fm; xfmark_T *fm;
int vi_idx;
int idx;
if (get_viminfo_parameter('f') == 0) if (get_viminfo_parameter('f') == 0)
return; return;
fputs(_("\n# File marks:\n"), fp); 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. * Find a mark that is the same file and position as the cursor.
* That one, or else the last one is deleted. * That one, or else the last one is deleted.
* Move '0 to '1, '1 to '2, etc. until the matching one or '9 * 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)) 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.mark = curwin->w_cursor;
namedfm[NMARKS].fmark.fnum = curbuf->b_fnum; namedfm[NMARKS].fmark.fnum = curbuf->b_fnum;
namedfm[NMARKS].fname = NULL; namedfm[NMARKS].fname = NULL;
namedfm[NMARKS].time_set = vim_time();
} }
/* Write the filemarks '0 - '9 and 'A - 'Z */ /* Write the filemarks '0 - '9. Newest (highest timestamp) first. */
for (i = 0; i < NMARKS + EXTRA_MARKS; i++) vi_idx = NMARKS;
write_one_filemark(fp, &namedfm[i], '\'', idx = NMARKS;
i < NMARKS ? i + 'A' : i - NMARKS + '0'); 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 #ifdef FEAT_JUMPLIST
/* Write the jumplist with -' */ /* Write the jumplist with -' */
fputs(_("\n# Jumplist (newest first):\n"), fp); fputs(_("\n# Jumplist (newest first):\n"), fp);
setpcmark(); /* add current cursor position */ setpcmark(); /* add current cursor position */
cleanup_jumplist(); cleanup_jumplist();
/* TODO: when vi_jumplist != NULL merge the two lists. */
for (fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1]; for (fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
fm >= &curwin->w_jumplist[0]; --fm) 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, fprintf(fp, "%c%c %ld %ld ", c1, c2, (long)fm->fmark.mark.lnum,
(long)fm->fmark.mark.col); (long)fm->fmark.mark.col);
viminfo_writestring(fp, name); 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) if (fm->fmark.fnum != 0)

View File

@@ -16,6 +16,7 @@ char_u *fm_getname(fmark_T *fmark, int lead_len);
void do_marks(exarg_T *eap); void do_marks(exarg_T *eap);
void ex_delmarks(exarg_T *eap); void ex_delmarks(exarg_T *eap);
void ex_jumps(exarg_T *eap); void ex_jumps(exarg_T *eap);
void ex_clearjumps(exarg_T *eap);
void ex_changes(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_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); 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 set_last_cursor(win_T *win);
void free_all_marks(void); void free_all_marks(void);
int read_viminfo_filemark(vir_T *virp, int force); 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); void write_viminfo_filemarks(FILE *fp);
int removable(char_u *name); int removable(char_u *name);
int write_viminfo_marks(FILE *fp_out); int write_viminfo_marks(FILE *fp_out);

View File

@@ -84,7 +84,7 @@ typedef struct file_buffer buf_T; /* forward declaration */
# ifdef FEAT_XCLIPBOARD # ifdef FEAT_XCLIPBOARD
# include <X11/Intrinsic.h> # include <X11/Intrinsic.h>
# endif # 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 */ * make FEAT_TERMGUICOLORS work */
# define INVALCOLOR ((guicolor_T)0x1ffffff) # define INVALCOLOR ((guicolor_T)0x1ffffff)
#endif #endif
@@ -112,6 +112,9 @@ typedef struct xfilemark
{ {
fmark_T fmark; fmark_T fmark;
char_u *fname; /* file name, used when fnum == 0 */ char_u *fname; /* file name, used when fnum == 0 */
#ifdef FEAT_VIMINFO
time_t time_set;
#endif
} xfmark_T; } xfmark_T;
/* /*

View File

@@ -17,9 +17,9 @@ function Test_read_and_write()
let lines = readfile('Xviminfo') let lines = readfile('Xviminfo')
let done = 0 let done = 0
for line in lines for line in lines
if line[0] == '|' && line !~ '^|3,' if line[0] == '|' && line !~ '^|[234],'
if done == 0 if done == 0
call assert_equal('|1,3', line) call assert_equal('|1,4', line)
elseif done == 1 elseif done == 1
call assert_equal('|copied as-is', line) call assert_equal('|copied as-is', line)
elseif done == 2 elseif done == 2
@@ -217,6 +217,102 @@ func Test_viminfo_registers()
call delete('Xviminfo') call delete('Xviminfo')
endfunc 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() func Test_viminfo_encoding()
if !has('multi_byte') if !has('multi_byte')
return return

View File

@@ -753,6 +753,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1925,
/**/ /**/
1924, 1924,
/**/ /**/

View File

@@ -1076,10 +1076,12 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
#define BARTYPE_VERSION 1 #define BARTYPE_VERSION 1
#define BARTYPE_HISTORY 2 #define BARTYPE_HISTORY 2
#define BARTYPE_REGISTER 3 #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_HISTORY 2
#define VIMINFO_VERSION_WITH_REGISTERS 3 #define VIMINFO_VERSION_WITH_REGISTERS 3
#define VIMINFO_VERSION_WITH_MARKS 4
typedef enum { typedef enum {
BVAL_NR, BVAL_NR,