To: vim_dev@googlegroups.com Subject: Patch 8.2.0159 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0159 Problem: Non-materialized range() list causes problems. (Fujiwara Takuya) Solution: Materialize the list where needed. Files: src/testdir/test_functions.vim, src/testdir/test_python3.vim, src/userfunc.c, src/evalfunc.c, src/highlight.c, src/evalvars.c, src/popupmenu.c, src/insexpand.c, src/json.c, src/channel.c, src/eval.c *** ../vim-8.2.0158/src/testdir/test_functions.vim 2019-12-06 12:39:44.000000000 +0100 --- src/testdir/test_functions.vim 2020-01-27 22:05:10.013950351 +0100 *************** *** 1147,1152 **** --- 1147,1153 ---- if has('balloon_eval') " This won't do anything but must not crash either. call balloon_show('hi!') + call balloon_show(range(3)) endif endfunc *************** *** 1742,1744 **** --- 1743,1966 ---- call StopVimInTerminal(buf) call delete('XState') endfunc + + func Test_range() + " destructuring + let [x, y] = range(2) + call assert_equal([0, 1], [x, y]) + + " index + call assert_equal(4, range(1, 10)[3]) + + " add() + call assert_equal([0, 1, 2, 3], add(range(3), 3)) + call assert_equal([0, 1, 2, [0, 1, 2]], add([0, 1, 2], range(3))) + call assert_equal([0, 1, 2, [0, 1, 2]], add(range(3), range(3))) + + " append() + new + call append('.', range(5)) + call assert_equal(['', '0', '1', '2', '3', '4'], getline(1, '$')) + bwipe! + + " appendbufline() + new + call appendbufline(bufnr(''), '.', range(5)) + call assert_equal(['0', '1', '2', '3', '4', ''], getline(1, '$')) + bwipe! + + " call() + func TwoArgs(a, b) + return [a:a, a:b] + endfunc + call assert_equal([0, 1], call('TwoArgs', range(2))) + + " col() + new + call setline(1, ['foo', 'bar']) + call assert_equal(2, col(range(1, 2))) + bwipe! + + " complete() + execute "normal! a\=[complete(col('.'), range(10)), ''][1]\" + " complete_info() + execute "normal! a\=[complete(col('.'), range(10)), ''][1]\\=[complete_info(range(5)), ''][1]\" + + " copy() + call assert_equal([1, 2, 3], copy(range(1, 3))) + + " count() + call assert_equal(0, count(range(0), 3)) + call assert_equal(0, count(range(2), 3)) + call assert_equal(1, count(range(5), 3)) + + " cursor() + new + call setline(1, ['aaa', 'bbb', 'ccc']) + call cursor(range(1, 2)) + call assert_equal([2, 1], [col('.'), line('.')]) + bwipe! + + " deepcopy() + call assert_equal([1, 2, 3], deepcopy(range(1, 3))) + + " empty() + call assert_true(empty(range(0))) + call assert_false(empty(range(2))) + + " execute() + new + call setline(1, ['aaa', 'bbb', 'ccc']) + call execute(range(3)) + call assert_equal(2, line('.')) + bwipe! + + " extend() + call assert_equal([1, 2, 3, 4], extend([1], range(2, 4))) + call assert_equal([1, 2, 3, 4], extend(range(1, 1), range(2, 4))) + call assert_equal([1, 2, 3, 4], extend(range(1, 1), [2, 3, 4])) + + " filter() + call assert_equal([1, 3], filter(range(5), 'v:val % 2')) + + " funcref() + call assert_equal([0, 1], funcref('TwoArgs', range(2))()) + + " function() + call assert_equal([0, 1], function('TwoArgs', range(2))()) + + " garbagecollect() + let thelist = [1, range(2), 3] + let otherlist = range(3) + call test_garbagecollect_now() + + " get() + call assert_equal(4, get(range(1, 10), 3)) + call assert_equal(-1, get(range(1, 10), 42, -1)) + + " index() + call assert_equal(1, index(range(1, 5), 2)) + + " inputlist() + call test_feedinput("1\") + call assert_equal(1, inputlist(range(10))) + call test_feedinput("1\") + call assert_equal(1, inputlist(range(3, 10))) + + call assert_equal('[0,1,2,3]', json_encode(range(4))) + + " insert() + call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42)) + call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42, 0)) + call assert_equal([1, 42, 2, 3, 4, 5], insert(range(1, 5), 42, 1)) + call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, 4)) + call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, -1)) + call assert_equal([1, 2, 3, 4, 5, 42], insert(range(1, 5), 42, 5)) + + " join() + call assert_equal('0 1 2 3 4', join(range(5))) + + " len() + call assert_equal(0, len(range(0))) + call assert_equal(2, len(range(2))) + call assert_equal(5, len(range(0, 12, 3))) + call assert_equal(4, len(range(3, 0, -1))) + + " list2str() + call assert_equal('ABC', list2str(range(65, 67))) + + " lock() + let thelist = range(5) + lockvar thelist + + " map() + call assert_equal([0, 2, 4, 6, 8], map(range(5), 'v:val * 2')) + + " match() + call assert_equal(3, match(range(5), 3)) + + " matchaddpos() + highlight MyGreenGroup ctermbg=green guibg=green + call matchaddpos('MyGreenGroup', range(line('.'), line('.'))) + + " matchend() + call assert_equal(4, matchend(range(5), '4')) + call assert_equal(3, matchend(range(1, 5), '4')) + call assert_equal(-1, matchend(range(1, 5), '42')) + + " matchstrpos() + call assert_equal(['4', 4, 0, 1], matchstrpos(range(5), '4')) + call assert_equal(['4', 3, 0, 1], matchstrpos(range(1, 5), '4')) + call assert_equal(['', -1, -1, -1], matchstrpos(range(1, 5), '42')) + + " max() reverse() + call assert_equal(0, max(range(0))) + call assert_equal(0, max(range(10, 9))) + call assert_equal(9, max(range(10))) + call assert_equal(18, max(range(0, 20, 3))) + call assert_equal(20, max(range(20, 0, -3))) + call assert_equal(99999, max(range(100000))) + call assert_equal(99999, max(range(99999, 0, -1))) + call assert_equal(99999, max(reverse(range(100000)))) + call assert_equal(99999, max(reverse(range(99999, 0, -1)))) + + " min() reverse() + call assert_equal(0, min(range(0))) + call assert_equal(0, min(range(10, 9))) + call assert_equal(5, min(range(5, 10))) + call assert_equal(5, min(range(5, 10, 3))) + call assert_equal(2, min(range(20, 0, -3))) + call assert_equal(0, min(range(100000))) + call assert_equal(0, min(range(99999, 0, -1))) + call assert_equal(0, min(reverse(range(100000)))) + call assert_equal(0, min(reverse(range(99999, 0, -1)))) + + " remove() + call assert_equal(1, remove(range(1, 10), 0)) + call assert_equal(2, remove(range(1, 10), 1)) + call assert_equal(9, remove(range(1, 10), 8)) + call assert_equal(10, remove(range(1, 10), 9)) + call assert_equal(10, remove(range(1, 10), -1)) + call assert_equal([3, 4, 5], remove(range(1, 10), 2, 4)) + + " repeat() + call assert_equal([0, 1, 2, 0, 1, 2], repeat(range(3), 2)) + call assert_equal([0, 1, 2], repeat(range(3), 1)) + call assert_equal([], repeat(range(3), 0)) + call assert_equal([], repeat(range(5, 4), 2)) + call assert_equal([], repeat(range(5, 4), 0)) + + " reverse() + call assert_equal([2, 1, 0], reverse(range(3))) + call assert_equal([0, 1, 2, 3], reverse(range(3, 0, -1))) + call assert_equal([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], reverse(range(10))) + call assert_equal([20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10], reverse(range(10, 20))) + call assert_equal([16, 13, 10], reverse(range(10, 18, 3))) + call assert_equal([19, 16, 13, 10], reverse(range(10, 19, 3))) + call assert_equal([19, 16, 13, 10], reverse(range(10, 20, 3))) + call assert_equal([11, 14, 17, 20], reverse(range(20, 10, -3))) + call assert_equal([], reverse(range(0))) + + " TODO: setpos() + " new + " call setline(1, repeat([''], bufnr(''))) + " call setline(bufnr('') + 1, repeat('x', bufnr('') * 2 + 6)) + " call setpos('x', range(bufnr(''), bufnr('') + 3)) + " bwipe! + + " setreg() + call setreg('a', range(3)) + call assert_equal("0\n1\n2\n", getreg('a')) + + " sort() + call assert_equal([0, 1, 2, 3, 4, 5], sort(range(5, 0, -1))) + + " string() + call assert_equal('[0, 1, 2, 3, 4]', string(range(5))) + + " type() + call assert_equal(v:t_list, type(range(5))) + + " uniq() + call assert_equal([0, 1, 2, 3, 4], uniq(range(5))) + endfunc *** ../vim-8.2.0158/src/testdir/test_python3.vim 2020-01-19 13:57:51.465877807 +0100 --- src/testdir/test_python3.vim 2020-01-27 20:11:45.939463607 +0100 *************** *** 189,195 **** endfunc " Test range objects, see :help python-range ! func Test_range() new py3 b = vim.current.buffer --- 189,195 ---- endfunc " Test range objects, see :help python-range ! func Test_python3_range() new py3 b = vim.current.buffer *** ../vim-8.2.0158/src/userfunc.c 2020-01-26 16:50:02.522754194 +0100 --- src/userfunc.c 2020-01-27 20:04:33.945240885 +0100 *************** *** 1600,1612 **** dict_T *selfdict, typval_T *rettv) { listitem_T *item; typval_T argv[MAX_FUNC_ARGS + 1]; int argc = 0; int r = 0; ! for (item = args->vval.v_list->lv_first; item != NULL; ! item = item->li_next) { if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) { --- 1600,1613 ---- dict_T *selfdict, typval_T *rettv) { + list_T *l = args->vval.v_list; listitem_T *item; typval_T argv[MAX_FUNC_ARGS + 1]; int argc = 0; int r = 0; ! range_list_materialize(l); ! for (item = l->lv_first; item != NULL; item = item->li_next) { if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) { *** ../vim-8.2.0158/src/evalfunc.c 2020-01-26 15:52:33.015833276 +0100 --- src/evalfunc.c 2020-01-27 22:00:04.979283109 +0100 *************** *** 1856,1862 **** #endif case VAR_LIST: n = argvars[0].vval.v_list == NULL ! || argvars[0].vval.v_list->lv_first == NULL; break; case VAR_DICT: n = argvars[0].vval.v_dict == NULL --- 1856,1862 ---- #endif case VAR_LIST: n = argvars[0].vval.v_list == NULL ! || argvars[0].vval.v_list->lv_len == 0; break; case VAR_DICT: n = argvars[0].vval.v_dict == NULL *************** *** 2064,2070 **** if (argvars[arg_off].v_type == VAR_LIST) { list = argvars[arg_off].vval.v_list; ! if (list == NULL || list->lv_first == NULL) // empty list, no commands, empty output return; ++list->lv_refcount; --- 2064,2070 ---- if (argvars[arg_off].v_type == VAR_LIST) { list = argvars[arg_off].vval.v_list; ! if (list == NULL || list->lv_len == 0) // empty list, no commands, empty output return; ++list->lv_refcount; *************** *** 2114,2121 **** do_cmdline_cmd(cmd); else { ! listitem_T *item = list->lv_first; do_cmdline(NULL, get_list_line, (void *)&item, DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); --list->lv_refcount; --- 2114,2123 ---- do_cmdline_cmd(cmd); else { ! listitem_T *item; + range_list_materialize(list); + item = list->lv_first; do_cmdline(NULL, get_list_line, (void *)&item, DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); --list->lv_refcount; *************** *** 2643,2651 **** --- 2645,2656 ---- for (i = 0; i < arg_len; i++) copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); if (lv_len > 0) + { + range_list_materialize(list); for (li = list->lv_first; li != NULL; li = li->li_next) copy_tv(&li->li_tv, &pt->pt_argv[i++]); + } } // For "function(dict.func, [], dict)" and "func" is a partial *************** *** 4058,4063 **** --- 4063,4069 ---- l = argvars[0].vval.v_list; if (l != NULL) { + range_list_materialize(l); item = l->lv_first; if (argvars[2].v_type != VAR_UNKNOWN) { *************** *** 4139,4144 **** --- 4145,4151 ---- static void f_inputlist(typval_T *argvars, typval_T *rettv) { + list_T *l; listitem_T *li; int selected; int mouse_used; *************** *** 4161,4167 **** msg_scroll = TRUE; msg_clr_eos(); ! for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) { msg_puts((char *)tv_get_string(&li->li_tv)); msg_putchar('\n'); --- 4168,4176 ---- msg_scroll = TRUE; msg_clr_eos(); ! l = argvars[0].vval.v_list; ! range_list_materialize(l); ! for (li = l->lv_first; li != NULL; li = li->li_next) { msg_puts((char *)tv_get_string(&li->li_tv)); msg_putchar('\n'); *************** *** 4644,4649 **** --- 4653,4659 ---- { if ((l = argvars[0].vval.v_list) == NULL) goto theend; + range_list_materialize(l); li = l->lv_first; } else *************** *** 4873,4878 **** --- 4883,4889 ---- l = argvars[0].vval.v_list; if (l != NULL) { + range_list_materialize(l); li = l->lv_first; if (li != NULL) { *************** *** 5322,5328 **** list->lv_start = start; list->lv_end = end; list->lv_stride = stride; ! list->lv_len = (end - start + 1) / stride; } } --- 5333,5339 ---- list->lv_start = start; list->lv_end = end; list->lv_stride = stride; ! list->lv_len = (end - start) / stride + 1; } } *************** *** 6790,6811 **** allocval = lstval + len + 2; curallocval = allocval; ! for (li = ll == NULL ? NULL : ll->lv_first; li != NULL; ! li = li->li_next) { ! strval = tv_get_string_buf_chk(&li->li_tv, buf); ! if (strval == NULL) ! goto free_lstval; ! if (strval == buf) { ! // Need to make a copy, next tv_get_string_buf_chk() will ! // overwrite the string. ! strval = vim_strsave(buf); if (strval == NULL) goto free_lstval; ! *curallocval++ = strval; } - *curval++ = strval; } *curval++ = NULL; --- 6801,6825 ---- allocval = lstval + len + 2; curallocval = allocval; ! if (ll != NULL) { ! range_list_materialize(ll); ! for (li = ll->lv_first; li != NULL; li = li->li_next) { ! strval = tv_get_string_buf_chk(&li->li_tv, buf); if (strval == NULL) goto free_lstval; ! if (strval == buf) ! { ! // Need to make a copy, next tv_get_string_buf_chk() will ! // overwrite the string. ! strval = vim_strsave(buf); ! if (strval == NULL) ! goto free_lstval; ! *curallocval++ = strval; ! } ! *curval++ = strval; } } *curval++ = NULL; *** ../vim-8.2.0158/src/highlight.c 2019-12-29 23:04:20.290639897 +0100 --- src/highlight.c 2020-01-27 20:10:10.455858061 +0100 *************** *** 3739,3744 **** --- 3739,3745 ---- listitem_T *li; int i; + range_list_materialize(pos_list); for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH; i++, li = li->li_next) { *** ../vim-8.2.0158/src/evalvars.c 2020-01-26 21:59:25.620718163 +0100 --- src/evalvars.c 2020-01-27 22:07:57.889244337 +0100 *************** *** 843,848 **** --- 843,849 ---- return FAIL; } + range_list_materialize(l); item = l->lv_first; while (*arg != ']') { *************** *** 1699,1705 **** l->lv_lock |= VAR_LOCKED; else l->lv_lock &= ~VAR_LOCKED; ! if (deep < 0 || deep > 1) // recursive: lock/unlock the items the List contains for (li = l->lv_first; li != NULL; li = li->li_next) item_lock(&li->li_tv, deep - 1, lock); --- 1700,1706 ---- l->lv_lock |= VAR_LOCKED; else l->lv_lock &= ~VAR_LOCKED; ! if ((deep < 0 || deep > 1) && l->lv_first != &range_list_item) // recursive: lock/unlock the items the List contains for (li = l->lv_first; li != NULL; li = li->li_next) item_lock(&li->li_tv, deep - 1, lock); *** ../vim-8.2.0158/src/popupmenu.c 2020-01-11 16:05:19.594287610 +0100 --- src/popupmenu.c 2020-01-27 20:19:10.853571272 +0100 *************** *** 1314,1319 **** --- 1314,1320 ---- balloon_array = ALLOC_CLEAR_MULT(pumitem_T, list->lv_len); if (balloon_array == NULL) return; + range_list_materialize(list); for (idx = 0, li = list->lv_first; li != NULL; li = li->li_next, ++idx) { char_u *text = tv_get_string_chk(&li->li_tv); *** ../vim-8.2.0158/src/insexpand.c 2020-01-26 22:43:27.484098902 +0100 --- src/insexpand.c 2020-01-27 20:56:58.472883625 +0100 *************** *** 2330,2335 **** --- 2330,2336 ---- int dir = compl_direction; // Go through the List with matches and add each of them. + range_list_materialize(list); for (li = list->lv_first; li != NULL; li = li->li_next) { if (ins_compl_add_tv(&li->li_tv, dir) == OK) *************** *** 2511,2516 **** --- 2512,2518 ---- else { what_flag = 0; + range_list_materialize(what_list); for (item = what_list->lv_first; item != NULL; item = item->li_next) { char_u *what = tv_get_string(&item->li_tv); *** ../vim-8.2.0158/src/json.c 2020-01-26 21:42:00.089532706 +0100 --- src/json.c 2020-01-27 20:57:49.132706404 +0100 *************** *** 265,270 **** --- 265,271 ---- l->lv_copyID = copyID; ga_append(gap, '['); + range_list_materialize(l); for (li = l->lv_first; li != NULL && !got_int; ) { if (json_encode_item(gap, &li->li_tv, copyID, *** ../vim-8.2.0158/src/channel.c 2020-01-26 15:52:33.015833276 +0100 --- src/channel.c 2020-01-27 21:16:21.856502906 +0100 *************** *** 5123,5128 **** --- 5123,5129 ---- return FAIL; } + range_list_materialize(item->vval.v_list); li = item->vval.v_list->lv_first; for (; li != NULL && n < 16; li = li->li_next, n++) { *************** *** 5529,5534 **** --- 5530,5536 ---- listitem_T *li; char_u *s; + range_list_materialize(l); for (li = l->lv_first; li != NULL; li = li->li_next) { s = tv_get_string_chk(&li->li_tv); *** ../vim-8.2.0158/src/eval.c 2020-01-26 19:26:42.794068329 +0100 --- src/eval.c 2020-01-27 21:54:41.756814825 +0100 *************** *** 4205,4211 **** cur_l = l; for (;;) { ! if (!abort) // Mark each item in the list. If the item contains a hashtab // it is added to ht_stack, if it contains a list it is added to // list_stack. --- 4205,4211 ---- cur_l = l; for (;;) { ! if (!abort && cur_l->lv_first != &range_list_item) // Mark each item in the list. If the item contains a hashtab // it is added to ht_stack, if it contains a list it is added to // list_stack. *** ../vim-8.2.0158/src/version.c 2020-01-26 22:43:27.488098884 +0100 --- src/version.c 2020-01-27 22:08:27.829119850 +0100 *************** *** 744,745 **** --- 744,747 ---- { /* Add new patch number below this line */ + /**/ + 159, /**/ -- I think that you'll agree that engineers are very effective in their social interactions. It's the "normal" people who are nuts. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///