mirror of
https://github.com/neovim/neovim.git
synced 2025-09-24 20:18:32 +00:00
Merge pull request #16553 from seandewar/vim-8.2.0878
vim-patch:8.2.{0882,1051,1083}: port `reduce()` function
This commit is contained in:
@@ -100,6 +100,7 @@ PRAGMA_DIAG_POP
|
||||
|
||||
static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
|
||||
static char *e_invalwindow = N_("E957: Invalid window number");
|
||||
static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value");
|
||||
|
||||
/// Dummy va_list for passing to vim_snprintf
|
||||
///
|
||||
@@ -8054,6 +8055,102 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// "reduce(list, { accumlator, element -> value } [, initial])" function
|
||||
static void f_reduce(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) {
|
||||
emsg(_(e_listblobreq));
|
||||
return;
|
||||
}
|
||||
|
||||
const char_u *func_name;
|
||||
partial_T *partial = NULL;
|
||||
if (argvars[1].v_type == VAR_FUNC) {
|
||||
func_name = argvars[1].vval.v_string;
|
||||
} else if (argvars[1].v_type == VAR_PARTIAL) {
|
||||
partial = argvars[1].vval.v_partial;
|
||||
func_name = partial_name(partial);
|
||||
} else {
|
||||
func_name = (const char_u *)tv_get_string(&argvars[1]);
|
||||
}
|
||||
if (*func_name == NUL) {
|
||||
return; // type error or empty name
|
||||
}
|
||||
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.evaluate = true;
|
||||
funcexe.partial = partial;
|
||||
|
||||
typval_T initial;
|
||||
typval_T argv[3];
|
||||
if (argvars[0].v_type == VAR_LIST) {
|
||||
list_T *const l = argvars[0].vval.v_list;
|
||||
const listitem_T *li;
|
||||
|
||||
if (argvars[2].v_type == VAR_UNKNOWN) {
|
||||
if (tv_list_len(l) == 0) {
|
||||
semsg(_(e_reduceempty), "List");
|
||||
return;
|
||||
}
|
||||
const listitem_T *const first = tv_list_first(l);
|
||||
initial = *TV_LIST_ITEM_TV(first);
|
||||
li = TV_LIST_ITEM_NEXT(l, first);
|
||||
} else {
|
||||
initial = argvars[2];
|
||||
li = tv_list_first(l);
|
||||
}
|
||||
|
||||
tv_copy(&initial, rettv);
|
||||
|
||||
if (l != NULL) {
|
||||
const VarLockStatus prev_locked = tv_list_locked(l);
|
||||
const int called_emsg_start = called_emsg;
|
||||
|
||||
tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here
|
||||
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
|
||||
argv[0] = *rettv;
|
||||
argv[1] = *TV_LIST_ITEM_TV(li);
|
||||
rettv->v_type = VAR_UNKNOWN;
|
||||
const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe);
|
||||
tv_clear(&argv[0]);
|
||||
if (r == FAIL || called_emsg != called_emsg_start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tv_list_set_lock(l, prev_locked);
|
||||
}
|
||||
} else {
|
||||
const blob_T *const b = argvars[0].vval.v_blob;
|
||||
int i;
|
||||
|
||||
if (argvars[2].v_type == VAR_UNKNOWN) {
|
||||
if (tv_blob_len(b) == 0) {
|
||||
semsg(_(e_reduceempty), "Blob");
|
||||
return;
|
||||
}
|
||||
initial.v_type = VAR_NUMBER;
|
||||
initial.vval.v_number = tv_blob_get(b, 0);
|
||||
i = 1;
|
||||
} else if (argvars[2].v_type != VAR_NUMBER) {
|
||||
emsg(_(e_number_exp));
|
||||
return;
|
||||
} else {
|
||||
initial = argvars[2];
|
||||
i = 0;
|
||||
}
|
||||
|
||||
tv_copy(&initial, rettv);
|
||||
for (; i < tv_blob_len(b); i++) {
|
||||
argv[0] = *rettv;
|
||||
argv[1].v_type = VAR_NUMBER;
|
||||
argv[1].vval.v_number = tv_blob_get(b, i);
|
||||
if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SP_NOMOVE 0x01 ///< don't move cursor
|
||||
#define SP_REPEAT 0x02 ///< repeat to find outer pair
|
||||
#define SP_RETCOUNT 0x04 ///< return matchcount
|
||||
|
Reference in New Issue
Block a user