mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #2244 from bfredl/registers
Restore clipboard support for `:registers` and `:put` and `:<c-r>*`, don't clobber `"0` on paste and update tests.
This commit is contained in:
commit
5e67f0b5b1
BIN
src/nvim/.screen.c.swn
Normal file
BIN
src/nvim/.screen.c.swn
Normal file
Binary file not shown.
@ -1699,16 +1699,11 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* accept numbered register only when no count allowed (:put) */
|
/* accept numbered register only when no count allowed (:put) */
|
||||||
if ( (ea.argt & REGSTR)
|
if ((ea.argt & REGSTR)
|
||||||
&& *ea.arg != NUL
|
&& *ea.arg != NUL
|
||||||
/* Do not allow register = for user commands */
|
/* Do not allow register = for user commands */
|
||||||
&& (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=')
|
&& (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=')
|
||||||
&& !((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg))) {
|
&& !((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg))) {
|
||||||
/* check these explicitly for a more specific error message */
|
|
||||||
if (*ea.arg == '*' || *ea.arg == '+') {
|
|
||||||
errormsg = (char_u *)_(e_invalidreg);
|
|
||||||
goto doend;
|
|
||||||
}
|
|
||||||
if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put
|
if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put
|
||||||
&& !IS_USER_CMDIDX(ea.cmdidx)))) {
|
&& !IS_USER_CMDIDX(ea.cmdidx)))) {
|
||||||
ea.regname = *ea.arg++;
|
ea.regname = *ea.arg++;
|
||||||
|
171
src/nvim/ops.c
171
src/nvim/ops.c
@ -53,17 +53,21 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Registers:
|
* Registers:
|
||||||
* 0 = unnamed register, for normal yanks and puts
|
* 0 = register for latest (unnamed) yank
|
||||||
* 1..9 = registers '1' to '9', for deletes
|
* 1..9 = registers '1' to '9', for deletes
|
||||||
* 10..35 = registers 'a' to 'z'
|
* 10..35 = registers 'a' to 'z'
|
||||||
* 36 = delete register '-'
|
* 36 = delete register '-'
|
||||||
|
* 37 = selection register '*'
|
||||||
|
* 38 = clipboard register '+'
|
||||||
*/
|
*/
|
||||||
#define NUM_REGISTERS 38
|
|
||||||
#define DELETION_REGISTER 36
|
#define DELETION_REGISTER 36
|
||||||
#define CLIP_REGISTER 37
|
#define NUM_SAVED_REGISTERS 37
|
||||||
|
// The following registers should not be saved in viminfo:
|
||||||
|
#define STAR_REGISTER 37
|
||||||
|
#define PLUS_REGISTER 38
|
||||||
|
#define NUM_REGISTERS 39
|
||||||
|
|
||||||
#define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS)
|
#define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS)
|
||||||
#define CB_LATEST (-1)
|
|
||||||
/*
|
/*
|
||||||
* Each yank register is an array of pointers to lines.
|
* Each yank register is an array of pointers to lines.
|
||||||
*/
|
*/
|
||||||
@ -743,21 +747,37 @@ valid_yank_reg (
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
typedef enum {
|
||||||
* Set y_current and y_append, according to the value of "regname".
|
YREG_PASTE,
|
||||||
* Cannot handle the '_' register.
|
YREG_YANK,
|
||||||
* Must only be called with a valid register name!
|
YREG_PUT,
|
||||||
*
|
} yreg_mode_t;
|
||||||
* If regname is 0 and writing, use register 0
|
|
||||||
* If regname is 0 and reading, use previous register
|
/// Set y_current and y_append, according to the value of `regname`.
|
||||||
*/
|
/// Cannot handle the '_' (black hole) register.
|
||||||
void get_yank_register(int regname, int writing)
|
/// Must only be called with a valid register name!
|
||||||
|
///
|
||||||
|
/// @param regname The name of the register used or 0 for the unnamed register
|
||||||
|
/// @param mode One of the following three flags:
|
||||||
|
///
|
||||||
|
/// `YREG_PASTE`:
|
||||||
|
/// Prepare for pasting the register `regname`. With no regname specified,
|
||||||
|
/// read from last written register, or from unnamed clipboard (depending on the
|
||||||
|
/// `clipboard=unnamed` option). Queries the clipboard provider if necessary.
|
||||||
|
///
|
||||||
|
/// `YREG_YANK`:
|
||||||
|
/// Preparare for yanking into `regname`. With no regname specified,
|
||||||
|
/// yank into `"0` register. Update `y_previous` for next unnamed paste.
|
||||||
|
///
|
||||||
|
/// `YREG_PUT`:
|
||||||
|
/// Obtain the location that would be read when pasting `regname`.
|
||||||
|
void get_yank_register(int regname, int mode)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
y_append = FALSE;
|
y_append = FALSE;
|
||||||
int unnamedclip = cb_flags & CB_UNNAMEDMASK;
|
int unnamedclip = cb_flags & CB_UNNAMEDMASK;
|
||||||
if ((regname == 0 || regname == '"') && !unnamedclip && !writing && y_previous != NULL) {
|
if ((regname == 0 || regname == '"') && !unnamedclip && mode != YREG_YANK && y_previous != NULL) {
|
||||||
y_current = y_previous;
|
y_current = y_previous;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -771,13 +791,19 @@ void get_yank_register(int regname, int writing)
|
|||||||
y_append = TRUE;
|
y_append = TRUE;
|
||||||
} else if (regname == '-')
|
} else if (regname == '-')
|
||||||
i = DELETION_REGISTER;
|
i = DELETION_REGISTER;
|
||||||
else if (regname == '*' || regname == '+')
|
else if (regname == '*')
|
||||||
i = CLIP_REGISTER;
|
i = STAR_REGISTER;
|
||||||
|
else if (regname == '+')
|
||||||
|
i = PLUS_REGISTER;
|
||||||
else /* not 0-9, a-z, A-Z or '-': use register 0 */
|
else /* not 0-9, a-z, A-Z or '-': use register 0 */
|
||||||
i = 0;
|
i = 0;
|
||||||
y_current = &(y_regs[i]);
|
y_current = &(y_regs[i]);
|
||||||
if (writing) /* remember the register we write into for do_put() */
|
if (mode == YREG_YANK) {
|
||||||
|
// remember the written register for unnamed paste
|
||||||
y_previous = y_current;
|
y_previous = y_current;
|
||||||
|
} else if (mode == YREG_PASTE) {
|
||||||
|
get_clipboard(regname, &y_current, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -791,8 +817,7 @@ get_register (
|
|||||||
int copy /* make a copy, if FALSE make register empty. */
|
int copy /* make a copy, if FALSE make register empty. */
|
||||||
) FUNC_ATTR_NONNULL_RET
|
) FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
get_yank_register(name, 0);
|
get_yank_register(name, YREG_PASTE);
|
||||||
get_clipboard(name);
|
|
||||||
|
|
||||||
struct yankreg *reg = xmalloc(sizeof(struct yankreg));
|
struct yankreg *reg = xmalloc(sizeof(struct yankreg));
|
||||||
*reg = *y_current;
|
*reg = *y_current;
|
||||||
@ -816,7 +841,7 @@ get_register (
|
|||||||
*/
|
*/
|
||||||
void put_register(int name, void *reg)
|
void put_register(int name, void *reg)
|
||||||
{
|
{
|
||||||
get_yank_register(name, 0);
|
get_yank_register(name, YREG_PUT);
|
||||||
free_yank_all();
|
free_yank_all();
|
||||||
*y_current = *(struct yankreg *)reg;
|
*y_current = *(struct yankreg *)reg;
|
||||||
free(reg);
|
free(reg);
|
||||||
@ -832,7 +857,7 @@ int yank_register_mline(int regname)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
if (regname == '_') /* black hole is always empty */
|
if (regname == '_') /* black hole is always empty */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, YREG_PASTE);
|
||||||
return y_current->y_type == MLINE;
|
return y_current->y_type == MLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,7 +931,7 @@ static int stuff_yank(int regname, char_u *p)
|
|||||||
free(p);
|
free(p);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
get_yank_register(regname, TRUE);
|
get_yank_register(regname, YREG_YANK);
|
||||||
if (y_append && y_current->y_array != NULL) {
|
if (y_append && y_current->y_array != NULL) {
|
||||||
char_u **pp = &(y_current->y_array[y_current->y_size - 1]);
|
char_u **pp = &(y_current->y_array[y_current->y_size - 1]);
|
||||||
char_u *lp = xmalloc(STRLEN(*pp) + STRLEN(p) + 1);
|
char_u *lp = xmalloc(STRLEN(*pp) + STRLEN(p) + 1);
|
||||||
@ -960,8 +985,6 @@ do_execreg (
|
|||||||
}
|
}
|
||||||
execreg_lastc = regname;
|
execreg_lastc = regname;
|
||||||
|
|
||||||
get_clipboard(regname);
|
|
||||||
|
|
||||||
if (regname == '_') /* black hole: don't stuff anything */
|
if (regname == '_') /* black hole: don't stuff anything */
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
@ -1000,7 +1023,7 @@ do_execreg (
|
|||||||
retval = put_in_typebuf(p, FALSE, colon, silent);
|
retval = put_in_typebuf(p, FALSE, colon, silent);
|
||||||
free(p);
|
free(p);
|
||||||
} else {
|
} else {
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, YREG_PASTE);
|
||||||
if (y_current->y_array == NULL)
|
if (y_current->y_array == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
@ -1125,8 +1148,6 @@ insert_reg (
|
|||||||
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
get_clipboard(regname);
|
|
||||||
|
|
||||||
if (regname == '.') /* insert last inserted text */
|
if (regname == '.') /* insert last inserted text */
|
||||||
retval = stuff_inserted(NUL, 1L, TRUE);
|
retval = stuff_inserted(NUL, 1L, TRUE);
|
||||||
else if (get_spec_reg(regname, &arg, &allocated, TRUE)) {
|
else if (get_spec_reg(regname, &arg, &allocated, TRUE)) {
|
||||||
@ -1136,7 +1157,7 @@ insert_reg (
|
|||||||
if (allocated)
|
if (allocated)
|
||||||
free(arg);
|
free(arg);
|
||||||
} else { /* name or number register */
|
} else { /* name or number register */
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, YREG_PASTE);
|
||||||
if (y_current->y_array == NULL)
|
if (y_current->y_array == NULL)
|
||||||
retval = FAIL;
|
retval = FAIL;
|
||||||
else {
|
else {
|
||||||
@ -1283,7 +1304,7 @@ cmdline_paste_reg (
|
|||||||
{
|
{
|
||||||
long i;
|
long i;
|
||||||
|
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, YREG_PASTE);
|
||||||
if (y_current->y_array == NULL)
|
if (y_current->y_array == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
@ -1390,7 +1411,7 @@ int op_delete(oparg_T *oap)
|
|||||||
beep_flush();
|
beep_flush();
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
get_yank_register(oap->regname, TRUE); /* yank into specif'd reg. */
|
get_yank_register(oap->regname, YREG_YANK); /* yank into specif'd reg. */
|
||||||
if (op_yank(oap, TRUE, FALSE) == OK) /* yank without message */
|
if (op_yank(oap, TRUE, FALSE) == OK) /* yank without message */
|
||||||
did_yank = TRUE;
|
did_yank = TRUE;
|
||||||
}
|
}
|
||||||
@ -1416,14 +1437,14 @@ int op_delete(oparg_T *oap)
|
|||||||
if (oap->regname == 0 && oap->motion_type != MLINE
|
if (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, YREG_YANK);
|
||||||
if (op_yank(oap, TRUE, FALSE) == OK)
|
if (op_yank(oap, TRUE, FALSE) == OK)
|
||||||
did_yank = TRUE;
|
did_yank = TRUE;
|
||||||
oap->regname = 0;
|
oap->regname = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(oap->regname == 0 && did_yank) {
|
if(oap->regname == 0 && did_yank) {
|
||||||
set_clipboard(CB_LATEST);
|
set_clipboard(0);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If there's too much stuff to fit in the yank register, then get a
|
* If there's too much stuff to fit in the yank register, then get a
|
||||||
@ -2365,7 +2386,7 @@ int op_yank(oparg_T *oap, int deleting, int mess)
|
|||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
if (!deleting) /* op_delete() already set y_current */
|
if (!deleting) /* op_delete() already set y_current */
|
||||||
get_yank_register(oap->regname, TRUE);
|
get_yank_register(oap->regname, YREG_YANK);
|
||||||
|
|
||||||
curr = y_current;
|
curr = y_current;
|
||||||
/* append to existing contents */
|
/* append to existing contents */
|
||||||
@ -2613,8 +2634,6 @@ do_put (
|
|||||||
int allocated = FALSE;
|
int allocated = FALSE;
|
||||||
long cnt;
|
long cnt;
|
||||||
|
|
||||||
get_clipboard(regname);
|
|
||||||
|
|
||||||
if (flags & PUT_FIXINDENT)
|
if (flags & PUT_FIXINDENT)
|
||||||
orig_indent = get_indent();
|
orig_indent = get_indent();
|
||||||
|
|
||||||
@ -2687,7 +2706,7 @@ do_put (
|
|||||||
y_array = &insert_string;
|
y_array = &insert_string;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, YREG_PASTE);
|
||||||
|
|
||||||
y_type = y_current->y_type;
|
y_type = y_current->y_type;
|
||||||
y_width = y_current->y_width;
|
y_width = y_current->y_width;
|
||||||
@ -3190,6 +3209,10 @@ int get_register_name(int num)
|
|||||||
return num + '0';
|
return num + '0';
|
||||||
else if (num == DELETION_REGISTER)
|
else if (num == DELETION_REGISTER)
|
||||||
return '-';
|
return '-';
|
||||||
|
else if (num == STAR_REGISTER)
|
||||||
|
return '*';
|
||||||
|
else if (num == PLUS_REGISTER)
|
||||||
|
return '+';
|
||||||
else {
|
else {
|
||||||
return num + 'a' - 10;
|
return num + 'a' - 10;
|
||||||
}
|
}
|
||||||
@ -3222,7 +3245,6 @@ void ex_display(exarg_T *eap)
|
|||||||
continue; /* did not ask for this register */
|
continue; /* did not ask for this register */
|
||||||
}
|
}
|
||||||
|
|
||||||
get_clipboard(name);
|
|
||||||
|
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
if (y_previous != NULL)
|
if (y_previous != NULL)
|
||||||
@ -3232,6 +3254,8 @@ void ex_display(exarg_T *eap)
|
|||||||
} else
|
} else
|
||||||
yb = &(y_regs[i]);
|
yb = &(y_regs[i]);
|
||||||
|
|
||||||
|
get_clipboard(name, &yb, true);
|
||||||
|
|
||||||
if (name == vim_tolower(redir_reg)
|
if (name == vim_tolower(redir_reg)
|
||||||
|| (redir_reg == '"' && yb == y_previous))
|
|| (redir_reg == '"' && yb == y_previous))
|
||||||
continue; /* do not list register being written to, the
|
continue; /* do not list register being written to, the
|
||||||
@ -4489,7 +4513,7 @@ int read_viminfo_register(vir_T *virp, int force)
|
|||||||
return TRUE; /* too many errors, pretend end-of-file */
|
return TRUE; /* too many errors, pretend end-of-file */
|
||||||
do_it = FALSE;
|
do_it = FALSE;
|
||||||
}
|
}
|
||||||
get_yank_register(*str++, FALSE);
|
get_yank_register(*str++, YREG_PUT);
|
||||||
if (!force && y_current->y_array != NULL)
|
if (!force && y_current->y_array != NULL)
|
||||||
do_it = FALSE;
|
do_it = FALSE;
|
||||||
|
|
||||||
@ -4566,12 +4590,11 @@ void write_viminfo_registers(FILE *fp)
|
|||||||
if (max_kbyte == 0)
|
if (max_kbyte == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < NUM_REGISTERS; i++) {
|
// don't include clipboard registers '*'/'+'
|
||||||
|
for (i = 0; i < NUM_SAVED_REGISTERS; i++) {
|
||||||
if (y_regs[i].y_array == NULL)
|
if (y_regs[i].y_array == NULL)
|
||||||
continue;
|
continue;
|
||||||
// Skip '*'/'+' register, we don't want them back next time
|
|
||||||
if (i == CLIP_REGISTER)
|
|
||||||
continue;
|
|
||||||
/* Skip empty registers. */
|
/* Skip empty registers. */
|
||||||
num_lines = y_regs[i].y_size;
|
num_lines = y_regs[i].y_size;
|
||||||
if (num_lines == 0
|
if (num_lines == 0
|
||||||
@ -4651,12 +4674,10 @@ char_u get_reg_type(int regname, long *reglen)
|
|||||||
return MCHAR;
|
return MCHAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_clipboard(regname);
|
|
||||||
|
|
||||||
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
||||||
return MAUTO;
|
return MAUTO;
|
||||||
|
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, YREG_PASTE);
|
||||||
|
|
||||||
if (y_current->y_array != NULL) {
|
if (y_current->y_array != NULL) {
|
||||||
if (reglen != NULL && y_current->y_type == MBLOCK)
|
if (reglen != NULL && y_current->y_type == MBLOCK)
|
||||||
@ -4712,8 +4733,6 @@ void *get_reg_contents(int regname, int flags)
|
|||||||
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
get_clipboard(regname);
|
|
||||||
|
|
||||||
char_u *retval;
|
char_u *retval;
|
||||||
int allocated;
|
int allocated;
|
||||||
if (get_spec_reg(regname, &retval, &allocated, FALSE)) {
|
if (get_spec_reg(regname, &retval, &allocated, FALSE)) {
|
||||||
@ -4725,7 +4744,7 @@ void *get_reg_contents(int regname, int flags)
|
|||||||
return get_reg_wrap_one_line(vim_strsave(retval), flags);
|
return get_reg_wrap_one_line(vim_strsave(retval), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, YREG_PASTE);
|
||||||
if (y_current->y_array == NULL)
|
if (y_current->y_array == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -4786,7 +4805,7 @@ static bool init_write_reg(int name, struct yankreg **old_y_previous,
|
|||||||
*old_y_previous = y_previous;
|
*old_y_previous = y_previous;
|
||||||
*old_y_current = y_current;
|
*old_y_current = y_current;
|
||||||
|
|
||||||
get_yank_register(name, true);
|
get_yank_register(name, YREG_YANK);
|
||||||
if (!y_append && !must_append) {
|
if (!y_append && !must_append) {
|
||||||
free_yank_all();
|
free_yank_all();
|
||||||
}
|
}
|
||||||
@ -5292,31 +5311,32 @@ static void free_register(struct yankreg *reg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return target register
|
// return target register
|
||||||
static struct yankreg* adjust_clipboard_name(int *name) {
|
static struct yankreg* adjust_clipboard_name(int *name, bool quiet, bool writing) {
|
||||||
if (*name == '*' || *name == '+') {
|
if (*name == '*' || *name == '+') {
|
||||||
if(!eval_has_provider("clipboard")) {
|
if(!eval_has_provider("clipboard")) {
|
||||||
EMSG("clipboard: provider is not available");
|
if (!quiet) {
|
||||||
return NULL;
|
EMSG("clipboard: provider is not available");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return &y_regs[CLIP_REGISTER];
|
return &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER];
|
||||||
} else if ((*name == NUL || *name == CB_LATEST) && (cb_flags & CB_UNNAMEDMASK)) {
|
} else if ((*name == NUL) && (cb_flags & CB_UNNAMEDMASK)) {
|
||||||
if(!eval_has_provider("clipboard")) {
|
if(!eval_has_provider("clipboard")) {
|
||||||
if (!clipboard_didwarn_unnamed) {
|
if (!quiet && !clipboard_didwarn_unnamed) {
|
||||||
msg((char_u*)"clipboard: provider not available, ignoring clipboard=unnamed[plus]");
|
msg((char_u*)"clipboard: provider not available, ignoring clipboard=unnamed[plus]");
|
||||||
clipboard_didwarn_unnamed = true;
|
clipboard_didwarn_unnamed = true;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
struct yankreg* target;
|
struct yankreg* target;
|
||||||
if (*name == CB_LATEST) {
|
|
||||||
target = y_current;
|
|
||||||
} else {
|
|
||||||
target = &y_regs[0];
|
|
||||||
}
|
|
||||||
if (cb_flags & CB_UNNAMEDPLUS) {
|
if (cb_flags & CB_UNNAMEDPLUS) {
|
||||||
*name = '+';
|
*name = '+';
|
||||||
|
target = &y_regs[STAR_REGISTER];
|
||||||
} else {
|
} else {
|
||||||
*name = '*';
|
*name = '*';
|
||||||
|
target = &y_regs[PLUS_REGISTER];
|
||||||
|
}
|
||||||
|
if (writing) {
|
||||||
|
target = y_current;
|
||||||
}
|
}
|
||||||
return target; // unnamed register
|
return target; // unnamed register
|
||||||
}
|
}
|
||||||
@ -5324,9 +5344,9 @@ static struct yankreg* adjust_clipboard_name(int *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_clipboard(int name)
|
static void get_clipboard(int name, struct yankreg** target, bool quiet)
|
||||||
{
|
{
|
||||||
struct yankreg* reg = adjust_clipboard_name(&name);
|
struct yankreg* reg = adjust_clipboard_name(&name, quiet, false);
|
||||||
if (reg == NULL) {
|
if (reg == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -5349,10 +5369,13 @@ static void get_clipboard(int name)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
char_u* regtype = res->lv_last->li_tv.vval.v_string;
|
char_u* regtype = res->lv_last->li_tv.vval.v_string;
|
||||||
if (regtype == NULL || strlen((char*)regtype) != 1) {
|
if (regtype == NULL || strlen((char*)regtype) > 1) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
switch (regtype[0]) {
|
switch (regtype[0]) {
|
||||||
|
case 0:
|
||||||
|
reg->y_type = MAUTO;
|
||||||
|
break;
|
||||||
case 'v': case 'c':
|
case 'v': case 'c':
|
||||||
reg->y_type = MCHAR;
|
reg->y_type = MCHAR;
|
||||||
break;
|
break;
|
||||||
@ -5382,15 +5405,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 (reg->y_type == MAUTO) {
|
if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
|
||||||
if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
|
// a known-to-be charwise yank might have a final linebreak
|
||||||
reg->y_type = MLINE;
|
// but otherwise there is no line after the final newline
|
||||||
|
if (reg->y_type != MCHAR) {
|
||||||
free(reg->y_array[reg->y_size-1]);
|
free(reg->y_array[reg->y_size-1]);
|
||||||
reg->y_size--;
|
reg->y_size--;
|
||||||
} else {
|
if (reg->y_type == MAUTO) {
|
||||||
|
reg->y_type = MLINE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (reg->y_type == MAUTO) {
|
||||||
reg->y_type = MCHAR;
|
reg->y_type = MCHAR;
|
||||||
}
|
}
|
||||||
} else if (reg->y_type == MBLOCK) {
|
}
|
||||||
|
|
||||||
|
if (reg->y_type == MBLOCK) {
|
||||||
int maxlen = 0;
|
int maxlen = 0;
|
||||||
for (int i = 0; i < reg->y_size; i++) {
|
for (int i = 0; i < reg->y_size; i++) {
|
||||||
int rowlen = STRLEN(reg->y_array[i]);
|
int rowlen = STRLEN(reg->y_array[i]);
|
||||||
@ -5401,6 +5432,7 @@ static void get_clipboard(int name)
|
|||||||
reg->y_width = maxlen-1;
|
reg->y_width = maxlen-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*target = reg;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -5417,7 +5449,7 @@ err:
|
|||||||
|
|
||||||
static void set_clipboard(int name)
|
static void set_clipboard(int name)
|
||||||
{
|
{
|
||||||
struct yankreg* reg = adjust_clipboard_name(&name);
|
struct yankreg* reg = adjust_clipboard_name(&name, false, true);
|
||||||
if (reg == NULL) {
|
if (reg == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -5442,6 +5474,7 @@ static void set_clipboard(int name)
|
|||||||
break;
|
break;
|
||||||
case MBLOCK:
|
case MBLOCK:
|
||||||
regtype = 'b';
|
regtype = 'b';
|
||||||
|
list_append_string(lines, (char_u*)"", 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
list_append_string(args, ®type, 1);
|
list_append_string(args, ®type, 1);
|
||||||
|
@ -2,12 +2,20 @@ let g:test_clip = { '+': [''], '*': [''], }
|
|||||||
|
|
||||||
let s:methods = {}
|
let s:methods = {}
|
||||||
|
|
||||||
|
let g:cliplossy = 0
|
||||||
|
|
||||||
function! s:methods.get(reg)
|
function! s:methods.get(reg)
|
||||||
return g:test_clip[a:reg]
|
if g:cliplossy
|
||||||
|
" behave like pure text clipboard
|
||||||
|
return g:test_clip[a:reg][0]
|
||||||
|
else
|
||||||
|
"behave like VIMENC clipboard
|
||||||
|
return g:test_clip[a:reg]
|
||||||
|
end
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:methods.set(lines, regtype, reg)
|
function! s:methods.set(lines, regtype, reg)
|
||||||
let g:test_clip[a:reg] = a:lines
|
let g:test_clip[a:reg] = [a:lines, a:regtype]
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
-- Test clipboard provider support
|
-- Test clipboard provider support
|
||||||
|
|
||||||
local helpers = require('test.functional.helpers')
|
local helpers = require('test.functional.helpers')
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||||
local execute, expect, eq, eval = helpers.execute, helpers.expect, helpers.eq, helpers.eval
|
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 nvim, run, stop, restart = helpers.nvim, helpers.run, helpers.stop, helpers.restart
|
||||||
|
|
||||||
local function reset()
|
local function basic_register_test(noblock)
|
||||||
clear()
|
|
||||||
execute('let &rtp = "test/functional/clipboard,".&rtp')
|
|
||||||
end
|
|
||||||
|
|
||||||
local function basic_register_test()
|
|
||||||
insert("some words")
|
insert("some words")
|
||||||
|
|
||||||
feed('^dwP')
|
feed('^dwP')
|
||||||
@ -58,22 +54,44 @@ local function basic_register_test()
|
|||||||
expect([[
|
expect([[
|
||||||
, stuff and some more
|
, stuff and some more
|
||||||
some textsome some text, stuff and some more]])
|
some textsome some text, stuff and some more]])
|
||||||
reset()
|
|
||||||
|
feed('ggw<c-v>jwyggP')
|
||||||
|
if noblock then
|
||||||
|
expect([[
|
||||||
|
stuf
|
||||||
|
me t
|
||||||
|
, stuff and some more
|
||||||
|
some textsome some text, stuff and some more]])
|
||||||
|
else
|
||||||
|
expect([[
|
||||||
|
stuf, stuff and some more
|
||||||
|
me tsome textsome some text, stuff and some more]])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe('clipboard usage', function()
|
describe('the unnamed register', function()
|
||||||
setup(reset)
|
before_each(clear)
|
||||||
it("works", function()
|
it('works without provider', function()
|
||||||
basic_register_test()
|
basic_register_test()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
-- "* and unnamed should function as independent registers
|
describe('clipboard usage', function()
|
||||||
|
before_each(function()
|
||||||
|
clear()
|
||||||
|
execute('let &rtp = "test/functional/clipboard,".&rtp')
|
||||||
|
execute('call getreg("*")') -- force load of provider
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('has independent "* and unnamed registers per default', function()
|
||||||
insert("some words")
|
insert("some words")
|
||||||
feed('^"*dwdw"*P')
|
feed('^"*dwdw"*P')
|
||||||
expect('some ')
|
expect('some ')
|
||||||
eq({'some '}, eval("g:test_clip['*']"))
|
eq({{'some '}, 'v'}, eval("g:test_clip['*']"))
|
||||||
reset()
|
eq('words', eval("getreg('\"', 1)"))
|
||||||
|
end)
|
||||||
|
|
||||||
-- "* and "+ should be independent when the provider supports it
|
it('supports separate "* and "+ when the provider supports it', function()
|
||||||
insert([[
|
insert([[
|
||||||
text:
|
text:
|
||||||
first line
|
first line
|
||||||
@ -87,35 +105,56 @@ describe('clipboard usage', function()
|
|||||||
secound line
|
secound line
|
||||||
first line]])
|
first line]])
|
||||||
-- linewise selection should be encoded as an extra newline
|
-- linewise selection should be encoded as an extra newline
|
||||||
eq({'third line', ''}, eval("g:test_clip['+']"))
|
eq({{'third line', ''}, 'V'}, eval("g:test_clip['+']"))
|
||||||
eq({'secound line', ''}, eval("g:test_clip['*']"))
|
eq({{'secound line', ''}, 'V'}, eval("g:test_clip['*']"))
|
||||||
reset()
|
end)
|
||||||
|
|
||||||
-- handle null bytes
|
it('handles null bytes when pasting and in getreg', function()
|
||||||
insert("some\022000text\n\022000very binary\022000")
|
insert("some\022000text\n\022000very binary\022000")
|
||||||
feed('"*y-+"*p')
|
feed('"*y-+"*p')
|
||||||
eq({'some\ntext', '\nvery binary\n',''}, eval("g:test_clip['*']"))
|
eq({{'some\ntext', '\nvery binary\n',''}, 'V'}, eval("g:test_clip['*']"))
|
||||||
expect("some\00text\n\00very binary\00\nsome\00text\n\00very binary\00")
|
expect("some\00text\n\00very binary\00\nsome\00text\n\00very binary\00")
|
||||||
|
|
||||||
-- test getreg/getregtype
|
-- test getreg/getregtype
|
||||||
eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1)"))
|
eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1)"))
|
||||||
eq("V", eval("getregtype('*')"))
|
eq("V", eval("getregtype('*')"))
|
||||||
reset()
|
|
||||||
|
|
||||||
-- blockwise paste
|
-- getreg supports three arguments
|
||||||
|
eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1, 0)"))
|
||||||
|
eq({'some\ntext', '\nvery binary\n'}, eval("getreg('*', 1, 1)"))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('support autodectection of regtype', function()
|
||||||
|
execute("let g:test_clip['*'] = ['linewise stuff','']")
|
||||||
|
execute("let g:test_clip['+'] = ['charwise','stuff']")
|
||||||
|
eq("V", eval("getregtype('*')"))
|
||||||
|
eq("v", eval("getregtype('+')"))
|
||||||
|
insert("just some text")
|
||||||
|
feed('"*p"+p')
|
||||||
|
expect([[
|
||||||
|
just some text
|
||||||
|
lcharwise
|
||||||
|
stuffinewise stuff]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('support blockwise operations', function()
|
||||||
insert([[
|
insert([[
|
||||||
much
|
much
|
||||||
text]])
|
text]])
|
||||||
feed('"*yy') -- force load of provider
|
|
||||||
execute("let g:test_clip['*'] = [['very','block'],'b']")
|
execute("let g:test_clip['*'] = [['very','block'],'b']")
|
||||||
feed('gg"*P')
|
feed('gg"*P')
|
||||||
expect([[
|
expect([[
|
||||||
very much
|
very much
|
||||||
blocktext]])
|
blocktext]])
|
||||||
eq("\0225", eval("getregtype('*')"))
|
eq("\0225", eval("getregtype('*')"))
|
||||||
reset()
|
feed('gg4l<c-v>j4l"+ygg"+P')
|
||||||
|
expect([[
|
||||||
|
muchvery much
|
||||||
|
ktextblocktext]])
|
||||||
|
eq({{' much', 'ktext', ''}, 'b'}, eval("g:test_clip['+']"))
|
||||||
|
end)
|
||||||
|
|
||||||
-- test setreg
|
it('supports setreg', function()
|
||||||
execute('call setreg("*", "setted\\ntext", "c")')
|
execute('call setreg("*", "setted\\ntext", "c")')
|
||||||
execute('call setreg("+", "explicitly\\nlines", "l")')
|
execute('call setreg("+", "explicitly\\nlines", "l")')
|
||||||
feed('"+P"*p')
|
feed('"+P"*p')
|
||||||
@ -124,38 +163,118 @@ describe('clipboard usage', function()
|
|||||||
textxplicitly
|
textxplicitly
|
||||||
lines
|
lines
|
||||||
]])
|
]])
|
||||||
reset()
|
execute('call setreg("+", "blocky\\nindeed", "b")')
|
||||||
|
feed('"+p')
|
||||||
|
expect([[
|
||||||
|
esblockyetted
|
||||||
|
teindeedxtxplicitly
|
||||||
|
lines
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
-- test let @+ (issue #1427)
|
it('supports let @+ (issue #1427)', function()
|
||||||
execute("let @+ = 'some'")
|
execute("let @+ = 'some'")
|
||||||
execute("let @* = ' other stuff'")
|
execute("let @* = ' other stuff'")
|
||||||
eq({'some'}, eval("g:test_clip['+']"))
|
eq({{'some'}, 'v'}, eval("g:test_clip['+']"))
|
||||||
eq({' other stuff'}, eval("g:test_clip['*']"))
|
eq({{' other stuff'}, 'v'}, eval("g:test_clip['*']"))
|
||||||
feed('"+p"*p')
|
feed('"+p"*p')
|
||||||
expect('some other stuff')
|
expect('some other stuff')
|
||||||
execute("let @+ .= ' more'")
|
execute("let @+ .= ' more'")
|
||||||
feed('dd"+p')
|
feed('dd"+p')
|
||||||
expect('some more')
|
expect('some more')
|
||||||
reset()
|
end)
|
||||||
|
|
||||||
|
describe('with clipboard=unnamed', function()
|
||||||
-- the basic behavior of unnamed register should be the same
|
-- the basic behavior of unnamed register should be the same
|
||||||
-- even when handled by clipboard provider
|
-- even when handled by clipboard provider
|
||||||
execute('set clipboard=unnamed')
|
before_each(function()
|
||||||
basic_register_test()
|
execute('set clipboard=unnamed')
|
||||||
|
|
||||||
-- 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)
|
||||||
|
|
||||||
|
it('works', function()
|
||||||
|
basic_register_test()
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('works with pure text clipboard', function()
|
||||||
|
execute("let g:cliplossy = 1")
|
||||||
|
-- expect failure for block mode
|
||||||
|
basic_register_test(true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('links the "* and unnamed registers', function()
|
||||||
|
-- with cb=unnamed, "* and unnamed will be the same register
|
||||||
|
insert("some words")
|
||||||
|
feed('^"*dwdw"*P')
|
||||||
|
expect('words')
|
||||||
|
eq({{'words'}, 'v'}, eval("g:test_clip['*']"))
|
||||||
|
|
||||||
|
execute("let g:test_clip['*'] = ['linewise stuff','']")
|
||||||
|
feed('p')
|
||||||
|
expect([[
|
||||||
|
words
|
||||||
|
linewise stuff]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('does not clobber "0 when pasting', function()
|
||||||
|
insert('a line')
|
||||||
|
feed('yy')
|
||||||
|
execute("let g:test_clip['*'] = ['b line','']")
|
||||||
|
feed('"0pp"0p')
|
||||||
|
expect([[
|
||||||
|
a line
|
||||||
|
a line
|
||||||
|
b line
|
||||||
|
a line]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('supports :put', function()
|
||||||
|
insert("a line")
|
||||||
|
execute("let g:test_clip['*'] = ['some text']")
|
||||||
|
execute("let g:test_clip['+'] = ['more', 'text', '']")
|
||||||
|
execute(":put *")
|
||||||
|
expect([[
|
||||||
|
a line
|
||||||
|
some text]])
|
||||||
|
execute(":put +")
|
||||||
|
expect([[
|
||||||
|
a line
|
||||||
|
some text
|
||||||
|
more
|
||||||
|
text]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('supports "+ and "* in registers', function()
|
||||||
|
local screen = Screen.new(60, 10)
|
||||||
|
screen:attach()
|
||||||
|
execute("let g:test_clip['*'] = ['some', 'star data','']")
|
||||||
|
execute("let g:test_clip['+'] = ['such', 'plus', 'stuff']")
|
||||||
|
execute("registers")
|
||||||
|
screen:expect([[
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
:registers |
|
||||||
|
{1:--- Registers ---} |
|
||||||
|
"* some{2:^J}star data{2:^J} |
|
||||||
|
"+ such{2:^J}plus{2:^J}stuff |
|
||||||
|
": let g:test_clip['+'] = ['such', 'plus', 'stuff'] |
|
||||||
|
{3:Press ENTER or type command to continue}^ |
|
||||||
|
]], {
|
||||||
|
[1] = {bold = true, foreground = Screen.colors.Fuchsia},
|
||||||
|
[2] = {foreground = Screen.colors.Blue},
|
||||||
|
[3] = {bold = true, foreground = Screen.colors.SeaGreen}},
|
||||||
|
{{bold = true, foreground = Screen.colors.Blue}})
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('can paste "* to the commandline', function()
|
||||||
|
insert('s/s/t/')
|
||||||
|
feed('gg"*y$:<c-r>*<cr>')
|
||||||
|
expect('t/s/t/')
|
||||||
|
execute("let g:test_clip['*'] = ['s/s/u']")
|
||||||
|
feed(':<c-r>*<cr>')
|
||||||
|
expect('t/u/t/')
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user