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:
Foxe Chen
2025-10-14 19:35:17 +00:00
committed by Christian Brabandt
parent 1a09f11f5d
commit 67860efe5b
21 changed files with 851 additions and 22 deletions

31
src/auto/configure vendored
View File

@ -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

View File

@ -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(&reg_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

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 : */

View File

@ -1559,6 +1559,10 @@ do_put(
#ifdef FEAT_CLIPBOARD
// Adjust register name for "unnamed" in 'clipboard'.
adjust_clip_reg(&regname);
# ifdef FEAT_CLIPBOARD_PROVIDER
if (clipmethod == CLIPMETHOD_PROVIDER)
clip_access_type = CLIP_ACCESS_EXPLICIT;
# endif
(void)may_get_selection(regname);
#endif

View File

@ -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 \

View 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

View File

@ -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,
/**/

View File

@ -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