diff --git a/src/nvim/normal.c b/src/nvim/normal.c index fc5073b1772aa5..5a4c3a326ab8e8 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -923,6 +923,7 @@ normal_cmd ( /* Adjust the register according to 'clipboard', so that when * "unnamed" is present it becomes '*' or '+' instead of '"'. */ + adjust_clipboard_register(®name); set_reg_var(regname); } } @@ -5101,6 +5102,7 @@ static void nv_brackets(cmdarg_T *cap) end = equalpos(start, VIsual) ? curwin->w_cursor : VIsual; curwin->w_cursor = (dir == BACKWARD ? start : end); } + adjust_clipboard_register(®name); prep_redo_cmd(cap); do_put(regname, dir, cap->count1, PUT_FIXINDENT); if (was_visual) { @@ -7267,9 +7269,10 @@ static void nv_put(cmdarg_T *cap) */ was_visual = TRUE; regname = cap->oap->regname; + bool adjusted = adjust_clipboard_register(®name); if (regname == 0 || regname == '"' || VIM_ISDIGIT(regname) || regname == '-' - + || adjusted ) { /* The delete is going to overwrite the register we want to * put, save it first. */ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 4432116193743e..3008af94f3ab85 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -47,6 +47,9 @@ #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/window.h" +#include "nvim/os/provider.h" +#include "nvim/os/msgpack_rpc_helpers.h" +#include "nvim/api/private/helpers.h" /* * Registers: @@ -55,8 +58,9 @@ * 10..35 = registers 'a' to 'z' * 36 = delete register '-' */ -#define NUM_REGISTERS 37 +#define NUM_REGISTERS 38 #define DELETION_REGISTER 36 +#define CLIP_REGISTER 37 /* * Each yank register is an array of pointers to lines. @@ -711,6 +715,8 @@ valid_yank_reg ( || regname == '"' || regname == '-' || regname == '_' + || regname == '*' + || regname == '+' ) return TRUE; return FALSE; @@ -743,6 +749,8 @@ void get_yank_register(int regname, int writing) y_append = TRUE; } else if (regname == '-') i = DELETION_REGISTER; + else if (regname == '*' || regname == '+') + i = CLIP_REGISTER; else /* not 0-9, a-z, A-Z or '-': use register 0 */ i = 0; y_current = &(y_regs[i]); @@ -762,6 +770,7 @@ get_register ( ) FUNC_ATTR_NONNULL_RET { get_yank_register(name, 0); + get_clipboard(name); struct yankreg *reg = xmalloc(sizeof(struct yankreg)); *reg = *y_current; @@ -789,7 +798,7 @@ void put_register(int name, void *reg) free_yank_all(); *y_current = *(struct yankreg *)reg; free(reg); - + set_clipboard(name); } /* @@ -929,6 +938,7 @@ do_execreg ( } execreg_lastc = regname; + get_clipboard(regname); if (regname == '_') /* black hole: don't stuff anything */ return OK; @@ -1093,6 +1103,7 @@ insert_reg ( if (regname != NUL && !valid_yank_reg(regname, FALSE)) return FAIL; + get_clipboard(regname); if (regname == '.') /* insert last inserted text */ retval = stuff_inserted(NUL, 1L, TRUE); @@ -1278,6 +1289,17 @@ cmdline_paste_reg ( return OK; } +bool adjust_clipboard_register(int *rp) +{ + // If no reg. specified and 'unnamedclip' is set, use the + // clipboard register. + if (*rp == 0 && p_unc && provider_has_feature("clipboard")) { + *rp = '+'; + return true; + } + + return false; +} /* * Handle a delete operation. @@ -1307,6 +1329,7 @@ int op_delete(oparg_T *oap) return FAIL; } + bool adjusted = adjust_clipboard_register(&oap->regname); if (has_mbyte) mb_adjust_opend(oap); @@ -1389,6 +1412,7 @@ int op_delete(oparg_T *oap) /* Yank into small delete register when no named register specified * and the delete is within one line. */ if (( + adjusted || oap->regname == 0) && oap->motion_type != MLINE && oap->line_count == 1) { oap->regname = '-'; @@ -2336,7 +2360,6 @@ int op_yank(oparg_T *oap, int deleting, int mess) if (oap->regname == '_') /* black hole: nothing to do */ return OK; - if (!deleting) /* op_delete() already set y_current */ get_yank_register(oap->regname, TRUE); @@ -2519,6 +2542,8 @@ int op_yank(oparg_T *oap, int deleting, int mess) curbuf->b_op_end.col = MAXCOL; } + set_clipboard(oap->regname); + return OK; } @@ -2581,6 +2606,8 @@ do_put ( int allocated = FALSE; long cnt; + adjust_clipboard_register(®name); + get_clipboard(regname); if (flags & PUT_FIXINDENT) orig_indent = get_indent(); @@ -3171,6 +3198,8 @@ void ex_display(exarg_T *eap) ) continue; /* did not ask for this register */ + adjust_clipboard_register(&name); + get_clipboard(name); if (i == -1) { if (y_previous != NULL) @@ -4528,6 +4557,9 @@ void write_viminfo_registers(FILE *fp) for (i = 0; i < NUM_REGISTERS; i++) { if (y_regs[i].y_array == NULL) continue; + // Skip '*'/'+' register, we don't want them back next time + if (i == CLIP_REGISTER) + continue; /* Skip empty registers. */ num_lines = y_regs[i].y_size; if (num_lines == 0 @@ -4607,6 +4639,7 @@ char_u get_reg_type(int regname, long *reglen) return MCHAR; } + get_clipboard(regname); if (regname != NUL && !valid_yank_reg(regname, FALSE)) return MAUTO; @@ -4654,6 +4687,7 @@ get_reg_contents ( if (regname != NUL && !valid_yank_reg(regname, FALSE)) return NULL; + get_clipboard(regname); if (get_spec_reg(regname, &retval, &allocated, FALSE)) { if (retval == NULL) @@ -5162,3 +5196,88 @@ void cursor_pos_info(void) } } +static void free_register(struct yankreg *reg) +{ + // Save 'y_current' into 'curr' + struct yankreg *curr = y_current; + // Set it to 'y_current' since 'free_yank_all' operates on it + y_current = reg; + free_yank_all(); + // Restore 'y_current' + y_current = curr; +} + +static void copy_register(struct yankreg *dest, struct yankreg *src) +{ + free_register(dest); + *dest = *src; + dest->y_array = xcalloc(src->y_size, sizeof(uint8_t *)); + for (int j = 0; j < src->y_size; ++j) { + dest->y_array[j] = (uint8_t *)xstrdup((char *)src->y_array[j]); + } +} + +static void get_clipboard(int name) +{ + if (!(name == '*' || name == '+' + || (p_unc && !name && provider_has_feature("clipboard")))) { + return; + } + + struct yankreg *reg = &y_regs[CLIP_REGISTER]; + free_register(reg); + Object result = provider_call("clipboard_get", NIL); + + if (result.type != kObjectTypeArray) { + goto err; + } + + Array lines = result.data.array; + reg->y_array = xcalloc(lines.size, sizeof(uint8_t *)); + reg->y_size = lines.size; + + for (size_t i = 0; i < lines.size; i++) { + if (lines.items[i].type != kObjectTypeString) { + goto err; + } + reg->y_array[i] = (uint8_t *)lines.items[i].data.string.data; + } + + if (!name && p_unc) { + // copy to the unnamed register + copy_register(&y_regs[0], reg); + } + + return; + +err: + msgpack_rpc_free_object(result); + free(reg->y_array); + reg->y_array = NULL; + reg->y_size = 0; + EMSG("Clipboard provider returned invalid data"); +} + +static void set_clipboard(int name) +{ + if (!(name == '*' || name == '+' + || (p_unc && !name && provider_has_feature("clipboard")))) { + return; + } + + struct yankreg *reg = &y_regs[CLIP_REGISTER]; + + if (!name && p_unc) { + // copy from the unnamed register + copy_register(reg, &y_regs[0]); + } + + Array lines = {0, 0, 0}; + + for (int i = 0; i < reg->y_size; i++) { + ADD(lines, STRING_OBJ(cstr_to_string((char *)reg->y_array[i]))); + } + + Object result = provider_call("clipboard_set", ARRAY_OBJ(lines)); + msgpack_rpc_free_object(result); +} diff --git a/src/nvim/option.c b/src/nvim/option.c index 5b3f0d5612ae72..28bbfb41e7001f 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -963,6 +963,9 @@ static struct vimoption {"infercase", "inf", P_BOOL|P_VI_DEF, (char_u *)&p_inf, PV_INF, {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, + {"initclipboard","icpb",P_STRING|P_VI_DEF|P_SECURE, + (char_u *)&p_icpb, PV_NONE, + {(char_u *)NULL, (char_u *)0L} SCRIPTID_INIT}, {"initpython","ipy",P_STRING|P_VI_DEF|P_SECURE, (char_u *)&p_ipy, PV_NONE, {(char_u *)NULL, (char_u *)0L} SCRIPTID_INIT}, @@ -1628,6 +1631,9 @@ static struct vimoption {"undoreload", "ur", P_NUM|P_VI_DEF, (char_u *)&p_ur, PV_NONE, { (char_u *)10000L, (char_u *)0L} SCRIPTID_INIT}, + {"unnamedclip", "ucp", P_BOOL|P_VI_DEF|P_VIM, + (char_u *)&p_unc, PV_NONE, + {(char_u *)FALSE, (char_u *)FALSE} SCRIPTID_INIT}, {"updatecount", "uc", P_NUM|P_VI_DEF, (char_u *)&p_uc, PV_NONE, {(char_u *)200L, (char_u *)0L} SCRIPTID_INIT}, diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 401cf3d2001e6a..f75824ec03fe36 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -586,6 +586,7 @@ static char *(p_ttym_values[]) = EXTERN char_u *p_udir; /* 'undodir' */ EXTERN long p_ul; /* 'undolevels' */ EXTERN long p_ur; /* 'undoreload' */ +EXTERN int p_unc; /* 'unnamedclip' */ EXTERN long p_uc; /* 'updatecount' */ EXTERN long p_ut; /* 'updatetime' */ EXTERN char_u *p_fcs; /* 'fillchar' */ @@ -631,6 +632,7 @@ EXTERN int p_wa; /* 'writeany' */ EXTERN int p_wb; /* 'writebackup' */ EXTERN long p_wd; /* 'writedelay' */ EXTERN char *p_ipy; // 'initpython' +EXTERN char *p_icpb; // 'initclipboard' /* * "indir" values for buffer-local opions. diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c index 9bd1c8256947fd..2e42cbb8f28500 100644 --- a/src/nvim/os/provider.c +++ b/src/nvim/os/provider.c @@ -36,7 +36,12 @@ static struct feature { "python_execute", "python_execute_file", "python_do_range", - "python_eval") + "python_eval"), + + FEATURE("clipboard", + &p_icpb, + "clipboard_get", + "clipboard_set") }; static Map(cstr_t, uint64_t) *registered_providers = NULL;