refactor(api): use keydict and arena for more api return values

Implement api_keydict_to_dict as the complement to api_dict_to_keydict

Fix a conversion error when nvim_get_win_config gets called from lua,
where Float values "x" and "y" didn't get converted to lua numbers.
This commit is contained in:
bfredl
2024-01-31 22:02:06 +01:00
parent 24d26b4cd1
commit f9d81c43d2
10 changed files with 252 additions and 115 deletions

View File

@@ -1688,7 +1688,7 @@ def filter_source(filename, keep_tmpfiles):
else: else:
"""Filters the source to fix macros that confuse Doxygen.""" """Filters the source to fix macros that confuse Doxygen."""
with open(filename, 'rt') as fp: with open(filename, 'rt') as fp:
print(re.sub(r'^(ArrayOf|DictionaryOf)(\(.*?\))', print(re.sub(r'^(ArrayOf|DictionaryOf|Dict)(\(.*?\))',
lambda m: m.group(1)+'_'.join( lambda m: m.group(1)+'_'.join(
re.split(r'[^\w]+', m.group(2))), re.split(r'[^\w]+', m.group(2))),
fp.read(), flags=re.M)) fp.read(), flags=re.M))

View File

@@ -105,73 +105,81 @@ bool ns_initialized(uint32_t ns)
return ns < (uint32_t)next_namespace_id; return ns < (uint32_t)next_namespace_id;
} }
Array virt_text_to_array(VirtText vt, bool hl_name) Array virt_text_to_array(VirtText vt, bool hl_name, Arena *arena)
{ {
Array chunks = ARRAY_DICT_INIT; Array chunks = arena_array(arena, kv_size(vt));
Array hl_array = ARRAY_DICT_INIT;
for (size_t i = 0; i < kv_size(vt); i++) { for (size_t i = 0; i < kv_size(vt); i++) {
size_t j = i;
for (; j < kv_size(vt); j++) {
if (kv_A(vt, j).text != NULL) {
break;
}
}
Array hl_array = arena_array(arena, i < j ? j - i + 1 : 0);
for (; i < j; i++) {
int hl_id = kv_A(vt, i).hl_id;
if (hl_id > 0) {
ADD_C(hl_array, hl_group_name(hl_id, hl_name));
}
}
char *text = kv_A(vt, i).text; char *text = kv_A(vt, i).text;
int hl_id = kv_A(vt, i).hl_id; int hl_id = kv_A(vt, i).hl_id;
if (text == NULL) { Array chunk = arena_array(arena, 2);
if (hl_id > 0) { ADD_C(chunk, CSTR_AS_OBJ(text));
ADD(hl_array, hl_group_name(hl_id, hl_name));
}
continue;
}
Array chunk = ARRAY_DICT_INIT;
ADD(chunk, CSTR_TO_OBJ(text));
if (hl_array.size > 0) { if (hl_array.size > 0) {
if (hl_id > 0) { if (hl_id > 0) {
ADD(hl_array, hl_group_name(hl_id, hl_name)); ADD_C(hl_array, hl_group_name(hl_id, hl_name));
} }
ADD(chunk, ARRAY_OBJ(hl_array)); ADD_C(chunk, ARRAY_OBJ(hl_array));
hl_array = (Array)ARRAY_DICT_INIT;
} else if (hl_id > 0) { } else if (hl_id > 0) {
ADD(chunk, hl_group_name(hl_id, hl_name)); ADD_C(chunk, hl_group_name(hl_id, hl_name));
} }
ADD(chunks, ARRAY_OBJ(chunk)); ADD_C(chunks, ARRAY_OBJ(chunk));
} }
assert(hl_array.size == 0);
return chunks; return chunks;
} }
static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_name) static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_name, Arena *arena)
{ {
MTKey start = extmark.start; MTKey start = extmark.start;
Array rv = ARRAY_DICT_INIT; Array rv = arena_array(arena, 4);
if (id) { if (id) {
ADD(rv, INTEGER_OBJ((Integer)start.id)); ADD_C(rv, INTEGER_OBJ((Integer)start.id));
} }
ADD(rv, INTEGER_OBJ(start.pos.row)); ADD_C(rv, INTEGER_OBJ(start.pos.row));
ADD(rv, INTEGER_OBJ(start.pos.col)); ADD_C(rv, INTEGER_OBJ(start.pos.col));
if (add_dict) { if (add_dict) {
Dictionary dict = ARRAY_DICT_INIT; // TODO(bfredl): coding the size like this is a bit fragile.
// We want ArrayOf(Dict(set_extmark)) as the return type..
Dictionary dict = arena_dict(arena, ARRAY_SIZE(set_extmark_table));
PUT(dict, "ns_id", INTEGER_OBJ((Integer)start.ns)); PUT_C(dict, "ns_id", INTEGER_OBJ((Integer)start.ns));
PUT(dict, "right_gravity", BOOLEAN_OBJ(mt_right(start))); PUT_C(dict, "right_gravity", BOOLEAN_OBJ(mt_right(start)));
if (mt_paired(start)) { if (mt_paired(start)) {
PUT(dict, "end_row", INTEGER_OBJ(extmark.end_pos.row)); PUT_C(dict, "end_row", INTEGER_OBJ(extmark.end_pos.row));
PUT(dict, "end_col", INTEGER_OBJ(extmark.end_pos.col)); PUT_C(dict, "end_col", INTEGER_OBJ(extmark.end_pos.col));
PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity)); PUT_C(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity));
} }
if (mt_no_undo(start)) { if (mt_no_undo(start)) {
PUT(dict, "undo_restore", BOOLEAN_OBJ(false)); PUT_C(dict, "undo_restore", BOOLEAN_OBJ(false));
} }
if (mt_invalidate(start)) { if (mt_invalidate(start)) {
PUT(dict, "invalidate", BOOLEAN_OBJ(true)); PUT_C(dict, "invalidate", BOOLEAN_OBJ(true));
} }
if (mt_invalid(start)) { if (mt_invalid(start)) {
PUT(dict, "invalid", BOOLEAN_OBJ(true)); PUT_C(dict, "invalid", BOOLEAN_OBJ(true));
} }
decor_to_dict_legacy(&dict, mt_decor(start), hl_name); decor_to_dict_legacy(&dict, mt_decor(start), hl_name, arena);
ADD(rv, DICTIONARY_OBJ(dict)); ADD_C(rv, DICTIONARY_OBJ(dict));
} }
return rv; return rv;
@@ -190,7 +198,7 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na
/// absent /// absent
ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
Integer id, Dict(get_extmark) *opts, Integer id, Dict(get_extmark) *opts,
Error *err) Arena *arena, Error *err)
FUNC_API_SINCE(7) FUNC_API_SINCE(7)
{ {
Array rv = ARRAY_DICT_INIT; Array rv = ARRAY_DICT_INIT;
@@ -213,7 +221,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
if (extmark.start.pos.row < 0) { if (extmark.start.pos.row < 0) {
return rv; return rv;
} }
return extmark_to_array(extmark, false, details, hl_name); return extmark_to_array(extmark, false, details, hl_name, arena);
} }
/// Gets |extmarks| in "traversal order" from a |charwise| region defined by /// Gets |extmarks| in "traversal order" from a |charwise| region defined by
@@ -272,7 +280,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
/// @param[out] err Error details, if any /// @param[out] err Error details, if any
/// @return List of [extmark_id, row, col] tuples in "traversal order". /// @return List of [extmark_id, row, col] tuples in "traversal order".
Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object end, Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object end,
Dict(get_extmarks) *opts, Error *err) Dict(get_extmarks) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(7) FUNC_API_SINCE(7)
{ {
Array rv = ARRAY_DICT_INIT; Array rv = ARRAY_DICT_INIT;
@@ -336,8 +344,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
ExtmarkInfoArray marks = extmark_get(buf, (uint32_t)ns_id, l_row, l_col, u_row, ExtmarkInfoArray marks = extmark_get(buf, (uint32_t)ns_id, l_row, l_col, u_row,
u_col, (int64_t)limit, reverse, type, opts->overlap); u_col, (int64_t)limit, reverse, type, opts->overlap);
rv = arena_array(arena, kv_size(marks));
for (size_t i = 0; i < kv_size(marks); i++) { for (size_t i = 0; i < kv_size(marks); i++) {
ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name))); ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name, arena)));
} }
kv_destroy(marks); kv_destroy(marks);

View File

@@ -1014,6 +1014,54 @@ bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error
return true; return true;
} }
Dictionary api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size, Arena *arena)
{
Dictionary rv = arena_dict(arena, max_size);
for (size_t i = 0; table[i].str; i++) {
KeySetLink *field = &table[i];
bool is_set = true;
if (field->opt_index >= 0) {
OptKeySet *ks = (OptKeySet *)value;
is_set = ks->is_set_ & (1ULL << field->opt_index);
}
if (!is_set) {
continue;
}
char *mem = ((char *)value + field->ptr_off);
Object val = NIL;
if (field->type == kObjectTypeNil) {
val = *(Object *)mem;
} else if (field->type == kObjectTypeInteger) {
val = INTEGER_OBJ(*(Integer *)mem);
} else if (field->type == kObjectTypeFloat) {
val = FLOAT_OBJ(*(Float *)mem);
} else if (field->type == kObjectTypeBoolean) {
val = BOOLEAN_OBJ(*(Boolean *)mem);
} else if (field->type == kObjectTypeString) {
val = STRING_OBJ(*(String *)mem);
} else if (field->type == kObjectTypeArray) {
val = ARRAY_OBJ(*(Array *)mem);
} else if (field->type == kObjectTypeDictionary) {
val = DICTIONARY_OBJ(*(Dictionary *)mem);
} else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
|| field->type == kObjectTypeTabpage) {
val.data.integer = *(Integer *)mem;
val.type = field->type;
} else if (field->type == kObjectTypeLuaRef) {
// do nothing
} else {
abort();
}
PUT_C(rv, field->str, val);
}
return rv;
}
void api_free_keydict(void *dict, KeySetLink *table) void api_free_keydict(void *dict, KeySetLink *table)
{ {
for (size_t i = 0; table[i].str; i++) { for (size_t i = 0; table[i].str; i++) {

View File

@@ -32,6 +32,7 @@
#define CSTR_AS_OBJ(s) STRING_OBJ(cstr_as_string(s)) #define CSTR_AS_OBJ(s) STRING_OBJ(cstr_as_string(s))
#define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s)) #define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s))
#define CSTR_TO_ARENA_OBJ(arena, s) STRING_OBJ(arena_string(arena, cstr_as_string(s)))
#define BUFFER_OBJ(s) ((Object) { \ #define BUFFER_OBJ(s) ((Object) { \
.type = kObjectTypeBuffer, \ .type = kObjectTypeBuffer, \
@@ -70,6 +71,9 @@
#define PUT_C(dict, k, v) \ #define PUT_C(dict, k, v) \
kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v })) kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v }))
#define PUT_KEY(d, typ, key, v) \
do { (d).is_set__##typ##_ |= (1 << KEYSET_OPTIDX_##typ##__##key); (d).key = v; } while (0)
#define ADD(array, item) \ #define ADD(array, item) \
kv_push(array, item) kv_push(array, item)

View File

@@ -539,30 +539,24 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err)
#undef HAS_KEY_X #undef HAS_KEY_X
} }
static Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, #define PUT_KEY_X(d, key, value) PUT_KEY(d, float_config, key, value)
BorderTextType bordertext_type) static void config_put_bordertext(Dict(float_config) *config, FloatConfig *fconfig,
BorderTextType bordertext_type, Arena *arena)
{ {
VirtText vt; VirtText vt;
AlignTextPos align; AlignTextPos align;
char *field_name;
char *field_pos_name;
switch (bordertext_type) { switch (bordertext_type) {
case kBorderTextTitle: case kBorderTextTitle:
vt = fconfig->title_chunks; vt = fconfig->title_chunks;
align = fconfig->title_pos; align = fconfig->title_pos;
field_name = "title";
field_pos_name = "title_pos";
break; break;
case kBorderTextFooter: case kBorderTextFooter:
vt = fconfig->footer_chunks; vt = fconfig->footer_chunks;
align = fconfig->footer_pos; align = fconfig->footer_pos;
field_name = "footer";
field_pos_name = "footer_pos";
break; break;
} }
Array bordertext = virt_text_to_array(vt, true); Array bordertext = virt_text_to_array(vt, true, arena);
PUT(config, field_name, ARRAY_OBJ(bordertext));
char *pos; char *pos;
switch (align) { switch (align) {
@@ -576,9 +570,16 @@ static Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig,
pos = "right"; pos = "right";
break; break;
} }
PUT(config, field_pos_name, CSTR_TO_OBJ(pos));
return config; switch (bordertext_type) {
case kBorderTextTitle:
PUT_KEY_X(*config, title, ARRAY_OBJ(bordertext));
PUT_KEY_X(*config, title_pos, cstr_as_string(pos));
break;
case kBorderTextFooter:
PUT_KEY_X(*config, footer, ARRAY_OBJ(bordertext));
PUT_KEY_X(*config, footer_pos, cstr_as_string(pos));
}
} }
/// Gets window configuration. /// Gets window configuration.
@@ -590,7 +591,7 @@ static Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig,
/// @param window Window handle, or 0 for current window /// @param window Window handle, or 0 for current window
/// @param[out] err Error details, if any /// @param[out] err Error details, if any
/// @return Map defining the window configuration, see |nvim_open_win()| /// @return Map defining the window configuration, see |nvim_open_win()|
Dictionary nvim_win_get_config(Window window, Error *err) Dict(float_config) nvim_win_get_config(Window window, Arena *arena, Error *err)
FUNC_API_SINCE(6) FUNC_API_SINCE(6)
{ {
/// Keep in sync with FloatRelative in buffer_defs.h /// Keep in sync with FloatRelative in buffer_defs.h
@@ -599,7 +600,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
/// Keep in sync with WinSplit in buffer_defs.h /// Keep in sync with WinSplit in buffer_defs.h
static const char *const win_split_str[] = { "left", "right", "above", "below" }; static const char *const win_split_str[] = { "left", "right", "above", "below" };
Dictionary rv = ARRAY_DICT_INIT; Dict(float_config) rv = { 0 };
win_T *wp = find_window_by_handle(window, err); win_T *wp = find_window_by_handle(window, err);
if (!wp) { if (!wp) {
@@ -608,65 +609,62 @@ Dictionary nvim_win_get_config(Window window, Error *err)
FloatConfig *config = &wp->w_float_config; FloatConfig *config = &wp->w_float_config;
PUT(rv, "focusable", BOOLEAN_OBJ(config->focusable)); PUT_KEY_X(rv, focusable, config->focusable);
PUT(rv, "external", BOOLEAN_OBJ(config->external)); PUT_KEY_X(rv, external, config->external);
PUT(rv, "hide", BOOLEAN_OBJ(config->hide)); PUT_KEY_X(rv, hide, config->hide);
if (wp->w_floating) { if (wp->w_floating) {
PUT(rv, "width", INTEGER_OBJ(config->width)); PUT_KEY_X(rv, width, config->width);
PUT(rv, "height", INTEGER_OBJ(config->height)); PUT_KEY_X(rv, height, config->height);
if (!config->external) { if (!config->external) {
if (config->relative == kFloatRelativeWindow) { if (config->relative == kFloatRelativeWindow) {
PUT(rv, "win", INTEGER_OBJ(config->window)); PUT_KEY_X(rv, win, config->window);
if (config->bufpos.lnum >= 0) { if (config->bufpos.lnum >= 0) {
Array pos = ARRAY_DICT_INIT; Array pos = arena_array(arena, 2);
ADD(pos, INTEGER_OBJ(config->bufpos.lnum)); ADD_C(pos, INTEGER_OBJ(config->bufpos.lnum));
ADD(pos, INTEGER_OBJ(config->bufpos.col)); ADD_C(pos, INTEGER_OBJ(config->bufpos.col));
PUT(rv, "bufpos", ARRAY_OBJ(pos)); PUT_KEY_X(rv, bufpos, pos);
} }
} }
PUT(rv, "anchor", CSTR_TO_OBJ(float_anchor_str[config->anchor])); PUT_KEY_X(rv, anchor, cstr_as_string((char *)float_anchor_str[config->anchor]));
PUT(rv, "row", FLOAT_OBJ(config->row)); PUT_KEY_X(rv, row, config->row);
PUT(rv, "col", FLOAT_OBJ(config->col)); PUT_KEY_X(rv, col, config->col);
PUT(rv, "zindex", INTEGER_OBJ(config->zindex)); PUT_KEY_X(rv, zindex, config->zindex);
} }
if (config->border) { if (config->border) {
Array border = ARRAY_DICT_INIT; Array border = arena_array(arena, 8);
for (size_t i = 0; i < 8; i++) { for (size_t i = 0; i < 8; i++) {
Array tuple = ARRAY_DICT_INIT; String s = cstrn_as_string(config->border_chars[i], MAX_SCHAR_SIZE);
String s = cstrn_to_string(config->border_chars[i], MAX_SCHAR_SIZE);
int hi_id = config->border_hl_ids[i]; int hi_id = config->border_hl_ids[i];
char *hi_name = syn_id2name(hi_id); char *hi_name = syn_id2name(hi_id);
if (hi_name[0]) { if (hi_name[0]) {
ADD(tuple, STRING_OBJ(s)); Array tuple = arena_array(arena, 2);
ADD(tuple, CSTR_TO_OBJ(hi_name)); ADD_C(tuple, STRING_OBJ(s));
ADD(border, ARRAY_OBJ(tuple)); ADD_C(tuple, CSTR_AS_OBJ(hi_name));
ADD_C(border, ARRAY_OBJ(tuple));
} else { } else {
ADD(border, STRING_OBJ(s)); ADD_C(border, STRING_OBJ(s));
} }
} }
PUT(rv, "border", ARRAY_OBJ(border)); PUT_KEY_X(rv, border, ARRAY_OBJ(border));
if (config->title) { if (config->title) {
rv = config_put_bordertext(rv, config, kBorderTextTitle); config_put_bordertext(&rv, config, kBorderTextTitle, arena);
} }
if (config->footer) { if (config->footer) {
rv = config_put_bordertext(rv, config, kBorderTextFooter); config_put_bordertext(&rv, config, kBorderTextFooter, arena);
} }
} }
} else if (!config->external) { } else if (!config->external) {
PUT(rv, "width", INTEGER_OBJ(wp->w_width)); PUT_KEY_X(rv, width, wp->w_width);
PUT(rv, "height", INTEGER_OBJ(wp->w_height)); PUT_KEY_X(rv, height, wp->w_height);
WinSplit split = win_split_dir(wp); WinSplit split = win_split_dir(wp);
PUT(rv, "split", CSTR_TO_OBJ(win_split_str[split])); PUT_KEY_X(rv, split, cstr_as_string((char *)win_split_str[split]));
} }
if (wp->w_floating && !config->external) { const char *rel = (wp->w_floating && !config->external
PUT(rv, "relative", CSTR_TO_OBJ(float_relative_str[config->relative])); ? float_relative_str[config->relative] : "");
} else { PUT_KEY_X(rv, relative, cstr_as_string((char *)rel));
PUT(rv, "relative", CSTR_TO_OBJ(""));
}
return rv; return rv;
} }

View File

@@ -919,7 +919,9 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo
} }
/// This assumes maximum one entry of each kind, which will not always be the case. /// This assumes maximum one entry of each kind, which will not always be the case.
void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name) ///
/// NB: assumes caller has allocated enough space in dict for all fields!
void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name, Arena *arena)
{ {
DecorSignHighlight sh_hl = DECOR_SIGN_HIGHLIGHT_INIT; DecorSignHighlight sh_hl = DECOR_SIGN_HIGHLIGHT_INIT;
DecorSignHighlight sh_sign = DECOR_SIGN_HIGHLIGHT_INIT; DecorSignHighlight sh_sign = DECOR_SIGN_HIGHLIGHT_INIT;
@@ -953,58 +955,58 @@ void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name)
} }
if (sh_hl.hl_id) { if (sh_hl.hl_id) {
PUT(*dict, "hl_group", hl_group_name(sh_hl.hl_id, hl_name)); PUT_C(*dict, "hl_group", hl_group_name(sh_hl.hl_id, hl_name));
PUT(*dict, "hl_eol", BOOLEAN_OBJ(sh_hl.flags & kSHHlEol)); PUT_C(*dict, "hl_eol", BOOLEAN_OBJ(sh_hl.flags & kSHHlEol));
priority = sh_hl.priority; priority = sh_hl.priority;
} }
if (sh_hl.flags & kSHConceal) { if (sh_hl.flags & kSHConceal) {
char buf[MAX_SCHAR_SIZE]; char buf[MAX_SCHAR_SIZE];
schar_get(buf, sh_hl.text[0]); schar_get(buf, sh_hl.text[0]);
PUT(*dict, "conceal", CSTR_TO_OBJ(buf)); PUT_C(*dict, "conceal", CSTR_TO_ARENA_OBJ(arena, buf));
} }
if (sh_hl.flags & kSHSpellOn) { if (sh_hl.flags & kSHSpellOn) {
PUT(*dict, "spell", BOOLEAN_OBJ(true)); PUT_C(*dict, "spell", BOOLEAN_OBJ(true));
} else if (sh_hl.flags & kSHSpellOff) { } else if (sh_hl.flags & kSHSpellOff) {
PUT(*dict, "spell", BOOLEAN_OBJ(false)); PUT_C(*dict, "spell", BOOLEAN_OBJ(false));
} }
if (sh_hl.flags & kSHUIWatched) { if (sh_hl.flags & kSHUIWatched) {
PUT(*dict, "ui_watched", BOOLEAN_OBJ(true)); PUT_C(*dict, "ui_watched", BOOLEAN_OBJ(true));
} }
if (sh_hl.url != NULL) { if (sh_hl.url != NULL) {
PUT(*dict, "url", STRING_OBJ(cstr_to_string(sh_hl.url))); PUT_C(*dict, "url", STRING_OBJ(cstr_as_string((char *)sh_hl.url)));
} }
if (virt_text) { if (virt_text) {
if (virt_text->hl_mode) { if (virt_text->hl_mode) {
PUT(*dict, "hl_mode", CSTR_TO_OBJ(hl_mode_str[virt_text->hl_mode])); PUT_C(*dict, "hl_mode", CSTR_AS_OBJ((char *)hl_mode_str[virt_text->hl_mode]));
} }
Array chunks = virt_text_to_array(virt_text->data.virt_text, hl_name); Array chunks = virt_text_to_array(virt_text->data.virt_text, hl_name, arena);
PUT(*dict, "virt_text", ARRAY_OBJ(chunks)); PUT_C(*dict, "virt_text", ARRAY_OBJ(chunks));
PUT(*dict, "virt_text_hide", BOOLEAN_OBJ(virt_text->flags & kVTHide)); PUT_C(*dict, "virt_text_hide", BOOLEAN_OBJ(virt_text->flags & kVTHide));
PUT(*dict, "virt_text_repeat_linebreak", BOOLEAN_OBJ(virt_text->flags & kVTRepeatLinebreak)); PUT_C(*dict, "virt_text_repeat_linebreak", BOOLEAN_OBJ(virt_text->flags & kVTRepeatLinebreak));
if (virt_text->pos == kVPosWinCol) { if (virt_text->pos == kVPosWinCol) {
PUT(*dict, "virt_text_win_col", INTEGER_OBJ(virt_text->col)); PUT_C(*dict, "virt_text_win_col", INTEGER_OBJ(virt_text->col));
} }
PUT(*dict, "virt_text_pos", CSTR_TO_OBJ(virt_text_pos_str[virt_text->pos])); PUT_C(*dict, "virt_text_pos", CSTR_AS_OBJ((char *)virt_text_pos_str[virt_text->pos]));
priority = virt_text->priority; priority = virt_text->priority;
} }
if (virt_lines) { if (virt_lines) {
Array all_chunks = ARRAY_DICT_INIT; Array all_chunks = arena_array(arena, kv_size(virt_lines->data.virt_lines));
bool virt_lines_leftcol = false; bool virt_lines_leftcol = false;
for (size_t i = 0; i < kv_size(virt_lines->data.virt_lines); i++) { for (size_t i = 0; i < kv_size(virt_lines->data.virt_lines); i++) {
virt_lines_leftcol = kv_A(virt_lines->data.virt_lines, i).left_col; virt_lines_leftcol = kv_A(virt_lines->data.virt_lines, i).left_col;
Array chunks = virt_text_to_array(kv_A(virt_lines->data.virt_lines, i).line, hl_name); Array chunks = virt_text_to_array(kv_A(virt_lines->data.virt_lines, i).line, hl_name, arena);
ADD(all_chunks, ARRAY_OBJ(chunks)); ADD(all_chunks, ARRAY_OBJ(chunks));
} }
PUT(*dict, "virt_lines", ARRAY_OBJ(all_chunks)); PUT_C(*dict, "virt_lines", ARRAY_OBJ(all_chunks));
PUT(*dict, "virt_lines_above", BOOLEAN_OBJ(virt_lines->flags & kVTLinesAbove)); PUT_C(*dict, "virt_lines_above", BOOLEAN_OBJ(virt_lines->flags & kVTLinesAbove));
PUT(*dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol)); PUT_C(*dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol));
priority = virt_lines->priority; priority = virt_lines->priority;
} }
@@ -1012,11 +1014,11 @@ void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name)
if (sh_sign.text[0]) { if (sh_sign.text[0]) {
char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; char buf[SIGN_WIDTH * MAX_SCHAR_SIZE];
describe_sign_text(buf, sh_sign.text); describe_sign_text(buf, sh_sign.text);
PUT(*dict, "sign_text", CSTR_TO_OBJ(buf)); PUT_C(*dict, "sign_text", CSTR_TO_ARENA_OBJ(arena, buf));
} }
if (sh_sign.sign_name) { if (sh_sign.sign_name) {
PUT(*dict, "sign_name", CSTR_TO_OBJ(sh_sign.sign_name)); PUT_C(*dict, "sign_name", CSTR_AS_OBJ(sh_sign.sign_name));
} }
// uncrustify:off // uncrustify:off
@@ -1033,14 +1035,14 @@ void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name)
for (int j = 0; hls[j].name; j++) { for (int j = 0; hls[j].name; j++) {
if (hls[j].val) { if (hls[j].val) {
PUT(*dict, hls[j].name, hl_group_name(hls[j].val, hl_name)); PUT_C(*dict, hls[j].name, hl_group_name(hls[j].val, hl_name));
} }
} }
priority = sh_sign.priority; priority = sh_sign.priority;
} }
if (priority != -1) { if (priority != -1) {
PUT(*dict, "priority", INTEGER_OBJ(priority)); PUT_C(*dict, "priority", INTEGER_OBJ(priority));
} }
} }
@@ -1068,7 +1070,7 @@ uint16_t decor_type_flags(DecorInline decor)
Object hl_group_name(int hl_id, bool hl_name) Object hl_group_name(int hl_id, bool hl_name)
{ {
if (hl_name) { if (hl_name) {
return CSTR_TO_OBJ(syn_id2name(hl_id)); return CSTR_AS_OBJ(syn_id2name(hl_id));
} else { } else {
return INTEGER_OBJ(hl_id); return INTEGER_OBJ(hl_id);
} }

View File

@@ -212,6 +212,9 @@ for _, f in ipairs(functions) do
end end
f_exported.parameters[i] = param f_exported.parameters[i] = param
end end
if startswith(f.return_type, 'Dict(') then
f_exported.return_type = 'Dictionary'
end
exported_functions[#exported_functions + 1] = f_exported exported_functions[#exported_functions + 1] = f_exported
end end
end end
@@ -279,7 +282,7 @@ for _, k in ipairs(keysets) do
return k.name .. '_table[' .. idx .. '].str' return k.name .. '_table[' .. idx .. '].str'
end) end)
keysets_defs:write('extern KeySetLink ' .. k.name .. '_table[];\n') keysets_defs:write('extern KeySetLink ' .. k.name .. '_table[' .. (1 + #neworder) .. '];\n')
local function typename(type) local function typename(type)
if type == 'HLGroupID' then if type == 'HLGroupID' then
@@ -596,7 +599,17 @@ for i = 1, #functions do
output:write(');\n') output:write(');\n')
end end
if fn.return_type ~= 'void' then local ret_type = real_type(fn.return_type)
if string.match(ret_type, '^KeyDict_') then
local table = string.sub(ret_type, 9) .. '_table'
output:write(
'\n ret = DICTIONARY_OBJ(api_keydict_to_dict(&rv, '
.. table
.. ', ARRAY_SIZE('
.. table
.. '), arena));'
)
elseif ret_type ~= 'void' then
output:write('\n ret = ' .. string.upper(real_type(fn.return_type)) .. '_OBJ(rv);') output:write('\n ret = ' .. string.upper(real_type(fn.return_type)) .. '_OBJ(rv);')
end end
output:write('\n\ncleanup:') output:write('\n\ncleanup:')
@@ -869,7 +882,7 @@ local function process_function(fn)
output, output,
string.format( string.format(
[[ [[
const %s ret = %s(%s); %s ret = %s(%s);
]], ]],
fn.return_type, fn.return_type,
fn.name, fn.name,
@@ -877,6 +890,7 @@ local function process_function(fn)
) )
) )
local ret_type = real_type(fn.return_type)
if fn.has_lua_imp then if fn.has_lua_imp then
-- only push onto the Lua stack if we haven't already -- only push onto the Lua stack if we haven't already
write_shifted_output( write_shifted_output(
@@ -890,6 +904,16 @@ local function process_function(fn)
return_type return_type
) )
) )
elseif string.match(ret_type, '^KeyDict_') then
write_shifted_output(
output,
string.format(
[[
nlua_push_keydict(lstate, &ret, %s_table);
]],
string.sub(ret_type, 9)
)
)
else else
local special = (fn.since ~= nil and fn.since < 11) local special = (fn.since ~= nil and fn.since < 11)
write_shifted_output( write_shifted_output(

View File

@@ -1360,3 +1360,46 @@ void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_
lua_pop(L, 1); lua_pop(L, 1);
// [] // []
} }
void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table)
{
lua_createtable(L, 0, 0);
for (size_t i = 0; table[i].str; i++) {
KeySetLink *field = &table[i];
bool is_set = true;
if (field->opt_index >= 0) {
OptKeySet *ks = (OptKeySet *)value;
is_set = ks->is_set_ & (1ULL << field->opt_index);
}
if (!is_set) {
continue;
}
char *mem = ((char *)value + field->ptr_off);
lua_pushstring(L, field->str);
if (field->type == kObjectTypeNil) {
nlua_push_Object(L, *(Object *)mem, false);
} else if (field->type == kObjectTypeInteger || field->type == kObjectTypeBuffer
|| field->type == kObjectTypeWindow || field->type == kObjectTypeTabpage) {
lua_pushinteger(L, *(Integer *)mem);
} else if (field->type == kObjectTypeFloat) {
lua_pushnumber(L, *(Float *)mem);
} else if (field->type == kObjectTypeBoolean) {
lua_pushboolean(L, *(Boolean *)mem);
} else if (field->type == kObjectTypeString) {
nlua_push_String(L, *(String *)mem, false);
} else if (field->type == kObjectTypeArray) {
nlua_push_Array(L, *(Array *)mem, false);
} else if (field->type == kObjectTypeDictionary) {
nlua_push_Dictionary(L, *(Dictionary *)mem, false);
} else if (field->type == kObjectTypeLuaRef) {
nlua_pushref(L, *(LuaRef *)mem);
} else {
abort();
}
lua_rawset(L, -3);
}
}

View File

@@ -665,7 +665,7 @@ static void ui_ext_tabline_update(void)
win_T *cwp = (tp == curtab) ? curwin : tp->tp_curwin; win_T *cwp = (tp == curtab) ? curwin : tp->tp_curwin;
get_trans_bufname(cwp->w_buffer); get_trans_bufname(cwp->w_buffer);
PUT_C(tab_info, "name", STRING_OBJ(arena_string(&arena, cstr_as_string(NameBuff)))); PUT_C(tab_info, "name", CSTR_TO_ARENA_OBJ(&arena, NameBuff));
ADD_C(tabs, DICTIONARY_OBJ(tab_info)); ADD_C(tabs, DICTIONARY_OBJ(tab_info));
} }
@@ -686,7 +686,7 @@ static void ui_ext_tabline_update(void)
PUT_C(buffer_info, "buffer", BUFFER_OBJ(buf->handle)); PUT_C(buffer_info, "buffer", BUFFER_OBJ(buf->handle));
get_trans_bufname(buf); get_trans_bufname(buf);
PUT_C(buffer_info, "name", STRING_OBJ(arena_string(&arena, cstr_as_string(NameBuff)))); PUT_C(buffer_info, "name", CSTR_TO_ARENA_OBJ(&arena, NameBuff));
ADD_C(buffers, DICTIONARY_OBJ(buffer_info)); ADD_C(buffers, DICTIONARY_OBJ(buffer_info));
} }

View File

@@ -1101,6 +1101,15 @@ describe('float window', function()
local win = api.nvim_open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5, zindex=60}) local win = api.nvim_open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5, zindex=60})
local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false} local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false}
eq(expected, api.nvim_win_get_config(win)) eq(expected, api.nvim_win_get_config(win))
eq(true, exec_lua([[
local expected, win = ...
local actual = vim.api.nvim_win_get_config(win)
for k,v in pairs(expected) do
if v ~= actual[k] then
error(k)
end
end
return true]], expected, win))
eq({external=false, focusable=true, hide=false, relative='',split="left",width=40,height=6}, api.nvim_win_get_config(0)) eq({external=false, focusable=true, hide=false, relative='',split="left",width=40,height=6}, api.nvim_win_get_config(0))