diff options
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 79 |
1 files changed, 54 insertions, 25 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a14b098caf..930cda4bd4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1692,7 +1692,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool lp->ll_n2 = tv_blob_len(lp->ll_blob) - 1; } - if (tv_blob_set_range(lp->ll_blob, (int)lp->ll_n1, (int)lp->ll_n2, rettv) == FAIL) { + if (tv_blob_set_range(lp->ll_blob, lp->ll_n1, lp->ll_n2, rettv) == FAIL) { return; } } else { @@ -3542,7 +3542,7 @@ static int eval_index(char **arg, typval_T *rettv, evalarg_T *const evalarg, boo if (evaluate) { int res = eval_index_inner(rettv, range, - empty1 ? NULL : &var1, empty2 ? NULL : &var2, + empty1 ? NULL : &var1, empty2 ? NULL : &var2, false, key, keylen, verbose); if (!empty1) { tv_clear(&var1); @@ -3592,17 +3592,31 @@ static int check_can_index(typval_T *rettv, bool evaluate, bool verbose) return OK; } +/// slice() function +void f_slice(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + if (check_can_index(argvars, true, false) == OK) { + tv_copy(argvars, rettv); + eval_index_inner(rettv, true, argvars + 1, + argvars[2].v_type == VAR_UNKNOWN ? NULL : argvars + 2, + true, NULL, 0, false); + } +} + /// Apply index or range to "rettv". -/// "var1" is the first index, NULL for [:expr]. -/// "var2" is the second index, NULL for [expr] and [expr: ] +/// +/// @param var1 the first index, NULL for [:expr]. +/// @param var2 the second index, NULL for [expr] and [expr: ] +/// @param exclusive true for slice(): second index is exclusive, use character +/// index for string. /// Alternatively, "key" is not NULL, then key[keylen] is the dict index. static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typval_T *var2, - const char *key, ptrdiff_t keylen, bool verbose) + bool exclusive, const char *key, ptrdiff_t keylen, bool verbose) { - int n1 = 0; - int n2 = 0; + varnumber_T n1 = 0; + varnumber_T n2 = 0; if (var1 != NULL && rettv->v_type != VAR_DICT) { - n1 = (int)tv_get_number(var1); + n1 = tv_get_number(var1); } if (is_range) { @@ -3612,10 +3626,10 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv } return FAIL; } - if (var2 == NULL) { - n2 = -1; + if (var2 != NULL) { + n2 = tv_get_number(var2); } else { - n2 = (int)tv_get_number(var2); + n2 = VARNUMBER_MAX; } } @@ -3632,7 +3646,13 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv const char *const s = tv_get_string(rettv); char *v; int len = (int)strlen(s); - if (is_range) { + if (exclusive) { + if (is_range) { + v = string_slice(s, n1, n2, exclusive); + } else { + v = char_from_string(s, n1); + } + } else if (is_range) { // The resulting variable is a substring. If the indexes // are out of range the result is empty. if (n1 < 0) { @@ -3646,6 +3666,9 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv } else if (n2 >= len) { n2 = len; } + if (exclusive) { + n2--; + } if (n1 >= len || n2 < 0 || n1 > n2) { v = NULL; } else { @@ -3680,7 +3703,10 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv if (n2 < 0) { n2 = len + n2; } else if (n2 >= len) { - n2 = len - 1; + n2 = len - (exclusive ? 0 : 1); + } + if (exclusive) { + n2--; } if (n1 >= len || n2 < 0 || n1 > n2) { tv_clear(rettv); @@ -3688,10 +3714,10 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv rettv->vval.v_blob = NULL; } else { blob_T *const blob = tv_blob_alloc(); - ga_grow(&blob->bv_ga, n2 - n1 + 1); - blob->bv_ga.ga_len = n2 - n1 + 1; - for (int i = n1; i <= n2; i++) { - tv_blob_set(blob, i - n1, tv_blob_get(rettv->vval.v_blob, i)); + ga_grow(&blob->bv_ga, (int)(n2 - n1 + 1)); + blob->bv_ga.ga_len = (int)(n2 - n1 + 1); + for (int i = (int)n1; i <= (int)n2; i++) { + tv_blob_set(blob, i - (int)n1, tv_blob_get(rettv->vval.v_blob, i)); } tv_clear(rettv); tv_blob_set_ret(rettv, blob); @@ -3703,7 +3729,7 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv n1 = len + n1; } if (n1 < len && n1 >= 0) { - const int v = (int)tv_blob_get(rettv->vval.v_blob, n1); + const int v = (int)tv_blob_get(rettv->vval.v_blob, (int)n1); tv_clear(rettv); rettv->v_type = VAR_NUMBER; rettv->vval.v_number = v; @@ -3718,10 +3744,10 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv n1 = 0; } if (var2 == NULL) { - n2 = -1; + n2 = VARNUMBER_MAX; } if (tv_list_slice_or_index(rettv->vval.v_list, - is_range, n1, n2, rettv, verbose) == FAIL) { + is_range, n1, n2, exclusive, rettv, verbose) == FAIL) { return FAIL; } break; @@ -7266,7 +7292,7 @@ int check_luafunc_name(const char *const str, const bool paren) /// Return the character "str[index]" where "index" is the character index. If /// "index" is out of range NULL is returned. -char *char_from_string(char *str, varnumber_T index) +char *char_from_string(const char *str, varnumber_T index) { size_t nbyte = 0; varnumber_T nchar = index; @@ -7290,7 +7316,7 @@ char *char_from_string(char *str, varnumber_T index) /// If going over the end return "str_len". /// If "idx" is negative count from the end, -1 is the last character. /// When going over the start return -1. -static ssize_t char_idx2byte(char *str, size_t str_len, varnumber_T idx) +static ssize_t char_idx2byte(const char *str, size_t str_len, varnumber_T idx) { varnumber_T nchar = idx; size_t nbyte = 0; @@ -7315,8 +7341,11 @@ static ssize_t char_idx2byte(char *str, size_t str_len, varnumber_T idx) } /// Return the slice "str[first:last]" using character indexes. +/// +/// @param exclusive true for slice(). +/// /// Return NULL when the result is empty. -char *string_slice(char *str, varnumber_T first, varnumber_T last) +char *string_slice(const char *str, varnumber_T first, varnumber_T last, bool exclusive) { if (str == NULL) { return NULL; @@ -7327,11 +7356,11 @@ char *string_slice(char *str, varnumber_T first, varnumber_T last) start_byte = 0; // first index very negative: use zero } ssize_t end_byte; - if (last == -1) { + if ((last == -1 && !exclusive) || last == VARNUMBER_MAX) { end_byte = (ssize_t)slen; } else { end_byte = char_idx2byte(str, slen, last); - if (end_byte >= 0 && end_byte < (ssize_t)slen) { + if (!exclusive && end_byte >= 0 && end_byte < (ssize_t)slen) { // end index is inclusive end_byte += utf_ptr2len(str + end_byte); } |