Patch 8.2.1969
Problem:    Vim9: map() may change the list or dict item type.
Solution:   Add mapnew().
Files:      runtime/doc/eval.txt, runtime/doc/usr_41.txt, src/evalfunc.c,
            src/list.c, src/proto/list.pro, src/testdir/test_filter_map.vim


*** ../vim-8.2.1968/runtime/doc/eval.txt        2020-11-01 13:57:37.551988657 
+0100
--- runtime/doc/eval.txt        2020-11-09 18:27:17.973436627 +0100
***************
*** 2635,2642 ****
                                        rhs of mapping {name} in mode {mode}
  mapcheck({name} [, {mode} [, {abbr}]])
                                String  check for mappings matching {name}
! mapset({mode}, {abbr}, {dict})
!                               none    restore mapping from |maparg()| result
  match({expr}, {pat} [, {start} [, {count}]])
                                Number  position where {pat} matches in {expr}
  matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])
--- 2669,2677 ----
                                        rhs of mapping {name} in mode {mode}
  mapcheck({name} [, {mode} [, {abbr}]])
                                String  check for mappings matching {name}
! mapnew({expr1}, {expr2})      List/Dict  like |map()| but creates a new List
!                                          or Dictionary
! mapset({mode}, {abbr}, {dict})        none    restore mapping from |maparg()| 
result
  match({expr}, {pat} [, {start} [, {count}]])
                                Number  position where {pat} matches in {expr}
  matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])
***************
*** 6922,6930 ****
  <             {only available when compiled with the |+lua| feature}
  
  map({expr1}, {expr2})                                 *map()*
!               {expr1} must be a |List| or a |Dictionary|.
                Replace each item in {expr1} with the result of evaluating
!               {expr2}.  {expr2} must be a |string| or |Funcref|.
  
                If {expr2} is a |string|, inside {expr2} |v:val| has the value
                of the current item.  For a |Dictionary| |v:key| has the key
--- 6988,7001 ----
  <             {only available when compiled with the |+lua| feature}
  
  map({expr1}, {expr2})                                 *map()*
!               {expr1} must be a |List|, |Blob| or |Dictionary|.
                Replace each item in {expr1} with the result of evaluating
!               {expr2}.  For a |Blob| each byte is replaced.
!               If the item type changes you may want to use |mapnew()| to
!               create a new List or Dictionary.  This is required when using
!               Vim9 script.
! 
!               {expr2} must be a |string| or |Funcref|.
  
                If {expr2} is a |string|, inside {expr2} |v:val| has the value
                of the current item.  For a |Dictionary| |v:key| has the key
***************
*** 6959,6969 ****
                |Dictionary| to remain unmodified make a copy first: >
                        :let tlist = map(copy(mylist), ' v:val . "\t"')
  
! <             Returns {expr1}, the |List| or |Dictionary| that was filtered.
!               When an error is encountered while evaluating {expr2} no
!               further items in {expr1} are processed.  When {expr2} is a
!               Funcref errors inside a function are ignored, unless it was
!               defined with the "abort" flag.
  
                Can also be used as a |method|: >
                        mylist->map(expr2)
--- 7030,7040 ----
                |Dictionary| to remain unmodified make a copy first: >
                        :let tlist = map(copy(mylist), ' v:val . "\t"')
  
! <             Returns {expr1}, the |List|, |Blob| or |Dictionary| that was
!               filtered.  When an error is encountered while evaluating
!               {expr2} no further items in {expr1} are processed.  When
!               {expr2} is a Funcref errors inside a function are ignored,
!               unless it was defined with the "abort" flag.
  
                Can also be used as a |method|: >
                        mylist->map(expr2)
***************
*** 7072,7078 ****
                        GetKey()->mapcheck('n')
  
  
! mapset({mode}, {abbr}, {dict})                                *mapset()*
                Restore a mapping from a dictionary returned by |maparg()|.
                {mode} and {abbr} should be the same as for the call to
                |maparg()|. *E460*
--- 7143,7155 ----
                        GetKey()->mapcheck('n')
  
  
! mapnew({expr1}, {expr2})                                      *mapnew()*
!               Like |map()| but instead of replacing items in {expr1} a new
!               List or Dictionary is created and returned.  {expr1} remains
!               unchanged.
! 
! 
! mapset({mode}, {abbr}, {dict})                                        
*mapset()*
                Restore a mapping from a dictionary returned by |maparg()|.
                {mode} and {abbr} should be the same as for the call to
                |maparg()|. *E460*
*** ../vim-8.2.1968/runtime/doc/usr_41.txt      2020-09-22 20:33:30.437223175 
+0200
--- runtime/doc/usr_41.txt      2020-11-09 12:54:27.258287675 +0100
***************
*** 636,641 ****
--- 644,650 ----
        deepcopy()              make a full copy of a List
        filter()                remove selected items from a List
        map()                   change each List item
+       mapnew()                make a new List with changed items
        reduce()                reduce a List to a value
        sort()                  sort a List
        reverse()               reverse the order of a List
***************
*** 661,666 ****
--- 670,676 ----
        extend()                add entries from one Dictionary to another
        filter()                remove selected entries from a Dictionary
        map()                   change each Dictionary entry
+       mapnew()                make a new Dictionary with changed items
        keys()                  get List of Dictionary keys
        values()                get List of Dictionary values
        items()                 get List of Dictionary key-value pairs
*** ../vim-8.2.1968/src/evalfunc.c      2020-11-08 12:49:43.120372854 +0100
--- src/evalfunc.c      2020-11-09 18:27:51.937350831 +0100
***************
*** 479,485 ****
  {
      return &t_job;
  }
- 
      static type_T *
  ret_first_arg(int argcount, type_T **argtypes)
  {
--- 479,484 ----
***************
*** 487,492 ****
--- 486,503 ----
        return argtypes[0];
      return &t_void;
  }
+ // for map(): returns first argument but item type may differ
+     static type_T *
+ ret_first_cont(int argcount UNUSED, type_T **argtypes)
+ {
+     if (argtypes[0]->tt_type == VAR_LIST)
+       return &t_list_any;
+     if (argtypes[0]->tt_type == VAR_DICT)
+       return &t_dict_any;
+     if (argtypes[0]->tt_type == VAR_BLOB)
+       return argtypes[0];
+     return &t_any;
+ }
  
  /*
   * Used for getqflist(): returns list if there is no argument, dict if there 
is
***************
*** 1115,1125 ****
  #endif
                        },
      {"map",           2, 2, FEARG_1,      NULL,
!                       ret_any,            f_map},
      {"maparg",                1, 4, FEARG_1,      NULL,
                        ret_maparg,         f_maparg},
      {"mapcheck",      1, 3, FEARG_1,      NULL,
                        ret_string,         f_mapcheck},
      {"mapset",                3, 3, FEARG_1,      NULL,
                        ret_void,           f_mapset},
      {"match",         2, 4, FEARG_1,      NULL,
--- 1126,1138 ----
  #endif
                        },
      {"map",           2, 2, FEARG_1,      NULL,
!                       ret_first_cont,     f_map},
      {"maparg",                1, 4, FEARG_1,      NULL,
                        ret_maparg,         f_maparg},
      {"mapcheck",      1, 3, FEARG_1,      NULL,
                        ret_string,         f_mapcheck},
+     {"mapnew",                2, 2, FEARG_1,      NULL,
+                       ret_first_cont,     f_mapnew},
      {"mapset",                3, 3, FEARG_1,      NULL,
                        ret_void,           f_mapset},
      {"match",         2, 4, FEARG_1,      NULL,
*** ../vim-8.2.1968/src/list.c  2020-11-04 11:36:31.412190527 +0100
--- src/list.c  2020-11-09 18:11:04.635604330 +0100
***************
*** 1903,1940 ****
      do_sort_uniq(argvars, rettv, FALSE);
  }
  
  /*
   * Handle one item for map() and filter().
   */
      static int
! filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
  {
-     typval_T  rettv;
      typval_T  argv[3];
      int               retval = FAIL;
  
      copy_tv(tv, get_vim_var_tv(VV_VAL));
      argv[0] = *get_vim_var_tv(VV_KEY);
      argv[1] = *get_vim_var_tv(VV_VAL);
!     if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
        goto theend;
!     if (map)
!     {
!       // map(): replace the list item value
!       clear_tv(tv);
!       rettv.v_lock = 0;
!       *tv = rettv;
!     }
!     else
      {
        int         error = FALSE;
  
        // filter(): when expr is zero remove the item
        if (in_vim9script())
!           *remp = !tv2bool(&rettv);
        else
!           *remp = (tv_get_number_chk(&rettv, &error) == 0);
!       clear_tv(&rettv);
        // On type error, nothing has been removed; return FAIL to stop the
        // loop.  The error message was given by tv_get_number_chk().
        if (error)
--- 1903,1944 ----
      do_sort_uniq(argvars, rettv, FALSE);
  }
  
+ typedef enum {
+     FILTERMAP_FILTER,
+     FILTERMAP_MAP,
+     FILTERMAP_MAPNEW
+ } filtermap_T;
+ 
  /*
   * Handle one item for map() and filter().
+  * Sets v:val to "tv".  Caller must set v:key.
   */
      static int
! filter_map_one(
!       typval_T        *tv,        // original value
!       typval_T        *expr,      // callback
!       filtermap_T     filtermap,
!       typval_T        *newtv,     // for map() and mapnew(): new value
!       int             *remp)      // for filter(): remove flag
  {
      typval_T  argv[3];
      int               retval = FAIL;
  
      copy_tv(tv, get_vim_var_tv(VV_VAL));
      argv[0] = *get_vim_var_tv(VV_KEY);
      argv[1] = *get_vim_var_tv(VV_VAL);
!     if (eval_expr_typval(expr, argv, 2, newtv) == FAIL)
        goto theend;
!     if (filtermap == FILTERMAP_FILTER)
      {
        int         error = FALSE;
  
        // filter(): when expr is zero remove the item
        if (in_vim9script())
!           *remp = !tv2bool(newtv);
        else
!           *remp = (tv_get_number_chk(newtv, &error) == 0);
!       clear_tv(newtv);
        // On type error, nothing has been removed; return FAIL to stop the
        // loop.  The error message was given by tv_get_number_chk().
        if (error)
***************
*** 1950,1956 ****
   * Implementation of map() and filter().
   */
      static void
! filter_map(typval_T *argvars, typval_T *rettv, int map)
  {
      typval_T  *expr;
      listitem_T        *li, *nli;
--- 1954,1960 ----
   * Implementation of map() and filter().
   */
      static void
! filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
  {
      typval_T  *expr;
      listitem_T        *li, *nli;
***************
*** 1962,1991 ****
      blob_T    *b = NULL;
      int               rem;
      int               todo;
!     char_u    *ermsg = (char_u *)(map ? "map()" : "filter()");
!     char_u    *arg_errmsg = (char_u *)(map ? N_("map() argument")
!                                  : N_("filter() argument"));
      int               save_did_emsg;
      int               idx = 0;
  
!     // Always return the first argument, also on failure.
!     copy_tv(&argvars[0], rettv);
  
      if (argvars[0].v_type == VAR_BLOB)
      {
        if ((b = argvars[0].vval.v_blob) == NULL)
            return;
      }
      else if (argvars[0].v_type == VAR_LIST)
      {
        if ((l = argvars[0].vval.v_list) == NULL
!             || (!map && value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
            return;
      }
      else if (argvars[0].v_type == VAR_DICT)
      {
        if ((d = argvars[0].vval.v_dict) == NULL
!             || (!map && value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
            return;
      }
      else
--- 1966,2018 ----
      blob_T    *b = NULL;
      int               rem;
      int               todo;
!     char_u    *ermsg = (char_u *)(filtermap == FILTERMAP_MAP ? "map()"
!                                 : filtermap == FILTERMAP_MAPNEW ? "mapnew()"
!                                 : "filter()");
!     char_u    *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP
!                                                        ? N_("map() argument")
!                                      : filtermap == FILTERMAP_MAPNEW
!                                                     ? N_("mapnew() argument")
!                                                   : N_("filter() argument"));
      int               save_did_emsg;
      int               idx = 0;
  
!     // map() and filter() return the first argument, also on failure.
!     if (filtermap != FILTERMAP_MAPNEW)
!       copy_tv(&argvars[0], rettv);
  
      if (argvars[0].v_type == VAR_BLOB)
      {
+       if (filtermap == FILTERMAP_MAPNEW)
+       {
+           rettv->v_type = VAR_BLOB;
+           rettv->vval.v_blob = NULL;
+       }
        if ((b = argvars[0].vval.v_blob) == NULL)
            return;
      }
      else if (argvars[0].v_type == VAR_LIST)
      {
+       if (filtermap == FILTERMAP_MAPNEW)
+       {
+           rettv->v_type = VAR_LIST;
+           rettv->vval.v_list = NULL;
+       }
        if ((l = argvars[0].vval.v_list) == NULL
!             || (filtermap == FILTERMAP_FILTER
!                           && value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
            return;
      }
      else if (argvars[0].v_type == VAR_DICT)
      {
+       if (filtermap == FILTERMAP_MAPNEW)
+       {
+           rettv->v_type = VAR_DICT;
+           rettv->vval.v_dict = NULL;
+       }
        if ((d = argvars[0].vval.v_dict) == NULL
!             || (filtermap == FILTERMAP_FILTER
!                           && value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
            return;
      }
      else
***************
*** 2014,2021 ****
        if (argvars[0].v_type == VAR_DICT)
        {
            int     prev_lock = d->dv_lock;
  
!           if (map && d->dv_lock == 0)
                d->dv_lock = VAR_LOCKED;
            ht = &d->dv_hashtab;
            hash_lock(ht);
--- 2041,2056 ----
        if (argvars[0].v_type == VAR_DICT)
        {
            int     prev_lock = d->dv_lock;
+           dict_T  *d_ret = NULL;
  
!           if (filtermap == FILTERMAP_MAPNEW)
!           {
!               if (rettv_dict_alloc(rettv) == FAIL)
!                   return;
!               d_ret = rettv->vval.v_dict;
!           }
! 
!           if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0)
                d->dv_lock = VAR_LOCKED;
            ht = &d->dv_hashtab;
            hash_lock(ht);
***************
*** 2024,2045 ****
            {
                if (!HASHITEM_EMPTY(hi))
                {
!                   int r;
  
                    --todo;
                    di = HI2DI(hi);
!                   if (map && (value_check_lock(di->di_tv.v_lock,
                                                           arg_errmsg, TRUE)
                                || var_check_ro(di->di_flags,
                                                           arg_errmsg, TRUE)))
                        break;
                    set_vim_var_string(VV_KEY, di->di_key, -1);
!                   r = filter_map_one(&di->di_tv, expr, map, &rem);
                    clear_tv(get_vim_var_tv(VV_KEY));
                    if (r == FAIL || did_emsg)
                        break;
!                   if (!map && rem)
                    {
                        if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
                            || var_check_ro(di->di_flags, arg_errmsg, TRUE))
                            break;
--- 2059,2102 ----
            {
                if (!HASHITEM_EMPTY(hi))
                {
!                   int         r;
!                   typval_T    newtv;
  
                    --todo;
                    di = HI2DI(hi);
!                   if (filtermap != FILTERMAP_FILTER
!                                        && (value_check_lock(di->di_tv.v_lock,
                                                           arg_errmsg, TRUE)
                                || var_check_ro(di->di_flags,
                                                           arg_errmsg, TRUE)))
                        break;
                    set_vim_var_string(VV_KEY, di->di_key, -1);
!                   r = filter_map_one(&di->di_tv, expr, filtermap,
!                                                                &newtv, &rem);
                    clear_tv(get_vim_var_tv(VV_KEY));
                    if (r == FAIL || did_emsg)
+                   {
+                       clear_tv(&newtv);
                        break;
!                   }
!                   if (filtermap == FILTERMAP_MAP)
!                   {
!                       // map(): replace the dict item value
!                       clear_tv(&di->di_tv);
!                       newtv.v_lock = 0;
!                       di->di_tv = newtv;
!                   }
!                   else if (filtermap == FILTERMAP_MAPNEW)
!                   {
!                       // mapnew(): add the item value to the new dict
!                       r = dict_add_tv(d_ret, (char *)di->di_key, &newtv);
!                       clear_tv(&newtv);
!                       if (r == FAIL)
!                           break;
!                   }
!                   else if (filtermap == FILTERMAP_FILTER && rem)
                    {
+                       // filter(false): remove the item from the dict
                        if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
                            || var_check_ro(di->di_flags, arg_errmsg, TRUE))
                            break;
***************
*** 2055,2081 ****
            int         i;
            typval_T    tv;
            varnumber_T val;
  
            // set_vim_var_nr() doesn't set the type
            set_vim_var_type(VV_KEY, VAR_NUMBER);
  
            for (i = 0; i < b->bv_ga.ga_len; i++)
            {
                tv.v_type = VAR_NUMBER;
                val = blob_get(b, i);
                tv.vval.v_number = val;
                set_vim_var_nr(VV_KEY, idx);
!               if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg)
                    break;
!               if (tv.v_type != VAR_NUMBER)
                {
                    emsg(_(e_invalblob));
                    break;
                }
!               if (map)
                {
!                   if (tv.vval.v_number != val)
!                       blob_set(b, i, tv.vval.v_number);
                }
                else if (rem)
                {
--- 2112,2150 ----
            int         i;
            typval_T    tv;
            varnumber_T val;
+           blob_T      *b_ret = b;
+ 
+           if (filtermap == FILTERMAP_MAPNEW)
+           {
+               if (blob_copy(b, rettv) == FAIL)
+                   return;
+               b_ret = rettv->vval.v_blob;
+           }
  
            // set_vim_var_nr() doesn't set the type
            set_vim_var_type(VV_KEY, VAR_NUMBER);
  
            for (i = 0; i < b->bv_ga.ga_len; i++)
            {
+               typval_T newtv;
+ 
                tv.v_type = VAR_NUMBER;
                val = blob_get(b, i);
                tv.vval.v_number = val;
                set_vim_var_nr(VV_KEY, idx);
!               if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
!                                                                  || did_emsg)
                    break;
!               if (newtv.v_type != VAR_NUMBER)
                {
+                   clear_tv(&newtv);
                    emsg(_(e_invalblob));
                    break;
                }
!               if (filtermap != FILTERMAP_FILTER)
                {
!                   if (newtv.vval.v_number != val)
!                       blob_set(b_ret, i, newtv.vval.v_number);
                }
                else if (rem)
                {
***************
*** 2091,2114 ****
        }
        else // argvars[0].v_type == VAR_LIST
        {
!           int prev_lock = l->lv_lock;
  
            // set_vim_var_nr() doesn't set the type
            set_vim_var_type(VV_KEY, VAR_NUMBER);
  
            CHECK_LIST_MATERIALIZE(l);
!           if (map && l->lv_lock == 0)
                l->lv_lock = VAR_LOCKED;
            for (li = l->lv_first; li != NULL; li = nli)
            {
!               if (map && value_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
                    break;
                nli = li->li_next;
                set_vim_var_nr(VV_KEY, idx);
!               if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
!                                                                 || did_emsg)
                    break;
!               if (!map && rem)
                    listitem_remove(l, li);
                ++idx;
            }
--- 2160,2206 ----
        }
        else // argvars[0].v_type == VAR_LIST
        {
!           int     prev_lock = l->lv_lock;
!           list_T  *l_ret = NULL;
  
+           if (filtermap == FILTERMAP_MAPNEW)
+           {
+               if (rettv_list_alloc(rettv) == FAIL)
+                   return;
+               l_ret = rettv->vval.v_list;
+           }
            // set_vim_var_nr() doesn't set the type
            set_vim_var_type(VV_KEY, VAR_NUMBER);
  
            CHECK_LIST_MATERIALIZE(l);
!           if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
                l->lv_lock = VAR_LOCKED;
            for (li = l->lv_first; li != NULL; li = nli)
            {
!               typval_T newtv;
! 
!               if (filtermap != FILTERMAP_FILTER
!                      && value_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
                    break;
                nli = li->li_next;
                set_vim_var_nr(VV_KEY, idx);
!               if (filter_map_one(&li->li_tv, expr, filtermap,
!                                            &newtv, &rem) == FAIL || did_emsg)
                    break;
!               if (filtermap == FILTERMAP_MAP)
!               {
!                   // map(): replace the list item value
!                   clear_tv(&li->li_tv);
!                   newtv.v_lock = 0;
!                   li->li_tv = newtv;
!               }
!               else if (filtermap == FILTERMAP_MAPNEW)
!               {
!                   // mapnew(): append the list item value
!                   if (list_append_tv_move(l_ret, &newtv) == FAIL)
!                       break;
!               }
!               else if (filtermap == FILTERMAP_FILTER && rem)
                    listitem_remove(l, li);
                ++idx;
            }
***************
*** 2128,2134 ****
      void
  f_filter(typval_T *argvars, typval_T *rettv)
  {
!     filter_map(argvars, rettv, FALSE);
  }
  
  /*
--- 2220,2226 ----
      void
  f_filter(typval_T *argvars, typval_T *rettv)
  {
!     filter_map(argvars, rettv, FILTERMAP_FILTER);
  }
  
  /*
***************
*** 2137,2143 ****
      void
  f_map(typval_T *argvars, typval_T *rettv)
  {
!     filter_map(argvars, rettv, TRUE);
  }
  
  /*
--- 2229,2244 ----
      void
  f_map(typval_T *argvars, typval_T *rettv)
  {
!     filter_map(argvars, rettv, FILTERMAP_MAP);
! }
! 
! /*
!  * "mapnew()" function
!  */
!     void
! f_mapnew(typval_T *argvars, typval_T *rettv)
! {
!     filter_map(argvars, rettv, FILTERMAP_MAPNEW);
  }
  
  /*
*** ../vim-8.2.1968/src/proto/list.pro  2020-08-15 22:14:49.055890417 +0200
--- src/proto/list.pro  2020-11-09 12:45:56.079722242 +0100
***************
*** 48,53 ****
--- 48,54 ----
  void f_uniq(typval_T *argvars, typval_T *rettv);
  void f_filter(typval_T *argvars, typval_T *rettv);
  void f_map(typval_T *argvars, typval_T *rettv);
+ void f_mapnew(typval_T *argvars, typval_T *rettv);
  void f_add(typval_T *argvars, typval_T *rettv);
  void f_count(typval_T *argvars, typval_T *rettv);
  void f_extend(typval_T *argvars, typval_T *rettv);
*** ../vim-8.2.1968/src/testdir/test_filter_map.vim     2020-10-15 
22:29:13.566726912 +0200
--- src/testdir/test_filter_map.vim     2020-11-09 18:15:15.067132031 +0100
***************
*** 118,121 ****
--- 118,142 ----
    call assert_fails('echo map(d, {k,v -> remove(d, k)})', 'E741:')
  endfunc
  
+ func Test_mapnew_dict()
+   let din = #{one: 1, two: 2}
+   let dout = mapnew(din, {k, v -> string(v)})
+   call assert_equal(#{one: 1, two: 2}, din)
+   call assert_equal(#{one: '1', two: '2'}, dout)
+ endfunc
+ 
+ func Test_mapnew_list()
+   let lin = [1, 2, 3]
+   let lout = mapnew(lin, {k, v -> string(v)})
+   call assert_equal([1, 2, 3], lin)
+   call assert_equal(['1', '2', '3'], lout)
+ endfunc
+ 
+ func Test_mapnew_blob()
+   let bin = 0z123456
+   let bout = mapnew(bin, {k, v -> k == 1 ? 0x99 : v})
+   call assert_equal(0z123456, bin)
+   call assert_equal(0z129956, bout)
+ endfunc
+ 
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.1968/src/version.c       2020-11-08 12:49:43.120372854 +0100
--- src/version.c       2020-11-09 12:19:49.495595596 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     1969,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
221. Your wife melts your keyboard in the oven.

 /// Bram Moolenaar -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202011091732.0A9HWD08296528%40masaka.moolenaar.net.

Raspunde prin e-mail lui