diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-08-01 12:27:37 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2022-08-01 21:54:18 +0800 |
commit | 083865071b52d746de50294a0603bc6dbe20b3ec (patch) | |
tree | 9bd9fda27f8dc86963b3c4567502d139afe9b9ed | |
parent | db6e93c48df551e2906c9e0f4472f9e54cea3dd9 (diff) | |
download | rneovim-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.txt | 19 | ||||
-rw-r--r-- | src/nvim/eval.lua | 1 | ||||
-rw-r--r-- | src/nvim/mapping.c | 174 | ||||
-rw-r--r-- | src/nvim/testdir/test_maparg.vim | 51 |
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 |