feat(tui): add support for CSI 4 : [2,4,5] m

This commit finishes support for colored and styled underlines adding
`CSI 4 : [2,4,5] m` support providing double, dashed, and dotted
underlines

Fixes #17362.
This commit is contained in:
Kirill Chibisov 2022-03-02 00:48:11 +03:00
parent 7211d8ef21
commit f89fb41a7a
No known key found for this signature in database
GPG Key ID: 7EA8F8B94622A6A9
14 changed files with 134 additions and 43 deletions

View File

@ -7937,8 +7937,11 @@ synIDattr({synID}, {what} [, {mode}]) *synIDattr()*
"inverse" "1" if inverse (= reverse)
"standout" "1" if standout
"underline" "1" if underlined
"underlineline" "1" if double underlined
"undercurl" "1" if undercurled
"strikethrough" "1" if struckthrough
"underdot" "1" if dotted underlined
"underdash" "1" if dashed underlined
"strikethrough" "1" if struckthrough
Example (echoes the color of the syntax item under the
cursor): >

View File

@ -4875,7 +4875,8 @@ the same syntax file on all UIs.
1. TUI highlight arguments
*bold* *underline* *undercurl*
*bold* *underline* *underlineline*
*undercurl* *underdot* *underdash*
*inverse* *italic* *standout*
*nocombine* *strikethrough*
cterm={attr-list} *attr-list* *highlight-cterm* *E418*
@ -4883,7 +4884,10 @@ cterm={attr-list} *attr-list* *highlight-cterm* *E418*
following items (in any order):
bold
underline
underlineline double underline
undercurl curly underline
underdot dotted underline
underdash dashed underline
strikethrough
reverse
inverse same as reverse
@ -4894,8 +4898,9 @@ cterm={attr-list} *attr-list* *highlight-cterm* *E418*
Note that "bold" can be used here and by using a bold font. They
have the same effect.
"undercurl" falls back to "underline" in a terminal that does not
support it. The color is set using |highlight-guisp|.
"underlineline", "undercurl", "underdot", and "underdash" falls back
to "underline" in a terminal that does not support it. The color is set
using |highlight-guisp|.
start={term-list} *highlight-start* *E422*
stop={term-list} *term-list* *highlight-stop*
@ -5028,8 +5033,8 @@ guifg={color-name} *highlight-guifg*
guibg={color-name} *highlight-guibg*
guisp={color-name} *highlight-guisp*
These give the foreground (guifg), background (guibg) and special
(guisp) color to use in the GUI. "guisp" is used for undercurl
and underline.
(guisp) color to use in the GUI. "guisp" is used for various
underlines.
There are a few special names:
NONE no color (transparent)
bg use normal background color

View File

@ -283,19 +283,24 @@ numerical highlight ids to the actual attributes.
attributes specified by the `rgb_attr` and `cterm_attr` dicts, with the
following (all optional) keys.
`foreground`: foreground color.
`background`: background color.
`special`: color to use for underline and undercurl, when present.
`reverse`: reverse video. Foreground and background colors are
switched.
`italic`: italic text.
`bold`: bold text.
`strikethrough`: struckthrough text.
`underline`: underlined text. The line has `special` color.
`undercurl`: undercurled text. The curl has `special` color.
`blend`: Blend level (0-100). Could be used by UIs to support
blending floating windows to the background or to
signal a transparent cursor.
`foreground`: foreground color.
`background`: background color.
`special`: color to use for various underlines, when
present.
`reverse`: reverse video. Foreground and background colors
are switched.
`italic`: italic text.
`bold`: bold text.
`strikethrough`: struckthrough text.
`underline`: underlined text. The line has `special` color.
`underlineline`: double underlined text. The lines has `special`
color.
`undercurl`: undercurled text. The curl has `special` color.
`underdot`: underdotted text. The dots has `special` color.
`underdash`: underdashed text. The dashes has `special` color.
`blend`: Blend level (0-100). Could be used by UIs to
support blending floating windows to the
background or to signal a transparent cursor.
For absent color keys the default color should be used. Don't store
the default value in the table, rather a sentinel value, so that
@ -444,14 +449,17 @@ is not active. New UIs should implement |ui-linegrid| instead.
`foreground`: foreground color.
`background`: background color.
`special`: color to use for underline and undercurl, when present.
`special`: color to use for various underlines, when present.
`reverse`: reverse video. Foreground and background colors are
switched.
`italic`: italic text.
`bold`: bold text.
`strikethrough`: struckthrough text.
`underline`: underlined text. The line has `special` color.
`underlineline`: double underlined text. The lines has `special` color.
`undercurl`: undercurled text. The curl has `special` color.
`underdot`: underdotted text. The dots has `special` color.
`underdash`: underdashed text. The dashes has `special` color.
["put", text]
The (utf-8 encoded) string `text` is put at the cursor position

View File

@ -574,7 +574,7 @@ syn match vimHiBang contained "!" skipwhite nextgroup=@vimHighlightCluster
syn match vimHiGroup contained "\i\+"
syn case ignore
syn keyword vimHiAttrib contained none bold inverse italic nocombine reverse standout strikethrough underline undercurl
syn keyword vimHiAttrib contained none bold inverse italic nocombine reverse standout strikethrough underline underlineline undercurl underdot underdash
syn keyword vimFgBgAttrib contained none bg background fg foreground
syn case match
syn match vimHiAttribList contained "\i\+" contains=vimHiAttrib

View File

@ -83,7 +83,10 @@ return {
"standout";
"strikethrough";
"underline";
"underlineline";
"undercurl";
"underdot";
"underdash";
"italic";
"reverse";
"nocombine";
@ -105,7 +108,10 @@ return {
"standout";
"strikethrough";
"underline";
"underlineline";
"undercurl";
"underdot";
"underdash";
"italic";
"reverse";
"nocombine";

View File

@ -11409,14 +11409,22 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p = highlight_has_attr(id, HL_STANDOUT, modec);
}
break;
case 'u':
if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') { // underline
p = highlight_has_attr(id, HL_UNDERLINE, modec);
} else { // undercurl
case 'u': {
int len = STRLEN(what);
if (len <= 5 || (TOLOWER_ASC(what[5]) == 'l' && len <= 9)) { // underline
p = highlight_has_attr(id, HL_UNDERCURL, modec);
} else if (TOLOWER_ASC(what[5]) == 'c') { // undercurl
p = highlight_has_attr(id, HL_UNDERCURL, modec);
} else if (len > 9 && TOLOWER_ASC(what[9]) == 'l') { // underlineline
p = highlight_has_attr(id, HL_UNDERLINELINE, modec);
} else if (len > 5 && TOLOWER_ASC(what[6]) == 'o') { // underdot
p = highlight_has_attr(id, HL_UNDERDOT, modec);
} else { // underdash
p = highlight_has_attr(id, HL_UNDERDASH, modec);
}
break;
}
}
rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char_u *)(p == NULL ? p : xstrdup(p));

View File

@ -420,7 +420,10 @@ static void prt_get_attr(int hl_id, prt_text_attr_T *pattr, int modec)
pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
pattr->underline = (highlight_has_attr(hl_id, HL_UNDERLINE, modec) != NULL);
pattr->underlineline = (highlight_has_attr(hl_id, HL_UNDERLINELINE, modec) != NULL);
pattr->undercurl = (highlight_has_attr(hl_id, HL_UNDERCURL, modec) != NULL);
pattr->underdot = (highlight_has_attr(hl_id, HL_UNDERDOT, modec) != NULL);
pattr->underdash = (highlight_has_attr(hl_id, HL_UNDERDASH, modec) != NULL);
uint32_t fg_color = prt_get_color(hl_id, modec);

View File

@ -18,6 +18,9 @@ typedef struct {
TriState italic;
TriState underline;
int undercurl;
int underlineline;
int underdot;
int underdash;
} prt_text_attr_T;
/*

View File

@ -558,7 +558,7 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through)
cattrs = battrs;
cattrs.rgb_fg_color = rgb_blend(ratio, battrs.rgb_fg_color,
fattrs.rgb_bg_color);
if (cattrs.rgb_ae_attr & (HL_UNDERLINE|HL_UNDERCURL)) {
if (cattrs.rgb_ae_attr & (HL_ANY_UNDERLINE)) {
cattrs.rgb_sp_color = rgb_blend(ratio, battrs.rgb_sp_color,
fattrs.rgb_bg_color);
} else {
@ -576,7 +576,7 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through)
}
cattrs.rgb_fg_color = rgb_blend(ratio/2, battrs.rgb_fg_color,
fattrs.rgb_fg_color);
if (cattrs.rgb_ae_attr & (HL_UNDERLINE|HL_UNDERCURL)) {
if (cattrs.rgb_ae_attr & (HL_ANY_UNDERLINE)) {
cattrs.rgb_sp_color = rgb_blend(ratio/2, battrs.rgb_bg_color,
fattrs.rgb_sp_color);
} else {
@ -743,10 +743,23 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb)
PUT(hl, "underline", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERLINELINE) {
PUT(hl, "underlineline", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERCURL) {
PUT(hl, "undercurl", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERDOT) {
PUT(hl, "underdot", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERDASH) {
PUT(hl, "underdash", BOOLEAN_OBJ(true));
}
if (mask & HL_ITALIC) {
PUT(hl, "italic", BOOLEAN_OBJ(true));
}
@ -813,7 +826,10 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(dict, mask, bold, , HL_BOLD);
CHECK_FLAG(dict, mask, standout, , HL_STANDOUT);
CHECK_FLAG(dict, mask, underline, , HL_UNDERLINE);
CHECK_FLAG(dict, mask, underlineline, , HL_UNDERLINELINE);
CHECK_FLAG(dict, mask, undercurl, , HL_UNDERCURL);
CHECK_FLAG(dict, mask, underdot, , HL_UNDERDOT);
CHECK_FLAG(dict, mask, underdash, , HL_UNDERDASH);
CHECK_FLAG(dict, mask, italic, , HL_ITALIC);
CHECK_FLAG(dict, mask, reverse, , HL_INVERSE);
CHECK_FLAG(dict, mask, strikethrough, , HL_STRIKETHROUGH);

View File

@ -24,6 +24,10 @@ typedef enum {
HL_FG_INDEXED = 0x0200,
HL_DEFAULT = 0x0400,
HL_GLOBAL = 0x0800,
HL_UNDERLINELINE = 0x1000,
HL_UNDERDOT = 0x2000,
HL_UNDERDASH = 0x4000,
HL_ANY_UNDERLINE = HL_UNDERLINE | HL_UNDERLINELINE | HL_UNDERCURL | HL_UNDERDOT | HL_UNDERDASH,
} HlAttrFlags;
/// Stores a complete highlighting entry, including colors and attributes

View File

@ -121,11 +121,11 @@ static int include_link = 0; // when 2 include "nvim/link" and "clear"
/// The "term", "cterm" and "gui" arguments can be any combination of the
/// following names, separated by commas (but no spaces!).
static char *(hl_name_table[]) =
{ "bold", "standout", "underline", "undercurl",
"italic", "reverse", "inverse", "strikethrough", "nocombine", "NONE" };
{ "bold", "standout", "underline", "underlineline", "undercurl", "underdot",
"underdash", "italic", "reverse", "inverse", "strikethrough", "nocombine", "NONE" };
static int hl_attr_table[] =
{ HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE,
HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 };
{ HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERLINELINE, HL_UNDERCURL, HL_UNDERDOT, HL_UNDERDASH,
HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 };
static char e_illegal_arg[] = N_("E390: Illegal argument: %s");

View File

@ -528,7 +528,7 @@ static bool attrs_differ(UI *ui, int id1, int id2, bool rgb)
return a1.cterm_fg_color != a2.cterm_fg_color
|| a1.cterm_bg_color != a2.cterm_bg_color
|| a1.cterm_ae_attr != a2.cterm_ae_attr
|| (a1.cterm_ae_attr & (HL_UNDERLINE|HL_UNDERCURL)
|| (a1.cterm_ae_attr & HL_ANY_UNDERLINE
&& a1.rgb_sp_color != a2.rgb_sp_color);
}
}
@ -552,15 +552,27 @@ static void update_attrs(UI *ui, int attr_id)
bool strikethrough = attr & HL_STRIKETHROUGH;
bool underline;
bool underlineline;
bool undercurl;
bool underdot;
bool underdash;
if (data->unibi_ext.set_underline_style != -1) {
underline = attr & HL_UNDERLINE;
underlineline = attr & HL_UNDERLINELINE;
undercurl = attr & HL_UNDERCURL;
underdash = attr & HL_UNDERDASH;
underdot = attr & HL_UNDERDOT;
} else {
underline = (attr & HL_UNDERLINE) || (attr & HL_UNDERCURL);
underline = attr & HL_ANY_UNDERLINE;
underlineline = false;
undercurl = false;
underdot = false;
underdash = false;
}
bool has_any_underline = undercurl || underline
|| underdot || underdash || underlineline;
if (unibi_get_str(data->ut, unibi_set_attributes)) {
if (bold || reverse || underline || standout) {
UNIBI_SET_NUM_VAR(data->params[0], standout);
@ -599,11 +611,24 @@ static void update_attrs(UI *ui, int attr_id)
if (strikethrough && data->unibi_ext.enter_strikethrough_mode != -1) {
unibi_out_ext(ui, data->unibi_ext.enter_strikethrough_mode);
}
if (underlineline && data->unibi_ext.set_underline_style != -1) {
UNIBI_SET_NUM_VAR(data->params[0], 2);
unibi_out_ext(ui, data->unibi_ext.set_underline_style);
}
if (undercurl && data->unibi_ext.set_underline_style != -1) {
UNIBI_SET_NUM_VAR(data->params[0], 3);
unibi_out_ext(ui, data->unibi_ext.set_underline_style);
}
if ((undercurl || underline) && data->unibi_ext.set_underline_color != -1) {
if (underdot && data->unibi_ext.set_underline_style != -1) {
UNIBI_SET_NUM_VAR(data->params[0], 4);
unibi_out_ext(ui, data->unibi_ext.set_underline_style);
}
if (underdash && data->unibi_ext.set_underline_style != -1) {
UNIBI_SET_NUM_VAR(data->params[0], 5);
unibi_out_ext(ui, data->unibi_ext.set_underline_style);
}
if (has_any_underline && data->unibi_ext.set_underline_color != -1) {
int color = attrs.rgb_sp_color;
if (color != -1) {
UNIBI_SET_NUM_VAR(data->params[0], (color >> 16) & 0xff); // red
@ -652,13 +677,13 @@ static void update_attrs(UI *ui, int attr_id)
data->default_attr = fg == -1 && bg == -1
&& !bold && !italic && !underline && !undercurl && !reverse && !standout
&& !bold && !italic && !has_any_underline && !reverse && !standout
&& !strikethrough;
// Non-BCE terminals can't clear with non-default background color. Some BCE
// terminals don't support attributes either, so don't rely on it. But assume
// italic and bold has no effect if there is no text.
data->can_clear_attr = !reverse && !standout && !underline && !undercurl
data->can_clear_attr = !reverse && !standout && !has_any_underline
&& !strikethrough && (data->bce || bg == -1);
}

View File

@ -28,8 +28,11 @@ describe('API: highlight',function()
bold = true,
italic = true,
reverse = true,
undercurl = true,
underline = true,
underlineline = true,
undercurl = true,
underdot = true,
underdash = true,
strikethrough = true,
}
@ -52,7 +55,7 @@ describe('API: highlight',function()
eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
-- Test all highlight properties.
command('hi NewHighlight gui=underline,bold,undercurl,italic,reverse,strikethrough')
command('hi NewHighlight gui=underline,bold,underlineline,undercurl,underdot,underdash,italic,reverse,strikethrough')
eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true))
-- Test nil argument.
@ -195,6 +198,9 @@ describe("API: set highlight", function()
reverse = true,
undercurl = true,
underline = true,
underdash = true,
underdot = true,
underlineline = true,
strikethrough = true,
cterm = {
italic = true,
@ -211,6 +217,9 @@ describe("API: set highlight", function()
reverse = true,
undercurl = true,
underline = true,
underdash = true,
underdot = true,
underlineline = true,
strikethrough = true,
}
local highlight3_result_cterm = {
@ -274,7 +283,7 @@ describe("API: set highlight", function()
exec_capture('highlight Test_hl'))
meths.set_hl(0, 'Test_hl2', highlight3_config)
eq('Test_hl2 xxx cterm=undercurl,italic,reverse,strikethrough ctermfg=8 ctermbg=15 gui=bold,underline,undercurl,italic,reverse,strikethrough guifg=#ff0000 guibg=#0032aa',
eq('Test_hl2 xxx cterm=undercurl,italic,reverse,strikethrough ctermfg=8 ctermbg=15 gui=bold,underline,underlineline,undercurl,underdot,underdash,italic,reverse,strikethrough guifg=#ff0000 guibg=#0032aa',
exec_capture('highlight Test_hl2'))
-- Colors are stored exactly as they are defined.

View File

@ -1559,10 +1559,11 @@ end
function Screen:_equal_attrs(a, b)
return a.bold == b.bold and a.standout == b.standout and
a.underline == b.underline and a.undercurl == b.undercurl and
a.italic == b.italic and a.reverse == b.reverse and
a.foreground == b.foreground and a.background == b.background and
a.special == b.special and a.blend == b.blend and
a.underline == b.underline and a.underlineline == b.underlineline and
a.undercurl == b.undercurl and a.underdot == b.underdot and
a.underdash == b.underdash and a.italic == b.italic and
a.reverse == b.reverse and a.foreground == b.foreground and
a.background == b.background and a.special == b.special and a.blend == b.blend and
a.strikethrough == b.strikethrough and
a.fg_indexed == b.fg_indexed and a.bg_indexed == b.bg_indexed
end