]> granicus.if.org Git - vim/commitdiff
patch 8.2.4820: not simple programmatic way to find a specific mapping v8.2.4820
authorErnie Rael <errael@raelity.com>
Sun, 24 Apr 2022 17:40:28 +0000 (18:40 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 24 Apr 2022 17:40:28 +0000 (18:40 +0100)
Problem:    Not simple programmatic way to find a specific mapping.
Solution:   Add getmappings(). (Ernie Rael, closes #10273)

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

index 8695edd2dd7e9ba2f1810cae82df077422dc94c7..5a6ebb88c189a07ad8558e44f1ccd5f283aff57a 100644 (file)
@@ -235,6 +235,7 @@ getline({lnum})                     String  line {lnum} of current buffer
 getline({lnum}, {end})         List    lines {lnum} to {end} of current buffer
 getloclist({nr})               List    list of location list items
 getloclist({nr}, {what})       Dict    get specific location list properties
+getmappings()                  List    list of all mappings, a dict for each
 getmarklist([{buf}])           List    list of global/local marks
 getmatches([{win}])            List    list of current matches
 getmousepos()                  Dict    last known mouse position
@@ -3570,6 +3571,17 @@ getloclist({nr} [, {what}])                              *getloclist()*
                        :echo getloclist(5, {'filewinid': 0})
 
 
+getmappings()                                          *getmappings()*
+               Returns a |List| of all mappings.  Each List item is a |Dict|,
+               the same as what is returned by |maparg()|, see
+               |mapping-dict|.
+
+               Example to show all mappings with 'MultiMatch' in rhs: >
+                       vim9script
+                       echo getmappings()->filter(
+                               (_, m) => match(m.rhs, 'MultiMatch') >= 0)
+
+
 getmarklist([{buf}])                                   *getmarklist()*
                Without the {buf} argument returns a |List| with information
                about all the global marks. |mark|
@@ -5262,7 +5274,7 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]])                   *maparg()*
 
                When {dict} is there and it is |TRUE| return a dictionary
                containing all the information of the mapping with the
-               following items:
+               following items:                        *mapping-dict*
                  "lhs"      The {lhs} of the mapping as it would be typed
                  "lhsraw"   The {lhs} of the mapping as raw bytes
                  "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
index eb269e16cb2edb1cb795e34eaae542b2e0dbf066..12d3adc1b0123083abb3ac67589007d65057cdda 100644 (file)
@@ -1089,6 +1089,7 @@ Mappings and Menus:                           *mapping-functions*
        digraph_getlist()       get all |digraph|s
        digraph_set()           register |digraph|
        digraph_setlist()       register multiple |digraph|s
+       getmappings()           get list of all mappings
        hasmapto()              check if a mapping exists
        mapcheck()              check if a matching mapping exists
        maparg()                get rhs of a mapping
index f6d4b05e04e9c7b8d9ade9bb340cdc4560e36b64..090f3a7364740b0f3382b6f8e568fefa385fe2ff 100644 (file)
@@ -1871,6 +1871,8 @@ static funcentry_T global_functions[] =
                        ret_getline,        f_getline},
     {"getloclist",     1, 2, 0,            arg2_number_dict_any,
                        ret_list_or_dict_1, f_getloclist},
+    {"getmappings",            0, 0, 0,            NULL,
+                       ret_list_dict_any,  f_getmappings},
     {"getmarklist",    0, 1, FEARG_1,      arg1_buffer,
                        ret_list_dict_any,  f_getmarklist},
     {"getmatches",     0, 1, 0,            arg1_number,
index f3ff00729b2296f3db72204bd4fe798ff999dd0d..38f5282899efdbab3f7553759dbca60ea80fd306 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -2274,6 +2274,42 @@ check_map(
     return NULL;
 }
 
+/*
+ * Fill in the empty dictionary with items as defined by maparg builtin.
+ */
+    static void
+mapblock2dict(
+       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);
+
+    dict_add_string(dict, "lhs", lhs);
+    vim_free(lhs);
+    dict_add_string(dict, "lhsraw", mp->m_keys);
+    if (lhsrawalt)
+       // Also add the value for the simplified entry.
+       dict_add_string(dict, "lhsrawalt", lhsrawalt);
+    dict_add_string(dict, "rhs", mp->m_orig_str);
+    dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
+    dict_add_number(dict, "script", mp->m_noremap == REMAP_SCRIPT
+                   ? 1L : 0L);
+    dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
+    dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
+    dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
+    dict_add_number(dict, "scriptversion",
+                   (long)mp->m_script_ctx.sc_version);
+    dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
+    dict_add_number(dict, "buffer", (long)buffer_local);
+    dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
+    dict_add_string(dict, "mode", mapmode);
+
+    vim_free(mapmode);
+}
+
     static void
 get_maparg(typval_T *argvars, typval_T *rettv, int exact)
 {
@@ -2346,39 +2382,66 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact)
 
     }
     else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
-    {
-       // Return a dictionary.
-       char_u      *lhs = str2special_save(mp->m_keys, TRUE);
-       char_u      *mapmode = map_mode_to_chars(mp->m_mode);
-       dict_T      *dict = rettv->vval.v_dict;
-
-       dict_add_string(dict, "lhs", lhs);
-       vim_free(lhs);
-       dict_add_string(dict, "lhsraw", mp->m_keys);
-       if (did_simplify)
-           // Also add the value for the simplified entry.
-           dict_add_string(dict, "lhsrawalt", mp_simplified->m_keys);
-       dict_add_string(dict, "rhs", mp->m_orig_str);
-       dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
-       dict_add_number(dict, "script", mp->m_noremap == REMAP_SCRIPT
-                                                                   ? 1L : 0L);
-       dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
-       dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
-       dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
-       dict_add_number(dict, "scriptversion",
-                                           (long)mp->m_script_ctx.sc_version);
-       dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
-       dict_add_number(dict, "buffer", (long)buffer_local);
-       dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
-       dict_add_string(dict, "mode", mapmode);
-
-       vim_free(mapmode);
-    }
+       mapblock2dict(mp, rettv->vval.v_dict,
+                   did_simplify ? mp_simplified->m_keys : NULL, buffer_local);
 
     vim_free(keys_buf);
     vim_free(alt_keys_buf);
 }
 
+/*
+ * "getmappings()" function
+ */
+    void
+f_getmappings(typval_T *argvars UNUSED, typval_T *rettv)
+{
+    dict_T     *d;
+    mapblock_T *mp;
+    int                buffer_local;
+    char_u     *keys_buf;
+    int                did_simplify;
+    int                hash;
+    char_u     *lhs;
+    const int  flags = REPTERM_FROM_PART | REPTERM_DO_LT;
+
+    if (rettv_list_alloc(rettv) != OK)
+       return;
+
+    validate_maphash();
+
+    // Do it twice: once for global maps and once for local maps.
+    for (buffer_local = 0; buffer_local <= 1; ++buffer_local)
+    {
+       for (hash = 0; hash < 256; ++hash)
+       {
+           if (buffer_local)
+               mp = curbuf->b_maphash[hash];
+           else
+               mp = maphash[hash];
+           for (; mp; mp = mp->m_next)
+           {
+               if (mp->m_simplified)
+                   continue;
+               if ((d = dict_alloc()) == NULL)
+                   return;
+               if (list_append_dict(rettv->vval.v_list, d) == FAIL)
+                   return;
+
+               keys_buf = NULL;
+               did_simplify = FALSE;
+
+               lhs = str2special_save(mp->m_keys, TRUE);
+               (void)replace_termcodes(lhs, &keys_buf, flags, &did_simplify);
+               vim_free(lhs);
+
+               mapblock2dict(mp, d,
+                                did_simplify ? keys_buf : NULL, buffer_local);
+               vim_free(keys_buf);
+           }
+       }
+    }
+}
+
 /*
  * "maparg()" function
  */
index 8b8bc062461d2f3afbe67303570f2020b5dfcb4d..88e61bd5e668a885ab7147245cc6f36874e41723 100644 (file)
@@ -17,6 +17,7 @@ int makemap(FILE *fd, buf_T *buf);
 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 f_getmappings(typval_T *argvars, typval_T *rettv);
 void f_maparg(typval_T *argvars, typval_T *rettv);
 void f_mapcheck(typval_T *argvars, typval_T *rettv);
 void f_mapset(typval_T *argvars, typval_T *rettv);
index 64e02a7327cb7dd47dc25cc606292981ea03bee0..6e73b39553135cfd6e5b2810d71e177222f9099d 100644 (file)
@@ -297,4 +297,76 @@ func Test_map_restore()
 
 endfunc
 
+def Test_getmappings()
+  new
+  def ClearMaps()
+    mapclear | nmapclear | vmapclear | xmapclear | smapclear | omapclear
+    mapclear!  | imapclear | lmapclear | cmapclear | tmapclear
+    mapclear <buffer> | nmapclear <buffer> | vmapclear <buffer>
+    xmapclear <buffer> | smapclear <buffer> | omapclear <buffer>
+    mapclear! <buffer> | imapclear <buffer> | lmapclear <buffer>
+    cmapclear <buffer> | tmapclear <buffer>
+  enddef
+
+  def AddMaps(new: list<string>, accum: list<string>)
+    if len(new) > 0 && new[0] != "No mapping found"
+      accum->extend(new)
+    endif
+  enddef
+
+  ClearMaps()
+  assert_equal(0, len(getmappings()))
+
+  # Set up some mappings.
+  map dup bar
+  map <buffer> dup bufbar
+  map foo<C-V> is<F4>foo
+  vnoremap <script> <buffer> <expr> <silent> bar isbar
+  tmap baz foo
+  omap h w
+  lmap i w
+  nmap j w
+  xmap k w
+  smap l w
+  map abc <Nop>
+  nmap <M-j> x
+  nmap <M-Space> y
+
+  # Get a list of the mappings with the ':map' commands.
+  # Check getmappings() return a list of the same size.
+  assert_equal(13, len(getmappings()))
+
+  # collect all the current maps using :map commands
+  var maps_command: list<string>
+  AddMaps(split(execute('map'), '\n'), maps_command)
+  AddMaps(split(execute('map!'), '\n'), maps_command)
+  AddMaps(split(execute('tmap'), '\n'), maps_command)
+  AddMaps(split(execute('lmap'), '\n'), maps_command)
+
+  # Use getmappings to get all the maps
+  var maps_getmappings = getmappings()
+  assert_equal(len(maps_command), len(maps_getmappings))
+
+  # make sure all the mode-lhs are unique, no duplicates
+  var map_set: dict<number>
+  for d in maps_getmappings
+    map_set[d.mode .. "-" .. d.lhs .. "-" .. d.buffer] = 0
+  endfor
+  assert_equal(len(maps_getmappings), len(map_set))
+
+  # For everything returned by getmappings, should be the same as from maparg.
+  # Except for "map dup", bacause maparg returns the <buffer> version
+  for d in maps_getmappings
+    if d.lhs == 'dup' && d.buffer == 0
+      continue
+    endif
+    var d_maparg = maparg(d.lhs, d.mode, false, true)
+    assert_equal(d_maparg, d)
+  endfor
+
+  ClearMaps()
+  assert_equal(0, len(getmappings()))
+enddef
+
+
 " vim: shiftwidth=2 sts=2 expandtab
index 1d54137bf9f1f80ce1921808cf6f89898b77fd22..62d6e5df3f6c2ad7d66d43136dfec7784d313a12 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4820,
 /**/
     4819,
 /**/