From 52c251909572dc289006ef1741f99994c326bc0d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 7 Aug 2025 23:56:10 +0800 Subject: [PATCH] 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 --- runtime/doc/options.txt | 2 ++ runtime/lua/vim/_meta/options.lua | 2 ++ src/nvim/diff.c | 9 +++++++-- src/nvim/errors.h | 1 + src/nvim/options.lua | 2 ++ test/old/testdir/test_diffmode.vim | 4 ++++ 6 files changed, 18 insertions(+), 2 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 8d738620f5..348624629f 100644 --- 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 index daea333483..88a83c010e 100644 --- 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 index 2882d52723..3f5268205c 100644 --- 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 index c82520bd59..16d7ea930f 100644 --- 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 index ebaa5a69d0..b90abd01d9 100644 --- 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 index 6a4c923900..475a9e3f1d 100644 --- 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&