diff options
-rw-r--r-- | src/nvim/api/vim.c | 5 | ||||
-rw-r--r-- | src/nvim/decoration.h | 1 | ||||
-rw-r--r-- | src/nvim/highlight.c | 31 | ||||
-rw-r--r-- | src/nvim/highlight_defs.h | 7 | ||||
-rw-r--r-- | src/nvim/screen.c | 2 | ||||
-rw-r--r-- | src/nvim/syntax.c | 15 | ||||
-rw-r--r-- | src/nvim/types.h | 1 | ||||
-rw-r--r-- | test/functional/ui/decorations_spec.lua | 74 |
8 files changed, 114 insertions, 22 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index cf822782d8..710885d295 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -212,6 +212,9 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err) /// @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|. +/// in addition the following keys are also recognized: +/// `default`: don't override existing definition, +/// like `hi default` /// @param[out] err Error details, if any /// /// TODO: ns_id = 0, should modify :highlight namespace @@ -249,7 +252,7 @@ void nvim_set_hl_ns(Integer ns_id, Error *err) // 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) { + if (!provider_active && !ns_hl_changed) { multiqueue_put(main_loop.events, on_redraw_event, 0); } ns_hl_changed = true; diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 90fdc3dc43..c5941ae2fe 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -58,6 +58,7 @@ typedef struct { EXTERN kvec_t(DecorProvider) decor_providers INIT(= KV_INITIAL_VALUE); EXTERN DecorState decor_state INIT(= { 0 }); +EXTERN bool provider_active INIT(= false); #define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \ { ns_id, false, LUA_NOREF, LUA_NOREF, \ diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 898ff4ebfe..b01cdde236 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -149,22 +149,22 @@ int hl_get_syn_attr(int ns_id, int idx, HlAttrs at_en) } } -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) { DecorProvider *p = get_provider(ns_id, true); + if ((attrs.rgb_ae_attr & HL_DEFAULT) + && map_has(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id))) { + return; + } 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); + .version = p->hl_valid, + .is_default = (attrs.rgb_ae_attr & HL_DEFAULT) }; + map_put(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id), it); } -int ns_get_hl(NS ns_id, int hl_id, bool link) +int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault) { static int recursive = 0; @@ -176,7 +176,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link) } DecorProvider *p = get_provider(ns_id, true); - ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id)); + ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id)); // TODO(bfredl): map_ref true even this? bool valid_cache = it.version >= p->hl_valid; @@ -218,11 +218,16 @@ int ns_get_hl(NS ns_id, int hl_id, bool link) 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); + it.is_default = attrs.rgb_ae_attr & HL_DEFAULT; + map_put(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id), it); + } + + if (it.is_default && nodefault) { + return -1; } if (link) { - return it.attr_id >= 0 ? -1 : it.link_id; + return it.attr_id >= 0 ? 0 : it.link_id; } else { return it.attr_id; } @@ -307,7 +312,7 @@ void update_window_hl(win_T *wp, bool invalid) // // 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); + int ns_attr = ns_get_hl(-1, normality, false, false); if (ns_attr > 0) { // TODO(bfredl): hantera NormalNC and so on wp->w_hl_attr_normal = ns_attr; @@ -793,6 +798,8 @@ HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err) { "undercurl", HL_UNDERCURL }, { "italic", HL_ITALIC }, { "reverse", HL_INVERSE }, + { "default", HL_DEFAULT }, + { "global", HL_GLOBAL }, { NULL, 0 }, }; diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 6a5c593ab1..2bda094d8e 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -22,6 +22,8 @@ typedef enum { HL_NOCOMBINE = 0x80, HL_BG_INDEXED = 0x0100, HL_FG_INDEXED = 0x0200, + HL_DEFAULT = 0x0400, + HL_GLOBAL = 0x0800, } HlAttrFlags; /// Stores a complete highlighting entry, including colors and attributes @@ -188,13 +190,16 @@ typedef struct { int ns_id; int syn_id; } ColorKey; +#define ColorKey(n, s) (ColorKey) { .ns_id = (int)(n), .syn_id = (s) } typedef struct { int attr_id; int link_id; int version; + bool is_default; } ColorItem; -#define COLOR_ITEM_INITIALIZER { .attr_id = -1, .link_id = -1, .version = -1 } +#define COLOR_ITEM_INITIALIZER { .attr_id = -1, .link_id = -1, \ + .version = -1, .is_default = false } #endif // NVIM_HIGHLIGHT_DEFS_H diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 8998f9037e..5f09912116 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -173,7 +173,9 @@ static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, Error err = ERROR_INIT; textlock++; + provider_active = true; Object ret = nlua_call_ref(ref, name, args, true, &err); + provider_active = false; textlock--; if (!ERROR_SET(&err) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 5e54354ea8..e91d560284 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -7563,14 +7563,13 @@ static void syn_unadd_group(void) /// @see syn_attr2entry int syn_id2attr(int hl_id) { - struct hl_group *sgp; - hl_id = syn_get_final_id(hl_id); - int attr = ns_get_hl(-1, hl_id, false); + struct hl_group *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one + + int attr = ns_get_hl(-1, hl_id, false, sgp->sg_set); if (attr >= 0) { return attr; } - sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one return sgp->sg_attr; } @@ -7583,7 +7582,6 @@ int syn_id2attr(int hl_id) int syn_get_final_id(int hl_id) { int count; - struct hl_group *sgp; if (hl_id > highlight_ga.ga_len || hl_id < 1) return 0; /* Can be called from eval!! */ @@ -7593,19 +7591,20 @@ int syn_get_final_id(int hl_id) * Look out for loops! Break after 100 links. */ for (count = 100; --count >= 0; ) { + struct hl_group *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one + // ACHTUNG: when using "tmp" attribute (no link) the function might be // called twice. it needs be smart enough to remember attr only to // syn_id2attr time - int check = ns_get_hl(-1, hl_id, true); + int check = ns_get_hl(-1, hl_id, true, sgp->sg_set); if (check == 0) { - return 0; // how dare! it broke the link! + return hl_id; // how dare! it broke the link! } else if (check > 0) { hl_id = check; continue; } - sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) { break; } diff --git a/src/nvim/types.h b/src/nvim/types.h index 17f7e16740..2dbeecbf6d 100644 --- a/src/nvim/types.h +++ b/src/nvim/types.h @@ -2,6 +2,7 @@ #define NVIM_TYPES_H #include <stdint.h> +#include <stdbool.h> // dummy to pass an ACL to a function typedef void *vim_acl_T; diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 4182090732..781fdf7203 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -27,6 +27,7 @@ describe('decorations providers', function() [9] = {reverse = true}; [10] = {italic = true, background = Screen.colors.Magenta}; [11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')}; + [12] = {foreground = tonumber('0x990000')}; } end) @@ -227,4 +228,77 @@ describe('decorations providers', function() ]]} end) + + it('can break an existing link', function() + insert(mulholland) + local ns1 = setup_provider() + + exec [[ + highlight OriginalGroup guifg='#990000' + highlight link LinkGroup OriginalGroup + ]] + + meths.buf_set_virtual_text(0, 0, 2, {{'- not red', 'LinkGroup'}}, {}) + screen:expect{grid=[[ + // just to see if there was an accident | + // on Mulholland Drive | + try_start(); {12:- not red} | + bufref_T save_buf; | + switch_buffer(&save_buf, buf); | + posp = getmark(mark, false); | + restore_buffer(&save_buf);^ | + | + ]]} + + meths.set_hl(ns1, 'LinkGroup', {fg = 'Blue'}) + meths.set_hl_ns(ns1) + + screen:expect{grid=[[ + // just to see if there was an accident | + // on Mulholland Drive | + try_start(); {4:- not red} | + bufref_T save_buf; | + switch_buffer(&save_buf, buf); | + posp = getmark(mark, false); | + restore_buffer(&save_buf);^ | + | + ]]} + end) + + it("with 'default': do not break an existing link", function() + insert(mulholland) + local ns1 = setup_provider() + + exec [[ + highlight OriginalGroup guifg='#990000' + highlight link LinkGroup OriginalGroup + ]] + + meths.buf_set_virtual_text(0, 0, 2, {{'- not red', 'LinkGroup'}}, {}) + screen:expect{grid=[[ + // just to see if there was an accident | + // on Mulholland Drive | + try_start(); {12:- not red} | + bufref_T save_buf; | + switch_buffer(&save_buf, buf); | + posp = getmark(mark, false); | + restore_buffer(&save_buf);^ | + | + ]]} + + meths.set_hl(ns1, 'LinkGroup', {fg = 'Blue', default=true}) + meths.set_hl_ns(ns1) + feed 'k' + + screen:expect{grid=[[ + // just to see if there was an accident | + // on Mulholland Drive | + try_start(); {12:- not red} | + bufref_T save_buf; | + switch_buffer(&save_buf, buf); | + posp = getmark(mark, false^); | + restore_buffer(&save_buf); | + | + ]]} + end) end) |