]> granicus.if.org Git - vim/commitdiff
patch 9.0.0449: there is no easy way to translate a key code into a string v9.0.0449
authorzeertzjq <zeertzjq@outlook.com>
Mon, 12 Sep 2022 12:38:41 +0000 (13:38 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 12 Sep 2022 12:38:41 +0000 (13:38 +0100)
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)

runtime/doc/builtin.txt
src/evalfunc.c
src/map.c
src/menu.c
src/message.c
src/option.c
src/proto/message.pro
src/testdir/test_functions.vim
src/version.c

index 3448ed58551e906fc56fb29c5527fc0436e92b2f..fb8b116010095ae173e4f86c2d45eb1f20daafa7 100644 (file)
@@ -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
index bc0e23e9c8e1bf0c576fc17eae7c5e33c5d9324b..cd315629498b0e59a1101510abe2f42b2da89754 100644 (file)
@@ -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,
@@ -7135,6 +7138,24 @@ f_islocked(typval_T *argvars, typval_T *rettv)
     clear_lval(&lv);
 }
 
+/*
+ * "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.
  */
index 140cbc84f8399feeacf2ebd441ebcb51152535e4..d063e053ae109c3e26aea6f51be972fe954a39a7 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -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);
 
index 014d0518de0bbc7e25b391119607675aab1af45e..6a93316ab40da528164fb655d6e59daa1509eeb1 100644 (file)
@@ -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)
index b68c089747d627ffebe10158d2bd416278cc56ef..57197c1a8364002438391789bd8748d0ad3cc680 100644 (file)
@@ -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);
     }
index 5ce52184eab2fa46d4041e1a6c493d67cafaff58..37c81aaa48752fae619f7a0d865ada3646f5b719 100644 (file)
@@ -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 ~
index 3f8a8fe2e39eeaab93a9fa9b62fa2cf0439229b8..6657a08ec3b7a59ff2a63f129e17a43da55f157c 100644 (file)
@@ -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);
index cad1d4b435ae114b7258d0f71a8eeedce803b509..4c71e227ae2856e48535ac63c64565c0bf8b839b 100644 (file)
@@ -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
index 2764ad9ad481e47178a66cb8f07baafda7125e98..3633b198c21a5bdb06a684cff5b36d10522e6451 100644 (file)
@@ -703,6 +703,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    449,
 /**/
     448,
 /**/