Merge #7806 from ZyX-I/list-stat
Add a way to collect list usage statistics
This commit is contained in:
commit
de0a9548f7
|
@ -277,6 +277,8 @@ else()
|
|||
set(DEBUG 0)
|
||||
endif()
|
||||
|
||||
option(LOG_LIST_ACTIONS "Add list actions logging" OFF)
|
||||
|
||||
add_definitions(-DINCLUDE_GENERATED_DECLARATIONS)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
|
||||
#ifndef UNIT_TESTING
|
||||
#cmakedefine HAVE_JEMALLOC
|
||||
#cmakedefine LOG_LIST_ACTIONS
|
||||
#endif
|
||||
|
||||
#cmakedefine HAVE_BE64TOH
|
||||
|
|
|
@ -783,7 +783,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
|
|||
break;
|
||||
|
||||
case kObjectTypeArray: {
|
||||
list_T *const list = tv_list_alloc();
|
||||
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];
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "nvim/api/ui.h"
|
||||
#include "nvim/channel.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/encode.h"
|
||||
#include "nvim/event/socket.h"
|
||||
#include "nvim/msgpack_rpc/channel.h"
|
||||
#include "nvim/msgpack_rpc/server.h"
|
||||
|
@ -522,32 +523,21 @@ err:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/// NB: mutates buf in place!
|
||||
static list_T *buffer_to_tv_list(char *buf, size_t count)
|
||||
/// Convert binary byte array to a readfile()-style list
|
||||
///
|
||||
/// @param[in] buf Array to convert.
|
||||
/// @param[in] len Array length.
|
||||
///
|
||||
/// @return [allocated] Converted list.
|
||||
static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
|
||||
{
|
||||
list_T *ret = tv_list_alloc();
|
||||
char *ptr = buf;
|
||||
size_t remaining = count;
|
||||
size_t off = 0;
|
||||
|
||||
while (off < remaining) {
|
||||
// append the line
|
||||
if (ptr[off] == NL) {
|
||||
tv_list_append_string(ret, ptr, (ssize_t)off);
|
||||
size_t skip = off + 1;
|
||||
ptr += skip;
|
||||
remaining -= skip;
|
||||
off = 0;
|
||||
continue;
|
||||
}
|
||||
if (ptr[off] == NUL) {
|
||||
// Translate NUL to NL
|
||||
ptr[off] = NL;
|
||||
}
|
||||
off++;
|
||||
}
|
||||
tv_list_append_string(ret, ptr, (ssize_t)off);
|
||||
return ret;
|
||||
list_T *const l = tv_list_alloc(kListLenMayKnow);
|
||||
// Empty buffer should be represented by [''], encode_list_write() thinks
|
||||
// empty list is fine for the case.
|
||||
tv_list_append_string(l, "", 0);
|
||||
encode_list_write(l, buf, len);
|
||||
return l;
|
||||
}
|
||||
|
||||
// vimscript job callbacks must be executed on Nvim main loop
|
||||
|
|
241
src/nvim/eval.c
241
src/nvim/eval.c
|
@ -568,7 +568,7 @@ void eval_init(void)
|
|||
|
||||
dict_T *const msgpack_types_dict = tv_dict_alloc();
|
||||
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
|
||||
list_T *const type_list = tv_list_alloc();
|
||||
list_T *const type_list = tv_list_alloc(0);
|
||||
tv_list_set_lock(type_list, VAR_FIXED);
|
||||
tv_list_ref(type_list);
|
||||
dictitem_T *const di = tv_dict_item_alloc(msgpack_type_names[i]);
|
||||
|
@ -591,7 +591,7 @@ void eval_init(void)
|
|||
dict_T *v_event = tv_dict_alloc();
|
||||
v_event->dv_lock = VAR_FIXED;
|
||||
set_vim_var_dict(VV_EVENT, v_event);
|
||||
set_vim_var_list(VV_ERRORS, tv_list_alloc());
|
||||
set_vim_var_list(VV_ERRORS, tv_list_alloc(kListLenUnknown));
|
||||
set_vim_var_nr(VV_STDERR, CHAN_STDERR);
|
||||
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
|
||||
set_vim_var_nr(VV_HLSEARCH, 1L);
|
||||
|
@ -1546,6 +1546,7 @@ ex_let_vars (
|
|||
assert(l != NULL);
|
||||
|
||||
listitem_T *item = tv_list_first(l);
|
||||
size_t rest_len = tv_list_len(l);
|
||||
while (*arg != ']') {
|
||||
arg = skipwhite(arg + 1);
|
||||
arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, (const char_u *)",;]",
|
||||
|
@ -1553,13 +1554,14 @@ ex_let_vars (
|
|||
if (arg == NULL) {
|
||||
return FAIL;
|
||||
}
|
||||
rest_len--;
|
||||
|
||||
item = TV_LIST_ITEM_NEXT(l, item);
|
||||
arg = skipwhite(arg);
|
||||
if (*arg == ';') {
|
||||
/* Put the rest of the list (may be empty) in the var after ';'.
|
||||
* Create a new list for this. */
|
||||
list_T *const rest_list = tv_list_alloc();
|
||||
list_T *const rest_list = tv_list_alloc(rest_len);
|
||||
while (item != NULL) {
|
||||
tv_list_append_tv(rest_list, TV_LIST_ITEM_TV(item));
|
||||
item = TV_LIST_ITEM_NEXT(l, item);
|
||||
|
@ -4512,7 +4514,7 @@ eval_index (
|
|||
if (!empty2 && (n2 < 0 || n2 + 1 < n1)) {
|
||||
n2 = -1;
|
||||
}
|
||||
l = tv_list_alloc();
|
||||
l = tv_list_alloc(n2 - n1 + 1);
|
||||
item = tv_list_find(rettv->vval.v_list, n1);
|
||||
while (n1++ <= n2) {
|
||||
tv_list_append_tv(l, TV_LIST_ITEM_TV(item));
|
||||
|
@ -4870,7 +4872,7 @@ static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||
list_T *l = NULL;
|
||||
|
||||
if (evaluate) {
|
||||
l = tv_list_alloc();
|
||||
l = tv_list_alloc(kListLenShouldKnow);
|
||||
}
|
||||
|
||||
*arg = skipwhite(*arg + 1);
|
||||
|
@ -6666,7 +6668,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
}
|
||||
rettv->v_type = VAR_STRING;
|
||||
} else {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, ARGCOUNT);
|
||||
for (idx = 0; idx < ARGCOUNT; idx++) {
|
||||
tv_list_append_string(rettv->vval.v_list,
|
||||
(const char *)alist_name(&ARGLIST[idx]), -1);
|
||||
|
@ -6776,7 +6778,7 @@ static void assert_error(garray_T *gap)
|
|||
|
||||
if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) {
|
||||
// Make sure v:errors is a list.
|
||||
set_vim_var_list(VV_ERRORS, tv_list_alloc());
|
||||
set_vim_var_list(VV_ERRORS, tv_list_alloc(1));
|
||||
}
|
||||
tv_list_append_string(vimvars[VV_ERRORS].vv_list,
|
||||
(const char *)gap->ga_data, (ptrdiff_t)gap->ga_len);
|
||||
|
@ -8225,7 +8227,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
result = eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL);
|
||||
emsg_off--;
|
||||
if (rettv->v_type == VAR_LIST) {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, (result != NULL));
|
||||
if (result != NULL) {
|
||||
tv_list_append_string(rettv->vval.v_list, (const char *)result, -1);
|
||||
}
|
||||
|
@ -8248,8 +8250,8 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
rettv->vval.v_string = ExpandOne(&xpc, (char_u *)s, NULL, options,
|
||||
WILD_ALL);
|
||||
} else {
|
||||
tv_list_alloc_ret(rettv);
|
||||
ExpandOne(&xpc, (char_u *)s, NULL, options, WILD_ALL_KEEP);
|
||||
tv_list_alloc_ret(rettv, xpc.xp_numfiles);
|
||||
for (int i = 0; i < xpc.xp_numfiles; i++) {
|
||||
tv_list_append_string(rettv->vval.v_list,
|
||||
(const char *)xpc.xp_files[i], -1);
|
||||
|
@ -8266,7 +8268,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
/// "menu_get(path [, modes])" function
|
||||
static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
int modes = MENU_ALL_MODES;
|
||||
if (argvars[1].v_type == VAR_STRING) {
|
||||
const char_u *const strmodes = (char_u *)tv_get_string(&argvars[1]);
|
||||
|
@ -8427,7 +8429,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
|
|||
}
|
||||
|
||||
if (count < 0) {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenUnknown);
|
||||
}
|
||||
|
||||
if (*fname != NUL && !error) {
|
||||
|
@ -9108,7 +9110,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
}
|
||||
} else if (strcmp(what, "args") == 0) {
|
||||
rettv->v_type = VAR_LIST;
|
||||
if (tv_list_alloc_ret(rettv) != NULL) {
|
||||
if (tv_list_alloc_ret(rettv, pt->pt_argc) != NULL) {
|
||||
for (int i = 0; i < pt->pt_argc; i++) {
|
||||
tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
|
||||
}
|
||||
|
@ -9132,8 +9134,10 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
}
|
||||
|
||||
/// Returns information about signs placed in a buffer as list of dicts.
|
||||
static void get_buffer_signs(buf_T *buf, list_T *l)
|
||||
static list_T *get_buffer_signs(buf_T *buf)
|
||||
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
list_T *const l = tv_list_alloc(kListLenMayKnow);
|
||||
for (signlist_T *sign = buf->b_signlist; sign; sign = sign->next) {
|
||||
dict_T *const d = tv_dict_alloc();
|
||||
|
||||
|
@ -9144,6 +9148,7 @@ static void get_buffer_signs(buf_T *buf, list_T *l)
|
|||
|
||||
tv_list_append_dict(l, d);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/// Returns buffer options, variables and other attributes in a dictionary.
|
||||
|
@ -9167,7 +9172,7 @@ static dict_T *get_buffer_info(buf_T *buf)
|
|||
tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
|
||||
|
||||
// List of windows displaying this buffer
|
||||
list_T *const windows = tv_list_alloc();
|
||||
list_T *const windows = tv_list_alloc(kListLenMayKnow);
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer == buf) {
|
||||
tv_list_append_number(windows, (varnumber_T)wp->handle);
|
||||
|
@ -9177,9 +9182,7 @@ static dict_T *get_buffer_info(buf_T *buf)
|
|||
|
||||
if (buf->b_signlist != NULL) {
|
||||
// List of signs placed in this buffer
|
||||
list_T *const signs = tv_list_alloc();
|
||||
get_buffer_signs(buf, signs);
|
||||
tv_dict_add_list(dict, S_LEN("signs"), signs);
|
||||
tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
|
||||
}
|
||||
|
||||
return dict;
|
||||
|
@ -9193,7 +9196,7 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
bool sel_buflisted = false;
|
||||
bool sel_bufloaded = false;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
|
||||
// List of all the buffers or selected buffers
|
||||
if (argvars[0].v_type == VAR_DICT) {
|
||||
|
@ -9252,35 +9255,31 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
*/
|
||||
static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
|
||||
rettv->vval.v_string = NULL;
|
||||
if (retlist) {
|
||||
tv_list_alloc_ret(rettv);
|
||||
|
||||
if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0 || end < start) {
|
||||
tv_list_alloc_ret(rettv, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
|
||||
return;
|
||||
|
||||
if (!retlist) {
|
||||
if (start >= 1 && start <= buf->b_ml.ml_line_count)
|
||||
p = ml_get_buf(buf, start, FALSE);
|
||||
else
|
||||
p = (char_u *)"";
|
||||
rettv->vval.v_string = vim_strsave(p);
|
||||
} else {
|
||||
if (end < start)
|
||||
return;
|
||||
|
||||
if (start < 1)
|
||||
if (retlist) {
|
||||
if (start < 1) {
|
||||
start = 1;
|
||||
if (end > buf->b_ml.ml_line_count)
|
||||
}
|
||||
if (end > buf->b_ml.ml_line_count) {
|
||||
end = buf->b_ml.ml_line_count;
|
||||
}
|
||||
tv_list_alloc_ret(rettv, end - start + 1);
|
||||
while (start <= end) {
|
||||
tv_list_append_string(rettv->vval.v_list,
|
||||
(const char *)ml_get_buf(buf, start++, false), -1);
|
||||
}
|
||||
} else {
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = ((start >= 1 && start <= buf->b_ml.ml_line_count)
|
||||
? vim_strsave(ml_get_buf(buf, start, false))
|
||||
: NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9605,8 +9604,8 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
|
||||
theend:
|
||||
pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
|
||||
tv_list_alloc_ret(rettv);
|
||||
ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
|
||||
tv_list_alloc_ret(rettv, xpc.xp_numfiles);
|
||||
|
||||
for (int i = 0; i < xpc.xp_numfiles; i++) {
|
||||
tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i],
|
||||
|
@ -9900,7 +9899,7 @@ static void f_getline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
|
||||
const linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (argvars[1].v_type == VAR_UNKNOWN) {
|
||||
end = 0;
|
||||
end = lnum;
|
||||
retlist = false;
|
||||
} else {
|
||||
end = tv_get_lnum(&argvars[1]);
|
||||
|
@ -9914,7 +9913,7 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg,
|
|||
typval_T *rettv)
|
||||
{
|
||||
if (what_arg->v_type == VAR_UNKNOWN) {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
if (is_qf || wp != NULL) {
|
||||
(void)get_errorlist(wp, -1, rettv->vval.v_list);
|
||||
}
|
||||
|
@ -9949,7 +9948,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
matchitem_T *cur = curwin->w_match_head;
|
||||
int i;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
while (cur != NULL) {
|
||||
dict_T *dict = tv_dict_alloc();
|
||||
if (cur->match.regprog == NULL) {
|
||||
|
@ -9962,7 +9961,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
if (llpos->lnum == 0) {
|
||||
break;
|
||||
}
|
||||
list_T *l = tv_list_alloc();
|
||||
list_T *const l = tv_list_alloc(1 + (llpos->col > 0 ? 2 : 0));
|
||||
tv_list_append_number(l, (varnumber_T)llpos->lnum);
|
||||
if (llpos->col > 0) {
|
||||
tv_list_append_number(l, (varnumber_T)llpos->col);
|
||||
|
@ -10011,7 +10010,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos)
|
|||
fp = var2fpos(&argvars[0], true, &fnum);
|
||||
}
|
||||
|
||||
list_T *l = tv_list_alloc_ret(rettv);
|
||||
list_T *const l = tv_list_alloc_ret(rettv, 4 + (!!getcurpos));
|
||||
tv_list_append_number(l, (fnum != -1) ? (varnumber_T)fnum : (varnumber_T)0);
|
||||
tv_list_append_number(l, ((fp != NULL)
|
||||
? (varnumber_T)fp->lnum
|
||||
|
@ -10084,10 +10083,10 @@ static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
|
||||
if (return_list) {
|
||||
rettv->v_type = VAR_LIST;
|
||||
rettv->vval.v_list =
|
||||
rettv->vval.v_list =
|
||||
get_reg_contents(regname, (arg2 ? kGRegExprSrc : 0) | kGRegList);
|
||||
if (rettv->vval.v_list == NULL) {
|
||||
rettv->vval.v_list = tv_list_alloc();
|
||||
rettv->vval.v_list = tv_list_alloc(0);
|
||||
}
|
||||
tv_list_ref(rettv->vval.v_list);
|
||||
} else {
|
||||
|
@ -10137,7 +10136,7 @@ static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
|
|||
|
||||
tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx);
|
||||
|
||||
list_T *const l = tv_list_alloc();
|
||||
list_T *const l = tv_list_alloc(kListLenMayKnow);
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
tv_list_append_number(l, (varnumber_T)wp->handle);
|
||||
}
|
||||
|
@ -10154,7 +10153,9 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
{
|
||||
tabpage_T *tparg = NULL;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, (argvars[0].v_type == VAR_UNKNOWN
|
||||
? 1
|
||||
: kListLenMayKnow));
|
||||
|
||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
// Information about one tab page
|
||||
|
@ -10253,7 +10254,7 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
{
|
||||
win_T *wparg = NULL;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
|
||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
wparg = win_id2wp(argvars);
|
||||
|
@ -10478,9 +10479,9 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
rettv->vval.v_string = ExpandOne(
|
||||
&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options, WILD_ALL);
|
||||
} else {
|
||||
tv_list_alloc_ret(rettv);
|
||||
ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options,
|
||||
WILD_ALL_KEEP);
|
||||
tv_list_alloc_ret(rettv, xpc.xp_numfiles);
|
||||
for (int i = 0; i < xpc.xp_numfiles; i++) {
|
||||
tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i],
|
||||
-1);
|
||||
|
@ -10529,7 +10530,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
if (rettv->v_type == VAR_STRING) {
|
||||
rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n");
|
||||
} else {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, ga.ga_len);
|
||||
for (int i = 0; i < ga.ga_len; i++) {
|
||||
tv_list_append_string(rettv->vval.v_list,
|
||||
((const char **)(ga.ga_data))[i], -1);
|
||||
|
@ -11429,7 +11430,7 @@ static void dict_list(typval_T *const tv, typval_T *const rettv,
|
|||
return;
|
||||
}
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, tv_dict_len(tv->vval.v_dict));
|
||||
|
||||
TV_DICT_ITER(tv->vval.v_dict, di, {
|
||||
typval_T tv = { .v_lock = VAR_UNLOCKED };
|
||||
|
@ -11446,7 +11447,7 @@ static void dict_list(typval_T *const tv, typval_T *const rettv,
|
|||
}
|
||||
case kDictListItems: {
|
||||
// items()
|
||||
list_T *const sub_l = tv_list_alloc();
|
||||
list_T *const sub_l = tv_list_alloc(2);
|
||||
tv.v_type = VAR_LIST;
|
||||
tv.vval.v_list = sub_l;
|
||||
tv_list_ref(sub_l);
|
||||
|
@ -11776,7 +11777,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
}
|
||||
}
|
||||
|
||||
list_T *rv = tv_list_alloc();
|
||||
list_T *const rv = tv_list_alloc(tv_list_len(args));
|
||||
|
||||
// restore the parent queue for any jobs still alive
|
||||
for (i = 0; i < tv_list_len(args); i++) {
|
||||
|
@ -12204,12 +12205,12 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
|
|||
switch (type) {
|
||||
// matchlist(): return empty list when there are no matches.
|
||||
case kSomeMatchList: {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
break;
|
||||
}
|
||||
// matchstrpos(): return ["", -1, -1, -1]
|
||||
case kSomeMatchStrPos: {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, 4);
|
||||
tv_list_append_string(rettv->vval.v_list, "", 0);
|
||||
tv_list_append_number(rettv->vval.v_list, -1);
|
||||
tv_list_append_number(rettv->vval.v_list, -1);
|
||||
|
@ -12516,10 +12517,12 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
*/
|
||||
static void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv);
|
||||
|
||||
const int id = tv_get_number(&argvars[0]);
|
||||
|
||||
tv_list_alloc_ret(rettv, (id >= 1 && id <= 3
|
||||
? 2
|
||||
: 0));
|
||||
|
||||
if (id >= 1 && id <= 3) {
|
||||
matchitem_T *const m = (matchitem_T *)get_match(curwin, id);
|
||||
|
||||
|
@ -12705,8 +12708,8 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
EMSG2(_(e_listarg), "msgpackdump()");
|
||||
return;
|
||||
}
|
||||
list_T *ret_list = tv_list_alloc_ret(rettv);
|
||||
list_T *list = argvars[0].vval.v_list;
|
||||
list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
list_T *const list = argvars[0].vval.v_list;
|
||||
msgpack_packer *lpacker = msgpack_packer_new(ret_list, &encode_list_write);
|
||||
const char *const msg = _("msgpackdump() argument, index %i");
|
||||
// Assume that translation will not take more then 4 times more space
|
||||
|
@ -12730,8 +12733,8 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
EMSG2(_(e_listarg), "msgpackparse()");
|
||||
return;
|
||||
}
|
||||
list_T *ret_list = tv_list_alloc_ret(rettv);
|
||||
const list_T *list = argvars[0].vval.v_list;
|
||||
list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
const list_T *const list = argvars[0].vval.v_list;
|
||||
if (tv_list_len(list) == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -12986,7 +12989,7 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
} else if (stride > 0 ? end + 1 < start : end - 1 > start) {
|
||||
emsgf(_("E727: Start past end"));
|
||||
} else {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, (end - start) / stride);
|
||||
for (i = start; stride > 0 ? i <= end : i >= end; i += stride) {
|
||||
tv_list_append_number(rettv->vval.v_list, (varnumber_T)i);
|
||||
}
|
||||
|
@ -13017,8 +13020,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
}
|
||||
}
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
list_T *const l = rettv->vval.v_list;
|
||||
list_T *const l = tv_list_alloc_ret(rettv, kListLenUnknown);
|
||||
|
||||
// Always open the file in binary mode, library functions have a mind of
|
||||
// their own about CR-LF conversion.
|
||||
|
@ -13231,7 +13233,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
STATIC_ASSERT(sizeof(u.prof) == sizeof(u) && sizeof(u.split) == sizeof(u),
|
||||
"type punning will produce incorrect results on this platform");
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, 2);
|
||||
tv_list_append_number(rettv->vval.v_list, u.split.high);
|
||||
tv_list_append_number(rettv->vval.v_list, u.split.low);
|
||||
}
|
||||
|
@ -13324,7 +13326,8 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
if (li == NULL) { // Didn't find "item2" after "item".
|
||||
emsgf(_(e_invrange));
|
||||
} else {
|
||||
tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv), cnt);
|
||||
tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv, cnt),
|
||||
cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13354,7 +13357,7 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
{
|
||||
varnumber_T n = tv_get_number(&argvars[1]);
|
||||
if (argvars[0].v_type == VAR_LIST) {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, (n > 0) * n * tv_list_len(argvars[0].vval.v_list));
|
||||
while (n-- > 0) {
|
||||
tv_list_extend(rettv->vval.v_list, argvars[0].vval.v_list, NULL);
|
||||
}
|
||||
|
@ -14124,7 +14127,7 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
int lnum = 0;
|
||||
int col = 0;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, 2);
|
||||
|
||||
if (searchpair_cmn(argvars, &match_pos) > 0) {
|
||||
lnum = match_pos.lnum;
|
||||
|
@ -14292,18 +14295,14 @@ do_searchpair (
|
|||
static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
pos_T match_pos;
|
||||
int lnum = 0;
|
||||
int col = 0;
|
||||
int n;
|
||||
int flags = 0;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
const int n = search_cmn(argvars, &match_pos, &flags);
|
||||
|
||||
n = search_cmn(argvars, &match_pos, &flags);
|
||||
if (n > 0) {
|
||||
lnum = match_pos.lnum;
|
||||
col = match_pos.col;
|
||||
}
|
||||
tv_list_alloc_ret(rettv, 2 + (!!(flags & SP_SUBPAT)));
|
||||
|
||||
const int lnum = (n > 0 ? match_pos.lnum : 0);
|
||||
const int col = (n > 0 ? match_pos.col : 0);
|
||||
|
||||
tv_list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
|
||||
tv_list_append_number(rettv->vval.v_list, (varnumber_T)col);
|
||||
|
@ -14319,7 +14318,7 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
char **addrs = server_address_list(&n);
|
||||
|
||||
// Copy addrs into a linked list.
|
||||
list_T *l = tv_list_alloc_ret(rettv);
|
||||
list_T *const l = tv_list_alloc_ret(rettv, n);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
tv_list_append_allocated_string(l, addrs[i]);
|
||||
}
|
||||
|
@ -14715,7 +14714,7 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
dictitem_T *const di = tv_dict_find(d, S_LEN("pattern"));
|
||||
if (di == NULL) {
|
||||
if (s == NULL) {
|
||||
s = tv_list_alloc();
|
||||
s = tv_list_alloc(9);
|
||||
}
|
||||
|
||||
// match from matchaddpos()
|
||||
|
@ -15531,8 +15530,6 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
hlf_T attr = HLF_COUNT;
|
||||
size_t len = 0;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
// Find the start and length of the badly spelled word.
|
||||
len = spell_move_to(curwin, FORWARD, true, true, &attr);
|
||||
|
@ -15557,6 +15554,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
}
|
||||
|
||||
assert(len <= INT_MAX);
|
||||
tv_list_alloc_ret(rettv, 2);
|
||||
tv_list_append_string(rettv->vval.v_list, word, len);
|
||||
tv_list_append_string(rettv->vval.v_list,
|
||||
(attr == HLF_SPB ? "bad"
|
||||
|
@ -15573,35 +15571,36 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
{
|
||||
bool typeerr = false;
|
||||
int maxcount;
|
||||
garray_T ga;
|
||||
garray_T ga = GA_EMPTY_INIT_VALUE;
|
||||
bool need_capital = false;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
|
||||
if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) {
|
||||
const char *const str = tv_get_string(&argvars[0]);
|
||||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||
maxcount = tv_get_number_chk(&argvars[1], &typeerr);
|
||||
if (maxcount <= 0) {
|
||||
return;
|
||||
goto f_spellsuggest_return;
|
||||
}
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
need_capital = tv_get_number_chk(&argvars[2], &typeerr);
|
||||
if (typeerr) {
|
||||
return;
|
||||
goto f_spellsuggest_return;
|
||||
}
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
maxcount = 25;
|
||||
}
|
||||
|
||||
spell_suggest_list(&ga, (char_u *)str, maxcount, need_capital, false);
|
||||
|
||||
for (int i = 0; i < ga.ga_len; i++) {
|
||||
char *p = ((char **)ga.ga_data)[i];
|
||||
tv_list_append_allocated_string(rettv->vval.v_list, p);
|
||||
}
|
||||
ga_clear(&ga);
|
||||
}
|
||||
|
||||
f_spellsuggest_return:
|
||||
tv_list_alloc_ret(rettv, (ptrdiff_t)ga.ga_len);
|
||||
for (int i = 0; i < ga.ga_len; i++) {
|
||||
char *const p = ((char **)ga.ga_data)[i];
|
||||
tv_list_append_allocated_string(rettv->vval.v_list, p);
|
||||
}
|
||||
ga_clear(&ga);
|
||||
}
|
||||
|
||||
static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
|
@ -15633,10 +15632,11 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
pat = "[\\x01- ]\\+";
|
||||
}
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
|
||||
if (typeerr)
|
||||
if (typeerr) {
|
||||
return;
|
||||
}
|
||||
|
||||
regmatch.regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING);
|
||||
if (regmatch.regprog != NULL) {
|
||||
|
@ -16263,7 +16263,6 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
|
||||
memset(str, NUL, sizeof(str));
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0
|
||||
&& (size_t)col <= STRLEN(ml_get(lnum)) && curwin->w_p_cole > 0) {
|
||||
(void)syn_get_id(curwin, lnum, col, false, NULL, false);
|
||||
|
@ -16276,14 +16275,12 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
cchar = lcs_conceal;
|
||||
}
|
||||
if (cchar != NUL) {
|
||||
if (has_mbyte)
|
||||
(*mb_char2bytes)(cchar, str);
|
||||
else
|
||||
str[0] = cchar;
|
||||
utf_char2bytes(cchar, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tv_list_alloc_ret(rettv, 3);
|
||||
tv_list_append_number(rettv->vval.v_list, (syntax_flags & HL_CONCEAL) != 0);
|
||||
// -1 to auto-determine strlen
|
||||
tv_list_append_string(rettv->vval.v_list, (const char *)str, -1);
|
||||
|
@ -16306,7 +16303,7 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
&& lnum <= curbuf->b_ml.ml_line_count
|
||||
&& col >= 0
|
||||
&& (size_t)col <= STRLEN(ml_get(lnum))) {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
(void)syn_get_id(curwin, lnum, col, false, NULL, true);
|
||||
|
||||
int id;
|
||||
|
@ -16322,7 +16319,7 @@ static list_T *string_to_list(const char *str, size_t len, const bool keepempty)
|
|||
if (!keepempty && str[len - 1] == NL) {
|
||||
len--;
|
||||
}
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc(kListLenMayKnow);
|
||||
encode_list_write(list, str, len);
|
||||
return list;
|
||||
}
|
||||
|
@ -16368,7 +16365,7 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
|
|||
if (res == NULL) {
|
||||
if (retlist) {
|
||||
// return an empty list when there's no output
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, 0);
|
||||
} else {
|
||||
rettv->vval.v_string = (char_u *) xstrdup("");
|
||||
}
|
||||
|
@ -16434,7 +16431,7 @@ static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
}
|
||||
}
|
||||
if (wp != NULL) {
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
while (wp != NULL) {
|
||||
tv_list_append_number(rettv->vval.v_list, wp->w_buffer->b_fnum);
|
||||
wp = wp->w_next;
|
||||
|
@ -16532,7 +16529,7 @@ static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
char *fname;
|
||||
tagname_T tn;
|
||||
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenUnknown);
|
||||
fname = xmalloc(MAXPATHL);
|
||||
|
||||
bool first = true;
|
||||
|
@ -16561,8 +16558,8 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||
fname = tv_get_string(&argvars[1]);
|
||||
}
|
||||
(void)get_tags(tv_list_alloc_ret(rettv), (char_u *)tag_pattern,
|
||||
(char_u *)fname);
|
||||
(void)get_tags(tv_list_alloc_ret(rettv, kListLenUnknown),
|
||||
(char_u *)tag_pattern, (char_u *)fname);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -16668,6 +16665,18 @@ static void f_test_garbagecollect_now(typval_T *argvars,
|
|||
garbage_collect(true);
|
||||
}
|
||||
|
||||
// "test_write_list_log()" function
|
||||
static void f_test_write_list_log(typval_T *const argvars,
|
||||
typval_T *const rettv,
|
||||
FunPtr fptr)
|
||||
{
|
||||
const char *const fname = tv_get_string_chk(&argvars[0]);
|
||||
if (fname == NULL) {
|
||||
return;
|
||||
}
|
||||
list_write_log(fname);
|
||||
}
|
||||
|
||||
bool callback_from_typval(Callback *const callback, typval_T *const arg)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
|
@ -16803,7 +16812,9 @@ static void add_timer_info_all(typval_T *rettv)
|
|||
/// "timer_info([timer])" function
|
||||
static void f_timer_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, (argvars[0].v_type != VAR_UNKNOWN
|
||||
? 1
|
||||
: timers->table->n_occupied));
|
||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
if (argvars[0].v_type != VAR_NUMBER) {
|
||||
EMSG(_(e_number_exp));
|
||||
|
@ -17163,7 +17174,6 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
tv_dict_alloc_ret(rettv);
|
||||
|
||||
dict_T *dict = rettv->vval.v_dict;
|
||||
list_T *list;
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("synced"), (varnumber_T)curbuf->b_u_synced);
|
||||
tv_dict_add_nr(dict, S_LEN("seq_last"), (varnumber_T)curbuf->b_u_seq_last);
|
||||
|
@ -17173,9 +17183,7 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
tv_dict_add_nr(dict, S_LEN("time_cur"), (varnumber_T)curbuf->b_u_time_cur);
|
||||
tv_dict_add_nr(dict, S_LEN("save_cur"), (varnumber_T)curbuf->b_u_save_nr_cur);
|
||||
|
||||
list = tv_list_alloc();
|
||||
u_eval_tree(curbuf->b_u_oldhead, list);
|
||||
tv_dict_add_list(dict, S_LEN("entries"), list);
|
||||
tv_dict_add_list(dict, S_LEN("entries"), u_eval_tree(curbuf->b_u_oldhead));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -17234,7 +17242,7 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
/// "win_findbuf()" function
|
||||
static void f_win_findbuf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv);
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
win_findbuf(argvars, rettv->vval.v_list);
|
||||
}
|
||||
|
||||
|
@ -17253,8 +17261,7 @@ static void f_win_gotoid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||
/// "win_id2tabwin()" function
|
||||
static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv);
|
||||
win_id2tabwin(argvars, rettv->vval.v_list);
|
||||
win_id2tabwin(argvars, rettv);
|
||||
}
|
||||
|
||||
/// "win_id2win()" function
|
||||
|
@ -22367,7 +22374,7 @@ static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv)
|
|||
return;
|
||||
}
|
||||
|
||||
list_T *args = tv_list_alloc();
|
||||
list_T *args = tv_list_alloc(1);
|
||||
tv_list_append_string(args, (const char *)argvars[0].vval.v_string, -1);
|
||||
*rettv = eval_call_provider(name, "eval", args);
|
||||
}
|
||||
|
|
|
@ -313,6 +313,7 @@ return {
|
|||
tempname={},
|
||||
termopen={args={1, 2}},
|
||||
test_garbagecollect_now={},
|
||||
test_write_list_log={args=1},
|
||||
timer_info={args={0,1}},
|
||||
timer_pause={args=2},
|
||||
timer_start={args={2,3}},
|
||||
|
|
|
@ -150,7 +150,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
|
|||
}
|
||||
obj_di->di_tv = obj.val;
|
||||
} else {
|
||||
list_T *const kv_pair = tv_list_alloc();
|
||||
list_T *const kv_pair = tv_list_alloc(2);
|
||||
tv_list_append_list(last_container.special_val, kv_pair);
|
||||
tv_list_append_owned_tv(kv_pair, key.val);
|
||||
tv_list_append_owned_tv(kv_pair, obj.val);
|
||||
|
@ -221,13 +221,18 @@ static inline int json_decoder_pop(ValuesStackItem obj,
|
|||
/// Create a new special dictionary that ought to represent a MAP
|
||||
///
|
||||
/// @param[out] ret_tv Address where new special dictionary is saved.
|
||||
/// @param[in] len Expected number of items to be populated before list
|
||||
/// becomes accessible from VimL. It is still valid to
|
||||
/// underpopulate a list, value only controls how many elements
|
||||
/// will be allocated in advance. @see ListLenSpecials.
|
||||
///
|
||||
/// @return [allocated] list which should contain key-value pairs. Return value
|
||||
/// may be safely ignored.
|
||||
list_T *decode_create_map_special_dict(typval_T *const ret_tv)
|
||||
list_T *decode_create_map_special_dict(typval_T *const ret_tv,
|
||||
const ptrdiff_t len)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc(len);
|
||||
tv_list_ref(list);
|
||||
create_special_dict(ret_tv, kMPMap, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
|
@ -263,7 +268,7 @@ typval_T decode_string(const char *const s, const size_t len,
|
|||
? ((s != NULL) && (memchr(s, NUL, len) != NULL))
|
||||
: (bool)hasnul);
|
||||
if (really_hasnul) {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc(kListLenMayKnow);
|
||||
tv_list_ref(list);
|
||||
typval_T tv;
|
||||
create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) {
|
||||
|
@ -843,7 +848,7 @@ json_decode_string_cycle_start:
|
|||
break;
|
||||
}
|
||||
case '[': {
|
||||
list_T *list = tv_list_alloc();
|
||||
list_T *list = tv_list_alloc(kListLenMayKnow);
|
||||
tv_list_ref(list);
|
||||
typval_T tv = {
|
||||
.v_type = VAR_LIST,
|
||||
|
@ -864,7 +869,7 @@ json_decode_string_cycle_start:
|
|||
list_T *val_list = NULL;
|
||||
if (next_map_special) {
|
||||
next_map_special = false;
|
||||
val_list = decode_create_map_special_dict(&tv);
|
||||
val_list = decode_create_map_special_dict(&tv, kListLenMayKnow);
|
||||
} else {
|
||||
dict_T *dict = tv_dict_alloc();
|
||||
dict->dv_refcount++;
|
||||
|
@ -964,7 +969,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
.vval = { .v_number = (varnumber_T) mobj.via.u64 },
|
||||
};
|
||||
} else {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc(4);
|
||||
tv_list_ref(list);
|
||||
create_special_dict(rettv, kMPInteger, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
|
@ -987,7 +992,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
.vval = { .v_number = (varnumber_T) mobj.via.i64 },
|
||||
};
|
||||
} else {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc(4);
|
||||
tv_list_ref(list);
|
||||
create_special_dict(rettv, kMPInteger, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
|
@ -1033,7 +1038,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
break;
|
||||
}
|
||||
case MSGPACK_OBJECT_ARRAY: {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size);
|
||||
tv_list_ref(list);
|
||||
*rettv = (typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
|
@ -1085,9 +1090,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
}
|
||||
break;
|
||||
msgpack_to_vim_generic_map: {}
|
||||
list_T *const list = decode_create_map_special_dict(rettv);
|
||||
list_T *const list = decode_create_map_special_dict(
|
||||
rettv, (ptrdiff_t)mobj.via.map.size);
|
||||
for (size_t i = 0; i < mobj.via.map.size; i++) {
|
||||
list_T *const kv_pair = tv_list_alloc();
|
||||
list_T *const kv_pair = tv_list_alloc(2);
|
||||
tv_list_append_list(list, kv_pair);
|
||||
|
||||
typval_T key_tv = { .v_type = VAR_UNKNOWN };
|
||||
|
@ -1107,10 +1113,10 @@ msgpack_to_vim_generic_map: {}
|
|||
break;
|
||||
}
|
||||
case MSGPACK_OBJECT_EXT: {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc(2);
|
||||
tv_list_ref(list);
|
||||
tv_list_append_number(list, mobj.via.ext.type);
|
||||
list_T *const ext_val_list = tv_list_alloc();
|
||||
list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
|
||||
tv_list_append_list(list, ext_val_list);
|
||||
create_special_dict(rettv, kMPExt, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "nvim/message.h"
|
||||
// TODO(ZyX-I): Move line_breakcheck out of misc1
|
||||
#include "nvim/misc1.h" // For line_breakcheck
|
||||
#include "nvim/os/fileio.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "eval/typval.c.generated.h"
|
||||
|
@ -45,6 +46,70 @@ bool tv_in_free_unref_items = false;
|
|||
const char *const tv_empty_string = "";
|
||||
|
||||
//{{{1 Lists
|
||||
//{{{2 List log
|
||||
#ifdef LOG_LIST_ACTIONS
|
||||
ListLog *list_log_first = NULL;
|
||||
ListLog *list_log_last = NULL;
|
||||
|
||||
/// Write list log to the given file
|
||||
///
|
||||
/// @param[in] fname File to write log to. Will be appended to if already
|
||||
/// present.
|
||||
void list_write_log(const char *const fname)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
FileDescriptor fp;
|
||||
const int fo_ret = file_open(&fp, fname, kFileCreate|kFileAppend, 0600);
|
||||
if (fo_ret != 0) {
|
||||
emsgf(_("E5142: Failed to open file %s: %s"), fname, os_strerror(fo_ret));
|
||||
return;
|
||||
}
|
||||
for (ListLog *chunk = list_log_first; chunk != NULL;) {
|
||||
for (size_t i = 0; i < chunk->size; i++) {
|
||||
char buf[10 + 1 + ((16 + 3) * 3) + (8 + 2) + 2];
|
||||
// act : hex " c:" len "[]" "\n\0"
|
||||
const ListLogEntry entry = chunk->entries[i];
|
||||
const size_t snp_len = (size_t)snprintf(
|
||||
buf, sizeof(buf),
|
||||
"%-10.10s: l:%016" PRIxPTR "[%08d] 1:%016" PRIxPTR " 2:%016" PRIxPTR
|
||||
"\n",
|
||||
entry.action, entry.l, entry.len, entry.li1, entry.li2);
|
||||
assert(snp_len + 1 == sizeof(buf));
|
||||
const ptrdiff_t fw_ret = file_write(&fp, buf, snp_len);
|
||||
if (fw_ret != (ptrdiff_t)snp_len) {
|
||||
assert(fw_ret < 0);
|
||||
if (i) {
|
||||
memmove(chunk->entries, chunk->entries + i,
|
||||
sizeof(chunk->entries[0]) * (chunk->size - i));
|
||||
chunk->size -= i;
|
||||
}
|
||||
emsgf(_("E5143: Failed to write to file %s: %s"),
|
||||
fname, os_strerror((int)fw_ret));
|
||||
return;
|
||||
}
|
||||
}
|
||||
list_log_first = chunk->next;
|
||||
xfree(chunk);
|
||||
chunk = list_log_first;
|
||||
}
|
||||
const int fc_ret = file_close(&fp, true);
|
||||
if (fc_ret != 0) {
|
||||
emsgf(_("E5144: Failed to close file %s: %s"), fname, os_strerror(fc_ret));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXITFREE
|
||||
/// Free list log
|
||||
void list_free_log(void)
|
||||
{
|
||||
for (ListLog *chunk = list_log_first; chunk != NULL;) {
|
||||
list_log_first = chunk->next;
|
||||
xfree(chunk);
|
||||
chunk = list_log_first;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
//{{{2 List item
|
||||
|
||||
/// Allocate a list item
|
||||
|
@ -132,8 +197,14 @@ void tv_list_watch_fix(list_T *const l, const listitem_T *const item)
|
|||
///
|
||||
/// Caller should take care of the reference count.
|
||||
///
|
||||
/// @param[in] len Expected number of items to be populated before list
|
||||
/// becomes accessible from VimL. It is still valid to
|
||||
/// underpopulate a list, value only controls how many elements
|
||||
/// will be allocated in advance. Currently does nothing.
|
||||
/// @see ListLenSpecials.
|
||||
///
|
||||
/// @return [allocated] new list.
|
||||
list_T *tv_list_alloc(void)
|
||||
list_T *tv_list_alloc(const ptrdiff_t len)
|
||||
FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
list_T *const list = xcalloc(1, sizeof(list_T));
|
||||
|
@ -145,6 +216,7 @@ list_T *tv_list_alloc(void)
|
|||
list->lv_used_prev = NULL;
|
||||
list->lv_used_next = gc_first_list;
|
||||
gc_first_list = list;
|
||||
list_log(list, NULL, (void *)(uintptr_t)len, "alloc");
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -174,6 +246,8 @@ void tv_list_init_static10(staticList10_T *const sl)
|
|||
li->li_prev = li - 1;
|
||||
li->li_next = li + 1;
|
||||
}
|
||||
list_log((const list_T *)sl, &sl->sl_items[0], &sl->sl_items[SL_SIZE - 1],
|
||||
"s10init");
|
||||
#undef SL_SIZE
|
||||
}
|
||||
|
||||
|
@ -185,6 +259,7 @@ void tv_list_init_static(list_T *const l)
|
|||
{
|
||||
memset(l, 0, sizeof(*l));
|
||||
l->lv_refcount = DO_NOT_FREE_CNT;
|
||||
list_log(l, NULL, NULL, "sinit");
|
||||
}
|
||||
|
||||
/// Free items contained in a list
|
||||
|
@ -193,6 +268,7 @@ void tv_list_init_static(list_T *const l)
|
|||
void tv_list_free_contents(list_T *const l)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_log(l, NULL, NULL, "freecont");
|
||||
for (listitem_T *item = l->lv_first; item != NULL; item = l->lv_first) {
|
||||
// Remove the item before deleting it.
|
||||
l->lv_first = item->li_next;
|
||||
|
@ -222,6 +298,7 @@ void tv_list_free_list(list_T *const l)
|
|||
if (l->lv_used_next != NULL) {
|
||||
l->lv_used_next->lv_used_prev = l->lv_used_prev;
|
||||
}
|
||||
list_log(l, NULL, NULL, "freelist");
|
||||
|
||||
xfree(l);
|
||||
}
|
||||
|
@ -266,6 +343,7 @@ void tv_list_drop_items(list_T *const l, listitem_T *const item,
|
|||
listitem_T *const item2)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_log(l, item, item2, "drop");
|
||||
// Notify watchers.
|
||||
for (listitem_T *ip = item; ip != item2->li_next; ip = ip->li_next) {
|
||||
l->lv_len--;
|
||||
|
@ -283,6 +361,7 @@ void tv_list_drop_items(list_T *const l, listitem_T *const item,
|
|||
item->li_prev->li_next = item2->li_next;
|
||||
}
|
||||
l->lv_idx_item = NULL;
|
||||
list_log(l, l->lv_first, l->lv_last, "afterdrop");
|
||||
}
|
||||
|
||||
/// Like tv_list_drop_items, but also frees all removed items
|
||||
|
@ -290,6 +369,7 @@ void tv_list_remove_items(list_T *const l, listitem_T *const item,
|
|||
listitem_T *const item2)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_log(l, item, item2, "remove");
|
||||
tv_list_drop_items(l, item, item2);
|
||||
for (listitem_T *li = item;;) {
|
||||
tv_clear(TV_LIST_ITEM_TV(li));
|
||||
|
@ -314,6 +394,7 @@ void tv_list_move_items(list_T *const l, listitem_T *const item,
|
|||
const int cnt)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_log(l, item, item2, "move");
|
||||
tv_list_drop_items(l, item, item2);
|
||||
item->li_prev = tgt_l->lv_last;
|
||||
item2->li_next = NULL;
|
||||
|
@ -324,6 +405,7 @@ void tv_list_move_items(list_T *const l, listitem_T *const item,
|
|||
}
|
||||
tgt_l->lv_last = item2;
|
||||
tgt_l->lv_len += cnt;
|
||||
list_log(tgt_l, tgt_l->lv_first, tgt_l->lv_last, "movetgt");
|
||||
}
|
||||
|
||||
/// Insert list item
|
||||
|
@ -352,6 +434,7 @@ void tv_list_insert(list_T *const l, listitem_T *const ni,
|
|||
}
|
||||
item->li_prev = ni;
|
||||
l->lv_len++;
|
||||
list_log(l, ni, item, "insert");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,6 +461,7 @@ void tv_list_insert_tv(list_T *const l, typval_T *const tv,
|
|||
void tv_list_append(list_T *const l, listitem_T *const item)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_log(l, item, NULL, "append");
|
||||
if (l->lv_last == NULL) {
|
||||
// empty list
|
||||
l->lv_first = item;
|
||||
|
@ -521,7 +605,7 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
list_T *copy = tv_list_alloc();
|
||||
list_T *copy = tv_list_alloc(tv_list_len(orig));
|
||||
tv_list_ref(copy);
|
||||
if (copyID != 0) {
|
||||
// Do this before adding the items, because one of the items may
|
||||
|
@ -741,6 +825,7 @@ void tv_list_reverse(list_T *const l)
|
|||
if (tv_list_len(l) <= 1) {
|
||||
return;
|
||||
}
|
||||
list_log(l, NULL, NULL, "reverse");
|
||||
#define SWAP(a, b) \
|
||||
do { \
|
||||
tmp = a; \
|
||||
|
@ -779,6 +864,7 @@ void tv_list_item_sort(list_T *const l, ListSortItem *const ptrs,
|
|||
if (len <= 1) {
|
||||
return;
|
||||
}
|
||||
list_log(l, NULL, NULL, "sort");
|
||||
int i = 0;
|
||||
TV_LIST_ITER(l, li, {
|
||||
ptrs[i].item = li;
|
||||
|
@ -867,6 +953,7 @@ listitem_T *tv_list_find(list_T *const l, int n)
|
|||
// Cache the used index.
|
||||
l->lv_idx = idx;
|
||||
l->lv_idx_item = item;
|
||||
list_log(l, l->lv_idx_item, (void *)(uintptr_t)l->lv_idx, "find");
|
||||
|
||||
return item;
|
||||
}
|
||||
|
@ -1817,12 +1904,16 @@ void tv_dict_set_keys_readonly(dict_T *const dict)
|
|||
/// Also sets reference count.
|
||||
///
|
||||
/// @param[out] ret_tv Structure where list is saved.
|
||||
/// @param[in] len Expected number of items to be populated before list
|
||||
/// becomes accessible from VimL. It is still valid to
|
||||
/// underpopulate a list, value only controls how many elements
|
||||
/// will be allocated in advance. @see ListLenSpecials.
|
||||
///
|
||||
/// @return [allocated] pointer to the created list.
|
||||
list_T *tv_list_alloc_ret(typval_T *const ret_tv)
|
||||
list_T *tv_list_alloc_ret(typval_T *const ret_tv, const ptrdiff_t len)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_T *const l = tv_list_alloc();
|
||||
list_T *const l = tv_list_alloc(len);
|
||||
ret_tv->vval.v_list = l;
|
||||
ret_tv->v_type = VAR_LIST;
|
||||
ret_tv->v_lock = VAR_UNLOCKED;
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include "nvim/gettext.h"
|
||||
#include "nvim/message.h"
|
||||
#include "nvim/macros.h"
|
||||
#ifdef LOG_LIST_ACTIONS
|
||||
# include "nvim/memory.h"
|
||||
#endif
|
||||
|
||||
/// Type used for VimL VAR_NUMBER values
|
||||
typedef int64_t varnumber_T;
|
||||
|
@ -31,6 +34,25 @@ typedef double float_T;
|
|||
/// Refcount for dict or list that should not be freed
|
||||
enum { DO_NOT_FREE_CNT = (INT_MAX / 2) };
|
||||
|
||||
/// Additional values for tv_list_alloc() len argument
|
||||
enum {
|
||||
/// List length is not known in advance
|
||||
///
|
||||
/// To be used when there is neither a way to know how many elements will be
|
||||
/// needed nor are any educated guesses.
|
||||
kListLenUnknown = -1,
|
||||
/// List length *should* be known, but is actually not
|
||||
///
|
||||
/// All occurrences of this value should be eventually removed. This is for
|
||||
/// the case when the only reason why list length is not known is that it
|
||||
/// would be hard to code without refactoring, but refactoring is needed.
|
||||
kListLenShouldKnow = -2,
|
||||
/// List length may be known in advance, but it requires too much effort
|
||||
///
|
||||
/// To be used when it looks impractical to determine list length.
|
||||
kListLenMayKnow = -3,
|
||||
} ListLenSpecials;
|
||||
|
||||
/// Maximal possible value of varnumber_T variable
|
||||
#define VARNUMBER_MAX INT64_MAX
|
||||
#define UVARNUMBER_MAX UINT64_MAX
|
||||
|
@ -304,6 +326,96 @@ typedef struct {
|
|||
|
||||
typedef int (*ListSorter)(const void *, const void *);
|
||||
|
||||
#ifdef LOG_LIST_ACTIONS
|
||||
|
||||
/// List actions log entry
|
||||
typedef struct {
|
||||
uintptr_t l; ///< List log entry belongs to.
|
||||
uintptr_t li1; ///< First list item log entry belongs to, if applicable.
|
||||
uintptr_t li2; ///< Second list item log entry belongs to, if applicable.
|
||||
int len; ///< List length when log entry was created.
|
||||
const char *action; ///< Logged action.
|
||||
} ListLogEntry;
|
||||
|
||||
typedef struct list_log ListLog;
|
||||
|
||||
/// List actions log
|
||||
struct list_log {
|
||||
ListLog *next; ///< Next chunk or NULL.
|
||||
size_t capacity; ///< Number of entries in current chunk.
|
||||
size_t size; ///< Current chunk size.
|
||||
ListLogEntry entries[]; ///< Actual log entries.
|
||||
};
|
||||
|
||||
extern ListLog *list_log_first; ///< First list log chunk, NULL if missing
|
||||
extern ListLog *list_log_last; ///< Last list log chunk
|
||||
|
||||
static inline ListLog *list_log_alloc(const size_t size)
|
||||
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Allocate a new log chunk and update globals
|
||||
///
|
||||
/// @param[in] size Number of entries in a new chunk.
|
||||
///
|
||||
/// @return [allocated] Newly allocated chunk.
|
||||
static inline ListLog *list_log_new(const size_t size)
|
||||
{
|
||||
ListLog *ret = xmalloc(offsetof(ListLog, entries)
|
||||
+ size * sizeof(ret->entries[0]));
|
||||
ret->size = 0;
|
||||
ret->capacity = size;
|
||||
ret->next = NULL;
|
||||
if (list_log_first == NULL) {
|
||||
list_log_first = ret;
|
||||
} else {
|
||||
list_log_last->next = ret;
|
||||
}
|
||||
list_log_last = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void list_log(const list_T *const l,
|
||||
const listitem_T *const li1,
|
||||
const listitem_T *const li2,
|
||||
const char *const action)
|
||||
REAL_FATTR_ALWAYS_INLINE;
|
||||
|
||||
/// Add new entry to log
|
||||
///
|
||||
/// If last chunk was filled it uses twice as much memory to allocate the next
|
||||
/// chunk.
|
||||
///
|
||||
/// @param[in] l List to which entry belongs.
|
||||
/// @param[in] li1 List item 1.
|
||||
/// @param[in] li2 List item 2, often used for integers and not list items.
|
||||
/// @param[in] action Logged action.
|
||||
static inline void list_log(const list_T *const l,
|
||||
const listitem_T *const li1,
|
||||
const listitem_T *const li2,
|
||||
const char *const action)
|
||||
{
|
||||
ListLog *tgt;
|
||||
if (list_log_first == NULL) {
|
||||
tgt = list_log_new(128);
|
||||
} else if (list_log_last->size == list_log_last->capacity) {
|
||||
tgt = list_log_new(list_log_last->capacity * 2);
|
||||
} else {
|
||||
tgt = list_log_last;
|
||||
}
|
||||
tgt->entries[tgt->size++] = (ListLogEntry) {
|
||||
.l = (uintptr_t)l,
|
||||
.li1 = (uintptr_t)li1,
|
||||
.li2 = (uintptr_t)li2,
|
||||
.len = (l == NULL ? 0 : l->lv_len),
|
||||
.action = action,
|
||||
};
|
||||
}
|
||||
#else
|
||||
# define list_log(...)
|
||||
# define list_write_log(...)
|
||||
# define list_free_log()
|
||||
#endif
|
||||
|
||||
// In a hashtab item "hi_key" points to "di_key" in a dictitem.
|
||||
// This avoids adding a pointer to the hashtab item.
|
||||
|
||||
|
@ -377,6 +489,7 @@ static inline int tv_list_len(const list_T *const l)
|
|||
/// @param[in] l List to check.
|
||||
static inline int tv_list_len(const list_T *const l)
|
||||
{
|
||||
list_log(l, NULL, NULL, "len");
|
||||
if (l == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -460,8 +573,10 @@ static inline listitem_T *tv_list_first(const list_T *const l)
|
|||
static inline listitem_T *tv_list_first(const list_T *const l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
list_log(l, NULL, NULL, "first");
|
||||
return NULL;
|
||||
}
|
||||
list_log(l, l->lv_first, NULL, "first");
|
||||
return l->lv_first;
|
||||
}
|
||||
|
||||
|
@ -476,8 +591,10 @@ static inline listitem_T *tv_list_last(const list_T *const l)
|
|||
static inline listitem_T *tv_list_last(const list_T *const l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
list_log(l, NULL, NULL, "last");
|
||||
return NULL;
|
||||
}
|
||||
list_log(l, l->lv_last, NULL, "last");
|
||||
return l->lv_last;
|
||||
}
|
||||
|
||||
|
@ -545,6 +662,7 @@ extern bool tv_in_free_unref_items;
|
|||
#define _TV_LIST_ITER_MOD(modifier, l, li, code) \
|
||||
do { \
|
||||
modifier list_T *const l_ = (l); \
|
||||
list_log(l_, NULL, NULL, "iter" #modifier); \
|
||||
if (l_ != NULL) { \
|
||||
for (modifier listitem_T *li = l_->lv_first; \
|
||||
li != NULL; li = li->li_next) { \
|
||||
|
|
|
@ -3758,7 +3758,7 @@ static void script_host_execute(char *name, exarg_T *eap)
|
|||
char *const script = script_get(eap, &len);
|
||||
|
||||
if (script != NULL) {
|
||||
list_T *const args = tv_list_alloc();
|
||||
list_T *const args = tv_list_alloc(3);
|
||||
// script
|
||||
tv_list_append_allocated_string(args, script);
|
||||
// current range
|
||||
|
@ -3773,7 +3773,7 @@ static void script_host_execute_file(char *name, exarg_T *eap)
|
|||
uint8_t buffer[MAXPATHL];
|
||||
vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false);
|
||||
|
||||
list_T *args = tv_list_alloc();
|
||||
list_T *args = tv_list_alloc(3);
|
||||
// filename
|
||||
tv_list_append_string(args, (const char *)buffer, -1);
|
||||
// current range
|
||||
|
@ -3784,7 +3784,7 @@ static void script_host_execute_file(char *name, exarg_T *eap)
|
|||
|
||||
static void script_host_do_range(char *name, exarg_T *eap)
|
||||
{
|
||||
list_T *args = tv_list_alloc();
|
||||
list_T *args = tv_list_alloc(3);
|
||||
tv_list_append_number(args, (int)eap->line1);
|
||||
tv_list_append_number(args, (int)eap->line2);
|
||||
tv_list_append_string(args, (const char *)eap->arg, -1);
|
||||
|
|
|
@ -211,7 +211,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
size_t len;
|
||||
const char *s = lua_tolstring(lstate, -2, &len);
|
||||
if (cur.special) {
|
||||
list_T *const kv_pair = tv_list_alloc();
|
||||
list_T *const kv_pair = tv_list_alloc(2);
|
||||
|
||||
typval_T s_tv = decode_string(s, len, kTrue, false, false);
|
||||
if (s_tv.v_type == VAR_UNKNOWN) {
|
||||
|
@ -321,7 +321,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
switch (table_props.type) {
|
||||
case kObjectTypeArray: {
|
||||
cur.tv->v_type = VAR_LIST;
|
||||
cur.tv->vval.v_list = tv_list_alloc();
|
||||
cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx);
|
||||
tv_list_ref(cur.tv->vval.v_list);
|
||||
if (table_props.maxidx != 0) {
|
||||
cur.container = true;
|
||||
|
@ -338,7 +338,8 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
} else {
|
||||
cur.special = table_props.has_string_with_nul;
|
||||
if (table_props.has_string_with_nul) {
|
||||
decode_create_map_special_dict(cur.tv);
|
||||
decode_create_map_special_dict(
|
||||
cur.tv, (ptrdiff_t)table_props.string_keys_num);
|
||||
assert(cur.tv->v_type == VAR_DICT);
|
||||
dictitem_T *const val_di = tv_dict_find(cur.tv->vval.v_dict,
|
||||
S_LEN("_VAL"));
|
||||
|
|
|
@ -412,7 +412,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
// It's better to make v:oldfiles an empty list than NULL.
|
||||
if (get_vim_var_list(VV_OLDFILES) == NULL) {
|
||||
set_vim_var_list(VV_OLDFILES, tv_list_alloc());
|
||||
set_vim_var_list(VV_OLDFILES, tv_list_alloc(0));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -559,6 +559,7 @@ void time_to_bytes(time_t time_, uint8_t buf[8])
|
|||
#include "nvim/tag.h"
|
||||
#include "nvim/window.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
|
||||
/*
|
||||
* Free everything that we allocated.
|
||||
|
@ -692,6 +693,7 @@ void free_all_mem(void)
|
|||
free_screenlines();
|
||||
|
||||
clear_hl_tables();
|
||||
list_free_log();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -714,7 +714,7 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
|
|||
}
|
||||
} else {
|
||||
// visit recursively all children
|
||||
list_T *children_list = tv_list_alloc();
|
||||
list_T *const children_list = tv_list_alloc(kListLenMayKnow);
|
||||
for (menu = menu->children; menu != NULL; menu = menu->next) {
|
||||
dict_T *dic = menu_get_recursive(menu, modes);
|
||||
if (tv_dict_len(dict) > 0) {
|
||||
|
|
|
@ -2564,7 +2564,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
|
|||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
|
||||
// the yanked text
|
||||
list_T *list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
|
||||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
tv_list_append_string(list, (const char *)reg->y_array[i], -1);
|
||||
}
|
||||
|
@ -4854,7 +4854,7 @@ static void *get_reg_wrap_one_line(char_u *s, int flags)
|
|||
if (!(flags & kGRegList)) {
|
||||
return s;
|
||||
}
|
||||
list_T *const list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc(1);
|
||||
tv_list_append_allocated_string(list, (char *)s);
|
||||
return list;
|
||||
}
|
||||
|
@ -4904,7 +4904,7 @@ void *get_reg_contents(int regname, int flags)
|
|||
return NULL;
|
||||
|
||||
if (flags & kGRegList) {
|
||||
list_T *list = tv_list_alloc();
|
||||
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
|
||||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
tv_list_append_string(list, (const char *)reg->y_array[i], -1);
|
||||
}
|
||||
|
@ -5593,7 +5593,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
|
|||
}
|
||||
free_register(reg);
|
||||
|
||||
list_T *const args = tv_list_alloc();
|
||||
list_T *const args = tv_list_alloc(1);
|
||||
const char regname = (char)name;
|
||||
tv_list_append_string(args, ®name, 1);
|
||||
|
||||
|
@ -5712,15 +5712,13 @@ static void set_clipboard(int name, yankreg_T *reg)
|
|||
return;
|
||||
}
|
||||
|
||||
list_T *lines = tv_list_alloc();
|
||||
list_T *const lines = tv_list_alloc(
|
||||
(ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise));
|
||||
|
||||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
tv_list_append_string(lines, (const char *)reg->y_array[i], -1);
|
||||
}
|
||||
|
||||
list_T *args = tv_list_alloc();
|
||||
tv_list_append_list(args, lines);
|
||||
|
||||
char regtype;
|
||||
switch (reg->y_type) {
|
||||
case kMTLineWise: {
|
||||
|
@ -5741,10 +5739,11 @@ static void set_clipboard(int name, yankreg_T *reg)
|
|||
assert(false);
|
||||
}
|
||||
}
|
||||
tv_list_append_string(args, ®type, 1);
|
||||
|
||||
const char regname = (char)name;
|
||||
tv_list_append_string(args, ®name, 1);
|
||||
list_T *args = tv_list_alloc(3);
|
||||
tv_list_append_list(args, lines);
|
||||
tv_list_append_string(args, ®type, 1);
|
||||
tv_list_append_string(args, ((char[]) { (char)name }), 1);
|
||||
|
||||
(void)eval_call_provider("clipboard", "set", args);
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
/// @param[in] fname File name to open.
|
||||
/// @param[in] flags Flags, @see FileOpenFlags. Currently reading from and
|
||||
/// writing to the file at once is not supported, so either
|
||||
/// FILE_WRITE_ONLY or FILE_READ_ONLY is required.
|
||||
/// kFileWriteOnly or kFileReadOnly is required.
|
||||
/// @param[in] mode Permissions for the newly created file (ignored if flags
|
||||
/// does not have FILE_CREATE\*).
|
||||
/// does not have kFileCreate\*).
|
||||
///
|
||||
/// @return Error code (@see os_strerror()) or 0.
|
||||
int file_open(FileDescriptor *const ret_fp, const char *const fname,
|
||||
|
@ -120,7 +120,7 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const bool wr)
|
|||
/// @param[in] fname File name to open.
|
||||
/// @param[in] flags Flags, @see FileOpenFlags.
|
||||
/// @param[in] mode Permissions for the newly created file (ignored if flags
|
||||
/// does not have FILE_CREATE\*).
|
||||
/// does not have kFileCreate\*).
|
||||
///
|
||||
/// @return [allocated] Opened file or NULL in case of error.
|
||||
FileDescriptor *file_open_new(int *const error, const char *const fname,
|
||||
|
|
|
@ -4193,7 +4193,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
|||
}
|
||||
}
|
||||
if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
|
||||
list_T *l = tv_list_alloc();
|
||||
list_T *l = tv_list_alloc(kListLenMayKnow);
|
||||
(void)get_errorlist(wp, qf_idx, l);
|
||||
tv_dict_add_list(retdict, S_LEN("items"), l);
|
||||
}
|
||||
|
|
|
@ -7044,7 +7044,7 @@ list_T *reg_submatch_list(int no)
|
|||
colnr_T scol = rsm.sm_mmatch->startpos[no].col;
|
||||
colnr_T ecol = rsm.sm_mmatch->endpos[no].col;
|
||||
|
||||
list = tv_list_alloc();
|
||||
list = tv_list_alloc(elnum - slnum + 1);
|
||||
|
||||
s = (const char *)reg_getline_submatch(slnum) + scol;
|
||||
if (slnum == elnum) {
|
||||
|
@ -7063,7 +7063,7 @@ list_T *reg_submatch_list(int no)
|
|||
if (s == NULL || rsm.sm_match->endp[no] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
list = tv_list_alloc();
|
||||
list = tv_list_alloc(1);
|
||||
tv_list_append_string(list, s, (const char *)rsm.sm_match->endp[no] - s);
|
||||
}
|
||||
|
||||
|
|
|
@ -1217,7 +1217,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
|
|||
khash_t(fnamebufs) fname_bufs = KHASH_EMPTY_TABLE(fnamebufs);
|
||||
khash_t(strset) oldfiles_set = KHASH_EMPTY_TABLE(strset);
|
||||
if (get_old_files && (oldfiles_list == NULL || force)) {
|
||||
oldfiles_list = tv_list_alloc();
|
||||
oldfiles_list = tv_list_alloc(kListLenUnknown);
|
||||
set_vim_var_list(VV_OLDFILES, oldfiles_list);
|
||||
}
|
||||
ShaDaReadResult srni_ret;
|
||||
|
|
|
@ -667,7 +667,7 @@ do_tag (
|
|||
|
||||
fname = xmalloc(MAXPATHL + 1);
|
||||
cmd = xmalloc(CMDBUFFSIZE + 1);
|
||||
list = tv_list_alloc();
|
||||
list = tv_list_alloc(num_matches);
|
||||
|
||||
for (i = 0; i < num_matches; ++i) {
|
||||
int len, cmd_len;
|
||||
|
|
|
@ -2941,17 +2941,20 @@ bool curbufIsChanged(void)
|
|||
&& (curbuf->b_changed || file_ff_differs(curbuf, true)));
|
||||
}
|
||||
|
||||
/*
|
||||
* For undotree(): Append the list of undo blocks at "first_uhp" to "list".
|
||||
* Recursive.
|
||||
*/
|
||||
void u_eval_tree(u_header_T *first_uhp, list_T *list)
|
||||
/// Append the list of undo blocks to a newly allocated list
|
||||
///
|
||||
/// For use in undotree(). Recursive.
|
||||
///
|
||||
/// @param[in] first_uhp Undo blocks list to start with.
|
||||
///
|
||||
/// @return [allocated] List with a representation of undo blocks.
|
||||
list_T *u_eval_tree(const u_header_T *const first_uhp)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
u_header_T *uhp = first_uhp;
|
||||
dict_T *dict;
|
||||
list_T *const list = tv_list_alloc(kListLenMayKnow);
|
||||
|
||||
while (uhp != NULL) {
|
||||
dict = tv_dict_alloc();
|
||||
for (const u_header_T *uhp = first_uhp; uhp != NULL; uhp = uhp->uh_prev.ptr) {
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
tv_dict_add_nr(dict, S_LEN("seq"), (varnumber_T)uhp->uh_seq);
|
||||
tv_dict_add_nr(dict, S_LEN("time"), (varnumber_T)uhp->uh_time);
|
||||
if (uhp == curbuf->b_u_newhead) {
|
||||
|
@ -2965,14 +2968,12 @@ void u_eval_tree(u_header_T *first_uhp, list_T *list)
|
|||
}
|
||||
|
||||
if (uhp->uh_alt_next.ptr != NULL) {
|
||||
list_T *alt_list = tv_list_alloc();
|
||||
|
||||
// Recursive call to add alternate undo tree.
|
||||
u_eval_tree(uhp->uh_alt_next.ptr, alt_list);
|
||||
tv_dict_add_list(dict, S_LEN("alt"), alt_list);
|
||||
tv_dict_add_list(dict, S_LEN("alt"), u_eval_tree(uhp->uh_alt_next.ptr));
|
||||
}
|
||||
|
||||
tv_list_append_dict(list, dict);
|
||||
uhp = uhp->uh_prev.ptr;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
|
|
@ -5921,13 +5921,15 @@ void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
|
|||
}
|
||||
}
|
||||
|
||||
void win_id2tabwin(typval_T *argvars, list_T *list)
|
||||
void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
|
||||
{
|
||||
int winnr = 1;
|
||||
int tabnr = 1;
|
||||
handle_T id = (handle_T)tv_get_number(&argvars[0]);
|
||||
|
||||
win_get_tabwin(id, &tabnr, &winnr);
|
||||
|
||||
list_T *const list = tv_list_alloc_ret(rettv, 2);
|
||||
tv_list_append_number(list, tabnr);
|
||||
tv_list_append_number(list, winnr);
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ local lua2typvalt_type_tab = {
|
|||
processed[l].lv_refcount = processed[l].lv_refcount + 1
|
||||
return typvalt(eval.VAR_LIST, {v_list=processed[l]})
|
||||
end
|
||||
local lst = populate_list(eval.tv_list_alloc(), l, processed)
|
||||
local lst = populate_list(eval.tv_list_alloc(#l), l, processed)
|
||||
return typvalt(eval.VAR_LIST, {v_list=lst})
|
||||
end,
|
||||
[dict_type] = function(l, processed)
|
||||
|
@ -433,7 +433,8 @@ local function int(n)
|
|||
end
|
||||
|
||||
local function list(...)
|
||||
return populate_list(ffi.gc(eval.tv_list_alloc(), eval.tv_list_unref),
|
||||
return populate_list(ffi.gc(eval.tv_list_alloc(select('#', ...)),
|
||||
eval.tv_list_unref),
|
||||
{...}, {})
|
||||
end
|
||||
|
||||
|
|
|
@ -2407,7 +2407,7 @@ describe('typval.c', function()
|
|||
describe('list ret()', function()
|
||||
itp('works', function()
|
||||
local rettv = typvalt(lib.VAR_UNKNOWN)
|
||||
local l = lib.tv_list_alloc_ret(rettv)
|
||||
local l = lib.tv_list_alloc_ret(rettv, 0)
|
||||
eq(empty_list, typvalt2lua(rettv))
|
||||
eq(rettv.vval.v_list, l)
|
||||
end)
|
||||
|
|
Loading…
Reference in New Issue