diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-09-12 13:38:41 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-09-12 13:38:41 +0100 |
commit | cdc839353f68ca43db6446e1b727fc7ba657b738 (patch) | |
tree | 0729860faa774e594b183ce0823ae23776b92701 | |
parent | 5a4eb55122e45444d3a6c56ce108ce29bc8e52ab (diff) |
patch 9.0.0449: there is no easy way to translate a key code into a stringv9.0.0449
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)
-rw-r--r-- | runtime/doc/builtin.txt | 12 | ||||
-rw-r--r-- | src/evalfunc.c | 21 | ||||
-rw-r--r-- | src/map.c | 6 | ||||
-rw-r--r-- | src/menu.c | 2 | ||||
-rw-r--r-- | src/message.c | 20 | ||||
-rw-r--r-- | src/option.c | 5 | ||||
-rw-r--r-- | src/proto/message.pro | 4 | ||||
-rw-r--r-- | src/testdir/test_functions.vim | 26 | ||||
-rw-r--r-- | src/version.c | 2 |
9 files changed, 83 insertions, 15 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 3448ed5855..fb8b116010 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -325,6 +325,8 @@ js_encode({expr}) String encode JS style JSON json_decode({string}) any decode JSON json_encode({expr}) String encode JSON keys({dict}) List keys in {dict} +keytrans({string}) String translate internal keycodes to a form + that can be used by |:map| len({expr}) Number the length of {expr} libcall({lib}, {func}, {arg}) String call {func} in library {lib} with {arg} libcallnr({lib}, {func}, {arg}) Number idem, but return a Number @@ -5205,6 +5207,16 @@ keys({dict}) *keys()* Can also be used as a |method|: > mydict->keys() +keytrans({string}) *keytrans()* + Turn the internal byte representation of keys into a form that + can be used for |:map|. E.g. > + :let xx = "\<C-Home>" + :echo keytrans(xx) +< <C-Home> + + Can also be used as a |method|: > + "\<C-Home>"->keytrans() + < *len()* *E701* len({expr}) The result is a Number, which is the length of the argument. When {expr} is a String or a Number the length in bytes is diff --git a/src/evalfunc.c b/src/evalfunc.c index bc0e23e9c8..cd31562949 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -89,6 +89,7 @@ static void f_inputsecret(typval_T *argvars, typval_T *rettv); static void f_interrupt(typval_T *argvars, typval_T *rettv); static void f_invert(typval_T *argvars, typval_T *rettv); static void f_islocked(typval_T *argvars, typval_T *rettv); +static void f_keytrans(typval_T *argvars, typval_T *rettv); static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); static void f_libcall(typval_T *argvars, typval_T *rettv); static void f_libcallnr(typval_T *argvars, typval_T *rettv); @@ -2058,6 +2059,8 @@ static funcentry_T global_functions[] = ret_string, f_json_encode}, {"keys", 1, 1, FEARG_1, arg1_dict_any, ret_list_string, f_keys}, + {"keytrans", 1, 1, FEARG_1, arg1_string, + ret_string, f_keytrans}, {"last_buffer_nr", 0, 0, 0, NULL, // obsolete ret_number, f_last_buffer_nr}, {"len", 1, 1, FEARG_1, arg1_len, @@ -7136,6 +7139,24 @@ f_islocked(typval_T *argvars, typval_T *rettv) } /* + * "keytrans()" function + */ + static void +f_keytrans(typval_T *argvars, typval_T *rettv) +{ + char_u *escaped; + + rettv->v_type = VAR_STRING; + if (check_for_string_arg(argvars, 0) == FAIL + || argvars[0].vval.v_string == NULL) + return; + // Need to escape K_SPECIAL and CSI for mb_unescape(). + escaped = vim_strsave_escape_csi(argvars[0].vval.v_string); + rettv->vval.v_string = str2special_save(escaped, TRUE, TRUE); + vim_free(escaped); +} + +/* * "last_buffer_nr()" function. */ static void @@ -2317,7 +2317,7 @@ mapblock2dict( int buffer_local, // false if not buffer local mapping int abbr) // true if abbreviation { - char_u *lhs = str2special_save(mp->m_keys, TRUE); + char_u *lhs = str2special_save(mp->m_keys, TRUE, FALSE); char_u *mapmode = map_mode_to_chars(mp->m_mode); dict_add_string(dict, "lhs", lhs); @@ -2409,7 +2409,7 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) if (*rhs == NUL) rettv->vval.v_string = vim_strsave((char_u *)"<Nop>"); else - rettv->vval.v_string = str2special_save(rhs, FALSE); + rettv->vval.v_string = str2special_save(rhs, FALSE, FALSE); } } @@ -2478,7 +2478,7 @@ f_maplist(typval_T *argvars UNUSED, typval_T *rettv) keys_buf = NULL; did_simplify = FALSE; - lhs = str2special_save(mp->m_keys, TRUE); + lhs = str2special_save(mp->m_keys, TRUE, FALSE); (void)replace_termcodes(lhs, &keys_buf, flags, &did_simplify); vim_free(lhs); diff --git a/src/menu.c b/src/menu.c index 014d0518de..6a93316ab4 100644 --- a/src/menu.c +++ b/src/menu.c @@ -2890,7 +2890,7 @@ menuitem_getinfo(char_u *menu_name, vimmenu_T *menu, int modes, dict_T *dict) *menu->strings[bit] == NUL ? (char_u *)"<Nop>" : (tofree = str2special_save( - menu->strings[bit], FALSE))); + menu->strings[bit], FALSE, FALSE))); vim_free(tofree); } if (status == OK) diff --git a/src/message.c b/src/message.c index b68c089747..57197c1a83 100644 --- a/src/message.c +++ b/src/message.c @@ -1759,7 +1759,7 @@ msg_outtrans_special( ++str; } else - text = (char *)str2special(&str, from); + text = (char *)str2special(&str, from, FALSE); if (text[0] != NUL && text[1] == NUL) // single-byte character or illegal byte text = (char *)transchar_byte((char_u)text[0]); @@ -1782,14 +1782,16 @@ msg_outtrans_special( char_u * str2special_save( char_u *str, - int is_lhs) // TRUE for lhs, FALSE for rhs + int replace_spaces, // TRUE to replace " " with "<Space>". + // used for the lhs of mapping and keytrans(). + int replace_lt) // TRUE to replace "<" with "<lt>". { garray_T ga; char_u *p = str; ga_init2(&ga, 1, 40); while (*p != NUL) - ga_concat(&ga, str2special(&p, is_lhs)); + ga_concat(&ga, str2special(&p, replace_spaces, replace_lt)); ga_append(&ga, NUL); return (char_u *)ga.ga_data; } @@ -1804,7 +1806,9 @@ str2special_save( char_u * str2special( char_u **sp, - int from) // TRUE for lhs of mapping + int replace_spaces, // TRUE to replace " " with "<Space>". + // used for the lhs of mapping and keytrans(). + int replace_lt) // TRUE to replace "<" with "<lt>". { int c; static char_u buf[7]; @@ -1861,8 +1865,10 @@ str2special( *sp = str + (*str == NUL ? 0 : 1); // Make special keys and C0 control characters in <> form, also <M-Space>. - // Use <Space> only for lhs of a mapping. - if (special || c < ' ' || (from && c == ' ')) + if (special + || c < ' ' + || (replace_spaces && c == ' ') + || (replace_lt && c == '<')) return get_special_key_name(c, modifiers); buf[0] = c; buf[1] = NUL; @@ -1880,7 +1886,7 @@ str2specialbuf(char_u *sp, char_u *buf, int len) *buf = NUL; while (*sp) { - s = str2special(&sp, FALSE); + s = str2special(&sp, FALSE, FALSE); if ((int)(STRLEN(s) + STRLEN(buf)) < len) STRCAT(buf, s); } diff --git a/src/option.c b/src/option.c index 5ce52184ea..37c81aaa48 100644 --- a/src/option.c +++ b/src/option.c @@ -3994,7 +3994,8 @@ get_option_value( if (stringval != NULL) { if ((char_u **)varp == &p_pt) // 'pastetoggle' - *stringval = str2special_save(*(char_u **)(varp), FALSE); + *stringval = str2special_save(*(char_u **)(varp), FALSE, + FALSE); #ifdef FEAT_CRYPT // never return the value of the crypt key else if ((char_u **)varp == &curbuf->b_p_key @@ -4879,7 +4880,7 @@ put_setstring( { s = *valuep; while (*s != NUL) - if (put_escstr(fd, str2special(&s, FALSE), 2) == FAIL) + if (put_escstr(fd, str2special(&s, FALSE, FALSE), 2) == FAIL) return FAIL; } // expand the option value, replace $HOME by ~ diff --git a/src/proto/message.pro b/src/proto/message.pro index 3f8a8fe2e3..6657a08ec3 100644 --- a/src/proto/message.pro +++ b/src/proto/message.pro @@ -37,8 +37,8 @@ char_u *msg_outtrans_one(char_u *p, int attr); int msg_outtrans_len_attr(char_u *msgstr, int len, int attr); void msg_make(char_u *arg); int msg_outtrans_special(char_u *strstart, int from, int maxlen); -char_u *str2special_save(char_u *str, int is_lhs); -char_u *str2special(char_u **sp, int from); +char_u *str2special_save(char_u *str, int replace_spaces, int replace_lt); +char_u *str2special(char_u **sp, int replace_spaces, int replace_lt); void str2specialbuf(char_u *sp, char_u *buf, int len); void msg_prt_line(char_u *s, int list); void msg_puts(char *s); diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index cad1d4b435..4c71e227ae 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2764,6 +2764,32 @@ func Test_eval() call assert_fails("call eval('5 a')", 'E488:') endfunc +" Test for the keytrans() function +func Test_keytrans() + call assert_equal('<Space>', keytrans(' ')) + call assert_equal('<lt>', keytrans('<')) + call assert_equal('<lt>Tab>', keytrans('<Tab>')) + call assert_equal('<Tab>', keytrans("\<Tab>")) + call assert_equal('<C-V>', keytrans("\<C-V>")) + call assert_equal('<BS>', keytrans("\<BS>")) + call assert_equal('<Home>', keytrans("\<Home>")) + call assert_equal('<C-Home>', keytrans("\<C-Home>")) + call assert_equal('<M-Home>', keytrans("\<M-Home>")) + call assert_equal('<C-Space>', keytrans("\<C-Space>")) + call assert_equal('<M-Space>', keytrans("\<*M-Space>")) + call assert_equal('<M-x>', "\<*M-x>"->keytrans()) + call assert_equal('<C-I>', "\<*C-I>"->keytrans()) + call assert_equal('<S-3>', "\<*S-3>"->keytrans()) + call assert_equal('π', 'π'->keytrans()) + call assert_equal('<M-π>', "\<M-π>"->keytrans()) + call assert_equal('ě', 'ě'->keytrans()) + call assert_equal('<M-ě>', "\<M-ě>"->keytrans()) + call assert_equal('', ''->keytrans()) + call assert_equal('', test_null_string()->keytrans()) + call assert_fails('call keytrans(1)', 'E1174:') + call assert_fails('call keytrans()', 'E119:') +endfunc + " Test for the nr2char() function func Test_nr2char() set encoding=latin1 diff --git a/src/version.c b/src/version.c index 2764ad9ad4..3633b198c2 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 449, +/**/ 448, /**/ 447, |