summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-08-15 21:10:16 +0200
committerBram Moolenaar <Bram@vim.org>2020-08-15 21:10:16 +0200
commit11107bab7ead9124f46a7ddf6aa3bb66b43a8246 (patch)
tree113c14273a2c908c44e38d0fde516aa682abd4b4 /src/eval.c
parent3d1cde8a2f28dce2c82d2b2b4c5e35e6662030e0 (diff)
patch 8.2.1462: Vim9: string slice not supported yetv8.2.1462
Problem: Vim9: string slice not supported yet. Solution: Add support for string slicing.
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c76
1 files changed, 71 insertions, 5 deletions
diff --git a/src/eval.c b/src/eval.c
index 5a61a50fa7..cbbb9002bb 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3699,7 +3699,14 @@ eval_index(
case VAR_STRING:
s = tv_get_string(rettv);
len = (long)STRLEN(s);
- if (range)
+ if (in_vim9script())
+ {
+ if (range)
+ s = string_slice(s, n1, n2);
+ else
+ s = char_from_string(s, n1);
+ }
+ else if (range)
{
// The resulting variable is a substring. If the indexes
// are out of range the result is empty.
@@ -3718,10 +3725,6 @@ eval_index(
else
s = vim_strnsave(s + n1, n2 - n1 + 1);
}
- else if (in_vim9script())
- {
- s = char_from_string(s, n1);
- }
else
{
// The resulting variable is a string of a single
@@ -5313,6 +5316,69 @@ char_from_string(char_u *str, varnumber_T index)
}
/*
+ * Get the byte index for character index "idx" in string "str" with length
+ * "str_len".
+ * 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 zero.
+ */
+ static size_t
+char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
+{
+ varnumber_T nchar = idx;
+ size_t nbyte = 0;
+
+ if (nchar >= 0)
+ {
+ while (nchar > 0 && nbyte < str_len)
+ {
+ nbyte += MB_CPTR2LEN(str + nbyte);
+ --nchar;
+ }
+ }
+ else
+ {
+ nbyte = str_len;
+ while (nchar < 0 && nbyte > 0)
+ {
+ --nbyte;
+ nbyte -= mb_head_off(str, str + nbyte);
+ ++nchar;
+ }
+ }
+ return nbyte;
+}
+
+/*
+ * Return the slice "str[first:last]" using character indexes.
+ * Return NULL when the result is empty.
+ */
+ char_u *
+string_slice(char_u *str, varnumber_T first, varnumber_T last)
+{
+ size_t start_byte, end_byte;
+ size_t slen;
+
+ if (str == NULL)
+ return NULL;
+ slen = STRLEN(str);
+ start_byte = char_idx2byte(str, slen, first);
+ if (last == -1)
+ end_byte = slen;
+ else
+ {
+ end_byte = char_idx2byte(str, slen, last);
+ if (end_byte < slen)
+ // end index is inclusive
+ end_byte += MB_CPTR2LEN(str + end_byte);
+ }
+
+ if (start_byte >= slen || end_byte <= start_byte)
+ return NULL;
+ return vim_strnsave(str + start_byte, end_byte - start_byte);
+}
+
+/*
* Handle:
* - expr[expr], expr[expr:expr] subscript
* - ".name" lookup