neovim

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

inccommand_spec.lua (84175B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 local Screen = require('test.functional.ui.screen')
      4 
      5 local clear = n.clear
      6 local command = n.command
      7 local eq = t.eq
      8 local eval = n.eval
      9 local expect = n.expect
     10 local feed = n.feed
     11 local insert = n.insert
     12 local fn = n.fn
     13 local api = n.api
     14 local matches = t.matches
     15 local ok = t.ok
     16 local retry = t.retry
     17 local source = n.source
     18 local poke_eventloop = n.poke_eventloop
     19 local sleep = vim.uv.sleep
     20 local testprg = n.testprg
     21 local assert_alive = n.assert_alive
     22 
     23 local default_text = [[
     24  Inc substitution on
     25  two lines
     26 ]]
     27 
     28 local multiline_text = [[
     29  1 2 3
     30  A B C
     31  4 5 6
     32  X Y Z
     33  7 8 9
     34 ]]
     35 
     36 local multimatch_text = [[
     37  a bdc eae a fgl lzia r
     38  x
     39 ]]
     40 
     41 local multibyte_text = [[
     42 £ ¥ ѫѫ PEPPERS
     43 £ ¥ ѫfѫ
     44 a£ ѫ¥KOL
     45 £ ¥  libm
     46 £ ¥
     47 ]]
     48 
     49 local long_multiline_text = [[
     50  1 2 3
     51  A B C
     52  4 5 6
     53  X Y Z
     54  7 8 9
     55  K L M
     56  a b c
     57  d e f
     58  q r s
     59  x y z
     60  £ m n
     61  t œ ¥
     62 ]]
     63 
     64 local function common_setup(screen, inccommand, text)
     65  if screen then
     66    command('syntax on')
     67    command('set nohlsearch')
     68    command('hi Substitute guifg=red guibg=yellow')
     69 
     70    screen:add_extra_attr_ids {
     71      [100] = { underline = true },
     72      [101] = { underline = true, foreground = Screen.colors.SlateBlue, bold = true },
     73      vis = { background = Screen.colors.LightGrey },
     74    }
     75  end
     76 
     77  command('set inccommand=' .. (inccommand or ''))
     78 
     79  if text then
     80    insert(text)
     81  end
     82 end
     83 
     84 describe(':substitute, inccommand=split interactivity', function()
     85  before_each(function()
     86    clear()
     87    common_setup(nil, 'split', default_text)
     88  end)
     89 
     90  -- Test the tests: verify that the `1==bufnr('$')` assertion
     91  -- in the "no preview" tests (below) actually means something.
     92  it('previews interactive cmdline', function()
     93    feed(':%s/tw/MO/g')
     94    retry(nil, 1000, function()
     95      eq(2, eval("bufnr('$')"))
     96    end)
     97  end)
     98 
     99  it('no preview if invoked by a script', function()
    100    source('%s/tw/MO/g')
    101    poke_eventloop()
    102    eq(1, eval("bufnr('$')"))
    103    -- sanity check: assert the buffer state
    104    expect(default_text:gsub('tw', 'MO'))
    105  end)
    106 
    107  it('no preview if invoked by feedkeys()', function()
    108    -- in a script...
    109    source([[:call feedkeys(":%s/tw/MO/g\<CR>")]])
    110    -- or interactively...
    111    feed([[:call feedkeys(":%s/bs/BUU/g\<lt>CR>")<CR>]])
    112    eq(1, eval("bufnr('$')"))
    113    -- sanity check: assert the buffer state
    114    expect(default_text:gsub('tw', 'MO'):gsub('bs', 'BUU'))
    115  end)
    116 end)
    117 
    118 describe(":substitute, 'inccommand' preserves", function()
    119  before_each(clear)
    120 
    121  it('listed buffers (:ls)', function()
    122    local screen = Screen.new(30, 10)
    123    common_setup(screen, 'split', 'ABC')
    124 
    125    feed(':%s/AB/BA/')
    126    poke_eventloop()
    127    feed('<CR>')
    128    feed(':ls<CR>')
    129 
    130    screen:expect([[
    131      BAC                           |
    132      {1:~                             }|*3
    133      {3:                              }|
    134      :ls                           |
    135        1 %a + "[No Name]"          |
    136                line 1              |
    137      {6:Press ENTER or type command to}|
    138      {6: continue}^                     |
    139    ]])
    140  end)
    141 
    142  it("'[ and '] marks #26439", function()
    143    local screen = Screen.new(30, 10)
    144    common_setup(screen, 'nosplit', ('abc\ndef\n'):rep(50))
    145 
    146    feed('ggyG')
    147    local X = api.nvim_get_vvar('maxcol')
    148    eq({ 0, 1, 1, 0 }, fn.getpos("'["))
    149    eq({ 0, 101, X, 0 }, fn.getpos("']"))
    150 
    151    feed(":'[,']s/def/")
    152    poke_eventloop()
    153    eq({ 0, 1, 1, 0 }, fn.getpos("'["))
    154    eq({ 0, 101, X, 0 }, fn.getpos("']"))
    155 
    156    feed('DEF/g')
    157    poke_eventloop()
    158    eq({ 0, 1, 1, 0 }, fn.getpos("'["))
    159    eq({ 0, 101, X, 0 }, fn.getpos("']"))
    160 
    161    feed('<CR>')
    162    expect(('abc\nDEF\n'):rep(50))
    163  end)
    164 
    165  for _, case in pairs { '', 'split', 'nosplit' } do
    166    it('various delimiters (inccommand=' .. case .. ')', function()
    167      insert(default_text)
    168      command('set inccommand=' .. case)
    169 
    170      local delims = { '/', '#', ';', '%', ',', '@', '!' }
    171      for _, delim in pairs(delims) do
    172        feed(':%s' .. delim .. 'lines' .. delim .. 'LINES' .. delim .. 'g')
    173        poke_eventloop()
    174        feed('<CR>')
    175        expect([[
    176          Inc substitution on
    177          two LINES
    178          ]])
    179        command('undo')
    180      end
    181    end)
    182  end
    183 
    184  for _, case in pairs { '', 'split', 'nosplit' } do
    185    it("'undolevels' (inccommand=" .. case .. ')', function()
    186      command('set undolevels=139')
    187      command('setlocal undolevels=34')
    188      command('split') -- Show the buffer in multiple windows
    189      command('set inccommand=' .. case)
    190      insert('as')
    191      feed(':%s/as/glork/')
    192      poke_eventloop()
    193      feed('<enter>')
    194      eq(139, api.nvim_get_option_value('undolevels', { scope = 'global' }))
    195      eq(34, api.nvim_get_option_value('undolevels', { buf = 0 }))
    196    end)
    197  end
    198 
    199  for _, case in ipairs({ '', 'split', 'nosplit' }) do
    200    it('empty undotree() (inccommand=' .. case .. ')', function()
    201      command('set undolevels=1000')
    202      command('set inccommand=' .. case)
    203      local expected_undotree = eval('undotree()')
    204 
    205      -- Start typing an incomplete :substitute command.
    206      feed([[:%s/e/YYYY/g]])
    207      poke_eventloop()
    208      -- Cancel the :substitute.
    209      feed([[<C-\><C-N>]])
    210 
    211      -- The undo tree should be unchanged.
    212      eq(expected_undotree, eval('undotree()'))
    213      eq({}, eval('undotree()')['entries'])
    214    end)
    215  end
    216 
    217  for _, case in ipairs({ '', 'split', 'nosplit' }) do
    218    it('undotree() with branches (inccommand=' .. case .. ')', function()
    219      command('set undolevels=1000')
    220      command('set inccommand=' .. case)
    221      -- Make some changes.
    222      feed([[isome text 1<C-\><C-N>]])
    223      feed([[osome text 2<C-\><C-N>]])
    224      -- Add an undo branch.
    225      feed([[u]])
    226      -- More changes, more undo branches.
    227      feed([[osome text 3<C-\><C-N>]])
    228      feed([[AX<C-\><C-N>]])
    229      feed([[...]])
    230      feed([[uu]])
    231      feed([[osome text 4<C-\><C-N>]])
    232      feed([[u<C-R>u]])
    233      feed([[osome text 5<C-\><C-N>]])
    234      expect([[
    235        some text 1
    236        some text 3XX
    237        some text 5]])
    238      local expected_undotree = eval('undotree()')
    239      eq(5, #expected_undotree['entries']) -- sanity
    240 
    241      -- Start typing an incomplete :substitute command.
    242      feed([[:%s/e/YYYY/g]])
    243      poke_eventloop()
    244      -- Cancel the :substitute.
    245      feed([[<C-\><C-N>]])
    246 
    247      -- The undo tree should be unchanged.
    248      eq(expected_undotree, eval('undotree()'))
    249    end)
    250  end
    251 
    252  for _, case in pairs { '', 'split', 'nosplit' } do
    253    it('b:changedtick (inccommand=' .. case .. ')', function()
    254      command('set inccommand=' .. case)
    255      feed([[isome text 1<C-\><C-N>]])
    256      feed([[osome text 2<C-\><C-N>]])
    257      local expected_tick = eval('b:changedtick')
    258      ok(expected_tick > 0)
    259 
    260      expect([[
    261        some text 1
    262        some text 2]])
    263      feed(':%s/e/XXX/')
    264      poke_eventloop()
    265 
    266      eq(expected_tick, eval('b:changedtick'))
    267    end)
    268  end
    269 
    270  for _, case in ipairs({ '', 'split', 'nosplit' }) do
    271    it('previous substitute string ~ (inccommand=' .. case .. ') #12109', function()
    272      local screen = Screen.new(30, 10)
    273      common_setup(screen, case, default_text)
    274 
    275      feed(':%s/Inc/SUB<CR>')
    276      expect([[
    277        SUB substitution on
    278        two lines
    279        ]])
    280 
    281      feed(':%s/line/')
    282      poke_eventloop()
    283      feed('~')
    284      poke_eventloop()
    285      feed('<CR>')
    286      expect([[
    287        SUB substitution on
    288        two SUBs
    289        ]])
    290 
    291      feed(':%s/sti/')
    292      poke_eventloop()
    293      feed('~')
    294      poke_eventloop()
    295      feed('B')
    296      poke_eventloop()
    297      feed('<CR>')
    298      expect([[
    299        SUB subSUBBtution on
    300        two SUBs
    301        ]])
    302 
    303      feed(':%s/ion/NEW<CR>')
    304      expect([[
    305        SUB subSUBBtutNEW on
    306        two SUBs
    307        ]])
    308 
    309      feed(':%s/two/')
    310      poke_eventloop()
    311      feed('N')
    312      poke_eventloop()
    313      feed('~')
    314      poke_eventloop()
    315      feed('<CR>')
    316      expect([[
    317        SUB subSUBBtutNEW on
    318        NNEW SUBs
    319        ]])
    320 
    321      feed(':%s/bS/')
    322      poke_eventloop()
    323      feed('~')
    324      poke_eventloop()
    325      feed('W')
    326      poke_eventloop()
    327      feed('<CR>')
    328      expect([[
    329        SUB suNNEWWUBBtutNEW on
    330        NNEW SUBs
    331        ]])
    332    end)
    333  end
    334 end)
    335 
    336 describe(":substitute, 'inccommand' preserves undo", function()
    337  local cases = { '', 'split', 'nosplit' }
    338 
    339  local substrings = {
    340    { ':%s/', '1' },
    341    { ':%s/', '1', '/' },
    342    { ':%s/', '1', '/', '<bs>' },
    343    { ':%s/', '1', '/', 'a' },
    344    { ':%s/', '1', '/', 'a', '<bs>' },
    345    { ':%s/', '1', '/', 'a', 'x' },
    346    { ':%s/', '1', '/', 'a', 'x', '<bs>' },
    347    { ':%s/', '1', '/', 'a', 'x', '<bs>', '<bs>' },
    348    { ':%s/', '1', '/', 'a', 'x', '<bs>', '<bs>', '<bs>' },
    349    { ':%s/', '1', '/', 'a', 'x', '/' },
    350    { ':%s/', '1', '/', 'a', 'x', '/', '<bs>' },
    351    { ':%s/', '1', '/', 'a', 'x', '/', '<bs>', '/' },
    352    { ':%s/', '1', '/', 'a', 'x', '/', 'g' },
    353    { ':%s/', '1', '/', 'a', 'x', '/', 'g', '<bs>' },
    354    { ':%s/', '1', '/', 'a', 'x', '/', 'g', '<bs>', '<bs>' },
    355  }
    356 
    357  local function test_sub(substring, split, redoable)
    358    command('bwipe!')
    359    command('set inccommand=' .. split)
    360 
    361    insert('1')
    362    feed('o2<esc>')
    363    command('undo')
    364    feed('o3<esc>')
    365    if redoable then
    366      feed('o4<esc>')
    367      command('undo')
    368    end
    369    for _, s in pairs(substring) do
    370      feed(s)
    371    end
    372    poke_eventloop()
    373    feed('<enter>')
    374    command('undo')
    375 
    376    feed('g-')
    377    expect([[
    378      1
    379      2]])
    380 
    381    feed('g+')
    382    expect([[
    383      1
    384      3]])
    385  end
    386 
    387  local function test_notsub(substring, split, redoable)
    388    command('bwipe!')
    389    command('set inccommand=' .. split)
    390 
    391    insert('1')
    392    feed('o2<esc>')
    393    command('undo')
    394    feed('o3<esc>')
    395    if redoable then
    396      feed('o4<esc>')
    397      command('undo')
    398    end
    399    for _, s in pairs(substring) do
    400      feed(s)
    401    end
    402    poke_eventloop()
    403    feed('<esc>')
    404 
    405    feed('g-')
    406    expect([[
    407      1
    408      2]])
    409 
    410    feed('g+')
    411    expect([[
    412      1
    413      3]])
    414 
    415    if redoable then
    416      feed('<c-r>')
    417      expect([[
    418        1
    419        3
    420        4]])
    421    end
    422  end
    423 
    424  local function test_threetree(substring, split)
    425    command('bwipe!')
    426    command('set inccommand=' .. split)
    427 
    428    insert('1')
    429    feed('o2<esc>')
    430    feed('o3<esc>')
    431    feed('uu')
    432    feed('oa<esc>')
    433    feed('ob<esc>')
    434    feed('uu')
    435    feed('oA<esc>')
    436    feed('oB<esc>')
    437 
    438    -- This is the undo tree (x-Axis is timeline), we're at B now
    439    --    ----------------A - B
    440    --   /
    441    --  | --------a - b
    442    --  |/
    443    --  1 - 2 - 3
    444 
    445    feed('2u')
    446    for _, s in pairs(substring) do
    447      feed(s)
    448      poke_eventloop()
    449    end
    450    feed('<esc>')
    451    expect([[
    452      1]])
    453    feed('g-')
    454    expect([[
    455      ]])
    456    feed('g+')
    457    expect([[
    458      1]])
    459    feed('<c-r>')
    460    expect([[
    461      1
    462      A]])
    463 
    464    feed('g-') -- go to b
    465    feed('2u')
    466    for _, s in pairs(substring) do
    467      feed(s)
    468      poke_eventloop()
    469    end
    470    feed('<esc>')
    471    feed('<c-r>')
    472    expect([[
    473      1
    474      a]])
    475 
    476    feed('g-') -- go to 3
    477    feed('2u')
    478    for _, s in pairs(substring) do
    479      feed(s)
    480      poke_eventloop()
    481    end
    482    feed('<esc>')
    483    feed('<c-r>')
    484    expect([[
    485      1
    486      2]])
    487  end
    488 
    489  before_each(clear)
    490 
    491  it('at a non-leaf of the undo tree', function()
    492    for _, case in pairs(cases) do
    493      for _, str in pairs(substrings) do
    494        for _, redoable in pairs({ true }) do
    495          test_sub(str, case, redoable)
    496        end
    497      end
    498    end
    499  end)
    500 
    501  it('at a leaf of the undo tree', function()
    502    for _, case in pairs(cases) do
    503      for _, str in pairs(substrings) do
    504        for _, redoable in pairs({ false }) do
    505          test_sub(str, case, redoable)
    506        end
    507      end
    508    end
    509  end)
    510 
    511  it('when interrupting substitution', function()
    512    for _, case in pairs(cases) do
    513      for _, str in pairs(substrings) do
    514        for _, redoable in pairs({ true, false }) do
    515          test_notsub(str, case, redoable)
    516        end
    517      end
    518    end
    519  end)
    520 
    521  it('in a complex undo scenario', function()
    522    for _, case in pairs(cases) do
    523      for _, str in pairs(substrings) do
    524        test_threetree(str, case)
    525      end
    526    end
    527  end)
    528 
    529  it('with undolevels=0', function()
    530    for _, case in pairs(cases) do
    531      clear()
    532      common_setup(nil, case, default_text)
    533      command('set undolevels=0')
    534 
    535      feed('1G0')
    536      insert('X')
    537      feed(':%s/tw/MO/')
    538      poke_eventloop()
    539      feed('<esc>')
    540      command('undo')
    541      expect(default_text)
    542      command('undo')
    543      expect(default_text:gsub('Inc', 'XInc'))
    544      command('undo')
    545 
    546      feed(':%s/tw/MO/g')
    547      poke_eventloop()
    548      feed('<CR>')
    549      expect(default_text:gsub('tw', 'MO'))
    550      command('undo')
    551      expect(default_text)
    552      command('undo')
    553      expect(default_text:gsub('tw', 'MO'))
    554    end
    555  end)
    556 
    557  it('with undolevels=1', function()
    558    for _, case in pairs(cases) do
    559      clear()
    560      local screen = Screen.new(20, 10)
    561      common_setup(screen, case, default_text)
    562      screen:expect([[
    563        Inc substitution on |
    564        two lines           |
    565        ^                    |
    566        {1:~                   }|*6
    567                            |
    568      ]])
    569      command('set undolevels=1')
    570 
    571      feed('1G0')
    572      insert('X')
    573      feed('IY<esc>')
    574      feed(':%s/tw/MO/')
    575      poke_eventloop()
    576      feed('<esc>')
    577      feed('u')
    578      expect(default_text:gsub('Inc', 'XInc'))
    579      feed('u')
    580      expect(default_text)
    581 
    582      feed(':%s/tw/MO/g')
    583      poke_eventloop()
    584      feed('<enter>')
    585      feed(':%s/MO/GO/g')
    586      poke_eventloop()
    587      feed('<enter>')
    588      feed(':%s/GO/NO/g')
    589      poke_eventloop()
    590      feed('<enter>')
    591      feed('u')
    592      expect(default_text:gsub('tw', 'GO'))
    593      feed('u')
    594      expect(default_text:gsub('tw', 'MO'))
    595      feed('u')
    596 
    597      if case == 'split' then
    598        screen:expect([[
    599          Inc substitution on |
    600          ^MOo lines           |
    601                              |
    602          {1:~                   }|*6
    603          Already ...t change |
    604        ]])
    605      else
    606        screen:expect([[
    607          Inc substitution on |
    608          ^MOo lines           |
    609                              |
    610          {1:~                   }|*6
    611          Already ...t change |
    612        ]])
    613      end
    614    end
    615  end)
    616 
    617  it('with undolevels=2', function()
    618    for _, case in pairs(cases) do
    619      clear()
    620      local screen = Screen.new(20, 10)
    621      common_setup(screen, case, default_text)
    622      command('set undolevels=2')
    623 
    624      feed('2GAx<esc>')
    625      feed('Ay<esc>')
    626      feed('Az<esc>')
    627      feed(':%s/tw/AR')
    628      poke_eventloop()
    629      feed('<esc>')
    630      feed('u')
    631      expect(default_text:gsub('lines', 'linesxy'))
    632      feed('u')
    633      expect(default_text:gsub('lines', 'linesx'))
    634      feed('u')
    635      expect(default_text)
    636      feed('u')
    637 
    638      if case == 'split' then
    639        screen:expect([[
    640          Inc substitution on |
    641          two line^s           |
    642                              |
    643          {1:~                   }|*6
    644          Already ...t change |
    645        ]])
    646      else
    647        screen:expect([[
    648          Inc substitution on |
    649          two line^s           |
    650                              |
    651          {1:~                   }|*6
    652          Already ...t change |
    653        ]])
    654      end
    655 
    656      feed(':%s/tw/MO/g')
    657      poke_eventloop()
    658      feed('<enter>')
    659      feed(':%s/MO/GO/g')
    660      poke_eventloop()
    661      feed('<enter>')
    662      feed(':%s/GO/NO/g')
    663      poke_eventloop()
    664      feed('<enter>')
    665      feed(':%s/NO/LO/g')
    666      poke_eventloop()
    667      feed('<enter>')
    668      feed('u')
    669      expect(default_text:gsub('tw', 'NO'))
    670      feed('u')
    671      expect(default_text:gsub('tw', 'GO'))
    672      feed('u')
    673      expect(default_text:gsub('tw', 'MO'))
    674      feed('u')
    675 
    676      if case == 'split' then
    677        screen:expect([[
    678          Inc substitution on |
    679          ^MOo lines           |
    680                              |
    681          {1:~                   }|*6
    682          Already ...t change |
    683        ]])
    684      else
    685        screen:expect([[
    686          Inc substitution on |
    687          ^MOo lines           |
    688                              |
    689          {1:~                   }|*6
    690          Already ...t change |
    691        ]])
    692      end
    693    end
    694  end)
    695 
    696  it('with undolevels=-1', function()
    697    for _, case in pairs(cases) do
    698      clear()
    699      local screen = Screen.new(20, 10)
    700      common_setup(screen, case, default_text)
    701 
    702      command('set undolevels=-1')
    703      feed(':%s/tw/MO/g')
    704      poke_eventloop()
    705      feed('<enter>')
    706      feed('u')
    707      if case == 'split' then
    708        screen:expect([[
    709          Inc substitution on |
    710          ^MOo lines           |
    711                              |
    712          {1:~                   }|*6
    713          Already ...t change |
    714        ]])
    715      else
    716        screen:expect([[
    717          Inc substitution on |
    718          ^MOo lines           |
    719                              |
    720          {1:~                   }|*6
    721          Already ...t change |
    722        ]])
    723      end
    724 
    725      -- repeat with an interrupted substitution
    726      clear()
    727      screen = Screen.new(20, 10)
    728      common_setup(screen, case, default_text)
    729 
    730      command('set undolevels=-1')
    731      feed('1G')
    732      feed('IL<esc>')
    733      feed(':%s/tw/MO/g')
    734      poke_eventloop()
    735      feed('<esc>')
    736      feed('u')
    737 
    738      screen:expect([[
    739        ^LInc substitution on|
    740        two lines           |
    741                            |
    742        {1:~                   }|*6
    743        Already ...t change |
    744      ]])
    745    end
    746  end)
    747 end)
    748 
    749 describe(':substitute, inccommand=split', function()
    750  local screen
    751 
    752  before_each(function()
    753    clear()
    754    screen = Screen.new(30, 15)
    755    common_setup(screen, 'split', default_text .. default_text)
    756  end)
    757 
    758  it("preserves 'modified' buffer flag", function()
    759    command('set nomodified')
    760    feed(':%s/tw')
    761    screen:expect([[
    762      Inc substitution on           |
    763      {20:tw}o lines                     |
    764      Inc substitution on           |
    765      {20:tw}o lines                     |
    766                                    |
    767      {3:[No Name]                     }|
    768      |2| {20:tw}o lines                 |
    769      |4| {20:tw}o lines                 |
    770      {1:~                             }|*5
    771      {2:[Preview]                     }|
    772      :%s/tw^                        |
    773    ]])
    774    feed([[<C-\><C-N>]]) -- Cancel the :substitute command.
    775    eq(0, eval('&modified'))
    776  end)
    777 
    778  it('shows preview when cmd modifiers are present', function()
    779    -- one modifier
    780    feed(':keeppatterns %s/tw/to')
    781    screen:expect { any = [[{20:to}o lines]] }
    782    feed('<Esc>')
    783    screen:expect { any = [[two lines]] }
    784 
    785    -- multiple modifiers
    786    feed(':keeppatterns silent %s/tw/to')
    787    screen:expect { any = [[{20:to}o lines]] }
    788    feed('<Esc>')
    789    screen:expect { any = [[two lines]] }
    790 
    791    -- non-modifier prefix
    792    feed(':silent tabedit %s/tw/to')
    793    screen:expect([[
    794      Inc substitution on           |
    795      two lines                     |
    796      Inc substitution on           |
    797      two lines                     |
    798                                    |
    799      {1:~                             }|*9
    800      :silent tabedit %s/tw/to^      |
    801    ]])
    802    feed('<Esc>')
    803 
    804    -- leading colons
    805    feed(':::%s/tw/to')
    806    screen:expect { any = [[{20:to}o lines]] }
    807    feed('<Esc>')
    808    screen:expect { any = [[two lines]] }
    809  end)
    810 
    811  it('ignores new-window modifiers when splitting the preview window', function()
    812    -- one modifier
    813    feed(':topleft %s/tw/to')
    814    screen:expect([[
    815      Inc substitution on           |
    816      {20:to}o lines                     |
    817      Inc substitution on           |
    818      {20:to}o lines                     |
    819                                    |
    820      {3:[No Name] [+]                 }|
    821      |2| {20:to}o lines                 |
    822      |4| {20:to}o lines                 |
    823      {1:~                             }|*5
    824      {2:[Preview]                     }|
    825      :topleft %s/tw/to^             |
    826    ]])
    827    feed('<Esc>')
    828    screen:expect { any = [[two lines]] }
    829 
    830    -- multiple modifiers
    831    feed(':topleft vert %s/tw/to')
    832    screen:expect([[
    833      Inc substitution on           |
    834      {20:to}o lines                     |
    835      Inc substitution on           |
    836      {20:to}o lines                     |
    837                                    |
    838      {3:[No Name] [+]                 }|
    839      |2| {20:to}o lines                 |
    840      |4| {20:to}o lines                 |
    841      {1:~                             }|*5
    842      {2:[Preview]                     }|
    843      :topleft vert %s/tw/to^        |
    844    ]])
    845    feed('<Esc>')
    846    screen:expect { any = [[two lines]] }
    847  end)
    848 
    849  it('shows split window when typing the pattern', function()
    850    feed(':%s/tw')
    851    screen:expect([[
    852      Inc substitution on           |
    853      {20:tw}o lines                     |
    854      Inc substitution on           |
    855      {20:tw}o lines                     |
    856                                    |
    857      {3:[No Name] [+]                 }|
    858      |2| {20:tw}o lines                 |
    859      |4| {20:tw}o lines                 |
    860      {1:~                             }|*5
    861      {2:[Preview]                     }|
    862      :%s/tw^                        |
    863    ]])
    864  end)
    865 
    866  it('shows preview with empty replacement', function()
    867    feed(':%s/tw/')
    868    screen:expect([[
    869      Inc substitution on           |
    870      o lines                       |
    871      Inc substitution on           |
    872      o lines                       |
    873                                    |
    874      {3:[No Name] [+]                 }|
    875      |2| o lines                   |
    876      |4| o lines                   |
    877      {1:~                             }|*5
    878      {2:[Preview]                     }|
    879      :%s/tw/^                       |
    880    ]])
    881 
    882    feed('x')
    883    screen:expect([[
    884      Inc substitution on           |
    885      {20:x}o lines                      |
    886      Inc substitution on           |
    887      {20:x}o lines                      |
    888                                    |
    889      {3:[No Name] [+]                 }|
    890      |2| {20:x}o lines                  |
    891      |4| {20:x}o lines                  |
    892      {1:~                             }|*5
    893      {2:[Preview]                     }|
    894      :%s/tw/x^                      |
    895    ]])
    896 
    897    feed('<bs>')
    898    screen:expect([[
    899      Inc substitution on           |
    900      o lines                       |
    901      Inc substitution on           |
    902      o lines                       |
    903                                    |
    904      {3:[No Name] [+]                 }|
    905      |2| o lines                   |
    906      |4| o lines                   |
    907      {1:~                             }|*5
    908      {2:[Preview]                     }|
    909      :%s/tw/^                       |
    910    ]])
    911  end)
    912 
    913  it('shows split window when typing replacement', function()
    914    feed(':%s/tw/XX')
    915    screen:expect([[
    916      Inc substitution on           |
    917      {20:XX}o lines                     |
    918      Inc substitution on           |
    919      {20:XX}o lines                     |
    920                                    |
    921      {3:[No Name] [+]                 }|
    922      |2| {20:XX}o lines                 |
    923      |4| {20:XX}o lines                 |
    924      {1:~                             }|*5
    925      {2:[Preview]                     }|
    926      :%s/tw/XX^                     |
    927    ]])
    928  end)
    929 
    930  it('does not show split window for :s/', function()
    931    feed('2gg')
    932    feed(':s/tw')
    933    screen:expect([[
    934      Inc substitution on           |
    935      {20:tw}o lines                     |
    936      Inc substitution on           |
    937      two lines                     |
    938                                    |
    939      {1:~                             }|*9
    940      :s/tw^                         |
    941    ]])
    942  end)
    943 
    944  it("'hlsearch' is active, 'cursorline' is not", function()
    945    command('set hlsearch cursorline')
    946    feed('gg')
    947 
    948    -- Assert that 'cursorline' is active.
    949    screen:expect([[
    950      {21:^Inc substitution on           }|
    951      two lines                     |
    952      Inc substitution on           |
    953      two lines                     |
    954                                    |
    955      {1:~                             }|*9
    956                                    |
    957    ]])
    958 
    959    feed(':%s/tw')
    960    -- 'cursorline' is NOT active during preview.
    961    screen:expect([[
    962      Inc substitution on           |
    963      {20:tw}o lines                     |
    964      Inc substitution on           |
    965      {20:tw}o lines                     |
    966                                    |
    967      {3:[No Name] [+]                 }|
    968      |2| {20:tw}o lines                 |
    969      |4| {20:tw}o lines                 |
    970      {1:~                             }|*5
    971      {2:[Preview]                     }|
    972      :%s/tw^                        |
    973    ]])
    974  end)
    975 
    976  it('highlights the replacement text', function()
    977    feed('ggO')
    978    feed('M     M       M<esc>')
    979    feed(':%s/M/123/g')
    980    screen:expect([[
    981      {20:123}     {20:123}       {20:123}         |
    982      Inc substitution on           |
    983      two lines                     |
    984      Inc substitution on           |
    985      two lines                     |
    986      {3:[No Name] [+]                 }|
    987      |1| {20:123}     {20:123}       {20:123}     |
    988      {1:~                             }|*6
    989      {2:[Preview]                     }|
    990      :%s/M/123/g^                   |
    991    ]])
    992  end)
    993 
    994  it("highlights nothing when there's no match", function()
    995    feed('gg')
    996    feed(':%s/Inx')
    997    screen:expect([[
    998      Inc substitution on           |
    999      two lines                     |
   1000      Inc substitution on           |
   1001      two lines                     |
   1002                                    |
   1003      {3:[No Name] [+]                 }|
   1004                                    |
   1005      {1:~                             }|*6
   1006      {2:[Preview]                     }|
   1007      :%s/Inx^                       |
   1008    ]])
   1009  end)
   1010 
   1011  it('previews correctly when previewhight is small', function()
   1012    command('set cwh=3')
   1013    command('set hls')
   1014    feed('ggdG')
   1015    insert(string.rep('abc abc abc\n', 20))
   1016    feed(':%s/abc/MMM/g')
   1017    screen:expect([[
   1018      {20:MMM} {20:MMM} {20:MMM}                   |*9
   1019      {3:[No Name] [+]                 }|
   1020      | 1| {20:MMM} {20:MMM} {20:MMM}              |
   1021      | 2| {20:MMM} {20:MMM} {20:MMM}              |
   1022      | 3| {20:MMM} {20:MMM} {20:MMM}              |
   1023      {2:[Preview]                     }|
   1024      :%s/abc/MMM/g^                 |
   1025    ]])
   1026  end)
   1027 
   1028  it('actually replaces text', function()
   1029    feed(':%s/tw/XX/g')
   1030    poke_eventloop()
   1031    feed('<Enter>')
   1032 
   1033    screen:expect([[
   1034      Inc substitution on           |
   1035      XXo lines                     |
   1036      Inc substitution on           |
   1037      ^XXo lines                     |
   1038                                    |
   1039      {1:~                             }|*9
   1040      :%s/tw/XX/g                   |
   1041    ]])
   1042  end)
   1043 
   1044  it('shows correct line numbers with many lines', function()
   1045    feed('gg')
   1046    feed('2yy')
   1047    feed('2000p')
   1048    command('1,1000s/tw/BB/g')
   1049 
   1050    feed(':%s/tw/X')
   1051    screen:expect([[
   1052      Inc substitution on           |
   1053      BBo lines                     |
   1054      Inc substitution on           |
   1055      {20:X}o lines                      |
   1056      Inc substitution on           |
   1057      {3:[No Name] [+]                 }|
   1058      |1001| {20:X}o lines               |
   1059      |1003| {20:X}o lines               |
   1060      |1005| {20:X}o lines               |
   1061      |1007| {20:X}o lines               |
   1062      |1009| {20:X}o lines               |
   1063      |1011| {20:X}o lines               |
   1064      |1013| {20:X}o lines               |
   1065      {2:[Preview]                     }|
   1066      :%s/tw/X^                      |
   1067    ]])
   1068  end)
   1069 
   1070  it('does not spam the buffer numbers', function()
   1071    -- The preview buffer is re-used (unless user deleted it), so buffer numbers
   1072    -- will not increase on each keystroke.
   1073    feed(':%s/tw/Xo/g')
   1074    -- Delete and re-type the g a few times.
   1075    feed('<BS>')
   1076    poke_eventloop()
   1077    feed('g')
   1078    poke_eventloop()
   1079    feed('<BS>')
   1080    poke_eventloop()
   1081    feed('g')
   1082    poke_eventloop()
   1083    feed('<CR>')
   1084    poke_eventloop()
   1085    feed(':vs tmp<enter>')
   1086    eq(3, fn.bufnr('$'))
   1087  end)
   1088 
   1089  it('works with the n flag', function()
   1090    feed(':%s/tw/Mix/n')
   1091    poke_eventloop()
   1092    feed('<Enter>')
   1093    screen:expect([[
   1094      Inc substitution on           |
   1095      two lines                     |
   1096      Inc substitution on           |
   1097      two lines                     |
   1098      ^                              |
   1099      {1:~                             }|*9
   1100      2 matches on 2 lines          |
   1101    ]])
   1102  end)
   1103 
   1104  it("deactivates if 'redrawtime' is exceeded #5602", function()
   1105    -- prevent redraws from 'incsearch'
   1106    api.nvim_set_option_value('incsearch', false, {})
   1107    -- Assert that 'inccommand' is ENABLED initially.
   1108    eq('split', eval('&inccommand'))
   1109    -- Set 'redrawtime' to minimal value, to ensure timeout is triggered.
   1110    command('set redrawtime=1 nowrap')
   1111    -- Load a big file.
   1112    command('silent edit! test/functional/fixtures/bigfile_oneline.txt')
   1113    -- Start :substitute with a slow pattern.
   1114    feed([[:%s/B.*N/x]])
   1115    poke_eventloop()
   1116 
   1117    -- Assert that 'inccommand' is DISABLED in cmdline mode.
   1118    eq('', eval('&inccommand'))
   1119    -- Assert that preview cleared (or never manifested).
   1120    screen:expect([[
   1121      0000;<control>;Cc;0;BN;;;;;N;N|
   1122      2F923;CJK COMPATIBILITY IDEOGR|
   1123      2F924;CJK COMPATIBILITY IDEOGR|
   1124      2F925;CJK COMPATIBILITY IDEOGR|
   1125      2F926;CJK COMPATIBILITY IDEOGR|
   1126      2F927;CJK COMPATIBILITY IDEOGR|
   1127      2F928;CJK COMPATIBILITY IDEOGR|
   1128      2F929;CJK COMPATIBILITY IDEOGR|
   1129      2F92A;CJK COMPATIBILITY IDEOGR|
   1130      2F92B;CJK COMPATIBILITY IDEOGR|
   1131      2F92C;CJK COMPATIBILITY IDEOGR|
   1132      2F92D;CJK COMPATIBILITY IDEOGR|
   1133      2F92E;CJK COMPATIBILITY IDEOGR|
   1134      2F92F;CJK COMPATIBILITY IDEOGR|
   1135      :%s/B.*N/x^                    |
   1136    ]])
   1137 
   1138    -- Assert that 'inccommand' is again ENABLED after leaving cmdline mode.
   1139    feed([[<C-\><C-N>]])
   1140    eq('split', eval('&inccommand'))
   1141  end)
   1142 
   1143  it("deactivates if 'foldexpr' is slow #9557", function()
   1144    insert([[
   1145      a
   1146      a
   1147      a
   1148      a
   1149      a
   1150      a
   1151      a
   1152      a
   1153    ]])
   1154    source([[
   1155      function! Slowfold(lnum)
   1156        sleep 5m
   1157        return a:lnum % 3
   1158      endfun
   1159    ]])
   1160    command('set redrawtime=1 inccommand=split')
   1161    command('set foldmethod=expr foldexpr=Slowfold(v:lnum)')
   1162    feed(':%s/a/bcdef')
   1163 
   1164    -- Assert that 'inccommand' is DISABLED in cmdline mode.
   1165    retry(nil, nil, function()
   1166      eq('', eval('&inccommand'))
   1167    end)
   1168 
   1169    -- Assert that 'inccommand' is again ENABLED after leaving cmdline mode.
   1170    feed([[<C-\><C-N>]])
   1171    retry(nil, nil, function()
   1172      eq('split', eval('&inccommand'))
   1173    end)
   1174  end)
   1175 
   1176  it('clears preview if non-previewable command is edited #5585', function()
   1177    feed('gg')
   1178    -- Put a non-previewable command in history.
   1179    feed(":echo 'foo'<CR>")
   1180    -- Start an incomplete :substitute command.
   1181    feed(':1,2s/t/X')
   1182 
   1183    screen:expect([[
   1184      Inc subs{20:X}itution on           |
   1185      {20:X}wo lines                     |
   1186      Inc substitution on           |
   1187      two lines                     |
   1188                                    |
   1189      {3:[No Name] [+]                 }|
   1190      |1| Inc subs{20:X}itution on       |
   1191      |2| {20:X}wo lines                 |
   1192      {1:~                             }|*5
   1193      {2:[Preview]                     }|
   1194      :1,2s/t/X^                     |
   1195    ]])
   1196 
   1197    -- Select the previous command.
   1198    feed('<C-P>')
   1199    -- Assert that preview was cleared.
   1200    screen:expect([[
   1201      Inc substitution on           |
   1202      two lines                     |
   1203      Inc substitution on           |
   1204      two lines                     |
   1205                                    |
   1206      {1:~                             }|*9
   1207      :echo 'foo'^                   |
   1208    ]])
   1209  end)
   1210 
   1211  it([[preview changes correctly with c_CTRL-R_= and c_CTRL-\_e]], function()
   1212    feed('gg')
   1213    feed(':1,2s/t/X')
   1214    screen:expect([[
   1215      Inc subs{20:X}itution on           |
   1216      {20:X}wo lines                     |
   1217      Inc substitution on           |
   1218      two lines                     |
   1219                                    |
   1220      {3:[No Name] [+]                 }|
   1221      |1| Inc subs{20:X}itution on       |
   1222      |2| {20:X}wo lines                 |
   1223      {1:~                             }|*5
   1224      {2:[Preview]                     }|
   1225      :1,2s/t/X^                     |
   1226    ]])
   1227 
   1228    feed([[<C-R>='Y']])
   1229    -- preview should be unchanged during c_CTRL-R_= editing
   1230    screen:expect([[
   1231      Inc subs{20:X}itution on           |
   1232      {20:X}wo lines                     |
   1233      Inc substitution on           |
   1234      two lines                     |
   1235                                    |
   1236      {3:[No Name] [+]                 }|
   1237      |1| Inc subs{20:X}itution on       |
   1238      |2| {20:X}wo lines                 |
   1239      {1:~                             }|*5
   1240      {2:[Preview]                     }|
   1241      ={26:'Y'}^                          |
   1242    ]])
   1243 
   1244    feed('<CR>')
   1245    -- preview should be changed by the result of the expression
   1246    screen:expect([[
   1247      Inc subs{20:XY}itution on          |
   1248      {20:XY}wo lines                    |
   1249      Inc substitution on           |
   1250      two lines                     |
   1251                                    |
   1252      {3:[No Name] [+]                 }|
   1253      |1| Inc subs{20:XY}itution on      |
   1254      |2| {20:XY}wo lines                |
   1255      {1:~                             }|*5
   1256      {2:[Preview]                     }|
   1257      :1,2s/t/XY^                    |
   1258    ]])
   1259 
   1260    feed([[<C-\>e'echo']])
   1261    -- preview should be unchanged during c_CTRL-\_e editing
   1262    screen:expect([[
   1263      Inc subs{20:XY}itution on          |
   1264      {20:XY}wo lines                    |
   1265      Inc substitution on           |
   1266      two lines                     |
   1267                                    |
   1268      {3:[No Name] [+]                 }|
   1269      |1| Inc subs{20:XY}itution on      |
   1270      |2| {20:XY}wo lines                |
   1271      {1:~                             }|*5
   1272      {2:[Preview]                     }|
   1273      ={26:'echo'}^                       |
   1274    ]])
   1275 
   1276    feed('<CR>')
   1277    -- preview should be cleared if command is changed to a non-previewable one
   1278    screen:expect([[
   1279      Inc substitution on           |
   1280      two lines                     |
   1281      Inc substitution on           |
   1282      two lines                     |
   1283                                    |
   1284      {1:~                             }|*9
   1285      :echo^                         |
   1286    ]])
   1287  end)
   1288 end)
   1289 
   1290 describe('inccommand=nosplit', function()
   1291  local screen
   1292 
   1293  before_each(function()
   1294    clear()
   1295    screen = Screen.new(20, 10)
   1296    common_setup(screen, 'nosplit', default_text .. default_text)
   1297  end)
   1298 
   1299  it('works with :smagic, :snomagic', function()
   1300    command('set hlsearch')
   1301    insert('Line *.3.* here')
   1302 
   1303    feed(':%smagic/3.*/X') -- start :smagic command
   1304    screen:expect([[
   1305      Inc substitution on |
   1306      two lines           |
   1307      Inc substitution on |
   1308      two lines           |
   1309      Line *.{20:X}            |
   1310      {1:~                   }|*4
   1311      :%smagic/3.*/X^      |
   1312    ]])
   1313 
   1314    feed([[<C-\><C-N>]]) -- cancel
   1315    feed(':%snomagic/3.*/X') -- start :snomagic command
   1316    screen:expect([[
   1317      Inc substitution on |
   1318      two lines           |
   1319      Inc substitution on |
   1320      two lines           |
   1321      Line *.{20:X} here       |
   1322      {1:~                   }|*4
   1323      :%snomagic/3.*/X^    |
   1324    ]])
   1325  end)
   1326 
   1327  it('shows preview when cmd modifiers are present', function()
   1328    -- one modifier
   1329    feed(':keeppatterns %s/tw/to')
   1330    screen:expect { any = [[{20:to}o lines]] }
   1331    feed('<Esc>')
   1332    screen:expect { any = [[two lines]] }
   1333 
   1334    -- multiple modifiers
   1335    feed(':keeppatterns silent %s/tw/to')
   1336    screen:expect { any = [[{20:to}o lines]] }
   1337    feed('<Esc>')
   1338    screen:expect { any = [[two lines]] }
   1339 
   1340    -- non-modifier prefix
   1341    feed(':silent tabedit %s/tw/to')
   1342    screen:expect([[
   1343      Inc substitution on |
   1344      two lines           |
   1345      Inc substitution on |
   1346      two lines           |
   1347                          |
   1348      {1:~                   }|*2
   1349      {3:                    }|
   1350      :silent tabedit %s/t|
   1351      w/to^                |
   1352    ]])
   1353  end)
   1354 
   1355  it('does not show window after toggling :set inccommand', function()
   1356    feed(':%s/tw/OKOK')
   1357    feed('<Esc>')
   1358    command('set icm=split')
   1359    feed(':%s/tw/OKOK')
   1360    feed('<Esc>')
   1361    command('set icm=nosplit')
   1362    feed(':%s/tw/OKOK')
   1363    poke_eventloop()
   1364    screen:expect([[
   1365      Inc substitution on |
   1366      {20:OKOK}o lines         |
   1367      Inc substitution on |
   1368      {20:OKOK}o lines         |
   1369                          |
   1370      {1:~                   }|*4
   1371      :%s/tw/OKOK^         |
   1372    ]])
   1373  end)
   1374 
   1375  it('never shows preview buffer', function()
   1376    command('set hlsearch')
   1377 
   1378    feed(':%s/tw')
   1379    screen:expect([[
   1380      Inc substitution on |
   1381      {20:tw}o lines           |
   1382      Inc substitution on |
   1383      {20:tw}o lines           |
   1384                          |
   1385      {1:~                   }|*4
   1386      :%s/tw^              |
   1387    ]])
   1388 
   1389    feed('/BM')
   1390    screen:expect([[
   1391      Inc substitution on |
   1392      {20:BM}o lines           |
   1393      Inc substitution on |
   1394      {20:BM}o lines           |
   1395                          |
   1396      {1:~                   }|*4
   1397      :%s/tw/BM^           |
   1398    ]])
   1399 
   1400    feed('/')
   1401    screen:expect([[
   1402      Inc substitution on |
   1403      {20:BM}o lines           |
   1404      Inc substitution on |
   1405      {20:BM}o lines           |
   1406                          |
   1407      {1:~                   }|*4
   1408      :%s/tw/BM/^          |
   1409    ]])
   1410 
   1411    feed('<enter>')
   1412    screen:expect([[
   1413      Inc substitution on |
   1414      BMo lines           |
   1415      Inc substitution on |
   1416      ^BMo lines           |
   1417                          |
   1418      {1:~                   }|*4
   1419      :%s/tw/BM/          |
   1420    ]])
   1421  end)
   1422 
   1423  it('clears preview if non-previewable command is edited', function()
   1424    -- Put a non-previewable command in history.
   1425    feed(":echo 'foo'<CR>")
   1426    -- Start an incomplete :substitute command.
   1427    feed(':1,2s/t/X')
   1428 
   1429    screen:expect([[
   1430      Inc subs{20:X}itution on |
   1431      {20:X}wo lines           |
   1432      Inc substitution on |
   1433      two lines           |
   1434                          |
   1435      {1:~                   }|*4
   1436      :1,2s/t/X^           |
   1437    ]])
   1438 
   1439    -- Select the previous command.
   1440    feed('<C-P>')
   1441    -- Assert that preview was cleared.
   1442    screen:expect([[
   1443      Inc substitution on |
   1444      two lines           |
   1445      Inc substitution on |
   1446      two lines           |
   1447                          |
   1448      {1:~                   }|*4
   1449      :echo 'foo'^         |
   1450    ]])
   1451  end)
   1452 
   1453  it('does not execute trailing bar-separated commands #7494', function()
   1454    feed(':%s/two/three/g|q!')
   1455    screen:expect([[
   1456      Inc substitution on |
   1457      {20:three} lines         |
   1458      Inc substitution on |
   1459      {20:three} lines         |
   1460                          |
   1461      {1:~                   }|*4
   1462      :%s/two/three/g|q!^  |
   1463    ]])
   1464    eq(eval('v:null'), eval('v:exiting'))
   1465  end)
   1466 
   1467  it('does not break bar-separated command #8796', function()
   1468    source([[
   1469      function! F()
   1470        if v:false | return | endif
   1471      endfun
   1472    ]])
   1473    command('call timer_start(10, {-> F()}, {"repeat":-1})')
   1474    feed(':%s/')
   1475    sleep(20) -- Allow some timer activity.
   1476    screen:expect([[
   1477      Inc substitution on |
   1478      two lines           |
   1479      Inc substitution on |
   1480      two lines           |
   1481                          |
   1482      {1:~                   }|*4
   1483      :%s/^                |
   1484    ]])
   1485  end)
   1486 end)
   1487 
   1488 describe(":substitute, 'inccommand' with a failing expression", function()
   1489  local screen
   1490  local cases = { '', 'split', 'nosplit' }
   1491 
   1492  local function refresh(case)
   1493    clear()
   1494    screen = Screen.new(20, 10)
   1495    common_setup(screen, case, default_text)
   1496  end
   1497 
   1498  it('in the pattern does nothing', function()
   1499    for _, case in pairs(cases) do
   1500      refresh(case)
   1501      command('set inccommand=' .. case)
   1502      feed(':silent! %s/tw\\(/LARD/')
   1503      poke_eventloop()
   1504      feed('<enter>')
   1505      expect(default_text)
   1506    end
   1507  end)
   1508 
   1509  it('in the replacement deletes the matches', function()
   1510    for _, case in pairs(cases) do
   1511      refresh(case)
   1512      local replacements = { "\\='LARD", '\\=xx_novar__xx' }
   1513 
   1514      for _, repl in pairs(replacements) do
   1515        command('set inccommand=' .. case)
   1516        feed(':silent! %s/tw/' .. repl .. '/')
   1517        poke_eventloop()
   1518        feed('<enter>')
   1519        expect(default_text:gsub('tw', ''))
   1520        command('undo')
   1521      end
   1522    end
   1523  end)
   1524 
   1525  it('in the range does not error #5912', function()
   1526    for _, case in pairs(cases) do
   1527      refresh(case)
   1528      feed(':100s/')
   1529 
   1530      screen:expect([[
   1531        Inc substitution on |
   1532        two lines           |
   1533                            |
   1534        {1:~                   }|*6
   1535        :100s/^              |
   1536      ]])
   1537 
   1538      feed('<enter>')
   1539      screen:expect([[
   1540        Inc substitution on |
   1541        two lines           |
   1542        ^                    |
   1543        {1:~                   }|*6
   1544        {9:E16: Invalid range}  |
   1545      ]])
   1546    end
   1547  end)
   1548 end)
   1549 
   1550 describe("'inccommand' and :cnoremap", function()
   1551  local cases = { '', 'split', 'nosplit' }
   1552  local screen
   1553 
   1554  local function refresh(case, visual)
   1555    clear()
   1556    screen = visual and Screen.new(80, 10) or nil
   1557    common_setup(screen, case, default_text)
   1558  end
   1559 
   1560  it('work with remapped characters', function()
   1561    for _, case in pairs(cases) do
   1562      refresh(case)
   1563      local cmd = '%s/lines/LINES/g'
   1564 
   1565      for i = 1, string.len(cmd) do
   1566        local c = string.sub(cmd, i, i)
   1567        command('cnoremap ' .. c .. ' ' .. c)
   1568      end
   1569 
   1570      feed(':' .. cmd)
   1571      poke_eventloop()
   1572      feed('<CR>')
   1573      expect([[
   1574        Inc substitution on
   1575        two LINES
   1576        ]])
   1577    end
   1578  end)
   1579 
   1580  it('work when mappings move the cursor', function()
   1581    for _, case in pairs(cases) do
   1582      refresh(case)
   1583      command('cnoremap ,S LINES/<left><left><left><left><left><left>')
   1584 
   1585      feed(':%s/lines/')
   1586      poke_eventloop()
   1587      feed(',S')
   1588      poke_eventloop()
   1589      feed('or three <enter>')
   1590      poke_eventloop()
   1591      expect([[
   1592        Inc substitution on
   1593        two or three LINES
   1594        ]])
   1595 
   1596      command('cnoremap ;S /X/<left><left><left>')
   1597      feed(':%s/')
   1598      poke_eventloop()
   1599      feed(';S')
   1600      poke_eventloop()
   1601      feed('I<enter>')
   1602      expect([[
   1603        Xnc substitution on
   1604        two or three LXNES
   1605        ]])
   1606 
   1607      command('cnoremap ,T //Y/<left><left><left>')
   1608      feed(':%s')
   1609      poke_eventloop()
   1610      feed(',T')
   1611      poke_eventloop()
   1612      feed('X<enter>')
   1613      expect([[
   1614        Ync substitution on
   1615        two or three LYNES
   1616        ]])
   1617 
   1618      command('cnoremap ;T s//Z/<left><left><left>')
   1619      feed(':%')
   1620      poke_eventloop()
   1621      feed(';T')
   1622      poke_eventloop()
   1623      feed('Y<enter>')
   1624      expect([[
   1625        Znc substitution on
   1626        two or three LZNES
   1627        ]])
   1628    end
   1629  end)
   1630 
   1631  it('still works with a broken mapping', function()
   1632    for _, case in pairs(cases) do
   1633      refresh(case, true)
   1634      command("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
   1635 
   1636      api.nvim_set_vvar('errmsg', '')
   1637      feed(':%s/tw/tox')
   1638      -- error thrown b/c of the mapping
   1639      matches('^E565:', api.nvim_get_vvar('errmsg'))
   1640 
   1641      feed('<enter>')
   1642      expect([[
   1643      Inc substitution on
   1644      toxo lines
   1645      ]])
   1646    end
   1647  end)
   1648 
   1649  it('work when temporarily moving the cursor', function()
   1650    for _, case in pairs(cases) do
   1651      refresh(case)
   1652      command("cnoremap <expr> x cursor(1, 1)[-1].'x'")
   1653 
   1654      feed(':%s/tw/tox')
   1655      poke_eventloop()
   1656      feed('/g<enter>')
   1657      expect(default_text:gsub('tw', 'tox'))
   1658    end
   1659  end)
   1660 
   1661  it("work when a mapping disables 'inccommand'", function()
   1662    for _, case in pairs(cases) do
   1663      refresh(case)
   1664      command("cnoremap <expr> x execute('set inccommand=')[-1]")
   1665 
   1666      feed(':%s/tw/tox')
   1667      poke_eventloop()
   1668      feed('a/g<enter>')
   1669      expect(default_text:gsub('tw', 'toa'))
   1670    end
   1671  end)
   1672 
   1673  it('work with a complex mapping', function()
   1674    for _, case in pairs(cases) do
   1675      refresh(case)
   1676      source([[cnoremap x <C-\>eextend(g:, {'fo': getcmdline()})
   1677      \.fo<CR><C-c>:new<CR>:bw!<CR>:<C-r>=remove(g:, 'fo')<CR>x]])
   1678 
   1679      feed(':%s/tw/tox')
   1680      poke_eventloop()
   1681      feed('/<enter>')
   1682      expect(default_text:gsub('tw', 'tox'))
   1683    end
   1684  end)
   1685 end)
   1686 
   1687 describe("'inccommand' autocommands", function()
   1688  before_each(clear)
   1689 
   1690  -- keys are events to be tested
   1691  -- values are arrays like
   1692  --    { open = { 1 }, close = { 2, 3} }
   1693  -- which would mean that during the test below the event fires for
   1694  -- buffer 1 when opening the preview window, and for buffers 2 and 3
   1695  -- when closing the preview window
   1696  local eventsExpected = {
   1697    BufAdd = {},
   1698    BufDelete = {},
   1699    BufEnter = {},
   1700    BufFilePost = {},
   1701    BufFilePre = {},
   1702    BufHidden = {},
   1703    BufLeave = {},
   1704    BufNew = {},
   1705    BufNewFile = {},
   1706    BufRead = {},
   1707    BufReadCmd = {},
   1708    BufReadPre = {},
   1709    BufUnload = {},
   1710    BufWinEnter = {},
   1711    BufWinLeave = {},
   1712    BufWipeout = {},
   1713    BufWrite = {},
   1714    BufWriteCmd = {},
   1715    BufWritePost = {},
   1716    Syntax = {},
   1717    FileType = {},
   1718    WinEnter = {},
   1719    WinLeave = {},
   1720    CmdwinEnter = {},
   1721    CmdwinLeave = {},
   1722  }
   1723 
   1724  local function bufferlist(q)
   1725    local s = ''
   1726    for _, buffer in pairs(q) do
   1727      s = s .. ', ' .. tostring(buffer)
   1728    end
   1729    return s
   1730  end
   1731 
   1732  -- fill the table with default values
   1733  for event, _ in pairs(eventsExpected) do
   1734    eventsExpected[event].open = eventsExpected[event].open or {}
   1735    eventsExpected[event].close = eventsExpected[event].close or {}
   1736  end
   1737 
   1738  local function register_autocmd(event)
   1739    api.nvim_set_var(event .. '_fired', {})
   1740    command('autocmd ' .. event .. ' * call add(g:' .. event .. "_fired, expand('<abuf>'))")
   1741  end
   1742 
   1743  it('are not fired when splitting', function()
   1744    common_setup(nil, 'split', default_text)
   1745 
   1746    local eventsObserved = {}
   1747    for event, _ in pairs(eventsExpected) do
   1748      eventsObserved[event] = {}
   1749      register_autocmd(event)
   1750    end
   1751 
   1752    feed(':%s/tw')
   1753 
   1754    for event, _ in pairs(eventsExpected) do
   1755      eventsObserved[event].open = api.nvim_get_var(event .. '_fired')
   1756      api.nvim_set_var(event .. '_fired', {})
   1757    end
   1758 
   1759    feed('/<enter>')
   1760 
   1761    for event, _ in pairs(eventsExpected) do
   1762      eventsObserved[event].close = api.nvim_get_var(event .. '_fired')
   1763    end
   1764 
   1765    for event, _ in pairs(eventsExpected) do
   1766      eq(
   1767        event .. bufferlist(eventsExpected[event].open),
   1768        event .. bufferlist(eventsObserved[event].open)
   1769      )
   1770      eq(
   1771        event .. bufferlist(eventsExpected[event].close),
   1772        event .. bufferlist(eventsObserved[event].close)
   1773      )
   1774    end
   1775  end)
   1776 end)
   1777 
   1778 describe("'inccommand' split windows", function()
   1779  local screen
   1780  local function refresh()
   1781    clear()
   1782    screen = Screen.new(40, 30)
   1783    common_setup(screen, 'split', default_text)
   1784  end
   1785 
   1786  it('work after more splits', function()
   1787    refresh()
   1788 
   1789    feed('gg')
   1790    command('vsplit')
   1791    command('split')
   1792    feed(':%s/tw')
   1793    screen:expect([[
   1794      Inc substitution on Inc substitution on|
   1795      {20:tw}o lines           {20:tw}o lines          |
   1796                                             |
   1797      {1:~                   }{1:~                  }|*11
   1798      {3:[No Name] [+]       }{1:~                  }|
   1799      Inc substitution on {1:~                  }|
   1800      {20:tw}o lines           {1:~                  }|
   1801                          {1:~                  }|
   1802      {1:~                   }{1:~                  }|*2
   1803      {2:[No Name] [+]        [No Name] [+]      }|
   1804      |2| {20:tw}o lines                           |
   1805      {1:~                                       }|*6
   1806      {2:[Preview]                               }|
   1807      :%s/tw^                                  |
   1808    ]])
   1809 
   1810    feed('<esc>')
   1811    command('only')
   1812    command('split')
   1813    command('vsplit')
   1814 
   1815    feed(':%s/tw')
   1816    screen:expect([[
   1817      Inc substitution on Inc substitution on|
   1818      {20:tw}o lines           {20:tw}o lines          |
   1819                                             |
   1820      {1:~                   }{1:~                  }|*11
   1821      {3:[No Name] [+]        }{2:[No Name] [+]      }|
   1822      Inc substitution on                     |
   1823      {20:tw}o lines                               |
   1824                                              |
   1825      {1:~                                       }|*2
   1826      {2:[No Name] [+]                           }|
   1827      |2| {20:tw}o lines                           |
   1828      {1:~                                       }|*6
   1829      {2:[Preview]                               }|
   1830      :%s/tw^                                  |
   1831    ]])
   1832  end)
   1833 
   1834  local settings = {
   1835    'splitbelow',
   1836    'splitright',
   1837    'noequalalways',
   1838    'equalalways eadirection=ver',
   1839    'equalalways eadirection=hor',
   1840    'equalalways eadirection=both',
   1841  }
   1842 
   1843  it('are not affected by various settings', function()
   1844    for _, setting in pairs(settings) do
   1845      refresh()
   1846      command('set ' .. setting)
   1847 
   1848      feed(':%s/tw')
   1849 
   1850      screen:expect([[
   1851        Inc substitution on                     |
   1852        {20:tw}o lines                               |
   1853                                                |
   1854        {1:~                                       }|*17
   1855        {3:[No Name] [+]                           }|
   1856        |2| {20:tw}o lines                           |
   1857        {1:~                                       }|*6
   1858        {2:[Preview]                               }|
   1859        :%s/tw^                                  |
   1860      ]])
   1861    end
   1862  end)
   1863 
   1864  it("don't open if there's not enough room", function()
   1865    refresh()
   1866    screen:try_resize(40, 3)
   1867    feed('gg:%s/tw')
   1868    screen:expect([[
   1869      Inc substitution on                     |
   1870      {20:tw}o lines                               |
   1871      :%s/tw^                                  |
   1872    ]])
   1873  end)
   1874 end)
   1875 
   1876 describe("'inccommand' with 'gdefault'", function()
   1877  before_each(function()
   1878    clear()
   1879  end)
   1880 
   1881  it('does not lock up #7244', function()
   1882    common_setup(nil, 'nosplit', '{')
   1883    command('set gdefault')
   1884    feed(':s/{\\n')
   1885    eq({ mode = 'c', blocking = false }, api.nvim_get_mode())
   1886    feed('/A<Enter>')
   1887    expect('A')
   1888    eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
   1889  end)
   1890 
   1891  it('with multiline text and range, does not lock up #7244', function()
   1892    common_setup(nil, 'nosplit', '{\n\n{')
   1893    command('set gdefault')
   1894    feed(':%s/{\\n')
   1895    eq({ mode = 'c', blocking = false }, api.nvim_get_mode())
   1896    feed('/A<Enter>')
   1897    expect('A\nA')
   1898    eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
   1899  end)
   1900 
   1901  it('does not crash on zero-width matches #7485', function()
   1902    common_setup(nil, 'split', default_text)
   1903    command('set gdefault')
   1904    feed('gg')
   1905    feed('Vj')
   1906    feed(':s/\\%V')
   1907    eq({ mode = 'c', blocking = false }, api.nvim_get_mode())
   1908    feed('<Esc>')
   1909    eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
   1910  end)
   1911 
   1912  it('removes highlights after abort for a zero-width match', function()
   1913    local screen = Screen.new(30, 5)
   1914    common_setup(screen, 'nosplit', default_text)
   1915    command('set gdefault')
   1916 
   1917    feed(':%s/\\%1c/a/')
   1918    screen:expect([[
   1919      {20:a}Inc substitution on          |
   1920      {20:a}two lines                    |
   1921      {20:a}                             |
   1922      {1:~                             }|
   1923      :%s/\%1c/a/^                   |
   1924    ]])
   1925 
   1926    feed('<Esc>')
   1927    screen:expect([[
   1928      Inc substitution on           |
   1929      two lines                     |
   1930      ^                              |
   1931      {1:~                             }|
   1932                                    |
   1933    ]])
   1934  end)
   1935 end)
   1936 
   1937 describe(':substitute', function()
   1938  local screen
   1939  before_each(function()
   1940    clear()
   1941    screen = Screen.new(30, 15)
   1942  end)
   1943 
   1944  it('inccommand=split, highlights multiline substitutions', function()
   1945    common_setup(screen, 'split', multiline_text)
   1946    feed('gg')
   1947 
   1948    feed(':%s/2\\_.*X')
   1949    screen:expect([[
   1950      1 {20:2 3}                         |
   1951      {20:A B C}                         |
   1952      {20:4 5 6}                         |
   1953      {20:X} Y Z                         |
   1954      7 8 9                         |
   1955      {3:[No Name] [+]                 }|
   1956      |1| 1 {20:2 3}                     |
   1957      |2|{20: A B C}                     |
   1958      |3|{20: 4 5 6}                     |
   1959      |4|{20: X} Y Z                     |
   1960      {1:~                             }|*3
   1961      {2:[Preview]                     }|
   1962      :%s/2\_.*X^                    |
   1963    ]])
   1964 
   1965    feed('/MMM')
   1966    screen:expect([[
   1967      1 {20:MMM} Y Z                     |
   1968      7 8 9                         |
   1969                                    |
   1970      {1:~                             }|*2
   1971      {3:[No Name] [+]                 }|
   1972      |1| 1 {20:MMM} Y Z                 |
   1973      {1:~                             }|*6
   1974      {2:[Preview]                     }|
   1975      :%s/2\_.*X/MMM^                |
   1976    ]])
   1977 
   1978    feed('\\rK\\rLLL')
   1979    screen:expect([[
   1980      1 {20:MMM}                         |
   1981      {20:K}                             |
   1982      {20:LLL} Y Z                       |
   1983      7 8 9                         |
   1984                                    |
   1985      {3:[No Name] [+]                 }|
   1986      |1| 1 {20:MMM}                     |
   1987      |2|{20: K}                         |
   1988      |3|{20: LLL} Y Z                   |
   1989      {1:~                             }|*4
   1990      {2:[Preview]                     }|
   1991      :%s/2\_.*X/MMM\rK\rLLL^        |
   1992    ]])
   1993  end)
   1994 
   1995  it('inccommand=nosplit, highlights multiline substitutions', function()
   1996    common_setup(screen, 'nosplit', multiline_text)
   1997    feed('gg')
   1998 
   1999    feed(':%s/2\\_.*X/MMM')
   2000    screen:expect([[
   2001      1 {20:MMM} Y Z                     |
   2002      7 8 9                         |
   2003                                    |
   2004      {1:~                             }|*11
   2005      :%s/2\_.*X/MMM^                |
   2006    ]])
   2007 
   2008    feed('\\rK\\rLLL')
   2009    screen:expect([[
   2010      1 {20:MMM}                         |
   2011      {20:K}                             |
   2012      {20:LLL} Y Z                       |
   2013      7 8 9                         |
   2014                                    |
   2015      {1:~                             }|*9
   2016      :%s/2\_.*X/MMM\rK\rLLL^        |
   2017    ]])
   2018  end)
   2019 
   2020  it('inccommand=split, highlights multiple matches on a line', function()
   2021    common_setup(screen, 'split', multimatch_text)
   2022    command('set gdefault')
   2023    feed('gg')
   2024 
   2025    feed(':%s/a/XLK')
   2026    screen:expect([[
   2027      {20:XLK} bdc e{20:XLK}e {20:XLK} fgl lzi{20:XLK} r|
   2028      x                             |
   2029                                    |
   2030      {1:~                             }|*2
   2031      {3:[No Name] [+]                 }|
   2032      |1| {20:XLK} bdc e{20:XLK}e {20:XLK} fgl lzi{20:X}|
   2033      {20:LK} r                          |
   2034      {1:~                             }|*5
   2035      {2:[Preview]                     }|
   2036      :%s/a/XLK^                     |
   2037    ]])
   2038  end)
   2039 
   2040  it('inccommand=nosplit, highlights multiple matches on a line', function()
   2041    common_setup(screen, 'nosplit', multimatch_text)
   2042    command('set gdefault')
   2043    feed('gg')
   2044 
   2045    feed(':%s/a/XLK')
   2046    screen:expect([[
   2047      {20:XLK} bdc e{20:XLK}e {20:XLK} fgl lzi{20:XLK} r|
   2048      x                             |
   2049                                    |
   2050      {1:~                             }|*11
   2051      :%s/a/XLK^                     |
   2052    ]])
   2053  end)
   2054 
   2055  it('inccommand=split, with \\zs', function()
   2056    common_setup(screen, 'split', multiline_text)
   2057    feed('gg')
   2058 
   2059    feed(':%s/[0-9]\\n\\zs[A-Z]/OKO')
   2060    screen:expect([[
   2061      {20:OKO} B C                       |
   2062      4 5 6                         |
   2063      {20:OKO} Y Z                       |
   2064      7 8 9                         |
   2065                                    |
   2066      {3:[No Name] [+]                 }|
   2067      |1| 1 2 3                     |
   2068      |2| {20:OKO} B C                   |
   2069      |3| 4 5 6                     |
   2070      |4| {20:OKO} Y Z                   |
   2071      {1:~                             }|*3
   2072      {2:[Preview]                     }|
   2073      :%s/[0-9]\n\zs[A-Z]/OKO^       |
   2074    ]])
   2075  end)
   2076 
   2077  it('inccommand=nosplit, with \\zs', function()
   2078    common_setup(screen, 'nosplit', multiline_text)
   2079    feed('gg')
   2080 
   2081    feed(':%s/[0-9]\\n\\zs[A-Z]/OKO')
   2082    screen:expect([[
   2083      1 2 3                         |
   2084      {20:OKO} B C                       |
   2085      4 5 6                         |
   2086      {20:OKO} Y Z                       |
   2087      7 8 9                         |
   2088                                    |
   2089      {1:~                             }|*8
   2090      :%s/[0-9]\n\zs[A-Z]/OKO^       |
   2091    ]])
   2092  end)
   2093 
   2094  it('inccommand=split, substitutions of different length', function()
   2095    common_setup(screen, 'split', 'T T123 T2T TTT T090804\nx')
   2096 
   2097    feed(':%s/T\\([0-9]\\+\\)/\\1\\1/g')
   2098    screen:expect([[
   2099      T {20:123123} {20:22}T TTT {20:090804090804} |
   2100      x                             |
   2101      {1:~                             }|*3
   2102      {3:[No Name] [+]                 }|
   2103      |1| T {20:123123} {20:22}T TTT {20:090804090}|
   2104      {20:804}                           |
   2105      {1:~                             }|*5
   2106      {2:[Preview]                     }|
   2107      :%s/T\([0-9]\+\)/\1\1/g^       |
   2108    ]])
   2109  end)
   2110 
   2111  it('inccommand=nosplit, substitutions of different length', function()
   2112    common_setup(screen, 'nosplit', 'T T123 T2T TTT T090804\nx')
   2113 
   2114    feed(':%s/T\\([0-9]\\+\\)/\\1\\1/g')
   2115    screen:expect([[
   2116      T {20:123123} {20:22}T TTT {20:090804090804} |
   2117      x                             |
   2118      {1:~                             }|*12
   2119      :%s/T\([0-9]\+\)/\1\1/g^       |
   2120    ]])
   2121  end)
   2122 
   2123  it('inccommand=split, contraction of lines', function()
   2124    local text = [[
   2125      T T123 T T123 T2T TT T23423424
   2126      x
   2127      afa Q
   2128      adf la;lkd R
   2129      alx
   2130      ]]
   2131 
   2132    common_setup(screen, 'split', text)
   2133    feed(':%s/[QR]\\n')
   2134    screen:expect([[
   2135      afa {20:Q}                         |
   2136      adf la;lkd {20:R}                  |
   2137      alx                           |
   2138                                    |
   2139      {1:~                             }|
   2140      {3:[No Name] [+]                 }|
   2141      |3| afa {20:Q}                     |
   2142      |4|{20: }adf la;lkd {20:R}              |
   2143      |5|{20: }alx                       |
   2144      {1:~                             }|*4
   2145      {2:[Preview]                     }|
   2146      :%s/[QR]\n^                    |
   2147    ]])
   2148 
   2149    feed('/KKK')
   2150    screen:expect([[
   2151      T T123 T T123 T2T TT T23423424|
   2152      x                             |
   2153      afa {20:KKK}adf la;lkd {20:KKK}alx      |
   2154                                    |
   2155      {1:~                             }|
   2156      {3:[No Name] [+]                 }|
   2157      |3| afa {20:KKK}adf la;lkd {20:KKK}alx  |
   2158      {1:~                             }|*6
   2159      {2:[Preview]                     }|
   2160      :%s/[QR]\n/KKK^                |
   2161    ]])
   2162  end)
   2163 
   2164  it('inccommand=nosplit, contraction of lines', function()
   2165    local text = [[
   2166      T T123 T T123 T2T TT T23423424
   2167      x
   2168      afa Q
   2169      adf la;lkd R
   2170      alx
   2171      ]]
   2172 
   2173    common_setup(screen, 'nosplit', text)
   2174    feed(':%s/[QR]\\n/KKK')
   2175    screen:expect([[
   2176      T T123 T T123 T2T TT T23423424|
   2177      x                             |
   2178      afa {20:KKK}adf la;lkd {20:KKK}alx      |
   2179                                    |
   2180      {1:~                             }|*10
   2181      :%s/[QR]\n/KKK^                |
   2182    ]])
   2183  end)
   2184 
   2185  it('inccommand=split, contraction of two subsequent NL chars', function()
   2186    local text = [[
   2187      AAA AA
   2188 
   2189      BBB BB
   2190 
   2191      CCC CC
   2192 
   2193 ]]
   2194 
   2195    -- This used to crash, but more than 20 highlight entries are required
   2196    -- to reproduce it (so that the marktree has multiple nodes)
   2197    common_setup(screen, 'split', string.rep(text, 10))
   2198    feed(':%s/\\n\\n/<c-v><c-m>/g')
   2199    screen:expect {
   2200      grid = [[
   2201      CCC CC                        |
   2202      AAA AA                        |
   2203      BBB BB                        |
   2204      CCC CC                        |
   2205                                    |
   2206      {3:[No Name] [+]                 }|
   2207      | 1| AAA AA                   |
   2208      | 2|{20: }BBB BB                   |
   2209      | 3|{20: }CCC CC                   |
   2210      | 4|{20: }AAA AA                   |
   2211      | 5|{20: }BBB BB                   |
   2212      | 6|{20: }CCC CC                   |
   2213      | 7|{20: }AAA AA                   |
   2214      {2:[Preview]                     }|
   2215      :%s/\n\n/{18:^M}/g^                 |
   2216    ]],
   2217    }
   2218    assert_alive()
   2219  end)
   2220 
   2221  it('inccommand=nosplit, contraction of two subsequent NL chars', function()
   2222    local text = [[
   2223      AAA AA
   2224 
   2225      BBB BB
   2226 
   2227      CCC CC
   2228 
   2229 ]]
   2230 
   2231    common_setup(screen, 'nosplit', string.rep(text, 10))
   2232    feed(':%s/\\n\\n/<c-v><c-m>/g')
   2233    screen:expect {
   2234      grid = [[
   2235      CCC CC                        |
   2236      AAA AA                        |
   2237      BBB BB                        |
   2238      CCC CC                        |
   2239      AAA AA                        |
   2240      BBB BB                        |
   2241      CCC CC                        |
   2242      AAA AA                        |
   2243      BBB BB                        |
   2244      CCC CC                        |
   2245      AAA AA                        |
   2246      BBB BB                        |
   2247      CCC CC                        |
   2248                                    |
   2249      :%s/\n\n/{18:^M}/g^                 |
   2250    ]],
   2251    }
   2252    assert_alive()
   2253  end)
   2254 
   2255  it('inccommand=split, multibyte text', function()
   2256    common_setup(screen, 'split', multibyte_text)
   2257    feed(':%s/£.*ѫ/X¥¥')
   2258    screen:expect([[
   2259       a{20:X¥¥}¥KOL                     |
   2260      £ ¥  libm                     |
   2261      £ ¥                           |
   2262                                    |
   2263      {1:~                             }|
   2264      {3:[No Name] [+]                 }|
   2265      |1|  {20:X¥¥} PEPPERS              |
   2266      |2| {20:X¥¥}                       |
   2267      |3|  a{20:X¥¥}¥KOL                 |
   2268      {1:~                             }|*4
   2269      {2:[Preview]                     }|
   2270      :%s/£.*ѫ/X¥¥^                  |
   2271    ]])
   2272 
   2273    feed('\\ra££   ¥')
   2274    screen:expect([[
   2275       a{20:X¥¥}                         |
   2276      {20:a££   ¥}¥KOL                   |
   2277      £ ¥  libm                     |
   2278      £ ¥                           |
   2279                                    |
   2280      {3:[No Name] [+]                 }|
   2281      |1|  {20:X¥¥}                      |
   2282      |2|{20: a££   ¥} PEPPERS           |
   2283      |3| {20:X¥¥}                       |
   2284      |4|{20: a££   ¥}                   |
   2285      |5|  a{20:X¥¥}                     |
   2286      |6|{20: a££   ¥}¥KOL               |
   2287      {1:~                             }|
   2288      {2:[Preview]                     }|
   2289      :%s/£.*ѫ/X¥¥\ra££   ¥^         |
   2290    ]])
   2291  end)
   2292 
   2293  it('inccommand=nosplit, multibyte text', function()
   2294    common_setup(screen, 'nosplit', multibyte_text)
   2295    feed(':%s/£.*ѫ/X¥¥')
   2296    screen:expect([[
   2297       {20:X¥¥} PEPPERS                  |
   2298      {20:X¥¥}                           |
   2299       a{20:X¥¥}¥KOL                     |
   2300      £ ¥  libm                     |
   2301      £ ¥                           |
   2302                                    |
   2303      {1:~                             }|*8
   2304      :%s/£.*ѫ/X¥¥^                  |
   2305    ]])
   2306 
   2307    feed('\\ra££   ¥')
   2308    screen:expect([[
   2309       {20:X¥¥}                          |
   2310      {20:a££   ¥} PEPPERS               |
   2311      {20:X¥¥}                           |
   2312      {20:a££   ¥}                       |
   2313       a{20:X¥¥}                         |
   2314      {20:a££   ¥}¥KOL                   |
   2315      £ ¥  libm                     |
   2316      £ ¥                           |
   2317                                    |
   2318      {1:~                             }|*5
   2319      :%s/£.*ѫ/X¥¥\ra££   ¥^         |
   2320    ]])
   2321  end)
   2322 
   2323  it('inccommand=split, small cmdwinheight', function()
   2324    common_setup(screen, 'split', long_multiline_text)
   2325    command('set cmdwinheight=2')
   2326 
   2327    feed(':%s/[a-z]')
   2328    screen:expect([[
   2329      X Y Z                         |
   2330      7 8 9                         |
   2331      K L M                         |
   2332      {20:a} b c                         |
   2333      {20:d} e f                         |
   2334      {20:q} r s                         |
   2335      {20:x} y z                         |
   2336      £ {20:m} n                         |
   2337      {20:t} œ ¥                         |
   2338                                    |
   2339      {3:[No Name] [+]                 }|
   2340      | 7| {20:a} b c                    |
   2341      | 8| {20:d} e f                    |
   2342      {2:[Preview]                     }|
   2343      :%s/[a-z]^                     |
   2344    ]])
   2345 
   2346    feed('/JLKR £')
   2347    screen:expect([[
   2348      X Y Z                         |
   2349      7 8 9                         |
   2350      K L M                         |
   2351      {20:JLKR £} b c                    |
   2352      {20:JLKR £} e f                    |
   2353      {20:JLKR £} r s                    |
   2354      {20:JLKR £} y z                    |
   2355      £ {20:JLKR £} n                    |
   2356      {20:JLKR £} œ ¥                    |
   2357                                    |
   2358      {3:[No Name] [+]                 }|
   2359      | 7| {20:JLKR £} b c               |
   2360      | 8| {20:JLKR £} e f               |
   2361      {2:[Preview]                     }|
   2362      :%s/[a-z]/JLKR £^              |
   2363    ]])
   2364 
   2365    feed('\\rѫ ab   \\rXXXX')
   2366    screen:expect([[
   2367      7 8 9                         |
   2368      K L M                         |
   2369      {20:JLKR £}                        |
   2370      {20:ѫ ab   }                       |
   2371      {20:XXXX} b c                      |
   2372      {20:JLKR £}                        |
   2373      {20:ѫ ab   }                       |
   2374      {20:XXXX} e f                      |
   2375      {20:JLKR £}                        |
   2376      {20:ѫ ab   }                       |
   2377      {3:[No Name] [+]                 }|
   2378      | 7| {20:JLKR £}                   |
   2379      {3:                              }|
   2380      :%s/[a-z]/JLKR £\ ab   \rXXX|
   2381      X^                             |
   2382    ]])
   2383  end)
   2384 
   2385  it('inccommand=split, large cmdwinheight', function()
   2386    common_setup(screen, 'split', long_multiline_text)
   2387    command('set cmdwinheight=11')
   2388 
   2389    feed(':%s/. .$')
   2390    screen:expect([[
   2391      t {20:œ ¥}                         |
   2392      {3:[No Name] [+]                 }|
   2393      | 1| 1 {20:2 3}                    |
   2394      | 2| A {20:B C}                    |
   2395      | 3| 4 {20:5 6}                    |
   2396      | 4| X {20:Y Z}                    |
   2397      | 5| 7 {20:8 9}                    |
   2398      | 6| K {20:L M}                    |
   2399      | 7| a {20:b c}                    |
   2400      | 8| d {20:e f}                    |
   2401      | 9| q {20:r s}                    |
   2402      |10| x {20:y z}                    |
   2403      |11| £ {20:m n}                    |
   2404      {2:[Preview]                     }|
   2405      :%s/. .$^                      |
   2406    ]])
   2407 
   2408    feed('/ YYY')
   2409    screen:expect([[
   2410      t {20: YYY}                        |
   2411      {3:[No Name] [+]                 }|
   2412      | 1| 1 {20: YYY}                   |
   2413      | 2| A {20: YYY}                   |
   2414      | 3| 4 {20: YYY}                   |
   2415      | 4| X {20: YYY}                   |
   2416      | 5| 7 {20: YYY}                   |
   2417      | 6| K {20: YYY}                   |
   2418      | 7| a {20: YYY}                   |
   2419      | 8| d {20: YYY}                   |
   2420      | 9| q {20: YYY}                   |
   2421      |10| x {20: YYY}                   |
   2422      |11| £ {20: YYY}                   |
   2423      {2:[Preview]                     }|
   2424      :%s/. .$/ YYY^                 |
   2425    ]])
   2426 
   2427    feed('\\r KKK')
   2428    screen:expect([[
   2429      a {20: YYY}                        |
   2430      {3:[No Name] [+]                 }|
   2431      | 1| 1 {20: YYY}                   |
   2432      | 2|{20:  KKK}                     |
   2433      | 3| A {20: YYY}                   |
   2434      | 4|{20:  KKK}                     |
   2435      | 5| 4 {20: YYY}                   |
   2436      | 6|{20:  KKK}                     |
   2437      | 7| X {20: YYY}                   |
   2438      | 8|{20:  KKK}                     |
   2439      | 9| 7 {20: YYY}                   |
   2440      |10|{20:  KKK}                     |
   2441      |11| K {20: YYY}                   |
   2442      {2:[Preview]                     }|
   2443      :%s/. .$/ YYY\r KKK^           |
   2444    ]])
   2445  end)
   2446 
   2447  it('inccommand=split, lookaround', function()
   2448    common_setup(screen, 'split', 'something\neverything\nsomeone')
   2449    feed([[:%s/\(some\)\@<lt>=thing/one/]])
   2450    screen:expect([[
   2451      some{20:one}                       |
   2452      everything                    |
   2453      someone                       |
   2454      {1:~                             }|*2
   2455      {3:[No Name] [+]                 }|
   2456      |1| some{20:one}                   |
   2457      {1:~                             }|*6
   2458      {2:[Preview]                     }|
   2459      :%s/\(some\)\@<=thing/one/^    |
   2460    ]])
   2461 
   2462    feed('<C-c>')
   2463    feed('gg')
   2464    poke_eventloop()
   2465    feed([[:%s/\(some\)\@<lt>!thing/one/]])
   2466    screen:expect([[
   2467      something                     |
   2468      every{20:one}                      |
   2469      someone                       |
   2470      {1:~                             }|*2
   2471      {3:[No Name] [+]                 }|
   2472      |2| every{20:one}                  |
   2473      {1:~                             }|*6
   2474      {2:[Preview]                     }|
   2475      :%s/\(some\)\@<!thing/one/^    |
   2476    ]])
   2477 
   2478    feed([[<C-c>]])
   2479    poke_eventloop()
   2480    feed([[:%s/some\(thing\)\@=/every/]])
   2481    screen:expect([[
   2482      {20:every}thing                    |
   2483      everything                    |
   2484      someone                       |
   2485      {1:~                             }|*2
   2486      {3:[No Name] [+]                 }|
   2487      |1| {20:every}thing                |
   2488      {1:~                             }|*6
   2489      {2:[Preview]                     }|
   2490      :%s/some\(thing\)\@=/every/^   |
   2491    ]])
   2492 
   2493    feed([[<C-c>]])
   2494    poke_eventloop()
   2495    feed([[:%s/some\(thing\)\@!/every/]])
   2496    screen:expect([[
   2497      something                     |
   2498      everything                    |
   2499      {20:every}one                      |
   2500      {1:~                             }|*2
   2501      {3:[No Name] [+]                 }|
   2502      |3| {20:every}one                  |
   2503      {1:~                             }|*6
   2504      {2:[Preview]                     }|
   2505      :%s/some\(thing\)\@!/every/^   |
   2506    ]])
   2507  end)
   2508 
   2509  it("doesn't prompt to swap cmd range", function()
   2510    screen:try_resize(50, 8) -- wide to avoid hit-enter prompt
   2511    common_setup(screen, 'split', default_text)
   2512    feed(':2,1s/tw/MO/g')
   2513 
   2514    -- substitution preview should have been made, without prompting
   2515    screen:expect([[
   2516      {20:MO}o lines                                         |
   2517      {3:[No Name] [+]                                     }|
   2518      |2| {20:MO}o lines                                     |
   2519      {1:~                                                 }|*3
   2520      {2:[Preview]                                         }|
   2521      :2,1s/tw/MO/g^                                     |
   2522    ]])
   2523 
   2524    -- but should be prompted on hitting enter
   2525    feed('<CR>')
   2526    screen:expect([[
   2527      {20:MO}o lines                                         |
   2528      {3:[No Name] [+]                                     }|
   2529      |2| {20:MO}o lines                                     |
   2530      {1:~                                                 }|*3
   2531      {2:[Preview]                                         }|
   2532      {6:Backwards range given, OK to swap (y/n)?}^          |
   2533    ]])
   2534 
   2535    feed('y')
   2536    screen:expect([[
   2537      Inc substitution on                               |
   2538      ^MOo lines                                         |
   2539                                                        |
   2540      {1:~                                                 }|*4
   2541      {6:Backwards range given, OK to swap (y/n)?}y         |
   2542    ]])
   2543  end)
   2544 end)
   2545 
   2546 it(':substitute with inccommand during :terminal activity', function()
   2547  if t.skip_fragile(pending) then
   2548    return
   2549  end
   2550  retry(2, 40000, function()
   2551    clear()
   2552    local screen = Screen.new(30, 15)
   2553 
   2554    command('set cmdwinheight=3')
   2555    feed(([[:terminal "%s" REP 5000 xxx<cr>]]):format(testprg('shell-test')))
   2556    command('file term')
   2557    feed('G') -- Follow :terminal output.
   2558    command('new')
   2559    common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
   2560    command('wincmd =')
   2561 
   2562    feed('gg')
   2563    feed(':%s/foo/ZZZ')
   2564    sleep(20) -- Allow some terminal activity.
   2565    poke_eventloop()
   2566    screen:sleep(0)
   2567    screen:expect_unchanged()
   2568  end)
   2569 end)
   2570 
   2571 it(':substitute with inccommand, timer-induced :redraw #9777', function()
   2572  clear()
   2573  local screen = Screen.new(30, 12)
   2574  command('set cmdwinheight=3')
   2575  command('call timer_start(10, {-> execute("redraw")}, {"repeat":-1})')
   2576  command('call timer_start(10, {-> execute("redrawstatus")}, {"repeat":-1})')
   2577  common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
   2578 
   2579  feed('gg')
   2580  feed(':%s/foo/ZZZ')
   2581  sleep(20) -- Allow some timer activity.
   2582  screen:expect([[
   2583    {20:ZZZ} bar baz                   |
   2584    bar baz fox                   |
   2585    bar {20:ZZZ} baz                   |
   2586    {1:~                             }|*3
   2587    {3:[No Name] [+]                 }|
   2588    |1| {20:ZZZ} bar baz               |
   2589    |3| bar {20:ZZZ} baz               |
   2590    {1:~                             }|
   2591    {2:[Preview]                     }|
   2592    :%s/foo/ZZZ^                   |
   2593  ]])
   2594 
   2595  -- Also with nvim__redraw()
   2596  command('call timer_start(10, {-> nvim__redraw(#{flush:1})}, {"repeat":-1})')
   2597  command('call timer_start(10, {-> nvim__redraw(#{statusline:1})}, {"repeat":-1})')
   2598  sleep(20) -- Allow some timer activity.
   2599  screen:expect_unchanged()
   2600 end)
   2601 
   2602 it(':substitute with inccommand, allows :redraw before first separator is typed #18857', function()
   2603  clear()
   2604  local screen = Screen.new(30, 6)
   2605  common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
   2606  command('hi! link NormalFloat CursorLine')
   2607  local float_buf = api.nvim_create_buf(false, true)
   2608  api.nvim_open_win(float_buf, false, {
   2609    relative = 'editor',
   2610    height = 1,
   2611    width = 5,
   2612    row = 3,
   2613    col = 0,
   2614    focusable = false,
   2615  })
   2616  feed(':')
   2617  screen:expect([[
   2618    foo bar baz                   |
   2619    bar baz fox                   |
   2620    bar foo baz                   |
   2621    {21:     }{1:                         }|
   2622    {1:~                             }|
   2623    :^                             |
   2624  ]])
   2625  feed('%s')
   2626  screen:expect([[
   2627    foo bar baz                   |
   2628    bar baz fox                   |
   2629    bar foo baz                   |
   2630    {21:     }{1:                         }|
   2631    {1:~                             }|
   2632    :%s^                           |
   2633  ]])
   2634  api.nvim_buf_set_lines(float_buf, 0, -1, true, { 'foo' })
   2635  command('redraw')
   2636  screen:expect([[
   2637    foo bar baz                   |
   2638    bar baz fox                   |
   2639    bar foo baz                   |
   2640    {21:foo  }{1:                         }|
   2641    {1:~                             }|
   2642    :%s^                           |
   2643  ]])
   2644 end)
   2645 
   2646 it(':substitute with inccommand, does not crash if range contains invalid marks', function()
   2647  clear()
   2648  local screen = Screen.new(30, 6)
   2649  common_setup(screen, 'split', 'test')
   2650  feed([[:'a,'bs]])
   2651  screen:expect([[
   2652    test                          |
   2653    {1:~                             }|*4
   2654    :'a,'bs^                       |
   2655  ]])
   2656  -- v:errmsg shouldn't be set either before the first separator is typed
   2657  eq('', eval('v:errmsg'))
   2658  feed('/')
   2659  screen:expect([[
   2660    test                          |
   2661    {1:~                             }|*4
   2662    :'a,'bs/^                      |
   2663  ]])
   2664 end)
   2665 
   2666 it(':substitute with inccommand, no unnecessary redraw if preview is not shown', function()
   2667  clear()
   2668  local screen = Screen.new(60, 6)
   2669  common_setup(screen, 'split', 'test')
   2670  feed(':ls<CR>')
   2671  screen:expect([[
   2672    test                                                        |
   2673    {1:~                                                           }|
   2674    {3:                                                            }|
   2675    :ls                                                         |
   2676      1 %a + "[No Name]"                    line 1              |
   2677    {6:Press ENTER or type command to continue}^                     |
   2678  ]])
   2679  feed(':s')
   2680  -- no unnecessary redraw, so messages are still shown
   2681  screen:expect([[
   2682    test                                                        |
   2683    {1:~                                                           }|
   2684    {3:                                                            }|
   2685    :ls                                                         |
   2686      1 %a + "[No Name]"                    line 1              |
   2687    :s^                                                          |
   2688  ]])
   2689  feed('o')
   2690  screen:expect([[
   2691    test                                                        |
   2692    {1:~                                                           }|
   2693    {3:                                                            }|
   2694    :ls                                                         |
   2695      1 %a + "[No Name]"                    line 1              |
   2696    :so^                                                         |
   2697  ]])
   2698  feed('<BS>')
   2699  screen:expect([[
   2700    test                                                        |
   2701    {1:~                                                           }|
   2702    {3:                                                            }|
   2703    :ls                                                         |
   2704      1 %a + "[No Name]"                    line 1              |
   2705    :s^                                                          |
   2706  ]])
   2707  feed('/test')
   2708  -- now inccommand is shown, so screen is redrawn
   2709  screen:expect([[
   2710    {20:test}                                                        |
   2711    {1:~                                                           }|*4
   2712    :s/test^                                                     |
   2713  ]])
   2714 end)
   2715 
   2716 it(":substitute doesn't crash with inccommand, if undo is empty #12932", function()
   2717  clear()
   2718  local screen = Screen.new(10, 5)
   2719  command('set undolevels=-1')
   2720  common_setup(screen, 'split', 'test')
   2721  feed(':%s/test')
   2722  sleep(100)
   2723  feed('/')
   2724  sleep(100)
   2725  feed('f')
   2726  screen:expect([[
   2727  {20:f}           |
   2728  {1:~           }|*3
   2729  :%s/test/f^  |
   2730  ]])
   2731  assert_alive()
   2732 end)
   2733 
   2734 it(':substitute with inccommand works properly if undo is not synced #20029', function()
   2735  clear()
   2736  local screen = Screen.new(30, 6)
   2737  common_setup(screen, 'nosplit', 'foo\nbar\nbaz')
   2738  api.nvim_set_keymap('x', '<F2>', '<Esc>`<Oaaaaa asdf<Esc>`>obbbbb asdf<Esc>V`<k:s/asdf/', {})
   2739  feed('gg0<C-V>lljj<F2>')
   2740  screen:expect([[
   2741    aaaaa                         |
   2742    foo                           |
   2743    bar                           |
   2744    baz                           |
   2745    bbbbb                         |
   2746    :'<,'>s/asdf/^                 |
   2747  ]])
   2748  feed('hjkl')
   2749  screen:expect([[
   2750    aaaaa {20:hjkl}                    |
   2751    foo                           |
   2752    bar                           |
   2753    baz                           |
   2754    bbbbb {20:hjkl}                    |
   2755    :'<,'>s/asdf/hjkl^             |
   2756  ]])
   2757  feed('<CR>')
   2758  expect([[
   2759    aaaaa hjkl
   2760    foo
   2761    bar
   2762    baz
   2763    bbbbb hjkl]])
   2764  feed('u')
   2765  expect([[
   2766    foo
   2767    bar
   2768    baz]])
   2769 end)
   2770 
   2771 it(':substitute with inccommand does not unexpectedly change viewport #25697', function()
   2772  clear()
   2773  local screen = Screen.new(45, 5)
   2774  common_setup(screen, 'nosplit', long_multiline_text)
   2775  command('vnew | tabnew | tabclose')
   2776  screen:expect([[
   2777    ^                      │£ m n                 |
   2778    {1:~                     }t œ ¥                 |
   2779    {1:~                     }                      |
   2780    {3:[No Name]              }{2:[No Name] [+]         }|
   2781                                                 |
   2782  ]])
   2783  feed(':s/')
   2784  screen:expect([[
   2785                          │£ m n                 |
   2786    {1:~                     }t œ ¥                 |
   2787    {1:~                     }                      |
   2788    {3:[No Name]              }{2:[No Name] [+]         }|
   2789    :s/^                                          |
   2790  ]])
   2791  feed('<Esc>')
   2792  screen:expect([[
   2793    ^                      │£ m n                 |
   2794    {1:~                     }t œ ¥                 |
   2795    {1:~                     }                      |
   2796    {3:[No Name]              }{2:[No Name] [+]         }|
   2797                                                 |
   2798  ]])
   2799 end)
   2800 
   2801 it('long :%s/ with inccommand does not collapse cmdline', function()
   2802  clear()
   2803  local screen = Screen.new(10, 5)
   2804  common_setup(screen, 'nosplit')
   2805  feed(
   2806    ':%s/AAAAAAA',
   2807    'A',
   2808    'A',
   2809    'A',
   2810    'A',
   2811    'A',
   2812    'A',
   2813    'A',
   2814    'A',
   2815    'A',
   2816    'A',
   2817    'A',
   2818    'A',
   2819    'A',
   2820    'A',
   2821    'A',
   2822    'A',
   2823    'A',
   2824    'A',
   2825    'A',
   2826    'A'
   2827  )
   2828  screen:expect([[
   2829                |
   2830    {3:            }|
   2831    :%s/AAAAAAAA|
   2832    AAAAAAAAAAAA|
   2833    AAAAAAA^     |
   2834  ]])
   2835 end)
   2836 
   2837 it("with 'inccommand' typing invalid `={expr}` does not show error", function()
   2838  clear()
   2839  local screen = Screen.new(30, 6)
   2840  common_setup(screen, 'nosplit')
   2841  feed(':edit `=`')
   2842  screen:expect([[
   2843                                  |
   2844    {1:~                             }|*4
   2845    :edit `=`^                     |
   2846  ]])
   2847 end)
   2848 
   2849 it("with 'inccommand' typing :filter doesn't segfault or leak memory #19057", function()
   2850  clear()
   2851  common_setup(nil, 'nosplit')
   2852  feed(':filter s')
   2853  assert_alive()
   2854  feed(' ')
   2855  assert_alive()
   2856  feed('h')
   2857  assert_alive()
   2858  feed('i')
   2859  assert_alive()
   2860 end)
   2861 
   2862 it("'inccommand' cannot be changed during preview #23136", function()
   2863  clear()
   2864  local screen = Screen.new(30, 6)
   2865  common_setup(screen, 'nosplit', 'foo\nbar\nbaz')
   2866  source([[
   2867    function! IncCommandToggle()
   2868      let prev = &inccommand
   2869 
   2870      if &inccommand ==# 'split'
   2871        set inccommand=nosplit
   2872      elseif &inccommand ==# 'nosplit'
   2873        set inccommand=split
   2874      elseif &inccommand ==# ''
   2875        set inccommand=nosplit
   2876      else
   2877        throw 'unknown inccommand'
   2878      endif
   2879 
   2880      return " \<BS>"
   2881    endfun
   2882 
   2883    cnoremap <expr> <C-E> IncCommandToggle()
   2884  ]])
   2885 
   2886  feed(':%s/foo/bar<C-E><C-E><C-E>')
   2887  assert_alive()
   2888 end)
   2889 
   2890 it("'inccommand' value can be changed multiple times #27086", function()
   2891  clear()
   2892  local screen = Screen.new(30, 20)
   2893  common_setup(screen, 'split', 'foo1\nfoo2\nfoo3')
   2894  for _ = 1, 3 do
   2895    feed(':%s/foo/bar')
   2896    screen:expect([[
   2897      {20:bar}1                          |
   2898      {20:bar}2                          |
   2899      {20:bar}3                          |
   2900      {1:~                             }|*7
   2901      {3:[No Name] [+]                 }|
   2902      |1| {20:bar}1                      |
   2903      |2| {20:bar}2                      |
   2904      |3| {20:bar}3                      |
   2905      {1:~                             }|*4
   2906      {2:[Preview]                     }|
   2907      :%s/foo/bar^                   |
   2908    ]])
   2909    feed('<Esc>')
   2910    command('set inccommand=nosplit')
   2911    feed(':%s/foo/bar')
   2912    screen:expect([[
   2913      {20:bar}1                          |
   2914      {20:bar}2                          |
   2915      {20:bar}3                          |
   2916      {1:~                             }|*16
   2917      :%s/foo/bar^                   |
   2918    ]])
   2919    feed('<Esc>')
   2920    command('set inccommand=split')
   2921  end
   2922 end)
   2923 
   2924 it("'inccommand' disables preview if preview buffer can't be created #27086", function()
   2925  clear()
   2926  api.nvim_buf_set_name(0, '[Preview]')
   2927  local screen = Screen.new(30, 20)
   2928  common_setup(screen, 'split', 'foo1\nfoo2\nfoo3')
   2929  eq('split', api.nvim_get_option_value('inccommand', {}))
   2930  feed(':%s/foo/bar')
   2931  screen:expect([[
   2932    {20:bar}1                          |
   2933    {20:bar}2                          |
   2934    {20:bar}3                          |
   2935    {1:~                             }|*16
   2936    :%s/foo/bar^                   |
   2937  ]])
   2938  eq('nosplit', api.nvim_get_option_value('inccommand', {}))
   2939 end)
   2940 
   2941 it("'inccommand' :substitute preview skips input() prompt #11940", function()
   2942  clear()
   2943  local screen = Screen.new(30, 3)
   2944  common_setup(screen, 'split', 'foo')
   2945  feed([[:s/f/\=input("sub: ")]])
   2946  screen:expect([[
   2947    oo                            |
   2948    {1:~                             }|
   2949    :s/f/\=input("sub: ")^         |
   2950  ]])
   2951 end)