Mercurial > vim
diff src/vim9execute.c @ 24234:7ffc795288dd v8.2.2658
patch 8.2.2658: :for cannot loop over a string
Commit: https://github.com/vim/vim/commit/74e54fcb447e5db32f9c2df34c0554bbecdccca2
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Mar 26 20:41:29 2021 +0100
patch 8.2.2658: :for cannot loop over a string
Problem: :for cannot loop over a string.
Solution: Accept a string argument and iterate over its characters.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 26 Mar 2021 20:45:02 +0100 |
parents | f49f80a0905d |
children | cabed216cc2f |
line wrap: on
line diff
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2741,36 +2741,76 @@ call_def_function( // top of a for loop case ISN_FOR: { - list_T *list = STACK_TV_BOT(-1)->vval.v_list; + typval_T *ltv = STACK_TV_BOT(-1); typval_T *idxtv = STACK_TV_VAR(iptr->isn_arg.forloop.for_idx); - // push the next item from the list if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; - ++idxtv->vval.v_number; - if (list == NULL || idxtv->vval.v_number >= list->lv_len) + if (ltv->v_type == VAR_LIST) { - // past the end of the list, jump to "endfor" - ectx.ec_iidx = iptr->isn_arg.forloop.for_end; - may_restore_cmdmod(&funclocal); + list_T *list = ltv->vval.v_list; + + // push the next item from the list + ++idxtv->vval.v_number; + if (list == NULL + || idxtv->vval.v_number >= list->lv_len) + { + // past the end of the list, jump to "endfor" + ectx.ec_iidx = iptr->isn_arg.forloop.for_end; + may_restore_cmdmod(&funclocal); + } + else if (list->lv_first == &range_list_item) + { + // non-materialized range() list + tv = STACK_TV_BOT(0); + tv->v_type = VAR_NUMBER; + tv->v_lock = 0; + tv->vval.v_number = list_find_nr( + list, idxtv->vval.v_number, NULL); + ++ectx.ec_stack.ga_len; + } + else + { + listitem_T *li = list_find(list, + idxtv->vval.v_number); + + copy_tv(&li->li_tv, STACK_TV_BOT(0)); + ++ectx.ec_stack.ga_len; + } } - else if (list->lv_first == &range_list_item) + else if (ltv->v_type == VAR_STRING) { - // non-materialized range() list - tv = STACK_TV_BOT(0); - tv->v_type = VAR_NUMBER; - tv->v_lock = 0; - tv->vval.v_number = list_find_nr( - list, idxtv->vval.v_number, NULL); - ++ectx.ec_stack.ga_len; + char_u *str = ltv->vval.v_string; + int len = str == NULL ? 0 : (int)STRLEN(str); + + // Push the next character from the string. The index + // is for the last byte of the previous character. + ++idxtv->vval.v_number; + if (idxtv->vval.v_number >= len) + { + // past the end of the string, jump to "endfor" + ectx.ec_iidx = iptr->isn_arg.forloop.for_end; + may_restore_cmdmod(&funclocal); + } + else + { + int clen = mb_ptr2len(str + idxtv->vval.v_number); + + tv = STACK_TV_BOT(0); + tv->v_type = VAR_STRING; + tv->vval.v_string = vim_strnsave( + str + idxtv->vval.v_number, clen); + ++ectx.ec_stack.ga_len; + idxtv->vval.v_number += clen - 1; + } } else { - listitem_T *li = list_find(list, idxtv->vval.v_number); - - copy_tv(&li->li_tv, STACK_TV_BOT(0)); - ++ectx.ec_stack.ga_len; + // TODO: support Blob + semsg(_(e_for_loop_on_str_not_supported), + vartype_name(ltv->v_type)); + goto failed; } } break;