changeset 26690:84d60deb8f82 v8.2.3874

patch 8.2.3874: cannot highlight the number column for a sign Commit: https://github.com/vim/vim/commit/a80aad717464760a5a50ac2201ce35b24a0cf7a5 Author: James McCoy <jamessan@jamessan.com> Date: Wed Dec 22 19:45:28 2021 +0000 patch 8.2.3874: cannot highlight the number column for a sign Problem: Cannot highlight the number column for a sign. Solution: Add the "numhl" argument. (James McCoy, closes https://github.com/vim/vim/issues/9381)
author Bram Moolenaar <Bram@vim.org>
date Wed, 22 Dec 2021 21:00:05 +0100
parents c5a5e166dba8
children 87c4291e1f0d
files runtime/doc/options.txt runtime/doc/sign.txt src/drawline.c src/popupwin.c src/proto/sign.pro src/sign.c src/structs.h src/testdir/test_signs.vim src/version.c
diffstat 9 files changed, 94 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5601,8 +5601,8 @@ A jump table for the options with a shor
 	number.
 	When a long, wrapped line doesn't start with the first character, '-'
 	characters are put before the number.
-	See |hl-LineNr|  and |hl-CursorLineNr| for the highlighting used for
-	the number.
+	For highlighting see |hl-LineNr|, and |hl-CursorLineNr|, and the
+	|:sign-define| "numhl" argument.
 						*number_relativenumber*
 	The 'relativenumber' option changes the displayed number to be
 	relative to the cursor.  Together with 'number' there are these
--- a/runtime/doc/sign.txt
+++ b/runtime/doc/sign.txt
@@ -140,6 +140,11 @@ See |sign_define()| for the equivalent V
 		Highlighting group used for the whole line the sign is placed
 		in.  Most useful is defining a background color.
 
+	numhl={group}
+		Highlighting group used for the line number on the line where
+		the sign is placed.  Overrides |hl-LineNr|, |hl-LineNrAbove|,
+		|hl-LineNrBelow|, and |hl-CursorLineNr|.
+
 	text={text}						*E239*
 		Define the text that is displayed when there is no icon or the
 		GUI is not being used.  Only printable characters are allowed
@@ -396,6 +401,8 @@ sign_define({list})
 		   icon		full path to the bitmap file for the sign.
 		   linehl	highlight group used for the whole line the
 				sign is placed in.
+		   numhl	highlight group used for the line number where
+				the sign is placed.
 		   text		text that is displayed when there is no icon
 				or the GUI is not being used.
 		   texthl	highlight group used for the text item
@@ -443,6 +450,8 @@ sign_getdefined([{name}])				*sign_getde
 		   linehl	highlight group used for the whole line the
 				sign is placed in; not present if not set
 		   name		name of the sign
+		   numhl	highlight group used for the line number where
+				the sign is placed; not present if not set
 		   text		text that is displayed when there is no icon
 				or the GUI is not being used.
 		   texthl	highlight group used for the text item; not
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -377,6 +377,7 @@ win_line(
 #ifdef FEAT_SIGNS
     int		sign_present = FALSE;
     sign_attrs_T sattr;
+    int		num_attr = 0;		// attribute for the number column
 #endif
 #ifdef FEAT_ARABIC
     int		prev_c = 0;		// previous Arabic character
@@ -699,6 +700,8 @@ win_line(
 
 #ifdef FEAT_SIGNS
     sign_present = buf_get_signattrs(wp, lnum, &sattr);
+    if (sign_present)
+	num_attr = sattr.sat_numhl;
 #endif
 
 #ifdef LINE_ATTR
@@ -1206,6 +1209,10 @@ win_line(
 			  char_attr = hl_combine_attr(wcr_attr,
 							     HL_ATTR(HLF_LNB));
 		    }
+#ifdef FEAT_SIGNS
+		    if (num_attr)
+			char_attr = num_attr;
+#endif
 		}
 	    }
 
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -632,7 +632,7 @@ popup_highlight_curline(win_T *wp)
 
 	    if (syn_name2id((char_u *)linehl) == 0)
 		linehl = "PmenuSel";
-	    sign_define_by_name(sign_name, NULL, (char_u *)linehl, NULL, NULL, NULL);
+	    sign_define_by_name(sign_name, NULL, (char_u *)linehl, NULL, NULL, NULL, NULL);
 	}
 
 	sign_place(&sign_id, (char_u *)"PopUpMenu", sign_name,
--- a/src/proto/sign.pro
+++ b/src/proto/sign.pro
@@ -8,7 +8,7 @@ int buf_findsigntype_id(buf_T *buf, line
 int buf_signcount(buf_T *buf, linenr_T lnum);
 void buf_delete_signs(buf_T *buf, char_u *group);
 void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after);
-int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl, char_u *culhl);
+int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl, char_u *culhl, char_u *numhl);
 int sign_exists_by_name(char_u *name);
 int sign_undefine_by_name(char_u *name, int give_error);
 int sign_place(int *sign_id, char_u *sign_group, char_u *sign_name, buf_T *buf, linenr_T lnum, int prio);
--- a/src/sign.c
+++ b/src/sign.c
@@ -33,6 +33,7 @@ struct sign
     int		sn_line_hl;	// highlight ID for line
     int		sn_text_hl;	// highlight ID for text
     int		sn_cul_hl;	// highlight ID for text on current line when 'cursorline' is set
+    int		sn_num_hl;	// highlight ID for line number
 };
 
 static sign_T	*first_sign = NULL;
@@ -520,6 +521,8 @@ buf_get_signattrs(win_T *wp, linenr_T ln
 		sattr->sat_linehl = syn_id2attr(sp->sn_line_hl);
 	    if (sp->sn_cul_hl > 0)
 		sattr->sat_culhl = syn_id2attr(sp->sn_cul_hl);
+	    if (sp->sn_num_hl > 0)
+		sattr->sat_numhl = syn_id2attr(sp->sn_num_hl);
 	    sattr->sat_priority = sign->se_priority;
 
 	    // If there is another sign next with the same priority, may
@@ -545,6 +548,8 @@ buf_get_signattrs(win_T *wp, linenr_T ln
 			sattr->sat_linehl = syn_id2attr(next_sp->sn_line_hl);
 		    if (sp->sn_cul_hl <= 0 && next_sp->sn_cul_hl > 0)
 			sattr->sat_culhl = syn_id2attr(next_sp->sn_cul_hl);
+		    if (sp->sn_num_hl <= 0 && next_sp->sn_num_hl > 0)
+			sattr->sat_numhl = syn_id2attr(next_sp->sn_num_hl);
 		}
 	    }
 	    return TRUE;
@@ -1041,7 +1046,8 @@ sign_define_by_name(
 	char_u	*linehl,
 	char_u	*text,
 	char_u	*texthl,
-	char_u	*culhl)
+	char_u	*culhl,
+	char_u	*numhl)
 {
     sign_T	*sp_prev;
     sign_T	*sp;
@@ -1101,6 +1107,14 @@ sign_define_by_name(
 	    sp->sn_cul_hl = syn_check_group(culhl, (int)STRLEN(culhl));
     }
 
+    if (numhl != NULL)
+    {
+	if (*numhl == NUL)
+	    sp->sn_num_hl = 0;
+	else
+	    sp->sn_num_hl = syn_check_group(numhl, (int)STRLEN(numhl));
+    }
+
     return OK;
 }
 
@@ -1323,6 +1337,7 @@ sign_define_cmd(char_u *sign_name, char_
     char_u	*linehl = NULL;
     char_u	*texthl = NULL;
     char_u	*culhl = NULL;
+    char_u	*numhl = NULL;
     int		failed = FALSE;
 
     // set values for a defined sign.
@@ -1357,6 +1372,11 @@ sign_define_cmd(char_u *sign_name, char_
 	    arg += 6;
 	    culhl = vim_strnsave(arg, p - arg);
 	}
+	else if (STRNCMP(arg, "numhl=", 6) == 0)
+	{
+	    arg += 6;
+	    numhl = vim_strnsave(arg, p - arg);
+	}
 	else
 	{
 	    semsg(_(e_invarg2), arg);
@@ -1366,13 +1386,14 @@ sign_define_cmd(char_u *sign_name, char_
     }
 
     if (!failed)
-	sign_define_by_name(sign_name, icon, linehl, text, texthl, culhl);
+	sign_define_by_name(sign_name, icon, linehl, text, texthl, culhl, numhl);
 
     vim_free(icon);
     vim_free(text);
     vim_free(linehl);
     vim_free(texthl);
     vim_free(culhl);
+    vim_free(numhl);
 }
 
 /*
@@ -1750,6 +1771,13 @@ sign_getinfo(sign_T *sp, dict_T *retdict
 	    p = (char_u *)"NONE";
 	dict_add_string(retdict, "culhl", (char_u *)p);
     }
+    if (sp->sn_num_hl > 0)
+    {
+	p = get_highlight_name_ext(NULL, sp->sn_num_hl - 1, FALSE);
+	if (p == NULL)
+	    p = (char_u *)"NONE";
+	dict_add_string(retdict, "numhl", (char_u *)p);
+    }
 }
 
 /*
@@ -1930,6 +1958,15 @@ sign_list_defined(sign_T *sp)
 	else
 	    msg_puts((char *)p);
     }
+    if (sp->sn_num_hl > 0)
+    {
+	msg_puts(" numhl=");
+	p = get_highlight_name_ext(NULL, sp->sn_num_hl - 1, FALSE);
+	if (p == NULL)
+	    msg_puts("NONE");
+	else
+	    msg_puts((char *)p);
+    }
 }
 
 /*
@@ -2051,7 +2088,7 @@ get_sign_name(expand_T *xp UNUSED, int i
 	{
 	    char *define_arg[] =
 	    {
-		"icon=", "linehl=", "text=", "texthl=", NULL
+		"culhl=", "icon=", "linehl=", "numhl=", "text=", "texthl=", NULL
 	    };
 	    return (char_u *)define_arg[idx];
 	}
@@ -2176,7 +2213,9 @@ set_context_in_sign_cmd(expand_T *xp, ch
 	{
 	    case SIGNCMD_DEFINE:
 		if (STRNCMP(last, "texthl", 6) == 0
-			|| STRNCMP(last, "linehl", 6) == 0)
+			|| STRNCMP(last, "linehl", 6) == 0
+			|| STRNCMP(last, "culhl", 5) == 0
+			|| STRNCMP(last, "numhl", 5) == 0)
 		    xp->xp_context = EXPAND_HIGHLIGHT;
 		else if (STRNCMP(last, "icon", 4) == 0)
 		    xp->xp_context = EXPAND_FILES;
@@ -2221,6 +2260,7 @@ sign_define_from_dict(char_u *name_arg, 
     char_u	*text = NULL;
     char_u	*texthl = NULL;
     char_u	*culhl = NULL;
+    char_u	*numhl = NULL;
     int		retval = -1;
 
     if (name_arg == NULL)
@@ -2240,9 +2280,10 @@ sign_define_from_dict(char_u *name_arg, 
 	text = dict_get_string(dict, (char_u *)"text", TRUE);
 	texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
 	culhl = dict_get_string(dict, (char_u *)"culhl", TRUE);
+	numhl = dict_get_string(dict, (char_u *)"numhl", TRUE);
     }
 
-    if (sign_define_by_name(name, icon, linehl, text, texthl, culhl) == OK)
+    if (sign_define_by_name(name, icon, linehl, text, texthl, culhl, numhl) == OK)
 	retval = 0;
 
 cleanup:
@@ -2252,6 +2293,7 @@ cleanup:
     vim_free(text);
     vim_free(texthl);
     vim_free(culhl);
+    vim_free(numhl);
 
     return retval;
 }
--- a/src/structs.h
+++ b/src/structs.h
@@ -854,6 +854,7 @@ typedef struct sign_attrs_S {
     int		sat_texthl;
     int		sat_linehl;
     int		sat_culhl;
+    int		sat_numhl;
     int		sat_priority;
 } sign_attrs_T;
 
--- a/src/testdir/test_signs.vim
+++ b/src/testdir/test_signs.vim
@@ -15,13 +15,13 @@ func Test_sign()
   " the icon name when listing signs.
   sign define Sign1 text=x
 
-  call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error culhl=Search icon=../../pixmaps/stock_vim_find_help.png')
+  call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error culhl=Search numhl=Number icon=../../pixmaps/stock_vim_find_help.png')
 
   " Test listing signs.
   let a=execute('sign list')
   call assert_match('^\nsign Sign1 text=x \nsign Sign2 ' .
 	      \ 'icon=../../pixmaps/stock_vim_find_help.png .*text=xy ' .
-	      \ 'linehl=Error texthl=Title culhl=Search$', a)
+	      \ 'linehl=Error texthl=Title culhl=Search numhl=Number$', a)
 
   let a=execute('sign list Sign1')
   call assert_equal("\nsign Sign1 text=x ", a)
@@ -127,26 +127,34 @@ func Test_sign()
   call assert_fails("sign define Sign4 text=\\ ab  linehl=Comment", 'E239:')
 
   " an empty highlight argument for an existing sign clears it
-  sign define SignY texthl=TextHl culhl=CulHl linehl=LineHl
+  sign define SignY texthl=TextHl culhl=CulHl linehl=LineHl numhl=NumHl
   let sl = sign_getdefined('SignY')[0]
   call assert_equal('TextHl', sl.texthl)
   call assert_equal('CulHl', sl.culhl)
   call assert_equal('LineHl', sl.linehl)
+  call assert_equal('NumHl', sl.numhl)
 
-  sign define SignY texthl= culhl=CulHl linehl=LineHl
+  sign define SignY texthl= culhl=CulHl linehl=LineHl numhl=NumHl
   let sl = sign_getdefined('SignY')[0]
   call assert_false(has_key(sl, 'texthl'))
   call assert_equal('CulHl', sl.culhl)
   call assert_equal('LineHl', sl.linehl)
+  call assert_equal('NumHl', sl.numhl)
 
   sign define SignY linehl=
   let sl = sign_getdefined('SignY')[0]
   call assert_false(has_key(sl, 'linehl'))
   call assert_equal('CulHl', sl.culhl)
+  call assert_equal('NumHl', sl.numhl)
 
   sign define SignY culhl=
   let sl = sign_getdefined('SignY')[0]
   call assert_false(has_key(sl, 'culhl'))
+  call assert_equal('NumHl', sl.numhl)
+
+  sign define SignY numhl=
+  let sl = sign_getdefined('SignY')[0]
+  call assert_false(has_key(sl, 'numhl'))
 
   sign undefine SignY
 
@@ -218,15 +226,13 @@ func Test_sign_completion()
   call assert_equal('"sign define jump list place undefine unplace', @:)
 
   call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
-  call assert_equal('"sign define Sign icon= linehl= text= texthl=', @:)
+  call assert_equal('"sign define Sign culhl= icon= linehl= numhl= text= texthl=', @:)
 
-  call feedkeys(":sign define Sign linehl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
-  call assert_equal('"sign define Sign linehl=SpellBad SpellCap ' .
-	      \ 'SpellLocal SpellRare', @:)
-
-  call feedkeys(":sign define Sign texthl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
-  call assert_equal('"sign define Sign texthl=SpellBad SpellCap ' .
-	      \ 'SpellLocal SpellRare', @:)
+  for hl in ['culhl', 'linehl', 'numhl', 'texthl']
+    call feedkeys(":sign define Sign "..hl.."=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
+    call assert_equal('"sign define Sign '..hl..'=SpellBad SpellCap ' .
+                \ 'SpellLocal SpellRare', @:)
+  endfor
 
   call writefile(repeat(["Sun is shining"], 30), "XsignOne")
   call writefile(repeat(["Sky is blue"], 30), "XsignTwo")
@@ -417,20 +423,21 @@ func Test_sign_funcs()
 
   " Tests for sign_define()
   let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error',
-              \ 'culhl': 'Visual'}
+              \ 'culhl': 'Visual', 'numhl': 'Number'}
   call assert_equal(0, "sign1"->sign_define(attr))
-  call assert_equal([{'name' : 'sign1', 'texthl' : 'Error',
-	      \ 'linehl' : 'Search', 'culhl' : 'Visual', 'text' : '=>'}],
+  call assert_equal([{'name' : 'sign1', 'texthl' : 'Error', 'linehl' : 'Search',
+              \ 'culhl' : 'Visual', 'numhl': 'Number', 'text' : '=>'}],
               \ sign_getdefined())
 
   " Define a new sign without attributes and then update it
   call sign_define("sign2")
   let attr = {'text' : '!!', 'linehl' : 'DiffAdd', 'texthl' : 'DiffChange',
-	      \ 'culhl': 'DiffDelete', 'icon' : 'sign2.ico'}
+	      \ 'culhl': 'DiffDelete', 'numhl': 'Number', 'icon' : 'sign2.ico'}
   call Sign_define_ignore_error("sign2", attr)
   call assert_equal([{'name' : 'sign2', 'texthl' : 'DiffChange',
 	      \ 'linehl' : 'DiffAdd', 'culhl' : 'DiffDelete', 'text' : '!!',
-              \ 'icon' : 'sign2.ico'}], "sign2"->sign_getdefined())
+              \ 'numhl': 'Number', 'icon' : 'sign2.ico'}],
+              \ "sign2"->sign_getdefined())
 
   " Test for a sign name with digits
   call assert_equal(0, sign_define(0002, {'linehl' : 'StatusLine'}))
--- a/src/version.c
+++ b/src/version.c
@@ -750,6 +750,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3874,
+/**/
     3873,
 /**/
     3872,