diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2014-12-08 18:23:09 -0500 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2014-12-08 18:23:09 -0500 |
commit | 8bb7aa329d20cb265d8952c96c84a0e54a5726ab (patch) | |
tree | 83a0ac7a24243d357c75ee976298901642df92c2 | |
parent | 8666a148ccacefe2d574eb2c1f2887b740fe6bfc (diff) | |
parent | df2eeaeb375a7a7f7cb92586b03d10260d485c90 (diff) | |
download | rneovim-8bb7aa329d20cb265d8952c96c84a0e54a5726ab.tar.gz rneovim-8bb7aa329d20cb265d8952c96c84a0e54a5726ab.tar.bz2 rneovim-8bb7aa329d20cb265d8952c96c84a0e54a5726ab.zip |
Merge pull request #1182 from bfredl/clipboard
clipboard: support separate +/* clipboards, linewise copy/paste and add tests
-rw-r--r-- | runtime/autoload/provider/clipboard.vim | 36 | ||||
-rw-r--r-- | runtime/doc/options.txt | 7 | ||||
-rw-r--r-- | src/nvim/eval.c | 20 | ||||
-rw-r--r-- | src/nvim/normal.c | 12 | ||||
-rw-r--r-- | src/nvim/ops.c | 163 | ||||
-rw-r--r-- | src/nvim/option.c | 10 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 8 | ||||
-rw-r--r-- | test/functional/clipboard/autoload/provider/clipboard.vim | 16 | ||||
-rw-r--r-- | test/functional/clipboard/clipboard_provider_spec.lua | 141 |
9 files changed, 319 insertions, 94 deletions
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 46c05a882c..458ef6257d 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -1,11 +1,11 @@ " The clipboard provider uses shell commands to communicate with the clipboard. " The provider function will only be registered if one of the supported " commands are available. -let s:copy = '' -let s:paste = '' +let s:copy = {} +let s:paste = {} function! s:try_cmd(cmd, ...) - let out = a:0 ? systemlist(a:cmd, a:1) : systemlist(a:cmd) + let out = a:0 ? systemlist(a:cmd, a:1, 1) : systemlist(a:cmd, [''], 1) if v:shell_error echo "clipboard: error: ".(len(out) ? out[0] : '') return '' @@ -14,14 +14,20 @@ function! s:try_cmd(cmd, ...) endfunction if executable('pbcopy') - let s:copy = 'pbcopy' - let s:paste = 'pbpaste' -elseif executable('xsel') - let s:copy = 'xsel -i -b' - let s:paste = 'xsel -o -b' + let s:copy['+'] = 'pbcopy' + let s:paste['+'] = 'pbpaste' + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] elseif executable('xclip') - let s:copy = 'xclip -i -selection clipboard' - let s:paste = 'xclip -o -selection clipboard' + let s:copy['+'] = 'xclip -i -selection clipboard' + let s:paste['+'] = 'xclip -o -selection clipboard' + let s:copy['*'] = 'xclip -i -selection primary' + let s:paste['*'] = 'xclip -o -selection primary' +elseif executable('xsel') + let s:copy['+'] = 'xsel -i -b' + let s:paste['+'] = 'xsel -o -b' + let s:copy['*'] = 'xsel -i -p' + let s:paste['*'] = 'xsel -o -p' else echom 'clipboard: No shell command for communicating with the clipboard found.' finish @@ -29,14 +35,14 @@ endif let s:clipboard = {} -function! s:clipboard.get(...) - return s:try_cmd(s:paste) +function! s:clipboard.get(reg) + return s:try_cmd(s:paste[a:reg]) endfunction -function! s:clipboard.set(...) - call s:try_cmd(s:copy, a:1) +function! s:clipboard.set(lines, regtype, reg) + call s:try_cmd(s:copy[a:reg], a:lines) endfunction function! provider#clipboard#Call(method, args) - return s:clipboard[a:method](a:args) + return call(s:clipboard[a:method],a:args,s:clipboard) endfunction diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 0844d74070..8672ab2af9 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -7547,13 +7547,6 @@ A jump table for the options with a short description can be found at |Q_op|. Note that this causes the whole buffer to be stored in memory. Set this option to a lower value if you run out of memory. - {Nvim} *'unnamedclip'* *ucp'* -'unnamedclip' 'ucp' boolean (default off) - global - Use the unnamed register to access the clipboard(when available). - This option has the same effect of setting 'clipboard' to - 'unnamed/unnamedplus' in Vim. - *'updatecount'* *'uc'* 'updatecount' 'uc' number (default: 200) global diff --git a/src/nvim/eval.c b/src/nvim/eval.c index be69bdbe61..b4d1677520 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5119,6 +5119,20 @@ void list_append_tv(list_T *l, typval_T *tv) } /* + * Add a list to a list. + */ +void list_append_list(list_T *list, list_T *itemlist) +{ + listitem_T *li = listitem_alloc(); + + li->li_tv.v_type = VAR_LIST; + li->li_tv.v_lock = 0; + li->li_tv.vval.v_list = itemlist; + list_append(list, li); + ++list->lv_refcount; +} + +/* * Add a dictionary to a list. Used by getqflist(). */ void list_append_dict(list_T *list, dict_T *dict) @@ -19815,16 +19829,12 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments) bool eval_has_provider(char *name) { -#define source_provider(name) \ - do_source((uint8_t *)"$VIMRUNTIME/autoload/provider/" name ".vim", \ - false, \ - false) #define check_provider(name) \ if (has_##name == -1) { \ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ if (!has_##name) { \ - source_provider(#name); \ + script_autoload((uint8_t *)"provider#" #name "#Call", false); \ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ } \ } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 1b21100933..192633a996 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -915,14 +915,7 @@ getcount: && !oap->op_type && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) { clearop(oap); - { - int regname = 0; - - /* Adjust the register according to 'clipboard', so that when - * "unnamed" is present it becomes '*' or '+' instead of '"'. */ - adjust_clipboard_register(®name); - set_reg_var(regname); - } + set_reg_var(0); } /* Get the length of mapped chars again after typing a count, second @@ -5105,7 +5098,6 @@ static void nv_brackets(cmdarg_T *cap) end = equalpos(start, VIsual) ? curwin->w_cursor : VIsual; curwin->w_cursor = (dir == BACKWARD ? start : end); } - adjust_clipboard_register(®name); prep_redo_cmd(cap); do_put(regname, dir, cap->count1, PUT_FIXINDENT); if (was_visual) { @@ -7272,10 +7264,8 @@ static void nv_put(cmdarg_T *cap) */ was_visual = true; regname = cap->oap->regname; - bool adjusted = adjust_clipboard_register(®name); if (regname == 0 || regname == '"' || VIM_ISDIGIT(regname) || regname == '-' - || adjusted ) { /* The delete is going to overwrite the register we want to * put, save it first. */ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 6bf3f6036f..c20a017088 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -60,6 +60,7 @@ #define DELETION_REGISTER 36 #define CLIP_REGISTER 37 +# define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS) /* * Each yank register is an array of pointers to lines. */ @@ -74,6 +75,7 @@ static struct yankreg *y_current; /* ptr to current yankreg */ static int y_append; /* TRUE when appending */ static struct yankreg *y_previous = NULL; /* ptr to last written yankreg */ +static bool clipboard_didwarn_unnamed = false; /* * structure used by block_prep, op_delete and op_yank for blockwise operators * also op_change, op_shift, op_insert, op_replace - AKelly @@ -751,7 +753,8 @@ void get_yank_register(int regname, int writing) int i; y_append = FALSE; - if ((regname == 0 || regname == '"') && !writing && y_previous != NULL) { + int unnamedclip = cb_flags & CB_UNNAMEDMASK; + if ((regname == 0 || regname == '"') && !unnamedclip && !writing && y_previous != NULL) { y_current = y_previous; return; } @@ -1302,18 +1305,6 @@ cmdline_paste_reg ( return OK; } -bool adjust_clipboard_register(int *rp) -{ - // If no reg. specified and 'unnamedclip' is set, use the - // clipboard register. - if (*rp == 0 && p_unc && eval_has_provider("clipboard")) { - *rp = '+'; - return true; - } - - return false; -} - /* * Handle a delete operation. * @@ -1328,7 +1319,6 @@ int op_delete(oparg_T *oap) struct block_def bd; linenr_T old_lcount = curbuf->b_ml.ml_line_count; int did_yank = FALSE; - int orig_regname = oap->regname; if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */ return OK; @@ -1342,8 +1332,6 @@ int op_delete(oparg_T *oap) return FAIL; } - bool adjusted = adjust_clipboard_register(&oap->regname); - if (has_mbyte) mb_adjust_opend(oap); @@ -1393,9 +1381,10 @@ int op_delete(oparg_T *oap) * register. For the black hole register '_' don't yank anything. */ if (oap->regname != '_') { - if (oap->regname != 0) { + bool unnamedclip = oap->regname == 0 && (cb_flags & CB_UNNAMEDMASK); + if (oap->regname != 0 || unnamedclip) { /* check for read-only register */ - if (!valid_yank_reg(oap->regname, TRUE)) { + if (!( valid_yank_reg(oap->regname, TRUE) || unnamedclip )) { beep_flush(); return OK; } @@ -1407,10 +1396,8 @@ int op_delete(oparg_T *oap) /* * Put deleted text into register 1 and shift number registers if the * delete contains a line break, or when a regname has been specified. - * Use the register name from before adjust_clip_reg() may have - * changed it. */ - if (orig_regname != 0 || oap->motion_type == MLINE + if (oap->regname != 0 || oap->motion_type == MLINE || oap->line_count > 1 || oap->use_reg_one) { y_current = &y_regs[9]; free_yank_all(); /* free register nine */ @@ -1424,9 +1411,7 @@ int op_delete(oparg_T *oap) /* Yank into small delete register when no named register specified * and the delete is within one line. */ - if (( - adjusted || - oap->regname == 0) && oap->motion_type != MLINE + if (oap->regname == 0 && oap->motion_type != MLINE && oap->line_count == 1) { oap->regname = '-'; get_yank_register(oap->regname, TRUE); @@ -2623,7 +2608,6 @@ do_put ( int allocated = FALSE; long cnt; - adjust_clipboard_register(®name); get_clipboard(regname); if (flags & PUT_FIXINDENT) @@ -3215,7 +3199,6 @@ void ex_display(exarg_T *eap) ) continue; /* did not ask for this register */ - adjust_clipboard_register(&name); get_clipboard(name); if (i == -1) { @@ -4842,6 +4825,7 @@ void write_reg_contents_ex(int name, if (!y_append && !must_append) free_yank_all(); str_to_reg(y_current, yank_type, str, len, block_len); + set_clipboard(name); /* ':let @" = "val"' should change the meaning of the "" register */ @@ -5225,33 +5209,82 @@ static void free_register(struct yankreg *reg) y_current = curr; } -static void copy_register(struct yankreg *dest, struct yankreg *src) -{ - free_register(dest); - *dest = *src; - dest->y_array = xcalloc(src->y_size, sizeof(uint8_t *)); - for (int j = 0; j < src->y_size; ++j) { - dest->y_array[j] = (uint8_t *)xstrdup((char *)src->y_array[j]); +// return target register +static int adjust_clipboard_name(int *name) { + if (*name == '*' || *name == '+') { + if(!eval_has_provider("clipboard")) { + EMSG("clipboard: provider is not available"); + return -1; + } + return CLIP_REGISTER; + } else if (*name == NUL && (cb_flags & (CB_UNNAMED | CB_UNNAMEDPLUS))) { + if(!eval_has_provider("clipboard")) { + if (!clipboard_didwarn_unnamed) { + msg((char_u*)"clipboard: provider not available, ignoring clipboard=unnamed[plus]"); + clipboard_didwarn_unnamed = true; + } + return -1; + } + if (cb_flags & CB_UNNAMEDPLUS) { + *name = '+'; + } else { + *name = '*'; + } + return 0; //unnamed } + // don't do anything for other register names + return -1; } static void get_clipboard(int name) { - if (!(name == '*' || name == '+' - || (p_unc && !name && eval_has_provider("clipboard")))) { + int ireg = adjust_clipboard_name(&name); + if (ireg < 0) { return; } - struct yankreg *reg = &y_regs[CLIP_REGISTER]; + struct yankreg *reg = &y_regs[ireg]; free_register(reg); + list_T *args = list_alloc(); + char_u regname = name; + list_append_string(args, ®name, 1); + typval_T result = eval_call_provider("clipboard", "get", args); if (result.v_type != VAR_LIST) { goto err; } - list_T *lines = result.vval.v_list; + list_T *res = result.vval.v_list, *lines = NULL; + if (res->lv_len == 2 && res->lv_first->li_tv.v_type == VAR_LIST) { + lines = res->lv_first->li_tv.vval.v_list; + if (res->lv_last->li_tv.v_type != VAR_STRING) { + goto err; + } + char_u* regtype = res->lv_last->li_tv.vval.v_string; + if (regtype == NULL || strlen((char*)regtype) != 1) { + goto err; + } + switch (regtype[0]) { + case 'v': case 'c': + reg->y_type = MCHAR; + break; + case 'V': case 'l': + reg->y_type = MLINE; + break; + case 'b': case Ctrl_V: + reg->y_type = MBLOCK; + break; + default: + goto err; + } + } else { + lines = res; + // provider did not specify regtype, calculate it below + reg->y_type = MAUTO; + } + reg->y_array = xcalloc(lines->lv_len, sizeof(uint8_t *)); reg->y_size = lines->lv_len; @@ -5263,9 +5296,23 @@ static void get_clipboard(int name) reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string); } - if (!name && p_unc) { - // copy to the unnamed register - copy_register(&y_regs[0], reg); + if (reg->y_type == MAUTO) { + if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) { + reg->y_type = MLINE; + free(reg->y_array[reg->y_size-1]); + reg->y_size--; + } else { + reg->y_type = MCHAR; + } + } else if (reg->y_type == MBLOCK) { + int maxlen = 0; + for (int i = 0; i < reg->y_size; i++) { + int rowlen = STRLEN(reg->y_array[i]); + if (rowlen > maxlen) { + maxlen = rowlen; + } + } + reg->y_width = maxlen-1; } return; @@ -5279,22 +5326,17 @@ err: } reg->y_array = NULL; reg->y_size = 0; - EMSG("Clipboard provider returned invalid data"); + EMSG("clipboard: provider returned invalid data"); } static void set_clipboard(int name) { - if (!(name == '*' || name == '+' - || (p_unc && !name && eval_has_provider("clipboard")))) { + int ireg = adjust_clipboard_name(&name); + if (ireg < 0) { return; } - struct yankreg *reg = &y_regs[CLIP_REGISTER]; - - if (!name && p_unc) { - // copy from the unnamed register - copy_register(reg, &y_regs[0]); - } + struct yankreg *reg = &y_regs[ireg]; list_T *lines = list_alloc(); @@ -5302,5 +5344,26 @@ static void set_clipboard(int name) list_append_string(lines, reg->y_array[i], -1); } - (void)eval_call_provider("clipboard", "set", lines); + list_T *args = list_alloc(); + list_append_list(args, lines); + + char_u regtype; + switch (reg->y_type) { + case MLINE: + regtype = 'V'; + list_append_string(lines, (char_u*)"", 0); + break; + case MCHAR: + regtype = 'v'; + break; + case MBLOCK: + regtype = 'b'; + break; + } + list_append_string(args, ®type, 1); + + char_u regname = name; + list_append_string(args, ®name, 1); + + (void)eval_call_provider("clipboard", "set", args); } diff --git a/src/nvim/option.c b/src/nvim/option.c index 2882d7a511..fd0978f3a6 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -527,7 +527,7 @@ static struct vimoption (char_u *)0L} SCRIPTID_INIT}, {"clipboard", "cb", P_STRING|P_VI_DEF|P_COMMA|P_NODUP, - (char_u *)NULL, PV_NONE, + (char_u *)&p_cb, PV_NONE, {(char_u *)"", (char_u *)0L} SCRIPTID_INIT}, {"cmdheight", "ch", P_NUM|P_VI_DEF|P_RALL, @@ -1620,9 +1620,6 @@ static struct vimoption {"undoreload", "ur", P_NUM|P_VI_DEF, (char_u *)&p_ur, PV_NONE, { (char_u *)10000L, (char_u *)0L} SCRIPTID_INIT}, - {"unnamedclip", "ucp", P_BOOL|P_VI_DEF|P_VIM, - (char_u *)&p_unc, PV_NONE, - {(char_u *)FALSE, (char_u *)FALSE} SCRIPTID_INIT}, {"updatecount", "uc", P_NUM|P_VI_DEF, (char_u *)&p_uc, PV_NONE, {(char_u *)200L, (char_u *)0L} SCRIPTID_INIT}, @@ -4279,6 +4276,10 @@ did_set_string_option ( if (check_opt_strings(p_ead, p_ead_values, FALSE) != OK) errmsg = e_invarg; } + else if (varp == &p_cb) { + if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, TRUE) != OK) + errmsg = e_invarg; + } /* When 'spelllang' or 'spellfile' is set and there is a window for this * buffer in which 'spell' is set load the wordlists. */ else if (varp == &(curbuf->b_s.b_p_spl) || varp == &(curbuf->b_s.b_p_spf)) { @@ -4846,7 +4847,6 @@ char_u *check_stl_option(char_u *s) return NULL; } - /* * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. * Return error message when failed, NULL when OK. diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 89264f8982..39dfbe8b88 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -317,6 +317,13 @@ EXTERN char_u *p_enc; /* 'encoding' */ EXTERN int p_deco; /* 'delcombine' */ EXTERN char_u *p_ccv; /* 'charconvert' */ EXTERN char_u *p_cedit; /* 'cedit' */ +EXTERN char_u *p_cb; /* 'clipboard' */ +EXTERN unsigned cb_flags; +#ifdef IN_OPTION_C +static char *(p_cb_values[]) = {"unnamed", "unnamedplus", NULL}; +#endif +# define CB_UNNAMED 0x001 +# define CB_UNNAMEDPLUS 0x002 EXTERN long p_cwh; /* 'cmdwinheight' */ EXTERN long p_ch; /* 'cmdheight' */ EXTERN int p_confirm; /* 'confirm' */ @@ -582,7 +589,6 @@ static char *(p_ttym_values[]) = EXTERN char_u *p_udir; /* 'undodir' */ EXTERN long p_ul; /* 'undolevels' */ EXTERN long p_ur; /* 'undoreload' */ -EXTERN int p_unc; /* 'unnamedclip' */ EXTERN long p_uc; /* 'updatecount' */ EXTERN long p_ut; /* 'updatetime' */ EXTERN char_u *p_fcs; /* 'fillchar' */ diff --git a/test/functional/clipboard/autoload/provider/clipboard.vim b/test/functional/clipboard/autoload/provider/clipboard.vim new file mode 100644 index 0000000000..6c05a19fc3 --- /dev/null +++ b/test/functional/clipboard/autoload/provider/clipboard.vim @@ -0,0 +1,16 @@ +let g:test_clip = { '+': [''], '*': [''], } + +let s:methods = {} + +function! s:methods.get(reg) + return g:test_clip[a:reg] +endfunction + +function! s:methods.set(lines, regtype, reg) + let g:test_clip[a:reg] = a:lines +endfunction + + +function! provider#clipboard#Call(method, args) + return call(s:methods[a:method],a:args,s:methods) +endfunction diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua new file mode 100644 index 0000000000..ccbb74e487 --- /dev/null +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -0,0 +1,141 @@ +-- Test clipboard provider support + +local helpers = require('test.functional.helpers') +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') +end + +local function basic_register_test() + insert("some words") + + feed('^dwP') + expect('some words') + + feed('veyP') + expect('some words words') + + feed('^dwywe"-p') + expect('wordssome words') + + feed('p') + expect('wordssome words words') + + feed('yyp') + expect([[ + wordssome words words + wordssome words words]]) + feed('d-') + + insert([[ + some text, and some more + random text stuff]]) + feed('ggtav+2ed$p') + expect([[ + some text, stuff and some more + random text]]) + reset() +end + +describe('clipboard usage', function() + setup(reset) + it("works", function() + basic_register_test() + + -- "* and unnamed should function as independent registers + insert("some words") + feed('^"*dwdw"*P') + expect('some ') + eq({'some '}, eval("g:test_clip['*']")) + reset() + + -- "* and "+ should be independent when the provider supports it + insert([[ + text: + first line + secound line + third line]]) + + feed('G"+dd"*dddd"+p"*pp') + expect([[ + text: + third line + 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['*']")) + reset() + + -- handle null bytes + insert("some\x16000text\n\x16000very binary\x16000") + feed('"*y-+"*p') + eq({'some\ntext', '\nvery binary\n',''}, eval("g:test_clip['*']")) + expect("some\x00text\n\x00very binary\x00\nsome\x00text\n\x00very binary\x00") + + -- test getreg/getregtype + eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1)")) + eq("V", eval("getregtype('*')")) + reset() + + -- blockwise paste + 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("\x165", eval("getregtype('*')")) + reset() + + -- test setreg + execute('call setreg("*", "setted\\ntext", "c")') + execute('call setreg("+", "explicitly\\nlines", "l")') + feed('"+P"*p') + expect([[ + esetted + textxplicitly + lines + ]]) + reset() + + -- test let @+ (issue #1427) + execute("let @+ = 'some'") + execute("let @* = ' other stuff'") + eq({'some'}, eval("g:test_clip['+']")) + eq({' other stuff'}, eval("g:test_clip['*']")) + feed('"+p"*p') + expect('some other stuff') + execute("let @+ .= ' more'") + feed('dd"+p') + expect('some more') + reset() + + -- the basic behavior of unnamed register should be the same + -- even when handled by clipboard provider + execute('set clipboard=unnamed') + basic_register_test() + + -- with cb=unnamed, "* and unnamed will be the same register + execute('set clipboard=unnamed') + insert("some words") + feed('^"*dwdw"*P') + expect('words') + eq({'words'}, eval("g:test_clip['*']")) + + execute("let g:test_clip['*'] = ['linewise stuff','']") + feed('p') + expect([[ + words + linewise stuff]]) + reset() + + end) +end) |