Patch 8.2.4861
Problem:    It is not easy to restore saved mappings.
Solution:   Make mapset() accept a dict argument. (Ernie Rael, closes #10295)
Files:      runtime/doc/builtin.txt, src/errors.h, src/evalfunc.c, src/map.c,
            src/typval.c, src/proto/typval.pro,
            src/testdir/test_map_functions.vim,
            src/testdir/test_vim9_builtin.vim


*** ../vim-8.2.4860/runtime/doc/builtin.txt     2022-05-03 11:01:59.058826963 
+0100
--- runtime/doc/builtin.txt     2022-05-04 15:30:45.712569245 +0100
***************
*** 5291,5296 ****
--- 5310,5316 ----
                  "lnum"     The line number in "sid", zero if unknown.
                  "nowait"   Do not wait for other, longer mappings.
                             (|:map-<nowait>|).
+                 "abbr"     True if this is an |abbreviation|.
  
                The dictionary can be used to restore a mapping with
                |mapset()|.
***************
*** 5361,5369 ****
  
  
  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*
                {mode} is used to define the mode in which the mapping is set,
                not the "mode" entry in {dict}.
                Example for saving and restoring a mapping: >
--- 5381,5398 ----
  
  
  mapset({mode}, {abbr}, {dict})                                        
*mapset()*
! mapset({dict})
!               Restore a mapping from a dictionary, possibly returned by
!               |maparg()| or |maplist()|.  A buffer mapping, when dict.buffer
!               is true, is set on the current buffer; it is up to the caller
!               to insure that the intended buffer is the current buffer. This
!               feature allows copying mappings from one buffer to another.
!               The dict.mode value may restore a single mapping that covers
!               more than one mode, like with mode values of '!', ' ', 'nox',
!               or 'v'. *E1276*
! 
!               In the first form, {mode} and {abbr} should be the same as
!               for the call to |maparg()|. *E460*
                {mode} is used to define the mode in which the mapping is set,
                not the "mode" entry in {dict}.
                Example for saving and restoring a mapping: >
***************
*** 5372,5379 ****
                        ...
                        call mapset('n', 0, save_map)
  <             Note that if you are going to replace a map in several modes,
!               e.g. with `:map!`, you need to save the mapping for all of
!               them, since they can differ.
  
  
  match({expr}, {pat} [, {start} [, {count}]])                  *match()*
--- 5401,5422 ----
                        ...
                        call mapset('n', 0, save_map)
  <             Note that if you are going to replace a map in several modes,
!               e.g. with `:map!`, you need to save/restore the mapping for
!               all of them, when they might differ.
! 
!               In the second form, with {dict} as the only argument, mode
!               and abbr are taken from the dict.
!               Example: >
!                       vim9script
!                       var save_maps = maplist()->filter(
!                                               (_, m) => m.lhs == 'K')
!                       nnoremap K somethingelse
!                       cnoremap K somethingelse2
!                       # ...
!                       unmap K
!                       for d in save_maps
!                           mapset(d)
!                       endfor
  
  
  match({expr}, {pat} [, {start} [, {count}]])                  *match()*
*** ../vim-8.2.4860/src/errors.h        2022-04-17 15:06:31.042622659 +0100
--- src/errors.h        2022-05-04 15:23:24.912707862 +0100
***************
*** 3262,3265 ****
--- 3262,3267 ----
  #ifdef FEAT_EVAL
  EXTERN char e_string_or_function_required_for_arrow_parens_expr[]
        INIT(= N_("E1275: String or function required for ->(expr)"));
+ EXTERN char e_illegal_map_mode_string_str[]
+       INIT(= N_("E1276: Illegal map mode string: '%s'"));
  #endif
*** ../vim-8.2.4860/src/evalfunc.c      2022-04-28 17:52:19.532130311 +0100
--- src/evalfunc.c      2022-05-04 15:33:30.232502013 +0100
***************
*** 422,427 ****
--- 422,442 ----
  }
  
  /*
+  * Check "type" is a string or a dict of 'any'
+  */
+     static int
+ arg_string_or_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T 
*context)
+ {
+     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_DICT)
+       return OK;
+     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
+     return FAIL;
+ }
+ 
+ /*
   * Check "type" is a string or a blob
   */
      static int
***************
*** 998,1005 ****
  static argcheck_T arg3_string_any_dict[] = {arg_string, NULL, arg_dict_any};
  static argcheck_T arg3_string_any_string[] = {arg_string, NULL, arg_string};
  static argcheck_T arg3_string_bool_bool[] = {arg_string, arg_bool, arg_bool};
- static argcheck_T arg3_string_bool_dict[] = {arg_string, arg_bool, 
arg_dict_any};
  static argcheck_T arg3_string_number_bool[] = {arg_string, arg_number, 
arg_bool};
  static argcheck_T arg3_string_string_bool[] = {arg_string, arg_string, 
arg_bool};
  static argcheck_T arg3_string_string_dict[] = {arg_string, arg_string, 
arg_dict_any};
  static argcheck_T arg3_string_string_number[] = {arg_string, arg_string, 
arg_number};
--- 1013,1020 ----
  static argcheck_T arg3_string_any_dict[] = {arg_string, NULL, arg_dict_any};
  static argcheck_T arg3_string_any_string[] = {arg_string, NULL, arg_string};
  static argcheck_T arg3_string_bool_bool[] = {arg_string, arg_bool, arg_bool};
  static argcheck_T arg3_string_number_bool[] = {arg_string, arg_number, 
arg_bool};
+ static argcheck_T arg3_string_or_dict_bool_dict[] = {arg_string_or_dict_any, 
arg_bool, arg_dict_any};
  static argcheck_T arg3_string_string_bool[] = {arg_string, arg_string, 
arg_bool};
  static argcheck_T arg3_string_string_dict[] = {arg_string, arg_string, 
arg_dict_any};
  static argcheck_T arg3_string_string_number[] = {arg_string, arg_string, 
arg_number};
***************
*** 2053,2059 ****
                        ret_list_dict_any,  f_maplist},
      {"mapnew",                2, 2, FEARG_1,      arg2_mapnew,
                        ret_first_cont,     f_mapnew},
!     {"mapset",                3, 3, FEARG_1,      arg3_string_bool_dict,
                        ret_void,           f_mapset},
      {"match",         2, 4, FEARG_1,      arg24_match_func,
                        ret_any,            f_match},
--- 2068,2074 ----
                        ret_list_dict_any,  f_maplist},
      {"mapnew",                2, 2, FEARG_1,      arg2_mapnew,
                        ret_first_cont,     f_mapnew},
!     {"mapset",                1, 3, FEARG_1,      
arg3_string_or_dict_bool_dict,
                        ret_void,           f_mapset},
      {"match",         2, 4, FEARG_1,      arg24_match_func,
                        ret_any,            f_match},
*** ../vim-8.2.4860/src/map.c   2022-04-26 21:36:14.402164072 +0100
--- src/map.c   2022-05-04 15:36:18.096428302 +0100
***************
*** 2283,2289 ****
        mapblock_T  *mp,
        dict_T      *dict,
        char_u      *lhsrawalt,     // may be NULL
!       int         buffer_local)   // false if not buffer local mapping
  {
      char_u        *lhs = str2special_save(mp->m_keys, TRUE);
      char_u        *mapmode = map_mode_to_chars(mp->m_mode);
--- 2283,2290 ----
        mapblock_T  *mp,
        dict_T      *dict,
        char_u      *lhsrawalt,     // may be NULL
!       int         buffer_local,   // false if not buffer local mapping
!       int         abbr)           // true if abbreviation
  {
      char_u        *lhs = str2special_save(mp->m_keys, TRUE);
      char_u        *mapmode = map_mode_to_chars(mp->m_mode);
***************
*** 2307,2312 ****
--- 2308,2314 ----
      dict_add_number(dict, "buffer", (long)buffer_local);
      dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
      dict_add_string(dict, "mode", mapmode);
+     dict_add_number(dict, "abbr", abbr ? 1L : 0L);
  
      vim_free(mapmode);
  }
***************
*** 2381,2387 ****
      }
      else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
        mapblock2dict(mp, rettv->vval.v_dict,
!                         did_simplify ? keys_simplified : NULL, buffer_local);
  
      vim_free(keys_buf);
      vim_free(alt_keys_buf);
--- 2383,2390 ----
      }
      else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
        mapblock2dict(mp, rettv->vval.v_dict,
!                         did_simplify ? keys_simplified : NULL,
!                         buffer_local, abbr);
  
      vim_free(keys_buf);
      vim_free(alt_keys_buf);
***************
*** 2448,2454 ****
                vim_free(lhs);
  
                mapblock2dict(mp, d,
!                                did_simplify ? keys_buf : NULL, buffer_local);
                vim_free(keys_buf);
            }
        }
--- 2451,2458 ----
                vim_free(lhs);
  
                mapblock2dict(mp, d,
!                                did_simplify ? keys_buf : NULL,
!                                buffer_local, abbr);
                vim_free(keys_buf);
            }
        }
***************
*** 2490,2495 ****
--- 2494,2549 ----
  }
  
  /*
+  * Get the mapping mode from the mode string.
+  * It may contain multiple characters, eg "nox", or "!", or ' '
+  * Return 0 if there is an error.
+  */
+     static int
+ get_map_mode_string(char_u *mode_string, int abbr)
+ {
+     char_u    *p = mode_string;
+     int               mode = 0;
+     int               tmode;
+     int               modec;
+     const int MASK_V = VISUAL + SELECTMODE;
+     const int MASK_MAP = VISUAL + SELECTMODE + NORMAL + OP_PENDING;
+     const int MASK_BANG = INSERT + CMDLINE;
+ 
+     if (*p == NUL)
+       p = (char_u *)" ";      // compatibility
+     while ((modec = *p++))
+     {
+       switch (modec)
+       {
+           case 'i': tmode = INSERT;           break;
+           case 'l': tmode = LANGMAP;          break;
+           case 'c': tmode = CMDLINE;          break;
+           case 'n': tmode = NORMAL;           break;
+           case 'x': tmode = VISUAL;           break;
+           case 's': tmode = SELECTMODE;       break;
+           case 'o': tmode = OP_PENDING;       break;
+           case 't': tmode = TERMINAL;         break;
+           case 'v': tmode = MASK_V;           break;
+           case '!': tmode = MASK_BANG;        break;
+           case ' ': tmode = MASK_MAP;         break;
+           default:
+                     return 0; // error, unknown mode character
+       }
+       mode |= tmode;
+     }
+     if ((abbr && (mode & ~MASK_BANG) != 0)
+       || (!abbr && (mode & (mode-1)) != 0 // more than one bit set
+           && (
+               // false if multiple bits set in mode and mode is fully
+               // contained in one mask
+               !(((mode & MASK_BANG) != 0 && (mode & ~MASK_BANG) == 0)
+                   || ((mode & MASK_MAP) != 0 && (mode & ~MASK_MAP) == 0)))))
+       return 0;
+ 
+     return mode;
+ }
+ 
+ /*
   * "mapset()" function
   */
      void
***************
*** 2518,2542 ****
      mapblock_T  **abbr_table = &first_abbr;
      int               nowait;
      char_u    *arg;
  
      if (in_vim9script()
!           && (check_for_string_arg(argvars, 0) == FAIL
!               || check_for_bool_arg(argvars, 1) == FAIL
!               || check_for_dict_arg(argvars, 2) == FAIL))
        return;
  
!     which = tv_get_string_buf_chk(&argvars[0], buf);
!     if (which == NULL)
!       return;
!     mode = get_map_mode(&which, 0);
!     is_abbr = (int)tv_get_bool(&argvars[1]);
  
!     if (argvars[2].v_type != VAR_DICT)
      {
!       emsg(_(e_key_not_present_in_dictionary));
        return;
      }
!     d = argvars[2].vval.v_dict;
  
      // Get the values in the same order as above in get_maparg().
      lhs = dict_get_string(d, (char_u *)"lhs", FALSE);
--- 2572,2622 ----
      mapblock_T  **abbr_table = &first_abbr;
      int               nowait;
      char_u    *arg;
+     int               dict_only;
  
+     // If first arg is a dict, then that's the only arg permitted.
+     dict_only = argvars[0].v_type == VAR_DICT;
      if (in_vim9script()
!           && (check_for_string_or_dict_arg(argvars, 0) == FAIL
!               || (dict_only && check_for_unknown_arg(argvars, 1) == FAIL)
!               || (!dict_only
!                   && (check_for_string_arg(argvars, 0) == FAIL
!                       || check_for_bool_arg(argvars, 1) == FAIL
!                       || check_for_dict_arg(argvars, 2) == FAIL))))
        return;
  
!     if (dict_only)
!     {
!       d = argvars[0].vval.v_dict;
!       which = dict_get_string(d, (char_u *)"mode", FALSE);
!       is_abbr = dict_get_bool(d, (char_u *)"abbr", -1);
!       if (which == NULL || is_abbr < 0)
!       {
!           emsg(_(e_entries_missing_in_mapset_dict_argument));
!           return;
!       }
!     }
!     else
!     {
!       which = tv_get_string_buf_chk(&argvars[0], buf);
!       if (which == NULL)
!           return;
!       is_abbr = (int)tv_get_bool(&argvars[1]);
  
!       if (argvars[2].v_type != VAR_DICT)
!       {
!           emsg(_(e_dictionary_required));
!           return;
!       }
!       d = argvars[2].vval.v_dict;
!     }
!     mode = get_map_mode_string(which, is_abbr);
!     if (mode == 0)
      {
!       semsg(_(e_illegal_map_mode_string_str), which);
        return;
      }
! 
  
      // Get the values in the same order as above in get_maparg().
      lhs = dict_get_string(d, (char_u *)"lhs", FALSE);
*** ../vim-8.2.4860/src/typval.c        2022-05-02 22:53:41.384211031 +0100
--- src/typval.c        2022-05-04 15:23:24.916707862 +0100
***************
*** 360,365 ****
--- 360,379 ----
  #endif
  
  /*
+  * Give an error and return FAIL unless "args[idx]" is unknown
+  */
+     int
+ check_for_unknown_arg(typval_T *args, int idx)
+ {
+     if (args[idx].v_type != VAR_UNKNOWN)
+     {
+       semsg(_(e_too_many_arguments), idx + 1);
+       return FAIL;
+     }
+     return OK;
+ }
+ 
+ /*
   * Give an error and return FAIL unless "args[idx]" is a string.
   */
      int
*** ../vim-8.2.4860/src/proto/typval.pro        2022-03-01 19:23:20.544357315 
+0000
--- src/proto/typval.pro        2022-05-04 15:23:24.916707862 +0100
***************
*** 9,14 ****
--- 9,15 ----
  varnumber_T tv_get_bool(typval_T *varp);
  varnumber_T tv_get_bool_chk(typval_T *varp, int *denote);
  float_T tv_get_float(typval_T *varp);
+ int check_for_unknown_arg(typval_T *args, int idx);
  int check_for_string_arg(typval_T *args, int idx);
  int check_for_nonempty_string_arg(typval_T *args, int idx);
  int check_for_opt_string_arg(typval_T *args, int idx);
*** ../vim-8.2.4860/src/testdir/test_map_functions.vim  2022-04-26 
21:36:14.402164072 +0100
--- src/testdir/test_map_functions.vim  2022-05-04 15:23:24.916707862 +0100
***************
*** 19,31 ****
          \ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16",
          \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 1, 
!       \ 'rhs': 'is<F4>foo', 'buffer': 0},
        \ maparg('foo<C-V>', '', 0, 1))
    call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar',
          \ 'lhsraw': 'bar', 'mode': 'v',
          \ 'nowait': 0, 'expr': 1, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 2,
!       \ 'rhs': 'isbar', 'buffer': 1},
          \ 'bar'->maparg('', 0, 1))
    let lnum = expand('<sflnum>')
    map <buffer> <nowait> foo bar
--- 19,31 ----
          \ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16",
          \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 1, 
!       \ 'rhs': 'is<F4>foo', 'buffer': 0, 'abbr': 0},
        \ maparg('foo<C-V>', '', 0, 1))
    call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar',
          \ 'lhsraw': 'bar', 'mode': 'v',
          \ 'nowait': 0, 'expr': 1, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 2,
!       \ 'rhs': 'isbar', 'buffer': 1, 'abbr': 0},
          \ 'bar'->maparg('', 0, 1))
    let lnum = expand('<sflnum>')
    map <buffer> <nowait> foo bar
***************
*** 33,39 ****
          \ 'lhsraw': 'foo', 'mode': ' ',
          \ 'nowait': 1, 'expr': 0, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 1, 'rhs': 'bar',
!       \ 'buffer': 1},
          \ maparg('foo', '', 0, 1))
    let lnum = expand('<sflnum>')
    tmap baz foo
--- 33,39 ----
          \ 'lhsraw': 'foo', 'mode': ' ',
          \ 'nowait': 1, 'expr': 0, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 1, 'rhs': 'bar',
!       \ 'buffer': 1, 'abbr': 0},
          \ maparg('foo', '', 0, 1))
    let lnum = expand('<sflnum>')
    tmap baz foo
***************
*** 41,48 ****
          \ 'lhsraw': 'baz', 'mode': 't',
          \ 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 1, 'rhs': 'foo',
!       \ 'buffer': 0},
          \ maparg('baz', 't', 0, 1))
  
    map abc x<char-114>x
    call assert_equal("xrx", maparg('abc'))
--- 41,57 ----
          \ 'lhsraw': 'baz', 'mode': 't',
          \ 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
          \ 'lnum': lnum + 1, 'rhs': 'foo',
!       \ 'buffer': 0, 'abbr': 0},
          \ maparg('baz', 't', 0, 1))
+   let lnum = expand('<sflnum>')
+   iab A B
+   call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'A',
+         \ 'lhsraw': 'A', 'mode': 'i',
+         \ 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1,
+         \ 'lnum': lnum + 1, 'rhs': 'B',
+       \ 'buffer': 0, 'abbr': 1},
+         \ maparg('A', 'i', 1, 1))
+   iuna A
  
    map abc x<char-114>x
    call assert_equal("xrx", maparg('abc'))
***************
*** 250,259 ****
    bwipe!
  
    call assert_fails('call mapset([], v:false, {})', 'E730:')
!   call assert_fails('call mapset("i", 0, "")', 'E716:')
    call assert_fails('call mapset("i", 0, {})', 'E460:')
  endfunc
  
  func Check_ctrlb_map(d, check_alt)
    call assert_equal('<C-B>', a:d.lhs)
    if a:check_alt
--- 259,414 ----
    bwipe!
  
    call assert_fails('call mapset([], v:false, {})', 'E730:')
!   call assert_fails('call mapset("i", 0, "")', 'E715:')
    call assert_fails('call mapset("i", 0, {})', 'E460:')
  endfunc
  
+ def Test_mapset_arg1_dir()
+   # This test is mostly about get_map_mode_string.
+   # Once the code gets past that, it's common with the 3 arg mapset.
+ 
+   # GetModes() return list of modes for 'XZ' lhs using maplist.
+   # There is one list item per mapping
+   def GetModes(abbr: bool = false): list<string>
+     return maplist(abbr)->filter((_, m) => m.lhs == 'XZ')
+                 ->mapnew((_, m) => m.mode)
+   enddef
+ 
+   const unmap_cmds = [ 'unmap', 'unmap!', 'tunmap', 'lunmap' ]
+   def UnmapAll(lhs: string)
+     for cmd in unmap_cmds
+       try | execute(cmd .. ' ' .. lhs) | catch /E31/ | endtry
+     endfor
+   enddef
+ 
+   var tmap: dict<any>
+ 
+   # some mapset(mode, abbr, dict) tests using get_map_mode_str
+   map XZ x
+   tmap = maplist()->filter((_, m) => m.lhs == 'XZ')[0]->copy()
+   # this splits the mapping into 2 mappings
+   mapset('ox', false, tmap)
+   assert_equal(2, len(GetModes()))
+   mapset('o', false, tmap)
+   assert_equal(3, len(GetModes()))
+   # test that '' acts like ' ', and that the 3 mappings become 1
+   mapset('', false, tmap)
+   assert_equal([' '], GetModes())
+   # dict's mode/abbr are ignored
+   UnmapAll('XZ')
+   tmap.mode = '!'
+   tmap.abbr = true
+   mapset('o', false, tmap)
+   assert_equal(['o'], GetModes())
+ 
+   # test the 3 arg version handles bad mode string, dict not used
+   assert_fails("mapset('vi', false, {})", 'E1276:')
+ 
+ 
+   # get the abbreviations out of the way
+   abbreviate XZ ZX
+   tmap = maplist(true)->filter((_, m) => m.lhs == 'XZ')[0]->copy()
+ 
+   abclear
+   # 'ic' is the default ab command, shows up as '!'
+   tmap.mode = 'ic'
+   mapset(tmap)
+   assert_equal(['!'], GetModes(true))
+ 
+   abclear
+   tmap.mode = 'i'
+   mapset(tmap)
+   assert_equal(['i'], GetModes(true))
+ 
+   abclear
+   tmap.mode = 'c'
+   mapset(tmap)
+   assert_equal(['c'], GetModes(true))
+ 
+   abclear
+   tmap.mode = '!'
+   mapset(tmap)
+   assert_equal(['!'], GetModes(true))
+ 
+   assert_fails("mapset({mode: ' !', abbr: 1})", 'E1276:')
+   assert_fails("mapset({mode: 'cl', abbr: 1})", 'E1276:')
+   assert_fails("mapset({mode: 'in', abbr: 1})", 'E1276:')
+ 
+   # the map commands
+   map XZ x
+   tmap = maplist()->filter((_, m) => m.lhs == 'XZ')[0]->copy()
+ 
+   # try the combos
+   UnmapAll('XZ')
+   # 'nxso' is ' ', the unadorned :map
+   tmap.mode = 'nxso'
+   mapset(tmap)
+   assert_equal([' '], GetModes())
+ 
+   UnmapAll('XZ')
+   # 'ic' is '!'
+   tmap.mode = 'ic'
+   mapset(tmap)
+   assert_equal(['!'], GetModes())
+ 
+   UnmapAll('XZ')
+   # 'xs' is really 'v'
+   tmap.mode = 'xs'
+   mapset(tmap)
+   assert_equal(['v'], GetModes())
+ 
+   # try the individual modes
+   UnmapAll('XZ')
+   tmap.mode = 'n'
+   mapset(tmap)
+   assert_equal(['n'], GetModes())
+ 
+   UnmapAll('XZ')
+   tmap.mode = 'x'
+   mapset(tmap)
+   assert_equal(['x'], GetModes())
+ 
+   UnmapAll('XZ')
+   tmap.mode = 's'
+   mapset(tmap)
+   assert_equal(['s'], GetModes())
+ 
+   UnmapAll('XZ')
+   tmap.mode = 'o'
+   mapset(tmap)
+   assert_equal(['o'], GetModes())
+ 
+   UnmapAll('XZ')
+   tmap.mode = 'i'
+   mapset(tmap)
+   assert_equal(['i'], GetModes())
+ 
+   UnmapAll('XZ')
+   tmap.mode = 'c'
+   mapset(tmap)
+   assert_equal(['c'], GetModes())
+ 
+   UnmapAll('XZ')
+   tmap.mode = 't'
+   mapset(tmap)
+   assert_equal(['t'], GetModes())
+ 
+   UnmapAll('XZ')
+   tmap.mode = 'l'
+   mapset(tmap)
+   assert_equal(['l'], GetModes())
+ 
+   UnmapAll('XZ')
+ 
+   # get errors for modes that can't be in one mapping
+   assert_fails("mapset({mode: 'nxsoi', abbr: 0})", 'E1276:')
+   assert_fails("mapset({mode: ' !', abbr: 0})", 'E1276:')
+   assert_fails("mapset({mode: 'ix', abbr: 0})", 'E1276:')
+   assert_fails("mapset({mode: 'tl', abbr: 0})", 'E1276:')
+   assert_fails("mapset({mode: ' l', abbr: 0})", 'E1276:')
+   assert_fails("mapset({mode: ' t', abbr: 0})", 'E1276:')
+ enddef
+ 
  func Check_ctrlb_map(d, check_alt)
    call assert_equal('<C-B>', a:d.lhs)
    if a:check_alt
*** ../vim-8.2.4860/src/testdir/test_vim9_builtin.vim   2022-04-23 
10:50:18.971609285 +0100
--- src/testdir/test_vim9_builtin.vim   2022-05-04 15:23:24.916707862 +0100
***************
*** 2463,2469 ****
          sid: SID(),
          scriptversion: 999999,
          rhs: 'bar',
!         buffer: 0})
    unmap foo
    v9.CheckDefAndScriptFailure(['maparg(1)'], ['E1013: Argument 1: type 
mismatch, expected string but got number', 'E1174: String required for argument 
1'])
    v9.CheckDefAndScriptFailure(['maparg("a", 2)'], ['E1013: Argument 2: type 
mismatch, expected string but got number', 'E1174: String required for argument 
2'])
--- 2463,2470 ----
          sid: SID(),
          scriptversion: 999999,
          rhs: 'bar',
!         buffer: 0,
!         abbr: 0})
    unmap foo
    v9.CheckDefAndScriptFailure(['maparg(1)'], ['E1013: Argument 1: type 
mismatch, expected string but got number', 'E1174: String required for argument 
1'])
    v9.CheckDefAndScriptFailure(['maparg("a", 2)'], ['E1013: Argument 2: type 
mismatch, expected string but got number', 'E1174: String required for argument 
2'])
***************
*** 2545,2551 ****
  enddef
  
  def Test_mapset()
!   v9.CheckDefAndScriptFailure(['mapset(1, true, {})'], ['E1013: Argument 1: 
type mismatch, expected string but got number', 'E1174: String required for 
argument 1'])
    v9.CheckDefAndScriptFailure(['mapset("a", 2, {})'], ['E1013: Argument 2: 
type mismatch, expected bool but got number', 'E1212: Bool required for 
argument 2'])
    v9.CheckDefAndScriptFailure(['mapset("a", false, [])'], ['E1013: Argument 
3: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary 
required for argument 3'])
  enddef
--- 2546,2552 ----
  enddef
  
  def Test_mapset()
!   v9.CheckDefAndScriptFailure(['mapset(1, true, {})'], ['E1013: Argument 1: 
type mismatch, expected string but got number', 'E1223: String or Dictionary 
required for argument 1'])
    v9.CheckDefAndScriptFailure(['mapset("a", 2, {})'], ['E1013: Argument 2: 
type mismatch, expected bool but got number', 'E1212: Bool required for 
argument 2'])
    v9.CheckDefAndScriptFailure(['mapset("a", false, [])'], ['E1013: Argument 
3: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary 
required for argument 3'])
  enddef
*** ../vim-8.2.4860/src/version.c       2022-05-03 11:01:59.062826957 +0100
--- src/version.c       2022-05-04 15:38:48.612358985 +0100
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     4861,
  /**/

-- 
I AM THANKFUL...
...for the piles of laundry and ironing because it means I
have plenty of clothes to wear.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            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/20220504144059.32BDB1C19BB%40moolenaar.net.

Raspunde prin e-mail lui