Merge pull request #19039 from bfredl/multicolor

perf: get rid of unnecessary allocations in highlight groups
This commit is contained in:
bfredl
2022-06-22 10:49:36 +02:00
committed by GitHub
10 changed files with 297 additions and 269 deletions

View File

@@ -686,10 +686,7 @@ Dictionary arena_dict(Arena *arena, size_t max_size)
String arena_string(Arena *arena, String str) String arena_string(Arena *arena, String str)
{ {
if (str.size) { if (str.size) {
char *mem = arena_alloc(arena, str.size + 1, false); return cbuf_as_string(arena_memdupz(arena, str.data, str.size), str.size);
memcpy(mem, str.data, str.size);
mem[str.size] = NUL;
return cbuf_as_string(mem, str.size);
} else { } else {
return (String)STRING_INIT; return (String)STRING_INIT;
} }

View File

@@ -1293,7 +1293,8 @@ void nvim_unsubscribe(uint64_t channel_id, String event)
Integer nvim_get_color_by_name(String name) Integer nvim_get_color_by_name(String name)
FUNC_API_SINCE(1) FUNC_API_SINCE(1)
{ {
return name_to_color(name.data); int dummy;
return name_to_color(name.data, &dummy);
} }
/// Returns a map of color names and RGB values. /// Returns a map of color names and RGB values.

View File

@@ -43,43 +43,45 @@ cursorentry_T shape_table[SHAPE_IDX_COUNT] =
}; };
/// Converts cursor_shapes into an Array of Dictionaries /// Converts cursor_shapes into an Array of Dictionaries
/// @param arena initialized arena where memory will be alocated
///
/// @return Array of the form {[ "cursor_shape": ... ], ...} /// @return Array of the form {[ "cursor_shape": ... ], ...}
Array mode_style_array(void) Array mode_style_array(Arena *arena)
{ {
Array all = ARRAY_DICT_INIT; Array all = arena_array(arena, SHAPE_IDX_COUNT);
for (int i = 0; i < SHAPE_IDX_COUNT; i++) { for (int i = 0; i < SHAPE_IDX_COUNT; i++) {
Dictionary dic = ARRAY_DICT_INIT;
cursorentry_T *cur = &shape_table[i]; cursorentry_T *cur = &shape_table[i];
Dictionary dic = arena_dict(arena, 3 + ((cur->used_for & SHAPE_CURSOR) ? 9 : 0));
PUT_C(dic, "name", STRING_OBJ(cstr_as_string(cur->full_name)));
PUT_C(dic, "short_name", STRING_OBJ(cstr_as_string(cur->name)));
if (cur->used_for & SHAPE_MOUSE) { if (cur->used_for & SHAPE_MOUSE) {
PUT(dic, "mouse_shape", INTEGER_OBJ(cur->mshape)); PUT_C(dic, "mouse_shape", INTEGER_OBJ(cur->mshape));
} }
if (cur->used_for & SHAPE_CURSOR) { if (cur->used_for & SHAPE_CURSOR) {
String shape_str; String shape_str;
switch (cur->shape) { switch (cur->shape) {
case SHAPE_BLOCK: case SHAPE_BLOCK:
shape_str = cstr_to_string("block"); break; shape_str = cstr_as_string("block"); break;
case SHAPE_VER: case SHAPE_VER:
shape_str = cstr_to_string("vertical"); break; shape_str = cstr_as_string("vertical"); break;
case SHAPE_HOR: case SHAPE_HOR:
shape_str = cstr_to_string("horizontal"); break; shape_str = cstr_as_string("horizontal"); break;
default: default:
shape_str = cstr_to_string("unknown"); shape_str = cstr_as_string("unknown");
} }
PUT(dic, "cursor_shape", STRING_OBJ(shape_str)); PUT_C(dic, "cursor_shape", STRING_OBJ(shape_str));
PUT(dic, "cell_percentage", INTEGER_OBJ(cur->percentage)); PUT_C(dic, "cell_percentage", INTEGER_OBJ(cur->percentage));
PUT(dic, "blinkwait", INTEGER_OBJ(cur->blinkwait)); PUT_C(dic, "blinkwait", INTEGER_OBJ(cur->blinkwait));
PUT(dic, "blinkon", INTEGER_OBJ(cur->blinkon)); PUT_C(dic, "blinkon", INTEGER_OBJ(cur->blinkon));
PUT(dic, "blinkoff", INTEGER_OBJ(cur->blinkoff)); PUT_C(dic, "blinkoff", INTEGER_OBJ(cur->blinkoff));
PUT(dic, "hl_id", INTEGER_OBJ(cur->id)); PUT_C(dic, "hl_id", INTEGER_OBJ(cur->id));
PUT(dic, "id_lm", INTEGER_OBJ(cur->id_lm)); PUT_C(dic, "id_lm", INTEGER_OBJ(cur->id_lm));
PUT(dic, "attr_id", INTEGER_OBJ(cur->id ? syn_id2attr(cur->id) : 0)); PUT_C(dic, "attr_id", INTEGER_OBJ(cur->id ? syn_id2attr(cur->id) : 0));
PUT(dic, "attr_id_lm", INTEGER_OBJ(cur->id_lm ? syn_id2attr(cur->id_lm) : 0)); PUT_C(dic, "attr_id_lm", INTEGER_OBJ(cur->id_lm ? syn_id2attr(cur->id_lm) : 0));
} }
PUT(dic, "name", STRING_OBJ(cstr_to_string(cur->full_name)));
PUT(dic, "short_name", STRING_OBJ(cstr_to_string(cur->name)));
ADD(all, DICTIONARY_OBJ(dic)); ADD_C(all, DICTIONARY_OBJ(dic));
} }
return all; return all;

View File

@@ -392,7 +392,7 @@ static uint32_t prt_get_color(int hl_id, int modec)
const char *color = highlight_color(hl_id, "fg#", 'g'); const char *color = highlight_color(hl_id, "fg#", 'g');
if (color != NULL) { if (color != NULL) {
RgbValue rgb = name_to_color(color); RgbValue rgb = name_to_color(color, &colorindex);
if (rgb != -1) { if (rgb != -1) {
return (uint32_t)rgb; return (uint32_t)rgb;
} }

View File

@@ -962,7 +962,8 @@ int object_to_color(Object val, char *key, bool rgb, Error *err)
} }
int color; int color;
if (rgb) { if (rgb) {
color = name_to_color(str.data); int dummy;
color = name_to_color(str.data, &dummy);
} else { } else {
color = name_to_ctermcolor(str.data); color = name_to_ctermcolor(str.data);
} }

View File

@@ -30,6 +30,9 @@
// builtin |highlight-groups| // builtin |highlight-groups|
static garray_T highlight_ga = GA_EMPTY_INIT_VALUE; static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
// arena for object with same lifetime as highlight_ga (aka hl_table)
Arena highlight_arena = ARENA_EMPTY;
Map(cstr_t, int) highlight_unames = MAP_INIT; Map(cstr_t, int) highlight_unames = MAP_INIT;
/// The "term", "cterm" and "gui" arguments can be any combination of the /// The "term", "cterm" and "gui" arguments can be any combination of the
@@ -66,21 +69,25 @@ typedef struct {
RgbValue sg_rgb_fg; ///< RGB foreground color RgbValue sg_rgb_fg; ///< RGB foreground color
RgbValue sg_rgb_bg; ///< RGB background color RgbValue sg_rgb_bg; ///< RGB background color
RgbValue sg_rgb_sp; ///< RGB special color RgbValue sg_rgb_sp; ///< RGB special color
char *sg_rgb_fg_name; ///< RGB foreground color name int sg_rgb_fg_idx; ///< RGB foreground color index
char *sg_rgb_bg_name; ///< RGB background color name int sg_rgb_bg_idx; ///< RGB background color index
char *sg_rgb_sp_name; ///< RGB special color name int sg_rgb_sp_idx; ///< RGB special color index
int sg_blend; ///< blend level (0-100 inclusive), -1 if unset int sg_blend; ///< blend level (0-100 inclusive), -1 if unset
} HlGroup; } HlGroup;
enum {
kColorIdxNone = -1,
kColorIdxHex = -2,
kColorIdxFg = -3,
kColorIdxBg = -4,
};
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "highlight_group.c.generated.h" # include "highlight_group.c.generated.h"
#endif #endif
static inline HlGroup *HL_TABLE(void) #define hl_table ((HlGroup *)((highlight_ga.ga_data)))
{
return ((HlGroup *)((highlight_ga.ga_data)));
}
// The default highlight groups. These are compiled-in for fast startup and // The default highlight groups. These are compiled-in for fast startup and
// they still work when the runtime files can't be found. // they still work when the runtime files can't be found.
@@ -464,13 +471,13 @@ int highlight_num_groups(void)
/// Returns the name of a highlight group. /// Returns the name of a highlight group.
char_u *highlight_group_name(int id) char_u *highlight_group_name(int id)
{ {
return HL_TABLE()[id].sg_name; return hl_table[id].sg_name;
} }
/// Returns the ID of the link to a highlight group. /// Returns the ID of the link to a highlight group.
int highlight_link_id(int id) int highlight_link_id(int id)
{ {
return HL_TABLE()[id].sg_link; return hl_table[id].sg_link;
} }
/// Create default links for Nvim* highlight groups used for cmdline coloring /// Create default links for Nvim* highlight groups used for cmdline coloring
@@ -673,7 +680,7 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id)
return; return;
} }
HlGroup *g = &HL_TABLE()[idx]; HlGroup *g = &hl_table[idx];
if (link_id > 0) { if (link_id > 0) {
g->sg_cleared = false; g->sg_cleared = false;
@@ -698,34 +705,21 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id)
g->sg_rgb_sp = attrs.rgb_sp_color; g->sg_rgb_sp = attrs.rgb_sp_color;
struct { struct {
char **dest; RgbValue val; Object name; int *dest; RgbValue val; Object name;
} cattrs[] = { } cattrs[] = {
{ &g->sg_rgb_fg_name, g->sg_rgb_fg, HAS_KEY(dict->fg) ? dict->fg : dict->foreground }, { &g->sg_rgb_fg_idx, g->sg_rgb_fg, HAS_KEY(dict->fg) ? dict->fg : dict->foreground },
{ &g->sg_rgb_bg_name, g->sg_rgb_bg, HAS_KEY(dict->bg) ? dict->bg : dict->background }, { &g->sg_rgb_bg_idx, g->sg_rgb_bg, HAS_KEY(dict->bg) ? dict->bg : dict->background },
{ &g->sg_rgb_sp_name, g->sg_rgb_sp, HAS_KEY(dict->sp) ? dict->sp : dict->special }, { &g->sg_rgb_sp_idx, g->sg_rgb_sp, HAS_KEY(dict->sp) ? dict->sp : dict->special },
{ NULL, -1, NIL }, { NULL, -1, NIL },
}; };
char hex_name[8];
char *name;
for (int j = 0; cattrs[j].dest; j++) { for (int j = 0; cattrs[j].dest; j++) {
if (cattrs[j].val < 0) { if (cattrs[j].val < 0) {
XFREE_CLEAR(*cattrs[j].dest); *cattrs[j].dest = kColorIdxNone;
continue; } else if (cattrs[j].name.type == kObjectTypeString && cattrs[j].name.data.string.size) {
} name_to_color(cattrs[j].name.data.string.data, cattrs[j].dest);
if (cattrs[j].name.type == kObjectTypeString && cattrs[j].name.data.string.size) {
name = cattrs[j].name.data.string.data;
} else { } else {
snprintf(hex_name, sizeof(hex_name), "#%06x", cattrs[j].val); *cattrs[j].dest = kColorIdxHex;
name = hex_name;
}
if (!*cattrs[j].dest
|| STRCMP(*cattrs[j].dest, name) != 0) {
xfree(*cattrs[j].dest);
*cattrs[j].dest = xstrdup(name);
} }
} }
@@ -860,7 +854,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
} }
if (from_id > 0) { if (from_id > 0) {
hlgroup = &HL_TABLE()[from_id - 1]; hlgroup = &hl_table[from_id - 1];
if (dodefault && (forceit || hlgroup->sg_deflink == 0)) { if (dodefault && (forceit || hlgroup->sg_deflink == 0)) {
hlgroup->sg_deflink = to_id; hlgroup->sg_deflink = to_id;
hlgroup->sg_deflink_sctx = current_sctx; hlgroup->sg_deflink_sctx = current_sctx;
@@ -931,19 +925,19 @@ void do_highlight(const char *line, const bool forceit, const bool init)
} }
// Make a copy so we can check if any attribute actually changed // Make a copy so we can check if any attribute actually changed
item_before = HL_TABLE()[idx]; item_before = hl_table[idx];
is_normal_group = (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0); is_normal_group = (STRCMP(hl_table[idx].sg_name_u, "NORMAL") == 0);
// Clear the highlighting for ":hi clear {group}" and ":hi clear". // Clear the highlighting for ":hi clear {group}" and ":hi clear".
if (doclear || (forceit && init)) { if (doclear || (forceit && init)) {
highlight_clear(idx); highlight_clear(idx);
if (!doclear) { if (!doclear) {
HL_TABLE()[idx].sg_set = 0; hl_table[idx].sg_set = 0;
} }
} }
char *key = NULL; char key[64];
char *arg = NULL; char arg[512];
if (!doclear) { if (!doclear) {
while (!ends_excmd((uint8_t)(*linep))) { while (!ends_excmd((uint8_t)(*linep))) {
key_start = linep; key_start = linep;
@@ -958,15 +952,21 @@ void do_highlight(const char *line, const bool forceit, const bool init)
while (*linep && !ascii_iswhite(*linep) && *linep != '=') { while (*linep && !ascii_iswhite(*linep) && *linep != '=') {
linep++; linep++;
} }
xfree(key); size_t key_len = (size_t)(linep - key_start);
key = (char *)vim_strnsave_up((const char_u *)key_start, if (key_len > sizeof key - 1) {
(size_t)(linep - key_start)); semsg(_("E423: Illegal argument"));
error = true;
break;
}
memcpy(key, key_start, key_len);
key[key_len] = NUL;
vim_strup((char_u *)key);
linep = (const char *)skipwhite(linep); linep = (const char *)skipwhite(linep);
if (strcmp(key, "NONE") == 0) { if (strcmp(key, "NONE") == 0) {
if (!init || HL_TABLE()[idx].sg_set == 0) { if (!init || hl_table[idx].sg_set == 0) {
if (!init) { if (!init) {
HL_TABLE()[idx].sg_set |= SG_CTERM + SG_GUI; hl_table[idx].sg_set |= SG_CTERM + SG_GUI;
} }
highlight_clear(idx); highlight_clear(idx);
} }
@@ -1000,8 +1000,14 @@ void do_highlight(const char *line, const bool forceit, const bool init)
error = true; error = true;
break; break;
} }
xfree(arg); size_t arg_len = (size_t)(linep - arg_start);
arg = xstrndup(arg_start, (size_t)(linep - arg_start)); if (arg_len > sizeof arg - 1) {
semsg(_("E423: Illegal argument"));
error = true;
break;
}
memcpy(arg, arg_start, arg_len);
arg[arg_len] = NUL;
if (*linep == '\'') { if (*linep == '\'') {
linep++; linep++;
@@ -1036,34 +1042,34 @@ void do_highlight(const char *line, const bool forceit, const bool init)
break; break;
} }
if (*key == 'C') { if (*key == 'C') {
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) { if (!init || !(hl_table[idx].sg_set & SG_CTERM)) {
if (!init) { if (!init) {
HL_TABLE()[idx].sg_set |= SG_CTERM; hl_table[idx].sg_set |= SG_CTERM;
} }
HL_TABLE()[idx].sg_cterm = attr; hl_table[idx].sg_cterm = attr;
HL_TABLE()[idx].sg_cterm_bold = false; hl_table[idx].sg_cterm_bold = false;
} }
} else if (*key == 'G') { } else if (*key == 'G') {
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) { if (!init || !(hl_table[idx].sg_set & SG_GUI)) {
if (!init) { if (!init) {
HL_TABLE()[idx].sg_set |= SG_GUI; hl_table[idx].sg_set |= SG_GUI;
} }
HL_TABLE()[idx].sg_gui = attr; hl_table[idx].sg_gui = attr;
} }
} }
} else if (STRCMP(key, "FONT") == 0) { } else if (STRCMP(key, "FONT") == 0) {
// in non-GUI fonts are simply ignored // in non-GUI fonts are simply ignored
} else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) { } else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) { if (!init || !(hl_table[idx].sg_set & SG_CTERM)) {
if (!init) { if (!init) {
HL_TABLE()[idx].sg_set |= SG_CTERM; hl_table[idx].sg_set |= SG_CTERM;
} }
// When setting the foreground color, and previously the "bold" // When setting the foreground color, and previously the "bold"
// flag was set for a light color, reset it now // flag was set for a light color, reset it now
if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold) { if (key[5] == 'F' && hl_table[idx].sg_cterm_bold) {
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD; hl_table[idx].sg_cterm &= ~HL_BOLD;
HL_TABLE()[idx].sg_cterm_bold = false; hl_table[idx].sg_cterm_bold = false;
} }
if (ascii_isdigit(*arg)) { if (ascii_isdigit(*arg)) {
@@ -1107,21 +1113,21 @@ void do_highlight(const char *line, const bool forceit, const bool init)
// set/reset bold attribute to get light foreground // set/reset bold attribute to get light foreground
// colors (on some terminals, e.g. "linux") // colors (on some terminals, e.g. "linux")
if (bold == kTrue) { if (bold == kTrue) {
HL_TABLE()[idx].sg_cterm |= HL_BOLD; hl_table[idx].sg_cterm |= HL_BOLD;
HL_TABLE()[idx].sg_cterm_bold = true; hl_table[idx].sg_cterm_bold = true;
} else if (bold == kFalse) { } else if (bold == kFalse) {
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD; hl_table[idx].sg_cterm &= ~HL_BOLD;
} }
} }
// Add one to the argument, to avoid zero. Zero is used for // Add one to the argument, to avoid zero. Zero is used for
// "NONE", then "color" is -1. // "NONE", then "color" is -1.
if (key[5] == 'F') { if (key[5] == 'F') {
HL_TABLE()[idx].sg_cterm_fg = color + 1; hl_table[idx].sg_cterm_fg = color + 1;
if (is_normal_group) { if (is_normal_group) {
cterm_normal_fg_color = color + 1; cterm_normal_fg_color = color + 1;
} }
} else { } else {
HL_TABLE()[idx].sg_cterm_bg = color + 1; hl_table[idx].sg_cterm_bg = color + 1;
if (is_normal_group) { if (is_normal_group) {
cterm_normal_bg_color = color + 1; cterm_normal_bg_color = color + 1;
if (!ui_rgb_attached()) { if (!ui_rgb_attached()) {
@@ -1148,95 +1154,94 @@ void do_highlight(const char *line, const bool forceit, const bool init)
} }
} }
} else if (strcmp(key, "GUIFG") == 0) { } else if (strcmp(key, "GUIFG") == 0) {
char **namep = &HL_TABLE()[idx].sg_rgb_fg_name; int *indexp = &hl_table[idx].sg_rgb_fg_idx;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) { if (!init || !(hl_table[idx].sg_set & SG_GUI)) {
if (!init) { if (!init) {
HL_TABLE()[idx].sg_set |= SG_GUI; hl_table[idx].sg_set |= SG_GUI;
} }
if (*namep == NULL || STRCMP(*namep, arg) != 0) { RgbValue old_color = hl_table[idx].sg_rgb_fg;
xfree(*namep); int old_idx = hl_table[idx].sg_rgb_fg_idx;
if (strcmp(arg, "NONE") != 0) {
*namep = xstrdup(arg); if (strcmp(arg, "NONE") != 0) {
HL_TABLE()[idx].sg_rgb_fg = name_to_color(arg); hl_table[idx].sg_rgb_fg = name_to_color(arg, indexp);
} else { } else {
*namep = NULL; hl_table[idx].sg_rgb_fg = -1;
HL_TABLE()[idx].sg_rgb_fg = -1; hl_table[idx].sg_rgb_fg_idx = kColorIdxNone;
}
did_change = true;
} }
did_change = hl_table[idx].sg_rgb_fg != old_color || hl_table[idx].sg_rgb_fg != old_idx;
} }
if (is_normal_group) { if (is_normal_group) {
normal_fg = HL_TABLE()[idx].sg_rgb_fg; normal_fg = hl_table[idx].sg_rgb_fg;
} }
} else if (STRCMP(key, "GUIBG") == 0) { } else if (STRCMP(key, "GUIBG") == 0) {
char **const namep = &HL_TABLE()[idx].sg_rgb_bg_name; int *indexp = &hl_table[idx].sg_rgb_bg_idx;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) { if (!init || !(hl_table[idx].sg_set & SG_GUI)) {
if (!init) { if (!init) {
HL_TABLE()[idx].sg_set |= SG_GUI; hl_table[idx].sg_set |= SG_GUI;
} }
if (*namep == NULL || STRCMP(*namep, arg) != 0) { RgbValue old_color = hl_table[idx].sg_rgb_bg;
xfree(*namep); int old_idx = hl_table[idx].sg_rgb_bg_idx;
if (STRCMP(arg, "NONE") != 0) {
*namep = xstrdup(arg); if (STRCMP(arg, "NONE") != 0) {
HL_TABLE()[idx].sg_rgb_bg = name_to_color(arg); hl_table[idx].sg_rgb_bg = name_to_color(arg, indexp);
} else { } else {
*namep = NULL; hl_table[idx].sg_rgb_bg = -1;
HL_TABLE()[idx].sg_rgb_bg = -1; hl_table[idx].sg_rgb_bg_idx = kColorIdxNone;
}
did_change = true;
} }
did_change = hl_table[idx].sg_rgb_bg != old_color || hl_table[idx].sg_rgb_bg != old_idx;
} }
if (is_normal_group) { if (is_normal_group) {
normal_bg = HL_TABLE()[idx].sg_rgb_bg; normal_bg = hl_table[idx].sg_rgb_bg;
} }
} else if (strcmp(key, "GUISP") == 0) { } else if (strcmp(key, "GUISP") == 0) {
char **const namep = &HL_TABLE()[idx].sg_rgb_sp_name; int *indexp = &hl_table[idx].sg_rgb_sp_idx;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) { if (!init || !(hl_table[idx].sg_set & SG_GUI)) {
if (!init) { if (!init) {
HL_TABLE()[idx].sg_set |= SG_GUI; hl_table[idx].sg_set |= SG_GUI;
} }
if (*namep == NULL || STRCMP(*namep, arg) != 0) { RgbValue old_color = hl_table[idx].sg_rgb_sp;
xfree(*namep); int old_idx = hl_table[idx].sg_rgb_sp_idx;
if (strcmp(arg, "NONE") != 0) {
*namep = xstrdup(arg); if (strcmp(arg, "NONE") != 0) {
HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg); hl_table[idx].sg_rgb_sp = name_to_color(arg, indexp);
} else { } else {
*namep = NULL; hl_table[idx].sg_rgb_sp = -1;
HL_TABLE()[idx].sg_rgb_sp = -1;
}
did_change = true;
} }
did_change = hl_table[idx].sg_rgb_sp != old_color || hl_table[idx].sg_rgb_sp != old_idx;
} }
if (is_normal_group) { if (is_normal_group) {
normal_sp = HL_TABLE()[idx].sg_rgb_sp; normal_sp = hl_table[idx].sg_rgb_sp;
} }
} else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) { } else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) {
// Ignored for now // Ignored for now
} else if (strcmp(key, "BLEND") == 0) { } else if (strcmp(key, "BLEND") == 0) {
if (strcmp(arg, "NONE") != 0) { if (strcmp(arg, "NONE") != 0) {
HL_TABLE()[idx].sg_blend = (int)strtol(arg, NULL, 10); hl_table[idx].sg_blend = (int)strtol(arg, NULL, 10);
} else { } else {
HL_TABLE()[idx].sg_blend = -1; hl_table[idx].sg_blend = -1;
} }
} else { } else {
semsg(_("E423: Illegal argument: %s"), key_start); semsg(_("E423: Illegal argument: %s"), key_start);
error = true; error = true;
break; break;
} }
HL_TABLE()[idx].sg_cleared = false; hl_table[idx].sg_cleared = false;
// When highlighting has been given for a group, don't link it. // When highlighting has been given for a group, don't link it.
if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK)) { if (!init || !(hl_table[idx].sg_set & SG_LINK)) {
HL_TABLE()[idx].sg_link = 0; hl_table[idx].sg_link = 0;
} }
// Continue with next argument. // Continue with next argument.
@@ -1244,40 +1249,33 @@ void do_highlight(const char *line, const bool forceit, const bool init)
} }
} }
// If there is an error, and it's a new entry, remove it from the table. if (!error && is_normal_group) {
if (error && idx == highlight_ga.ga_len) { // Need to update all groups, because they might be using "bg" and/or
syn_unadd_group(); // "fg", which have been changed now.
} else { highlight_attr_set_all();
if (!error && is_normal_group) {
// Need to update all groups, because they might be using "bg" and/or
// "fg", which have been changed now.
highlight_attr_set_all();
if (!ui_has(kUILinegrid) && starting == 0) { if (!ui_has(kUILinegrid) && starting == 0) {
// Older UIs assume that we clear the screen after normal group is // Older UIs assume that we clear the screen after normal group is
// changed // changed
ui_refresh(); ui_refresh();
} else {
// TUI and newer UIs will repaint the screen themselves. NOT_VALID
// redraw below will still handle usages of guibg=fg etc.
ui_default_colors_set();
}
did_highlight_changed = true;
redraw_all_later(NOT_VALID);
} else { } else {
set_hl_attr(idx); // TUI and newer UIs will repaint the screen themselves. NOT_VALID
// redraw below will still handle usages of guibg=fg etc.
ui_default_colors_set();
} }
HL_TABLE()[idx].sg_script_ctx = current_sctx; did_highlight_changed = true;
HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum; redraw_all_later(NOT_VALID);
nlua_set_sctx(&HL_TABLE()[idx].sg_script_ctx); } else {
set_hl_attr(idx);
} }
xfree(key); hl_table[idx].sg_script_ctx = current_sctx;
xfree(arg); hl_table[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
nlua_set_sctx(&hl_table[idx].sg_script_ctx);
// Only call highlight_changed() once, after a sequence of highlight // Only call highlight_changed() once, after a sequence of highlight
// commands, and only if an attribute actually changed // commands, and only if an attribute actually changed
if ((did_change if ((did_change
|| memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0) || memcmp(&hl_table[idx], &item_before, sizeof(item_before)) != 0)
&& !did_highlight_changed) { && !did_highlight_changed) {
// Do not trigger a redraw when highlighting is changed while // Do not trigger a redraw when highlighting is changed while
// redrawing. This may happen when evaluating 'statusline' changes the // redrawing. This may happen when evaluating 'statusline' changes the
@@ -1292,13 +1290,9 @@ void do_highlight(const char *line, const bool forceit, const bool init)
#if defined(EXITFREE) #if defined(EXITFREE)
void free_highlight(void) void free_highlight(void)
{ {
for (int i = 0; i < highlight_ga.ga_len; i++) {
highlight_clear(i);
xfree(HL_TABLE()[i].sg_name);
xfree(HL_TABLE()[i].sg_name_u);
}
ga_clear(&highlight_ga); ga_clear(&highlight_ga);
map_destroy(cstr_t, int)(&highlight_unames); map_destroy(cstr_t, int)(&highlight_unames);
arena_mem_free(arena_finish(&highlight_arena), NULL);
} }
#endif #endif
@@ -1319,39 +1313,39 @@ void restore_cterm_colors(void)
/// @return TRUE if highlight group "idx" has any settings. /// @return TRUE if highlight group "idx" has any settings.
static int hl_has_settings(int idx, bool check_link) static int hl_has_settings(int idx, bool check_link)
{ {
return HL_TABLE()[idx].sg_cleared == 0 return hl_table[idx].sg_cleared == 0
&& (HL_TABLE()[idx].sg_attr != 0 && (hl_table[idx].sg_attr != 0
|| HL_TABLE()[idx].sg_cterm_fg != 0 || hl_table[idx].sg_cterm_fg != 0
|| HL_TABLE()[idx].sg_cterm_bg != 0 || hl_table[idx].sg_cterm_bg != 0
|| HL_TABLE()[idx].sg_rgb_fg_name != NULL || hl_table[idx].sg_rgb_fg_idx != kColorIdxNone
|| HL_TABLE()[idx].sg_rgb_bg_name != NULL || hl_table[idx].sg_rgb_bg_idx != kColorIdxNone
|| HL_TABLE()[idx].sg_rgb_sp_name != NULL || hl_table[idx].sg_rgb_sp_idx != kColorIdxNone
|| (check_link && (HL_TABLE()[idx].sg_set & SG_LINK))); || (check_link && (hl_table[idx].sg_set & SG_LINK)));
} }
/// Clear highlighting for one group. /// Clear highlighting for one group.
static void highlight_clear(int idx) static void highlight_clear(int idx)
{ {
HL_TABLE()[idx].sg_cleared = true; hl_table[idx].sg_cleared = true;
HL_TABLE()[idx].sg_attr = 0; hl_table[idx].sg_attr = 0;
HL_TABLE()[idx].sg_cterm = 0; hl_table[idx].sg_cterm = 0;
HL_TABLE()[idx].sg_cterm_bold = false; hl_table[idx].sg_cterm_bold = false;
HL_TABLE()[idx].sg_cterm_fg = 0; hl_table[idx].sg_cterm_fg = 0;
HL_TABLE()[idx].sg_cterm_bg = 0; hl_table[idx].sg_cterm_bg = 0;
HL_TABLE()[idx].sg_gui = 0; hl_table[idx].sg_gui = 0;
HL_TABLE()[idx].sg_rgb_fg = -1; hl_table[idx].sg_rgb_fg = -1;
HL_TABLE()[idx].sg_rgb_bg = -1; hl_table[idx].sg_rgb_bg = -1;
HL_TABLE()[idx].sg_rgb_sp = -1; hl_table[idx].sg_rgb_sp = -1;
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_fg_name); hl_table[idx].sg_rgb_fg_idx = kColorIdxNone;
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name); hl_table[idx].sg_rgb_bg_idx = kColorIdxNone;
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name); hl_table[idx].sg_rgb_sp_idx = kColorIdxNone;
HL_TABLE()[idx].sg_blend = -1; hl_table[idx].sg_blend = -1;
// Restore default link and context if they exist. Otherwise clears. // Restore default link and context if they exist. Otherwise clears.
HL_TABLE()[idx].sg_link = HL_TABLE()[idx].sg_deflink; hl_table[idx].sg_link = hl_table[idx].sg_deflink;
// Since we set the default link, set the location to where the default // Since we set the default link, set the location to where the default
// link was set. // link was set.
HL_TABLE()[idx].sg_script_ctx = HL_TABLE()[idx].sg_deflink_sctx; hl_table[idx].sg_script_ctx = hl_table[idx].sg_deflink_sctx;
} }
/// \addtogroup LIST_XXX /// \addtogroup LIST_XXX
@@ -1363,7 +1357,7 @@ static void highlight_clear(int idx)
static void highlight_list_one(const int id) static void highlight_list_one(const int id)
{ {
const HlGroup *sgp = &HL_TABLE()[id - 1]; // index is ID minus one const HlGroup *sgp = &hl_table[id - 1]; // index is ID minus one
bool didh = false; bool didh = false;
if (message_filtered(sgp->sg_name)) { if (message_filtered(sgp->sg_name)) {
@@ -1379,12 +1373,13 @@ static void highlight_list_one(const int id)
didh = highlight_list_arg(id, didh, LIST_ATTR, didh = highlight_list_arg(id, didh, LIST_ATTR,
sgp->sg_gui, NULL, "gui"); sgp->sg_gui, NULL, "gui");
didh = highlight_list_arg(id, didh, LIST_STRING, char hexbuf[8];
0, sgp->sg_rgb_fg_name, "guifg"); didh = highlight_list_arg(id, didh, LIST_STRING, 0,
didh = highlight_list_arg(id, didh, LIST_STRING, coloridx_to_name(sgp->sg_rgb_fg_idx, sgp->sg_rgb_fg, hexbuf), "guifg");
0, sgp->sg_rgb_bg_name, "guibg"); didh = highlight_list_arg(id, didh, LIST_STRING, 0,
didh = highlight_list_arg(id, didh, LIST_STRING, coloridx_to_name(sgp->sg_rgb_bg_idx, sgp->sg_rgb_bg, hexbuf), "guibg");
0, sgp->sg_rgb_sp_name, "guisp"); didh = highlight_list_arg(id, didh, LIST_STRING, 0,
coloridx_to_name(sgp->sg_rgb_sp_idx, sgp->sg_rgb_sp, hexbuf), "guisp");
didh = highlight_list_arg(id, didh, LIST_INT, didh = highlight_list_arg(id, didh, LIST_INT,
sgp->sg_blend + 1, NULL, "blend"); sgp->sg_blend + 1, NULL, "blend");
@@ -1394,7 +1389,7 @@ static void highlight_list_one(const int id)
didh = true; didh = true;
msg_puts_attr("links to", HL_ATTR(HLF_D)); msg_puts_attr("links to", HL_ATTR(HLF_D));
msg_putchar(' '); msg_putchar(' ');
msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name); msg_outtrans(hl_table[hl_table[id - 1].sg_link - 1].sg_name);
} }
if (!didh) { if (!didh) {
@@ -1410,11 +1405,11 @@ Dictionary get_global_hl_defs(void)
Dictionary rv = ARRAY_DICT_INIT; Dictionary rv = ARRAY_DICT_INIT;
for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) { for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
Dictionary attrs = ARRAY_DICT_INIT; Dictionary attrs = ARRAY_DICT_INIT;
HlGroup *h = &HL_TABLE()[i - 1]; HlGroup *h = &hl_table[i - 1];
if (h->sg_attr > 0) { if (h->sg_attr > 0) {
attrs = hlattrs2dict(syn_attr2entry(h->sg_attr), true); attrs = hlattrs2dict(syn_attr2entry(h->sg_attr), true);
} else if (h->sg_link > 0) { } else if (h->sg_link > 0) {
const char *link = (const char *)HL_TABLE()[h->sg_link - 1].sg_name; const char *link = (const char *)hl_table[h->sg_link - 1].sg_name;
PUT(attrs, "link", STRING_OBJ(cstr_to_string(link))); PUT(attrs, "link", STRING_OBJ(cstr_to_string(link)));
} }
PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs)); PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs));
@@ -1428,7 +1423,7 @@ Dictionary get_global_hl_defs(void)
/// @param type one of \ref LIST_XXX /// @param type one of \ref LIST_XXX
/// @param iarg integer argument used if \p type == LIST_INT /// @param iarg integer argument used if \p type == LIST_INT
/// @param sarg string used if \p type == LIST_STRING /// @param sarg string used if \p type == LIST_STRING
static bool highlight_list_arg(const int id, bool didh, const int type, int iarg, char *const sarg, static bool highlight_list_arg(const int id, bool didh, const int type, int iarg, const char *sarg,
const char *const name) const char *const name)
{ {
char buf[100]; char buf[100];
@@ -1437,7 +1432,7 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg
return false; return false;
} }
if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0)) { if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0)) {
char *ts = buf; const char *ts = buf;
if (type == LIST_INT) { if (type == LIST_INT) {
snprintf((char *)buf, sizeof(buf), "%d", iarg - 1); snprintf((char *)buf, sizeof(buf), "%d", iarg - 1);
} else if (type == LIST_STRING) { } else if (type == LIST_STRING) {
@@ -1485,9 +1480,9 @@ const char *highlight_has_attr(const int id, const int flag, const int modec)
} }
if (modec == 'g') { if (modec == 'g') {
attr = HL_TABLE()[id - 1].sg_gui; attr = hl_table[id - 1].sg_gui;
} else { } else {
attr = HL_TABLE()[id - 1].sg_cterm; attr = hl_table[id - 1].sg_cterm;
} }
return (attr & flag) ? "1" : NULL; return (attr & flag) ? "1" : NULL;
@@ -1528,11 +1523,11 @@ const char *highlight_color(const int id, const char *const what, const int mode
if (modec == 'g') { if (modec == 'g') {
if (what[2] == '#' && ui_rgb_attached()) { if (what[2] == '#' && ui_rgb_attached()) {
if (fg) { if (fg) {
n = HL_TABLE()[id - 1].sg_rgb_fg; n = hl_table[id - 1].sg_rgb_fg;
} else if (sp) { } else if (sp) {
n = HL_TABLE()[id - 1].sg_rgb_sp; n = hl_table[id - 1].sg_rgb_sp;
} else { } else {
n = HL_TABLE()[id - 1].sg_rgb_bg; n = hl_table[id - 1].sg_rgb_bg;
} }
if (n < 0 || n > 0xffffff) { if (n < 0 || n > 0xffffff) {
return NULL; return NULL;
@@ -1541,21 +1536,21 @@ const char *highlight_color(const int id, const char *const what, const int mode
return name; return name;
} }
if (fg) { if (fg) {
return (const char *)HL_TABLE()[id - 1].sg_rgb_fg_name; return coloridx_to_name(hl_table[id - 1].sg_rgb_fg_idx, hl_table[id - 1].sg_rgb_fg, name);
} else if (sp) {
return coloridx_to_name(hl_table[id - 1].sg_rgb_sp_idx, hl_table[id - 1].sg_rgb_sp, name);
} else {
return coloridx_to_name(hl_table[id - 1].sg_rgb_bg_idx, hl_table[id - 1].sg_rgb_bg, name);
} }
if (sp) {
return (const char *)HL_TABLE()[id - 1].sg_rgb_sp_name;
}
return (const char *)HL_TABLE()[id - 1].sg_rgb_bg_name;
} }
if (font || sp) { if (font || sp) {
return NULL; return NULL;
} }
if (modec == 'c') { if (modec == 'c') {
if (fg) { if (fg) {
n = HL_TABLE()[id - 1].sg_cterm_fg - 1; n = hl_table[id - 1].sg_cterm_fg - 1;
} else { } else {
n = HL_TABLE()[id - 1].sg_cterm_bg - 1; n = hl_table[id - 1].sg_cterm_bg - 1;
} }
if (n < 0) { if (n < 0) {
return NULL; return NULL;
@@ -1586,7 +1581,7 @@ bool syn_list_header(const bool did_header, const int outlen, const int id, bool
if (got_int) { if (got_int) {
return true; return true;
} }
msg_outtrans(HL_TABLE()[id - 1].sg_name); msg_outtrans(hl_table[id - 1].sg_name);
name_col = msg_col; name_col = msg_col;
endcol = 15; endcol = 15;
} else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) { } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
@@ -1630,7 +1625,7 @@ bool syn_list_header(const bool did_header, const int outlen, const int id, bool
static void set_hl_attr(int idx) static void set_hl_attr(int idx)
{ {
HlAttrs at_en = HLATTRS_INIT; HlAttrs at_en = HLATTRS_INIT;
HlGroup *sgp = HL_TABLE() + idx; HlGroup *sgp = hl_table + idx;
at_en.cterm_ae_attr = (int16_t)sgp->sg_cterm; at_en.cterm_ae_attr = (int16_t)sgp->sg_cterm;
at_en.cterm_fg_color = sgp->sg_cterm_fg; at_en.cterm_fg_color = sgp->sg_cterm_fg;
@@ -1639,9 +1634,9 @@ static void set_hl_attr(int idx)
// FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is // 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 // 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 // before setting attr_entry->{f,g}g_color to a other than -1
at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1; at_en.rgb_fg_color = sgp->sg_rgb_fg_idx != kColorIdxNone ? sgp->sg_rgb_fg : -1;
at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1; at_en.rgb_bg_color = sgp->sg_rgb_bg_idx != kColorIdxNone ? sgp->sg_rgb_bg : -1;
at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1; at_en.rgb_sp_color = sgp->sg_rgb_sp_idx != kColorIdxNone ? sgp->sg_rgb_sp : -1;
at_en.hl_blend = sgp->sg_blend; at_en.hl_blend = sgp->sg_blend;
sgp->sg_attr = hl_get_syn_attr(0, idx + 1, at_en); sgp->sg_attr = hl_get_syn_attr(0, idx + 1, at_en);
@@ -1708,7 +1703,7 @@ char_u *syn_id2name(int id)
if (id <= 0 || id > highlight_ga.ga_len) { if (id <= 0 || id > highlight_ga.ga_len) {
return (char_u *)""; return (char_u *)"";
} }
return HL_TABLE()[id - 1].sg_name; return hl_table[id - 1].sg_name;
} }
/// Find highlight group name in the table and return its ID. /// Find highlight group name in the table and return its ID.
@@ -1726,7 +1721,7 @@ int syn_check_group(const char *name, size_t len)
} }
int id = syn_name2id_len((char_u *)name, len); int id = syn_name2id_len((char_u *)name, len);
if (id == 0) { // doesn't exist yet if (id == 0) { // doesn't exist yet
return syn_add_group(vim_strnsave((char_u *)name, len)); return syn_add_group(name, len);
} }
return id; return id;
} }
@@ -1735,18 +1730,16 @@ int syn_check_group(const char *name, size_t len)
/// ///
/// @param name must be an allocated string, it will be consumed. /// @param name must be an allocated string, it will be consumed.
/// @return 0 for failure, else the allocated group id /// @return 0 for failure, else the allocated group id
/// @see syn_check_group syn_unadd_group /// @see syn_check_group
static int syn_add_group(char_u *name) static int syn_add_group(const char *name, size_t len)
{ {
char_u *p;
// Check that the name is ASCII letters, digits and underscore. // Check that the name is ASCII letters, digits and underscore.
for (p = name; *p != NUL; p++) { for (size_t i = 0; i < len; i++) {
if (!vim_isprintc(*p)) { int c = (int8_t)name[i];
if (!vim_isprintc(c)) {
emsg(_("E669: Unprintable character in group name")); emsg(_("E669: Unprintable character in group name"));
xfree(name);
return 0; return 0;
} else if (!ASCII_ISALNUM(*p) && *p != '_') { } else if (!ASCII_ISALNUM(c) && c != '_') {
// This is an error, but since there previously was no check only give a warning. // This is an error, but since there previously was no check only give a warning.
msg_source(HL_ATTR(HLF_W)); msg_source(HL_ATTR(HLF_W));
msg(_("W18: Invalid character in group name")); msg(_("W18: Invalid character in group name"));
@@ -1762,46 +1755,36 @@ static int syn_add_group(char_u *name)
if (highlight_ga.ga_len >= MAX_HL_ID) { if (highlight_ga.ga_len >= MAX_HL_ID) {
emsg(_("E849: Too many highlight and syntax groups")); emsg(_("E849: Too many highlight and syntax groups"));
xfree(name);
return 0; return 0;
} }
char *const name_up = (char *)vim_strsave_up(name);
// Append another syntax_highlight entry. // Append another syntax_highlight entry.
HlGroup *hlgp = GA_APPEND_VIA_PTR(HlGroup, &highlight_ga); HlGroup *hlgp = GA_APPEND_VIA_PTR(HlGroup, &highlight_ga);
memset(hlgp, 0, sizeof(*hlgp)); memset(hlgp, 0, sizeof(*hlgp));
hlgp->sg_name = name; hlgp->sg_name = (char_u *)arena_memdupz(&highlight_arena, name, len);
hlgp->sg_rgb_bg = -1; hlgp->sg_rgb_bg = -1;
hlgp->sg_rgb_fg = -1; hlgp->sg_rgb_fg = -1;
hlgp->sg_rgb_sp = -1; hlgp->sg_rgb_sp = -1;
hlgp->sg_rgb_bg_idx = kColorIdxNone;
hlgp->sg_rgb_fg_idx = kColorIdxNone;
hlgp->sg_rgb_sp_idx = kColorIdxNone;
hlgp->sg_blend = -1; hlgp->sg_blend = -1;
hlgp->sg_name_u = name_up; hlgp->sg_name_u = arena_memdupz(&highlight_arena, name, len);
vim_strup((char_u *)hlgp->sg_name_u);
int id = highlight_ga.ga_len; // ID is index plus one int id = highlight_ga.ga_len; // ID is index plus one
map_put(cstr_t, int)(&highlight_unames, name_up, id); map_put(cstr_t, int)(&highlight_unames, hlgp->sg_name_u, id);
return id; return id;
} }
/// When, just after calling syn_add_group(), an error is discovered, this
/// function deletes the new name.
static void syn_unadd_group(void)
{
highlight_ga.ga_len--;
HlGroup *item = &HL_TABLE()[highlight_ga.ga_len];
map_del(cstr_t, int)(&highlight_unames, item->sg_name_u);
xfree(item->sg_name);
xfree(item->sg_name_u);
}
/// Translate a group ID to highlight attributes. /// Translate a group ID to highlight attributes.
/// @see syn_attr2entry /// @see syn_attr2entry
int syn_id2attr(int hl_id) int syn_id2attr(int hl_id)
{ {
hl_id = syn_get_final_id(hl_id); hl_id = syn_get_final_id(hl_id);
HlGroup *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one HlGroup *sgp = &hl_table[hl_id - 1]; // index is ID minus one
int attr = ns_get_hl(-1, hl_id, false, sgp->sg_set); int attr = ns_get_hl(-1, hl_id, false, sgp->sg_set);
if (attr >= 0) { if (attr >= 0) {
@@ -1822,7 +1805,7 @@ int syn_get_final_id(int hl_id)
// Follow links until there is no more. // Follow links until there is no more.
// Look out for loops! Break after 100 links. // Look out for loops! Break after 100 links.
for (count = 100; --count >= 0;) { for (count = 100; --count >= 0;) {
HlGroup *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one HlGroup *sgp = &hl_table[hl_id - 1]; // index is ID minus one
// ACHTUNG: when using "tmp" attribute (no link) the function might be // ACHTUNG: when using "tmp" attribute (no link) the function might be
// called twice. it needs be smart enough to remember attr only to // called twice. it needs be smart enough to remember attr only to
@@ -1848,15 +1831,21 @@ int syn_get_final_id(int hl_id)
void highlight_attr_set_all(void) void highlight_attr_set_all(void)
{ {
for (int idx = 0; idx < highlight_ga.ga_len; idx++) { for (int idx = 0; idx < highlight_ga.ga_len; idx++) {
HlGroup *sgp = &HL_TABLE()[idx]; HlGroup *sgp = &hl_table[idx];
if (sgp->sg_rgb_bg_name != NULL) { if (sgp->sg_rgb_bg_idx == kColorIdxFg) {
sgp->sg_rgb_bg = name_to_color(sgp->sg_rgb_bg_name); sgp->sg_rgb_bg = normal_fg;
} else if (sgp->sg_rgb_bg_idx == kColorIdxBg) {
sgp->sg_rgb_bg = normal_bg;
} }
if (sgp->sg_rgb_fg_name != NULL) { if (sgp->sg_rgb_fg_idx == kColorIdxFg) {
sgp->sg_rgb_fg = name_to_color(sgp->sg_rgb_fg_name); sgp->sg_rgb_fg = normal_fg;
} else if (sgp->sg_rgb_fg_idx == kColorIdxBg) {
sgp->sg_rgb_fg = normal_bg;
} }
if (sgp->sg_rgb_sp_name != NULL) { if (sgp->sg_rgb_sp_idx == kColorIdxFg) {
sgp->sg_rgb_sp = name_to_color(sgp->sg_rgb_sp_name); sgp->sg_rgb_sp = normal_fg;
} else if (sgp->sg_rgb_sp_idx == kColorIdxBg) {
sgp->sg_rgb_sp = normal_bg;
} }
set_hl_attr(idx); set_hl_attr(idx);
} }
@@ -1866,7 +1855,7 @@ void highlight_attr_set_all(void)
static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int hlf, int *table) static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int hlf, int *table)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
HlGroup *const hlt = HL_TABLE(); HlGroup *const hlt = hl_table;
if (id_alt == 0) { if (id_alt == 0) {
memset(&hlt[hlcnt + i], 0, sizeof(HlGroup)); memset(&hlt[hlcnt + i], 0, sizeof(HlGroup));
@@ -1951,7 +1940,7 @@ void highlight_changed(void)
hlcnt = highlight_ga.ga_len; hlcnt = highlight_ga.ga_len;
if (id_S == -1) { if (id_S == -1) {
// Make sure id_S is always valid to simplify code below. Use the last entry // Make sure id_S is always valid to simplify code below. Use the last entry
memset(&HL_TABLE()[hlcnt + 9], 0, sizeof(HlGroup)); memset(&hl_table[hlcnt + 9], 0, sizeof(HlGroup));
id_S = hlcnt + 10; id_S = hlcnt + 10;
} }
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
@@ -2048,7 +2037,7 @@ const char *get_highlight_name_ext(expand_T *xp, int idx, bool skip_cleared)
} }
// Items are never removed from the table, skip the ones that were cleared. // Items are never removed from the table, skip the ones that were cleared.
if (skip_cleared && idx < highlight_ga.ga_len && HL_TABLE()[idx].sg_cleared) { if (skip_cleared && idx < highlight_ga.ga_len && hl_table[idx].sg_cleared) {
return ""; return "";
} }
@@ -2066,7 +2055,7 @@ const char *get_highlight_name_ext(expand_T *xp, int idx, bool skip_cleared)
} else if (idx >= highlight_ga.ga_len) { } else if (idx >= highlight_ga.ga_len) {
return NULL; return NULL;
} }
return (const char *)HL_TABLE()[idx].sg_name; return (const char *)hl_table[idx].sg_name;
} }
color_name_table_T color_name_table[] = { color_name_table_T color_name_table[] = {
@@ -2758,29 +2747,55 @@ color_name_table_T color_name_table[] = {
/// hex value /// hex value
/// ///
/// @param[in] name string value to convert to RGB /// @param[in] name string value to convert to RGB
/// @param[out] idx index in color table or special value
/// return the hex value or -1 if could not find a correct value /// return the hex value or -1 if could not find a correct value
RgbValue name_to_color(const char *name) RgbValue name_to_color(const char *name, int *idx)
{ {
if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2]) if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2])
&& isxdigit(name[3]) && isxdigit(name[4]) && isxdigit(name[5]) && isxdigit(name[3]) && isxdigit(name[4]) && isxdigit(name[5])
&& isxdigit(name[6]) && name[7] == NUL) { && isxdigit(name[6]) && name[7] == NUL) {
// rgb hex string // rgb hex string
*idx = kColorIdxHex;
return (RgbValue)strtol((char *)(name + 1), NULL, 16); return (RgbValue)strtol((char *)(name + 1), NULL, 16);
} else if (!STRICMP(name, "bg") || !STRICMP(name, "background")) { } else if (!STRICMP(name, "bg") || !STRICMP(name, "background")) {
*idx = kColorIdxBg;
return normal_bg; return normal_bg;
} else if (!STRICMP(name, "fg") || !STRICMP(name, "foreground")) { } else if (!STRICMP(name, "fg") || !STRICMP(name, "foreground")) {
*idx = kColorIdxFg;
return normal_fg; return normal_fg;
} }
for (int i = 0; color_name_table[i].name != NULL; i++) { for (int i = 0; color_name_table[i].name != NULL; i++) {
if (!STRICMP(name, color_name_table[i].name)) { if (!STRICMP(name, color_name_table[i].name)) {
*idx = i;
return color_name_table[i].color; return color_name_table[i].color;
} }
} }
*idx = kColorIdxNone;
return -1; return -1;
} }
const char *coloridx_to_name(int idx, int val, char hexbuf[8])
{
if (idx >= 0) {
return color_name_table[idx].name;
}
switch (idx) {
case kColorIdxNone:
return NULL;
case kColorIdxFg:
return "fg";
case kColorIdxBg:
return "bg";
case kColorIdxHex:
snprintf(hexbuf, 7 + 1, "#%06x", val);
return hexbuf;
default:
abort();
}
}
int name_to_ctermcolor(const char *name) int name_to_ctermcolor(const char *name)
{ {
int i; int i;

View File

@@ -605,6 +605,14 @@ void arena_mem_free(ArenaMem mem, ArenaMem *reuse_blk)
} }
} }
char *arena_memdupz(Arena *arena, const char *buf, size_t size)
{
char *mem = arena_alloc(arena, size + 1, false);
memcpy(mem, buf, size);
mem[size] = NUL;
return mem;
}
#if defined(EXITFREE) #if defined(EXITFREE)
# include "nvim/buffer.h" # include "nvim/buffer.h"

View File

@@ -257,7 +257,8 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
snprintf(var, sizeof(var), "terminal_color_%d", i); snprintf(var, sizeof(var), "terminal_color_%d", i);
char *name = get_config_string(var); char *name = get_config_string(var);
if (name) { if (name) {
color_val = name_to_color(name); int dummy;
color_val = name_to_color(name, &dummy);
xfree(name); xfree(name);
if (color_val != -1) { if (color_val != -1) {

View File

@@ -507,10 +507,12 @@ void ui_flush(void)
pending_cursor_update = false; pending_cursor_update = false;
} }
if (pending_mode_info_update) { if (pending_mode_info_update) {
Array style = mode_style_array(); Arena arena = ARENA_EMPTY;
arena_start(&arena, &ui_ext_fixblk);
Array style = mode_style_array(&arena);
bool enabled = (*p_guicursor != NUL); bool enabled = (*p_guicursor != NUL);
ui_call_mode_info_set(enabled, style); ui_call_mode_info_set(enabled, style);
api_free_array(style); arena_mem_free(arena_finish(&arena), &ui_ext_fixblk);
pending_mode_info_update = false; pending_mode_info_update = false;
} }
if (pending_mode_update && !starting) { if (pending_mode_update && !starting) {

View File

@@ -293,19 +293,20 @@ describe("API: set highlight", function()
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', 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')) exec_capture('highlight Test_hl2'))
-- Colors are stored exactly as they are defined. -- Colors are stored with the name they are defined, but
-- with canonical casing
meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue'}) meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue'})
eq('Test_hl3 xxx guifg=bLue guibg=reD', eq('Test_hl3 xxx guifg=Blue guibg=Red',
exec_capture('highlight Test_hl3')) exec_capture('highlight Test_hl3'))
end) end)
it ("can modify a highlight in the global namespace", function() it ("can modify a highlight in the global namespace", function()
meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'}) meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'})
eq('Test_hl3 xxx guifg=blue guibg=red', eq('Test_hl3 xxx guifg=Blue guibg=Red',
exec_capture('highlight Test_hl3')) exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { bg = 'red' }) meths.set_hl(0, 'Test_hl3', { bg = 'red' })
eq('Test_hl3 xxx guibg=red', eq('Test_hl3 xxx guibg=Red',
exec_capture('highlight Test_hl3')) exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12}) meths.set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12})
@@ -327,7 +328,7 @@ describe("API: set highlight", function()
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'})) pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'}))
meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'}) meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'})
eq('Test_hl3 xxx guifg=#FF00FF', eq('Test_hl3 xxx guifg=#ff00ff',
exec_capture('highlight Test_hl3')) exec_capture('highlight Test_hl3'))
eq("'#FF00FF' is not a valid color", eq("'#FF00FF' is not a valid color",
@@ -340,7 +341,7 @@ describe("API: set highlight", function()
end end
meths.set_hl(0, 'Test_hl3', {fg='#FF00FF', blend=50}) meths.set_hl(0, 'Test_hl3', {fg='#FF00FF', blend=50})
eq('Test_hl3 xxx guifg=#FF00FF blend=50', eq('Test_hl3 xxx guifg=#ff00ff blend=50',
exec_capture('highlight Test_hl3')) exec_capture('highlight Test_hl3'))
end) end)