mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.1.1972: No way to access the clipboard without X11/Wayland
Problem: No way to access the clipboard without X11/Wayland. Solution: Add the clipboard provider feature (Foxe Chen). closes: #18781 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
98a0cbf05b
commit
fcd3958dcb
+116
-2
@@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 9.1. Last change: 2025 Dec 01
|
||||
*eval.txt* For Vim version 9.1. Last change: 2025 Dec 11
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -38,6 +38,7 @@ a remark is given.
|
||||
12. The sandbox |eval-sandbox|
|
||||
13. Textlock |textlock|
|
||||
14. Vim script library |vim-script-library|
|
||||
15. Clipboard providers |clipboard-providers|
|
||||
|
||||
Testing support is documented in |testing.txt|.
|
||||
Profiling is documented at |profiling|.
|
||||
@@ -2247,7 +2248,14 @@ v:clipmethod The current method of accessing the clipboard that is being
|
||||
x11 X11 selections are being used.
|
||||
none The above methods are unavailable or
|
||||
cannot be used.
|
||||
See 'clipmethod' for more details.
|
||||
If it is set to a value not in the above list, then a
|
||||
clipboard provider with the given name is being used for the
|
||||
clipboard functionality. See 'clipmethod' for more details.
|
||||
|
||||
*v:clipproviders*
|
||||
v:clipproviders
|
||||
A dictionary containing clipboard providers, see
|
||||
|clipboard-providers| for more information.
|
||||
|
||||
*v:cmdarg* *cmdarg-variable*
|
||||
v:cmdarg This variable is used for two purposes:
|
||||
@@ -5266,5 +5274,111 @@ Usage: >vim
|
||||
:call dist#vim9#Launch(<args>)
|
||||
:Launch <app> <args>.
|
||||
<
|
||||
==============================================================================
|
||||
15. Clipboard providers *clipboard-providers*
|
||||
|
||||
The clipboard provider feature allows the "+" |quoteplus| and "*" |quotestar|
|
||||
registers to be overridden by custom Vimscript functions. There can be
|
||||
multiple providers, and Vim chooses which one to use based on 'clipmethod'.
|
||||
Despite the name, it does not use the 'clipboard' option and should be treated
|
||||
separate from the clipboard functionality. It essentially overrides the
|
||||
existing behaviour of the clipboard registers.
|
||||
|
||||
*clipboard-providers-no-clipboard*
|
||||
If the |+clipboard| feature is not enabled, then the "+" and "*" registers
|
||||
will not be enabled/available unless |v:clipmethod| is set to a provider. If
|
||||
it is set to a provider, then the clipboard registers will be exposed despite
|
||||
not having the |+clipboard| feature.
|
||||
|
||||
*clipboard-providers-plus*
|
||||
If on a platform that only has the "*" register, then the "+" register will
|
||||
only be available when |v:clipmethod| is set to a provider. If you want to
|
||||
check if the "+" is available for use, it can be checked with: >
|
||||
if has('unnamedplus')
|
||||
<
|
||||
*clipboard-providers-clipmethod*
|
||||
To integrate the providers with Vim's clipboard functionality, the
|
||||
'clipmethod' option is used on all platforms. The names of clipboard
|
||||
providers should be put inside the option, and if Vim chooses it, then it
|
||||
overrides the "+" and "*" registers. Note that the "+" and "*" will not be
|
||||
saved in the viminfo at all.
|
||||
|
||||
*clipboard-providers-define*
|
||||
To define a clipboard provider, the |v:clipproviders| vim variable is used. It
|
||||
is a |dict| where each key is the clipboard provider name, and the value is
|
||||
another |dict| declaring the "available", "copy", and "paste" callbacks: >vim
|
||||
let v:clipproviders["myprovider"] = {
|
||||
\ "available": function("Available"),
|
||||
\ "paste": {
|
||||
\ "+": function("Paste"),
|
||||
\ "*": function("Paste")
|
||||
\ },
|
||||
\ "copy": {
|
||||
\ "+": function("Copy"),
|
||||
\ "*": function("Copy")
|
||||
\ }
|
||||
\ }
|
||||
set clipmethod^=myprovider
|
||||
<
|
||||
Each callback can either be a name of a function in a string, a |Funcref|, or
|
||||
a |lambda| expression.
|
||||
|
||||
With the exception of the "available" callback if a callback is not provided,
|
||||
Vim will not invoke anything, and this is not an error.
|
||||
|
||||
*clipboard-providers-textlock*
|
||||
In both the "paste" and "copy" callbacks, it is not allowed to change the
|
||||
buffer text, see |textlock|.
|
||||
|
||||
*clipboard-providers-available*
|
||||
The "available" callback is optional, does not take any arguments and should
|
||||
return a |boolean| or non-zero number, which tells Vim if it is available
|
||||
for use. If it is not, then Vim skips over it and tries the next 'clipmethod'
|
||||
value. If the "available" callback is not provided, Vim assumes the provider
|
||||
is always available for use (true).
|
||||
|
||||
*clipboard-providers-paste*
|
||||
The "paste" callback takes the following arguments in the following order:
|
||||
1. Name of the register being accessed, either "+" or "*".
|
||||
|
||||
It should return a |list| or |tuple| containing the following elements in
|
||||
order:
|
||||
1. Register type (and optional width) conforming to |setreg()|
|
||||
2. A |list| of strings to return to Vim, each representing a line.
|
||||
|
||||
*clipboard-providers-copy*
|
||||
The "copy" callback returns nothing and takes the following arguments in the
|
||||
following order:
|
||||
1. Name of the register being accessed, either "+" or "*".
|
||||
2. Register type conforming to |getregtype()|
|
||||
3. List of strings to use, each representing a line.
|
||||
|
||||
Below is a sample script that makes use of the clipboard provider feature: >vim
|
||||
func Available()
|
||||
return v:true
|
||||
endfunc
|
||||
|
||||
func Copy(reg, type, str)
|
||||
echom "Register: " .. a:reg
|
||||
echom "Register type: " .. a:type
|
||||
echom "Contents: " .. string(a:str)
|
||||
endfunc
|
||||
|
||||
func Paste(reg)
|
||||
return ("b40", ["this", "is", "the", a:reg, "register!"])
|
||||
endfunc
|
||||
|
||||
let v:clipproviders["test"] = {
|
||||
\ "available": function("Available"),
|
||||
\ "copy": {
|
||||
\ "+": function("Copy"),
|
||||
\ "*": function("Copy")
|
||||
\ },
|
||||
\ "paste": {
|
||||
\ "+": function("Paste"),
|
||||
\ "*": function("Paste")
|
||||
\ }
|
||||
\ }
|
||||
set clipmethod^=test
|
||||
<
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
||||
+12
-8
@@ -1,4 +1,4 @@
|
||||
*options.txt* For Vim version 9.1. Last change: 2025 Dec 09
|
||||
*options.txt* For Vim version 9.1. Last change: 2025 Dec 11
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -1912,18 +1912,22 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
for VMS: "x11",
|
||||
otherwise: "")
|
||||
global
|
||||
{only when the |+xterm_clipboard| or
|
||||
|+wayland_clipboard| features are included}
|
||||
Specifies which method of accessing the system clipboard is used,
|
||||
depending on which method works first or is available. Supported
|
||||
methods are:
|
||||
{only when the |+xterm_clipboard|, |+wayland_clipboard|,
|
||||
or |+eval| features are included}
|
||||
Specifies which method of accessing the system clipboard (or clipboard
|
||||
provider) is used. Methods are tried in the order given; the first
|
||||
working method is used. Supported methods are:
|
||||
wayland Wayland selections
|
||||
x11 X11 selections
|
||||
<name> Use a clipboard provider with the given name
|
||||
|
||||
Note: This option is ignored when either the GUI is running or if Vim
|
||||
is run on a system without Wayland or X11 support, such as Windows or
|
||||
macOS. The GUI or system way of accessing the clipboard is always
|
||||
used instead.
|
||||
macOS. The GUI or system way of accessing the clipboard is used
|
||||
instead, meaning |v:clipmethod| will be set to "none". The
|
||||
exception to this is the |clipboard-providers| feature, in which if
|
||||
a clipboard provider is being used, then it will override the existing
|
||||
clipboard functionality.
|
||||
|
||||
The option value is a list of comma separated items. The list is
|
||||
parsed left to right in order, and the first method that Vim
|
||||
|
||||
@@ -1410,6 +1410,7 @@ $quote eval.txt /*$quote*
|
||||
+cindent various.txt /*+cindent*
|
||||
+clientserver various.txt /*+clientserver*
|
||||
+clipboard various.txt /*+clipboard*
|
||||
+clipboard_provider various.txt /*+clipboard_provider*
|
||||
+clipboard_working various.txt /*+clipboard_working*
|
||||
+cmd editing.txt /*+cmd*
|
||||
+cmdline_compl various.txt /*+cmdline_compl*
|
||||
@@ -6692,6 +6693,15 @@ clipboard-autoselectml options.txt /*clipboard-autoselectml*
|
||||
clipboard-autoselectplus options.txt /*clipboard-autoselectplus*
|
||||
clipboard-exclude options.txt /*clipboard-exclude*
|
||||
clipboard-html options.txt /*clipboard-html*
|
||||
clipboard-providers eval.txt /*clipboard-providers*
|
||||
clipboard-providers-available eval.txt /*clipboard-providers-available*
|
||||
clipboard-providers-clipmethod eval.txt /*clipboard-providers-clipmethod*
|
||||
clipboard-providers-copy eval.txt /*clipboard-providers-copy*
|
||||
clipboard-providers-define eval.txt /*clipboard-providers-define*
|
||||
clipboard-providers-no-clipboard eval.txt /*clipboard-providers-no-clipboard*
|
||||
clipboard-providers-paste eval.txt /*clipboard-providers-paste*
|
||||
clipboard-providers-plus eval.txt /*clipboard-providers-plus*
|
||||
clipboard-providers-textlock eval.txt /*clipboard-providers-textlock*
|
||||
clipboard-unnamed options.txt /*clipboard-unnamed*
|
||||
clipboard-unnamedplus options.txt /*clipboard-unnamedplus*
|
||||
clojure-indent indent.txt /*clojure-indent*
|
||||
@@ -11258,6 +11268,7 @@ v:char eval.txt /*v:char*
|
||||
v:charconvert_from eval.txt /*v:charconvert_from*
|
||||
v:charconvert_to eval.txt /*v:charconvert_to*
|
||||
v:clipmethod eval.txt /*v:clipmethod*
|
||||
v:clipproviders eval.txt /*v:clipproviders*
|
||||
v:cmdarg eval.txt /*v:cmdarg*
|
||||
v:cmdbang eval.txt /*v:cmdbang*
|
||||
v:collate eval.txt /*v:collate*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*various.txt* For Vim version 9.1. Last change: 2025 Nov 09
|
||||
*various.txt* For Vim version 9.1. Last change: 2025 Dec 11
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -379,6 +379,7 @@ T *+cindent* 'cindent', C indenting; Always enabled
|
||||
N *+clientserver* Unix and Win32: Remote invocation |clientserver|
|
||||
*+clipboard* |clipboard| support compiled-in
|
||||
*+clipboard_working* |clipboard| support compiled-in and working
|
||||
*+clipboard_provider* |clipboard-providers| support compiled-in
|
||||
T *+cmdline_compl* command line completion |cmdline-completion|
|
||||
T *+cmdline_hist* command line history |cmdline-history|
|
||||
T *+cmdline_info* 'showcmd' and 'ruler'; Always enabled since
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*version9.txt* For Vim version 9.1. Last change: 2025 Dec 10
|
||||
*version9.txt* For Vim version 9.1. Last change: 2025 Dec 11
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -41653,6 +41653,8 @@ Other new features ~
|
||||
|
||||
- |items()| function now supports Blob.
|
||||
|
||||
- The clipboard provider feature has been added |clipboard-providers|.
|
||||
|
||||
*changed-9.2*
|
||||
Changed~
|
||||
-------
|
||||
@@ -41907,6 +41909,8 @@ Options: ~
|
||||
|
||||
Vim Variables: ~
|
||||
|v:clipmethod| The current 'clipmethod'.
|
||||
|v:clipproviders| A dictionary containing clipboard providers
|
||||
configuration |clipboard-providers|.
|
||||
|v:stacktrace| The most recent caught exception.
|
||||
|v:t_enumvalue| Value of |enumvalue|.
|
||||
|v:t_enum| Value of |enum| type.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
" Language: Vim script
|
||||
" Maintainer: Hirohito Higashi <h.east.727 ATMARK gmail.com>
|
||||
" Doug Kearns <dougkearns@gmail.com>
|
||||
" Last Change: 2025 Dec 04
|
||||
" Last Change: 2025 Dec 11
|
||||
" Former Maintainer: Charles E. Campbell
|
||||
|
||||
" DO NOT CHANGE DIRECTLY.
|
||||
@@ -166,7 +166,7 @@ syn keyword vimFuncName contained win_findbuf win_getid win_gettype win_gotoid w
|
||||
" Predefined variable names {{{2
|
||||
" GEN_SYN_VIM: vimVarName, START_STR='syn keyword vimVimVarName contained', END_STR=''
|
||||
syn keyword vimVimVarName contained count count1 prevcount errmsg warningmsg statusmsg shell_error this_session version lnum termresponse fname lang lc_time ctype charconvert_from charconvert_to fname_in fname_out fname_new fname_diff cmdarg foldstart foldend folddashes foldlevel progname servername dying exception throwpoint register cmdbang insertmode val key profiling fcs_reason fcs_choice beval_bufnr beval_winnr beval_winid beval_lnum beval_col beval_text scrollstart swapname swapchoice swapcommand char mouse_win mouse_winid mouse_lnum mouse_col operator searchforward hlsearch oldfiles windowid progpath completed_item option_new option_old option_oldlocal option_oldglobal option_command option_type errors false true none null numbermax numbermin numbersize
|
||||
syn keyword vimVimVarName contained vim_did_enter testing t_number t_string t_func t_list t_dict t_float t_bool t_none t_job t_channel t_blob t_class t_object termrfgresp termrbgresp termu7resp termstyleresp termblinkresp event versionlong echospace argv collate exiting colornames sizeofint sizeoflong sizeofpointer maxcol python3_version t_typealias t_enum t_enumvalue stacktrace t_tuple wayland_display clipmethod termda1 termosc vim_did_init
|
||||
syn keyword vimVimVarName contained vim_did_enter testing t_number t_string t_func t_list t_dict t_float t_bool t_none t_job t_channel t_blob t_class t_object termrfgresp termrbgresp termu7resp termstyleresp termblinkresp event versionlong echospace argv collate exiting colornames sizeofint sizeoflong sizeofpointer maxcol python3_version t_typealias t_enum t_enumvalue stacktrace t_tuple wayland_display clipmethod termda1 termosc vim_did_init clipproviders
|
||||
|
||||
"--- syntax here and above generated by runtime/syntax/generator/gen_syntax_vim.vim ---
|
||||
|
||||
|
||||
+458
-14
@@ -8,7 +8,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* clipboard.c: Functions to handle the clipboard
|
||||
* clipboard.c: Functions to handle the clipboard. Additionally contains the
|
||||
* clipboard provider code, which is separate from the main
|
||||
* clipboard code.
|
||||
*/
|
||||
|
||||
#include "vim.h"
|
||||
@@ -29,6 +31,11 @@
|
||||
// versions of these for the 'clipboard' selection, as Visual mode has no use
|
||||
// for them.
|
||||
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
static int clip_provider_is_available(char_u *provider);
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_CLIPBOARD)
|
||||
|
||||
#if defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
@@ -3415,6 +3422,9 @@ clip_wl_owner_exists(Clipboard_T *cbd)
|
||||
|
||||
#endif // FEAT_WAYLAND_CLIPBOARD
|
||||
|
||||
#endif // FEAT_CLIPBOARD
|
||||
|
||||
#ifdef HAVE_CLIPMETHOD
|
||||
|
||||
/*
|
||||
* Returns the first method for accessing the clipboard that is available/works,
|
||||
@@ -3473,8 +3483,30 @@ get_clipmethod(char_u *str)
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = CLIPMETHOD_FAIL;
|
||||
goto exit;
|
||||
#ifdef FEAT_EVAL
|
||||
// Check if name matches a clipboard provider
|
||||
int r = clip_provider_is_available(buf);
|
||||
|
||||
if (r == 1)
|
||||
{
|
||||
method = CLIPMETHOD_PROVIDER;
|
||||
if (ret == CLIPMETHOD_FAIL)
|
||||
{
|
||||
vim_free(clip_provider);
|
||||
clip_provider = vim_strsave(buf);
|
||||
if (clip_provider == NULL)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else if (r == -1)
|
||||
#endif
|
||||
{
|
||||
#ifdef FEAT_EVAL
|
||||
fail:
|
||||
#endif
|
||||
ret = CLIPMETHOD_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep on going in order to catch errors
|
||||
@@ -3494,17 +3526,21 @@ exit:
|
||||
/*
|
||||
* Returns name of clipmethod in a statically allocated string.
|
||||
*/
|
||||
static char *
|
||||
static char_u *
|
||||
clipmethod_to_str(clipmethod_T method)
|
||||
{
|
||||
switch(method)
|
||||
{
|
||||
case CLIPMETHOD_WAYLAND:
|
||||
return "wayland";
|
||||
return (char_u *)"wayland";
|
||||
case CLIPMETHOD_X11:
|
||||
return "x11";
|
||||
return (char_u *)"x11";
|
||||
case CLIPMETHOD_PROVIDER:
|
||||
#ifdef FEAT_EVAL
|
||||
return clip_provider;
|
||||
#endif
|
||||
default:
|
||||
return "none";
|
||||
return (char_u *)"none";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3522,9 +3558,10 @@ choose_clipmethod(void)
|
||||
|
||||
// If GUI is running or we are not on a system with Wayland or X11, then always
|
||||
// return CLIPMETHOD_NONE. System or GUI clipboard handling always overrides.
|
||||
// This is unless a provider is being used.
|
||||
#if defined(FEAT_XCLIPBOARD) || defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
# if defined(FEAT_GUI)
|
||||
if (gui.in_use)
|
||||
if (method != CLIPMETHOD_PROVIDER && gui.in_use)
|
||||
{
|
||||
# ifdef FEAT_WAYLAND
|
||||
// We only interact with Wayland for the clipboard, we can just deinit
|
||||
@@ -3538,19 +3575,26 @@ choose_clipmethod(void)
|
||||
# endif
|
||||
#else
|
||||
// If on a system like windows or macos, then clipmethod is irrelevant, we
|
||||
// use their way of accessing the clipboard.
|
||||
method = CLIPMETHOD_NONE;
|
||||
goto exit;
|
||||
// use their way of accessing the clipboard. This is unless we are using the
|
||||
// clipboard provider
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
if (method != CLIPMETHOD_PROVIDER)
|
||||
#endif
|
||||
{
|
||||
method = CLIPMETHOD_NONE;
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// Deinitialize clipboard if there is no way to access clipboard
|
||||
if (method == CLIPMETHOD_NONE)
|
||||
clip_init(FALSE);
|
||||
// If we have a clipmethod that works now, then initialize clipboard
|
||||
else if (clipmethod == CLIPMETHOD_NONE && method != CLIPMETHOD_NONE)
|
||||
{
|
||||
clip_init(TRUE);
|
||||
did_warn_clipboard = false;
|
||||
clip_init(TRUE);
|
||||
did_warn_clipboard = false;
|
||||
}
|
||||
// Disown clipboard if we are switching to a new method
|
||||
else if (clipmethod != CLIPMETHOD_NONE && method != clipmethod)
|
||||
@@ -3572,6 +3616,7 @@ lose_sel_exit:
|
||||
did_warn_clipboard = false;
|
||||
}
|
||||
}
|
||||
#endif // FEAT_CLIPBOARD
|
||||
|
||||
#if !defined(FEAT_XCLIPBOARD) && !defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
exit:
|
||||
@@ -3603,4 +3648,403 @@ ex_clipreset(exarg_T *eap UNUSED)
|
||||
clipmethod_to_str(clipmethod));
|
||||
}
|
||||
|
||||
#endif // FEAT_CLIPBOARD
|
||||
#endif // HAVE_CLIPMETHOD
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
|
||||
/*
|
||||
* Check if a clipboard provider with given name is available. Returns 1 if available,
|
||||
* 0 if not available, and -1 on error
|
||||
*/
|
||||
static int
|
||||
clip_provider_is_available(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};
|
||||
int res = 0;
|
||||
|
||||
if (dict_get_tv(providers, (char *)provider, &provider_tv) == FAIL
|
||||
|| provider_tv.v_type != VAR_DICT)
|
||||
// clipboard provider not defined
|
||||
return -1;
|
||||
|
||||
if (dict_get_tv(provider_tv.vval.v_dict, "available", &func_tv) == FAIL)
|
||||
{
|
||||
clear_tv(&provider_tv);
|
||||
// If "available" function 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_BOOL && rettv.v_type != VAR_NUMBER))
|
||||
goto fail;
|
||||
|
||||
if (rettv.vval.v_number)
|
||||
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 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_copy(char_u *reg, char_u *provider)
|
||||
{
|
||||
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;
|
||||
|
||||
// Convert register type into a string
|
||||
if (*reg == '+')
|
||||
y_ptr = get_y_register(REAL_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_paste(char_u *reg, char_u *provider)
|
||||
{
|
||||
callback_T callback;
|
||||
typval_T argvars[2];
|
||||
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_UNKNOWN;
|
||||
|
||||
textlock++;
|
||||
ret = call_callback(&callback, -1, &rettv, 1, argvars);
|
||||
textlock--;
|
||||
|
||||
if (ret == FAIL)
|
||||
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, *cur_y_ptr;
|
||||
char_u **lstval;
|
||||
char_u **allocval;
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u **curval;
|
||||
char_u **curallocval;
|
||||
char_u *strval;
|
||||
listitem_T *li;
|
||||
int len;
|
||||
|
||||
// If the list is NULL handle like an empty list.
|
||||
len = lines == NULL ? 0 : lines->lv_len;
|
||||
|
||||
// First half: use for pointers to result lines; second half: use for
|
||||
// pointers to allocated copies.
|
||||
lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
|
||||
if (lstval == NULL)
|
||||
goto exit;
|
||||
curval = lstval;
|
||||
allocval = lstval + len + 2;
|
||||
curallocval = allocval;
|
||||
|
||||
if (lines != NULL)
|
||||
{
|
||||
CHECK_LIST_MATERIALIZE(lines);
|
||||
FOR_ALL_LIST_ITEMS(lines, li)
|
||||
{
|
||||
strval = tv_get_string_buf_chk(&li->li_tv, buf);
|
||||
if (strval == NULL)
|
||||
goto free_lstval;
|
||||
if (strval == buf)
|
||||
{
|
||||
// Need to make a copy, next tv_get_string_buf_chk() will
|
||||
// overwrite the string.
|
||||
strval = vim_strsave(buf);
|
||||
if (strval == NULL)
|
||||
goto free_lstval;
|
||||
*curallocval++ = strval;
|
||||
}
|
||||
*curval++ = strval;
|
||||
}
|
||||
}
|
||||
*curval++ = NULL;
|
||||
|
||||
if (STRLEN(reg_type) <= 0
|
||||
|| get_yank_type(®_type, &yank_type, &block_len) == FAIL)
|
||||
{
|
||||
emsg(e_invalid_argument);
|
||||
goto free_lstval;
|
||||
}
|
||||
|
||||
if (*reg == '+')
|
||||
y_ptr = get_y_register(REAL_PLUS_REGISTER);
|
||||
else
|
||||
y_ptr = get_y_register(STAR_REGISTER);
|
||||
|
||||
// Free previous register contents
|
||||
cur_y_ptr = get_y_current();
|
||||
set_y_current(y_ptr);
|
||||
|
||||
free_yank_all();
|
||||
get_y_current()->y_size = 0;
|
||||
|
||||
set_y_current(cur_y_ptr);
|
||||
|
||||
str_to_reg(y_ptr,
|
||||
yank_type,
|
||||
(char_u *)lstval,
|
||||
-1,
|
||||
block_len,
|
||||
TRUE);
|
||||
|
||||
free_lstval:
|
||||
while (curallocval > allocval)
|
||||
vim_free(*--curallocval);
|
||||
vim_free(lstval);
|
||||
}
|
||||
|
||||
exit:
|
||||
free_callback(&callback);
|
||||
clear_tv(&rettv);
|
||||
}
|
||||
|
||||
// Used to stop calling the provider callback every time there is an update.
|
||||
// This prevents unnecessary calls when accessing the provider often in an
|
||||
// interval.
|
||||
//
|
||||
// If -1 then allow provider callback to be called then set to zero. Default
|
||||
// value (is allowed) is -2.
|
||||
static int star_pause_count = -2, plus_pause_count = -2;
|
||||
|
||||
void
|
||||
call_clip_provider_request(int reg)
|
||||
{
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
return;
|
||||
|
||||
if (reg == '+' && plus_pause_count < 0)
|
||||
{
|
||||
if (plus_pause_count == -1)
|
||||
plus_pause_count = 1;
|
||||
clip_provider_paste((char_u *)"+", clip_provider);
|
||||
}
|
||||
else if (reg == '*' && star_pause_count < 0)
|
||||
{
|
||||
if (star_pause_count == -1)
|
||||
star_pause_count = 1;
|
||||
clip_provider_paste((char_u *)"*", clip_provider);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
call_clip_provider_set(int reg)
|
||||
{
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
return;
|
||||
|
||||
if (reg == '+' && plus_pause_count < 0)
|
||||
{
|
||||
if (plus_pause_count == -1)
|
||||
plus_pause_count = 1;
|
||||
clip_provider_copy((char_u *)"+", clip_provider);
|
||||
}
|
||||
else if (reg == '*' && star_pause_count < 0)
|
||||
{
|
||||
if (star_pause_count == -1)
|
||||
star_pause_count = 1;
|
||||
clip_provider_copy((char_u *)"*", clip_provider);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes it so that the next provider call is only done once any calls after are
|
||||
* ignored, until dec_clip_provider is called the same number of times after
|
||||
* again. Note that this is per clipboard register ("+", "*")
|
||||
*/
|
||||
void
|
||||
inc_clip_provider(void)
|
||||
{
|
||||
plus_pause_count = plus_pause_count == -2 ? -1 : plus_pause_count + 1;
|
||||
star_pause_count = star_pause_count == -2 ? -1 : star_pause_count + 1;
|
||||
}
|
||||
|
||||
void
|
||||
dec_clip_provider(void)
|
||||
{
|
||||
plus_pause_count = plus_pause_count == -1 ? -1 : plus_pause_count - 1;
|
||||
star_pause_count = star_pause_count == -1 ? -1 : star_pause_count - 1;
|
||||
|
||||
if (plus_pause_count == 0 || plus_pause_count == -1)
|
||||
plus_pause_count = -2;
|
||||
if (star_pause_count == 0 || star_pause_count == -1)
|
||||
star_pause_count = -2;
|
||||
}
|
||||
|
||||
#endif // FEAT_CLIPBOARD_PROVIDER
|
||||
|
||||
+29
-10
@@ -6866,6 +6866,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},
|
||||
@@ -7563,14 +7570,6 @@ f_has(typval_T *argvars, typval_T *rettv)
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
},
|
||||
{"unnamedplus",
|
||||
#if defined(FEAT_CLIPBOARD) && (defined(FEAT_X11) \
|
||||
|| defined(FEAT_WAYLAND_CLIPBOARD))
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
},
|
||||
{"user-commands", 1}, // was accidentally included in 5.4
|
||||
@@ -7918,7 +7917,27 @@ f_has(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
x = TRUE;
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
n = clip_star.available;
|
||||
n = clipmethod == CLIPMETHOD_PROVIDER ? TRUE : clip_star.available;
|
||||
#endif
|
||||
}
|
||||
else if (STRICMP(name, "unnamedplus") == 0)
|
||||
{
|
||||
x = TRUE;
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// The + register is available when clipmethod is set to a provider,
|
||||
// but becomes unavailable if on a platform that doesn't support it
|
||||
// and clipmethod is "none".
|
||||
// (Windows, MacOS).
|
||||
# if defined(FEAT_X11) || defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
n = TRUE;
|
||||
# elif defined(FEAT_EVAL)
|
||||
if (clipmethod == CLIPMETHOD_PROVIDER)
|
||||
n = TRUE;
|
||||
else
|
||||
n = FALSE;
|
||||
# else
|
||||
n = FALSE;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -11493,7 +11512,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;
|
||||
|
||||
@@ -168,6 +168,7 @@ static struct vimvar
|
||||
{VV_NAME("termda1", VAR_STRING), NULL, VV_RO},
|
||||
{VV_NAME("termosc", VAR_STRING), NULL, VV_RO},
|
||||
{VV_NAME("vim_did_init", VAR_NUMBER), NULL, VV_RO},
|
||||
{VV_NAME("clipproviders", VAR_DICT), NULL, VV_RO},
|
||||
};
|
||||
|
||||
// shorthand
|
||||
|
||||
@@ -5489,12 +5489,18 @@ ex_global(exarg_T *eap)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
inc_clip_provider();
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
start_global_changes();
|
||||
#endif
|
||||
global_exe(cmd);
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
end_global_changes();
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
dec_clip_provider();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -536,6 +536,9 @@ ex_listdo(exarg_T *eap)
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
start_global_changes();
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
inc_clip_provider();
|
||||
#endif
|
||||
|
||||
if (eap->cmdidx == CMD_windo
|
||||
|| eap->cmdidx == CMD_tabdo
|
||||
@@ -760,6 +763,9 @@ ex_listdo(exarg_T *eap)
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
end_global_changes();
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
dec_clip_provider();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
|
||||
+8
-2
@@ -375,7 +375,7 @@ static void ex_folddo(exarg_T *eap);
|
||||
#if !defined(FEAT_WAYLAND)
|
||||
# define ex_wlrestore ex_ni
|
||||
#endif
|
||||
#if !defined(FEAT_CLIPBOARD)
|
||||
#if !defined(HAVE_CLIPMETHOD)
|
||||
# define ex_clipreset ex_ni
|
||||
#endif
|
||||
#if !defined(FEAT_PROP_POPUP)
|
||||
@@ -2372,7 +2372,7 @@ do_one_cmd(
|
||||
&& (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=')
|
||||
&& !((ea.argt & EX_COUNT) && VIM_ISDIGIT(*ea.arg)))
|
||||
{
|
||||
#ifndef FEAT_CLIPBOARD
|
||||
#if !defined(FEAT_CLIPBOARD) && !defined(FEAT_CLIPBOARD_PROVIDER)
|
||||
// check these explicitly for a more specific error message
|
||||
if (*ea.arg == '*' || *ea.arg == '+')
|
||||
{
|
||||
@@ -10404,6 +10404,9 @@ ex_folddo(exarg_T *eap)
|
||||
# ifdef FEAT_CLIPBOARD
|
||||
start_global_changes();
|
||||
# endif
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
inc_clip_provider();
|
||||
#endif
|
||||
|
||||
// First set the marks for all lines closed/open.
|
||||
for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
|
||||
@@ -10416,6 +10419,9 @@ ex_folddo(exarg_T *eap)
|
||||
# ifdef FEAT_CLIPBOARD
|
||||
end_global_changes();
|
||||
# endif
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
dec_clip_provider();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+6
-1
@@ -993,6 +993,11 @@ EXTERN regprog_T *clip_exclude_prog INIT(= NULL);
|
||||
EXTERN int clip_unnamed_saved INIT(= 0);
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
EXTERN char_u *clip_provider INIT(= NULL);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* All regular windows are linked in a list. "firstwin" points to the first
|
||||
* entry, "lastwin" to the last entry (can be the same as firstwin) and
|
||||
@@ -2070,7 +2075,7 @@ EXTERN int p_tgc_set INIT(= FALSE);
|
||||
// If we've already warned about missing/unavailable clipboard
|
||||
EXTERN bool did_warn_clipboard INIT(= FALSE);
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
#ifdef HAVE_CLIPMETHOD
|
||||
EXTERN clipmethod_T clipmethod INIT(= CLIPMETHOD_NONE);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -146,9 +146,11 @@ gui_start(char_u *arg UNUSED)
|
||||
emsg(msg);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_CLIPMETHOD
|
||||
else
|
||||
// Reset clipmethod to CLIPMETHOD_NONE
|
||||
choose_clipmethod();
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_SOCKETSERVER
|
||||
// Install socket server listening socket if we are running it
|
||||
|
||||
+1
-1
@@ -704,7 +704,7 @@ vim_main2(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
#ifdef HAVE_CLIPMETHOD
|
||||
choose_clipmethod();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -507,6 +507,8 @@ EXTERN char_u *p_cedit; // 'cedit'
|
||||
EXTERN long p_cwh; // 'cmdwinheight'
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
EXTERN char_u *p_cb; // 'clipboard'
|
||||
#endif
|
||||
#ifdef HAVE_CLIPMETHOD
|
||||
EXTERN char_u *p_cpm; // 'clipmethod'
|
||||
#endif
|
||||
EXTERN long p_ch; // 'cmdheight'
|
||||
|
||||
+1
-1
@@ -632,7 +632,7 @@ static struct vimoption options[] =
|
||||
#endif
|
||||
SCTX_INIT},
|
||||
{"clipmethod", "cpm", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
#ifdef HAVE_CLIPMETHOD
|
||||
(char_u *)&p_cpm, PV_NONE, did_set_clipmethod, expand_set_clipmethod,
|
||||
# ifdef UNIX
|
||||
{(char_u *)"wayland,x11", (char_u *)0L}
|
||||
|
||||
+54
-5
@@ -44,8 +44,6 @@ static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// Note: Keep this in sync with did_set_clipboard()
|
||||
static char *(p_cb_values[]) = {"unnamed", "unnamedplus", "autoselect", "autoselectplus", "autoselectml", "html", "exclude:", NULL};
|
||||
// Note: Keep this in sync with get_clipmethod()
|
||||
static char *(p_cpm_values[]) = {"wayland", "x11", NULL};
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
|
||||
@@ -1402,7 +1400,9 @@ expand_set_clipboard(optexpand_T *args, int *numMatches, char_u ***matches)
|
||||
numMatches,
|
||||
matches);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CLIPMETHOD
|
||||
char *
|
||||
did_set_clipmethod(optset_T *args UNUSED)
|
||||
{
|
||||
@@ -1412,12 +1412,61 @@ did_set_clipmethod(optset_T *args UNUSED)
|
||||
int
|
||||
expand_set_clipmethod(optexpand_T *args, int *numMatches, char_u ***matches)
|
||||
{
|
||||
return expand_set_opt_string(
|
||||
// We want to expand using the predefined clipmethod values + clipboard
|
||||
// provider names.
|
||||
int result;
|
||||
char **values;
|
||||
int count, pos = 0, start = 0;
|
||||
#ifdef FEAT_EVAL
|
||||
dict_T *providers = get_vim_var_dict(VV_CLIPPROVIDERS);
|
||||
#else
|
||||
dict_T *providers = NULL;
|
||||
#endif
|
||||
hashtab_T *ht = providers == NULL ? NULL : &providers->dv_hashtab;
|
||||
|
||||
count = (ht == NULL ? 0 : ht->ht_used);
|
||||
#ifdef FEAT_WAYLAND_CLIPBOARD
|
||||
count++;
|
||||
start++;
|
||||
#endif
|
||||
#ifdef FEAT_XCLIPBOARD
|
||||
count++;
|
||||
start++;
|
||||
#endif
|
||||
values = ALLOC_MULT(char *, count + 1); // Add NULL terminator too
|
||||
|
||||
if (values == NULL)
|
||||
return FAIL;
|
||||
|
||||
#ifdef FEAT_WAYLAND_CLIPBOARD
|
||||
values[pos++] = "wayland";
|
||||
#endif
|
||||
#ifdef FEAT_XCLIPBOARD
|
||||
values[pos++] = "x11";
|
||||
#endif
|
||||
|
||||
if (ht != NULL)
|
||||
for (long_u i = 0; i < ht->ht_mask + 1; i++)
|
||||
{
|
||||
hashitem_T *hi = ht->ht_array + i;
|
||||
|
||||
if (!HASHITEM_EMPTY(hi))
|
||||
values[pos++] = (char *)vim_strsave(hi->hi_key);
|
||||
}
|
||||
values[pos++] = NULL;
|
||||
|
||||
result = expand_set_opt_string(
|
||||
args,
|
||||
p_cpm_values,
|
||||
ARRAY_LENGTH(p_cpm_values) - 1,
|
||||
values,
|
||||
count,
|
||||
numMatches,
|
||||
matches);
|
||||
|
||||
for (int i = start; i < count; i++)
|
||||
vim_free(values[i]);
|
||||
vim_free(values);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -40,4 +40,8 @@ void clip_uninit_wayland(void);
|
||||
int clip_reset_wayland(void);
|
||||
char *choose_clipmethod(void);
|
||||
void ex_clipreset(exarg_T *eap);
|
||||
void call_clip_provider_request(int reg);
|
||||
void call_clip_provider_set(int reg);
|
||||
void inc_clip_provider(void);
|
||||
void dec_clip_provider(void);
|
||||
/* vim: set ft=c : */
|
||||
|
||||
@@ -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 : */
|
||||
|
||||
+152
-59
@@ -46,7 +46,7 @@ get_y_regs(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_CLIPBOARD)
|
||||
#if defined(FEAT_CLIPBOARD) || defined(FEAT_CLIPBOARD_PROVIDER)
|
||||
yankreg_T *
|
||||
get_y_register(int reg)
|
||||
{
|
||||
@@ -190,9 +190,17 @@ valid_yank_reg(
|
||||
|| regname == '"'
|
||||
|| regname == '-'
|
||||
|| regname == '_'
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
#if defined(FEAT_CLIPBOARD) // If +clipboard is enabled, then these registers
|
||||
// always exist.
|
||||
|| regname == '*'
|
||||
|| regname == '+'
|
||||
#elif defined(FEAT_CLIPBOARD_PROVIDER)
|
||||
|| ( // If -clipboard, then these registers only exist when
|
||||
// clipmethod is set to provider.
|
||||
clipmethod == CLIPMETHOD_PROVIDER && (
|
||||
regname == '*'
|
||||
|| regname == '+'
|
||||
))
|
||||
#endif
|
||||
#ifdef FEAT_DND
|
||||
|| (!writing && regname == '~')
|
||||
@@ -256,7 +264,25 @@ get_yank_register(int regname, int writing)
|
||||
// When clipboard is not available, use register 0 instead of '+'
|
||||
else if (clip_plus.available && regname == '+')
|
||||
{
|
||||
i = PLUS_REGISTER;
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
// We want to use the actual + register, since PLUS_REGISTER may be
|
||||
// pointing to STAR_REGISTER.
|
||||
if (clipmethod == CLIPMETHOD_PROVIDER)
|
||||
i = REAL_PLUS_REGISTER;
|
||||
else
|
||||
#endif
|
||||
i = PLUS_REGISTER;
|
||||
ret = TRUE;
|
||||
}
|
||||
#elif defined(FEAT_CLIPBOARD_PROVIDER)
|
||||
else if (regname == '*')
|
||||
{
|
||||
i = STAR_REGISTER;
|
||||
ret = TRUE;
|
||||
}
|
||||
else if (regname == '+')
|
||||
{
|
||||
i = REAL_PLUS_REGISTER;
|
||||
ret = TRUE;
|
||||
}
|
||||
#endif
|
||||
@@ -284,20 +310,26 @@ get_register(
|
||||
yankreg_T *reg;
|
||||
int i;
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_request(name);
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// When Visual area changed, may have to update selection. Obtain the
|
||||
// selection too.
|
||||
if (name == '*' && clip_star.available)
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
{
|
||||
if (clip_isautosel_star())
|
||||
clip_update_selection(&clip_star);
|
||||
may_get_selection(name);
|
||||
}
|
||||
if (name == '+' && clip_plus.available)
|
||||
{
|
||||
if (clip_isautosel_plus())
|
||||
clip_update_selection(&clip_plus);
|
||||
may_get_selection(name);
|
||||
// When Visual area changed, may have to update selection. Obtain the
|
||||
// selection too.
|
||||
if (name == '*' && clip_star.available)
|
||||
{
|
||||
if (clip_isautosel_star())
|
||||
clip_update_selection(&clip_star);
|
||||
may_get_selection(name);
|
||||
}
|
||||
if (name == '+' && clip_plus.available)
|
||||
{
|
||||
if (clip_isautosel_plus())
|
||||
clip_update_selection(&clip_plus);
|
||||
may_get_selection(name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -615,8 +647,12 @@ do_execreg(
|
||||
}
|
||||
execreg_lastc = regname;
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_request(regname);
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
regname = may_get_selection(regname);
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
regname = may_get_selection(regname);
|
||||
#endif
|
||||
|
||||
// black hole: don't stuff anything
|
||||
@@ -823,8 +859,12 @@ insert_reg(
|
||||
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
||||
return FAIL;
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_request(regname);
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
regname = may_get_selection(regname);
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
regname = may_get_selection(regname);
|
||||
#endif
|
||||
|
||||
if (regname == '.') // insert last inserted text
|
||||
@@ -1379,39 +1419,49 @@ op_yank(oparg_T *oap, int deleting, int mess)
|
||||
decl(&curbuf->b_op_end);
|
||||
}
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// If we were yanking to the '*' register, send result to clipboard.
|
||||
// If no register was specified, and "unnamed" in 'clipboard', make a copy
|
||||
// to the '*' register.
|
||||
if (clip_star.available
|
||||
&& (curr == &(y_regs[STAR_REGISTER])
|
||||
|| (!deleting && oap->regname == 0
|
||||
&& ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
|
||||
{
|
||||
if (curr != &(y_regs[STAR_REGISTER]))
|
||||
// Copy the text from register 0 to the clipboard register.
|
||||
copy_yank_reg(&(y_regs[STAR_REGISTER]));
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
if (curr == &y_regs[REAL_PLUS_REGISTER])
|
||||
call_clip_provider_set('+');
|
||||
else if (curr == &y_regs[STAR_REGISTER])
|
||||
call_clip_provider_set('*');
|
||||
#endif
|
||||
|
||||
clip_own_selection(&clip_star);
|
||||
clip_gen_set_selection(&clip_star);
|
||||
}
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
{
|
||||
// If we were yanking to the '*' register, send result to clipboard. If
|
||||
// no register was specified, and "unnamed" in 'clipboard', make a copy
|
||||
// to the '*' register.
|
||||
if (clip_star.available
|
||||
&& (curr == &(y_regs[STAR_REGISTER])
|
||||
|| (!deleting && oap->regname == 0
|
||||
&& ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
|
||||
{
|
||||
if (curr != &(y_regs[STAR_REGISTER]))
|
||||
// Copy the text from register 0 to the clipboard register.
|
||||
copy_yank_reg(&(y_regs[STAR_REGISTER]));
|
||||
|
||||
clip_own_selection(&clip_star);
|
||||
clip_gen_set_selection(&clip_star);
|
||||
}
|
||||
|
||||
# if defined(FEAT_X11) || defined(FEAT_WAYLAND_CLIPBOARD)
|
||||
// If we were yanking to the '+' register, send result to selection.
|
||||
if (clip_plus.available
|
||||
&& (curr == &(y_regs[PLUS_REGISTER])
|
||||
|| (!deleting && oap->regname == 0
|
||||
&& ((clip_unnamed | clip_unnamed_saved) &
|
||||
CLIP_UNNAMED_PLUS))))
|
||||
{
|
||||
if (curr != &(y_regs[PLUS_REGISTER]))
|
||||
// Copy the text from register 0 to the clipboard register.
|
||||
copy_yank_reg(&(y_regs[PLUS_REGISTER]));
|
||||
// If we were yanking to the '+' register, send result to selection.
|
||||
if (clip_plus.available
|
||||
&& (curr == &(y_regs[PLUS_REGISTER])
|
||||
|| (!deleting && oap->regname == 0
|
||||
&& ((clip_unnamed | clip_unnamed_saved) &
|
||||
CLIP_UNNAMED_PLUS))))
|
||||
{
|
||||
if (curr != &(y_regs[PLUS_REGISTER]))
|
||||
// Copy the text from register 0 to the clipboard register.
|
||||
copy_yank_reg(&(y_regs[PLUS_REGISTER]));
|
||||
|
||||
clip_own_selection(&clip_plus);
|
||||
clip_gen_set_selection(&clip_plus);
|
||||
}
|
||||
clip_own_selection(&clip_plus);
|
||||
clip_gen_set_selection(&clip_plus);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_EVAL)
|
||||
@@ -1535,11 +1585,18 @@ do_put(
|
||||
pos_T orig_end = curbuf->b_op_end;
|
||||
unsigned int cur_ve_flags = get_ve_flags();
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// Adjust register name for "unnamed" in 'clipboard'.
|
||||
adjust_clip_reg(®name);
|
||||
(void)may_get_selection(regname);
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_request(regname);
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
{
|
||||
// Adjust register name for "unnamed" in 'clipboard'.
|
||||
adjust_clip_reg(®name);
|
||||
(void)may_get_selection(regname);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
|
||||
curbuf->b_op_end = curwin->w_cursor; // default for '] mark
|
||||
@@ -2326,10 +2383,16 @@ get_register_name(int num)
|
||||
return num + '0';
|
||||
else if (num == DELETION_REGISTER)
|
||||
return '-';
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
#if defined(FEAT_CLIPBOARD) || defined(FEAT_CLIPBOARD_PROVIDER)
|
||||
else if (num == STAR_REGISTER)
|
||||
return '*';
|
||||
else if (num == PLUS_REGISTER)
|
||||
// If there is only one clipboard, we only want the plus register to point
|
||||
// to the star register if the clipboard provider is not being used. If the
|
||||
// clipboard provider is being used, then both registers should be available
|
||||
// no matter the platform
|
||||
else if (clipmethod == CLIPMETHOD_PROVIDER && num == REAL_PLUS_REGISTER)
|
||||
return '+';
|
||||
else if (clipmethod != CLIPMETHOD_PROVIDER && num == PLUS_REGISTER)
|
||||
return '+';
|
||||
#endif
|
||||
else
|
||||
@@ -2368,6 +2431,10 @@ ex_display(exarg_T *eap)
|
||||
arg = NULL;
|
||||
attr = HL_ATTR(HLF_8);
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
inc_clip_provider();
|
||||
#endif
|
||||
|
||||
// Highlight title
|
||||
msg_puts_title(_("\nType Name Content"));
|
||||
for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
|
||||
@@ -2381,18 +2448,24 @@ ex_display(exarg_T *eap)
|
||||
}
|
||||
if (arg != NULL && vim_strchr(arg, name) == NULL
|
||||
#ifdef ONE_CLIPBOARD
|
||||
// Star register and plus register contain the same thing.
|
||||
// Star register and plus register contain the same thing.
|
||||
&& (name != '*' || vim_strchr(arg, '+') == NULL)
|
||||
#endif
|
||||
)
|
||||
continue; // did not ask for this register
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_request(name);
|
||||
#endif
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
// Adjust register name for "unnamed" in 'clipboard'.
|
||||
// When it's a clipboard register, fill it with the current contents
|
||||
// of the clipboard.
|
||||
adjust_clip_reg(&name);
|
||||
(void)may_get_selection(name);
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
{
|
||||
// Adjust register name for "unnamed" in 'clipboard'.
|
||||
// When it's a clipboard register, fill it with the current contents
|
||||
// of the clipboard.
|
||||
adjust_clip_reg(&name);
|
||||
(void)may_get_selection(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i == -1)
|
||||
@@ -2513,6 +2586,10 @@ ex_display(exarg_T *eap)
|
||||
dis_msg(expr_line, FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
dec_clip_provider();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2585,8 +2662,12 @@ get_reg_type(int regname, long *reglen)
|
||||
return MCHAR;
|
||||
}
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_request(regname);
|
||||
#endif
|
||||
# ifdef FEAT_CLIPBOARD
|
||||
regname = may_get_selection(regname);
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
regname = may_get_selection(regname);
|
||||
# endif
|
||||
|
||||
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
||||
@@ -2664,8 +2745,12 @@ get_reg_contents(int regname, int flags)
|
||||
if (regname != NUL && !valid_yank_reg(regname, FALSE))
|
||||
return NULL;
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_request(regname);
|
||||
#endif
|
||||
# ifdef FEAT_CLIPBOARD
|
||||
regname = may_get_selection(regname);
|
||||
if (clipmethod != CLIPMETHOD_PROVIDER)
|
||||
regname = may_get_selection(regname);
|
||||
# endif
|
||||
|
||||
if (get_spec_reg(regname, &retval, &allocated, FALSE))
|
||||
@@ -2830,6 +2915,10 @@ write_reg_contents_lst(
|
||||
str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
|
||||
|
||||
finish_write_reg(name, old_y_previous, old_y_current);
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_set(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2904,6 +2993,10 @@ write_reg_contents_ex(
|
||||
str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
|
||||
|
||||
finish_write_reg(name, old_y_previous, old_y_current);
|
||||
|
||||
#ifdef FEAT_CLIPBOARD_PROVIDER
|
||||
call_clip_provider_set(name);
|
||||
#endif
|
||||
}
|
||||
#endif // FEAT_EVAL
|
||||
|
||||
|
||||
+15
-3
@@ -4874,12 +4874,20 @@ typedef enum {
|
||||
|
||||
// Symbolic names for some registers.
|
||||
#define DELETION_REGISTER 36
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
#if defined(FEAT_CLIPBOARD) || defined(HAVE_CLIPMETHOD)
|
||||
# define STAR_REGISTER 37
|
||||
# if defined(FEAT_X11) || defined(FEAT_WAYLAND)
|
||||
# define PLUS_REGISTER 38
|
||||
# define REAL_PLUS_REGISTER PLUS_REGISTER
|
||||
# else
|
||||
# define PLUS_REGISTER STAR_REGISTER // there is only one
|
||||
# ifdef FEAT_EVAL
|
||||
// Make it so that if clipmethod is "none", the plus register is not available,
|
||||
// but if clipmethod is a provider, then expose the plus register for use.
|
||||
# define REAL_PLUS_REGISTER 38
|
||||
# else
|
||||
# define REAL_PLUS_REGISTER STAR_REGISTER
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#ifdef FEAT_DND
|
||||
@@ -4890,10 +4898,14 @@ typedef enum {
|
||||
# ifdef FEAT_DND
|
||||
# define NUM_REGISTERS (TILDE_REGISTER + 1)
|
||||
# else
|
||||
# define NUM_REGISTERS (PLUS_REGISTER + 1)
|
||||
# define NUM_REGISTERS (REAL_PLUS_REGISTER + 1)
|
||||
# endif
|
||||
#else
|
||||
# define NUM_REGISTERS 37
|
||||
# ifdef HAVE_CLIPMETHOD
|
||||
# define NUM_REGISTERS (REAL_PLUS_REGISTER + 1)
|
||||
# else
|
||||
# define NUM_REGISTERS 37
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// structure used by block_prep, op_delete and op_yank for blockwise operators
|
||||
|
||||
@@ -3,21 +3,26 @@
|
||||
source util/window_manager.vim
|
||||
|
||||
CheckFeature clipboard_working
|
||||
CheckFeature xterm_clipboard
|
||||
CheckFeature wayland_clipboard
|
||||
CheckUnix
|
||||
|
||||
" Test if no available clipmethod sets v:clipmethod to none and deinits clipboard
|
||||
func Test_no_clipmethod_sets_v_clipmethod_none()
|
||||
CheckFeature xterm_clipboard
|
||||
CheckFeature wayland_clipboard
|
||||
CheckUnix
|
||||
CheckNotGui
|
||||
|
||||
set clipmethod=
|
||||
call assert_equal("none", v:clipmethod)
|
||||
call assert_equal(0, has('clipboard_working'))
|
||||
|
||||
set clipmethod&
|
||||
endfunc
|
||||
|
||||
" Test if method chosen is in line with clipmethod order
|
||||
func Test_clipmethod_order()
|
||||
CheckFeature xterm_clipboard
|
||||
CheckFeature wayland_clipboard
|
||||
CheckUnix
|
||||
CheckNotGui
|
||||
|
||||
set cpm=wayland,x11
|
||||
@@ -60,6 +65,8 @@ func Test_clipmethod_order()
|
||||
call assert_equal("wayland", v:clipmethod)
|
||||
|
||||
call EndWaylandCompositor(l:wayland_display)
|
||||
|
||||
set clipmethod&
|
||||
endfunc
|
||||
|
||||
" Test if clipmethod is set to 'none' when gui is started
|
||||
@@ -83,6 +90,9 @@ endfunc
|
||||
|
||||
" Test if :clipreset switches methods when current one doesn't work
|
||||
func Test_clipreset_switches()
|
||||
CheckFeature xterm_clipboard
|
||||
CheckFeature wayland_clipboard
|
||||
CheckUnix
|
||||
CheckNotGui
|
||||
CheckFeature clientserver
|
||||
CheckXServer
|
||||
@@ -171,6 +181,48 @@ func Test_clipreset_switches()
|
||||
" existing, this why WaitForAssert() is used.
|
||||
call WaitForAssert({-> assert_equal(['SUCCESS'], readfile('Xtest'))}, 1000)
|
||||
endif
|
||||
|
||||
set clipmethod&
|
||||
endfunc
|
||||
|
||||
func s:AAvailable()
|
||||
return g:a_available
|
||||
endfunc
|
||||
|
||||
func s:BAvailable()
|
||||
return g:b_available
|
||||
endfunc
|
||||
|
||||
" Test clipmethod when using provider
|
||||
func Test_clipmethod_provider()
|
||||
CheckFeature clipboard_provider
|
||||
|
||||
let v:clipproviders["a"] = {
|
||||
\ "available": function("s:AAvailable"),
|
||||
\ }
|
||||
let v:clipproviders["b"] = {
|
||||
\ "available": function("s:BAvailable"),
|
||||
\ }
|
||||
let g:a_available = 1
|
||||
let g:b_available = 1
|
||||
|
||||
set clipmethod=a,b
|
||||
call assert_equal("a", v:clipmethod)
|
||||
|
||||
let g:a_available = 0
|
||||
clipreset
|
||||
call assert_equal("b", v:clipmethod)
|
||||
|
||||
let g:b_available = 0
|
||||
clipreset
|
||||
call assert_equal("none", v:clipmethod)
|
||||
|
||||
let g:a_available = 1
|
||||
let g:b_available = 1
|
||||
clipreset
|
||||
call assert_equal("a", v:clipmethod)
|
||||
|
||||
set clipmethod&
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -727,4 +727,360 @@ func Test_eval_string_in_special_key()
|
||||
silent! echo 0{1-$"\<S--{>n|nö% | ||||