vim-patch:9.1.0538: not possible to assign priority when defining a sign (#29592)

Problem:  not possible to assign priority when defining a sign
          (Mathias Fußenegger)
Solution: Add the priority argument for the :sign-define ex command and
          the sign_define() function (LemonBoy)

Use the specified value instead of the default one (SIGN_DEF_PRIO) when
no priority is explicitly specified in sign_place or :sign place.

fixes: vim/vim#8334
closes: vim/vim#15124

b975ddfdf9

Co-authored-by: LemonBoy <thatlemon@gmail.com>
This commit is contained in:
zeertzjq 2024-07-07 07:21:14 +08:00 committed by GitHub
parent 472b5b9b20
commit 6a886a2511
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 96 additions and 26 deletions

View File

@ -7110,6 +7110,7 @@ sign_getdefined([{name}]) *sign_getdefined()*
linehl highlight group used for the whole line the linehl highlight group used for the whole line the
sign is placed in; not present if not set. sign is placed in; not present if not set.
name name of the sign name name of the sign
priority default priority value of the sign
numhl highlight group used for the line number where numhl highlight group used for the line number where
the sign is placed; not present if not set. the sign is placed; not present if not set.
text text that is displayed when there is no icon text text that is displayed when there is no icon
@ -7282,7 +7283,8 @@ sign_placelist({list}) *sign_placelist()*
priority Priority of the sign. When multiple signs are priority Priority of the sign. When multiple signs are
placed on a line, the sign with the highest placed on a line, the sign with the highest
priority is used. If not specified, the priority is used. If not specified, the
default value of 10 is used. See default value of 10 is used, unless specified
otherwise by the sign definition. See
|sign-priority| for more information. |sign-priority| for more information.
If {id} refers to an existing sign, then the existing sign is If {id} refers to an existing sign, then the existing sign is

View File

@ -68,11 +68,12 @@ other plugins using signs.
*sign-priority* *sign-priority*
Each placed sign is assigned a priority value independently of the sign group. Each placed sign is assigned a priority value independently of the sign group.
The default priority for a sign is 10. When multiple signs that each have an The default priority for a sign is 10, this value can be changed for different
icon or text are placed on the same line, signs are ordered with decreasing signs by specifying a different value at definition time. When multiple signs
priority from left to right, up until the maximum width set in 'signcolumn'. that each have an icon or text are placed on the same line, signs are ordered
Lower priority signs that do not fit are hidden. Highest priority signs with with decreasing priority from left to right, up until the maximum width set in
highlight attributes are always shown. 'signcolumn'. Low priority signs that do not fit are hidden. Highest priority
signs with highlight attributes are always shown.
When the line on which the sign is placed is deleted, the sign is removed along When the line on which the sign is placed is deleted, the sign is removed along
with it. with it.
@ -113,6 +114,9 @@ See |sign_define()| for the equivalent Vim script function.
toolkit supports ~ toolkit supports ~
Win32 .bmp, .ico, .cur Win32 .bmp, .ico, .cur
priority={prio}
Default priority for the sign, see |sign-priority|.
linehl={group} linehl={group}
Highlighting group used for the whole line the sign is placed Highlighting group used for the whole line the sign is placed
in. Most useful is defining a background color. in. Most useful is defining a background color.
@ -183,11 +187,11 @@ See |sign_place()| for the equivalent Vim script function.
By default, the sign is placed in the global sign group. By default, the sign is placed in the global sign group.
By default, the sign is assigned a default priority of 10. To By default, the sign is assigned a default priority of 10,
assign a different priority value, use "priority={prio}" to unless specified otherwise by the sign definition. To assign a
specify a value. The priority is used to determine the sign different priority value, use "priority={prio}" to specify a
that is displayed when multiple signs are placed on the same value. The priority is used to determine the sign that is
line. displayed when multiple signs are placed on the same line.
Examples: > Examples: >
:sign place 5 line=3 name=sign1 file=a.py :sign place 5 line=3 name=sign1 file=a.py

View File

@ -8477,6 +8477,7 @@ function vim.fn.sign_define(list) end
--- linehl highlight group used for the whole line the --- linehl highlight group used for the whole line the
--- sign is placed in; not present if not set. --- sign is placed in; not present if not set.
--- name name of the sign --- name name of the sign
--- priority default priority value of the sign
--- numhl highlight group used for the line number where --- numhl highlight group used for the line number where
--- the sign is placed; not present if not set. --- the sign is placed; not present if not set.
--- text text that is displayed when there is no icon --- text text that is displayed when there is no icon
@ -8668,7 +8669,8 @@ function vim.fn.sign_place(id, group, name, buf, dict) end
--- priority Priority of the sign. When multiple signs are --- priority Priority of the sign. When multiple signs are
--- placed on a line, the sign with the highest --- placed on a line, the sign with the highest
--- priority is used. If not specified, the --- priority is used. If not specified, the
--- default value of 10 is used. See --- default value of 10 is used, unless specified
--- otherwise by the sign definition. See
--- |sign-priority| for more information. --- |sign-priority| for more information.
--- ---
--- If {id} refers to an existing sign, then the existing sign is --- If {id} refers to an existing sign, then the existing sign is

View File

@ -10112,6 +10112,7 @@ M.funcs = {
linehl highlight group used for the whole line the linehl highlight group used for the whole line the
sign is placed in; not present if not set. sign is placed in; not present if not set.
name name of the sign name name of the sign
priority default priority value of the sign
numhl highlight group used for the line number where numhl highlight group used for the line number where
the sign is placed; not present if not set. the sign is placed; not present if not set.
text text that is displayed when there is no icon text text that is displayed when there is no icon
@ -10322,7 +10323,8 @@ M.funcs = {
priority Priority of the sign. When multiple signs are priority Priority of the sign. When multiple signs are
placed on a line, the sign with the highest placed on a line, the sign with the highest
priority is used. If not specified, the priority is used. If not specified, the
default value of 10 is used. See default value of 10 is used, unless specified
otherwise by the sign definition. See
|sign-priority| for more information. |sign-priority| for more information.
If {id} refers to an existing sign, then the existing sign is If {id} refers to an existing sign, then the existing sign is

View File

@ -401,7 +401,7 @@ int init_sign_text(sign_T *sp, schar_T *sign_text, char *text)
/// Define a new sign or update an existing sign /// Define a new sign or update an existing sign
static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, char *texthl, static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, char *texthl,
char *culhl, char *numhl) char *culhl, char *numhl, int prio)
{ {
cstr_t *key; cstr_t *key;
sign_T **sp = (sign_T **)pmap_put_ref(cstr_t)(&sign_map, name, &key, NULL); sign_T **sp = (sign_T **)pmap_put_ref(cstr_t)(&sign_map, name, &key, NULL);
@ -431,6 +431,8 @@ static int sign_define_by_name(char *name, char *icon, char *text, char *linehl,
return FAIL; return FAIL;
} }
(*sp)->sn_priority = prio;
char *arg[] = { linehl, texthl, culhl, numhl }; char *arg[] = { linehl, texthl, culhl, numhl };
int *hl[] = { &(*sp)->sn_line_hl, &(*sp)->sn_text_hl, &(*sp)->sn_cul_hl, &(*sp)->sn_num_hl }; int *hl[] = { &(*sp)->sn_line_hl, &(*sp)->sn_text_hl, &(*sp)->sn_cul_hl, &(*sp)->sn_num_hl };
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -472,6 +474,11 @@ static void sign_list_defined(sign_T *sp)
describe_sign_text(buf, sp->sn_text); describe_sign_text(buf, sp->sn_text);
msg_outtrans(buf, 0); msg_outtrans(buf, 0);
} }
if (sp->sn_priority > 0) {
char lbuf[MSG_BUF_LEN];
vim_snprintf(lbuf, MSG_BUF_LEN, " priority=%d", sp->sn_priority);
msg_puts(lbuf);
}
static char *arg[] = { " linehl=", " texthl=", " culhl=", " numhl=" }; static char *arg[] = { " linehl=", " texthl=", " culhl=", " numhl=" };
int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl };
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -508,6 +515,11 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_
return FAIL; return FAIL;
} }
// Use the default priority value for this sign.
if (prio == -1) {
prio = (sp->sn_priority != -1) ? sp->sn_priority : SIGN_DEF_PRIO;
}
if (lnum > 0) { if (lnum > 0) {
// ":sign place {id} line={lnum} name={name} file={fname}": place a sign // ":sign place {id} line={lnum} name={name} file={fname}": place a sign
buf_set_sign(buf, id, group, prio, lnum, sp); buf_set_sign(buf, id, group, prio, lnum, sp);
@ -602,6 +614,7 @@ static void sign_define_cmd(char *name, char *cmdline)
char *texthl = NULL; char *texthl = NULL;
char *culhl = NULL; char *culhl = NULL;
char *numhl = NULL; char *numhl = NULL;
int prio = -1;
// set values for a defined sign. // set values for a defined sign.
while (true) { while (true) {
@ -622,6 +635,8 @@ static void sign_define_cmd(char *name, char *cmdline)
culhl = arg + 6; culhl = arg + 6;
} else if (strncmp(arg, "numhl=", 6) == 0) { } else if (strncmp(arg, "numhl=", 6) == 0) {
numhl = arg + 6; numhl = arg + 6;
} else if (strncmp(arg, "priority=", 9) == 0) {
prio = atoi(arg + 9);
} else { } else {
semsg(_(e_invarg2), arg); semsg(_(e_invarg2), arg);
return; return;
@ -632,7 +647,7 @@ static void sign_define_cmd(char *name, char *cmdline)
*cmdline++ = NUL; *cmdline++ = NUL;
} }
sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl); sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl, prio);
} }
/// ":sign place" command /// ":sign place" command
@ -847,7 +862,7 @@ void ex_sign(exarg_T *eap)
linenr_T lnum = -1; linenr_T lnum = -1;
char *name = NULL; char *name = NULL;
char *group = NULL; char *group = NULL;
int prio = SIGN_DEF_PRIO; int prio = -1;
buf_T *buf = NULL; buf_T *buf = NULL;
// Parse command line arguments // Parse command line arguments
@ -880,6 +895,9 @@ static dict_T *sign_get_info_dict(sign_T *sp)
describe_sign_text(buf, sp->sn_text); describe_sign_text(buf, sp->sn_text);
tv_dict_add_str(d, S_LEN("text"), buf); tv_dict_add_str(d, S_LEN("text"), buf);
} }
if (sp->sn_priority > 0) {
tv_dict_add_nr(d, S_LEN("priority"), sp->sn_priority);
}
static char *arg[] = { "linehl", "texthl", "culhl", "numhl" }; static char *arg[] = { "linehl", "texthl", "culhl", "numhl" };
int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl };
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -1044,7 +1062,8 @@ char *get_sign_name(expand_T *xp, int idx)
case EXP_SUBCMD: case EXP_SUBCMD:
return cmds[idx]; return cmds[idx];
case EXP_DEFINE: { case EXP_DEFINE: {
char *define_arg[] = { "culhl=", "icon=", "linehl=", "numhl=", "text=", "texthl=", NULL }; char *define_arg[] = { "culhl=", "icon=", "linehl=", "numhl=", "text=", "texthl=",
"priority=", NULL };
return define_arg[idx]; return define_arg[idx];
} }
case EXP_PLACE: { case EXP_PLACE: {
@ -1200,6 +1219,7 @@ static int sign_define_from_dict(char *name, dict_T *dict)
char *texthl = NULL; char *texthl = NULL;
char *culhl = NULL; char *culhl = NULL;
char *numhl = NULL; char *numhl = NULL;
int prio = -1;
if (dict != NULL) { if (dict != NULL) {
icon = tv_dict_get_string(dict, "icon", false); icon = tv_dict_get_string(dict, "icon", false);
@ -1208,9 +1228,10 @@ static int sign_define_from_dict(char *name, dict_T *dict)
texthl = tv_dict_get_string(dict, "texthl", false); texthl = tv_dict_get_string(dict, "texthl", false);
culhl = tv_dict_get_string(dict, "culhl", false); culhl = tv_dict_get_string(dict, "culhl", false);
numhl = tv_dict_get_string(dict, "numhl", false); numhl = tv_dict_get_string(dict, "numhl", false);
prio = (int)tv_dict_get_number_def(dict, "priority", -1);
} }
return sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl) - 1; return sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl, prio) - 1;
} }
/// Define multiple signs using attributes from list 'l' and store the return /// Define multiple signs using attributes from list 'l' and store the return
@ -1442,7 +1463,7 @@ static int sign_place_from_dict(typval_T *id_tv, typval_T *group_tv, typval_T *n
} }
} }
int prio = SIGN_DEF_PRIO; int prio = -1;
di = tv_dict_find(dict, "priority", -1); di = tv_dict_find(dict, "priority", -1);
if (di != NULL) { if (di != NULL) {
prio = (int)tv_get_number_chk(&di->di_tv, &notanum); prio = (int)tv_get_number_chk(&di->di_tv, &notanum);

View File

@ -18,6 +18,7 @@ typedef struct {
int sn_text_hl; // highlight ID for text 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_cul_hl; // highlight ID for text on current line when 'cursorline' is set
int sn_num_hl; // highlight ID for line number int sn_num_hl; // highlight ID for line number
int sn_priority; // default priority of this sign, -1 means SIGN_DEF_PRIO
} sign_T; } sign_T;
typedef struct { typedef struct {

View File

@ -2920,11 +2920,12 @@ describe('builtin popupmenu', function()
feed('<C-U>sign define <Tab>') feed('<C-U>sign define <Tab>')
screen:expect([[ screen:expect([[
| |
{1:~ }|*2 {1:~ }|
{1:~ }{s: culhl= }{1: }| {1:~ }{s: culhl= }{1: }|
{1:~ }{n: icon= }{1: }| {1:~ }{n: icon= }{1: }|
{1:~ }{n: linehl= }{1: }| {1:~ }{n: linehl= }{1: }|
{1:~ }{n: numhl= }{1: }| {1:~ }{n: numhl= }{1: }|
{1:~ }{n: priority= }{1: }|
{1:~ }{n: text= }{1: }| {1:~ }{n: text= }{1: }|
{1:~ }{n: texthl= }{1: }| {1:~ }{n: texthl= }{1: }|
:sign define culhl=^ | :sign define culhl=^ |
@ -2933,11 +2934,12 @@ describe('builtin popupmenu', function()
feed('<Space><Tab>') feed('<Space><Tab>')
screen:expect([[ screen:expect([[
| |
{1:~ }|*2 {1:~ }|
{1:~ }{s: culhl= }{1: }| {1:~ }{s: culhl= }{1: }|
{1:~ }{n: icon= }{1: }| {1:~ }{n: icon= }{1: }|
{1:~ }{n: linehl= }{1: }| {1:~ }{n: linehl= }{1: }|
{1:~ }{n: numhl= }{1: }| {1:~ }{n: numhl= }{1: }|
{1:~ }{n: priority= }{1: }|
{1:~ }{n: text= }{1: }| {1:~ }{n: text= }{1: }|
{1:~ }{n: texthl= }{1: }| {1:~ }{n: texthl= }{1: }|
:sign define culhl= culhl=^ | :sign define culhl= culhl=^ |

View File

@ -246,7 +246,7 @@ func Test_sign_completion()
call assert_equal('"sign define jump list place undefine unplace', @:) call assert_equal('"sign define jump list place undefine unplace', @:)
call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx') call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign define Sign culhl= icon= linehl= numhl= text= texthl=', @:) call assert_equal('"sign define Sign culhl= icon= linehl= numhl= priority= text= texthl=', @:)
for hl in ['culhl', 'linehl', 'numhl', 'texthl'] for hl in ['culhl', 'linehl', 'numhl', 'texthl']
call feedkeys(":sign define Sign "..hl.."=Spell\<C-A>\<C-B>\"\<CR>", 'tx') call feedkeys(":sign define Sign "..hl.."=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
@ -1240,9 +1240,28 @@ func Test_sign_priority()
call sign_define("sign1", attr) call sign_define("sign1", attr)
call sign_define("sign2", attr) call sign_define("sign2", attr)
call sign_define("sign3", attr) call sign_define("sign3", attr)
let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Search', 'priority': 60}
call sign_define("sign4", attr)
" Test for :sign list
let a = execute('sign list')
call assert_equal("\nsign sign1 text==> linehl=Search texthl=Search\n" .
\ "sign sign2 text==> linehl=Search texthl=Search\n" .
\ "sign sign3 text==> linehl=Search texthl=Search\n" .
\ "sign sign4 text==> priority=60 linehl=Search texthl=Search", a)
" Test for sign_getdefined()
let s = sign_getdefined()
call assert_equal([
\ {'name': 'sign1', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'},
\ {'name': 'sign2', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'},
\ {'name': 'sign3', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'},
\ {'name': 'sign4', 'priority': 60, 'texthl': 'Search', 'linehl': 'Search',
\ 'text': '=>'}],
\ s)
" Place three signs with different priority in the same line " Place three signs with different priority in the same line
call writefile(repeat(["Sun is shining"], 30), "Xsign") call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D')
edit Xsign edit Xsign
call sign_place(1, 'g1', 'sign1', 'Xsign', call sign_place(1, 'g1', 'sign1', 'Xsign',
@ -1577,16 +1596,34 @@ func Test_sign_priority()
call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" . call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
\ " line=10 id=5 group=g1 name=sign1 priority=20\n", a) \ " line=10 id=5 group=g1 name=sign1 priority=20\n", a)
call sign_unplace('*')
" Test for sign with default priority.
call sign_place(1, 'g1', 'sign4', 'Xsign', {'lnum' : 3})
sign place 2 line=5 name=sign4 group=g1 file=Xsign
let s = sign_getplaced('Xsign', {'group' : '*'})
call assert_equal([
\ {'id' : 1, 'name' : 'sign4', 'lnum' : 3, 'group' : 'g1',
\ 'priority' : 60},
\ {'id' : 2, 'name' : 'sign4', 'lnum' : 5, 'group' : 'g1',
\ 'priority' : 60}],
\ s[0].signs)
let a = execute('sign place group=g1')
call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
\ " line=3 id=1 group=g1 name=sign4 priority=60\n" .
\ " line=5 id=2 group=g1 name=sign4 priority=60\n", a)
call sign_unplace('*') call sign_unplace('*')
call sign_undefine() call sign_undefine()
enew | only enew | only
call delete("Xsign")
endfunc endfunc
" Tests for memory allocation failures in sign functions " Tests for memory allocation failures in sign functions
func Test_sign_memfailures() func Test_sign_memfailures()
CheckFunction test_alloc_fail CheckFunction test_alloc_fail
call writefile(repeat(["Sun is shining"], 30), "Xsign") call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D')
edit Xsign edit Xsign
call test_alloc_fail(GetAllocId('sign_getdefined'), 0, 0) call test_alloc_fail(GetAllocId('sign_getdefined'), 0, 0)
@ -1623,7 +1660,6 @@ func Test_sign_memfailures()
call sign_unplace('*') call sign_unplace('*')
call sign_undefine() call sign_undefine()
enew | only enew | only
call delete("Xsign")
endfunc endfunc
" Test for auto-adjusting the line number of a placed sign. " Test for auto-adjusting the line number of a placed sign.