vim-patch:8.2.1703: ":highlight clear" does not restore default link

Problem:    ":highlight clear" does not restore default link.
Solution:   Remember the default link and restore it. (Antony Scriven,
            closes vim/vim#6970, closes vim/vim#4405)
213da551de
This commit is contained in:
Andy K. Massimino 2021-03-04 00:58:07 -05:00
parent 4e6b31d978
commit 8601e8b0d6
3 changed files with 64 additions and 19 deletions

View File

@ -4689,6 +4689,7 @@ in their own color.
highlighting for groups added by the user! highlighting for groups added by the user!
Uses the current value of 'background' to decide which Uses the current value of 'background' to decide which
default colors to use. default colors to use.
If there was a default link, restore it. |:hi-link|
:hi[ghlight] clear {group-name} :hi[ghlight] clear {group-name}
:hi[ghlight] {group-name} NONE :hi[ghlight] {group-name} NONE

View File

@ -59,6 +59,7 @@ struct hl_group {
bool sg_cleared; ///< "hi clear" was used bool sg_cleared; ///< "hi clear" was used
int sg_attr; ///< Screen attr @see ATTR_ENTRY int sg_attr; ///< Screen attr @see ATTR_ENTRY
int sg_link; ///< link to this highlight group ID int sg_link; ///< link to this highlight group ID
int sg_deflink; ///< default link; restored in highlight_clear()
int sg_set; ///< combination of flags in \ref SG_SET int sg_set; ///< combination of flags in \ref SG_SET
sctx_T sg_script_ctx; ///< script in which the group was last set sctx_T sg_script_ctx; ///< script in which the group was last set
// for terminal UIs // for terminal UIs
@ -6601,6 +6602,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
const char *to_end; const char *to_end;
int from_id; int from_id;
int to_id; int to_id;
struct hl_group *hlgroup = NULL;
from_end = (const char *)skiptowhite((const char_u *)from_start); from_end = (const char *)skiptowhite((const char_u *)from_start);
to_start = (const char *)skipwhite((const char_u *)from_end); to_start = (const char *)skipwhite((const char_u *)from_end);
@ -6627,7 +6629,14 @@ void do_highlight(const char *line, const bool forceit, const bool init)
(int)(to_end - to_start)); (int)(to_end - to_start));
} }
if (from_id > 0 && (!init || HL_TABLE()[from_id - 1].sg_set == 0)) { if (from_id > 0) {
hlgroup = &HL_TABLE()[from_id - 1];
if (dodefault && (forceit || hlgroup->sg_deflink == 0)) {
hlgroup->sg_deflink = to_id;
}
}
if (from_id > 0 && (!init || hlgroup->sg_set == 0)) {
// Don't allow a link when there already is some highlighting // Don't allow a link when there already is some highlighting
// for the group, unless '!' is used // for the group, unless '!' is used
if (to_id > 0 && !forceit && !init if (to_id > 0 && !forceit && !init
@ -6635,17 +6644,16 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (sourcing_name == NULL && !dodefault) { if (sourcing_name == NULL && !dodefault) {
EMSG(_("E414: group has settings, highlight link ignored")); EMSG(_("E414: group has settings, highlight link ignored"));
} }
} else if (HL_TABLE()[from_id - 1].sg_link != to_id } else if (hlgroup->sg_link != to_id
|| HL_TABLE()[from_id - 1].sg_script_ctx.sc_sid || hlgroup->sg_script_ctx.sc_sid != current_sctx.sc_sid
!= current_sctx.sc_sid || hlgroup->sg_cleared) {
|| HL_TABLE()[from_id - 1].sg_cleared) {
if (!init) { if (!init) {
HL_TABLE()[from_id - 1].sg_set |= SG_LINK; hlgroup->sg_set |= SG_LINK;
} }
HL_TABLE()[from_id - 1].sg_link = to_id; hlgroup->sg_link = to_id;
HL_TABLE()[from_id - 1].sg_script_ctx = current_sctx; hlgroup->sg_script_ctx = current_sctx;
HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += sourcing_lnum; hlgroup->sg_script_ctx.sc_lnum += sourcing_lnum;
HL_TABLE()[from_id - 1].sg_cleared = false; hlgroup->sg_cleared = false;
redraw_all_later(SOME_VALID); redraw_all_later(SOME_VALID);
// Only call highlight changed() once after multiple changes // Only call highlight changed() once after multiple changes
@ -7106,6 +7114,8 @@ static void highlight_clear(int idx)
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name); XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name);
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name); XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name);
HL_TABLE()[idx].sg_blend = -1; HL_TABLE()[idx].sg_blend = -1;
// Restore any default link.
HL_TABLE()[idx].sg_link = HL_TABLE()[idx].sg_deflink;
// Clear the script ID only when there is no link, since that is not // Clear the script ID only when there is no link, since that is not
// cleared. // cleared.
if (HL_TABLE()[idx].sg_link == 0) { if (HL_TABLE()[idx].sg_link == 0) {

View File

@ -623,10 +623,47 @@ func Test_xxlast_highlight_RGB_color()
hi clear hi clear
endfunc endfunc
" Test default highlighting is restored func Test_highlight_clear_restores_links()
func Test_highlight_restore_defaults() let aaa_id = hlID('aaa')
hi! link TestLink Identifier call assert_equal(aaa_id, 0)
hi! TestHi ctermbg=red
" create default link aaa --> bbb
hi def link aaa bbb
let id_aaa = hlID('aaa')
let hl_aaa_bbb = HighlightArgs('aaa')
" try to redefine default link aaa --> ccc; check aaa --> bbb
hi def link aaa ccc
call assert_equal(HighlightArgs('aaa'), hl_aaa_bbb)
" clear aaa; check aaa --> bbb
hi clear aaa
call assert_equal(HighlightArgs('aaa'), hl_aaa_bbb)
" link aaa --> ccc; clear aaa; check aaa --> bbb
hi link aaa ccc
let id_ccc = hlID('ccc')
call assert_equal(synIDtrans(id_aaa), id_ccc)
hi clear aaa
call assert_equal(HighlightArgs('aaa'), hl_aaa_bbb)
" forcibly set default link aaa --> ddd
hi! def link aaa ddd
let id_ddd = hlID('ddd')
let hl_aaa_ddd = HighlightArgs('aaa')
call assert_equal(synIDtrans(id_aaa), id_ddd)
" link aaa --> eee; clear aaa; check aaa --> ddd
hi link aaa eee
let eee_id = hlID('eee')
call assert_equal(synIDtrans(id_aaa), eee_id)
hi clear aaa
call assert_equal(HighlightArgs('aaa'), hl_aaa_ddd)
endfunc
func Test_highlight_default_colorscheme_restores_links()
hi link TestLink Identifier
hi TestHi ctermbg=red
let hlTestLinkPre = HighlightArgs('TestLink') let hlTestLinkPre = HighlightArgs('TestLink')
let hlTestHiPre = HighlightArgs('TestHi') let hlTestHiPre = HighlightArgs('TestHi')
@ -637,19 +674,16 @@ func Test_highlight_restore_defaults()
syntax reset syntax reset
endif endif
let g:colors_name = 'test' let g:colors_name = 'test'
hi! link TestLink ErrorMsg hi link TestLink ErrorMsg
hi! TestHi ctermbg=green hi TestHi ctermbg=green
" Restore default highlighting " Restore default highlighting
colorscheme default colorscheme default
syntax on
" 'default' should work no matter if highlight group was cleared " 'default' should work no matter if highlight group was cleared
hi def link TestLink Identifier hi def link TestLink Identifier
hi def TestHi ctermbg=red hi def TestHi ctermbg=red
let hlTestLinkPost = HighlightArgs('TestLink') let hlTestLinkPost = HighlightArgs('TestLink')
let hlTestHiPost = HighlightArgs('TestHi') let hlTestHiPost = HighlightArgs('TestHi')
call assert_equal(hlTestLinkPre, hlTestLinkPost) call assert_equal(hlTestLinkPre, hlTestLinkPost)
call assert_equal(hlTestHiPre, hlTestHiPost) call assert_equal(hlTestHiPre, hlTestHiPost)
hi clear hi clear