aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/syntax.c57
-rw-r--r--src/nvim/testdir/script_util.vim69
-rw-r--r--src/nvim/testdir/test_highlight.vim100
-rw-r--r--src/nvim/testdir/test_options.vim2
4 files changed, 204 insertions, 24 deletions
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 547d953be9..d204968c0f 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -59,7 +59,9 @@ struct hl_group {
bool sg_cleared; ///< "hi clear" was used
int sg_attr; ///< Screen attr @see ATTR_ENTRY
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
+ sctx_T sg_deflink_sctx; ///< script where the default link was set
sctx_T sg_script_ctx; ///< script in which the group was last set
// for terminal UIs
int sg_cterm; ///< "cterm=" highlighting attr
@@ -6601,6 +6603,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
const char *to_end;
int from_id;
int to_id;
+ struct hl_group *hlgroup = NULL;
from_end = (const char *)skiptowhite((const char_u *)from_start);
to_start = (const char *)skipwhite((const char_u *)from_end);
@@ -6627,7 +6630,16 @@ void do_highlight(const char *line, const bool forceit, const bool init)
(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;
+ hlgroup->sg_deflink_sctx = current_sctx;
+ hlgroup->sg_deflink_sctx.sc_lnum += sourcing_lnum;
+ }
+ }
+
+ if (from_id > 0 && (!init || hlgroup->sg_set == 0)) {
// Don't allow a link when there already is some highlighting
// for the group, unless '!' is used
if (to_id > 0 && !forceit && !init
@@ -6635,17 +6647,16 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (sourcing_name == NULL && !dodefault) {
EMSG(_("E414: group has settings, highlight link ignored"));
}
- } else if (HL_TABLE()[from_id - 1].sg_link != to_id
- || HL_TABLE()[from_id - 1].sg_script_ctx.sc_sid
- != current_sctx.sc_sid
- || HL_TABLE()[from_id - 1].sg_cleared) {
+ } else if (hlgroup->sg_link != to_id
+ || hlgroup->sg_script_ctx.sc_sid != current_sctx.sc_sid
+ || hlgroup->sg_cleared) {
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;
- HL_TABLE()[from_id - 1].sg_script_ctx = current_sctx;
- HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += sourcing_lnum;
- HL_TABLE()[from_id - 1].sg_cleared = false;
+ hlgroup->sg_link = to_id;
+ hlgroup->sg_script_ctx = current_sctx;
+ hlgroup->sg_script_ctx.sc_lnum += sourcing_lnum;
+ hlgroup->sg_cleared = false;
redraw_all_later(SOME_VALID);
// Only call highlight changed() once after multiple changes
@@ -7076,13 +7087,14 @@ void restore_cterm_colors(void)
*/
static int hl_has_settings(int idx, int check_link)
{
- return HL_TABLE()[idx].sg_attr != 0
- || HL_TABLE()[idx].sg_cterm_fg != 0
- || HL_TABLE()[idx].sg_cterm_bg != 0
- || HL_TABLE()[idx].sg_rgb_fg_name != NULL
- || HL_TABLE()[idx].sg_rgb_bg_name != NULL
- || HL_TABLE()[idx].sg_rgb_sp_name != NULL
- || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK));
+ return HL_TABLE()[idx].sg_cleared == 0
+ && (HL_TABLE()[idx].sg_attr != 0
+ || HL_TABLE()[idx].sg_cterm_fg != 0
+ || HL_TABLE()[idx].sg_cterm_bg != 0
+ || HL_TABLE()[idx].sg_rgb_fg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_bg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_sp_name != NULL
+ || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)));
}
/*
@@ -7105,12 +7117,11 @@ static void highlight_clear(int idx)
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name);
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name);
HL_TABLE()[idx].sg_blend = -1;
- // Clear the script ID only when there is no link, since that is not
- // cleared.
- if (HL_TABLE()[idx].sg_link == 0) {
- HL_TABLE()[idx].sg_script_ctx.sc_sid = 0;
- HL_TABLE()[idx].sg_script_ctx.sc_lnum = 0;
- }
+ // Restore default link and context if they exist. Otherwise clears.
+ HL_TABLE()[idx].sg_link = HL_TABLE()[idx].sg_deflink;
+ // Since we set the default link, set the location to where the default
+ // link was set.
+ HL_TABLE()[idx].sg_script_ctx = HL_TABLE()[idx].sg_deflink_sctx;
}
diff --git a/src/nvim/testdir/script_util.vim b/src/nvim/testdir/script_util.vim
new file mode 100644
index 0000000000..9913b1dfaf
--- /dev/null
+++ b/src/nvim/testdir/script_util.vim
@@ -0,0 +1,69 @@
+" Functions shared by the tests for Vim Script
+
+" Commands to track the execution path of a script
+com! XpathINIT let g:Xpath = ''
+com! -nargs=1 -bar Xpath let g:Xpath ..= <args>
+com! XloopINIT let g:Xloop = 1
+com! -nargs=1 -bar Xloop let g:Xpath ..= <args> .. g:Xloop
+com! XloopNEXT let g:Xloop += 1
+
+" MakeScript() - Make a script file from a function. {{{2
+"
+" Create a script that consists of the body of the function a:funcname.
+" Replace any ":return" by a ":finish", any argument variable by a global
+" variable, and every ":call" by a ":source" for the next following argument
+" in the variable argument list. This function is useful if similar tests are
+" to be made for a ":return" from a function call or a ":finish" in a script
+" file.
+func MakeScript(funcname, ...)
+ let script = tempname()
+ execute "redir! >" . script
+ execute "function" a:funcname
+ redir END
+ execute "edit" script
+ " Delete the "function" and the "endfunction" lines. Do not include the
+ " word "function" in the pattern since it might be translated if LANG is
+ " set. When MakeScript() is being debugged, this deletes also the debugging
+ " output of its line 3 and 4.
+ exec '1,/.*' . a:funcname . '(.*)/d'
+ /^\d*\s*endfunction\>/,$d
+ %s/^\d*//e
+ %s/return/finish/e
+ %s/\<a:\(\h\w*\)/g:\1/ge
+ normal gg0
+ let cnt = 0
+ while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
+ let cnt = cnt + 1
+ s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
+ endwhile
+ g/^\s*$/d
+ write
+ bwipeout
+ return script
+endfunc
+
+" ExecAsScript - Source a temporary script made from a function. {{{2
+"
+" Make a temporary script file from the function a:funcname, ":source" it, and
+" delete it afterwards. However, if an exception is thrown the file may remain,
+" the caller should call DeleteTheScript() afterwards.
+let s:script_name = ''
+function! ExecAsScript(funcname)
+ " Make a script from the function passed as argument.
+ let s:script_name = MakeScript(a:funcname)
+
+ " Source and delete the script.
+ exec "source" s:script_name
+ call delete(s:script_name)
+ let s:script_name = ''
+endfunction
+
+function! DeleteTheScript()
+ if s:script_name
+ call delete(s:script_name)
+ let s:script_name = ''
+ endif
+endfunc
+
+com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
+
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 4cc4d775d1..ce22de09ca 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -3,6 +3,7 @@
source view_util.vim
source screendump.vim
source check.vim
+source script_util.vim
func Test_highlight()
" basic test if ":highlight" doesn't crash
@@ -623,4 +624,103 @@ func Test_xxlast_highlight_RGB_color()
hi clear
endfunc
+func Test_highlight_clear_restores_links()
+ let aaa_id = hlID('aaa')
+ call assert_equal(aaa_id, 0)
+
+ " 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_clear_restores_context()
+ func FuncContextDefault()
+ hi def link Context ContextDefault
+ endfun
+
+ func FuncContextRelink()
+ " Dummy line
+ hi link Context ContextRelink
+ endfunc
+
+ let scriptContextDefault = MakeScript("FuncContextDefault")
+ let scriptContextRelink = MakeScript("FuncContextRelink")
+ let patContextDefault = fnamemodify(scriptContextDefault, ':t') .. ' line 1'
+ let patContextRelink = fnamemodify(scriptContextRelink, ':t') .. ' line 2'
+
+ exec "source" scriptContextDefault
+ let hlContextDefault = execute("verbose hi Context")
+ call assert_match(patContextDefault, hlContextDefault)
+
+ exec "source" scriptContextRelink
+ let hlContextRelink = execute("verbose hi Context")
+ call assert_match(patContextRelink, hlContextRelink)
+
+ hi clear
+ let hlContextAfterClear = execute("verbose hi Context")
+ call assert_match(patContextDefault, hlContextAfterClear)
+
+ delfunc FuncContextDefault
+ delfunc FuncContextRelink
+ call delete(scriptContextDefault)
+ call delete(scriptContextRelink)
+endfunc
+
+func Test_highlight_default_colorscheme_restores_links()
+ hi link TestLink Identifier
+ hi TestHi ctermbg=red
+
+ let hlTestLinkPre = HighlightArgs('TestLink')
+ let hlTestHiPre = HighlightArgs('TestHi')
+
+ " Test colorscheme
+ hi clear
+ if exists('syntax_on')
+ syntax reset
+ endif
+ let g:colors_name = 'test'
+ hi link TestLink ErrorMsg
+ hi TestHi ctermbg=green
+
+ " Restore default highlighting
+ colorscheme default
+ " 'default' should work no matter if highlight group was cleared
+ hi def link TestLink Identifier
+ hi def TestHi ctermbg=red
+ let hlTestLinkPost = HighlightArgs('TestLink')
+ let hlTestHiPost = HighlightArgs('TestHi')
+ call assert_equal(hlTestLinkPre, hlTestLinkPost)
+ call assert_equal(hlTestHiPre, hlTestHiPost)
+ hi clear
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 79481097ec..07e2481f95 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -225,7 +225,7 @@ func Test_set_completion()
" Expand files and directories.
call feedkeys(":set tags=./\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('./samples/ ./sautest/ ./screendump.vim ./setup.vim ./shared.vim', @:)
+ call assert_match('./samples/ ./sautest/ ./screendump.vim ./script_util.vim ./setup.vim ./shared.vim', @:)
call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)