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 -- Br...@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 ///