mirror of
https://github.com/neovim/neovim.git
synced 2025-10-07 10:26:31 +00:00
refactor(eval): use arena when converting typvals to Object
Note: this contains two _temporary_ changes which can be reverted once the Arena vs no-Arena distinction in API wrappers has been removed. Both nlua_push_Object and object_to_vim_take_luaref() has been changed to take the object argument as a pointer. This is not going to be necessary once these are only used with arena (or not at all) allocated Objects. The object_to_vim() variant which leaves luaref untouched might need to stay for a little longer.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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, \
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user