aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/windows.txt9
-rw-r--r--src/nvim/buffer.c37
-rw-r--r--src/nvim/mark.c51
-rw-r--r--src/nvim/tag.c2
-rw-r--r--src/nvim/tag.h1
-rw-r--r--test/old/testdir/test_jumplist.vim22
-rw-r--r--test/old/testdir/test_tagjump.vim17
-rw-r--r--test/old/testdir/test_winfixbuf.vim1
8 files changed, 90 insertions, 50 deletions
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 4791e73929..840d8b51af 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -1175,11 +1175,12 @@ 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
- :%bwipeout " wipe out all buffers
+ :.+,$bwipeout " wipe out all buffers after the current
+ " one
+ :%bwipeout " wipe out all buffers
<
:[N]bun[load][!] *:bun* *:bunload* *E515*
:bun[load][!] [N]
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 3812ff6b44..6878b02a6e 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -699,6 +699,9 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
if (buf->b_nwindows > 0) {
return false;
}
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ mark_forget_file(wp, buf->b_fnum);
+ }
if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
} else {
@@ -1184,32 +1187,6 @@ static int empty_curbuf(bool close_others, int forceit, int action)
return retval;
}
-/// Remove every jump list entry referring to a given buffer.
-/// This function will also adjust the current jump list index.
-void buf_remove_from_jumplist(buf_T *deleted_buf)
-{
- // Remove all jump list entries that match the deleted buffer.
- for (int i = curwin->w_jumplistlen - 1; i >= 0; i--) {
- buf_T *buf = buflist_findnr(curwin->w_jumplist[i].fmark.fnum);
-
- if (buf == deleted_buf) {
- // Found an entry that we want to delete.
- curwin->w_jumplistlen -= 1;
-
- // If the current jump list index behind the entry we want to
- // delete, move it back by one.
- if (curwin->w_jumplistidx > i && curwin->w_jumplistidx > 0) {
- curwin->w_jumplistidx -= 1;
- }
-
- // Actually remove the entry from the jump list.
- for (int d = i; d < curwin->w_jumplistlen; d++) {
- curwin->w_jumplist[d] = curwin->w_jumplist[d + 1];
- }
- }
- }
-}
-
/// Implementation of the commands for the buffer list.
///
/// action == DOBUF_GOTO go to specified buffer
@@ -1364,6 +1341,8 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
}
}
+ int buf_fnum = buf->b_fnum;
+
// When closing the current buffer stop Visual mode.
if (buf == curbuf && VIsual_active) {
end_visual_mode();
@@ -1398,7 +1377,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
if (buf != curbuf) {
if (jop_flags & JOP_UNLOAD) {
// Remove the buffer to be deleted from the jump list.
- buf_remove_from_jumplist(buf);
+ mark_jumplist_forget_file(curwin, buf_fnum);
}
close_windows(buf, false);
@@ -1423,8 +1402,8 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
buf = au_new_curbuf.br_buf;
} else if (curwin->w_jumplistlen > 0) {
if (jop_flags & JOP_UNLOAD) {
- // Remove the current buffer from the jump list.
- buf_remove_from_jumplist(curbuf);
+ // Remove the buffer from the jump list.
+ mark_jumplist_forget_file(curwin, buf_fnum);
}
// It's possible that we removed all jump list entries, in that case we need to try another
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 16f444a316..fae28ef6e1 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -43,6 +43,7 @@
#include "nvim/pos_defs.h"
#include "nvim/quickfix.h"
#include "nvim/strings.h"
+#include "nvim/tag.h"
#include "nvim/textobject.h"
#include "nvim/types_defs.h"
#include "nvim/vim_defs.h"
@@ -165,6 +166,56 @@ int setmark_pos(int c, pos_T *pos, int fnum, fmarkv_T *view_pt)
return FAIL;
}
+/// Remove every jump list entry referring to a given buffer.
+/// This function will also adjust the current jump list index.
+void mark_jumplist_forget_file(win_T *wp, int fnum)
+{
+ // Remove all jump list entries that match the deleted buffer.
+ for (int i = wp->w_jumplistlen - 1; i >= 0; i--) {
+ if (wp->w_jumplist[i].fmark.fnum == fnum) {
+ // Found an entry that we want to delete.
+ free_xfmark(wp->w_jumplist[i]);
+
+ // If the current jump list index is behind the entry we want to delete,
+ // move it back by one.
+ if (wp->w_jumplistidx > i) {
+ wp->w_jumplistidx--;
+ }
+
+ // Actually remove the entry from the jump list.
+ wp->w_jumplistlen--;
+ memmove(&wp->w_jumplist[i], &wp->w_jumplist[i + 1],
+ (size_t)(wp->w_jumplistlen - i) * sizeof(wp->w_jumplist[i]));
+ }
+ }
+}
+
+/// Delete every entry referring to file "fnum" from both the jumplist and the
+/// tag stack.
+void mark_forget_file(win_T *wp, int fnum)
+{
+ mark_jumplist_forget_file(wp, fnum);
+
+ // Remove all tag stack entries that match the deleted buffer.
+ for (int i = wp->w_tagstacklen - 1; i >= 0; i--) {
+ if (wp->w_tagstack[i].fmark.fnum == fnum) {
+ // Found an entry that we want to delete.
+ tagstack_clear_entry(&wp->w_tagstack[i]);
+
+ // If the current tag stack index is behind the entry we want to delete,
+ // move it back by one.
+ if (wp->w_tagstackidx > i) {
+ wp->w_tagstackidx--;
+ }
+
+ // Actually remove the entry from the tag stack.
+ wp->w_tagstacklen--;
+ memmove(&wp->w_tagstack[i], &wp->w_tagstack[i + 1],
+ (size_t)(wp->w_tagstacklen - i) * sizeof(wp->w_tagstack[i]));
+ }
+ }
+}
+
// Set the previous context mark to the current position and add it to the
// jump list.
void setpcmark(void)
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 8f6342bfcc..90269c776e 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -3184,7 +3184,7 @@ static int find_extra(char **pp)
//
// Free a single entry in a tag stack
//
-static void tagstack_clear_entry(taggy_T *item)
+void tagstack_clear_entry(taggy_T *item)
{
XFREE_CLEAR(item->tagname);
XFREE_CLEAR(item->user_data);
diff --git a/src/nvim/tag.h b/src/nvim/tag.h
index 42196b44b7..1c6f41050d 100644
--- a/src/nvim/tag.h
+++ b/src/nvim/tag.h
@@ -1,5 +1,6 @@
#pragma once
+#include "nvim/buffer_defs.h" // IWYU pragma: keep
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
#include "nvim/option_defs.h" // IWYU pragma: keep
diff --git a/test/old/testdir/test_jumplist.vim b/test/old/testdir/test_jumplist.vim
index b4dcdad9d6..5cf4f32628 100644
--- a/test/old/testdir/test_jumplist.vim
+++ b/test/old/testdir/test_jumplist.vim
@@ -68,26 +68,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/test/old/testdir/test_tagjump.vim b/test/old/testdir/test_tagjump.vim
index a614c19ce2..b715aedde6 100644
--- a/test/old/testdir/test_tagjump.vim
+++ b/test/old/testdir/test_tagjump.vim
@@ -1001,6 +1001,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/test/old/testdir/test_winfixbuf.vim b/test/old/testdir/test_winfixbuf.vim
index b41eaf3c9b..1777bec184 100644
--- a/test/old/testdir/test_winfixbuf.vim
+++ b/test/old/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