Merge pull request #27460 from bfredl/merarena

refactor(eval): use arena when converting typvals to Object
This commit is contained in:
bfredl 2024-02-15 11:10:45 +01:00 committed by GitHub
commit c6f7419420
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 227 additions and 192 deletions

View File

@ -869,7 +869,7 @@ Integer nvim_buf_get_offset(Buffer buffer, Integer index, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
Object nvim_buf_get_var(Buffer buffer, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -878,7 +878,7 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
return (Object)OBJECT_INIT;
}
return dict_get_value(buf->b_vars, name, err);
return dict_get_value(buf->b_vars, name, arena, err);
}
/// Gets a changed tick of a buffer
@ -957,7 +957,7 @@ void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err)
return;
}
dict_set_var(buf->b_vars, name, value, false, false, err);
dict_set_var(buf->b_vars, name, value, false, false, NULL, err);
}
/// Removes a buffer-scoped (b:) variable
@ -974,7 +974,7 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err)
return;
}
dict_set_var(buf->b_vars, name, NIL, true, false, err);
dict_set_var(buf->b_vars, name, NIL, true, false, NULL, err);
}
/// Gets the full file name for the buffer
@ -1175,7 +1175,7 @@ Boolean nvim_buf_set_mark(Buffer buffer, String name, Integer line, Integer col,
/// uppercase/file mark set in another buffer.
/// @see |nvim_buf_set_mark()|
/// @see |nvim_buf_del_mark()|
ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
@ -1205,8 +1205,9 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
pos = fm->mark;
}
ADD(rv, INTEGER_OBJ(pos.lnum));
ADD(rv, INTEGER_OBJ(pos.col));
rv = arena_array(arena, 2);
ADD_C(rv, INTEGER_OBJ(pos.lnum));
ADD_C(rv, INTEGER_OBJ(pos.col));
return rv;
}

View File

@ -305,7 +305,7 @@ end:
/// - output: (boolean, default false) Whether to return command output.
/// @param[out] err Error details, if any.
/// @return Command output (non-error, non-shell |:!|) if `output` is true, else empty string.
String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error *err)
String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(10)
{
exarg_T ea;
@ -343,7 +343,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
goto end;
});
cmdname = string_to_cstr(cmd->cmd);
cmdname = arena_string(arena, cmd->cmd).data;
ea.cmd = cmdname;
char *p = find_ex_command(&ea, NULL);
@ -352,9 +352,8 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
// autocommands defined, trigger the matching autocommands.
if (p != NULL && ea.cmdidx == CMD_SIZE && ASCII_ISUPPER(*ea.cmd)
&& has_event(EVENT_CMDUNDEFINED)) {
p = xstrdup(cmdname);
p = arena_string(arena, cmd->cmd).data;
int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL);
xfree(p);
// If the autocommands did something and didn't cause an error, try
// finding the command again.
p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd;
@ -383,28 +382,31 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
if (HAS_KEY(cmd, cmd, args)) {
// Process all arguments. Convert non-String arguments to String and check if String arguments
// have non-whitespace characters.
args = arena_array(arena, cmd->args.size);
for (size_t i = 0; i < cmd->args.size; i++) {
Object elem = cmd->args.items[i];
char *data_str;
switch (elem.type) {
case kObjectTypeBoolean:
data_str = xcalloc(2, sizeof(char));
data_str = arena_alloc(arena, 2, false);
data_str[0] = elem.data.boolean ? '1' : '0';
data_str[1] = '\0';
ADD_C(args, CSTR_AS_OBJ(data_str));
break;
case kObjectTypeBuffer:
case kObjectTypeWindow:
case kObjectTypeTabpage:
case kObjectTypeInteger:
data_str = xcalloc(NUMBUFLEN, sizeof(char));
data_str = arena_alloc(arena, NUMBUFLEN, false);
snprintf(data_str, NUMBUFLEN, "%" PRId64, elem.data.integer);
ADD_C(args, CSTR_AS_OBJ(data_str));
break;
case kObjectTypeString:
VALIDATE_EXP(!string_iswhite(elem.data.string), "command arg", "non-whitespace", NULL, {
goto end;
});
data_str = string_to_cstr(elem.data.string);
ADD_C(args, elem);
break;
default:
VALIDATE_EXP(false, "command arg", "valid type", api_typename(elem.type), {
@ -412,8 +414,6 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
});
break;
}
ADD(args, CSTR_AS_OBJ(data_str));
}
bool argc_valid;
@ -666,26 +666,20 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
}
if (opts->output && capture_local.ga_len > 1) {
retv = (String){
.data = capture_local.ga_data,
.size = (size_t)capture_local.ga_len,
};
// TODO(bfredl): if there are more cases like this we might want custom xfree-list in arena
retv = CBUF_TO_ARENA_STR(arena, capture_local.ga_data, (size_t)capture_local.ga_len);
// redir usually (except :echon) prepends a newline.
if (retv.data[0] == '\n') {
memmove(retv.data, retv.data + 1, retv.size - 1);
retv.data[retv.size - 1] = '\0';
retv.size = retv.size - 1;
retv.data++;
retv.size--;
}
goto end;
}
clear_ga:
if (opts->output) {
ga_clear(&capture_local);
}
end:
api_free_array(args);
xfree(cmdline);
xfree(cmdname);
xfree(ea.args);
xfree(ea.arglens);

View File

@ -362,7 +362,7 @@ void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean in
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
Object buffer_set_var(Buffer buffer, String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -371,7 +371,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
return NIL;
}
return dict_set_var(buf->b_vars, name, value, false, true, err);
return dict_set_var(buf->b_vars, name, value, false, true, arena, err);
}
/// Removes a buffer-scoped (b:) variable
@ -382,7 +382,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Old value
Object buffer_del_var(Buffer buffer, String name, Error *err)
Object buffer_del_var(Buffer buffer, String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -391,7 +391,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err)
return NIL;
}
return dict_set_var(buf->b_vars, name, NIL, true, true, err);
return dict_set_var(buf->b_vars, name, NIL, true, true, arena, err);
}
/// Sets a window-scoped (w:) variable
@ -406,7 +406,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object window_set_var(Window window, String name, Object value, Error *err)
Object window_set_var(Window window, String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@ -415,7 +415,7 @@ Object window_set_var(Window window, String name, Object value, Error *err)
return NIL;
}
return dict_set_var(win->w_vars, name, value, false, true, err);
return dict_set_var(win->w_vars, name, value, false, true, arena, err);
}
/// Removes a window-scoped (w:) variable
@ -426,7 +426,7 @@ Object window_set_var(Window window, String name, Object value, Error *err)
/// @param name variable name
/// @param[out] err Error details, if any
/// @return Old value
Object window_del_var(Window window, String name, Error *err)
Object window_del_var(Window window, String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@ -435,7 +435,7 @@ Object window_del_var(Window window, String name, Error *err)
return NIL;
}
return dict_set_var(win->w_vars, name, NIL, true, true, err);
return dict_set_var(win->w_vars, name, NIL, true, true, arena, err);
}
/// Sets a tab-scoped (t:) variable
@ -450,7 +450,7 @@ Object window_del_var(Window window, String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -459,7 +459,7 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
return NIL;
}
return dict_set_var(tab->tp_vars, name, value, false, true, err);
return dict_set_var(tab->tp_vars, name, value, false, true, arena, err);
}
/// Removes a tab-scoped (t:) variable
@ -470,7 +470,7 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Old value
Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
Object tabpage_del_var(Tabpage tabpage, String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -479,7 +479,7 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
return NIL;
}
return dict_set_var(tab->tp_vars, name, NIL, true, true, err);
return dict_set_var(tab->tp_vars, name, NIL, true, true, arena, err);
}
/// @deprecated
@ -487,18 +487,18 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
/// @warning May return nil if there was no previous value
/// OR if previous value was `v:null`.
/// @return Old value or nil if there was no previous value.
Object vim_set_var(String name, Object value, Error *err)
Object vim_set_var(String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
return dict_set_var(&globvardict, name, value, false, true, err);
return dict_set_var(&globvardict, name, value, false, true, arena, err);
}
/// @deprecated
/// @see nvim_del_var
Object vim_del_var(String name, Error *err)
Object vim_del_var(String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
return dict_set_var(&globvardict, name, NIL, true, true, err);
return dict_set_var(&globvardict, name, NIL, true, true, arena, err);
}
static int64_t convert_index(int64_t index)

View File

@ -19,6 +19,8 @@
/// Helper structure for vim_to_object
typedef struct {
kvec_withinit_t(Object, 2) stack; ///< Object stack.
Arena *arena; ///< arena where objects will be allocated
bool reuse_strdata;
} EncodedData;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@ -41,12 +43,21 @@ typedef struct {
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
kvi_push(edata->stack, FLOAT_OBJ((Float)(flt)))
static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t len)
{
if (edata->reuse_strdata) {
return STRING_OBJ(cbuf_as_string((char *)(len ? data : ""), len));
} else {
return CBUF_TO_ARENA_OBJ(edata->arena, data, len);
}
}
#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \
do { \
const size_t len_ = (size_t)(len); \
const char *const str_ = (str); \
assert(len_ == 0 || str_ != NULL); \
kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_ ? str_ : ""), len_))); \
kvi_push(edata->stack, typval_cbuf_to_obj(edata, str_, len_)); \
} while (0)
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
@ -58,10 +69,7 @@ typedef struct {
do { \
const size_t len_ = (size_t)(len); \
const blob_T *const blob_ = (blob); \
kvi_push(edata->stack, STRING_OBJ(((String) { \
.data = len_ != 0 ? xmemdupz(blob_->bv_ga.ga_data, len_) : xstrdup(""), \
.size = len_ \
}))); \
kvi_push(edata->stack, typval_cbuf_to_obj(edata, len_ ? blob_->bv_ga.ga_data : "", len_)); \
} while (0)
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
@ -90,11 +98,7 @@ typedef struct {
static inline void typval_encode_list_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
kvi_push(edata->stack, ARRAY_OBJ(((Array) {
.capacity = len,
.size = 0,
.items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.array.items)),
})));
kvi_push(edata->stack, ARRAY_OBJ(arena_array(edata->arena, len)));
}
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
@ -109,7 +113,7 @@ static inline void typval_encode_between_list_items(EncodedData *const edata)
Object *const list = &kv_last(edata->stack);
assert(list->type == kObjectTypeArray);
assert(list->data.array.size < list->data.array.capacity);
list->data.array.items[list->data.array.size++] = item;
ADD_C(list->data.array, item);
}
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \
@ -131,11 +135,7 @@ static inline void typval_encode_list_end(EncodedData *const edata)
static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
kvi_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
.capacity = len,
.size = 0,
.items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.dictionary.items)),
})));
kvi_push(edata->stack, DICTIONARY_OBJ(arena_dict(edata->arena, len)));
}
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
@ -156,9 +156,8 @@ static inline void typval_encode_after_key(EncodedData *const edata)
dict->data.dictionary.items[dict->data.dictionary.size].key
= key.data.string;
} else {
api_free_object(key);
dict->data.dictionary.items[dict->data.dictionary.size].key
= STATIC_CSTR_TO_STRING("__INVALID_KEY__");
= STATIC_CSTR_AS_STRING("__INVALID_KEY__");
}
}
@ -233,17 +232,22 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
#undef TYPVAL_ENCODE_CONV_RECURSE
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
/// Convert a vim object to an `Object` instance, recursively expanding
/// Convert a vim object to an `Object` instance, recursively converting
/// Arrays/Dictionaries.
///
/// @param obj The source object
/// @param arena if NULL, use direct allocation
/// @param reuse_strdata when true, don't copy string data to Arena but reference
/// typval strings directly. takes no effect when arena is
/// NULL
/// @return The converted value
Object vim_to_object(typval_T *obj)
Object vim_to_object(typval_T *obj, Arena *arena, bool reuse_strdata)
{
EncodedData edata;
kvi_init(edata.stack);
const int evo_ret = encode_vim_to_object(&edata, obj,
"vim_to_object argument");
edata.arena = arena;
edata.reuse_strdata = reuse_strdata;
const int evo_ret = encode_vim_to_object(&edata, obj, "vim_to_object argument");
(void)evo_ret;
assert(evo_ret == OK);
Object ret = kv_A(edata.stack, 0);
@ -259,11 +263,19 @@ Object vim_to_object(typval_T *obj)
/// set to VAR_UNKNOWN (no allocation was made for this variable).
/// @param err Error object.
void object_to_vim(Object obj, typval_T *tv, Error *err)
{
object_to_vim_take_luaref(&obj, tv, false, err);
}
/// same as object_to_vim but consumes all luarefs (nested) in `obj`
///
/// useful when `obj` is allocated on an arena
void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Error *err)
{
tv->v_type = VAR_UNKNOWN;
tv->v_lock = VAR_UNLOCKED;
switch (obj.type) {
switch (obj->type) {
case kObjectTypeNil:
tv->v_type = VAR_SPECIAL;
tv->vval.v_special = kSpecialVarNull;
@ -271,41 +283,40 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
case kObjectTypeBoolean:
tv->v_type = VAR_BOOL;
tv->vval.v_bool = obj.data.boolean ? kBoolVarTrue : kBoolVarFalse;
tv->vval.v_bool = obj->data.boolean ? kBoolVarTrue : kBoolVarFalse;
break;
case kObjectTypeBuffer:
case kObjectTypeWindow:
case kObjectTypeTabpage:
case kObjectTypeInteger:
STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T),
STATIC_ASSERT(sizeof(obj->data.integer) <= sizeof(varnumber_T),
"Integer size must be <= Vimscript number size");
tv->v_type = VAR_NUMBER;
tv->vval.v_number = (varnumber_T)obj.data.integer;
tv->vval.v_number = (varnumber_T)obj->data.integer;
break;
case kObjectTypeFloat:
tv->v_type = VAR_FLOAT;
tv->vval.v_float = obj.data.floating;
tv->vval.v_float = obj->data.floating;
break;
case kObjectTypeString:
tv->v_type = VAR_STRING;
if (obj.data.string.data == NULL) {
if (obj->data.string.data == NULL) {
tv->vval.v_string = NULL;
} else {
tv->vval.v_string = xmemdupz(obj.data.string.data,
obj.data.string.size);
tv->vval.v_string = xmemdupz(obj->data.string.data,
obj->data.string.size);
}
break;
case kObjectTypeArray: {
list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size);
list_T *const list = tv_list_alloc((ptrdiff_t)obj->data.array.size);
for (uint32_t i = 0; i < obj.data.array.size; i++) {
Object item = obj.data.array.items[i];
for (uint32_t i = 0; i < obj->data.array.size; i++) {
typval_T li_tv;
object_to_vim(item, &li_tv, err);
object_to_vim_take_luaref(&obj->data.array.items[i], &li_tv, take_luaref, err);
tv_list_append_owned_tv(list, li_tv);
}
tv_list_ref(list);
@ -318,11 +329,11 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
case kObjectTypeDictionary: {
dict_T *const dict = tv_dict_alloc();
for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
KeyValuePair item = obj.data.dictionary.items[i];
String key = item.key;
for (uint32_t i = 0; i < obj->data.dictionary.size; i++) {
KeyValuePair *item = &obj->data.dictionary.items[i];
String key = item->key;
dictitem_T *const di = tv_dict_item_alloc(key.data);
object_to_vim(item.value, &di->di_tv, err);
object_to_vim_take_luaref(&item->value, &di->di_tv, take_luaref, err);
tv_dict_add(dict, di);
}
dict->dv_refcount++;
@ -333,7 +344,13 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
}
case kObjectTypeLuaRef: {
char *name = register_luafunc(api_new_luaref(obj.data.luaref));
LuaRef ref = obj->data.luaref;
if (take_luaref) {
obj->data.luaref = LUA_NOREF;
} else {
ref = api_new_luaref(ref);
}
char *name = register_luafunc(ref);
tv->v_type = VAR_FUNC;
tv->vval.v_string = xstrdup(name);
break;

View File

@ -175,7 +175,7 @@ bool try_end(Error *err)
/// @param dict The vimscript dict
/// @param key The key
/// @param[out] err Details of an error that may have occurred
Object dict_get_value(dict_T *dict, String key, Error *err)
Object dict_get_value(dict_T *dict, String key, Arena *arena, Error *err)
{
dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
@ -184,7 +184,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
return (Object)OBJECT_INIT;
}
return vim_to_object(&di->di_tv);
return vim_to_object(&di->di_tv, arena, true);
}
dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
@ -221,7 +221,8 @@ dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
/// @param retval If true the old value will be converted and returned.
/// @param[out] err Details of an error that may have occurred
/// @return The old value if `retval` is true and the key was present, else NIL
Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retval, Error *err)
Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retval, Arena *arena,
Error *err)
{
Object rv = OBJECT_INIT;
dictitem_T *di = dict_check_writable(dict, key, del, err);
@ -244,7 +245,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
}
// Return the old value
if (retval) {
rv = vim_to_object(&di->di_tv);
rv = vim_to_object(&di->di_tv, arena, false);
}
// Delete the entry
tv_dict_item_remove(dict, di);
@ -265,7 +266,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
} else {
// Return the old value
if (retval) {
rv = vim_to_object(&di->di_tv);
rv = vim_to_object(&di->di_tv, arena, false);
}
bool type_error = false;
if (dict == &vimvardict

View File

@ -35,6 +35,7 @@
#define CSTR_TO_ARENA_STR(arena, s) arena_string(arena, cstr_as_string(s))
#define CSTR_TO_ARENA_OBJ(arena, s) STRING_OBJ(CSTR_TO_ARENA_STR(arena, s))
#define CBUF_TO_ARENA_STR(arena, s, len) arena_string(arena, cbuf_as_string((char *)(s), len))
#define CBUF_TO_ARENA_OBJ(arena, s, len) STRING_OBJ(CBUF_TO_ARENA_STR(arena, s, len))
#define BUFFER_OBJ(s) ((Object) { \
.type = kObjectTypeBuffer, \

View File

@ -49,7 +49,7 @@ ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
Object nvim_tabpage_get_var(Tabpage tabpage, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -58,7 +58,7 @@ Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
return (Object)OBJECT_INIT;
}
return dict_get_value(tab->tp_vars, name, err);
return dict_get_value(tab->tp_vars, name, arena, err);
}
/// Sets a tab-scoped (t:) variable
@ -76,7 +76,7 @@ void nvim_tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err
return;
}
dict_set_var(tab->tp_vars, name, value, false, false, err);
dict_set_var(tab->tp_vars, name, value, false, false, NULL, err);
}
/// Removes a tab-scoped (t:) variable
@ -93,7 +93,7 @@ void nvim_tabpage_del_var(Tabpage tabpage, String name, Error *err)
return;
}
dict_set_var(tab->tp_vars, name, NIL, true, false, err);
dict_set_var(tab->tp_vars, name, NIL, true, false, NULL, err);
}
/// Gets the current window in a tabpage

View File

@ -1029,12 +1029,12 @@ static Array translate_contents(UI *ui, Array contents, Arena *arena)
if (attr) {
Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb_attrs, NULL, syn_attr2entry(attr), ui->rgb, false);
ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
ADD_C(new_item, DICTIONARY_OBJ(rgb_attrs));
} else {
ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
ADD_C(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
}
ADD(new_item, item.items[1]);
ADD(new_contents, ARRAY_OBJ(new_item));
ADD_C(new_item, item.items[1]);
ADD_C(new_contents, ARRAY_OBJ(new_item));
}
return new_contents;
}

View File

@ -690,7 +690,7 @@ void nvim_del_current_line(Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_get_var(String name, Error *err)
Object nvim_get_var(String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
dictitem_T *di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size);
@ -704,7 +704,7 @@ Object nvim_get_var(String name, Error *err)
VALIDATE((di != NULL), "Key not found: %s", name.data, {
return (Object)OBJECT_INIT;
});
return vim_to_object(&di->di_tv);
return vim_to_object(&di->di_tv, arena, true);
}
/// Sets a global (g:) variable.
@ -715,7 +715,7 @@ Object nvim_get_var(String name, Error *err)
void nvim_set_var(String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
dict_set_var(&globvardict, name, value, false, false, err);
dict_set_var(&globvardict, name, value, false, false, NULL, err);
}
/// Removes a global (g:) variable.
@ -725,7 +725,7 @@ void nvim_set_var(String name, Object value, Error *err)
void nvim_del_var(String name, Error *err)
FUNC_API_SINCE(1)
{
dict_set_var(&globvardict, name, NIL, true, false, err);
dict_set_var(&globvardict, name, NIL, true, false, NULL, err);
}
/// Gets a v: variable.
@ -733,10 +733,10 @@ void nvim_del_var(String name, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_get_vvar(String name, Error *err)
Object nvim_get_vvar(String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
return dict_get_value(&vimvardict, name, err);
return dict_get_value(&vimvardict, name, arena, err);
}
/// Sets a v: variable, if it is not readonly.
@ -747,7 +747,7 @@ Object nvim_get_vvar(String name, Error *err)
void nvim_set_vvar(String name, Object value, Error *err)
FUNC_API_SINCE(6)
{
dict_set_var(&vimvardict, name, value, false, false, err);
dict_set_var(&vimvardict, name, value, false, false, NULL, err);
}
/// Echo a message.
@ -1370,7 +1370,7 @@ Dictionary nvim_get_color_map(Arena *arena)
/// @param[out] err Error details, if any
///
/// @return map of global |context|.
Dictionary nvim_get_context(Dict(context) *opts, Error *err)
Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(6)
{
Array types = ARRAY_DICT_INIT;
@ -1406,7 +1406,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err)
Context ctx = CONTEXT_INIT;
ctx_save(&ctx, int_types);
Dictionary dict = ctx_to_dict(&ctx);
Dictionary dict = ctx_to_dict(&ctx, arena);
ctx_free(&ctx);
return dict;
}
@ -2065,7 +2065,7 @@ Boolean nvim_del_mark(String name, Error *err)
/// not set.
/// @see |nvim_buf_set_mark()|
/// @see |nvim_del_mark()|
Array nvim_get_mark(String name, Dict(empty) *opts, Error *err)
Array nvim_get_mark(String name, Dict(empty) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(8)
{
Array rv = ARRAY_DICT_INIT;
@ -2113,10 +2113,11 @@ Array nvim_get_mark(String name, Dict(empty) *opts, Error *err)
col = pos.col;
}
ADD(rv, INTEGER_OBJ(row));
ADD(rv, INTEGER_OBJ(col));
ADD(rv, INTEGER_OBJ(bufnr));
ADD(rv, CSTR_TO_OBJ(filename));
rv = arena_array(arena, 4);
ADD_C(rv, INTEGER_OBJ(row));
ADD_C(rv, INTEGER_OBJ(col));
ADD_C(rv, INTEGER_OBJ(bufnr));
ADD_C(rv, CSTR_TO_ARENA_OBJ(arena, filename));
if (allocated) {
xfree(filename);

View File

@ -148,7 +148,7 @@ void nvim_command(String command, Error *err)
/// @param expr Vimscript expression string
/// @param[out] err Error details, if any
/// @return Evaluation result or expanded object
Object nvim_eval(String expr, Error *err)
Object nvim_eval(String expr, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
static int recursive = 0; // recursion depth
@ -179,7 +179,7 @@ Object nvim_eval(String expr, Error *err)
api_set_error(err, kErrorTypeException,
"Failed to evaluate expression: '%.*s'", 256, expr.data);
} else {
rv = vim_to_object(&rettv);
rv = vim_to_object(&rettv, arena, false);
}
}
@ -196,7 +196,7 @@ Object nvim_eval(String expr, Error *err)
/// @param self `self` dict, or NULL for non-dict functions
/// @param[out] err Error details, if any
/// @return Result of the function call
static Object _call_function(String fn, Array args, dict_T *self, Error *err)
static Object _call_function(String fn, Array args, dict_T *self, Arena *arena, Error *err)
{
static int recursive = 0; // recursion depth
Object rv = OBJECT_INIT;
@ -239,7 +239,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
});
if (!ERROR_SET(err)) {
rv = vim_to_object(&rettv);
rv = vim_to_object(&rettv, arena, false);
}
tv_clear(&rettv);
@ -260,10 +260,10 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
/// @return Result of the function call
Object nvim_call_function(String fn, Array args, Error *err)
Object nvim_call_function(String fn, Array args, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
return _call_function(fn, args, NULL, err);
return _call_function(fn, args, NULL, arena, err);
}
/// Calls a Vimscript |Dictionary-function| with the given arguments.
@ -275,7 +275,7 @@ Object nvim_call_function(String fn, Array args, Error *err)
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
/// @return Result of the function call
Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
Object rv = OBJECT_INIT;
@ -337,7 +337,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
goto end;
}
rv = _call_function(fn, args, self_dict, err);
rv = _call_function(fn, args, self_dict, arena, err);
end:
if (mustfree) {
tv_clear(&rettv);

View File

@ -237,7 +237,7 @@ void nvim_win_set_width(Window window, Integer width, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_win_get_var(Window window, String name, Error *err)
Object nvim_win_get_var(Window window, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@ -246,7 +246,7 @@ Object nvim_win_get_var(Window window, String name, Error *err)
return (Object)OBJECT_INIT;
}
return dict_get_value(win->w_vars, name, err);
return dict_get_value(win->w_vars, name, arena, err);
}
/// Sets a window-scoped (w:) variable
@ -264,7 +264,7 @@ void nvim_win_set_var(Window window, String name, Object value, Error *err)
return;
}
dict_set_var(win->w_vars, name, value, false, false, err);
dict_set_var(win->w_vars, name, value, false, false, NULL, err);
}
/// Removes a window-scoped (w:) variable
@ -281,7 +281,7 @@ void nvim_win_del_var(Window window, String name, Error *err)
return;
}
dict_set_var(win->w_vars, name, NIL, true, false, err);
dict_set_var(win->w_vars, name, NIL, true, false, NULL, err);
}
/// Gets the window position in display cells. First position is zero.
@ -289,15 +289,16 @@ void nvim_win_del_var(Window window, String name, Error *err)
/// @param window Window handle, or 0 for current window
/// @param[out] err Error details, if any
/// @return (row, col) tuple with the window position
ArrayOf(Integer, 2) nvim_win_get_position(Window window, Error *err)
ArrayOf(Integer, 2) nvim_win_get_position(Window window, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
if (win) {
ADD(rv, INTEGER_OBJ(win->w_winrow));
ADD(rv, INTEGER_OBJ(win->w_wincol));
rv = arena_array(arena, 2);
ADD_C(rv, INTEGER_OBJ(win->w_winrow));
ADD_C(rv, INTEGER_OBJ(win->w_wincol));
}
return rv;

View File

@ -296,7 +296,7 @@ static inline void ctx_restore_funcs(Context *ctx)
/// @param[in] sbuf msgpack_sbuffer to convert.
///
/// @return readfile()-style array representation of "sbuf".
static inline Array sbuf_to_array(msgpack_sbuffer sbuf)
static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena)
{
list_T *const list = tv_list_alloc(kListLenMayKnow);
tv_list_append_string(list, "", 0);
@ -310,7 +310,7 @@ static inline Array sbuf_to_array(msgpack_sbuffer sbuf)
.vval.v_list = list
};
Array array = vim_to_object(&list_tv).data.array;
Array array = vim_to_object(&list_tv, arena, false).data.array;
tv_clear(&list_tv);
return array;
}
@ -346,18 +346,18 @@ static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err)
/// @param[in] ctx Context to convert.
///
/// @return Dictionary representing "ctx".
Dictionary ctx_to_dict(Context *ctx)
Dictionary ctx_to_dict(Context *ctx, Arena *arena)
FUNC_ATTR_NONNULL_ALL
{
assert(ctx != NULL);
Dictionary rv = ARRAY_DICT_INIT;
Dictionary rv = arena_dict(arena, 5);
PUT(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs)));
PUT(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps)));
PUT(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs)));
PUT(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars)));
PUT(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, NULL)));
PUT_C(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs, arena)));
PUT_C(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps, arena)));
PUT_C(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs, arena)));
PUT_C(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars, arena)));
PUT_C(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, arena)));
return rv;
}

View File

@ -1355,7 +1355,7 @@ Object eval_foldtext(win_T *wp)
retval = STRING_OBJ(NULL_STRING);
} else {
if (tv.v_type == VAR_LIST) {
retval = vim_to_object(&tv);
retval = vim_to_object(&tv, NULL, false);
} else {
retval = STRING_OBJ(cstr_to_string(tv_get_string(&tv)));
}

View File

@ -359,15 +359,15 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
MsgpackRpcRequestHandler handler = *fptr.api_handler;
Array args = ARRAY_DICT_INIT;
MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars; tv->v_type != VAR_UNKNOWN; tv++) {
ADD(args, vim_to_object(tv));
ADD_C(args, vim_to_object(tv, &arena, false));
}
Error err = ERROR_INIT;
Arena res_arena = ARENA_EMPTY;
Object result = handler.fn(VIML_INTERNAL_CALL, args, &res_arena, &err);
Object result = handler.fn(VIML_INTERNAL_CALL, args, &arena, &err);
if (ERROR_SET(&err)) {
semsg_multiline(e_api_error, err.msg);
@ -377,12 +377,10 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
object_to_vim(result, rettv, &err);
end:
api_free_array(args);
if (handler.arena_return) {
arena_mem_free(arena_finish(&res_arena));
} else {
if (!handler.arena_return) {
api_free_object(result);
}
arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
}
@ -1037,10 +1035,11 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
Dictionary ctx_dict = ctx_to_dict(ctx);
Arena arena = ARENA_EMPTY;
Dictionary ctx_dict = ctx_to_dict(ctx, &arena);
Error err = ERROR_INIT;
object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err);
api_free_dictionary(ctx_dict);
arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
}
@ -1108,7 +1107,8 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const int save_did_emsg = did_emsg;
did_emsg = false;
Dictionary dict = vim_to_object(&argvars[0]).data.dictionary;
Arena arena = ARENA_EMPTY;
Dictionary dict = vim_to_object(&argvars[0], &arena, true).data.dictionary;
Context tmp = CONTEXT_INIT;
Error err = ERROR_INIT;
ctx_from_dict(dict, &tmp, &err);
@ -1121,7 +1121,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
*ctx = tmp;
}
api_free_dictionary(dict);
arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
did_emsg = save_did_emsg;
}
@ -6883,16 +6883,17 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
Array args = ARRAY_DICT_INIT;
MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
ADD(args, vim_to_object(tv));
ADD_C(args, vim_to_object(tv, &arena, true));
}
bool ok = rpc_send_event((uint64_t)argvars[0].vval.v_number,
tv_get_string(&argvars[1]), args);
api_free_array(args);
arena_mem_free(arena_finish(&arena));
if (!ok) {
semsg(_(e_invarg2), "Channel doesn't exist");
@ -6922,10 +6923,11 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
Array args = ARRAY_DICT_INIT;
MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
ADD(args, vim_to_object(tv));
ADD_C(args, vim_to_object(tv, &arena, true));
}
sctx_T save_current_sctx;
@ -6961,7 +6963,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
ArenaMem res_mem = NULL;
Object result = rpc_send_call(chan_id, method, args, &res_mem, &err);
api_free_array(args);
arena_mem_free(arena_finish(&arena));
if (l_provider_call_nesting) {
current_sctx = save_current_sctx;
@ -8868,10 +8870,10 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
Error err = ERROR_INIT;
// deprecated: use 'channel' buffer option
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_id"),
INTEGER_OBJ((Integer)chan->id), false, false, &err);
INTEGER_OBJ((Integer)chan->id), false, false, NULL, &err);
api_clear_error(&err);
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_pid"),
INTEGER_OBJ(pid), false, false, &err);
INTEGER_OBJ(pid), false, false, NULL, &err);
api_clear_error(&err);
channel_incref(chan);

View File

@ -845,15 +845,17 @@ exit_0:
write_shifted_output(' %s ret = %s(%s);\n', fn.return_type, fn.name, cparams)
local ret_type = real_type(fn.return_type)
local ret_mode = (ret_type == 'Object') and '&' or ''
if fn.has_lua_imp then
-- only push onto the Lua stack if we haven't already
write_shifted_output(string.format(
[[
if (lua_gettop(lstate) == 0) {
nlua_push_%s(lstate, ret, true);
nlua_push_%s(lstate, %sret, true);
}
]],
return_type
return_type,
ret_mode
))
elseif string.match(ret_type, '^KeyDict_') then
write_shifted_output(
@ -862,7 +864,12 @@ exit_0:
)
else
local special = (fn.since ~= nil and fn.since < 11)
write_shifted_output(' nlua_push_%s(lstate, ret, %s);\n', return_type, tostring(special))
write_shifted_output(
' nlua_push_%s(lstate, %sret, %s);\n',
return_type,
ret_mode,
tostring(special)
)
end
-- NOTE: we currently assume err_throw needs nothing from arena

View File

@ -719,7 +719,7 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special
}
for (size_t i = 0; i < dict.size; i++) {
nlua_push_String(lstate, dict.items[i].key, special);
nlua_push_Object(lstate, dict.items[i].value, special);
nlua_push_Object(lstate, &dict.items[i].value, special);
lua_rawset(lstate, -3);
}
}
@ -732,7 +732,7 @@ void nlua_push_Array(lua_State *lstate, const Array array, bool special)
{
lua_createtable(lstate, (int)array.size, 0);
for (size_t i = 0; i < array.size; i++) {
nlua_push_Object(lstate, array.items[i], special);
nlua_push_Object(lstate, &array.items[i], special);
lua_rawseti(lstate, -2, (int)i + 1);
}
}
@ -753,10 +753,10 @@ GENERATE_INDEX_FUNCTION(Tabpage)
/// Convert given Object to lua value
///
/// Leaves converted value on top of the stack.
void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
void nlua_push_Object(lua_State *lstate, Object *obj, bool special)
FUNC_ATTR_NONNULL_ALL
{
switch (obj.type) {
switch (obj->type) {
case kObjectTypeNil:
if (special) {
lua_pushnil(lstate);
@ -765,12 +765,14 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
}
break;
case kObjectTypeLuaRef: {
nlua_pushref(lstate, obj.data.luaref);
nlua_pushref(lstate, obj->data.luaref);
api_free_luaref(obj->data.luaref);
obj->data.luaref = LUA_NOREF;
break;
}
#define ADD_TYPE(type, data_key) \
case kObjectType##type: { \
nlua_push_##type(lstate, obj.data.data_key, special); \
nlua_push_##type(lstate, obj->data.data_key, special); \
break; \
}
ADD_TYPE(Boolean, boolean)
@ -782,7 +784,7 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
#undef ADD_TYPE
#define ADD_REMOTE_TYPE(type) \
case kObjectType##type: { \
nlua_push_##type(lstate, (type)obj.data.integer, special); \
nlua_push_##type(lstate, (type)obj->data.integer, special); \
break; \
}
ADD_REMOTE_TYPE(Buffer)
@ -1378,7 +1380,7 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table)
lua_pushstring(L, field->str);
if (field->type == kObjectTypeNil) {
nlua_push_Object(L, *(Object *)mem, false);
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);

View File

@ -1260,7 +1260,7 @@ static int nlua_rpc(lua_State *lstate, bool request)
ArenaMem res_mem = NULL;
Object result = rpc_send_call(chan_id, name, args, &res_mem, &err);
if (!ERROR_SET(&err)) {
nlua_push_Object(lstate, result, false);
nlua_push_Object(lstate, &result, false);
arena_mem_free(res_mem);
}
} else {
@ -1563,7 +1563,7 @@ Object nlua_exec(const String str, const Array args, LuaRetMode mode, Arena *are
}
for (size_t i = 0; i < args.size; i++) {
nlua_push_Object(lstate, args.items[i], false);
nlua_push_Object(lstate, &args.items[i], false);
}
if (nlua_pcall(lstate, (int)args.size, 1)) {
@ -1610,7 +1610,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode,
nargs++;
}
for (size_t i = 0; i < args.size; i++) {
nlua_push_Object(lstate, args.items[i], false);
nlua_push_Object(lstate, &args.items[i], false);
}
if (nlua_pcall(lstate, nargs, 1)) {

View File

@ -1102,7 +1102,7 @@ static void command_line_scan(mparm_T *parmp)
}
Object md = DICTIONARY_OBJ(api_metadata());
msgpack_rpc_from_object(md, p);
msgpack_rpc_from_object(&md, p);
msgpack_packer_free(p);
const int ff_ret = file_flush(&fp);

View File

@ -22,6 +22,7 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_session.h"
#include "nvim/garray.h"
@ -2305,13 +2306,13 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
LuaRef rhs_lua = LUA_NOREF;
dictitem_T *callback_di = tv_dict_find(d, S_LEN("callback"));
if (callback_di != NULL) {
Object callback_obj = vim_to_object(&callback_di->di_tv);
if (callback_obj.type == kObjectTypeLuaRef && callback_obj.data.luaref != LUA_NOREF) {
rhs_lua = callback_obj.data.luaref;
orig_rhs = "";
callback_obj.data.luaref = LUA_NOREF;
if (callback_di->di_tv.v_type == VAR_FUNC) {
ufunc_T *fp = find_func(callback_di->di_tv.vval.v_string);
if (fp != NULL && (fp->uf_flags & FC_LUAREF)) {
rhs_lua = api_new_luaref(fp->uf_luaref);
orig_rhs = "";
}
}
api_free_object(callback_obj);
}
if (lhs == NULL || lhsraw == NULL || orig_rhs == NULL) {
emsg(_(e_entries_missing_in_mapset_dict_argument));

View File

@ -449,7 +449,7 @@ static void request_event(void **argv)
e->type,
e->request_id,
&error,
result,
&result,
&out_buffer));
}
if (!handler.arena_return) {
@ -538,7 +538,7 @@ static void send_error(Channel *chan, MsgpackRpcRequestHandler handler, MessageT
type,
id,
&e,
NIL,
&NIL,
&out_buffer));
api_clear_error(&e);
}
@ -669,7 +669,7 @@ static WBuffer *serialize_request(uint64_t channel_id, uint32_t request_id, cons
}
static WBuffer *serialize_response(uint64_t channel_id, MsgpackRpcRequestHandler handler,
MessageType type, uint32_t response_id, Error *err, Object arg,
MessageType type, uint32_t response_id, Error *err, Object *arg,
msgpack_sbuffer *sbuffer)
{
msgpack_packer pac;

View File

@ -10,6 +10,7 @@
#include "msgpack/pack.h"
#include "nvim/api/private/helpers.h"
#include "nvim/assert_defs.h"
#include "nvim/lua/executor.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/types_defs.h"
@ -309,34 +310,40 @@ static void msgpack_rpc_from_handle(ObjectType type, Integer o, msgpack_packer *
}
typedef struct {
const Object *aobj;
Object *aobj;
bool container;
size_t idx;
} APIToMPObjectStackItem;
/// Convert type used by Nvim API to msgpack type.
///
/// consumes (frees) any luaref inside `result`, even though they are not used
/// (just represented as NIL)
///
/// @param[in] result Object to convert.
/// @param[out] res Structure that defines where conversion results are saved.
///
/// @return true in case of success, false otherwise.
void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
void msgpack_rpc_from_object(Object *result, msgpack_packer *const res)
FUNC_ATTR_NONNULL_ARG(2)
{
kvec_withinit_t(APIToMPObjectStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
kvi_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 }));
kvi_push(stack, ((APIToMPObjectStackItem) { result, false, 0 }));
while (kv_size(stack)) {
APIToMPObjectStackItem cur = kv_last(stack);
STATIC_ASSERT(kObjectTypeWindow == kObjectTypeBuffer + 1
&& kObjectTypeTabpage == kObjectTypeWindow + 1,
"Buffer, window and tabpage enum items are in order");
switch (cur.aobj->type) {
case kObjectTypeNil:
case kObjectTypeLuaRef:
// TODO(bfredl): could also be an error. Though kObjectTypeLuaRef
// should only appear when the caller has opted in to handle references,
// see nlua_pop_Object.
api_free_luaref(cur.aobj->data.luaref);
cur.aobj->data.luaref = LUA_NOREF;
FALLTHROUGH;
case kObjectTypeNil:
msgpack_pack_nil(res);
break;
case kObjectTypeBoolean:
@ -415,7 +422,7 @@ void msgpack_rpc_from_array(Array result, msgpack_packer *res)
msgpack_pack_array(res, result.size);
for (size_t i = 0; i < result.size; i++) {
msgpack_rpc_from_object(result.items[i], res);
msgpack_rpc_from_object(&result.items[i], res);
}
}
@ -426,7 +433,7 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res)
for (size_t i = 0; i < result.size; i++) {
msgpack_rpc_from_string(result.items[i].key, res);
msgpack_rpc_from_object(result.items[i].value, res);
msgpack_rpc_from_object(&result.items[i].value, res);
}
}
@ -447,9 +454,9 @@ void msgpack_rpc_serialize_request(uint32_t request_id, const String method, Arr
}
/// Serializes a msgpack-rpc response
void msgpack_rpc_serialize_response(uint32_t response_id, Error *err, Object arg,
void msgpack_rpc_serialize_response(uint32_t response_id, Error *err, Object *arg,
msgpack_packer *pac)
FUNC_ATTR_NONNULL_ARG(2, 4)
FUNC_ATTR_NONNULL_ALL
{
msgpack_pack_array(pac, 4);
msgpack_pack_int(pac, 1);

View File

@ -343,7 +343,6 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
if (name) {
int dummy;
RgbValue color_val = name_to_color(name, &dummy);
xfree(name);
if (color_val != -1) {
VTermColor color;
@ -1003,6 +1002,7 @@ static void buf_set_term_title(buf_T *buf, const char *title, size_t len)
STRING_OBJ(((String){ .data = (char *)title, .size = len })),
false,
false,
NULL,
&err);
api_clear_error(&err);
status_redraw_buf(buf);
@ -1883,10 +1883,10 @@ static char *get_config_string(char *key)
{
Error err = ERROR_INIT;
// Only called from terminal_open where curbuf->terminal is the context.
Object obj = dict_get_value(curbuf->b_vars, cstr_as_string(key), &err);
Object obj = dict_get_value(curbuf->b_vars, cstr_as_string(key), NULL, &err);
api_clear_error(&err);
if (obj.type == kObjectTypeNil) {
obj = dict_get_value(&globvardict, cstr_as_string(key), &err);
obj = dict_get_value(&globvardict, cstr_as_string(key), NULL, &err);
api_clear_error(&err);
}
if (obj.type == kObjectTypeString) {

View File

@ -22,7 +22,7 @@ local api = cimport('./src/nvim/api/private/helpers.h', './src/nvim/api/private/
describe('vim_to_object', function()
local vim_to_object = function(l)
return obj2lua(api.vim_to_object(lua2typvalt(l)))
return obj2lua(api.vim_to_object(lua2typvalt(l), nil, false))
end
local different_output_test = function(name, input, output)
@ -92,13 +92,13 @@ describe('vim_to_object', function()
itp('outputs empty list for NULL list', function()
local tt = typvalt('VAR_LIST', { v_list = NULL })
eq(nil, tt.vval.v_list)
eq({ [type_key] = list_type }, obj2lua(api.vim_to_object(tt)))
eq({ [type_key] = list_type }, obj2lua(api.vim_to_object(tt, nil, false)))
end)
itp('outputs empty dict for NULL dict', function()
local tt = typvalt('VAR_DICT', { v_dict = NULL })
eq(nil, tt.vval.v_dict)
eq({}, obj2lua(api.vim_to_object(tt)))
eq({}, obj2lua(api.vim_to_object(tt, nil, false)))
end)
itp('regression: partials in a list', function()
@ -113,6 +113,6 @@ describe('vim_to_object', function()
}
local list = lua2typvalt(llist)
eq(llist, typvalt2lua(list))
eq({ nil_value, {} }, obj2lua(api.vim_to_object(list)))
eq({ nil_value, {} }, obj2lua(api.vim_to_object(list, nil, false)))
end)
end)