mirror of
				https://github.com/vim/vim.git
				synced 2025-10-29 09:37:35 -04:00 
			
		
		
		
	patch 8.2.0807: cannot easily restore a mapping
Problem: Cannot easily restore a mapping. Solution: Add mapset().
This commit is contained in:
		| @@ -2586,6 +2586,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}]]]) | ||||
| @@ -6794,6 +6796,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 | ||||
| @@ -6844,6 +6847,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. | ||||
| @@ -6890,6 +6897,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 | ||||
|   | ||||
| @@ -664,6 +664,7 @@ static funcentry_T global_functions[] = | ||||
|     {"map",		2, 2, FEARG_1,	  ret_any,	f_map}, | ||||
|     {"maparg",		1, 4, FEARG_1,	  ret_string,	f_maparg}, | ||||
|     {"mapcheck",	1, 3, FEARG_1,	  ret_string,	f_mapcheck}, | ||||
|     {"mapset",		3, 3, FEARG_1,	  ret_void,	f_mapset}, | ||||
|     {"match",		2, 4, FEARG_1,	  ret_any,	f_match}, | ||||
|     {"matchadd",	2, 5, FEARG_1,	  ret_number,	f_matchadd}, | ||||
|     {"matchaddpos",	2, 5, FEARG_1,	  ret_number,	f_matchaddpos}, | ||||
|   | ||||
							
								
								
									
										222
									
								
								src/map.c
									
									
									
									
									
								
							
							
						
						
									
										222
									
								
								src/map.c
									
									
									
									
									
								
							| @@ -204,6 +204,86 @@ showmap( | ||||
|     out_flush();			// show one line at a time | ||||
| } | ||||
|  | ||||
|     static int | ||||
| map_add( | ||||
| 	mapblock_T  **map_table, | ||||
| 	mapblock_T  **abbr_table, | ||||
| 	char_u	    *keys, | ||||
| 	char_u	    *rhs, | ||||
| 	char_u	    *orig_rhs, | ||||
| 	int	    expr, | ||||
| 	int	    noremap, | ||||
| 	int	    nowait, | ||||
| 	int	    silent, | ||||
| 	int	    mode, | ||||
| 	int	    is_abbr, | ||||
| #ifdef FEAT_EVAL | ||||
| 	scid_T	    sid,	    // -1 to use current_sctx | ||||
| 	linenr_T    lnum, | ||||
| #endif | ||||
| 	int	    simplified) | ||||
| { | ||||
|     mapblock_T	*mp = ALLOC_ONE(mapblock_T); | ||||
|  | ||||
|     if (mp == NULL) | ||||
| 	return FAIL; | ||||
|  | ||||
|     // If CTRL-C has been mapped, don't always use it for Interrupting. | ||||
|     if (*keys == Ctrl_C) | ||||
|     { | ||||
| 	if (map_table == curbuf->b_maphash) | ||||
| 	    curbuf->b_mapped_ctrl_c |= mode; | ||||
| 	else | ||||
| 	    mapped_ctrl_c |= mode; | ||||
|     } | ||||
|  | ||||
|     mp->m_keys = vim_strsave(keys); | ||||
|     mp->m_str = vim_strsave(rhs); | ||||
|     mp->m_orig_str = vim_strsave(orig_rhs); | ||||
|     if (mp->m_keys == NULL || mp->m_str == NULL) | ||||
|     { | ||||
| 	vim_free(mp->m_keys); | ||||
| 	vim_free(mp->m_str); | ||||
| 	vim_free(mp->m_orig_str); | ||||
| 	vim_free(mp); | ||||
| 	return FAIL; | ||||
|     } | ||||
|     mp->m_keylen = (int)STRLEN(mp->m_keys); | ||||
|     mp->m_noremap = noremap; | ||||
|     mp->m_nowait = nowait; | ||||
|     mp->m_silent = silent; | ||||
|     mp->m_mode = mode; | ||||
|     mp->m_simplified = simplified; | ||||
| #ifdef FEAT_EVAL | ||||
|     mp->m_expr = expr; | ||||
|     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; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     // add the new entry in front of the abbrlist or maphash[] list | ||||
|     if (is_abbr) | ||||
|     { | ||||
| 	mp->m_next = *abbr_table; | ||||
| 	*abbr_table = mp; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	int n = MAP_HASH(mp->m_mode, mp->m_keys[0]); | ||||
|  | ||||
| 	mp->m_next = map_table[n]; | ||||
| 	map_table[n] = mp; | ||||
|     } | ||||
|     return OK; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * map[!]		    : show all key mappings | ||||
|  * map[!] {lhs}		    : show key mapping for {lhs} | ||||
| @@ -501,7 +581,8 @@ do_map( | ||||
| 	    msg_start(); | ||||
|  | ||||
| 	// Check if a new local mapping wasn't already defined globally. | ||||
| 	if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1) | ||||
| 	if (unique && map_table == curbuf->b_maphash | ||||
| 					   && haskey && hasarg && maptype != 1) | ||||
| 	{ | ||||
| 	    // need to loop over all global hash lists | ||||
| 	    for (hash = 0; hash < 256 && !got_int; ++hash) | ||||
| @@ -519,7 +600,6 @@ do_map( | ||||
| 		    // check entries with the same mode | ||||
| 		    if ((mp->m_mode & mode) != 0 | ||||
| 			    && mp->m_keylen == len | ||||
| 			    && unique | ||||
| 			    && STRNCMP(mp->m_keys, keys, (size_t)len) == 0) | ||||
| 		    { | ||||
| 			if (abbrev) | ||||
| @@ -759,57 +839,16 @@ do_map( | ||||
| 	    continue;	// have added the new entry already | ||||
|  | ||||
| 	// Get here when adding a new entry to the maphash[] list or abbrlist. | ||||
| 	mp = ALLOC_ONE(mapblock_T); | ||||
| 	if (mp == NULL) | ||||
| 	{ | ||||
| 	    retval = 4;	    // no mem | ||||
| 	    goto theend; | ||||
| 	} | ||||
|  | ||||
| 	// If CTRL-C has been mapped, don't always use it for Interrupting. | ||||
| 	if (*keys == Ctrl_C) | ||||
| 	{ | ||||
| 	    if (map_table == curbuf->b_maphash) | ||||
| 		curbuf->b_mapped_ctrl_c |= mode; | ||||
| 	    else | ||||
| 		mapped_ctrl_c |= mode; | ||||
| 	} | ||||
|  | ||||
| 	mp->m_keys = vim_strsave(keys); | ||||
| 	mp->m_str = vim_strsave(rhs); | ||||
| 	mp->m_orig_str = vim_strsave(orig_rhs); | ||||
| 	if (mp->m_keys == NULL || mp->m_str == NULL) | ||||
| 	{ | ||||
| 	    vim_free(mp->m_keys); | ||||
| 	    vim_free(mp->m_str); | ||||
| 	    vim_free(mp->m_orig_str); | ||||
| 	    vim_free(mp); | ||||
| 	    retval = 4;	// no mem | ||||
| 	    goto theend; | ||||
| 	} | ||||
| 	mp->m_keylen = (int)STRLEN(mp->m_keys); | ||||
| 	mp->m_noremap = noremap; | ||||
| 	mp->m_nowait = nowait; | ||||
| 	mp->m_silent = silent; | ||||
| 	mp->m_mode = mode; | ||||
| 	mp->m_simplified = did_simplify && keyround == 1; | ||||
| 	if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, expr, | ||||
| 		    noremap, nowait, silent, mode, | ||||
| 		    abbrev, | ||||
| #ifdef FEAT_EVAL | ||||
| 	mp->m_expr = expr; | ||||
| 	mp->m_script_ctx = current_sctx; | ||||
| 	mp->m_script_ctx.sc_lnum += SOURCING_LNUM; | ||||
| 		    /* sid */ -1, /* lnum */ 0, | ||||
| #endif | ||||
|  | ||||
| 	// add the new entry in front of the abbrlist or maphash[] list | ||||
| 	if (abbrev) | ||||
| 		    did_simplify && keyround == 1) == FAIL) | ||||
| 	{ | ||||
| 	    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; | ||||
| 	    retval = 4;	    // no mem | ||||
| 	    goto theend; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
| @@ -2209,13 +2248,96 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) | ||||
| 	dict_add_number(dict, "buffer", (long)buffer_local); | ||||
| 	dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L); | ||||
| 	dict_add_string(dict, "mode", mapmode); | ||||
| 	dict_add_number(dict, "simplified", mp->m_simplified); | ||||
|  | ||||
| 	vim_free(lhs); | ||||
| 	vim_free(mapmode); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * "mapset()" function | ||||
|  */ | ||||
|     void | ||||
| f_mapset(typval_T *argvars, typval_T *rettv UNUSED) | ||||
| { | ||||
|     char_u	*keys; | ||||
|     char_u	*keys_buf = NULL; | ||||
|     char_u	*which; | ||||
|     int		mode; | ||||
|     char_u	buf[NUMBUFLEN]; | ||||
|     int		is_abbr; | ||||
|     dict_T	*d; | ||||
|     char_u	*lhs; | ||||
|     char_u	*rhs; | ||||
|     int		noremap; | ||||
|     int		expr; | ||||
|     int		silent; | ||||
|     scid_T	sid; | ||||
|     linenr_T	lnum; | ||||
|     mapblock_T	**map_table = maphash; | ||||
|     mapblock_T  **abbr_table = &first_abbr; | ||||
|     int		nowait; | ||||
|     int		simplified; | ||||
|     char_u	*arg; | ||||
|  | ||||
|     which = tv_get_string_buf_chk(&argvars[0], buf); | ||||
|     mode = get_map_mode(&which, 0); | ||||
|     is_abbr = (int)tv_get_number(&argvars[1]); | ||||
|  | ||||
|     if (argvars[2].v_type != VAR_DICT) | ||||
|     { | ||||
| 	emsg(_(e_dictkey)); | ||||
| 	return; | ||||
|     } | ||||
|     d = argvars[2].vval.v_dict; | ||||
|  | ||||
|     // Get the values in the same order as above in get_maparg(). | ||||
|     lhs = dict_get_string(d, (char_u *)"lhs", FALSE); | ||||
|     if (lhs == NULL) | ||||
|     { | ||||
| 	emsg(_("E99: lhs entry missing in mapset() dict argument")); | ||||
| 	return; | ||||
|     } | ||||
|     rhs = dict_get_string(d, (char_u *)"rhs", FALSE); | ||||
|     if (rhs == NULL) | ||||
|     { | ||||
| 	emsg(_("E99: rhs entry missing in mapset() dict argument")); | ||||
| 	return; | ||||
|     } | ||||
|  | ||||
|     noremap = dict_get_number(d, (char_u *)"noremap") ? REMAP_NONE: 0; | ||||
|     if (dict_get_number(d, (char_u *)"script") != 0) | ||||
| 	noremap = REMAP_SCRIPT; | ||||
|     expr = dict_get_number(d, (char_u *)"expr") != 0; | ||||
|     silent = dict_get_number(d, (char_u *)"silent") != 0; | ||||
|     sid = dict_get_number(d, (char_u *)"sid"); | ||||
|     lnum = dict_get_number(d, (char_u *)"lnum"); | ||||
|     if (dict_get_number(d, (char_u *)"buffer")) | ||||
|     { | ||||
| 	map_table = curbuf->b_maphash; | ||||
| 	abbr_table = &curbuf->b_first_abbr; | ||||
|     } | ||||
|     nowait = dict_get_number(d, (char_u *)"nowait") != 0; | ||||
|     // mode from the dict is not used | ||||
|     simplified = dict_get_number(d, (char_u *)"simplified") != 0; | ||||
|  | ||||
|     // Delete any existing mapping for this lhs and mode. | ||||
|     arg = vim_strsave(lhs); | ||||
|     if (arg == NULL) | ||||
| 	return; | ||||
|     do_map(1, arg, mode, is_abbr); | ||||
|     vim_free(arg); | ||||
|  | ||||
|     keys = replace_termcodes(lhs, &keys_buf, | ||||
| 				      REPTERM_FROM_PART | REPTERM_DO_LT, NULL); | ||||
|     (void)map_add(map_table, abbr_table, keys, rhs, rhs, expr, | ||||
| 		noremap, nowait, silent, mode, is_abbr, sid, lnum, simplified); | ||||
|     vim_free(keys_buf); | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #if defined(MSWIN) || defined(MACOS_X) | ||||
|  | ||||
| # define VIS_SEL	(VISUAL+SELECTMODE)	// abbreviation | ||||
|   | ||||
| @@ -18,6 +18,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what); | ||||
| void check_map_keycodes(void); | ||||
| char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr, int *local_ptr); | ||||
| void get_maparg(typval_T *argvars, typval_T *rettv, int exact); | ||||
| void f_mapset(typval_T *argvars, typval_T *rettv); | ||||
| void init_mappings(void); | ||||
| void add_map(char_u *map, int mode); | ||||
| int langmap_adjust_mb(int c); | ||||
|   | ||||
| @@ -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 | ||||
| @@ -18,23 +18,23 @@ function Test_maparg() | ||||
|   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}, | ||||
| 	\ '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 | ||||
| @@ -75,7 +75,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')) | ||||
| @@ -116,7 +116,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 | ||||
| @@ -131,6 +131,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 | ||||
|   | ||||
| @@ -746,6 +746,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     807, | ||||
| /**/ | ||||
|     806, | ||||
| /**/ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user