From c1854d2433a10122ae2933e2dcbc970b53e9438b Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 22 Nov 2014 16:01:14 +0100 Subject: clipboard: support separate '+' and '*' clipboards --- src/nvim/eval.c | 14 ++++++++++++++ src/nvim/ops.c | 13 ++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index be69bdbe61..c2156c5d58 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5118,6 +5118,20 @@ void list_append_tv(list_T *l, typval_T *tv) list_append(l, li); } +/* + * Add a list to a list. + */ +void list_append_list(list_T *list, list_T *itemlist) +{ + listitem_T *li = listitem_alloc(); + + li->li_tv.v_type = VAR_LIST; + li->li_tv.v_lock = 0; + li->li_tv.vval.v_list = itemlist; + list_append(list, li); + ++list->lv_refcount; +} + /* * Add a dictionary to a list. Used by getqflist(). */ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 6bf3f6036f..8dfb986714 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5244,7 +5244,11 @@ static void get_clipboard(int name) struct yankreg *reg = &y_regs[CLIP_REGISTER]; free_register(reg); + list_T *args = list_alloc(); + char_u regname = (char_u)name; + list_append_string(args, ®name, 1); + typval_T result = eval_call_provider("clipboard", "get", args); if (result.v_type != VAR_LIST) { @@ -5294,6 +5298,7 @@ static void set_clipboard(int name) if (!name && p_unc) { // copy from the unnamed register copy_register(reg, &y_regs[0]); + name = '+'; } list_T *lines = list_alloc(); @@ -5302,5 +5307,11 @@ static void set_clipboard(int name) list_append_string(lines, reg->y_array[i], -1); } - (void)eval_call_provider("clipboard", "set", lines); + list_T *args = list_alloc(); + list_append_list(args, lines); + + char_u regname = (char_u)name; + list_append_string(args, ®name, 1); + + (void)eval_call_provider("clipboard", "set", args); } -- cgit From 63efb9b1f14420f5402e04c282b79d4515c2384e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 22 Nov 2014 19:16:04 +0100 Subject: clipboard: handle linewise/charwise selections correctly --- src/nvim/ops.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 8dfb986714..8a174c2a9e 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5255,7 +5255,35 @@ static void get_clipboard(int name) goto err; } - list_T *lines = result.vval.v_list; + list_T *res = result.vval.v_list, *lines = NULL; + if (res->lv_len == 2 && res->lv_first->li_tv.v_type == VAR_LIST) { + lines = res->lv_first->li_tv.vval.v_list; + if (res->lv_last->li_tv.v_type != VAR_STRING) { + goto err; + } + char_u* regtype = res->lv_last->li_tv.vval.v_string; + if (regtype == NULL || strlen((char*)regtype) != 1) { + goto err; + } + switch (regtype[0]) { + case 'v': case 'c': + reg->y_type = MCHAR; + break; + case 'V': case 'l': + reg->y_type = MLINE; + break; + case 'b': case Ctrl_V: + reg->y_type = MBLOCK; + break; + default: + goto err; + } + } else { + lines = res; + // provider did not specify regtype, calculate it below + reg->y_type = MAUTO; + } + reg->y_array = xcalloc(lines->lv_len, sizeof(uint8_t *)); reg->y_size = lines->lv_len; @@ -5267,6 +5295,25 @@ static void get_clipboard(int name) reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string); } + if (reg->y_type == MAUTO) { + if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) { + reg->y_type = MLINE; + free(reg->y_array[reg->y_size-1]); + reg->y_size--; + } else { + reg->y_type = MCHAR; + } + } else if (reg->y_type == MBLOCK) { + int maxlen = 0; + for (int i = 0; i < reg->y_size; i++) { + int rowlen = STRLEN(reg->y_array[i]); + if (rowlen > maxlen) { + maxlen = rowlen; + } + } + reg->y_width = maxlen-1; + } + if (!name && p_unc) { // copy to the unnamed register copy_register(&y_regs[0], reg); @@ -5310,6 +5357,21 @@ static void set_clipboard(int name) list_T *args = list_alloc(); list_append_list(args, lines); + char_u regtype; + switch (reg->y_type) { + case MLINE: + regtype = 'V'; + list_append_string(lines, (char_u*)"", 0); + break; + case MCHAR: + regtype = 'v'; + break; + case MBLOCK: + regtype = 'b'; + break; + } + list_append_string(args, ®type, 1); + char_u regname = (char_u)name; list_append_string(args, ®name, 1); -- cgit From 61aaf815dbf42c11947748656f377f578c4ed4c7 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 16 Sep 2014 11:32:02 +0200 Subject: clipboard: clean up unnamedclip logic --- src/nvim/normal.c | 12 +-------- src/nvim/ops.c | 74 +++++++++++++++++-------------------------------------- 2 files changed, 23 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 1b21100933..192633a996 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -915,14 +915,7 @@ getcount: && !oap->op_type && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) { clearop(oap); - { - int regname = 0; - - /* 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); - } + set_reg_var(0); } /* Get the length of mapped chars again after typing a count, second @@ -5105,7 +5098,6 @@ 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) { @@ -7272,10 +7264,8 @@ 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 8a174c2a9e..b19140813f 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -751,7 +751,7 @@ void get_yank_register(int regname, int writing) int i; y_append = FALSE; - if ((regname == 0 || regname == '"') && !writing && y_previous != NULL) { + if ((regname == 0 || regname == '"') && !p_unc && !writing && y_previous != NULL) { y_current = y_previous; return; } @@ -1302,18 +1302,6 @@ 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 && eval_has_provider("clipboard")) { - *rp = '+'; - return true; - } - - return false; -} - /* * Handle a delete operation. * @@ -1328,7 +1316,6 @@ int op_delete(oparg_T *oap) struct block_def bd; linenr_T old_lcount = curbuf->b_ml.ml_line_count; int did_yank = FALSE; - int orig_regname = oap->regname; if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */ return OK; @@ -1342,8 +1329,6 @@ int op_delete(oparg_T *oap) return FAIL; } - bool adjusted = adjust_clipboard_register(&oap->regname); - if (has_mbyte) mb_adjust_opend(oap); @@ -1393,9 +1378,9 @@ int op_delete(oparg_T *oap) * register. For the black hole register '_' don't yank anything. */ if (oap->regname != '_') { - if (oap->regname != 0) { + if (oap->regname != 0 || p_unc) { /* check for read-only register */ - if (!valid_yank_reg(oap->regname, TRUE)) { + if (!( valid_yank_reg(oap->regname, TRUE) || (p_unc && oap->regname == 0) )) { beep_flush(); return OK; } @@ -1407,10 +1392,8 @@ int op_delete(oparg_T *oap) /* * Put deleted text into register 1 and shift number registers if the * delete contains a line break, or when a regname has been specified. - * Use the register name from before adjust_clip_reg() may have - * changed it. */ - if (orig_regname != 0 || oap->motion_type == MLINE + if (oap->regname != 0 || oap->motion_type == MLINE || oap->line_count > 1 || oap->use_reg_one) { y_current = &y_regs[9]; free_yank_all(); /* free register nine */ @@ -1424,9 +1407,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 + if (oap->regname == 0 && oap->motion_type != MLINE && oap->line_count == 1) { oap->regname = '-'; get_yank_register(oap->regname, TRUE); @@ -2623,7 +2604,6 @@ do_put ( int allocated = FALSE; long cnt; - adjust_clipboard_register(®name); get_clipboard(regname); if (flags & PUT_FIXINDENT) @@ -3215,7 +3195,6 @@ void ex_display(exarg_T *eap) ) continue; /* did not ask for this register */ - adjust_clipboard_register(&name); get_clipboard(name); if (i == -1) { @@ -5225,28 +5204,30 @@ static void free_register(struct yankreg *reg) 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 int check_clipboard_name(int *name) { + if (*name == '*' || *name == '+') { + return CLIP_REGISTER; + } else if (p_unc && *name == NUL && eval_has_provider("clipboard")) { + *name = '+'; + return 0; //unnamed register + } else { + return -1; } } + static void get_clipboard(int name) { - if (!(name == '*' || name == '+' - || (p_unc && !name && eval_has_provider("clipboard")))) { + int ireg = check_clipboard_name(&name); + if (ireg < 0) { return; } - struct yankreg *reg = &y_regs[CLIP_REGISTER]; + struct yankreg *reg = &y_regs[ireg]; free_register(reg); list_T *args = list_alloc(); - char_u regname = (char_u)name; + char_u regname = name; list_append_string(args, ®name, 1); typval_T result = eval_call_provider("clipboard", "get", args); @@ -5314,11 +5295,6 @@ static void get_clipboard(int name) reg->y_width = maxlen-1; } - if (!name && p_unc) { - // copy to the unnamed register - copy_register(&y_regs[0], reg); - } - return; err: @@ -5335,18 +5311,12 @@ err: static void set_clipboard(int name) { - if (!(name == '*' || name == '+' - || (p_unc && !name && eval_has_provider("clipboard")))) { + int ireg = check_clipboard_name(&name); + if (ireg < 0) { return; } - struct yankreg *reg = &y_regs[CLIP_REGISTER]; - - if (!name && p_unc) { - // copy from the unnamed register - copy_register(reg, &y_regs[0]); - name = '+'; - } + struct yankreg *reg = &y_regs[ireg]; list_T *lines = list_alloc(); @@ -5372,7 +5342,7 @@ static void set_clipboard(int name) } list_append_string(args, ®type, 1); - char_u regname = (char_u)name; + char_u regname = name; list_append_string(args, ®name, 1); (void)eval_call_provider("clipboard", "set", args); -- cgit From 5476250ba3208c92cc9865becf540fdd335c2927 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 30 Sep 2014 18:04:22 +0200 Subject: options: change "unnamedclip" back to "clipboard=unnamed/unnamedplus" This allows to configure which of '*' and '+' should be used for the unnamed clipboard, and is consistent with vim. --- src/nvim/ops.c | 26 +++++++++++++++++--------- src/nvim/option.c | 10 +++++----- src/nvim/option_defs.h | 8 +++++++- 3 files changed, 29 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index b19140813f..e8cad24b92 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -60,6 +60,7 @@ #define DELETION_REGISTER 36 #define CLIP_REGISTER 37 +# define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS) /* * Each yank register is an array of pointers to lines. */ @@ -751,7 +752,8 @@ void get_yank_register(int regname, int writing) int i; y_append = FALSE; - if ((regname == 0 || regname == '"') && !p_unc && !writing && y_previous != NULL) { + int unnamedclip = cb_flags & CB_UNNAMEDMASK; + if ((regname == 0 || regname == '"') && !unnamedclip && !writing && y_previous != NULL) { y_current = y_previous; return; } @@ -1378,9 +1380,10 @@ int op_delete(oparg_T *oap) * register. For the black hole register '_' don't yank anything. */ if (oap->regname != '_') { - if (oap->regname != 0 || p_unc) { + bool unnamedclip = oap->regname == 0 && (cb_flags & CB_UNNAMEDMASK); + if (oap->regname != 0 || unnamedclip) { /* check for read-only register */ - if (!( valid_yank_reg(oap->regname, TRUE) || (p_unc && oap->regname == 0) )) { + if (!( valid_yank_reg(oap->regname, TRUE) || unnamedclip )) { beep_flush(); return OK; } @@ -5204,18 +5207,23 @@ static void free_register(struct yankreg *reg) y_current = curr; } +// return target register static int check_clipboard_name(int *name) { if (*name == '*' || *name == '+') { return CLIP_REGISTER; - } else if (p_unc && *name == NUL && eval_has_provider("clipboard")) { - *name = '+'; - return 0; //unnamed register - } else { - return -1; + } else if (*name == NUL && eval_has_provider("clipboard")) { + if (cb_flags & CB_UNNAMEDPLUS) { + *name = '+'; + return 0; //unnamed + } else if (cb_flags & CB_UNNAMED) { + *name = '*'; + return 0; //unnamed + } } + // don't do anything for other register names + return -1; } - static void get_clipboard(int name) { int ireg = check_clipboard_name(&name); diff --git a/src/nvim/option.c b/src/nvim/option.c index 2882d7a511..fd0978f3a6 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -527,7 +527,7 @@ static struct vimoption (char_u *)0L} SCRIPTID_INIT}, {"clipboard", "cb", P_STRING|P_VI_DEF|P_COMMA|P_NODUP, - (char_u *)NULL, PV_NONE, + (char_u *)&p_cb, PV_NONE, {(char_u *)"", (char_u *)0L} SCRIPTID_INIT}, {"cmdheight", "ch", P_NUM|P_VI_DEF|P_RALL, @@ -1620,9 +1620,6 @@ 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}, @@ -4279,6 +4276,10 @@ did_set_string_option ( if (check_opt_strings(p_ead, p_ead_values, FALSE) != OK) errmsg = e_invarg; } + else if (varp == &p_cb) { + if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, TRUE) != OK) + errmsg = e_invarg; + } /* When 'spelllang' or 'spellfile' is set and there is a window for this * buffer in which 'spell' is set load the wordlists. */ else if (varp == &(curbuf->b_s.b_p_spl) || varp == &(curbuf->b_s.b_p_spf)) { @@ -4846,7 +4847,6 @@ char_u *check_stl_option(char_u *s) return NULL; } - /* * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. * Return error message when failed, NULL when OK. diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 89264f8982..39dfbe8b88 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -317,6 +317,13 @@ EXTERN char_u *p_enc; /* 'encoding' */ EXTERN int p_deco; /* 'delcombine' */ EXTERN char_u *p_ccv; /* 'charconvert' */ EXTERN char_u *p_cedit; /* 'cedit' */ +EXTERN char_u *p_cb; /* 'clipboard' */ +EXTERN unsigned cb_flags; +#ifdef IN_OPTION_C +static char *(p_cb_values[]) = {"unnamed", "unnamedplus", NULL}; +#endif +# define CB_UNNAMED 0x001 +# define CB_UNNAMEDPLUS 0x002 EXTERN long p_cwh; /* 'cmdwinheight' */ EXTERN long p_ch; /* 'cmdheight' */ EXTERN int p_confirm; /* 'confirm' */ @@ -582,7 +589,6 @@ 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' */ -- cgit From cccc46acd7aa1a9b89f7252a074705a1f7039c61 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 29 Nov 2014 13:58:45 +0100 Subject: clipboard: better error messages when provider not available --- src/nvim/ops.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index e8cad24b92..1513eb2cbc 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -75,6 +75,7 @@ static struct yankreg *y_current; /* ptr to current yankreg */ static int y_append; /* TRUE when appending */ static struct yankreg *y_previous = NULL; /* ptr to last written yankreg */ +static bool clipboard_didwarn_unnamed = false; /* * structure used by block_prep, op_delete and op_yank for blockwise operators * also op_change, op_shift, op_insert, op_replace - AKelly @@ -5208,17 +5209,27 @@ static void free_register(struct yankreg *reg) } // return target register -static int check_clipboard_name(int *name) { +static int adjust_clipboard_name(int *name) { if (*name == '*' || *name == '+') { + if(!eval_has_provider("clipboard")) { + EMSG("clipboard: provider is not available"); + return -1; + } return CLIP_REGISTER; - } else if (*name == NUL && eval_has_provider("clipboard")) { + } else if (*name == NUL && (cb_flags & (CB_UNNAMED | CB_UNNAMEDPLUS))) { + if(!eval_has_provider("clipboard")) { + if (!clipboard_didwarn_unnamed) { + msg((char_u*)"clipboard: provider not available, ignoring clipboard=unnamed[plus]"); + clipboard_didwarn_unnamed = true; + } + return -1; + } if (cb_flags & CB_UNNAMEDPLUS) { *name = '+'; - return 0; //unnamed - } else if (cb_flags & CB_UNNAMED) { + } else { *name = '*'; - return 0; //unnamed } + return 0; //unnamed } // don't do anything for other register names return -1; @@ -5226,7 +5237,7 @@ static int check_clipboard_name(int *name) { static void get_clipboard(int name) { - int ireg = check_clipboard_name(&name); + int ireg = adjust_clipboard_name(&name); if (ireg < 0) { return; } @@ -5314,12 +5325,12 @@ err: } reg->y_array = NULL; reg->y_size = 0; - EMSG("Clipboard provider returned invalid data"); + EMSG("clipboard: provider returned invalid data"); } static void set_clipboard(int name) { - int ireg = check_clipboard_name(&name); + int ireg = adjust_clipboard_name(&name); if (ireg < 0) { return; } -- cgit From 6ddbe6d9be885c5d1b7c54b104f0322911bd9fef Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 7 Nov 2014 17:31:42 +0100 Subject: clipboard: fix `let @+ = ...` and add test --- src/nvim/ops.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 1513eb2cbc..c20a017088 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4825,6 +4825,7 @@ void write_reg_contents_ex(int name, if (!y_append && !must_append) free_yank_all(); str_to_reg(y_current, yank_type, str, len, block_len); + set_clipboard(name); /* ':let @" = "val"' should change the meaning of the "" register */ -- cgit From 9a0ec687d93ece7fea7383bcc7971cf9bc4735d3 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 29 Nov 2014 14:36:34 +0100 Subject: eval_has_provider: search autoload scripts same order as call_func --- src/nvim/eval.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c2156c5d58..b4d1677520 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19829,16 +19829,12 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments) bool eval_has_provider(char *name) { -#define source_provider(name) \ - do_source((uint8_t *)"$VIMRUNTIME/autoload/provider/" name ".vim", \ - false, \ - false) #define check_provider(name) \ if (has_##name == -1) { \ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ if (!has_##name) { \ - source_provider(#name); \ + script_autoload((uint8_t *)"provider#" #name "#Call", false); \ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ } \ } -- cgit