feat(api): add nvim_get_hl (#22693)

Problem: no way of getting all highlight group definitions in a namespace.

Solution: add `nvim_get_hl()`, deprecate `nvim_get_hl_by_name()` and `nvim_get_hl_by_id()`.
This commit is contained in:
Null Chilly
2023-03-23 16:31:39 +07:00
committed by GitHub
parent ea0b66d208
commit c0fe6c040e
10 changed files with 385 additions and 91 deletions

View File

@@ -10,11 +10,14 @@
#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/api/vimscript.h"
#include "nvim/buffer_defs.h"
#include "nvim/decoration.h"
#include "nvim/extmark.h"
#include "nvim/globals.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/memory.h"
#include "nvim/pos.h"
@@ -159,6 +162,49 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A
return src_id;
}
/// Gets a highlight definition by id. |hlID()|
///
/// @deprecated use |nvim_get_hl()| instead
///
/// @param hl_id Highlight id as returned by |hlID()|
/// @param rgb Export RGB colors
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_name
Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
FUNC_API_DEPRECATED_SINCE(9)
{
Dictionary dic = ARRAY_DICT_INIT;
VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, {
return dic;
});
int attrcode = syn_id2attr((int)hl_id);
return hl_get_attr_by_id(attrcode, rgb, arena, err);
}
/// Gets a highlight definition by name.
///
/// @deprecated use |nvim_get_hl()| instead
///
/// @param name Highlight group name
/// @param rgb Export RGB colors
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_id
Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
FUNC_API_DEPRECATED_SINCE(9)
{
Dictionary result = ARRAY_DICT_INIT;
int id = syn_name2id(name.data);
VALIDATE_S((id != 0), "highlight name", name.data, {
return result;
});
return nvim_get_hl_by_id(id, rgb, arena, err);
}
/// Inserts a sequence of lines to a buffer at a certain index
///
/// @deprecated use nvim_buf_set_lines(buffer, lnum, lnum, true, lines)

View File

@@ -145,6 +145,11 @@ return {
"altfont";
"nocombine";
}};
{ 'get_highlight', {
"id";
"name";
"link";
}};
-- Autocmds
{ 'clear_autocmds', {
"buffer";

View File

@@ -727,8 +727,8 @@ void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cte
ADD_C(args, INTEGER_OBJ(id));
MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE);
MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb, rgb_attrs, true);
hlattrs2dict(&cterm, rgb_attrs, false);
hlattrs2dict(&rgb, rgb_attrs, true, false);
hlattrs2dict(&cterm, rgb_attrs, false, false);
ADD_C(args, DICTIONARY_OBJ(rgb));
ADD_C(args, DICTIONARY_OBJ(cterm));
@@ -751,7 +751,7 @@ void remote_ui_highlight_set(UI *ui, int id)
}
data->hl_id = id;
MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE);
hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb);
hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb, false);
ADD_C(args, DICTIONARY_OBJ(dict));
push_call(ui, "highlight_set", args);
}
@@ -950,7 +950,7 @@ static Array translate_contents(UI *ui, Array contents, Arena *arena)
int attr = (int)item.items[0].data.integer;
if (attr) {
Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb);
hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb, false);
ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
} else {
ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));

View File

@@ -74,42 +74,6 @@
# include "api/vim.c.generated.h"
#endif
/// Gets a highlight definition by name.
///
/// @param name Highlight group name
/// @param rgb Export RGB colors
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_id
Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
{
Dictionary result = ARRAY_DICT_INIT;
int id = syn_name2id(name.data);
VALIDATE_S((id != 0), "highlight name", name.data, {
return result;
});
return nvim_get_hl_by_id(id, rgb, arena, err);
}
/// Gets a highlight definition by id. |hlID()|
/// @param hl_id Highlight id as returned by |hlID()|
/// @param rgb Export RGB colors
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_name
Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
{
Dictionary dic = ARRAY_DICT_INIT;
VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, {
return dic;
});
int attrcode = syn_id2attr((int)hl_id);
return hl_get_attr_by_id(attrcode, rgb, arena, err);
}
/// Gets a highlight group by name
///
/// similar to |hlID()|, but allocates a new ID if not present.
@@ -119,12 +83,22 @@ Integer nvim_get_hl_id_by_name(String name)
return syn_check_group(name.data, name.size);
}
Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err)
/// Gets all or specific highlight groups in a namespace.
///
/// @param ns_id Get highlight groups for namespace ns_id |nvim_get_namespaces()|.
/// Use 0 to get global highlight groups |:highlight|.
/// @param opts Options dict:
/// - name: (string) Get a highlight definition by name.
/// - id: (integer) Get a highlight definition by id.
/// - link: (boolean, default true) Show linked group name instead of effective definition |:hi-link|.
///
/// @param[out] err Error details, if any.
/// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|,
/// or only a single highlight definition map if requested by name or id.
Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(11)
{
if (ns_id == 0) {
return get_global_hl_defs(arena);
}
abort();
return ns_get_hl_defs((NS)ns_id, opts, arena, err);
}
/// Sets a highlight group.

View File

@@ -821,7 +821,7 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *
return dic;
}
Dictionary retval = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&retval, syn_attr2entry((int)attr_id), rgb);
hlattrs2dict(&retval, syn_attr2entry((int)attr_id), rgb, false);
return retval;
}
@@ -830,7 +830,9 @@ 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 *dict, HlAttrs ae, bool use_rgb, bool short_keys)
{
assert(dict->capacity >= HLATTRS_DICT_SIZE); // at most 16 items
Dictionary hl = *dict;
@@ -887,32 +889,34 @@ void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb)
}
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));
}
}

View File

@@ -12,6 +12,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
#include "nvim/buffer_defs.h"
@@ -1521,24 +1522,71 @@ static void highlight_list_one(const int id)
}
}
Dictionary get_global_hl_defs(Arena *arena)
static bool hlgroup2dict(Dictionary *hl, NS ns_id, int hl_id, Arena *arena)
{
HlGroup *sgp = &hl_table[hl_id - 1];
int link = ns_id == 0 ? sgp->sg_link : ns_get_hl(&ns_id, hl_id, true, sgp->sg_set);
if (link == -1) {
return false;
}
HlAttrs attr =
syn_attr2entry(ns_id == 0 ? sgp->sg_attr : ns_get_hl(&ns_id, hl_id, false, sgp->sg_set));
if (link > 0) {
*hl = arena_dict(arena, 1);
PUT_C(*hl, "link", STRING_OBJ(cstr_as_string(hl_table[link - 1].sg_name)));
} else {
*hl = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(hl, attr, true, true);
hlattrs2dict(hl, attr, false, true);
}
return true;
}
Dictionary ns_get_hl_defs(NS ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err)
{
Boolean link = api_object_to_bool(opts->link, "link", true, err);
int id = -1;
if (opts->name.type != kObjectTypeNil) {
VALIDATE_T("highlight name", kObjectTypeString, opts->name.type, {
goto cleanup;
});
String name = opts->name.data.string;
id = syn_check_group(name.data, name.size);
} else if (opts->id.type != kObjectTypeNil) {
VALIDATE_T("highlight id", kObjectTypeInteger, opts->id.type, {
goto cleanup;
});
id = (int)opts->id.data.integer;
}
if (id != -1) {
VALIDATE(1 <= id && id <= highlight_ga.ga_len, "%s", "Highlight id out of bounds", {
goto cleanup;
});
Dictionary attrs = ARRAY_DICT_INIT;
hlgroup2dict(&attrs, ns_id, link ? id : syn_get_final_id(id), arena);
return attrs;
}
if (ERROR_SET(err)) {
goto cleanup;
}
Dictionary rv = arena_dict(arena, (size_t)highlight_ga.ga_len);
for (int i = 1; i <= highlight_ga.ga_len; i++) {
Dictionary attrs = ARRAY_DICT_INIT;
HlGroup *h = &hl_table[i - 1];
if (h->sg_attr > 0) {
attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&attrs, syn_attr2entry(h->sg_attr), true);
} else if (h->sg_link > 0) {
attrs = arena_dict(arena, 1);
char *link = hl_table[h->sg_link - 1].sg_name;
PUT_C(attrs, "link", STRING_OBJ(cstr_as_string(link)));
if (!hlgroup2dict(&attrs, ns_id, i, arena)) {
continue;
}
PUT_C(rv, h->sg_name, DICTIONARY_OBJ(attrs));
PUT_C(rv, hl_table[(link ? i : syn_get_final_id(i)) - 1].sg_name, DICTIONARY_OBJ(attrs));
}
return rv;
cleanup:
api_free_integer(id);
api_free_boolean(link);
Dictionary empty = ARRAY_DICT_INIT;
return empty;
}
/// Outputs a highlight when doing ":hi MyHighlight"