# HG changeset patch # User Christian Brabandt # Date 1720548903 -7200 # Node ID 814fcbca4d8d52840c1e46774dae6a6dab74f418 # Parent aece1f56c24ad06adae56f33b14794d59d4fada8 patch 9.1.0554: :bw leaves jumplist and tagstack data around Commit: https://github.com/vim/vim/commit/4ff3a9b1e3ba45f9dbd0ea8c721f27d9315c4d93 Author: LemonBoy 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 Signed-off-by: Christian Brabandt diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 : */ diff --git a/src/tag.c b/src/tag.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); diff --git a/src/testdir/test_jumplist.vim b/src/testdir/test_jumplist.vim --- 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! \" - 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 --- 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 --- 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 --- 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,