0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 9.1.0554: :bw leaves jumplist and tagstack data around

Problem:  :bw leaves jumplist and tagstack data around
          (Paul "Joey" Clark)
Solution: Wipe jumplist and tagstack references to the wiped buffer
          (LemonBoy)

As documented the :bwipeout command brutally deletes all the references
to the buffer, so let's make it delete all the entries in the jump list
and tag stack referring to the wiped-out buffer.

fixes: #8201
closes: #15185

Signed-off-by: LemonBoy <thatlemon@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
LemonBoy
2024-07-09 20:03:24 +02:00
committed by Christian Brabandt
parent d33a518025
commit 4ff3a9b1e3
11 changed files with 72 additions and 20 deletions

View File

@@ -41579,6 +41579,7 @@ Changed~
- allow to specify a priority when defining a new sign |:sign-define| - allow to specify a priority when defining a new sign |:sign-define|
- provide information about function arguments using the get(func, "arity") - provide information about function arguments using the get(func, "arity")
function |get()-func| function |get()-func|
- |:bwipe| also wipes jumplist and tagstack data
*added-9.2* *added-9.2*
Added ~ Added ~

View File

@@ -1,4 +1,4 @@
*windows.txt* For Vim version 9.1. Last change: 2024 Feb 20 *windows.txt* For Vim version 9.1. Last change: 2024 Jul 09
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1223,7 +1223,8 @@ list of buffers. |unlisted-buffer|
:bw[ipeout][!] N1 N2 ... :bw[ipeout][!] N1 N2 ...
Like |:bdelete|, but really delete the buffer. Everything Like |:bdelete|, but really delete the buffer. Everything
related to the buffer is lost. All marks in this buffer related to the buffer is lost. All marks in this buffer
become invalid, option settings are lost, etc. Don't use this become invalid, option settings are lost, the jumplist and
tagstack data will be purged, etc. Don't use this
unless you know what you are doing. Examples: > unless you know what you are doing. Examples: >
:.+,$bwipeout " wipe out all buffers after the current :.+,$bwipeout " wipe out all buffers after the current
" one " one

View File

@@ -750,10 +750,15 @@ aucmd_abort:
*/ */
if (wipe_buf) if (wipe_buf)
{ {
win_T *wp;
// Do not wipe out the buffer if it is used in a window. // Do not wipe out the buffer if it is used in a window.
if (buf->b_nwindows > 0) if (buf->b_nwindows > 0)
return FALSE; return FALSE;
FOR_ALL_WINDOWS(wp)
mark_forget_file(wp, buf->b_fnum);
if (action == DOBUF_WIPE_REUSE) if (action == DOBUF_WIPE_REUSE)
{ {
// we can re-use this buffer number, store it // we can re-use this buffer number, store it

View File

@@ -129,6 +129,40 @@ setmark_pos(int c, pos_T *pos, int fnum)
return FAIL; return FAIL;
} }
/*
* Delete every entry referring to file 'fnum' from both the jumplist and the
* tag stack.
*/
void
mark_forget_file(win_T *wp, int fnum)
{
int i;
for (i = 0; i < wp->w_jumplistlen; ++i)
if (wp->w_jumplist[i].fmark.fnum == fnum)
{
vim_free(wp->w_jumplist[i].fname);
mch_memmove(&wp->w_jumplist[i], &wp->w_jumplist[i + 1],
(wp->w_jumplistlen - i - 1) * sizeof(xfmark_T));
if (wp->w_jumplistidx > i)
--wp->w_jumplistidx;
--wp->w_jumplistlen;
--i;
}
for (i = 0; i < wp->w_tagstacklen; i++)
if (wp->w_tagstack[i].fmark.fnum == fnum)
{
tagstack_clear_entry(&wp->w_tagstack[i]);
mch_memmove(&wp->w_tagstack[i], &wp->w_tagstack[i + 1],
(wp->w_tagstacklen - i - 1) * sizeof(taggy_T));
if (wp->w_tagstackidx > i)
--wp->w_tagstackidx;
--wp->w_tagstacklen;
--i;
}
}
/* /*
* Set the previous context mark to the current position and add it to the * Set the previous context mark to the current position and add it to the
* jump list. * jump list.

View File

@@ -28,4 +28,5 @@ void set_last_cursor(win_T *win);
void free_all_marks(void); void free_all_marks(void);
xfmark_T *get_namedfm(void); xfmark_T *get_namedfm(void);
void f_getmarklist(typval_T *argvars, typval_T *rettv); void f_getmarklist(typval_T *argvars, typval_T *rettv);
void mark_forget_file(win_T *wp, int fnum);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -14,4 +14,5 @@ int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file);
int get_tags(list_T *list, char_u *pat, char_u *buf_fname); int get_tags(list_T *list, char_u *pat, char_u *buf_fname);
void get_tagstack(win_T *wp, dict_T *retdict); void get_tagstack(win_T *wp, dict_T *retdict);
int set_tagstack(win_T *wp, dict_T *d, int action); int set_tagstack(win_T *wp, dict_T *d, int action);
void tagstack_clear_entry(taggy_T *item);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -144,7 +144,6 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_
#if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL) #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
static int add_llist_tags(char_u *tag, int num_matches, char_u **matches); static int add_llist_tags(char_u *tag, int num_matches, char_u **matches);
#endif #endif
static void tagstack_clear_entry(taggy_T *item);
static char_u *tagmatchname = NULL; // name of last used tag static char_u *tagmatchname = NULL; // name of last used tag
@@ -4233,7 +4232,7 @@ find_extra(char_u **pp)
/* /*
* Free a single entry in a tag stack * Free a single entry in a tag stack
*/ */
static void void
tagstack_clear_entry(taggy_T *item) tagstack_clear_entry(taggy_T *item)
{ {
VIM_CLEAR(item->tagname); VIM_CLEAR(item->tagname);

View File

@@ -62,26 +62,16 @@ endfunc
func Test_jumplist_invalid() func Test_jumplist_invalid()
new new
clearjumps clearjumps
" put some randome text " Put some random text and fill the jump list.
put ='a' call setline(1, ['foo', 'bar', 'baz'])
let prev = bufnr('%') normal G
normal gg
setl nomodified bufhidden=wipe setl nomodified bufhidden=wipe
e XXJumpListBuffer e XXJumpListBuffer
let bnr = bufnr('%') " The jump list is empty as the buffer was wiped out.
" 1) empty jumplist call assert_equal([[], 0], getjumplist())
let expected = [[
\ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0}], 1]
call assert_equal(expected, getjumplist())
let jumps = execute(':jumps') let jumps = execute(':jumps')
call assert_equal('>', jumps[-1:]) call assert_equal('>', jumps[-1:])
" now jump back
exe ":norm! \<c-o>"
let expected = [[
\ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0},
\ {'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0}], 0]
call assert_equal(expected, getjumplist())
let jumps = execute(':jumps')
call assert_match('> 0 2 0 -invalid-', jumps)
endfunc endfunc
" Test for '' mark in an empty buffer " Test for '' mark in an empty buffer

View File

@@ -958,6 +958,23 @@ func Test_tag_stack()
call settagstack(1, {'items' : []}) call settagstack(1, {'items' : []})
call assert_fails('pop', 'E73:') call assert_fails('pop', 'E73:')
" References to wiped buffer are deleted.
for i in range(10, 20)
edit Xtest
exe "tag var" .. i
endfor
edit Xtest
let t = gettagstack()
call assert_equal(11, t.length)
call assert_equal(12, t.curidx)
bwipe!
let t = gettagstack()
call assert_equal(0, t.length)
call assert_equal(1, t.curidx)
set tags& set tags&
%bwipe %bwipe
endfunc endfunc

View File

@@ -2934,6 +2934,7 @@ func Test_tfirst()
\ "Xtags", 'D') \ "Xtags", 'D')
call writefile(["one", "two", "three"], "Xfile", 'D') call writefile(["one", "two", "three"], "Xfile", 'D')
call writefile(["one"], "Xother", 'D') call writefile(["one"], "Xother", 'D')
tag one
edit Xother edit Xother
set winfixbuf set winfixbuf

View File

@@ -704,6 +704,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 */
/**/
554,
/**/ /**/
553, 553,
/**/ /**/