mirror of
https://github.com/neovim/neovim.git
synced 2025-09-19 09:48:19 +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 ns_id number of namespace for this highlight
|
||||||
/// @param name highlight group name, like ErrorMsg
|
/// @param name highlight group name, like ErrorMsg
|
||||||
/// @param val highlight definiton map, like |nvim_get_hl_by_name|.
|
/// @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
|
/// @param[out] err Error details, if any
|
||||||
///
|
///
|
||||||
/// TODO: ns_id = 0, should modify :highlight namespace
|
/// 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
|
// event path for redraws caused by "fast" events. This could tie in with
|
||||||
// better throttling of async events causing redraws, such as non-batched
|
// better throttling of async events causing redraws, such as non-batched
|
||||||
// nvim_buf_set_extmark calls from async contexts.
|
// 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);
|
multiqueue_put(main_loop.events, on_redraw_event, 0);
|
||||||
}
|
}
|
||||||
ns_hl_changed = true;
|
ns_hl_changed = true;
|
||||||
|
@@ -58,6 +58,7 @@ typedef struct {
|
|||||||
|
|
||||||
EXTERN kvec_t(DecorProvider) decor_providers INIT(= KV_INITIAL_VALUE);
|
EXTERN kvec_t(DecorProvider) decor_providers INIT(= KV_INITIAL_VALUE);
|
||||||
EXTERN DecorState decor_state INIT(= { 0 });
|
EXTERN DecorState decor_state INIT(= { 0 });
|
||||||
|
EXTERN bool provider_active INIT(= false);
|
||||||
|
|
||||||
#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
|
#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
|
||||||
{ ns_id, false, LUA_NOREF, LUA_NOREF, \
|
{ 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)
|
void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)
|
||||||
{
|
{
|
||||||
DecorProvider *p = get_provider(ns_id, true);
|
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);
|
int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs);
|
||||||
ColorItem it = { .attr_id = attr_id,
|
ColorItem it = { .attr_id = attr_id,
|
||||||
.link_id = link_id,
|
.link_id = link_id,
|
||||||
.version = p->hl_valid };
|
.version = p->hl_valid,
|
||||||
map_put(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id), it);
|
.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;
|
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);
|
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?
|
// TODO(bfredl): map_ref true even this?
|
||||||
bool valid_cache = it.version >= p->hl_valid;
|
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.attr_id = fallback ? -1 : hl_get_syn_attr((int)ns_id, hl_id, attrs);
|
||||||
it.version = p->hl_valid-tmp;
|
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) {
|
if (link) {
|
||||||
return it.attr_id >= 0 ? -1 : it.link_id;
|
return it.attr_id >= 0 ? 0 : it.link_id;
|
||||||
} else {
|
} else {
|
||||||
return it.attr_id;
|
return it.attr_id;
|
||||||
}
|
}
|
||||||
@@ -307,7 +312,7 @@ void update_window_hl(win_T *wp, bool invalid)
|
|||||||
//
|
//
|
||||||
// haha, theme engine go brrr
|
// haha, theme engine go brrr
|
||||||
int normality = syn_check_group((const char_u *)S_LEN("Normal"));
|
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) {
|
if (ns_attr > 0) {
|
||||||
// TODO(bfredl): hantera NormalNC and so on
|
// TODO(bfredl): hantera NormalNC and so on
|
||||||
wp->w_hl_attr_normal = ns_attr;
|
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 },
|
{ "undercurl", HL_UNDERCURL },
|
||||||
{ "italic", HL_ITALIC },
|
{ "italic", HL_ITALIC },
|
||||||
{ "reverse", HL_INVERSE },
|
{ "reverse", HL_INVERSE },
|
||||||
|
{ "default", HL_DEFAULT },
|
||||||
|
{ "global", HL_GLOBAL },
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -22,6 +22,8 @@ typedef enum {
|
|||||||
HL_NOCOMBINE = 0x80,
|
HL_NOCOMBINE = 0x80,
|
||||||
HL_BG_INDEXED = 0x0100,
|
HL_BG_INDEXED = 0x0100,
|
||||||
HL_FG_INDEXED = 0x0200,
|
HL_FG_INDEXED = 0x0200,
|
||||||
|
HL_DEFAULT = 0x0400,
|
||||||
|
HL_GLOBAL = 0x0800,
|
||||||
} HlAttrFlags;
|
} HlAttrFlags;
|
||||||
|
|
||||||
/// Stores a complete highlighting entry, including colors and attributes
|
/// Stores a complete highlighting entry, including colors and attributes
|
||||||
@@ -188,13 +190,16 @@ typedef struct {
|
|||||||
int ns_id;
|
int ns_id;
|
||||||
int syn_id;
|
int syn_id;
|
||||||
} ColorKey;
|
} ColorKey;
|
||||||
|
#define ColorKey(n, s) (ColorKey) { .ns_id = (int)(n), .syn_id = (s) }
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int attr_id;
|
int attr_id;
|
||||||
int link_id;
|
int link_id;
|
||||||
int version;
|
int version;
|
||||||
|
bool is_default;
|
||||||
} ColorItem;
|
} 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
|
#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;
|
Error err = ERROR_INIT;
|
||||||
|
|
||||||
textlock++;
|
textlock++;
|
||||||
|
provider_active = true;
|
||||||
Object ret = nlua_call_ref(ref, name, args, true, &err);
|
Object ret = nlua_call_ref(ref, name, args, true, &err);
|
||||||
|
provider_active = false;
|
||||||
textlock--;
|
textlock--;
|
||||||
|
|
||||||
if (!ERROR_SET(&err)
|
if (!ERROR_SET(&err)
|
||||||
|
@@ -7563,14 +7563,13 @@ static void syn_unadd_group(void)
|
|||||||
/// @see syn_attr2entry
|
/// @see syn_attr2entry
|
||||||
int syn_id2attr(int hl_id)
|
int syn_id2attr(int hl_id)
|
||||||
{
|
{
|
||||||
struct hl_group *sgp;
|
|
||||||
|
|
||||||
hl_id = syn_get_final_id(hl_id);
|
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) {
|
if (attr >= 0) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
|
|
||||||
return sgp->sg_attr;
|
return sgp->sg_attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7583,7 +7582,6 @@ int syn_id2attr(int hl_id)
|
|||||||
int syn_get_final_id(int hl_id)
|
int syn_get_final_id(int hl_id)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
struct hl_group *sgp;
|
|
||||||
|
|
||||||
if (hl_id > highlight_ga.ga_len || hl_id < 1)
|
if (hl_id > highlight_ga.ga_len || hl_id < 1)
|
||||||
return 0; /* Can be called from eval!! */
|
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.
|
* Look out for loops! Break after 100 links.
|
||||||
*/
|
*/
|
||||||
for (count = 100; --count >= 0; ) {
|
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
|
// ACHTUNG: when using "tmp" attribute (no link) the function might be
|
||||||
// called twice. it needs be smart enough to remember attr only to
|
// called twice. it needs be smart enough to remember attr only to
|
||||||
// syn_id2attr time
|
// 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) {
|
if (check == 0) {
|
||||||
return 0; // how dare! it broke the link!
|
return hl_id; // how dare! it broke the link!
|
||||||
} else if (check > 0) {
|
} else if (check > 0) {
|
||||||
hl_id = check;
|
hl_id = check;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
|
|
||||||
if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) {
|
if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
#define NVIM_TYPES_H
|
#define NVIM_TYPES_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
// dummy to pass an ACL to a function
|
// dummy to pass an ACL to a function
|
||||||
typedef void *vim_acl_T;
|
typedef void *vim_acl_T;
|
||||||
|
@@ -27,6 +27,7 @@ describe('decorations providers', function()
|
|||||||
[9] = {reverse = true};
|
[9] = {reverse = true};
|
||||||
[10] = {italic = true, background = Screen.colors.Magenta};
|
[10] = {italic = true, background = Screen.colors.Magenta};
|
||||||
[11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')};
|
[11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')};
|
||||||
|
[12] = {foreground = tonumber('0x990000')};
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -227,4 +228,77 @@ describe('decorations providers', function()
|
|||||||
]]}
|
]]}
|
||||||
|
|
||||||
end)
|
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)
|
end)
|
||||||
|
Reference in New Issue
Block a user