From 64753b5c37cf9d0d3aa2ced068d749cdab43e250 Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 27 Jun 2025 17:52:28 +0800 Subject: [PATCH] fix(highlight): spurious underline in 'winblend' floating window #34614 Problem: When a floating window with high winblend uses a highlight group with underline (but without guisp), the underline appears red. Solution: Only blend the special color (for underline/undercurl) if the foreground highlight actually has underline or undercurl set. Otherwise, ignore the special color. --- src/nvim/highlight.c | 15 ++++----- test/functional/ui/float_spec.lua | 54 +++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 71e4236b9e..6c427dda33 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -726,11 +726,10 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through) if (*through) { cattrs = battrs; - cattrs.rgb_fg_color = rgb_blend(ratio, battrs.rgb_fg_color, - fattrs.rgb_bg_color); - if (cattrs.rgb_ae_attr & (HL_UNDERLINE_MASK)) { - cattrs.rgb_sp_color = rgb_blend(ratio, battrs.rgb_sp_color, - fattrs.rgb_bg_color); + cattrs.rgb_fg_color = rgb_blend(ratio, battrs.rgb_fg_color, fattrs.rgb_bg_color); + // Only apply special colors when the foreground attribute has an underline or undercurl. + if (fattrs_raw.rgb_ae_attr & (HL_UNDERLINE | HL_UNDERCURL)) { + cattrs.rgb_sp_color = rgb_blend(ratio, battrs.rgb_sp_color, fattrs.rgb_bg_color); } else { cattrs.rgb_sp_color = -1; } @@ -744,11 +743,9 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through) if (ratio >= 50) { cattrs.rgb_ae_attr = hl_combine_ae(battrs.rgb_ae_attr, cattrs.rgb_ae_attr); } - cattrs.rgb_fg_color = rgb_blend(ratio/2, battrs.rgb_fg_color, - fattrs.rgb_fg_color); + cattrs.rgb_fg_color = rgb_blend(ratio/2, battrs.rgb_fg_color, fattrs.rgb_fg_color); if (cattrs.rgb_ae_attr & (HL_UNDERLINE_MASK)) { - cattrs.rgb_sp_color = rgb_blend(ratio/2, battrs.rgb_bg_color, - fattrs.rgb_sp_color); + cattrs.rgb_sp_color = rgb_blend(ratio/2, battrs.rgb_bg_color, fattrs.rgb_sp_color); } else { cattrs.rgb_sp_color = -1; } diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index dbd16a9d91..b533ea7346 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -8460,6 +8460,8 @@ describe('float window', function() [30] = { bold = true, foreground = tonumber('0x00007f') }, [31] = { foreground = Screen.colors.Red, blend = 80 }, [32] = { foreground = Screen.colors.Blue1, blend = 100, bold = true }, + [33] = { foreground = Screen.colors.Gray0, underline = true }, + [34] = { underline = true }, }) insert([[ Lorem ipsum dolor sit amet, consectetur @@ -8473,6 +8475,7 @@ describe('float window', function() occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]) + local curbufnr = api.nvim_get_current_buf() local buf = api.nvim_create_buf(false, false) local test_data = { 'test', '', 'popup text' } api.nvim_buf_set_lines(buf, 0, -1, true, test_data) @@ -8824,6 +8827,57 @@ describe('float window', function() | ]]) end + + -- winblend highlight with underline (but without guisp) in a floatwin. #14453 + command('fclose | hi TestUnderLine gui=underline') + api.nvim_buf_add_highlight(curbufnr, -1, 'TestUnderLine', 3, 0, -1) + api.nvim_buf_add_highlight(curbufnr, -1, 'TestUnderLine', 4, 0, -1) + api.nvim_buf_set_lines(buf, 0, -1, false, {}) + api.nvim_open_win(buf, false, { relative = 'win', row = 0, col = 0, width = 50, height = 1 }) + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------------------------]|*8 + [3:--------------------------------------------------]| + ## grid 2 + {34:Ut enim ad minim veniam, quis nostrud} | + {34:exercitation ullamco laboris nisi ut aliquip ex} | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + {16:^qui officia deserunt mollit anim id est }| + laborum. | + ## grid 3 + | + ## grid 5 + {17: }| + ]], + win_pos = { [2] = { height = 8, startcol = 0, startrow = 0, width = 50, win = 1000 } }, + float_pos = { [5] = { 1002, 'NW', 2, 0, 0, true, 50, 1, 0, 0 } }, + win_viewport = { + [2] = { win = 1000, topline = 3, botline = 11, curline = 9, curcol = 0, linecount = 11, sum_scroll_delta = 3 }, + [5] = { win = 1002, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0 }, + }, + win_viewport_margins = { + [2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 }, + [5] = { bottom = 0, left = 0, right = 0, top = 0, win = 1002 }, + }, + }) + else + screen:expect([[ + {33:Ut enim ad minim veniam, quis nostrud}{26: }| + {34:exercitation ullamco laboris nisi ut aliquip ex} | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + {16:^qui officia deserunt mollit anim id est }| + laborum. | + | + ]]) + end end) it('can overlap doublewidth chars', function()