diff options
-rw-r--r-- | runtime/doc/eval.txt | 44 | ||||
-rw-r--r-- | src/eval.c | 43 | ||||
-rw-r--r-- | src/getchar.c | 126 | ||||
-rw-r--r-- | src/gui_w48.c | 6 | ||||
-rw-r--r-- | src/message.c | 21 | ||||
-rw-r--r-- | src/proto/getchar.pro | 3 | ||||
-rw-r--r-- | src/proto/message.pro | 1 | ||||
-rw-r--r-- | src/structs.h | 5 | ||||
-rw-r--r-- | src/testdir/test75.in | 16 | ||||
-rw-r--r-- | src/testdir/test75.ok | 3 | ||||
-rw-r--r-- | src/version.c | 2 |
11 files changed, 196 insertions, 74 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index d37fe2ab3..d1a1ba3f2 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1827,7 +1827,7 @@ localtime() Number current time log( {expr}) Float natural logarithm (base e) of {expr} log10( {expr}) Float logarithm of Float {expr} to base 10 map( {expr}, {string}) List/Dict change each item in {expr} to {expr} -maparg( {name}[, {mode} [, {abbr}]]) +maparg( {name}[, {mode} [, {abbr} [, {dict}]]]) String rhs of mapping {name} in mode {mode} mapcheck( {name}[, {mode} [, {abbr}]]) String check for mappings matching {name} @@ -3972,23 +3972,51 @@ map({expr}, {string}) *map()* further items in {expr} are processed. -maparg({name}[, {mode} [, {abbr}]]) *maparg()* - Return the rhs of mapping {name} in mode {mode}. When there - is no mapping for {name}, an empty String is returned. +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 + characters translated like in the output of the ":map" command + listing. + + When there is no mapping for {name}, an empty String is + returned. + + The {name} can have special key names, like in the ":map" + command. + {mode} can be one of these strings: "n" Normal - "v" Visual + "v" Visual (including Select) "o" Operator-pending "i" Insert "c" Cmd-line + "s" Select + "x" Visual "l" langmap |language-mapping| "" Normal, Visual and Operator-pending When {mode} is omitted, the modes for "" are used. + When {abbr} is there and it is non-zero use abbreviations instead of mappings. - The {name} can have special key names, like in the ":map" - command. The returned String has special characters - translated like in the output of the ":map" command listing. + + When {dict} is there and it is non-zero return a dictionary + containing all the information of the mapping with the + following items: + "lhs" The {lhs} of the mapping. + "rhs" The {rhs} of the mapping as typed. + "silent" 1 for a |:map-silent| mapping, else 0. + "noremap" 1 if the {rhs} of the mapping is remappable. + "expr" 1 for an expression mapping (|:map-<expr>|). + "buffer" 1 for a buffer local mapping (|:map-local|). + "mode" Modes for which the mapping is defined. In + addition to the modes mentioned above, these + characters will be used: + " " Normal, Visual and Operator-pending + "!" Insert and Commandline mode + (|mapmpde-ic|) + "sid" the Script local ID, used for <sid> mappings + (|<SID>|) + The mappings local to the current buffer are checked first, then the global mappings. This function can be used to map a key even when it's already diff --git a/src/eval.c b/src/eval.c index 1216dc672..d7cee7435 100644 --- a/src/eval.c +++ b/src/eval.c @@ -7804,7 +7804,7 @@ static struct fst {"log10", 1, 1, f_log10}, #endif {"map", 2, 2, f_map}, - {"maparg", 1, 3, f_maparg}, + {"maparg", 1, 4, f_maparg}, {"mapcheck", 1, 3, f_mapcheck}, {"match", 2, 4, f_match}, {"matchadd", 2, 4, f_matchadd}, @@ -13292,8 +13292,10 @@ get_maparg(argvars, rettv, exact) char_u *keys_buf = NULL; char_u *rhs; int mode; - garray_T ga; int abbr = FALSE; + int get_dict = FALSE; + mapblock_T *mp; + int buffer_local; /* return empty string for failure */ rettv->v_type = VAR_STRING; @@ -13307,7 +13309,11 @@ get_maparg(argvars, rettv, exact) { which = get_tv_string_buf_chk(&argvars[1], buf); if (argvars[2].v_type != VAR_UNKNOWN) + { abbr = get_tv_number(&argvars[2]); + if (argvars[3].v_type != VAR_UNKNOWN) + get_dict = get_tv_number(&argvars[3]); + } } else which = (char_u *)""; @@ -13317,19 +13323,34 @@ get_maparg(argvars, rettv, exact) mode = get_map_mode(&which, 0); keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); - rhs = check_map(keys, mode, exact, FALSE, abbr); + rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); vim_free(keys_buf); - if (rhs != NULL) + + if (!get_dict) { - ga_init(&ga); - ga.ga_itemsize = 1; - ga.ga_growsize = 40; + /* Return a string. */ + if (rhs != NULL) + rettv->vval.v_string = str2special_save(rhs, FALSE); - while (*rhs != NUL) - ga_concat(&ga, str2special(&rhs, FALSE)); + } + else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL) + { + /* Return a dictionary. */ + char_u *lhs = str2special_save(mp->m_keys, TRUE); + char_u *mapmode = map_mode_to_chars(mp->m_mode); + dict_T *dict = rettv->vval.v_dict; - ga_append(&ga, NUL); - rettv->vval.v_string = (char_u *)ga.ga_data; + dict_add_nr_str(dict, "lhs", 0L, lhs); + dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str); + dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL); + dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL); + dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL); + dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL); + dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL); + dict_add_nr_str(dict, "mode", 0L, mapmode); + + vim_free(lhs); + vim_free(mapmode); } } diff --git a/src/getchar.c b/src/getchar.c index c892b4645..8462517cd 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -3168,6 +3168,7 @@ do_map(maptype, arg, mode, abbrev) int expr = FALSE; #endif int noremap; + char_u *orig_rhs; keys = arg; map_table = maphash; @@ -3266,6 +3267,7 @@ do_map(maptype, arg, mode, abbrev) } if (*p != NUL) *p++ = NUL; + p = skipwhite(p); rhs = p; hasarg = (*rhs != NUL); @@ -3290,6 +3292,7 @@ do_map(maptype, arg, mode, abbrev) keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special); if (hasarg) { + orig_rhs = rhs; if (STRICMP(rhs, "<nop>") == 0) /* "<Nop>" means nothing */ rhs = (char_u *)""; else @@ -3298,7 +3301,7 @@ do_map(maptype, arg, mode, abbrev) #ifdef FEAT_FKMAP /* - * when in right-to-left mode and alternate keymap option set, + * When in right-to-left mode and alternate keymap option set, * reverse the character flow in the rhs in Farsi. */ if (p_altkeymap && curwin->w_p_rl) @@ -3556,6 +3559,8 @@ do_map(maptype, arg, mode, abbrev) } vim_free(mp->m_str); mp->m_str = newstr; + vim_free(mp->m_orig_str); + mp->m_orig_str = vim_strsave(orig_rhs); mp->m_noremap = noremap; mp->m_silent = silent; mp->m_mode = mode; @@ -3633,10 +3638,12 @@ do_map(maptype, arg, mode, abbrev) 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; @@ -3682,6 +3689,7 @@ map_free(mpp) mp = *mpp; vim_free(mp->m_keys); vim_free(mp->m_str); + vim_free(mp->m_orig_str); *mpp = mp->m_next; vim_free(mp); } @@ -3851,12 +3859,57 @@ map_clear_int(buf, mode, local, abbr) } } +/* + * Return characters to represent the map mode in an allocated string. + * Returns NULL when out of memory. + */ + char_u * +map_mode_to_chars(mode) + int mode; +{ + garray_T mapmode; + + ga_init2(&mapmode, 1, 7); + + if ((mode & (INSERT + CMDLINE)) == INSERT + CMDLINE) + ga_append(&mapmode, '!'); /* :map! */ + else if (mode & INSERT) + ga_append(&mapmode, 'i'); /* :imap */ + else if (mode & LANGMAP) + ga_append(&mapmode, 'l'); /* :lmap */ + else if (mode & CMDLINE) + ga_append(&mapmode, 'c'); /* :cmap */ + else if ((mode & (NORMAL + VISUAL + SELECTMODE + OP_PENDING)) + == NORMAL + VISUAL + SELECTMODE + OP_PENDING) + ga_append(&mapmode, ' '); /* :map */ + else + { + if (mode & NORMAL) + ga_append(&mapmode, 'n'); /* :nmap */ + if (mode & OP_PENDING) + ga_append(&mapmode, 'o'); /* :omap */ + if ((mode & (VISUAL + SELECTMODE)) == VISUAL + SELECTMODE) + ga_append(&mapmode, 'v'); /* :vmap */ + else + { + if (mode & VISUAL) + ga_append(&mapmode, 'x'); /* :xmap */ + if (mode & SELECTMODE) + ga_append(&mapmode, 's'); /* :smap */ + } + } + + ga_append(&mapmode, NUL); + return (char_u *)mapmode.ga_data; +} + static void showmap(mp, local) mapblock_T *mp; int local; /* TRUE for buffer-local map */ { - int len = 1; + int len = 1; + char_u *mapchars; if (msg_didout || msg_silent != 0) { @@ -3864,49 +3917,15 @@ showmap(mp, local) if (got_int) /* 'q' typed at MORE prompt */ return; } - if ((mp->m_mode & (INSERT + CMDLINE)) == INSERT + CMDLINE) - msg_putchar('!'); /* :map! */ - else if (mp->m_mode & INSERT) - msg_putchar('i'); /* :imap */ - else if (mp->m_mode & LANGMAP) - msg_putchar('l'); /* :lmap */ - else if (mp->m_mode & CMDLINE) - msg_putchar('c'); /* :cmap */ - else if ((mp->m_mode & (NORMAL + VISUAL + SELECTMODE + OP_PENDING)) - == NORMAL + VISUAL + SELECTMODE + OP_PENDING) - msg_putchar(' '); /* :map */ - else + + mapchars = map_mode_to_chars(mp->m_mode); + if (mapchars != NULL) { - len = 0; - if (mp->m_mode & NORMAL) - { - msg_putchar('n'); /* :nmap */ - ++len; - } - if (mp->m_mode & OP_PENDING) - { - msg_putchar('o'); /* :omap */ - ++len; - } - if ((mp->m_mode & (VISUAL + SELECTMODE)) == VISUAL + SELECTMODE) - { - msg_putchar('v'); /* :vmap */ - ++len; - } - else - { - if (mp->m_mode & VISUAL) - { - msg_putchar('x'); /* :xmap */ - ++len; - } - if (mp->m_mode & SELECTMODE) - { - msg_putchar('s'); /* :smap */ - ++len; - } - } + msg_puts(mapchars); + len = STRLEN(mapchars); + vim_free(mapchars); } + while (++len <= 3) msg_putchar(' '); @@ -3931,8 +3950,7 @@ showmap(mp, local) msg_putchar(' '); /* Use FALSE below if we only want things like <Up> to show up as such on - * the rhs, and not M-x etc, TRUE gets both -- webb - */ + * the rhs, and not M-x etc, TRUE gets both -- webb */ if (*mp->m_str == NUL) msg_puts_attr((char_u *)"<Nop>", hl_attr(HLF_8)); else @@ -4995,19 +5013,21 @@ check_map_keycodes() sourcing_name = save_name; } -#ifdef FEAT_EVAL +#if defined(FEAT_EVAL) || defined(PROTO) /* - * Check the string "keys" against the lhs of all mappings - * Return pointer to rhs of mapping (mapblock->m_str) - * NULL otherwise + * Check the string "keys" against the lhs of all mappings. + * Return pointer to rhs of mapping (mapblock->m_str). + * NULL when no mapping found. */ char_u * -check_map(keys, mode, exact, ign_mod, abbr) +check_map(keys, mode, exact, ign_mod, abbr, mp_ptr, local_ptr) char_u *keys; int mode; int exact; /* require exact match */ int ign_mod; /* ignore preceding modifier */ int abbr; /* do abbreviations */ + mapblock_T **mp_ptr; /* return: pointer to mapblock or NULL */ + int *local_ptr; /* return: buffer-local mapping or NULL */ { int hash; int len, minlen; @@ -5062,7 +5082,13 @@ check_map(keys, mode, exact, ign_mod, abbr) minlen = mp->m_keylen - 3; } if (STRNCMP(s, keys, minlen) == 0) + { + if (mp_ptr != NULL) + *mp_ptr = mp; + if (local_ptr != NULL) + *local_ptr = local; return mp->m_str; + } } } } diff --git a/src/gui_w48.c b/src/gui_w48.c index 80b75ff38..445104dae 100644 --- a/src/gui_w48.c +++ b/src/gui_w48.c @@ -1810,7 +1810,8 @@ process_message(void) * mapped we want to use the mapping instead. */ if (vk == VK_F10 && gui.menu_is_active - && check_map(k10, State, FALSE, TRUE, FALSE) == NULL) + && check_map(k10, State, FALSE, TRUE, FALSE, + NULL, NULL) == NULL) break; #endif if (GetKeyState(VK_SHIFT) & 0x8000) @@ -1924,7 +1925,8 @@ process_message(void) /* Check for <F10>: Default effect is to select the menu. When <F10> is * mapped we need to stop it here to avoid strange effects (e.g., for the * key-up event) */ - if (vk != VK_F10 || check_map(k10, State, FALSE, TRUE, FALSE) == NULL) + if (vk != VK_F10 || check_map(k10, State, FALSE, TRUE, FALSE, + NULL, NULL) == NULL) #endif DispatchMessage(&msg); } diff --git a/src/message.c b/src/message.c index c33b173b8..ac81948f2 100644 --- a/src/message.c +++ b/src/message.c @@ -1477,6 +1477,27 @@ msg_outtrans_special(strstart, from) return retval; } +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Return the lhs or rhs of a mapping, with the key codes turned into printable + * strings, in an allocated string. + */ + char_u * +str2special_save(str, is_lhs) + char_u *str; + int is_lhs; /* TRUE for lhs, FALSE for rhs */ +{ + garray_T ga; + char_u *p = str; + + ga_init2(&ga, 1, 40); + while (*p != NUL) + ga_concat(&ga, str2special(&p, is_lhs)); + ga_append(&ga, NUL); + return (char_u *)ga.ga_data; +} +#endif + /* * Return the printable string for the key codes at "*sp". * Used for translating the lhs or rhs of a mapping to printable chars. diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro index 06081c321..a304bafa5 100644 --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -51,6 +51,7 @@ int do_map __ARGS((int maptype, char_u *arg, int mode, int abbrev)); int get_map_mode __ARGS((char_u **cmdp, int forceit)); void map_clear __ARGS((char_u *cmdp, char_u *arg, int forceit, int abbr)); void map_clear_int __ARGS((buf_T *buf, int mode, int local, int abbr)); +char_u *map_mode_to_chars __ARGS((int mode)); int map_to_exists __ARGS((char_u *str, char_u *modechars, int abbr)); int map_to_exists_mode __ARGS((char_u *rhs, int mode, int abbr)); char_u *set_context_in_map_cmd __ARGS((expand_T *xp, char_u *cmd, char_u *arg, int forceit, int isabbrev, int isunmap, cmdidx_T cmdidx)); @@ -61,7 +62,7 @@ void vim_unescape_csi __ARGS((char_u *p)); int makemap __ARGS((FILE *fd, buf_T *buf)); int put_escstr __ARGS((FILE *fd, char_u *strstart, int what)); void check_map_keycodes __ARGS((void)); -char_u *check_map __ARGS((char_u *keys, int mode, int exact, int ign_mod, int abbr)); +char_u *check_map __ARGS((char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr, int *local_ptr)); void init_mappings __ARGS((void)); void add_map __ARGS((char_u *map, int mode)); /* vim: set ft=c : */ diff --git a/src/proto/message.pro b/src/proto/message.pro index 09b9152b7..a752ddcf5 100644 --- a/src/proto/message.pro +++ b/src/proto/message.pro @@ -33,6 +33,7 @@ char_u *msg_outtrans_one __ARGS((char_u *p, int attr)); int msg_outtrans_len_attr __ARGS((char_u *msgstr, int len, int attr)); void msg_make __ARGS((char_u *arg)); int msg_outtrans_special __ARGS((char_u *strstart, int from)); +char_u *str2special_save __ARGS((char_u *str, int is_lhs)); char_u *str2special __ARGS((char_u **sp, int from)); void str2specialbuf __ARGS((char_u *sp, char_u *buf, int len)); void msg_prt_line __ARGS((char_u *s, int list)); diff --git a/src/structs.h b/src/structs.h index 884d6a9fe..aa93aaedc 100644 --- a/src/structs.h +++ b/src/structs.h @@ -979,9 +979,10 @@ typedef struct mapblock mapblock_T; struct mapblock { mapblock_T *m_next; /* next mapblock in list */ - char_u *m_keys; /* mapped from */ + char_u *m_keys; /* mapped from, lhs */ int m_keylen; /* strlen(m_keys) */ - char_u *m_str; /* mapped to */ + char_u *m_str; /* mapped to, rhs */ + char_u *m_orig_str; /* rhs as entered by the user */ int m_mode; /* valid mode */ int m_noremap; /* if non-zero no re-mapping for m_str */ char m_silent; /* <silent> used, don't echo commands */ diff --git a/src/testdir/test75.in b/src/testdir/test75.in new file mode 100644 index 000000000..2de7a089b --- /dev/null +++ b/src/testdir/test75.in @@ -0,0 +1,16 @@ +" Tests for functions. + +STARTTEST +:so small.vim +:" Test maparg() with a string result +:map foo<C-V> is<F4>foo +:vnoremap <script> <buffer> <expr> <silent> bar isbar +:call append('$', maparg('foo<C-V>')) +:call append('$', string(maparg('foo<C-V>', '', 0, 1))) +:call append('$', string(maparg('bar', '', 0, 1))) +:" +:/^eof/+1,$w! test.out +:qa! +ENDTEST + +eof diff --git a/src/testdir/test75.ok b/src/testdir/test75.ok new file mode 100644 index 000000000..791656377 --- /dev/null +++ b/src/testdir/test75.ok @@ -0,0 +1,3 @@ +is<F4>foo +{'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>', 'mode': ' ', 'expr': 0, 'sid': 0, 'rhs': 'is<F4>foo', 'buffer': 0} +{'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v', 'expr': 1, 'sid': 0, 'rhs': 'isbar', 'buffer': 1} diff --git a/src/version.c b/src/version.c index e5164d362..d8e9a519f 100644 --- a/src/version.c +++ b/src/version.c @@ -715,6 +715,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 32, +/**/ 31, /**/ 30, |