commit f8d59cfab9585a538760e404789029be743b61dc
parent 8ab511bba524bcd5b5913d1b1205b5e4fe3f7210
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sun, 15 Feb 2026 08:03:44 +0800
fix(highlight): setting 'winhl' doesn't work with global ns (#37868)
Problem: Setting 'winhighlight' doesn't after setting global namespace
using nvim_win_set_hl_ns().
Solution: Check if using another namespace when setting 'winhighlight'
instead of disabling 'winhighlight' in nvim_win_set_hl_ns().
Diffstat:
4 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
@@ -454,7 +454,6 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err)
}
win->w_ns_hl = (NS)ns_id;
- win->w_ns_hl_winhl = -1;
win->w_hl_needs_update = true;
redraw_later(win, UPD_NOT_VALID);
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
@@ -1100,7 +1100,7 @@ struct window_S {
synblock_T *w_s; ///< for :ownsyntax
int w_ns_hl;
- int w_ns_hl_winhl; ///< when set to -1, 'winhighlight' shouldn't be used
+ int w_ns_hl_winhl;
int w_ns_hl_active;
int *w_ns_hl_attr;
diff --git a/src/nvim/option.c b/src/nvim/option.c
@@ -1730,12 +1730,6 @@ bool parse_winhl_opt(const char *winhl, win_T *wp)
p = wp->w_p_winhl;
}
- if (wp != NULL && wp->w_ns_hl_winhl < 0) {
- // 'winhighlight' shouldn't be used for this window.
- // Only check that the value is valid.
- wp = NULL;
- }
-
if (!*p) {
if (wp != NULL && wp->w_ns_hl_winhl > 0 && wp->w_ns_hl == wp->w_ns_hl_winhl) {
wp->w_ns_hl = 0;
@@ -1754,8 +1748,10 @@ bool parse_winhl_opt(const char *winhl, win_T *wp)
DecorProvider *dp = get_decor_provider(wp->w_ns_hl_winhl, true);
dp->hl_valid++;
}
- wp->w_ns_hl = wp->w_ns_hl_winhl;
- ns_hl = wp->w_ns_hl;
+ ns_hl = wp->w_ns_hl_winhl;
+ if (wp->w_ns_hl <= 0) {
+ wp->w_ns_hl = wp->w_ns_hl_winhl;
+ }
}
while (*p) {
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local clear, eq = n.clear, t.eq
+local clear, eq, neq = n.clear, t.eq, t.neq
local command = n.command
local exec_capture = n.exec_capture
local api = n.api
@@ -548,6 +548,8 @@ describe('API: get highlight', function()
end)
describe('API: set/get highlight namespace', function()
+ before_each(clear)
+
it('set/get highlight namespace', function()
eq(0, api.nvim_get_hl_ns({}))
local ns = api.nvim_create_namespace('')
@@ -563,16 +565,38 @@ describe('API: set/get highlight namespace', function()
end)
it('setting namespace takes priority over &winhighlight', function()
+ local win = api.nvim_get_current_win()
+ eq(-1, api.nvim_get_hl_ns({ winid = win }))
command('set winhighlight=Visual:Search')
+ local winhl_ns = api.nvim_get_hl_ns({ winid = win })
+ neq(0, winhl_ns)
+ eq('Search', api.nvim_get_hl(winhl_ns, { name = 'Visual' }).link)
n.insert('foobar')
local ns = api.nvim_create_namespace('')
- api.nvim_win_set_hl_ns(0, ns)
- eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
- command('enew') -- switching buffer keeps namespace #30904
- eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
+ neq(winhl_ns, ns)
+ api.nvim_win_set_hl_ns(win, ns)
+ eq(ns, api.nvim_get_hl_ns({ winid = win }))
+ command('enew') -- Switching buffer keeps namespace. #30904
+ eq(ns, api.nvim_get_hl_ns({ winid = win }))
command('set winhighlight=')
- eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
- command('set winhighlight=Visual:Search')
- eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
+ eq(ns, api.nvim_get_hl_ns({ winid = win }))
+ -- Setting 'winhighlight' changes its namespace even when not using it.
+ command('set winhighlight=Visual:IncSearch')
+ eq('IncSearch', api.nvim_get_hl(winhl_ns, { name = 'Visual' }).link)
+ eq(ns, api.nvim_get_hl_ns({ winid = win }))
+ -- Setting 'winhighlight' works with global namespace. #37865
+ api.nvim_win_set_hl_ns(win, 0)
+ eq(0, api.nvim_get_hl_ns({ winid = win }))
+ command('set winhighlight=Visual:IncSearch')
+ eq('IncSearch', api.nvim_get_hl(winhl_ns, { name = 'Visual' }).link)
+ eq(winhl_ns, api.nvim_get_hl_ns({ winid = win }))
+ command('set winhighlight=')
+ eq(0, api.nvim_get_hl_ns({ winid = win }))
+ -- 'winhighlight' keeps the same namespace.
+ api.nvim_win_set_hl_ns(win, winhl_ns)
+ eq(winhl_ns, api.nvim_get_hl_ns({ winid = win }))
+ command('set winhighlight=Visual:Substitute')
+ eq('Substitute', api.nvim_get_hl(winhl_ns, { name = 'Visual' }).link)
+ eq(winhl_ns, api.nvim_get_hl_ns({ winid = win }))
end)
end)