summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2024-07-09 20:03:24 +0200
committerChristian Brabandt <cb@256bit.org>2024-07-09 20:03:24 +0200
commit4ff3a9b1e3ba45f9dbd0ea8c721f27d9315c4d93 (patch)
tree4bfd88e4c40f3873eccaa6d38ed4b27a21bc2b88
parentd33a518025765c4a3530ad6cfb6cab83a30c8f55 (diff)
patch 9.1.0554: :bw leaves jumplist and tagstack data aroundv9.1.0554
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>
-rw-r--r--runtime/doc/version9.txt1
-rw-r--r--runtime/doc/windows.txt5
-rw-r--r--src/buffer.c5
-rw-r--r--src/mark.c34
-rw-r--r--src/proto/mark.pro1
-rw-r--r--src/proto/tag.pro1
-rw-r--r--src/tag.c3
-rw-r--r--src/testdir/test_jumplist.vim22
-rw-r--r--src/testdir/test_tagjump.vim17
-rw-r--r--src/testdir/test_winfixbuf.vim1
-rw-r--r--src/version.c2
11 files changed, 72 insertions, 20 deletions
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 9cf20300fa..df56215ea8 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -41579,6 +41579,7 @@ Changed~
- allow to specify a priority when defining a new sign |:sign-define|
- provide information about function arguments using the get(func, "arity")
function |get()-func|
+- |:bwipe| also wipes jumplist and tagstack data
*added-9.2*
Added ~
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index e264e51170..d3e5f67858 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -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
@@ -1223,7 +1223,8 @@ list of buffers. |unlisted-buffer|
:bw[ipeout][!] N1 N2 ...
Like |:bdelete|, but really delete the buffer. Everything
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: >
:.+,$bwipeout " wipe out all buffers after the current
" one
diff --git a/src/buffer.c b/src/buffer.c
index cbec9b980c..28967342d0 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -750,10 +750,15 @@ aucmd_abort:
*/
if (wipe_buf)
{
+ win_T *wp;
+
// Do not wipe out the buffer if it is used in a window.
if (buf->b_nwindows > 0)
return FALSE;
+ FOR_ALL_WINDOWS(wp)
+ mark_forget_file(wp, buf->b_fnum);
+
if (action == DOBUF_WIPE_REUSE)
{
// we can re-use this buffer number, store it
diff --git a/src/mark.c b/src/mark.c
index 22e3c62575..85f7b68e2f 100644
--- a/src/mark.c
+++ b/src/mark.c
@@ -130,6 +130,40 @@ setmark_pos(int c, pos_T *pos, int fnum)
}
/*
+ * 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
* jump list.
*/
diff --git a/src/proto/mark.pro b/src/proto/mark.pro
index cc45f0d3c3..d398c3677c 100644
--- a/src/proto/mark.pro
+++ b/src/proto/mark.pro
@@ -28,4 +28,5 @@ void set_last_cursor(win_T *win);
void free_all_marks(void);
xfmark_T *get_namedfm(void);
void f_getmarklist(typval_T *argvars, typval_T *rettv);
+void mark_forget_file(win_T *wp, int fnum);
/* vim: set ft=c : */
diff --git a/src/proto/tag.pro b/src/proto/tag.pro
index 6de463e92c..eec7c24ed4 100644
--- a/src/proto/tag.pro
+++ b/src/proto/tag.pro
@@ -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);
void get_tagstack(win_T *wp, dict_T *retdict);
int set_tagstack(win_T *wp, dict_T *d, int action);
+void tagstack_clear_entry(taggy_T *item);
/* vim: set ft=c : */
diff --git a/src/tag.c b/src/tag.c
index d406fdec1a..57f9fe016a 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -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)
static int add_llist_tags(char_u *tag, int num_matches, char_u **matches);
#endif
-static void tagstack_clear_entry(taggy_T *item);
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
*/
- static void
+ void
tagstack_clear_entry(taggy_T *item)
{
VIM_CLEAR(item->tagname);
diff --git a/src/testdir/test_jumplist.vim b/src/testdir/test_jumplist.vim
index 8fbf39f55b..0f43a8c6eb 100644
--- a/src/testdir/test_jumplist.vim
+++ b/src/testdir/test_jumplist.vim
@@ -62,26 +62,16 @@ endfunc
func Test_jumplist_invalid()
new
clearjumps
- " put some randome text
- put ='a'
- let prev = bufnr('%')
+ " Put some random text and fill the jump list.
+ call setline(1, ['foo', 'bar', 'baz'])
+ normal G
+ normal gg
setl nomodified bufhidden=wipe
e XXJumpListBuffer
- let bnr = bufnr('%')
- " 1) empty jumplist
- let expected = [[
- \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0}], 1]
- call assert_equal(expected, getjumplist())
+ " The jump list is empty as the buffer was wiped out.
+ call assert_equal([[], 0], getjumplist())
let jumps = execute(':jumps')
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
" Test for '' mark in an empty buffer
diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim
index 432906efbf..71237855c9 100644
--- a/src/testdir/test_tagjump.vim
+++ b/src/testdir/test_tagjump.vim
@@ -958,6 +958,23 @@ func Test_tag_stack()
call settagstack(1, {'items' : []})
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&
%bwipe
endfunc
diff --git a/src/testdir/test_winfixbuf.vim b/src/testdir/test_winfixbuf.vim
index f800338cbd..3cec4ed70b 100644
--- a/src/testdir/test_winfixbuf.vim
+++ b/src/testdir/test_winfixbuf.vim
@@ -2934,6 +2934,7 @@ func Test_tfirst()
\ "Xtags", 'D')
call writefile(["one", "two", "three"], "Xfile", 'D')
call writefile(["one"], "Xother", 'D')
+ tag one
edit Xother
set winfixbuf
diff --git a/src/version.c b/src/version.c
index 936a05c086..0de9c555dd 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 554,
+/**/
553,
/**/
552,