Patch 8.0.1394
Problem:    Cannot intercept a yank command.
Solution:   Add the TextYankPost autocommand event. (Philippe Vaucher et al.,
            closes #2333)
Files:      runtime/doc/autocmd.txt, runtime/doc/eval.txt, src/dict.c,
            src/eval.c, src/fileio.c, src/ops.c, src/proto/dict.pro,
            src/proto/eval.pro, src/proto/fileio.pro,
            src/testdir/test_autocmd.vim, src/vim.h


*** ../vim-8.0.1393/runtime/doc/autocmd.txt     2017-10-19 18:35:46.090557740 
+0200
--- runtime/doc/autocmd.txt     2017-12-16 18:08:43.586241339 +0100
***************
*** 314,319 ****
--- 330,336 ----
  
  |TextChanged|         after a change was made to the text in Normal mode
  |TextChangedI|                after a change was made to the text in Insert 
mode
+ |TextYankPost|                after text is yanked or deleted
  
  |ColorScheme|         after loading a color scheme
  
***************
*** 935,940 ****
--- 957,982 ----
                                current buffer in Insert mode.
                                Not triggered when the popup menu is visible.
                                Otherwise the same as TextChanged.
+                                                       |TextYankPost|
+ TextYankPost                  After text has been yanked or deleted in the
+                               current buffer.  The following values of
+                               |v:event| can be used to determine the operation
+                               that triggered this autocmd:
+                                  operator     The operation performed.
+                                  regcontents  Text that was stored in the
+                                               register, as a list of lines,
+                                               like with: >
+                                               getreg(r, 1, 1)
+ <                                regname      Name of the |register| or
+                                               empty string for the unnamed
+                                               register.
+                                  regtype      Type of the register, see
+                                               |getregtype()|.
+                               Not triggered when |quote_| is used nor when
+                               called recursively.
+                               It is not allowed to change the buffer text,
+                               see |textlock|.
+ 
                                                        *User*
  User                          Never executed automatically.  To be used for
                                autocommands that are only executed with
*** ../vim-8.0.1393/runtime/doc/eval.txt        2017-12-12 22:45:07.141808185 
+0100
--- runtime/doc/eval.txt        2017-12-16 18:13:36.452281594 +0100
***************
*** 1554,1559 ****
--- 1554,1565 ----
  <             If v:errors is set to anything but a list it is made an empty
                list by the assert function.
  
+                                       *v:event* *event-variable*
+ v:event               Dictionary containing information about the current
+               |autocommand|.  The dictionary is emptied when the |autocommand|
+               finishes, please refer to |dict-identity| for how to get an
+               independent copy of it.
+ 
                                        *v:exception* *exception-variable*
  v:exception   The value of the exception most recently caught and not
                finished.  See also |v:throwpoint| and |throw-variables|.
*** ../vim-8.0.1393/src/dict.c  2017-04-30 20:12:53.370810715 +0200
--- src/dict.c  2017-12-16 18:21:39.013085280 +0100
***************
*** 47,52 ****
--- 47,62 ----
      return d;
  }
  
+     dict_T *
+ dict_alloc_lock(int lock)
+ {
+     dict_T *d = dict_alloc();
+ 
+     if (d != NULL)
+       d->dv_lock = lock;
+     return d;
+ }
+ 
  /*
   * Allocate an empty dict for a return value.
   * Returns OK or FAIL.
***************
*** 54,66 ****
      int
  rettv_dict_alloc(typval_T *rettv)
  {
!     dict_T    *d = dict_alloc();
  
      if (d == NULL)
        return FAIL;
  
      rettv_dict_set(rettv, d);
-     rettv->v_lock = 0;
      return OK;
  }
  
--- 64,75 ----
      int
  rettv_dict_alloc(typval_T *rettv)
  {
!     dict_T    *d = dict_alloc_lock(0);
  
      if (d == NULL)
        return FAIL;
  
      rettv_dict_set(rettv, d);
      return OK;
  }
  
***************
*** 80,86 ****
   * Free a Dictionary, including all non-container items it contains.
   * Ignores the reference count.
   */
!     static void
  dict_free_contents(dict_T *d)
  {
      int               todo;
--- 89,95 ----
   * Free a Dictionary, including all non-container items it contains.
   * Ignores the reference count.
   */
!     void
  dict_free_contents(dict_T *d)
  {
      int               todo;
***************
*** 102,107 ****
--- 111,118 ----
            --todo;
        }
      }
+ 
+     /* The hashtab is still locked, it has to be re-initialized anyway */
      hash_clear(&d->dv_hashtab);
  }
  
***************
*** 846,849 ****
--- 857,879 ----
      }
  }
  
+ /*
+  * Make each item in the dict readonly (not the value of the item).
+  */
+     void
+ dict_set_items_ro(dict_T *di)
+ {
+     int               todo = (int)di->dv_hashtab.ht_used;
+     hashitem_T        *hi;
+ 
+     /* Set readonly */
+     for (hi = di->dv_hashtab.ht_array; todo > 0 ; ++hi)
+     {
+       if (HASHITEM_EMPTY(hi))
+           continue;
+       --todo;
+       HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
+     }
+ }
+ 
  #endif /* defined(FEAT_EVAL) */
*** ../vim-8.0.1393/src/eval.c  2017-12-07 22:11:01.094438719 +0100
--- src/eval.c  2017-12-16 18:24:14.024063214 +0100
***************
*** 192,197 ****
--- 192,198 ----
      {VV_NAME("termu7resp",     VAR_STRING), VV_RO},
      {VV_NAME("termstyleresp", VAR_STRING), VV_RO},
      {VV_NAME("termblinkresp", VAR_STRING), VV_RO},
+     {VV_NAME("event",         VAR_DICT), VV_RO},
  };
  
  /* shorthand */
***************
*** 319,326 ****
  
      set_vim_var_nr(VV_SEARCHFORWARD, 1L);
      set_vim_var_nr(VV_HLSEARCH, 1L);
!     set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
      set_vim_var_list(VV_ERRORS, list_alloc());
  
      set_vim_var_nr(VV_FALSE, VVAL_FALSE);
      set_vim_var_nr(VV_TRUE, VVAL_TRUE);
--- 320,328 ----
  
      set_vim_var_nr(VV_SEARCHFORWARD, 1L);
      set_vim_var_nr(VV_HLSEARCH, 1L);
!     set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
      set_vim_var_list(VV_ERRORS, list_alloc());
+     set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
  
      set_vim_var_nr(VV_FALSE, VVAL_FALSE);
      set_vim_var_nr(VV_TRUE, VVAL_TRUE);
***************
*** 6633,6638 ****
--- 6635,6650 ----
  }
  
  /*
+  * Get Dict v: variable value.  Caller must take care of reference count when
+  * needed.
+  */
+     dict_T *
+ get_vim_var_dict(int idx)
+ {
+     return vimvars[idx].vv_dict;
+ }
+ 
+ /*
   * Set v:char to character "c".
   */
      void
***************
*** 6706,6730 ****
      void
  set_vim_var_dict(int idx, dict_T *val)
  {
-     int               todo;
-     hashitem_T        *hi;
- 
      clear_tv(&vimvars[idx].vv_di.di_tv);
      vimvars[idx].vv_type = VAR_DICT;
      vimvars[idx].vv_dict = val;
      if (val != NULL)
      {
        ++val->dv_refcount;
! 
!       /* Set readonly */
!       todo = (int)val->dv_hashtab.ht_used;
!       for (hi = val->dv_hashtab.ht_array; todo > 0 ; ++hi)
!       {
!           if (HASHITEM_EMPTY(hi))
!               continue;
!           --todo;
!           HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
!       }
      }
  }
  
--- 6718,6730 ----
      void
  set_vim_var_dict(int idx, dict_T *val)
  {
      clear_tv(&vimvars[idx].vv_di.di_tv);
      vimvars[idx].vv_type = VAR_DICT;
      vimvars[idx].vv_dict = val;
      if (val != NULL)
      {
        ++val->dv_refcount;
!       dict_set_items_ro(val);
      }
  }
  
*** ../vim-8.0.1393/src/fileio.c        2017-11-18 14:55:19.315803253 +0100
--- src/fileio.c        2017-12-16 18:03:25.440404381 +0100
***************
*** 6478,6483 ****
--- 6478,6484 ----
  /*
   * Like fgets(), but if the file line is too long, it is truncated and the
   * rest of the line is thrown away.  Returns TRUE for end-of-file.
+  * If the line is truncated then buf[size - 2] will not be NUL.
   */
      int
  vim_fgets(char_u *buf, int size, FILE *fp)
***************
*** 7856,7861 ****
--- 7857,7863 ----
      {"WinEnter",      EVENT_WINENTER},
      {"WinLeave",      EVENT_WINLEAVE},
      {"VimResized",    EVENT_VIMRESIZED},
+     {"TextYankPost",  EVENT_TEXTYANKPOST},
      {NULL,            (event_T)0}
  };
  
***************
*** 9400,9405 ****
--- 9402,9416 ----
  }
  
  /*
+  * Return TRUE when there is a TextYankPost autocommand defined.
+  */
+     int
+ has_textyankpost(void)
+ {
+     return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
+ }
+ 
+ /*
   * Execute autocommands for "event" and file name "fname".
   * Return TRUE if some commands were executed.
   */
*** ../vim-8.0.1393/src/ops.c   2017-12-05 17:22:07.386721705 +0100
--- src/ops.c   2017-12-16 18:21:46.457036162 +0100
***************
*** 1645,1650 ****
--- 1645,1707 ----
      y_regs[1].y_array = NULL;         /* set register one to empty */
  }
  
+     static void
+ yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
+ {
+     static int        recursive = FALSE;
+     dict_T    *v_event;
+     list_T    *list;
+     int               n;
+     char_u    buf[NUMBUFLEN + 2];
+     long      reglen = 0;
+ 
+     if (recursive)
+       return;
+ 
+     v_event = get_vim_var_dict(VV_EVENT);
+ 
+     list = list_alloc();
+     for (n = 0; n < reg->y_size; n++)
+       list_append_string(list, reg->y_array[n], -1);
+     list->lv_lock = VAR_FIXED;
+     dict_add_list(v_event, "regcontents", list);
+ 
+     buf[0] = (char_u)oap->regname;
+     buf[1] = NUL;
+     dict_add_nr_str(v_event, "regname", 0, buf);
+ 
+     buf[0] = get_op_char(oap->op_type);
+     buf[1] = get_extra_op_char(oap->op_type);
+     buf[2] = NUL;
+     dict_add_nr_str(v_event, "operator", 0, buf);
+ 
+     buf[0] = NUL;
+     buf[1] = NUL;
+     switch (get_reg_type(oap->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_nr_str(v_event, "regtype", 0, buf);
+ 
+     /* Lock the dictionary and its keys */
+     dict_set_items_ro(v_event);
+ 
+     recursive = TRUE;
+     textlock++;
+     apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
+     textlock--;
+     recursive = FALSE;
+ 
+     /* Empty the dictionary, v:event is still valid */
+     dict_free_contents(v_event);
+     hash_init(&v_event->dv_hashtab);
+ }
+ 
  /*
   * Handle a delete operation.
   *
***************
*** 1798,1803 ****
--- 1855,1865 ----
                return FAIL;
            }
        }
+ 
+ #ifdef FEAT_AUTOCMD
+       if (did_yank && has_textyankpost())
+           yank_do_autocmd(oap, y_current);
+ #endif
      }
  
      /*
***************
*** 3270,3275 ****
--- 3332,3342 ----
  # endif
  #endif
  
+ #ifdef FEAT_AUTOCMD
+     if (!deleting && has_textyankpost())
+       yank_do_autocmd(oap, y_current);
+ #endif
+ 
      return OK;
  
  fail:         /* free the allocated lines */
*** ../vim-8.0.1393/src/proto/dict.pro  2017-04-30 20:12:53.378810666 +0200
--- src/proto/dict.pro  2017-12-16 18:21:52.764994543 +0100
***************
*** 1,7 ****
--- 1,9 ----
  /* dict.c */
  dict_T *dict_alloc(void);
+ dict_T *dict_alloc_lock(int lock);
  int rettv_dict_alloc(typval_T *rettv);
  void rettv_dict_set(typval_T *rettv, dict_T *d);
+ void dict_free_contents(dict_T *d);
  void dict_unref(dict_T *d);
  int dict_free_nonref(int copyID);
  void dict_free_items(int copyID);
***************
*** 23,26 ****
--- 25,29 ----
  dictitem_T *dict_lookup(hashitem_T *hi);
  int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive);
  void dict_list(typval_T *argvars, typval_T *rettv, int what);
+ void dict_set_items_ro(dict_T *di);
  /* vim: set ft=c : */
*** ../vim-8.0.1393/src/proto/eval.pro  2017-10-30 21:48:36.482732724 +0100
--- src/proto/eval.pro  2017-12-16 18:03:25.440404381 +0100
***************
*** 64,69 ****
--- 64,70 ----
  varnumber_T get_vim_var_nr(int idx);
  char_u *get_vim_var_str(int idx);
  list_T *get_vim_var_list(int idx);
+ dict_T * get_vim_var_dict(int idx);
  void set_vim_var_char(int c);
  void set_vcount(long count, long count1, int set_prevcount);
  void set_vim_var_string(int idx, char_u *val, int len);
*** ../vim-8.0.1393/src/proto/fileio.pro        2016-09-12 13:04:04.000000000 
+0200
--- src/proto/fileio.pro        2017-12-16 18:03:25.440404381 +0100
***************
*** 51,56 ****
--- 51,57 ----
  int has_insertcharpre(void);
  int has_cmdundefined(void);
  int has_funcundefined(void);
+ int has_textyankpost(void);
  void block_autocmds(void);
  void unblock_autocmds(void);
  int is_autocmd_blocked(void);
*** ../vim-8.0.1393/src/testdir/test_autocmd.vim        2017-11-05 
16:23:05.085838996 +0100
--- src/testdir/test_autocmd.vim        2017-12-16 18:03:25.440404381 +0100
***************
*** 1124,1126 ****
--- 1124,1165 ----
    let &shelltemp = shelltemp
    bwipe!
  endfunc
+ 
+ func Test_TextYankPost()
+   enew!
+   call setline(1, ['foo'])
+ 
+   let g:event = []
+   au TextYankPost * let g:event = copy(v:event)
+ 
+   call assert_equal({}, v:event)
+   call assert_fails('let v:event = {}', 'E46:')
+   call assert_fails('let v:event.mykey = 0', 'E742:')
+ 
+   norm "ayiw
+   call assert_equal(
+     \{'regcontents': ['foo'], 'regname': 'a', 'operator': 'y', 'regtype': 
'v'},
+     \g:event)
+   norm y_
+   call assert_equal(
+     \{'regcontents': ['foo'], 'regname': '',  'operator': 'y', 'regtype': 
'V'},
+     \g:event)
+   call feedkeys("\<C-V>y", 'x')
+   call assert_equal(
+     \{'regcontents': ['f'], 'regname': '',  'operator': 'y', 'regtype': 
"\x161"},
+     \g:event)
+   norm "xciwbar
+   call assert_equal(
+     \{'regcontents': ['foo'], 'regname': 'x', 'operator': 'c', 'regtype': 
'v'},
+     \g:event)
+   norm "bdiw
+   call assert_equal(
+     \{'regcontents': ['bar'], 'regname': 'b', 'operator': 'd', 'regtype': 
'v'},
+     \g:event)
+ 
+   call assert_equal({}, v:event)
+ 
+   au! TextYankPost
+   unlet g:event
+   bwipe!
+ endfunc
*** ../vim-8.0.1393/src/vim.h   2017-12-05 20:31:02.524899040 +0100
--- src/vim.h   2017-12-16 18:03:25.440404381 +0100
***************
*** 1339,1344 ****
--- 1339,1345 ----
      EVENT_TEXTCHANGEDI,               /* text was modified in Insert mode*/
      EVENT_CMDUNDEFINED,               /* command undefined */
      EVENT_OPTIONSET,          /* option was set */
+     EVENT_TEXTYANKPOST,               /* after some text was yanked */
      NUM_EVENTS                        /* MUST be the last one */
  };
  
***************
*** 1988,1994 ****
  #define VV_TERMU7RESP 83
  #define VV_TERMSTYLERESP 84
  #define VV_TERMBLINKRESP 85
! #define VV_LEN                86      /* number of v: vars */
  
  /* used for v_number in VAR_SPECIAL */
  #define VVAL_FALSE    0L
--- 1989,1996 ----
  #define VV_TERMU7RESP 83
  #define VV_TERMSTYLERESP 84
  #define VV_TERMBLINKRESP 85
! #define VV_EVENT      86
! #define VV_LEN                87      /* number of v: vars */
  
  /* used for v_number in VAR_SPECIAL */
  #define VVAL_FALSE    0L
*** ../vim-8.0.1393/src/version.c       2017-12-16 16:33:39.703175875 +0100
--- src/version.c       2017-12-16 18:04:13.280075913 +0100
***************
*** 773,774 ****
--- 773,776 ----
  {   /* Add new patch number below this line */
+ /**/
+     1394,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
109. You actually read -- and enjoy -- lists like this.

 /// 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].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui