diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/highlight.c | |
parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.gz rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.bz2 rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.zip |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/highlight.c')
-rw-r--r-- | src/nvim/highlight.c | 343 |
1 files changed, 185 insertions, 158 deletions
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index c20eac3c28..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_UNDERCURL: - PUT_C(hl, "undercurl", BOOLEAN_OBJ(true)); + PUT_C(*hl_attrs, "undercurl", BOOLEAN_OBJ(true)); break; case HL_UNDERDOUBLE: - PUT_C(hl, "underdouble", BOOLEAN_OBJ(true)); + 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,8 +947,11 @@ 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); @@ -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)); |