Patch 8.2.0924
Problem:    Cannot save and restore a register properly.
Solution:   Add getreginfo() and make setreg() accept a dictionary. (Andy
            Massimino, closes #3370)
Files:      runtime/doc/eval.txt, runtime/doc/usr_41.txt, src/evalfunc.c,
            src/proto/register.pro, src/register.c,
            src/testdir/test_eval_stuff.vim, src/testdir/test_registers.vim


*** ../vim-8.2.0923/runtime/doc/eval.txt        2020-06-06 18:37:47.860138513 
+0200
--- runtime/doc/eval.txt        2020-06-07 18:10:05.464595139 +0200
***************
*** 2500,2507 ****
  getpos({expr})                        List    position of cursor, mark, etc.
  getqflist([{what}])           List    list of quickfix items
  getreg([{regname} [, 1 [, {list}]]])
!                               String or List   contents of register
! getregtype([{regname}])               String  type of register
  gettabinfo([{expr}])          List    list of tab pages
  gettabvar({nr}, {varname} [, {def}])
                                any     variable {varname} in tab {nr} or {def}
--- 2506,2514 ----
  getpos({expr})                        List    position of cursor, mark, etc.
  getqflist([{what}])           List    list of quickfix items
  getreg([{regname} [, 1 [, {list}]]])
!                               String or List   contents of a register
! getreginfo([{regname}])               Dict    information about a register
! getregtype([{regname}])               String  type of a register
  gettabinfo([{expr}])          List    list of tab pages
  gettabvar({nr}, {varname} [, {def}])
                                any     variable {varname} in tab {nr} or {def}
***************
*** 5587,5592 ****
--- 5597,5627 ----
                Can also be used as a |method|: >
                        GetRegname()->getreg()
  
+ getreginfo([{regname}])                                       *getreginfo()*
+               Returns detailed information about register {regname} as a
+               Dictionary with the following entries:
+                       regcontents     List of lines contained in register
+                                       {regname}, like
+                                       |getreg|({regname}, 1, 1).
+                       regtype         the type of register {regname}, as in
+                                       |getregtype()|.
+                       isunnamed       Boolean flag, v:true if this register
+                                       is currently pointed to by the unnamed
+                                       register.
+                       points_to       for the unnamed register, gives the
+                                       single letter name of the register
+                                       currently pointed to (see |quotequote|).
+                                       For example, after deleting a line
+                                       with `dd`, this field will be "1",
+                                       which is the register that got the
+                                       deleted text.
+ 
+               If {regname} is invalid or not set, an empty Dictionary
+               will be returned.
+               If {regname} is not specified, |v:register| is used.
+ 
+               Can also be used as a |method|: >
+                       GetRegname()->getreginfo()
  
  getregtype([{regname}])                                       *getregtype()*
                The result is a String, which is type of register {regname}.
***************
*** 9073,9080 ****
  setreg({regname}, {value} [, {options}])
                Set the register {regname} to {value}.
                If {regname} is "" or "@", the unnamed register '"' is used.
!               {value} may be any value returned by |getreg()|, including
!               a |List|.
                If {options} contains "a" or {regname} is upper case,
                then the value is appended.
                {options} can also contain a register type specification:
--- 9116,9123 ----
  setreg({regname}, {value} [, {options}])
                Set the register {regname} to {value}.
                If {regname} is "" or "@", the unnamed register '"' is used.
!               {value} may be any value returned by |getreg()| or
!               |getreginfo()|, including a |List| or |Dict|.
                If {options} contains "a" or {regname} is upper case,
                then the value is appended.
                {options} can also contain a register type specification:
***************
*** 9101,9109 ****
--- 9144,9156 ----
                        :call setreg(v:register, @*)
                        :call setreg('*', @%, 'ac')
                        :call setreg('a', "1\n2\n3", 'b5')
+                       :call setreg('"', { 'points_to': 'a'})
  
  <             This example shows using the functions to save and restore a
                register: >
+                       :let var_a = getreginfo()
+                       :call setreg('a', var_a)
+ <             or:
                        :let var_a = getreg('a', 1, 1)
                        :let var_amode = getregtype('a')
                            ....
*** ../vim-8.2.0923/runtime/doc/usr_41.txt      2020-06-04 15:21:45.482189580 
+0200
--- runtime/doc/usr_41.txt      2020-06-07 18:04:33.633724938 +0200
***************
*** 1150,1155 ****
--- 1155,1161 ----
        undotree()              return the state of the undo tree
  
        getreg()                get contents of a register
+       getreginfo()            get information about a register
        getregtype()            get type of a register
        setreg()                set contents and type of a register
        reg_executing()         return the name of the register being executed
*** ../vim-8.2.0923/src/evalfunc.c      2020-06-07 14:50:47.271846855 +0200
--- src/evalfunc.c      2020-06-07 18:14:06.423781096 +0200
***************
*** 94,99 ****
--- 94,100 ----
  static void f_getcurpos(typval_T *argvars, typval_T *rettv);
  static void f_getpos(typval_T *argvars, typval_T *rettv);
  static void f_getreg(typval_T *argvars, typval_T *rettv);
+ static void f_getreginfo(typval_T *argvars, typval_T *rettv);
  static void f_getregtype(typval_T *argvars, typval_T *rettv);
  static void f_gettagstack(typval_T *argvars, typval_T *rettv);
  static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
***************
*** 586,591 ****
--- 587,593 ----
      {"getpos",                1, 1, FEARG_1,    ret_list_number,      
f_getpos},
      {"getqflist",     0, 1, 0,          ret_list_dict_any,    f_getqflist},
      {"getreg",                0, 3, FEARG_1,    ret_string,   f_getreg},
+     {"getreginfo",    0, 1, FEARG_1,    ret_dict_any, f_getreginfo},
      {"getregtype",    0, 1, FEARG_1,    ret_string,   f_getregtype},
      {"gettabinfo",    0, 1, FEARG_1,    ret_list_dict_any,    f_gettabinfo},
      {"gettabvar",     2, 3, FEARG_1,    ret_any,      f_gettabvar},
***************
*** 6227,6232 ****
--- 6229,6300 ----
            break;
  }
  
+ /*
+  * "getreginfo()" function
+  */
+     static void
+ f_getreginfo(typval_T *argvars, typval_T *rettv)
+ {
+     char_u    *strregname;
+     int               regname;
+     char_u    buf[NUMBUFLEN + 2];
+     long      reglen = 0;
+     dict_T    *dict;
+     list_T    *list;
+ 
+     if (argvars[0].v_type != VAR_UNKNOWN)
+     {
+       strregname = tv_get_string_chk(&argvars[0]);
+       if (strregname == NULL)
+           return;
+     }
+     else
+       strregname = get_vim_var_str(VV_REG);
+ 
+     regname = (strregname == NULL ? '"' : *strregname);
+     if (regname == 0 || regname == '@')
+       regname = '"';
+ 
+     if (rettv_dict_alloc(rettv) == FAIL)
+       return;
+     dict = rettv->vval.v_dict;
+ 
+     list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
+     if (list == NULL)
+       return;
+     dict_add_list(dict, "regcontents", list);
+ 
+     buf[0] = NUL;
+     buf[1] = NUL;
+     switch (get_reg_type(regname, &reglen))
+     {
+       case MLINE: buf[0] = 'V'; break;
+       case MCHAR: buf[0] = 'v'; break;
+       case MBLOCK:
+                   vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
+                           reglen + 1);
+                   break;
+     }
+     dict_add_string(dict, (char *)"regtype", buf);
+ 
+     buf[0] = get_register_name(get_unname_register());
+     buf[1] = NUL;
+     if (regname == '"')
+       dict_add_string(dict, (char *)"points_to", buf);
+     else
+     {
+       dictitem_T      *item = dictitem_alloc((char_u *)"isunnamed");
+ 
+       if (item != NULL)
+       {
+           item->di_tv.v_type = VAR_SPECIAL;
+           item->di_tv.vval.v_number = regname == buf[0]
+               ? VVAL_TRUE : VVAL_FALSE;
+           dict_add(dict, item);
+       }
+     }
+ }
+ 
      static void
  return_register(int regname, typval_T *rettv)
  {
***************
*** 7203,7209 ****
--- 7271,7281 ----
      int               append;
      char_u    yank_type;
      long      block_len;
+     typval_T  *regcontents;
+     int               pointreg;
  
+     pointreg = 0;
+     regcontents = NULL;
      block_len = -1;
      yank_type = MAUTO;
      append = FALSE;
***************
*** 7217,7222 ****
--- 7289,7337 ----
      if (regname == 0 || regname == '@')
        regname = '"';
  
+     if (argvars[1].v_type == VAR_DICT)
+     {
+       dict_T      *d = argvars[1].vval.v_dict;
+       dictitem_T  *di = dict_find(d, (char_u *)"regcontents", -1);
+       if (di != NULL)
+           regcontents = &di->di_tv;
+ 
+       stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
+       if (stropt != NULL)
+           switch (*stropt)
+           {
+               case 'v':               // character-wise selection
+                   yank_type = MCHAR;
+                   break;
+               case 'V':               // line-wise selection
+                   yank_type = MLINE;
+                   break;
+               case Ctrl_V:            // block-wise selection
+                   yank_type = MBLOCK;
+                   if (VIM_ISDIGIT(stropt[1]))
+                   {
+                       ++stropt;
+                       block_len = getdigits(&stropt) - 1;
+                       --stropt;
+                   }
+                   break;
+           }
+ 
+       if (regname == '"')
+       {
+           stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
+           if (stropt != NULL)
+           {
+               pointreg = *stropt;
+               regname = pointreg;
+           }
+       }
+       else if (dict_get_number(d, (char_u *)"isunnamed"))
+           pointreg = regname;
+     }
+     else
+       regcontents = &argvars[1];
+ 
      if (argvars[2].v_type != VAR_UNKNOWN)
      {
        stropt = tv_get_string_chk(&argvars[2]);
***************
*** 7246,7259 ****
            }
      }
  
!     if (argvars[1].v_type == VAR_LIST)
      {
        char_u          **lstval;
        char_u          **allocval;
        char_u          buf[NUMBUFLEN];
        char_u          **curval;
        char_u          **curallocval;
!       list_T          *ll = argvars[1].vval.v_list;
        listitem_T      *li;
        int             len;
  
--- 7361,7374 ----
            }
      }
  
!     if (regcontents && regcontents->v_type == VAR_LIST)
      {
        char_u          **lstval;
        char_u          **allocval;
        char_u          buf[NUMBUFLEN];
        char_u          **curval;
        char_u          **curallocval;
!       list_T          *ll = regcontents->vval.v_list;
        listitem_T      *li;
        int             len;
  
***************
*** 7298,7311 ****
            vim_free(*--curallocval);
        vim_free(lstval);
      }
!     else
      {
!       strval = tv_get_string_chk(&argvars[1]);
        if (strval == NULL)
            return;
        write_reg_contents_ex(regname, strval, -1,
                                                append, yank_type, block_len);
      }
      rettv->vval.v_number = 0;
  }
  
--- 7413,7429 ----
            vim_free(*--curallocval);
        vim_free(lstval);
      }
!     else if (regcontents)
      {
!       strval = tv_get_string_chk(regcontents);
        if (strval == NULL)
            return;
        write_reg_contents_ex(regname, strval, -1,
                                                append, yank_type, block_len);
      }
+     if (pointreg != 0)
+       get_yank_register(pointreg, TRUE);
+ 
      rettv->vval.v_number = 0;
  }
  
*** ../vim-8.2.0923/src/proto/register.pro      2020-03-24 21:41:38.027535418 
+0100
--- src/proto/register.pro      2020-06-07 18:14:15.487750550 +0200
***************
*** 29,34 ****
--- 29,35 ----
  int op_yank(oparg_T *oap, int deleting, int mess);
  void do_put(int regname, int dir, long count, int flags);
  int get_register_name(int num);
+ int get_unname_register(void);
  void ex_display(exarg_T *eap);
  void dnd_yank_drag_data(char_u *str, long len);
  char_u get_reg_type(int regname, long *reglen);
*** ../vim-8.2.0923/src/register.c      2020-04-30 22:29:36.626024141 +0200
--- src/register.c      2020-06-07 18:14:10.655766831 +0200
***************
*** 2111,2116 ****
--- 2111,2125 ----
  }
  
  /*
+  * Return the index of the register "" points to.
+  */
+     int
+ get_unname_register()
+ {
+     return y_previous == NULL ? -1 : y_previous - &y_regs[0];
+ }
+ 
+ /*
   * ":dis" and ":registers": Display the contents of the yank registers.
   */
      void
*** ../vim-8.2.0923/src/testdir/test_eval_stuff.vim     2020-06-02 
21:38:18.719856309 +0200
--- src/testdir/test_eval_stuff.vim     2020-06-07 18:04:33.637724924 +0200
***************
*** 529,535 ****
    call assert_fails('call setreg(1)', 'E119:')
    call assert_fails('call setreg(1, 2, 3, 4)', 'E118:')
    call assert_fails('call setreg([], 2)', 'E730:')
-   call assert_fails('call setreg(1, {})', 'E731:')
    call assert_fails('call setreg(1, 2, [])', 'E730:')
    call assert_fails('call setreg("/", ["1", "2"])', 'E883:')
    call assert_fails('call setreg("=", ["1", "2"])', 'E883:')
--- 529,534 ----
*** ../vim-8.2.0923/src/testdir/test_registers.vim      2020-04-26 
15:59:51.206952132 +0200
--- src/testdir/test_registers.vim      2020-06-07 18:04:33.637724924 +0200
***************
*** 416,419 ****
--- 416,491 ----
    call assert_beeps('normal! c@r')
  endfunc
  
+ " Test for getting register info
+ func Test_get_reginfo()
+   enew
+   call setline(1, ['foo', 'bar'])
+ 
+   exe 'norm! "zyy'
+   let info = getreginfo('"')
+   call assert_equal('z', info.points_to)
+   call setreg('y', 'baz')
+   call assert_equal('z', getreginfo('').points_to)
+   call setreg('y', { 'isunnamed': v:true })
+   call assert_equal('y', getreginfo('"').points_to)
+ 
+   exe '$put'
+   call assert_equal(getreg('y'), getline(3))
+   call setreg('', 'qux')
+   call assert_equal('0', getreginfo('').points_to)
+   call setreg('x', 'quux')
+   call assert_equal('0', getreginfo('').points_to)
+ 
+   let info = getreginfo('')
+   call assert_equal(getreg('', 1, 1), info.regcontents)
+   call assert_equal(getregtype(''), info.regtype)
+ 
+   exe "norm! 0\<c-v>e" .. '"zy'
+   let info = getreginfo('z')
+   call assert_equal(getreg('z', 1, 1), info.regcontents)
+   call assert_equal(getregtype('z'), info.regtype)
+   call assert_equal(1, +info.isunnamed)
+ 
+   let info = getreginfo('"')
+   call assert_equal('z', info.points_to)
+ 
+   bwipe!
+ endfunc
+ 
+ " Test for restoring register with dict from getreginfo
+ func Test_set_register_dict()
+   enew!
+ 
+   call setreg('"', #{ regcontents: ['one', 'two'],
+         \ regtype: 'V', points_to: 'z' })
+   call assert_equal(['one', 'two'], getreg('"', 1, 1))
+   let info = getreginfo('"')
+   call assert_equal('z', info.points_to)
+   call assert_equal('V', info.regtype)
+   call assert_equal(1, +getreginfo('z').isunnamed)
+ 
+   call setreg('x', #{ regcontents: ['three', 'four'],
+         \ regtype: 'v', isunnamed: v:true })
+   call assert_equal(['three', 'four'], getreg('"', 1, 1))
+   let info = getreginfo('"')
+   call assert_equal('x', info.points_to)
+   call assert_equal('v', info.regtype)
+   call assert_equal(1, +getreginfo('x').isunnamed)
+ 
+   call setreg('y', #{ regcontents: 'five',
+         \ regtype: "\<c-v>", isunnamed: v:false })
+   call assert_equal("\<c-v>4", getreginfo('y').regtype)
+   call assert_equal(0, +getreginfo('y').isunnamed)
+   call assert_equal(['three', 'four'], getreg('"', 1, 1))
+   call assert_equal('x', getreginfo('"').points_to)
+ 
+   call setreg('"', #{ regcontents: 'six' })
+   call assert_equal('0', getreginfo('"').points_to)
+   call assert_equal(1, +getreginfo('0').isunnamed)
+   call assert_equal(['six'], getreginfo('0').regcontents)
+   call assert_equal(['six'], getreginfo('"').regcontents)
+ 
+   bwipe!
+ endfunc
+ 
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.0923/src/version.c       2020-06-07 17:30:28.716850169 +0200
--- src/version.c       2020-06-07 18:06:24.817344757 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     924,
  /**/

-- 
The psychic said, "God bless you."  I said, "I didn't sneeze."  She
looked deep into my eyes and said, "You will, eventually."  And, damn
if she wasn't right.  Two days later, I sneezed.  --Ellen Degeneres

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202006071617.057GH3FV081732%40masaka.moolenaar.net.

Raspunde prin e-mail lui