mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			3115 lines
		
	
	
		
			94 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			3115 lines
		
	
	
		
			94 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local helpers = require('test.functional.helpers')(after_each)
 | |
| local Screen = require('test.functional.ui.screen')
 | |
| local clear = helpers.clear
 | |
| local command = helpers.command
 | |
| local curbufmeths = helpers.curbufmeths
 | |
| local eq = helpers.eq
 | |
| local eval = helpers.eval
 | |
| local feed_command = helpers.feed_command
 | |
| local expect = helpers.expect
 | |
| local feed = helpers.feed
 | |
| local insert = helpers.insert
 | |
| local meths = helpers.meths
 | |
| local neq = helpers.neq
 | |
| local ok = helpers.ok
 | |
| local retry = helpers.retry
 | |
| local source = helpers.source
 | |
| local poke_eventloop = helpers.poke_eventloop
 | |
| local nvim = helpers.nvim
 | |
| local sleep = helpers.sleep
 | |
| local testprg = helpers.testprg
 | |
| local assert_alive = helpers.assert_alive
 | |
| 
 | |
| local default_text = [[
 | |
|   Inc substitution on
 | |
|   two lines
 | |
| ]]
 | |
| 
 | |
| local multiline_text = [[
 | |
|   1 2 3
 | |
|   A B C
 | |
|   4 5 6
 | |
|   X Y Z
 | |
|   7 8 9
 | |
| ]]
 | |
| 
 | |
| local multimatch_text  = [[
 | |
|   a bdc eae a fgl lzia r
 | |
|   x
 | |
| ]]
 | |
| 
 | |
| local multibyte_text = [[
 | |
|  £ ¥ ѫѫ PEPPERS
 | |
| £ ¥ ѫfѫ
 | |
|  a£ ѫ¥KOL
 | |
| £ ¥  libm
 | |
| £ ¥
 | |
| ]]
 | |
| 
 | |
| local long_multiline_text = [[
 | |
|   1 2 3
 | |
|   A B C
 | |
|   4 5 6
 | |
|   X Y Z
 | |
|   7 8 9
 | |
|   K L M
 | |
|   a b c
 | |
|   d e f
 | |
|   q r s
 | |
|   x y z
 | |
|   £ m n
 | |
|   t œ ¥
 | |
| ]]
 | |
| 
 | |
| local function common_setup(screen, inccommand, text)
 | |
|   if screen then
 | |
|     command("syntax on")
 | |
|     command("set nohlsearch")
 | |
|     command("hi Substitute guifg=red guibg=yellow")
 | |
|     screen:attach()
 | |
|     screen:set_default_attr_ids({
 | |
|       [1]  = {foreground = Screen.colors.Fuchsia},
 | |
|       [2]  = {foreground = Screen.colors.Brown, bold = true},
 | |
|       [3]  = {foreground = Screen.colors.SlateBlue},
 | |
|       [4]  = {bold = true, foreground = Screen.colors.SlateBlue},
 | |
|       [5]  = {foreground = Screen.colors.DarkCyan},
 | |
|       [6]  = {bold = true},
 | |
|       [7]  = {underline = true, bold = true, foreground = Screen.colors.SlateBlue},
 | |
|       [8]  = {foreground = Screen.colors.Slateblue, underline = true},
 | |
|       [9]  = {background = Screen.colors.Yellow},
 | |
|       [10] = {reverse = true},
 | |
|       [11] = {reverse = true, bold=true},
 | |
|       [12] = {foreground = Screen.colors.Red, background = Screen.colors.Yellow},
 | |
|       [13] = {bold = true, foreground = Screen.colors.SeaGreen},
 | |
|       [14] = {foreground = Screen.colors.White, background = Screen.colors.Red},
 | |
|       [15] = {bold=true, foreground=Screen.colors.Blue},
 | |
|       [16] = {background=Screen.colors.Grey90},  -- cursorline
 | |
|       [17] = {foreground = Screen.colors.Blue1},
 | |
|       vis  = {background=Screen.colors.LightGrey}
 | |
|     })
 | |
|   end
 | |
| 
 | |
|   command("set inccommand=" .. (inccommand or ""))
 | |
| 
 | |
|   if text then
 | |
|     insert(text)
 | |
|   end
 | |
| end
 | |
| 
 | |
| describe(":substitute, inccommand=split interactivity", function()
 | |
|   before_each(function()
 | |
|     clear()
 | |
|     common_setup(nil, "split", default_text)
 | |
|   end)
 | |
| 
 | |
|   -- Test the tests: verify that the `1==bufnr('$')` assertion
 | |
|   -- in the "no preview" tests (below) actually means something.
 | |
|   it("previews interactive cmdline", function()
 | |
|     feed(':%s/tw/MO/g')
 | |
|     retry(nil, 1000, function()
 | |
|       eq(2, eval("bufnr('$')"))
 | |
|     end)
 | |
|   end)
 | |
| 
 | |
|   it("no preview if invoked by a script", function()
 | |
|     source('%s/tw/MO/g')
 | |
|     poke_eventloop()
 | |
|     eq(1, eval("bufnr('$')"))
 | |
|     -- sanity check: assert the buffer state
 | |
|     expect(default_text:gsub("tw", "MO"))
 | |
|   end)
 | |
| 
 | |
|   it("no preview if invoked by feedkeys()", function()
 | |
|     -- in a script...
 | |
|     source([[:call feedkeys(":%s/tw/MO/g\<CR>")]])
 | |
|     -- or interactively...
 | |
|     feed([[:call feedkeys(":%s/bs/BUU/g\<lt>CR>")<CR>]])
 | |
|     eq(1, eval("bufnr('$')"))
 | |
|     -- sanity check: assert the buffer state
 | |
|     expect(default_text:gsub("tw", "MO"):gsub("bs", "BUU"))
 | |
|   end)
 | |
| end)
 | |
| 
 | |
| describe(":substitute, 'inccommand' preserves", function()
 | |
|   before_each(clear)
 | |
| 
 | |
|   it('listed buffers (:ls)', function()
 | |
|     local screen = Screen.new(30,10)
 | |
|     common_setup(screen, "split", "ABC")
 | |
| 
 | |
|     feed_command("%s/AB/BA/")
 | |
|     feed_command("ls")
 | |
| 
 | |
|     screen:expect([[
 | |
|       BAC                           |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:                              }|
 | |
|       :ls                           |
 | |
|         1 %a + "[No Name]"          |
 | |
|                 line 1              |
 | |
|       {13:Press ENTER or type command to}|
 | |
|       {13: continue}^                     |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   for _, case in pairs{"", "split", "nosplit"} do
 | |
|     it("various delimiters (inccommand="..case..")", function()
 | |
|       insert(default_text)
 | |
|       feed_command("set inccommand=" .. case)
 | |
| 
 | |
|       local delims = { '/', '#', ';', '%', ',', '@', '!' }
 | |
|       for _,delim in pairs(delims) do
 | |
|         feed_command("%s"..delim.."lines"..delim.."LINES"..delim.."g")
 | |
|         expect([[
 | |
|           Inc substitution on
 | |
|           two LINES
 | |
|           ]])
 | |
|         feed_command("undo")
 | |
|       end
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   for _, case in pairs{"", "split", "nosplit"} do
 | |
|     it("'undolevels' (inccommand="..case..")", function()
 | |
|       feed_command("set undolevels=139")
 | |
|       feed_command("setlocal undolevels=34")
 | |
|       feed_command("set inccommand=" .. case)
 | |
|       insert("as")
 | |
|       feed(":%s/as/glork/<enter>")
 | |
|       eq(meths.get_option('undolevels'), 139)
 | |
|       eq(curbufmeths.get_option('undolevels'), 34)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   for _, case in ipairs({"", "split", "nosplit"}) do
 | |
|     it("empty undotree() (inccommand="..case..")", function()
 | |
|       feed_command("set undolevels=1000")
 | |
|       feed_command("set inccommand=" .. case)
 | |
|       local expected_undotree = eval("undotree()")
 | |
| 
 | |
|       -- Start typing an incomplete :substitute command.
 | |
|       feed([[:%s/e/YYYY/g]])
 | |
|       poke_eventloop()
 | |
|       -- Cancel the :substitute.
 | |
|       feed([[<C-\><C-N>]])
 | |
| 
 | |
|       -- The undo tree should be unchanged.
 | |
|       eq(expected_undotree, eval("undotree()"))
 | |
|       eq({}, eval("undotree()")["entries"])
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   for _, case in ipairs({"", "split", "nosplit"}) do
 | |
|     it("undotree() with branches (inccommand="..case..")", function()
 | |
|       feed_command("set undolevels=1000")
 | |
|       feed_command("set inccommand=" .. case)
 | |
|       -- Make some changes.
 | |
|       feed([[isome text 1<C-\><C-N>]])
 | |
|       feed([[osome text 2<C-\><C-N>]])
 | |
|       -- Add an undo branch.
 | |
|       feed([[u]])
 | |
|       -- More changes, more undo branches.
 | |
|       feed([[osome text 3<C-\><C-N>]])
 | |
|       feed([[AX<C-\><C-N>]])
 | |
|       feed([[...]])
 | |
|       feed([[uu]])
 | |
|       feed([[osome text 4<C-\><C-N>]])
 | |
|       feed([[u<C-R>u]])
 | |
|       feed([[osome text 5<C-\><C-N>]])
 | |
|       expect([[
 | |
|         some text 1
 | |
|         some text 3XX
 | |
|         some text 5]])
 | |
|       local expected_undotree = eval("undotree()")
 | |
|       eq(5, #expected_undotree["entries"])  -- sanity
 | |
| 
 | |
|       -- Start typing an incomplete :substitute command.
 | |
|       feed([[:%s/e/YYYY/g]])
 | |
|       poke_eventloop()
 | |
|       -- Cancel the :substitute.
 | |
|       feed([[<C-\><C-N>]])
 | |
| 
 | |
|       -- The undo tree should be unchanged.
 | |
|       eq(expected_undotree, eval("undotree()"))
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   for _, case in pairs{"", "split", "nosplit"} do
 | |
|     it("b:changedtick (inccommand="..case..")", function()
 | |
|       feed_command("set inccommand=" .. case)
 | |
|       feed([[isome text 1<C-\><C-N>]])
 | |
|       feed([[osome text 2<C-\><C-N>]])
 | |
|       local expected_tick = eval("b:changedtick")
 | |
|       ok(expected_tick > 0)
 | |
| 
 | |
|       expect([[
 | |
|         some text 1
 | |
|         some text 2]])
 | |
|       feed(":%s/e/XXX/")
 | |
|       poke_eventloop()
 | |
| 
 | |
|       eq(expected_tick, eval("b:changedtick"))
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   for _, case in ipairs({'', 'split', 'nosplit'}) do
 | |
|     it('previous substitute string ~ (inccommand='..case..') #12109', function()
 | |
|       local screen = Screen.new(30,10)
 | |
|       common_setup(screen, case, default_text)
 | |
| 
 | |
|       feed(':%s/Inc/SUB<CR>')
 | |
|       expect([[
 | |
|         SUB substitution on
 | |
|         two lines
 | |
|         ]])
 | |
| 
 | |
|       feed(':%s/line/')
 | |
|       poke_eventloop()
 | |
|       feed('~')
 | |
|       poke_eventloop()
 | |
|       feed('<CR>')
 | |
|       expect([[
 | |
|         SUB substitution on
 | |
|         two SUBs
 | |
|         ]])
 | |
| 
 | |
|       feed(':%s/sti/')
 | |
|       poke_eventloop()
 | |
|       feed('~')
 | |
|       poke_eventloop()
 | |
|       feed('B')
 | |
|       poke_eventloop()
 | |
|       feed('<CR>')
 | |
|       expect([[
 | |
|         SUB subSUBBtution on
 | |
|         two SUBs
 | |
|         ]])
 | |
| 
 | |
|       feed(':%s/ion/NEW<CR>')
 | |
|       expect([[
 | |
|         SUB subSUBBtutNEW on
 | |
|         two SUBs
 | |
|         ]])
 | |
| 
 | |
|       feed(':%s/two/')
 | |
|       poke_eventloop()
 | |
|       feed('N')
 | |
|       poke_eventloop()
 | |
|       feed('~')
 | |
|       poke_eventloop()
 | |
|       feed('<CR>')
 | |
|       expect([[
 | |
|         SUB subSUBBtutNEW on
 | |
|         NNEW SUBs
 | |
|         ]])
 | |
| 
 | |
|       feed(':%s/bS/')
 | |
|       poke_eventloop()
 | |
|       feed('~')
 | |
|       poke_eventloop()
 | |
|       feed('W')
 | |
|       poke_eventloop()
 | |
|       feed('<CR>')
 | |
|       expect([[
 | |
|         SUB suNNEWWUBBtutNEW on
 | |
|         NNEW SUBs
 | |
|         ]])
 | |
|     end)
 | |
|   end
 | |
| end)
 | |
| 
 | |
| describe(":substitute, 'inccommand' preserves undo", function()
 | |
|   local cases = { "", "split", "nosplit" }
 | |
| 
 | |
|   local substrings = {
 | |
|     ":%s/1",
 | |
|     ":%s/1/",
 | |
|     ":%s/1/<bs>",
 | |
|     ":%s/1/a",
 | |
|     ":%s/1/a<bs>",
 | |
|     ":%s/1/ax",
 | |
|     ":%s/1/ax<bs>",
 | |
|     ":%s/1/ax<bs><bs>",
 | |
|     ":%s/1/ax<bs><bs><bs>",
 | |
|     ":%s/1/ax/",
 | |
|     ":%s/1/ax/<bs>",
 | |
|     ":%s/1/ax/<bs>/",
 | |
|     ":%s/1/ax/g",
 | |
|     ":%s/1/ax/g<bs>",
 | |
|     ":%s/1/ax/g<bs><bs>"
 | |
|   }
 | |
| 
 | |
|   local function test_sub(substring, split, redoable)
 | |
|     command('bwipe!')
 | |
|     feed_command("set inccommand=" .. split)
 | |
| 
 | |
|     insert("1")
 | |
|     feed("o2<esc>")
 | |
|     feed_command("undo")
 | |
|     feed("o3<esc>")
 | |
|     if redoable then
 | |
|       feed("o4<esc>")
 | |
|       feed_command("undo")
 | |
|     end
 | |
|     feed(substring.. "<enter>")
 | |
|     feed_command("undo")
 | |
| 
 | |
|     feed("g-")
 | |
|     expect([[
 | |
|       1
 | |
|       2]])
 | |
| 
 | |
|     feed("g+")
 | |
|     expect([[
 | |
|       1
 | |
|       3]])
 | |
|   end
 | |
| 
 | |
|   local function test_notsub(substring, split, redoable)
 | |
|     command('bwipe!')
 | |
|     feed_command("set inccommand=" .. split)
 | |
| 
 | |
|     insert("1")
 | |
|     feed("o2<esc>")
 | |
|     feed_command("undo")
 | |
|     feed("o3<esc>")
 | |
|     if redoable then
 | |
|       feed("o4<esc>")
 | |
|       feed_command("undo")
 | |
|     end
 | |
|     feed(substring .. "<esc>")
 | |
| 
 | |
|     feed("g-")
 | |
|     expect([[
 | |
|       1
 | |
|       2]])
 | |
| 
 | |
|     feed("g+")
 | |
|     expect([[
 | |
|       1
 | |
|       3]])
 | |
| 
 | |
|     if redoable then
 | |
|       feed("<c-r>")
 | |
|       expect([[
 | |
|         1
 | |
|         3
 | |
|         4]])
 | |
|     end
 | |
|   end
 | |
| 
 | |
| 
 | |
|   local function test_threetree(substring, split)
 | |
|     command('bwipe!')
 | |
|     feed_command("set inccommand=" .. split)
 | |
| 
 | |
|     insert("1")
 | |
|     feed("o2<esc>")
 | |
|     feed("o3<esc>")
 | |
|     feed("uu")
 | |
|     feed("oa<esc>")
 | |
|     feed("ob<esc>")
 | |
|     feed("uu")
 | |
|     feed("oA<esc>")
 | |
|     feed("oB<esc>")
 | |
| 
 | |
|     -- This is the undo tree (x-Axis is timeline), we're at B now
 | |
|     --    ----------------A - B
 | |
|     --   /
 | |
|     --  | --------a - b
 | |
|     --  |/
 | |
|     --  1 - 2 - 3
 | |
| 
 | |
|     feed("2u")
 | |
|     feed(substring .. "<esc>")
 | |
|     expect([[
 | |
|       1]])
 | |
|     feed("g-")
 | |
|     expect([[
 | |
|       ]])
 | |
|     feed("g+")
 | |
|     expect([[
 | |
|       1]])
 | |
|     feed("<c-r>")
 | |
|     expect([[
 | |
|       1
 | |
|       A]])
 | |
| 
 | |
|     feed("g-") -- go to b
 | |
|     feed("2u")
 | |
|     feed(substring .. "<esc>")
 | |
|     feed("<c-r>")
 | |
|     expect([[
 | |
|       1
 | |
|       a]])
 | |
| 
 | |
|     feed("g-") -- go to 3
 | |
|     feed("2u")
 | |
|     feed(substring .. "<esc>")
 | |
|     feed("<c-r>")
 | |
|     expect([[
 | |
|       1
 | |
|       2]])
 | |
|   end
 | |
| 
 | |
|   before_each(clear)
 | |
| 
 | |
|   it("at a non-leaf of the undo tree", function()
 | |
|    for _, case in pairs(cases) do
 | |
|      for _, str in pairs(substrings) do
 | |
|        for _, redoable in pairs({true}) do
 | |
|          test_sub(str, case, redoable)
 | |
|        end
 | |
|      end
 | |
|    end
 | |
|   end)
 | |
| 
 | |
|   it("at a leaf of the undo tree", function()
 | |
|     for _, case in pairs(cases) do
 | |
|       for _, str in pairs(substrings) do
 | |
|         for _, redoable in pairs({false}) do
 | |
|           test_sub(str, case, redoable)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it("when interrupting substitution", function()
 | |
|     for _, case in pairs(cases) do
 | |
|       for _, str in pairs(substrings) do
 | |
|         for _, redoable in pairs({true,false}) do
 | |
|           test_notsub(str, case, redoable)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it("in a complex undo scenario", function()
 | |
|     for _, case in pairs(cases) do
 | |
|       for _, str in pairs(substrings) do
 | |
|         test_threetree(str, case)
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('with undolevels=0', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       clear()
 | |
|       common_setup(nil, case, default_text)
 | |
|       feed_command("set undolevels=0")
 | |
| 
 | |
|       feed("1G0")
 | |
|       insert("X")
 | |
|       feed(":%s/tw/MO/<esc>")
 | |
|       feed_command("undo")
 | |
|       expect(default_text)
 | |
|       feed_command("undo")
 | |
|       expect(default_text:gsub("Inc", "XInc"))
 | |
|       feed_command("undo")
 | |
| 
 | |
|       feed_command("%s/tw/MO/g")
 | |
|       expect(default_text:gsub("tw", "MO"))
 | |
|       feed_command("undo")
 | |
|       expect(default_text)
 | |
|       feed_command("undo")
 | |
|       expect(default_text:gsub("tw", "MO"))
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('with undolevels=1', function()
 | |
|     local screen = Screen.new(20,10)
 | |
| 
 | |
|     for _, case in pairs(cases) do
 | |
|       clear()
 | |
|       common_setup(screen, case, default_text)
 | |
|       screen:expect([[
 | |
|         Inc substitution on |
 | |
|         two lines           |
 | |
|         ^                    |
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|                             |
 | |
|       ]])
 | |
|       feed_command("set undolevels=1")
 | |
| 
 | |
|       feed("1G0")
 | |
|       insert("X")
 | |
|       feed("IY<esc>")
 | |
|       feed(":%s/tw/MO/<esc>")
 | |
|       -- feed_command("undo") here would cause "Press ENTER".
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("Inc", "XInc"))
 | |
|       feed("u")
 | |
|       expect(default_text)
 | |
| 
 | |
|       feed(":%s/tw/MO/g<enter>")
 | |
|       feed(":%s/MO/GO/g<enter>")
 | |
|       feed(":%s/GO/NO/g<enter>")
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("tw", "GO"))
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("tw", "MO"))
 | |
|       feed("u")
 | |
| 
 | |
|       if case == "split" then
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           ^MOo lines           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       else
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           ^MOo lines           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('with undolevels=2', function()
 | |
|     local screen = Screen.new(20,10)
 | |
| 
 | |
|     for _, case in pairs(cases) do
 | |
|       clear()
 | |
|       common_setup(screen, case, default_text)
 | |
|       feed_command("set undolevels=2")
 | |
| 
 | |
|       feed("2GAx<esc>")
 | |
|       feed("Ay<esc>")
 | |
|       feed("Az<esc>")
 | |
|       feed(":%s/tw/AR<esc>")
 | |
|       -- feed_command("undo") here would cause "Press ENTER".
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("lines", "linesxy"))
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("lines", "linesx"))
 | |
|       feed("u")
 | |
|       expect(default_text)
 | |
|       feed("u")
 | |
| 
 | |
|       if case == "split" then
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           two line^s           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       else
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           two line^s           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       end
 | |
| 
 | |
|       feed(":%s/tw/MO/g<enter>")
 | |
|       feed(":%s/MO/GO/g<enter>")
 | |
|       feed(":%s/GO/NO/g<enter>")
 | |
|       feed(":%s/NO/LO/g<enter>")
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("tw", "NO"))
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("tw", "GO"))
 | |
|       feed("u")
 | |
|       expect(default_text:gsub("tw", "MO"))
 | |
|       feed("u")
 | |
| 
 | |
|       if case == "split" then
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           ^MOo lines           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       else
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           ^MOo lines           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('with undolevels=-1', function()
 | |
|     local screen = Screen.new(20,10)
 | |
| 
 | |
|     for _, case in pairs(cases) do
 | |
|       clear()
 | |
|       common_setup(screen, case, default_text)
 | |
| 
 | |
|       feed_command("set undolevels=-1")
 | |
|       feed(":%s/tw/MO/g<enter>")
 | |
|       -- feed_command("undo") here will result in a "Press ENTER" prompt
 | |
|       feed("u")
 | |
|       if case == "split" then
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           ^MOo lines           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       else
 | |
|         screen:expect([[
 | |
|           Inc substitution on |
 | |
|           ^MOo lines           |
 | |
|                               |
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           {15:~                   }|
 | |
|           Already ...t change |
 | |
|         ]])
 | |
|       end
 | |
| 
 | |
|       -- repeat with an interrupted substitution
 | |
|       clear()
 | |
|       common_setup(screen, case, default_text)
 | |
| 
 | |
|       feed_command("set undolevels=-1")
 | |
|       feed("1G")
 | |
|       feed("IL<esc>")
 | |
|       feed(":%s/tw/MO/g<esc>")
 | |
|       feed("u")
 | |
| 
 | |
|       screen:expect([[
 | |
|         ^LInc substitution on|
 | |
|         two lines           |
 | |
|                             |
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         Already ...t change |
 | |
|       ]])
 | |
|     end
 | |
|   end)
 | |
| 
 | |
| end)
 | |
| 
 | |
| describe(":substitute, inccommand=split", function()
 | |
|   local screen = Screen.new(30,15)
 | |
| 
 | |
|   before_each(function()
 | |
|     clear()
 | |
|     common_setup(screen, "split", default_text .. default_text)
 | |
|   end)
 | |
| 
 | |
|   it("preserves 'modified' buffer flag", function()
 | |
|     feed_command("set nomodified")
 | |
|     feed(":%s/tw")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:tw}o lines                     |
 | |
|       Inc substitution on           |
 | |
|       {12:tw}o lines                     |
 | |
|                                     |
 | |
|       {11:[No Name]                     }|
 | |
|       |2| {12:tw}o lines                 |
 | |
|       |4| {12:tw}o lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw^                        |
 | |
|     ]])
 | |
|     feed([[<C-\><C-N>]])  -- Cancel the :substitute command.
 | |
|     eq(0, eval("&modified"))
 | |
|   end)
 | |
| 
 | |
|   it("shows preview when cmd modifiers are present", function()
 | |
|     -- one modifier
 | |
|     feed(':keeppatterns %s/tw/to')
 | |
|     screen:expect{any=[[{12:to}o lines]]}
 | |
|     feed('<Esc>')
 | |
|     screen:expect{any=[[two lines]]}
 | |
| 
 | |
|     -- multiple modifiers
 | |
|     feed(':keeppatterns silent %s/tw/to')
 | |
|     screen:expect{any=[[{12:to}o lines]]}
 | |
|     feed('<Esc>')
 | |
|     screen:expect{any=[[two lines]]}
 | |
| 
 | |
|     -- non-modifier prefix
 | |
|     feed(':silent tabedit %s/tw/to')
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :silent tabedit %s/tw/to^      |
 | |
|     ]])
 | |
|     feed('<Esc>')
 | |
| 
 | |
|     -- leading colons
 | |
|     feed(':::%s/tw/to')
 | |
|     screen:expect{any=[[{12:to}o lines]]}
 | |
|     feed('<Esc>')
 | |
|     screen:expect{any=[[two lines]]}
 | |
|   end)
 | |
| 
 | |
|   it("ignores new-window modifiers when splitting the preview window", function()
 | |
|     -- one modifier
 | |
|     feed(':topleft %s/tw/to')
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:to}o lines                     |
 | |
|       Inc substitution on           |
 | |
|       {12:to}o lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| {12:to}o lines                 |
 | |
|       |4| {12:to}o lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :topleft %s/tw/to^             |
 | |
|     ]])
 | |
|     feed('<Esc>')
 | |
|     screen:expect{any=[[two lines]]}
 | |
| 
 | |
|     -- multiple modifiers
 | |
|     feed(':topleft vert %s/tw/to')
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:to}o lines                     |
 | |
|       Inc substitution on           |
 | |
|       {12:to}o lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| {12:to}o lines                 |
 | |
|       |4| {12:to}o lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :topleft vert %s/tw/to^        |
 | |
|     ]])
 | |
|     feed('<Esc>')
 | |
|     screen:expect{any=[[two lines]]}
 | |
|   end)
 | |
| 
 | |
|   it('shows split window when typing the pattern', function()
 | |
|     feed(":%s/tw")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:tw}o lines                     |
 | |
|       Inc substitution on           |
 | |
|       {12:tw}o lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| {12:tw}o lines                 |
 | |
|       |4| {12:tw}o lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw^                        |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('shows preview with empty replacement', function()
 | |
|     feed(":%s/tw/")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       o lines                       |
 | |
|       Inc substitution on           |
 | |
|       o lines                       |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| o lines                   |
 | |
|       |4| o lines                   |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw/^                       |
 | |
|     ]])
 | |
| 
 | |
|     feed("x")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:x}o lines                      |
 | |
|       Inc substitution on           |
 | |
|       {12:x}o lines                      |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| {12:x}o lines                  |
 | |
|       |4| {12:x}o lines                  |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw/x^                      |
 | |
|     ]])
 | |
| 
 | |
|     feed("<bs>")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       o lines                       |
 | |
|       Inc substitution on           |
 | |
|       o lines                       |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| o lines                   |
 | |
|       |4| o lines                   |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw/^                       |
 | |
|     ]])
 | |
| 
 | |
|   end)
 | |
| 
 | |
|   it('shows split window when typing replacement', function()
 | |
|     feed(":%s/tw/XX")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:XX}o lines                     |
 | |
|       Inc substitution on           |
 | |
|       {12:XX}o lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| {12:XX}o lines                 |
 | |
|       |4| {12:XX}o lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw/XX^                     |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('does not show split window for :s/', function()
 | |
|     feed("2gg")
 | |
|     feed(":s/tw")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:tw}o lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :s/tw^                         |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("'hlsearch' is active, 'cursorline' is not", function()
 | |
|     feed_command("set hlsearch cursorline")
 | |
|     feed("gg")
 | |
| 
 | |
|     -- Assert that 'cursorline' is active.
 | |
|     screen:expect([[
 | |
|       {16:^Inc substitution on           }|
 | |
|       two lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :set hlsearch cursorline      |
 | |
|     ]])
 | |
| 
 | |
|     feed(":%s/tw")
 | |
|     -- 'cursorline' is NOT active during preview.
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       {12:tw}o lines                     |
 | |
|       Inc substitution on           |
 | |
|       {12:tw}o lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| {12:tw}o lines                 |
 | |
|       |4| {12:tw}o lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw^                        |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('highlights the replacement text', function()
 | |
|     feed('ggO')
 | |
|     feed('M     M       M<esc>')
 | |
|     feed(':%s/M/123/g')
 | |
|     screen:expect([[
 | |
|       {12:123}     {12:123}       {12:123}         |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| {12:123}     {12:123}       {12:123}     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/M/123/g^                   |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("highlights nothing when there's no match", function()
 | |
|     feed('gg')
 | |
|     feed(':%s/Inx')
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/Inx^                       |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('previews correctly when previewhight is small', function()
 | |
|     feed_command('set cwh=3')
 | |
|     feed_command('set hls')
 | |
|     feed('ggdG')
 | |
|     insert(string.rep('abc abc abc\n', 20))
 | |
|     feed(':%s/abc/MMM/g')
 | |
|     screen:expect([[
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {12:MMM} {12:MMM} {12:MMM}                   |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 1| {12:MMM} {12:MMM} {12:MMM}              |
 | |
|       | 2| {12:MMM} {12:MMM} {12:MMM}              |
 | |
|       | 3| {12:MMM} {12:MMM} {12:MMM}              |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/abc/MMM/g^                 |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('actually replaces text', function()
 | |
|     feed(":%s/tw/XX/g<Enter>")
 | |
| 
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       XXo lines                     |
 | |
|       Inc substitution on           |
 | |
|       ^XXo lines                     |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/tw/XX/g                   |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('shows correct line numbers with many lines', function()
 | |
|     feed("gg")
 | |
|     feed("2yy")
 | |
|     feed("2000p")
 | |
|     feed_command("1,1000s/tw/BB/g")
 | |
| 
 | |
|     feed(":%s/tw/X")
 | |
|     screen:expect([[
 | |
|       BBo lines                     |
 | |
|       Inc substitution on           |
 | |
|       {12:X}o lines                      |
 | |
|       Inc substitution on           |
 | |
|       {12:X}o lines                      |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1001| {12:X}o lines               |
 | |
|       |1003| {12:X}o lines               |
 | |
|       |1005| {12:X}o lines               |
 | |
|       |1007| {12:X}o lines               |
 | |
|       |1009| {12:X}o lines               |
 | |
|       |1011| {12:X}o lines               |
 | |
|       |1013| {12:X}o lines               |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/tw/X^                      |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('does not spam the buffer numbers', function()
 | |
|     -- The preview buffer is re-used (unless user deleted it), so buffer numbers
 | |
|     -- will not increase on each keystroke.
 | |
|     feed(":%s/tw/Xo/g")
 | |
|     -- Delete and re-type the g a few times.
 | |
|     feed("<BS>")
 | |
|     poke_eventloop()
 | |
|     feed("g")
 | |
|     poke_eventloop()
 | |
|     feed("<BS>")
 | |
|     poke_eventloop()
 | |
|     feed("g")
 | |
|     poke_eventloop()
 | |
|     feed("<CR>")
 | |
|     poke_eventloop()
 | |
|     feed(":vs tmp<enter>")
 | |
|     eq(3, helpers.call('bufnr', '$'))
 | |
|   end)
 | |
| 
 | |
|   it('works with the n flag', function()
 | |
|     feed(":%s/tw/Mix/n<Enter>")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       ^                              |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       2 matches on 2 lines          |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("deactivates if 'redrawtime' is exceeded #5602", function()
 | |
|     -- prevent redraws from 'incsearch'
 | |
|     meths.set_option('incsearch', false)
 | |
|     -- Assert that 'inccommand' is ENABLED initially.
 | |
|     eq("split", eval("&inccommand"))
 | |
|     -- Set 'redrawtime' to minimal value, to ensure timeout is triggered.
 | |
|     feed_command("set redrawtime=1 nowrap")
 | |
|     -- Load a big file.
 | |
|     feed_command("silent edit! test/functional/fixtures/bigfile_oneline.txt")
 | |
|     -- Start :substitute with a slow pattern.
 | |
|     feed([[:%s/B.*N/x]])
 | |
|     poke_eventloop()
 | |
| 
 | |
|     -- Assert that 'inccommand' is DISABLED in cmdline mode.
 | |
|     eq("", eval("&inccommand"))
 | |
|     -- Assert that preview cleared (or never manifested).
 | |
|     screen:expect([[
 | |
|       0000;<control>;Cc;0;BN;;;;;N;N|
 | |
|       2F923;CJK COMPATIBILITY IDEOGR|
 | |
|       2F924;CJK COMPATIBILITY IDEOGR|
 | |
|       2F925;CJK COMPATIBILITY IDEOGR|
 | |
|       2F926;CJK COMPATIBILITY IDEOGR|
 | |
|       2F927;CJK COMPATIBILITY IDEOGR|
 | |
|       2F928;CJK COMPATIBILITY IDEOGR|
 | |
|       2F929;CJK COMPATIBILITY IDEOGR|
 | |
|       2F92A;CJK COMPATIBILITY IDEOGR|
 | |
|       2F92B;CJK COMPATIBILITY IDEOGR|
 | |
|       2F92C;CJK COMPATIBILITY IDEOGR|
 | |
|       2F92D;CJK COMPATIBILITY IDEOGR|
 | |
|       2F92E;CJK COMPATIBILITY IDEOGR|
 | |
|       2F92F;CJK COMPATIBILITY IDEOGR|
 | |
|       :%s/B.*N/x^                    |
 | |
|     ]])
 | |
| 
 | |
|     -- Assert that 'inccommand' is again ENABLED after leaving cmdline mode.
 | |
|     feed([[<C-\><C-N>]])
 | |
|     eq("split", eval("&inccommand"))
 | |
|   end)
 | |
| 
 | |
|   it("deactivates if 'foldexpr' is slow #9557", function()
 | |
|     insert([[
 | |
|       a
 | |
|       a
 | |
|       a
 | |
|       a
 | |
|       a
 | |
|       a
 | |
|       a
 | |
|       a
 | |
|     ]])
 | |
|     source([[
 | |
|       function! Slowfold(lnum)
 | |
|         sleep 5m
 | |
|         return a:lnum % 3
 | |
|       endfun
 | |
|     ]])
 | |
|     command('set redrawtime=1 inccommand=split')
 | |
|     command('set foldmethod=expr foldexpr=Slowfold(v:lnum)')
 | |
|     feed(':%s/a/bcdef')
 | |
| 
 | |
|     -- Assert that 'inccommand' is DISABLED in cmdline mode.
 | |
|     retry(nil, nil, function()
 | |
|       eq('', eval('&inccommand'))
 | |
|     end)
 | |
| 
 | |
|     -- Assert that 'inccommand' is again ENABLED after leaving cmdline mode.
 | |
|     feed([[<C-\><C-N>]])
 | |
|     retry(nil, nil, function()
 | |
|       eq('split', eval('&inccommand'))
 | |
|     end)
 | |
|   end)
 | |
| 
 | |
|   it("clears preview if non-previewable command is edited #5585", function()
 | |
|     feed('gg')
 | |
|     -- Put a non-previewable command in history.
 | |
|     feed_command("echo 'foo'")
 | |
|     -- Start an incomplete :substitute command.
 | |
|     feed(":1,2s/t/X")
 | |
| 
 | |
|     screen:expect([[
 | |
|       Inc subs{12:X}itution on           |
 | |
|       {12:X}wo lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| Inc subs{12:X}itution on       |
 | |
|       |2| {12:X}wo lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :1,2s/t/X^                     |
 | |
|     ]])
 | |
| 
 | |
|     -- Select the previous command.
 | |
|     feed("<C-P>")
 | |
|     -- Assert that preview was cleared.
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :echo 'foo'^                   |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it([[preview changes correctly with c_CTRL-R_= and c_CTRL-\_e]], function()
 | |
|     feed('gg')
 | |
|     feed(":1,2s/t/X")
 | |
|     screen:expect([[
 | |
|       Inc subs{12:X}itution on           |
 | |
|       {12:X}wo lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| Inc subs{12:X}itution on       |
 | |
|       |2| {12:X}wo lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :1,2s/t/X^                     |
 | |
|     ]])
 | |
| 
 | |
|     feed([[<C-R>='Y']])
 | |
|     -- preview should be unchanged during c_CTRL-R_= editing
 | |
|     screen:expect([[
 | |
|       Inc subs{12:X}itution on           |
 | |
|       {12:X}wo lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| Inc subs{12:X}itution on       |
 | |
|       |2| {12:X}wo lines                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       ={1:'Y'}^                          |
 | |
|     ]])
 | |
| 
 | |
|     feed('<CR>')
 | |
|     -- preview should be changed by the result of the expression
 | |
|     screen:expect([[
 | |
|       Inc subs{12:XY}itution on          |
 | |
|       {12:XY}wo lines                    |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| Inc subs{12:XY}itution on      |
 | |
|       |2| {12:XY}wo lines                |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :1,2s/t/XY^                    |
 | |
|     ]])
 | |
| 
 | |
|     feed([[<C-\>e'echo']])
 | |
|     -- preview should be unchanged during c_CTRL-\_e editing
 | |
|     screen:expect([[
 | |
|       Inc subs{12:XY}itution on          |
 | |
|       {12:XY}wo lines                    |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| Inc subs{12:XY}itution on      |
 | |
|       |2| {12:XY}wo lines                |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       ={1:'echo'}^                       |
 | |
|     ]])
 | |
| 
 | |
|     feed('<CR>')
 | |
|     -- preview should be cleared if command is changed to a non-previewable one
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :echo^                         |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
| end)
 | |
| 
 | |
| describe("inccommand=nosplit", function()
 | |
|   local screen = Screen.new(20,10)
 | |
| 
 | |
|   before_each(function()
 | |
|     clear()
 | |
|     common_setup(screen, "nosplit", default_text .. default_text)
 | |
|   end)
 | |
| 
 | |
|   it("works with :smagic, :snomagic", function()
 | |
|     feed_command("set hlsearch")
 | |
|     insert("Line *.3.* here")
 | |
| 
 | |
|     feed(":%smagic/3.*/X")    -- start :smagic command
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|       Line *.{12:X}            |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%smagic/3.*/X^      |
 | |
|     ]])
 | |
| 
 | |
|     feed([[<C-\><C-N>]])      -- cancel
 | |
|     feed(":%snomagic/3.*/X")  -- start :snomagic command
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|       Line *.{12:X} here       |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%snomagic/3.*/X^    |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("shows preview when cmd modifiers are present", function()
 | |
|     -- one modifier
 | |
|     feed(':keeppatterns %s/tw/to')
 | |
|     screen:expect{any=[[{12:to}o lines]]}
 | |
|     feed('<Esc>')
 | |
|     screen:expect{any=[[two lines]]}
 | |
| 
 | |
|     -- multiple modifiers
 | |
|     feed(':keeppatterns silent %s/tw/to')
 | |
|     screen:expect{any=[[{12:to}o lines]]}
 | |
|     feed('<Esc>')
 | |
|     screen:expect{any=[[two lines]]}
 | |
| 
 | |
|     -- non-modifier prefix
 | |
|     feed(':silent tabedit %s/tw/to')
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {11:                    }|
 | |
|       :silent tabedit %s/t|
 | |
|       w/to^                |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("does not show window after toggling :set inccommand", function()
 | |
|     feed(":%s/tw/OKOK")
 | |
|     feed("<Esc>")
 | |
|     command("set icm=split")
 | |
|     feed(":%s/tw/OKOK")
 | |
|     feed("<Esc>")
 | |
|     command("set icm=nosplit")
 | |
|     feed(":%s/tw/OKOK")
 | |
|     poke_eventloop()
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       {12:OKOK}o lines         |
 | |
|       Inc substitution on |
 | |
|       {12:OKOK}o lines         |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%s/tw/OKOK^         |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it('never shows preview buffer', function()
 | |
|     feed_command("set hlsearch")
 | |
| 
 | |
|     feed(":%s/tw")
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       {12:tw}o lines           |
 | |
|       Inc substitution on |
 | |
|       {12:tw}o lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%s/tw^              |
 | |
|     ]])
 | |
| 
 | |
|     feed("/BM")
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       {12:BM}o lines           |
 | |
|       Inc substitution on |
 | |
|       {12:BM}o lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%s/tw/BM^           |
 | |
|     ]])
 | |
| 
 | |
|     feed("/")
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       {12:BM}o lines           |
 | |
|       Inc substitution on |
 | |
|       {12:BM}o lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%s/tw/BM/^          |
 | |
|     ]])
 | |
| 
 | |
|     feed("<enter>")
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       BMo lines           |
 | |
|       Inc substitution on |
 | |
|       ^BMo lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%s/tw/BM/          |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("clears preview if non-previewable command is edited", function()
 | |
|     -- Put a non-previewable command in history.
 | |
|     feed_command("echo 'foo'")
 | |
|     -- Start an incomplete :substitute command.
 | |
|     feed(":1,2s/t/X")
 | |
| 
 | |
|     screen:expect([[
 | |
|       Inc subs{12:X}itution on |
 | |
|       {12:X}wo lines           |
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :1,2s/t/X^           |
 | |
|     ]])
 | |
| 
 | |
|     -- Select the previous command.
 | |
|     feed("<C-P>")
 | |
|     -- Assert that preview was cleared.
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :echo 'foo'^         |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("does not execute trailing bar-separated commands #7494", function()
 | |
|     feed(':%s/two/three/g|q!')
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       {12:three} lines         |
 | |
|       Inc substitution on |
 | |
|       {12:three} lines         |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%s/two/three/g|q!^  |
 | |
|     ]])
 | |
|     eq(eval('v:null'), eval('v:exiting'))
 | |
|   end)
 | |
| 
 | |
|   it("does not break bar-separated command #8796", function()
 | |
|     source([[
 | |
|       function! F()
 | |
|         if v:false | return | endif
 | |
|       endfun
 | |
|     ]])
 | |
|     command('call timer_start(10, {-> F()}, {"repeat":-1})')
 | |
|     feed(':%s/')
 | |
|     sleep(20)  -- Allow some timer activity.
 | |
|     screen:expect([[
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|       Inc substitution on |
 | |
|       two lines           |
 | |
|                           |
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       {15:~                   }|
 | |
|       :%s/^                |
 | |
|     ]])
 | |
|   end)
 | |
| end)
 | |
| 
 | |
| describe(":substitute, 'inccommand' with a failing expression", function()
 | |
|   local screen = Screen.new(20,10)
 | |
|   local cases = { "", "split", "nosplit" }
 | |
| 
 | |
|   local function refresh(case)
 | |
|     clear()
 | |
|     common_setup(screen, case, default_text)
 | |
|   end
 | |
| 
 | |
|   it('in the pattern does nothing', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       feed_command("set inccommand=" .. case)
 | |
|       feed(":silent! %s/tw\\(/LARD/<enter>")
 | |
|       expect(default_text)
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('in the replacement deletes the matches', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       local replacements = { "\\='LARD", "\\=xx_novar__xx" }
 | |
| 
 | |
|       for _, repl in pairs(replacements) do
 | |
|         feed_command("set inccommand=" .. case)
 | |
|         feed(":silent! %s/tw/" .. repl .. "/<enter>")
 | |
|         expect(default_text:gsub("tw", ""))
 | |
|         feed_command("undo")
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('in the range does not error #5912', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       feed(':100s/')
 | |
| 
 | |
|       screen:expect([[
 | |
|         Inc substitution on |
 | |
|         two lines           |
 | |
|                             |
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         :100s/^              |
 | |
|       ]])
 | |
| 
 | |
|       feed('<enter>')
 | |
|       screen:expect([[
 | |
|         Inc substitution on |
 | |
|         two lines           |
 | |
|         ^                    |
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {15:~                   }|
 | |
|         {14:E16: Invalid range}  |
 | |
|       ]])
 | |
|     end
 | |
|   end)
 | |
| 
 | |
| end)
 | |
| 
 | |
| describe("'inccommand' and :cnoremap", function()
 | |
|   local cases = { "",  "split", "nosplit" }
 | |
|   local screen
 | |
| 
 | |
|   local function refresh(case, visual)
 | |
|     clear()
 | |
|     screen = visual and Screen.new(50,10) or nil
 | |
|     common_setup(screen, case, default_text)
 | |
|   end
 | |
| 
 | |
|   it('work with remapped characters', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       local cmd = "%s/lines/LINES/g"
 | |
| 
 | |
|       for i = 1, string.len(cmd) do
 | |
|         local c = string.sub(cmd, i, i)
 | |
|         feed_command("cnoremap ".. c .. " " .. c)
 | |
|       end
 | |
| 
 | |
|       feed_command(cmd)
 | |
|       expect([[
 | |
|         Inc substitution on
 | |
|         two LINES
 | |
|         ]])
 | |
|       end
 | |
|   end)
 | |
| 
 | |
|   it('work when mappings move the cursor', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       feed_command("cnoremap ,S LINES/<left><left><left><left><left><left>")
 | |
| 
 | |
|       feed(":%s/lines/,Sor three <enter>")
 | |
|       expect([[
 | |
|         Inc substitution on
 | |
|         two or three LINES
 | |
|         ]])
 | |
| 
 | |
|       feed_command("cnoremap ;S /X/<left><left><left>")
 | |
|       feed(":%s/;SI<enter>")
 | |
|       expect([[
 | |
|         Xnc substitution on
 | |
|         two or three LXNES
 | |
|         ]])
 | |
| 
 | |
|       feed_command("cnoremap ,T //Y/<left><left><left>")
 | |
|       feed(":%s,TX<enter>")
 | |
|       expect([[
 | |
|         Ync substitution on
 | |
|         two or three LYNES
 | |
|         ]])
 | |
| 
 | |
|       feed_command("cnoremap ;T s//Z/<left><left><left>")
 | |
|       feed(":%;TY<enter>")
 | |
|       expect([[
 | |
|         Znc substitution on
 | |
|         two or three LZNES
 | |
|         ]])
 | |
|       end
 | |
|   end)
 | |
| 
 | |
|   it('still works with a broken mapping', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case, true)
 | |
|       feed_command("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
 | |
| 
 | |
|       feed(":%s/tw/tox<enter>")
 | |
|       screen:expect{any=[[{14:^E565:]]}
 | |
|       feed('<c-c>')
 | |
| 
 | |
|       -- error thrown b/c of the mapping
 | |
|       neq(nil, eval('v:errmsg'):find('^E565:'))
 | |
|       expect([[
 | |
|       Inc substitution on
 | |
|       toxo lines
 | |
|       ]])
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('work when temporarily moving the cursor', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       feed_command("cnoremap <expr> x cursor(1, 1)[-1].'x'")
 | |
| 
 | |
|       feed(":%s/tw/tox/g<enter>")
 | |
|       expect(default_text:gsub("tw", "tox"))
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it("work when a mapping disables 'inccommand'", function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       feed_command("cnoremap <expr> x execute('set inccommand=')[-1]")
 | |
| 
 | |
|       feed(":%s/tw/toxa/g<enter>")
 | |
|       expect(default_text:gsub("tw", "toa"))
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it('work with a complex mapping', function()
 | |
|     for _, case in pairs(cases) do
 | |
|       refresh(case)
 | |
|       source([[cnoremap x <C-\>eextend(g:, {'fo': getcmdline()})
 | |
|       \.fo<CR><C-c>:new<CR>:bw!<CR>:<C-r>=remove(g:, 'fo')<CR>x]])
 | |
| 
 | |
|       feed(":%s/tw/tox")
 | |
|       feed("/<enter>")
 | |
|       expect(default_text:gsub("tw", "tox"))
 | |
|     end
 | |
|   end)
 | |
| 
 | |
| end)
 | |
| 
 | |
| describe("'inccommand' autocommands", function()
 | |
|   before_each(clear)
 | |
| 
 | |
|   -- keys are events to be tested
 | |
|   -- values are arrays like
 | |
|   --    { open = { 1 }, close = { 2, 3} }
 | |
|   -- which would mean that during the test below the event fires for
 | |
|   -- buffer 1 when opening the preview window, and for buffers 2 and 3
 | |
|   -- when closing the preview window
 | |
|   local eventsExpected = {
 | |
|     BufAdd = {},
 | |
|     BufDelete = {},
 | |
|     BufEnter = {},
 | |
|     BufFilePost = {},
 | |
|     BufFilePre = {},
 | |
|     BufHidden = {},
 | |
|     BufLeave = {},
 | |
|     BufNew = {},
 | |
|     BufNewFile = {},
 | |
|     BufRead = {},
 | |
|     BufReadCmd = {},
 | |
|     BufReadPre = {},
 | |
|     BufUnload = {},
 | |
|     BufWinEnter = {},
 | |
|     BufWinLeave = {},
 | |
|     BufWipeout = {},
 | |
|     BufWrite = {},
 | |
|     BufWriteCmd = {},
 | |
|     BufWritePost = {},
 | |
|     Syntax = {},
 | |
|     FileType = {},
 | |
|     WinEnter = {},
 | |
|     WinLeave = {},
 | |
|     CmdwinEnter = {},
 | |
|     CmdwinLeave = {},
 | |
|   }
 | |
| 
 | |
|   local function bufferlist(t)
 | |
|     local s = ""
 | |
|     for _, buffer in pairs(t) do
 | |
|       s = s .. ", " .. tostring(buffer)
 | |
|     end
 | |
|     return s
 | |
|   end
 | |
| 
 | |
|   -- fill the table with default values
 | |
|   for event, _ in pairs(eventsExpected) do
 | |
|     eventsExpected[event].open = eventsExpected[event].open or {}
 | |
|     eventsExpected[event].close = eventsExpected[event].close or {}
 | |
|   end
 | |
| 
 | |
|   local function register_autocmd(event)
 | |
|     meths.set_var(event .. "_fired", {})
 | |
|     feed_command("autocmd " .. event .. " * call add(g:" .. event .. "_fired, expand('<abuf>'))")
 | |
|   end
 | |
| 
 | |
|   it('are not fired when splitting', function()
 | |
|     common_setup(nil, "split", default_text)
 | |
| 
 | |
|     local eventsObserved = {}
 | |
|     for event, _ in pairs(eventsExpected) do
 | |
|       eventsObserved[event] = {}
 | |
|       register_autocmd(event)
 | |
|     end
 | |
| 
 | |
|     feed(":%s/tw")
 | |
| 
 | |
|     for event, _ in pairs(eventsExpected) do
 | |
|       eventsObserved[event].open = meths.get_var(event .. "_fired")
 | |
|       meths.set_var(event .. "_fired", {})
 | |
|     end
 | |
| 
 | |
|     feed("/<enter>")
 | |
| 
 | |
|     for event, _ in pairs(eventsExpected) do
 | |
|         eventsObserved[event].close = meths.get_var(event .. "_fired")
 | |
|     end
 | |
| 
 | |
|     for event, _ in pairs(eventsExpected) do
 | |
|       eq(event .. bufferlist(eventsExpected[event].open),
 | |
|          event .. bufferlist(eventsObserved[event].open))
 | |
|       eq(event .. bufferlist(eventsExpected[event].close),
 | |
|          event .. bufferlist(eventsObserved[event].close))
 | |
|     end
 | |
|   end)
 | |
| 
 | |
| end)
 | |
| 
 | |
| describe("'inccommand' split windows", function()
 | |
|   local screen
 | |
|   local function refresh()
 | |
|     clear()
 | |
|     screen = Screen.new(40,30)
 | |
|     common_setup(screen, "split", default_text)
 | |
|   end
 | |
| 
 | |
|   it('work after more splits', function()
 | |
|     refresh()
 | |
| 
 | |
|     feed("gg")
 | |
|     feed_command("vsplit")
 | |
|     feed_command("split")
 | |
|     feed(":%s/tw")
 | |
|     screen:expect([[
 | |
|       Inc substitution on │Inc substitution on|
 | |
|       {12:tw}o lines           │{12:tw}o lines          |
 | |
|                           │                   |
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {11:[No Name] [+]       }│{15:~                  }|
 | |
|       Inc substitution on │{15:~                  }|
 | |
|       {12:tw}o lines           │{15:~                  }|
 | |
|                           │{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {10:[No Name] [+]        [No Name] [+]      }|
 | |
|       |2| {12:tw}o lines                           |
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {10:[Preview]                               }|
 | |
|       :%s/tw^                                  |
 | |
|     ]])
 | |
| 
 | |
|     feed("<esc>")
 | |
|     feed_command("only")
 | |
|     feed_command("split")
 | |
|     feed_command("vsplit")
 | |
| 
 | |
|     feed(":%s/tw")
 | |
|     screen:expect([[
 | |
|       Inc substitution on │Inc substitution on|
 | |
|       {12:tw}o lines           │{12:tw}o lines          |
 | |
|                           │                   |
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {15:~                   }│{15:~                  }|
 | |
|       {11:[No Name] [+]        }{10:[No Name] [+]      }|
 | |
|       Inc substitution on                     |
 | |
|       {12:tw}o lines                               |
 | |
|                                               |
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {10:[No Name] [+]                           }|
 | |
|       |2| {12:tw}o lines                           |
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {15:~                                       }|
 | |
|       {10:[Preview]                               }|
 | |
|       :%s/tw^                                  |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   local settings = {
 | |
|   "splitbelow",
 | |
|   "splitright",
 | |
|   "noequalalways",
 | |
|   "equalalways eadirection=ver",
 | |
|   "equalalways eadirection=hor",
 | |
|   "equalalways eadirection=both",
 | |
|   }
 | |
| 
 | |
|   it("are not affected by various settings", function()
 | |
|     for _, setting in pairs(settings) do
 | |
|       refresh()
 | |
|       feed_command("set " .. setting)
 | |
| 
 | |
|       feed(":%s/tw")
 | |
| 
 | |
|       screen:expect([[
 | |
|         Inc substitution on                     |
 | |
|         {12:tw}o lines                               |
 | |
|                                                 |
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {11:[No Name] [+]                           }|
 | |
|         |2| {12:tw}o lines                           |
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {15:~                                       }|
 | |
|         {10:[Preview]                               }|
 | |
|         :%s/tw^                                  |
 | |
|       ]])
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   it("don't open if there's not enough room", function()
 | |
|     refresh()
 | |
|     screen:try_resize(40, 3)
 | |
|     feed("gg:%s/tw")
 | |
|     screen:expect([[
 | |
|       Inc substitution on                     |
 | |
|       {12:tw}o lines                               |
 | |
|       :%s/tw^                                  |
 | |
|     ]])
 | |
|   end)
 | |
| end)
 | |
| 
 | |
| describe("'inccommand' with 'gdefault'", function()
 | |
|   before_each(function()
 | |
|     clear()
 | |
|   end)
 | |
| 
 | |
|   it("does not lock up #7244", function()
 | |
|     common_setup(nil, "nosplit", "{")
 | |
|     command("set gdefault")
 | |
|     feed(":s/{\\n")
 | |
|     eq({mode='c', blocking=false}, nvim("get_mode"))
 | |
|     feed("/A<Enter>")
 | |
|     expect("A")
 | |
|     eq({mode='n', blocking=false}, nvim("get_mode"))
 | |
|   end)
 | |
| 
 | |
|   it("with multiline text and range, does not lock up #7244", function()
 | |
|     common_setup(nil, "nosplit", "{\n\n{")
 | |
|     command("set gdefault")
 | |
|     feed(":%s/{\\n")
 | |
|     eq({mode='c', blocking=false}, nvim("get_mode"))
 | |
|     feed("/A<Enter>")
 | |
|     expect("A\nA")
 | |
|     eq({mode='n', blocking=false}, nvim("get_mode"))
 | |
|   end)
 | |
| 
 | |
|   it("does not crash on zero-width matches #7485", function()
 | |
|     common_setup(nil, "split", default_text)
 | |
|     command("set gdefault")
 | |
|     feed("gg")
 | |
|     feed("Vj")
 | |
|     feed(":s/\\%V")
 | |
|     eq({mode='c', blocking=false}, nvim("get_mode"))
 | |
|     feed("<Esc>")
 | |
|     eq({mode='n', blocking=false}, nvim("get_mode"))
 | |
|   end)
 | |
| 
 | |
|   it("removes highlights after abort for a zero-width match", function()
 | |
|     local screen = Screen.new(30,5)
 | |
|     common_setup(screen, "nosplit", default_text)
 | |
|     command("set gdefault")
 | |
| 
 | |
|     feed(":%s/\\%1c/a/")
 | |
|     screen:expect([[
 | |
|       {12:a}Inc substitution on          |
 | |
|       {12:a}two lines                    |
 | |
|       {12:a}                             |
 | |
|       {15:~                             }|
 | |
|       :%s/\%1c/a/^                   |
 | |
|     ]])
 | |
| 
 | |
|     feed("<Esc>")
 | |
|     screen:expect([[
 | |
|       Inc substitution on           |
 | |
|       two lines                     |
 | |
|       ^                              |
 | |
|       {15:~                             }|
 | |
|                                     |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
| end)
 | |
| 
 | |
| describe(":substitute", function()
 | |
|   local screen = Screen.new(30,15)
 | |
|   before_each(function()
 | |
|     clear()
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, highlights multiline substitutions", function()
 | |
|     common_setup(screen, "split", multiline_text)
 | |
|     feed("gg")
 | |
| 
 | |
|     feed(":%s/2\\_.*X")
 | |
|     screen:expect([[
 | |
|       1 {12:2 3}                         |
 | |
|       {12:A B C}                         |
 | |
|       {12:4 5 6}                         |
 | |
|       {12:X} Y Z                         |
 | |
|       7 8 9                         |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| 1 {12:2 3}                     |
 | |
|       |2|{12: A B C}                     |
 | |
|       |3|{12: 4 5 6}                     |
 | |
|       |4|{12: X} Y Z                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/2\_.*X^                    |
 | |
|     ]])
 | |
| 
 | |
|     feed("/MMM")
 | |
|     screen:expect([[
 | |
|       1 {12:MMM} Y Z                     |
 | |
|       7 8 9                         |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| 1 {12:MMM} Y Z                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/2\_.*X/MMM^                |
 | |
|     ]])
 | |
| 
 | |
|     feed("\\rK\\rLLL")
 | |
|     screen:expect([[
 | |
|       1 {12:MMM}                         |
 | |
|       {12:K}                             |
 | |
|       {12:LLL} Y Z                       |
 | |
|       7 8 9                         |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| 1 {12:MMM}                     |
 | |
|       |2|{12: K}                         |
 | |
|       |3|{12: LLL} Y Z                   |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/2\_.*X/MMM\rK\rLLL^        |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=nosplit, highlights multiline substitutions", function()
 | |
|     common_setup(screen, "nosplit", multiline_text)
 | |
|     feed("gg")
 | |
| 
 | |
|     feed(":%s/2\\_.*X/MMM")
 | |
|     screen:expect([[
 | |
|       1 {12:MMM} Y Z                     |
 | |
|       7 8 9                         |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/2\_.*X/MMM^                |
 | |
|     ]])
 | |
| 
 | |
|     feed("\\rK\\rLLL")
 | |
|     screen:expect([[
 | |
|       1 {12:MMM}                         |
 | |
|       {12:K}                             |
 | |
|       {12:LLL} Y Z                       |
 | |
|       7 8 9                         |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/2\_.*X/MMM\rK\rLLL^        |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, highlights multiple matches on a line", function()
 | |
|     common_setup(screen, "split", multimatch_text)
 | |
|     command("set gdefault")
 | |
|     feed("gg")
 | |
| 
 | |
|     feed(":%s/a/XLK")
 | |
|     screen:expect([[
 | |
|       {12:XLK} bdc e{12:XLK}e {12:XLK} fgl lzi{12:XLK} r|
 | |
|       x                             |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| {12:XLK} bdc e{12:XLK}e {12:XLK} fgl lzi{12:X}|
 | |
|       {12:LK} r                          |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/a/XLK^                     |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=nosplit, highlights multiple matches on a line", function()
 | |
|     common_setup(screen, "nosplit", multimatch_text)
 | |
|     command("set gdefault")
 | |
|     feed("gg")
 | |
| 
 | |
|     feed(":%s/a/XLK")
 | |
|     screen:expect([[
 | |
|       {12:XLK} bdc e{12:XLK}e {12:XLK} fgl lzi{12:XLK} r|
 | |
|       x                             |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/a/XLK^                     |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, with \\zs", function()
 | |
|     common_setup(screen, "split", multiline_text)
 | |
|     feed("gg")
 | |
| 
 | |
|     feed(":%s/[0-9]\\n\\zs[A-Z]/OKO")
 | |
|     screen:expect([[
 | |
|       {12:OKO} B C                       |
 | |
|       4 5 6                         |
 | |
|       {12:OKO} Y Z                       |
 | |
|       7 8 9                         |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| 1 2 3                     |
 | |
|       |2| {12:OKO} B C                   |
 | |
|       |3| 4 5 6                     |
 | |
|       |4| {12:OKO} Y Z                   |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/[0-9]\n\zs[A-Z]/OKO^       |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=nosplit, with \\zs", function()
 | |
|     common_setup(screen, "nosplit", multiline_text)
 | |
|     feed("gg")
 | |
| 
 | |
|     feed(":%s/[0-9]\\n\\zs[A-Z]/OKO")
 | |
|     screen:expect([[
 | |
|       1 2 3                         |
 | |
|       {12:OKO} B C                       |
 | |
|       4 5 6                         |
 | |
|       {12:OKO} Y Z                       |
 | |
|       7 8 9                         |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/[0-9]\n\zs[A-Z]/OKO^       |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, substitutions of different length",
 | |
|     function()
 | |
|     common_setup(screen, "split", "T T123 T2T TTT T090804\nx")
 | |
| 
 | |
|     feed(":%s/T\\([0-9]\\+\\)/\\1\\1/g")
 | |
|     screen:expect([[
 | |
|       T {12:123123} {12:22}T TTT {12:090804090804} |
 | |
|       x                             |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| T {12:123123} {12:22}T TTT {12:090804090}|
 | |
|       {12:804}                           |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/T\([0-9]\+\)/\1\1/g^       |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=nosplit, substitutions of different length", function()
 | |
|     common_setup(screen, "nosplit", "T T123 T2T TTT T090804\nx")
 | |
| 
 | |
|     feed(":%s/T\\([0-9]\\+\\)/\\1\\1/g")
 | |
|     screen:expect([[
 | |
|       T {12:123123} {12:22}T TTT {12:090804090804} |
 | |
|       x                             |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/T\([0-9]\+\)/\1\1/g^       |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, contraction of lines", function()
 | |
|     local text = [[
 | |
|       T T123 T T123 T2T TT T23423424
 | |
|       x
 | |
|       afa Q
 | |
|       adf la;lkd R
 | |
|       alx
 | |
|       ]]
 | |
| 
 | |
|     common_setup(screen, "split", text)
 | |
|     feed(":%s/[QR]\\n")
 | |
|     screen:expect([[
 | |
|       afa {12:Q}                         |
 | |
|       adf la;lkd {12:R}                  |
 | |
|       alx                           |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |3| afa {12:Q}                     |
 | |
|       |4|{12: }adf la;lkd {12:R}              |
 | |
|       |5|{12: }alx                       |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/[QR]\n^                    |
 | |
|     ]])
 | |
| 
 | |
|     feed("/KKK")
 | |
|     screen:expect([[
 | |
|       T T123 T T123 T2T TT T23423424|
 | |
|       x                             |
 | |
|       afa {12:KKK}adf la;lkd {12:KKK}alx      |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |3| afa {12:KKK}adf la;lkd {12:KKK}alx  |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/[QR]\n/KKK^                |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=nosplit, contraction of lines", function()
 | |
|     local text = [[
 | |
|       T T123 T T123 T2T TT T23423424
 | |
|       x
 | |
|       afa Q
 | |
|       adf la;lkd R
 | |
|       alx
 | |
|       ]]
 | |
| 
 | |
|     common_setup(screen, "nosplit", text)
 | |
|     feed(":%s/[QR]\\n/KKK")
 | |
|     screen:expect([[
 | |
|       T T123 T T123 T2T TT T23423424|
 | |
|       x                             |
 | |
|       afa {12:KKK}adf la;lkd {12:KKK}alx      |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/[QR]\n/KKK^                |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, contraction of two subsequent NL chars", function()
 | |
|     -- luacheck: push ignore 611
 | |
|     local text = [[
 | |
|       AAA AA
 | |
|       
 | |
|       BBB BB
 | |
|       
 | |
|       CCC CC
 | |
|       
 | |
| ]]
 | |
|     -- luacheck: pop
 | |
| 
 | |
|     -- This used to crash, but more than 20 highlight entries are required
 | |
|     -- to reproduce it (so that the marktree has multiple nodes)
 | |
|     common_setup(screen, "split", string.rep(text,10))
 | |
|     feed(":%s/\\n\\n/<c-v><c-m>/g")
 | |
|     screen:expect{grid=[[
 | |
|       CCC CC                        |
 | |
|       AAA AA                        |
 | |
|       BBB BB                        |
 | |
|       CCC CC                        |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 1| AAA AA                   |
 | |
|       | 2|{12: }BBB BB                   |
 | |
|       | 3|{12: }CCC CC                   |
 | |
|       | 4|{12: }AAA AA                   |
 | |
|       | 5|{12: }BBB BB                   |
 | |
|       | 6|{12: }CCC CC                   |
 | |
|       | 7|{12: }AAA AA                   |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/\n\n/{17:^M}/g^                 |
 | |
|     ]]}
 | |
|     assert_alive()
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=nosplit, contraction of two subsequent NL chars", function()
 | |
|     -- luacheck: push ignore 611
 | |
|     local text = [[
 | |
|       AAA AA
 | |
|       
 | |
|       BBB BB
 | |
|       
 | |
|       CCC CC
 | |
|       
 | |
| ]]
 | |
|     -- luacheck: pop
 | |
| 
 | |
|     common_setup(screen, "nosplit", string.rep(text,10))
 | |
|     feed(":%s/\\n\\n/<c-v><c-m>/g")
 | |
|     screen:expect{grid=[[
 | |
|       CCC CC                        |
 | |
|       AAA AA                        |
 | |
|       BBB BB                        |
 | |
|       CCC CC                        |
 | |
|       AAA AA                        |
 | |
|       BBB BB                        |
 | |
|       CCC CC                        |
 | |
|       AAA AA                        |
 | |
|       BBB BB                        |
 | |
|       CCC CC                        |
 | |
|       AAA AA                        |
 | |
|       BBB BB                        |
 | |
|       CCC CC                        |
 | |
|                                     |
 | |
|       :%s/\n\n/{17:^M}/g^                 |
 | |
|     ]]}
 | |
|     assert_alive()
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, multibyte text", function()
 | |
|     common_setup(screen, "split", multibyte_text)
 | |
|     feed(":%s/£.*ѫ/X¥¥")
 | |
|     screen:expect([[
 | |
|        a{12:X¥¥}¥KOL                     |
 | |
|       £ ¥  libm                     |
 | |
|       £ ¥                           |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1|  {12:X¥¥} PEPPERS              |
 | |
|       |2| {12:X¥¥}                       |
 | |
|       |3|  a{12:X¥¥}¥KOL                 |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/£.*ѫ/X¥¥^                  |
 | |
|     ]])
 | |
| 
 | |
|     feed("\\ra££   ¥")
 | |
|     screen:expect([[
 | |
|        a{12:X¥¥}                         |
 | |
|       {12:a££   ¥}¥KOL                   |
 | |
|       £ ¥  libm                     |
 | |
|       £ ¥                           |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1|  {12:X¥¥}                      |
 | |
|       |2|{12: a££   ¥} PEPPERS           |
 | |
|       |3| {12:X¥¥}                       |
 | |
|       |4|{12: a££   ¥}                   |
 | |
|       |5|  a{12:X¥¥}                     |
 | |
|       |6|{12: a££   ¥}¥KOL               |
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/£.*ѫ/X¥¥\ra££   ¥^         |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=nosplit, multibyte text", function()
 | |
|     common_setup(screen, "nosplit", multibyte_text)
 | |
|     feed(":%s/£.*ѫ/X¥¥")
 | |
|     screen:expect([[
 | |
|        {12:X¥¥} PEPPERS                  |
 | |
|       {12:X¥¥}                           |
 | |
|        a{12:X¥¥}¥KOL                     |
 | |
|       £ ¥  libm                     |
 | |
|       £ ¥                           |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/£.*ѫ/X¥¥^                  |
 | |
|     ]])
 | |
| 
 | |
|     feed("\\ra££   ¥")
 | |
|     screen:expect([[
 | |
|        {12:X¥¥}                          |
 | |
|       {12:a££   ¥} PEPPERS               |
 | |
|       {12:X¥¥}                           |
 | |
|       {12:a££   ¥}                       |
 | |
|        a{12:X¥¥}                         |
 | |
|       {12:a££   ¥}¥KOL                   |
 | |
|       £ ¥  libm                     |
 | |
|       £ ¥                           |
 | |
|                                     |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       :%s/£.*ѫ/X¥¥\ra££   ¥^         |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, small cmdwinheight", function()
 | |
|     common_setup(screen, "split", long_multiline_text)
 | |
|     command("set cmdwinheight=2")
 | |
| 
 | |
|     feed(":%s/[a-z]")
 | |
|     screen:expect([[
 | |
|       X Y Z                         |
 | |
|       7 8 9                         |
 | |
|       K L M                         |
 | |
|       {12:a} b c                         |
 | |
|       {12:d} e f                         |
 | |
|       {12:q} r s                         |
 | |
|       {12:x} y z                         |
 | |
|       £ {12:m} n                         |
 | |
|       {12:t} œ ¥                         |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 7| {12:a} b c                    |
 | |
|       | 8| {12:d} e f                    |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/[a-z]^                     |
 | |
|     ]])
 | |
| 
 | |
|     feed("/JLKR £")
 | |
|     screen:expect([[
 | |
|       X Y Z                         |
 | |
|       7 8 9                         |
 | |
|       K L M                         |
 | |
|       {12:JLKR £} b c                    |
 | |
|       {12:JLKR £} e f                    |
 | |
|       {12:JLKR £} r s                    |
 | |
|       {12:JLKR £} y z                    |
 | |
|       £ {12:JLKR £} n                    |
 | |
|       {12:JLKR £} œ ¥                    |
 | |
|                                     |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 7| {12:JLKR £} b c               |
 | |
|       | 8| {12:JLKR £} e f               |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/[a-z]/JLKR £^              |
 | |
|     ]])
 | |
| 
 | |
|     feed("\\rѫ ab   \\rXXXX")
 | |
|     screen:expect([[
 | |
|       7 8 9                         |
 | |
|       K L M                         |
 | |
|       {12:JLKR £}                        |
 | |
|       {12:ѫ ab   }                       |
 | |
|       {12:XXXX} b c                      |
 | |
|       {12:JLKR £}                        |
 | |
|       {12:ѫ ab   }                       |
 | |
|       {12:XXXX} e f                      |
 | |
|       {12:JLKR £}                        |
 | |
|       {12:ѫ ab   }                       |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 7| {12:JLKR £}                   |
 | |
|       {11:                              }|
 | |
|       :%s/[a-z]/JLKR £\rѫ ab   \rXXX|
 | |
|       X^                             |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, large cmdwinheight", function()
 | |
|     common_setup(screen, "split", long_multiline_text)
 | |
|     command("set cmdwinheight=11")
 | |
| 
 | |
|     feed(":%s/. .$")
 | |
|     screen:expect([[
 | |
|       t {12:œ ¥}                         |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 1| 1 {12:2 3}                    |
 | |
|       | 2| A {12:B C}                    |
 | |
|       | 3| 4 {12:5 6}                    |
 | |
|       | 4| X {12:Y Z}                    |
 | |
|       | 5| 7 {12:8 9}                    |
 | |
|       | 6| K {12:L M}                    |
 | |
|       | 7| a {12:b c}                    |
 | |
|       | 8| d {12:e f}                    |
 | |
|       | 9| q {12:r s}                    |
 | |
|       |10| x {12:y z}                    |
 | |
|       |11| £ {12:m n}                    |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/. .$^                      |
 | |
|     ]])
 | |
| 
 | |
|     feed("/ YYY")
 | |
|     screen:expect([[
 | |
|       t {12: YYY}                        |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 1| 1 {12: YYY}                   |
 | |
|       | 2| A {12: YYY}                   |
 | |
|       | 3| 4 {12: YYY}                   |
 | |
|       | 4| X {12: YYY}                   |
 | |
|       | 5| 7 {12: YYY}                   |
 | |
|       | 6| K {12: YYY}                   |
 | |
|       | 7| a {12: YYY}                   |
 | |
|       | 8| d {12: YYY}                   |
 | |
|       | 9| q {12: YYY}                   |
 | |
|       |10| x {12: YYY}                   |
 | |
|       |11| £ {12: YYY}                   |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/. .$/ YYY^                 |
 | |
|     ]])
 | |
| 
 | |
|     feed("\\r KKK")
 | |
|     screen:expect([[
 | |
|       a {12: YYY}                        |
 | |
|       {11:[No Name] [+]                 }|
 | |
|       | 1| 1 {12: YYY}                   |
 | |
|       | 2|{12:  KKK}                     |
 | |
|       | 3| A {12: YYY}                   |
 | |
|       | 4|{12:  KKK}                     |
 | |
|       | 5| 4 {12: YYY}                   |
 | |
|       | 6|{12:  KKK}                     |
 | |
|       | 7| X {12: YYY}                   |
 | |
|       | 8|{12:  KKK}                     |
 | |
|       | 9| 7 {12: YYY}                   |
 | |
|       |10|{12:  KKK}                     |
 | |
|       |11| K {12: YYY}                   |
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/. .$/ YYY\r KKK^           |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("inccommand=split, lookaround", function()
 | |
|     common_setup(screen, "split", "something\neverything\nsomeone")
 | |
|     feed([[:%s/\(some\)\@<lt>=thing/one/]])
 | |
|     screen:expect([[
 | |
|       some{12:one}                       |
 | |
|       everything                    |
 | |
|       someone                       |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| some{12:one}                   |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/\(some\)\@<=thing/one/^    |
 | |
|     ]])
 | |
| 
 | |
|     feed("<C-c>")
 | |
|     feed('gg')
 | |
|     poke_eventloop()
 | |
|     feed([[:%s/\(some\)\@<lt>!thing/one/]])
 | |
|     screen:expect([[
 | |
|       something                     |
 | |
|       every{12:one}                      |
 | |
|       someone                       |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |2| every{12:one}                  |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/\(some\)\@<!thing/one/^    |
 | |
|     ]])
 | |
| 
 | |
|     feed([[<C-c>]])
 | |
|     poke_eventloop()
 | |
|     feed([[:%s/some\(thing\)\@=/every/]])
 | |
|     screen:expect([[
 | |
|       {12:every}thing                    |
 | |
|       everything                    |
 | |
|       someone                       |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |1| {12:every}thing                |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/some\(thing\)\@=/every/^   |
 | |
|     ]])
 | |
| 
 | |
|     feed([[<C-c>]])
 | |
|     poke_eventloop()
 | |
|     feed([[:%s/some\(thing\)\@!/every/]])
 | |
|     screen:expect([[
 | |
|       something                     |
 | |
|       everything                    |
 | |
|       {12:every}one                      |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {11:[No Name] [+]                 }|
 | |
|       |3| {12:every}one                  |
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {15:~                             }|
 | |
|       {10:[Preview]                     }|
 | |
|       :%s/some\(thing\)\@!/every/^   |
 | |
|     ]])
 | |
|   end)
 | |
| 
 | |
|   it("doesn't prompt to swap cmd range", function()
 | |
|     screen = Screen.new(50, 8) -- wide to avoid hit-enter prompt
 | |
|     common_setup(screen, "split", default_text)
 | |
|     feed(':2,1s/tw/MO/g')
 | |
| 
 | |
|     -- substitution preview should have been made, without prompting
 | |
|     screen:expect([[
 | |
|       {12:MO}o lines                                         |
 | |
|       {11:[No Name] [+]                                     }|
 | |
|       |2| {12:MO}o lines                                     |
 | |
|       {15:~                                                 }|
 | |
|       {15:~                                                 }|
 | |
|       {15:~                                                 }|
 | |
|       {10:[Preview]                                         }|
 | |
|       :2,1s/tw/MO/g^                                     |
 | |
|     ]])
 | |
| 
 | |
|     -- but should be prompted on hitting enter
 | |
|     feed('<CR>')
 | |
|     screen:expect([[
 | |
|       {12:MO}o lines                                         |
 | |
|       {11:[No Name] [+]                                     }|
 | |
|       |2| {12:MO}o lines                                     |
 | |
|       {15:~                                                 }|
 | |
|       {15:~                                                 }|
 | |
|       {15:~                                                 }|
 | |
|       {10:[Preview]                                         }|
 | |
|       {13:Backwards range given, OK to swap (y/n)?}^          |
 | |
|     ]])
 | |
| 
 | |
|     feed('y')
 | |
|     screen:expect([[
 | |
|       Inc substitution on                               |
 | |
|       ^MOo lines                                         |
 | |
|                                                         |
 | |
|       {15:~                                                 }|
 | |
|       {15:~                                                 }|
 | |
|       {15:~                                                 }|
 | |
|       {15:~                                                 }|
 | |
|       {13:Backwards range given, OK to swap (y/n)?}y         |
 | |
|     ]])
 | |
|   end)
 | |
| end)
 | |
| 
 | |
| it(':substitute with inccommand during :terminal activity', function()
 | |
|   if helpers.skip_fragile(pending) then
 | |
|     return
 | |
|   end
 | |
|   retry(2, 40000, function()
 | |
|     local screen = Screen.new(30,15)
 | |
|     clear()
 | |
| 
 | |
|     command("set cmdwinheight=3")
 | |
|     feed(([[:terminal "%s" REP 5000 xxx<cr>]]):format(testprg('shell-test')))
 | |
|     command('file term')
 | |
|     feed('G')  -- Follow :terminal output.
 | |
|     command('new')
 | |
|     common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
 | |
|     command('wincmd =')
 | |
| 
 | |
|     feed('gg')
 | |
|     feed(':%s/foo/ZZZ')
 | |
|     sleep(20)  -- Allow some terminal activity.
 | |
|     helpers.poke_eventloop()
 | |
|     screen:expect_unchanged()
 | |
|   end)
 | |
| end)
 | |
| 
 | |
| it(':substitute with inccommand, timer-induced :redraw #9777', function()
 | |
|   local screen = Screen.new(30,12)
 | |
|   clear()
 | |
|   command('set cmdwinheight=3')
 | |
|   command('call timer_start(10, {-> execute("redraw")}, {"repeat":-1})')
 | |
|   command('call timer_start(10, {-> execute("redrawstatus")}, {"repeat":-1})')
 | |
|   common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
 | |
| 
 | |
|   feed('gg')
 | |
|   feed(':%s/foo/ZZZ')
 | |
|   sleep(20)  -- Allow some timer activity.
 | |
|   screen:expect([[
 | |
|     {12:ZZZ} bar baz                   |
 | |
|     bar baz fox                   |
 | |
|     bar {12:ZZZ} baz                   |
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     {11:[No Name] [+]                 }|
 | |
|     |1| {12:ZZZ} bar baz               |
 | |
|     |3| bar {12:ZZZ} baz               |
 | |
|     {15:~                             }|
 | |
|     {10:[Preview]                     }|
 | |
|     :%s/foo/ZZZ^                   |
 | |
|   ]])
 | |
| end)
 | |
| 
 | |
| it(':substitute with inccommand, allows :redraw before first separator is typed #18857', function()
 | |
|   local screen = Screen.new(30,6)
 | |
|   clear()
 | |
|   common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
 | |
|   command('hi! link NormalFloat CursorLine')
 | |
|   local float_buf = meths.create_buf(false, true)
 | |
|   meths.open_win(float_buf, false, {
 | |
|     relative = 'editor', height = 1, width = 5, row = 3, col = 0, focusable = false,
 | |
|   })
 | |
|   feed(':%s')
 | |
|   screen:expect([[
 | |
|     foo bar baz                   |
 | |
|     bar baz fox                   |
 | |
|     bar foo baz                   |
 | |
|     {16:     }{15:                         }|
 | |
|     {15:~                             }|
 | |
|     :%s^                           |
 | |
|   ]])
 | |
|   meths.buf_set_lines(float_buf, 0, -1, true, {'foo'})
 | |
|   command('redraw')
 | |
|   screen:expect([[
 | |
|     foo bar baz                   |
 | |
|     bar baz fox                   |
 | |
|     bar foo baz                   |
 | |
|     {16:foo  }{15:                         }|
 | |
|     {15:~                             }|
 | |
|     :%s^                           |
 | |
|   ]])
 | |
| end)
 | |
| 
 | |
| it(':substitute with inccommand, does not crash if range contains invalid marks', function()
 | |
|   local screen = Screen.new(30, 6)
 | |
|   clear()
 | |
|   common_setup(screen, 'split', 'test')
 | |
|   feed([[:'a,'bs]])
 | |
|   screen:expect([[
 | |
|     test                          |
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     :'a,'bs^                       |
 | |
|   ]])
 | |
|   -- v:errmsg shouldn't be set either before the first separator is typed
 | |
|   eq('', eval('v:errmsg'))
 | |
|   feed('/')
 | |
|   screen:expect([[
 | |
|     test                          |
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     {15:~                             }|
 | |
|     :'a,'bs/^                      |
 | |
|   ]])
 | |
| end)
 | |
| 
 | |
| it(':substitute with inccommand, no unnecessary redraw if preview is not shown', function()
 | |
|   local screen = Screen.new(60, 6)
 | |
|   clear()
 | |
|   common_setup(screen, 'split', 'test')
 | |
|   feed(':ls<CR>')
 | |
|   screen:expect([[
 | |
|     test                                                        |
 | |
|     {15:~                                                           }|
 | |
|     {11:                                                            }|
 | |
|     :ls                                                         |
 | |
|       1 %a + "[No Name]"                    line 1              |
 | |
|     {13:Press ENTER or type command to continue}^                     |
 | |
|   ]])
 | |
|   feed(':s')
 | |
|   -- no unnecessary redraw, so messages are still shown
 | |
|   screen:expect([[
 | |
|     test                                                        |
 | |
|     {15:~                                                           }|
 | |
|     {11:                                                            }|
 | |
|     :ls                                                         |
 | |
|       1 %a + "[No Name]"                    line 1              |
 | |
|     :s^                                                          |
 | |
|   ]])
 | |
|   feed('o')
 | |
|   screen:expect([[
 | |
|     test                                                        |
 | |
|     {15:~                                                           }|
 | |
|     {11:                                                            }|
 | |
|     :ls                                                         |
 | |
|       1 %a + "[No Name]"                    line 1              |
 | |
|     :so^                                                         |
 | |
|   ]])
 | |
|   feed('<BS>')
 | |
|   screen:expect([[
 | |
|     test                                                        |
 | |
|     {15:~                                                           }|
 | |
|     {11:                                                            }|
 | |
|     :ls                                                         |
 | |
|       1 %a + "[No Name]"                    line 1              |
 | |
|     :s^                                                          |
 | |
|   ]])
 | |
|   feed('/test')
 | |
|   -- now inccommand is shown, so screen is redrawn
 | |
|   screen:expect([[
 | |
|     {12:test}                                                        |
 | |
|     {15:~                                                           }|
 | |
|     {15:~                                                           }|
 | |
|     {15:~                                                           }|
 | |
|     {15:~                                                           }|
 | |
|     :s/test^                                                     |
 | |
|   ]])
 | |
| end)
 | |
| 
 | |
| it(":substitute doesn't crash with inccommand, if undo is empty #12932", function()
 | |
|   local screen = Screen.new(10,5)
 | |
|   clear()
 | |
|   command('set undolevels=-1')
 | |
|   common_setup(screen, 'split', 'test')
 | |
|   feed(':%s/test')
 | |
|   sleep(100)
 | |
|   feed('/')
 | |
|   sleep(100)
 | |
|   feed('f')
 | |
|   screen:expect([[
 | |
|   {12:f}           |
 | |
|   {15:~           }|
 | |
|   {15:~           }|
 | |
|   {15:~           }|
 | |
|   :%s/test/f^  |
 | |
|   ]])
 | |
|   assert_alive()
 | |
| end)
 | |
| 
 | |
| it(':substitute with inccommand works properly if undo is not synced #20029', function()
 | |
|   local screen = Screen.new(30, 6)
 | |
|   clear()
 | |
|   common_setup(screen, 'nosplit', 'foo\nbar\nbaz')
 | |
|   meths.set_keymap('x', '<F2>', '<Esc>`<Oaaaaa asdf<Esc>`>obbbbb asdf<Esc>V`<k:s/asdf/', {})
 | |
|   feed('gg0<C-V>lljj<F2>')
 | |
|   screen:expect([[
 | |
|     aaaaa                         |
 | |
|     foo                           |
 | |
|     bar                           |
 | |
|     baz                           |
 | |
|     bbbbb                         |
 | |
|     :'<,'>s/asdf/^                 |
 | |
|   ]])
 | |
|   feed('hjkl')
 | |
|   screen:expect([[
 | |
|     aaaaa {12:hjkl}                    |
 | |
|     foo                           |
 | |
|     bar                           |
 | |
|     baz                           |
 | |
|     bbbbb {12:hjkl}                    |
 | |
|     :'<,'>s/asdf/hjkl^             |
 | |
|   ]])
 | |
|   feed('<CR>')
 | |
|   expect([[
 | |
|     aaaaa hjkl
 | |
|     foo
 | |
|     bar
 | |
|     baz
 | |
|     bbbbb hjkl]])
 | |
|   feed('u')
 | |
|   expect([[
 | |
|     foo
 | |
|     bar
 | |
|     baz]])
 | |
| end)
 | |
| 
 | |
| it('long :%s/ with inccommand does not collapse cmdline', function()
 | |
|   local screen = Screen.new(10,5)
 | |
|   clear()
 | |
|   common_setup(screen)
 | |
|   command('set inccommand=nosplit')
 | |
|   feed(':%s/AAAAAAA', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
 | |
|     'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A')
 | |
|   screen:expect([[
 | |
|                 |
 | |
|     {11:            }|
 | |
|     :%s/AAAAAAAA|
 | |
|     AAAAAAAAAAAA|
 | |
|     AAAAAAA^     |
 | |
|   ]])
 | |
| end)
 | |
| 
 | |
| it("with 'inccommand' typing :filter doesn't segfault or leak memory #19057", function()
 | |
|   clear()
 | |
|   common_setup(nil, 'nosplit')
 | |
|   feed(':filter s')
 | |
|   assert_alive()
 | |
|   feed(' ')
 | |
|   assert_alive()
 | |
|   feed('h')
 | |
|   assert_alive()
 | |
|   feed('i')
 | |
|   assert_alive()
 | |
| end)
 | 
