From 638ceea092f01675e964a5e5a6adc6af8f28f423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Wed, 25 Mar 2015 18:21:02 +0100 Subject: [PATCH 1/6] test/clipboard: split unrelated subtests --- .../clipboard/clipboard_provider_spec.lua | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index 1a798ec48c..c5577327f9 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -8,6 +8,7 @@ local nvim, run, stop, restart = helpers.nvim, helpers.run, helpers.stop, helper local function reset() clear() execute('let &rtp = "test/functional/clipboard,".&rtp') + execute('call getreg("*")') -- force load of provider end local function basic_register_test() @@ -62,7 +63,8 @@ local function basic_register_test() end describe('clipboard usage', function() - setup(reset) + before_each(reset) + it("works", function() basic_register_test() @@ -71,9 +73,9 @@ describe('clipboard usage', function() feed('^"*dwdw"*P') expect('some ') eq({'some '}, eval("g:test_clip['*']")) - reset() + end) - -- "* and "+ should be independent when the provider supports it + it('supports separate "* and "+ when the provider supports it', function() insert([[ text: first line @@ -89,9 +91,9 @@ describe('clipboard usage', function() -- linewise selection should be encoded as an extra newline eq({'third line', ''}, eval("g:test_clip['+']")) eq({'secound line', ''}, eval("g:test_clip['*']")) - reset() + end) - -- handle null bytes + it('handles null bytes', function() insert("some\022000text\n\022000very binary\022000") feed('"*y-+"*p') eq({'some\ntext', '\nvery binary\n',''}, eval("g:test_clip['*']")) @@ -100,22 +102,21 @@ describe('clipboard usage', function() -- test getreg/getregtype eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1)")) eq("V", eval("getregtype('*')")) - reset() + end) - -- blockwise paste + it('support blockwise operations', function() insert([[ much text]]) - feed('"*yy') -- force load of provider execute("let g:test_clip['*'] = [['very','block'],'b']") feed('gg"*P') expect([[ very much blocktext]]) eq("\0225", eval("getregtype('*')")) - reset() + end) - -- test setreg + it('supports setreg', function() execute('call setreg("*", "setted\\ntext", "c")') execute('call setreg("+", "explicitly\\nlines", "l")') feed('"+P"*p') @@ -124,9 +125,9 @@ describe('clipboard usage', function() textxplicitly lines ]]) - reset() + end) - -- test let @+ (issue #1427) + it('supports let @+ (issue #1427)', function() execute("let @+ = 'some'") execute("let @* = ' other stuff'") eq({'some'}, eval("g:test_clip['+']")) @@ -136,8 +137,9 @@ describe('clipboard usage', function() execute("let @+ .= ' more'") feed('dd"+p') expect('some more') - reset() + end) + it('supports clipboard=unnamed', function() -- the basic behavior of unnamed register should be the same -- even when handled by clipboard provider execute('set clipboard=unnamed') @@ -155,7 +157,6 @@ describe('clipboard usage', function() expect([[ words linewise stuff]]) - reset() + end) - end) end) From 5600b80c1fcdf9d056bb7a0b5a74e5563dcb991f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Wed, 18 Mar 2015 22:38:19 +0100 Subject: [PATCH 2/6] clipboard: show "* and "+ in :registers Helped-by: Robin Allen Helped-by: Scott Prager --- src/nvim/ops.c | 57 +++++++++++-------- .../clipboard/clipboard_provider_spec.lua | 24 ++++++++ 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 2714798368..e73868a0fa 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -57,10 +57,15 @@ * 1..9 = registers '1' to '9', for deletes * 10..35 = registers 'a' to 'z' * 36 = delete register '-' + * 37 = selection register '*' + * 38 = clipboard register '+' */ -#define NUM_REGISTERS 38 #define DELETION_REGISTER 36 -#define CLIP_REGISTER 37 +#define NUM_SAVED_REGISTERS 37 +// The following registers should not be saved in viminfo: +#define STAR_REGISTER 37 +#define PLUS_REGISTER 38 +#define NUM_REGISTERS 39 #define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS) #define CB_LATEST (-1) @@ -771,8 +776,10 @@ void get_yank_register(int regname, int writing) y_append = TRUE; } else if (regname == '-') i = DELETION_REGISTER; - else if (regname == '*' || regname == '+') - i = CLIP_REGISTER; + else if (regname == '*') + i = STAR_REGISTER; + else if (regname == '+') + i = PLUS_REGISTER; else /* not 0-9, a-z, A-Z or '-': use register 0 */ i = 0; y_current = &(y_regs[i]); @@ -792,7 +799,7 @@ get_register ( ) FUNC_ATTR_NONNULL_RET { get_yank_register(name, 0); - get_clipboard(name); + get_clipboard(name, false); struct yankreg *reg = xmalloc(sizeof(struct yankreg)); *reg = *y_current; @@ -960,7 +967,7 @@ do_execreg ( } execreg_lastc = regname; - get_clipboard(regname); + get_clipboard(regname, false); if (regname == '_') /* black hole: don't stuff anything */ return OK; @@ -1125,7 +1132,7 @@ insert_reg ( if (regname != NUL && !valid_yank_reg(regname, FALSE)) return FAIL; - get_clipboard(regname); + get_clipboard(regname, false); if (regname == '.') /* insert last inserted text */ retval = stuff_inserted(NUL, 1L, TRUE); @@ -2613,7 +2620,7 @@ do_put ( int allocated = FALSE; long cnt; - get_clipboard(regname); + get_clipboard(regname, false); if (flags & PUT_FIXINDENT) orig_indent = get_indent(); @@ -3190,6 +3197,10 @@ int get_register_name(int num) return num + '0'; else if (num == DELETION_REGISTER) return '-'; + else if (num == STAR_REGISTER) + return '*'; + else if (num == PLUS_REGISTER) + return '+'; else { return num + 'a' - 10; } @@ -3222,7 +3233,7 @@ void ex_display(exarg_T *eap) continue; /* did not ask for this register */ } - get_clipboard(name); + get_clipboard(name, true); if (i == -1) { if (y_previous != NULL) @@ -4566,12 +4577,11 @@ void write_viminfo_registers(FILE *fp) if (max_kbyte == 0) return; - for (i = 0; i < NUM_REGISTERS; i++) { + // don't include clipboard registers '*'/'+' + for (i = 0; i < NUM_SAVED_REGISTERS; i++) { if (y_regs[i].y_array == NULL) continue; - // Skip '*'/'+' register, we don't want them back next time - if (i == CLIP_REGISTER) - continue; + /* Skip empty registers. */ num_lines = y_regs[i].y_size; if (num_lines == 0 @@ -4651,7 +4661,7 @@ char_u get_reg_type(int regname, long *reglen) return MCHAR; } - get_clipboard(regname); + get_clipboard(regname, false); if (regname != NUL && !valid_yank_reg(regname, FALSE)) return MAUTO; @@ -4712,7 +4722,7 @@ void *get_reg_contents(int regname, int flags) if (regname != NUL && !valid_yank_reg(regname, FALSE)) return NULL; - get_clipboard(regname); + get_clipboard(regname, false); char_u *retval; int allocated; @@ -5292,16 +5302,17 @@ static void free_register(struct yankreg *reg) } // return target register -static struct yankreg* adjust_clipboard_name(int *name) { +static struct yankreg* adjust_clipboard_name(int *name, bool quiet) { if (*name == '*' || *name == '+') { if(!eval_has_provider("clipboard")) { - EMSG("clipboard: provider is not available"); - return NULL; + if (!quiet) { + EMSG("clipboard: provider is not available"); + } } - return &y_regs[CLIP_REGISTER]; + return &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER]; } else if ((*name == NUL || *name == CB_LATEST) && (cb_flags & CB_UNNAMEDMASK)) { if(!eval_has_provider("clipboard")) { - if (!clipboard_didwarn_unnamed) { + if (!quiet && !clipboard_didwarn_unnamed) { msg((char_u*)"clipboard: provider not available, ignoring clipboard=unnamed[plus]"); clipboard_didwarn_unnamed = true; } @@ -5324,9 +5335,9 @@ static struct yankreg* adjust_clipboard_name(int *name) { return NULL; } -static void get_clipboard(int name) +static void get_clipboard(int name, bool quiet) { - struct yankreg* reg = adjust_clipboard_name(&name); + struct yankreg* reg = adjust_clipboard_name(&name, quiet); if (reg == NULL) { return; } @@ -5417,7 +5428,7 @@ err: static void set_clipboard(int name) { - struct yankreg* reg = adjust_clipboard_name(&name); + struct yankreg* reg = adjust_clipboard_name(&name, false); if (reg == NULL) { return; } diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index c5577327f9..c1c56c94c1 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -1,6 +1,7 @@ -- Test clipboard provider support local helpers = require('test.functional.helpers') +local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect, eq, eval = helpers.execute, helpers.expect, helpers.eq, helpers.eval local nvim, run, stop, restart = helpers.nvim, helpers.run, helpers.stop, helpers.restart @@ -159,4 +160,27 @@ describe('clipboard usage', function() linewise stuff]]) end) + it('supports "+ and "* in registers', function() + local screen = Screen.new(60, 10) + screen:attach() + execute("let g:test_clip['*'] = ['some', 'star data','']") + execute("let g:test_clip['+'] = ['such', 'plus', 'stuff']") + execute("registers") + screen:expect([[ + ~ | + ~ | + ~ | + ~ | + :registers | + {1:--- Registers ---} | + "* some{2:^J}star data{2:^J} | + "+ such{2:^J}plus{2:^J}stuff | + ": let g:test_clip['+'] = ['such', 'plus', 'stuff'] | + {3:Press ENTER or type command to continue}^ | + ]], { + [1] = {bold = true, foreground = Screen.colors.Fuchsia}, + [2] = {foreground = Screen.colors.Blue}, + [3] = {bold = true, foreground = Screen.colors.SeaGreen}}, + {{bold = true, foreground = Screen.colors.Blue}}) + end) end) From 34dba3d7cd43b4797d60f636dc9c7c3040a56f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Wed, 18 Mar 2015 23:43:49 +0100 Subject: [PATCH 3/6] clipboard: reallow `:put` --- src/nvim/.screen.c.swn | Bin 0 -> 16384 bytes src/nvim/ex_docmd.c | 15 +++++---------- .../clipboard/clipboard_provider_spec.lua | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 src/nvim/.screen.c.swn diff --git a/src/nvim/.screen.c.swn b/src/nvim/.screen.c.swn new file mode 100644 index 0000000000000000000000000000000000000000..5b9fe1863075620f1dc243d3af0c326270eea79d GIT binary patch literal 16384 zcmeHNTZ~;*89s_!%1v&9f)9(L&P+460*QrMu?$oOI@Hh(4Jq}w&fe?H+3ntY9rk6; z45cN+P>IHC42ds188yKKUwjbJAW{^(Aa@WD6j1?DQ7&FU{rWyVFx<<&oI8k`nP!a?-+OWapvJw{ogX~=I2Wu{u{>I zZ2wgcf0}U@f9r^<{a-V_!20)i_*0C#`CoHnRsUC>{#QKwmyEmojykHU|0Lrszs$p* zU_9se9`NvAFrG1f!O>Owk9+vd9{w2PA7}mXw^#KaWxUDwO&`X(|9r;7Z)e=`cg4w7``>5$TK4~Law#H133rs67FXEAh$vGKw?M)IR$bzg1ruME#yOx;~`Jtu6Yw=7i0;t3i8Au zjmB3YUxtK`6CrouPJAomJCG8x3i1T*;a`BvKu&-h3)zRm5Z(XJfE*4v6!LAnPtcHa zARmA{558`I5O14^JN}4OqR>Jv>L?VM3NzV@(gmRwRkmDo@O4s%bIU>$9VKFwE)*T1 z+aiqeZY-BoDB>tpxk$>q5UDO2ux5=kV_B$dbn~XU^P88h-#B~T7`Z9CAs!oJy^fBR zfU{8dL<=7BB8p>C=1Sy2rehdhAagT1Nn{%4P?CiRIx<~Qq7yB2Vn{);0u^1I=TR$O z7J(!Sl5N1Jw!sB5j$w{0w#s%}WfW&Wi`FuS)`V~TzmCx{Vd9^p@g_Oacc}$s1{<8= z#hbPaCD@UR@Q$IxmrX7gZJp8Y|2Z2lAYE8dKE&>*np~J17r81-rXz)H<%RB!jBzS& zI0v?nkB#r2j-9Ck|qWA!HjRY-W;UPmoQjQ1zyc$p@yElHrI=iRK;MqiR)LtRc@VS?wSvndfDKo+*rr zmPWx029q&cc{ExH6Je}%7cNj$rV4En^(%E;^g2<{u>-ill*E5=qDBiQ zGTUh!%1lXo={Hqq8p*iH)D>lvseYPd>VSP{asY>v0JqhkTb%ROa-niK@6XkswT8RO zmf>KnFs(#}ncTrV?cc37R~77RqBnD$ajJc8%|p~K@+XUn5iJ%%|Dp>` z1q<14mjn24a{(3d&-G}gXW)SBZ$SwRPd$$`y--=4anyxL8j4D%#mZJ;2hm)0m06yR7* z^r8^Q4D?urR#4fPaXS>q>D#uGjwxsC_Lu=|u&N9uc67--c1WyUly7iawG%ZD(*oAUvUT6Rca_Gr`4X#7mnKU0Xdl&BqOMaEy{FiwJwR+0|&}^3p{zD8~d5P!QBOTQk|sw`IDw zUEs4Jmgd+XXpc6%M#}}JE2G0lkH)$lGPOYK7X`Os1!>z-cbX<>aMBePHK%>Fz9=&EH$^=B0J?~|Vh*Pl9ng}7;{uc-oZMAD6yIQ%9#u<0 zT$+=ZIVRBZfU_cq6R2^Or4r{EKHTru;@dpe5<|Pou37EfAva4Cc5FVj3GDqD4x{lh zlRtd8F;u}d4t*+Vsf>ECM~flqNyaz|g|Kehrf(PY*foZ3Eu=tAMH`3d*-d59rHfHz zy&I(x!NmskqOv5S92Lq~VoAdJM|^mG*6noU7z3gtx>C`JgSfYzCxf$*ElL`7{9VE8xINxqzCIE5(o%qSj0v zr9c%|<`OqJ*nmHrb4>A27WCixC*WJm&UG^cAFjZ3otw!-%xN&1N|{m8bpM~k9sOnq z-T&SD|EF=k-v{{yAx+2(lN5g)SS!TTlzTtQ?}l?+jd9h+2Y=CN&e)-19bQNnrL} Date: Sat, 28 Mar 2015 20:57:06 +0100 Subject: [PATCH 4/6] clipboard: improve the handling of newlines in `get_clipboard` This makes the interpretion consistent with the way newlines are used in the VIMENC format, while keeping the same fallback behaviour when regtype is unspecified. Also check both cases explicitly in the tests. --- src/nvim/ops.c | 24 +++++++--- .../clipboard/autoload/provider/clipboard.vim | 2 +- .../clipboard/clipboard_provider_spec.lua | 45 +++++++++++++++---- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index e73868a0fa..f0caaad97b 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5360,10 +5360,13 @@ static void get_clipboard(int name, bool quiet) goto err; } char_u* regtype = res->lv_last->li_tv.vval.v_string; - if (regtype == NULL || strlen((char*)regtype) != 1) { + if (regtype == NULL || strlen((char*)regtype) > 1) { goto err; } switch (regtype[0]) { + case 0: + reg->y_type = MAUTO; + break; case 'v': case 'c': reg->y_type = MCHAR; break; @@ -5393,15 +5396,23 @@ static void get_clipboard(int name, bool quiet) reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string); } - if (reg->y_type == MAUTO) { - if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) { - reg->y_type = MLINE; + if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) { + // a known-to-be charwise yank might have a final linebreak + // but otherwise there is no line after the final newline + if (reg->y_type != MCHAR) { free(reg->y_array[reg->y_size-1]); reg->y_size--; - } else { + if (reg->y_type == MAUTO) { + reg->y_type = MLINE; + } + } + } else { + if (reg->y_type == MAUTO) { reg->y_type = MCHAR; } - } else if (reg->y_type == MBLOCK) { + } + + if (reg->y_type == MBLOCK) { int maxlen = 0; for (int i = 0; i < reg->y_size; i++) { int rowlen = STRLEN(reg->y_array[i]); @@ -5453,6 +5464,7 @@ static void set_clipboard(int name) break; case MBLOCK: regtype = 'b'; + list_append_string(lines, (char_u*)"", 0); break; } list_append_string(args, ®type, 1); diff --git a/test/functional/clipboard/autoload/provider/clipboard.vim b/test/functional/clipboard/autoload/provider/clipboard.vim index 6c05a19fc3..c7fd630782 100644 --- a/test/functional/clipboard/autoload/provider/clipboard.vim +++ b/test/functional/clipboard/autoload/provider/clipboard.vim @@ -7,7 +7,7 @@ function! s:methods.get(reg) endfunction function! s:methods.set(lines, regtype, reg) - let g:test_clip[a:reg] = a:lines + let g:test_clip[a:reg] = [a:lines, a:regtype] endfunction diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index f1e011f12d..363dcb1d11 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -73,7 +73,7 @@ describe('clipboard usage', function() insert("some words") feed('^"*dwdw"*P') expect('some ') - eq({'some '}, eval("g:test_clip['*']")) + eq({{'some '}, 'v'}, eval("g:test_clip['*']")) end) it('supports separate "* and "+ when the provider supports it', function() @@ -90,19 +90,36 @@ describe('clipboard usage', function() secound line first line]]) -- linewise selection should be encoded as an extra newline - eq({'third line', ''}, eval("g:test_clip['+']")) - eq({'secound line', ''}, eval("g:test_clip['*']")) + eq({{'third line', ''}, 'V'}, eval("g:test_clip['+']")) + eq({{'secound line', ''}, 'V'}, eval("g:test_clip['*']")) end) - it('handles null bytes', function() + it('handles null bytes when pasting and in getreg', function() insert("some\022000text\n\022000very binary\022000") feed('"*y-+"*p') - eq({'some\ntext', '\nvery binary\n',''}, eval("g:test_clip['*']")) + eq({{'some\ntext', '\nvery binary\n',''}, 'V'}, eval("g:test_clip['*']")) expect("some\00text\n\00very binary\00\nsome\00text\n\00very binary\00") -- test getreg/getregtype eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1)")) eq("V", eval("getregtype('*')")) + + -- getreg supports three arguments + eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1, 0)")) + eq({'some\ntext', '\nvery binary\n'}, eval("getreg('*', 1, 1)")) + end) + + it('support autodectection of regtype', function() + execute("let g:test_clip['*'] = ['linewise stuff','']") + execute("let g:test_clip['+'] = ['charwise','stuff']") + eq("V", eval("getregtype('*')")) + eq("v", eval("getregtype('+')")) + insert("just some text") + feed('"*p"+p') + expect([[ + just some text + lcharwise + stuffinewise stuff]]) end) it('support blockwise operations', function() @@ -115,6 +132,11 @@ describe('clipboard usage', function() very much blocktext]]) eq("\0225", eval("getregtype('*')")) + feed('gg4lj4l"+ygg"+P') + expect([[ + muchvery much + ktextblocktext]]) + eq({{' much', 'ktext', ''}, 'b'}, eval("g:test_clip['+']")) end) it('supports setreg', function() @@ -126,13 +148,20 @@ describe('clipboard usage', function() textxplicitly lines ]]) + execute('call setreg("+", "blocky\\nindeed", "b")') + feed('"+p') + expect([[ + esblockyetted + teindeedxtxplicitly + lines + ]]) end) it('supports let @+ (issue #1427)', function() execute("let @+ = 'some'") execute("let @* = ' other stuff'") - eq({'some'}, eval("g:test_clip['+']")) - eq({' other stuff'}, eval("g:test_clip['*']")) + eq({{'some'}, 'v'}, eval("g:test_clip['+']")) + eq({{' other stuff'}, 'v'}, eval("g:test_clip['*']")) feed('"+p"*p') expect('some other stuff') execute("let @+ .= ' more'") @@ -151,7 +180,7 @@ describe('clipboard usage', function() insert("some words") feed('^"*dwdw"*P') expect('words') - eq({'words'}, eval("g:test_clip['*']")) + eq({{'words'}, 'v'}, eval("g:test_clip['*']")) execute("let g:test_clip['*'] = ['linewise stuff','']") feed('p') From db92fcdba3f596838f524a049efe1c7e82bb734f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Sun, 29 Mar 2015 12:20:26 +0200 Subject: [PATCH 5/6] test/clipboard: more clipboard test cleanups --- .../clipboard/autoload/provider/clipboard.vim | 10 ++- .../clipboard/clipboard_provider_spec.lua | 82 +++++++++++++------ 2 files changed, 64 insertions(+), 28 deletions(-) diff --git a/test/functional/clipboard/autoload/provider/clipboard.vim b/test/functional/clipboard/autoload/provider/clipboard.vim index c7fd630782..d88b68464e 100644 --- a/test/functional/clipboard/autoload/provider/clipboard.vim +++ b/test/functional/clipboard/autoload/provider/clipboard.vim @@ -2,8 +2,16 @@ let g:test_clip = { '+': [''], '*': [''], } let s:methods = {} +let g:cliplossy = 0 + function! s:methods.get(reg) - return g:test_clip[a:reg] + if g:cliplossy + " behave like pure text clipboard + return g:test_clip[a:reg][0] + else + "behave like VIMENC clipboard + return g:test_clip[a:reg] + end endfunction function! s:methods.set(lines, regtype, reg) diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index 363dcb1d11..74a3bf4ae0 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -6,13 +6,7 @@ local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect, eq, eval = helpers.execute, helpers.expect, helpers.eq, helpers.eval local nvim, run, stop, restart = helpers.nvim, helpers.run, helpers.stop, helpers.restart -local function reset() - clear() - execute('let &rtp = "test/functional/clipboard,".&rtp') - execute('call getreg("*")') -- force load of provider -end - -local function basic_register_test() +local function basic_register_test(noblock) insert("some words") feed('^dwP') @@ -60,20 +54,41 @@ local function basic_register_test() expect([[ , stuff and some more some textsome some text, stuff and some more]]) - reset() + + feed('ggwjwyggP') + if noblock then + expect([[ + stuf + me t + , stuff and some more + some textsome some text, stuff and some more]]) + else + expect([[ + stuf, stuff and some more + me tsome textsome some text, stuff and some more]]) + end end -describe('clipboard usage', function() - before_each(reset) - - it("works", function() +describe('the unnamed register', function() + before_each(clear) + it('works without provider', function() basic_register_test() + end) +end) - -- "* and unnamed should function as independent registers +describe('clipboard usage', function() + before_each(function() + clear() + execute('let &rtp = "test/functional/clipboard,".&rtp') + execute('call getreg("*")') -- force load of provider + end) + + it('has independent "* and unnamed registers per default', function() insert("some words") feed('^"*dwdw"*P') expect('some ') eq({{'some '}, 'v'}, eval("g:test_clip['*']")) + eq('words', eval("getreg('\"', 1)")) end) it('supports separate "* and "+ when the provider supports it', function() @@ -169,24 +184,37 @@ describe('clipboard usage', function() expect('some more') end) - it('supports clipboard=unnamed', function() + describe('with clipboard=unnamed', function() -- the basic behavior of unnamed register should be the same -- even when handled by clipboard provider - execute('set clipboard=unnamed') - basic_register_test() + before_each(function() + execute('set clipboard=unnamed') + end) - -- with cb=unnamed, "* and unnamed will be the same register - execute('set clipboard=unnamed') - insert("some words") - feed('^"*dwdw"*P') - expect('words') - eq({{'words'}, 'v'}, eval("g:test_clip['*']")) + it('works', function() + basic_register_test() + end) - execute("let g:test_clip['*'] = ['linewise stuff','']") - feed('p') - expect([[ - words - linewise stuff]]) + it('works with pure text clipboard', function() + execute("let g:cliplossy = 1") + -- expect failure for block mode + basic_register_test(true) + end) + + it('links the "* and unnamed registers', function() + -- with cb=unnamed, "* and unnamed will be the same register + execute('set clipboard=unnamed') + insert("some words") + feed('^"*dwdw"*P') + expect('words') + eq({{'words'}, 'v'}, eval("g:test_clip['*']")) + + execute("let g:test_clip['*'] = ['linewise stuff','']") + feed('p') + expect([[ + words + linewise stuff]]) + end) end) it('supports :put', function() From adcf268a72827be38510b1830b67b287dec50c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Sun, 29 Mar 2015 12:39:52 +0200 Subject: [PATCH 6/6] clipboard: handle clipboard reading directly in `get_yank_register` This makes :* work as expected and avoids clobbering zero register ("0) when pasting unnamed clipboard Helped-By: Scott Prager Helped-By: Michael Reed --- src/nvim/ops.c | 112 ++++++++++-------- .../clipboard/clipboard_provider_spec.lua | 23 +++- 2 files changed, 83 insertions(+), 52 deletions(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index f0caaad97b..572b557ad3 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -53,7 +53,7 @@ /* * Registers: - * 0 = unnamed register, for normal yanks and puts + * 0 = register for latest (unnamed) yank * 1..9 = registers '1' to '9', for deletes * 10..35 = registers 'a' to 'z' * 36 = delete register '-' @@ -68,7 +68,6 @@ #define NUM_REGISTERS 39 #define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS) -#define CB_LATEST (-1) /* * Each yank register is an array of pointers to lines. */ @@ -748,21 +747,37 @@ valid_yank_reg ( return FALSE; } -/* - * Set y_current and y_append, according to the value of "regname". - * Cannot handle the '_' register. - * Must only be called with a valid register name! - * - * If regname is 0 and writing, use register 0 - * If regname is 0 and reading, use previous register - */ -void get_yank_register(int regname, int writing) +typedef enum { + YREG_PASTE, + YREG_YANK, + YREG_PUT, +} yreg_mode_t; + +/// Set y_current and y_append, according to the value of `regname`. +/// Cannot handle the '_' (black hole) register. +/// Must only be called with a valid register name! +/// +/// @param regname The name of the register used or 0 for the unnamed register +/// @param mode One of the following three flags: +/// +/// `YREG_PASTE`: +/// Prepare for pasting the register `regname`. With no regname specified, +/// read from last written register, or from unnamed clipboard (depending on the +/// `clipboard=unnamed` option). Queries the clipboard provider if necessary. +/// +/// `YREG_YANK`: +/// Preparare for yanking into `regname`. With no regname specified, +/// yank into `"0` register. Update `y_previous` for next unnamed paste. +/// +/// `YREG_PUT`: +/// Obtain the location that would be read when pasting `regname`. +void get_yank_register(int regname, int mode) { int i; y_append = FALSE; int unnamedclip = cb_flags & CB_UNNAMEDMASK; - if ((regname == 0 || regname == '"') && !unnamedclip && !writing && y_previous != NULL) { + if ((regname == 0 || regname == '"') && !unnamedclip && mode != YREG_YANK && y_previous != NULL) { y_current = y_previous; return; } @@ -783,8 +798,12 @@ void get_yank_register(int regname, int writing) else /* not 0-9, a-z, A-Z or '-': use register 0 */ i = 0; y_current = &(y_regs[i]); - if (writing) /* remember the register we write into for do_put() */ + if (mode == YREG_YANK) { + // remember the written register for unnamed paste y_previous = y_current; + } else if (mode == YREG_PASTE) { + get_clipboard(regname, &y_current, false); + } } @@ -798,8 +817,7 @@ get_register ( int copy /* make a copy, if FALSE make register empty. */ ) FUNC_ATTR_NONNULL_RET { - get_yank_register(name, 0); - get_clipboard(name, false); + get_yank_register(name, YREG_PASTE); struct yankreg *reg = xmalloc(sizeof(struct yankreg)); *reg = *y_current; @@ -823,7 +841,7 @@ get_register ( */ void put_register(int name, void *reg) { - get_yank_register(name, 0); + get_yank_register(name, YREG_PUT); free_yank_all(); *y_current = *(struct yankreg *)reg; free(reg); @@ -839,7 +857,7 @@ int yank_register_mline(int regname) return FALSE; if (regname == '_') /* black hole is always empty */ return FALSE; - get_yank_register(regname, FALSE); + get_yank_register(regname, YREG_PASTE); return y_current->y_type == MLINE; } @@ -913,7 +931,7 @@ static int stuff_yank(int regname, char_u *p) free(p); return OK; } - get_yank_register(regname, TRUE); + get_yank_register(regname, YREG_YANK); if (y_append && y_current->y_array != NULL) { char_u **pp = &(y_current->y_array[y_current->y_size - 1]); char_u *lp = xmalloc(STRLEN(*pp) + STRLEN(p) + 1); @@ -967,8 +985,6 @@ do_execreg ( } execreg_lastc = regname; - get_clipboard(regname, false); - if (regname == '_') /* black hole: don't stuff anything */ return OK; @@ -1007,7 +1023,7 @@ do_execreg ( retval = put_in_typebuf(p, FALSE, colon, silent); free(p); } else { - get_yank_register(regname, FALSE); + get_yank_register(regname, YREG_PASTE); if (y_current->y_array == NULL) return FAIL; @@ -1132,8 +1148,6 @@ insert_reg ( if (regname != NUL && !valid_yank_reg(regname, FALSE)) return FAIL; - get_clipboard(regname, false); - if (regname == '.') /* insert last inserted text */ retval = stuff_inserted(NUL, 1L, TRUE); else if (get_spec_reg(regname, &arg, &allocated, TRUE)) { @@ -1143,7 +1157,7 @@ insert_reg ( if (allocated) free(arg); } else { /* name or number register */ - get_yank_register(regname, FALSE); + get_yank_register(regname, YREG_PASTE); if (y_current->y_array == NULL) retval = FAIL; else { @@ -1290,7 +1304,7 @@ cmdline_paste_reg ( { long i; - get_yank_register(regname, FALSE); + get_yank_register(regname, YREG_PASTE); if (y_current->y_array == NULL) return FAIL; @@ -1397,7 +1411,7 @@ int op_delete(oparg_T *oap) beep_flush(); return OK; } - get_yank_register(oap->regname, TRUE); /* yank into specif'd reg. */ + get_yank_register(oap->regname, YREG_YANK); /* yank into specif'd reg. */ if (op_yank(oap, TRUE, FALSE) == OK) /* yank without message */ did_yank = TRUE; } @@ -1423,14 +1437,14 @@ int op_delete(oparg_T *oap) if (oap->regname == 0 && oap->motion_type != MLINE && oap->line_count == 1) { oap->regname = '-'; - get_yank_register(oap->regname, TRUE); + get_yank_register(oap->regname, YREG_YANK); if (op_yank(oap, TRUE, FALSE) == OK) did_yank = TRUE; oap->regname = 0; } if(oap->regname == 0 && did_yank) { - set_clipboard(CB_LATEST); + set_clipboard(0); } /* * If there's too much stuff to fit in the yank register, then get a @@ -2372,7 +2386,7 @@ int op_yank(oparg_T *oap, int deleting, int mess) return OK; if (!deleting) /* op_delete() already set y_current */ - get_yank_register(oap->regname, TRUE); + get_yank_register(oap->regname, YREG_YANK); curr = y_current; /* append to existing contents */ @@ -2620,8 +2634,6 @@ do_put ( int allocated = FALSE; long cnt; - get_clipboard(regname, false); - if (flags & PUT_FIXINDENT) orig_indent = get_indent(); @@ -2694,7 +2706,7 @@ do_put ( y_array = &insert_string; } } else { - get_yank_register(regname, FALSE); + get_yank_register(regname, YREG_PASTE); y_type = y_current->y_type; y_width = y_current->y_width; @@ -3233,7 +3245,6 @@ void ex_display(exarg_T *eap) continue; /* did not ask for this register */ } - get_clipboard(name, true); if (i == -1) { if (y_previous != NULL) @@ -3243,6 +3254,8 @@ void ex_display(exarg_T *eap) } else yb = &(y_regs[i]); + get_clipboard(name, &yb, true); + if (name == vim_tolower(redir_reg) || (redir_reg == '"' && yb == y_previous)) continue; /* do not list register being written to, the @@ -4500,7 +4513,7 @@ int read_viminfo_register(vir_T *virp, int force) return TRUE; /* too many errors, pretend end-of-file */ do_it = FALSE; } - get_yank_register(*str++, FALSE); + get_yank_register(*str++, YREG_PUT); if (!force && y_current->y_array != NULL) do_it = FALSE; @@ -4661,12 +4674,10 @@ char_u get_reg_type(int regname, long *reglen) return MCHAR; } - get_clipboard(regname, false); - if (regname != NUL && !valid_yank_reg(regname, FALSE)) return MAUTO; - get_yank_register(regname, FALSE); + get_yank_register(regname, YREG_PASTE); if (y_current->y_array != NULL) { if (reglen != NULL && y_current->y_type == MBLOCK) @@ -4722,8 +4733,6 @@ void *get_reg_contents(int regname, int flags) if (regname != NUL && !valid_yank_reg(regname, FALSE)) return NULL; - get_clipboard(regname, false); - char_u *retval; int allocated; if (get_spec_reg(regname, &retval, &allocated, FALSE)) { @@ -4735,7 +4744,7 @@ void *get_reg_contents(int regname, int flags) return get_reg_wrap_one_line(vim_strsave(retval), flags); } - get_yank_register(regname, FALSE); + get_yank_register(regname, YREG_PASTE); if (y_current->y_array == NULL) return NULL; @@ -4796,7 +4805,7 @@ static bool init_write_reg(int name, struct yankreg **old_y_previous, *old_y_previous = y_previous; *old_y_current = y_current; - get_yank_register(name, true); + get_yank_register(name, YREG_YANK); if (!y_append && !must_append) { free_yank_all(); } @@ -5302,7 +5311,7 @@ static void free_register(struct yankreg *reg) } // return target register -static struct yankreg* adjust_clipboard_name(int *name, bool quiet) { +static struct yankreg* adjust_clipboard_name(int *name, bool quiet, bool writing) { if (*name == '*' || *name == '+') { if(!eval_has_provider("clipboard")) { if (!quiet) { @@ -5310,7 +5319,7 @@ static struct yankreg* adjust_clipboard_name(int *name, bool quiet) { } } return &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER]; - } else if ((*name == NUL || *name == CB_LATEST) && (cb_flags & CB_UNNAMEDMASK)) { + } else if ((*name == NUL) && (cb_flags & CB_UNNAMEDMASK)) { if(!eval_has_provider("clipboard")) { if (!quiet && !clipboard_didwarn_unnamed) { msg((char_u*)"clipboard: provider not available, ignoring clipboard=unnamed[plus]"); @@ -5319,15 +5328,15 @@ static struct yankreg* adjust_clipboard_name(int *name, bool quiet) { return NULL; } struct yankreg* target; - if (*name == CB_LATEST) { - target = y_current; - } else { - target = &y_regs[0]; - } if (cb_flags & CB_UNNAMEDPLUS) { *name = '+'; + target = &y_regs[STAR_REGISTER]; } else { *name = '*'; + target = &y_regs[PLUS_REGISTER]; + } + if (writing) { + target = y_current; } return target; // unnamed register } @@ -5335,9 +5344,9 @@ static struct yankreg* adjust_clipboard_name(int *name, bool quiet) { return NULL; } -static void get_clipboard(int name, bool quiet) +static void get_clipboard(int name, struct yankreg** target, bool quiet) { - struct yankreg* reg = adjust_clipboard_name(&name, quiet); + struct yankreg* reg = adjust_clipboard_name(&name, quiet, false); if (reg == NULL) { return; } @@ -5423,6 +5432,7 @@ static void get_clipboard(int name, bool quiet) reg->y_width = maxlen-1; } + *target = reg; return; err: @@ -5439,7 +5449,7 @@ err: static void set_clipboard(int name) { - struct yankreg* reg = adjust_clipboard_name(&name, false); + struct yankreg* reg = adjust_clipboard_name(&name, false, true); if (reg == NULL) { return; } diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index 74a3bf4ae0..e7ca183a0e 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -203,7 +203,6 @@ describe('clipboard usage', function() it('links the "* and unnamed registers', function() -- with cb=unnamed, "* and unnamed will be the same register - execute('set clipboard=unnamed') insert("some words") feed('^"*dwdw"*P') expect('words') @@ -215,6 +214,19 @@ describe('clipboard usage', function() words linewise stuff]]) end) + + it('does not clobber "0 when pasting', function() + insert('a line') + feed('yy') + execute("let g:test_clip['*'] = ['b line','']") + feed('"0pp"0p') + expect([[ + a line + a line + b line + a line]]) + end) + end) it('supports :put', function() @@ -256,4 +268,13 @@ describe('clipboard usage', function() [3] = {bold = true, foreground = Screen.colors.SeaGreen}}, {{bold = true, foreground = Screen.colors.Blue}}) end) + + it('can paste "* to the commandline', function() + insert('s/s/t/') + feed('gg"*y$:*') + expect('t/s/t/') + execute("let g:test_clip['*'] = ['s/s/u']") + feed(':*') + expect('t/u/t/') + end) end)