feat(highlight): support more SGR attributes #37901

Problem:
TUI does not support several standard SGR text attributes:
- dim/faint (SGR 2)
- blink (SGR 5)
- conceal (SGR 8)
- overline (SGR 53)
This means that when a program running in the embedded terminal emits
one of these escape codes, we drop it and don't surface it to the
outer terminal.

Solution:
- Add support for those attributes.
- Also add corresponding flags to `nvim_set_hl` opts, so users can set
  these attributes in highlight groups.
  - refactor(highlight): widen `HlAttrFlags` from `int16_t` to `int32_t`
    Widen the `rgb_ae_attr` and `cterm_ae_attr` fields in HlAttrs from
    int16_t to int32_t to make room for new highlight attribute flags,
    since there was only one spare bit left.
  - The C flag is named HL_CONCEALED to avoid colliding with the
    existing HL_CONCEAL in syntax.h (which is a syntax group flag, not
    an SGR attribute).
- Also note that libvterm doesn't currently support the dim and overline
  attributes, so e.g. `printf '\e[2mThis should be dim\n'` and `printf
  '\e[53mThis should have an overline\n'` are still not rendered
  correctly when run from the embedded terminal.
This commit is contained in:
Riccardo Mazzarini
2026-02-21 00:35:55 +01:00
committed by GitHub
parent 57c6b61cf2
commit cb8c9186e6
21 changed files with 236 additions and 26 deletions

View File

@@ -335,6 +335,10 @@ numerical highlight ids to the actual attributes.
`underdotted`: underdotted text. The dots have `special` color.
`underdashed`: underdashed text. The dashes have `special` color.
`altfont`: alternative font.
`dim`: half-bright/faint text.
`blink`: blinking text.
`conceal`: concealed/hidden text.
`overline`: overlined text.
`blend`: blend level (0-100). Could be used by UIs to
support blending floating windows to the
background or to signal a transparent cursor.
@@ -504,6 +508,10 @@ is not active. New UIs should implement |ui-linegrid| instead.
`underdouble`: double underlined text. The lines have `special` color.
`underdotted`: underdotted text. The dots have `special` color.
`underdashed`: underdashed text. The dashes have `special` color.
`dim`: half-bright/faint text.
`blink`: blinking text.
`conceal`: concealed/hidden text.
`overline`: overlined text.
["put", text] ~
The (utf-8 encoded) string `text` is put at the cursor position

View File

@@ -1553,6 +1553,11 @@ nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()*
• sp: color name or "#RRGGBB"
• blend: integer between 0 and 100
• bold: boolean
• altfont: boolean
• blink: boolean
• dim: boolean
• conceal: boolean
• overline: boolean
• standout: boolean
• underline: boolean
• undercurl: boolean

View File

@@ -248,6 +248,8 @@ HIGHLIGHTS
• |hl-OkMsg| |hl-StderrMsg| |hl-StdoutMsg|
• |hl-SnippetTabstopActive| highlights the currently active tabstop.
• |hl-PmenuBorder| |hl-PmenuShadow| |hl-PmenuShadowThrough| see 'pumborder'.
• |nvim_set_hl()| and |nvim_get_hl()| support the SGR attributes "dim",
"blink", "conceal", and "overline".
LSP
@@ -404,6 +406,8 @@ TUI
• |TermResponse| now supports DA1 and APC query responses.
• Native progress bars are displayed for |Progress| events using the OSC 9;4
sequence.
• The TUI now renders the SGR dim (faint), blink, conceal, and overline
attributes.
UI

View File

@@ -5059,7 +5059,7 @@ the same syntax file on all UIs.
*underdouble* *underdotted*
*underdashed* *inverse* *italic*
*standout* *strikethrough* *altfont*
*nocombine*
*dim* *blink* *hl-conceal* *overline* *nocombine*
cterm={attr-list} *attr-list* *highlight-cterm* *E418*
attr-list is a comma-separated list (without spaces) of the
following items (in any order):
@@ -5075,6 +5075,10 @@ cterm={attr-list} *attr-list* *highlight-cterm* *E418*
italic
standout
altfont
dim half-bright/faint text
blink blinking text
conceal concealed/hidden text
overline overlined text
nocombine override attributes instead of combining them
NONE no attributes used (used to reset it)

View File

@@ -11046,6 +11046,10 @@ synIDattr({synID}, {what} [, {mode}]) *synIDattr()*
"strikethrough" "1" if struckthrough
"altfont" "1" if alternative font
"nocombine" "1" if nocombine
"dim" "1" if half-bright/dimmed
"blink" "1" if blinking
"conceal" "1" if concealed
"overline" "1" if overlined
Returns an empty string on error.

View File

@@ -2208,6 +2208,11 @@ function vim.api.nvim_set_decoration_provider(ns_id, opts) end
--- - sp: color name or "#RRGGBB"
--- - blend: integer between 0 and 100
--- - bold: boolean
--- - altfont: boolean
--- - blink: boolean
--- - dim: boolean
--- - conceal: boolean
--- - overline: boolean
--- - standout: boolean
--- - underline: boolean
--- - undercurl: boolean

View File

@@ -306,6 +306,10 @@ error('Cannot require a meta file')
--- @field italic? boolean
--- @field reverse? boolean
--- @field altfont? boolean
--- @field dim? boolean
--- @field blink? boolean
--- @field conceal? boolean
--- @field overline? boolean
--- @field nocombine? boolean
--- @field default? boolean
--- @field cterm? vim.api.keyset.highlight_cterm
@@ -338,6 +342,10 @@ error('Cannot require a meta file')
--- @field italic? boolean
--- @field reverse? boolean
--- @field altfont? boolean
--- @field dim? boolean
--- @field blink? boolean
--- @field conceal? boolean
--- @field overline? boolean
--- @field nocombine? boolean
--- @class vim.api.keyset.keymap

View File

@@ -10078,6 +10078,10 @@ function vim.fn.synID(lnum, col, trans) end
--- "strikethrough" "1" if struckthrough
--- "altfont" "1" if alternative font
--- "nocombine" "1" if nocombine
--- "dim" "1" if half-bright/dimmed
--- "blink" "1" if blinking
--- "conceal" "1" if concealed
--- "overline" "1" if overlined
---
--- Returns an empty string on error.
---

View File

@@ -53,10 +53,13 @@ local wanted_strings = {
'cursor_up',
'cursor_right',
'delete_line',
'enter_blink_mode',
'enter_bold_mode',
'enter_ca_mode',
'enter_dim_mode',
'enter_italics_mode',
'enter_reverse_mode',
'enter_secure_mode',
'enter_standout_mode',
'enter_underline_mode',
'erase_chars',

View File

@@ -179,6 +179,10 @@ typedef struct {
Boolean italic;
Boolean reverse;
Boolean altfont;
Boolean dim;
Boolean blink;
Boolean conceal;
Boolean overline;
Boolean nocombine;
Boolean default_ DictKey(default);
DictAs(highlight_cterm) cterm;
@@ -212,6 +216,10 @@ typedef struct {
Boolean italic;
Boolean reverse;
Boolean altfont;
Boolean dim;
Boolean blink;
Boolean conceal;
Boolean overline;
Boolean nocombine;
} Dict(highlight_cterm);

View File

@@ -152,6 +152,11 @@ DictAs(get_hl_info) nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena
/// - sp: color name or "#RRGGBB"
/// - blend: integer between 0 and 100
/// - bold: boolean
/// - altfont: boolean
/// - blink: boolean
/// - dim: boolean
/// - conceal: boolean
/// - overline: boolean
/// - standout: boolean
/// - underline: boolean
/// - undercurl: boolean

View File

@@ -9681,7 +9681,7 @@ M.funcs = {
The optional argument {opts} is a Dict and supports the following items:
peer : If |TRUE|, servers not started by |serverstart()|
peer : If |TRUE|, servers not started by |serverstart()|
will also be returned. (default: |FALSE|)
Not supported on Windows yet.
@@ -12158,6 +12158,10 @@ M.funcs = {
"strikethrough" "1" if struckthrough
"altfont" "1" if alternative font
"nocombine" "1" if nocombine
"dim" "1" if half-bright/dimmed
"blink" "1" if blinking
"conceal" "1" if concealed
"overline" "1" if overlined
Returns an empty string on error.

View File

@@ -7371,10 +7371,21 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
case 'b':
if (TOLOWER_ASC(what[1]) == 'g') { // bg[#]
p = highlight_color(id, what, modec);
} else if (TOLOWER_ASC(what[1]) == 'l') { // blink
p = highlight_has_attr(id, HL_BLINK, modec);
} else { // bold
p = highlight_has_attr(id, HL_BOLD, modec);
}
break;
case 'c': // conceal
p = highlight_has_attr(id, HL_CONCEALED, modec);
break;
case 'd': // dim
p = highlight_has_attr(id, HL_DIM, modec);
break;
case 'o': // overline
p = highlight_has_attr(id, HL_OVERLINE, modec);
break;
case 'f': // fg[#] or font
p = highlight_color(id, what, modec);
break;

View File

@@ -562,11 +562,11 @@ void hl_invalidate_blends(void)
/// Combine HlAttrFlags.
/// The underline attribute in "prim_ae" overrules the one in "char_ae" if both are present.
static int16_t hl_combine_ae(int16_t char_ae, int16_t prim_ae)
static int32_t hl_combine_ae(int32_t char_ae, int32_t prim_ae)
{
int16_t char_ul = char_ae & HL_UNDERLINE_MASK;
int16_t prim_ul = prim_ae & HL_UNDERLINE_MASK;
int16_t new_ul = prim_ul ? prim_ul : char_ul;
int32_t char_ul = char_ae & HL_UNDERLINE_MASK;
int32_t prim_ul = prim_ae & HL_UNDERLINE_MASK;
int32_t new_ul = prim_ul ? prim_ul : char_ul;
return (char_ae & ~HL_UNDERLINE_MASK) | (prim_ae & ~HL_UNDERLINE_MASK) | new_ul;
}
@@ -946,6 +946,22 @@ void hlattrs2dict(Dict *hl, Dict *hl_attrs, HlAttrs ae, bool use_rgb, bool short
PUT_C(*hl_attrs, "altfont", BOOLEAN_OBJ(true));
}
if (mask & HL_DIM) {
PUT_C(*hl_attrs, "dim", BOOLEAN_OBJ(true));
}
if (mask & HL_BLINK) {
PUT_C(*hl_attrs, "blink", BOOLEAN_OBJ(true));
}
if (mask & HL_CONCEALED) {
PUT_C(*hl_attrs, "conceal", BOOLEAN_OBJ(true));
}
if (mask & HL_OVERLINE) {
PUT_C(*hl_attrs, "overline", BOOLEAN_OBJ(true));
}
if (mask & HL_NOCOMBINE) {
PUT_C(*hl_attrs, "nocombine", BOOLEAN_OBJ(true));
}
@@ -997,8 +1013,8 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
int32_t ctermbg = -1;
int32_t sp = -1;
int blend = -1;
int16_t mask = 0;
int16_t cterm_mask = 0;
int32_t mask = 0;
int32_t cterm_mask = 0;
bool cterm_mask_provided = false;
#define CHECK_FLAG(d, m, name, extra, flag) \
@@ -1020,6 +1036,10 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(dict, mask, standout, , HL_STANDOUT);
CHECK_FLAG(dict, mask, strikethrough, , HL_STRIKETHROUGH);
CHECK_FLAG(dict, mask, altfont, , HL_ALTFONT);
CHECK_FLAG(dict, mask, dim, , HL_DIM);
CHECK_FLAG(dict, mask, blink, , HL_BLINK);
CHECK_FLAG(dict, mask, conceal, , HL_CONCEALED);
CHECK_FLAG(dict, mask, overline, , HL_OVERLINE);
if (use_rgb) {
CHECK_FLAG(dict, mask, fg_indexed, , HL_FG_INDEXED);
CHECK_FLAG(dict, mask, bg_indexed, , HL_BG_INDEXED);
@@ -1100,6 +1120,10 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(cterm, cterm_mask, standout, , HL_STANDOUT);
CHECK_FLAG(cterm, cterm_mask, strikethrough, , HL_STRIKETHROUGH);
CHECK_FLAG(cterm, cterm_mask, altfont, , HL_ALTFONT);
CHECK_FLAG(cterm, cterm_mask, dim, , HL_DIM);
CHECK_FLAG(cterm, cterm_mask, blink, , HL_BLINK);
CHECK_FLAG(cterm, cterm_mask, conceal, , HL_CONCEALED);
CHECK_FLAG(cterm, cterm_mask, overline, , HL_OVERLINE);
CHECK_FLAG(cterm, cterm_mask, nocombine, , HL_NOCOMBINE);
}
#undef CHECK_FLAG

View File

@@ -25,7 +25,10 @@ typedef enum {
HL_STANDOUT = 0x0040,
HL_STRIKETHROUGH = 0x0080,
HL_ALTFONT = 0x0100,
// 0x0200 spare
HL_DIM = 0x0200,
HL_BLINK = 0x8000,
HL_CONCEALED = 0x10000,
HL_OVERLINE = 0x20000,
HL_NOCOMBINE = 0x0400,
HL_BG_INDEXED = 0x0800,
HL_FG_INDEXED = 0x1000,
@@ -36,7 +39,7 @@ typedef enum {
/// Stores a complete highlighting entry, including colors and attributes
/// for both TUI and GUI.
typedef struct {
int16_t rgb_ae_attr, cterm_ae_attr; ///< HlAttrFlags
int32_t rgb_ae_attr, cterm_ae_attr; ///< HlAttrFlags
RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
int16_t cterm_fg_color, cterm_bg_color;
int32_t hl_blend;
@@ -175,4 +178,4 @@ typedef struct {
#define COLOR_ITEM_INITIALIZER { .attr_id = -1, .link_id = -1, .version = -1, \
.is_default = false, .link_global = false }
enum { HLATTRS_DICT_SIZE = 16, };
enum { HLATTRS_DICT_SIZE = 20, };

View File

@@ -77,12 +77,12 @@ static char *(hl_name_table[]) =
{ "bold", "standout", "underline",
"undercurl", "underdouble", "underdotted", "underdashed",
"italic", "reverse", "inverse", "strikethrough", "altfont",
"nocombine", "NONE" };
"dim", "blink", "conceal", "overline", "nocombine", "NONE" };
static int hl_attr_table[] =
{ HL_BOLD, HL_STANDOUT, HL_UNDERLINE,
HL_UNDERCURL, HL_UNDERDOUBLE, HL_UNDERDOTTED, HL_UNDERDASHED,
HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_STRIKETHROUGH, HL_ALTFONT,
HL_NOCOMBINE, 0 };
HL_DIM, HL_BLINK, HL_CONCEALED, HL_OVERLINE, HL_NOCOMBINE, 0 };
/// Structure that stores information about a highlight group.
/// The ID of a highlight group is also called group ID. It is the index in
@@ -1951,10 +1951,10 @@ static void set_hl_attr(int idx)
HlAttrs at_en = HLATTRS_INIT;
HlGroup *sgp = hl_table + idx;
at_en.cterm_ae_attr = (int16_t)sgp->sg_cterm;
at_en.cterm_ae_attr = (int32_t)sgp->sg_cterm;
at_en.cterm_fg_color = (int16_t)sgp->sg_cterm_fg;
at_en.cterm_bg_color = (int16_t)sgp->sg_cterm_bg;
at_en.rgb_ae_attr = (int16_t)sgp->sg_gui;
at_en.rgb_ae_attr = (int32_t)sgp->sg_gui;
// FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is
// initialized with 0 (by garray functions), check for sg_rgb_{f,b}g_name
// before setting attr_entry->{f,g}g_color to a other than -1

View File

@@ -1405,6 +1405,8 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te
bool bg_set = vt_bg_idx && vt_bg_idx <= 16 && term->color_set[vt_bg_idx - 1];
int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0)
| (cell.attrs.blink ? HL_BLINK : 0)
| (cell.attrs.conceal ? HL_CONCEALED : 0)
| (cell.attrs.italic ? HL_ITALIC : 0)
| (cell.attrs.reverse ? HL_INVERSE : 0)
| get_underline_hl_flag(cell.attrs)
@@ -1416,10 +1418,10 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te
if (hl_attrs || !fg_default || !bg_default) {
attr_id = hl_get_term_attr(&(HlAttrs) {
.cterm_ae_attr = (int16_t)hl_attrs,
.cterm_ae_attr = (int32_t)hl_attrs,
.cterm_fg_color = vt_fg_idx,
.cterm_bg_color = vt_bg_idx,
.rgb_ae_attr = (int16_t)hl_attrs,
.rgb_ae_attr = (int32_t)hl_attrs,
.rgb_fg_color = vt_fg,
.rgb_bg_color = vt_bg,
.rgb_sp_color = -1,

View File

@@ -28,10 +28,13 @@ static const TerminfoEntry ansi_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = NULL,
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = "\033[8m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -104,10 +107,13 @@ static const TerminfoEntry ghostty_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = NULL,
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = "\033[8m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -243,10 +249,13 @@ static const TerminfoEntry interix_8colour_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = NULL,
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[s\033[1b",
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = NULL,
@@ -379,10 +388,13 @@ static const TerminfoEntry iterm_256colour_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h\033[22;0;0t",
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = NULL,
@@ -479,10 +491,13 @@ static const TerminfoEntry linux_16colour_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = NULL,
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -575,10 +590,13 @@ static const TerminfoEntry putty_256colour_terminfo = {
[kTerm_cursor_up] = "\033M",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -671,10 +689,13 @@ static const TerminfoEntry rxvt_256colour_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\0337\033[?47h",
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = NULL,
@@ -791,10 +812,13 @@ static const TerminfoEntry screen_256colour_terminfo = {
[kTerm_cursor_up] = "\033M",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[3m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = NULL,
@@ -879,10 +903,13 @@ static const TerminfoEntry st_256colour_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = "\033[8m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -1018,10 +1045,13 @@ static const TerminfoEntry tmux_256colour_terminfo = {
[kTerm_cursor_up] = "\033M",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = "\033[8m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = NULL,
@@ -1157,10 +1187,13 @@ static const TerminfoEntry vte_256colour_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h\033[22;0;0t",
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = "\033[8m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -1296,10 +1329,13 @@ static const TerminfoEntry xterm_256colour_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = "\033[5m",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h\033[22;0;0t",
[kTerm_enter_dim_mode] = "\033[2m",
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = "\033[8m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -1435,10 +1471,13 @@ static const TerminfoEntry cygwin_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = NULL,
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\0337\033[?47h",
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = "\033[8m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = NULL,
@@ -1531,10 +1570,13 @@ static const TerminfoEntry win32con_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = NULL,
[kTerm_enter_blink_mode] = NULL,
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\0337\033[?47h",
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = NULL,
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = NULL,
[kTerm_erase_chars] = NULL,
@@ -1651,10 +1693,13 @@ static const TerminfoEntry conemu_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = NULL,
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -1772,10 +1817,13 @@ static const TerminfoEntry vtpcon_terminfo = {
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_blink_mode] = NULL,
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_dim_mode] = NULL,
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_secure_mode] = NULL,
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
@@ -1886,10 +1934,13 @@ static const TerminfoEntry vtpcon_terminfo = {
X(cursor_up) \
X(cursor_right) \
X(delete_line) \
X(enter_blink_mode) \
X(enter_bold_mode) \
X(enter_ca_mode) \
X(enter_dim_mode) \
X(enter_italics_mode) \
X(enter_reverse_mode) \
X(enter_secure_mode) \
X(enter_standout_mode) \
X(enter_underline_mode) \
X(erase_chars) \

View File

@@ -17,10 +17,13 @@ typedef enum {
kTerm_cursor_up,
kTerm_cursor_right,
kTerm_delete_line,
kTerm_enter_blink_mode,
kTerm_enter_bold_mode,
kTerm_enter_ca_mode,
kTerm_enter_dim_mode,
kTerm_enter_italics_mode,
kTerm_enter_reverse_mode,
kTerm_enter_secure_mode,
kTerm_enter_standout_mode,
kTerm_enter_underline_mode,
kTerm_erase_chars,

View File

@@ -752,6 +752,10 @@ static void update_attrs(TUIData *tui, int attr_id)
bool standout = attr & HL_STANDOUT;
bool strikethrough = attr & HL_STRIKETHROUGH;
bool altfont = attr & HL_ALTFONT;
bool dim = attr & HL_DIM;
bool blink = attr & HL_BLINK;
bool conceal = attr & HL_CONCEALED;
bool overline = attr & HL_OVERLINE;
bool underline;
bool undercurl;
@@ -777,13 +781,13 @@ static void update_attrs(TUIData *tui, int attr_id)
|| underdouble || underdotted || underdashed;
if (tui->ti.defs[kTerm_set_attributes] != NULL) {
if (bold || reverse || underline || standout) {
if (bold || dim || blink || reverse || underline || standout) {
TPVAR params[9] = { 0 };
params[0].num = standout;
params[1].num = underline;
params[2].num = reverse;
params[3].num = 0; // blink
params[4].num = 0; // dim
params[3].num = blink;
params[4].num = dim;
params[5].num = bold;
params[6].num = 0; // blank
params[7].num = 0; // protect
@@ -808,6 +812,12 @@ static void update_attrs(TUIData *tui, int attr_id)
if (reverse) {
terminfo_out(tui, kTerm_enter_reverse_mode);
}
if (dim) {
terminfo_out(tui, kTerm_enter_dim_mode);
}
if (blink) {
terminfo_out(tui, kTerm_enter_blink_mode);
}
}
if (italic) {
terminfo_out(tui, kTerm_enter_italics_mode);
@@ -818,6 +828,12 @@ static void update_attrs(TUIData *tui, int attr_id)
if (strikethrough) {
terminfo_out(tui, kTerm_enter_strikethrough_mode);
}
if (conceal) {
terminfo_out(tui, kTerm_enter_secure_mode);
}
if (overline) {
out(tui, S_LEN("\x1b[53m"));
}
if (tui->ti.defs[kTerm_set_underline_style]) {
if (undercurl) {
terminfo_print_num1(tui, kTerm_set_underline_style, 3);
@@ -898,14 +914,14 @@ static void update_attrs(TUIData *tui, int attr_id)
}
tui->default_attr = fg == -1 && bg == -1
&& !bold && !italic && !has_any_underline && !reverse && !standout
&& !strikethrough;
&& !bold && !dim && !blink && !conceal && !overline && !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.
tui->can_clear_attr = !reverse && !standout && !has_any_underline
&& !strikethrough && (tui->bce || bg == -1);
tui->can_clear_attr = !reverse && !standout && !dim && !blink && !conceal && !overline
&& !has_any_underline && !strikethrough && (tui->bce || bg == -1);
}
static void final_column_wrap(TUIData *tui)

View File

@@ -46,11 +46,19 @@ describe('API: set highlight', function()
underdashed = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
cterm = {
italic = true,
reverse = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
nocombine = true,
},
}
@@ -63,6 +71,10 @@ describe('API: set highlight', function()
underdashed = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
}
local highlight3_result_cterm = {
ctermbg = highlight_color.ctermbg,
@@ -71,6 +83,10 @@ describe('API: set highlight', function()
reverse = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
nocombine = true,
}
@@ -172,7 +188,7 @@ describe('API: set highlight', function()
api.nvim_set_hl(0, 'Test_hl2', highlight3_config)
eq(
'Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,nocombine ctermfg=8 ctermbg=15 gui=bold,underdashed,italic,reverse,strikethrough,altfont guifg=#ff0000 guibg=#0032aa',
'Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,dim,blink,conceal,overline,nocombine ctermfg=8 ctermbg=15 gui=bold,underdashed,italic,reverse,strikethrough,altfont,dim,blink,conceal,overline guifg=#ff0000 guibg=#0032aa',
exec_capture('highlight Test_hl2')
)
@@ -272,11 +288,19 @@ describe('API: get highlight', function()
underdashed = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
cterm = {
italic = true,
reverse = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
nocombine = true,
},
}
@@ -291,12 +315,20 @@ describe('API: get highlight', function()
underdashed = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
cterm = {
italic = true,
nocombine = true,
reverse = true,
strikethrough = true,
altfont = true,
dim = true,
blink = true,
conceal = true,
overline = true,
},
}
@@ -438,15 +470,21 @@ describe('API: get highlight', function()
)
-- Test all highlight properties.
command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
command(
'hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,dim,blink,conceal,overline,nocombine'
)
eq({
fg = 16711680,
bg = 16776960,
sp = 255,
altfont = true,
blink = true,
bold = true,
conceal = true,
dim = true,
italic = true,
nocombine = true,
overline = true,
reverse = true,
strikethrough = true,
underline = true,