]> granicus.if.org Git - vim/commitdiff
patch 8.2.0807: cannot easily restore a mapping v8.2.0807
authorBram Moolenaar <Bram@vim.org>
Fri, 22 May 2020 11:10:44 +0000 (13:10 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 22 May 2020 11:10:44 +0000 (13:10 +0200)
Problem:    Cannot easily restore a mapping.
Solution:   Add mapset().

runtime/doc/eval.txt
src/evalfunc.c
src/map.c
src/proto/map.pro
src/testdir/test_maparg.vim
src/version.c

index 8259e9920b31c3c834717e28e5a4857659fd482c..afda3505b1e5778c18a5d73bb8c2b43560efba70 100644 (file)
@@ -2586,6 +2586,8 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]])
                                        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}]]])
@@ -6794,6 +6796,7 @@ map({expr1}, {expr2})                                     *map()*
                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
@@ -6844,6 +6847,10 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]])                  *maparg()*
                  "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.
@@ -6890,6 +6897,18 @@ mapcheck({name} [, {mode} [, {abbr}]])                   *mapcheck()*
                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
index 297961184a77d3c0db54bc68ff004f2744ebd173..37cb72f7ee4d95aa14f7d76205c3a046d111aeee 100644 (file)
@@ -664,6 +664,7 @@ static funcentry_T global_functions[] =
     {"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},
index 2e20d401cbd988d9ccfa58f262875a6e1fb3e512..34a956e0be0bd5dbd94f47f1969c2492704c4340 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -204,6 +204,86 @@ showmap(
     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,7 +581,8 @@ do_map(
            msg_start();
 
        // Check if a new local mapping wasn't already defined globally.
-       if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
+       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,7 +600,6 @@ do_map(
                    // 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)
@@ -759,57 +839,16 @@ do_map(
            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;
+       if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, expr,
+                   noremap, nowait, silent, mode,
+                   abbrev,
 #ifdef FEAT_EVAL
-       mp->m_expr = expr;
-       mp->m_script_ctx = current_sctx;
-       mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
+                   /* sid */ -1, /* lnum */ 0,
 #endif
-
-       // add the new entry in front of the abbrlist or maphash[] list
-       if (abbrev)
-       {
-           mp->m_next = *abbr_table;
-           *abbr_table = mp;
-       }
-       else
+                   did_simplify && keyround == 1) == FAIL)
        {
-           n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
-           mp->m_next = map_table[n];
-           map_table[n] = mp;
+           retval = 4;     // no mem
+           goto theend;
        }
     }
 
@@ -2209,13 +2248,96 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact)
        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
index cf1b31a4cc1d658ac8a612e2ef36602120330489..6da455a7e47163f58085a6aafc50399bf212a0fb 100644 (file)
@@ -18,6 +18,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what);
 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);
index cc72e7e8e65f4ea71bc595b5b0dfad8bfc853406..5fb8045a64648014e95073b6748d9f5f877ec7c6 100644 (file)
@@ -1,12 +1,12 @@
-" Tests for maparg().
+" Tests for maparg(), mapcheck() and mapset().
 " Also test utf8 map with a 0x80 byte.
 " Also test mapcheck()
 
-function s:SID()     
+func s:SID()     
   return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
-endfun
+endfunc
 
-function Test_maparg()
+funct Test_maparg()
   new
   set cpo-=<
   set encoding=utf8
@@ -18,23 +18,23 @@ function Test_maparg()
   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},
+       \ '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,
-       \ 'rhs': 'isbar', 'buffer': 1},
+       \ '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',
-       \ 'buffer': 1},
+       \ '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',
-       \ 'buffer': 0},
+       \ 'simplified': 0, 'buffer': 0},
         \ maparg('baz', 't', 0, 1))
 
   map abc x<char-114>x
@@ -75,7 +75,7 @@ function Test_maparg()
   let d = maparg('esc', 'i', 1, 1)
   call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, d.mode])
   abclear
-endfunction
+endfunc
 
 func Test_mapcheck()
   call assert_equal('', mapcheck('a'))
@@ -116,7 +116,7 @@ func Test_mapcheck()
   unabbr ab
 endfunc
 
-function Test_range_map()
+func Test_range_map()
   new
   " Outside of the range, minimum
   inoremap <Char-0x1040> a
@@ -131,6 +131,31 @@ function Test_range_map()
   inoremap <Char-0xf040> d
   execute "normal a\uf040\<Esc>"
   call assert_equal("abcd", getline(1))
-endfunction
+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
index d36fa4a2a1151eeaec799f62bafd11cdbe2a4f09..565ebbbcb364b8c96d7ad353f650bb086fe80f91 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    807,
 /**/
     806,
 /**/