mirror of
https://github.com/neovim/neovim.git
synced 2025-09-16 00:08:19 +00:00
provider: Add support for clipboard registers.
This reimplements the '+'/'*' clipboard registers(both are aliases to the same register, no dedicated storage for the X11 selection) on top of the provider infrastructure. This adds two new 'unnamedclip' option, has the same effect of setting 'clipboard' to 'unnamed/unnamedplus' in vim The 'clipboard' option was not reused because all values(except 'unnamedplus') seem to be useless for Neovim, and the code to parse the option was relatively big. The option remains for vim compatibility but it's silently ignored.
This commit is contained in:
@@ -923,6 +923,7 @@ getcount:
|
|||||||
|
|
||||||
/* Adjust the register according to 'clipboard', so that when
|
/* Adjust the register according to 'clipboard', so that when
|
||||||
* "unnamed" is present it becomes '*' or '+' instead of '"'. */
|
* "unnamed" is present it becomes '*' or '+' instead of '"'. */
|
||||||
|
adjust_clipboard_register(®name);
|
||||||
set_reg_var(regname);
|
set_reg_var(regname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5101,6 +5102,7 @@ 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(®name);
|
||||||
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) {
|
||||||
@@ -7267,9 +7269,10 @@ 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(®name);
|
||||||
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. */
|
||||||
|
125
src/nvim/ops.c
125
src/nvim/ops.c
@@ -47,6 +47,9 @@
|
|||||||
#include "nvim/ui.h"
|
#include "nvim/ui.h"
|
||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
|
#include "nvim/os/provider.h"
|
||||||
|
#include "nvim/os/msgpack_rpc_helpers.h"
|
||||||
|
#include "nvim/api/private/helpers.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Registers:
|
* Registers:
|
||||||
@@ -55,8 +58,9 @@
|
|||||||
* 10..35 = registers 'a' to 'z'
|
* 10..35 = registers 'a' to 'z'
|
||||||
* 36 = delete register '-'
|
* 36 = delete register '-'
|
||||||
*/
|
*/
|
||||||
#define NUM_REGISTERS 37
|
#define NUM_REGISTERS 38
|
||||||
#define DELETION_REGISTER 36
|
#define DELETION_REGISTER 36
|
||||||
|
#define CLIP_REGISTER 37
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each yank register is an array of pointers to lines.
|
* Each yank register is an array of pointers to lines.
|
||||||
@@ -711,6 +715,8 @@ valid_yank_reg (
|
|||||||
|| regname == '"'
|
|| regname == '"'
|
||||||
|| regname == '-'
|
|| regname == '-'
|
||||||
|| regname == '_'
|
|| regname == '_'
|
||||||
|
|| regname == '*'
|
||||||
|
|| regname == '+'
|
||||||
)
|
)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -743,6 +749,8 @@ 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 == '+')
|
||||||
|
i = CLIP_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]);
|
||||||
@@ -762,6 +770,7 @@ get_register (
|
|||||||
) FUNC_ATTR_NONNULL_RET
|
) FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
get_yank_register(name, 0);
|
get_yank_register(name, 0);
|
||||||
|
get_clipboard(name);
|
||||||
|
|
||||||
struct yankreg *reg = xmalloc(sizeof(struct yankreg));
|
struct yankreg *reg = xmalloc(sizeof(struct yankreg));
|
||||||
*reg = *y_current;
|
*reg = *y_current;
|
||||||
@@ -789,7 +798,7 @@ void put_register(int name, void *reg)
|
|||||||
free_yank_all();
|
free_yank_all();
|
||||||
*y_current = *(struct yankreg *)reg;
|
*y_current = *(struct yankreg *)reg;
|
||||||
free(reg);
|
free(reg);
|
||||||
|
set_clipboard(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -929,6 +938,7 @@ 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;
|
||||||
@@ -1093,6 +1103,7 @@ 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);
|
||||||
@@ -1278,6 +1289,17 @@ 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 && provider_has_feature("clipboard")) {
|
||||||
|
*rp = '+';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle a delete operation.
|
* Handle a delete operation.
|
||||||
@@ -1307,6 +1329,7 @@ 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);
|
||||||
@@ -1389,6 +1412,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 ((
|
||||||
|
adjusted ||
|
||||||
oap->regname == 0) && oap->motion_type != MLINE
|
oap->regname == 0) && oap->motion_type != MLINE
|
||||||
&& oap->line_count == 1) {
|
&& oap->line_count == 1) {
|
||||||
oap->regname = '-';
|
oap->regname = '-';
|
||||||
@@ -2336,7 +2360,6 @@ int op_yank(oparg_T *oap, int deleting, int mess)
|
|||||||
if (oap->regname == '_') /* black hole: nothing to do */
|
if (oap->regname == '_') /* black hole: nothing to do */
|
||||||
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, TRUE);
|
||||||
|
|
||||||
@@ -2519,6 +2542,8 @@ int op_yank(oparg_T *oap, int deleting, int mess)
|
|||||||
curbuf->b_op_end.col = MAXCOL;
|
curbuf->b_op_end.col = MAXCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_clipboard(oap->regname);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2581,6 +2606,8 @@ do_put (
|
|||||||
int allocated = FALSE;
|
int allocated = FALSE;
|
||||||
long cnt;
|
long cnt;
|
||||||
|
|
||||||
|
adjust_clipboard_register(®name);
|
||||||
|
get_clipboard(regname);
|
||||||
|
|
||||||
if (flags & PUT_FIXINDENT)
|
if (flags & PUT_FIXINDENT)
|
||||||
orig_indent = get_indent();
|
orig_indent = get_indent();
|
||||||
@@ -3171,6 +3198,8 @@ 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);
|
||||||
|
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
if (y_previous != NULL)
|
if (y_previous != NULL)
|
||||||
@@ -4528,6 +4557,9 @@ void write_viminfo_registers(FILE *fp)
|
|||||||
for (i = 0; i < NUM_REGISTERS; i++) {
|
for (i = 0; i < NUM_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
|
||||||
@@ -4607,6 +4639,7 @@ 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;
|
||||||
@@ -4654,6 +4687,7 @@ get_reg_contents (
|
|||||||
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
get_clipboard(regname);
|
||||||
|
|
||||||
if (get_spec_reg(regname, &retval, &allocated, FALSE)) {
|
if (get_spec_reg(regname, &retval, &allocated, FALSE)) {
|
||||||
if (retval == NULL)
|
if (retval == NULL)
|
||||||
@@ -5162,3 +5196,88 @@ void cursor_pos_info(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_register(struct yankreg *reg)
|
||||||
|
{
|
||||||
|
// Save 'y_current' into 'curr'
|
||||||
|
struct yankreg *curr = y_current;
|
||||||
|
// Set it to 'y_current' since 'free_yank_all' operates on it
|
||||||
|
y_current = reg;
|
||||||
|
free_yank_all();
|
||||||
|
// Restore 'y_current'
|
||||||
|
y_current = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_register(struct yankreg *dest, struct yankreg *src)
|
||||||
|
{
|
||||||
|
free_register(dest);
|
||||||
|
*dest = *src;
|
||||||
|
dest->y_array = xcalloc(src->y_size, sizeof(uint8_t *));
|
||||||
|
for (int j = 0; j < src->y_size; ++j) {
|
||||||
|
dest->y_array[j] = (uint8_t *)xstrdup((char *)src->y_array[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_clipboard(int name)
|
||||||
|
{
|
||||||
|
if (!(name == '*' || name == '+'
|
||||||
|
|| (p_unc && !name && provider_has_feature("clipboard")))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct yankreg *reg = &y_regs[CLIP_REGISTER];
|
||||||
|
free_register(reg);
|
||||||
|
Object result = provider_call("clipboard_get", NIL);
|
||||||
|
|
||||||
|
if (result.type != kObjectTypeArray) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array lines = result.data.array;
|
||||||
|
reg->y_array = xcalloc(lines.size, sizeof(uint8_t *));
|
||||||
|
reg->y_size = lines.size;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lines.size; i++) {
|
||||||
|
if (lines.items[i].type != kObjectTypeString) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
reg->y_array[i] = (uint8_t *)lines.items[i].data.string.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name && p_unc) {
|
||||||
|
// copy to the unnamed register
|
||||||
|
copy_register(&y_regs[0], reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
msgpack_rpc_free_object(result);
|
||||||
|
free(reg->y_array);
|
||||||
|
reg->y_array = NULL;
|
||||||
|
reg->y_size = 0;
|
||||||
|
EMSG("Clipboard provider returned invalid data");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_clipboard(int name)
|
||||||
|
{
|
||||||
|
if (!(name == '*' || name == '+'
|
||||||
|
|| (p_unc && !name && provider_has_feature("clipboard")))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct yankreg *reg = &y_regs[CLIP_REGISTER];
|
||||||
|
|
||||||
|
if (!name && p_unc) {
|
||||||
|
// copy from the unnamed register
|
||||||
|
copy_register(reg, &y_regs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array lines = {0, 0, 0};
|
||||||
|
|
||||||
|
for (int i = 0; i < reg->y_size; i++) {
|
||||||
|
ADD(lines, STRING_OBJ(cstr_to_string((char *)reg->y_array[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object result = provider_call("clipboard_set", ARRAY_OBJ(lines));
|
||||||
|
msgpack_rpc_free_object(result);
|
||||||
|
}
|
||||||
|
@@ -963,6 +963,9 @@ static struct vimoption
|
|||||||
{"infercase", "inf", P_BOOL|P_VI_DEF,
|
{"infercase", "inf", P_BOOL|P_VI_DEF,
|
||||||
(char_u *)&p_inf, PV_INF,
|
(char_u *)&p_inf, PV_INF,
|
||||||
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
|
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
|
||||||
|
{"initclipboard","icpb",P_STRING|P_VI_DEF|P_SECURE,
|
||||||
|
(char_u *)&p_icpb, PV_NONE,
|
||||||
|
{(char_u *)NULL, (char_u *)0L} SCRIPTID_INIT},
|
||||||
{"initpython","ipy",P_STRING|P_VI_DEF|P_SECURE,
|
{"initpython","ipy",P_STRING|P_VI_DEF|P_SECURE,
|
||||||
(char_u *)&p_ipy, PV_NONE,
|
(char_u *)&p_ipy, PV_NONE,
|
||||||
{(char_u *)NULL, (char_u *)0L} SCRIPTID_INIT},
|
{(char_u *)NULL, (char_u *)0L} SCRIPTID_INIT},
|
||||||
@@ -1628,6 +1631,9 @@ 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},
|
||||||
|
@@ -586,6 +586,7 @@ 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' */
|
||||||
@@ -631,6 +632,7 @@ EXTERN int p_wa; /* 'writeany' */
|
|||||||
EXTERN int p_wb; /* 'writebackup' */
|
EXTERN int p_wb; /* 'writebackup' */
|
||||||
EXTERN long p_wd; /* 'writedelay' */
|
EXTERN long p_wd; /* 'writedelay' */
|
||||||
EXTERN char *p_ipy; // 'initpython'
|
EXTERN char *p_ipy; // 'initpython'
|
||||||
|
EXTERN char *p_icpb; // 'initclipboard'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "indir" values for buffer-local opions.
|
* "indir" values for buffer-local opions.
|
||||||
|
@@ -36,7 +36,12 @@ static struct feature {
|
|||||||
"python_execute",
|
"python_execute",
|
||||||
"python_execute_file",
|
"python_execute_file",
|
||||||
"python_do_range",
|
"python_do_range",
|
||||||
"python_eval")
|
"python_eval"),
|
||||||
|
|
||||||
|
FEATURE("clipboard",
|
||||||
|
&p_icpb,
|
||||||
|
"clipboard_get",
|
||||||
|
"clipboard_set")
|
||||||
};
|
};
|
||||||
|
|
||||||
static Map(cstr_t, uint64_t) *registered_providers = NULL;
|
static Map(cstr_t, uint64_t) *registered_providers = NULL;
|
||||||
|
Reference in New Issue
Block a user