changeset 35622:814fcbca4d8d v9.1.0554

patch 9.1.0554: :bw leaves jumplist and tagstack data around Commit: https://github.com/vim/vim/commit/4ff3a9b1e3ba45f9dbd0ea8c721f27d9315c4d93 Author: LemonBoy <thatlemon@gmail.com> Date: Tue Jul 9 20:03:24 2024 +0200 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>
author Christian Brabandt <cb@256bit.org>
date Tue, 09 Jul 2024 20:15:03 +0200
parents aece1f56c24a
children c037664384d0
files runtime/doc/version9.txt runtime/doc/windows.txt src/buffer.c src/mark.c src/proto/mark.pro src/proto/tag.pro src/tag.c src/testdir/test_jumplist.vim src/testdir/test_tagjump.vim src/testdir/test_winfixbuf.vim src/version.c
diffstat 11 files changed, 72 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- 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 ~
--- 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
--- 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
--- 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.
  */
--- 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 : */
--- a/src/proto/tag.pro
+++ b/src/proto/tag.pro
@@ -14,4 +14,5 @@ int expand_tags(int tagnames, char_u *pa
 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 : */
--- a/src/tag.c
+++ b/src/tag.c
@@ -144,7 +144,6 @@ static void print_tag_list(int new_tag, 
 #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);
--- 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
--- 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
--- 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
--- 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,