Skip to content

Commit cdc8393

Browse files
zeertzjqbrammool
authored andcommitted
patch 9.0.0449: there is no easy way to translate a key code into a string
Problem: There is no easy way to translate a string with a key code into a readable string. Solution: Add the keytrans() function. (closes #11114)
1 parent 5a4eb55 commit cdc8393

File tree

9 files changed

+83
-15
lines changed

9 files changed

+83
-15
lines changed

runtime/doc/builtin.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ js_encode({expr}) String encode JS style JSON
325325
json_decode({string}) any decode JSON
326326
json_encode({expr}) String encode JSON
327327
keys({dict}) List keys in {dict}
328+
keytrans({string}) String translate internal keycodes to a form
329+
that can be used by |:map|
328330
len({expr}) Number the length of {expr}
329331
libcall({lib}, {func}, {arg}) String call {func} in library {lib} with {arg}
330332
libcallnr({lib}, {func}, {arg}) Number idem, but return a Number
@@ -5205,6 +5207,16 @@ keys({dict}) *keys()*
52055207
Can also be used as a |method|: >
52065208
mydict->keys()
52075209
5210+
keytrans({string}) *keytrans()*
5211+
Turn the internal byte representation of keys into a form that
5212+
can be used for |:map|. E.g. >
5213+
:let xx = "\<C-Home>"
5214+
:echo keytrans(xx)
5215+
< <C-Home>
5216+
5217+
Can also be used as a |method|: >
5218+
"\<C-Home>"->keytrans()
5219+
52085220
< *len()* *E701*
52095221
len({expr}) The result is a Number, which is the length of the argument.
52105222
When {expr} is a String or a Number the length in bytes is

src/evalfunc.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static void f_inputsecret(typval_T *argvars, typval_T *rettv);
8989
static void f_interrupt(typval_T *argvars, typval_T *rettv);
9090
static void f_invert(typval_T *argvars, typval_T *rettv);
9191
static void f_islocked(typval_T *argvars, typval_T *rettv);
92+
static void f_keytrans(typval_T *argvars, typval_T *rettv);
9293
static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
9394
static void f_libcall(typval_T *argvars, typval_T *rettv);
9495
static void f_libcallnr(typval_T *argvars, typval_T *rettv);
@@ -2058,6 +2059,8 @@ static funcentry_T global_functions[] =
20582059
ret_string, f_json_encode},
20592060
{"keys", 1, 1, FEARG_1, arg1_dict_any,
20602061
ret_list_string, f_keys},
2062+
{"keytrans", 1, 1, FEARG_1, arg1_string,
2063+
ret_string, f_keytrans},
20612064
{"last_buffer_nr", 0, 0, 0, NULL, // obsolete
20622065
ret_number, f_last_buffer_nr},
20632066
{"len", 1, 1, FEARG_1, arg1_len,
@@ -7135,6 +7138,24 @@ f_islocked(typval_T *argvars, typval_T *rettv)
71357138
clear_lval(&lv);
71367139
}
71377140

7141+
/*
7142+
* "keytrans()" function
7143+
*/
7144+
static void
7145+
f_keytrans(typval_T *argvars, typval_T *rettv)
7146+
{
7147+
char_u *escaped;
7148+
7149+
rettv->v_type = VAR_STRING;
7150+
if (check_for_string_arg(argvars, 0) == FAIL
7151+
|| argvars[0].vval.v_string == NULL)
7152+
return;
7153+
// Need to escape K_SPECIAL and CSI for mb_unescape().
7154+
escaped = vim_strsave_escape_csi(argvars[0].vval.v_string);
7155+
rettv->vval.v_string = str2special_save(escaped, TRUE, TRUE);
7156+
vim_free(escaped);
7157+
}
7158+
71387159
/*
71397160
* "last_buffer_nr()" function.
71407161
*/

src/map.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2317,7 +2317,7 @@ mapblock2dict(
23172317
int buffer_local, // false if not buffer local mapping
23182318
int abbr) // true if abbreviation
23192319
{
2320-
char_u *lhs = str2special_save(mp->m_keys, TRUE);
2320+
char_u *lhs = str2special_save(mp->m_keys, TRUE, FALSE);
23212321
char_u *mapmode = map_mode_to_chars(mp->m_mode);
23222322

23232323
dict_add_string(dict, "lhs", lhs);
@@ -2409,7 +2409,7 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact)
24092409
if (*rhs == NUL)
24102410
rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
24112411
else
2412-
rettv->vval.v_string = str2special_save(rhs, FALSE);
2412+
rettv->vval.v_string = str2special_save(rhs, FALSE, FALSE);
24132413
}
24142414

24152415
}
@@ -2478,7 +2478,7 @@ f_maplist(typval_T *argvars UNUSED, typval_T *rettv)
24782478
keys_buf = NULL;
24792479
did_simplify = FALSE;
24802480

2481-
lhs = str2special_save(mp->m_keys, TRUE);
2481+
lhs = str2special_save(mp->m_keys, TRUE, FALSE);
24822482
(void)replace_termcodes(lhs, &keys_buf, flags, &did_simplify);
24832483
vim_free(lhs);
24842484

src/menu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2890,7 +2890,7 @@ menuitem_getinfo(char_u *menu_name, vimmenu_T *menu, int modes, dict_T *dict)
28902890
*menu->strings[bit] == NUL
28912891
? (char_u *)"<Nop>"
28922892
: (tofree = str2special_save(
2893-
menu->strings[bit], FALSE)));
2893+
menu->strings[bit], FALSE, FALSE)));
28942894
vim_free(tofree);
28952895
}
28962896
if (status == OK)

src/message.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,7 +1759,7 @@ msg_outtrans_special(
17591759
++str;
17601760
}
17611761
else
1762-
text = (char *)str2special(&str, from);
1762+
text = (char *)str2special(&str, from, FALSE);
17631763
if (text[0] != NUL && text[1] == NUL)
17641764
// single-byte character or illegal byte
17651765
text = (char *)transchar_byte((char_u)text[0]);
@@ -1782,14 +1782,16 @@ msg_outtrans_special(
17821782
char_u *
17831783
str2special_save(
17841784
char_u *str,
1785-
int is_lhs) // TRUE for lhs, FALSE for rhs
1785+
int replace_spaces, // TRUE to replace " " with "<Space>".
1786+
// used for the lhs of mapping and keytrans().
1787+
int replace_lt) // TRUE to replace "<" with "<lt>".
17861788
{
17871789
garray_T ga;
17881790
char_u *p = str;
17891791

17901792
ga_init2(&ga, 1, 40);
17911793
while (*p != NUL)
1792-
ga_concat(&ga, str2special(&p, is_lhs));
1794+
ga_concat(&ga, str2special(&p, replace_spaces, replace_lt));
17931795
ga_append(&ga, NUL);
17941796
return (char_u *)ga.ga_data;
17951797
}
@@ -1804,7 +1806,9 @@ str2special_save(
18041806
char_u *
18051807
str2special(
18061808
char_u **sp,
1807-
int from) // TRUE for lhs of mapping
1809+
int replace_spaces, // TRUE to replace " " with "<Space>".
1810+
// used for the lhs of mapping and keytrans().
1811+
int replace_lt) // TRUE to replace "<" with "<lt>".
18081812
{
18091813
int c;
18101814
static char_u buf[7];
@@ -1861,8 +1865,10 @@ str2special(
18611865
*sp = str + (*str == NUL ? 0 : 1);
18621866

18631867
// Make special keys and C0 control characters in <> form, also <M-Space>.
1864-
// Use <Space> only for lhs of a mapping.
1865-
if (special || c < ' ' || (from && c == ' '))
1868+
if (special
1869+
|| c < ' '
1870+
|| (replace_spaces && c == ' ')
1871+
|| (replace_lt && c == '<'))
18661872
return get_special_key_name(c, modifiers);
18671873
buf[0] = c;
18681874
buf[1] = NUL;
@@ -1880,7 +1886,7 @@ str2specialbuf(char_u *sp, char_u *buf, int len)
18801886
*buf = NUL;
18811887
while (*sp)
18821888
{
1883-
s = str2special(&sp, FALSE);
1889+
s = str2special(&sp, FALSE, FALSE);
18841890
if ((int)(STRLEN(s) + STRLEN(buf)) < len)
18851891
STRCAT(buf, s);
18861892
}

src/option.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3994,7 +3994,8 @@ get_option_value(
39943994
if (stringval != NULL)
39953995
{
39963996
if ((char_u **)varp == &p_pt) // 'pastetoggle'
3997-
*stringval = str2special_save(*(char_u **)(varp), FALSE);
3997+
*stringval = str2special_save(*(char_u **)(varp), FALSE,
3998+
FALSE);
39983999
#ifdef FEAT_CRYPT
39994000
// never return the value of the crypt key
40004001
else if ((char_u **)varp == &curbuf->b_p_key
@@ -4879,7 +4880,7 @@ put_setstring(
48794880
{
48804881
s = *valuep;
48814882
while (*s != NUL)
4882-
if (put_escstr(fd, str2special(&s, FALSE), 2) == FAIL)
4883+
if (put_escstr(fd, str2special(&s, FALSE, FALSE), 2) == FAIL)
48834884
return FAIL;
48844885
}
48854886
// expand the option value, replace $HOME by ~

src/proto/message.pro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ char_u *msg_outtrans_one(char_u *p, int attr);
3737
int msg_outtrans_len_attr(char_u *msgstr, int len, int attr);
3838
void msg_make(char_u *arg);
3939
int msg_outtrans_special(char_u *strstart, int from, int maxlen);
40-
char_u *str2special_save(char_u *str, int is_lhs);
41-
char_u *str2special(char_u **sp, int from);
40+
char_u *str2special_save(char_u *str, int replace_spaces, int replace_lt);
41+
char_u *str2special(char_u **sp, int replace_spaces, int replace_lt);
4242
void str2specialbuf(char_u *sp, char_u *buf, int len);
4343
void msg_prt_line(char_u *s, int list);
4444
void msg_puts(char *s);

src/testdir/test_functions.vim

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2764,6 +2764,32 @@ func Test_eval()
27642764
call assert_fails("call eval('5 a')", 'E488:')
27652765
endfunc
27662766

2767+
" Test for the keytrans() function
2768+
func Test_keytrans()
2769+
call assert_equal('<Space>', keytrans(' '))
2770+
call assert_equal('<lt>', keytrans('<'))
2771+
call assert_equal('<lt>Tab>', keytrans('<Tab>'))
2772+
call assert_equal('<Tab>', keytrans("\<Tab>"))
2773+
call assert_equal('<C-V>', keytrans("\<C-V>"))
2774+
call assert_equal('<BS>', keytrans("\<BS>"))
2775+
call assert_equal('<Home>', keytrans("\<Home>"))
2776+
call assert_equal('<C-Home>', keytrans("\<C-Home>"))
2777+
call assert_equal('<M-Home>', keytrans("\<M-Home>"))
2778+
call assert_equal('<C-Space>', keytrans("\<C-Space>"))
2779+
call assert_equal('<M-Space>', keytrans("\<*M-Space>"))
2780+
call assert_equal('<M-x>', "\<*M-x>"->keytrans())
2781+
call assert_equal('<C-I>', "\<*C-I>"->keytrans())
2782+
call assert_equal('<S-3>', "\<*S-3>"->keytrans())
2783+
call assert_equal('π', 'π'->keytrans())
2784+
call assert_equal('<M-π>', "\<M-π>"->keytrans())
2785+
call assert_equal('ě', 'ě'->keytrans())
2786+
call assert_equal('<M-ě>', "\<M-ě>"->keytrans())
2787+
call assert_equal('', ''->keytrans())
2788+
call assert_equal('', test_null_string()->keytrans())
2789+
call assert_fails('call keytrans(1)', 'E1174:')
2790+
call assert_fails('call keytrans()', 'E119:')
2791+
endfunc
2792+
27672793
" Test for the nr2char() function
27682794
func Test_nr2char()
27692795
set encoding=latin1

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ static char *(features[]) =
703703

704704
static int included_patches[] =
705705
{ /* Add new patch number below this line */
706+
/**/
707+
449,
706708
/**/
707709
448,
708710
/**/

0 commit comments

Comments
 (0)