signs: Add "numhl" argument #9113

close #9113
ref #9040
This commit is contained in:
Reto Schnyder 2018-10-13 19:33:08 +02:00 committed by Justin M. Keyes
parent 8bbb28b973
commit bddcbbb571
10 changed files with 127 additions and 53 deletions

View File

@ -4256,12 +4256,11 @@ A jump table for the options with a short description can be found at |Q_op|.
Print the line number in front of each line. When the 'n' option is Print the line number in front of each line. When the 'n' option is
excluded from 'cpoptions' a wrapped line will not use the column of excluded from 'cpoptions' a wrapped line will not use the column of
line numbers. line numbers.
The 'numberwidth' option can be used to set the room used for the line Use the 'numberwidth' option to adjust the room for the line number.
number.
When a long, wrapped line doesn't start with the first character, '-' When a long, wrapped line doesn't start with the first character, '-'
characters are put before the number. characters are put before the number.
See |hl-LineNr| and |hl-CursorLineNr| for the highlighting used for For highlighting see |hl-LineNr|, |hl-CursorLineNr|, and the
the number. |:sign-define| "numhl" argument.
*number_relativenumber* *number_relativenumber*
The 'relativenumber' option changes the displayed number to be The 'relativenumber' option changes the displayed number to be
relative to the cursor. Together with 'number' there are these relative to the cursor. Together with 'number' there are these

View File

@ -85,6 +85,10 @@ DEFINING A SIGN. *:sign-define* *E255* *E160* *E612*
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.
numhl={group}
Highlighting group used for 'number' column at the associated
line. Overrides |hl-LineNr|, |hl-CursorLineNr|.
text={text} *E239* text={text} *E239*
Define the text that is displayed when there is no icon or the Define the text that is displayed when there is no icon or the
GUI is not being used. Only printable characters are allowed GUI is not being used. Only printable characters are allowed

View File

@ -136,6 +136,7 @@ Commands:
|:cquit| can use [count] to set the exit code |:cquit| can use [count] to set the exit code
|:drop| is always available |:drop| is always available
|:Man| is available by default, with many improvements such as completion |:Man| is available by default, with many improvements such as completion
|:sign-define| accepts a `numhl` argument, to highlight the line number
|:tchdir| tab-local |current-directory| |:tchdir| tab-local |current-directory|
Events: Events:

View File

@ -5084,13 +5084,16 @@ linenr_T buf_change_sign_type(
return (linenr_T)0; return (linenr_T)0;
} }
int buf_getsigntype( /// Gets a sign from a given line.
buf_T *buf, /// In case of multiple signs, returns the most recently placed one.
linenr_T lnum, ///
int type /* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */ /// @param buf Buffer in which to search
) /// @param lnum Line in which to search
/// @param type Type of sign to look for
/// @return Identifier of the first matching sign, or 0
int buf_getsigntype(buf_T *buf, linenr_T lnum, SignType type)
{ {
signlist_T *sign; /* a sign in a b_signlist */ signlist_T *sign; // a sign in a b_signlist
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) { for (sign = buf->b_signlist; sign != NULL; sign = sign->next) {
if (sign->lnum == lnum if (sign->lnum == lnum
@ -5098,7 +5101,9 @@ int buf_getsigntype(
|| (type == SIGN_TEXT || (type == SIGN_TEXT
&& sign_get_text(sign->typenr) != NULL) && sign_get_text(sign->typenr) != NULL)
|| (type == SIGN_LINEHL || (type == SIGN_LINEHL
&& sign_get_attr(sign->typenr, TRUE) != 0))) { && sign_get_attr(sign->typenr, SIGN_LINEHL) != 0)
|| (type == SIGN_NUMHL
&& sign_get_attr(sign->typenr, SIGN_NUMHL) != 0))) {
return sign->typenr; return sign->typenr;
} }
} }

View File

@ -5471,13 +5471,14 @@ void ex_helptags(exarg_T *eap)
struct sign struct sign
{ {
sign_T *sn_next; /* next sign in list */ sign_T *sn_next; // next sign in list
int sn_typenr; /* type number of sign */ int sn_typenr; // type number of sign
char_u *sn_name; /* name of sign */ char_u *sn_name; // name of sign
char_u *sn_icon; /* name of pixmap */ char_u *sn_icon; // name of pixmap
char_u *sn_text; /* text used instead of pixmap */ char_u *sn_text; // text used instead of pixmap
int sn_line_hl; /* highlight ID for line */ int sn_line_hl; // highlight ID for line
int sn_text_hl; /* highlight ID for text */ int sn_text_hl; // highlight ID for text
int sn_num_hl; // highlight ID for line number
}; };
static sign_T *first_sign = NULL; static sign_T *first_sign = NULL;
@ -5675,6 +5676,9 @@ void ex_sign(exarg_T *eap)
} else if (STRNCMP(arg, "texthl=", 7) == 0) { } else if (STRNCMP(arg, "texthl=", 7) == 0) {
arg += 7; arg += 7;
sp->sn_text_hl = syn_check_group(arg, (int)(p - arg)); sp->sn_text_hl = syn_check_group(arg, (int)(p - arg));
} else if (STRNCMP(arg, "numhl=", 6) == 0) {
arg += 6;
sp->sn_num_hl = syn_check_group(arg, (int)(p - arg));
} else { } else {
EMSG2(_(e_invarg2), arg); EMSG2(_(e_invarg2), arg);
return; return;
@ -5901,6 +5905,16 @@ static void sign_list_defined(sign_T *sp)
msg_puts(p); msg_puts(p);
} }
} }
if (sp->sn_num_hl > 0) {
msg_puts(" numhl=");
const char *const p = get_highlight_name_ext(NULL,
sp->sn_num_hl - 1, false);
if (p == NULL) {
msg_puts("NONE");
} else {
msg_puts(p);
}
}
} }
/* /*
@ -5918,25 +5932,33 @@ static void sign_undefine(sign_T *sp, sign_T *sp_prev)
xfree(sp); xfree(sp);
} }
/* /// Gets highlighting attribute for sign "typenr" corresponding to "type".
* Get highlighting attribute for sign "typenr". int sign_get_attr(int typenr, SignType type)
* If "line" is TRUE: line highl, if FALSE: text highl.
*/
int sign_get_attr(int typenr, int line)
{ {
sign_T *sp; sign_T *sp;
int sign_hl = 0;
for (sp = first_sign; sp != NULL; sp = sp->sn_next) for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
if (sp->sn_typenr == typenr) { if (sp->sn_typenr == typenr) {
if (line) { switch (type) {
if (sp->sn_line_hl > 0) case SIGN_TEXT:
return syn_id2attr(sp->sn_line_hl); sign_hl = sp->sn_text_hl;
} else { break;
if (sp->sn_text_hl > 0) case SIGN_LINEHL:
return syn_id2attr(sp->sn_text_hl); sign_hl = sp->sn_line_hl;
break;
case SIGN_NUMHL:
sign_hl = sp->sn_num_hl;
break;
default:
abort();
}
if (sign_hl > 0) {
return syn_id2attr(sign_hl);
} }
break; break;
} }
}
return 0; return 0;
} }
@ -5997,7 +6019,8 @@ char_u * get_sign_name(expand_T *xp, int idx)
case EXP_SUBCMD: case EXP_SUBCMD:
return (char_u *)cmds[idx]; return (char_u *)cmds[idx];
case EXP_DEFINE: { case EXP_DEFINE: {
char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", NULL }; char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", "numhl=",
NULL };
return (char_u *)define_arg[idx]; return (char_u *)define_arg[idx];
} }
case EXP_PLACE: { case EXP_PLACE: {
@ -6120,7 +6143,8 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
{ {
case SIGNCMD_DEFINE: case SIGNCMD_DEFINE:
if (STRNCMP(last, "texthl", p - last) == 0 if (STRNCMP(last, "texthl", p - last) == 0
|| STRNCMP(last, "linehl", p - last) == 0) { || STRNCMP(last, "linehl", p - last) == 0
|| STRNCMP(last, "numhl", p - last) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT; xp->xp_context = EXPAND_HIGHLIGHT;
} else if (STRNCMP(last, "icon", p - last) == 0) { } else if (STRNCMP(last, "icon", p - last) == 0) {
xp->xp_context = EXPAND_FILES; xp->xp_context = EXPAND_FILES;

View File

@ -2486,7 +2486,7 @@ win_line (
// If this line has a sign with line highlighting set line_attr. // If this line has a sign with line highlighting set line_attr.
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL); v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
if (v != 0) { if (v != 0) {
line_attr = sign_get_attr((int)v, true); line_attr = sign_get_attr((int)v, SIGN_LINEHL);
} }
// Highlight the current line in the quickfix window. // Highlight the current line in the quickfix window.
@ -2794,7 +2794,7 @@ win_line (
p_extra = extra; p_extra = extra;
p_extra[n_extra] = NUL; p_extra[n_extra] = NUL;
} }
char_attr = sign_get_attr(text_sign, FALSE); char_attr = sign_get_attr(text_sign, SIGN_TEXT);
} }
} }
} }
@ -2841,12 +2841,17 @@ win_line (
c_extra = ' '; c_extra = ' ';
n_extra = number_width(wp) + 1; n_extra = number_width(wp) + 1;
char_attr = win_hl_attr(wp, HLF_N); char_attr = win_hl_attr(wp, HLF_N);
// When 'cursorline' is set highlight the line number of
// the current line differently. int num_sign = buf_getsigntype(wp->w_buffer, lnum, SIGN_NUMHL);
// TODO(vim): Can we use CursorLine instead of CursorLineNr if (num_sign != 0) {
// when CursorLineNr isn't set? // :sign defined with "numhl" highlight.
if ((wp->w_p_cul || wp->w_p_rnu) char_attr = sign_get_attr(num_sign, SIGN_NUMHL);
&& lnum == wp->w_cursor.lnum) { } else if ((wp->w_p_cul || wp->w_p_rnu)
&& lnum == wp->w_cursor.lnum) {
// When 'cursorline' is set highlight the line number of
// the current line differently.
// TODO(vim): Can we use CursorLine instead of CursorLineNr
// when CursorLineNr isn't set?
char_attr = win_hl_attr(wp, HLF_CLN); char_attr = win_hl_attr(wp, HLF_CLN);
} }
} }

View File

@ -9,17 +9,20 @@ typedef struct signlist signlist_T;
struct signlist struct signlist
{ {
int id; /* unique identifier for each placed sign */ int id; // unique identifier for each placed sign
linenr_T lnum; /* line number which has this sign */ linenr_T lnum; // line number which has this sign
int typenr; /* typenr of sign */ int typenr; // typenr of sign
signlist_T *next; /* next signlist entry */ signlist_T *next; // next signlist entry
}; };
/* type argument for buf_getsigntype() */ // type argument for buf_getsigntype() and sign_get_attr()
#define SIGN_ANY 0 typedef enum {
#define SIGN_LINEHL 1 SIGN_ANY,
#define SIGN_ICON 2 SIGN_LINEHL,
#define SIGN_TEXT 3 SIGN_ICON,
SIGN_TEXT,
SIGN_NUMHL,
} SignType;

View File

@ -14,7 +14,7 @@ func Test_sign()
" the icon name when listing signs. " the icon name when listing signs.
sign define Sign1 text=x sign define Sign1 text=x
try try
sign define Sign2 text=xy texthl=Title linehl=Error icon=../../pixmaps/stock_vim_find_help.png sign define Sign2 text=xy texthl=Title linehl=Error numhl=Number icon=../../pixmaps/stock_vim_find_help.png
catch /E255:/ catch /E255:/
" ignore error: E255: Couldn't read in sign data! " ignore error: E255: Couldn't read in sign data!
" This error can happen when running in gui. " This error can happen when running in gui.
@ -23,7 +23,7 @@ func Test_sign()
" Test listing signs. " Test listing signs.
let a=execute('sign list') 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$", a) call assert_match("^\nsign Sign1 text=x \nsign Sign2 icon=../../pixmaps/stock_vim_find_help.png .*text=xy linehl=Error texthl=Title numhl=Number$", a)
let a=execute('sign list Sign1') let a=execute('sign list Sign1')
call assert_equal("\nsign Sign1 text=x ", a) call assert_equal("\nsign Sign1 text=x ", a)
@ -140,7 +140,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 icon= linehl= text= texthl=', @:) call assert_equal('"sign define Sign icon= linehl= numhl= text= texthl=', @:)
call feedkeys(":sign define Sign linehl=Spell\<C-A>\<C-B>\"\<CR>", 'tx') 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 assert_equal('"sign define Sign linehl=SpellBad SpellCap SpellLocal SpellRare', @:)

View File

@ -7,7 +7,7 @@ describe('sign', function()
describe('without specifying buffer', function() describe('without specifying buffer', function()
it('deletes the sign from all buffers', function() it('deletes the sign from all buffers', function()
-- place a sign with id 34 to first buffer -- place a sign with id 34 to first buffer
nvim('command', 'sign define Foo text=+ texthl=Delimiter linehl=Comment') nvim('command', 'sign define Foo text=+ texthl=Delimiter linehl=Comment numhl=Number')
local buf1 = nvim('eval', 'bufnr("%")') local buf1 = nvim('eval', 'bufnr("%")')
nvim('command', 'sign place 34 line=3 name=Foo buffer='..buf1) nvim('command', 'sign place 34 line=3 name=Foo buffer='..buf1)
-- create a second buffer and place the sign on it as well -- create a second buffer and place the sign on it as well

View File

@ -17,6 +17,9 @@ describe('Signs', function()
[3] = {background = Screen.colors.Gray90}, [3] = {background = Screen.colors.Gray90},
[4] = {bold = true, reverse = true}, [4] = {bold = true, reverse = true},
[5] = {reverse = true}, [5] = {reverse = true},
[6] = {foreground = Screen.colors.Brown},
[7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
[8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
} ) } )
end) end)
@ -78,5 +81,35 @@ describe('Signs', function()
| |
]]) ]])
end) end)
it('can combine text, linehl and numhl', function()
feed('ia<cr>b<cr>c<cr><esc>')
command('set number')
command('sign define piet text=>> texthl=Search')
command('sign define pietx linehl=ErrorMsg')
command('sign define pietxx numhl=Folded')
command('sign place 1 line=1 name=piet buffer=1')
command('sign place 2 line=2 name=pietx buffer=1')
command('sign place 3 line=3 name=pietxx buffer=1')
command('sign place 4 line=4 name=piet buffer=1')
command('sign place 5 line=4 name=pietx buffer=1')
command('sign place 6 line=4 name=pietxx buffer=1')
screen:expect([[
{1:>>}{6: 1 }a |
{2: }{6: 2 }{8:b }|
{2: }{7: 3 }c |
{1:>>}{7: 4 }{8:^ }|
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
{2: }{0:~ }|
|
]])
end)
end) end)
end) end)