vim-patch:8.2.0807: cannot easily restore a mapping

Problem:    Cannot easily restore a mapping.
Solution:   Add mapset().
4c9243f9fb

Use MapArgument to reduce number of arguments of map_add().

N/A patches for version.c:

vim-patch:8.2.0809: build failure with small features

Problem:    Build failure with small features. (Tony Mechelynck)
Solution:   Move "expr" inside #ifdef.
5a80f8ad5d
This commit is contained in:
zeertzjq
2022-08-01 12:27:37 +08:00
parent db6e93c48d
commit 083865071b
4 changed files with 187 additions and 58 deletions

View File

@@ -295,6 +295,8 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]])
rhs of mapping {name} in mode {mode} rhs of mapping {name} in mode {mode}
mapcheck({name} [, {mode} [, {abbr}]]) mapcheck({name} [, {mode} [, {abbr}]])
String check for mappings matching {name} String check for mappings matching {name}
mapset({name}, {mode}, {abbr}, {dict}
none restore mapping from |maparg()| result
match({expr}, {pat} [, {start} [, {count}]]) match({expr}, {pat} [, {start} [, {count}]])
Number position where {pat} matches in {expr} Number position where {pat} matches in {expr}
matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]]) matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])
@@ -4716,6 +4718,7 @@ map({expr1}, {expr2}) *map()*
Can also be used as a |method|: > Can also be used as a |method|: >
mylist->map(expr2) mylist->map(expr2)
maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
When {dict} is omitted or zero: Return the rhs of mapping When {dict} is omitted or zero: Return the rhs of mapping
{name} in mode {mode}. The returned String has special {name} in mode {mode}. The returned String has special
@@ -4767,6 +4770,10 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
"lnum" The line number in "sid", zero if unknown. "lnum" The line number in "sid", zero if unknown.
"nowait" Do not wait for other, longer mappings. "nowait" Do not wait for other, longer mappings.
(|:map-<nowait>|). (|:map-<nowait>|).
"simplified"
The dictionary can be used to restore a mapping with
|mapset()|.
The mappings local to the current buffer are checked first, The mappings local to the current buffer are checked first,
then the global mappings. then the global mappings.
@@ -4813,6 +4820,18 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetKey()->mapcheck('n') 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()* match({expr}, {pat} [, {start} [, {count}]]) *match()*
When {expr} is a |List| then this returns the index of the When {expr} is a |List| then this returns the index of the
first item where {pat} matches. Each item is used as a first item where {pat} matches. Each item is used as a

View File

@@ -250,6 +250,7 @@ return {
map={args=2, base=1}, map={args=2, base=1},
maparg={args={1, 4}, base=1}, maparg={args={1, 4}, base=1},
mapcheck={args={1, 3}, base=1}, mapcheck={args={1, 3}, base=1},
mapset={args=3, base=1},
match={args={2, 4}, base=1}, match={args={2, 4}, base=1},
matchadd={args={2, 5}, base=1}, matchadd={args={2, 5}, base=1},
matchaddpos={args={2, 5}, base=1}, matchaddpos={args={2, 5}, base=1},

View File

@@ -428,6 +428,63 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma
return 0; return 0;
} }
/// @param sid -1 to use current_sctx
static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char_u *keys,
MapArguments *args, int noremap, int mode, bool is_abbr, scid_T sid,
linenr_T lnum, bool simplified)
{
mapblock_T *mp = xcalloc(1, sizeof(mapblock_T));
// If CTRL-C has been mapped, don't always use it for Interrupting.
if (*keys == Ctrl_C) {
if (map_table == buf->b_maphash) {
buf->b_mapped_ctrl_c |= mode;
} else {
mapped_ctrl_c |= mode;
}
}
mp->m_keys = vim_strsave(keys);
mp->m_str = args->rhs;
mp->m_orig_str = args->orig_rhs;
mp->m_luaref = args->rhs_lua;
if (!simplified) {
args->rhs = NULL;
args->orig_rhs = NULL;
args->rhs_lua = LUA_NOREF;
}
mp->m_keylen = (int)STRLEN(mp->m_keys);
mp->m_noremap = noremap;
mp->m_nowait = args->nowait;
mp->m_silent = args->silent;
mp->m_mode = mode;
mp->m_simplified = simplified;
mp->m_expr = args->expr;
mp->m_replace_keycodes = args->replace_keycodes;
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;
nlua_set_sctx(&mp->m_script_ctx);
}
mp->m_desc = NULL;
if (args->desc != NULL) {
mp->m_desc = xstrdup(args->desc);
}
// add the new entry in front of the abbrlist or maphash[] list
if (is_abbr) {
mp->m_next = *abbr_table;
*abbr_table = mp;
} else {
const int n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
mp->m_next = map_table[n];
map_table[n] = mp;
}
}
/// Sets or removes a mapping or abbreviation in buffer `buf`. /// Sets or removes a mapping or abbreviation in buffer `buf`.
/// ///
/// @param maptype @see do_map /// @param maptype @see do_map
@@ -780,51 +837,10 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
} }
// Get here when adding a new entry to the maphash[] list or abbrlist. // Get here when adding a new entry to the maphash[] list or abbrlist.
mp = xmalloc(sizeof(mapblock_T)); map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev,
-1, // sid
// If CTRL-C has been mapped, don't always use it for Interrupting. 0, // lnum
if (*lhs == Ctrl_C) { keyround1_simplified);
if (map_table == buf->b_maphash) {
buf->b_mapped_ctrl_c |= mode;
} else {
mapped_ctrl_c |= mode;
}
}
mp->m_keys = vim_strsave(lhs);
mp->m_str = args->rhs;
mp->m_orig_str = args->orig_rhs;
mp->m_luaref = args->rhs_lua;
if (!keyround1_simplified) {
args->rhs = NULL;
args->orig_rhs = NULL;
args->rhs_lua = LUA_NOREF;
}
mp->m_keylen = (int)STRLEN(mp->m_keys);
mp->m_noremap = noremap;
mp->m_nowait = args->nowait;
mp->m_silent = args->silent;
mp->m_mode = mode;
mp->m_simplified = keyround1_simplified; // Notice this when porting patch 8.2.0807
mp->m_expr = args->expr;
mp->m_replace_keycodes = args->replace_keycodes;
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += sourcing_lnum;
nlua_set_sctx(&mp->m_script_ctx);
mp->m_desc = NULL;
if (args->desc != NULL) {
mp->m_desc = xstrdup(args->desc);
}
// add the new entry in front of the abbrlist or maphash[] list
if (is_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;
}
} }
theend: theend:
@@ -2023,6 +2039,7 @@ static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, l
tv_dict_add_nr(dict, S_LEN("replace_keycodes"), 1); tv_dict_add_nr(dict, S_LEN("replace_keycodes"), 1);
} }
tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode); tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode);
tv_dict_add_nr(dict, S_LEN("simplified"), mp->m_simplified ? 1 : 0);
} }
static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
@@ -2108,6 +2125,73 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
xfree(alt_keys_buf); xfree(alt_keys_buf);
} }
/// "mapset()" function
void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char buf[NUMBUFLEN];
const char *which = tv_get_string_buf_chk(&argvars[0], buf);
int mode = get_map_mode((char **)&which, 0);
bool is_abbr = tv_get_number(&argvars[1]) != 0;
if (argvars[2].v_type != VAR_DICT) {
emsg(_(e_dictreq));
return;
}
dict_T *d = argvars[2].vval.v_dict;
// Get the values in the same order as above in get_maparg().
char *lhs = tv_dict_get_string(d, "lhs", false);
if (lhs == NULL) {
emsg(_("E99: lhs entry missing in mapset() dict argument"));
return;
}
char *rhs = tv_dict_get_string(d, "rhs", false);
if (rhs == NULL) {
emsg(_("E99: rhs entry missing in mapset() dict argument"));
return;
}
int noremap = tv_dict_get_number(d, "noremap") ? REMAP_NONE : 0;
if (tv_dict_get_number(d, "script") != 0) {
noremap = REMAP_SCRIPT;
}
// TODO: support "callback" and "desc"
MapArguments args = {
.rhs = vim_strsave((char_u *)rhs),
.rhs_lua = LUA_NOREF,
.orig_rhs = vim_strsave((char_u *)rhs),
.expr = tv_dict_get_number(d, "expr") != 0,
.silent = tv_dict_get_number(d, "silent") != 0,
.nowait = tv_dict_get_number(d, "nowait") != 0,
};
scid_T sid = (scid_T)tv_dict_get_number(d, "sid");
linenr_T lnum = (linenr_T)tv_dict_get_number(d, "lnum");
mapblock_T **map_table = maphash;
mapblock_T **abbr_table = &first_abbr;
if (tv_dict_get_number(d, "buffer") != 0) {
map_table = curbuf->b_maphash;
abbr_table = &curbuf->b_first_abbr;
}
// mode from the dict is not used
bool simplified = tv_dict_get_number(d, "simplified") != 0;
// Delete any existing mapping for this lhs and mode.
char_u *arg = vim_strsave((char_u *)lhs);
do_map(1, arg, mode, is_abbr); // TODO: refactor this later
xfree(arg);
char *keys_buf = NULL;
char *keys = replace_termcodes(lhs, STRLEN(lhs), &keys_buf, REPTERM_FROM_PART | REPTERM_DO_LT,
NULL, CPO_TO_CPO_FLAGS);
map_add(curbuf, map_table, abbr_table, (char_u *)keys, &args, noremap, mode, is_abbr, sid, lnum,
simplified);
xfree(keys_buf);
}
/// "maparg()" function /// "maparg()" function
void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{ {

View File

@@ -1,12 +1,12 @@
" Tests for maparg(). " Tests for maparg(), mapcheck() and mapset().
" Also test utf8 map with a 0x80 byte. " Also test utf8 map with a 0x80 byte.
" Also test mapcheck() " Also test mapcheck()
function s:SID() func s:SID()
return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')) return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
endfun endfunc
function Test_maparg() funct Test_maparg()
new new
set cpo-=< set cpo-=<
set encoding=utf8 set encoding=utf8
@@ -17,24 +17,24 @@ function Test_maparg()
vnoremap <script> <buffer> <expr> <silent> bar isbar vnoremap <script> <buffer> <expr> <silent> bar isbar
call assert_equal("is<F4>foo", maparg('foo<C-V>')) call assert_equal("is<F4>foo", maparg('foo<C-V>'))
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': '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, \ '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)) \ maparg('foo<C-V>', '', 0, 1))
call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v', call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v',
\ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2, \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
\ 'rhs': 'isbar', 'buffer': 1}, \ 'simplified': 0, 'rhs': 'isbar', 'buffer': 1},
\ 'bar'->maparg('', 0, 1)) \ 'bar'->maparg('', 0, 1))
let lnum = expand('<sflnum>') let lnum = expand('<sflnum>')
map <buffer> <nowait> foo bar map <buffer> <nowait> foo bar
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 'mode': ' ', call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 'mode': ' ',
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar', \ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
\ 'buffer': 1}, \ 'simplified': 0, 'buffer': 1},
\ maparg('foo', '', 0, 1)) \ maparg('foo', '', 0, 1))
let lnum = expand('<sflnum>') let lnum = expand('<sflnum>')
tmap baz foo tmap baz foo
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 'mode': 't', call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 'mode': 't',
\ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo', \ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
\ 'buffer': 0}, \ 'simplified': 0, 'buffer': 0},
\ maparg('baz', 't', 0, 1)) \ maparg('baz', 't', 0, 1))
map abc x<char-114>x map abc x<char-114>x
@@ -89,7 +89,7 @@ function Test_maparg()
let d = maparg('esc', 'i', 1, 1) let d = maparg('esc', 'i', 1, 1)
call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, d.mode]) call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, d.mode])
abclear abclear
endfunction endfunc
func Test_mapcheck() func Test_mapcheck()
call assert_equal('', mapcheck('a')) call assert_equal('', mapcheck('a'))
@@ -130,7 +130,7 @@ func Test_mapcheck()
unabbr ab unabbr ab
endfunc endfunc
function Test_range_map() func Test_range_map()
new new
" Outside of the range, minimum " Outside of the range, minimum
inoremap <Char-0x1040> a inoremap <Char-0x1040> a
@@ -145,6 +145,31 @@ function Test_range_map()
inoremap <Char-0xf040> d inoremap <Char-0xf040> d
execute "normal a\uf040\<Esc>" execute "normal a\uf040\<Esc>"
call assert_equal("abcd", getline(1)) 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 " vim: shiftwidth=2 sts=2 expandtab