xref: /vim-8.2.3635/src/testdir/test_fold.vim (revision 3fa5e64e)
1" Test for folding
2
3source check.vim
4source view_util.vim
5source screendump.vim
6
7func PrepIndent(arg)
8  return [a:arg] + repeat(["\t".a:arg], 5)
9endfu
10
11func Test_address_fold()
12  new
13  call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
14	      \ 'after fold 1', 'after fold 2', 'after fold 3'])
15  setl fen fdm=marker
16  " The next commands should all copy the same part of the buffer,
17  " regardless of the addressing type, since the part to be copied
18  " is folded away
19  :1y
20  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
21  :.y
22  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
23  :.+y
24  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
25  :.,.y
26  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
27  :sil .1,.y
28  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
29  " use silent to make E493 go away
30  :sil .+,.y
31  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
32  :,y
33  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
34  :,+y
35  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/','after fold 1'], getreg(0,1,1))
36  " using .+3 as second address should copy the whole folded line + the next 3
37  " lines
38  :.,+3y
39  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/',
40	      \ 'after fold 1', 'after fold 2', 'after fold 3'], getreg(0,1,1))
41  :sil .,-2y
42  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
43
44  " now test again with folding disabled
45  set nofoldenable
46  :1y
47  call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
48  :.y
49  call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
50  :.+y
51  call assert_equal(['1'], getreg(0,1,1))
52  :.,.y
53  call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
54  " use silent to make E493 go away
55  :sil .1,.y
56  call assert_equal(['int FuncName() {/*{{{*/', '1'], getreg(0,1,1))
57  " use silent to make E493 go away
58  :sil .+,.y
59  call assert_equal(['int FuncName() {/*{{{*/', '1'], getreg(0,1,1))
60  :,y
61  call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
62  :,+y
63  call assert_equal(['int FuncName() {/*{{{*/', '1'], getreg(0,1,1))
64  " using .+3 as second address should copy the whole folded line + the next 3
65  " lines
66  :.,+3y
67  call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3'], getreg(0,1,1))
68  :7
69  :sil .,-2y
70  call assert_equal(['4', '5', '}/*}}}*/'], getreg(0,1,1))
71
72  quit!
73endfunc
74
75func Test_indent_fold()
76    new
77    call setline(1, ['', 'a', '    b', '    c'])
78    setl fen fdm=indent
79    2
80    norm! >>
81    let a=map(range(1,4), 'foldclosed(v:val)')
82    call assert_equal([-1,-1,-1,-1], a)
83    bw!
84endfunc
85
86func Test_indent_fold2()
87    new
88    call setline(1, ['', '{{{', '}}}', '{{{', '}}}'])
89    setl fen fdm=marker
90    2
91    norm! >>
92    let a=map(range(1,5), 'v:val->foldclosed()')
93    call assert_equal([-1,-1,-1,4,4], a)
94    bw!
95endfunc
96
97" Test for fold indent with indents greater than 'foldnestmax'
98func Test_indent_fold_max()
99  new
100  setlocal foldmethod=indent
101  setlocal shiftwidth=2
102  " 'foldnestmax' default value is 20
103  call setline(1, "\t\t\t\t\t\ta")
104  call assert_equal(20, foldlevel(1))
105  setlocal foldnestmax=10
106  call assert_equal(10, foldlevel(1))
107  setlocal foldnestmax=-1
108  call assert_equal(0, foldlevel(1))
109  bw!
110endfunc
111
112func Test_manual_fold_with_filter()
113  CheckExecutable cat
114  for type in ['manual', 'marker']
115    exe 'set foldmethod=' . type
116    new
117    call setline(1, range(1, 20))
118    4,$fold
119    %foldopen
120    10,$fold
121    %foldopen
122    " This filter command should not have an effect
123    1,8! cat
124    call feedkeys('5ggzdzMGdd', 'xt')
125    call assert_equal(['1', '2', '3', '4', '5', '6', '7', '8', '9'], getline(1, '$'))
126
127    bwipe!
128    set foldmethod&
129  endfor
130endfunc
131
132func Test_indent_fold_with_read()
133  new
134  set foldmethod=indent
135  call setline(1, repeat(["\<Tab>a"], 4))
136  for n in range(1, 4)
137    call assert_equal(1, foldlevel(n))
138  endfor
139
140  call writefile(["a", "", "\<Tab>a"], 'Xfile')
141  foldopen
142  2read Xfile
143  %foldclose
144  call assert_equal(1, foldlevel(1))
145  call assert_equal(2, foldclosedend(1))
146  call assert_equal(0, foldlevel(3))
147  call assert_equal(0, foldlevel(4))
148  call assert_equal(1, foldlevel(5))
149  call assert_equal(7, 5->foldclosedend())
150
151  bwipe!
152  set foldmethod&
153  call delete('Xfile')
154endfunc
155
156func Test_combining_folds_indent()
157  new
158  let one = "\<Tab>a"
159  let zero = 'a'
160  call setline(1, [one, one, zero, zero, zero, one, one, one])
161  set foldmethod=indent
162  3,5d
163  %foldclose
164  call assert_equal(5, foldclosedend(1))
165
166  set foldmethod&
167  bwipe!
168endfunc
169
170func Test_combining_folds_marker()
171  new
172  call setline(1, ['{{{', '}}}', '', '', '', '{{{', '', '}}}'])
173  set foldmethod=marker
174  3,5d
175  %foldclose
176  call assert_equal(2, foldclosedend(1))
177
178  set foldmethod&
179  bwipe!
180endfunc
181
182func Test_folds_marker_in_comment()
183  new
184  call setline(1, ['" foo', 'bar', 'baz'])
185  setl fen fdm=marker
186  setl com=sO:\"\ -,mO:\"\ \ ,eO:\"\",:\" cms=\"%s
187  norm! zf2j
188  setl nofen
189  :1y
190  call assert_equal(['" foo{{{'], getreg(0,1,1))
191  :+2y
192  call assert_equal(['baz"}}}'], getreg(0,1,1))
193
194  set foldmethod&
195  bwipe!
196endfunc
197
198func s:TestFoldExpr(lnum)
199  let thisline = getline(a:lnum)
200  if thisline == 'a'
201    return 1
202  elseif thisline == 'b'
203    return 0
204  elseif thisline == 'c'
205    return '<1'
206  elseif thisline == 'd'
207    return '>1'
208  endif
209  return 0
210endfunction
211
212func Test_update_folds_expr_read()
213  new
214  call setline(1, ['a', 'a', 'a', 'a', 'a', 'a'])
215  set foldmethod=expr
216  set foldexpr=s:TestFoldExpr(v:lnum)
217  2
218  foldopen
219  call writefile(['b', 'b', 'a', 'a', 'd', 'a', 'a', 'c'], 'Xfile')
220  read Xfile
221  %foldclose
222  call assert_equal(2, foldclosedend(1))
223  call assert_equal(0, foldlevel(3))
224  call assert_equal(0, 4->foldlevel())
225  call assert_equal(6, foldclosedend(5))
226  call assert_equal(10, foldclosedend(7))
227  call assert_equal(14, foldclosedend(11))
228
229  call delete('Xfile')
230  bwipe!
231  set foldmethod& foldexpr&
232endfunc
233
234func Check_foldlevels(expected)
235  call assert_equal(a:expected, map(range(1, line('$')), 'foldlevel(v:val)'))
236endfunc
237
238func Test_move_folds_around_manual()
239  new
240  let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
241  call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
242  let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
243  " all folds closed
244  set foldenable foldlevel=0 fdm=indent
245  " needs a forced redraw
246  redraw!
247  set fdm=manual
248  call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
249  call assert_equal(input, getline(1, '$'))
250  7,12m0
251  call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
252  call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
253  10,12m0
254  call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] +  PrepIndent("c"), getline(1, '$'))
255  call assert_equal([1, 1, 1, 1, 1, -1, 7, 7, 7, 7, 7, -1, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
256  " moving should not close the folds
257  %d
258  call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
259  set fdm=indent
260  redraw!
261  set fdm=manual
262  call cursor(2, 1)
263  %foldopen
264  7,12m0
265  let folds=repeat([-1], 18)
266  call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
267  call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
268  norm! zM
269  " folds are not corrupted and all have been closed
270  call assert_equal([-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
271  %d
272  call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
273  set fdm=indent
274  redraw!
275  set fdm=manual
276  %foldopen
277  3m4
278  %foldclose
279  call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
280  call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
281  %d
282  call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
283  set fdm=indent foldlevel=0
284  set fdm=manual
285  %foldopen
286  3m1
287  %foldclose
288  call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
289  call assert_equal(0, foldlevel(2))
290  call assert_equal(5, foldclosedend(3))
291  call assert_equal([-1, -1, 3, 3, 3, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
292  2,6m$
293  %foldclose
294  call assert_equal(5, foldclosedend(2))
295  call assert_equal(0, foldlevel(6))
296  call assert_equal(9, foldclosedend(7))
297  call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
298
299  %d
300  " Ensure moving around the edges still works.
301  call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
302  set fdm=indent foldlevel=0
303  set fdm=manual
304  %foldopen
305  6m$
306  " The first fold has been truncated to the 5'th line.
307  " Second fold has been moved up because the moved line is now below it.
308  call Check_foldlevels([0, 1, 1, 1, 1, 0, 0, 0, 1, 0])
309
310  %delete
311  set fdm=indent foldlevel=0
312  call setline(1, [
313	\ "a",
314	\ "\ta",
315	\ "\t\ta",
316	\ "\t\ta",
317	\ "\t\ta",
318	\ "a",
319	\ "a"])
320  set fdm=manual
321  %foldopen!
322  4,5m6
323  call Check_foldlevels([0, 1, 2, 0, 0, 0, 0])
324
325  %delete
326  set fdm=indent
327  call setline(1, [
328	\ "\ta",
329	\ "\t\ta",
330	\ "\t\ta",
331	\ "\t\ta",
332	\ "\ta",
333	\ "\t\ta",
334	\ "\t\ta",
335	\ "\t\ta",
336	\ "\ta",
337	\ "\t\ta",
338	\ "\t\ta",
339	\ "\t\ta",
340	\ "\t\ta",
341	\ "\ta",
342	\ "a"])
343  set fdm=manual
344  %foldopen!
345  13m7
346  call Check_foldlevels([1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0])
347
348  bw!
349endfunc
350
351func Test_move_folds_around_indent()
352  new
353  let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
354  call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
355  let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
356  " all folds closed
357  set fdm=indent
358  call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
359  call assert_equal(input, getline(1, '$'))
360  7,12m0
361  call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
362  call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
363  10,12m0
364  call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] +  PrepIndent("c"), getline(1, '$'))
365  call assert_equal([1, 1, 1, 1, 1, -1, 7, 7, 7, 7, 7, -1, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
366  " moving should not close the folds
367  %d
368  call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
369  set fdm=indent
370  call cursor(2, 1)
371  %foldopen
372  7,12m0
373  let folds=repeat([-1], 18)
374  call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
375  call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
376  norm! zM
377  " folds are not corrupted and all have been closed
378  call assert_equal([-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
379  %d
380  call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
381  set fdm=indent
382  %foldopen
383  3m4
384  %foldclose
385  call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
386  call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
387  %d
388  call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
389  set fdm=indent foldlevel=0
390  %foldopen
391  3m1
392  %foldclose
393  call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
394  call assert_equal(1, foldlevel(2))
395  call assert_equal(5, foldclosedend(3))
396  call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
397  2,6m$
398  %foldclose
399  call assert_equal(9, foldclosedend(2))
400  call assert_equal(1, foldlevel(6))
401  call assert_equal(9, foldclosedend(7))
402  call assert_equal([-1, 2, 2, 2, 2, 2, 2, 2, 2, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
403  " Ensure moving around the edges still works.
404  %d
405  call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
406  set fdm=indent foldlevel=0
407  %foldopen
408  6m$
409  " The first fold has been truncated to the 5'th line.
410  " Second fold has been moved up because the moved line is now below it.
411  call Check_foldlevels([0, 1, 1, 1, 1, 0, 0, 0, 1, 1])
412  bw!
413endfunc
414
415func Test_folddoopen_folddoclosed()
416  new
417  call setline(1, range(1, 9))
418  set foldmethod=manual
419  1,3 fold
420  6,8 fold
421
422  " Test without range.
423  folddoopen   s/$/o/
424  folddoclosed s/$/c/
425  call assert_equal(['1c', '2c', '3c',
426  \                  '4o', '5o',
427  \                  '6c', '7c', '8c',
428  \                  '9o'], getline(1, '$'))
429
430  " Test with range.
431  call setline(1, range(1, 9))
432  1,8 folddoopen   s/$/o/
433  4,$ folddoclosed s/$/c/
434  call assert_equal(['1',  '2', '3',
435  \                  '4o', '5o',
436  \                  '6c', '7c', '8c',
437  \                  '9'], getline(1, '$'))
438
439  set foldmethod&
440  bw!
441endfunc
442
443func Test_fold_error()
444  new
445  call setline(1, [1, 2])
446
447  for fm in ['indent', 'expr', 'syntax', 'diff']
448    exe 'set foldmethod=' . fm
449    call assert_fails('norm zf', 'E350:')
450    call assert_fails('norm zd', 'E351:')
451    call assert_fails('norm zE', 'E352:')
452  endfor
453
454  set foldmethod=manual
455  call assert_fails('norm zd', 'E490:')
456  call assert_fails('norm zo', 'E490:')
457  call assert_fails('3fold',   'E16:')
458
459  set foldmethod=marker
460  set nomodifiable
461  call assert_fails('1,2fold', 'E21:')
462
463  set modifiable&
464  set foldmethod&
465  bw!
466endfunc
467
468func Test_foldtext_recursive()
469  new
470  call setline(1, ['{{{', 'some text', '}}}'])
471  setlocal foldenable foldmethod=marker foldtext=foldtextresult(v\:foldstart)
472  " This was crashing because of endless recursion.
473  2foldclose
474  redraw
475  call assert_equal(1, foldlevel(2))
476  call assert_equal(1, foldclosed(2))
477  call assert_equal(3, foldclosedend(2))
478  bwipe!
479endfunc
480
481" Various fold related tests
482
483" Basic test if a fold can be created, opened, moving to the end and closed
484func Test_fold_manual()
485  new
486  set fdm=manual
487
488  let content = ['1 aa', '2 bb', '3 cc']
489  call append(0, content)
490  call cursor(1, 1)
491  normal zf2j
492  call assert_equal('1 aa', getline(foldclosed('.')))
493  normal zo
494  call assert_equal(-1, foldclosed('.'))
495  normal ]z
496  call assert_equal('3 cc', getline('.'))
497  normal zc
498  call assert_equal('1 aa', getline(foldclosed('.')))
499
500  set fdm&
501  bw!
502endfunc
503
504" test folding with markers.
505func Test_fold_marker()
506  new
507  set fdm=marker fdl=1 fdc=3
508
509  let content = ['4 dd {{{', '5 ee {{{ }}}', '6 ff }}}']
510  call append(0, content)
511  call cursor(2, 1)
512  call assert_equal(2, foldlevel('.'))
513  normal [z
514  call assert_equal(1, foldlevel('.'))
515  exe "normal jo{{ \<Esc>r{jj"
516  call assert_equal(1, foldlevel('.'))
517  normal kYpj
518  call assert_equal(0, foldlevel('.'))
519
520  " Use only closing fold marker (without and with a count)
521  set fdl&
522  %d _
523  call setline(1, ['one }}}', 'two'])
524  call assert_equal([0, 0], [foldlevel(1), foldlevel(2)])
525  %d _
526  call setline(1, ['one }}}4', 'two'])
527  call assert_equal([4, 3], [foldlevel(1), foldlevel(2)])
528
529  set fdm& fdl& fdc&
530  bw!
531endfunc
532
533" test create fold markers with C filetype
534func Test_fold_create_marker_in_C()
535  bw!
536  set fdm=marker fdl=9
537  set filetype=c
538
539  let content =<< trim [CODE]
540    /*
541     * comment
542     *
543     *
544     */
545    int f(int* p) {
546        *p = 3;
547        return 0;
548    }
549  [CODE]
550
551  for c in range(len(content) - 1)
552    bw!
553    call append(0, content)
554    call cursor(c + 1, 1)
555    norm! zfG
556    call assert_equal(content[c] . (c < 4 ? '{{{' : '/*{{{*/'), getline(c + 1))
557  endfor
558
559  set fdm& fdl&
560  bw!
561endfunc
562
563" test folding with indent
564func Test_fold_indent()
565  new
566  set fdm=indent sw=2
567
568  let content = ['1 aa', '2 bb', '3 cc']
569  call append(0, content)
570  call cursor(2, 1)
571  exe "normal i  \<Esc>jI    "
572  call assert_equal(2, foldlevel('.'))
573  normal k
574  call assert_equal(1, foldlevel('.'))
575
576  set fdm& sw&
577  bw!
578endfunc
579
580" test syntax folding
581func Test_fold_syntax()
582  CheckFeature syntax
583
584  new
585  set fdm=syntax fdl=0
586
587  syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3
588  syn region Fd1 start="ee" end="ff" fold contained
589  syn region Fd2 start="gg" end="hh" fold contained
590  syn region Fd3 start="commentstart" end="commentend" fold contained
591  let content = ['3 cc', '4 dd {{{', '5 ee {{{ }}}', '{{{{', '6 ff }}}',
592	      \ '6 ff }}}', '7 gg', '8 hh', '9 ii']
593  call append(0, content)
594  normal Gzk
595  call assert_equal('9 ii', getline('.'))
596  normal k
597  call assert_equal('3 cc', getline('.'))
598  exe "normal jAcommentstart   \<Esc>Acommentend"
599  set fdl=1
600  normal 3j
601  call assert_equal('7 gg', getline('.'))
602  set fdl=0
603  exe "normal zO\<C-L>j"
604  call assert_equal('8 hh', getline('.'))
605  syn clear Fd1 Fd2 Fd3 Hup
606
607  set fdm& fdl&
608  bw!
609endfunc
610
611func Flvl()
612  let l = getline(v:lnum)
613  if l =~ "bb$"
614    return 2
615  elseif l =~ "gg$"
616    return "s1"
617  elseif l =~ "ii$"
618    return ">2"
619  elseif l =~ "kk$"
620    return "0"
621  endif
622  return "="
623endfun
624
625" test expression folding
626func Test_fold_expr()
627  new
628  set fdm=expr fde=Flvl()
629
630  let content = ['1 aa',
631	      \ '2 bb',
632	      \ '3 cc',
633	      \ '4 dd {{{commentstart  commentend',
634	      \ '5 ee {{{ }}}',
635	      \ '{{{',
636	      \ '6 ff }}}',
637	      \ '6 ff }}}',
638	      \ '  7 gg',
639	      \ '    8 hh',
640	      \ '9 ii',
641	      \ 'a jj',
642	      \ 'b kk']
643  call append(0, content)
644  call cursor(1, 1)
645  exe "normal /bb$\<CR>"
646  call assert_equal(2, foldlevel('.'))
647  exe "normal /hh$\<CR>"
648  call assert_equal(1, foldlevel('.'))
649  exe "normal /ii$\<CR>"
650  call assert_equal(2, foldlevel('.'))
651  exe "normal /kk$\<CR>"
652  call assert_equal(0, foldlevel('.'))
653
654  set fdm& fde&
655  bw!
656endfunc
657
658" Bug with fdm=indent and moving folds
659" Moving a fold a few times, messes up the folds below the moved fold.
660" Fixed by 7.4.700
661func Test_fold_move()
662  new
663  set fdm=indent sw=2 fdl=0
664
665  let content = ['', '', 'Line1', '  Line2', '  Line3',
666	      \ 'Line4', '  Line5', '  Line6',
667	      \ 'Line7', '  Line8', '  Line9']
668  call append(0, content)
669  normal zM
670  call cursor(4, 1)
671  move 2
672  move 1
673  call assert_equal(7, foldclosed(7))
674  call assert_equal(8, foldclosedend(7))
675  call assert_equal(0, foldlevel(9))
676  call assert_equal(10, foldclosed(10))
677  call assert_equal(11, foldclosedend(10))
678  call assert_equal('+--  2 lines: Line2', foldtextresult(2))
679  call assert_equal('+--  2 lines: Line8', 10->foldtextresult())
680
681  set fdm& sw& fdl&
682  bw!
683endfunc
684
685" test for patch 7.3.637
686" Cannot catch the error caused by a foldopen when there is no fold.
687func Test_foldopen_exception()
688  new
689  let a = 'No error caught'
690  try
691    foldopen
692  catch
693    let a = matchstr(v:exception,'^[^ ]*')
694  endtry
695  call assert_equal('Vim(foldopen):E490:', a)
696
697  let a = 'No error caught'
698  try
699    foobar
700  catch
701    let a = matchstr(v:exception,'^[^ ]*')
702  endtry
703  call assert_match('E492:', a)
704  bw!
705endfunc
706
707func Test_fold_last_line_with_pagedown()
708  new
709  set fdm=manual
710
711  let expect = '+-- 11 lines: 9---'
712  let content = range(1,19)
713  call append(0, content)
714  normal dd9G
715  normal zfG
716  normal zt
717  call assert_equal('9', getline(foldclosed('.')))
718  call assert_equal('19', getline(foldclosedend('.')))
719  call assert_equal(expect, ScreenLines(1, len(expect))[0])
720  call feedkeys("\<C-F>", 'xt')
721  call assert_equal(expect, ScreenLines(1, len(expect))[0])
722  call feedkeys("\<C-F>", 'xt')
723  call assert_equal(expect, ScreenLines(1, len(expect))[0])
724  call feedkeys("\<C-B>\<C-F>\<C-F>", 'xt')
725  call assert_equal(expect, ScreenLines(1, len(expect))[0])
726
727  set fdm&
728  bw!
729endfunc
730
731func Test_folds_with_rnu()
732  CheckScreendump
733
734  call writefile([
735	\ 'set fdm=marker rnu foldcolumn=2',
736	\ 'call setline(1, ["{{{1", "nline 1", "{{{1", "line 2"])',
737	\ ], 'Xtest_folds_with_rnu')
738  let buf = RunVimInTerminal('-S Xtest_folds_with_rnu', {})
739
740  call VerifyScreenDump(buf, 'Test_folds_with_rnu_01', {})
741  call term_sendkeys(buf, "j")
742  call VerifyScreenDump(buf, 'Test_folds_with_rnu_02', {})
743
744  " clean up
745  call StopVimInTerminal(buf)
746  call delete('Xtest_folds_with_rnu')
747endfunc
748
749func Test_folds_marker_in_comment2()
750  new
751  call setline(1, ['Lorem ipsum dolor sit', 'Lorem ipsum dolor sit', 'Lorem ipsum dolor sit'])
752  setl fen fdm=marker
753  setl commentstring=<!--%s-->
754  setl comments=s:<!--,m:\ \ \ \ ,e:-->
755  norm! zf2j
756  setl nofen
757  :1y
758  call assert_equal(['Lorem ipsum dolor sit<!--{{{-->'], getreg(0,1,1))
759  :+2y
760  call assert_equal(['Lorem ipsum dolor sit<!--}}}-->'], getreg(0,1,1))
761
762  set foldmethod&
763  bwipe!
764endfunc
765
766func Test_fold_delete_with_marker()
767  new
768  call setline(1, ['func Func() {{{1', 'endfunc'])
769  1,2yank
770  new
771  set fdm=marker
772  call setline(1, 'x')
773  normal! Vp
774  normal! zd
775  call assert_equal(['func Func() ', 'endfunc'], getline(1, '$'))
776
777  set fdm&
778  bwipe!
779  bwipe!
780endfunc
781
782func Test_fold_delete_with_marker_and_whichwrap()
783  new
784  let content1 = ['']
785  let content2 = ['folded line 1 "{{{1', '  test', '  test2', '  test3', '', 'folded line 2 "{{{1', '  test', '  test2', '  test3']
786  call setline(1, content1 + content2)
787  set fdm=marker ww+=l
788  normal! x
789  call assert_equal(content2, getline(1, '$'))
790  set fdm& ww&
791  bwipe!
792endfunc
793
794func Test_fold_delete_first_line()
795  new
796  call setline(1, [
797	\ '" x {{{1',
798	\ '" a',
799	\ '" aa',
800	\ '" x {{{1',
801	\ '" b',
802	\ '" bb',
803	\ '" x {{{1',
804	\ '" c',
805	\ '" cc',
806	\ ])
807  set foldmethod=marker
808  1
809  normal dj
810  call assert_equal([
811	\ '" x {{{1',
812	\ '" c',
813	\ '" cc',
814	\ ], getline(1,'$'))
815  bwipe!
816  set foldmethod&
817endfunc
818
819" Test for errors in 'foldexpr'
820func Test_fold_expr_error()
821  new
822  call setline(1, ['one', 'two', 'three'])
823  " In a window with no folds, foldlevel() should return 0
824  call assert_equal(0, foldlevel(1))
825
826  " Return a list from the expression
827  set foldexpr=[]
828  set foldmethod=expr
829  for i in range(3)
830    call assert_equal(0, foldlevel(i))
831  endfor
832
833  " expression error
834  set foldexpr=[{]
835  set foldmethod=expr
836  for i in range(3)
837    call assert_equal(0, foldlevel(i))
838  endfor
839
840  set foldmethod& foldexpr&
841  close!
842endfunc
843
844func Test_undo_fold_deletion()
845  new
846  set fdm=marker
847  let lines =<< trim END
848      " {{{
849      " }}}1
850      " {{{
851  END
852  call setline(1, lines)
853  3d
854  g/"/d
855  undo
856  redo
857  eval getline(1, '$')->assert_equal([''])
858
859  set fdm&vim
860  bwipe!
861endfunc
862
863" this was crashing
864func Test_move_no_folds()
865  new
866  fold
867  setlocal fdm=expr
868  normal zj
869  bwipe!
870endfunc
871
872" this was crashing
873func Test_fold_create_delete_create()
874  new
875  fold
876  fold
877  normal zd
878  fold
879  bwipe!
880endfunc
881
882" this was crashing
883func Test_fold_create_delete()
884  new
885  norm zFzFzdzj
886  bwipe!
887endfunc
888
889func Test_fold_relative_move()
890  new
891  set fdm=indent sw=2 wrap tw=80
892
893  let content = [ '  foo', '  bar', '  baz',
894              \   repeat('x', &columns + 1),
895              \   '  foo', '  bar', '  baz'
896              \ ]
897  call append(0, content)
898
899  normal zM
900
901  call cursor(3, 1)
902  call assert_true(foldclosed(line('.')))
903  normal gj
904  call assert_equal(2, winline())
905
906  call cursor(2, 1)
907  call assert_true(foldclosed(line('.')))
908  normal 2gj
909  call assert_equal(3, winline())
910
911  call cursor(5, 1)
912  call assert_true(foldclosed(line('.')))
913  normal gk
914  call assert_equal(3, winline())
915
916  call cursor(6, 1)
917  call assert_true(foldclosed(line('.')))
918  normal 2gk
919  call assert_equal(2, winline())
920
921  set fdm& sw& wrap& tw&
922  bw!
923endfunc
924
925" Test for using multibyte characters as 'foldopen', 'foldclose' and
926" 'foldsetp' items in 'fillchars'
927func s:mbyte_fillchar_tests(fo, fc, fs)
928  setlocal foldcolumn=3
929
930  normal zE
931  1,2fold
932  call assert_equal([a:fc .. '  +--  2 ', '   three  '],
933        \ ScreenLines([1, 2], 10))
934  1,2foldopen
935  call assert_equal([a:fo .. '  one ', a:fs .. '  two '],
936        \ ScreenLines([1, 2], 7))
937  1,2foldclose
938  redraw!
939  call assert_equal([a:fc .. '  +--  2 ', '   three  '],
940        \  ScreenLines([1, 2], 10))
941
942  " Two level fold
943  normal zE
944  2,3fold
945  1,4fold
946  call assert_equal([a:fc .. '  +--  4 ', '   five   '],
947        \ ScreenLines([1, 2], 10))
948  1,4foldopen
949  call assert_equal([a:fo .. '  one    ', a:fs .. a:fc .. ' +---  2'],
950        \ ScreenLines([1, 2], 10))
951  1,4foldopen
952  call assert_equal([a:fo .. '  one    ', a:fs .. a:fo .. ' two    ',
953        \ a:fs .. a:fs .. ' three  '], ScreenLines([1, 3], 10))
954  2,3foldclose
955  call assert_equal([a:fo .. '  one    ', a:fs .. a:fc .. ' +---  2'],
956        \ ScreenLines([1, 2], 10))
957  1,4foldclose
958  call assert_equal([a:fc .. '  +--  4 ', '   five   '],
959        \ ScreenLines([1, 2], 10))
960
961  " Three level fold
962  normal zE
963  3,4fold
964  2,5fold
965  1,6fold
966  call assert_equal([a:fc .. '  +--  6 '], ScreenLines(1, 10))
967  " open all the folds
968  normal zR
969  call assert_equal([
970        \ a:fo .. '  one    ',
971        \ a:fs .. a:fo .. ' two    ',
972        \ '2' .. a:fo .. ' three  ',
973        \ '23 four   ',
974        \ a:fs .. a:fs .. ' five   ',
975        \ a:fs .. '  six    ',
976        \ ], ScreenLines([1, 6], 10))
977  " close the innermost fold
978  3,4foldclose
979  call assert_equal([
980        \ a:fo .. '  one    ',
981        \ a:fs .. a:fo .. ' two    ',
982        \ a:fs .. a:fs .. a:fc .. '+----  ',
983        \ a:fs .. a:fs .. ' five   ',
984        \ a:fs .. '  six    ',
985        \ ], ScreenLines([1, 5], 10))
986  " close the next fold
987  2,5foldclose
988  call assert_equal([
989        \ a:fo .. '  one    ',
990        \ a:fs .. a:fc .. ' +---  4',
991        \ a:fs .. '  six    ',
992        \ ], ScreenLines([1, 3], 10))
993
994  " set the fold column size to 2
995  setlocal fdc=2
996  normal zR
997  call assert_equal([
998        \ a:fo .. ' one  ',
999        \ a:fo .. ' two  ',
1000        \ a:fo .. ' three',
1001        \ '3 four ',
1002        \ '2 five ',
1003        \ a:fs .. ' six  ',
1004        \ ], ScreenLines([1, 6], 7))
1005
1006  " set the fold column size to 1
1007  setlocal fdc=1
1008  normal zR
1009  call assert_equal([
1010        \ a:fo .. 'one   ',
1011        \ a:fo .. 'two   ',
1012        \ a:fo .. 'three ',
1013        \ '3four  ',
1014        \ '2five  ',
1015        \ a:fs .. 'six   ',
1016        \ ], ScreenLines([1, 6], 7))
1017
1018  " Enable number and sign columns and place some signs
1019  setlocal fdc=3
1020  setlocal number
1021  setlocal signcolumn=auto
1022  sign define S1 text=->
1023  sign place 10 line=3 name=S1
1024  call assert_equal([
1025        \ a:fo .. '      1 one  ',
1026        \ a:fs .. a:fo .. '     2 two  ',
1027        \ '2' .. a:fo .. ' ->  3 three',
1028        \ '23     4 four ',
1029        \ a:fs .. a:fs .. '     5 five ',
1030        \ a:fs .. '      6 six  '
1031        \ ], ScreenLines([1, 6], 14))
1032
1033  " Test with 'rightleft'
1034  if has('rightleft')
1035    setlocal rightleft
1036    let lines = ScreenLines([1, 6], winwidth(0))
1037    call assert_equal('o 1      ' .. a:fo,
1038          \  strcharpart(lines[0], strchars(lines[0]) - 10, 10))
1039    call assert_equal('t 2     ' .. a:fo .. a:fs,
1040          \  strcharpart(lines[1], strchars(lines[1]) - 10, 10))
1041    call assert_equal('t 3  >- ' .. a:fo .. '2',
1042          \  strcharpart(lines[2], strchars(lines[2]) - 10, 10))
1043    call assert_equal('f 4     32',
1044          \  strcharpart(lines[3], strchars(lines[3]) - 10, 10))
1045    call assert_equal('f 5     ' .. a:fs .. a:fs,
1046          \  strcharpart(lines[4], strchars(lines[4]) - 10, 10))
1047    call assert_equal('s 6      ' .. a:fs,
1048          \  strcharpart(lines[5], strchars(lines[5]) - 10, 10))
1049    setlocal norightleft
1050  endif
1051
1052  sign unplace *
1053  sign undefine S1
1054  setlocal number& signcolumn&
1055
1056  " Add a test with more than 9 folds (and then delete some folds)
1057  normal zE
1058  for i in range(1, 10)
1059    normal zfGzo
1060  endfor
1061  normal zR
1062  call assert_equal([
1063        \ a:fo .. a:fo .. ' one ',
1064        \ '9> two '
1065        \ ], ScreenLines([1, 2], 7))
1066  normal 1Gzd
1067  call assert_equal([
1068        \ a:fo .. a:fo .. ' one ',
1069        \ '89 two '
1070        \ ], ScreenLines([1, 2], 7))
1071  normal 1Gzdzdzdzdzdzdzd
1072  call assert_equal([
1073        \ a:fo .. a:fo .. ' one ',
1074        \ a:fs .. a:fs .. ' two '
1075        \ ], ScreenLines([1, 2], 7))
1076
1077  setlocal foldcolumn& number& signcolumn&
1078endfunc
1079
1080func Test_foldcolumn_multibyte_char()
1081  new
1082  call setline(1, ['one', 'two', 'three', 'four', 'five', 'six'])
1083  setlocal foldenable foldmethod=manual
1084
1085  " First test with the default setting
1086  call s:mbyte_fillchar_tests('-', '+', '|')
1087
1088  " Use multi-byte characters
1089  set fillchars+=foldopen:▾,foldsep:│,foldclose:▸
1090  call s:mbyte_fillchar_tests('▾', '▸', '│')
1091
1092  " Use a mix of multi-byte and single-byte characters
1093  set fillchars+=foldopen:¬,foldsep:\|,foldclose:+
1094  call s:mbyte_fillchar_tests('¬', '+', '|')
1095  set fillchars+=foldopen:+,foldsep:\|,foldclose:¬
1096  call s:mbyte_fillchar_tests('+', '¬', '|')
1097
1098  bw!
1099  set foldenable& fdc& fdm& fillchars&
1100endfunc
1101
1102" Test for calling foldlevel() from a fold expression
1103let g:FoldLevels = []
1104func FoldExpr1(lnum)
1105  let f = [a:lnum]
1106  for i in range(1, line('$'))
1107    call add(f, foldlevel(i))
1108  endfor
1109  call add(g:FoldLevels, f)
1110  return getline(a:lnum)[0] == "\t"
1111endfunc
1112
1113func Test_foldexpr_foldlevel()
1114  new
1115  call setline(1, ['one', "\ttwo", "\tthree"])
1116  setlocal foldmethod=expr
1117  setlocal foldexpr=FoldExpr1(v:lnum)
1118  setlocal foldenable
1119  setlocal foldcolumn=3
1120  redraw!
1121  call assert_equal([[1, -1, -1, -1], [2, -1, -1, -1], [3, 0, 1, -1]],
1122        \ g:FoldLevels)
1123  set foldmethod& foldexpr& foldenable& foldcolumn&
1124  bw!
1125endfunc
1126
1127" Test for returning different values from a fold expression
1128func FoldExpr2(lnum)
1129  if a:lnum == 1 || a:lnum == 4
1130    return -2
1131  elseif a:lnum == 2
1132    return 'a1'
1133  elseif a:lnum == 3
1134    return 's4'
1135  endif
1136  return '='
1137endfunc
1138
1139func Test_foldexpr_2()
1140  new
1141  call setline(1, ['one', 'two', 'three', 'four'])
1142  setlocal foldexpr=FoldExpr2(v:lnum)
1143  setlocal foldmethod=expr
1144  call assert_equal([0, 1, 1, 0], [foldlevel(1), foldlevel(2), foldlevel(3),
1145        \ foldlevel(4)])
1146  bw!
1147endfunc
1148
1149" Test for the 'foldclose' option
1150func Test_foldclose_opt()
1151  CheckScreendump
1152
1153  let lines =<< trim END
1154    set foldmethod=manual foldclose=all foldopen=all
1155    call setline(1, ['one', 'two', 'three', 'four'])
1156    2,3fold
1157    func XsaveFoldLevels()
1158      redraw!
1159      call writefile([json_encode([foldclosed(1), foldclosed(2), foldclosed(3),
1160        \ foldclosed(4)])], 'Xoutput', 'a')
1161    endfunc
1162  END
1163  call writefile(lines, 'Xscript')
1164  let rows = 10
1165  let buf = RunVimInTerminal('-S Xscript', {'rows': rows})
1166  call term_wait(buf)
1167  call term_sendkeys(buf, ":set noruler\n")
1168  call term_wait(buf)
1169  call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1170  call term_sendkeys(buf, "2G")
1171  call WaitForAssert({-> assert_equal('two', term_getline(buf, 2))})
1172  call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1173  call term_sendkeys(buf, "4G")
1174  call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
1175  call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1176  call term_sendkeys(buf, "3G")
1177  call WaitForAssert({-> assert_equal('three', term_getline(buf, 3))})
1178  call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1179  call term_sendkeys(buf, "1G")
1180  call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
1181  call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1182
1183  " clean up
1184  call StopVimInTerminal(buf)
1185
1186  call assert_equal(['[-1,2,2,-1]', '[-1,-1,-1,-1]', '[-1,2,2,-1]',
1187        \ '[-1,-1,-1,-1]', '[-1,2,2,-1]'], readfile('Xoutput'))
1188  call delete('Xscript')
1189  call delete('Xoutput')
1190endfunc
1191
1192" Test for foldtextresult()
1193func Test_foldtextresult()
1194  new
1195  call assert_equal('', foldtextresult(-1))
1196  call assert_equal('', foldtextresult(0))
1197  call assert_equal('', foldtextresult(1))
1198  call setline(1, ['one', 'two', 'three', 'four'])
1199  2,3fold
1200  call assert_equal('', foldtextresult(1))
1201  call assert_equal('+--  2 lines: two', foldtextresult(2))
1202  setlocal foldtext=
1203  call assert_equal('+--  2 lines folded ', foldtextresult(2))
1204
1205  " Fold text for a C comment fold
1206  %d _
1207  setlocal foldtext&
1208  call setline(1, ['', '/*', ' * Comment', ' */', ''])
1209  2,4fold
1210  call assert_equal('+--  3 lines: Comment', foldtextresult(2))
1211
1212  bw!
1213endfunc
1214
1215" Test for merging two recursive folds when an intermediate line with no fold
1216" is removed
1217func Test_fold_merge_recrusive()
1218  new
1219  call setline(1, ['  one', '    two', 'xxxx', '    three',
1220        \ '      four', "\tfive"])
1221  setlocal foldmethod=indent shiftwidth=2
1222  3d_
1223  %foldclose
1224  call assert_equal([1, 5], [foldclosed(5), foldclosedend(1)])
1225  bw!
1226endfunc
1227
1228" Test for moving a line which is the start of a fold from a recursive fold to
1229" outside. The fold length should reduce.
1230func Test_fold_move_foldlevel()
1231  new
1232  call setline(1, ['a{{{', 'b{{{', 'c{{{', 'd}}}', 'e}}}', 'f}}}', 'g'])
1233  setlocal foldmethod=marker
1234  normal zR
1235  call assert_equal([3, 2, 1], [foldlevel(4), foldlevel(5), foldlevel(6)])
1236  3move 7
1237  call assert_equal([2, 1, 0], [foldlevel(3), foldlevel(4), foldlevel(5)])
1238  call assert_equal(1, foldlevel(7))
1239
1240  " Move a line from outside a fold to inside the fold.
1241  %d _
1242  call setline(1, ['a', 'b{{{', 'c}}}'])
1243  normal zR
1244  1move 2
1245  call assert_equal([1, 1, 1], [foldlevel(1), foldlevel(2), foldlevel(3)])
1246
1247  " Move the start of one fold to inside another fold
1248  %d _
1249  call setline(1, ['a', 'b{{{', 'c}}}', 'd{{{', 'e}}}'])
1250  normal zR
1251  call assert_equal([0, 1, 1, 1, 1], [foldlevel(1), foldlevel(2),
1252        \ foldlevel(3), foldlevel(4), foldlevel(5)])
1253  1,2move 4
1254  call assert_equal([0, 1, 1, 2, 2], [foldlevel(1), foldlevel(2),
1255        \ foldlevel(3), foldlevel(4), foldlevel(5)])
1256
1257  bw!
1258endfunc
1259
1260" vim: shiftwidth=2 sts=2 expandtab
1261