aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-08-01 12:27:37 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-08-01 21:54:18 +0800
commit083865071b52d746de50294a0603bc6dbe20b3ec (patch)
tree9bd9fda27f8dc86963b3c4567502d139afe9b9ed
parentdb6e93c48df551e2906c9e0f4472f9e54cea3dd9 (diff)
downloadrneovim-083865071b52d746de50294a0603bc6dbe20b3ec.tar.gz
rneovim-083865071b52d746de50294a0603bc6dbe20b3ec.tar.bz2
rneovim-083865071b52d746de50294a0603bc6dbe20b3ec.zip
vim-patch:8.2.0807: cannot easily restore a mapping
Problem: Cannot easily restore a mapping. Solution: Add mapset(). https://github.com/vim/vim/commit/4c9243f9fb708c9010867d3cc8e928f36b58509a 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. https://github.com/vim/vim/commit/5a80f8ad5dc0b2cc63400255dcf3c63f6c1a2ef9
-rw-r--r--runtime/doc/builtin.txt19
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/mapping.c174
-rw-r--r--src/nvim/testdir/test_maparg.vim51
4 files changed, 187 insertions, 58 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index f844ae5aaf..994f1ab7f5 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -295,6 +295,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}]]])
@@ -4716,6 +4718,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
@@ -4767,6 +4770,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.
@@ -4813,6 +4820,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
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 3db0d27018..c8eb0334fa 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -250,6 +250,7 @@ return {
map={args=2, base=1},
maparg={args={1, 4}, base=1},
mapcheck={args={1, 3}, base=1},
+ mapset={args=3, base=1},
match={args={2, 4}, base=1},
matchadd={args={2, 5}, base=1},
matchaddpos={args={2, 5}, base=1},
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 93374a41bd..384497174d 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -428,6 +428,63 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma
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`.
///
/// @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.
- mp = xmalloc(sizeof(mapblock_T));
-
- // If CTRL-C has been mapped, don't always use it for Interrupting.
- if (*lhs == Ctrl_C) {
- 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;
- }
+ map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev,
+ -1, // sid
+ 0, // lnum
+ keyround1_simplified);
}
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_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)
@@ -2108,6 +2125,73 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
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
void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index f9429a8020..ec9af3d825 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -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
@@ -17,24 +17,24 @@ function Test_maparg()
vnoremap <script> <buffer> <expr> <silent> bar isbar
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))
+ \ '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,
- \ '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
@@ -89,7 +89,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'))
@@ -130,7 +130,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
@@ -145,6 +145,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