refactor(highlight): make hlattrs2dict always use pre-allocated dict

hlattrs2dict used to work with both allocated and unallocated
dicts which was quite messy. Now always delegate allocation to caller.
This commit is contained in:
bfredl 2022-08-31 14:49:15 +02:00
parent f078a3453a
commit ba8be7446d
5 changed files with 66 additions and 68 deletions

View File

@ -748,10 +748,12 @@ static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAt
UIData *data = ui->data; UIData *data = ui->data;
Array args = data->call_buf; Array args = data->call_buf;
ADD_C(args, INTEGER_OBJ(id)); ADD_C(args, INTEGER_OBJ(id));
MAXSIZE_TEMP_DICT(rgb, 16); MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE);
MAXSIZE_TEMP_DICT(cterm, 16); MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE);
ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&rgb, rgb_attrs, true))); hlattrs2dict(&rgb, rgb_attrs, true);
ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&cterm, cterm_attrs, false))); hlattrs2dict(&cterm, rgb_attrs, false);
ADD_C(args, DICTIONARY_OBJ(rgb));
ADD_C(args, DICTIONARY_OBJ(cterm));
if (ui->ui_ext[kUIHlState]) { if (ui->ui_ext[kUIHlState]) {
ADD_C(args, ARRAY_OBJ(info)); ADD_C(args, ARRAY_OBJ(info));
@ -771,8 +773,9 @@ static void remote_ui_highlight_set(UI *ui, int id)
return; return;
} }
data->hl_id = id; data->hl_id = id;
MAXSIZE_TEMP_DICT(dict, 16); MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE);
ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb))); hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb);
ADD_C(args, DICTIONARY_OBJ(dict));
push_call(ui, "highlight_set", args); push_call(ui, "highlight_set", args);
} }
@ -952,65 +955,63 @@ static void remote_ui_flush(UI *ui)
} }
} }
static Array translate_contents(UI *ui, Array contents) static Array translate_contents(UI *ui, Array contents, Arena *arena)
{ {
Array new_contents = ARRAY_DICT_INIT; Array new_contents = arena_array(arena, contents.size);
for (size_t i = 0; i < contents.size; i++) { for (size_t i = 0; i < contents.size; i++) {
Array item = contents.items[i].data.array; Array item = contents.items[i].data.array;
Array new_item = ARRAY_DICT_INIT; Array new_item = arena_array(arena, 2);
int attr = (int)item.items[0].data.integer; int attr = (int)item.items[0].data.integer;
if (attr) { if (attr) {
Dictionary rgb_attrs = hlattrs2dict(NULL, syn_attr2entry(attr), ui->rgb); Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb);
ADD(new_item, DICTIONARY_OBJ(rgb_attrs)); ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
} else { } else {
ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
} }
ADD(new_item, copy_object(item.items[1], NULL)); ADD(new_item, item.items[1]);
ADD(new_contents, ARRAY_OBJ(new_item)); ADD(new_contents, ARRAY_OBJ(new_item));
} }
return new_contents; return new_contents;
} }
static Array translate_firstarg(UI *ui, Array args) static Array translate_firstarg(UI *ui, Array args, Arena *arena)
{ {
Array new_args = ARRAY_DICT_INIT; Array new_args = arena_array(arena, args.size);
Array contents = args.items[0].data.array; Array contents = args.items[0].data.array;
ADD(new_args, ARRAY_OBJ(translate_contents(ui, contents))); ADD_C(new_args, ARRAY_OBJ(translate_contents(ui, contents, arena)));
for (size_t i = 1; i < args.size; i++) { for (size_t i = 1; i < args.size; i++) {
ADD(new_args, copy_object(args.items[i], NULL)); ADD(new_args, args.items[i]);
} }
return new_args; return new_args;
} }
static void remote_ui_event(UI *ui, char *name, Array args) static void remote_ui_event(UI *ui, char *name, Array args)
{ {
Arena arena = ARENA_EMPTY;
UIData *data = ui->data; UIData *data = ui->data;
if (!ui->ui_ext[kUILinegrid]) { if (!ui->ui_ext[kUILinegrid]) {
// the representation of highlights in cmdline changed, translate back // the representation of highlights in cmdline changed, translate back
// never consumes args // never consumes args
if (strequal(name, "cmdline_show")) { if (strequal(name, "cmdline_show")) {
Array new_args = translate_firstarg(ui, args); Array new_args = translate_firstarg(ui, args, &arena);
push_call(ui, name, new_args); push_call(ui, name, new_args);
api_free_array(new_args); goto free_ret;
return;
} else if (strequal(name, "cmdline_block_show")) { } else if (strequal(name, "cmdline_block_show")) {
Array new_args = data->call_buf; Array new_args = data->call_buf;
Array block = args.items[0].data.array; Array block = args.items[0].data.array;
Array new_block = ARRAY_DICT_INIT; Array new_block = arena_array(&arena, block.size);
for (size_t i = 0; i < block.size; i++) { for (size_t i = 0; i < block.size; i++) {
ADD(new_block, ADD_C(new_block, ARRAY_OBJ(translate_contents(ui, block.items[i].data.array, &arena)));
ARRAY_OBJ(translate_contents(ui, block.items[i].data.array)));
} }
ADD_C(new_args, ARRAY_OBJ(new_block)); ADD_C(new_args, ARRAY_OBJ(new_block));
push_call(ui, name, new_args); push_call(ui, name, new_args);
api_free_array(new_block); goto free_ret;
return;
} else if (strequal(name, "cmdline_block_append")) { } else if (strequal(name, "cmdline_block_append")) {
Array new_args = translate_firstarg(ui, args); Array new_args = translate_firstarg(ui, args, &arena);
push_call(ui, name, new_args); push_call(ui, name, new_args);
api_free_array(new_args); goto free_ret;
return;
} }
} }
@ -1022,19 +1023,18 @@ static void remote_ui_event(UI *ui, char *name, Array args)
if (data->wildmenu_active) { if (data->wildmenu_active) {
Array new_args = data->call_buf; Array new_args = data->call_buf;
Array items = args.items[0].data.array; Array items = args.items[0].data.array;
Array new_items = ARRAY_DICT_INIT; Array new_items = arena_array(&arena, items.size);
for (size_t i = 0; i < items.size; i++) { for (size_t i = 0; i < items.size; i++) {
ADD(new_items, copy_object(items.items[i].data.array.items[0], NULL)); ADD_C(new_items, items.items[i].data.array.items[0]);
} }
ADD_C(new_args, ARRAY_OBJ(new_items)); ADD_C(new_args, ARRAY_OBJ(new_items));
push_call(ui, "wildmenu_show", new_args); push_call(ui, "wildmenu_show", new_args);
api_free_array(new_items);
if (args.items[1].data.integer != -1) { if (args.items[1].data.integer != -1) {
Array new_args2 = data->call_buf; Array new_args2 = data->call_buf;
ADD_C(new_args2, args.items[1]); ADD_C(new_args2, args.items[1]);
push_call(ui, "wildmenu_select", new_args2); push_call(ui, "wildmenu_select", new_args2);
} }
return; goto free_ret;
} }
} else if (strequal(name, "popupmenu_select")) { } else if (strequal(name, "popupmenu_select")) {
if (data->wildmenu_active) { if (data->wildmenu_active) {
@ -1048,6 +1048,10 @@ static void remote_ui_event(UI *ui, char *name, Array args)
} }
push_call(ui, name, args); push_call(ui, name, args);
return;
free_ret:
arena_mem_free(arena_finish(&arena));
} }
static void remote_ui_inspect(UI *ui, Dictionary *info) static void remote_ui_inspect(UI *ui, Dictionary *info)

View File

@ -79,7 +79,7 @@
/// @param[out] err Error details, if any /// @param[out] err Error details, if any
/// @return Highlight definition map /// @return Highlight definition map
/// @see nvim_get_hl_by_id /// @see nvim_get_hl_by_id
Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err) Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3) FUNC_API_SINCE(3)
{ {
Dictionary result = ARRAY_DICT_INIT; Dictionary result = ARRAY_DICT_INIT;
@ -89,8 +89,7 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data); api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data);
return result; return result;
} }
result = nvim_get_hl_by_id(id, rgb, err); return nvim_get_hl_by_id(id, rgb, arena, err);
return result;
} }
/// Gets a highlight definition by id. |hlID()| /// Gets a highlight definition by id. |hlID()|
@ -99,7 +98,7 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
/// @param[out] err Error details, if any /// @param[out] err Error details, if any
/// @return Highlight definition map /// @return Highlight definition map
/// @see nvim_get_hl_by_name /// @see nvim_get_hl_by_name
Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err) Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3) FUNC_API_SINCE(3)
{ {
Dictionary dic = ARRAY_DICT_INIT; Dictionary dic = ARRAY_DICT_INIT;
@ -108,7 +107,7 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
return dic; return dic;
} }
int attrcode = syn_id2attr((int)hl_id); int attrcode = syn_id2attr((int)hl_id);
return hl_get_attr_by_id(attrcode, rgb, err); return hl_get_attr_by_id(attrcode, rgb, arena, err);
} }
/// Gets a highlight group by name /// Gets a highlight group by name
@ -120,10 +119,10 @@ Integer nvim_get_hl_id_by_name(String name)
return syn_check_group(name.data, name.size); return syn_check_group(name.data, name.size);
} }
Dictionary nvim__get_hl_defs(Integer ns_id, Error *err) Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err)
{ {
if (ns_id == 0) { if (ns_id == 0) {
return get_global_hl_defs(); return get_global_hl_defs(arena);
} }
abort(); abort();
} }
@ -1934,7 +1933,7 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di
} }
/// NB: if your UI doesn't use hlstate, this will not return hlstate first time /// NB: if your UI doesn't use hlstate, this will not return hlstate first time
Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err) Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, Error *err)
{ {
Array ret = ARRAY_DICT_INIT; Array ret = ARRAY_DICT_INIT;
@ -1958,13 +1957,14 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
|| col < 0 || col >= g->cols) { || col < 0 || col >= g->cols) {
return ret; return ret;
} }
ret = arena_array(arena, 3);
size_t off = g->line_offset[(size_t)row] + (size_t)col; size_t off = g->line_offset[(size_t)row] + (size_t)col;
ADD(ret, STRING_OBJ(cstr_to_string((char *)g->chars[off]))); ADD_C(ret, STRING_OBJ(cstr_as_string((char *)g->chars[off])));
int attr = g->attrs[off]; int attr = g->attrs[off];
ADD(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, err))); ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err)));
// will not work first time // will not work first time
if (!highlight_use_hlstate()) { if (!highlight_use_hlstate()) {
ADD(ret, ARRAY_OBJ(hl_inspect(attr))); ADD_C(ret, ARRAY_OBJ(hl_inspect(attr)));
} }
return ret; return ret;
} }

View File

@ -788,7 +788,7 @@ HlAttrs syn_attr2entry(int attr)
} }
/// Gets highlight description for id `attr_id` as a map. /// Gets highlight description for id `attr_id` as a map.
Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err) Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *err)
{ {
Dictionary dic = ARRAY_DICT_INIT; Dictionary dic = ARRAY_DICT_INIT;
@ -801,25 +801,21 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
"Invalid attribute id: %" PRId64, attr_id); "Invalid attribute id: %" PRId64, attr_id);
return dic; return dic;
} }
Dictionary retval = arena_dict(arena, HLATTRS_DICT_SIZE);
return hlattrs2dict(NULL, syn_attr2entry((int)attr_id), rgb); hlattrs2dict(&retval, syn_attr2entry((int)attr_id), rgb);
return retval;
} }
/// Converts an HlAttrs into Dictionary /// Converts an HlAttrs into Dictionary
/// ///
/// @param[out] hl optional pre-allocated dictionary for return value /// @param[in/out] hl Dictionary with pre-allocated space for HLATTRS_DICT_SIZE elements
/// if present, must be allocated with at least 16 elements!
/// @param[in] aep data to convert /// @param[in] aep data to convert
/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*' /// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
Dictionary hlattrs2dict(Dictionary *hl_alloc, HlAttrs ae, bool use_rgb) void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb)
{ {
assert(dict->capacity >= HLATTRS_DICT_SIZE); // at most 16 items
Dictionary hl = *dict;
int mask = use_rgb ? ae.rgb_ae_attr : ae.cterm_ae_attr; int mask = use_rgb ? ae.rgb_ae_attr : ae.cterm_ae_attr;
Dictionary hl = ARRAY_DICT_INIT;
if (hl_alloc) {
hl = *hl_alloc;
} else {
kv_ensure_space(hl, 16);
}
if (mask & HL_BOLD) { if (mask & HL_BOLD) {
PUT_C(hl, "bold", BOOLEAN_OBJ(true)); PUT_C(hl, "bold", BOOLEAN_OBJ(true));
@ -899,14 +895,7 @@ Dictionary hlattrs2dict(Dictionary *hl_alloc, HlAttrs ae, bool use_rgb)
PUT_C(hl, "blend", INTEGER_OBJ(ae.hl_blend)); PUT_C(hl, "blend", INTEGER_OBJ(ae.hl_blend));
} }
if (hl_alloc) { *dict = hl;
*hl_alloc = hl;
return hl;
} else {
Dictionary allocated = copy_dictionary(hl, NULL);
kv_destroy(hl);
return allocated;
}
} }
HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *err) HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *err)
@ -1086,6 +1075,7 @@ int object_to_color(Object val, char *key, bool rgb, Error *err)
Array hl_inspect(int attr) Array hl_inspect(int attr)
{ {
// TODO(bfredl): use arena allocation
Array ret = ARRAY_DICT_INIT; Array ret = ARRAY_DICT_INIT;
if (hlstate_active) { if (hlstate_active) {
hl_inspect_impl(&ret, attr); hl_inspect_impl(&ret, attr);

View File

@ -19,6 +19,8 @@ static inline int win_hl_attr(win_T *wp, int hlf)
return ((wp->w_ns_hl_attr && ns_hl_fast < 0) ? wp->w_ns_hl_attr : hl_attr_active)[hlf]; return ((wp->w_ns_hl_attr && ns_hl_fast < 0) ? wp->w_ns_hl_attr : hl_attr_active)[hlf];
} }
#define HLATTRS_DICT_SIZE 16
#define HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp) \ #define HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp) \
do { \ do { \
bool dark_ = (*p_bg == 'd'); \ bool dark_ = (*p_bg == 'd'); \

View File

@ -1466,19 +1466,21 @@ static void highlight_list_one(const int id)
} }
} }
Dictionary get_global_hl_defs(void) Dictionary get_global_hl_defs(Arena *arena)
{ {
Dictionary rv = ARRAY_DICT_INIT; Dictionary rv = arena_dict(arena, (size_t)highlight_ga.ga_len);
for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) { for (int i = 1; i <= highlight_ga.ga_len; i++) {
Dictionary attrs = ARRAY_DICT_INIT; Dictionary attrs = ARRAY_DICT_INIT;
HlGroup *h = &hl_table[i - 1]; HlGroup *h = &hl_table[i - 1];
if (h->sg_attr > 0) { if (h->sg_attr > 0) {
attrs = hlattrs2dict(NULL, syn_attr2entry(h->sg_attr), true); attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&attrs, syn_attr2entry(h->sg_attr), true);
} else if (h->sg_link > 0) { } else if (h->sg_link > 0) {
const char *link = (const char *)hl_table[h->sg_link - 1].sg_name; attrs = arena_dict(arena, 1);
PUT(attrs, "link", STRING_OBJ(cstr_to_string(link))); char *link = (char *)hl_table[h->sg_link - 1].sg_name;
PUT_C(attrs, "link", STRING_OBJ(cstr_as_string(link)));
} }
PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs)); PUT_C(rv, (char *)h->sg_name, DICTIONARY_OBJ(attrs));
} }
return rv; return rv;