diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-10-25 07:16:54 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-24 23:16:54 +0000 |
commit | e4a74e986c40ca60ad49ea89020d6a9be36e928b (patch) | |
tree | 72dd847fb4ddda9e82fafbc5b77e6c4dc1e037e9 | |
parent | 54249d051c3e0b97321939e6a3ae3d2e83971ce7 (diff) | |
download | rneovim-e4a74e986c40ca60ad49ea89020d6a9be36e928b.tar.gz rneovim-e4a74e986c40ca60ad49ea89020d6a9be36e928b.tar.bz2 rneovim-e4a74e986c40ca60ad49ea89020d6a9be36e928b.zip |
vim-patch:9.1.0814: mapset() may remove unrelated mapping (#30941)
Problem: mapset() may remove unrelated mapping whose {rhs} matches the
restored mapping's {lhs}.
Solution: only match by {lhs} when unmapping for mapset() (zeertzjq).
closes: vim/vim#15935
https://github.com/vim/vim/commit/fdf135a0525746cc0ff85bed2fbbde320ddb6d0d
-rw-r--r-- | src/nvim/mapping.c | 20 | ||||
-rw-r--r-- | src/nvim/mapping.h | 7 | ||||
-rw-r--r-- | test/old/testdir/test_map_functions.vim | 19 |
3 files changed, 37 insertions, 9 deletions
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index e055ebc2fa..23efd2a841 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -568,6 +568,12 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, mapblock_T **abbr_table = args->buffer ? &buf->b_first_abbr : &first_abbr; mapblock_T *mp_result[2] = { NULL, NULL }; + bool unmap_lhs_only = false; + if (maptype == MAPTYPE_UNMAP_LHS) { + unmap_lhs_only = true; + maptype = MAPTYPE_UNMAP; + } + // For ":noremap" don't remap, otherwise do remap. int noremap = args->script ? REMAP_SCRIPT : maptype == MAPTYPE_NOREMAP ? REMAP_NONE : REMAP_YES; @@ -720,8 +726,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, // entry with a matching 'to' part. This was done to allow ":ab foo bar" // to be unmapped by typing ":unab foo", where "foo" will be replaced by // "bar" because of the abbreviation. - for (int round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1 - && !did_it && !got_int; round++) { + const int num_rounds = maptype == MAPTYPE_UNMAP && !unmap_lhs_only ? 2 : 1; + for (int round = 0; round < num_rounds && !did_it && !got_int; round++) { int hash_start, hash_end; if ((round == 0 && has_lhs) || is_abbrev) { // just use one hash @@ -935,9 +941,11 @@ theend: /// for :cabbr mode is MODE_CMDLINE /// ``` /// -/// @param maptype MAPTYPE_MAP for |:map| -/// MAPTYPE_UNMAP for |:unmap| -/// MAPTYPE_NOREMAP for |:noremap|. +/// @param maptype MAPTYPE_MAP for |:map| or |:abbr| +/// MAPTYPE_UNMAP for |:unmap| or |:unabbr| +/// MAPTYPE_NOREMAP for |:noremap| or |:noreabbr| +/// MAPTYPE_UNMAP_LHS is like MAPTYPE_UNMAP, but doesn't try to match +/// with {rhs} if there is no match with {lhs}. /// @param arg C-string containing the arguments of the map/abbrev /// command, i.e. everything except the initial `:[X][nore]map`. /// - Cannot be a read-only string; it will be modified. @@ -2348,7 +2356,7 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) MapArguments unmap_args = MAP_ARGUMENTS_INIT; set_maparg_lhs_rhs(lhs, strlen(lhs), "", 0, LUA_NOREF, p_cpo, &unmap_args); unmap_args.buffer = buffer; - buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, is_abbr, curbuf); + buf_do_map(MAPTYPE_UNMAP_LHS, &unmap_args, mode, is_abbr, curbuf); xfree(unmap_args.rhs); xfree(unmap_args.orig_rhs); diff --git a/src/nvim/mapping.h b/src/nvim/mapping.h index b82117ea86..fc120b683c 100644 --- a/src/nvim/mapping.h +++ b/src/nvim/mapping.h @@ -19,9 +19,10 @@ /// Used for the first argument of do_map() enum { - MAPTYPE_MAP = 0, - MAPTYPE_UNMAP = 1, - MAPTYPE_NOREMAP = 2, + MAPTYPE_MAP = 0, + MAPTYPE_UNMAP = 1, + MAPTYPE_NOREMAP = 2, + MAPTYPE_UNMAP_LHS = 3, }; /// Adjust chars in a language according to 'langmap' option. diff --git a/test/old/testdir/test_map_functions.vim b/test/old/testdir/test_map_functions.vim index 8f7c8bae76..5118063b36 100644 --- a/test/old/testdir/test_map_functions.vim +++ b/test/old/testdir/test_map_functions.vim @@ -527,6 +527,25 @@ func Test_map_restore_negative_sid() call delete('Xresult') endfunc +" Check that restoring a mapping doesn't remove a mapping whose {rhs} matches +" the restored mapping's {lhs}. +func Test_map_restore_with_rhs_match_lhs() + nnoremap <F2> <F3> + nnoremap <F3> <F4> + call assert_equal('<F3>', maparg('<F2>', 'n')) + call assert_equal('<F4>', maparg('<F3>', 'n')) + let d = maparg('<F3>', 'n', v:false, v:true) + nunmap <F3> + call assert_equal('<F3>', maparg('<F2>', 'n')) + call assert_equal('', maparg('<F3>', 'n')) + call mapset(d) + call assert_equal('<F3>', maparg('<F2>', 'n')) + call assert_equal('<F4>', maparg('<F3>', 'n')) + + nunmap <F2> + nunmap <F3> +endfunc + func Test_maplist() new func s:ClearMappingsAbbreviations() |