Skip to content

Commit 659c240

Browse files
erraelbrammool
authored andcommitted
patch 8.2.4820: not simple programmatic way to find a specific mapping
Problem: Not simple programmatic way to find a specific mapping. Solution: Add getmappings(). (Ernie Rael, closes #10273)
1 parent a4e3332 commit 659c240

File tree

7 files changed

+182
-29
lines changed

7 files changed

+182
-29
lines changed

runtime/doc/builtin.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ getline({lnum}) String line {lnum} of current buffer
235235
getline({lnum}, {end}) List lines {lnum} to {end} of current buffer
236236
getloclist({nr}) List list of location list items
237237
getloclist({nr}, {what}) Dict get specific location list properties
238+
getmappings() List list of all mappings, a dict for each
238239
getmarklist([{buf}]) List list of global/local marks
239240
getmatches([{win}]) List list of current matches
240241
getmousepos() Dict last known mouse position
@@ -3570,6 +3571,17 @@ getloclist({nr} [, {what}]) *getloclist()*
35703571
:echo getloclist(5, {'filewinid': 0})
35713572
35723573
3574+
getmappings() *getmappings()*
3575+
Returns a |List| of all mappings. Each List item is a |Dict|,
3576+
the same as what is returned by |maparg()|, see
3577+
|mapping-dict|.
3578+
3579+
Example to show all mappings with 'MultiMatch' in rhs: >
3580+
vim9script
3581+
echo getmappings()->filter(
3582+
(_, m) => match(m.rhs, 'MultiMatch') >= 0)
3583+
3584+
35733585
getmarklist([{buf}]) *getmarklist()*
35743586
Without the {buf} argument returns a |List| with information
35753587
about all the global marks. |mark|
@@ -5262,7 +5274,7 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
52625274

52635275
When {dict} is there and it is |TRUE| return a dictionary
52645276
containing all the information of the mapping with the
5265-
following items:
5277+
following items: *mapping-dict*
52665278
"lhs" The {lhs} of the mapping as it would be typed
52675279
"lhsraw" The {lhs} of the mapping as raw bytes
52685280
"lhsrawalt" The {lhs} of the mapping as raw bytes, alternate

runtime/doc/usr_41.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,7 @@ Mappings and Menus: *mapping-functions*
10891089
digraph_getlist() get all |digraph|s
10901090
digraph_set() register |digraph|
10911091
digraph_setlist() register multiple |digraph|s
1092+
getmappings() get list of all mappings
10921093
hasmapto() check if a mapping exists
10931094
mapcheck() check if a matching mapping exists
10941095
maparg() get rhs of a mapping

src/evalfunc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,6 +1871,8 @@ static funcentry_T global_functions[] =
18711871
ret_getline, f_getline},
18721872
{"getloclist", 1, 2, 0, arg2_number_dict_any,
18731873
ret_list_or_dict_1, f_getloclist},
1874+
{"getmappings", 0, 0, 0, NULL,
1875+
ret_list_dict_any, f_getmappings},
18741876
{"getmarklist", 0, 1, FEARG_1, arg1_buffer,
18751877
ret_list_dict_any, f_getmarklist},
18761878
{"getmatches", 0, 1, 0, arg1_number,

src/map.c

Lines changed: 91 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2274,6 +2274,42 @@ check_map(
22742274
return NULL;
22752275
}
22762276

2277+
/*
2278+
* Fill in the empty dictionary with items as defined by maparg builtin.
2279+
*/
2280+
static void
2281+
mapblock2dict(
2282+
mapblock_T *mp,
2283+
dict_T *dict,
2284+
char_u *lhsrawalt, // may be NULL
2285+
int buffer_local) // false if not buffer local mapping
2286+
{
2287+
char_u *lhs = str2special_save(mp->m_keys, TRUE);
2288+
char_u *mapmode = map_mode_to_chars(mp->m_mode);
2289+
2290+
dict_add_string(dict, "lhs", lhs);
2291+
vim_free(lhs);
2292+
dict_add_string(dict, "lhsraw", mp->m_keys);
2293+
if (lhsrawalt)
2294+
// Also add the value for the simplified entry.
2295+
dict_add_string(dict, "lhsrawalt", lhsrawalt);
2296+
dict_add_string(dict, "rhs", mp->m_orig_str);
2297+
dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
2298+
dict_add_number(dict, "script", mp->m_noremap == REMAP_SCRIPT
2299+
? 1L : 0L);
2300+
dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
2301+
dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
2302+
dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
2303+
dict_add_number(dict, "scriptversion",
2304+
(long)mp->m_script_ctx.sc_version);
2305+
dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
2306+
dict_add_number(dict, "buffer", (long)buffer_local);
2307+
dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
2308+
dict_add_string(dict, "mode", mapmode);
2309+
2310+
vim_free(mapmode);
2311+
}
2312+
22772313
static void
22782314
get_maparg(typval_T *argvars, typval_T *rettv, int exact)
22792315
{
@@ -2346,39 +2382,66 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact)
23462382

23472383
}
23482384
else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
2349-
{
2350-
// Return a dictionary.
2351-
char_u *lhs = str2special_save(mp->m_keys, TRUE);
2352-
char_u *mapmode = map_mode_to_chars(mp->m_mode);
2353-
dict_T *dict = rettv->vval.v_dict;
2354-
2355-
dict_add_string(dict, "lhs", lhs);
2356-
vim_free(lhs);
2357-
dict_add_string(dict, "lhsraw", mp->m_keys);
2358-
if (did_simplify)
2359-
// Also add the value for the simplified entry.
2360-
dict_add_string(dict, "lhsrawalt", mp_simplified->m_keys);
2361-
dict_add_string(dict, "rhs", mp->m_orig_str);
2362-
dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
2363-
dict_add_number(dict, "script", mp->m_noremap == REMAP_SCRIPT
2364-
? 1L : 0L);
2365-
dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
2366-
dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
2367-
dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
2368-
dict_add_number(dict, "scriptversion",
2369-
(long)mp->m_script_ctx.sc_version);
2370-
dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
2371-
dict_add_number(dict, "buffer", (long)buffer_local);
2372-
dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
2373-
dict_add_string(dict, "mode", mapmode);
2374-
2375-
vim_free(mapmode);
2376-
}
2385+
mapblock2dict(mp, rettv->vval.v_dict,
2386+
did_simplify ? mp_simplified->m_keys : NULL, buffer_local);
23772387

23782388
vim_free(keys_buf);
23792389
vim_free(alt_keys_buf);
23802390
}
23812391

2392+
/*
2393+
* "getmappings()" function
2394+
*/
2395+
void
2396+
f_getmappings(typval_T *argvars UNUSED, typval_T *rettv)
2397+
{
2398+
dict_T *d;
2399+
mapblock_T *mp;
2400+
int buffer_local;
2401+
char_u *keys_buf;
2402+
int did_simplify;
2403+
int hash;
2404+
char_u *lhs;
2405+
const int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
2406+
2407+
if (rettv_list_alloc(rettv) != OK)
2408+
return;
2409+
2410+
validate_maphash();
2411+
2412+
// Do it twice: once for global maps and once for local maps.
2413+
for (buffer_local = 0; buffer_local <= 1; ++buffer_local)
2414+
{
2415+
for (hash = 0; hash < 256; ++hash)
2416+
{
2417+
if (buffer_local)
2418+
mp = curbuf->b_maphash[hash];
2419+
else
2420+
mp = maphash[hash];
2421+
for (; mp; mp = mp->m_next)
2422+
{
2423+
if (mp->m_simplified)
2424+
continue;
2425+
if ((d = dict_alloc()) == NULL)
2426+
return;
2427+
if (list_append_dict(rettv->vval.v_list, d) == FAIL)
2428+
return;
2429+
2430+
keys_buf = NULL;
2431+
did_simplify = FALSE;
2432+
2433+
lhs = str2special_save(mp->m_keys, TRUE);
2434+
(void)replace_termcodes(lhs, &keys_buf, flags, &did_simplify);
2435+
vim_free(lhs);
2436+
2437+
mapblock2dict(mp, d,
2438+
did_simplify ? keys_buf : NULL, buffer_local);
2439+
vim_free(keys_buf);
2440+
}
2441+
}
2442+
}
2443+
}
2444+
23822445
/*
23832446
* "maparg()" function
23842447
*/

src/proto/map.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ int makemap(FILE *fd, buf_T *buf);
1717
int put_escstr(FILE *fd, char_u *strstart, int what);
1818
void check_map_keycodes(void);
1919
char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr, int *local_ptr);
20+
void f_getmappings(typval_T *argvars, typval_T *rettv);
2021
void f_maparg(typval_T *argvars, typval_T *rettv);
2122
void f_mapcheck(typval_T *argvars, typval_T *rettv);
2223
void f_mapset(typval_T *argvars, typval_T *rettv);

src/testdir/test_maparg.vim

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,76 @@ func Test_map_restore()
297297

298298
endfunc
299299

300+
def Test_getmappings()
301+
new
302+
def ClearMaps()
303+
mapclear | nmapclear | vmapclear | xmapclear | smapclear | omapclear
304+
mapclear! | imapclear | lmapclear | cmapclear | tmapclear
305+
mapclear <buffer> | nmapclear <buffer> | vmapclear <buffer>
306+
xmapclear <buffer> | smapclear <buffer> | omapclear <buffer>
307+
mapclear! <buffer> | imapclear <buffer> | lmapclear <buffer>
308+
cmapclear <buffer> | tmapclear <buffer>
309+
enddef
310+
311+
def AddMaps(new: list<string>, accum: list<string>)
312+
if len(new) > 0 && new[0] != "No mapping found"
313+
accum->extend(new)
314+
endif
315+
enddef
316+
317+
ClearMaps()
318+
assert_equal(0, len(getmappings()))
319+
320+
# Set up some mappings.
321+
map dup bar
322+
map <buffer> dup bufbar
323+
map foo<C-V> is<F4>foo
324+
vnoremap <script> <buffer> <expr> <silent> bar isbar
325+
tmap baz foo
326+
omap h w
327+
lmap i w
328+
nmap j w
329+
xmap k w
330+
smap l w
331+
map abc <Nop>
332+
nmap <M-j> x
333+
nmap <M-Space> y
334+
335+
# Get a list of the mappings with the ':map' commands.
336+
# Check getmappings() return a list of the same size.
337+
assert_equal(13, len(getmappings()))
338+
339+
# collect all the current maps using :map commands
340+
var maps_command: list<string>
341+
AddMaps(split(execute('map'), '\n'), maps_command)
342+
AddMaps(split(execute('map!'), '\n'), maps_command)
343+
AddMaps(split(execute('tmap'), '\n'), maps_command)
344+
AddMaps(split(execute('lmap'), '\n'), maps_command)
345+
346+
# Use getmappings to get all the maps
347+
var maps_getmappings = getmappings()
348+
assert_equal(len(maps_command), len(maps_getmappings))
349+
350+
# make sure all the mode-lhs are unique, no duplicates
351+
var map_set: dict<number>
352+
for d in maps_getmappings
353+
map_set[d.mode .. "-" .. d.lhs .. "-" .. d.buffer] = 0
354+
endfor
355+
assert_equal(len(maps_getmappings), len(map_set))
356+
357+
# For everything returned by getmappings, should be the same as from maparg.
358+
# Except for "map dup", bacause maparg returns the <buffer> version
359+
for d in maps_getmappings
360+
if d.lhs == 'dup' && d.buffer == 0
361+
continue
362+
endif
363+
var d_maparg = maparg(d.lhs, d.mode, false, true)
364+
assert_equal(d_maparg, d)
365+
endfor
366+
367+
ClearMaps()
368+
assert_equal(0, len(getmappings()))
369+
enddef
370+
371+
300372
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,8 @@ static char *(features[]) =
746746

747747
static int included_patches[] =
748748
{ /* Add new patch number below this line */
749+
/**/
750+
4820,
749751
/**/
750752
4819,
751753
/**/

0 commit comments

Comments
 (0)