Patch 8.2.0807
Problem:    Cannot easily restore a mapping.
Solution:   Add mapset().
Files:      runtime/doc/eval.txt, src/map.c, src/proto/map.pro, src/evalfunc.c
            src/testdir/test_maparg.vim


*** ../vim-8.2.0806/runtime/doc/eval.txt        2020-05-13 16:34:10.397723799 
+0200
--- runtime/doc/eval.txt        2020-05-22 12:52:07.920142788 +0200
***************
*** 2582,2587 ****
--- 2586,2593 ----
                                        rhs of mapping {name} in mode {mode}
  mapcheck({name} [, {mode} [, {abbr}]])
                                String  check for mappings matching {name}
+ mapset({name}, {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}]]])
***************
*** 6785,6790 ****
--- 6797,6803 ----
                Can also be used as a |method|: >
                        mylist->map(expr2)
  
+ 
  maparg({name} [, {mode} [, {abbr} [, {dict}]]])                       
*maparg()*
                When {dict} is omitted or zero: Return the rhs of mapping
                {name} in mode {mode}.  The returned String has special
***************
*** 6835,6840 ****
--- 6848,6857 ----
                  "lnum"     The line number in "sid", zero if unknown.
                  "nowait"   Do not wait for other, longer mappings.
                             (|:map-<nowait>|).
+                 "simplified"
+ 
+               The dictionary can be used to restore a mapping with
+               |mapset()|.
  
                The mappings local to the current buffer are checked first,
                then the global mappings.
***************
*** 6881,6886 ****
--- 6898,6915 ----
                Can also be used as a |method|: >
                        GetKey()->mapcheck('n')
  
+ mapset({mode}, {abbr}, {dict})                                *mapset()*
+               Restore a mapping from a dictionary returned by |maparg()|.
+               {name}, {mode} and {abbr} should be the same as for the call
+               to |maparg()|.
+               {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: >
+                       let save_map = maparg('K', 'n', 0, 1)
+                       nnoremap K somethingelse
+                       ...
+                       call mapset('n', 0, save_map)
+ <
  match({expr}, {pat} [, {start} [, {count}]])                  *match()*
                When {expr} is a |List| then this returns the index of the
                first item where {pat} matches.  Each item is used as a
***************
*** 7200,7210 ****
                Returns an empty dictionary if the menu item is not found.
  
                Examples: >
!                       :echo maparg('Edit.Cut')
!                       :echo maparg('File.Save', 'n')
  <
                Can also be used as a |method|: >
!                       GetMenuName()->maparg('v')
  
  
  <                                                     *min()*
--- 7233,7243 ----
                Returns an empty dictionary if the menu item is not found.
  
                Examples: >
!                       :echo menu_info('Edit.Cut')
!                       :echo menu_info('File.Save', 'n')
  <
                Can also be used as a |method|: >
!                       GetMenuName()->menu_info('v')
  
  
  <                                                     *min()*
***************
*** 7757,7763 ****
                        GetExpr()->range()
  <
  
! rand([{expr}])                                                *rand()*
                Return a pseudo-random Number generated with an xoshiro128**
                algorithm using seed {expr}.  The returned number is 32 bits,
                also on 64 bits systems, for consistency.
--- 7790,7796 ----
                        GetExpr()->range()
  <
  
! rand([{expr}])                                                *rand()* 
*random*
                Return a pseudo-random Number generated with an xoshiro128**
                algorithm using seed {expr}.  The returned number is 32 bits,
                also on 64 bits systems, for consistency.
*** ../vim-8.2.0806/src/map.c   2020-04-30 22:29:36.626024141 +0200
--- src/map.c   2020-05-22 13:01:00.430155164 +0200
***************
*** 204,209 ****
--- 204,289 ----
      out_flush();                      // show one line at a time
  }
  
+     static int
+ map_add(
+       mapblock_T  **map_table,
+       mapblock_T  **abbr_table,
+       char_u      *keys,
+       char_u      *rhs,
+       char_u      *orig_rhs,
+       int         expr,
+       int         noremap,
+       int         nowait,
+       int         silent,
+       int         mode,
+       int         is_abbr,
+ #ifdef FEAT_EVAL
+       scid_T      sid,            // -1 to use current_sctx
+       linenr_T    lnum,
+ #endif
+       int         simplified)
+ {
+     mapblock_T        *mp = ALLOC_ONE(mapblock_T);
+ 
+     if (mp == NULL)
+       return FAIL;
+ 
+     // If CTRL-C has been mapped, don't always use it for Interrupting.
+     if (*keys == Ctrl_C)
+     {
+       if (map_table == curbuf->b_maphash)
+           curbuf->b_mapped_ctrl_c |= mode;
+       else
+           mapped_ctrl_c |= mode;
+     }
+ 
+     mp->m_keys = vim_strsave(keys);
+     mp->m_str = vim_strsave(rhs);
+     mp->m_orig_str = vim_strsave(orig_rhs);
+     if (mp->m_keys == NULL || mp->m_str == NULL)
+     {
+       vim_free(mp->m_keys);
+       vim_free(mp->m_str);
+       vim_free(mp->m_orig_str);
+       vim_free(mp);
+       return FAIL;
+     }
+     mp->m_keylen = (int)STRLEN(mp->m_keys);
+     mp->m_noremap = noremap;
+     mp->m_nowait = nowait;
+     mp->m_silent = silent;
+     mp->m_mode = mode;
+     mp->m_simplified = simplified;
+ #ifdef FEAT_EVAL
+     mp->m_expr = expr;
+     if (sid >= 0)
+     {
+       mp->m_script_ctx.sc_sid = sid;
+       mp->m_script_ctx.sc_lnum = lnum;
+     }
+     else
+     {
+       mp->m_script_ctx = current_sctx;
+       mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
+     }
+ #endif
+ 
+     // add the new entry in front of the abbrlist or maphash[] list
+     if (is_abbr)
+     {
+       mp->m_next = *abbr_table;
+       *abbr_table = mp;
+     }
+     else
+     {
+       int n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ 
+       mp->m_next = map_table[n];
+       map_table[n] = mp;
+     }
+     return OK;
+ }
+ 
  /*
   * map[!]                 : show all key mappings
   * map[!] {lhs}                   : show key mapping for {lhs}
***************
*** 501,507 ****
            msg_start();
  
        // Check if a new local mapping wasn't already defined globally.
!       if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
        {
            // need to loop over all global hash lists
            for (hash = 0; hash < 256 && !got_int; ++hash)
--- 581,588 ----
            msg_start();
  
        // Check if a new local mapping wasn't already defined globally.
!       if (unique && map_table == curbuf->b_maphash
!                                          && haskey && hasarg && maptype != 1)
        {
            // need to loop over all global hash lists
            for (hash = 0; hash < 256 && !got_int; ++hash)
***************
*** 519,525 ****
                    // check entries with the same mode
                    if ((mp->m_mode & mode) != 0
                            && mp->m_keylen == len
-                           && unique
                            && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
                    {
                        if (abbrev)
--- 600,605 ----
***************
*** 759,815 ****
            continue;   // have added the new entry already
  
        // Get here when adding a new entry to the maphash[] list or abbrlist.
!       mp = ALLOC_ONE(mapblock_T);
!       if (mp == NULL)
!       {
!           retval = 4;     // no mem
!           goto theend;
!       }
! 
!       // If CTRL-C has been mapped, don't always use it for Interrupting.
!       if (*keys == Ctrl_C)
!       {
!           if (map_table == curbuf->b_maphash)
!               curbuf->b_mapped_ctrl_c |= mode;
!           else
!               mapped_ctrl_c |= mode;
!       }
! 
!       mp->m_keys = vim_strsave(keys);
!       mp->m_str = vim_strsave(rhs);
!       mp->m_orig_str = vim_strsave(orig_rhs);
!       if (mp->m_keys == NULL || mp->m_str == NULL)
!       {
!           vim_free(mp->m_keys);
!           vim_free(mp->m_str);
!           vim_free(mp->m_orig_str);
!           vim_free(mp);
!           retval = 4; // no mem
!           goto theend;
!       }
!       mp->m_keylen = (int)STRLEN(mp->m_keys);
!       mp->m_noremap = noremap;
!       mp->m_nowait = nowait;
!       mp->m_silent = silent;
!       mp->m_mode = mode;
!       mp->m_simplified = did_simplify && keyround == 1;
  #ifdef FEAT_EVAL
!       mp->m_expr = expr;
!       mp->m_script_ctx = current_sctx;
!       mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
  #endif
! 
!       // add the new entry in front of the abbrlist or maphash[] list
!       if (abbrev)
!       {
!           mp->m_next = *abbr_table;
!           *abbr_table = mp;
!       }
!       else
        {
!           n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
!           mp->m_next = map_table[n];
!           map_table[n] = mp;
        }
      }
  
--- 839,854 ----
            continue;   // have added the new entry already
  
        // Get here when adding a new entry to the maphash[] list or abbrlist.
!       if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, expr,
!                   noremap, nowait, silent, mode,
!                   abbrev,
  #ifdef FEAT_EVAL
!                   /* sid */ -1, /* lnum */ 0,
  #endif
!                   did_simplify && keyround == 1) == FAIL)
        {
!           retval = 4;     // no mem
!           goto theend;
        }
      }
  
***************
*** 2209,2221 ****
--- 2248,2343 ----
        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, "simplified", mp->m_simplified);
  
        vim_free(lhs);
        vim_free(mapmode);
      }
  }
+ 
+ /*
+  * "mapset()" function
+  */
+     void
+ f_mapset(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+     char_u    *keys;
+     char_u    *keys_buf = NULL;
+     char_u    *which;
+     int               mode;
+     char_u    buf[NUMBUFLEN];
+     int               is_abbr;
+     dict_T    *d;
+     char_u    *lhs;
+     char_u    *rhs;
+     int               noremap;
+     int               expr;
+     int               silent;
+     scid_T    sid;
+     linenr_T  lnum;
+     mapblock_T        **map_table = maphash;
+     mapblock_T  **abbr_table = &first_abbr;
+     int               nowait;
+     int               simplified;
+     char_u    *arg;
+ 
+     which = tv_get_string_buf_chk(&argvars[0], buf);
+     mode = get_map_mode(&which, 0);
+     is_abbr = (int)tv_get_number(&argvars[1]);
+ 
+     if (argvars[2].v_type != VAR_DICT)
+     {
+       emsg(_(e_dictkey));
+       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);
+     if (lhs == NULL)
+     {
+       emsg(_("E99: lhs entry missing in mapset() dict argument"));
+       return;
+     }
+     rhs = dict_get_string(d, (char_u *)"rhs", FALSE);
+     if (rhs == NULL)
+     {
+       emsg(_("E99: rhs entry missing in mapset() dict argument"));
+       return;
+     }
+ 
+     noremap = dict_get_number(d, (char_u *)"noremap") ? REMAP_NONE: 0;
+     if (dict_get_number(d, (char_u *)"script") != 0)
+       noremap = REMAP_SCRIPT;
+     expr = dict_get_number(d, (char_u *)"expr") != 0;
+     silent = dict_get_number(d, (char_u *)"silent") != 0;
+     sid = dict_get_number(d, (char_u *)"sid");
+     lnum = dict_get_number(d, (char_u *)"lnum");
+     if (dict_get_number(d, (char_u *)"buffer"))
+     {
+       map_table = curbuf->b_maphash;
+       abbr_table = &curbuf->b_first_abbr;
+     }
+     nowait = dict_get_number(d, (char_u *)"nowait") != 0;
+     // mode from the dict is not used
+     simplified = dict_get_number(d, (char_u *)"simplified") != 0;
+ 
+     // Delete any existing mapping for this lhs and mode.
+     arg = vim_strsave(lhs);
+     if (arg == NULL)
+       return;
+     do_map(1, arg, mode, is_abbr);
+     vim_free(arg);
+ 
+     keys = replace_termcodes(lhs, &keys_buf,
+                                     REPTERM_FROM_PART | REPTERM_DO_LT, NULL);
+     (void)map_add(map_table, abbr_table, keys, rhs, rhs, expr,
+               noremap, nowait, silent, mode, is_abbr, sid, lnum, simplified);
+     vim_free(keys_buf);
+ }
  #endif
  
+ 
  #if defined(MSWIN) || defined(MACOS_X)
  
  # define VIS_SEL      (VISUAL+SELECTMODE)     // abbreviation
*** ../vim-8.2.0806/src/proto/map.pro   2019-12-12 12:55:26.000000000 +0100
--- src/proto/map.pro   2020-05-21 22:21:13.598255655 +0200
***************
*** 18,23 ****
--- 18,24 ----
  void check_map_keycodes(void);
  char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, 
mapblock_T **mp_ptr, int *local_ptr);
  void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
+ void f_mapset(typval_T *argvars, typval_T *rettv);
  void init_mappings(void);
  void add_map(char_u *map, int mode);
  int langmap_adjust_mb(int c);
*** ../vim-8.2.0806/src/evalfunc.c      2020-05-14 22:41:10.229637563 +0200
--- src/evalfunc.c      2020-05-21 23:29:43.048018776 +0200
***************
*** 664,669 ****
--- 664,670 ----
      {"map",           2, 2, FEARG_1,    ret_any,      f_map},
      {"maparg",                1, 4, FEARG_1,    ret_string,   f_maparg},
      {"mapcheck",      1, 3, FEARG_1,    ret_string,   f_mapcheck},
+     {"mapset",                3, 3, FEARG_1,    ret_void,     f_mapset},
      {"match",         2, 4, FEARG_1,    ret_any,      f_match},
      {"matchadd",      2, 5, FEARG_1,    ret_number,   f_matchadd},
      {"matchaddpos",   2, 5, FEARG_1,    ret_number,   f_matchaddpos},
*** ../vim-8.2.0806/src/testdir/test_maparg.vim 2020-04-01 19:22:06.522507242 
+0200
--- src/testdir/test_maparg.vim 2020-05-22 13:04:04.637486342 +0200
***************
*** 1,12 ****
! " Tests for maparg().
  " Also test utf8 map with a 0x80 byte.
  " Also test mapcheck()
  
! function s:SID()     
    return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
! endfun
  
! function Test_maparg()
    new
    set cpo-=<
    set encoding=utf8
--- 1,12 ----
! " Tests for maparg(), mapcheck() and mapset().
  " Also test utf8 map with a 0x80 byte.
  " Also test mapcheck()
  
! func s:SID()     
    return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
! endfunc
  
! funct Test_maparg()
    new
    set cpo-=<
    set encoding=utf8
***************
*** 18,40 ****
    call assert_equal("is<F4>foo", maparg('foo<C-V>'))
    call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 
'foo<C-V>',
          \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, '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', 
'mode': 'v',
          \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
!       \ 'rhs': 'isbar', 'buffer': 1},
          \ 'bar'->maparg('', 0, 1))
    let lnum = expand('<sflnum>')
    map <buffer> <nowait> foo bar
    call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 
'mode': ' ',
          \ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
!       \ 'buffer': 1},
          \ maparg('foo', '', 0, 1))
    let lnum = expand('<sflnum>')
    tmap baz foo
    call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 
'mode': 't',
          \ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
!       \ 'buffer': 0},
          \ maparg('baz', 't', 0, 1))
  
    map abc x<char-114>x
--- 18,40 ----
    call assert_equal("is<F4>foo", maparg('foo<C-V>'))
    call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 
'foo<C-V>',
          \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 
!       \ 'simplified': 1, 'rhs': 'is<F4>foo', 'buffer': 0},
        \ maparg('foo<C-V>', '', 0, 1))
    call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 
'mode': 'v',
          \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
!       \ 'simplified': 0, 'rhs': 'isbar', 'buffer': 1},
          \ 'bar'->maparg('', 0, 1))
    let lnum = expand('<sflnum>')
    map <buffer> <nowait> foo bar
    call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 
'mode': ' ',
          \ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
!       \ 'simplified': 0, 'buffer': 1},
          \ maparg('foo', '', 0, 1))
    let lnum = expand('<sflnum>')
    tmap baz foo
    call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 
'mode': 't',
          \ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
!       \ 'simplified': 0, 'buffer': 0},
          \ maparg('baz', 't', 0, 1))
  
    map abc x<char-114>x
***************
*** 75,81 ****
    let d = maparg('esc', 'i', 1, 1)
    call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, 
d.mode])
    abclear
! endfunction
  
  func Test_mapcheck()
    call assert_equal('', mapcheck('a'))
--- 75,81 ----
    let d = maparg('esc', 'i', 1, 1)
    call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, 
d.mode])
    abclear
! endfunc
  
  func Test_mapcheck()
    call assert_equal('', mapcheck('a'))
***************
*** 116,122 ****
    unabbr ab
  endfunc
  
! function Test_range_map()
    new
    " Outside of the range, minimum
    inoremap <Char-0x1040> a
--- 116,122 ----
    unabbr ab
  endfunc
  
! func Test_range_map()
    new
    " Outside of the range, minimum
    inoremap <Char-0x1040> a
***************
*** 131,136 ****
    inoremap <Char-0xf040> d
    execute "normal a\uf040\<Esc>"
    call assert_equal("abcd", getline(1))
! endfunction
  
  " vim: shiftwidth=2 sts=2 expandtab
--- 131,161 ----
    inoremap <Char-0xf040> d
    execute "normal a\uf040\<Esc>"
    call assert_equal("abcd", getline(1))
! endfunc
! 
! func One_mapset_test(keys)
!   exe 'nnoremap ' .. a:keys .. ' original<CR>'
!   let orig = maparg(a:keys, 'n', 0, 1)
!   call assert_equal(a:keys, orig.lhs)
!   call assert_equal('original<CR>', orig.rhs)
!   call assert_equal('n', orig.mode)
! 
!   exe 'nunmap ' .. a:keys
!   let d = maparg(a:keys, 'n', 0, 1)
!   call assert_equal({}, d)
! 
!   call mapset('n', 0, orig)
!   let d = maparg(a:keys, 'n', 0, 1)
!   call assert_equal(a:keys, d.lhs)
!   call assert_equal('original<CR>', d.rhs)
!   call assert_equal('n', d.mode)
! 
!   exe 'nunmap ' .. a:keys
! endfunc
! 
! func Test_mapset()
!   call One_mapset_test('K')
!   call One_mapset_test('<F3>')
! endfunc
  
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.0806/src/version.c       2020-05-21 21:50:54.180651652 +0200
--- src/version.c       2020-05-22 13:08:00.584637022 +0200
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     807,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
154. You fondle your mouse.

 /// Bram Moolenaar -- b...@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    ///

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202005221111.04MBBIQp014911%40masaka.moolenaar.net.

Raspunde prin e-mail lui