diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-08-15 21:10:16 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-08-15 21:10:16 +0200 |
commit | 11107bab7ead9124f46a7ddf6aa3bb66b43a8246 (patch) | |
tree | 113c14273a2c908c44e38d0fde516aa682abd4b4 /src/eval.c | |
parent | 3d1cde8a2f28dce2c82d2b2b4c5e35e6662030e0 (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.c | 76 |
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 |