Merge pull request #1182 from bfredl/clipboard

clipboard: support separate +/* clipboards, linewise copy/paste and add tests
This commit is contained in:
Justin M. Keyes
2014-12-08 18:23:09 -05:00
9 changed files with 319 additions and 94 deletions

View File

@@ -1,11 +1,11 @@
" The clipboard provider uses shell commands to communicate with the clipboard. " The clipboard provider uses shell commands to communicate with the clipboard.
" The provider function will only be registered if one of the supported " The provider function will only be registered if one of the supported
" commands are available. " commands are available.
let s:copy = '' let s:copy = {}
let s:paste = '' let s:paste = {}
function! s:try_cmd(cmd, ...) function! s:try_cmd(cmd, ...)
let out = a:0 ? systemlist(a:cmd, a:1) : systemlist(a:cmd) let out = a:0 ? systemlist(a:cmd, a:1, 1) : systemlist(a:cmd, [''], 1)
if v:shell_error if v:shell_error
echo "clipboard: error: ".(len(out) ? out[0] : '') echo "clipboard: error: ".(len(out) ? out[0] : '')
return '' return ''
@@ -14,14 +14,20 @@ function! s:try_cmd(cmd, ...)
endfunction endfunction
if executable('pbcopy') if executable('pbcopy')
let s:copy = 'pbcopy' let s:copy['+'] = 'pbcopy'
let s:paste = 'pbpaste' let s:paste['+'] = 'pbpaste'
elseif executable('xsel') let s:copy['*'] = s:copy['+']
let s:copy = 'xsel -i -b' let s:paste['*'] = s:paste['+']
let s:paste = 'xsel -o -b'
elseif executable('xclip') elseif executable('xclip')
let s:copy = 'xclip -i -selection clipboard' let s:copy['+'] = 'xclip -i -selection clipboard'
let s:paste = 'xclip -o -selection clipboard' let s:paste['+'] = 'xclip -o -selection clipboard'
let s:copy['*'] = 'xclip -i -selection primary'
let s:paste['*'] = 'xclip -o -selection primary'
elseif executable('xsel')
let s:copy['+'] = 'xsel -i -b'
let s:paste['+'] = 'xsel -o -b'
let s:copy['*'] = 'xsel -i -p'
let s:paste['*'] = 'xsel -o -p'
else else
echom 'clipboard: No shell command for communicating with the clipboard found.' echom 'clipboard: No shell command for communicating with the clipboard found.'
finish finish
@@ -29,14 +35,14 @@ endif
let s:clipboard = {} let s:clipboard = {}
function! s:clipboard.get(...) function! s:clipboard.get(reg)
return s:try_cmd(s:paste) return s:try_cmd(s:paste[a:reg])
endfunction endfunction
function! s:clipboard.set(...) function! s:clipboard.set(lines, regtype, reg)
call s:try_cmd(s:copy, a:1) call s:try_cmd(s:copy[a:reg], a:lines)
endfunction endfunction
function! provider#clipboard#Call(method, args) function! provider#clipboard#Call(method, args)
return s:clipboard[a:method](a:args) return call(s:clipboard[a:method],a:args,s:clipboard)
endfunction endfunction

View File

@@ -7547,13 +7547,6 @@ A jump table for the options with a short description can be found at |Q_op|.
Note that this causes the whole buffer to be stored in memory. Set Note that this causes the whole buffer to be stored in memory. Set
this option to a lower value if you run out of memory. this option to a lower value if you run out of memory.
{Nvim} *'unnamedclip'* *ucp'*
'unnamedclip' 'ucp' boolean (default off)
global
Use the unnamed register to access the clipboard(when available).
This option has the same effect of setting 'clipboard' to
'unnamed/unnamedplus' in Vim.
*'updatecount'* *'uc'* *'updatecount'* *'uc'*
'updatecount' 'uc' number (default: 200) 'updatecount' 'uc' number (default: 200)
global global

View File

@@ -5118,6 +5118,20 @@ void list_append_tv(list_T *l, typval_T *tv)
list_append(l, li); 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(). * Add a dictionary to a list. Used by getqflist().
*/ */
@@ -19815,16 +19829,12 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
bool eval_has_provider(char *name) 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) \ #define check_provider(name) \
if (has_##name == -1) { \ if (has_##name == -1) { \
has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \
if (!has_##name) { \ if (!has_##name) { \
source_provider(#name); \ script_autoload((uint8_t *)"provider#" #name "#Call", false); \
has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \
} \ } \
} }

View File

@@ -915,14 +915,7 @@ getcount:
&& !oap->op_type && !oap->op_type
&& (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) { && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) {
clearop(oap); clearop(oap);
{ set_reg_var(0);
int regname = 0;
/* Adjust the register according to 'clipboard', so that when
* "unnamed" is present it becomes '*' or '+' instead of '"'. */
adjust_clipboard_register(&regname);
set_reg_var(regname);
}
} }
/* Get the length of mapped chars again after typing a count, second /* 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; end = equalpos(start, VIsual) ? curwin->w_cursor : VIsual;
curwin->w_cursor = (dir == BACKWARD ? start : end); curwin->w_cursor = (dir == BACKWARD ? start : end);
} }
adjust_clipboard_register(&regname);
prep_redo_cmd(cap); prep_redo_cmd(cap);
do_put(regname, dir, cap->count1, PUT_FIXINDENT); do_put(regname, dir, cap->count1, PUT_FIXINDENT);
if (was_visual) { if (was_visual) {
@@ -7272,10 +7264,8 @@ static void nv_put(cmdarg_T *cap)
*/ */
was_visual = true; was_visual = true;
regname = cap->oap->regname; regname = cap->oap->regname;
bool adjusted = adjust_clipboard_register(&regname);
if (regname == 0 || regname == '"' if (regname == 0 || regname == '"'
|| VIM_ISDIGIT(regname) || regname == '-' || VIM_ISDIGIT(regname) || regname == '-'
|| adjusted
) { ) {
/* The delete is going to overwrite the register we want to /* The delete is going to overwrite the register we want to
* put, save it first. */ * put, save it first. */

View File

@@ -60,6 +60,7 @@
#define DELETION_REGISTER 36 #define DELETION_REGISTER 36
#define CLIP_REGISTER 37 #define CLIP_REGISTER 37
# define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS)
/* /*
* Each yank register is an array of pointers to lines. * Each yank register is an array of pointers to lines.
*/ */
@@ -74,6 +75,7 @@ static struct yankreg *y_current; /* ptr to current yankreg */
static int y_append; /* TRUE when appending */ static int y_append; /* TRUE when appending */
static struct yankreg *y_previous = NULL; /* ptr to last written yankreg */ 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 * structure used by block_prep, op_delete and op_yank for blockwise operators
* also op_change, op_shift, op_insert, op_replace - AKelly * also op_change, op_shift, op_insert, op_replace - AKelly
@@ -751,7 +753,8 @@ void get_yank_register(int regname, int writing)
int i; int i;
y_append = FALSE; y_append = FALSE;
if ((regname == 0 || regname == '"') && !writing && y_previous != NULL) { int unnamedclip = cb_flags & CB_UNNAMEDMASK;
if ((regname == 0 || regname == '"') && !unnamedclip && !writing && y_previous != NULL) {
y_current = y_previous; y_current = y_previous;
return; return;
} }
@@ -1302,18 +1305,6 @@ cmdline_paste_reg (
return OK; 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. * Handle a delete operation.
* *
@@ -1328,7 +1319,6 @@ int op_delete(oparg_T *oap)
struct block_def bd; struct block_def bd;
linenr_T old_lcount = curbuf->b_ml.ml_line_count; linenr_T old_lcount = curbuf->b_ml.ml_line_count;
int did_yank = FALSE; int did_yank = FALSE;
int orig_regname = oap->regname;
if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */ if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */
return OK; return OK;
@@ -1342,8 +1332,6 @@ int op_delete(oparg_T *oap)
return FAIL; return FAIL;
} }
bool adjusted = adjust_clipboard_register(&oap->regname);
if (has_mbyte) if (has_mbyte)
mb_adjust_opend(oap); mb_adjust_opend(oap);
@@ -1393,9 +1381,10 @@ int op_delete(oparg_T *oap)
* register. For the black hole register '_' don't yank anything. * register. For the black hole register '_' don't yank anything.
*/ */
if (oap->regname != '_') { if (oap->regname != '_') {
if (oap->regname != 0) { bool unnamedclip = oap->regname == 0 && (cb_flags & CB_UNNAMEDMASK);
if (oap->regname != 0 || unnamedclip) {
/* check for read-only register */ /* check for read-only register */
if (!valid_yank_reg(oap->regname, TRUE)) { if (!( valid_yank_reg(oap->regname, TRUE) || unnamedclip )) {
beep_flush(); beep_flush();
return OK; return OK;
} }
@@ -1407,10 +1396,8 @@ int op_delete(oparg_T *oap)
/* /*
* Put deleted text into register 1 and shift number registers if the * Put deleted text into register 1 and shift number registers if the
* delete contains a line break, or when a regname has been specified. * 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) { || oap->line_count > 1 || oap->use_reg_one) {
y_current = &y_regs[9]; y_current = &y_regs[9];
free_yank_all(); /* free register nine */ free_yank_all(); /* free register nine */
@@ -1424,9 +1411,7 @@ int op_delete(oparg_T *oap)
/* Yank into small delete register when no named register specified /* Yank into small delete register when no named register specified
* and the delete is within one line. */ * and the delete is within one line. */
if (( if (oap->regname == 0 && oap->motion_type != MLINE
adjusted ||
oap->regname == 0) && oap->motion_type != MLINE
&& oap->line_count == 1) { && oap->line_count == 1) {
oap->regname = '-'; oap->regname = '-';
get_yank_register(oap->regname, TRUE); get_yank_register(oap->regname, TRUE);
@@ -2623,7 +2608,6 @@ do_put (
int allocated = FALSE; int allocated = FALSE;
long cnt; long cnt;
adjust_clipboard_register(&regname);
get_clipboard(regname); get_clipboard(regname);
if (flags & PUT_FIXINDENT) if (flags & PUT_FIXINDENT)
@@ -3215,7 +3199,6 @@ void ex_display(exarg_T *eap)
) )
continue; /* did not ask for this register */ continue; /* did not ask for this register */
adjust_clipboard_register(&name);
get_clipboard(name); get_clipboard(name);
if (i == -1) { if (i == -1) {
@@ -4842,6 +4825,7 @@ void write_reg_contents_ex(int name,
if (!y_append && !must_append) if (!y_append && !must_append)
free_yank_all(); free_yank_all();
str_to_reg(y_current, yank_type, str, len, block_len); str_to_reg(y_current, yank_type, str, len, block_len);
set_clipboard(name);
/* ':let @" = "val"' should change the meaning of the "" register */ /* ':let @" = "val"' should change the meaning of the "" register */
@@ -5225,33 +5209,82 @@ static void free_register(struct yankreg *reg)
y_current = curr; y_current = curr;
} }
static void copy_register(struct yankreg *dest, struct yankreg *src) // return target register
{ static int adjust_clipboard_name(int *name) {
free_register(dest); if (*name == '*' || *name == '+') {
*dest = *src; if(!eval_has_provider("clipboard")) {
dest->y_array = xcalloc(src->y_size, sizeof(uint8_t *)); EMSG("clipboard: provider is not available");
for (int j = 0; j < src->y_size; ++j) { return -1;
dest->y_array[j] = (uint8_t *)xstrdup((char *)src->y_array[j]);
} }
return CLIP_REGISTER;
} 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 = '+';
} else {
*name = '*';
}
return 0; //unnamed
}
// don't do anything for other register names
return -1;
} }
static void get_clipboard(int name) static void get_clipboard(int name)
{ {
if (!(name == '*' || name == '+' int ireg = adjust_clipboard_name(&name);
|| (p_unc && !name && eval_has_provider("clipboard")))) { if (ireg < 0) {
return; return;
} }
struct yankreg *reg = &y_regs[CLIP_REGISTER]; struct yankreg *reg = &y_regs[ireg];
free_register(reg); free_register(reg);
list_T *args = list_alloc(); list_T *args = list_alloc();
char_u regname = name;
list_append_string(args, &regname, 1);
typval_T result = eval_call_provider("clipboard", "get", args); typval_T result = eval_call_provider("clipboard", "get", args);
if (result.v_type != VAR_LIST) { if (result.v_type != VAR_LIST) {
goto err; 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_array = xcalloc(lines->lv_len, sizeof(uint8_t *));
reg->y_size = lines->lv_len; reg->y_size = lines->lv_len;
@@ -5263,9 +5296,23 @@ static void get_clipboard(int name)
reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string); reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string);
} }
if (!name && p_unc) { if (reg->y_type == MAUTO) {
// copy to the unnamed register if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
copy_register(&y_regs[0], reg); 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;
} }
return; return;
@@ -5279,22 +5326,17 @@ err:
} }
reg->y_array = NULL; reg->y_array = NULL;
reg->y_size = 0; reg->y_size = 0;
EMSG("Clipboard provider returned invalid data"); EMSG("clipboard: provider returned invalid data");
} }
static void set_clipboard(int name) static void set_clipboard(int name)
{ {
if (!(name == '*' || name == '+' int ireg = adjust_clipboard_name(&name);
|| (p_unc && !name && eval_has_provider("clipboard")))) { if (ireg < 0) {
return; return;
} }
struct yankreg *reg = &y_regs[CLIP_REGISTER]; struct yankreg *reg = &y_regs[ireg];
if (!name && p_unc) {
// copy from the unnamed register
copy_register(reg, &y_regs[0]);
}
list_T *lines = list_alloc(); list_T *lines = list_alloc();
@@ -5302,5 +5344,26 @@ static void set_clipboard(int name)
list_append_string(lines, reg->y_array[i], -1); 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 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, &regtype, 1);
char_u regname = name;
list_append_string(args, &regname, 1);
(void)eval_call_provider("clipboard", "set", args);
} }

View File

@@ -527,7 +527,7 @@ static struct vimoption
(char_u *)0L} (char_u *)0L}
SCRIPTID_INIT}, SCRIPTID_INIT},
{"clipboard", "cb", P_STRING|P_VI_DEF|P_COMMA|P_NODUP, {"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} {(char_u *)"", (char_u *)0L}
SCRIPTID_INIT}, SCRIPTID_INIT},
{"cmdheight", "ch", P_NUM|P_VI_DEF|P_RALL, {"cmdheight", "ch", P_NUM|P_VI_DEF|P_RALL,
@@ -1620,9 +1620,6 @@ static struct vimoption
{"undoreload", "ur", P_NUM|P_VI_DEF, {"undoreload", "ur", P_NUM|P_VI_DEF,
(char_u *)&p_ur, PV_NONE, (char_u *)&p_ur, PV_NONE,
{ (char_u *)10000L, (char_u *)0L} SCRIPTID_INIT}, { (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, {"updatecount", "uc", P_NUM|P_VI_DEF,
(char_u *)&p_uc, PV_NONE, (char_u *)&p_uc, PV_NONE,
{(char_u *)200L, (char_u *)0L} SCRIPTID_INIT}, {(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) if (check_opt_strings(p_ead, p_ead_values, FALSE) != OK)
errmsg = e_invarg; 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 /* When 'spelllang' or 'spellfile' is set and there is a window for this
* buffer in which 'spell' is set load the wordlists. */ * 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)) { 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; return NULL;
} }
/* /*
* Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
* Return error message when failed, NULL when OK. * Return error message when failed, NULL when OK.

View File

@@ -317,6 +317,13 @@ EXTERN char_u *p_enc; /* 'encoding' */
EXTERN int p_deco; /* 'delcombine' */ EXTERN int p_deco; /* 'delcombine' */
EXTERN char_u *p_ccv; /* 'charconvert' */ EXTERN char_u *p_ccv; /* 'charconvert' */
EXTERN char_u *p_cedit; /* 'cedit' */ 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_cwh; /* 'cmdwinheight' */
EXTERN long p_ch; /* 'cmdheight' */ EXTERN long p_ch; /* 'cmdheight' */
EXTERN int p_confirm; /* 'confirm' */ EXTERN int p_confirm; /* 'confirm' */
@@ -582,7 +589,6 @@ static char *(p_ttym_values[]) =
EXTERN char_u *p_udir; /* 'undodir' */ EXTERN char_u *p_udir; /* 'undodir' */
EXTERN long p_ul; /* 'undolevels' */ EXTERN long p_ul; /* 'undolevels' */
EXTERN long p_ur; /* 'undoreload' */ EXTERN long p_ur; /* 'undoreload' */
EXTERN int p_unc; /* 'unnamedclip' */
EXTERN long p_uc; /* 'updatecount' */ EXTERN long p_uc; /* 'updatecount' */
EXTERN long p_ut; /* 'updatetime' */ EXTERN long p_ut; /* 'updatetime' */
EXTERN char_u *p_fcs; /* 'fillchar' */ EXTERN char_u *p_fcs; /* 'fillchar' */

View File

@@ -0,0 +1,16 @@
let g:test_clip = { '+': [''], '*': [''], }
let s:methods = {}
function! s:methods.get(reg)
return g:test_clip[a:reg]
endfunction
function! s:methods.set(lines, regtype, reg)
let g:test_clip[a:reg] = a:lines
endfunction
function! provider#clipboard#Call(method, args)
return call(s:methods[a:method],a:args,s:methods)
endfunction

View File

@@ -0,0 +1,141 @@
-- Test clipboard provider support
local helpers = require('test.functional.helpers')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local execute, expect, eq, eval = helpers.execute, helpers.expect, helpers.eq, helpers.eval
local nvim, run, stop, restart = helpers.nvim, helpers.run, helpers.stop, helpers.restart
local function reset()
clear()
execute('let &rtp = "test/functional/clipboard,".&rtp')
end
local function basic_register_test()
insert("some words")
feed('^dwP')
expect('some words')
feed('veyP')
expect('some words words')
feed('^dwywe"-p')
expect('wordssome words')
feed('p')
expect('wordssome words words')
feed('yyp')
expect([[
wordssome words words
wordssome words words]])
feed('d-')
insert([[
some text, and some more
random text stuff]])
feed('ggtav+2ed$p')
expect([[
some text, stuff and some more
random text]])
reset()
end
describe('clipboard usage', function()
setup(reset)
it("works", function()
basic_register_test()
-- "* and unnamed should function as independent registers
insert("some words")
feed('^"*dwdw"*P')
expect('some ')
eq({'some '}, eval("g:test_clip['*']"))
reset()
-- "* and "+ should be independent when the provider supports it
insert([[
text:
first line
secound line
third line]])
feed('G"+dd"*dddd"+p"*pp')
expect([[
text:
third line
secound line
first line]])
-- linewise selection should be encoded as an extra newline
eq({'third line', ''}, eval("g:test_clip['+']"))
eq({'secound line', ''}, eval("g:test_clip['*']"))
reset()
-- handle null bytes
insert("some\x16000text\n\x16000very binary\x16000")
feed('"*y-+"*p')
eq({'some\ntext', '\nvery binary\n',''}, eval("g:test_clip['*']"))
expect("some\x00text\n\x00very binary\x00\nsome\x00text\n\x00very binary\x00")
-- test getreg/getregtype
eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1)"))
eq("V", eval("getregtype('*')"))
reset()
-- blockwise paste
insert([[
much
text]])
feed('"*yy') -- force load of provider
execute("let g:test_clip['*'] = [['very','block'],'b']")
feed('gg"*P')
expect([[
very much
blocktext]])
eq("\x165", eval("getregtype('*')"))
reset()
-- test setreg
execute('call setreg("*", "setted\\ntext", "c")')
execute('call setreg("+", "explicitly\\nlines", "l")')
feed('"+P"*p')
expect([[
esetted
textxplicitly
lines
]])
reset()
-- test let @+ (issue #1427)
execute("let @+ = 'some'")
execute("let @* = ' other stuff'")
eq({'some'}, eval("g:test_clip['+']"))
eq({' other stuff'}, eval("g:test_clip['*']"))
feed('"+p"*p')
expect('some other stuff')
execute("let @+ .= ' more'")
feed('dd"+p')
expect('some more')
reset()
-- the basic behavior of unnamed register should be the same
-- even when handled by clipboard provider
execute('set clipboard=unnamed')
basic_register_test()
-- with cb=unnamed, "* and unnamed will be the same register
execute('set clipboard=unnamed')
insert("some words")
feed('^"*dwdw"*P')
expect('words')
eq({'words'}, eval("g:test_clip['*']"))
execute("let g:test_clip['*'] = ['linewise stuff','']")
feed('p')
expect([[
words
linewise stuff]])
reset()
end)
end)