mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	 6750d00fe9
			
		
	
	6750d00fe9
	
	
	
		
			
			Problem:    Sourcing buffer lines is too complicated.
Solution:   Simplify the code. Make it possible to source Vim9 script lines.
            (Yegappan Lakshmanan, closes vim/vim#9974)
85b43c6cb7
This commit changes the behavior of sourcing buffer lines to always have
a script ID, although sourcing the same buffer always produces the same
script ID.
vim-patch:9.1.0372: Calling CLEAR_FIELD() on the same struct twice
Problem:  Calling CLEAR_FIELD() on the same struct twice.
Solution: Remove the second CLEAR_FIELD().  Move the assignment of
          cookie.sourceing_lnum (zeertzjq).
closes: vim/vim#14627
f68517c167
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
		
	
		
			
				
	
	
		
			475 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			475 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local t = require('test.testutil')
 | |
| local n = require('test.functional.testnvim')()
 | |
| local Screen = require('test.functional.ui.screen')
 | |
| 
 | |
| local api = n.api
 | |
| local clear = n.clear
 | |
| local command = n.command
 | |
| local fn = n.fn
 | |
| local eq = t.eq
 | |
| local feed = n.feed
 | |
| local write_file = t.write_file
 | |
| local pcall_err = t.pcall_err
 | |
| local cursor = function()
 | |
|   return n.api.nvim_win_get_cursor(0)
 | |
| end
 | |
| 
 | |
| describe('named marks', function()
 | |
|   local file1 = 'Xtestfile-functional-editor-marks'
 | |
|   local file2 = 'Xtestfile-functional-editor-marks-2'
 | |
|   before_each(function()
 | |
|     clear()
 | |
|     write_file(file1, '1test1\n1test2\n1test3\n1test4', false, false)
 | |
|     write_file(file2, '2test1\n2test2\n2test3\n2test4', false, false)
 | |
|   end)
 | |
|   after_each(function()
 | |
|     os.remove(file1)
 | |
|     os.remove(file2)
 | |
|   end)
 | |
| 
 | |
|   it('can be set', function()
 | |
|     command('edit ' .. file1)
 | |
|     command('mark a')
 | |
|     eq({ 1, 0 }, api.nvim_buf_get_mark(0, 'a'))
 | |
|     feed('jmb')
 | |
|     eq({ 2, 0 }, api.nvim_buf_get_mark(0, 'b'))
 | |
|     feed('jmB')
 | |
|     eq({ 3, 0 }, api.nvim_buf_get_mark(0, 'B'))
 | |
|     command('4kc')
 | |
|     eq({ 4, 0 }, api.nvim_buf_get_mark(0, 'c'))
 | |
|   end)
 | |
| 
 | |
|   it('errors when set out of range with :mark', function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, '1000mark x')
 | |
|     eq('nvim_exec2(), line 1: Vim(mark):E16: Invalid range: 1000mark x', err)
 | |
|   end)
 | |
| 
 | |
|   it('errors when set out of range with :k', function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, '1000kx')
 | |
|     eq('nvim_exec2(), line 1: Vim(k):E16: Invalid range: 1000kx', err)
 | |
|   end)
 | |
| 
 | |
|   it('errors on unknown mark name with :mark', function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, 'mark #')
 | |
|     eq(
 | |
|       'nvim_exec2(), line 1: Vim(mark):E191: Argument must be a letter or forward/backward quote',
 | |
|       err
 | |
|     )
 | |
|   end)
 | |
| 
 | |
|   it("errors on unknown mark name with '", function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, "normal! '#")
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E78: Unknown mark', err)
 | |
|   end)
 | |
| 
 | |
|   it('errors on unknown mark name with `', function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, 'normal! `#')
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E78: Unknown mark', err)
 | |
|   end)
 | |
| 
 | |
|   it("errors when moving to a mark that is not set with '", function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, "normal! 'z")
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
 | |
|     err = pcall_err(n.exec_capture, "normal! '.")
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
 | |
|   end)
 | |
| 
 | |
|   it('errors when moving to a mark that is not set with `', function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, 'normal! `z')
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
 | |
|     err = pcall_err(n.exec_capture, 'normal! `>')
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
 | |
|   end)
 | |
| 
 | |
|   it("errors when moving to a global mark that is not set with '", function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, "normal! 'Z")
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
 | |
|   end)
 | |
| 
 | |
|   it('errors when moving to a global mark that is not set with `', function()
 | |
|     command('edit ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, 'normal! `Z')
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
 | |
|   end)
 | |
| 
 | |
|   it("can move to them using '", function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     feed('j')
 | |
|     feed('ma')
 | |
|     feed("G'a")
 | |
|     eq({ 2, 0 }, cursor())
 | |
|     feed('mA')
 | |
|     command('next')
 | |
|     feed("'A")
 | |
|     eq(1, api.nvim_get_current_buf())
 | |
|     eq({ 2, 0 }, cursor())
 | |
|   end)
 | |
| 
 | |
|   it('can move to them using `', function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     feed('jll')
 | |
|     feed('ma')
 | |
|     feed('G`a')
 | |
|     eq({ 2, 2 }, cursor())
 | |
|     feed('mA')
 | |
|     command('next')
 | |
|     feed('`A')
 | |
|     eq(1, api.nvim_get_current_buf())
 | |
|     eq({ 2, 2 }, cursor())
 | |
|   end)
 | |
| 
 | |
|   it("can move to them using g'", function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     feed('jll')
 | |
|     feed('ma')
 | |
|     feed("Gg'a")
 | |
|     eq({ 2, 0 }, cursor())
 | |
|     feed('mA')
 | |
|     command('next')
 | |
|     feed("g'A")
 | |
|     eq(1, api.nvim_get_current_buf())
 | |
|     eq({ 2, 0 }, cursor())
 | |
|   end)
 | |
| 
 | |
|   it('can move to them using g`', function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     feed('jll')
 | |
|     feed('ma')
 | |
|     feed('Gg`a')
 | |
|     eq({ 2, 2 }, cursor())
 | |
|     feed('mA')
 | |
|     command('next')
 | |
|     feed('g`A')
 | |
|     eq(1, api.nvim_get_current_buf())
 | |
|     eq({ 2, 2 }, cursor())
 | |
|   end)
 | |
| 
 | |
|   it("can move to them using :'", function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     feed('j')
 | |
|     feed('ma')
 | |
|     feed('G')
 | |
|     command("'a")
 | |
|     eq({ 2, 0 }, cursor())
 | |
|     feed('mA')
 | |
|     command('next')
 | |
|     command("'A")
 | |
|     eq(1, api.nvim_get_current_buf())
 | |
|     eq({ 2, 0 }, cursor())
 | |
|   end)
 | |
| 
 | |
|   it("errors when it can't find the buffer", function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     feed('mA')
 | |
|     command('next')
 | |
|     command('bw! ' .. file1)
 | |
|     local err = pcall_err(n.exec_capture, "normal! 'A")
 | |
|     eq('nvim_exec2(), line 1: Vim(normal):E92: Buffer 1 not found', err)
 | |
|     os.remove(file1)
 | |
|   end)
 | |
| 
 | |
|   it('errors when using a mark in another buffer in command range', function()
 | |
|     feed('ifoo<Esc>mA')
 | |
|     command('enew')
 | |
|     feed('ibar<Esc>')
 | |
|     eq("Vim(print):E20: Mark not set: 'Aprint", pcall_err(command, [['Aprint]]))
 | |
|   end)
 | |
| 
 | |
|   it("leave a context mark when moving with '", function()
 | |
|     command('edit ' .. file1)
 | |
|     feed('llmamA')
 | |
|     feed('10j0') -- first col, last line
 | |
|     local pos = cursor()
 | |
|     feed("'a")
 | |
|     feed('<C-o>')
 | |
|     eq(pos, cursor())
 | |
|     feed("'A")
 | |
|     feed('<C-o>')
 | |
|     eq(pos, cursor())
 | |
|   end)
 | |
| 
 | |
|   it('leave a context mark when moving with `', function()
 | |
|     command('edit ' .. file1)
 | |
|     feed('llmamA')
 | |
|     feed('10j0') -- first col, last line
 | |
|     local pos = cursor()
 | |
|     feed('`a')
 | |
|     feed('<C-o>')
 | |
|     eq(pos, cursor())
 | |
|     feed('`A')
 | |
|     feed('<C-o>')
 | |
|     eq(pos, cursor())
 | |
|   end)
 | |
| 
 | |
|   it("leave a context mark when the mark changes buffer with g'", function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     local pos
 | |
|     feed('GmA')
 | |
|     command('next')
 | |
|     pos = cursor()
 | |
|     command('clearjumps')
 | |
|     feed("g'A") -- since the mark is in another buffer, it leaves a context mark
 | |
|     feed('<C-o>')
 | |
|     eq(pos, cursor())
 | |
|   end)
 | |
| 
 | |
|   it('leave a context mark when the mark changes buffer with g`', function()
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     local pos
 | |
|     feed('GmA')
 | |
|     command('next')
 | |
|     pos = cursor()
 | |
|     command('clearjumps')
 | |
|     feed('g`A') -- since the mark is in another buffer, it leaves a context mark
 | |
|     feed('<C-o>')
 | |
|     eq(pos, cursor())
 | |
|   end)
 | |
| 
 | |
|   it("do not leave a context mark when moving with g'", function()
 | |
|     command('edit ' .. file1)
 | |
|     local pos
 | |
|     feed('ma')
 | |
|     pos = cursor() -- Mark pos
 | |
|     feed('10j0') -- first col, last line
 | |
|     feed("g'a")
 | |
|     feed('<C-o>') -- should do nothing
 | |
|     eq(pos, cursor())
 | |
|     feed('mA')
 | |
|     pos = cursor() -- Mark pos
 | |
|     feed('10j0') -- first col, last line
 | |
|     feed("g'a")
 | |
|     feed('<C-o>') -- should do nothing
 | |
|     eq(pos, cursor())
 | |
|   end)
 | |
| 
 | |
|   it('do not leave a context mark when moving with g`', function()
 | |
|     command('edit ' .. file1)
 | |
|     local pos
 | |
|     feed('ma')
 | |
|     pos = cursor() -- Mark pos
 | |
|     feed('10j0') -- first col, last line
 | |
|     feed('g`a')
 | |
|     feed('<C-o>') -- should do nothing
 | |
|     eq(pos, cursor())
 | |
|     feed('mA')
 | |
|     pos = cursor() -- Mark pos
 | |
|     feed('10j0') -- first col, last line
 | |
|     feed("g'a")
 | |
|     feed('<C-o>') -- should do nothing
 | |
|     eq(pos, cursor())
 | |
|   end)
 | |
| 
 | |
|   it('open folds when moving to them', function()
 | |
|     command('edit ' .. file1)
 | |
|     feed('jzfG') -- Fold from the second line to the end
 | |
|     command('3mark a')
 | |
|     feed('G') -- On top of the fold
 | |
|     assert(fn.foldclosed('.') ~= -1) -- folded
 | |
|     feed("'a")
 | |
|     eq(-1, fn.foldclosed('.'))
 | |
| 
 | |
|     feed('zc')
 | |
|     assert(fn.foldclosed('.') ~= -1) -- folded
 | |
|     -- TODO: remove this workaround after fixing #15873
 | |
|     feed('k`a')
 | |
|     eq(-1, fn.foldclosed('.'))
 | |
| 
 | |
|     feed('zc')
 | |
|     assert(fn.foldclosed('.') ~= -1) -- folded
 | |
|     feed("kg'a")
 | |
|     eq(-1, fn.foldclosed('.'))
 | |
| 
 | |
|     feed('zc')
 | |
|     assert(fn.foldclosed('.') ~= -1) -- folded
 | |
|     feed('kg`a')
 | |
|     eq(-1, fn.foldclosed('.'))
 | |
|   end)
 | |
| 
 | |
|   it("do not open folds when moving to them doesn't move the cursor", function()
 | |
|     command('edit ' .. file1)
 | |
|     feed('jzfG') -- Fold from the second line to the end
 | |
|     assert(fn.foldclosed('.') == 2) -- folded
 | |
|     feed('ma')
 | |
|     feed("'a")
 | |
|     feed('`a')
 | |
|     feed("g'a")
 | |
|     feed('g`a')
 | |
|     -- should still be folded
 | |
|     eq(2, fn.foldclosed('.'))
 | |
|   end)
 | |
| 
 | |
|   it("getting '{ '} '( ') does not move cursor", function()
 | |
|     api.nvim_buf_set_lines(0, 0, 0, true, { 'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee' })
 | |
|     api.nvim_win_set_cursor(0, { 2, 0 })
 | |
|     fn.getpos("'{")
 | |
|     eq({ 2, 0 }, api.nvim_win_get_cursor(0))
 | |
|     fn.getpos("'}")
 | |
|     eq({ 2, 0 }, api.nvim_win_get_cursor(0))
 | |
|     fn.getpos("'(")
 | |
|     eq({ 2, 0 }, api.nvim_win_get_cursor(0))
 | |
|     fn.getpos("')")
 | |
|     eq({ 2, 0 }, api.nvim_win_get_cursor(0))
 | |
|   end)
 | |
| 
 | |
|   it('in command range does not move cursor #19248', function()
 | |
|     api.nvim_create_user_command('Test', ':', { range = true })
 | |
|     api.nvim_buf_set_lines(0, 0, 0, true, { 'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee' })
 | |
|     api.nvim_win_set_cursor(0, { 2, 0 })
 | |
|     command([['{,'}Test]])
 | |
|     eq({ 2, 0 }, api.nvim_win_get_cursor(0))
 | |
|   end)
 | |
| end)
 | |
| 
 | |
| describe('named marks view', function()
 | |
|   local file1 = 'Xtestfile-functional-editor-marks'
 | |
|   local file2 = 'Xtestfile-functional-editor-marks-2'
 | |
|   local function content()
 | |
|     local c = {}
 | |
|     for i = 1, 30 do
 | |
|       c[i] = i .. ' line'
 | |
|     end
 | |
|     return table.concat(c, '\n')
 | |
|   end
 | |
|   before_each(function()
 | |
|     clear()
 | |
|     write_file(file1, content(), false, false)
 | |
|     write_file(file2, content(), false, false)
 | |
|     command('set jumpoptions+=view')
 | |
|   end)
 | |
|   after_each(function()
 | |
|     os.remove(file1)
 | |
|     os.remove(file2)
 | |
|   end)
 | |
| 
 | |
|   it('is restored in normal mode but not op-pending mode', function()
 | |
|     local screen = Screen.new(5, 8)
 | |
|     command('edit ' .. file1)
 | |
|     feed('<C-e>jWma')
 | |
|     feed("G'a")
 | |
|     local expected = [[
 | |
|       2 line      |
 | |
|       ^3 line      |
 | |
|       4 line      |
 | |
|       5 line      |
 | |
|       6 line      |
 | |
|       7 line      |
 | |
|       8 line      |
 | |
|                   |
 | |
|       ]]
 | |
|     screen:expect({ grid = expected })
 | |
|     feed('G`a')
 | |
|     screen:expect([[
 | |
|       2 line      |
 | |
|       3 ^line      |
 | |
|       4 line      |
 | |
|       5 line      |
 | |
|       6 line      |
 | |
|       7 line      |
 | |
|       8 line      |
 | |
|                   |
 | |
|       ]])
 | |
|     -- not in op-pending mode #20886
 | |
|     feed('ggj=`a')
 | |
|     screen:expect([[
 | |
|       1 line      |
 | |
|       ^2 line      |
 | |
|       3 line      |
 | |
|       4 line      |
 | |
|       5 line      |
 | |
|       6 line      |
 | |
|       7 line      |
 | |
|                   |
 | |
|       ]])
 | |
|   end)
 | |
| 
 | |
|   it('is restored across files', function()
 | |
|     local screen = Screen.new(5, 5)
 | |
|     command('args ' .. file1 .. ' ' .. file2)
 | |
|     feed('<C-e>mA')
 | |
|     local mark_view = [[
 | |
|     ^2 line      |
 | |
|     3 line      |
 | |
|     4 line      |
 | |
|     5 line      |
 | |
|                 |
 | |
|     ]]
 | |
|     screen:expect(mark_view)
 | |
|     command('next')
 | |
|     screen:expect([[
 | |
|     ^1 line      |
 | |
|     2 line      |
 | |
|     3 line      |
 | |
|     4 line      |
 | |
|                 |
 | |
|     ]])
 | |
|     feed("'A")
 | |
|     screen:expect(mark_view)
 | |
|   end)
 | |
| 
 | |
|   it("fallback to standard behavior when view can't be recovered", function()
 | |
|     local screen = Screen.new(10, 10)
 | |
|     command('edit ' .. file1)
 | |
|     feed('7GzbmaG') -- Seven lines from the top
 | |
|     command('new') -- Screen size for window is now half the height can't be restored
 | |
|     feed("<C-w>p'a")
 | |
|     screen:expect([[
 | |
|                   |
 | |
|       {1:~           }|*3
 | |
|       {2:[No Name]   }|
 | |
|       6 line      |
 | |
|       ^7 line      |
 | |
|       8 line      |
 | |
|       {3:<itor-marks }|
 | |
|                   |
 | |
|       ]])
 | |
|   end)
 | |
| 
 | |
|   it('fallback to standard behavior when mark is loaded from shada', function()
 | |
|     local screen = Screen.new(10, 6)
 | |
|     command('edit ' .. file1)
 | |
|     feed('G')
 | |
|     feed('mA')
 | |
|     screen:expect([[
 | |
|       26 line     |
 | |
|       27 line     |
 | |
|       28 line     |
 | |
|       29 line     |
 | |
|       ^30 line     |
 | |
|                   |
 | |
|     ]])
 | |
|     command('set shadafile=Xtestfile-functional-editor-marks-shada')
 | |
|     finally(function()
 | |
|       command('set shadafile=NONE')
 | |
|       os.remove('Xtestfile-functional-editor-marks-shada')
 | |
|     end)
 | |
|     command('wshada!')
 | |
|     command('bwipe!')
 | |
|     screen:expect([[
 | |
|       ^            |
 | |
|       {1:~           }|*4
 | |
|                   |
 | |
|     ]])
 | |
|     command('rshada!')
 | |
|     command('edit ' .. file1)
 | |
|     feed('`"')
 | |
|     screen:expect([[
 | |
|       26 line     |
 | |
|       27 line     |
 | |
|       28 line     |
 | |
|       29 line     |
 | |
|       ^30 line     |
 | |
|                   |
 | |
|     ]])
 | |
|     feed('`A')
 | |
|     screen:expect_unchanged()
 | |
|   end)
 | |
| end)
 |