mirror of
https://github.com/neovim/neovim.git
synced 2025-09-18 17:28:23 +00:00
decorations: allow nvim_set_hl to break existing links
also add `default` flag to NOT break existing links/defs
This commit is contained in:
@@ -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;
|
||||
|
@@ -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, \
|
||||
|
@@ -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 },
|
||||
};
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user