Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions runtime/doc/autocmd.txt
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ Name triggered by ~

|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 some text is yanked or deleted

|ColorScheme| after loading a color scheme

Expand Down Expand Up @@ -956,6 +957,24 @@ TextChangedI After a change was made to the text in the
current buffer in Insert mode.
Not triggered when the popup menu is visible.
Otherwise the same as TextChanged.
|TextYankPost|
TextYankPost After some 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 stored in the
register, as a list of
lines, like |readfile()|.
regname Name of the |register| or
empty string for the
unnamed one.
regtype Type of the register, see
|getregtype()|.
Not triggered when |quote_| is used nor when
called recursively.
It is not allowed to change the text |textlock|.

*User*
User Never executed automatically. To be used for
autocommands that are only executed with
Expand Down
6 changes: 6 additions & 0 deletions runtime/doc/eval.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1554,6 +1554,12 @@ v:errors Errors found by assert functions, such as |assert_true()|.
< 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 some informations 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|.
Expand Down
29 changes: 28 additions & 1 deletion src/dict.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ dict_alloc(void)
return d;
}

dict_T *
dict_alloc_lock(char 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.
Expand Down Expand Up @@ -80,7 +89,7 @@ rettv_dict_set(typval_T *rettv, dict_T *d)
* Free a Dictionary, including all non-container items it contains.
* Ignores the reference count.
*/
static void
void
dict_free_contents(dict_T *d)
{
int todo;
Expand All @@ -102,6 +111,8 @@ dict_free_contents(dict_T *d)
--todo;
}
}

/* The hashtab is still locked, it has to be re-initialized anyway */
hash_clear(&d->dv_hashtab);
}

Expand Down Expand Up @@ -846,4 +857,20 @@ dict_list(typval_T *argvars, typval_T *rettv, int what)
}
}

void
dict_set_ro_keys(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) */
27 changes: 14 additions & 13 deletions src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ static struct vimvar
{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 */
Expand Down Expand Up @@ -285,6 +286,7 @@ eval_init(void)
{
int i;
struct vimvar *p;
dict_T *d;

init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
Expand Down Expand Up @@ -321,6 +323,7 @@ eval_init(void)
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_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));

set_vim_var_nr(VV_FALSE, VVAL_FALSE);
set_vim_var_nr(VV_TRUE, VVAL_TRUE);
Expand Down Expand Up @@ -6627,6 +6630,16 @@ get_vim_var_list(int idx)
return vimvars[idx].vv_list;
}

/*
* 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".
*/
Expand Down Expand Up @@ -6701,25 +6714,13 @@ set_vim_var_list(int idx, list_T *val)
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;
}
dict_set_ro_keys(val);
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/fileio.c
Original file line number Diff line number Diff line change
Expand Up @@ -7805,6 +7805,7 @@ static struct event_name
{"WinEnter", EVENT_WINENTER},
{"WinLeave", EVENT_WINLEAVE},
{"VimResized", EVENT_VIMRESIZED},
{"TextYankPost", EVENT_TEXTYANKPOST},
{NULL, (event_T)0}
};

Expand Down Expand Up @@ -9348,6 +9349,15 @@ has_funcundefined(void)
return (first_autopat[(int)EVENT_FUNCUNDEFINED] != NULL);
}

/*
* 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.
Expand Down
67 changes: 67 additions & 0 deletions src/ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,63 @@ shift_delete_registers()
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_ro_keys(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.
*
Expand Down Expand Up @@ -1798,6 +1855,11 @@ op_delete(oparg_T *oap)
return FAIL;
}
}

#ifdef FEAT_AUTOCMD
if (did_yank && has_textyankpost())
yank_do_autocmd(oap, y_current);
#endif
}

/*
Expand Down Expand Up @@ -3270,6 +3332,11 @@ op_yank(oparg_T *oap, int deleting, int mess)
# endif
#endif

#ifdef FEAT_AUTOCMD
if (!deleting && has_textyankpost())
yank_do_autocmd(oap, y_current);
#endif

return OK;

fail: /* free the allocated lines */
Expand Down
3 changes: 3 additions & 0 deletions src/proto/dict.pro
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* dict.c */
dict_T *dict_alloc(void);
dict_T *dict_alloc_lock(char 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);
Expand All @@ -23,4 +25,5 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
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_ro_keys(dict_T *di);
/* vim: set ft=c : */
1 change: 1 addition & 0 deletions src/proto/eval.pro
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ void set_vim_var_nr(int idx, varnumber_T val);
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);
Expand Down
1 change: 1 addition & 0 deletions src/proto/fileio.pro
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ int has_textchangedI(void);
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);
Expand Down
39 changes: 39 additions & 0 deletions src/testdir/test_autocmd.vim
Original file line number Diff line number Diff line change
Expand Up @@ -1124,3 +1124,42 @@ func Test_Filter_noshelltemp()
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
4 changes: 3 additions & 1 deletion src/vim.h
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ enum auto_event
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 */
};

Expand Down Expand Up @@ -1983,7 +1984,8 @@ typedef int sock_T;
#define VV_TERMU7RESP 83
#define VV_TERMSTYLERESP 84
#define VV_TERMBLINKRESP 85
#define VV_LEN 86 /* number of v: vars */
#define VV_EVENT 86
#define VV_LEN 87 /* number of v: vars */

/* used for v_number in VAR_SPECIAL */
#define VVAL_FALSE 0L
Expand Down