neovim/test/functional/normal/fold_spec.lua
Matthew Malcomson 263849b2dd fold: foldMoveRange(): fix :move bug #6534
Closes #6540

In #6221 there was a mistake in calculating which folds need to be
re-ordered. When there are no folds after those that have been adjusted,
then `move_end` remains 0. This results in reverse_fold_order()
swapping folds that have been adjusted with uninitialised folds in the
remainder of the grow array.

Add a check in foldMoveRange() to account for this case.
2017-04-17 04:45:55 +02:00

363 lines
6.4 KiB
Lua

local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local insert = helpers.insert
local feed = helpers.feed
local expect = helpers.expect
local feed_command = helpers.feed_command
local funcs = helpers.funcs
local foldlevel = funcs.foldlevel
local foldclosedend = funcs.foldclosedend
local eq = helpers.eq
describe('Folds', function()
local tempfname = 'Xtest-fold.txt'
clear()
before_each(function() feed_command('enew!') end)
after_each(function() os.remove(tempfname) end)
it('manual folding adjusts with filter', function()
insert([[
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20]])
feed_command('4,$fold', '%foldopen', '10,$fold', '%foldopen')
feed_command('1,8! cat')
feed('5ggzdzMGdd')
expect([[
1
2
3
4
5
6
7
8
9]])
end)
describe('adjusting folds after :move', function()
local function manually_fold_indent()
-- setting foldmethod twice is a trick to get vim to set the folds for me
feed_command('set foldmethod=indent', 'set foldmethod=manual')
-- Ensure that all folds will get closed (makes it easier to test the
-- length of folds).
feed_command('set foldminlines=0')
-- Start with all folds open (so :move ranges aren't affected by closed
-- folds).
feed_command('%foldopen!')
end
local function get_folds()
local rettab = {}
for i = 1, funcs.line('$') do
table.insert(rettab, foldlevel(i))
end
return rettab
end
local function test_move_indent(insert_string, move_command)
-- This test is easy because we just need to ensure that the resulting
-- fold is the same as calculated when creating folds from scratch.
insert(insert_string)
feed_command(move_command)
local after_move_folds = get_folds()
-- Doesn't change anything, but does call foldUpdateAll()
feed_command('set foldminlines=0')
eq(after_move_folds, get_folds())
-- Set up the buffer with insert_string for the manual fold testing.
feed_command('enew!')
insert(insert_string)
manually_fold_indent()
feed_command(move_command)
end
it('neither closes nor corrupts folds', function()
test_move_indent([[
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a]], '7,12m0')
expect([[
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a]])
-- lines are not closed, folds are correct
for i = 1,funcs.line('$') do
eq(-1, funcs.foldclosed(i))
if i == 1 or i == 7 or i == 13 then
eq(0, foldlevel(i))
elseif i == 4 then
eq(2, foldlevel(i))
else
eq(1, foldlevel(i))
end
end
-- folds are not corrupted
feed('zM')
eq(6, foldclosedend(2))
eq(12, foldclosedend(8))
eq(18, foldclosedend(14))
end)
it("doesn't split a fold when the move is within it", function()
test_move_indent([[
a
a
a
a
a
a
a
a
a
a]], '5m6')
eq({0, 1, 1, 2, 2, 2, 2, 1, 1, 0}, get_folds())
end)
it('truncates folds that end in the moved range', function()
test_move_indent([[
a
a
a
a
a
a
a]], '4,5m6')
eq({0, 1, 2, 0, 0, 0, 0}, get_folds())
end)
it('moves folds that start between moved range and destination', function()
test_move_indent([[
a
a
a
a
a
a
a
a
a
a
a
a
a]], '3,4m$')
eq({0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0}, get_folds())
end)
it('does not affect folds outside changed lines', function()
test_move_indent([[
a
a
a
a
a
a
a
a
a]], '4m5')
eq({1, 1, 1, 0, 0, 0, 1, 1, 1}, get_folds())
end)
it('moves and truncates folds that start in moved range', function()
test_move_indent([[
a
a
a
a
a
a
a
a
a
a]], '1,3m7')
eq({0, 0, 0, 0, 0, 1, 2, 0, 0, 0}, get_folds())
end)
it('breaks a fold when moving text into it', function()
test_move_indent([[
a
a
a
a
a
a
a]], '$m4')
eq({0, 1, 2, 2, 0, 0, 0}, get_folds())
end)
it('adjusts correctly when moving a range backwards', function()
test_move_indent([[
a
a
a
a
a]], '2,3m0')
eq({1, 2, 0, 0, 0}, get_folds())
end)
it('handles shifting all remaining folds', function()
test_move_indent([[
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a]], '13m7')
eq({1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0}, get_folds())
end)
end)
it('updates correctly on :read', function()
-- luacheck: ignore 621
helpers.write_file(tempfname, [[
a
a]])
insert([[
a
a
a
a
]])
feed_command('set foldmethod=indent', '2', '%foldopen')
feed_command('read ' .. tempfname)
-- Just to check we have the correct file text.
expect([[
a
a
a
a
a
a
]])
for i = 1,2 do
eq(1, funcs.foldlevel(i))
end
for i = 3,5 do
eq(0, funcs.foldlevel(i))
end
for i = 6,8 do
eq(1, funcs.foldlevel(i))
end
end)
it('combines folds when removing separating space', function()
-- luacheck: ignore 621
insert([[
a
a
a
a
a
a
a
a
]])
feed_command('set foldmethod=indent', '3,5d')
eq(5, funcs.foldclosedend(1))
end)
it("doesn't combine folds that have a specified end", function()
insert([[
{{{
}}}
{{{
}}}
]])
feed_command('set foldmethod=marker', '3,5d', '%foldclose')
eq(2, funcs.foldclosedend(1))
end)
it('splits folds according to >N and <N with foldexpr', function()
helpers.source([[
function TestFoldExpr(lnum)
let thisline = getline(a:lnum)
if thisline == 'a'
return 1
elseif thisline == 'b'
return 0
elseif thisline == 'c'
return '<1'
elseif thisline == 'd'
return '>1'
endif
return 0
endfunction
]])
helpers.write_file(tempfname, [[
b
b
a
a
d
a
a
c]])
insert([[
a
a
a
a
a
a
]])
feed_command('set foldmethod=expr', 'set foldexpr=TestFoldExpr(v:lnum)', '2', 'foldopen')
feed_command('read ' .. tempfname, '%foldclose')
eq(2, funcs.foldclosedend(1))
eq(0, funcs.foldlevel(3))
eq(0, funcs.foldlevel(4))
eq(6, funcs.foldclosedend(5))
eq(10, funcs.foldclosedend(7))
eq(14, funcs.foldclosedend(11))
end)
end)