diff options
author | Rui Abreu Ferreira <raf-ep@gmx.com> | 2018-12-01 15:30:50 +0000 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2018-12-03 00:07:08 +0100 |
commit | 07ad5d71ab97a84dc9c59b3507bf7898040d24cf (patch) | |
tree | a924fb4043499daf3686adb44b6684448906cabd | |
parent | b19403e73e515786d2fcdb23674e3e29e62857b1 (diff) | |
download | rneovim-07ad5d71ab97a84dc9c59b3507bf7898040d24cf.tar.gz rneovim-07ad5d71ab97a84dc9c59b3507bf7898040d24cf.tar.bz2 rneovim-07ad5d71ab97a84dc9c59b3507bf7898040d24cf.zip |
clipboard: Support custom VimL functions #9304
Up to now g:clipboard["copy"] only supported string values invoked as
system commands.
This commit enables the use of VimL functions instead. The function
signatures are the same as in provider/clipboard.vim. A clipboard
provider is expected to store and return a list of lines (i.e. the text)
and a register type (as seen in setreg()).
cache_enabled is ignored if "copy" is provided by a VimL function.
-rw-r--r-- | runtime/autoload/provider/clipboard.vim | 25 | ||||
-rw-r--r-- | runtime/doc/provider.txt | 27 | ||||
-rw-r--r-- | test/functional/clipboard/clipboard_provider_spec.lua | 89 |
3 files changed, 134 insertions, 7 deletions
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 0ddfdf7e49..8bbb72f933 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -55,11 +55,22 @@ endfunction function! provider#clipboard#Executable() abort if exists('g:clipboard') if type({}) isnot# type(g:clipboard) - \ || type({}) isnot# type(get(g:clipboard, 'copy', v:null)) - \ || type({}) isnot# type(get(g:clipboard, 'paste', v:null)) let s:err = 'clipboard: invalid g:clipboard' return '' endif + + if type(get(g:clipboard, 'copy', v:null)) isnot# v:t_dict + \ && type(get(g:clipboard, 'copy', v:null)) isnot# v:t_func + let s:err = "clipboard: invalid g:clipboard['copy']" + return '' + endif + + if type(get(g:clipboard, 'paste', v:null)) isnot# v:t_dict + \ && type(get(g:clipboard, 'paste', v:null)) isnot# v:t_func + let s:err = "clipboard: invalid g:clipboard['paste']" + return '' + endif + let s:copy = get(g:clipboard, 'copy', { '+': v:null, '*': v:null }) let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null }) let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0) @@ -127,7 +138,9 @@ if empty(provider#clipboard#Executable()) endif function! s:clipboard.get(reg) abort - if s:selections[a:reg].owner > 0 + if type(s:paste[a:reg]) == v:t_func + return s:paste[a:reg]() + elseif s:selections[a:reg].owner > 0 return s:selections[a:reg].data end return s:try_cmd(s:paste[a:reg]) @@ -141,6 +154,12 @@ function! s:clipboard.set(lines, regtype, reg) abort end return 0 end + + if type(s:copy[a:reg]) == v:t_func + call s:copy[a:reg](a:lines, a:regtype) + return 0 + end + if s:cache_enabled == 0 call s:try_cmd(s:copy[a:reg], a:lines) return 0 diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt index 4de411a60e..930c73d06e 100644 --- a/runtime/doc/provider.txt +++ b/runtime/doc/provider.txt @@ -160,7 +160,9 @@ registers. Nvim looks for these clipboard tools, in order of priority: - tmux (if $TMUX is set) *g:clipboard* -To configure a custom clipboard tool, set `g:clipboard` to a dictionary: > +To configure a custom clipboard tool, set g:clipboard to a dictionary. +For example this configuration integrates the tmux clipboard: > + let g:clipboard = { \ 'name': 'myClipboard', \ 'copy': { @@ -174,9 +176,28 @@ To configure a custom clipboard tool, set `g:clipboard` to a dictionary: > \ 'cache_enabled': 1, \ } -If `cache_enabled` is |TRUE| then when a selection is copied, Nvim will cache +If "cache_enabled" is |TRUE| then when a selection is copied Nvim will cache the selection until the copy command process dies. When pasting, if the copy -process has not died, the cached selection is applied. +process has not died the cached selection is applied. + +g:clipboard can also use functions (see |lambda|) instead of strings. +For example this configuration uses the g:foo variable as a fake clipboard: > + + let g:clipboard = { + \ 'name': 'myClipboard', + \ 'copy': { + \ '+': {lines, regtype -> extend(g:, {'foo': [lines, regtype]}) }, + \ '*': {lines, regtype -> extend(g:, {'foo': [lines, regtype]}) }, + \ }, + \ 'paste': { + \ '+': {-> get(g:, 'foo', [])}, + \ '*': {-> get(g:, 'foo', [])}, + \ }, + \ } + +The "copy" function stores a list of lines and the register type. The "paste" +function returns the clipboard as a `[lines, regtype]` list, where `lines` is +a list of lines and `regtype` is a register type conforming to |setreg()|. ============================================================================== X11 selection mechanism *clipboard-x11* *x11-selection* diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index a40c080a6d..2bbc678a02 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -3,7 +3,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert -local feed_command, expect, eq, eval = helpers.feed_command, helpers.expect, helpers.eq, helpers.eval +local feed_command, expect, eq, eval, source = helpers.feed_command, helpers.expect, helpers.eq, helpers.eval, helpers.source local command = helpers.command local meths = helpers.meths @@ -147,6 +147,93 @@ describe('clipboard', function() eq('clippy!', eval('provider#clipboard#Executable()')) eq('', eval('provider#clipboard#Error()')) end) + + it('g:clipboard using VimL functions', function() + -- Implements a fake clipboard provider. cache_enabled is meaningless here. + source([[let g:clipboard = { + \ 'name': 'custom', + \ 'copy': { + \ '+': {lines, regtype -> extend(g:, {'dummy_clipboard_plus': [lines, regtype]}) }, + \ '*': {lines, regtype -> extend(g:, {'dummy_clipboard_star': [lines, regtype]}) }, + \ }, + \ 'paste': { + \ '+': {-> get(g:, 'dummy_clipboard_plus', [])}, + \ '*': {-> get(g:, 'dummy_clipboard_star', [])}, + \ }, + \ 'cache_enabled': 1, + \}]]) + + eq('', eval('provider#clipboard#Error()')) + eq('custom', eval('provider#clipboard#Executable()')) + + eq('', eval("getreg('*')")) + eq('', eval("getreg('+')")) + + command('call setreg("*", "star")') + command('call setreg("+", "plus")') + eq('star', eval("getreg('*')")) + eq('plus', eval("getreg('+')")) + + command('call setreg("*", "star", "v")') + eq({{'star'}, 'v'}, eval("g:dummy_clipboard_star")) + command('call setreg("*", "star", "V")') + eq({{'star', ''}, 'V'}, eval("g:dummy_clipboard_star")) + command('call setreg("*", "star", "b")') + eq({{'star', ''}, 'b'}, eval("g:dummy_clipboard_star")) + end) + + describe('g:clipboard[paste] VimL function', function() + it('can return empty list for empty clipboard', function() + source([[let g:dummy_clipboard = [] + let g:clipboard = { + \ 'name': 'custom', + \ 'copy': { '*': {lines, regtype -> 0} }, + \ 'paste': { '*': {-> g:dummy_clipboard} }, + \}]]) + eq('', eval('provider#clipboard#Error()')) + eq('custom', eval('provider#clipboard#Executable()')) + eq('', eval("getreg('*')")) + end) + + it('can return a list with a single string', function() + source([=[let g:dummy_clipboard = ['hello'] + let g:clipboard = { + \ 'name': 'custom', + \ 'copy': { '*': {lines, regtype -> 0} }, + \ 'paste': { '*': {-> g:dummy_clipboard} }, + \}]=]) + eq('', eval('provider#clipboard#Error()')) + eq('custom', eval('provider#clipboard#Executable()')) + + eq('hello', eval("getreg('*')")) + source([[let g:dummy_clipboard = [''] ]]) + eq('', eval("getreg('*')")) + end) + + it('can return a list of lines if a regtype is provided', function() + source([=[let g:dummy_clipboard = [['hello'], 'v'] + let g:clipboard = { + \ 'name': 'custom', + \ 'copy': { '*': {lines, regtype -> 0} }, + \ 'paste': { '*': {-> g:dummy_clipboard} }, + \}]=]) + eq('', eval('provider#clipboard#Error()')) + eq('custom', eval('provider#clipboard#Executable()')) + eq('hello', eval("getreg('*')")) + end) + + it('can return a list of lines instead of [lines, regtype]', function() + source([=[let g:dummy_clipboard = ['hello', 'v'] + let g:clipboard = { + \ 'name': 'custom', + \ 'copy': { '*': {lines, regtype -> 0} }, + \ 'paste': { '*': {-> g:dummy_clipboard} }, + \}]=]) + eq('', eval('provider#clipboard#Error()')) + eq('custom', eval('provider#clipboard#Executable()')) + eq('hello\nv', eval("getreg('*')")) + end) + end) end) describe('clipboard', function() |