diff options
| author | Michael Ennen <mike.ennen@gmail.com> | 2016-12-14 00:20:48 -0700 | 
|---|---|---|
| committer | Michael Ennen <mike.ennen@gmail.com> | 2017-02-14 17:38:16 -0700 | 
| commit | bb2afeb0266ffd410e2e226a376f7ddbac633491 (patch) | |
| tree | 0488197944e3fc6a7c5ddf887eebc545c9f34c8b /src | |
| parent | b0fc6108c923a198325354ae36b71f90c4c68e19 (diff) | |
| download | rneovim-bb2afeb0266ffd410e2e226a376f7ddbac633491.tar.gz rneovim-bb2afeb0266ffd410e2e226a376f7ddbac633491.tar.bz2 rneovim-bb2afeb0266ffd410e2e226a376f7ddbac633491.zip | |
vim-patch:7.4.1989
Problem:    filter() and map() only accept a string argument.
Solution:   Implement using a Funcref argument (Yasuhiro Matsumoto, Ken
            Takata)
https://github.com/vim/vim/commit/b33c7eb5b813cb631b2b0ca5c4029e1788a09bde
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/eval.c | 58 | ||||
| -rw-r--r-- | src/nvim/testdir/Makefile | 1 | ||||
| -rw-r--r-- | src/nvim/testdir/test_alot.vim | 1 | ||||
| -rw-r--r-- | src/nvim/testdir/test_filter_map.vim | 77 | ||||
| -rw-r--r-- | src/nvim/testdir/test_partial.vim | 21 | ||||
| -rw-r--r-- | src/nvim/version.c | 2 | 
6 files changed, 140 insertions, 20 deletions
| diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8692ddc334..e4afa18d10 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5285,7 +5285,8 @@ tv_equal (      return TRUE;    } -  // For VAR_FUNC and VAR_PARTIAL only compare the function name. +  // For VAR_FUNC and VAR_PARTIAL compare the function name, bound dict and +  // arguments.    if ((tv1->v_type == VAR_FUNC         || (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL))        && (tv2->v_type == VAR_FUNC @@ -9306,8 +9307,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)   */  static void filter_map(typval_T *argvars, typval_T *rettv, int map)  { -  char_u buf[NUMBUFLEN]; -  char_u      *expr; +  typval_T    *expr;    listitem_T  *li, *nli;    list_T      *l = NULL;    dictitem_T  *di; @@ -9339,16 +9339,15 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)      return;    } -  expr = get_tv_string_buf_chk(&argvars[1], buf); -  /* On type errors, the preceding call has already displayed an error -   * message.  Avoid a misleading error message for an empty string that -   * was not passed as argument. */ -  if (expr != NULL) { +  expr = &argvars[1]; +  // On type errors, the preceding call has already displayed an error +  // message.  Avoid a misleading error message for an empty string that +  // was not passed as argument. +  if (expr->v_type != VAR_UNKNOWN) {      prepare_vimvar(VV_VAL, &save_val); -    expr = skipwhite(expr); -    /* We reset "did_emsg" to be able to detect whether an error -     * occurred during evaluation of the expression. */ +    // We reset "did_emsg" to be able to detect whether an error +    // occurred during evaluation of the expression.      save_did_emsg = did_emsg;      did_emsg = FALSE; @@ -9412,20 +9411,41 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)    copy_tv(&argvars[0], rettv);  } -static int filter_map_one(typval_T *tv, char_u *expr, int map, int *remp) +static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)  {    typval_T rettv; +  typeval_T argv[3];    char_u      *s;    int retval = FAIL; +  int dummy;    copy_tv(tv, &vimvars[VV_VAL].vv_tv); -  s = expr; -  if (eval1(&s, &rettv, TRUE) == FAIL) -    goto theend; -  if (*s != NUL) {  /* check for trailing chars after expr */ -    EMSG2(_(e_invexpr2), s); -    clear_tv(&rettv); -    goto theend; +  argv[0] = vimvars[VV_KEY].vv_tv; +  argv[1] = vimvars[VV_VAL].vv_tv; +  s = expr->vval.v_string; +  if (expr->v_type == VAR_FUNC) { +    if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, 0L, 0L, &dummy, +                  true, NULL, NULL) == FAIL) { +      goto theend; +    } +  } else if (expr->v_type == VAR_PARTIAL) { +    partial_T *partial = expr->vval.v_partial; + +    s = partial->pt_name; +    if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, 0L, 0L, &dummy, +                  true, partial, NULL) == FAIL) { +      goto theend; +    } +  } else { +    s = skipwhite(s); +    if (eval1(&s, &rettv, true) == FAIL) { +      goto theend; +    } + +    if (*s != NUL) { // check for trailing chars after expr +      EMSG2(_(e_invexpr2), s); +      goto theend; +    }    }    if (map) {      /* map(): replace the list item value */ diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 721300c334..b8244fa0ec 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -34,6 +34,7 @@ NEW_TESTS ?= \  	    test_cscope.res \  	    test_digraph.res \  	    test_diffmode.res \ +		test_filter_map.res \  	    test_gn.res \  	    test_hardcopy.res \  	    test_help_tagjump.res \ diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index 60248bf430..6acc60163a 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -9,6 +9,7 @@ source test_ex_undo.vim  source test_expr.vim  source test_expr_utf8.vim  source test_feedkeys.vim +source test_filter_map.vim  source test_goto.vim  source test_jumps.vim  source test_match.vim diff --git a/src/nvim/testdir/test_filter_map.vim b/src/nvim/testdir/test_filter_map.vim new file mode 100644 index 0000000000..6bb063c76d --- /dev/null +++ b/src/nvim/testdir/test_filter_map.vim @@ -0,0 +1,77 @@ +" Test filter() and map() + +" list with expression string +func Test_filter_map_list_expr_string() +  " filter() +  call assert_equal([2, 3, 4], filter([1, 2, 3, 4], 'v:val > 1')) +  call assert_equal([3, 4], filter([1, 2, 3, 4], 'v:key > 1')) + +  " map() +  call assert_equal([2, 4, 6, 8], map([1, 2, 3, 4], 'v:val * 2')) +  call assert_equal([0, 2, 4, 6], map([1, 2, 3, 4], 'v:key * 2')) +endfunc + +" dict with expression string +func Test_filter_map_dict_expr_string() +  let dict = {"foo": 1, "bar": 2, "baz": 3} + +  " filter() +  call assert_equal({"bar": 2, "baz": 3}, filter(copy(dict), 'v:val > 1')) +  call assert_equal({"foo": 1, "baz": 3}, filter(copy(dict), 'v:key > "bar"')) + +  " map() +  call assert_equal({"foo": 2, "bar": 4, "baz": 6}, map(copy(dict), 'v:val * 2')) +  call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), 'v:key[0]')) +endfunc + +" list with funcref +func Test_filter_map_list_expr_funcref() +  " filter() +  func! s:filter1(index, val) abort +    return a:val > 1 +  endfunc +  call assert_equal([2, 3, 4], filter([1, 2, 3, 4], function('s:filter1'))) + +  func! s:filter2(index, val) abort +    return a:index > 1 +  endfunc +  call assert_equal([3, 4], filter([1, 2, 3, 4], function('s:filter2'))) + +  " map() +  func! s:filter3(index, val) abort +    return a:val * 2 +  endfunc +  call assert_equal([2, 4, 6, 8], map([1, 2, 3, 4], function('s:filter3'))) + +  func! s:filter4(index, val) abort +    return a:index * 2 +  endfunc +  call assert_equal([0, 2, 4, 6], map([1, 2, 3, 4], function('s:filter4'))) +endfunc + +" dict with funcref +func Test_filter_map_dict_expr_funcref() +  let dict = {"foo": 1, "bar": 2, "baz": 3} + +  " filter() +  func! s:filter1(key, val) abort +    return a:val > 1 +  endfunc +  call assert_equal({"bar": 2, "baz": 3}, filter(copy(dict), function('s:filter1'))) + +  func! s:filter2(key, val) abort +    return a:key > "bar" +  endfunc +  call assert_equal({"foo": 1, "baz": 3}, filter(copy(dict), function('s:filter2'))) + +  " map() +  func! s:filter3(key, val) abort +    return a:val * 2 +  endfunc +  call assert_equal({"foo": 2, "bar": 4, "baz": 6}, map(copy(dict), function('s:filter3'))) + +  func! s:filter4(key, val) abort +    return a:key[0] +  endfunc +  call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), function('s:filter4'))) +endfunc diff --git a/src/nvim/testdir/test_partial.vim b/src/nvim/testdir/test_partial.vim index 3a6e162453..de5c26c2dd 100644 --- a/src/nvim/testdir/test_partial.vim +++ b/src/nvim/testdir/test_partial.vim @@ -14,6 +14,14 @@ func MySort(up, one, two)    return a:one < a:two ? 1 : -1  endfunc +func MyMap(sub, index, val) +  return a:val - a:sub +endfunc + +func MyFilter(threshold, index, val) +  return a:val > a:threshold +endfunc +  func Test_partial_args()    let Cb = function('MyFunc', ["foo", "bar"]) @@ -36,6 +44,16 @@ func Test_partial_args()    call assert_equal([1, 2, 3], sort([3, 1, 2], Sort))    let Sort = function('MySort', [0])    call assert_equal([3, 2, 1], sort([3, 1, 2], Sort)) + +  let Map = function('MyMap', [2]) +  call assert_equal([-1, 0, 1], map([1, 2, 3], Map)) +  let Map = function('MyMap', [3]) +  call assert_equal([-2, -1, 0], map([1, 2, 3], Map)) + +  let Filter = function('MyFilter', [1]) +  call assert_equal([2, 3], filter([1, 2, 3], Filter)) +  let Filter = function('MyFilter', [2]) +  call assert_equal([3], filter([1, 2, 3], Filter))  endfunc  func MyDictFunc(arg1, arg2) dict @@ -59,6 +77,9 @@ func Test_partial_dict()    call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))    call assert_fails('Cb("fff")', 'E492:') +  let Cb = function('MyDictFunc', dict) +  call assert_equal({"foo": "hello/foo/1", "bar": "hello/bar/2"}, map({"foo": 1, "bar": 2}, Cb)) +    let dict = {"tr": function('tr', ['hello', 'h', 'H'])}    call assert_equal("Hello", dict.tr())  endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 111b597eba..96dce2ca46 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -451,7 +451,7 @@ static int included_patches[] = {    // 1992,    // 1991,    1990, -  // 1989, +  1989,    // 1988 NA    // 1987 NA    // 1986, | 
