From 7002a3433bed7600ec02d64927ae0e77d077f34e Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sat, 1 Jan 2022 07:27:46 +0000 Subject: vim-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. https://github.com/vim/vim/commit/74e54fcb447e5db32f9c2df34c0554bbecdccca2 v8.2.2659 is already ported. N/A patches for version.c: vim-patch:8.2.2736: Vim9: for loop over string is a bit slow Problem: Vim9: for loop over string is a bit slow. Solution: Avoid using strlen(). https://github.com/vim/vim/commit/175a41c13f3e27e30c662f2f418c5a347dbc645d --- src/nvim/eval.c | 34 ++++++++++++++++++++++++++++++---- src/nvim/testdir/test_vimscript.vim | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5d9326eb24..aecb23f251 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -112,9 +112,11 @@ typedef struct { int fi_semicolon; // TRUE if ending in '; var]' int fi_varcount; // nr of variables in the list listwatch_T fi_lw; // keep an eye on the item used. - list_T *fi_list; // list being used + list_T *fi_list; // list being used int fi_bi; // index of blob blob_T *fi_blob; // blob being used + char_u *fi_string; // copy of string being used + int fi_byte_idx; // byte index in fi_string } forinfo_T; // values for vv_flags: @@ -2641,6 +2643,13 @@ void *eval_for_line(const char_u *arg, bool *errp, char_u **nextcmdp, int skip) fi->fi_blob = btv.vval.v_blob; } tv_clear(&tv); + } else if (tv.v_type == VAR_STRING) { + fi->fi_byte_idx = 0; + fi->fi_string = tv.vval.v_string; + tv.vval.v_string = NULL; + if (fi->fi_string == NULL) { + fi->fi_string = vim_strsave((char_u *)""); + } } else { emsg(_(e_listblobreq)); tv_clear(&tv); @@ -2679,6 +2688,19 @@ bool next_for_item(void *fi_void, char_u *arg) fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK; } + if (fi->fi_string != NULL) { + const int len = utfc_ptr2len(fi->fi_string + fi->fi_byte_idx); + if (len == 0) { + return false; + } + typval_T tv; + tv.v_type = VAR_STRING; + tv.v_lock = VAR_FIXED; + tv.vval.v_string = vim_strnsave(fi->fi_string + fi->fi_byte_idx, len); + fi->fi_byte_idx += len; + return ex_let_vars(arg, &tv, true, fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK; + } + listitem_T *item = fi->fi_lw.lw_item; if (item == NULL) { return false; @@ -2698,12 +2720,16 @@ void free_for_info(void *fi_void) { forinfo_T *fi = (forinfo_T *)fi_void; - if (fi != NULL && fi->fi_list != NULL) { + if (fi == NULL) { + return; + } + if (fi->fi_list != NULL) { tv_list_watch_remove(fi->fi_list, &fi->fi_lw); tv_list_unref(fi->fi_list); - } - if (fi != NULL && fi->fi_blob != NULL) { + } else if (fi->fi_blob != NULL) { tv_blob_unref(fi->fi_blob); + } else { + xfree(fi->fi_string); } xfree(fi); } diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 34733f127f..c59cab5f36 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1692,6 +1692,26 @@ func Test_function_defined_line() call delete('Xtest.vim') endfunc +func Test_for_over_string() + let res = '' + for c in 'aéc̀d' + let res ..= c .. '-' + endfor + call assert_equal('a-é-c̀-d-', res) + + let res = '' + for c in '' + let res ..= c .. '-' + endfor + call assert_equal('', res) + + let res = '' + for c in v:_null_string + let res ..= c .. '-' + endfor + call assert_equal('', res) +endfunc + "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker -- cgit