diff options
43 files changed, 690 insertions, 203 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index cad4c8314f..4569ebc713 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -974,9 +974,9 @@ void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err) String k = opts.items[i].key; Object v = opts.items[i].value; if (strequal("force", k.data)) { - force = api_coerce_to_bool(v, "force", false, err); + force = api_object_to_bool(v, "force", false, err); } else if (strequal("unload", k.data)) { - unload = api_coerce_to_bool(v, "unload", false, err); + unload = api_object_to_bool(v, "unload", false, err); } else { api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); return; @@ -1441,7 +1441,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, goto error; } } else if (strequal("ephemeral", k.data)) { - ephemeral = api_coerce_to_bool(*v, "ephemeral", false, err); + ephemeral = api_object_to_bool(*v, "ephemeral", false, err); if (ERROR_SET(err)) { goto error; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 981d41ae6e..a9b1676879 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1625,11 +1625,8 @@ free_exit: /// @param what The name of the object, used for error message /// @param nil_value What to return if the type is nil. /// @param err Set if there was an error in converting to a bool -bool api_coerce_to_bool( - Object obj, - const char *what, - bool nil_value, - Error *err) +bool api_object_to_bool(Object obj, const char *what, + bool nil_value, Error *err) { if (obj.type == kObjectTypeBoolean) { return obj.data.boolean; @@ -1654,3 +1651,30 @@ const char *describe_ns(NS ns_id) }) return "(UNKNOWN PLUGIN)"; } + +DecorationProvider *get_provider(NS ns_id, bool force) +{ + ssize_t i; + for (i = 0; i < (ssize_t)kv_size(decoration_providers); i++) { + DecorationProvider *item = &kv_A(decoration_providers, i); + if (item->ns_id == ns_id) { + return item; + } else if (item->ns_id > ns_id) { + break; + } + } + + if (!force) { + return NULL; + } + + for (ssize_t j = (ssize_t)kv_size(decoration_providers)-1; j >= i; j++) { + // allocates if needed: + (void)kv_a(decoration_providers, (size_t)j+1); + kv_A(decoration_providers, (size_t)j+1) = kv_A(decoration_providers, j); + } + DecorationProvider *item = &kv_a(decoration_providers, (size_t)i); + *item = DECORATION_PROVIDER_INIT(ns_id); + + return item; +} diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 876b052a8e..24d82ccd0f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -199,6 +199,69 @@ Integer nvim_get_hl_id_by_name(String name) return syn_check_group((const char_u *)name.data, (int)name.size); } +Dictionary nvim__get_hl_defs(Integer ns_id, Error *err) +{ + if (ns_id == 0) { + return get_global_hl_defs(); + } + abort(); +} + +/// Set a highlight group. +/// +/// @param ns_id number of namespace for this highlight +/// @param name highlight group name, like ErrorMsg +/// @param val highlight definiton map, like |nvim_get_hl_by_name|. +/// @param[out] err Error details, if any +/// +/// TODO: ns_id = 0, should modify :highlight namespace +/// TODO val should take update vs reset flag +void nvim_set_hl(Integer ns_id, String name, Dictionary val, Error *err) + FUNC_API_SINCE(7) +{ + int hl_id = syn_check_group( (char_u *)(name.data), (int)name.size); + int link_id = -1; + + HlAttrs attrs = dict2hlattrs(val, true, &link_id, err); + if (!ERROR_SET(err)) { + ns_hl_def((NS)ns_id, hl_id, attrs, link_id); + } +} + +/// Set active namespace for highlights. +/// +/// NB: this function can be called from async contexts, but the +/// semantics are not yet well-defined. To start with +/// |nvim_set_decoration_provider| on_win and on_line callbacks +/// are explicitly allowed to change the namespace during a redraw cycle. +/// +/// @param ns_id the namespace to activate +/// @param[out] err Error details, if any +void nvim_set_hl_ns(Integer ns_id, Error *err) + FUNC_API_SINCE(7) + FUNC_API_FAST +{ + if (ns_id >= 0) { + ns_hl_active = (NS)ns_id; + } + + // TODO(bfredl): this is a little bit hackish. Eventually we want a standard + // event path for redraws caused by "fast" events. This could tie in with + // better throttling of async events causing redraws, such as non-batched + // nvim_buf_set_extmark calls from async contexts. + if (!updating_screen && !ns_hl_changed) { + multiqueue_put(main_loop.events, on_redraw_event, 0); + } + ns_hl_changed = true; +} + +static void on_redraw_event(void **argv) + FUNC_API_NOEXPORT +{ + redraw_all_later(NOT_VALID); +} + + /// Sends input-keys to Nvim, subject to various quirks controlled by `mode` /// flags. This is a blocking call, unlike |nvim_input()|. /// @@ -1477,7 +1540,7 @@ void nvim_unsubscribe(uint64_t channel_id, String event) Integer nvim_get_color_by_name(String name) FUNC_API_SINCE(1) { - return name_to_color((char_u *)name.data); + return name_to_color(name.data); } /// Returns a map of color names and RGB values. @@ -2610,33 +2673,6 @@ void nvim__screenshot(String path) ui_call_screenshot(path); } -static DecorationProvider *get_provider(NS ns_id, bool force) -{ - ssize_t i; - for (i = 0; i < (ssize_t)kv_size(decoration_providers); i++) { - DecorationProvider *item = &kv_A(decoration_providers, i); - if (item->ns_id == ns_id) { - return item; - } else if (item->ns_id > ns_id) { - break; - } - } - - if (!force) { - return NULL; - } - - for (ssize_t j = (ssize_t)kv_size(decoration_providers)-1; j >= i; j++) { - // allocates if needed: - (void)kv_a(decoration_providers, (size_t)j+1); - kv_A(decoration_providers, (size_t)j+1) = kv_A(decoration_providers, j); - } - DecorationProvider *item = &kv_a(decoration_providers, (size_t)i); - *item = DECORATION_PROVIDER_INIT(ns_id); - - return item; -} - static void clear_provider(DecorationProvider *p) { NLUA_CLEAR_REF(p->redraw_start); @@ -2695,7 +2731,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, clear_provider(p); // regardless of what happens, it seems good idea to redraw - redraw_later(NOT_VALID); // TODO(bfredl): too soon? + redraw_all_later(NOT_VALID); // TODO(bfredl): too soon? struct { const char *name; @@ -2706,6 +2742,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, { "on_win", &p->redraw_win }, { "on_line", &p->redraw_line }, { "on_end", &p->redraw_end }, + { "_on_hl_def", &p->hl_def }, { NULL, NULL }, }; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index ba43bc6cb2..f09a03f592 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -142,7 +142,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) // make sure cursor is in visible range even if win != curwin update_topline_win(win); - redraw_win_later(win, VALID); + redraw_later(win, VALID); } /// Gets the window height @@ -471,7 +471,7 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err) if (!win_new_float(win, fconfig, err)) { return; } - redraw_later(NOT_VALID); + redraw_later(win, NOT_VALID); } else { win_config_float(win, fconfig); win->w_pos_changed = true; diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 8f631ae13b..9cd2fd4beb 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1623,7 +1623,7 @@ void enter_buffer(buf_T *buf) } curbuf->b_last_used = time(NULL); - redraw_later(NOT_VALID); + redraw_later(curwin, NOT_VALID); } // Change to the directory of the current buffer. diff --git a/src/nvim/change.c b/src/nvim/change.c index be52750c44..9ee987b45d 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -294,7 +294,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, // change. if (wp->w_p_rnu || (wp->w_p_cul && lnum <= wp->w_last_cursorline)) { - redraw_win_later(wp, SOME_VALID); + redraw_later(wp, SOME_VALID); } } } @@ -348,7 +348,7 @@ void changed_bytes(linenr_T lnum, colnr_T col) FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_diff && wp != curwin) { - redraw_win_later(wp, VALID); + redraw_later(wp, VALID); wlnum = diff_lnum_win(lnum, wp); if (wlnum > 0) { changedOneline(wp->w_buffer, wlnum); @@ -475,7 +475,7 @@ changed_lines( FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_diff && wp != curwin) { - redraw_win_later(wp, VALID); + redraw_later(wp, VALID); wlnum = diff_lnum_win(lnum, wp); if (wlnum > 0) { changed_lines_buf(wp->w_buffer, wlnum, diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index 036ae32589..d3ffab1759 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -482,7 +482,7 @@ bool leftcol_changed(void) if (retval) curwin->w_set_curswant = true; - redraw_later(NOT_VALID); + redraw_later(curwin, NOT_VALID); return retval; } diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 3de5fc49bd..b9c293f6c8 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -643,7 +643,7 @@ void diff_redraw(bool dofold) if (!wp->w_p_diff) { continue; } - redraw_win_later(wp, SOME_VALID); + redraw_later(wp, SOME_VALID); if (dofold && foldmethodIsDiff(wp)) { foldUpdateAll(wp); } @@ -1415,7 +1415,7 @@ void diff_win_options(win_T *wp, int addbuf) if (addbuf) { diff_buf_add(wp->w_buffer); } - redraw_win_later(wp, NOT_VALID); + redraw_later(wp, NOT_VALID); } /// Set options not to show diffs. For the current window or all windows. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index ac0e6cc9f6..3e62ed9036 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -8571,7 +8571,7 @@ static void ins_up( if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill ) - redraw_later(VALID); + redraw_later(curwin, VALID); start_arrow(&tpos); can_cindent = true; } else { @@ -8619,7 +8619,7 @@ static void ins_down( if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill ) - redraw_later(VALID); + redraw_later(curwin, VALID); start_arrow(&tpos); can_cindent = true; } else { @@ -9013,7 +9013,7 @@ static int ins_ctrl_ey(int tc) scrolldown_clamp(); else scrollup_clamp(); - redraw_later(VALID); + redraw_later(curwin, VALID); } else { c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1)); if (c != NUL) { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 3669cbbd2d..41137bf2db 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3721,8 +3721,8 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, update_topline(); validate_cursor(); update_screen(SOME_VALID); - highlight_match = FALSE; - redraw_later(SOME_VALID); + highlight_match = false; + redraw_later(curwin, SOME_VALID); curwin->w_p_fen = save_p_fen; if (msg_row == Rows - 1) @@ -5751,7 +5751,7 @@ static buf_T *show_sub(exarg_T *eap, pos_T old_cusr, } xfree(str); - redraw_later(SOME_VALID); + redraw_later(curwin, SOME_VALID); win_enter(save_curwin, false); // Return to original window update_topline(); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 211791c19d..59e9f96c3a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7379,7 +7379,7 @@ static void ex_syncbind(exarg_T *eap) else scrolldown(-y, TRUE); curwin->w_scbind_pos = topline; - redraw_later(VALID); + redraw_later(curwin, VALID); cursor_correct(); curwin->w_redr_status = TRUE; } @@ -8504,7 +8504,7 @@ static void ex_pedit(exarg_T *eap) if (curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were validate_cursor(); - redraw_later(VALID); + redraw_later(curwin, VALID); win_enter(curwin_save, true); } g_do_tagpreview = 0; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index d67e9b2d7e..53feffd2d7 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -6483,7 +6483,7 @@ static int open_cmdwin(void) ccline.redraw_state = kCmdRedrawNone; ui_call_cmdline_hide(ccline.level); } - redraw_later(SOME_VALID); + redraw_later(curwin, SOME_VALID); // Save the command line info, can be used recursively. save_cmdline(&save_ccline); diff --git a/src/nvim/extmark_defs.h b/src/nvim/extmark_defs.h index f5ca0ebbb0..382aaf6ed3 100644 --- a/src/nvim/extmark_defs.h +++ b/src/nvim/extmark_defs.h @@ -50,10 +50,13 @@ typedef struct { LuaRef redraw_win; LuaRef redraw_line; LuaRef redraw_end; + LuaRef hl_def; + int hl_valid; } DecorationProvider; #define DECORATION_PROVIDER_INIT(ns_id) (DecorationProvider) \ { ns_id, false, LUA_NOREF, LUA_NOREF, \ - LUA_NOREF, LUA_NOREF, LUA_NOREF } + LUA_NOREF, LUA_NOREF, LUA_NOREF, \ + LUA_NOREF, -1 } #endif // NVIM_EXTMARK_DEFS_H diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 197aedabec..57001f77ed 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -862,7 +862,7 @@ void foldUpdateAfterInsert(void) void foldUpdateAll(win_T *win) { win->w_foldinvalid = true; - redraw_win_later(win, NOT_VALID); + redraw_later(win, NOT_VALID); } // foldMoveTo() {{{2 diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 2db8689a56..7f3e4a7dfc 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -92,6 +92,10 @@ EXTERN struct nvim_stats_s { EXTERN int Rows INIT(= DFLT_ROWS); // nr of rows in the screen EXTERN int Columns INIT(= DFLT_COLS); // nr of columns in the screen +EXTERN NS ns_hl_active INIT(= 0); // current ns that defines highlights +EXTERN bool ns_hl_changed INIT(= false); // highlight need update + + // We use 64-bit file functions here, if available. E.g. ftello() returns // off_t instead of long, which helps if long is 32 bit and off_t is 64 bit. // We assume that when fseeko() is available then ftello() is too. diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 262afba07a..8403615166 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -14,6 +14,7 @@ #include "nvim/ui.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/lua/executor.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "highlight.c.generated.h" @@ -28,12 +29,16 @@ static Map(int, int) *combine_attr_entries; static Map(int, int) *blend_attr_entries; static Map(int, int) *blendthrough_attr_entries; +/// highlight entries private to a namespace +static Map(ColorKey, ColorItem) *ns_hl; + void highlight_init(void) { attr_entry_ids = map_new(HlEntry, int)(); combine_attr_entries = map_new(int, int)(); blend_attr_entries = map_new(int, int)(); blendthrough_attr_entries = map_new(int, int)(); + ns_hl = map_new(ColorKey, ColorItem)(); // index 0 is no attribute, add dummy entry: kv_push(attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlUnknown, @@ -129,21 +134,114 @@ void ui_send_all_hls(UI *ui) } /// Get attribute code for a syntax group. -int hl_get_syn_attr(int idx, HlAttrs at_en) +int hl_get_syn_attr(int ns_id, int idx, HlAttrs at_en) { // TODO(bfredl): should we do this unconditionally if (at_en.cterm_fg_color != 0 || at_en.cterm_bg_color != 0 || at_en.rgb_fg_color != -1 || at_en.rgb_bg_color != -1 || at_en.rgb_sp_color != -1 || at_en.cterm_ae_attr != 0 - || at_en.rgb_ae_attr != 0) { + || at_en.rgb_ae_attr != 0 || ns_id != 0) { return get_attr_entry((HlEntry){ .attr = at_en, .kind = kHlSyntax, - .id1 = idx, .id2 = 0 }); + .id1 = idx, .id2 = ns_id }); } else { // If all the fields are cleared, clear the attr field back to default value return 0; } } +static ColorKey colored_key(NS ns_id, int syn_id) +{ + return (ColorKey){ .ns_id = (int)ns_id, .syn_id = syn_id }; +} + +void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id) +{ + DecorationProvider *p = get_provider(ns_id, true); + int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs); + ColorItem it = { .attr_id = attr_id, + .link_id = link_id, + .version = p->hl_valid }; + map_put(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id), it); +} + +int ns_get_hl(NS ns_id, int hl_id, bool link) +{ + static int recursive = 0; + + if (ns_id < 0) { + if (ns_hl_active <= 0) { + return -1; + } + ns_id = ns_hl_active; + } + + DecorationProvider *p = get_provider(ns_id, true); + ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id)); + // TODO(bfredl): map_ref true even this? + bool valid_cache = it.version >= p->hl_valid; + + if (!valid_cache && p->hl_def != LUA_NOREF && !recursive) { + FIXED_TEMP_ARRAY(args, 3); + args.items[0] = INTEGER_OBJ((Integer)ns_id); + args.items[1] = STRING_OBJ(cstr_to_string((char *)syn_id2name(hl_id))); + args.items[2] = BOOLEAN_OBJ(link); + // TODO(bfredl): preload the "global" attr dict? + + Error err = ERROR_INIT; + recursive++; + Object ret = nlua_call_ref(p->hl_def, "hl_def", args, true, &err); + recursive--; + + // TODO(bfredl): or "inherit", combine with global value? + bool fallback = true; + int tmp = false; + HlAttrs attrs = HLATTRS_INIT; + if (ret.type == kObjectTypeDictionary) { + Dictionary dict = ret.data.dictionary; + fallback = false; + attrs = dict2hlattrs(dict, true, &it.link_id, &err); + for (size_t i = 0; i < dict.size; i++) { + char *key = dict.items[i].key.data; + Object val = dict.items[i].value; + bool truthy = api_object_to_bool(val, key, false, &err); + + if (strequal(key, "fallback")) { + fallback = truthy; + } else if (strequal(key, "temp")) { + tmp = truthy; + } + } + if (it.link_id >= 0) { + fallback = true; + } + } + + it.attr_id = fallback ? -1 : hl_get_syn_attr((int)ns_id, hl_id, attrs); + it.version = p->hl_valid-tmp; + map_put(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id), it); + } + + if (link) { + return it.attr_id >= 0 ? -1 : it.link_id; + } else { + return it.attr_id; + } +} + + +bool win_check_ns_hl(win_T *wp) +{ + if (ns_hl_changed) { + highlight_changed(); + if (wp) { + update_window_hl(wp, true); + } + ns_hl_changed = false; + return true; + } + return false; +} + /// Get attribute code for a builtin highlight group. /// /// The final syntax group could be modified by hi-link or 'winhighlight'. @@ -204,6 +302,17 @@ void update_window_hl(win_T *wp, bool invalid) wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0; } + // NOOOO! You cannot just pretend that "Normal" is just like any other + // syntax group! It needs at least 10 layers of special casing! Noooooo! + // + // haha, theme engine go brrr + int normality = syn_check_group((const char_u *)S_LEN("Normal")); + int ns_attr = ns_get_hl(-1, normality, false); + if (ns_attr > 0) { + // TODO(bfredl): hantera NormalNC and so on + wp->w_hl_attr_normal = ns_attr; + } + // 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); @@ -275,6 +384,7 @@ void clear_hl_tables(bool reinit) map_free(int, int)(combine_attr_entries); map_free(int, int)(blend_attr_entries); map_free(int, int)(blendthrough_attr_entries); + map_free(ColorKey, ColorItem)(ns_hl); } } @@ -663,6 +773,103 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb) return hl; } +HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err) +{ + HlAttrs hlattrs = HLATTRS_INIT; + + int32_t fg = -1, bg = -1, sp = -1; + int16_t mask = 0; + for (size_t i = 0; i < dict.size; i++) { + char *key = dict.items[i].key.data; + Object val = dict.items[i].value; + + struct { + const char *name; + int16_t flag; + } flags[] = { + { "bold", HL_BOLD }, + { "standout", HL_STANDOUT }, + { "underline", HL_UNDERLINE }, + { "undercurl", HL_UNDERCURL }, + { "italic", HL_ITALIC }, + { "reverse", HL_INVERSE }, + { NULL, 0 }, + }; + + int j; + for (j = 0; flags[j].name; j++) { + if (strequal(flags[j].name, key)) { + if (api_object_to_bool(val, key, false, err)) { + mask = mask | flags[j].flag; + } + break; + } + } + + struct { + const char *name; + const char *shortname; + int *dest; + } colors[] = { + { "foreground", "fg", &fg }, + { "background", "bg", &bg }, + { "special", "sp", &sp }, + { NULL, NULL, NULL }, + }; + + int k; + for (k = 0; (!flags[j].name) && colors[k].name; k++) { + if (strequal(colors[k].name, key) || strequal(colors[k].shortname, key)) { + if (val.type == kObjectTypeInteger) { + *colors[k].dest = (int)val.data.integer; + } else if (val.type == kObjectTypeString) { + String str = val.data.string; + // TODO(bfredl): be more fancy with "bg", "fg" etc + if (str.size) { + *colors[k].dest = name_to_color(str.data); + } + } else { + api_set_error(err, kErrorTypeValidation, + "'%s' must be string or integer", key); + } + break; + } + } + + + if (flags[j].name || colors[k].name) { + // handled above + } else if (link_id && strequal(key, "link")) { + if (val.type == kObjectTypeString) { + String str = val.data.string; + *link_id = syn_check_group((const char_u *)str.data, (int)str.size); + } else if (val.type == kObjectTypeInteger) { + // TODO(bfredl): validate range? + *link_id = (int)val.data.integer; + } else { + api_set_error(err, kErrorTypeValidation, + "'link' must be string or integer"); + } + } + + if (ERROR_SET(err)) { + return hlattrs; // error set, caller should not use retval + } + } + + if (use_rgb) { + hlattrs.rgb_ae_attr = mask; + hlattrs.rgb_bg_color = bg; + hlattrs.rgb_fg_color = fg; + hlattrs.rgb_sp_color = sp; + } else { + hlattrs.cterm_ae_attr = mask; + hlattrs.cterm_bg_color = bg == -1 ? cterm_normal_bg_color : bg + 1; + hlattrs.cterm_fg_color = fg == -1 ? cterm_normal_fg_color : fg + 1; + } + + return hlattrs; +} Array hl_inspect(int attr) { Array ret = ARRAY_DICT_INIT; diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 36f3181674..6a5c593ab1 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -4,6 +4,7 @@ #inc |