changeset 26145:3da380450cce v8.2.3605

patch 8.2.3605: cannot clear and unlinke a highlight group with hlset() Commit: https://github.com/vim/vim/commit/2a16dc6613368c54d526850bcbcd03c3fec1be67 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Tue Nov 16 17:19:30 2021 +0000 patch 8.2.3605: cannot clear and unlinke a highlight group with hlset() Problem: Cannot clear and unlinke a highlight group with hlset() in a single call. Solution: Add the "force" option. (Yegappan Lakshmanan, closes #9117)
author Bram Moolenaar <Bram@vim.org>
date Tue, 16 Nov 2021 18:30:04 +0100
parents 18cbc3a4d8b9
children 3786ff30fe40
files runtime/doc/eval.txt src/highlight.c src/testdir/test_highlight.vim src/testdir/test_vim9_builtin.vim src/testdir/test_vim9_cmd.vim
diffstat 5 files changed, 144 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -6750,7 +6750,7 @@ hlget([{name} [, {resolve}]])				*hlget(
 
 		Each entry in the returned List is a Dictionary with the
 		following items:
-			cleared	Boolean flag, set to v:true if the highlight
+			cleared	boolean flag, set to v:true if the highlight
 				group attributes are cleared or not yet
 				specified.  See |highlight-clear|.
 			cterm	cterm attributes. See |highlight-cterm|.
@@ -6759,6 +6759,9 @@ hlget([{name} [, {resolve}]])				*hlget(
 			ctermfg	cterm foreground color.
 				See |highlight-ctermfg|.
 			ctermul	cterm underline color.  See |highlight-ctermul|.
+			default boolean flag, set to v:true if the highlight
+				group link is a default link. See
+				|highlight-default|.
 			font	highlight group font.  See |highlight-font|.
 			gui	gui attributes. See |highlight-gui|.
 			guibg	gui background color.  See |highlight-guibg|.
@@ -6791,6 +6794,13 @@ hlset({list})						*hlset()*
 		attributes of a highlight group. See |hlget()| for the list of
 		supported items in this dictionary.
 
+		In addition to the items described in |hlget()|, the following
+		additional items are supported in the dictionary:
+
+			force		boolean flag to force the creation of
+					a link for an existing highlight group
+					with attributes.
+
 		The highlight group is identified using the 'name' item and
 		the 'id' item (if supplied) is ignored.  If a highlight group
 		with a specified name doesn't exist, then it is created.
@@ -6820,6 +6830,11 @@ hlset({list})						*hlset()*
 			:call hlset([#{name: 'Title', term: {}}])
 			" create the MyHlg group linking it to DiffAdd
 			:call hlset([#{name: 'MyHlg', linksto: 'DiffAdd'}])
+			" remove the MyHlg group link
+			:call hlset([#{name: 'MyHlg', linksto: 'NONE'}])
+			" clear the attributes and a link
+			:call hlset([#{name: 'MyHlg', cleared: v:true,
+					\ linksto: 'NONE'}])
 <
 		Can also be used as a |method|: >
 			GetAttrList()->hlset()
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -4176,6 +4176,9 @@ highlight_get_info(int hl_idx, int resol
 	link = HL_TABLE()[sgp->sg_link - 1].sg_name;
 	if (link != NULL && dict_add_string(dict, "linksto", link) == FAIL)
 	    goto error;
+
+	if (sgp->sg_deflink)
+	    dict_add_bool(dict, "default", VVAL_TRUE);
     }
     if (dict_len(dict) == 2)
 	// If only 'name' is present, then the highlight group is cleared.
@@ -4337,25 +4340,19 @@ hlg_add_or_update(dict_T *dict)
 # ifdef FEAT_GUI
     char_u	*font;
 # endif
+    int		forceit = FALSE;
+    int		dodefault = FALSE;
+    int		done = FALSE;
 
     name = hldict_get_string(dict, (char_u *)"name", &error);
     if (name == NULL || error)
 	return FALSE;
 
-    if (dict_find(dict, (char_u *)"linksto", -1) != NULL)
-    {
-	char_u	*linksto;
-
-	// link highlight groups
-	linksto = hldict_get_string(dict, (char_u *)"linksto", &error);
-	if (linksto == NULL || error)
-	    return FALSE;
-
-	vim_snprintf((char *)IObuff, IOSIZE, "link %s %s", name, linksto);
-	do_highlight(IObuff, FALSE, FALSE);
-
-	return TRUE;
-    }
+    if (dict_get_bool(dict, (char_u *)"force", VVAL_FALSE) == VVAL_TRUE)
+	forceit = TRUE;
+
+    if (dict_get_bool(dict, (char_u *)"default", VVAL_FALSE) == VVAL_TRUE)
+	dodefault = TRUE;
 
     if (dict_find(dict, (char_u *)"cleared", -1) != NULL)
     {
@@ -4366,11 +4363,31 @@ hlg_add_or_update(dict_T *dict)
 	if (cleared == TRUE)
 	{
 	    vim_snprintf((char *)IObuff, IOSIZE, "clear %s", name);
-	    do_highlight(IObuff, FALSE, FALSE);
+	    do_highlight(IObuff, forceit, FALSE);
+	    done = TRUE;
 	}
-
+    }
+
+    if (dict_find(dict, (char_u *)"linksto", -1) != NULL)
+    {
+	char_u	*linksto;
+
+	// link highlight groups
+	linksto = hldict_get_string(dict, (char_u *)"linksto", &error);
+	if (linksto == NULL || error)
+	    return FALSE;
+
+	vim_snprintf((char *)IObuff, IOSIZE, "%slink %s %s",
+				dodefault ? "default " : "", name, linksto);
+	do_highlight(IObuff, forceit, FALSE);
+
+	done = TRUE;
+    }
+
+    // If 'cleared' or 'linksto' are specified, then don't process the other
+    // attributes.
+    if (done)
 	return TRUE;
-    }
 
     start = hldict_get_string(dict, (char_u *)"start", &error);
     if (error)
@@ -4434,7 +4451,8 @@ hlg_add_or_update(dict_T *dict)
 	return TRUE;
 
     vim_snprintf((char *)IObuff, IOSIZE,
-	    "%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s",
+	    "%s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s",
+	    dodefault ? "default " : "",
 	    name,
 	    term_attr[0] != NUL ? "term=" : "",
 	    term_attr[0] != NUL ? term_attr : (char_u *)"",
@@ -4466,7 +4484,7 @@ hlg_add_or_update(dict_T *dict)
 	    guisp != NULL ? guisp : (char_u *)""
 		);
 
-    do_highlight(IObuff, FALSE, FALSE);
+    do_highlight(IObuff, forceit, FALSE);
 
     return TRUE;
 }
--- a/src/testdir/test_highlight.vim
+++ b/src/testdir/test_highlight.vim
@@ -1046,9 +1046,6 @@ endfunc
 
 " Test for the hlset() function
 func Test_hlset()
-  let save_columns = &columns
-  let &columns = 80
-
   let lines =<< trim END
     call assert_equal(0, hlset(test_null_list()))
     call assert_equal(0, hlset([]))
@@ -1126,12 +1123,10 @@ func Test_hlset()
                 \ 'standout': v:true, 'nocombine': v:true}
     call hlset([{'name': 'myhlg2', 'term': attr, 'cterm': attr, 'gui': attr}])
     VAR id2 = hlID('myhlg2')
-    VAR output =<< trim END
-      myhlg2         xxx term=bold,standout,underline,undercurl,italic,reverse,nocombine,strikethrough
-                         cterm=bold,standout,underline,undercurl,italic,reverse,nocombine,strikethrough
-                         gui=bold,standout,underline,undercurl,italic,reverse,nocombine,strikethrough
-    END
-    call assert_equal(output, execute('highlight myhlg2')->split("\n"))
+    VAR expected = "myhlg2 xxx term=bold,standout,underline,undercurl,italic,reverse,nocombine,strikethrough cterm=bold,standout,underline,undercurl,italic,reverse,nocombine,strikethrough gui=bold,standout,underline,undercurl,italic,reverse,nocombine,strikethrough"
+    VAR output = execute('highlight myhlg2')
+    LET output = output->split("\n")->join()->substitute('\s\+', ' ', 'g')
+    call assert_equal(expected, output)
     call assert_equal([{'id': id2, 'name': 'myhlg2', 'gui': attr,
                       \ 'term': attr, 'cterm': attr}], hlget('myhlg2'))
   END
@@ -1143,18 +1138,96 @@ func Test_hlset()
     VAR attr = {'bold': v:false, 'underline': v:true, 'strikethrough': v:true}
     call hlset([{'name': 'myhlg2', 'term': attr, 'cterm': attr, 'gui': attr}])
     VAR id2 = hlID('myhlg2')
-    VAR output =<< trim END
-      myhlg2         xxx term=underline,strikethrough cterm=underline,strikethrough
-                         gui=underline,strikethrough
-    END
-    call assert_equal(output, execute('highlight myhlg2')->split("\n"))
+    VAR expected = "myhlg2 xxx term=underline,strikethrough cterm=underline,strikethrough gui=underline,strikethrough"
+    VAR output = execute('highlight myhlg2')
+    LET output = output->split("\n")->join()->substitute('\s\+', ' ', 'g')
+    call assert_equal(expected, output)
     LET attr = {'underline': v:true, 'strikethrough': v:true}
     call assert_equal([{'id': id2, 'name': 'myhlg2', 'gui': attr,
                       \ 'term': attr, 'cterm': attr}], hlget('myhlg2'))
   END
   call CheckLegacyAndVim9Success(lines)
 
-  let &columns = save_columns
+  " Test for clearing the attributes and link of a highlight group
+  let lines =<< trim END
+    highlight myhlg3 ctermbg=green guibg=green
+    highlight! default link myhlg3 ErrorMsg
+    VAR id3 = hlID('myhlg3')
+    call hlset([{'name': 'myhlg3', 'cleared': v:true, 'linksto': 'NONE'}])
+    call assert_equal([{'id': id3, 'name': 'myhlg3', 'cleared': v:true}],
+                      \ hlget('myhlg3'))
+    highlight clear hlg3
+  END
+  call CheckLegacyAndVim9Success(lines)
+
+  " Test for setting default attributes for a highlight group
+  let lines =<< trim END
+    call hlset([{'name': 'hlg4', 'ctermfg': '8'}])
+    call hlset([{'name': 'hlg4', 'default': v:true, 'ctermfg': '9'}])
+    VAR id4 = hlID('hlg4')
+    call assert_equal([{'id': id4, 'name': 'hlg4', 'ctermfg': '8'}],
+                    \ hlget('hlg4'))
+    highlight clear hlg4
+
+    call hlset([{'name': 'hlg5', 'default': v:true, 'ctermbg': '2'}])
+    call hlset([{'name': 'hlg5', 'ctermbg': '4'}])
+    VAR id5 = hlID('hlg5')
+    call assert_equal([{'id': id5, 'name': 'hlg5', 'ctermbg': '4'}],
+                    \ hlget('hlg5'))
+    highlight clear hlg5
+
+    call hlset([{'name': 'hlg6', 'linksto': 'Error'}])
+    VAR id6 = hlID('hlg6')
+    call hlset([{'name': 'hlg6', 'default': v:true, 'ctermbg': '2'}])
+    call assert_equal([{'id': id6, 'name': 'hlg6', 'linksto': 'Error'}],
+                    \ hlget('hlg6'))
+    highlight clear hlg6
+  END
+  call CheckLegacyAndVim9Success(lines)
+
+  " Test for setting default links for a highlight group
+  let lines =<< trim END
+    call hlset([{'name': 'hlg7', 'ctermfg': '5'}])
+    call hlset([{'name': 'hlg7', 'default': v:true, 'linksto': 'Search'}])
+    VAR id7 = hlID('hlg7')
+    call assert_equal([{'id': id7, 'name': 'hlg7', 'ctermfg': '5'}],
+                    \ hlget('hlg7'))
+    highlight clear hlg7
+
+    call hlset([{'name': 'hlg8', 'default': v:true, 'linksto': 'Search'}])
+    VAR id8 = hlID('hlg8')
+    call assert_equal([{'id': id8, 'name': 'hlg8', 'default': v:true,
+                    \ 'linksto': 'Search'}], hlget('hlg8'))
+    call hlset([{'name': 'hlg8', 'ctermbg': '2'}])
+    call assert_equal([{'id': id8, 'name': 'hlg8', 'ctermbg': '2'}],
+                    \ hlget('hlg8'))
+    highlight clear hlg8
+
+    highlight default link hlg9 ErrorMsg
+    VAR hlg_save = hlget('hlg9')
+    LET hlg_save[0]['name'] = 'hlg9dup'
+    call hlset(hlg_save)
+    VAR id9 = hlID('hlg9dup')
+    highlight clear hlg9dup
+    call assert_equal([{'id': id9, 'name': 'hlg9dup', 'default': v:true,
+                    \ 'linksto': 'ErrorMsg'}], hlget('hlg9dup'))
+    highlight clear hlg9
+  END
+  call CheckLegacyAndVim9Success(lines)
+
+  " Test for force creating a link to a highlight group
+  let lines =<< trim END
+    call hlset([{'name': 'hlg10', 'ctermfg': '8'}])
+    call hlset([{'name': 'hlg10', 'linksto': 'Search'}])
+    VAR id10 = hlID('hlg10')
+    call assert_equal([{'id': id10, 'name': 'hlg10', 'ctermfg': '8'}],
+                    \ hlget('hlg10'))
+    call hlset([{'name': 'hlg10', 'linksto': 'Search', 'force': v:true}])
+    call assert_equal([{'id': id10, 'name': 'hlg10', 'ctermfg': '8',
+                    \ 'linksto': 'Search'}], hlget('hlg10'))
+    highlight clear hlg10
+  END
+  call CheckLegacyAndVim9Success(lines)
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -3297,6 +3297,7 @@ def Test_sign_placelist()
   CheckDefAndScriptFailure2(['sign_placelist("x")'], 'E1013: Argument 1: type mismatch, expected list<any> but got string', 'E1211: List required for argument 1')
   CheckDefAndScriptFailure2(['sign_placelist({"a": 10})'], 'E1013: Argument 1: type mismatch, expected list<any> but got dict<number>', 'E1211: List required for argument 1')
   CheckDefExecAndScriptFailure(['sign_placelist([{"name": "MySign", "buffer": bufnr(), "lnum": ""}])'], 'E1209: Invalid value for a line number: ""')
+  assert_fails('sign_placelist([{name: "MySign", buffer: "", lnum: 1}])', 'E155:')
 enddef
 
 def Test_sign_undefine()
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -1570,8 +1570,8 @@ def Test_no_space_after_command()
   CheckDefExecAndScriptFailure(lines, 'E486:', 1)
 enddef
 
-" Test for the 'popuppreview' option
-def Test_popuppreview()
+" Test for the 'previewpopup' option
+def Test_previewpopup()
   set previewpopup=height:10,width:60
   pedit Xfile
   var id = popup_findpreview()