To: vim_dev@googlegroups.com Subject: Patch 8.2.0807 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0807 Problem: Cannot easily restore a mapping. Solution: Add mapset(). Files: runtime/doc/eval.txt, src/map.c, src/proto/map.pro, src/evalfunc.c src/testdir/test_maparg.vim *** ../vim-8.2.0806/runtime/doc/eval.txt 2020-05-13 16:34:10.397723799 +0200 --- runtime/doc/eval.txt 2020-05-22 12:52:07.920142788 +0200 *************** *** 2582,2587 **** --- 2586,2593 ---- 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}]]]) *************** *** 6785,6790 **** --- 6797,6803 ---- 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 *************** *** 6835,6840 **** --- 6848,6857 ---- "lnum" The line number in "sid", zero if unknown. "nowait" Do not wait for other, longer mappings. (|:map-|). + "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. *************** *** 6881,6886 **** --- 6898,6915 ---- 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 *************** *** 7200,7210 **** Returns an empty dictionary if the menu item is not found. Examples: > ! :echo maparg('Edit.Cut') ! :echo maparg('File.Save', 'n') < Can also be used as a |method|: > ! GetMenuName()->maparg('v') < *min()* --- 7233,7243 ---- Returns an empty dictionary if the menu item is not found. Examples: > ! :echo menu_info('Edit.Cut') ! :echo menu_info('File.Save', 'n') < Can also be used as a |method|: > ! GetMenuName()->menu_info('v') < *min()* *************** *** 7757,7763 **** GetExpr()->range() < ! rand([{expr}]) *rand()* Return a pseudo-random Number generated with an xoshiro128** algorithm using seed {expr}. The returned number is 32 bits, also on 64 bits systems, for consistency. --- 7790,7796 ---- GetExpr()->range() < ! rand([{expr}]) *rand()* *random* Return a pseudo-random Number generated with an xoshiro128** algorithm using seed {expr}. The returned number is 32 bits, also on 64 bits systems, for consistency. *** ../vim-8.2.0806/src/map.c 2020-04-30 22:29:36.626024141 +0200 --- src/map.c 2020-05-22 13:01:00.430155164 +0200 *************** *** 204,209 **** --- 204,289 ---- 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,507 **** msg_start(); // Check if a new local mapping wasn't already defined globally. ! if (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) --- 581,588 ---- msg_start(); // Check if a new local mapping wasn't already defined globally. ! 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,525 **** // 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) --- 600,605 ---- *************** *** 759,815 **** 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; #ifdef FEAT_EVAL ! mp->m_expr = expr; ! 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 (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; } } --- 839,854 ---- continue; // have added the new entry already // Get here when adding a new entry to the maphash[] list or abbrlist. ! if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, expr, ! noremap, nowait, silent, mode, ! abbrev, #ifdef FEAT_EVAL ! /* sid */ -1, /* lnum */ 0, #endif ! did_simplify && keyround == 1) == FAIL) { ! retval = 4; // no mem ! goto theend; } } *************** *** 2209,2221 **** --- 2248,2343 ---- 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 *** ../vim-8.2.0806/src/proto/map.pro 2019-12-12 12:55:26.000000000 +0100 --- src/proto/map.pro 2020-05-21 22:21:13.598255655 +0200 *************** *** 18,23 **** --- 18,24 ---- 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); *** ../vim-8.2.0806/src/evalfunc.c 2020-05-14 22:41:10.229637563 +0200 --- src/evalfunc.c 2020-05-21 23:29:43.048018776 +0200 *************** *** 664,669 **** --- 664,670 ---- {"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}, *** ../vim-8.2.0806/src/testdir/test_maparg.vim 2020-04-01 19:22:06.522507242 +0200 --- src/testdir/test_maparg.vim 2020-05-22 13:04:04.637486342 +0200 *************** *** 1,12 **** ! " Tests for maparg(). " Also test utf8 map with a 0x80 byte. " Also test mapcheck() ! function s:SID() return str2nr(matchstr(expand(''), '\zs\d\+\ze_SID$')) ! endfun ! function Test_maparg() new set cpo-=< set encoding=utf8 --- 1,12 ---- ! " Tests for maparg(), mapcheck() and mapset(). " Also test utf8 map with a 0x80 byte. " Also test mapcheck() ! func s:SID() return str2nr(matchstr(expand(''), '\zs\d\+\ze_SID$')) ! endfunc ! funct Test_maparg() new set cpo-=< set encoding=utf8 *************** *** 18,40 **** call assert_equal("isfoo", maparg('foo')) call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, ! \ 'rhs': 'isfoo', 'buffer': 0}, \ maparg('foo', '', 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}, \ 'bar'->maparg('', 0, 1)) let lnum = expand('') map 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}, \ maparg('foo', '', 0, 1)) let lnum = expand('') 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}, \ maparg('baz', 't', 0, 1)) map abc xx --- 18,40 ---- call assert_equal("isfoo", maparg('foo')) call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, ! \ 'simplified': 1, 'rhs': 'isfoo', 'buffer': 0}, \ maparg('foo', '', 0, 1)) call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v', \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2, ! \ 'simplified': 0, 'rhs': 'isbar', 'buffer': 1}, \ 'bar'->maparg('', 0, 1)) let lnum = expand('') map 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', ! \ 'simplified': 0, 'buffer': 1}, \ maparg('foo', '', 0, 1)) let lnum = expand('') 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', ! \ 'simplified': 0, 'buffer': 0}, \ maparg('baz', 't', 0, 1)) map abc xx *************** *** 75,81 **** let d = maparg('esc', 'i', 1, 1) call assert_equal(['esc', "\\\", '!'], [d.lhs, d.rhs, d.mode]) abclear ! endfunction func Test_mapcheck() call assert_equal('', mapcheck('a')) --- 75,81 ---- let d = maparg('esc', 'i', 1, 1) call assert_equal(['esc', "\\\", '!'], [d.lhs, d.rhs, d.mode]) abclear ! endfunc func Test_mapcheck() call assert_equal('', mapcheck('a')) *************** *** 116,122 **** unabbr ab endfunc ! function Test_range_map() new " Outside of the range, minimum inoremap a --- 116,122 ---- unabbr ab endfunc ! func Test_range_map() new " Outside of the range, minimum inoremap a *************** *** 131,136 **** inoremap d execute "normal a\uf040\" call assert_equal("abcd", getline(1)) ! endfunction " vim: shiftwidth=2 sts=2 expandtab --- 131,161 ---- inoremap d execute "normal a\uf040\" call assert_equal("abcd", getline(1)) ! endfunc ! ! func One_mapset_test(keys) ! exe 'nnoremap ' .. a:keys .. ' original' ! let orig = maparg(a:keys, 'n', 0, 1) ! call assert_equal(a:keys, orig.lhs) ! call assert_equal('original', 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', 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('') ! endfunc " vim: shiftwidth=2 sts=2 expandtab *** ../vim-8.2.0806/src/version.c 2020-05-21 21:50:54.180651652 +0200 --- src/version.c 2020-05-22 13:08:00.584637022 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 807, /**/ -- hundred-and-one symptoms of being an internet addict: 154. You fondle your mouse. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///