aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-10-25 07:16:54 +0800
committerGitHub <noreply@github.com>2024-10-24 23:16:54 +0000
commite4a74e986c40ca60ad49ea89020d6a9be36e928b (patch)
tree72dd847fb4ddda9e82fafbc5b77e6c4dc1e037e9
parent54249d051c3e0b97321939e6a3ae3d2e83971ce7 (diff)
downloadrneovim-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.c20
-rw-r--r--src/nvim/mapping.h7
-rw-r--r--test/old/testdir/test_map_functions.vim19
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()