1local helpers = require('test.functional.helpers')(after_each)
2
3local clear = helpers.clear
4local insert = helpers.insert
5local feed = helpers.feed
6local expect = helpers.expect
7local feed_command = helpers.feed_command
8local funcs = helpers.funcs
9local foldlevel = funcs.foldlevel
10local foldclosedend = funcs.foldclosedend
11local eq = helpers.eq
12
13describe('Folds', function()
14  local tempfname = 'Xtest-fold.txt'
15  clear()
16  before_each(function() feed_command('enew!') end)
17  after_each(function() os.remove(tempfname) end)
18  it('manual folding adjusts with filter', function()
19    insert([[
20    1
21    2
22    3
23    4
24    5
25    6
26    7
27    8
28    9
29    10
30    11
31    12
32    13
33    14
34    15
35    16
36    17
37    18
38    19
39    20]])
40    feed_command('4,$fold', '%foldopen', '10,$fold', '%foldopen')
41    feed_command('1,8! cat')
42    feed('5ggzdzMGdd')
43    expect([[
44    1
45    2
46    3
47    4
48    5
49    6
50    7
51    8
52    9]])
53  end)
54  describe('adjusting folds after :move', function()
55    local function manually_fold_indent()
56      -- setting foldmethod twice is a trick to get vim to set the folds for me
57      feed_command('set foldmethod=indent', 'set foldmethod=manual')
58      -- Ensure that all folds will get closed (makes it easier to test the
59      -- length of folds).
60      feed_command('set foldminlines=0')
61      -- Start with all folds open (so :move ranges aren't affected by closed
62      -- folds).
63      feed_command('%foldopen!')
64    end
65
66    local function get_folds()
67      local rettab = {}
68      for i = 1, funcs.line('$') do
69        table.insert(rettab, foldlevel(i))
70      end
71      return rettab
72    end
73
74    local function test_move_indent(insert_string, move_command)
75      -- This test is easy because we just need to ensure that the resulting
76      -- fold is the same as calculated when creating folds from scratch.
77      insert(insert_string)
78      feed_command(move_command)
79      local after_move_folds = get_folds()
80      -- Doesn't change anything, but does call foldUpdateAll()
81      feed_command('set foldminlines=0')
82      eq(after_move_folds, get_folds())
83      -- Set up the buffer with insert_string for the manual fold testing.
84      feed_command('enew!')
85      insert(insert_string)
86      manually_fold_indent()
87      feed_command(move_command)
88    end
89
90    it('neither closes nor corrupts folds', function()
91      test_move_indent([[
92a
93	a
94	a
95	a
96	a
97	a
98a
99	a
100	a
101		a
102	a
103	a
104a
105	a
106	a
107	a
108	a
109	a]], '7,12m0')
110      expect([[
111a
112	a
113	a
114		a
115	a
116	a
117a
118	a
119	a
120	a
121	a
122	a
123a
124	a
125	a
126	a
127	a
128	a]])
129      -- lines are not closed, folds are correct
130      for i = 1,funcs.line('$') do
131        eq(-1, funcs.foldclosed(i))
132        if i == 1 or i == 7 or i == 13 then
133          eq(0, foldlevel(i))
134        elseif i == 4 then
135          eq(2, foldlevel(i))
136        else
137          eq(1, foldlevel(i))
138        end
139      end
140      -- folds are not corrupted
141      feed('zM')
142      eq(6, foldclosedend(2))
143      eq(12, foldclosedend(8))
144      eq(18, foldclosedend(14))
145    end)
146    it("doesn't split a fold when the move is within it", function()
147      test_move_indent([[
148a
149	a
150	a
151		a
152		a
153		a
154		a
155	a
156	a
157a]], '5m6')
158      eq({0, 1, 1, 2, 2, 2, 2, 1, 1, 0}, get_folds())
159    end)
160    it('truncates folds that end in the moved range', function()
161      test_move_indent([[
162a
163	a
164		a
165		a
166		a
167a
168a]], '4,5m6')
169      eq({0, 1, 2, 0, 0, 0, 0}, get_folds())
170    end)
171    it('moves folds that start between moved range and destination', function()
172      test_move_indent([[
173a
174	a
175	a
176	a
177	a
178a
179a
180	a
181		a
182	a
183a
184a
185	a]], '3,4m$')
186      eq({0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0}, get_folds())
187    end)
188    it('does not affect folds outside changed lines', function()
189      test_move_indent([[
190	a
191	a
192	a
193a
194a
195a
196	a
197	a
198	a]], '4m5')
199      eq({1, 1, 1, 0, 0, 0, 1, 1, 1}, get_folds())
200    end)
201    it('moves and truncates folds that start in moved range', function()
202      test_move_indent([[
203a
204	a
205		a
206		a
207		a
208a
209a
210a
211a
212a]], '1,3m7')
213      eq({0, 0, 0, 0, 0, 1, 2, 0, 0, 0}, get_folds())
214    end)
215    it('breaks a fold when moving text into it', function()
216      test_move_indent([[
217a
218	a
219		a
220		a
221		a
222a
223a]], '$m4')
224      eq({0, 1, 2, 2, 0, 0, 0}, get_folds())
225    end)
226    it('adjusts correctly when moving a range backwards', function()
227      test_move_indent([[
228a
229	a
230		a
231		a
232a]], '2,3m0')
233      eq({1, 2, 0, 0, 0}, get_folds())
234    end)
235    it('handles shifting all remaining folds', function()
236      test_move_indent([[
237	a
238		a
239		a
240		a
241	a
242		a
243		a
244		a
245	a
246		a
247		a
248		a
249		a
250	a
251a]], '13m7')
252      eq({1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0}, get_folds())
253    end)
254  end)
255  it('updates correctly on :read', function()
256    -- luacheck: ignore 621
257    helpers.write_file(tempfname, [[
258    a
259
260
261    	a]])
262    insert([[
263    	a
264    	a
265    	a
266    	a
267    ]])
268    feed_command('set foldmethod=indent', '2', '%foldopen')
269    feed_command('read ' .. tempfname)
270    -- Just to check we have the correct file text.
271    expect([[
272    	a
273    	a
274    a
275
276
277    	a
278    	a
279    	a
280    ]])
281    for i = 1,2 do
282      eq(1, funcs.foldlevel(i))
283    end
284    for i = 3,5 do
285      eq(0, funcs.foldlevel(i))
286    end
287    for i = 6,8 do
288      eq(1, funcs.foldlevel(i))
289    end
290  end)
291  it('combines folds when removing separating space', function()
292    -- luacheck: ignore 621
293    insert([[
294    	a
295    	a
296    a
297    a
298    a
299    	a
300    	a
301    	a
302    ]])
303    feed_command('set foldmethod=indent', '3,5d')
304    eq(5, funcs.foldclosedend(1))
305  end)
306  it("doesn't combine folds that have a specified end", function()
307    insert([[
308    {{{
309    }}}
310
311
312
313    {{{
314
315    }}}
316    ]])
317    feed_command('set foldmethod=marker', '3,5d', '%foldclose')
318    eq(2, funcs.foldclosedend(1))
319  end)
320  it('splits folds according to >N and <N with foldexpr', function()
321    helpers.source([[
322    function TestFoldExpr(lnum)
323      let thisline = getline(a:lnum)
324      if thisline == 'a'
325        return 1
326      elseif thisline == 'b'
327        return 0
328      elseif thisline == 'c'
329        return '<1'
330      elseif thisline == 'd'
331        return '>1'
332      endif
333      return 0
334    endfunction
335    ]])
336    helpers.write_file(tempfname, [[
337    b
338    b
339    a
340    a
341    d
342    a
343    a
344    c]])
345    insert([[
346    a
347    a
348    a
349    a
350    a
351    a
352    ]])
353    feed_command('set foldmethod=expr', 'set foldexpr=TestFoldExpr(v:lnum)', '2', 'foldopen')
354    feed_command('read ' .. tempfname, '%foldclose')
355    eq(2, funcs.foldclosedend(1))
356    eq(0, funcs.foldlevel(3))
357    eq(0, funcs.foldlevel(4))
358    eq(6, funcs.foldclosedend(5))
359    eq(10, funcs.foldclosedend(7))
360    eq(14, funcs.foldclosedend(11))
361  end)
362end)
363