commit 52c251909572dc289006ef1741f99994c326bc0d
parent d994be44d77ac7527cf69995cb29d6fe0f158321
Author: zeertzjq <zeertzjq@outlook.com>
Date: Thu, 7 Aug 2025 23:56:10 +0800
vim-patch:9.1.1600: using diff anchors with hidden buffers fails silently (#35218)
Problem: diff: using diff anchors with hidden buffers fails silently
Solution: Give specific error message for diff anchors when using hidden
buffers (Yee Cheng Chin).
Diff anchors currently will fail to parse if a buffer used for diff'ing
is hidden. Previously it would just fail as the code assumes it would
not happen normally, but this is actually possible to do if `closeoff`
and `hideoff` are not set in diffopt. Git's default diff tool "vimdiff3"
also takes advantage of this.
This fix this properly would require the `{address}` parser to be
smarter about whether a particular address relies on window position or
not (e.g. the `'.` address requires an active window, but `'a` or `1234`
do not). Since hidden diff buffers seem relatively niche, just provide a
better error message / documentation for now. This could be improved
later if there's a demand for it.
related: vim/vim#17615
closes: vim/vim#17904
https://github.com/vim/vim/commit/cad3b2421de7b703e0ee619850a8a3bc55454281
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
Diffstat:
6 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
@@ -2135,6 +2135,8 @@ A jump table for the options with a short description can be found at |Q_op|.
If some of the {address} do not resolve to a line in each buffer (e.g.
a pattern search that does not match anything), none of the anchors
will be used.
+ *E1562*
+ Diff anchors can only be used when there are no hidden diff buffers.
*'diffexpr'* *'dex'*
'diffexpr' 'dex' string (default "")
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
@@ -1736,6 +1736,8 @@ vim.wo.diff = vim.o.diff
--- If some of the {address} do not resolve to a line in each buffer (e.g.
--- a pattern search that does not match anything), none of the anchors
--- will be used.
+--- *E1562*
+--- Diff anchors can only be used when there are no hidden diff buffers.
---
--- @type string
vim.o.diffanchors = ""
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
@@ -2553,8 +2553,13 @@ static int parse_diffanchors(bool check_only, buf_T *buf, linenr_T *anchors, int
break;
}
}
- if (bufwin == NULL) {
- return FAIL; // should not really happen
+ if (bufwin == NULL && *dia != NUL) {
+ // The buffer is hidden. Currently this is not supported due to the
+ // edge cases of needing to decide if an address is window-specific
+ // or not. We could add more checks in the future so we can detect
+ // whether an address relies on curwin to make this more fleixble.
+ emsg(_(e_diff_anchors_with_hidden_windows));
+ return FAIL;
}
}
diff --git a/src/nvim/errors.h b/src/nvim/errors.h
@@ -191,6 +191,7 @@ EXTERN const char e_invalid_return_type_from_findfunc[] INIT( = N_("E1514: 'find
EXTERN const char e_cannot_switch_to_a_closing_buffer[] INIT( = N_("E1546: Cannot switch to a closing buffer"));
EXTERN const char e_cannot_have_more_than_nr_diff_anchors[] INIT( = N_("E1549: Cannot have more than %d diff anchors"));
EXTERN const char e_failed_to_find_all_diff_anchors[] INIT( = N_("E1550: Failed to find all diff anchors"));
+EXTERN const char e_diff_anchors_with_hidden_windows[] INIT( = N_("E1562: Diff anchors cannot be used with hidden diff windows"));
EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
@@ -2286,6 +2286,8 @@ local options = {
If some of the {address} do not resolve to a line in each buffer (e.g.
a pattern search that does not match anything), none of the anchors
will be used.
+ *E1562*
+ Diff anchors can only be used when there are no hidden diff buffers.
]=],
full_name = 'diffanchors',
list = 'onecomma',
diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim
@@ -3231,6 +3231,10 @@ func Test_diffanchors_invalid()
call assert_fails('diffupdate', 'E1550:')
call assert_equal('orig_search_pat', @/)
+ " Hidden buffers are not supported right now
+ hide
+ call assert_fails('diffupdate', 'E1562:')
+
%bw!
set diffopt&
set diffanchors&