Patch 9.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)
Files:      runtime/doc/builtin.txt, runtime/doc/usr_41.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


*** ../vim-9.0.0448/runtime/doc/builtin.txt     2022-09-09 18:46:41.558660414 
+0100
--- runtime/doc/builtin.txt     2022-09-12 13:28:33.439747660 +0100
***************
*** 325,330 ****
--- 325,332 ----
  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
***************
*** 5195,5200 ****
--- 5207,5222 ----
                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
*** ../vim-9.0.0448/runtime/doc/usr_41.txt      2022-08-27 12:22:19.975008573 
+0100
--- runtime/doc/usr_41.txt      2022-09-12 13:28:33.439747660 +0100
***************
*** 736,741 ****
--- 737,744 ----
        fnameescape()           escape a file name for use with a Vim command
        tr()                    translate characters from one set to another
        strtrans()              translate a string to make it printable
+       keytrans()              translate internal keycodes to a form that
+                               can be used by |:map|
        tolower()               turn a string to lowercase
        toupper()               turn a string to uppercase
        charclass()             class of a character
***************
*** 1349,1355 ****
        did_filetype()          check if a FileType autocommand was used
        eventhandler()          check if invoked by an event handler
        getpid()                get process ID of Vim
!       getscriptinfo() get list of sourced vim scripts
        getimstatus()           check if IME status is active
        interrupt()             interrupt script execution
        windowsversion()        get MS-Windows version
--- 1352,1358 ----
        did_filetype()          check if a FileType autocommand was used
        eventhandler()          check if invoked by an event handler
        getpid()                get process ID of Vim
!       getscriptinfo()         get list of sourced vim scripts
        getimstatus()           check if IME status is active
        interrupt()             interrupt script execution
        windowsversion()        get MS-Windows version
*** ../vim-9.0.0448/src/evalfunc.c      2022-09-09 18:46:41.558660414 +0100
--- src/evalfunc.c      2022-09-12 13:28:33.439747660 +0100
***************
*** 89,94 ****
--- 89,95 ----
  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,2063 ****
--- 2059,2066 ----
                        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,7141 ****
--- 7139,7162 ----
  }
  
  /*
+  * "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
*** ../vim-9.0.0448/src/map.c   2022-08-31 16:40:14.250932016 +0100
--- src/map.c   2022-09-12 13:28:33.439747660 +0100
***************
*** 2317,2323 ****
        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        *mapmode = map_mode_to_chars(mp->m_mode);
  
      dict_add_string(dict, "lhs", lhs);
--- 2317,2323 ----
        int         buffer_local,   // false if not buffer local mapping
        int         abbr)           // true if abbreviation
  {
!     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,2415 ****
            if (*rhs == NUL)
                rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
            else
!               rettv->vval.v_string = str2special_save(rhs, FALSE);
        }
  
      }
--- 2409,2415 ----
            if (*rhs == NUL)
                rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
            else
!               rettv->vval.v_string = str2special_save(rhs, FALSE, FALSE);
        }
  
      }
***************
*** 2478,2484 ****
                keys_buf = NULL;
                did_simplify = FALSE;
  
!               lhs = str2special_save(mp->m_keys, TRUE);
                (void)replace_termcodes(lhs, &keys_buf, flags, &did_simplify);
                vim_free(lhs);
  
--- 2478,2484 ----
                keys_buf = NULL;
                did_simplify = FALSE;
  
!               lhs = str2special_save(mp->m_keys, TRUE, FALSE);
                (void)replace_termcodes(lhs, &keys_buf, flags, &did_simplify);
                vim_free(lhs);
  
*** ../vim-9.0.0448/src/menu.c  2022-08-14 14:16:07.995582211 +0100
--- src/menu.c  2022-09-12 13:28:33.443747653 +0100
***************
*** 2890,2896 ****
                        *menu->strings[bit] == NUL
                                ? (char_u *)"<Nop>"
                                : (tofree = str2special_save(
!                                                 menu->strings[bit], FALSE)));
                vim_free(tofree);
            }
            if (status == OK)
--- 2890,2896 ----
                        *menu->strings[bit] == NUL
                                ? (char_u *)"<Nop>"
                                : (tofree = str2special_save(
!                                       menu->strings[bit], FALSE, FALSE)));
                vim_free(tofree);
            }
            if (status == OK)
*** ../vim-9.0.0448/src/message.c       2022-09-11 21:35:47.554255165 +0100
--- src/message.c       2022-09-12 13:28:33.443747653 +0100
***************
*** 1759,1765 ****
            ++str;
        }
        else
!           text = (char *)str2special(&str, from);
        if (text[0] != NUL && text[1] == NUL)
            // single-byte character or illegal byte
            text = (char *)transchar_byte((char_u)text[0]);
--- 1759,1765 ----
            ++str;
        }
        else
!           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,1795 ****
      char_u *
  str2special_save(
      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;
  }
--- 1782,1797 ----
      char_u *
  str2special_save(
      char_u  *str,
!     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, replace_spaces, replace_lt));
      ga_append(&ga, NUL);
      return (char_u *)ga.ga_data;
  }
***************
*** 1804,1810 ****
      char_u *
  str2special(
      char_u    **sp,
!     int               from)   // TRUE for lhs of mapping
  {
      int                       c;
      static char_u     buf[7];
--- 1806,1814 ----
      char_u *
  str2special(
      char_u    **sp,
!     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,1868 ****
        *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 == ' '))
        return get_special_key_name(c, modifiers);
      buf[0] = c;
      buf[1] = NUL;
--- 1865,1874 ----
        *sp = str + (*str == NUL ? 0 : 1);
  
      // Make special keys and C0 control characters in <> form, also <M-Space>.
!     if (special
!       || c < ' '
!       || (replace_spaces && c == ' ')
!       || (replace_lt && c == '<'))
        return get_special_key_name(c, modifiers);
      buf[0] = c;
      buf[1] = NUL;
***************
*** 1880,1886 ****
      *buf = NUL;
      while (*sp)
      {
!       s = str2special(&sp, FALSE);
        if ((int)(STRLEN(s) + STRLEN(buf)) < len)
            STRCAT(buf, s);
      }
--- 1886,1892 ----
      *buf = NUL;
      while (*sp)
      {
!       s = str2special(&sp, FALSE, FALSE);
        if ((int)(STRLEN(s) + STRLEN(buf)) < len)
            STRCAT(buf, s);
      }
*** ../vim-9.0.0448/src/option.c        2022-08-31 14:46:07.911016920 +0100
--- src/option.c        2022-09-12 13:28:33.443747653 +0100
***************
*** 3994,4000 ****
        if (stringval != NULL)
        {
            if ((char_u **)varp == &p_pt)       // 'pastetoggle'
!               *stringval = str2special_save(*(char_u **)(varp), FALSE);
  #ifdef FEAT_CRYPT
            // never return the value of the crypt key
            else if ((char_u **)varp == &curbuf->b_p_key
--- 3994,4001 ----
        if (stringval != NULL)
        {
            if ((char_u **)varp == &p_pt)       // 'pastetoggle'
!               *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,4885 ****
        {
            s = *valuep;
            while (*s != NUL)
!               if (put_escstr(fd, str2special(&s, FALSE), 2) == FAIL)
                    return FAIL;
        }
        // expand the option value, replace $HOME by ~
--- 4880,4886 ----
        {
            s = *valuep;
            while (*s != NUL)
!               if (put_escstr(fd, str2special(&s, FALSE, FALSE), 2) == FAIL)
                    return FAIL;
        }
        // expand the option value, replace $HOME by ~
*** ../vim-9.0.0448/src/proto/message.pro       2022-08-31 14:46:07.907016957 
+0100
--- src/proto/message.pro       2022-09-12 13:28:33.443747653 +0100
***************
*** 37,44 ****
  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);
  void str2specialbuf(char_u *sp, char_u *buf, int len);
  void msg_prt_line(char_u *s, int list);
  void msg_puts(char *s);
--- 37,44 ----
  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 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);
*** ../vim-9.0.0448/src/testdir/test_functions.vim      2022-09-02 
21:55:45.503049444 +0100
--- src/testdir/test_functions.vim      2022-09-12 13:28:33.443747653 +0100
***************
*** 2764,2769 ****
--- 2764,2795 ----
    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
*** ../vim-9.0.0448/src/version.c       2022-09-12 12:43:20.289108044 +0100
--- src/version.c       2022-09-12 13:34:23.159037194 +0100
***************
*** 705,706 ****
--- 705,708 ----
  {   /* Add new patch number below this line */
+ /**/
+     449,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
49. You never have to deal with busy signals when calling your ISP...because
    you never log off.

 /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220912123946.C60A41C0D18%40moolenaar.net.

Raspunde prin e-mail lui