diff options
Diffstat (limited to 'src/nvim/ops.c')
| -rw-r--r-- | src/nvim/ops.c | 125 | 
1 files changed, 122 insertions, 3 deletions
| diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 4432116193..3008af94f3 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); +} | 
