diff options
author | Josh Rahm <rahm@google.com> | 2020-01-02 12:01:43 -0700 |
---|---|---|
committer | Josh Rahm <rahm@google.com> | 2022-01-11 14:31:07 -0700 |
commit | 1d4d42398055b1979b66a243161f8ee5fc7a19f5 (patch) | |
tree | b8c4a68041ac9f60c53f2f2b34184a3557656e74 | |
parent | 3b1675cc6215851fcf5c9274d6913539a7c97da6 (diff) | |
download | rneovim-1d4d42398055b1979b66a243161f8ee5fc7a19f5.tar.gz rneovim-1d4d42398055b1979b66a243161f8ee5fc7a19f5.tar.bz2 rneovim-1d4d42398055b1979b66a243161f8ee5fc7a19f5.zip |
Add user-registers for arbitrary registers.
This allows users to define behaviors for arbitrary registers. These
registers can be any character including multibyte characters. This
means that any character may be used as a register and if that register
is not a builtin register, it will defer to a user-defined vimscript
function for behavior.
This is done throw an option called 'userregfun'
The function that 'userregfun' defines is a function that takes 3
arguments:
action - Either set to "put" or "yank"
register - The character representing the register.
content - If the action is "yank" this string contains the content
yanked.
Multibyte registers are still broken for expressions. So while
let @&=xyz
Works as expected,
let @λ=xyz
will still throw a parse error.
-rw-r--r-- | src/nvim/buffer_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/eval.c | 4 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 1 | ||||
-rw-r--r-- | src/nvim/map.c | 2 | ||||
-rw-r--r-- | src/nvim/map.h | 2 | ||||
-rw-r--r-- | src/nvim/ops.c | 237 | ||||
-rw-r--r-- | src/nvim/ops.h | 13 | ||||
-rw-r--r-- | src/nvim/option.c | 4 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/options.lua | 9 | ||||
-rw-r--r-- | src/nvim/shada.c | 4 | ||||
-rw-r--r-- | src/nvim/yankmap.c | 42 | ||||
-rw-r--r-- | src/nvim/yankmap.h | 24 |
13 files changed, 291 insertions, 54 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index d5fb2df52b..0a7bd57565 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -700,6 +700,7 @@ struct file_buffer { char_u *b_p_cfu; ///< 'completefunc' char_u *b_p_ofu; ///< 'omnifunc' char_u *b_p_tfu; ///< 'tagfunc' + char_u *b_p_urf; ///< 'userregfunc' int b_p_eol; ///< 'endofline' int b_p_fixeol; ///< 'fixendofline' int b_p_et; ///< 'expandtab' diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6dbdc09c3b..a1c832bca5 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5313,7 +5313,7 @@ bool garbage_collect(bool testing) // registers (ShaDa additional data) { - const void *reg_iter = NULL; + iter_register_T reg_iter = ITER_REGISTER_NULL; do { yankreg_T reg; char name = NUL; @@ -5322,7 +5322,7 @@ bool garbage_collect(bool testing) if (name != NUL) { ABORTING(set_ref_dict)(reg.additional_data, copyID); } - } while (reg_iter != NULL); + } while (reg_iter != ITER_REGISTER_NULL); } // global marks (ShaDa additional data) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0525352e1c..875655d0b3 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4552,6 +4552,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) "nvim", "colorcolchar", "omnihighlight", + "userreg", }; bool n = false; diff --git a/src/nvim/map.c b/src/nvim/map.c index c77433df71..11102b022c 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -164,6 +164,8 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2) } +MAP_IMPL(ptr_t, int, DEFAULT_INITIALIZER) +MAP_IMPL(int, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(int, int, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER) diff --git a/src/nvim/map.h b/src/nvim/map.h index dbd85a4e1f..d94cfa92e8 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -34,6 +34,8 @@ // NOTE: Keys AND values must be allocated! khash.h does not make a copy. // MAP_DECLS(int, int) +MAP_DECLS(int, ptr_t) +MAP_DECLS(ptr_t, int) MAP_DECLS(cstr_t, ptr_t) MAP_DECLS(cstr_t, int) MAP_DECLS(ptr_t, ptr_t) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 013a78bdac..ef9fe055ac 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -57,7 +57,24 @@ #include "nvim/vim.h" #include "nvim/window.h" -static yankreg_T y_regs[NUM_REGISTERS]; +#include "nvim/yankmap.h" + +struct yank_registers { + yankmap_T inner; +}; + +yank_registers_T y_regs; + +static yankreg_T *get_reg(yank_registers_T *regs, int idx) +{ + return yankmap_get(®s->inner, idx); + +} + +static yankreg_T *get_global_reg(int idx) +{ + return get_reg(&y_regs, idx); +} static yankreg_T *y_previous = NULL; // ptr to last written yankreg @@ -776,6 +793,23 @@ char_u *get_expr_line_src(void) return vim_strsave(expr_line); } +int get_userreg(int regname) +{ + if ((regname >= 'a' && regname <= 'z') + || (regname >= 'A' && regname <= 'Z') + || (regname >= '0' && regname <= '9') + || (regname <= 127 && strchr("\"-:.%#=*+_/", regname)) + || regname == Ctrl_F + || regname == Ctrl_P + || regname == Ctrl_W + || regname == Ctrl_A + || (regname + USER_REGISTERS_START) < regname) { + return -1; + } + + return regname + USER_REGISTERS_START; +} + /// Returns whether `regname` is a valid name of a yank register. /// Note: There is no check for 0 (default register), caller should do this. /// The black hole register '_' is regarded as valid. @@ -791,7 +825,8 @@ bool valid_yank_reg(int regname, bool writing) || regname == '-' || regname == '_' || regname == '*' - || regname == '+') { + || regname == '+' + || get_userreg(regname) != -1) { return true; } return false; @@ -834,7 +869,7 @@ yankreg_T *get_yank_register(int regname, int mode) if (i == -1) { i = 0; } - reg = &y_regs[i]; + reg = get_global_reg(i); if (mode == YREG_YANK) { // remember the written register for unnamed paste @@ -1273,7 +1308,96 @@ static void stuffescaped(const char *arg, bool literally) /// @param errmsg give error message when failing /// /// @return true if "regname" is a special register, -bool get_spec_reg(int regname, char_u **argp, bool *allocated, bool errmsg) +bool get_spec_reg(int regname, char_u **argp, bool *allocated, bool errmsg); + +/* + * Executes a call to the put() function on a user-defined register to get the + * contents of a user defined register. + */ +static int eval_urf_put(char_u *ufn, int regname, char_u **argp) +{ + char_u regname_str[5]; + int len; + + len = (*utf_char2len)(regname); + regname_str[len] = 0; + utf_char2bytes(regname, regname_str); + + typval_T args[3]; + args[0].v_type = VAR_STRING; + args[1].v_type = VAR_STRING; + args[2].v_type = VAR_UNKNOWN; + + args[0].vval.v_string = (char_u *)"put"; + args[1].vval.v_string = regname_str; + + *argp = (char_u *)call_func_retstr((char *)ufn, 3, args); + return *argp == NULL; +} + +/* + * Executes the yank() function on a user-defined register to set the contents + * of that register. + */ +static int eval_yank_userreg(const char_u *ufn, int regname, yankreg_T *reg) +{ + if (!reg) + return -1; + + char_u *totalbuf; + size_t totallen = 0; + size_t i, j, k; + int ret, len; + char_u regname_str[5]; + + { + // Concat the contents of the register to pass into the yank() + // user-defined function. + for (i = 0; i < reg->y_size; ++i) { + totallen += strlen((char *)reg->y_array[i]) + 1; + } + totalbuf = xmalloc(sizeof(char_u) * totallen); + j = 0; + for (i = 0; i < reg->y_size; ++i) { + for (k = 0; reg->y_array[i][k] != 0; ++k, ++j) { + totalbuf[j] = reg->y_array[i][k]; + } + if (i < reg->y_size - 1) { + totalbuf[j++] = '\n'; + } + } + totalbuf[j++] = 0; + } + + len = (*utf_char2len)(regname); + regname_str[len] = 0; + utf_char2bytes(regname, regname_str); + + typval_T args[4]; + args[0].v_type = VAR_STRING; + args[1].v_type = VAR_STRING; + args[2].v_type = VAR_STRING; + args[3].v_type = VAR_UNKNOWN; + + args[0].vval.v_string = (char_u *)"yank"; + args[1].vval.v_string = regname_str; + args[2].vval.v_string = totalbuf; + + char_u *dup_ufn = (char_u *)xstrdup((char *)ufn); + ret = (int)call_func_retnr(dup_ufn, 3, args); + xfree(dup_ufn); + xfree(totalbuf); + return ret; +} + +// If "regname" is a special register, return true and store a pointer to its +// value in "argp". +bool get_spec_reg( + int regname, + char_u **argp, + bool *allocated, // return: true when value was allocated + bool errmsg // give error message when failing +) { size_t cnt; @@ -1351,6 +1475,15 @@ bool get_spec_reg(int regname, char_u **argp, bool *allocated, bool errmsg) case '_': // black hole: always empty *argp = (char_u *)""; return true; + + default: /* User-defined registers. */ + if (get_userreg(regname) != -1) { + if (!curbuf->b_p_urf || strlen((char *) curbuf->b_p_urf) == 0) + return false; + eval_urf_put(curbuf->b_p_urf, regname, argp); + *allocated = true; + return true; + } } return false; @@ -1397,14 +1530,14 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr) // Shift the delete registers: "9 is cleared, "8 becomes "9, etc. static void shift_delete_registers(bool y_append) { - free_register(&y_regs[9]); // free register "9 + free_register(get_global_reg(9)); // free register "9 for (int n = 9; n > 1; n--) { - y_regs[n] = y_regs[n - 1]; + *get_global_reg(n) = *get_global_reg(n - 1); } if (!y_append) { - y_previous = &y_regs[1]; + y_previous = get_global_reg(1); } - y_regs[1].y_array = NULL; // set register "1 to empty + get_global_reg(1)->y_array = NULL; // set register "1 to empty } /* @@ -1502,7 +1635,7 @@ int op_delete(oparg_T *oap) if (oap->regname != 0 || oap->motion_type == kMTLineWise || oap->line_count > 1 || oap->use_reg_one) { shift_delete_registers(is_append_register(oap->regname)); - reg = &y_regs[1]; + reg = get_global_reg(1); op_yank_reg(oap, false, reg, false); did_yank = true; } @@ -2510,7 +2643,7 @@ int op_change(oparg_T *oap) */ void init_yank(void) { - memset(&(y_regs[0]), 0, sizeof(y_regs)); + init_yankmap(&y_regs.inner); } #if defined(EXITFREE) @@ -2519,7 +2652,7 @@ void clear_registers(void) int i; for (i = 0; i < NUM_REGISTERS; i++) { - free_register(&y_regs[i]); + free_register(get_global_reg(i)); } } @@ -2563,6 +2696,11 @@ bool op_yank(oparg_T *oap, bool message, int deleting) yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK); op_yank_reg(oap, message, reg, is_append_register(oap->regname)); + + if (get_userreg(oap->regname) != -1) { + return eval_yank_userreg(curbuf->b_p_urf, oap->regname, reg) != -1; + } + // op_delete will set_clipboard and do_autocmd if (!deleting) { set_clipboard(oap->regname, reg); @@ -3017,7 +3155,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (insert_string != NULL) { y_type = kMTCharWise; - if (regname == '=') { + if (regname == '=' || get_userreg(regname) != -1) { /* For the = register we need to split the string at NL * characters. * Loop twice: count the number of lines and save them. */ @@ -3676,7 +3814,7 @@ int get_register_name(int num) /// @return the index of the register "" points to. int get_unname_register(void) { - return y_previous == NULL ? -1 : (int)(y_previous - &y_regs[0]); + return yankmap_find(&y_regs.inner, y_previous); } /* @@ -3718,10 +3856,10 @@ void ex_display(exarg_T *eap) if (y_previous != NULL) { yb = y_previous; } else { - yb = &(y_regs[0]); + yb = get_global_reg(0); } } else { - yb = &(y_regs[i]); + yb = get_global_reg(i); } get_clipboard(name, &yb, true); @@ -5406,6 +5544,10 @@ static void finish_write_reg(int name, yankreg_T *reg, yankreg_T *old_y_previous // Send text of clipboard register to the clipboard. set_clipboard(name, reg); + if (get_userreg(name) != -1) { + eval_yank_userreg(curbuf->b_p_urf, name, reg); + } + // ':let @" = "val"' should change the meaning of the "" register if (name != '"') { y_previous = old_y_previous; @@ -6784,7 +6926,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) } if (explicit_cb_reg) { - target = &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER]; + target = get_global_reg(*name == '*' ? STAR_REGISTER : PLUS_REGISTER); if (writing && (cb_flags & (*name == '*' ? CB_UNNAMED : CB_UNNAMEDPLUS))) { clipboard_needs_update = false; } @@ -6801,10 +6943,10 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) if (cb_flags & CB_UNNAMEDPLUS) { *name = (cb_flags & CB_UNNAMED && writing) ? '"': '+'; - target = &y_regs[PLUS_REGISTER]; + target = get_global_reg(PLUS_REGISTER); } else { *name = '*'; - target = &y_regs[STAR_REGISTER]; + target = get_global_reg(STAR_REGISTER); } goto end; } @@ -7121,11 +7263,11 @@ static inline bool reg_empty(const yankreg_T *const reg) /// Iterate over global registers. /// /// @see op_register_iter -const void *op_global_reg_iter(const void *const iter, char *const name, yankreg_T *const reg, - bool *is_unnamed) +iter_register_T op_global_reg_iter(iter_register_T iter, char *const name, + yankreg_T *const reg, bool *is_unnamed) FUNC_ATTR_NONNULL_ARG(2, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT { - return op_reg_iter(iter, y_regs, name, reg, is_unnamed); + return op_reg_iter(iter, &y_regs, name, reg, is_unnamed); } /// Iterate over registers `regs`. @@ -7137,30 +7279,31 @@ const void *op_global_reg_iter(const void *const iter, char *const name, yankreg /// /// @return Pointer that must be passed to next `op_register_iter` call or /// NULL if iteration is over. -const void *op_reg_iter(const void *const iter, const yankreg_T *const regs, char *const name, - yankreg_T *const reg, bool *is_unnamed) +iter_register_T op_reg_iter(iter_register_T iter, yank_registers_T *regs, + char *const name, yankreg_T *const reg, + bool *is_unnamed) FUNC_ATTR_NONNULL_ARG(3, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT { *name = NUL; - const yankreg_T *iter_reg = (iter == NULL - ? &(regs[0]) - : (const yankreg_T *const)iter); - while (iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS && reg_empty(iter_reg)) { - iter_reg++; - } - if (iter_reg - &(regs[0]) == NUM_SAVED_REGISTERS || reg_empty(iter_reg)) { - return NULL; - } - int iter_off = (int)(iter_reg - &(regs[0])); - *name = (char)get_register_name(iter_off); - *reg = *iter_reg; - *is_unnamed = (iter_reg == y_previous); - while (++iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS) { - if (!reg_empty(iter_reg)) { - return (void *)iter_reg; + int iter_idx = (int)(iter == ITER_REGISTER_NULL ? 0 : iter - 1); + + while (iter_idx < NUM_SAVED_REGISTERS && reg_empty(get_reg(regs, iter_idx))) + ++iter_idx; + + if (iter_idx >= NUM_SAVED_REGISTERS || reg_empty(get_reg(regs, iter_idx))) + return ITER_REGISTER_NULL; + + *reg = *get_reg(regs, iter_idx); + *name = (char)get_register_name((int)iter_idx); + *is_unnamed = (get_reg(regs, iter_idx) == y_previous); + + while (++iter_idx < NUM_SAVED_REGISTERS) { + if (!reg_empty(get_reg(regs, iter_idx))) { + return (iter_register_T)(iter_idx + 1); } } - return NULL; + + return ITER_REGISTER_NULL; } /// Get a number of non-empty registers @@ -7168,8 +7311,8 @@ size_t op_reg_amount(void) FUNC_ATTR_WARN_UNUSED_RESULT { size_t ret = 0; - for (size_t i = 0; i < NUM_SAVED_REGISTERS; i++) { - if (!reg_empty(y_regs + i)) { + for (int i = 0; i < NUM_SAVED_REGISTERS; i++) { + if (!reg_empty(get_global_reg(i))) { ret++; } } @@ -7189,11 +7332,11 @@ bool op_reg_set(const char name, const yankreg_T reg, bool is_unnamed) if (i == -1) { return false; } - free_register(&y_regs[i]); - y_regs[i] = reg; + free_register(get_global_reg(i)); + *get_global_reg(i) = reg; if (is_unnamed) { - y_previous = &y_regs[i]; + y_previous = get_global_reg(i); } return true; } @@ -7209,7 +7352,7 @@ const yankreg_T *op_reg_get(const char name) if (i == -1) { return NULL; } - return &y_regs[i]; + return get_global_reg(i); } /// Set the previous yank register @@ -7225,7 +7368,7 @@ bool op_reg_set_previous(const char name) return false; } - y_previous = &y_regs[i]; + y_previous = get_global_reg(i); return true; } diff --git a/src/nvim/ops.h b/src/nvim/ops.h index efde7290cf..af49e271cb 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -22,6 +22,7 @@ typedef int (*Indenter)(void); #define PUT_LINE_SPLIT 16 // split line for linewise register #define PUT_LINE_FORWARD 32 // put linewise register below Visual sel. #define PUT_BLOCK_INNER 64 // in block mode, do not add trailing spaces +#define ITER_REGISTER_NULL 0 /* * Registers: @@ -37,7 +38,8 @@ typedef int (*Indenter)(void); // The following registers should not be saved in ShaDa file: #define STAR_REGISTER 37 #define PLUS_REGISTER 38 -#define NUM_REGISTERS 39 +#define USER_REGISTERS_START 39 +#define NUM_REGISTERS USER_REGISTERS_START // Operator IDs; The order must correspond to opchars[] in ops.c! #define OP_NOP 0 // no pending operation @@ -96,6 +98,8 @@ typedef enum { YREG_YANK, YREG_PUT, } yreg_mode_t; +/// Returns a reference to a user-defined register. +int get_userreg(const int regname); /// Convert register name into register index /// @@ -118,10 +122,15 @@ static inline int op_reg_index(const int regname) } else if (regname == '+') { return PLUS_REGISTER; } else { - return -1; + return get_userreg(regname); } } +struct yank_registers; +typedef struct yank_registers yank_registers_T; + +typedef size_t iter_register_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ops.h.generated.h" #endif diff --git a/src/nvim/option.c b/src/nvim/option.c index 80f74f9d4a..80a6596469 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5980,7 +5980,6 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curwin->w_p_cocu); case PV_COLE: return (char_u *)&(curwin->w_p_cole); - case PV_AI: return (char_u *)&(curbuf->b_p_ai); case PV_BIN: @@ -6019,6 +6018,8 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_cfu); case PV_OFU: return (char_u *)&(curbuf->b_p_ofu); + case PV_URF: + return (char_u *)&(curbuf->b_p_urf); case PV_EOL: return (char_u *)&(curbuf->b_p_eol); case PV_FIXEOL: @@ -6364,6 +6365,7 @@ void buf_copy_options(buf_T *buf, int flags) #endif buf->b_p_cfu = vim_strsave(p_cfu); buf->b_p_ofu = vim_strsave(p_ofu); + buf->b_p_urf = vim_strsave(p_urf); buf->b_p_tfu = vim_strsave(p_tfu); buf->b_p_sts = p_sts; buf->b_p_sts_nopaste = p_sts_nopaste; diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 09c3bf3800..9b7715cbe4 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -744,6 +744,7 @@ EXTERN int p_wa; // 'writeany' EXTERN int p_wb; // 'writebackup' EXTERN long p_wd; // 'writedelay' EXTERN int p_cdh; // 'cdhome' +EXTERN char_u *p_urf; // 'userregister' EXTERN int p_force_on; ///< options that cannot be turned off. EXTERN int p_force_off; ///< options that cannot be turned on. @@ -839,6 +840,7 @@ enum { BV_WM, BV_VSTS, BV_VTS, + BV_URF, BV_COUNT, // must be the last one }; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 5133fe7ac8..7715a8803f 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2674,6 +2674,15 @@ return { defaults={if_true=4000} }, { + full_name='userregfun', abbreviation='urf', + type='string', scope={'buffer'}, + secure=true, + vi_def=true, + alloced=true, + varname='p_urf', + defaults={if_true=""} + }, + { full_name='varsofttabstop', abbreviation='vsts', short_desc=N_("list of numbers of spaces that <Tab> uses while editing"), type='string', list='comma', scope={'buffer'}, diff --git a/src/nvim/shada.c b/src/nvim/shada.c index e75a244031..d7bda03116 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -2380,7 +2380,7 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse, static inline void shada_initialize_registers(WriteMergerState *const wms, int max_reg_lines) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE { - const void *reg_iter = NULL; + iter_register_T reg_iter = ITER_REGISTER_NULL; const bool limit_reg_lines = max_reg_lines >= 0; do { yankreg_T reg; @@ -2411,7 +2411,7 @@ static inline void shada_initialize_registers(WriteMergerState *const wms, int m } } }; - } while (reg_iter != NULL); + } while (reg_iter != ITER_REGISTER_NULL); } /// Replace numbered mark in WriteMergerState diff --git a/src/nvim/yankmap.c b/src/nvim/yankmap.c new file mode 100644 index 0000000000..d9229e015d --- /dev/null +++ b/src/nvim/yankmap.c @@ -0,0 +1,42 @@ +#include "nvim/yankmap.h" + +#include "nvim/memory.h" + +void init_yankmap(yankmap_T* map) +{ + memset(map, 0, sizeof(yankmap_T)); + + map_init(int, ptr_t, &map->reg_to_yankreg); + map_init(ptr_t, int, &map->yankreg_to_reg); +} + +yankreg_T* yankmap_get(yankmap_T* yankmap, int reg) +{ + yankreg_T** ret = + (yankreg_T**) map_ref(int, ptr_t)(&yankmap->reg_to_yankreg, reg, true); + + if (ret) { + if (! (*ret)) { + *ret = xcalloc(sizeof(yankreg_T), 1); + } + + /* Add the back-reference */ + int* ref = map_ref(ptr_t, int)(&yankmap->yankreg_to_reg, *ret, true); + *ref = reg; + + return *ret; + } + + return NULL; +} + +int yankmap_find(yankmap_T* yankmap, yankreg_T* yankreg) +{ + int* ref = map_ref(ptr_t, int)(&yankmap->yankreg_to_reg, yankreg, false); + + if (ref) { + return *ref; + } + + return -1; +} diff --git a/src/nvim/yankmap.h b/src/nvim/yankmap.h new file mode 100644 index 0000000000..da7c4dcf13 --- /dev/null +++ b/src/nvim/yankmap.h @@ -0,0 +1,24 @@ +#ifndef YANK_TRIE_H_ +#define YANK_TRIE_H_ + +#include <stdbool.h> +#include "nvim/ops.h" +#include "nvim/map.h" + +typedef struct { + /* Register name to yank register. */ + Map(int, ptr_t) reg_to_yankreg; + + /* Yank register to register name. */ + Map(ptr_t, int) yankreg_to_reg; +} yankmap_T; + +void init_yankmap(yankmap_T* yankmap); + +yankreg_T* yankmap_get(yankmap_T* yankmap, int index); + +yankreg_T* yankmap_put(yankmap_T* yankmap, int index); + +int yankmap_find(yankmap_T* yankmap, yankreg_T* yankreg); + +#endif |