aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/funcs.c
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-08-17 13:41:43 +0800
committerzeertzjq <zeertzjq@outlook.com>2023-08-17 15:20:47 +0800
commitc5576fcc8003280489c0aa0323a966e6de33e31f (patch)
tree85b5fb71ed9e7c5d28a0491e7ded93c63eecfb10 /src/nvim/eval/funcs.c
parent7f51829cf75e0d3ca546cab0e70a4c089eac40ec (diff)
downloadrneovim-c5576fcc8003280489c0aa0323a966e6de33e31f.tar.gz
rneovim-c5576fcc8003280489c0aa0323a966e6de33e31f.tar.bz2
rneovim-c5576fcc8003280489c0aa0323a966e6de33e31f.zip
vim-patch:8.2.3848: cannot use reduce() for a string
Problem: Cannot use reduce() for a string. Solution: Make reduce() work with a string. (Naruhiko Nishino, closes vim/vim#9366) https://github.com/vim/vim/commit/0ccb5842f5fb103763d106c7aa364d758343c35a Omit tv_get_first_char() as it doesn't really save much code. Co-authored-by: rbtnn <naru123456789@gmail.com>
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r--src/nvim/eval/funcs.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 0506c08b07..bf11fdf029 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -150,8 +150,12 @@ static const char *e_invalwindow = N_("E957: Invalid window number");
static const char e_invalid_submatch_number_nr[]
= N_("E935: Invalid submatch number: %d");
static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value");
+static const char e_string_list_or_blob_required[]
+ = N_("E1098: String, List or Blob required");
static const char e_missing_function_argument[]
= N_("E1132: Missing function argument");
+static const char e_string_expected_for_argument_nr[]
+ = N_("E1253: String expected for argument %d");
/// Dummy va_list for passing to vim_snprintf
///
@@ -6168,11 +6172,16 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
/// "reduce(list, { accumulator, element -> value } [, initial])" function
+/// "reduce(blob, { accumulator, element -> value } [, initial])" function
+/// "reduce(string, { accumulator, element -> value } [, initial])" function
static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) {
- emsg(_(e_listblobreq));
- return;
+ const int called_emsg_start = called_emsg;
+
+ if (argvars[0].v_type != VAR_STRING
+ && argvars[0].v_type != VAR_LIST
+ && argvars[0].v_type != VAR_BLOB) {
+ emsg(_(e_string_list_or_blob_required));
}
const char *func_name;
@@ -6217,7 +6226,6 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
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)) {
@@ -6232,6 +6240,44 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
tv_list_set_lock(l, prev_locked);
}
+ } else if (argvars[0].v_type == VAR_STRING) {
+ const char *p = tv_get_string(&argvars[0]);
+ int len;
+
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ if (*p == NUL) {
+ semsg(_(e_reduceempty), "String");
+ return;
+ }
+ len = utfc_ptr2len(p);
+ *rettv = (typval_T){
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_string = xstrnsave(p, (size_t)len),
+ };
+ p += len;
+ } else if (argvars[2].v_type != VAR_STRING) {
+ semsg(_(e_string_expected_for_argument_nr), 3);
+ return;
+ } else {
+ tv_copy(&argvars[2], rettv);
+ }
+
+ for (; *p != NUL; p += len) {
+ argv[0] = *rettv;
+ len = utfc_ptr2len(p);
+ argv[1] = (typval_T){
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_string = xstrnsave(p, (size_t)len),
+ };
+ const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe);
+ tv_clear(&argv[0]);
+ tv_clear(&argv[1]);
+ if (r == FAIL || called_emsg != called_emsg_start) {
+ break;
+ }
+ }
} else {
const blob_T *const b = argvars[0].vval.v_blob;
int i;