neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

clipboard_spec.lua (23966B)


      1 -- Test clipboard provider support
      2 
      3 local t = require('test.testutil')
      4 local n = require('test.functional.testnvim')()
      5 local Screen = require('test.functional.ui.screen')
      6 
      7 local clear, feed, insert = n.clear, n.feed, n.insert
      8 local expect, eq, eval, source = n.expect, t.eq, n.eval, n.source
      9 local command = n.command
     10 local api = n.api
     11 
     12 local function basic_register_test(noblock)
     13  insert('some words')
     14 
     15  feed('^dwP')
     16  expect('some words')
     17 
     18  feed('veyP')
     19  expect('some words words')
     20 
     21  feed('^dwywe"-p')
     22  expect('wordssome  words')
     23 
     24  feed('p')
     25  expect('wordssome words  words')
     26 
     27  feed('yyp')
     28  expect([[
     29    wordssome words  words
     30    wordssome words  words]])
     31  feed('d-')
     32 
     33  insert([[
     34    some text, and some more
     35    random text stuff]])
     36  feed('ggtav+2ed$p')
     37  expect([[
     38    some text, stuff and some more
     39    random text]])
     40 
     41  -- deleting line or word uses "1/"- and doesn't clobber "0
     42  -- and deleting word to unnamed doesn't clobber "1
     43  feed('ggyyjdddw"0p"1p"-P')
     44  expect([[
     45    text, stuff and some more
     46    some text, stuff and some more
     47    some random text]])
     48 
     49  -- delete line doesn't clobber "-
     50  feed('dd"-P')
     51  expect([[
     52    text, stuff and some more
     53    some some text, stuff and some more]])
     54 
     55  -- deleting a word to named ("a) doesn't update "1 or "-
     56  feed('gg"adwj"1P^"-P')
     57  expect([[
     58    , stuff and some more
     59    some some random text
     60    some some text, stuff and some more]])
     61 
     62  -- deleting a line does update ""
     63  feed('ggdd""P')
     64  expect([[
     65    , stuff and some more
     66    some some random text
     67    some some text, stuff and some more]])
     68 
     69  feed('ggw<c-v>jwyggP')
     70  if noblock then
     71    expect([[
     72      stuf
     73      me s
     74      , stuff and some more
     75      some some random text
     76      some some text, stuff and some more]])
     77  else
     78    expect([[
     79      stuf, stuff and some more
     80      me ssome some random text
     81      some some text, stuff and some more]])
     82  end
     83 
     84  -- pasting in visual does unnamed delete of visual selection
     85  feed('ggdG')
     86  insert('one and two and three')
     87  feed('"ayiwbbviw"ap^viwp$viw"-p')
     88  expect('two and three and one')
     89 end
     90 
     91 describe('clipboard', function()
     92  local screen
     93 
     94  before_each(function()
     95    clear()
     96    screen = Screen.new(72, 4)
     97  end)
     98 
     99  it('unnamed register works without provider', function()
    100    eq('"', eval('v:register'))
    101    basic_register_test()
    102  end)
    103 
    104  it('using "+ in Normal mode with invalid g:clipboard always shows error', function()
    105    insert('a')
    106    command("let g:clipboard = 'bogus'")
    107    feed('"+yl')
    108    screen:expect([[
    109      ^a                                                                       |
    110      {1:~                                                                       }|*2
    111      clipboard: No provider. Try ":checkhealth" or ":h clipboard".           |
    112    ]])
    113    feed('"+p')
    114    screen:expect([[
    115      a^a                                                                      |
    116      {1:~                                                                       }|*2
    117      clipboard: No provider. Try ":checkhealth" or ":h clipboard".           |
    118    ]])
    119  end)
    120 
    121  it('using clipboard=unnamedplus with invalid g:clipboard shows error once', function()
    122    insert('a')
    123    command("let g:clipboard = 'bogus'")
    124    command('set clipboard=unnamedplus')
    125    feed('yl')
    126    screen:expect([[
    127      ^a                                                                       |
    128      {1:~                                                                       }|*2
    129      clipboard: No provider. Try ":checkhealth" or ":h clipboard".           |
    130    ]])
    131    feed(':<CR>')
    132    screen:expect([[
    133      ^a                                                                       |
    134      {1:~                                                                       }|*2
    135      :                                                                       |
    136    ]])
    137    feed('p')
    138    screen:expect([[
    139      a^a                                                                      |
    140      {1:~                                                                       }|*2
    141      :                                                                       |
    142    ]])
    143  end)
    144 
    145  it('`:redir @+>` with invalid g:clipboard shows exactly one error #7184', function()
    146    command("let g:clipboard = 'bogus'")
    147    n.exec([[
    148      redir @+>
    149        silent echo system("cat test/functional/fixtures/tty-test.c")
    150      redir END
    151    ]])
    152    screen:expect([[
    153      ^                                                                        |
    154      {1:~                                                                       }|*2
    155      clipboard: No provider. Try ":checkhealth" or ":h clipboard".           |
    156    ]])
    157  end)
    158 
    159  it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184', function()
    160    command("let g:clipboard = 'bogus'")
    161    feed(':redir @+> | bogus_cmd | redir END<cr>')
    162    screen:expect {
    163      grid = [[
    164    {3:                                                                        }|
    165    clipboard: No provider. Try ":checkhealth" or ":h clipboard".           |
    166    {9:E492: Not an editor command: bogus_cmd | redir END}                      |
    167    {6:Press ENTER or type command to continue}^                                 |
    168    ]],
    169    }
    170  end)
    171 
    172  it('invalid g:clipboard shows hint if :redir is not active', function()
    173    command("let g:clipboard = 'bogus'")
    174    eq('', eval('provider#clipboard#Executable()'))
    175    eq('clipboard: invalid g:clipboard', eval('provider#clipboard#Error()'))
    176 
    177    command("let g:clipboard = 'bogus'")
    178    -- Explicit clipboard attempt, should show a hint message.
    179    feed(':let @+="foo"<cr>')
    180    screen:expect([[
    181      ^                                                                        |
    182      {1:~                                                                       }|*2
    183      clipboard: No provider. Try ":checkhealth" or ":h clipboard".           |
    184    ]])
    185  end)
    186 
    187  it('valid g:clipboard', function()
    188    -- provider#clipboard#Executable() only checks the structure.
    189    api.nvim_set_var('clipboard', {
    190      ['name'] = 'clippy!',
    191      ['copy'] = { ['+'] = 'any command', ['*'] = 'some other' },
    192      ['paste'] = { ['+'] = 'any command', ['*'] = 'some other' },
    193    })
    194    eq('clippy!', eval('provider#clipboard#Executable()'))
    195    eq('', eval('provider#clipboard#Error()'))
    196  end)
    197 
    198  it('g:clipboard using lists', function()
    199    source([[let g:clipboard = {
    200            \  'name': 'custom',
    201            \  'copy': { '+': ['any', 'command'], '*': ['some', 'other'] },
    202            \  'paste': { '+': ['any', 'command'], '*': ['some', 'other'] },
    203            \}]])
    204    eq('custom', eval('provider#clipboard#Executable()'))
    205    eq('', eval('provider#clipboard#Error()'))
    206  end)
    207 
    208  it('g:clipboard using Vimscript functions', function()
    209    -- Implements a fake clipboard provider. cache_enabled is meaningless here.
    210    source([[let g:clipboard = {
    211            \  'name': 'custom',
    212            \  'copy': {
    213            \     '+': {lines, regtype -> extend(g:, {'dummy_clipboard_plus': [lines, regtype]}) },
    214            \     '*': {lines, regtype -> extend(g:, {'dummy_clipboard_star': [lines, regtype]}) },
    215            \   },
    216            \  'paste': {
    217            \     '+': {-> get(g:, 'dummy_clipboard_plus', [])},
    218            \     '*': {-> get(g:, 'dummy_clipboard_star', [])},
    219            \  },
    220            \  'cache_enabled': 1,
    221            \}]])
    222 
    223    eq('', eval('provider#clipboard#Error()'))
    224    eq('custom', eval('provider#clipboard#Executable()'))
    225 
    226    eq('', eval("getreg('*')"))
    227    eq('', eval("getreg('+')"))
    228 
    229    command('call setreg("*", "star")')
    230    command('call setreg("+", "plus")')
    231    eq('star', eval("getreg('*')"))
    232    eq('plus', eval("getreg('+')"))
    233 
    234    command('call setreg("*", "star", "v")')
    235    eq({ { 'star' }, 'v' }, eval('g:dummy_clipboard_star'))
    236    command('call setreg("*", "star", "V")')
    237    eq({ { 'star', '' }, 'V' }, eval('g:dummy_clipboard_star'))
    238    command('call setreg("*", "star", "b")')
    239    eq({ { 'star', '' }, 'b' }, eval('g:dummy_clipboard_star'))
    240  end)
    241 
    242  describe('g:clipboard[paste] Vimscript function', function()
    243    it('can return empty list for empty clipboard', function()
    244      source([[let g:dummy_clipboard = []
    245              let g:clipboard = {
    246              \  'name': 'custom',
    247              \  'copy': { '*': {lines, regtype ->  0} },
    248              \  'paste': { '*': {-> g:dummy_clipboard} },
    249              \}]])
    250      eq('', eval('provider#clipboard#Error()'))
    251      eq('custom', eval('provider#clipboard#Executable()'))
    252      eq('', eval("getreg('*')"))
    253    end)
    254 
    255    it('can return a list with a single string', function()
    256      source([=[let g:dummy_clipboard = ['hello']
    257              let g:clipboard = {
    258              \  'name': 'custom',
    259              \  'copy': { '*': {lines, regtype ->  0} },
    260              \  'paste': { '*': {-> g:dummy_clipboard} },
    261              \}]=])
    262      eq('', eval('provider#clipboard#Error()'))
    263      eq('custom', eval('provider#clipboard#Executable()'))
    264 
    265      eq('hello', eval("getreg('*')"))
    266      source([[let g:dummy_clipboard = [''] ]])
    267      eq('', eval("getreg('*')"))
    268    end)
    269 
    270    it('can return a list of lines if a regtype is provided', function()
    271      source([=[let g:dummy_clipboard = [['hello'], 'v']
    272              let g:clipboard = {
    273              \  'name': 'custom',
    274              \  'copy': { '*': {lines, regtype ->  0} },
    275              \  'paste': { '*': {-> g:dummy_clipboard} },
    276              \}]=])
    277      eq('', eval('provider#clipboard#Error()'))
    278      eq('custom', eval('provider#clipboard#Executable()'))
    279      eq('hello', eval("getreg('*')"))
    280    end)
    281 
    282    it('can return a list of lines instead of [lines, regtype]', function()
    283      source([=[let g:dummy_clipboard = ['hello', 'v']
    284              let g:clipboard = {
    285              \  'name': 'custom',
    286              \  'copy': { '*': {lines, regtype ->  0} },
    287              \  'paste': { '*': {-> g:dummy_clipboard} },
    288              \}]=])
    289      eq('', eval('provider#clipboard#Error()'))
    290      eq('custom', eval('provider#clipboard#Executable()'))
    291      eq('hello\nv', eval("getreg('*')"))
    292    end)
    293  end)
    294 end)
    295 
    296 describe('clipboard (with fake clipboard.vim)', function()
    297  local function reset(...)
    298    clear('--cmd', 'set rtp^=test/functional/fixtures', ...)
    299  end
    300 
    301  before_each(function()
    302    reset()
    303    command('call getreg("*")') -- force load of provider
    304  end)
    305 
    306  it('`:redir @+>` invokes clipboard once-per-message', function()
    307    eq(0, eval('g:clip_called_set'))
    308    n.exec([[
    309      redir @+>
    310        silent echo system("cat test/functional/fixtures/tty-test.c")
    311      redir END
    312    ]])
    313    -- Assuming tty-test.c has >100 lines.
    314    assert(eval('g:clip_called_set') > 100)
    315  end)
    316 
    317  it('`:redir @">` does NOT invoke clipboard', function()
    318    -- :redir to a non-clipboard register, with `:set clipboard=unnamed` does
    319    -- NOT propagate to the clipboard. This is consistent with Vim.
    320    command('set clipboard=unnamedplus')
    321    eq(0, eval('g:clip_called_set'))
    322    n.exec([[
    323      redir @">
    324        silent echo system("cat test/functional/fixtures/tty-test.c")
    325      redir END
    326    ]])
    327    eq(0, eval('g:clip_called_set'))
    328  end)
    329 
    330  it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184', function()
    331    local screen = Screen.new(72, 4)
    332    feed(':redir @+> | bogus_cmd | redir END<cr>')
    333    screen:expect([[
    334      ^                                                                        |
    335      {1:~                                                                       }|*2
    336      {9:E492: Not an editor command: bogus_cmd | redir END}                      |
    337    ]])
    338  end)
    339 
    340  it('has independent "* and unnamed registers by default', function()
    341    insert('some words')
    342    feed('^"*dwdw"*P')
    343    expect('some ')
    344    eq({ { 'some ' }, 'v' }, eval("g:test_clip['*']"))
    345    eq('words', eval("getreg('\"', 1)"))
    346  end)
    347 
    348  it('supports separate "* and "+ when the provider supports it', function()
    349    insert([[
    350      text:
    351      first line
    352      second line
    353      third line]])
    354 
    355    feed('G"+dd"*dddd"+p"*pp')
    356    expect([[
    357      text:
    358      third line
    359      second line
    360      first line]])
    361    -- linewise selection should be encoded as an extra newline
    362    eq({ { 'third line', '' }, 'V' }, eval("g:test_clip['+']"))
    363    eq({ { 'second line', '' }, 'V' }, eval("g:test_clip['*']"))
    364  end)
    365 
    366  it('handles null bytes when pasting and in getreg', function()
    367    insert('some\022000text\n\022000very binary\022000')
    368    feed('"*y-+"*p')
    369    eq({ { 'some\ntext', '\nvery binary\n', '' }, 'V' }, eval("g:test_clip['*']"))
    370    expect('some\00text\n\00very binary\00\nsome\00text\n\00very binary\00')
    371 
    372    -- test getreg/getregtype
    373    eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1)"))
    374    eq('V', eval("getregtype('*')"))
    375 
    376    -- getreg supports three arguments
    377    eq('some\ntext\n\nvery binary\n\n', eval("getreg('*', 1, 0)"))
    378    eq({ 'some\ntext', '\nvery binary\n' }, eval("getreg('*', 1, 1)"))
    379  end)
    380 
    381  it('autodetects regtype', function()
    382    command("let g:test_clip['*'] = ['linewise stuff','']")
    383    command("let g:test_clip['+'] = ['charwise','stuff']")
    384    eq('V', eval("getregtype('*')"))
    385    eq('v', eval("getregtype('+')"))
    386    insert('just some text')
    387    feed('"*p"+p')
    388    expect([[
    389      just some text
    390      lcharwise
    391      stuffinewise stuff]])
    392  end)
    393 
    394  it('support blockwise operations', function()
    395    insert([[
    396      much
    397      text]])
    398    command("let g:test_clip['*'] = [['very','block'],'b']")
    399    feed('gg"*P')
    400    expect([[
    401      very much
    402      blocktext]])
    403    eq('\0225', eval("getregtype('*')"))
    404    feed('gg4l<c-v>j4l"+ygg"+P')
    405    expect([[
    406       muchvery much
    407      ktextblocktext]])
    408    eq({ { ' much', 'ktext', '' }, 'b' }, eval("g:test_clip['+']"))
    409  end)
    410 
    411  it('supports setreg()', function()
    412    command('call setreg("*", "setted\\ntext", "c")')
    413    command('call setreg("+", "explicitly\\nlines", "l")')
    414    feed('"+P"*p')
    415    expect([[
    416        esetted
    417        textxplicitly
    418        lines
    419        ]])
    420    command('call setreg("+", "blocky\\nindeed", "b")')
    421    feed('"+p')
    422    expect([[
    423        esblockyetted
    424        teindeedxtxplicitly
    425        lines
    426        ]])
    427  end)
    428 
    429  it('supports :let @+ (issue #1427)', function()
    430    command("let @+ = 'some'")
    431    command("let @* = ' other stuff'")
    432    eq({ { 'some' }, 'v' }, eval("g:test_clip['+']"))
    433    eq({ { ' other stuff' }, 'v' }, eval("g:test_clip['*']"))
    434    feed('"+p"*p')
    435    expect('some other stuff')
    436    command("let @+ .= ' more'")
    437    feed('dd"+p')
    438    expect('some more')
    439  end)
    440 
    441  it('pastes unnamed register if the provider fails', function()
    442    insert('the text')
    443    feed('yy')
    444    command('let g:cliperror = 1')
    445    feed('"*p')
    446    expect([[
    447      the text
    448      the text]])
    449  end)
    450 
    451  describe('with clipboard=unnamed', function()
    452    -- the basic behavior of unnamed register should be the same
    453    -- even when handled by clipboard provider
    454    before_each(function()
    455      feed(':set clipboard=unnamed<cr>')
    456    end)
    457 
    458    it('works', function()
    459      basic_register_test()
    460    end)
    461 
    462    it('works with pure text clipboard', function()
    463      command('let g:cliplossy = 1')
    464      -- expect failure for block mode
    465      basic_register_test(true)
    466    end)
    467 
    468    it('links the "* and unnamed registers', function()
    469      -- with cb=unnamed, "* and unnamed will be the same register
    470      insert('some words')
    471      feed('^"*dwdw"*P')
    472      expect('words')
    473      eq({ { 'words' }, 'v' }, eval("g:test_clip['*']"))
    474 
    475      -- "+ shouldn't have changed
    476      eq({ '' }, eval("g:test_clip['+']"))
    477 
    478      command("let g:test_clip['*'] = ['linewise stuff','']")
    479      feed('p')
    480      expect([[
    481        words
    482        linewise stuff]])
    483    end)
    484 
    485    it('does not clobber "0 when pasting', function()
    486      insert('a line')
    487      feed('yy')
    488      command("let g:test_clip['*'] = ['b line','']")
    489      feed('"0pp"0p')
    490      expect([[
    491        a line
    492        a line
    493        b line
    494        a line]])
    495    end)
    496 
    497    it('supports v:register and getreg() without parameters', function()
    498      eq('*', eval('v:register'))
    499      command("let g:test_clip['*'] = [['some block',''], 'b']")
    500      eq('some block', eval('getreg()'))
    501      eq('\02210', eval('getregtype()'))
    502    end)
    503 
    504    it('yanks visual selection when pasting', function()
    505      insert('indeed visual')
    506      command("let g:test_clip['*'] = [['clipboard'], 'c']")
    507      feed('viwp')
    508      eq({ { 'visual' }, 'v' }, eval("g:test_clip['*']"))
    509      expect('indeed clipboard')
    510 
    511      -- explicit "* should do the same
    512      command("let g:test_clip['*'] = [['star'], 'c']")
    513      feed('viw"*p')
    514      eq({ { 'clipboard' }, 'v' }, eval("g:test_clip['*']"))
    515      expect('indeed star')
    516    end)
    517 
    518    it('unnamed operations work even if the provider fails', function()
    519      insert('the text')
    520      feed('yy')
    521      command('let g:cliperror = 1')
    522      feed('p')
    523      expect([[
    524        the text
    525        the text]])
    526    end)
    527 
    528    it('is updated on global changes', function()
    529      insert([[
    530 text
    531 match
    532 match
    533 text
    534      ]])
    535      command('g/match/d')
    536      eq('match\n', eval('getreg("*")'))
    537      feed('u')
    538      eval('setreg("*", "---")')
    539      command('g/test/')
    540      feed('<esc>')
    541      eq('---', eval('getreg("*")'))
    542    end)
    543 
    544    it('works in the cmdline window', function()
    545      feed('q:itext<esc>yy')
    546      eq({ { 'text', '' }, 'V' }, eval("g:test_clip['*']"))
    547      command("let g:test_clip['*'] = [['star'], 'c']")
    548      feed('p')
    549      eq('textstar', api.nvim_get_current_line())
    550    end)
    551 
    552    it('block paste works correctly', function()
    553      insert([[
    554        aabbcc
    555        ddeeff
    556      ]])
    557      feed('gg^<C-v>') -- Goto start of top line enter visual block mode
    558      feed('3ljy^k') -- yank 4x2 block & goto initial location
    559      feed('P') -- Paste it before cursor
    560      expect([[
    561        aabbaabbcc
    562        ddeeddeeff
    563      ]])
    564    end)
    565 
    566    it('block paste computes block width correctly #35034', function()
    567      insert('あいうえお')
    568      feed('0<C-V>ly')
    569      feed('P')
    570      expect('あいあいうえお')
    571      feed('A\nxxx\nxx<Esc>')
    572      feed('0<C-V>kkly')
    573      feed('P')
    574      expect([[
    575        あいあいあいうえお
    576        xxx xxx
    577        xx  xx]])
    578      feed('G0<C-V>ky')
    579      feed('P')
    580      expect([[
    581        あいあいあいうえお
    582        xxxx xxx
    583        xxx  xx]])
    584    end)
    585  end)
    586 
    587  describe('clipboard=unnamedplus', function()
    588    before_each(function()
    589      feed(':set clipboard=unnamedplus<cr>')
    590    end)
    591 
    592    it('links the "+ and unnamed registers', function()
    593      eq('+', eval('v:register'))
    594      insert('one two')
    595      feed('^"+dwdw"+P')
    596      expect('two')
    597      eq({ { 'two' }, 'v' }, eval("g:test_clip['+']"))
    598 
    599      -- "* shouldn't have changed
    600      eq({ '' }, eval("g:test_clip['*']"))
    601 
    602      command("let g:test_clip['+'] = ['three']")
    603      feed('p')
    604      expect('twothree')
    605    end)
    606 
    607    it('and unnamed, yanks to both', function()
    608      command('set clipboard=unnamedplus,unnamed')
    609      insert([[
    610        really unnamed
    611        text]])
    612      feed('ggdd"*p"+p')
    613      expect([[
    614        text
    615        really unnamed
    616        really unnamed]])
    617      eq({ { 'really unnamed', '' }, 'V' }, eval("g:test_clip['+']"))
    618      eq({ { 'really unnamed', '' }, 'V' }, eval("g:test_clip['*']"))
    619 
    620      -- unnamedplus takes precedence when pasting
    621      eq('+', eval('v:register'))
    622      command("let g:test_clip['+'] = ['the plus','']")
    623      command("let g:test_clip['*'] = ['the star','']")
    624      feed('p')
    625      expect([[
    626        text
    627        really unnamed
    628        really unnamed
    629        the plus]])
    630    end)
    631 
    632    it('is updated on global changes', function()
    633      insert([[
    634 text
    635 match
    636 match
    637 text
    638      ]])
    639      command('g/match/d')
    640      eq('match\n', eval('getreg("+")'))
    641      feed('u')
    642      eval('setreg("+", "---")')
    643      command('g/test/')
    644      feed('<esc>')
    645      eq('---', eval('getreg("+")'))
    646    end)
    647  end)
    648 
    649  it('sets v:register after startup', function()
    650    reset()
    651    eq('"', eval('v:register'))
    652    reset('--cmd', 'set clipboard=unnamed')
    653    eq('*', eval('v:register'))
    654  end)
    655 
    656  it('supports :put', function()
    657    insert('a line')
    658    command("let g:test_clip['*'] = ['some text']")
    659    command("let g:test_clip['+'] = ['more', 'text', '']")
    660    command(':put *')
    661    expect([[
    662    a line
    663    some text]])
    664    command(':put +')
    665    expect([[
    666    a line
    667    some text
    668    more
    669    text]])
    670  end)
    671 
    672  it('supports "+ and "* in registers', function()
    673    local screen = Screen.new(60, 10)
    674    feed(":let g:test_clip['*'] = ['some', 'star data','']<cr>")
    675    feed(":let g:test_clip['+'] = ['such', 'plus', 'stuff']<cr>")
    676    feed(':registers<cr>')
    677    screen:expect(
    678      [[
    679                                                                  |
    680      {0:~                                                           }|*2
    681      {4:                                                            }|
    682      :registers                                                  |
    683      {1:Type Name Content}                                           |
    684        l  "*   some{2:^J}star data{2:^J}                                 |
    685        c  "+   such{2:^J}plus{2:^J}stuff                                 |
    686        c  ":   let g:test_clip['+'] = ['such', 'plus', 'stuff']  |
    687      {3:Press ENTER or type command to continue}^                     |
    688    ]],
    689      {
    690        [0] = { bold = true, foreground = Screen.colors.Blue },
    691        [1] = { bold = true, foreground = Screen.colors.Fuchsia },
    692        [2] = { foreground = Screen.colors.Blue },
    693        [3] = { bold = true, foreground = Screen.colors.SeaGreen },
    694        [4] = { bold = true, reverse = true },
    695      }
    696    )
    697    feed('<cr>') -- clear out of Press ENTER screen
    698  end)
    699 
    700  it('can paste "* to the commandline', function()
    701    insert('s/s/t/')
    702    feed('gg"*y$:<c-r>*<cr>')
    703    expect('t/s/t/')
    704    command("let g:test_clip['*'] = ['s/s/u']")
    705    feed(':<c-r>*<cr>')
    706    expect('t/u/t/')
    707  end)
    708 
    709  it('supports :redir @*>', function()
    710    command("let g:test_clip['*'] = ['stuff']")
    711    command('redir @*>')
    712    -- it is made empty
    713    eq({ { '' }, 'v' }, eval("g:test_clip['*']"))
    714    feed(':let g:test = doesnotexist<cr>')
    715    feed('<cr>')
    716    eq(
    717      { {
    718        '',
    719        '',
    720        'E121: Undefined variable: doesnotexist',
    721      }, 'v' },
    722      eval("g:test_clip['*']")
    723    )
    724    feed(':echo "Howdy!"<cr>')
    725    eq({
    726      {
    727        '',
    728        '',
    729        'E121: Undefined variable: doesnotexist',
    730        '',
    731        'Howdy!',
    732      },
    733      'v',
    734    }, eval("g:test_clip['*']"))
    735  end)
    736 
    737  it('handles middleclick correctly', function()
    738    command('set mouse=a')
    739 
    740    local screen = Screen.new(30, 5)
    741    insert([[
    742      the source
    743      a target]])
    744    feed('gg"*ywwyw')
    745    -- clicking depends on the exact visual layout, so expect it:
    746    screen:expect([[
    747      the ^source                    |
    748      a target                      |
    749      {1:~                             }|*2
    750                                    |
    751    ]])
    752 
    753    feed('<MiddleMouse><0,1>')
    754    expect([[
    755      the source
    756      the a target]])
    757 
    758    -- on error, fall back to unnamed register
    759    command('let g:cliperror = 1')
    760    feed('<MiddleMouse><6,1>')
    761    expect([[
    762      the source
    763      the a sourcetarget]])
    764  end)
    765 
    766  it('setreg("*") with clipboard=unnamed #5646', function()
    767    source([=[
    768      function! Paste_without_yank(direction) range
    769        let [reg_save,regtype_save] = [getreg('*'), getregtype('*')]
    770        normal! gvp
    771        call setreg('*', reg_save, regtype_save)
    772      endfunction
    773      xnoremap p :call Paste_without_yank('p')<CR>
    774      set clipboard=unnamed
    775    ]=])
    776    insert('some words')
    777    feed('gg0yiw')
    778    feed('wviwp')
    779    expect('some some')
    780    eq('some', eval('getreg("*")'))
    781  end)
    782 
    783  it('does not fall back to unnamed register with getreg() #24257', function()
    784    eval('setreg("", "wrong")')
    785    command('let g:cliperror = 1')
    786    eq('', eval('getreg("*")'))
    787    eq('', eval('getreg("+")'))
    788  end)
    789 end)