mirror of
https://github.com/neovim/neovim.git
synced 2025-10-07 02:16:31 +00:00
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:
@@ -105,73 +105,81 @@ bool ns_initialized(uint32_t ns)
|
||||
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 hl_array = ARRAY_DICT_INIT;
|
||||
Array chunks = arena_array(arena, kv_size(vt));
|
||||
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;
|
||||
int hl_id = kv_A(vt, i).hl_id;
|
||||
if (text == NULL) {
|
||||
if (hl_id > 0) {
|
||||
ADD(hl_array, hl_group_name(hl_id, hl_name));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Array chunk = ARRAY_DICT_INIT;
|
||||
ADD(chunk, CSTR_TO_OBJ(text));
|
||||
Array chunk = arena_array(arena, 2);
|
||||
ADD_C(chunk, CSTR_AS_OBJ(text));
|
||||
if (hl_array.size > 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));
|
||||
hl_array = (Array)ARRAY_DICT_INIT;
|
||||
ADD_C(chunk, ARRAY_OBJ(hl_array));
|
||||
} 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;
|
||||
}
|
||||
|
||||
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;
|
||||
Array rv = ARRAY_DICT_INIT;
|
||||
Array rv = arena_array(arena, 4);
|
||||
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(rv, INTEGER_OBJ(start.pos.col));
|
||||
ADD_C(rv, INTEGER_OBJ(start.pos.row));
|
||||
ADD_C(rv, INTEGER_OBJ(start.pos.col));
|
||||
|
||||
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)) {
|
||||
PUT(dict, "end_row", INTEGER_OBJ(extmark.end_pos.row));
|
||||
PUT(dict, "end_col", INTEGER_OBJ(extmark.end_pos.col));
|
||||
PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity));
|
||||
PUT_C(dict, "end_row", INTEGER_OBJ(extmark.end_pos.row));
|
||||
PUT_C(dict, "end_col", INTEGER_OBJ(extmark.end_pos.col));
|
||||
PUT_C(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity));
|
||||
}
|
||||
|
||||
if (mt_no_undo(start)) {
|
||||
PUT(dict, "undo_restore", BOOLEAN_OBJ(false));
|
||||
PUT_C(dict, "undo_restore", BOOLEAN_OBJ(false));
|
||||
}
|
||||
|
||||
if (mt_invalidate(start)) {
|
||||
PUT(dict, "invalidate", BOOLEAN_OBJ(true));
|
||||
PUT_C(dict, "invalidate", BOOLEAN_OBJ(true));
|
||||
}
|
||||
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;
|
||||
@@ -190,7 +198,7 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na
|
||||
/// absent
|
||||
ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
|
||||
Integer id, Dict(get_extmark) *opts,
|
||||
Error *err)
|
||||
Arena *arena, Error *err)
|
||||
FUNC_API_SINCE(7)
|
||||
{
|
||||
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) {
|
||||
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
|
||||
@@ -272,7 +280,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
|
||||
/// @param[out] err Error details, if any
|
||||
/// @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,
|
||||
Dict(get_extmarks) *opts, Error *err)
|
||||
Dict(get_extmarks) *opts, Arena *arena, Error *err)
|
||||
FUNC_API_SINCE(7)
|
||||
{
|
||||
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,
|
||||
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++) {
|
||||
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);
|
||||
|
@@ -1014,6 +1014,54 @@ bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error
|
||||
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)
|
||||
{
|
||||
for (size_t i = 0; table[i].str; i++) {
|
||||
|
@@ -32,6 +32,7 @@
|
||||
|
||||
#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_ARENA_OBJ(arena, s) STRING_OBJ(arena_string(arena, cstr_as_string(s)))
|
||||
|
||||
#define BUFFER_OBJ(s) ((Object) { \
|
||||
.type = kObjectTypeBuffer, \
|
||||
@@ -70,6 +71,9 @@
|
||||
#define PUT_C(dict, k, 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) \
|
||||
kv_push(array, item)
|
||||
|
||||
|
@@ -539,30 +539,24 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err)
|
||||
#undef HAS_KEY_X
|
||||
}
|
||||
|
||||
static Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig,
|
||||
BorderTextType bordertext_type)
|
||||
#define PUT_KEY_X(d, key, value) PUT_KEY(d, float_config, key, value)
|
||||
static void config_put_bordertext(Dict(float_config) *config, FloatConfig *fconfig,
|
||||
BorderTextType bordertext_type, Arena *arena)
|
||||
{
|
||||
VirtText vt;
|
||||
AlignTextPos align;
|
||||
char *field_name;
|
||||
char *field_pos_name;
|
||||
switch (bordertext_type) {
|
||||
case kBorderTextTitle:
|
||||
vt = fconfig->title_chunks;
|
||||
align = fconfig->title_pos;
|
||||
field_name = "title";
|
||||
field_pos_name = "title_pos";
|
||||
break;
|
||||
case kBorderTextFooter:
|
||||
vt = fconfig->footer_chunks;
|
||||
align = fconfig->footer_pos;
|
||||
field_name = "footer";
|
||||
field_pos_name = "footer_pos";
|
||||
break;
|
||||
}
|
||||
|
||||
Array bordertext = virt_text_to_array(vt, true);
|
||||
PUT(config, field_name, ARRAY_OBJ(bordertext));
|
||||
Array bordertext = virt_text_to_array(vt, true, arena);
|
||||
|
||||
char *pos;
|
||||
switch (align) {
|
||||
@@ -576,9 +570,16 @@ static Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig,
|
||||
pos = "right";
|
||||
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.
|
||||
@@ -590,7 +591,7 @@ static Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig,
|
||||
/// @param window Window handle, or 0 for current window
|
||||
/// @param[out] err Error details, if any
|
||||
/// @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)
|
||||
{
|
||||
/// 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
|
||||
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);
|
||||
if (!wp) {
|
||||
@@ -608,65 +609,62 @@ Dictionary nvim_win_get_config(Window window, Error *err)
|
||||
|
||||
FloatConfig *config = &wp->w_float_config;
|
||||
|
||||
PUT(rv, "focusable", BOOLEAN_OBJ(config->focusable));
|
||||
PUT(rv, "external", BOOLEAN_OBJ(config->external));
|
||||
PUT(rv, "hide", BOOLEAN_OBJ(config->hide));
|
||||
PUT_KEY_X(rv, focusable, config->focusable);
|
||||
PUT_KEY_X(rv, external, config->external);
|
||||
PUT_KEY_X(rv, hide, config->hide);
|
||||
|
||||
if (wp->w_floating) {
|
||||
PUT(rv, "width", INTEGER_OBJ(config->width));
|
||||
PUT(rv, "height", INTEGER_OBJ(config->height));
|
||||
PUT_KEY_X(rv, width, config->width);
|
||||
PUT_KEY_X(rv, height, config->height);
|
||||
if (!config->external) {
|
||||
if (config->relative == kFloatRelativeWindow) {
|
||||
PUT(rv, "win", INTEGER_OBJ(config->window));
|
||||
PUT_KEY_X(rv, win, config->window);
|
||||
if (config->bufpos.lnum >= 0) {
|
||||
Array pos = ARRAY_DICT_INIT;
|
||||
ADD(pos, INTEGER_OBJ(config->bufpos.lnum));
|
||||
ADD(pos, INTEGER_OBJ(config->bufpos.col));
|
||||
PUT(rv, "bufpos", ARRAY_OBJ(pos));
|
||||
Array pos = arena_array(arena, 2);
|
||||
ADD_C(pos, INTEGER_OBJ(config->bufpos.lnum));
|
||||
ADD_C(pos, INTEGER_OBJ(config->bufpos.col));
|
||||
PUT_KEY_X(rv, bufpos, pos);
|
||||
}
|
||||
}
|
||||
PUT(rv, "anchor", CSTR_TO_OBJ(float_anchor_str[config->anchor]));
|
||||
PUT(rv, "row", FLOAT_OBJ(config->row));
|
||||
PUT(rv, "col", FLOAT_OBJ(config->col));
|
||||
PUT(rv, "zindex", INTEGER_OBJ(config->zindex));
|
||||
PUT_KEY_X(rv, anchor, cstr_as_string((char *)float_anchor_str[config->anchor]));
|
||||
PUT_KEY_X(rv, row, config->row);
|
||||
PUT_KEY_X(rv, col, config->col);
|
||||
PUT_KEY_X(rv, zindex, config->zindex);
|
||||
}
|
||||
if (config->border) {
|
||||
Array border = ARRAY_DICT_INIT;
|
||||
Array border = arena_array(arena, 8);
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
Array tuple = ARRAY_DICT_INIT;
|
||||
|
||||
String s = cstrn_to_string(config->border_chars[i], MAX_SCHAR_SIZE);
|
||||
String s = cstrn_as_string(config->border_chars[i], MAX_SCHAR_SIZE);
|
||||
|
||||
int hi_id = config->border_hl_ids[i];
|
||||
char *hi_name = syn_id2name(hi_id);
|
||||
if (hi_name[0]) {
|
||||
ADD(tuple, STRING_OBJ(s));
|
||||
ADD(tuple, CSTR_TO_OBJ(hi_name));
|
||||
ADD(border, ARRAY_OBJ(tuple));
|
||||
Array tuple = arena_array(arena, 2);
|
||||
ADD_C(tuple, STRING_OBJ(s));
|
||||
ADD_C(tuple, CSTR_AS_OBJ(hi_name));
|
||||
ADD_C(border, ARRAY_OBJ(tuple));
|
||||
} 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) {
|
||||
rv = config_put_bordertext(rv, config, kBorderTextTitle);
|
||||
config_put_bordertext(&rv, config, kBorderTextTitle, arena);
|
||||
}
|
||||
if (config->footer) {
|
||||
rv = config_put_bordertext(rv, config, kBorderTextFooter);
|
||||
config_put_bordertext(&rv, config, kBorderTextFooter, arena);
|
||||
}
|
||||
}
|
||||
} else if (!config->external) {
|
||||
PUT(rv, "width", INTEGER_OBJ(wp->w_width));
|
||||
PUT(rv, "height", INTEGER_OBJ(wp->w_height));
|
||||
PUT_KEY_X(rv, width, wp->w_width);
|
||||
PUT_KEY_X(rv, height, wp->w_height);
|
||||
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) {
|
||||
PUT(rv, "relative", CSTR_TO_OBJ(float_relative_str[config->relative]));
|
||||
} else {
|
||||
PUT(rv, "relative", CSTR_TO_OBJ(""));
|
||||
}
|
||||
const char *rel = (wp->w_floating && !config->external
|
||||
? float_relative_str[config->relative] : "");
|
||||
PUT_KEY_X(rv, relative, cstr_as_string((char *)rel));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
Reference in New Issue
Block a user