summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt44
-rw-r--r--src/eval.c43
-rw-r--r--src/getchar.c126
-rw-r--r--src/gui_w48.c6
-rw-r--r--src/message.c21
-rw-r--r--src/proto/getchar.pro3
-rw-r--r--src/proto/message.pro1
-rw-r--r--src/structs.h5
-rw-r--r--src/testdir/test75.in16
-rw-r--r--src/testdir/test75.ok3
-rw-r--r--src/version.c2
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,