patch 9.1.1857: Missing clipboard provider support
Problem: Missing clipboard provider support
(lilydjwg)
Solution: Add clipboard provider feature
(Foxe Chen)
fixes: #12419
closes: #17998
Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
1a09f11f5d
commit
67860efe5b
31
src/auto/configure
vendored
31
src/auto/configure
vendored
@ -857,6 +857,7 @@ enable_arabic
|
||||
enable_farsi
|
||||
enable_xim
|
||||
enable_fontset
|
||||
enable_clipboard_provider
|
||||
with_wayland
|
||||
enable_wayland_focus_steal
|
||||
with_x
|
||||
@ -1539,6 +1540,7 @@ Optional Features:
|
||||
--disable-farsi Deprecated.
|
||||
--enable-xim Include XIM input support.
|
||||
--enable-fontset Include X fontset output support.
|
||||
--enable-clipboard-provider Include clipboard provider support.
|
||||
--enable-wayland-focus-steal
|
||||
Include focus stealing support for Wayland
|
||||
clipboard.
|
||||
@ -9208,6 +9210,35 @@ fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_fontset" >&5
|
||||
printf "%s\n" "$enable_fontset" >&6; }
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking --enable-clipboard-provider" >&5
|
||||
printf %s "checking --enable-clipboard-provider... " >&6; }
|
||||
# Check whether --enable-clipboard-provider was given.
|
||||
if test ${enable_clipboard_provider+y}
|
||||
then :
|
||||
enableval=$enable_clipboard_provider; enable_clipboard_provider=$enableval
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enableval" >&5
|
||||
printf "%s\n" "$enableval" >&6; }
|
||||
else case e in #(
|
||||
e) if test "x$features" = xtiny
|
||||
then :
|
||||
enable_clipboard_provider="no"
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cannot use clipboard provider with tiny features" >&5
|
||||
printf "%s\n" "cannot use clipboard provider with tiny features" >&6; }
|
||||
else case e in #(
|
||||
e) enable_clipboard_provider="yes"
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; } ;;
|
||||
esac
|
||||
fi ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "$enable_clipboard_provider" = "yes"; then
|
||||
printf "%s\n" "#define FEAT_CLIPBOARD_PROVIDER 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if shm_open is available" >&5
|
||||
printf %s "checking if shm_open is available... " >&6; }
|
||||
cppflags_save=$CPPFLAGS
|
||||
|
||||
403
src/clipboard.c
403
src/clipboard.c
@ -134,6 +134,12 @@ static bool clip_wl_owner_exists(Clipboard_T *cbd);
|
||||
|
||||
#endif // FEAT_WAYLAND_CLIPBOARD
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
static int clip_provider_is_available(Clipboard_T *cbd, char_u *provider);
|
||||
static void clip_provider_set_selection(Clipboard_T *cbd, char_u *provider);
|
||||
static void clip_provider_request_selection(Clipboard_T *cbd, char_u *provider);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Selection stuff using Visual mode, for cutting and pasting text to other
|
||||
* windows.
|
||||
@ -254,7 +260,7 @@ clip_gen_own_selection(Clipboard_T *cbd UNUSED)
|
||||
}
|
||||
else if (clipmethod == CLIPMETHOD_OTHER)
|
||||
{
|
||||
#if !defined(FEAT_XCLIPBOARD) && !defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
#ifndef UNIX
|
||||
return clip_mch_own_selection(cbd);
|
||||
#endif
|
||||
}
|
||||
@ -321,7 +327,7 @@ clip_gen_lose_selection(Clipboard_T *cbd UNUSED)
|
||||
}
|
||||
else if (clipmethod == CLIPMETHOD_OTHER)
|
||||
{
|
||||
#if !defined(FEAT_XCLIPBOARD) && !defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
#ifndef UNIX
|
||||
clip_mch_lose_selection(cbd);
|
||||
#endif
|
||||
}
|
||||
@ -1354,7 +1360,7 @@ clip_gen_set_selection(Clipboard_T *cbd)
|
||||
{
|
||||
#ifdef FEAT_GUI
|
||||
if (gui.in_use)
|
||||
clip_mch_set_selection(cbd);
|
||||
clip_mch_set_selection(cbd);
|
||||
#endif
|
||||
}
|
||||
else if (clipmethod == CLIPMETHOD_WAYLAND)
|
||||
@ -1371,8 +1377,14 @@ clip_gen_set_selection(Clipboard_T *cbd)
|
||||
}
|
||||
else if (clipmethod == CLIPMETHOD_OTHER)
|
||||
{
|
||||
#if !defined(FEAT_XCLIPBOARD) && !defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
#ifndef UNIX
|
||||
clip_mch_set_selection(cbd);
|
||||
#endif
|
||||
}
|
||||
else if (clipmethod == CLIPMETHOD_PROVIDER)
|
||||
{
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
clip_provider_set_selection(cbd, clipprovider_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -1401,8 +1413,14 @@ clip_gen_request_selection(Clipboard_T *cbd UNUSED)
|
||||
}
|
||||
else if (clipmethod == CLIPMETHOD_OTHER)
|
||||
{
|
||||
#if !defined(FEAT_XCLIPBOARD) && !defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
#ifndef UNIX
|
||||
clip_mch_request_selection(cbd);
|
||||
#endif
|
||||
}
|
||||
else if (clipmethod == CLIPMETHOD_PROVIDER)
|
||||
{
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
clip_provider_request_selection(cbd, clipprovider_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -2266,10 +2284,18 @@ clip_get_selection(Clipboard_T *cbd)
|
||||
}
|
||||
else if (!is_clipboard_needs_update())
|
||||
{
|
||||
clip_free_selection(cbd);
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
// We will choose if we want to the free the selection if using provider
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
clip_free_selection(cbd);
|
||||
#endif
|
||||
|
||||
// Try to get selected text from another window
|
||||
clip_gen_request_selection(cbd);
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
if (clipmethod == CLIPMETHOD_PROVIDER)
|
||||
clip_access_type = CLIP_ACCESS_IMPLICIT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -3507,15 +3533,34 @@ get_clipmethod(char_u *str, bool *regular, bool *primary)
|
||||
}
|
||||
else if (STRCMP(buf, "other") == 0)
|
||||
{
|
||||
#if !defined(FEAT_XCLIPBOARD) && !defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
#ifndef UNIX
|
||||
method = CLIPMETHOD_OTHER;
|
||||
*regular = *primary = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = CLIPMETHOD_FAIL;
|
||||
goto exit;
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
// Check if it is the name of a provider
|
||||
int reg = clip_provider_is_available(&clip_plus, buf);
|
||||
int pri = clip_provider_is_available(&clip_star, buf);
|
||||
|
||||
if (reg == 1 || pri == 1)
|
||||
{
|
||||
method = CLIPMETHOD_PROVIDER;
|
||||
|
||||
vim_free(clipprovider_name);
|
||||
clipprovider_name = vim_strsave(buf);
|
||||
|
||||
*regular = reg == 1;
|
||||
*primary = pri == 1;
|
||||
}
|
||||
else if (reg == -1)
|
||||
#endif
|
||||
{
|
||||
ret = CLIPMETHOD_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep on going in order to catch errors
|
||||
@ -3548,6 +3593,15 @@ clipmethod_to_str(clipmethod_T method)
|
||||
return (char_u *)"gui";
|
||||
case CLIPMETHOD_OTHER:
|
||||
return (char_u *)"other";
|
||||
case CLIPMETHOD_PROVIDER:
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
if (clipprovider_name == NULL)
|
||||
return (char_u *)"none";
|
||||
else
|
||||
return clipprovider_name;
|
||||
#else
|
||||
return (char_u *)"none";
|
||||
#endif
|
||||
default:
|
||||
return (char_u *)"none";
|
||||
}
|
||||
@ -3584,16 +3638,26 @@ choose_clipmethod(void)
|
||||
clip_plus.did_warn = false;
|
||||
clip_star.did_warn = false;
|
||||
}
|
||||
// Disown clipboard if we are switching to a new method
|
||||
else if (clipmethod != CLIPMETHOD_NONE && method != clipmethod)
|
||||
else if ((clipmethod != CLIPMETHOD_NONE && method != clipmethod))
|
||||
{
|
||||
// Disown clipboard if we are switching to a new method
|
||||
if (clip_star.owned)
|
||||
clip_lose_selection(&clip_star);
|
||||
if (clip_plus.owned)
|
||||
clip_lose_selection(&clip_plus);
|
||||
|
||||
clip_init_single(&clip_plus, regular);
|
||||
clip_init_single(&clip_star, primary);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If availability of a clipboard changed, then update the clipboard
|
||||
// structure.
|
||||
if (regular != clip_plus.available)
|
||||
clip_init_single(&clip_plus, regular);
|
||||
if (primary != clip_star.available)
|
||||
clip_init_single(&clip_star, primary);
|
||||
}
|
||||
|
||||
clipmethod = method;
|
||||
|
||||
@ -3621,4 +3685,321 @@ ex_clipreset(exarg_T *eap UNUSED)
|
||||
clipmethod_to_str(clipmethod));
|
||||
}
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
|
||||
/*
|
||||
* Check if a clipboard provider with given name exists and is available for the
|
||||
* given clipboard. Returns 1 if the provider exists and the 'available'
|
||||
* function returned true, 0 if the provider exists but the function returned
|
||||
* false, and -1 on error.
|
||||
*/
|
||||
static int
|
||||
clip_provider_is_available(Clipboard_T *cbd, char_u *provider)
|
||||
{
|
||||
dict_T *providers = get_vim_var_dict(VV_CLIPPROVIDERS);
|
||||
typval_T provider_tv = {0};
|
||||
callback_T callback = {0};
|
||||
typval_T rettv = {0};
|
||||
typval_T func_tv = {0};
|
||||
char_u *avail;
|
||||
int res = 0;
|
||||
|
||||
if (dict_get_tv(providers, (char *)provider, &provider_tv) == FAIL
|
||||
|| provider_tv.v_type != VAR_DICT)
|
||||
return -1;
|
||||
|
||||
if (dict_get_tv(provider_tv.vval.v_dict, "available", &func_tv) == FAIL)
|
||||
{
|
||||
clear_tv(&provider_tv);
|
||||
// If "available" functon not specified assume always TRUE
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((callback = get_callback(&func_tv)).cb_name == NULL)
|
||||
goto fail;
|
||||
|
||||
if (call_callback(&callback, -1, &rettv, 0, NULL) == FAIL ||
|
||||
rettv.v_type != VAR_STRING)
|
||||
goto fail;
|
||||
|
||||
avail = rettv.vval.v_string;
|
||||
|
||||
if ((vim_strchr(avail, '+') != NULL && cbd == &clip_plus)
|
||||
|| (vim_strchr(avail, '*') != NULL && cbd == &clip_star))
|
||||
res = 1;
|
||||
|
||||
if (FALSE)
|
||||
fail:
|
||||
res = -1;
|
||||
|
||||
free_callback(&callback);
|
||||
clear_tv(&func_tv);
|
||||
clear_tv(&rettv);
|
||||
clear_tv(&provider_tv);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the specified callback "function" from the provider dictionary of for
|
||||
* register "reg".
|
||||
*/
|
||||
static int
|
||||
clip_provider_get_callback(
|
||||
char_u *reg,
|
||||
char_u *provider,
|
||||
char_u *function,
|
||||
callback_T *callback)
|
||||
{
|
||||
dict_T *providers = get_vim_var_dict(VV_CLIPPROVIDERS);
|
||||
typval_T provider_tv;
|
||||
typval_T action_tv;
|
||||
typval_T func_tv;
|
||||
callback_T cb;
|
||||
|
||||
if (dict_get_tv(providers, (char *)provider, &provider_tv) == FAIL)
|
||||
return FAIL;
|
||||
else if (provider_tv.v_type != VAR_DICT)
|
||||
{
|
||||
clear_tv(&provider_tv);
|
||||
return FAIL;
|
||||
}
|
||||
else if (dict_get_tv(
|
||||
provider_tv.vval.v_dict,
|
||||
(char *)function,
|
||||
&action_tv) == FAIL)
|
||||
{
|
||||
clear_tv(&provider_tv);
|
||||
return FAIL;
|
||||
}
|
||||
else if (action_tv.v_type != VAR_DICT)
|
||||
{
|
||||
clear_tv(&provider_tv);
|
||||
clear_tv(&action_tv);
|
||||
return FAIL;
|
||||
}
|
||||
else if (dict_get_tv(action_tv.vval.v_dict, (char *)reg, &func_tv) == FAIL)
|
||||
{
|
||||
clear_tv(&provider_tv);
|
||||
clear_tv(&action_tv);
|
||||
return FAIL;
|
||||
}
|
||||
else if ((cb = get_callback(&func_tv)).cb_name == NULL)
|
||||
{
|
||||
clear_tv(&provider_tv);
|
||||
clear_tv(&action_tv);
|
||||
clear_tv(&func_tv);
|
||||
return FAIL;
|
||||
}
|
||||
clear_tv(&provider_tv);
|
||||
clear_tv(&action_tv);
|
||||
|
||||
// func_tv owns the function name, so we must make a copy for the callback
|
||||
set_callback(callback, &cb);
|
||||
free_callback(&cb);
|
||||
clear_tv(&func_tv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void
|
||||
clip_provider_set_selection(Clipboard_T *cbd, char_u *provider)
|
||||
{
|
||||
char_u *reg = (char_u *)(cbd == &clip_star ? "*" : "+");
|
||||
callback_T callback;
|
||||
typval_T rettv;
|
||||
typval_T argvars[4];
|
||||
yankreg_T *y_ptr;
|
||||
char_u type[2 + NUMBUFLEN] = {0};
|
||||
list_T *list = NULL;
|
||||
|
||||
if (clip_provider_get_callback(
|
||||
reg,
|
||||
provider,
|
||||
(char_u *)"copy",
|
||||
&callback) == FAIL)
|
||||
return;
|
||||
|
||||
// Possibly get selected text, if using autoselect for 'clipboard'
|
||||
cbd->owned = TRUE;
|
||||
clip_get_selection(cbd);
|
||||
cbd->owned = FALSE;
|
||||
|
||||
// Convert register type into a string
|
||||
if (cbd == &clip_plus)
|
||||
y_ptr = get_y_register(PLUS_REGISTER);
|
||||
else
|
||||
y_ptr = get_y_register(STAR_REGISTER);
|
||||
|
||||
switch (y_ptr->y_type)
|
||||
{
|
||||
case MCHAR:
|
||||
type[0] = 'v';
|
||||
break;
|
||||
case MLINE:
|
||||
type[0] = 'V';
|
||||
break;
|
||||
case MBLOCK:
|
||||
sprintf((char *)type, "%c%d", Ctrl_V, y_ptr->y_width + 1);
|
||||
break;
|
||||
default:
|
||||
type[0] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
argvars[0].v_type = VAR_STRING;
|
||||
argvars[0].vval.v_string = reg;
|
||||
|
||||
argvars[1].v_type = VAR_STRING;
|
||||
argvars[1].vval.v_string = type;
|
||||
|
||||
// Get register contents by creating a list of lines
|
||||
list = list_alloc();
|
||||
|
||||
if (list == NULL)
|
||||
{
|
||||
free_callback(&callback);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < y_ptr->y_size; i++)
|
||||
if (list_append_string(list, y_ptr->y_array[i].string, -1) == FAIL)
|
||||
{
|
||||
free_callback(&callback);
|
||||
list_unref(list);
|
||||
return;
|
||||
}
|
||||
|
||||
list->lv_refcount++;
|
||||
|
||||
argvars[2].v_type = VAR_LIST;
|
||||
argvars[2].v_lock = VAR_FIXED;
|
||||
argvars[2].vval.v_list = list;
|
||||
|
||||
argvars[3].v_type = VAR_UNKNOWN;
|
||||
|
||||
textlock++;
|
||||
call_callback(&callback, -1, &rettv, 3, argvars);
|
||||
clear_tv(&rettv);
|
||||
textlock--;
|
||||
|
||||
free_callback(&callback);
|
||||
list_unref(list);
|
||||
}
|
||||
|
||||
static void
|
||||
clip_provider_request_selection(Clipboard_T *cbd, char_u *provider)
|
||||
{
|
||||
char_u *reg = (char_u *)(cbd == &clip_star ? "*" : "+");
|
||||
callback_T callback;
|
||||
typval_T argvars[3];
|
||||
typval_T rettv;
|
||||
int ret;
|
||||
char_u *reg_type;
|
||||
list_T *lines;
|
||||
|
||||
if (clip_provider_get_callback(
|
||||
reg,
|
||||
provider,
|
||||
(char_u *)"paste",
|
||||
&callback) == FAIL)
|
||||
return;
|
||||
|
||||
argvars[0].v_type = VAR_STRING;
|
||||
argvars[0].vval.v_string = reg;
|
||||
|
||||
argvars[1].v_type = VAR_STRING;
|
||||
argvars[1].vval.v_string = (char_u *)
|
||||
(clip_access_type == CLIP_ACCESS_EXPLICIT ? "explicit" : "implicit");
|
||||
|
||||
argvars[2].v_type = VAR_UNKNOWN;
|
||||
|
||||
textlock++;
|
||||
ret = call_callback(&callback, -1, &rettv, 2, argvars);
|
||||
textlock--;
|
||||
|
||||
if (ret == FAIL)
|
||||
goto exit;
|
||||
else if (rettv.v_type == VAR_STRING
|
||||
&& STRCMP(rettv.vval.v_string, "clear") == 0)
|
||||
{
|
||||
clip_free_selection(cbd);
|
||||
goto exit;
|
||||
}
|
||||
else if (rettv.v_type == VAR_STRING
|
||||
&& STRCMP(rettv.vval.v_string, "previous") == 0)
|
||||
goto exit;
|
||||
else if (rettv.v_type == VAR_TUPLE
|
||||
&& TUPLE_LEN(rettv.vval.v_tuple) == 2
|
||||
&& TUPLE_ITEM(rettv.vval.v_tuple, 0)->v_type == VAR_STRING
|
||||
&& TUPLE_ITEM(rettv.vval.v_tuple, 1)->v_type == VAR_LIST)
|
||||
{
|
||||
reg_type = TUPLE_ITEM(rettv.vval.v_tuple, 0)->vval.v_string;
|
||||
lines = TUPLE_ITEM(rettv.vval.v_tuple, 1)->vval.v_list;
|
||||
}
|
||||
else if (rettv.v_type == VAR_LIST
|
||||
&& rettv.vval.v_list->lv_len == 2
|
||||
&& rettv.vval.v_list->lv_first->li_tv.v_type == VAR_STRING
|
||||
&& rettv.vval.v_list->lv_first->li_next->li_tv.v_type == VAR_LIST)
|
||||
{
|
||||
reg_type = rettv.vval.v_list->lv_first->li_tv.vval.v_string;
|
||||
lines = rettv.vval.v_list->lv_first->li_next->li_tv.vval.v_list;
|
||||
}
|
||||
else
|
||||
goto exit;
|
||||
|
||||
{
|
||||
char_u yank_type = MAUTO;
|
||||
long block_len = -1;
|
||||
yankreg_T *y_ptr;
|
||||
char_u **contents;
|
||||
listitem_T *li;
|
||||
int i = 0;
|
||||
|
||||
contents = ALLOC_MULT(char_u *, lines->lv_len + 1); // Ends with a NULL
|
||||
|
||||
if (contents == NULL)
|
||||
goto exit;
|
||||
|
||||
// Convert strings in list to type char_u **
|
||||
FOR_ALL_LIST_ITEMS(lines, li)
|
||||
{
|
||||
char_u *str = tv_get_string_chk(&li->li_tv);
|
||||
|
||||
if (str == NULL)
|
||||
goto exit;
|
||||
|
||||
contents[i++] = vim_strsave(str);
|
||||
}
|
||||
contents[i] = NULL;
|
||||
|
||||
if (STRLEN(reg_type) > 0
|
||||
&& get_yank_type(®_type, &yank_type, &block_len) == FAIL)
|
||||
goto exit;
|
||||
|
||||
if (cbd == &clip_plus)
|
||||
y_ptr = get_y_register(PLUS_REGISTER);
|
||||
else
|
||||
y_ptr = get_y_register(STAR_REGISTER);
|
||||
|
||||
clip_free_selection(cbd);
|
||||
|
||||
str_to_reg(y_ptr,
|
||||
yank_type,
|
||||
(char_u *)contents,
|
||||
STRLEN(contents),
|
||||
block_len,
|
||||
TRUE);
|
||||
|
||||
for (int k = 0; k < i; k++)
|
||||
vim_free(contents[k]);
|
||||
vim_free(contents);
|
||||
}
|
||||
|
||||
exit:
|
||||
free_callback(&callback);
|
||||
clear_tv(&rettv);
|
||||
}
|
||||
|
||||
#endif // FEAT_CLIPBOARD_PROVIDER
|
||||
|
||||
#endif // FEAT_CLIPBOARD
|
||||
|
||||
@ -528,3 +528,6 @@
|
||||
|
||||
/* Define if you want to load libgpm dynamically */
|
||||
#undef DYNAMIC_GPM
|
||||
|
||||
/* Define if you want to have clipboard provider functionality*/
|
||||
#undef FEAT_CLIPBOARD_PROVIDER
|
||||
|
||||
@ -2434,6 +2434,21 @@ AC_ARG_ENABLE(fontset,
|
||||
AC_MSG_RESULT($enable_fontset)
|
||||
dnl defining FEAT_XFONTSET is delayed, so that it can be disabled for no GUI
|
||||
|
||||
AC_MSG_CHECKING(--enable-clipboard-provider)
|
||||
AC_ARG_ENABLE(clipboard-provider,
|
||||
[ --enable-clipboard-provider Include clipboard provider support.],
|
||||
[enable_clipboard_provider=$enableval
|
||||
AC_MSG_RESULT($enableval)],
|
||||
AS_IF([test "x$features" = xtiny],
|
||||
[enable_clipboard_provider="no"
|
||||
AC_MSG_RESULT([cannot use clipboard provider with tiny features])],
|
||||
[enable_clipboard_provider="yes"
|
||||
AC_MSG_RESULT([yes])]))
|
||||
if test "$enable_clipboard_provider" = "yes"; then
|
||||
AC_DEFINE(FEAT_CLIPBOARD_PROVIDER)
|
||||
fi
|
||||
|
||||
|
||||
AC_MSG_CHECKING(if shm_open is available)
|
||||
cppflags_save=$CPPFLAGS
|
||||
CPPFLAGS="$CPPFLAGS $X_CFLAGS"
|
||||
|
||||
@ -6500,6 +6500,11 @@ f_getreg(typval_T *argvars, typval_T *rettv)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
if (clipmethod == CLIPMETHOD_PROVIDER)
|
||||
clip_access_type = CLIP_ACCESS_EXPLICIT;
|
||||
#endif
|
||||
|
||||
if (return_list)
|
||||
{
|
||||
rettv->v_type = VAR_LIST;
|
||||
@ -6866,6 +6871,13 @@ f_has(typval_T *argvars, typval_T *rettv)
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
},
|
||||
{"clipboard_provider",
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
},
|
||||
{"cmdline_compl", 1},
|
||||
@ -11493,7 +11505,7 @@ f_setpos(typval_T *argvars, typval_T *rettv)
|
||||
/*
|
||||
* Translate a register type string to the yank type and block length
|
||||
*/
|
||||
static int
|
||||
int
|
||||
get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
|
||||
{
|
||||
char_u *stropt = *pp;
|
||||
|
||||
@ -166,7 +166,8 @@ static struct vimvar
|
||||
{VV_NAME("wayland_display", VAR_STRING), NULL, VV_RO},
|
||||
{VV_NAME("clipmethod", VAR_STRING), NULL, VV_RO},
|
||||
{VV_NAME("termda1", VAR_STRING), NULL, VV_RO},
|
||||
{VV_NAME("termosc", VAR_STRING), NULL, VV_RO},
|
||||
{VV_NAME("termosc", VAR_STRING), NULL, VV_RO},
|
||||
{VV_NAME("clipproviders", VAR_DICT), &t_dict_string, VV_RO}
|
||||
};
|
||||
|
||||
// shorthand
|
||||
|
||||
@ -905,6 +905,19 @@
|
||||
# define FEAT_CLIPBOARD
|
||||
#endif
|
||||
|
||||
/*
|
||||
* +clipboard_provider Allow Vim to use clipboard providers
|
||||
*/
|
||||
#if defined(FEAT_CLIPBOARD_PROVIDER)
|
||||
# ifndef FEAT_EVAL
|
||||
# undef FEAT_CLIPBOARD_PROVIDER
|
||||
# else
|
||||
# ifndef FEAT_CLIPBOARD
|
||||
# define FEAT_CLIPBOARD
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_GUI
|
||||
# ifndef FEAT_CLIPBOARD
|
||||
# define FEAT_CLIPBOARD
|
||||
|
||||
@ -972,7 +972,8 @@ EXTERN int gui_win_y INIT(= -1);
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
EXTERN Clipboard_T clip_star; // PRIMARY selection in X11/Wayland
|
||||
# if defined(FEAT_X11) || defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
# if defined(FEAT_X11) || defined(FEAT_WAYLAND_CLIPBOARD) \
|
||||
|| ((defined(UNIX) || defined(VMS)) && defined(FEAT_CLIPBOARD_PROVIDER))
|
||||
EXTERN Clipboard_T clip_plus; // CLIPBOARD selection in X11/Wayland
|
||||
# else
|
||||
# define clip_plus clip_star // there is only one clipboard
|
||||
@ -2067,6 +2068,9 @@ EXTERN int p_tgc_set INIT(= FALSE);
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
EXTERN clipmethod_T clipmethod INIT(= CLIPMETHOD_NONE);
|
||||
# ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
EXTERN char_u *clipprovider_name INIT(= NULL);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_WAYLAND
|
||||
@ -2116,3 +2120,16 @@ INIT(= CLIENTSERVER_METHOD_NONE);
|
||||
// Path to socket of last client that communicated with us
|
||||
EXTERN char_u *client_socket INIT(= NULL);
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
typedef enum
|
||||
{
|
||||
CLIP_ACCESS_IMPLICIT,
|
||||
CLIP_ACCESS_EXPLICIT,
|
||||
} clip_access_T;
|
||||
|
||||
// Only relevant for the clipboard provider feature. This indicates if the
|
||||
// clipboard request is implicit (ex. access when doing :registers),
|
||||
// explicit (ex. typing "+p). Always defaults to implicit.
|
||||
EXTERN clip_access_T clip_access_type INIT(= CLIP_ACCESS_IMPLICIT);
|
||||
#endif
|
||||
|
||||
@ -28,4 +28,5 @@ void f_len(typval_T *argvars, typval_T *rettv);
|
||||
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
|
||||
void range_list_materialize(list_T *list);
|
||||
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
|
||||
int get_yank_type(char_u **pp, char_u *yank_type, long *block_len);
|
||||
/* vim: set ft=c : */
|
||||
|
||||
@ -1559,6 +1559,10 @@ do_put(
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// Adjust register name for "unnamed" in 'clipboard'.
|
||||
adjust_clip_reg(®name);
|
||||
# ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
if (clipmethod == CLIPMETHOD_PROVIDER)
|
||||
clip_access_type = CLIP_ACCESS_EXPLICIT;
|
||||
# endif
|
||||
(void)may_get_selection(regname);
|
||||
#endif
|
||||
|
||||
|
||||
@ -105,6 +105,7 @@ NEW_TESTS = \
|
||||
test_cjk_linebreak \
|
||||
test_clientserver \
|
||||
test_clipmethod \
|
||||
test_clipboard_provider \
|
||||
test_close_count \
|
||||
test_cmd_lists \
|
||||
test_cmdline \
|
||||
@ -395,6 +396,7 @@ NEW_TESTS_RES = \
|
||||
test_cjk_linebreak.res \
|
||||
test_clientserver.res \
|
||||
test_clipmethod.res \
|
||||
test_clipboard_provider.res \
|
||||
test_close_count.res \
|
||||
test_cmd_lists.res \
|
||||
test_cmdline.res \
|
||||
|
||||
170
src/testdir/test_clipboard_provider.vim
Normal file
170
src/testdir/test_clipboard_provider.vim
Normal file
@ -0,0 +1,170 @@
|
||||
" Test for clipboard provider feature
|
||||
|
||||
CheckFeature clipboard_provider
|
||||
|
||||
func! AvailableBoth()
|
||||
return "+*"
|
||||
endfunc
|
||||
|
||||
func! AvailablePlus()
|
||||
return "+"
|
||||
endfunc
|
||||
|
||||
func! PasteList(reg, type)
|
||||
return ["c", ["list"]]
|
||||
endfunc
|
||||
|
||||
func! PasteTuple(reg, type)
|
||||
return ("", ["tuple", "of", "strings"])
|
||||
endfunc
|
||||
|
||||
func! PasteType(reg, type)
|
||||
let g:vim_test_type = a:type
|
||||
return ("c", [a:type])
|
||||
endfunc
|
||||
|
||||
func! PasteRegType(reg, type)
|
||||
return (g:vim_test_reg_type, ["7 chars"])
|
||||
endfunc
|
||||
|
||||
func! Copy(reg, type, lines)
|
||||
let g:vim_test_stuff = {
|
||||
\ "type": a:type,
|
||||
\ "lines": a:lines
|
||||
\ }
|
||||
endfunc
|
||||
|
||||
" Test if "available" function works properly for provider
|
||||
func Test_clipboard_provider_available()
|
||||
CheckUnix
|
||||
let v:clipproviders["test"] = {
|
||||
\ "available": function("AvailablePlus"),
|
||||
\ "paste": {
|
||||
\ '+': function("PasteList"),
|
||||
\ '*': function("PasteList")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
set clipmethod=test
|
||||
call assert_equal("test", v:clipmethod)
|
||||
|
||||
call assert_equal("list", getreg("+"))
|
||||
" Test if star register is unavailable
|
||||
call assert_equal("", getreg("*"))
|
||||
|
||||
let v:clipproviders["test"] = {
|
||||
\ "available": function("AvailableBoth"),
|
||||
\ "paste": {
|
||||
\ '+': function("PasteList"),
|
||||
\ '*': function("PasteList")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
clipreset
|
||||
|
||||
call assert_equal("list", getreg("+"))
|
||||
call assert_equal("list", getreg("*"))
|
||||
|
||||
let v:clipproviders["test"] = {
|
||||
\ "paste": {
|
||||
\ '+': function("PasteList"),
|
||||
\ '*': function("PasteList")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
" Should default to TRUE
|
||||
call assert_equal("list", getreg("+"))
|
||||
call assert_equal("list", getreg("*"))
|
||||
|
||||
set clipmethod&
|
||||
endfunc
|
||||
|
||||
" Test if "paste" functions work properly for provider
|
||||
func Test_clipboard_provider_paste()
|
||||
" Test if tuples and lists work the same
|
||||
let v:clipproviders["test"] = {
|
||||
\ "paste": {
|
||||
\ '*': function("PasteList")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
set clipmethod=test
|
||||
call assert_equal("test", v:clipmethod)
|
||||
|
||||
call assert_equal("list", getreg("*"))
|
||||
|
||||
let v:clipproviders["test"] = {
|
||||
\ "paste": {
|
||||
\ '*': function("PasteTuple")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
call assert_equal("tuple\nof\nstrings\n", getreg("*"))
|
||||
|
||||
" Test if "implicit" and "explicit" arguments are correctly used
|
||||
let v:clipproviders["test"] = {
|
||||
\ "paste": {
|
||||
\ '*': function("PasteType")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
call assert_equal("explicit", getreg("*"))
|
||||
|
||||
:registers
|
||||
|
||||
call assert_equal("implicit", g:vim_test_type)
|
||||
unlet g:vim_test_type
|
||||
|
||||
" Test if correct register type is used
|
||||
let v:clipproviders["test"] = {
|
||||
\ "paste": {
|
||||
\ '*': function("PasteRegType")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
let g:vim_test_reg_type = "v"
|
||||
call assert_equal("v", getregtype("*"))
|
||||
let g:vim_test_reg_type = "c"
|
||||
call assert_equal("v", getregtype("*"))
|
||||
|
||||
let g:vim_test_reg_type = "l"
|
||||
call assert_equal("V", getregtype("*"))
|
||||
let g:vim_test_reg_type = "l"
|
||||
call assert_equal("V", getregtype("*"))
|
||||
|
||||
let g:vim_test_reg_type = "b"
|
||||
call assert_equal("7", getregtype("*"))
|
||||
let g:vim_test_reg_type = ""
|
||||
call assert_equal("7", getregtype("*"))
|
||||
|
||||
let g:vim_test_reg_type = "b40"
|
||||
call assert_equal("40", getregtype("*"))
|
||||
|
||||
set clipmethod&
|
||||
endfunc
|
||||
|
||||
" Test if "copy" functions work properly for provider
|
||||
func Test_clipboard_provider_copy()
|
||||
let v:clipproviders["test"] = {
|
||||
\ "copy": {
|
||||
\ '*': function("Copy")
|
||||
\ }
|
||||
\ }
|
||||
|
||||
set clipmethod=test
|
||||
call assert_equal("test", v:clipmethod)
|
||||
|
||||
call setreg("*", ["hello", "world", "!"], "c")
|
||||
call assert_equal(["hello", "world", "!"], g:vim_test_stuff.lines)
|
||||
call assert_equal("v", g:vim_test_stuff.type)
|
||||
|
||||
call setreg("*", ["hello", "world", "!"], "l")
|
||||
call assert_equal(["hello", "world", "!"], g:vim_test_stuff.lines)
|
||||
call assert_equal("V", g:vim_test_stuff.type)
|
||||
|
||||
call setreg("*", ["hello", "world", "!"], "b40")
|
||||
call assert_equal(["hello", "world", "!"], g:vim_test_stuff.lines)
|
||||
call assert_equal("40", g:vim_test_stuff.type)
|
||||
|
||||
set clipmethod&
|
||||
endfunc
|
||||
@ -155,6 +155,11 @@ static char *(features[]) =
|
||||
"+clipboard",
|
||||
#else
|
||||
"-clipboard",
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
"+clipboard_provider",
|
||||
#else
|
||||
"-clipboard_provider",
|
||||
#endif
|
||||
"+cmdline_compl",
|
||||
"+cmdline_hist",
|
||||
@ -729,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1857,
|
||||
/**/
|
||||
1856,
|
||||
/**/
|
||||
|
||||
@ -2256,7 +2256,8 @@ typedef int sock_T;
|
||||
#define VV_CLIPMETHOD 113
|
||||
#define VV_TERMDA1 114
|
||||
#define VV_TERMOSC 115
|
||||
#define VV_LEN 116 // number of v: vars
|
||||
#define VV_CLIPPROVIDERS 116
|
||||
#define VV_LEN 117 // number of v: vars
|
||||
|
||||
// used for v_number in VAR_BOOL and VAR_SPECIAL
|
||||
#define VVAL_FALSE 0L // VAR_BOOL
|
||||
@ -2318,6 +2319,7 @@ typedef enum {
|
||||
CLIPMETHOD_X11,
|
||||
CLIPMETHOD_GUI,
|
||||
CLIPMETHOD_OTHER,
|
||||
CLIPMETHOD_PROVIDER
|
||||
} clipmethod_T;
|
||||
|
||||
// Info about selected text
|
||||
|
||||
Reference in New Issue
Block a user