fix(api): nvim_set_hl boolean false corrupts underline styles (#38504)

Problem: setting one underline style to false clears bits belonging
to another style. `{underdouble = true, underdashed = false}` results
in undercurl because CHECK_FLAG_WITH_KEY does `m &= ~flag` which
doesn't work for multi-bit encoded values sharing HL_UNDERLINE_MASK.

Solution: use a local variable to derive the correct clear mask from
the flag. Clear the whole HL_UNDERLINE_MASK field instead of individual
bits, and only clear on false when the current style actually matches.
This commit is contained in:
glepnir
2026-03-28 15:26:46 +08:00
committed by GitHub
parent f027f41e2c
commit 9383a096eb
2 changed files with 38 additions and 6 deletions

View File

@@ -1039,13 +1039,12 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, HlAttrs
#define CHECK_FLAG_WITH_KEY(d, m, name, extra, flag) \
if (HAS_KEY_X(d, name)) { \
int32_t flag_ = (flag); \
int32_t cmask_ = (flag_ & HL_UNDERLINE_MASK) ? HL_UNDERLINE_MASK : flag_; \
if (d->name##extra) { \
if (flag & HL_UNDERLINE_MASK) { \
m &= ~HL_UNDERLINE_MASK; \
} \
m |= flag; \
} else { \
m &= ~flag; \
m = (m & ~cmask_) | flag_; \
} else if ((m & cmask_) == flag_) { \
m &= ~cmask_; \
} \
}

View File

@@ -290,6 +290,39 @@ describe('API: set highlight', function()
hl = api.nvim_get_hl(0, { name = 'LinkedGroup' })
eq(nil, hl.link)
eq(true, hl.bold)
-- underline style flags: false must not corrupt other styles
local unders = { 'underline', 'undercurl', 'underdouble', 'underdotted', 'underdashed' }
for _, a in ipairs(unders) do
for _, b in ipairs(unders) do
if a ~= b then
api.nvim_set_hl(0, 'TestGroup', { [a] = true, [b] = false })
hl = api.nvim_get_hl(0, { name = 'TestGroup' })
eq(true, hl[a])
eq(nil, hl[b])
end
end
end
api.nvim_set_hl(0, 'TestGroup', { underdouble = true, fg = '#ff0000', bold = true })
api.nvim_set_hl(0, 'TestGroup', { fg = '#00ff00', update = true })
hl = api.nvim_get_hl(0, { name = 'TestGroup' })
eq(true, hl.underdouble)
eq(true, hl.bold)
eq(65280, hl.fg)
api.nvim_set_hl(0, 'TestGroup', { underdashed = true, update = true })
hl = api.nvim_get_hl(0, { name = 'TestGroup' })
eq(true, hl.underdashed)
eq(nil, hl.underdouble)
api.nvim_set_hl(0, 'TestGroup', { underdouble = true, bold = true })
api.nvim_set_hl(0, 'TestGroup', { underdashed = false, update = true })
hl = api.nvim_get_hl(0, { name = 'TestGroup' })
eq(true, hl.underdouble)
api.nvim_set_hl(0, 'TestGroup', { underdouble = false, update = true })
hl = api.nvim_get_hl(0, { name = 'TestGroup' })
eq(nil, hl.underdouble)
eq(true, hl.bold)
end)
end)