diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/auevents.lua | 1 | ||||
-rw-r--r-- | src/nvim/eval.c | 72 | ||||
-rw-r--r-- | src/nvim/eval.h | 3 | ||||
-rw-r--r-- | src/nvim/ops.c | 96 | ||||
-rw-r--r-- | src/nvim/pos.h | 6 |
5 files changed, 151 insertions, 27 deletions
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index aa4a8d8332..8d891effae 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -83,6 +83,7 @@ return { 'TermResponse', -- after setting "v:termresponse" 'TextChanged', -- text was modified 'TextChangedI', -- text was modified in Insert mode + 'TextYankPost', -- after a yank or delete was done (y, d, c) 'User', -- user defined autocommand 'VimEnter', -- after starting Vim 'VimLeave', -- before exiting Vim diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 76deedfad0..33b8415336 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -378,6 +378,7 @@ static struct vimvar { { VV_NAME("option_type", VAR_STRING), VV_RO }, { VV_NAME("errors", VAR_LIST), 0 }, { VV_NAME("msgpack_types", VAR_DICT), VV_RO }, + { VV_NAME("event", VAR_DICT), VV_RO }, }; /* shorthand */ @@ -545,6 +546,10 @@ void eval_init(void) set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict); set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc()); + + dict_T *v_event = dict_alloc(); + v_event->dv_lock = VAR_FIXED; + set_vim_var_dict(VV_EVENT, v_event); set_vim_var_list(VV_ERRORS, list_alloc()); set_vim_var_nr(VV_SEARCHFORWARD, 1L); set_vim_var_nr(VV_HLSEARCH, 1L); @@ -6017,6 +6022,27 @@ static void rettv_dict_alloc(typval_T *rettv) ++d->dv_refcount; } +/// Clear all the keys of a Dictionary. "d" remains a valid empty Dictionary. +/// +/// @param d The Dictionary to clear +void dict_clear(dict_T *d) + FUNC_ATTR_NONNULL_ALL +{ + hash_lock(&d->dv_hashtab); + assert(d->dv_hashtab.ht_locked > 0); + + size_t todo = d->dv_hashtab.ht_used; + for (hashitem_T *hi = d->dv_hashtab.ht_array; todo > 0; hi++) { + if (!HASHITEM_EMPTY(hi)) { + dictitem_free(HI2DI(hi)); + hash_remove(&d->dv_hashtab, hi); + todo--; + } + } + + hash_unlock(&d->dv_hashtab); +} + /* * Unreference a Dictionary: decrement the reference count and free it when it @@ -6258,6 +6284,24 @@ int dict_add_list(dict_T *d, char *key, list_T *list) return OK; } +/// Set all existing keys in "dict" as read-only. +/// +/// This does not protect against adding new keys to the Dictionary. +/// +/// @param dict The dict whose keys should be frozen +void dict_set_keys_readonly(dict_T *dict) + FUNC_ATTR_NONNULL_ALL +{ + size_t todo = dict->dv_hashtab.ht_used; + for (hashitem_T *hi = dict->dv_hashtab.ht_array; todo > 0 ; hi++) { + if (HASHITEM_EMPTY(hi)) { + continue; + } + todo--; + HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX; + } +} + /* * Get the number of items in a Dictionary. */ @@ -10579,8 +10623,6 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv) { char_u *strregname; int regname; - char_u buf[NUMBUFLEN + 2]; - long reglen = 0; if (argvars[0].v_type != VAR_UNKNOWN) { strregname = get_tv_string_chk(&argvars[0]); @@ -10597,18 +10639,13 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv) if (regname == 0) regname = '"'; - buf[0] = NUL; - buf[1] = NUL; - switch (get_reg_type(regname, ®len)) { - case MLINE: buf[0] = 'V'; break; - case MCHAR: buf[0] = 'v'; break; - case MBLOCK: - buf[0] = Ctrl_V; - sprintf((char *)buf + 1, "%" PRId64, (int64_t)(reglen + 1)); - break; - } + colnr_T reglen = 0; + char buf[NUMBUFLEN + 2]; + char_u reg_type = get_reg_type(regname, ®len); + format_reg_type(reg_type, reglen, buf, ARRAY_SIZE(buf)); + rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strsave(buf); + rettv->vval.v_string = (char_u *)xstrdup(buf); } /* @@ -18162,14 +18199,7 @@ void set_vim_var_dict(int idx, dict_T *val) if (val != NULL) { ++val->dv_refcount; // Set readonly - size_t todo = val->dv_hashtab.ht_used; - for (hashitem_T *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_keys_readonly(val); } } diff --git a/src/nvim/eval.h b/src/nvim/eval.h index 79a1341d98..f51b0f4921 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -113,7 +113,8 @@ enum { VV_OPTION_TYPE, VV_ERRORS, VV_MSGPACK_TYPES, - VV_LEN, /* number of v: vars */ + VV_EVENT, + VV_LEN, // number of v: vars }; /// Maximum number of function arguments diff --git a/src/nvim/ops.c b/src/nvim/ops.c index b1adc85e1d..ab6e0d2e7d 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -19,6 +19,7 @@ #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_getln.h" +#include "nvim/fileio.h" #include "nvim/fold.h" #include "nvim/getchar.h" #include "nvim/indent.h" @@ -1409,8 +1410,9 @@ int op_delete(oparg_T *oap) op_yank_reg(oap, false, reg, false); } - if(oap->regname == 0) { + if (oap->regname == 0) { set_clipboard(0, reg); + yank_do_autocmd(oap, reg); } } @@ -2309,6 +2311,8 @@ bool op_yank(oparg_T *oap, bool message) yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK); op_yank_reg(oap, message, reg, is_append_register(oap->regname)); set_clipboard(oap->regname, reg); + yank_do_autocmd(oap, reg); + return true; } @@ -2524,6 +2528,58 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, long y_idx) *pnew = NUL; } +/// Execute autocommands for TextYankPost. +/// +/// @param oap Operator arguments. +/// @param reg The yank register used. +static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg) + FUNC_ATTR_NONNULL_ALL +{ + static bool recursive = false; + + if (recursive || !has_event(EVENT_TEXTYANKPOST)) { + // No autocommand was defined + // or we yanked from this autocommand. + return; + } + + recursive = true; + + // set v:event to a dictionary with information about the yank + dict_T *dict = get_vim_var_dict(VV_EVENT); + + // the yanked text + list_T *list = list_alloc(); + for (linenr_T i = 0; i < reg->y_size; i++) { + list_append_string(list, reg->y_array[i], -1); + } + list->lv_lock = VAR_FIXED; + dict_add_list(dict, "regcontents", list); + + // the register type + char buf[NUMBUFLEN+2]; + format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf)); + dict_add_nr_str(dict, "regtype", 0, (char_u *)buf); + + // name of requested register or the empty string for an unnamed operation. + buf[0] = (char)oap->regname; + buf[1] = NUL; + dict_add_nr_str(dict, "regname", 0, (char_u *)buf); + + // kind of operation (yank/delete/change) + buf[0] = get_op_char(oap->op_type); + buf[1] = NUL; + dict_add_nr_str(dict, "operator", 0, (char_u *)buf); + + dict_set_keys_readonly(dict); + textlock++; + apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, false, curbuf); + textlock--; + dict_clear(dict); + + recursive = false; +} + /* * Put contents of register "regname" into the text. @@ -4631,7 +4687,7 @@ theend: * Used for getregtype() * Returns MAUTO for error. */ -char_u get_reg_type(int regname, long *reglen) +char_u get_reg_type(int regname, colnr_T *reg_width) { switch (regname) { case '%': /* file name */ @@ -4654,13 +4710,45 @@ char_u get_reg_type(int regname, long *reglen) yankreg_T *reg = get_yank_register(regname, YREG_PASTE); if (reg->y_array != NULL) { - if (reglen != NULL && reg->y_type == MBLOCK) - *reglen = reg->y_width; + if (reg_width != NULL && reg->y_type == MBLOCK) { + *reg_width = reg->y_width; + } return reg->y_type; } return MAUTO; } +/// Format the register type as a string. +/// +/// @param reg_type The register type. +/// @param reg_width The width, only used if "reg_type" is MBLOCK. +/// @param[out] buf Buffer to store formatted string. The allocated size should +/// be at least NUMBUFLEN+2 to always fit the value. +/// @param buf_len The allocated size of the buffer. +void format_reg_type(char_u reg_type, colnr_T reg_width, + char* buf, size_t buf_len) + FUNC_ATTR_NONNULL_ALL +{ + assert(buf_len > 1); + switch (reg_type) { + case MLINE: + buf[0] = 'V'; + buf[1] = NUL; + break; + case MCHAR: + buf[0] = 'v'; + buf[1] = NUL; + break; + case MBLOCK: + snprintf(buf, buf_len, CTRL_V_STR "%" PRIdCOLNR, reg_width + 1); + break; + case MAUTO: + buf[0] = NUL; + break; + } +} + + /// When `flags` has `kGRegList` return a list with text `s`. /// Otherwise just return `s`. /// diff --git a/src/nvim/pos.h b/src/nvim/pos.h index 7071df51e8..864f3fe866 100644 --- a/src/nvim/pos.h +++ b/src/nvim/pos.h @@ -2,7 +2,11 @@ #define NVIM_POS_H typedef long linenr_T; // line number type -typedef int colnr_T; // column number type + +/// Column number type +typedef int colnr_T; +/// Format used to print values which have colnr_T type +#define PRIdCOLNR "d" #define MAXLNUM 0x7fffffff // maximum (invalid) line number #define MAXCOL 0x7fffffff // maximum column number, 31 bits |