Merge #7708 from ZyX-I/hide-container-impl
This commit is contained in:
commit
dee78a4095
|
@ -5493,7 +5493,7 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]])
|
|||
sets buffer line boundaries to redraw screen. It is supposed
|
||||
to be used when fast match additions and deletions are
|
||||
required, for example to highlight matching parentheses.
|
||||
|
||||
*E5030* *E5031*
|
||||
The list {pos} can contain one of these items:
|
||||
- A number. This whole line will be highlighted. The first
|
||||
line has number 1.
|
||||
|
@ -5507,6 +5507,10 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]])
|
|||
- A list with three numbers, e.g., [23, 11, 3]. As above, but
|
||||
the third number gives the length of the highlight in bytes.
|
||||
|
||||
Entries with zero and negative line numbers are silently
|
||||
ignored, as well as entries with negative column numbers and
|
||||
lengths.
|
||||
|
||||
The maximum number of positions is 8.
|
||||
|
||||
Example: >
|
||||
|
|
18
src/clint.py
18
src/clint.py
|
@ -201,6 +201,7 @@ _ERROR_CATEGORIES = [
|
|||
'runtime/printf',
|
||||
'runtime/printf_format',
|
||||
'runtime/threadsafe_fn',
|
||||
'runtime/deprecated',
|
||||
'syntax/parenthesis',
|
||||
'whitespace/alignment',
|
||||
'whitespace/blank_line',
|
||||
|
@ -2123,8 +2124,10 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
|
|||
+ (level_starts[depth][2] == '{')):
|
||||
if depth not in ignore_error_levels:
|
||||
error(filename, linenum, 'whitespace/alignment', 2,
|
||||
'Inner expression should be aligned '
|
||||
'as opening brace + 1 (+ 2 in case of {)')
|
||||
('Inner expression should be aligned '
|
||||
'as opening brace + 1 (+ 2 in case of {{). '
|
||||
'Relevant opening is on line {0!r}').format(
|
||||
level_starts[depth][3]))
|
||||
prev_line_start = pos
|
||||
elif brace == 'e':
|
||||
pass
|
||||
|
@ -2141,7 +2144,8 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
|
|||
ignore_error_levels.add(depth)
|
||||
line_ended_with_opening = (
|
||||
pos == len(line) - 2 * (line.endswith(' \\')) - 1)
|
||||
level_starts[depth] = (pos, line_ended_with_opening, brace)
|
||||
level_starts[depth] = (pos, line_ended_with_opening, brace,
|
||||
linenum)
|
||||
if line_ended_with_opening:
|
||||
depth_line_starts[depth] = (prev_line_start, brace)
|
||||
else:
|
||||
|
@ -3200,6 +3204,14 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
|
|||
if match:
|
||||
error(filename, linenum, 'runtime/printf', 4,
|
||||
'Use xstrlcat or snprintf instead of %s' % match.group(1))
|
||||
if not Search(r'eval/typval\.[ch]$', filename):
|
||||
match = Search(r'(?:\.|->)'
|
||||
r'(?:lv_(?:first|last|refcount|len|watch|idx(?:_item)?'
|
||||
r'|copylist|lock)'
|
||||
r'|li_(?:next|prev|tv))\b', line)
|
||||
if match:
|
||||
error(filename, linenum, 'runtime/deprecated', 4,
|
||||
'Accessing list_T internals directly is prohibited')
|
||||
|
||||
# Check for suspicious usage of "if" like
|
||||
# } if (a == b) {
|
||||
|
|
|
@ -789,7 +789,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
|
|||
Object item = obj.data.array.items[i];
|
||||
listitem_T *li = tv_list_item_alloc();
|
||||
|
||||
if (!object_to_vim(item, &li->li_tv, err)) {
|
||||
if (!object_to_vim(item, TV_LIST_ITEM_TV(li), err)) {
|
||||
// cleanup
|
||||
tv_list_item_free(li);
|
||||
tv_list_free(list);
|
||||
|
@ -798,7 +798,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
|
|||
|
||||
tv_list_append(list, li);
|
||||
}
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
|
||||
tv->v_type = VAR_LIST;
|
||||
tv->vval.v_list = list;
|
||||
|
|
|
@ -900,9 +900,9 @@ typedef struct {
|
|||
Object *ret_node_p;
|
||||
} ExprASTConvStackItem;
|
||||
|
||||
///@cond DOXYGEN_NOT_A_FUNCTION
|
||||
/// @cond DOXYGEN_NOT_A_FUNCTION
|
||||
typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
|
||||
///@endcond
|
||||
/// @endcond
|
||||
|
||||
/// Parse a VimL expression
|
||||
///
|
||||
|
|
|
@ -688,7 +688,7 @@ static void on_channel_event(void **args)
|
|||
argv[1].v_type = VAR_LIST;
|
||||
argv[1].v_lock = VAR_UNLOCKED;
|
||||
argv[1].vval.v_list = ev->received;
|
||||
argv[1].vval.v_list->lv_refcount++;
|
||||
tv_list_ref(argv[1].vval.v_list);
|
||||
} else {
|
||||
argv[1].v_type = VAR_NUMBER;
|
||||
argv[1].v_lock = VAR_UNLOCKED;
|
||||
|
|
|
@ -3536,19 +3536,19 @@ theend:
|
|||
/*
|
||||
* Add completions from a list.
|
||||
*/
|
||||
static void ins_compl_add_list(list_T *list)
|
||||
static void ins_compl_add_list(list_T *const list)
|
||||
{
|
||||
listitem_T *li;
|
||||
int dir = compl_direction;
|
||||
|
||||
/* Go through the List with matches and add each of them. */
|
||||
for (li = list->lv_first; li != NULL; li = li->li_next) {
|
||||
if (ins_compl_add_tv(&li->li_tv, dir) == OK)
|
||||
/* if dir was BACKWARD then honor it just once */
|
||||
// Go through the List with matches and add each of them.
|
||||
TV_LIST_ITER(list, li, {
|
||||
if (ins_compl_add_tv(TV_LIST_ITEM_TV(li), dir) == OK) {
|
||||
// If dir was BACKWARD then honor it just once.
|
||||
dir = FORWARD;
|
||||
else if (did_emsg)
|
||||
} else if (did_emsg) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
1200
src/nvim/eval.c
1200
src/nvim/eval.c
File diff suppressed because it is too large
Load Diff
|
@ -60,8 +60,8 @@ static inline void create_special_dict(typval_T *const rettv,
|
|||
dictitem_T *const type_di = tv_dict_item_alloc_len(S_LEN("_TYPE"));
|
||||
type_di->di_tv.v_type = VAR_LIST;
|
||||
type_di->di_tv.v_lock = VAR_UNLOCKED;
|
||||
type_di->di_tv.vval.v_list = (list_T *) eval_msgpack_type_lists[type];
|
||||
type_di->di_tv.vval.v_list->lv_refcount++;
|
||||
type_di->di_tv.vval.v_list = (list_T *)eval_msgpack_type_lists[type];
|
||||
tv_list_ref(type_di->di_tv.vval.v_list);
|
||||
tv_dict_add(dict, type_di);
|
||||
dictitem_T *const val_di = tv_dict_item_alloc_len(S_LEN("_VAL"));
|
||||
val_di->di_tv = val;
|
||||
|
@ -120,7 +120,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
|
|||
last_container = kv_last(*container_stack);
|
||||
}
|
||||
if (last_container.container.v_type == VAR_LIST) {
|
||||
if (last_container.container.vval.v_list->lv_len != 0
|
||||
if (tv_list_len(last_container.container.vval.v_list) != 0
|
||||
&& !obj.didcomma) {
|
||||
EMSG2(_("E474: Expected comma before list item: %s"), val_location);
|
||||
tv_clear(&obj.val);
|
||||
|
@ -128,7 +128,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
|
|||
}
|
||||
assert(last_container.special_val == NULL);
|
||||
listitem_T *obj_li = tv_list_item_alloc();
|
||||
obj_li->li_tv = obj.val;
|
||||
*TV_LIST_ITEM_TV(obj_li) = obj.val;
|
||||
tv_list_append(last_container.container.vval.v_list, obj_li);
|
||||
} else if (last_container.stack_index == kv_size(*stack) - 2) {
|
||||
if (!obj.didcolon) {
|
||||
|
@ -155,10 +155,10 @@ static inline int json_decoder_pop(ValuesStackItem obj,
|
|||
list_T *const kv_pair = tv_list_alloc();
|
||||
tv_list_append_list(last_container.special_val, kv_pair);
|
||||
listitem_T *const key_li = tv_list_item_alloc();
|
||||
key_li->li_tv = key.val;
|
||||
*TV_LIST_ITEM_TV(key_li) = key.val;
|
||||
tv_list_append(kv_pair, key_li);
|
||||
listitem_T *const val_li = tv_list_item_alloc();
|
||||
val_li->li_tv = obj.val;
|
||||
*TV_LIST_ITEM_TV(val_li) = obj.val;
|
||||
tv_list_append(kv_pair, val_li);
|
||||
}
|
||||
} else {
|
||||
|
@ -234,7 +234,7 @@ list_T *decode_create_map_special_dict(typval_T *const ret_tv)
|
|||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
list_T *const list = tv_list_alloc();
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
create_special_dict(ret_tv, kMPMap, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
|
@ -270,7 +270,7 @@ typval_T decode_string(const char *const s, const size_t len,
|
|||
: (bool)hasnul);
|
||||
if (really_hasnul) {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
typval_T tv;
|
||||
create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
|
@ -738,8 +738,9 @@ json_decode_string_cycle_start:
|
|||
} else if (last_container.special_val == NULL
|
||||
? (last_container.container.v_type == VAR_DICT
|
||||
? (DICT_LEN(last_container.container.vval.v_dict) == 0)
|
||||
: (last_container.container.vval.v_list->lv_len == 0))
|
||||
: (last_container.special_val->lv_len == 0)) {
|
||||
: (tv_list_len(last_container.container.vval.v_list)
|
||||
== 0))
|
||||
: (tv_list_len(last_container.special_val) == 0)) {
|
||||
emsgf(_("E474: Leading comma: %.*s"), LENP(p, e));
|
||||
goto json_decode_string_fail;
|
||||
}
|
||||
|
@ -849,7 +850,7 @@ json_decode_string_cycle_start:
|
|||
}
|
||||
case '[': {
|
||||
list_T *list = tv_list_alloc();
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
typval_T tv = {
|
||||
.v_type = VAR_LIST,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
|
@ -970,7 +971,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
};
|
||||
} else {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
create_special_dict(rettv, kMPInteger, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
|
@ -993,7 +994,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
};
|
||||
} else {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
create_special_dict(rettv, kMPInteger, ((typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
|
@ -1039,7 +1040,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
}
|
||||
case MSGPACK_OBJECT_ARRAY: {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
*rettv = (typval_T) {
|
||||
.v_type = VAR_LIST,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
|
@ -1047,9 +1048,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
|
|||
};
|
||||
for (size_t i = 0; i < mobj.via.array.size; i++) {
|
||||
listitem_T *const li = tv_list_item_alloc();
|
||||
li->li_tv.v_type = VAR_UNKNOWN;
|
||||
TV_LIST_ITEM_TV(li)->v_type = VAR_UNKNOWN;
|
||||
tv_list_append(list, li);
|
||||
if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
|
||||
if (msgpack_to_vim(mobj.via.array.ptr[i], TV_LIST_ITEM_TV(li))
|
||||
== FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
@ -1094,15 +1096,17 @@ msgpack_to_vim_generic_map: {}
|
|||
list_T *const kv_pair = tv_list_alloc();
|
||||
tv_list_append_list(list, kv_pair);
|
||||
listitem_T *const key_li = tv_list_item_alloc();
|
||||
key_li->li_tv.v_type = VAR_UNKNOWN;
|
||||
TV_LIST_ITEM_TV(key_li)->v_type = VAR_UNKNOWN;
|
||||
tv_list_append(kv_pair, key_li);
|
||||
listitem_T *const val_li = tv_list_item_alloc();
|
||||
val_li->li_tv.v_type = VAR_UNKNOWN;
|
||||
TV_LIST_ITEM_TV(val_li)->v_type = VAR_UNKNOWN;
|
||||
tv_list_append(kv_pair, val_li);
|
||||
if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
|
||||
if (msgpack_to_vim(mobj.via.map.ptr[i].key, TV_LIST_ITEM_TV(key_li))
|
||||
== FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_li->li_tv) == FAIL) {
|
||||
if (msgpack_to_vim(mobj.via.map.ptr[i].val, TV_LIST_ITEM_TV(val_li))
|
||||
== FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
@ -1110,7 +1114,7 @@ msgpack_to_vim_generic_map: {}
|
|||
}
|
||||
case MSGPACK_OBJECT_EXT: {
|
||||
list_T *const list = tv_list_alloc();
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
tv_list_append_number(list, mobj.via.ext.type);
|
||||
list_T *const ext_val_list = tv_list_alloc();
|
||||
tv_list_append_list(list, ext_val_list);
|
||||
|
|
|
@ -53,17 +53,18 @@ int encode_list_write(void *const data, const char *const buf, const size_t len)
|
|||
list_T *const list = (list_T *) data;
|
||||
const char *const end = buf + len;
|
||||
const char *line_end = buf;
|
||||
listitem_T *li = list->lv_last;
|
||||
listitem_T *li = tv_list_last(list);
|
||||
|
||||
// Continue the last list element
|
||||
if (li != NULL) {
|
||||
line_end = xmemscan(buf, NL, len);
|
||||
if (line_end != buf) {
|
||||
const size_t line_length = (size_t)(line_end - buf);
|
||||
char *str = (char *)li->li_tv.vval.v_string;
|
||||
char *str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string;
|
||||
const size_t li_len = (str == NULL ? 0 : strlen(str));
|
||||
li->li_tv.vval.v_string = xrealloc(str, li_len + line_length + 1);
|
||||
str = (char *)li->li_tv.vval.v_string + li_len;
|
||||
TV_LIST_ITEM_TV(li)->vval.v_string = xrealloc(
|
||||
str, li_len + line_length + 1);
|
||||
str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string + li_len;
|
||||
memcpy(str, buf, line_length);
|
||||
str[line_length] = 0;
|
||||
memchrsub(str, NUL, NL, line_length);
|
||||
|
@ -135,21 +136,27 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
|
|||
}
|
||||
case kMPConvPairs:
|
||||
case kMPConvList: {
|
||||
int idx = 0;
|
||||
const listitem_T *li;
|
||||
for (li = v.data.l.list->lv_first;
|
||||
li != NULL && li->li_next != v.data.l.li;
|
||||
li = li->li_next) {
|
||||
idx++;
|
||||
}
|
||||
const int idx = (v.data.l.li == tv_list_first(v.data.l.list)
|
||||
? 0
|
||||
: (v.data.l.li == NULL
|
||||
? tv_list_len(v.data.l.list) - 1
|
||||
: (int)tv_list_idx_of_item(
|
||||
v.data.l.list,
|
||||
TV_LIST_ITEM_PREV(v.data.l.list,
|
||||
v.data.l.li))));
|
||||
const listitem_T *const li = (v.data.l.li == NULL
|
||||
? tv_list_last(v.data.l.list)
|
||||
: TV_LIST_ITEM_PREV(v.data.l.list,
|
||||
v.data.l.li));
|
||||
if (v.type == kMPConvList
|
||||
|| li == NULL
|
||||
|| (li->li_tv.v_type != VAR_LIST
|
||||
&& li->li_tv.vval.v_list->lv_len <= 0)) {
|
||||
vim_snprintf((char *) IObuff, IOSIZE, idx_msg, idx);
|
||||
|| (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
|
||||
&& tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) <= 0)) {
|
||||
vim_snprintf((char *)IObuff, IOSIZE, idx_msg, idx);
|
||||
ga_concat(&msg_ga, IObuff);
|
||||
} else {
|
||||
typval_T key_tv = li->li_tv.vval.v_list->lv_first->li_tv;
|
||||
typval_T key_tv = *TV_LIST_ITEM_TV(
|
||||
tv_list_first(TV_LIST_ITEM_TV(li)->vval.v_list));
|
||||
char *const key = encode_tv2echo(&key_tv, NULL);
|
||||
vim_snprintf((char *) IObuff, IOSIZE, key_pair_msg, key, idx);
|
||||
xfree(key);
|
||||
|
@ -202,21 +209,17 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len,
|
|||
FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
size_t len = 0;
|
||||
if (list != NULL) {
|
||||
for (const listitem_T *li = list->lv_first;
|
||||
li != NULL;
|
||||
li = li->li_next) {
|
||||
if (li->li_tv.v_type != VAR_STRING) {
|
||||
return false;
|
||||
}
|
||||
len++;
|
||||
if (li->li_tv.vval.v_string != 0) {
|
||||
len += STRLEN(li->li_tv.vval.v_string);
|
||||
}
|
||||
TV_LIST_ITER_CONST(list, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
|
||||
return false;
|
||||
}
|
||||
if (len) {
|
||||
len--;
|
||||
len++;
|
||||
if (TV_LIST_ITEM_TV(li)->vval.v_string != NULL) {
|
||||
len += STRLEN(TV_LIST_ITEM_TV(li)->vval.v_string);
|
||||
}
|
||||
});
|
||||
if (len) {
|
||||
len--;
|
||||
}
|
||||
*ret_len = len;
|
||||
if (len == 0) {
|
||||
|
@ -253,31 +256,34 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
|
|||
char *const buf_end = buf + nbuf;
|
||||
char *p = buf;
|
||||
while (p < buf_end) {
|
||||
assert(state->li_length == 0 || state->li->li_tv.vval.v_string != NULL);
|
||||
assert(state->li_length == 0
|
||||
|| TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL);
|
||||
for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) {
|
||||
assert(state->li->li_tv.vval.v_string != NULL);
|
||||
const char ch = (char)state->li->li_tv.vval.v_string[state->offset++];
|
||||
assert(TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL);
|
||||
const char ch = (char)(
|
||||
TV_LIST_ITEM_TV(state->li)->vval.v_string[state->offset++]);
|
||||
*p++ = (char)((char)ch == (char)NL ? (char)NUL : (char)ch);
|
||||
}
|
||||
if (p < buf_end) {
|
||||
state->li = state->li->li_next;
|
||||
state->li = TV_LIST_ITEM_NEXT(state->list, state->li);
|
||||
if (state->li == NULL) {
|
||||
*read_bytes = (size_t) (p - buf);
|
||||
return OK;
|
||||
}
|
||||
*p++ = NL;
|
||||
if (state->li->li_tv.v_type != VAR_STRING) {
|
||||
*read_bytes = (size_t) (p - buf);
|
||||
if (TV_LIST_ITEM_TV(state->li)->v_type != VAR_STRING) {
|
||||
*read_bytes = (size_t)(p - buf);
|
||||
return FAIL;
|
||||
}
|
||||
state->offset = 0;
|
||||
state->li_length = (state->li->li_tv.vval.v_string == NULL
|
||||
state->li_length = (TV_LIST_ITEM_TV(state->li)->vval.v_string == NULL
|
||||
? 0
|
||||
: STRLEN(state->li->li_tv.vval.v_string));
|
||||
: STRLEN(TV_LIST_ITEM_TV(state->li)->vval.v_string));
|
||||
}
|
||||
}
|
||||
*read_bytes = nbuf;
|
||||
return (state->offset < state->li_length || state->li->li_next != NULL
|
||||
return ((state->offset < state->li_length
|
||||
|| TV_LIST_ITEM_NEXT(state->list, state->li) != NULL)
|
||||
? NOTDONE
|
||||
: OK);
|
||||
}
|
||||
|
@ -727,12 +733,11 @@ bool encode_check_json_key(const typval_T *const tv)
|
|||
if (val_di->di_tv.vval.v_list == NULL) {
|
||||
return true;
|
||||
}
|
||||
for (const listitem_T *li = val_di->di_tv.vval.v_list->lv_first;
|
||||
li != NULL; li = li->li_next) {
|
||||
if (li->li_tv.v_type != VAR_STRING) {
|
||||
TV_LIST_ITER_CONST(val_di->di_tv.vval.v_list, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,10 @@ int encode_vim_to_echo(garray_T *const packer,
|
|||
|
||||
/// Structure defining state for read_from_list()
|
||||
typedef struct {
|
||||
const list_T *const list; ///< List being currently read.
|
||||
const listitem_T *li; ///< Item currently read.
|
||||
size_t offset; ///< Byte offset inside the read item.
|
||||
size_t li_length; ///< Length of the string inside the read item.
|
||||
size_t offset; ///< Byte offset inside the read item.
|
||||
size_t li_length; ///< Length of the string inside the read item.
|
||||
} ListReaderState;
|
||||
|
||||
/// Initialize ListReaderState structure
|
||||
|
@ -43,11 +44,13 @@ static inline ListReaderState encode_init_lrstate(const list_T *const list)
|
|||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
return (ListReaderState) {
|
||||
.li = list->lv_first,
|
||||
.list = list,
|
||||
.li = tv_list_first(list),
|
||||
.offset = 0,
|
||||
.li_length = (list->lv_first->li_tv.vval.v_string == NULL
|
||||
.li_length = (TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string == NULL
|
||||
? 0
|
||||
: STRLEN(list->lv_first->li_tv.vval.v_string)),
|
||||
: STRLEN(TV_LIST_ITEM_TV(
|
||||
tv_list_first(list))->vval.v_string)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ listitem_T *tv_list_item_alloc(void)
|
|||
void tv_list_item_free(listitem_T *const item)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
tv_clear(&item->li_tv);
|
||||
tv_clear(TV_LIST_ITEM_TV(item));
|
||||
xfree(item);
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,45 @@ list_T *tv_list_alloc(void)
|
|||
return list;
|
||||
}
|
||||
|
||||
/// Initialize a static list with 10 items
|
||||
///
|
||||
/// @param[out] sl Static list to initialize.
|
||||
void tv_list_init_static10(staticList10_T *const sl)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
#define SL_SIZE ARRAY_SIZE(sl->sl_items)
|
||||
list_T *const l = &sl->sl_list;
|
||||
|
||||
memset(sl, 0, sizeof(staticList10_T));
|
||||
l->lv_first = &sl->sl_items[0];
|
||||
l->lv_last = &sl->sl_items[SL_SIZE - 1];
|
||||
l->lv_refcount = DO_NOT_FREE_CNT;
|
||||
tv_list_set_lock(l, VAR_FIXED);
|
||||
sl->sl_list.lv_len = 10;
|
||||
|
||||
sl->sl_items[0].li_prev = NULL;
|
||||
sl->sl_items[0].li_next = &sl->sl_items[1];
|
||||
sl->sl_items[SL_SIZE - 1].li_prev = &sl->sl_items[SL_SIZE - 2];
|
||||
sl->sl_items[SL_SIZE - 1].li_next = NULL;
|
||||
|
||||
for (size_t i = 1; i < SL_SIZE - 1; i++) {
|
||||
listitem_T *const li = &sl->sl_items[i];
|
||||
li->li_prev = li - 1;
|
||||
li->li_next = li + 1;
|
||||
}
|
||||
#undef SL_SIZE
|
||||
}
|
||||
|
||||
/// Initialize static list with undefined number of elements
|
||||
///
|
||||
/// @param[out] l List to initialize.
|
||||
void tv_list_init_static(list_T *const l)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
memset(l, 0, sizeof(*l));
|
||||
l->lv_refcount = DO_NOT_FREE_CNT;
|
||||
}
|
||||
|
||||
/// Free items contained in a list
|
||||
///
|
||||
/// @param[in,out] l List to clear.
|
||||
|
@ -221,7 +260,7 @@ void tv_list_unref(list_T *const l)
|
|||
|
||||
//{{{2 Add/remove
|
||||
|
||||
/// Remove items "item" to "item2" from list "l".
|
||||
/// Remove items "item" to "item2" from list "l"
|
||||
///
|
||||
/// @warning Does not free the listitem or the value!
|
||||
///
|
||||
|
@ -251,6 +290,30 @@ void tv_list_remove_items(list_T *const l, listitem_T *const item,
|
|||
l->lv_idx_item = NULL;
|
||||
}
|
||||
|
||||
/// Move items "item" to "item2" from list "l" to the end of the list "tgt_l"
|
||||
///
|
||||
/// @param[out] l List to move from.
|
||||
/// @param[in] item First item to move.
|
||||
/// @param[in] item2 Last item to move.
|
||||
/// @param[out] tgt_l List to move to.
|
||||
/// @param[in] cnt Number of items moved.
|
||||
void tv_list_move_items(list_T *const l, listitem_T *const item,
|
||||
listitem_T *const item2, list_T *const tgt_l,
|
||||
const int cnt)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
tv_list_remove_items(l, item, item2);
|
||||
item->li_prev = tgt_l->lv_last;
|
||||
item2->li_next = NULL;
|
||||
if (tgt_l->lv_last == NULL) {
|
||||
tgt_l->lv_first = item;
|
||||
} else {
|
||||
tgt_l->lv_last->li_next = item;
|
||||
}
|
||||
tgt_l->lv_last = item2;
|
||||
tgt_l->lv_len += cnt;
|
||||
}
|
||||
|
||||
/// Insert list item
|
||||
///
|
||||
/// @param[out] l List to insert to.
|
||||
|
@ -326,7 +389,7 @@ void tv_list_append_tv(list_T *const l, typval_T *const tv)
|
|||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
listitem_T *const li = tv_list_item_alloc();
|
||||
tv_copy(tv, &li->li_tv);
|
||||
tv_copy(tv, TV_LIST_ITEM_TV(li));
|
||||
tv_list_append(l, li);
|
||||
}
|
||||
|
||||
|
@ -339,13 +402,11 @@ void tv_list_append_list(list_T *const list, list_T *const itemlist)
|
|||
{
|
||||
listitem_T *const li = tv_list_item_alloc();
|
||||
|
||||
li->li_tv.v_type = VAR_LIST;
|
||||
li->li_tv.v_lock = VAR_UNLOCKED;
|
||||
li->li_tv.vval.v_list = itemlist;
|
||||
TV_LIST_ITEM_TV(li)->v_type = VAR_LIST;
|
||||
TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED;
|
||||
TV_LIST_ITEM_TV(li)->vval.v_list = itemlist;
|
||||
tv_list_append(list, li);
|
||||
if (itemlist != NULL) {
|
||||
itemlist->lv_refcount++;
|
||||
}
|
||||
tv_list_ref(itemlist);
|
||||
}
|
||||
|
||||
/// Append a dictionary to a list
|
||||
|
@ -357,9 +418,9 @@ void tv_list_append_dict(list_T *const list, dict_T *const dict)
|
|||
{
|
||||
listitem_T *const li = tv_list_item_alloc();
|
||||
|
||||
li->li_tv.v_type = VAR_DICT;
|
||||
li->li_tv.v_lock = VAR_UNLOCKED;
|
||||
li->li_tv.vval.v_dict = dict;
|
||||
TV_LIST_ITEM_TV(li)->v_type = VAR_DICT;
|
||||
TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED;
|
||||
TV_LIST_ITEM_TV(li)->vval.v_dict = dict;
|
||||
tv_list_append(list, li);
|
||||
if (dict != NULL) {
|
||||
dict->dv_refcount++;
|
||||
|
@ -399,9 +460,9 @@ void tv_list_append_allocated_string(list_T *const l, char *const str)
|
|||
listitem_T *const li = tv_list_item_alloc();
|
||||
|
||||
tv_list_append(l, li);
|
||||
li->li_tv.v_type = VAR_STRING;
|
||||
li->li_tv.v_lock = VAR_UNLOCKED;
|
||||
li->li_tv.vval.v_string = (char_u *)str;
|
||||
TV_LIST_ITEM_TV(li)->v_type = VAR_STRING;
|
||||
TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED;
|
||||
TV_LIST_ITEM_TV(li)->vval.v_string = (char_u *)str;
|
||||
}
|
||||
|
||||
/// Append number to the list
|
||||
|
@ -412,9 +473,9 @@ void tv_list_append_allocated_string(list_T *const l, char *const str)
|
|||
void tv_list_append_number(list_T *const l, const varnumber_T n)
|
||||
{
|
||||
listitem_T *const li = tv_list_item_alloc();
|
||||
li->li_tv.v_type = VAR_NUMBER;
|
||||
li->li_tv.v_lock = VAR_UNLOCKED;
|
||||
li->li_tv.vval.v_number = n;
|
||||
TV_LIST_ITEM_TV(li)->v_type = VAR_NUMBER;
|
||||
TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED;
|
||||
TV_LIST_ITEM_TV(li)->vval.v_number = n;
|
||||
tv_list_append(l, li);
|
||||
}
|
||||
|
||||
|
@ -439,33 +500,35 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
|
|||
}
|
||||
|
||||
list_T *copy = tv_list_alloc();
|
||||
tv_list_ref(copy);
|
||||
if (copyID != 0) {
|
||||
// Do this before adding the items, because one of the items may
|
||||
// refer back to this list.
|
||||
orig->lv_copyID = copyID;
|
||||
orig->lv_copylist = copy;
|
||||
}
|
||||
listitem_T *item;
|
||||
for (item = orig->lv_first; item != NULL && !got_int;
|
||||
item = item->li_next) {
|
||||
TV_LIST_ITER(orig, item, {
|
||||
if (got_int) {
|
||||
break;
|
||||
}
|
||||
listitem_T *const ni = tv_list_item_alloc();
|
||||
if (deep) {
|
||||
if (var_item_copy(conv, &item->li_tv, &ni->li_tv, deep, copyID) == FAIL) {
|
||||
if (var_item_copy(conv, TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni),
|
||||
deep, copyID) == FAIL) {
|
||||
xfree(ni);
|
||||
break;
|
||||
goto tv_list_copy_error;
|
||||
}
|
||||
} else {
|
||||
tv_copy(&item->li_tv, &ni->li_tv);
|
||||
tv_copy(TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni));
|
||||
}
|
||||
tv_list_append(copy, ni);
|
||||
}
|
||||
copy->lv_refcount++;
|
||||
if (item != NULL) {
|
||||
tv_list_unref(copy);
|
||||
copy = NULL;
|
||||
}
|
||||
});
|
||||
|
||||
return copy;
|
||||
|
||||
tv_list_copy_error:
|
||||
tv_list_unref(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Extend first list with the second
|
||||
|
@ -475,17 +538,17 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
|
|||
/// @param[in] bef If not NULL, extends before this item.
|
||||
void tv_list_extend(list_T *const l1, list_T *const l2,
|
||||
listitem_T *const bef)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
int todo = l2->lv_len;
|
||||
int todo = tv_list_len(l2);
|
||||
listitem_T *const befbef = (bef == NULL ? NULL : bef->li_prev);
|
||||
listitem_T *const saved_next = (befbef == NULL ? NULL : befbef->li_next);
|
||||
// We also quit the loop when we have inserted the original item count of
|
||||
// the list, avoid a hang when we extend a list with itself.
|
||||
for (listitem_T *item = l2->lv_first
|
||||
; item != NULL && --todo >= 0
|
||||
for (listitem_T *item = tv_list_first(l2)
|
||||
; item != NULL && todo--
|
||||
; item = (item == befbef ? saved_next : item->li_next)) {
|
||||
tv_list_insert_tv(l1, &item->li_tv, bef);
|
||||
tv_list_insert_tv(l1, TV_LIST_ITEM_TV(item), bef);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,13 +603,15 @@ static int list_join_inner(garray_T *const gap, list_T *const l,
|
|||
{
|
||||
size_t sumlen = 0;
|
||||
bool first = true;
|
||||
listitem_T *item;
|
||||
|
||||
// Stringify each item in the list.
|
||||
for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) {
|
||||
TV_LIST_ITER(l, item, {
|
||||
if (got_int) {
|
||||
break;
|
||||
}
|
||||
char *s;
|
||||
size_t len;
|
||||
s = encode_tv2echo(&item->li_tv, &len);
|
||||
s = encode_tv2echo(TV_LIST_ITEM_TV(item), &len);
|
||||
if (s == NULL) {
|
||||
return FAIL;
|
||||
}
|
||||
|
@ -557,7 +622,7 @@ static int list_join_inner(garray_T *const gap, list_T *const l,
|
|||
p->tofree = p->s = (char_u *)s;
|
||||
|
||||
line_breakcheck();
|
||||
}
|
||||
});
|
||||
|
||||
// Allocate result buffer with its total size, avoid re-allocation and
|
||||
// multiple copy operations. Add 2 for a tailing ']' and NUL.
|
||||
|
@ -591,16 +656,16 @@ static int list_join_inner(garray_T *const gap, list_T *const l,
|
|||
///
|
||||
/// @return OK in case of success, FAIL otherwise.
|
||||
int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
if (l->lv_len < 1) {
|
||||
if (!tv_list_len(l)) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
garray_T join_ga;
|
||||
int retval;
|
||||
|
||||
ga_init(&join_ga, (int)sizeof(Join), l->lv_len);
|
||||
ga_init(&join_ga, (int)sizeof(Join), tv_list_len(l));
|
||||
retval = list_join_inner(gap, l, sep, &join_ga);
|
||||
|
||||
#define FREE_JOIN_TOFREE(join) xfree((join)->tofree)
|
||||
|
@ -632,11 +697,13 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic,
|
|||
return false;
|
||||
}
|
||||
|
||||
listitem_T *item1 = l1->lv_first;
|
||||
listitem_T *item2 = l2->lv_first;
|
||||
listitem_T *item1 = tv_list_first(l1);
|
||||
listitem_T *item2 = tv_list_first(l2);
|
||||
for (; item1 != NULL && item2 != NULL
|
||||
; item1 = item1->li_next, item2 = item2->li_next) {
|
||||
if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive)) {
|
||||
; (item1 = TV_LIST_ITEM_NEXT(l1, item1),
|
||||
item2 = TV_LIST_ITEM_NEXT(l2, item2))) {
|
||||
if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic,
|
||||
recursive)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -644,6 +711,31 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic,
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Reverse list in-place
|
||||
///
|
||||
/// @param[in,out] l List to reverse.
|
||||
void tv_list_reverse(list_T *const l)
|
||||
{
|
||||
if (tv_list_len(l) <= 1) {
|
||||
return;
|
||||
}
|
||||
#define SWAP(a, b) \
|
||||
do { \
|
||||
tmp = a; \
|
||||
a = b; \
|
||||
b = tmp; \
|
||||
} while (0)
|
||||
listitem_T *tmp;
|
||||
|
||||
SWAP(l->lv_first, l->lv_last);
|
||||
for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) {
|
||||
SWAP(li->li_next, li->li_prev);
|
||||
}
|
||||
#undef SWAP
|
||||
|
||||
l->lv_idx = l->lv_len - l->lv_idx - 1;
|
||||
}
|
||||
|
||||
//{{{2 Indexing/searching
|
||||
|
||||
/// Locate item with a given index in a list and return it
|
||||
|
@ -662,13 +754,8 @@ listitem_T *tv_list_find(list_T *const l, int n)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// Negative index is relative to the end.
|
||||
if (n < 0) {
|
||||
n = l->lv_len + n;
|
||||
}
|
||||
|
||||
// Check for index out of range.
|
||||
if (n < 0 || n >= l->lv_len) {
|
||||
n = tv_list_uidx(l, n);
|
||||
if (n == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -740,7 +827,7 @@ varnumber_T tv_list_find_nr(list_T *const l, const int n, bool *const ret_error)
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
return tv_get_number_chk(&li->li_tv, ret_error);
|
||||
return tv_get_number_chk(TV_LIST_ITEM_TV(li), ret_error);
|
||||
}
|
||||
|
||||
/// Get list item l[n] as a string
|
||||
|
@ -757,7 +844,7 @@ const char *tv_list_find_str(list_T *const l, const int n)
|
|||
emsgf(_(e_listidx), (int64_t)n);
|
||||
return NULL;
|
||||
}
|
||||
return tv_get_string(&li->li_tv);
|
||||
return tv_get_string(TV_LIST_ITEM_TV(li));
|
||||
}
|
||||
|
||||
/// Locate item in a list and return its index
|
||||
|
@ -772,15 +859,14 @@ long tv_list_idx_of_item(const list_T *const l, const listitem_T *const item)
|
|||
if (l == NULL) {
|
||||
return -1;
|
||||
}
|
||||
long idx = 0;
|
||||
const listitem_T *li;
|
||||
for (li = l->lv_first; li != NULL && li != item; li = li->li_next) {
|
||||
int idx = 0;
|
||||
TV_LIST_ITER_CONST(l, li, {
|
||||
if (li == item) {
|
||||
return idx;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
if (li == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return idx;
|
||||
});
|
||||
return -1;
|
||||
}
|
||||
|
||||
//{{{1 Dictionaries
|
||||
|
@ -1339,7 +1425,7 @@ int tv_dict_add_list(dict_T *const d, const char *const key,
|
|||
item->di_tv.v_lock = VAR_UNLOCKED;
|
||||
item->di_tv.v_type = VAR_LIST;
|
||||
item->di_tv.vval.v_list = list;
|
||||
list->lv_refcount++;
|
||||
tv_list_ref(list);
|
||||
if (tv_dict_add(d, item) == FAIL) {
|
||||
tv_dict_item_free(item);
|
||||
return FAIL;
|
||||
|
@ -1677,7 +1763,7 @@ list_T *tv_list_alloc_ret(typval_T *const ret_tv)
|
|||
ret_tv->vval.v_list = l;
|
||||
ret_tv->v_type = VAR_LIST;
|
||||
ret_tv->v_lock = VAR_UNLOCKED;
|
||||
l->lv_refcount++;
|
||||
tv_list_ref(l);
|
||||
return l;
|
||||
}
|
||||
|
||||
|
@ -2032,9 +2118,7 @@ void tv_copy(typval_T *const from, typval_T *const to)
|
|||
break;
|
||||
}
|
||||
case VAR_LIST: {
|
||||
if (from->vval.v_list != NULL) {
|
||||
to->vval.v_list->lv_refcount++;
|
||||
}
|
||||
tv_list_ref(to->vval.v_list);
|
||||
break;
|
||||
}
|
||||
case VAR_DICT: {
|
||||
|
@ -2090,9 +2174,9 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
|
|||
CHANGE_LOCK(lock, l->lv_lock);
|
||||
if (deep < 0 || deep > 1) {
|
||||
// Recursive: lock/unlock the items the List contains.
|
||||
for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) {
|
||||
tv_item_lock(&li->li_tv, deep - 1, lock);
|
||||
}
|
||||
TV_LIST_ITER(l, li, {
|
||||
tv_item_lock(TV_LIST_ITEM_TV(li), deep - 1, lock);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2128,6 +2212,8 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
|
|||
|
||||
/// Check whether VimL value is locked itself or refers to a locked container
|
||||
///
|
||||
/// @warning Fixed container is not the same as locked.
|
||||
///
|
||||
/// @param[in] tv Value to check.
|
||||
///
|
||||
/// @return True if value is locked, false otherwise.
|
||||
|
@ -2136,8 +2222,7 @@ bool tv_islocked(const typval_T *const tv)
|
|||
{
|
||||
return ((tv->v_lock == VAR_LOCKED)
|
||||
|| (tv->v_type == VAR_LIST
|
||||
&& tv->vval.v_list != NULL
|
||||
&& (tv->vval.v_list->lv_lock == VAR_LOCKED))
|
||||
&& (tv_list_locked(tv->vval.v_list) == VAR_LOCKED))
|
||||
|| (tv->v_type == VAR_DICT
|
||||
&& tv->vval.v_dict != NULL
|
||||
&& (tv->vval.v_dict->dv_lock == VAR_LOCKED)));
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/hashtab.h"
|
||||
|
@ -26,6 +28,9 @@ typedef uint64_t uvarnumber_T;
|
|||
/// Type used for VimL VAR_FLOAT values
|
||||
typedef double float_T;
|
||||
|
||||
/// Refcount for dict or list that should not be freed
|
||||
enum { DO_NOT_FREE_CNT = (INT_MAX / 2) };
|
||||
|
||||
/// Maximal possible value of varnumber_T variable
|
||||
#define VARNUMBER_MAX INT64_MAX
|
||||
#define UVARNUMBER_MAX UINT64_MAX
|
||||
|
@ -150,12 +155,26 @@ struct listvar_S {
|
|||
list_T *lv_used_prev; ///< Previous list in used lists list.
|
||||
};
|
||||
|
||||
// Static list with 10 items. Use init_static_list() to initialize.
|
||||
// Static list with 10 items. Use tv_list_init_static10() to initialize.
|
||||
typedef struct {
|
||||
list_T sl_list; // must be first
|
||||
listitem_T sl_items[10];
|
||||
} staticList10_T;
|
||||
|
||||
#define TV_LIST_STATIC10_INIT { \
|
||||
.sl_list = { \
|
||||
.lv_first = NULL, \
|
||||
.lv_last = NULL, \
|
||||
.lv_refcount = 0, \
|
||||
.lv_len = 0, \
|
||||
.lv_watch = NULL, \
|
||||
.lv_idx_item = NULL, \
|
||||
.lv_lock = VAR_FIXED, \
|
||||
.lv_used_next = NULL, \
|
||||
.lv_used_prev = NULL, \
|
||||
}, \
|
||||
}
|
||||
|
||||
// Structure to hold an item of a Dictionary.
|
||||
// Also used for a variable.
|
||||
// The key is copied into "di_key" to avoid an extra alloc/free for it.
|
||||
|
@ -284,13 +303,71 @@ typedef struct list_stack_S {
|
|||
#define TV_DICT_HI2DI(hi) \
|
||||
((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
|
||||
|
||||
static inline long tv_list_len(const list_T *const l)
|
||||
/// Increase reference count for a given list
|
||||
///
|
||||
/// Does nothing for NULL lists.
|
||||
///
|
||||
/// @param[in] l List to modify.
|
||||
static inline void tv_list_ref(list_T *const l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
return;
|
||||
}
|
||||
l->lv_refcount++;
|
||||
}
|
||||
|
||||
static inline VarLockStatus tv_list_locked(const list_T *const l)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Get list lock status
|
||||
///
|
||||
/// Returns VAR_FIXED for NULL lists.
|
||||
///
|
||||
/// @param[in] l List to check.
|
||||
static inline VarLockStatus tv_list_locked(const list_T *const l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
return VAR_FIXED;
|
||||
}
|
||||
return l->lv_lock;
|
||||
}
|
||||
|
||||
/// Set list lock status
|
||||
///
|
||||
/// May only “set” VAR_FIXED for NULL lists.
|
||||
///
|
||||
/// @param[out] l List to modify.
|
||||
/// @param[in] lock New lock status.
|
||||
static inline void tv_list_set_lock(list_T *const l,
|
||||
const VarLockStatus lock)
|
||||
{
|
||||
if (l == NULL) {
|
||||
assert(lock == VAR_FIXED);
|
||||
return;
|
||||
}
|
||||
l->lv_lock = lock;
|
||||
}
|
||||
|
||||
/// Set list copyID
|
||||
///
|
||||
/// Does not expect NULL list, be careful.
|
||||
///
|
||||
/// @param[out] l List to modify.
|
||||
/// @param[in] copyid New copyID.
|
||||
static inline void tv_list_set_copyid(list_T *const l,
|
||||
const int copyid)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
l->lv_copyID = copyid;
|
||||
}
|
||||
|
||||
static inline int tv_list_len(const list_T *const l)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Get the number of items in a list
|
||||
///
|
||||
/// @param[in] l List to check.
|
||||
static inline long tv_list_len(const list_T *const l)
|
||||
static inline int tv_list_len(const list_T *const l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
return 0;
|
||||
|
@ -298,6 +375,118 @@ static inline long tv_list_len(const list_T *const l)
|
|||
return l->lv_len;
|
||||
}
|
||||
|
||||
static inline int tv_list_copyid(const list_T *const l)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
|
||||
|
||||
/// Get list copyID
|
||||
///
|
||||
/// Does not expect NULL list, be careful.
|
||||
///
|
||||
/// @param[in] l List to check.
|
||||
static inline int tv_list_copyid(const list_T *const l)
|
||||
{
|
||||
return l->lv_copyID;
|
||||
}
|
||||
|
||||
static inline list_T *tv_list_latest_copy(const list_T *const l)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
|
||||
|
||||
/// Get latest list copy
|
||||
///
|
||||
/// Gets lv_copylist field assigned by tv_list_copy() earlier.
|
||||
///
|
||||
/// Does not expect NULL list, be careful.
|
||||
///
|
||||
/// @param[in] l List to check.
|
||||
static inline list_T *tv_list_latest_copy(const list_T *const l)
|
||||
{
|
||||
return l->lv_copylist;
|
||||
}
|
||||
|
||||
/// Clear the list without freeing anything at all
|
||||
///
|
||||
/// For use in sort() which saves items to a separate array and readds them back
|
||||
/// after sorting via a number of tv_list_append() calls.
|
||||
///
|
||||
/// @param[out] l List to clear.
|
||||
static inline void tv_list_clear(list_T *const l)
|
||||
{
|
||||
l->lv_first = NULL;
|
||||
l->lv_last = NULL;
|
||||
l->lv_idx_item = NULL;
|
||||
l->lv_len = 0;
|
||||
}
|
||||
|
||||
static inline int tv_list_uidx(const list_T *const l, int n)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Normalize index: that is, return either -1 or non-negative index
|
||||
///
|
||||
/// @param[in] l List to index. Used to get length.
|
||||
/// @param[in] n List index, possibly negative.
|
||||
///
|
||||
/// @return -1 or list index in range [0, tv_list_len(l)).
|
||||
static inline int tv_list_uidx(const list_T *const l, int n)
|
||||
{
|
||||
// Negative index is relative to the end.
|
||||
if (n < 0) {
|
||||
n += tv_list_len(l);
|
||||
}
|
||||
|
||||
// Check for index out of range.
|
||||
if (n < 0 || n >= tv_list_len(l)) {
|
||||
return -1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline bool tv_list_has_watchers(const list_T *const l)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Check whether list has watchers
|
||||
///
|
||||
/// E.g. is referenced by a :for loop.
|
||||
///
|
||||
/// @param[in] l List to check.
|
||||
///
|
||||
/// @return true if there are watchers, false otherwise.
|
||||
static inline bool tv_list_has_watchers(const list_T *const l)
|
||||
{
|
||||
return l && l->lv_watch;
|
||||
}
|
||||
|
||||
static inline listitem_T *tv_list_first(const list_T *const l)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Get first list item
|
||||
///
|
||||
/// @param[in] l List to get item from.
|
||||
///
|
||||
/// @return List item or NULL in case of an empty list.
|
||||
static inline listitem_T *tv_list_first(const list_T *const l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return l->lv_first;
|
||||
}
|
||||
|
||||
static inline listitem_T *tv_list_last(const list_T *const l)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Get last list item
|
||||
///
|
||||
/// @param[in] l List to get item from.
|
||||
///
|
||||
/// @return List item or NULL in case of an empty list.
|
||||
static inline listitem_T *tv_list_last(const list_T *const l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return l->lv_last;
|
||||
}
|
||||
|
||||
static inline long tv_dict_len(const dict_T *const d)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
|
@ -352,6 +541,75 @@ extern const char *const tv_empty_string;
|
|||
/// Specifies that free_unref_items() function has (not) been entered
|
||||
extern bool tv_in_free_unref_items;
|
||||
|
||||
/// Iterate over a list
|
||||
///
|
||||
/// @param modifier Modifier: expected to be const or nothing, volatile should
|
||||
/// also work if you have any uses for the volatile list.
|
||||
/// @param[in] l List to iterate over.
|
||||
/// @param li Name of the variable with current listitem_T entry.
|
||||
/// @param code Cycle body.
|
||||
#define _TV_LIST_ITER_MOD(modifier, l, li, code) \
|
||||
do { \
|
||||
modifier list_T *const l_ = (l); \
|
||||
if (l_ != NULL) { \
|
||||
for (modifier listitem_T *li = l_->lv_first; \
|
||||
li != NULL; li = li->li_next) { \
|
||||
code \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/// Iterate over a list
|
||||
///
|
||||
/// To be used when you need to modify list or values you iterate over, use
|
||||
/// #TV_LIST_ITER_CONST if you don’t.
|
||||
///
|
||||
/// @param[in] l List to iterate over.
|
||||
/// @param li Name of the variable with current listitem_T entry.
|
||||
/// @param code Cycle body.
|
||||
#define TV_LIST_ITER(l, li, code) \
|
||||
_TV_LIST_ITER_MOD(, l, li, code)
|
||||
|
||||
/// Iterate over a list
|
||||
///
|
||||
/// To be used when you don’t need to modify list or values you iterate over,
|
||||
/// use #TV_LIST_ITER if you do.
|
||||
///
|
||||
/// @param[in] l List to iterate over.
|
||||
/// @param li Name of the variable with current listitem_T entry.
|
||||
/// @param code Cycle body.
|
||||
#define TV_LIST_ITER_CONST(l, li, code) \
|
||||
_TV_LIST_ITER_MOD(const, l, li, code)
|
||||
|
||||
// Below macros are macros to avoid duplicating code for functionally identical
|
||||
// const and non-const function variants.
|
||||
|
||||
/// Get typval_T out of list item
|
||||
///
|
||||
/// @param[in] li List item to get typval_T from, must not be NULL.
|
||||
///
|
||||
/// @return Pointer to typval_T.
|
||||
#define TV_LIST_ITEM_TV(li) (&(li)->li_tv)
|
||||
|
||||
/// Get next list item given the current one
|
||||
///
|
||||
/// @param[in] l List to get item from.
|
||||
/// @param[in] li List item to get typval_T from.
|
||||
///
|
||||
/// @return Pointer to the next item or NULL.
|
||||
#define TV_LIST_ITEM_NEXT(l, li) ((li)->li_next)
|
||||
|
||||
/// Get previous list item given the current one
|
||||
///
|
||||
/// @param[in] l List to get item from.
|
||||
/// @param[in] li List item to get typval_T from.
|
||||
///
|
||||
/// @return Pointer to the previous item or NULL.
|
||||
#define TV_LIST_ITEM_PREV(l, li) ((li)->li_prev)
|
||||
// List argument is not used currently, but it is a must for lists implemented
|
||||
// as a pair (size(in list), array) without terminator - basically for lists on
|
||||
// top of kvec.
|
||||
|
||||
/// Iterate over a dictionary
|
||||
///
|
||||
/// @param[in] d Dictionary to iterate over.
|
||||
|
|
|
@ -355,14 +355,14 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
break;
|
||||
}
|
||||
case VAR_LIST: {
|
||||
if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) {
|
||||
if (tv->vval.v_list == NULL || tv_list_len(tv->vval.v_list) == 0) {
|
||||
TYPVAL_ENCODE_CONV_EMPTY_LIST(tv);
|
||||
break;
|
||||
}
|
||||
const int saved_copyID = tv->vval.v_list->lv_copyID;
|
||||
const int saved_copyID = tv_list_copyid(tv->vval.v_list);
|
||||
_TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, copyID,
|
||||
kMPConvList);
|
||||
TYPVAL_ENCODE_CONV_LIST_START(tv, tv->vval.v_list->lv_len);
|
||||
TYPVAL_ENCODE_CONV_LIST_START(tv, tv_list_len(tv->vval.v_list));
|
||||
assert(saved_copyID != copyID && saved_copyID != copyID - 1);
|
||||
_mp_push(*mpstack, ((MPConvStackVal) {
|
||||
.type = kMPConvList,
|
||||
|
@ -371,7 +371,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
.data = {
|
||||
.l = {
|
||||
.list = tv->vval.v_list,
|
||||
.li = tv->vval.v_list->lv_first,
|
||||
.li = tv_list_first(tv->vval.v_list),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
@ -440,23 +440,43 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
// bits is not checked), other unsigned and have at most 31
|
||||
// non-zero bits (number of bits is not checked).
|
||||
if (val_di->di_tv.v_type != VAR_LIST
|
||||
|| (val_list = val_di->di_tv.vval.v_list) == NULL
|
||||
|| val_list->lv_len != 4
|
||||
|| val_list->lv_first->li_tv.v_type != VAR_NUMBER
|
||||
|| (sign = val_list->lv_first->li_tv.vval.v_number) == 0
|
||||
|| val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER
|
||||
|| (highest_bits =
|
||||
val_list->lv_first->li_next->li_tv.vval.v_number) < 0
|
||||
|| val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER
|
||||
|| (high_bits =
|
||||
val_list->lv_last->li_prev->li_tv.vval.v_number) < 0
|
||||
|| val_list->lv_last->li_tv.v_type != VAR_NUMBER
|
||||
|| (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) {
|
||||
|| tv_list_len(val_list = val_di->di_tv.vval.v_list) != 4) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
uint64_t number = ((uint64_t)(((uint64_t)highest_bits) << 62)
|
||||
| (uint64_t)(((uint64_t)high_bits) << 31)
|
||||
| (uint64_t)low_bits);
|
||||
|
||||
const listitem_T *const sign_li = tv_list_first(val_list);
|
||||
if (TV_LIST_ITEM_TV(sign_li)->v_type != VAR_NUMBER
|
||||
|| (sign = TV_LIST_ITEM_TV(sign_li)->vval.v_number) == 0) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
|
||||
const listitem_T *const highest_bits_li = (
|
||||
TV_LIST_ITEM_NEXT(val_list, sign_li));
|
||||
if (TV_LIST_ITEM_TV(highest_bits_li)->v_type != VAR_NUMBER
|
||||
|| ((highest_bits
|
||||
= TV_LIST_ITEM_TV(highest_bits_li)->vval.v_number)
|
||||
< 0)) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
|
||||
const listitem_T *const high_bits_li = (
|
||||
TV_LIST_ITEM_NEXT(val_list, highest_bits_li));
|
||||
if (TV_LIST_ITEM_TV(high_bits_li)->v_type != VAR_NUMBER
|
||||
|| ((high_bits = TV_LIST_ITEM_TV(high_bits_li)->vval.v_number)
|
||||
< 0)) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
|
||||
const listitem_T *const low_bits_li = tv_list_last(val_list);
|
||||
if (TV_LIST_ITEM_TV(low_bits_li)->v_type != VAR_NUMBER
|
||||
|| ((low_bits = TV_LIST_ITEM_TV(low_bits_li)->vval.v_number)
|
||||
< 0)) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
|
||||
const uint64_t number = ((uint64_t)(((uint64_t)highest_bits) << 62)
|
||||
| (uint64_t)(((uint64_t)high_bits) << 31)
|
||||
| (uint64_t)low_bits);
|
||||
if (sign > 0) {
|
||||
TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, number);
|
||||
} else {
|
||||
|
@ -495,12 +515,12 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
if (val_di->di_tv.v_type != VAR_LIST) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
const int saved_copyID = val_di->di_tv.vval.v_list->lv_copyID;
|
||||
const int saved_copyID = tv_list_copyid(val_di->di_tv.vval.v_list);
|
||||
_TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list,
|
||||
lv_copyID, copyID,
|
||||
kMPConvList);
|
||||
TYPVAL_ENCODE_CONV_LIST_START(tv,
|
||||
val_di->di_tv.vval.v_list->lv_len);
|
||||
TYPVAL_ENCODE_CONV_LIST_START(
|
||||
tv, tv_list_len(val_di->di_tv.vval.v_list));
|
||||
assert(saved_copyID != copyID && saved_copyID != copyID - 1);
|
||||
_mp_push(*mpstack, ((MPConvStackVal) {
|
||||
.tv = tv,
|
||||
|
@ -509,7 +529,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
.data = {
|
||||
.l = {
|
||||
.list = val_di->di_tv.vval.v_list,
|
||||
.li = val_di->di_tv.vval.v_list->lv_first,
|
||||
.li = tv_list_first(val_di->di_tv.vval.v_list),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
@ -520,22 +540,21 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
list_T *const val_list = val_di->di_tv.vval.v_list;
|
||||
if (val_list == NULL || val_list->lv_len == 0) {
|
||||
if (val_list == NULL || tv_list_len(val_list) == 0) {
|
||||
TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, TYPVAL_ENCODE_NODICT_VAR);
|
||||
break;
|
||||
}
|
||||
for (const listitem_T *li = val_list->lv_first; li != NULL;
|
||||
li = li->li_next) {
|
||||
if (li->li_tv.v_type != VAR_LIST
|
||||
|| li->li_tv.vval.v_list->lv_len != 2) {
|
||||
TV_LIST_ITER_CONST(val_list, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
|
||||
|| tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) != 2) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
}
|
||||
const int saved_copyID = val_di->di_tv.vval.v_list->lv_copyID;
|
||||
});
|
||||
const int saved_copyID = tv_list_copyid(val_di->di_tv.vval.v_list);
|
||||
_TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_list, lv_copyID, copyID,
|
||||
kMPConvPairs);
|
||||
TYPVAL_ENCODE_CONV_DICT_START(tv, TYPVAL_ENCODE_NODICT_VAR,
|
||||
val_list->lv_len);
|
||||
tv_list_len(val_list));
|
||||
assert(saved_copyID != copyID && saved_copyID != copyID - 1);
|
||||
_mp_push(*mpstack, ((MPConvStackVal) {
|
||||
.tv = tv,
|
||||
|
@ -544,7 +563,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
.data = {
|
||||
.l = {
|
||||
.list = val_list,
|
||||
.li = val_list->lv_first,
|
||||
.li = tv_list_first(val_list),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
@ -554,18 +573,23 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
|||
const list_T *val_list;
|
||||
varnumber_T type;
|
||||
if (val_di->di_tv.v_type != VAR_LIST
|
||||
|| (val_list = val_di->di_tv.vval.v_list) == NULL
|
||||
|| val_list->lv_len != 2
|
||||
|| (val_list->lv_first->li_tv.v_type != VAR_NUMBER)
|
||||
|| (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX
|
||||
|| tv_list_len((val_list = val_di->di_tv.vval.v_list)) != 2
|
||||
|| (TV_LIST_ITEM_TV(tv_list_first(val_list))->v_type
|
||||
!= VAR_NUMBER)
|
||||
|| ((type
|
||||
= TV_LIST_ITEM_TV(tv_list_first(val_list))->vval.v_number)
|
||||
> INT8_MAX)
|
||||
|| type < INT8_MIN
|
||||
|| (val_list->lv_last->li_tv.v_type != VAR_LIST)) {
|
||||
|| (TV_LIST_ITEM_TV(tv_list_last(val_list))->v_type
|
||||
!= VAR_LIST)) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
size_t len;
|
||||
char *buf;
|
||||
if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list,
|
||||
&len, &buf)) {
|
||||
if (!(
|
||||
encode_vim_list_to_buf(
|
||||
TV_LIST_ITEM_TV(tv_list_last(val_list))->vval.v_list, &len,
|
||||
&buf))) {
|
||||
goto _convert_one_value_regular_dict;
|
||||
}
|
||||
TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type);
|
||||
|
@ -671,40 +695,45 @@ typval_encode_stop_converting_one_item:
|
|||
case kMPConvList: {
|
||||
if (cur_mpsv->data.l.li == NULL) {
|
||||
(void)_mp_pop(mpstack);
|
||||
cur_mpsv->data.l.list->lv_copyID = cur_mpsv->saved_copyID;
|
||||
tv_list_set_copyid(cur_mpsv->data.l.list, cur_mpsv->saved_copyID);
|
||||
TYPVAL_ENCODE_CONV_LIST_END(cur_mpsv->tv);
|
||||
continue;
|
||||
} else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) {
|
||||
} else if (cur_mpsv->data.l.li
|
||||
!= tv_list_first(cur_mpsv->data.l.list)) {
|
||||
TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(cur_mpsv->tv);
|
||||
}
|
||||
tv = &cur_mpsv->data.l.li->li_tv;
|
||||
cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next;
|
||||
tv = TV_LIST_ITEM_TV(cur_mpsv->data.l.li);
|
||||
cur_mpsv->data.l.li = TV_LIST_ITEM_NEXT(cur_mpsv->data.l.list,
|
||||
cur_mpsv->data.l.li);
|
||||
break;
|
||||
}
|
||||
case kMPConvPairs: {
|
||||
if (cur_mpsv->data.l.li == NULL) {
|
||||
(void)_mp_pop(mpstack);
|
||||
cur_mpsv->data.l.list->lv_copyID = cur_mpsv->saved_copyID;
|
||||
tv_list_set_copyid(cur_mpsv->data.l.list, cur_mpsv->saved_copyID);
|
||||
TYPVAL_ENCODE_CONV_DICT_END(cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR);
|
||||
continue;
|
||||
} else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) {
|
||||
} else if (cur_mpsv->data.l.li
|
||||
!= tv_list_first(cur_mpsv->data.l.list)) {
|
||||
TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(
|
||||
cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR);
|
||||
}
|
||||
const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list;
|
||||
const list_T *const kv_pair = (
|
||||
TV_LIST_ITEM_TV(cur_mpsv->data.l.li)->vval.v_list);
|
||||
TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(
|
||||
encode_vim_to__error_ret, kv_pair->lv_first->li_tv);
|
||||
if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME,
|
||||
&mpstack, cur_mpsv,
|
||||
&kv_pair->lv_first->li_tv,
|
||||
copyID,
|
||||
objname) == FAIL) {
|
||||
encode_vim_to__error_ret, *TV_LIST_ITEM_TV(tv_list_first(kv_pair)));
|
||||
if (
|
||||
_TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|
||||
TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, cur_mpsv,
|
||||
TV_LIST_ITEM_TV(tv_list_first(kv_pair)), copyID, objname)
|
||||
== FAIL) {
|
||||
goto encode_vim_to__error_ret;
|
||||
}
|
||||
TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(cur_mpsv->tv,
|
||||
TYPVAL_ENCODE_NODICT_VAR);
|
||||
tv = &kv_pair->lv_last->li_tv;
|
||||
cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next;
|
||||
tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair));
|
||||
cur_mpsv->data.l.li = TV_LIST_ITEM_NEXT(cur_mpsv->data.l.list,
|
||||
cur_mpsv->data.l.li);
|
||||
break;
|
||||
}
|
||||
case kMPConvPartial: {
|
||||
|
|
|
@ -6334,7 +6334,6 @@ char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
|
|||
void ex_oldfiles(exarg_T *eap)
|
||||
{
|
||||
list_T *l = get_vim_var_list(VV_OLDFILES);
|
||||
listitem_T *li;
|
||||
long nr = 0;
|
||||
|
||||
if (l == NULL) {
|
||||
|
@ -6342,19 +6341,22 @@ void ex_oldfiles(exarg_T *eap)
|
|||
} else {
|
||||
msg_start();
|
||||
msg_scroll = true;
|
||||
for (li = l->lv_first; li != NULL && !got_int; li = li->li_next) {
|
||||
TV_LIST_ITER(l, li, {
|
||||
if (got_int) {
|
||||
break;
|
||||
}
|
||||
nr++;
|
||||
const char *fname = tv_get_string(&li->li_tv);
|
||||
const char *fname = tv_get_string(TV_LIST_ITEM_TV(li));
|
||||
if (!message_filtered((char_u *)fname)) {
|
||||
msg_outnum(nr);
|
||||
MSG_PUTS(": ");
|
||||
msg_outtrans((char_u *)tv_get_string(&li->li_tv));
|
||||
msg_outtrans((char_u *)tv_get_string(TV_LIST_ITEM_TV(li)));
|
||||
msg_clr_eos();
|
||||
msg_putchar('\n');
|
||||
ui_flush(); // output one line at a time
|
||||
os_breakcheck();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Assume "got_int" was set to truncate the listing.
|
||||
got_int = false;
|
||||
|
@ -6364,7 +6366,7 @@ void ex_oldfiles(exarg_T *eap)
|
|||
quit_more = false;
|
||||
nr = prompt_for_number(false);
|
||||
msg_starthere();
|
||||
if (nr > 0 && nr <= l->lv_len) {
|
||||
if (nr > 0 && nr <= tv_list_len(l)) {
|
||||
const char *const p = tv_list_find_str(l, nr - 1);
|
||||
if (p == NULL) {
|
||||
return;
|
||||
|
|
|
@ -2618,20 +2618,20 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
|
|||
}
|
||||
varnumber_T prev_end = 0;
|
||||
int i = 0;
|
||||
for (const listitem_T *li = tv.vval.v_list->lv_first;
|
||||
li != NULL; li = li->li_next, i++) {
|
||||
if (li->li_tv.v_type != VAR_LIST) {
|
||||
TV_LIST_ITER_CONST(tv.vval.v_list, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST) {
|
||||
PRINT_ERRMSG(_("E5401: List item %i is not a List"), i);
|
||||
goto color_cmdline_error;
|
||||
}
|
||||
const list_T *const l = li->li_tv.vval.v_list;
|
||||
const list_T *const l = TV_LIST_ITEM_TV(li)->vval.v_list;
|
||||
if (tv_list_len(l) != 3) {
|
||||
PRINT_ERRMSG(_("E5402: List item %i has incorrect length: %li /= 3"),
|
||||
i, tv_list_len(l));
|
||||
goto color_cmdline_error;
|
||||
}
|
||||
bool error = false;
|
||||
const varnumber_T start = tv_get_number_chk(&l->lv_first->li_tv, &error);
|
||||
const varnumber_T start = (
|
||||
tv_get_number_chk(TV_LIST_ITEM_TV(tv_list_first(l)), &error));
|
||||
if (error) {
|
||||
goto color_cmdline_error;
|
||||
} else if (!(prev_end <= start && start < colored_ccline->cmdlen)) {
|
||||
|
@ -2651,8 +2651,8 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
|
|||
.attr = 0,
|
||||
}));
|
||||
}
|
||||
const varnumber_T end = tv_get_number_chk(&l->lv_first->li_next->li_tv,
|
||||
&error);
|
||||
const varnumber_T end = tv_get_number_chk(
|
||||
TV_LIST_ITEM_TV(TV_LIST_ITEM_NEXT(l, tv_list_first(l))), &error);
|
||||
if (error) {
|
||||
goto color_cmdline_error;
|
||||
} else if (!(start < end && end <= colored_ccline->cmdlen)) {
|
||||
|
@ -2668,7 +2668,8 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
|
|||
goto color_cmdline_error;
|
||||
}
|
||||
prev_end = end;
|
||||
const char *const group = tv_get_string_chk(&l->lv_last->li_tv);
|
||||
const char *const group = tv_get_string_chk(
|
||||
TV_LIST_ITEM_TV(tv_list_last(l)));
|
||||
if (group == NULL) {
|
||||
goto color_cmdline_error;
|
||||
}
|
||||
|
@ -2679,7 +2680,8 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
|
|||
.end = end,
|
||||
.attr = attr,
|
||||
}));
|
||||
}
|
||||
i++;
|
||||
});
|
||||
if (prev_end < colored_ccline->cmdlen) {
|
||||
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
|
||||
.start = prev_end,
|
||||
|
@ -5021,24 +5023,24 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
|
|||
*/
|
||||
static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
|
||||
{
|
||||
list_T *retlist;
|
||||
listitem_T *li;
|
||||
garray_T ga;
|
||||
|
||||
retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp,
|
||||
num_file, file);
|
||||
list_T *const retlist = call_user_expand_func(
|
||||
(user_expand_func_T)call_func_retlist, xp, num_file, file);
|
||||
if (retlist == NULL) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
garray_T ga;
|
||||
ga_init(&ga, (int)sizeof(char *), 3);
|
||||
/* Loop over the items in the list. */
|
||||
for (li = retlist->lv_first; li != NULL; li = li->li_next) {
|
||||
if (li->li_tv.v_type != VAR_STRING || li->li_tv.vval.v_string == NULL)
|
||||
continue; /* Skip non-string items and empty strings */
|
||||
// Loop over the items in the list.
|
||||
TV_LIST_ITER_CONST(retlist, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING
|
||||
|| TV_LIST_ITEM_TV(li)->vval.v_string == NULL) {
|
||||
continue; // Skip non-string items and empty strings.
|
||||
}
|
||||
|
||||
GA_APPEND(char_u *, &ga, vim_strsave(li->li_tv.vval.v_string));
|
||||
}
|
||||
GA_APPEND(char *, &ga, xstrdup(
|
||||
(const char *)TV_LIST_ITEM_TV(li)->vval.v_string));
|
||||
});
|
||||
tv_list_unref(retlist);
|
||||
|
||||
*file = ga.ga_data;
|
||||
|
|
|
@ -214,9 +214,9 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
list_T *const kv_pair = tv_list_alloc();
|
||||
tv_list_append_list(cur.tv->vval.v_list, kv_pair);
|
||||
listitem_T *const key = tv_list_item_alloc();
|
||||
key->li_tv = decode_string(s, len, kTrue, false, false);
|
||||
*TV_LIST_ITEM_TV(key) = decode_string(s, len, kTrue, false, false);
|
||||
tv_list_append(kv_pair, key);
|
||||
if (key->li_tv.v_type == VAR_UNKNOWN) {
|
||||
if (TV_LIST_ITEM_TV(key)->v_type == VAR_UNKNOWN) {
|
||||
ret = false;
|
||||
tv_list_unref(kv_pair);
|
||||
continue;
|
||||
|
@ -224,7 +224,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
listitem_T *const val = tv_list_item_alloc();
|
||||
tv_list_append(kv_pair, val);
|
||||
kv_push(stack, cur);
|
||||
cur = (TVPopStackItem) { &val->li_tv, false, false, 0 };
|
||||
cur = (TVPopStackItem) { TV_LIST_ITEM_TV(val), false, false, 0 };
|
||||
} else {
|
||||
dictitem_T *const di = tv_dict_item_alloc_len(s, len);
|
||||
if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) {
|
||||
|
@ -239,7 +239,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
}
|
||||
} else {
|
||||
assert(cur.tv->v_type == VAR_LIST);
|
||||
lua_rawgeti(lstate, -1, cur.tv->vval.v_list->lv_len + 1);
|
||||
lua_rawgeti(lstate, -1, tv_list_len(cur.tv->vval.v_list) + 1);
|
||||
if (lua_isnil(lstate, -1)) {
|
||||
lua_pop(lstate, 2);
|
||||
continue;
|
||||
|
@ -247,7 +247,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
listitem_T *const li = tv_list_item_alloc();
|
||||
tv_list_append(cur.tv->vval.v_list, li);
|
||||
kv_push(stack, cur);
|
||||
cur = (TVPopStackItem) { &li->li_tv, false, false, 0 };
|
||||
cur = (TVPopStackItem) { TV_LIST_ITEM_TV(li), false, false, 0 };
|
||||
}
|
||||
}
|
||||
assert(!cur.container);
|
||||
|
@ -306,7 +306,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
|
|||
case kObjectTypeArray: {
|
||||
cur.tv->v_type = VAR_LIST;
|
||||
cur.tv->vval.v_list = tv_list_alloc();
|
||||
cur.tv->vval.v_list->lv_refcount++;
|
||||
tv_list_ref(cur.tv->vval.v_list);
|
||||
if (table_props.maxidx != 0) {
|
||||
cur.container = true;
|
||||
cur.idx = lua_gettop(lstate);
|
||||
|
|
|
@ -2568,7 +2568,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
|
|||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
tv_list_append_string(list, (const char *)reg->y_array[i], -1);
|
||||
}
|
||||
list->lv_lock = VAR_FIXED;
|
||||
tv_list_set_lock(list, VAR_FIXED);
|
||||
tv_dict_add_list(dict, S_LEN("regcontents"), list);
|
||||
|
||||
// the register type
|
||||
|
@ -4854,9 +4854,8 @@ static void *get_reg_wrap_one_line(char_u *s, int flags)
|
|||
if (!(flags & kGRegList)) {
|
||||
return s;
|
||||
}
|
||||
list_T *list = tv_list_alloc();
|
||||
tv_list_append_string(list, NULL, 0);
|
||||
list->lv_first->li_tv.vval.v_string = s;
|
||||
list_T *const list = tv_list_alloc();
|
||||
tv_list_append_allocated_string(list, (char *)s);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -5610,13 +5609,14 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
|
|||
|
||||
list_T *res = result.vval.v_list;
|
||||
list_T *lines = NULL;
|
||||
if (res->lv_len == 2 && res->lv_first->li_tv.v_type == VAR_LIST) {
|
||||
lines = res->lv_first->li_tv.vval.v_list;
|
||||
if (res->lv_last->li_tv.v_type != VAR_STRING) {
|
||||
if (tv_list_len(res) == 2
|
||||
&& TV_LIST_ITEM_TV(tv_list_first(res))->v_type == VAR_LIST) {
|
||||
lines = TV_LIST_ITEM_TV(tv_list_first(res))->vval.v_list;
|
||||
if (TV_LIST_ITEM_TV(tv_list_last(res))->v_type != VAR_STRING) {
|
||||
goto err;
|
||||
}
|
||||
char_u *regtype = res->lv_last->li_tv.vval.v_string;
|
||||
if (regtype == NULL || strlen((char*)regtype) > 1) {
|
||||
char_u *regtype = TV_LIST_ITEM_TV(tv_list_last(res))->vval.v_string;
|
||||
if (regtype == NULL || strlen((char *)regtype) > 1) {
|
||||
goto err;
|
||||
}
|
||||
switch (regtype[0]) {
|
||||
|
@ -5641,20 +5641,21 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
|
|||
reg->y_type = kMTUnknown;
|
||||
}
|
||||
|
||||
reg->y_array = xcalloc((size_t)lines->lv_len, sizeof(uint8_t *));
|
||||
reg->y_size = (size_t)lines->lv_len;
|
||||
reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(char_u *));
|
||||
reg->y_size = (size_t)tv_list_len(lines);
|
||||
reg->additional_data = NULL;
|
||||
reg->timestamp = 0;
|
||||
// Timestamp is not saved for clipboard registers because clipboard registers
|
||||
// are not saved in the ShaDa file.
|
||||
|
||||
int i = 0;
|
||||
for (listitem_T *li = lines->lv_first; li != NULL; li = li->li_next) {
|
||||
if (li->li_tv.v_type != VAR_STRING) {
|
||||
TV_LIST_ITER_CONST(lines, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
|
||||
goto err;
|
||||
}
|
||||
reg->y_array[i++] = (char_u *)xstrdupnul((char *)li->li_tv.vval.v_string);
|
||||
}
|
||||
reg->y_array[i++] = (char_u *)xstrdupnul(
|
||||
(const char *)TV_LIST_ITEM_TV(li)->vval.v_string);
|
||||
});
|
||||
|
||||
if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
|
||||
// a known-to-be charwise yank might have a final linebreak
|
||||
|
|
|
@ -157,6 +157,7 @@ typedef struct {
|
|||
FILE *fd;
|
||||
typval_T *tv;
|
||||
char_u *p_str;
|
||||
list_T *p_list;
|
||||
listitem_T *p_li;
|
||||
buf_T *buf;
|
||||
linenr_T buflnum;
|
||||
|
@ -518,17 +519,17 @@ static int qf_get_next_list_line(qfstate_T *state)
|
|||
|
||||
// Get the next line from the supplied list
|
||||
while (p_li != NULL
|
||||
&& (p_li->li_tv.v_type != VAR_STRING
|
||||
|| p_li->li_tv.vval.v_string == NULL)) {
|
||||
p_li = p_li->li_next; // Skip non-string items
|
||||
&& (TV_LIST_ITEM_TV(p_li)->v_type != VAR_STRING
|
||||
|| TV_LIST_ITEM_TV(p_li)->vval.v_string == NULL)) {
|
||||
p_li = TV_LIST_ITEM_NEXT(state->p_list, p_li); // Skip non-string items.
|
||||
}
|
||||
|
||||
if (p_li == NULL) { // End of the list
|
||||
if (p_li == NULL) { // End of the list.
|
||||
state->p_li = NULL;
|
||||
return QF_END_OF_INPUT;
|
||||
}
|
||||
|
||||
len = STRLEN(p_li->li_tv.vval.v_string);
|
||||
len = STRLEN(TV_LIST_ITEM_TV(p_li)->vval.v_string);
|
||||
if (len > IOSIZE - 2) {
|
||||
state->linebuf = qf_grow_linebuf(state, len);
|
||||
} else {
|
||||
|
@ -536,9 +537,10 @@ static int qf_get_next_list_line(qfstate_T *state)
|
|||
state->linelen = len;
|
||||
}
|
||||
|
||||
STRLCPY(state->linebuf, p_li->li_tv.vval.v_string, state->linelen + 1);
|
||||
STRLCPY(state->linebuf, TV_LIST_ITEM_TV(p_li)->vval.v_string,
|
||||
state->linelen + 1);
|
||||
|
||||
state->p_li = p_li->li_next; // next item
|
||||
state->p_li = TV_LIST_ITEM_NEXT(state->p_list, p_li);
|
||||
return QF_OK;
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1091,8 @@ qf_init_ext(
|
|||
if (tv->v_type == VAR_STRING) {
|
||||
state.p_str = tv->vval.v_string;
|
||||
} else if (tv->v_type == VAR_LIST) {
|
||||
state.p_li = tv->vval.v_list->lv_first;
|
||||
state.p_list = tv->vval.v_list;
|
||||
state.p_li = tv_list_first(tv->vval.v_list);
|
||||
}
|
||||
state.tv = tv;
|
||||
}
|
||||
|
@ -4164,7 +4167,6 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
|||
static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
|
||||
int action)
|
||||
{
|
||||
listitem_T *li;
|
||||
dict_T *d;
|
||||
qfline_T *old_last = NULL;
|
||||
int retval = OK;
|
||||
|
@ -4181,13 +4183,15 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
|
|||
qf_store_title(qi, title);
|
||||
}
|
||||
|
||||
for (li = list->lv_first; li != NULL; li = li->li_next) {
|
||||
if (li->li_tv.v_type != VAR_DICT)
|
||||
continue; /* Skip non-dict items */
|
||||
TV_LIST_ITER_CONST(list, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_DICT) {
|
||||
continue; // Skip non-dict items.
|
||||
}
|
||||
|
||||
d = li->li_tv.vval.v_dict;
|
||||
if (d == NULL)
|
||||
d = TV_LIST_ITEM_TV(li)->vval.v_dict;
|
||||
if (d == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *const filename = tv_dict_get_string(d, "filename", true);
|
||||
int bufnum = (int)tv_dict_get_number(d, "bufnr");
|
||||
|
@ -4244,7 +4248,7 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
|
|||
retval = FAIL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (qi->qf_lists[qi->qf_curlist].qf_index == 0) {
|
||||
// no valid entry
|
||||
|
@ -4576,7 +4580,7 @@ void ex_cexpr(exarg_T *eap)
|
|||
typval_T tv;
|
||||
if (eval0(eap->arg, &tv, NULL, true) != FAIL) {
|
||||
if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL)
|
||||
|| (tv.v_type == VAR_LIST && tv.vval.v_list != NULL)) {
|
||||
|| tv.v_type == VAR_LIST) {
|
||||
if (qf_init_ext(qi, NULL, NULL, &tv, p_efm,
|
||||
(eap->cmdidx != CMD_caddexpr
|
||||
&& eap->cmdidx != CMD_laddexpr),
|
||||
|
|
|
@ -232,17 +232,17 @@
|
|||
#define LAST_NL NUPPER + ADD_NL
|
||||
#define WITH_NL(op) ((op) >= FIRST_NL && (op) <= LAST_NL)
|
||||
|
||||
#define MOPEN 80 /* -89 Mark this point in input as start of
|
||||
* \( subexpr. MOPEN + 0 marks start of
|
||||
* match. */
|
||||
#define MCLOSE 90 /* -99 Analogous to MOPEN. MCLOSE + 0 marks
|
||||
* end of match. */
|
||||
#define BACKREF 100 /* -109 node Match same string again \1-\9 */
|
||||
#define MOPEN 80 // -89 Mark this point in input as start of
|
||||
// \( … \) subexpr. MOPEN + 0 marks start of
|
||||
// match.
|
||||
#define MCLOSE 90 // -99 Analogous to MOPEN. MCLOSE + 0 marks
|
||||
// end of match.
|
||||
#define BACKREF 100 // -109 node Match same string again \1-\9.
|
||||
|
||||
# define ZOPEN 110 /* -119 Mark this point in input as start of
|
||||
* \z( subexpr. */
|
||||
# define ZCLOSE 120 /* -129 Analogous to ZOPEN. */
|
||||
# define ZREF 130 /* -139 node Match external submatch \z1-\z9 */
|
||||
# define ZOPEN 110 // -119 Mark this point in input as start of
|
||||
// \z( … \) subexpr.
|
||||
# define ZCLOSE 120 // -129 Analogous to ZOPEN.
|
||||
# define ZREF 130 // -139 node Match external submatch \z1-\z9
|
||||
|
||||
#define BRACE_COMPLEX 140 /* -149 node Match nodes between m & n times */
|
||||
|
||||
|
@ -462,11 +462,11 @@ static int toggle_Magic(int x)
|
|||
#define IEMSG_RET_NULL(m) return (IEMSG(m), rc_did_emsg = true, (void *)NULL)
|
||||
#define EMSG_RET_FAIL(m) return (EMSG(m), rc_did_emsg = true, FAIL)
|
||||
#define EMSG2_RET_NULL(m, c) \
|
||||
return (EMSG2((m), (c) ? "" : "\\"), rc_did_emsg = true, (void *)NULL)
|
||||
return (EMSG2((m), (c) ? "" : "\\"), rc_did_emsg = true, (void *)NULL)
|
||||
#define EMSG2_RET_FAIL(m, c) \
|
||||
return (EMSG2((m), (c) ? "" : "\\"), rc_did_emsg = true, FAIL)
|
||||
return (EMSG2((m), (c) ? "" : "\\"), rc_did_emsg = true, FAIL)
|
||||
#define EMSG_ONE_RET_NULL EMSG2_RET_NULL(_( \
|
||||
"E369: invalid item in %s%%[]"), reg_magic == MAGIC_ALL)
|
||||
"E369: invalid item in %s%%[]"), reg_magic == MAGIC_ALL)
|
||||
|
||||
#define MAX_LIMIT (32767L << 16L)
|
||||
|
||||
|
@ -6474,41 +6474,35 @@ static regsubmatch_T rsm; // can only be used when can_f_submatch is true
|
|||
/// vim_regsub_both().
|
||||
static int fill_submatch_list(int argc, typval_T *argv, int argcount)
|
||||
{
|
||||
listitem_T *li;
|
||||
int i;
|
||||
char_u *s;
|
||||
|
||||
if (argcount == 0) {
|
||||
// called function doesn't take an argument
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Relies on sl_list to be the first item in staticList10_T.
|
||||
init_static_list((staticList10_T *)(argv->vval.v_list));
|
||||
tv_list_init_static10((staticList10_T *)argv->vval.v_list);
|
||||
|
||||
// There are always 10 list items in staticList10_T.
|
||||
li = argv->vval.v_list->lv_first;
|
||||
for (i = 0; i < 10; i++) {
|
||||
s = rsm.sm_match->startp[i];
|
||||
listitem_T *li = tv_list_first(argv->vval.v_list);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
char_u *s = rsm.sm_match->startp[i];
|
||||
if (s == NULL || rsm.sm_match->endp[i] == NULL) {
|
||||
s = NULL;
|
||||
} else {
|
||||
s = vim_strnsave(s, (int)(rsm.sm_match->endp[i] - s));
|
||||
}
|
||||
li->li_tv.v_type = VAR_STRING;
|
||||
li->li_tv.vval.v_string = s;
|
||||
li = li->li_next;
|
||||
TV_LIST_ITEM_TV(li)->v_type = VAR_STRING;
|
||||
TV_LIST_ITEM_TV(li)->vval.v_string = s;
|
||||
li = TV_LIST_ITEM_NEXT(argv->vval.v_list, li);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void clear_submatch_list(staticList10_T *sl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
xfree(sl->sl_items[i].li_tv.vval.v_string);
|
||||
}
|
||||
TV_LIST_ITER(&sl->sl_list, li, {
|
||||
xfree(TV_LIST_ITEM_TV(li)->vval.v_string);
|
||||
});
|
||||
}
|
||||
|
||||
/// vim_regsub() - perform substitutions after a vim_regexec() or
|
||||
|
@ -6642,13 +6636,12 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
|
|||
typval_T argv[2];
|
||||
int dummy;
|
||||
typval_T rettv;
|
||||
staticList10_T matchList;
|
||||
staticList10_T matchList = TV_LIST_STATIC10_INIT;
|
||||
|
||||
rettv.v_type = VAR_STRING;
|
||||
rettv.vval.v_string = NULL;
|
||||
argv[0].v_type = VAR_LIST;
|
||||
argv[0].vval.v_list = &matchList.sl_list;
|
||||
matchList.sl_list.lv_len = 0;
|
||||
if (expr->v_type == VAR_FUNC) {
|
||||
s = expr->vval.v_string;
|
||||
call_func(s, (int)STRLEN(s), &rettv, 1, argv,
|
||||
|
@ -6662,7 +6655,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
|
|||
fill_submatch_list, 0L, 0L, &dummy,
|
||||
true, partial, NULL);
|
||||
}
|
||||
if (matchList.sl_list.lv_len > 0) {
|
||||
if (tv_list_len(&matchList.sl_list) > 0) {
|
||||
// fill_submatch_list() was called.
|
||||
clear_submatch_list(&matchList);
|
||||
}
|
||||
|
|
|
@ -1180,8 +1180,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
|
|||
list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES);
|
||||
const bool force = flags & kShaDaForceit;
|
||||
const bool get_old_files = (flags & (kShaDaGetOldfiles | kShaDaForceit)
|
||||
&& (force || oldfiles_list == NULL
|
||||
|| oldfiles_list->lv_len == 0));
|
||||
&& (force || tv_list_len(oldfiles_list) == 0));
|
||||
const bool want_marks = flags & kShaDaWantMarks;
|
||||
const unsigned srni_flags = (unsigned) (
|
||||
(flags & kShaDaWantInfo
|
||||
|
@ -1599,13 +1598,13 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
|
|||
#define DUMP_ADDITIONAL_ELEMENTS(src, what) \
|
||||
do { \
|
||||
if ((src) != NULL) { \
|
||||
for (listitem_T *li = (src)->lv_first; li != NULL; li = li->li_next) { \
|
||||
if (encode_vim_to_msgpack(spacker, &li->li_tv, \
|
||||
TV_LIST_ITER((src), li, { \
|
||||
if (encode_vim_to_msgpack(spacker, TV_LIST_ITEM_TV(li), \
|
||||
_("additional elements of ShaDa " what)) \
|
||||
== FAIL) { \
|
||||
goto shada_pack_entry_error; \
|
||||
} \
|
||||
} \
|
||||
}); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DUMP_ADDITIONAL_DATA(src, what) \
|
||||
|
@ -1647,25 +1646,21 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
|
|||
case kSDItemHistoryEntry: {
|
||||
const bool is_hist_search =
|
||||
entry.data.history_item.histtype == HIST_SEARCH;
|
||||
const size_t arr_size = 2 + (size_t) is_hist_search + (size_t) (
|
||||
entry.data.history_item.additional_elements == NULL
|
||||
? 0
|
||||
: entry.data.history_item.additional_elements->lv_len);
|
||||
const size_t arr_size = 2 + (size_t)is_hist_search + (size_t)(
|
||||
tv_list_len(entry.data.history_item.additional_elements));
|
||||
msgpack_pack_array(spacker, arr_size);
|
||||
msgpack_pack_uint8(spacker, entry.data.history_item.histtype);
|
||||
PACK_BIN(cstr_as_string(entry.data.history_item.string));
|
||||
if (is_hist_search) {
|
||||
msgpack_pack_uint8(spacker, (uint8_t) entry.data.history_item.sep);
|
||||
msgpack_pack_uint8(spacker, (uint8_t)entry.data.history_item.sep);
|
||||
}
|
||||
DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
|
||||
"history entry item");
|
||||
break;
|
||||
}
|
||||
case kSDItemVariable: {
|
||||
const size_t arr_size = 2 + (size_t) (
|
||||
entry.data.global_var.additional_elements == NULL
|
||||
? 0
|
||||
: entry.data.global_var.additional_elements->lv_len);
|
||||
const size_t arr_size = 2 + (size_t)(
|
||||
tv_list_len(entry.data.global_var.additional_elements));
|
||||
msgpack_pack_array(spacker, arr_size);
|
||||
const String varname = cstr_as_string(entry.data.global_var.name);
|
||||
PACK_BIN(varname);
|
||||
|
@ -1684,10 +1679,8 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
|
|||
break;
|
||||
}
|
||||
case kSDItemSubString: {
|
||||
const size_t arr_size = 1 + (size_t) (
|
||||
entry.data.sub_string.additional_elements == NULL
|
||||
? 0
|
||||
: entry.data.sub_string.additional_elements->lv_len);
|
||||
const size_t arr_size = 1 + (size_t)(
|
||||
tv_list_len(entry.data.sub_string.additional_elements));
|
||||
msgpack_pack_array(spacker, arr_size);
|
||||
PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
|
||||
DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
|
||||
|
|
|
@ -3213,26 +3213,25 @@ spell_find_suggest (
|
|||
// Find suggestions by evaluating expression "expr".
|
||||
static void spell_suggest_expr(suginfo_T *su, char_u *expr)
|
||||
{
|
||||
list_T *list;
|
||||
listitem_T *li;
|
||||
int score;
|
||||
const char *p;
|
||||
|
||||
// The work is split up in a few parts to avoid having to export
|
||||
// suginfo_T.
|
||||
// First evaluate the expression and get the resulting list.
|
||||
list = eval_spell_expr(su->su_badword, expr);
|
||||
list_T *const list = eval_spell_expr(su->su_badword, expr);
|
||||
if (list != NULL) {
|
||||
// Loop over the items in the list.
|
||||
for (li = list->lv_first; li != NULL; li = li->li_next)
|
||||
if (li->li_tv.v_type == VAR_LIST) {
|
||||
TV_LIST_ITER(list, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type == VAR_LIST) {
|
||||
// Get the word and the score from the items.
|
||||
score = get_spellword(li->li_tv.vval.v_list, &p);
|
||||
score = get_spellword(TV_LIST_ITEM_TV(li)->vval.v_list, &p);
|
||||
if (score >= 0 && score <= su->su_maxscore) {
|
||||
add_suggestion(su, &su->su_ga, (const char_u *)p, su->su_badlen,
|
||||
score, 0, true, su->su_sallang, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
tv_list_unref(list);
|
||||
}
|
||||
|
||||
|
|
|
@ -1532,22 +1532,24 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|
|||
// DECSCUSR (cursor shape) sequence is widely supported by several terminal
|
||||
// types. https://github.com/gnachman/iTerm2/pull/92
|
||||
// xterm extension: vertical bar
|
||||
if (!konsole && ((xterm && !vte_version) // anything claiming xterm compat
|
||||
// per MinTTY 0.4.3-1 release notes from 2009
|
||||
|| putty
|
||||
// per https://bugzilla.gnome.org/show_bug.cgi?id=720821
|
||||
|| (vte_version >= 3900)
|
||||
|| tmux // per tmux manual page
|
||||
// https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html
|
||||
|| screen
|
||||
|| st // #7641
|
||||
|| rxvt // per command.C
|
||||
// per analysis of VT100Terminal.m
|
||||
|| iterm || iterm_pretending_xterm
|
||||
|| teraterm // per TeraTerm "Supported Control Functions" doco
|
||||
// Some linux-type terminals (such as console-terminal-emulator
|
||||
// from the nosh toolset) implement the xterm extension.
|
||||
|| (linuxvt && (xterm_version || (vte_version > 0) || colorterm)))) {
|
||||
if (!konsole
|
||||
&& ((xterm && !vte_version) // anything claiming xterm compat
|
||||
// per MinTTY 0.4.3-1 release notes from 2009
|
||||
|| putty
|
||||
// per https://bugzilla.gnome.org/show_bug.cgi?id=720821
|
||||
|| (vte_version >= 3900)
|
||||
|| tmux // per tmux manual page
|
||||
// https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html
|
||||
|| screen
|
||||
|| st // #7641
|
||||
|| rxvt // per command.C
|
||||
// per analysis of VT100Terminal.m
|
||||
|| iterm || iterm_pretending_xterm
|
||||
|| teraterm // per TeraTerm "Supported Control Functions" doco
|
||||
// Some linux-type terminals implement the xterm extension.
|
||||
// Example: console-terminal-emulator from the nosh toolset.
|
||||
|| (linuxvt
|
||||
&& (xterm_version || (vte_version > 0) || colorterm)))) {
|
||||
data->unibi_ext.set_cursor_style =
|
||||
(int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
|
||||
if (-1 == data->unibi_ext.reset_cursor_style) {
|
||||
|
|
|
@ -5606,49 +5606,48 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
|
|||
}
|
||||
|
||||
// Set up position matches
|
||||
if (pos_list != NULL)
|
||||
{
|
||||
linenr_T toplnum = 0;
|
||||
linenr_T botlnum = 0;
|
||||
listitem_T *li;
|
||||
int i;
|
||||
if (pos_list != NULL) {
|
||||
linenr_T toplnum = 0;
|
||||
linenr_T botlnum = 0;
|
||||
|
||||
for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
|
||||
i++, li = li->li_next) {
|
||||
linenr_T lnum = 0;
|
||||
colnr_T col = 0;
|
||||
int len = 1;
|
||||
list_T *subl;
|
||||
listitem_T *subli;
|
||||
int i = 0;
|
||||
TV_LIST_ITER(pos_list, li, {
|
||||
linenr_T lnum = 0;
|
||||
colnr_T col = 0;
|
||||
int len = 1;
|
||||
bool error = false;
|
||||
|
||||
if (li->li_tv.v_type == VAR_LIST) {
|
||||
subl = li->li_tv.vval.v_list;
|
||||
if (subl == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
subli = subl->lv_first;
|
||||
if (TV_LIST_ITEM_TV(li)->v_type == VAR_LIST) {
|
||||
const list_T *const subl = TV_LIST_ITEM_TV(li)->vval.v_list;
|
||||
const listitem_T *subli = tv_list_first(subl);
|
||||
if (subli == NULL) {
|
||||
emsgf(_("E5030: Empty list at position %d"),
|
||||
(int)tv_list_idx_of_item(pos_list, li));
|
||||
goto fail;
|
||||
}
|
||||
lnum = tv_get_number_chk(&subli->li_tv, &error);
|
||||
lnum = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
|
||||
if (error) {
|
||||
goto fail;
|
||||
}
|
||||
if (lnum == 0) {
|
||||
--i;
|
||||
if (lnum <= 0) {
|
||||
continue;
|
||||
}
|
||||
m->pos.pos[i].lnum = lnum;
|
||||
subli = subli->li_next;
|
||||
subli = TV_LIST_ITEM_NEXT(subl, subli);
|
||||
if (subli != NULL) {
|
||||
col = tv_get_number_chk(&subli->li_tv, &error);
|
||||
col = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
|
||||
if (error) {
|
||||
goto fail;
|
||||
}
|
||||
subli = subli->li_next;
|
||||
if (col < 0) {
|
||||
continue;
|
||||
}
|
||||
subli = TV_LIST_ITEM_NEXT(subl, subli);
|
||||
if (subli != NULL) {
|
||||
len = tv_get_number_chk(&subli->li_tv, &error);
|
||||
len = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
|
||||
if (len < 0) {
|
||||
continue;
|
||||
}
|
||||
if (error) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -5656,16 +5655,16 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
|
|||
}
|
||||
m->pos.pos[i].col = col;
|
||||
m->pos.pos[i].len = len;
|
||||
} else if (li->li_tv.v_type == VAR_NUMBER) {
|
||||
if (li->li_tv.vval.v_number == 0) {
|
||||
--i;
|
||||
} else if (TV_LIST_ITEM_TV(li)->v_type == VAR_NUMBER) {
|
||||
if (TV_LIST_ITEM_TV(li)->vval.v_number <= 0) {
|
||||
continue;
|
||||
}
|
||||
m->pos.pos[i].lnum = li->li_tv.vval.v_number;
|
||||
m->pos.pos[i].lnum = TV_LIST_ITEM_TV(li)->vval.v_number;
|
||||
m->pos.pos[i].col = 0;
|
||||
m->pos.pos[i].len = 0;
|
||||
} else {
|
||||
EMSG(_("List or number required"));
|
||||
emsgf(_("E5031: List or number required at position %d"),
|
||||
(int)tv_list_idx_of_item(pos_list, li));
|
||||
goto fail;
|
||||
}
|
||||
if (toplnum == 0 || lnum < toplnum) {
|
||||
|
@ -5674,7 +5673,11 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
|
|||
if (botlnum == 0 || lnum >= botlnum) {
|
||||
botlnum = lnum + 1;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
if (i >= MAXPOSMATCH) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate top and bottom lines for redrawing area
|
||||
if (toplnum != 0){
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local command = helpers.command
|
||||
local meths = helpers.meths
|
||||
local clear = helpers.clear
|
||||
local sleep = helpers.sleep
|
||||
local wait = helpers.wait
|
||||
local feed = helpers.feed
|
||||
local eq = helpers.eq
|
||||
|
||||
local dur
|
||||
local min_dur = 8
|
||||
local len = 131072
|
||||
|
||||
describe('List support code', function()
|
||||
if not pending('does not actually allows interrupting with just got_int', function() end) then return end
|
||||
-- The following tests are confirmed to work with os_breakcheck() just before
|
||||
-- `if (got_int) {break;}` in tv_list_copy and list_join_inner() and not to
|
||||
-- work without.
|
||||
setup(function()
|
||||
clear()
|
||||
dur = 0
|
||||
while true do
|
||||
command(([[
|
||||
let rt = reltime()
|
||||
let bl = range(%u)
|
||||
let dur = reltimestr(reltime(rt))
|
||||
]]):format(len))
|
||||
dur = tonumber(meths.get_var('dur'))
|
||||
if dur >= min_dur then
|
||||
-- print(('Using len %u, dur %g'):format(len, dur))
|
||||
break
|
||||
else
|
||||
len = len * 2
|
||||
end
|
||||
end
|
||||
end)
|
||||
it('allows interrupting copy', function()
|
||||
feed(':let t_rt = reltime()<CR>:let t_bl = copy(bl)<CR>')
|
||||
sleep(min_dur / 16 * 1000)
|
||||
feed('<C-c>')
|
||||
wait()
|
||||
command('let t_dur = reltimestr(reltime(t_rt))')
|
||||
local t_dur = tonumber(meths.get_var('t_dur'))
|
||||
if t_dur >= dur / 8 then
|
||||
eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
|
||||
end
|
||||
end)
|
||||
it('allows interrupting join', function()
|
||||
feed(':let t_rt = reltime()<CR>:let t_j = join(bl)<CR>')
|
||||
sleep(min_dur / 16 * 1000)
|
||||
feed('<C-c>')
|
||||
wait()
|
||||
command('let t_dur = reltimestr(reltime(t_rt))')
|
||||
local t_dur = tonumber(meths.get_var('t_dur'))
|
||||
print(('t_dur: %g'):format(t_dur))
|
||||
if t_dur >= dur / 8 then
|
||||
eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
|
||||
end
|
||||
end)
|
||||
end)
|
|
@ -1,9 +1,11 @@
|
|||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local eq = helpers.eq
|
||||
local clear = helpers.clear
|
||||
local funcs = helpers.funcs
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
before_each(clear)
|
||||
|
||||
|
@ -59,3 +61,95 @@ describe('matchadd()', function()
|
|||
}}, funcs.getmatches())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('matchaddpos()', function()
|
||||
it('errors out on invalid input', function()
|
||||
command('hi clear PreProc')
|
||||
eq('Vim(let):E5030: Empty list at position 0',
|
||||
exc_exec('let val = matchaddpos("PreProc", [[]])'))
|
||||
eq('Vim(let):E5030: Empty list at position 1',
|
||||
exc_exec('let val = matchaddpos("PreProc", [1, v:_null_list])'))
|
||||
eq('Vim(let):E5031: List or number required at position 1',
|
||||
exc_exec('let val = matchaddpos("PreProc", [1, v:_null_dict])'))
|
||||
end)
|
||||
it('works with 0 lnum', function()
|
||||
command('hi clear PreProc')
|
||||
eq(4, funcs.matchaddpos('PreProc', {1}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
funcs.matchdelete(4)
|
||||
eq(4, funcs.matchaddpos('PreProc', {{0}, 1}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
funcs.matchdelete(4)
|
||||
eq(4, funcs.matchaddpos('PreProc', {0, 1}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
end)
|
||||
it('works with negative numbers', function()
|
||||
command('hi clear PreProc')
|
||||
eq(4, funcs.matchaddpos('PreProc', {-10, 1}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
funcs.matchdelete(4)
|
||||
eq(4, funcs.matchaddpos('PreProc', {{-10}, 1}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
funcs.matchdelete(4)
|
||||
eq(4, funcs.matchaddpos('PreProc', {{2, -1}, 1}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
funcs.matchdelete(4)
|
||||
eq(4, funcs.matchaddpos('PreProc', {{2, 0, -1}, 1}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
end)
|
||||
it('works with zero length', function()
|
||||
local screen = Screen.new(40, 5)
|
||||
screen:attach()
|
||||
funcs.setline(1, 'abcdef')
|
||||
command('hi PreProc guifg=Red')
|
||||
eq(4, funcs.matchaddpos('PreProc', {{1, 2, 0}}, 3, 4))
|
||||
eq({{
|
||||
group='PreProc',
|
||||
pos1 = {1, 2, 0},
|
||||
priority=3,
|
||||
id=4,
|
||||
}}, funcs.getmatches())
|
||||
screen:expect([[
|
||||
^a{1:b}cdef |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]], {[1] = {foreground = Screen.colors.Red}, [2] = {bold = true, foreground = Screen.colors.Blue1}})
|
||||
end)
|
||||
end)
|
||||
|
|
|
@ -628,7 +628,7 @@ describe('msgpackdump() function', function()
|
|||
it('fails to dump a recursive (key) map in a special dict', function()
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('call add(todump._VAL, [todump, 0])')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 1',
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
|
|
|
@ -41,35 +41,9 @@ describe('NULL', function()
|
|||
end
|
||||
describe('list', function()
|
||||
-- Incorrect behaviour
|
||||
|
||||
-- FIXME add() should not return 1 at all
|
||||
null_expr_test('does not crash add()', 'add(L, 0)', 0, 1)
|
||||
null_expr_test('does not crash extend()', 'extend(L, [1])', 'E742: Cannot change value of extend() argument', 0)
|
||||
null_expr_test('does not crash extend() (second position)', 'extend([1], L)', 0, {1})
|
||||
-- FIXME should be accepted by inputlist()
|
||||
null_expr_test('is accepted as an empty list by inputlist()',
|
||||
'[feedkeys("\\n"), inputlist(L)]', 'E686: Argument of inputlist() must be a List', {0, 0})
|
||||
-- FIXME should be accepted by writefile(), return {0, {}}
|
||||
null_expr_test('is accepted as an empty list by writefile()',
|
||||
('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname),
|
||||
'E484: Can\'t open file ' .. tmpfname, {0, {}})
|
||||
-- FIXME should give error message
|
||||
null_expr_test('does not crash remove()', 'remove(L, 0)', 0, 0)
|
||||
-- FIXME should return 0
|
||||
null_expr_test('is accepted by setqflist()', 'setqflist(L)', 0, -1)
|
||||
-- FIXME should return 0
|
||||
null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, -1)
|
||||
-- FIXME should return 0
|
||||
null_expr_test('is accepted by setmatches()', 'setmatches(L)', 0, -1)
|
||||
-- FIXME should return empty list or error out
|
||||
null_expr_test('is accepted by sort()', 'sort(L)', 0, 0)
|
||||
-- FIXME Should return 1
|
||||
null_expr_test('is accepted by sort()', 'sort(L) is L', 0, 0)
|
||||
-- FIXME should not error out
|
||||
null_test('is accepted by :cexpr', 'cexpr L', 'Vim(cexpr):E777: String or List expected')
|
||||
-- FIXME should not error out
|
||||
null_test('is accepted by :lexpr', 'lexpr L', 'Vim(lexpr):E777: String or List expected')
|
||||
null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
|
||||
-- FIXME Should error out with different message
|
||||
null_test('makes :unlet act as if it is not a list', ':unlet L[0]',
|
||||
'Vim(unlet):E689: Can only index a List or Dictionary')
|
||||
|
||||
-- Subjectable behaviour
|
||||
|
||||
|
@ -77,20 +51,19 @@ describe('NULL', function()
|
|||
null_expr_test('is equal to empty list', 'L == []', 0, 0)
|
||||
-- FIXME Should return 1
|
||||
null_expr_test('is equal to empty list (reverse order)', '[] == L', 0, 0)
|
||||
-- FIXME Should return 1
|
||||
null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
|
||||
|
||||
-- Crashes
|
||||
|
||||
-- null_expr_test('does not crash setreg', 'setreg("x", L)', 0, 0)
|
||||
-- null_expr_test('does not crash setline', 'setline(1, L)', 0, 0)
|
||||
-- null_expr_test('does not crash system()', 'system("cat", L)', 0, '')
|
||||
-- null_expr_test('does not crash systemlist()', 'systemlist("cat", L)', 0, {})
|
||||
|
||||
-- Correct behaviour
|
||||
null_expr_test('can be indexed with error message for empty list', 'L[0]',
|
||||
'E684: list index out of range: 0\nE15: Invalid expression: L[0]', nil)
|
||||
null_expr_test('can be splice-indexed', 'L[:]', 0, {})
|
||||
null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
|
||||
null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
|
||||
null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function()
|
||||
eq({''}, curbufmeths.get_lines(0, -1, false))
|
||||
end)
|
||||
null_expr_test('does not crash setline()', 'setline(1, L)', 0, 0, function()
|
||||
eq({''}, curbufmeths.get_lines(0, -1, false))
|
||||
end)
|
||||
null_expr_test('is identical to itself', 'L is L', 0, 1)
|
||||
null_expr_test('can be sliced', 'L[:]', 0, {})
|
||||
null_expr_test('can be copied', 'copy(L)', 0, {})
|
||||
|
@ -122,6 +95,42 @@ describe('NULL', function()
|
|||
null_expr_test('counts correctly', 'count([L], L)', 0, 1)
|
||||
null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 1)
|
||||
null_expr_test('makes filter() return v:_null_list', 'filter(L, "1") is# L', 0, 1)
|
||||
null_test('is treated by :let as empty list', ':let [l] = L', 'Vim(let):E688: More targets than List items')
|
||||
null_expr_test('is accepted as an empty list by inputlist()', '[feedkeys("\\n"), inputlist(L)]',
|
||||
'Type number and <Enter> or click with mouse (empty cancels): ', {0, 0})
|
||||
null_expr_test('is accepted as an empty list by writefile()',
|
||||
('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname),
|
||||
0, {0, {}})
|
||||
null_expr_test('makes add() error out', 'add(L, 0)',
|
||||
'E742: Cannot change value of add() argument', 1)
|
||||
null_expr_test('makes insert() error out', 'insert(L, 1)',
|
||||
'E742: Cannot change value of insert() argument', 0)
|
||||
null_expr_test('does not crash remove()', 'remove(L, 0)',
|
||||
'E742: Cannot change value of remove() argument', 0)
|
||||
null_expr_test('makes reverse() error out', 'reverse(L)',
|
||||
'E742: Cannot change value of reverse() argument', 0)
|
||||
null_expr_test('makes sort() error out', 'sort(L)',
|
||||
'E742: Cannot change value of sort() argument', 0)
|
||||
null_expr_test('makes uniq() error out', 'uniq(L)',
|
||||
'E742: Cannot change value of uniq() argument', 0)
|
||||
null_expr_test('does not crash extend()', 'extend(L, [1])', 'E742: Cannot change value of extend() argument', 0)
|
||||
null_expr_test('does not crash extend() (second position)', 'extend([1], L)', 0, {1})
|
||||
null_expr_test('makes join() return empty string', 'join(L, "")', 0, '')
|
||||
null_expr_test('makes msgpackdump() return empty list', 'msgpackdump(L)', 0, {})
|
||||
null_expr_test('does not crash system()', 'system("cat", L)', 0, '')
|
||||
null_expr_test('does not crash setreg', 'setreg("x", L)', 0, 0)
|
||||
null_expr_test('does not crash systemlist()', 'systemlist("cat", L)', 0, {})
|
||||
null_test('does not make Neovim crash when v:oldfiles gets assigned to that', ':let v:oldfiles = L|oldfiles', 0)
|
||||
null_expr_test('does not make complete() crash or error out',
|
||||
'execute(":normal i\\<C-r>=complete(1, L)[-1]\\n")',
|
||||
'', '\n', function()
|
||||
eq({''}, curbufmeths.get_lines(0, -1, false))
|
||||
end)
|
||||
null_expr_test('is accepted by setmatches()', 'setmatches(L)', 0, 0)
|
||||
null_expr_test('is accepted by setqflist()', 'setqflist(L)', 0, 0)
|
||||
null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, 0)
|
||||
null_test('is accepted by :cexpr', 'cexpr L', 0)
|
||||
null_test('is accepted by :lexpr', 'lexpr L', 0)
|
||||
end)
|
||||
describe('dict', function()
|
||||
it('does not crash when indexing NULL dict', function()
|
||||
|
|
|
@ -114,9 +114,11 @@ describe('063: Test for ":match", "matchadd()" and related functions', function(
|
|||
command("call clearmatches()")
|
||||
eq('\nE714: List required', redir_exec("let rf1 = setmatches(0)"))
|
||||
eq(-1, eval('rf1'))
|
||||
eq('\nE474: Invalid argument', redir_exec("let rf2 = setmatches([0])"))
|
||||
eq('\nE474: List item 0 is either not a dictionary or an empty one',
|
||||
redir_exec("let rf2 = setmatches([0])"))
|
||||
eq(-1, eval('rf2'))
|
||||
eq('\nE474: Invalid argument', redir_exec("let rf3 = setmatches([{'wrong key': 'wrong value'}])"))
|
||||
eq('\nE474: List item 0 is missing one of the required keys',
|
||||
redir_exec("let rf3 = setmatches([{'wrong key': 'wrong value'}])"))
|
||||
eq(-1, eval('rf3'))
|
||||
|
||||
-- Check that "matchaddpos()" positions matches correctly
|
||||
|
|
Loading…
Reference in New Issue