aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/highlight.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/highlight.c')
-rw-r--r--src/nvim/highlight.c349
1 files changed, 188 insertions, 161 deletions
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 9dab91cc2b..141761c52e 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -1,17 +1,15 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
// highlight.c: low level code for UI and syntax highlighting
#include <assert.h>
#include <inttypes.h>
-#include <limits.h>
+#include <lauxlib.h>
#include <string.h>
-#include "klib/kvec.h"
-#include "lauxlib.h"
+#include "nvim/api/keysets_defs.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/private/validate.h"
#include "nvim/api/ui.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
@@ -20,17 +18,17 @@
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
-#include "nvim/log.h"
#include "nvim/lua/executor.h"
-#include "nvim/macros.h"
-#include "nvim/map.h"
+#include "nvim/macros_defs.h"
+#include "nvim/map_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/popupmenu.h"
-#include "nvim/types.h"
+#include "nvim/strings.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "highlight.c.generated.h"
@@ -38,23 +36,23 @@
static bool hlstate_active = false;
-static kvec_t(HlEntry) attr_entries = KV_INITIAL_VALUE;
-
-static Map(HlEntry, int) attr_entry_ids = MAP_INIT;
+static Set(HlEntry) attr_entries = SET_INIT;
static Map(int, int) combine_attr_entries = MAP_INIT;
static Map(int, int) blend_attr_entries = MAP_INIT;
static Map(int, int) blendthrough_attr_entries = MAP_INIT;
+#define attr_entry(i) attr_entries.keys[i]
+
/// highlight entries private to a namespace
static Map(ColorKey, ColorItem) ns_hls;
typedef int NSHlAttr[HLF_COUNT + 1];
-static PMap(handle_T) ns_hl_attr;
+static PMap(int) ns_hl_attr;
void highlight_init(void)
{
// index 0 is no attribute, add dummy entry:
- kv_push(attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlUnknown,
- .id1 = 0, .id2 = 0 }));
+ set_put(HlEntry, &attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlInvalid,
+ .id1 = 0, .id2 = 0 }));
}
/// @return true if hl table was reset
@@ -75,6 +73,7 @@ bool highlight_use_hlstate(void)
/// @return 0 for error.
static int get_attr_entry(HlEntry entry)
{
+ bool retried = false;
if (!hlstate_active) {
// This information will not be used, erase it and reduce the table size.
entry.kind = kHlUnknown;
@@ -82,17 +81,19 @@ static int get_attr_entry(HlEntry entry)
entry.id2 = 0;
}
- int id = map_get(HlEntry, int)(&attr_entry_ids, entry);
- if (id > 0) {
- return id;
+retry: {}
+ MHPutStatus status;
+ uint32_t k = set_put_idx(HlEntry, &attr_entries, entry, &status);
+ if (status == kMHExisting) {
+ return (int)k;
}
static bool recursive = false;
- if (kv_size(attr_entries) > MAX_TYPENR) {
+ if (set_size(&attr_entries) > MAX_TYPENR) {
// Running out of attribute entries! remove all attributes, and
// compute new ones for all groups.
// When called recursively, we are really out of numbers.
- if (recursive) {
+ if (recursive || retried) {
emsg(_("E424: Too many different highlighting attributes in use"));
return 0;
}
@@ -105,17 +106,12 @@ static int get_attr_entry(HlEntry entry)
// This entry is now invalid, don't put it
return 0;
}
+ retried = true;
+ goto retry;
}
- size_t next_id = kv_size(attr_entries);
- if (next_id > INT_MAX) {
- ELOG("The index on attr_entries has overflowed");
- return 0;
- }
- id = (int)next_id;
- kv_push(attr_entries, entry);
-
- map_put(HlEntry, int)(&attr_entry_ids, entry, id);
+ // new attr id, send event to remote ui:s
+ int id = (int)k;
Array inspect = hl_inspect(id);
@@ -129,10 +125,10 @@ static int get_attr_entry(HlEntry entry)
/// When a UI connects, we need to send it the table of highlights used so far.
void ui_send_all_hls(UI *ui)
{
- for (size_t i = 1; i < kv_size(attr_entries); i++) {
+ for (size_t i = 1; i < set_size(&attr_entries); i++) {
Array inspect = hl_inspect((int)i);
- remote_ui_hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
- kv_A(attr_entries, i).attr, inspect);
+ HlAttrs attr = attr_entry(i).attr;
+ remote_ui_hl_attr_define(ui, (Integer)i, attr, attr, inspect);
api_free_array(inspect);
}
for (size_t hlf = 0; hlf < HLF_COUNT; hlf++) {
@@ -165,7 +161,7 @@ void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id, Dict(highlight)
return;
}
if ((attrs.rgb_ae_attr & HL_DEFAULT)
- && map_has(ColorKey, ColorItem)(&ns_hls, ColorKey(ns_id, hl_id))) {
+ && map_has(ColorKey, &ns_hls, (ColorKey(ns_id, hl_id)))) {
return;
}
DecorProvider *p = get_decor_provider(ns_id, true);
@@ -205,7 +201,7 @@ int ns_get_hl(NS *ns_hl, int hl_id, bool link, bool nodefault)
if (!valid_item && p->hl_def != LUA_NOREF && !recursive) {
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, INTEGER_OBJ((Integer)ns_id));
- ADD_C(args, STRING_OBJ(cstr_to_string((char *)syn_id2name(hl_id))));
+ ADD_C(args, CSTR_TO_OBJ(syn_id2name(hl_id)));
ADD_C(args, BOOLEAN_OBJ(link));
// TODO(bfredl): preload the "global" attr dict?
@@ -224,8 +220,8 @@ int ns_get_hl(NS *ns_hl, int hl_id, bool link, bool nodefault)
if (api_dict_to_keydict(&dict, KeyDict_highlight_get_field,
ret.data.dictionary, &err)) {
attrs = dict2hlattrs(&dict, true, &it.link_id, &err);
- fallback = api_object_to_bool(dict.fallback, "fallback", true, &err);
- tmp = api_object_to_bool(dict.fallback, "tmp", false, &err);
+ fallback = GET_BOOL_OR_TRUE(&dict, highlight, fallback);
+ tmp = dict.fallback; // or false
if (it.link_id >= 0) {
fallback = true;
}
@@ -275,7 +271,7 @@ bool hl_check_ns(void)
hl_attr_active = highlight_attr;
if (ns > 0) {
update_ns_hl(ns);
- NSHlAttr *hl_def = (NSHlAttr *)pmap_get(handle_T)(&ns_hl_attr, ns);
+ NSHlAttr *hl_def = (NSHlAttr *)pmap_get(int)(&ns_hl_attr, ns);
if (hl_def) {
hl_attr_active = *hl_def;
}
@@ -302,7 +298,7 @@ int hl_get_ui_attr(int ns_id, int idx, int final_id, bool optional)
bool available = false;
if (final_id > 0) {
- int syn_attr = syn_ns_id2attr(ns_id, final_id, optional);
+ int syn_attr = syn_ns_id2attr(ns_id, final_id, &optional);
if (syn_attr > 0) {
attrs = syn_attr2entry(syn_attr);
available = true;
@@ -325,6 +321,23 @@ int hl_get_ui_attr(int ns_id, int idx, int final_id, bool optional)
.id1 = idx, .id2 = final_id });
}
+/// Apply 'winblend' to highlight attributes.
+///
+/// @param wp The window to get 'winblend' value from.
+/// @param attr The original attribute code.
+///
+/// @return The attribute code with 'winblend' applied.
+int hl_apply_winblend(win_T *wp, int attr)
+{
+ HlEntry entry = attr_entry(attr);
+ // if blend= attribute is not set, 'winblend' value overrides it.
+ if (entry.attr.hl_blend == -1 && wp->w_p_winbl > 0) {
+ entry.attr.hl_blend = (int)wp->w_p_winbl;
+ attr = get_attr_entry(entry);
+ }
+ return attr;
+}
+
void update_window_hl(win_T *wp, bool invalid)
{
int ns_id = wp->w_ns_hl;
@@ -333,7 +346,7 @@ void update_window_hl(win_T *wp, bool invalid)
if (ns_id != wp->w_ns_hl_active || wp->w_ns_hl_attr == NULL) {
wp->w_ns_hl_active = ns_id;
- wp->w_ns_hl_attr = *(NSHlAttr *)pmap_get(handle_T)(&ns_hl_attr, ns_id);
+ wp->w_ns_hl_attr = *(NSHlAttr *)pmap_get(int)(&ns_hl_attr, ns_id);
if (!wp->w_ns_hl_attr) {
// No specific highlights, use the defaults.
wp->w_ns_hl_attr = highlight_attr;
@@ -360,13 +373,8 @@ void update_window_hl(win_T *wp, bool invalid)
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
}
- // if blend= attribute is not set, 'winblend' value overrides it.
- if (wp->w_floating && wp->w_p_winbl > 0) {
- HlEntry entry = kv_A(attr_entries, wp->w_hl_attr_normal);
- if (entry.attr.hl_blend == -1) {
- entry.attr.hl_blend = (int)wp->w_p_winbl;
- wp->w_hl_attr_normal = get_attr_entry(entry);
- }
+ if (wp->w_floating) {
+ wp->w_hl_attr_normal = hl_apply_winblend(wp, wp->w_hl_attr_normal);
}
wp->w_float_config.shadow = false;
@@ -376,10 +384,10 @@ void update_window_hl(win_T *wp, bool invalid)
if (wp->w_float_config.border_hl_ids[i]) {
attr = hl_get_ui_attr(ns_id, HLF_BORDER,
wp->w_float_config.border_hl_ids[i], false);
- HlAttrs a = syn_attr2entry(attr);
- if (a.hl_blend) {
- wp->w_float_config.shadow = true;
- }
+ }
+ attr = hl_apply_winblend(wp, attr);
+ if (syn_attr2entry(attr).hl_blend > 0) {
+ wp->w_float_config.shadow = true;
}
wp->w_float_config.border_attr[i] = attr;
}
@@ -396,6 +404,10 @@ void update_window_hl(win_T *wp, bool invalid)
} else {
wp->w_hl_attr_normalnc = hl_def[HLF_INACTIVE];
}
+
+ if (wp->w_floating) {
+ wp->w_hl_attr_normalnc = hl_apply_winblend(wp, wp->w_hl_attr_normalnc);
+ }
}
void update_ns_hl(int ns_id)
@@ -408,7 +420,7 @@ void update_ns_hl(int ns_id)
return;
}
- NSHlAttr **alloc = (NSHlAttr **)pmap_ref(handle_T)(&ns_hl_attr, ns_id, true);
+ NSHlAttr **alloc = (NSHlAttr **)pmap_put_ref(int)(&ns_hl_attr, ns_id, NULL, NULL);
if (*alloc == NULL) {
*alloc = xmalloc(sizeof(**alloc));
}
@@ -471,7 +483,7 @@ int hl_get_underline(void)
/// Get attribute code for forwarded :terminal highlights.
int hl_get_term_attr(HlAttrs *aep)
{
- return get_attr_entry((HlEntry){ .attr= *aep, .kind = kHlTerminal,
+ return get_attr_entry((HlEntry){ .attr = *aep, .kind = kHlTerminal,
.id1 = 0, .id2 = 0 });
}
@@ -479,33 +491,42 @@ int hl_get_term_attr(HlAttrs *aep)
void clear_hl_tables(bool reinit)
{
if (reinit) {
- kv_size(attr_entries) = 1;
- map_clear(HlEntry, int)(&attr_entry_ids);
- map_clear(int, int)(&combine_attr_entries);
- map_clear(int, int)(&blend_attr_entries);
- map_clear(int, int)(&blendthrough_attr_entries);
+ set_clear(HlEntry, &attr_entries);
+ highlight_init();
+ map_clear(int, &combine_attr_entries);
+ map_clear(int, &blend_attr_entries);
+ map_clear(int, &blendthrough_attr_entries);
memset(highlight_attr_last, -1, sizeof(highlight_attr_last));
highlight_attr_set_all();
highlight_changed();
screen_invalidate_highlights();
} else {
- kv_destroy(attr_entries);
- map_destroy(HlEntry, int)(&attr_entry_ids);
- map_destroy(int, int)(&combine_attr_entries);
- map_destroy(int, int)(&blend_attr_entries);
- map_destroy(int, int)(&blendthrough_attr_entries);
- map_destroy(ColorKey, ColorItem)(&ns_hls);
+ set_destroy(HlEntry, &attr_entries);
+ map_destroy(int, &combine_attr_entries);
+ map_destroy(int, &blend_attr_entries);
+ map_destroy(int, &blendthrough_attr_entries);
+ map_destroy(ColorKey, &ns_hls);
}
}
void hl_invalidate_blends(void)
{
- map_clear(int, int)(&blend_attr_entries);
- map_clear(int, int)(&blendthrough_attr_entries);
+ map_clear(int, &blend_attr_entries);
+ map_clear(int, &blendthrough_attr_entries);
highlight_changed();
update_window_hl(curwin, true);
}
+/// 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)
+{
+ 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;
+ return (char_ae & ~HL_UNDERLINE_MASK) | (prim_ae & ~HL_UNDERLINE_MASK) | new_ul;
+}
+
// Combine special attributes (e.g., for spelling) with other attributes
// (e.g., for syntax highlighting).
// "prim_attr" overrules "char_attr".
@@ -536,12 +557,12 @@ int hl_combine_attr(int char_attr, int prim_attr)
if (prim_aep.cterm_ae_attr & HL_NOCOMBINE) {
new_en.cterm_ae_attr = prim_aep.cterm_ae_attr;
} else {
- new_en.cterm_ae_attr |= prim_aep.cterm_ae_attr;
+ new_en.cterm_ae_attr = hl_combine_ae(new_en.cterm_ae_attr, prim_aep.cterm_ae_attr);
}
if (prim_aep.rgb_ae_attr & HL_NOCOMBINE) {
new_en.rgb_ae_attr = prim_aep.rgb_ae_attr;
} else {
- new_en.rgb_ae_attr |= prim_aep.rgb_ae_attr;
+ new_en.rgb_ae_attr = hl_combine_ae(new_en.rgb_ae_attr, prim_aep.rgb_ae_attr);
}
if (prim_aep.cterm_fg_color > 0) {
@@ -663,7 +684,7 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through)
} else {
cattrs = fattrs;
if (ratio >= 50) {
- cattrs.rgb_ae_attr |= battrs.rgb_ae_attr;
+ cattrs.rgb_ae_attr = hl_combine_ae(battrs.rgb_ae_attr, cattrs.rgb_ae_attr);
}
cattrs.rgb_fg_color = rgb_blend(ratio/2, battrs.rgb_fg_color,
fattrs.rgb_fg_color);
@@ -788,11 +809,11 @@ static int hl_cterm2rgb_color(int nr)
/// Get highlight attributes for a attribute code
HlAttrs syn_attr2entry(int attr)
{
- if (attr <= 0 || attr >= (int)kv_size(attr_entries)) {
+ if (attr <= 0 || attr >= (int)set_size(&attr_entries)) {
// invalid attribute code, or the tables were cleared
return HLATTRS_INIT;
}
- return kv_A(attr_entries, attr).attr;
+ return attr_entry(attr).attr;
}
/// Gets highlight description for id `attr_id` as a map.
@@ -804,13 +825,13 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *
return dic;
}
- if (attr_id <= 0 || attr_id >= (int)kv_size(attr_entries)) {
+ if (attr_id <= 0 || attr_id >= (int)set_size(&attr_entries)) {
api_set_error(err, kErrorTypeException,
"Invalid attribute id: %" PRId64, attr_id);
return dic;
}
Dictionary retval = arena_dict(arena, HLATTRS_DICT_SIZE);
- hlattrs2dict(&retval, syn_attr2entry((int)attr_id), rgb);
+ hlattrs2dict(&retval, NULL, syn_attr2entry((int)attr_id), rgb, false);
return retval;
}
@@ -819,101 +840,105 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *
/// @param[in/out] hl Dictionary with pre-allocated space for HLATTRS_DICT_SIZE elements
/// @param[in] aep data to convert
/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
-void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb)
+/// @param short_keys change (foreground, background, special) to (fg, bg, sp) for 'gui*' settings
+/// (foreground, background) to (ctermfg, ctermbg) for 'cterm*' settings
+void hlattrs2dict(Dictionary *hl, Dictionary *hl_attrs, HlAttrs ae, bool use_rgb, bool short_keys)
{
- assert(dict->capacity >= HLATTRS_DICT_SIZE); // at most 16 items
- Dictionary hl = *dict;
- int mask = use_rgb ? ae.rgb_ae_attr : ae.cterm_ae_attr;
+ hl_attrs = hl_attrs ? hl_attrs : hl;
+ assert(hl->capacity >= HLATTRS_DICT_SIZE); // at most 16 items
+ assert(hl_attrs->capacity >= HLATTRS_DICT_SIZE); // at most 16 items
+ int mask = use_rgb ? ae.rgb_ae_attr : ae.cterm_ae_attr;
if (mask & HL_INVERSE) {
- PUT_C(hl, "reverse", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "reverse", BOOLEAN_OBJ(true));
}
if (mask & HL_BOLD) {
- PUT_C(hl, "bold", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "bold", BOOLEAN_OBJ(true));
}
if (mask & HL_ITALIC) {
- PUT_C(hl, "italic", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "italic", BOOLEAN_OBJ(true));
}
switch (mask & HL_UNDERLINE_MASK) {
case HL_UNDERLINE:
- PUT_C(hl, "underline", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "underline", BOOLEAN_OBJ(true));
break;
- case HL_UNDERDOUBLE:
- PUT_C(hl, "underdouble", BOOLEAN_OBJ(true));
+ case HL_UNDERCURL:
+ PUT_C(*hl_attrs, "undercurl", BOOLEAN_OBJ(true));
break;
- case HL_UNDERCURL:
- PUT_C(hl, "undercurl", BOOLEAN_OBJ(true));
+ case HL_UNDERDOUBLE:
+ PUT_C(*hl_attrs, "underdouble", BOOLEAN_OBJ(true));
break;
case HL_UNDERDOTTED:
- PUT_C(hl, "underdotted", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "underdotted", BOOLEAN_OBJ(true));
break;
case HL_UNDERDASHED:
- PUT_C(hl, "underdashed", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "underdashed", BOOLEAN_OBJ(true));
break;
}
if (mask & HL_STANDOUT) {
- PUT_C(hl, "standout", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "standout", BOOLEAN_OBJ(true));
}
if (mask & HL_STRIKETHROUGH) {
- PUT_C(hl, "strikethrough", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "strikethrough", BOOLEAN_OBJ(true));
}
if (mask & HL_ALTFONT) {
- PUT_C(hl, "altfont", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "altfont", BOOLEAN_OBJ(true));
}
if (mask & HL_NOCOMBINE) {
- PUT_C(hl, "nocombine", BOOLEAN_OBJ(true));
+ PUT_C(*hl_attrs, "nocombine", BOOLEAN_OBJ(true));
}
if (use_rgb) {
- if (mask & HL_FG_INDEXED) {
- PUT_C(hl, "fg_indexed", BOOLEAN_OBJ(true));
- }
-
- if (mask & HL_BG_INDEXED) {
- PUT_C(hl, "bg_indexed", BOOLEAN_OBJ(true));
- }
-
if (ae.rgb_fg_color != -1) {
- PUT_C(hl, "foreground", INTEGER_OBJ(ae.rgb_fg_color));
+ PUT_C(*hl, short_keys ? "fg" : "foreground", INTEGER_OBJ(ae.rgb_fg_color));
}
if (ae.rgb_bg_color != -1) {
- PUT_C(hl, "background", INTEGER_OBJ(ae.rgb_bg_color));
+ PUT_C(*hl, short_keys ? "bg" : "background", INTEGER_OBJ(ae.rgb_bg_color));
}
if (ae.rgb_sp_color != -1) {
- PUT_C(hl, "special", INTEGER_OBJ(ae.rgb_sp_color));
+ PUT_C(*hl, short_keys ? "sp" : "special", INTEGER_OBJ(ae.rgb_sp_color));
+ }
+
+ if (!short_keys) {
+ if (mask & HL_FG_INDEXED) {
+ PUT_C(*hl, "fg_indexed", BOOLEAN_OBJ(true));
+ }
+
+ if (mask & HL_BG_INDEXED) {
+ PUT_C(*hl, "bg_indexed", BOOLEAN_OBJ(true));
+ }
}
} else {
if (ae.cterm_fg_color != 0) {
- PUT_C(hl, "foreground", INTEGER_OBJ(ae.cterm_fg_color - 1));
+ PUT_C(*hl, short_keys ? "ctermfg" : "foreground", INTEGER_OBJ(ae.cterm_fg_color - 1));
}
if (ae.cterm_bg_color != 0) {
- PUT_C(hl, "background", INTEGER_OBJ(ae.cterm_bg_color - 1));
+ PUT_C(*hl, short_keys ? "ctermbg" : "background", INTEGER_OBJ(ae.cterm_bg_color - 1));
}
}
- if (ae.hl_blend > -1) {
- PUT_C(hl, "blend", INTEGER_OBJ(ae.hl_blend));
+ if (ae.hl_blend > -1 && (use_rgb || !short_keys)) {
+ PUT_C(*hl, "blend", INTEGER_OBJ(ae.hl_blend));
}
-
- *dict = hl;
}
HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *err)
{
+#define HAS_KEY_X(d, key) HAS_KEY(d, highlight, key)
HlAttrs hlattrs = HLATTRS_INIT;
int32_t fg = -1, bg = -1, ctermfg = -1, ctermbg = -1, sp = -1;
int blend = -1;
@@ -922,16 +947,19 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
bool cterm_mask_provided = false;
#define CHECK_FLAG(d, m, name, extra, flag) \
- if (api_object_to_bool(d->name##extra, #name, false, err)) { \
- m = m | flag; \
+ if (d->name##extra) { \
+ if (flag & HL_UNDERLINE_MASK) { \
+ m &= ~HL_UNDERLINE_MASK; \
+ } \
+ m |= flag; \
}
CHECK_FLAG(dict, mask, reverse, , HL_INVERSE);
CHECK_FLAG(dict, mask, bold, , HL_BOLD);
CHECK_FLAG(dict, mask, italic, , HL_ITALIC);
CHECK_FLAG(dict, mask, underline, , HL_UNDERLINE);
- CHECK_FLAG(dict, mask, underdouble, , HL_UNDERDOUBLE);
CHECK_FLAG(dict, mask, undercurl, , HL_UNDERCURL);
+ CHECK_FLAG(dict, mask, underdouble, , HL_UNDERDOUBLE);
CHECK_FLAG(dict, mask, underdotted, , HL_UNDERDOTTED);
CHECK_FLAG(dict, mask, underdashed, , HL_UNDERDASHED);
CHECK_FLAG(dict, mask, standout, , HL_STANDOUT);
@@ -944,62 +972,56 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(dict, mask, nocombine, , HL_NOCOMBINE);
CHECK_FLAG(dict, mask, default, _, HL_DEFAULT);
- if (HAS_KEY(dict->fg)) {
+ if (HAS_KEY_X(dict, fg)) {
fg = object_to_color(dict->fg, "fg", use_rgb, err);
- } else if (HAS_KEY(dict->foreground)) {
+ } else if (HAS_KEY_X(dict, foreground)) {
fg = object_to_color(dict->foreground, "foreground", use_rgb, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
- if (HAS_KEY(dict->bg)) {
+ if (HAS_KEY_X(dict, bg)) {
bg = object_to_color(dict->bg, "bg", use_rgb, err);
- } else if (HAS_KEY(dict->background)) {
+ } else if (HAS_KEY_X(dict, background)) {
bg = object_to_color(dict->background, "background", use_rgb, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
- if (HAS_KEY(dict->sp)) {
+ if (HAS_KEY_X(dict, sp)) {
sp = object_to_color(dict->sp, "sp", true, err);
- } else if (HAS_KEY(dict->special)) {
+ } else if (HAS_KEY_X(dict, special)) {
sp = object_to_color(dict->special, "special", true, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
- if (dict->blend.type == kObjectTypeInteger) {
- Integer blend0 = dict->blend.data.integer;
- if (blend0 < 0 || blend0 > 100) {
- api_set_error(err, kErrorTypeValidation, "'blend' is not between 0 to 100");
- } else {
- blend = (int)blend0;
- }
- } else if (HAS_KEY(dict->blend)) {
- api_set_error(err, kErrorTypeValidation, "'blend' must be an integer");
- }
- if (ERROR_SET(err)) {
- return hlattrs;
+ if (HAS_KEY_X(dict, blend)) {
+ Integer blend0 = dict->blend;
+ VALIDATE_RANGE((blend0 >= 0 && blend0 <= 100), "blend", {
+ return hlattrs;
+ });
+ blend = (int)blend0;
}
- if (HAS_KEY(dict->link) || HAS_KEY(dict->global_link)) {
- if (link_id) {
- if (HAS_KEY(dict->global_link)) {
- *link_id = object_to_hl_id(dict->global_link, "link", err);
- mask |= HL_GLOBAL;
- } else {
- *link_id = object_to_hl_id(dict->link, "link", err);
- }
-
- if (ERROR_SET(err)) {
- return hlattrs;
- }
- } else {
+ if (HAS_KEY_X(dict, link) || HAS_KEY_X(dict, global_link)) {
+ if (!link_id) {
api_set_error(err, kErrorTypeValidation, "Invalid Key: '%s'",
- HAS_KEY(dict->global_link) ? "global_link" : "link");
+ HAS_KEY_X(dict, global_link) ? "global_link" : "link");
+ return hlattrs;
+ }
+ if (HAS_KEY_X(dict, global_link)) {
+ *link_id = object_to_hl_id(dict->global_link, "link", err);
+ mask |= HL_GLOBAL;
+ } else {
+ *link_id = object_to_hl_id(dict->link, "link", err);
+ }
+
+ if (ERROR_SET(err)) {
+ return hlattrs;
}
}
@@ -1025,19 +1047,21 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
// empty list from Lua API should clear all cterm attributes
// TODO(clason): handle via gen_api_dispatch
cterm_mask_provided = true;
- } else if (HAS_KEY(dict->cterm)) {
- api_set_error(err, kErrorTypeValidation, "'cterm' must be a Dictionary.");
+ } else if (HAS_KEY_X(dict, cterm)) {
+ VALIDATE_EXP(false, "cterm", "Dict", api_typename(dict->cterm.type), {
+ return hlattrs;
+ });
}
#undef CHECK_FLAG
- if (HAS_KEY(dict->ctermfg)) {
+ if (HAS_KEY_X(dict, ctermfg)) {
ctermfg = object_to_color(dict->ctermfg, "ctermfg", false, err);
if (ERROR_SET(err)) {
return hlattrs;
}
}
- if (HAS_KEY(dict->ctermbg)) {
+ if (HAS_KEY_X(dict, ctermbg)) {
ctermbg = object_to_color(dict->ctermbg, "ctermbg", false, err);
if (ERROR_SET(err)) {
return hlattrs;
@@ -1064,6 +1088,7 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
}
return hlattrs;
+#undef HAS_KEY_X
}
int object_to_color(Object val, char *key, bool rgb, Error *err)
@@ -1083,13 +1108,14 @@ int object_to_color(Object val, char *key, bool rgb, Error *err)
} else {
color = name_to_ctermcolor(str.data);
}
- if (color < 0) {
- api_set_error(err, kErrorTypeValidation, "'%s' is not a valid color", str.data);
- }
+ VALIDATE_S((color >= 0), "highlight color", str.data, {
+ return color;
+ });
return color;
} else {
- api_set_error(err, kErrorTypeValidation, "'%s' must be string or integer", key);
- return 0;
+ VALIDATE_EXP(false, key, "String or Integer", NULL, {
+ return 0;
+ });
}
}
@@ -1106,28 +1132,28 @@ Array hl_inspect(int attr)
static void hl_inspect_impl(Array *arr, int attr)
{
Dictionary item = ARRAY_DICT_INIT;
- if (attr <= 0 || attr >= (int)kv_size(attr_entries)) {
+ if (attr <= 0 || attr >= (int)set_size(&attr_entries)) {
return;
}
- HlEntry e = kv_A(attr_entries, attr);
+ HlEntry e = attr_entry(attr);
switch (e.kind) {
case kHlSyntax:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("syntax")));
+ PUT(item, "kind", CSTR_TO_OBJ("syntax"));
PUT(item, "hi_name",
- STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id1))));
+ CSTR_TO_OBJ(syn_id2name(e.id1)));
break;
case kHlUI:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("ui")));
+ PUT(item, "kind", CSTR_TO_OBJ("ui"));
const char *ui_name = (e.id1 == -1) ? "Normal" : hlf_names[e.id1];
- PUT(item, "ui_name", STRING_OBJ(cstr_to_string(ui_name)));
+ PUT(item, "ui_name", CSTR_TO_OBJ(ui_name));
PUT(item, "hi_name",
- STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id2))));
+ CSTR_TO_OBJ(syn_id2name(e.id2)));
break;
case kHlTerminal:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("term")));
+ PUT(item, "kind", CSTR_TO_OBJ("term"));
break;
case kHlCombine:
@@ -1139,6 +1165,7 @@ static void hl_inspect_impl(Array *arr, int attr)
return;
case kHlUnknown:
+ case kHlInvalid:
return;
}
PUT(item, "id", INTEGER_OBJ(attr));