mirror of
https://github.com/neovim/neovim.git
synced 2025-09-12 06:18:16 +00:00
Merge pull request #1182 from bfredl/clipboard
clipboard: support separate +/* clipboards, linewise copy/paste and add tests
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
" The clipboard provider uses shell commands to communicate with the clipboard.
|
||||
" The provider function will only be registered if one of the supported
|
||||
" commands are available.
|
||||
let s:copy = ''
|
||||
let s:paste = ''
|
||||
let s:copy = {}
|
||||
let s:paste = {}
|
||||
|
||||
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
|
||||
echo "clipboard: error: ".(len(out) ? out[0] : '')
|
||||
return ''
|
||||
@@ -14,14 +14,20 @@ function! s:try_cmd(cmd, ...)
|
||||
endfunction
|
||||
|
||||
if executable('pbcopy')
|
||||
let s:copy = 'pbcopy'
|
||||
let s:paste = 'pbpaste'
|
||||
elseif executable('xsel')
|
||||
let s:copy = 'xsel -i -b'
|
||||
let s:paste = 'xsel -o -b'
|
||||
let s:copy['+'] = 'pbcopy'
|
||||
let s:paste['+'] = 'pbpaste'
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
elseif executable('xclip')
|
||||
let s:copy = 'xclip -i -selection clipboard'
|
||||
let s:paste = 'xclip -o -selection clipboard'
|
||||
let s:copy['+'] = 'xclip -i -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
|
||||
echom 'clipboard: No shell command for communicating with the clipboard found.'
|
||||
finish
|
||||
@@ -29,14 +35,14 @@ endif
|
||||
|
||||
let s:clipboard = {}
|
||||
|
||||
function! s:clipboard.get(...)
|
||||
return s:try_cmd(s:paste)
|
||||
function! s:clipboard.get(reg)
|
||||
return s:try_cmd(s:paste[a:reg])
|
||||
endfunction
|
||||
|
||||
function! s:clipboard.set(...)
|
||||
call s:try_cmd(s:copy, a:1)
|
||||
function! s:clipboard.set(lines, regtype, reg)
|
||||
call s:try_cmd(s:copy[a:reg], a:lines)
|
||||
endfunction
|
||||
|
||||
function! provider#clipboard#Call(method, args)
|
||||
return s:clipboard[a:method](a:args)
|
||||
return call(s:clipboard[a:method],a:args,s:clipboard)
|
||||
endfunction
|
||||
|
@@ -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
|
||||
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' number (default: 200)
|
||||
global
|
||||
|
@@ -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().
|
||||
*/
|
||||
@@ -19815,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"); \
|
||||
} \
|
||||
}
|
||||
|
@@ -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. */
|
||||
|
163
src/nvim/ops.c
163
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.
|
||||
*/
|
||||
@@ -74,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
|
||||
@@ -751,7 +753,8 @@ void get_yank_register(int regname, int writing)
|
||||
int i;
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
@@ -1302,18 +1305,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 +1319,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 +1332,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 +1381,10 @@ int op_delete(oparg_T *oap)
|
||||
* register. For the black hole register '_' don't yank anything.
|
||||
*/
|
||||
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 */
|
||||
if (!valid_yank_reg(oap->regname, TRUE)) {
|
||||
if (!( valid_yank_reg(oap->regname, TRUE) || unnamedclip )) {
|
||||
beep_flush();
|
||||
return OK;
|
||||
}
|
||||
@@ -1407,10 +1396,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 +1411,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 +2608,6 @@ do_put (
|
||||
int allocated = FALSE;
|
||||
long cnt;
|
||||
|
||||
adjust_clipboard_register(®name);
|
||||
get_clipboard(regname);
|
||||
|
||||
if (flags & PUT_FIXINDENT)
|
||||
@@ -3215,7 +3199,6 @@ void ex_display(exarg_T *eap)
|
||||
)
|
||||
continue; /* did not ask for this register */
|
||||
|
||||
adjust_clipboard_register(&name);
|
||||
get_clipboard(name);
|
||||
|
||||
if (i == -1) {
|
||||
@@ -4842,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 */
|
||||
@@ -5225,33 +5209,82 @@ 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]);
|
||||
// return target register
|
||||
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 && (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)
|
||||
{
|
||||
if (!(name == '*' || name == '+'
|
||||
|| (p_unc && !name && eval_has_provider("clipboard")))) {
|
||||
int ireg = adjust_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 = name;
|
||||
list_append_string(args, ®name, 1);
|
||||
|
||||
typval_T result = eval_call_provider("clipboard", "get", args);
|
||||
|
||||
if (result.v_type != VAR_LIST) {
|
||||
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;
|
||||
|
||||
@@ -5263,9 +5296,23 @@ static void get_clipboard(int name)
|
||||
reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string);
|
||||
}
|
||||
|
||||
if (!name && p_unc) {
|
||||
// copy to the unnamed register
|
||||
copy_register(&y_regs[0], reg);
|
||||
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;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -5279,22 +5326,17 @@ 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)
|
||||
{
|
||||
if (!(name == '*' || name == '+'
|
||||
|| (p_unc && !name && eval_has_provider("clipboard")))) {
|
||||
int ireg = adjust_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]);
|
||||
}
|
||||
struct yankreg *reg = &y_regs[ireg];
|
||||
|
||||
list_T *lines = list_alloc();
|
||||
|
||||
@@ -5302,5 +5344,26 @@ 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 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 = name;
|
||||
list_append_string(args, ®name, 1);
|
||||
|
||||
(void)eval_call_provider("clipboard", "set", args);
|
||||
}
|
||||
|
@@ -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.
|
||||
|
@@ -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' */
|
||||
|
16
test/functional/clipboard/autoload/provider/clipboard.vim
Normal file
16
test/functional/clipboard/autoload/provider/clipboard.vim
Normal 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
|
141
test/functional/clipboard/clipboard_provider_spec.lua
Normal file
141
test/functional/clipboard/clipboard_provider_spec.lua
Normal 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)
|
Reference in New Issue
Block a user