mirror of
https://github.com/neovim/neovim.git
synced 2025-09-27 13:38:34 +00:00
vim-patch:8.2.2344: using inclusive index for slice is not always desired
Problem: Using inclusive index for slice is not always desired.
Solution: Add the slice() method, which has an exclusive index. (closes
vim/vim#7408)
6601b62943
Cherry-pick a line in docs added later.
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user