blob: 9b8cd7310d01afe394a6bf18859b7b71b042a8fc [file] [log] [blame]
Bram Moolenaarded27822017-01-02 14:27:34 +01001" Test for folding
2
Bram Moolenaar8c5a2782019-08-07 23:07:07 +02003source check.vim
Bram Moolenaar907dad72018-07-10 15:07:15 +02004source view_util.vim
Bram Moolenaar7701f302018-10-02 21:20:32 +02005source screendump.vim
Bram Moolenaar907dad72018-07-10 15:07:15 +02006
Bram Moolenaar94be6192017-04-22 22:40:11 +02007func PrepIndent(arg)
Bram Moolenaar88d298a2017-03-14 21:53:58 +01008 return [a:arg] + repeat(["\t".a:arg], 5)
9endfu
10
Bram Moolenaar94be6192017-04-22 22:40:11 +020011func Test_address_fold()
Bram Moolenaarded27822017-01-02 14:27:34 +010012 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
Bram Moolenaar518c9b12017-03-21 11:48:39 +010016 " The next commands should all copy the same part of the buffer,
17 " regardless of the addressing type, since the part to be copied
Bram Moolenaarded27822017-01-02 14:27:34 +010018 " 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!
Bram Moolenaar1159b162017-02-28 21:53:56 +010073endfunc
Bram Moolenaar54b2bfa2017-01-02 14:57:08 +010074
Bram Moolenaar94be6192017-04-22 22:40:11 +020075func Test_indent_fold()
Bram Moolenaar54b2bfa2017-01-02 14:57:08 +010076 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!
Bram Moolenaar1159b162017-02-28 21:53:56 +010084endfunc
Bram Moolenaar54b2bfa2017-01-02 14:57:08 +010085
Bram Moolenaar94be6192017-04-22 22:40:11 +020086func Test_indent_fold2()
Bram Moolenaar54b2bfa2017-01-02 14:57:08 +010087 new
88 call setline(1, ['', '{{{', '}}}', '{{{', '}}}'])
89 setl fen fdm=marker
90 2
91 norm! >>
Bram Moolenaara4208962019-08-24 20:50:19 +020092 let a=map(range(1,5), 'v:val->foldclosed()')
Bram Moolenaar54b2bfa2017-01-02 14:57:08 +010093 call assert_equal([-1,-1,-1,4,4], a)
94 bw!
Bram Moolenaar1159b162017-02-28 21:53:56 +010095endfunc
96
Bram Moolenaar5c504f62021-04-01 13:39:51 +020097" 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
Bram Moolenaar1159b162017-02-28 21:53:56 +0100112func Test_manual_fold_with_filter()
Bram Moolenaaraeb313f2020-11-27 19:13:28 +0100113 CheckExecutable cat
Bram Moolenaar3f3897e2017-03-04 15:28:53 +0100114 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
Bram Moolenaar1159b162017-02-28 21:53:56 +0100130endfunc
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100131
Bram Moolenaar94be6192017-04-22 22:40:11 +0200132func Test_indent_fold_with_read()
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100133 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
Bram Moolenaar70e67252022-09-27 19:34:35 +0100140 call writefile(["a", "", "\<Tab>a"], 'Xinfofile', 'D')
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100141 foldopen
Bram Moolenaarb18b4962022-09-02 21:55:50 +0100142 2read Xinfofile
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100143 %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))
Bram Moolenaara4208962019-08-24 20:50:19 +0200149 call assert_equal(7, 5->foldclosedend())
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100150
151 bwipe!
152 set foldmethod&
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100153endfunc
154
155func Test_combining_folds_indent()
156 new
157 let one = "\<Tab>a"
158 let zero = 'a'
159 call setline(1, [one, one, zero, zero, zero, one, one, one])
160 set foldmethod=indent
161 3,5d
162 %foldclose
163 call assert_equal(5, foldclosedend(1))
164
165 set foldmethod&
166 bwipe!
167endfunc
168
169func Test_combining_folds_marker()
170 new
171 call setline(1, ['{{{', '}}}', '', '', '', '{{{', '', '}}}'])
172 set foldmethod=marker
173 3,5d
174 %foldclose
175 call assert_equal(2, foldclosedend(1))
176
177 set foldmethod&
178 bwipe!
179endfunc
180
Bram Moolenaar025a6b72017-03-12 20:37:21 +0100181func Test_folds_marker_in_comment()
182 new
183 call setline(1, ['" foo', 'bar', 'baz'])
184 setl fen fdm=marker
185 setl com=sO:\"\ -,mO:\"\ \ ,eO:\"\",:\" cms=\"%s
186 norm! zf2j
187 setl nofen
188 :1y
189 call assert_equal(['" foo{{{'], getreg(0,1,1))
190 :+2y
191 call assert_equal(['baz"}}}'], getreg(0,1,1))
192
193 set foldmethod&
194 bwipe!
195endfunc
196
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100197func s:TestFoldExpr(lnum)
198 let thisline = getline(a:lnum)
199 if thisline == 'a'
200 return 1
201 elseif thisline == 'b'
202 return 0
203 elseif thisline == 'c'
204 return '<1'
205 elseif thisline == 'd'
206 return '>1'
207 endif
208 return 0
209endfunction
210
211func Test_update_folds_expr_read()
212 new
213 call setline(1, ['a', 'a', 'a', 'a', 'a', 'a'])
214 set foldmethod=expr
215 set foldexpr=s:TestFoldExpr(v:lnum)
216 2
217 foldopen
Bram Moolenaar70e67252022-09-27 19:34:35 +0100218 call writefile(['b', 'b', 'a', 'a', 'd', 'a', 'a', 'c'], 'Xupfofile', 'D')
Bram Moolenaarb18b4962022-09-02 21:55:50 +0100219 read Xupfofile
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100220 %foldclose
221 call assert_equal(2, foldclosedend(1))
222 call assert_equal(0, foldlevel(3))
Bram Moolenaara4208962019-08-24 20:50:19 +0200223 call assert_equal(0, 4->foldlevel())
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100224 call assert_equal(6, foldclosedend(5))
225 call assert_equal(10, foldclosedend(7))
226 call assert_equal(14, foldclosedend(11))
227
Bram Moolenaareadbc2b2017-03-04 18:42:39 +0100228 bwipe!
229 set foldmethod& foldexpr&
230endfunc
Bram Moolenaar88d298a2017-03-14 21:53:58 +0100231
zeertzjq93c15732022-05-21 16:34:38 +0100232" Test for what patch 8.1.0535 fixes.
233func Test_foldexpr_no_interrupt_addsub()
234 new
235 func! FoldFunc()
236 call setpos('.', getcurpos())
237 return '='
238 endfunc
239
240 set foldmethod=expr
241 set foldexpr=FoldFunc()
242 call setline(1, '1.2')
243
244 exe "norm! $\<C-A>"
245 call assert_equal('1.3', getline(1))
246
247 bwipe!
248 delfunc FoldFunc
249 set foldmethod& foldexpr&
250endfunc
251
Bram Moolenaar87b4e5c2022-10-01 15:32:46 +0100252" Fold function defined in another script
253func Test_foldexpr_compiled()
254 new
255 let lines =<< trim END
256 vim9script
257 def FoldFunc(): number
258 return v:lnum
259 enddef
260
261 set foldmethod=expr
262 set foldexpr=s:FoldFunc()
263 END
264 call writefile(lines, 'XfoldExpr', 'D')
265 source XfoldExpr
266
267 call setline(1, ['one', 'two', 'three'])
268 redraw
269 call assert_equal(1, foldlevel(1))
270 call assert_equal(2, foldlevel(2))
271 call assert_equal(3, foldlevel(3))
272
273 bwipe!
274 set foldmethod& foldexpr&
275endfunc
276
Bram Moolenaar94be6192017-04-22 22:40:11 +0200277func Check_foldlevels(expected)
278 call assert_equal(a:expected, map(range(1, line('$')), 'foldlevel(v:val)'))
279endfunc
280
281func Test_move_folds_around_manual()
Bram Moolenaar88d298a2017-03-14 21:53:58 +0100282 new
283 let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
284 call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
285 let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
286 " all folds closed
287 set foldenable foldlevel=0 fdm=indent
288 " needs a forced redraw
289 redraw!
290 set fdm=manual
291 call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
292 call assert_equal(input, getline(1, '$'))
293 7,12m0
294 call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
295 call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
296 10,12m0
297 call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] + PrepIndent("c"), getline(1, '$'))
298 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)'))
299 " moving should not close the folds
300 %d
301 call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
302 set fdm=indent
303 redraw!
304 set fdm=manual
305 call cursor(2, 1)
Bram Moolenaar40ebc0a2017-03-16 15:59:14 +0100306 %foldopen
Bram Moolenaar88d298a2017-03-14 21:53:58 +0100307 7,12m0
308 let folds=repeat([-1], 18)
309 call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
310 call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
311 norm! zM
312 " folds are not corrupted and all have been closed
313 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)'))
314 %d
315 call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
316 set fdm=indent
317 redraw!
318 set fdm=manual
319 %foldopen
320 3m4
321 %foldclose
322 call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
323 call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
324 %d
325 call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
326 set fdm=indent foldlevel=0
327 set fdm=manual
328 %foldopen
329 3m1
330 %foldclose
331 call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
332 call assert_equal(0, foldlevel(2))
333 call assert_equal(5, foldclosedend(3))
334 call assert_equal([-1, -1, 3, 3, 3, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
335 2,6m$
336 %foldclose
337 call assert_equal(5, foldclosedend(2))
338 call assert_equal(0, foldlevel(6))
339 call assert_equal(9, foldclosedend(7))
340 call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
Bram Moolenaar495b7dd2017-09-16 17:19:22 +0200341
Bram Moolenaar40ebc0a2017-03-16 15:59:14 +0100342 %d
343 " Ensure moving around the edges still works.
344 call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
345 set fdm=indent foldlevel=0
346 set fdm=manual
347 %foldopen
348 6m$
349 " The first fold has been truncated to the 5'th line.
350 " Second fold has been moved up because the moved line is now below it.
Bram Moolenaar94be6192017-04-22 22:40:11 +0200351 call Check_foldlevels([0, 1, 1, 1, 1, 0, 0, 0, 1, 0])
352
353 %delete
354 set fdm=indent foldlevel=0
355 call setline(1, [
356 \ "a",
357 \ "\ta",
358 \ "\t\ta",
359 \ "\t\ta",
360 \ "\t\ta",
361 \ "a",
362 \ "a"])
363 set fdm=manual
364 %foldopen!
365 4,5m6
366 call Check_foldlevels([0, 1, 2, 0, 0, 0, 0])
367
368 %delete
369 set fdm=indent
370 call setline(1, [
371 \ "\ta",
372 \ "\t\ta",
373 \ "\t\ta",
374 \ "\t\ta",
375 \ "\ta",
376 \ "\t\ta",
377 \ "\t\ta",
378 \ "\t\ta",
379 \ "\ta",
380 \ "\t\ta",
381 \ "\t\ta",
382 \ "\t\ta",
383 \ "\t\ta",
384 \ "\ta",
385 \ "a"])
386 set fdm=manual
387 %foldopen!
388 13m7
389 call Check_foldlevels([1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0])
390
Bram Moolenaar88d298a2017-03-14 21:53:58 +0100391 bw!
392endfunc
393
Bram Moolenaar94be6192017-04-22 22:40:11 +0200394func Test_move_folds_around_indent()
Bram Moolenaar88d298a2017-03-14 21:53:58 +0100395 new
396 let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
397 call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
398 let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
399 " all folds closed
400 set fdm=indent
401 call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
402 call assert_equal(input, getline(1, '$'))
403 7,12m0
404 call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
405 call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
406 10,12m0
407 call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] + PrepIndent("c"), getline(1, '$'))
408 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)'))
409 " moving should not close the folds
410 %d
411 call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
412 set fdm=indent
413 call cursor(2, 1)
Bram Moolenaar40ebc0a2017-03-16 15:59:14 +0100414 %foldopen
Bram Moolenaar88d298a2017-03-14 21:53:58 +0100415 7,12m0
416 let folds=repeat([-1], 18)
417 call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
418 call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
419 norm! zM
420 " folds are not corrupted and all have been closed
421 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)'))
422 %d
423 call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
424 set fdm=indent
425 %foldopen
426 3m4
427 %foldclose
428 call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
429 call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
430 %d
431 call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
432 set fdm=indent foldlevel=0
433 %foldopen
434 3m1
435 %foldclose
436 call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
437 call assert_equal(1, foldlevel(2))
438 call assert_equal(5, foldclosedend(3))
439 call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
440 2,6m$
441 %foldclose
442 call assert_equal(9, foldclosedend(2))
443 call assert_equal(1, foldlevel(6))
444 call assert_equal(9, foldclosedend(7))
445 call assert_equal([-1, 2, 2, 2, 2, 2, 2, 2, 2, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
Bram Moolenaar40ebc0a2017-03-16 15:59:14 +0100446 " Ensure moving around the edges still works.
447 %d
448 call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
449 set fdm=indent foldlevel=0
450 %foldopen
451 6m$
452 " The first fold has been truncated to the 5'th line.
453 " Second fold has been moved up because the moved line is now below it.
Bram Moolenaar94be6192017-04-22 22:40:11 +0200454 call Check_foldlevels([0, 1, 1, 1, 1, 0, 0, 0, 1, 1])
Bram Moolenaar88d298a2017-03-14 21:53:58 +0100455 bw!
456endfunc
Bram Moolenaar518c9b12017-03-21 11:48:39 +0100457
458func Test_folddoopen_folddoclosed()
459 new
460 call setline(1, range(1, 9))
461 set foldmethod=manual
462 1,3 fold
463 6,8 fold
464
465 " Test without range.
466 folddoopen s/$/o/
467 folddoclosed s/$/c/
468 call assert_equal(['1c', '2c', '3c',
469 \ '4o', '5o',
470 \ '6c', '7c', '8c',
471 \ '9o'], getline(1, '$'))
472
473 " Test with range.
474 call setline(1, range(1, 9))
475 1,8 folddoopen s/$/o/
476 4,$ folddoclosed s/$/c/
477 call assert_equal(['1', '2', '3',
478 \ '4o', '5o',
479 \ '6c', '7c', '8c',
480 \ '9'], getline(1, '$'))
481
482 set foldmethod&
483 bw!
484endfunc
485
486func Test_fold_error()
487 new
488 call setline(1, [1, 2])
489
490 for fm in ['indent', 'expr', 'syntax', 'diff']
491 exe 'set foldmethod=' . fm
492 call assert_fails('norm zf', 'E350:')
493 call assert_fails('norm zd', 'E351:')
494 call assert_fails('norm zE', 'E352:')
495 endfor
496
497 set foldmethod=manual
498 call assert_fails('norm zd', 'E490:')
499 call assert_fails('norm zo', 'E490:')
500 call assert_fails('3fold', 'E16:')
501
502 set foldmethod=marker
503 set nomodifiable
504 call assert_fails('1,2fold', 'E21:')
505
506 set modifiable&
507 set foldmethod&
508 bw!
509endfunc
Bram Moolenaar495b7dd2017-09-16 17:19:22 +0200510
511func Test_foldtext_recursive()
512 new
513 call setline(1, ['{{{', 'some text', '}}}'])
514 setlocal foldenable foldmethod=marker foldtext=foldtextresult(v\:foldstart)
515 " This was crashing because of endless recursion.
516 2foldclose
517 redraw
518 call assert_equal(1, foldlevel(2))
519 call assert_equal(1, foldclosed(2))
520 call assert_equal(3, foldclosedend(2))
521 bwipe!
522endfunc
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100523
524" Various fold related tests
525
526" Basic test if a fold can be created, opened, moving to the end and closed
527func Test_fold_manual()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200528 new
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100529 set fdm=manual
530
531 let content = ['1 aa', '2 bb', '3 cc']
532 call append(0, content)
533 call cursor(1, 1)
534 normal zf2j
535 call assert_equal('1 aa', getline(foldclosed('.')))
536 normal zo
537 call assert_equal(-1, foldclosed('.'))
538 normal ]z
539 call assert_equal('3 cc', getline('.'))
540 normal zc
541 call assert_equal('1 aa', getline(foldclosed('.')))
542
Bram Moolenaar68ffe8c2021-04-05 12:47:25 +0200543 " Create a fold inside a closed fold after setting 'foldlevel'
544 %d _
545 call setline(1, range(1, 5))
546 1,5fold
547 normal zR
548 2,4fold
549 set foldlevel=1
550 3fold
551 call assert_equal([1, 3, 3, 3, 1], map(range(1, 5), {->foldlevel(v:val)}))
552 set foldlevel&
553
554 " Create overlapping folds (at the start and at the end)
555 normal zE
556 2,3fold
557 normal zR
558 3,4fold
559 call assert_equal([0, 2, 2, 1, 0], map(range(1, 5), {->foldlevel(v:val)}))
560 normal zE
561 3,4fold
562 normal zR
563 2,3fold
564 call assert_equal([0, 1, 2, 2, 0], map(range(1, 5), {->foldlevel(v:val)}))
565
566 " Create a nested fold across two non-adjoining folds
567 %d _
568 call setline(1, range(1, 7))
569 1,2fold
570 normal zR
571 4,5fold
572 normal zR
573 6,7fold
574 normal zR
575 1,5fold
576 call assert_equal([2, 2, 1, 2, 2, 1, 1],
577 \ map(range(1, 7), {->foldlevel(v:val)}))
578
579 " A newly created nested fold should be closed
580 %d _
581 call setline(1, range(1, 6))
582 1,6fold
583 normal zR
584 3,4fold
585 normal zR
586 2,5fold
587 call assert_equal([1, 2, 3, 3, 2, 1], map(range(1, 6), {->foldlevel(v:val)}))
588 call assert_equal(2, foldclosed(4))
589 call assert_equal(5, foldclosedend(4))
590
591 " Test zO, zC and zA on a line with no folds.
592 normal zE
593 call assert_fails('normal zO', 'E490:')
594 call assert_fails('normal zC', 'E490:')
595 call assert_fails('normal zA', 'E490:')
596
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100597 set fdm&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200598 bw!
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100599endfunc
600
601" test folding with markers.
602func Test_fold_marker()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200603 new
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100604 set fdm=marker fdl=1 fdc=3
605
606 let content = ['4 dd {{{', '5 ee {{{ }}}', '6 ff }}}']
607 call append(0, content)
608 call cursor(2, 1)
609 call assert_equal(2, foldlevel('.'))
610 normal [z
611 call assert_equal(1, foldlevel('.'))
612 exe "normal jo{{ \<Esc>r{jj"
613 call assert_equal(1, foldlevel('.'))
614 normal kYpj
615 call assert_equal(0, foldlevel('.'))
616
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200617 " Use only closing fold marker (without and with a count)
618 set fdl&
619 %d _
620 call setline(1, ['one }}}', 'two'])
621 call assert_equal([0, 0], [foldlevel(1), foldlevel(2)])
622 %d _
623 call setline(1, ['one }}}4', 'two'])
624 call assert_equal([4, 3], [foldlevel(1), foldlevel(2)])
625
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100626 set fdm& fdl& fdc&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200627 bw!
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100628endfunc
629
Bram Moolenaar4af72592018-12-09 15:00:52 +0100630" test create fold markers with C filetype
631func Test_fold_create_marker_in_C()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200632 bw!
Bram Moolenaar4af72592018-12-09 15:00:52 +0100633 set fdm=marker fdl=9
634 set filetype=c
635
Bram Moolenaarc79745a2019-05-20 22:12:34 +0200636 let content =<< trim [CODE]
637 /*
638 * comment
639 *
640 *
641 */
642 int f(int* p) {
643 *p = 3;
644 return 0;
645 }
646 [CODE]
647
Bram Moolenaar4af72592018-12-09 15:00:52 +0100648 for c in range(len(content) - 1)
649 bw!
650 call append(0, content)
651 call cursor(c + 1, 1)
652 norm! zfG
653 call assert_equal(content[c] . (c < 4 ? '{{{' : '/*{{{*/'), getline(c + 1))
654 endfor
655
656 set fdm& fdl&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200657 bw!
Bram Moolenaar4af72592018-12-09 15:00:52 +0100658endfunc
659
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100660" test folding with indent
661func Test_fold_indent()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200662 new
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100663 set fdm=indent sw=2
664
665 let content = ['1 aa', '2 bb', '3 cc']
666 call append(0, content)
667 call cursor(2, 1)
668 exe "normal i \<Esc>jI "
669 call assert_equal(2, foldlevel('.'))
670 normal k
671 call assert_equal(1, foldlevel('.'))
672
673 set fdm& sw&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200674 bw!
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100675endfunc
676
677" test syntax folding
678func Test_fold_syntax()
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200679 CheckFeature syntax
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100680
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200681 new
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100682 set fdm=syntax fdl=0
683
684 syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3
685 syn region Fd1 start="ee" end="ff" fold contained
686 syn region Fd2 start="gg" end="hh" fold contained
687 syn region Fd3 start="commentstart" end="commentend" fold contained
688 let content = ['3 cc', '4 dd {{{', '5 ee {{{ }}}', '{{{{', '6 ff }}}',
689 \ '6 ff }}}', '7 gg', '8 hh', '9 ii']
690 call append(0, content)
691 normal Gzk
692 call assert_equal('9 ii', getline('.'))
693 normal k
694 call assert_equal('3 cc', getline('.'))
695 exe "normal jAcommentstart \<Esc>Acommentend"
696 set fdl=1
697 normal 3j
698 call assert_equal('7 gg', getline('.'))
699 set fdl=0
700 exe "normal zO\<C-L>j"
701 call assert_equal('8 hh', getline('.'))
702 syn clear Fd1 Fd2 Fd3 Hup
703
704 set fdm& fdl&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200705 bw!
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100706endfunc
707
708func Flvl()
709 let l = getline(v:lnum)
710 if l =~ "bb$"
711 return 2
712 elseif l =~ "gg$"
713 return "s1"
714 elseif l =~ "ii$"
715 return ">2"
716 elseif l =~ "kk$"
717 return "0"
718 endif
719 return "="
720endfun
721
722" test expression folding
723func Test_fold_expr()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200724 new
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100725 set fdm=expr fde=Flvl()
726
727 let content = ['1 aa',
728 \ '2 bb',
729 \ '3 cc',
730 \ '4 dd {{{commentstart commentend',
731 \ '5 ee {{{ }}}',
732 \ '{{{',
733 \ '6 ff }}}',
734 \ '6 ff }}}',
735 \ ' 7 gg',
736 \ ' 8 hh',
737 \ '9 ii',
738 \ 'a jj',
739 \ 'b kk']
740 call append(0, content)
741 call cursor(1, 1)
742 exe "normal /bb$\<CR>"
743 call assert_equal(2, foldlevel('.'))
744 exe "normal /hh$\<CR>"
745 call assert_equal(1, foldlevel('.'))
746 exe "normal /ii$\<CR>"
747 call assert_equal(2, foldlevel('.'))
748 exe "normal /kk$\<CR>"
749 call assert_equal(0, foldlevel('.'))
750
751 set fdm& fde&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200752 bw!
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100753endfunc
754
755" Bug with fdm=indent and moving folds
756" Moving a fold a few times, messes up the folds below the moved fold.
757" Fixed by 7.4.700
758func Test_fold_move()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200759 new
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100760 set fdm=indent sw=2 fdl=0
761
762 let content = ['', '', 'Line1', ' Line2', ' Line3',
763 \ 'Line4', ' Line5', ' Line6',
764 \ 'Line7', ' Line8', ' Line9']
765 call append(0, content)
766 normal zM
767 call cursor(4, 1)
768 move 2
769 move 1
770 call assert_equal(7, foldclosed(7))
771 call assert_equal(8, foldclosedend(7))
772 call assert_equal(0, foldlevel(9))
773 call assert_equal(10, foldclosed(10))
774 call assert_equal(11, foldclosedend(10))
775 call assert_equal('+-- 2 lines: Line2', foldtextresult(2))
Bram Moolenaara4208962019-08-24 20:50:19 +0200776 call assert_equal('+-- 2 lines: Line8', 10->foldtextresult())
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100777
778 set fdm& sw& fdl&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200779 bw!
Bram Moolenaar430dc5d2017-11-02 21:04:47 +0100780endfunc
Bram Moolenaarfb094e12017-11-05 20:59:28 +0100781
782" test for patch 7.3.637
783" Cannot catch the error caused by a foldopen when there is no fold.
784func Test_foldopen_exception()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200785 new
Bram Moolenaarfb094e12017-11-05 20:59:28 +0100786 let a = 'No error caught'
787 try
788 foldopen
789 catch
790 let a = matchstr(v:exception,'^[^ ]*')
791 endtry
792 call assert_equal('Vim(foldopen):E490:', a)
793
794 let a = 'No error caught'
795 try
796 foobar
797 catch
798 let a = matchstr(v:exception,'^[^ ]*')
799 endtry
800 call assert_match('E492:', a)
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200801 bw!
Bram Moolenaarfb094e12017-11-05 20:59:28 +0100802endfunc
Bram Moolenaar907dad72018-07-10 15:07:15 +0200803
804func Test_fold_last_line_with_pagedown()
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200805 new
Bram Moolenaar907dad72018-07-10 15:07:15 +0200806 set fdm=manual
807
808 let expect = '+-- 11 lines: 9---'
809 let content = range(1,19)
810 call append(0, content)
811 normal dd9G
812 normal zfG
813 normal zt
814 call assert_equal('9', getline(foldclosed('.')))
815 call assert_equal('19', getline(foldclosedend('.')))
816 call assert_equal(expect, ScreenLines(1, len(expect))[0])
817 call feedkeys("\<C-F>", 'xt')
818 call assert_equal(expect, ScreenLines(1, len(expect))[0])
819 call feedkeys("\<C-F>", 'xt')
820 call assert_equal(expect, ScreenLines(1, len(expect))[0])
821 call feedkeys("\<C-B>\<C-F>\<C-F>", 'xt')
822 call assert_equal(expect, ScreenLines(1, len(expect))[0])
823
824 set fdm&
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200825 bw!
Bram Moolenaar907dad72018-07-10 15:07:15 +0200826endfunc
Bram Moolenaar7701f302018-10-02 21:20:32 +0200827
828func Test_folds_with_rnu()
Bram Moolenaar8c5a2782019-08-07 23:07:07 +0200829 CheckScreendump
Bram Moolenaar7701f302018-10-02 21:20:32 +0200830
831 call writefile([
832 \ 'set fdm=marker rnu foldcolumn=2',
833 \ 'call setline(1, ["{{{1", "nline 1", "{{{1", "line 2"])',
Bram Moolenaar70e67252022-09-27 19:34:35 +0100834 \ ], 'Xtest_folds_with_rnu', 'D')
Bram Moolenaar7701f302018-10-02 21:20:32 +0200835 let buf = RunVimInTerminal('-S Xtest_folds_with_rnu', {})
836
837 call VerifyScreenDump(buf, 'Test_folds_with_rnu_01', {})
838 call term_sendkeys(buf, "j")
839 call VerifyScreenDump(buf, 'Test_folds_with_rnu_02', {})
840
841 " clean up
842 call StopVimInTerminal(buf)
Bram Moolenaar7701f302018-10-02 21:20:32 +0200843endfunc
Bram Moolenaar53932812018-12-07 21:08:49 +0100844
845func Test_folds_marker_in_comment2()
846 new
847 call setline(1, ['Lorem ipsum dolor sit', 'Lorem ipsum dolor sit', 'Lorem ipsum dolor sit'])
848 setl fen fdm=marker
849 setl commentstring=<!--%s-->
850 setl comments=s:<!--,m:\ \ \ \ ,e:-->
851 norm! zf2j
852 setl nofen
853 :1y
854 call assert_equal(['Lorem ipsum dolor sit<!--{{{-->'], getreg(0,1,1))
855 :+2y
856 call assert_equal(['Lorem ipsum dolor sit<!--}}}-->'], getreg(0,1,1))
857
858 set foldmethod&
859 bwipe!
860endfunc
Bram Moolenaar9a4a8c42019-08-19 22:48:30 +0200861
862func Test_fold_delete_with_marker()
863 new
864 call setline(1, ['func Func() {{{1', 'endfunc'])
865 1,2yank
866 new
867 set fdm=marker
868 call setline(1, 'x')
869 normal! Vp
870 normal! zd
871 call assert_equal(['func Func() ', 'endfunc'], getline(1, '$'))
872
873 set fdm&
874 bwipe!
875 bwipe!
876endfunc
Bram Moolenaar7a9bd7c2019-09-17 22:42:55 +0200877
878func Test_fold_delete_with_marker_and_whichwrap()
879 new
880 let content1 = ['']
881 let content2 = ['folded line 1 "{{{1', ' test', ' test2', ' test3', '', 'folded line 2 "{{{1', ' test', ' test2', ' test3']
882 call setline(1, content1 + content2)
883 set fdm=marker ww+=l
884 normal! x
885 call assert_equal(content2, getline(1, '$'))
886 set fdm& ww&
887 bwipe!
888endfunc
Bram Moolenaar3b681232019-12-13 19:35:55 +0100889
890func Test_fold_delete_first_line()
891 new
892 call setline(1, [
893 \ '" x {{{1',
894 \ '" a',
895 \ '" aa',
896 \ '" x {{{1',
897 \ '" b',
898 \ '" bb',
899 \ '" x {{{1',
900 \ '" c',
901 \ '" cc',
902 \ ])
903 set foldmethod=marker
904 1
905 normal dj
906 call assert_equal([
907 \ '" x {{{1',
908 \ '" c',
909 \ '" cc',
910 \ ], getline(1,'$'))
911 bwipe!
912 set foldmethod&
913endfunc
Bram Moolenaar9d8d0b52020-04-24 22:47:31 +0200914
Bram Moolenaar68ffe8c2021-04-05 12:47:25 +0200915" Add a test for deleting the outer fold of a nested fold and promoting the
916" inner folds to one level up with already a fold at that level following the
917" nested fold.
918func Test_fold_delete_recursive_fold()
919 new
920 call setline(1, range(1, 7))
921 2,3fold
922 normal zR
923 4,5fold
924 normal zR
925 1,5fold
926 normal zR
927 6,7fold
928 normal zR
929 normal 1Gzd
930 normal 1Gzj
931 call assert_equal(2, line('.'))
932 normal zj
933 call assert_equal(4, line('.'))
934 normal zj
935 call assert_equal(6, line('.'))
936 bw!
937endfunc
938
Bram Moolenaar9d8d0b52020-04-24 22:47:31 +0200939" Test for errors in 'foldexpr'
940func Test_fold_expr_error()
941 new
942 call setline(1, ['one', 'two', 'three'])
Bram Moolenaar5c504f62021-04-01 13:39:51 +0200943 " In a window with no folds, foldlevel() should return 0
944 call assert_equal(0, foldlevel(1))
Bram Moolenaar9d8d0b52020-04-24 22:47:31 +0200945
946 " Return a list from the expression
947 set foldexpr=[]
948 set foldmethod=expr
949 for i in range(3)
950 call assert_equal(0, foldlevel(i))
951 endfor
952
953 " expression error
954 set foldexpr=[{]
955 set foldmethod=expr
956 for i in range(3)
957 call assert_equal(0, foldlevel(i))
958 endfor
959
960 set foldmethod& foldexpr&
961 close!
962endfunc
963
Bram Moolenaarda697642020-09-17 19:36:04 +0200964func Test_undo_fold_deletion()
965 new
966 set fdm=marker
967 let lines =<< trim END
968 " {{{
969 " }}}1
970 " {{{
971 END
972 call setline(1, lines)
973 3d
974 g/"/d
975 undo
976 redo
977 eval getline(1, '$')->assert_equal([''])
978
979 set fdm&vim
980 bwipe!
981endfunc
982
Bram Moolenaarc136a352020-11-03 20:05:40 +0100983" this was crashing
984func Test_move_no_folds()
985 new
986 fold
987 setlocal fdm=expr
988 normal zj
989 bwipe!
990endfunc
991
Bram Moolenaar5e1f22f2020-11-10 18:23:52 +0100992" this was crashing
993func Test_fold_create_delete_create()
994 new
995 fold
996 fold
997 normal zd
998 fold
999 bwipe!
1000endfunc
1001
Bram Moolenaar6a78f322020-12-21 14:01:41 +01001002" this was crashing
1003func Test_fold_create_delete()
1004 new
1005 norm zFzFzdzj
1006 bwipe!
1007endfunc
1008
Bram Moolenaare71996b2021-01-21 17:03:07 +01001009func Test_fold_relative_move()
Bram Moolenaar5c504f62021-04-01 13:39:51 +02001010 new
Bram Moolenaare71996b2021-01-21 17:03:07 +01001011 set fdm=indent sw=2 wrap tw=80
1012
Bram Moolenaar3c49e742021-04-04 21:26:04 +02001013 let longtext = repeat('x', &columns + 1)
1014 let content = [ ' foo', ' ' .. longtext, ' baz',
1015 \ longtext,
1016 \ ' foo', ' ' .. longtext, ' baz'
Bram Moolenaare71996b2021-01-21 17:03:07 +01001017 \ ]
1018 call append(0, content)
1019
1020 normal zM
1021
Bram Moolenaar3c49e742021-04-04 21:26:04 +02001022 for lnum in range(1, 3)
1023 call cursor(lnum, 1)
1024 call assert_true(foldclosed(line('.')))
1025 normal gj
1026 call assert_equal(2, winline())
1027 endfor
Bram Moolenaare71996b2021-01-21 17:03:07 +01001028
1029 call cursor(2, 1)
1030 call assert_true(foldclosed(line('.')))
1031 normal 2gj
1032 call assert_equal(3, winline())
1033
Bram Moolenaar3c49e742021-04-04 21:26:04 +02001034 for lnum in range(5, 7)
1035 call cursor(lnum, 1)
1036 call assert_true(foldclosed(line('.')))
1037 normal gk
1038 call assert_equal(3, winline())
1039 endfor
Bram Moolenaare71996b2021-01-21 17:03:07 +01001040
1041 call cursor(6, 1)
1042 call assert_true(foldclosed(line('.')))
1043 normal 2gk
1044 call assert_equal(2, winline())
1045
1046 set fdm& sw& wrap& tw&
Bram Moolenaar5c504f62021-04-01 13:39:51 +02001047 bw!
Bram Moolenaare71996b2021-01-21 17:03:07 +01001048endfunc
1049
Bram Moolenaar4fa11752021-03-03 13:26:02 +01001050" Test for using multibyte characters as 'foldopen', 'foldclose' and
1051" 'foldsetp' items in 'fillchars'
1052func s:mbyte_fillchar_tests(fo, fc, fs)
1053 setlocal foldcolumn=3
1054
1055 normal zE
1056 1,2fold
1057 call assert_equal([a:fc .. ' +-- 2 ', ' three '],
1058 \ ScreenLines([1, 2], 10))
1059 1,2foldopen
1060 call assert_equal([a:fo .. ' one ', a:fs .. ' two '],
1061 \ ScreenLines([1, 2], 7))
1062 1,2foldclose
1063 redraw!
1064 call assert_equal([a:fc .. ' +-- 2 ', ' three '],
1065 \ ScreenLines([1, 2], 10))
1066
1067 " Two level fold
1068 normal zE
1069 2,3fold
1070 1,4fold
1071 call assert_equal([a:fc .. ' +-- 4 ', ' five '],
1072 \ ScreenLines([1, 2], 10))
1073 1,4foldopen
1074 call assert_equal([a:fo .. ' one ', a:fs .. a:fc .. ' +--- 2'],
1075 \ ScreenLines([1, 2], 10))
1076 1,4foldopen
1077 call assert_equal([a:fo .. ' one ', a:fs .. a:fo .. ' two ',
1078 \ a:fs .. a:fs .. ' three '], ScreenLines([1, 3], 10))
1079 2,3foldclose
1080 call assert_equal([a:fo .. ' one ', a:fs .. a:fc .. ' +--- 2'],
1081 \ ScreenLines([1, 2], 10))
1082 1,4foldclose
1083 call assert_equal([a:fc .. ' +-- 4 ', ' five '],
1084 \ ScreenLines([1, 2], 10))
1085
1086 " Three level fold
1087 normal zE
1088 3,4fold
1089 2,5fold
1090 1,6fold
1091 call assert_equal([a:fc .. ' +-- 6 '], ScreenLines(1, 10))
1092 " open all the folds
1093 normal zR
1094 call assert_equal([
1095 \ a:fo .. ' one ',
1096 \ a:fs .. a:fo .. ' two ',
1097 \ '2' .. a:fo .. ' three ',
1098 \ '23 four ',
1099 \ a:fs .. a:fs .. ' five ',
1100 \ a:fs .. ' six ',
1101 \ ], ScreenLines([1, 6], 10))
1102 " close the innermost fold
1103 3,4foldclose
1104 call assert_equal([
1105 \ a:fo .. ' one ',
1106 \ a:fs .. a:fo .. ' two ',
1107 \ a:fs .. a:fs .. a:fc .. '+---- ',
1108 \ a:fs .. a:fs .. ' five ',
1109 \ a:fs .. ' six ',
1110 \ ], ScreenLines([1, 5], 10))
1111 " close the next fold
1112 2,5foldclose
1113 call assert_equal([
1114 \ a:fo .. ' one ',
1115 \ a:fs .. a:fc .. ' +--- 4',
1116 \ a:fs .. ' six ',
1117 \ ], ScreenLines([1, 3], 10))
1118
1119 " set the fold column size to 2
1120 setlocal fdc=2
1121 normal zR
1122 call assert_equal([
1123 \ a:fo .. ' one ',
1124 \ a:fo .. ' two ',
1125 \ a:fo .. ' three',
1126 \ '3 four ',
1127 \ '2 five ',
1128 \ a:fs .. ' six ',
1129 \ ], ScreenLines([1, 6], 7))
1130
1131 " set the fold column size to 1
1132 setlocal fdc=1
1133 normal zR
1134 call assert_equal([
1135 \ a:fo .. 'one ',
1136 \ a:fo .. 'two ',
1137 \ a:fo .. 'three ',
1138 \ '3four ',
1139 \ '2five ',
1140 \ a:fs .. 'six ',
1141 \ ], ScreenLines([1, 6], 7))
1142
Bram Moolenaar008bff92021-03-04 21:55:58 +01001143 " Enable number and sign columns and place some signs
1144 setlocal fdc=3
1145 setlocal number
1146 setlocal signcolumn=auto
1147 sign define S1 text=->
1148 sign place 10 line=3 name=S1
1149 call assert_equal([
1150 \ a:fo .. ' 1 one ',
1151 \ a:fs .. a:fo .. ' 2 two ',
1152 \ '2' .. a:fo .. ' -> 3 three',
1153 \ '23 4 four ',
1154 \ a:fs .. a:fs .. ' 5 five ',
1155 \ a:fs .. ' 6 six '
1156 \ ], ScreenLines([1, 6], 14))
1157
1158 " Test with 'rightleft'
1159 if has('rightleft')
1160 setlocal rightleft
1161 let lines = ScreenLines([1, 6], winwidth(0))
1162 call assert_equal('o 1 ' .. a:fo,
1163 \ strcharpart(lines[0], strchars(lines[0]) - 10, 10))
1164 call assert_equal('t 2 ' .. a:fo .. a:fs,
1165 \ strcharpart(lines[1], strchars(lines[1]) - 10, 10))
1166 call assert_equal('t 3 >- ' .. a:fo .. '2',
1167 \ strcharpart(lines[2], strchars(lines[2]) - 10, 10))
1168 call assert_equal('f 4 32',
1169 \ strcharpart(lines[3], strchars(lines[3]) - 10, 10))
1170 call assert_equal('f 5 ' .. a:fs .. a:fs,
1171 \ strcharpart(lines[4], strchars(lines[4]) - 10, 10))
1172 call assert_equal('s 6 ' .. a:fs,
1173 \ strcharpart(lines[5], strchars(lines[5]) - 10, 10))
1174 setlocal norightleft
1175 endif
1176
1177 sign unplace *
1178 sign undefine S1
1179 setlocal number& signcolumn&
1180
1181 " Add a test with more than 9 folds (and then delete some folds)
1182 normal zE
1183 for i in range(1, 10)
1184 normal zfGzo
1185 endfor
1186 normal zR
1187 call assert_equal([
1188 \ a:fo .. a:fo .. ' one ',
1189 \ '9> two '
1190 \ ], ScreenLines([1, 2], 7))
1191 normal 1Gzd
1192 call assert_equal([
1193 \ a:fo .. a:fo .. ' one ',
1194 \ '89 two '
1195 \ ], ScreenLines([1, 2], 7))
1196 normal 1Gzdzdzdzdzdzdzd
1197 call assert_equal([
1198 \ a:fo .. a:fo .. ' one ',
1199 \ a:fs .. a:fs .. ' two '
1200 \ ], ScreenLines([1, 2], 7))
1201
1202 setlocal foldcolumn& number& signcolumn&
Bram Moolenaar4fa11752021-03-03 13:26:02 +01001203endfunc
1204
1205func Test_foldcolumn_multibyte_char()
1206 new
1207 call setline(1, ['one', 'two', 'three', 'four', 'five', 'six'])
1208 setlocal foldenable foldmethod=manual
1209
1210 " First test with the default setting
1211 call s:mbyte_fillchar_tests('-', '+', '|')
1212
1213 " Use multi-byte characters
1214 set fillchars+=foldopen:▾,foldsep:│,foldclose:▸
1215 call s:mbyte_fillchar_tests('▾', '▸', '│')
1216
Bram Moolenaar196a1f72021-03-21 14:39:19 +01001217 " Use a mix of multi-byte and single-byte characters
1218 set fillchars+=foldopen:¬,foldsep:\|,foldclose:+
1219 call s:mbyte_fillchar_tests('¬', '+', '|')
1220 set fillchars+=foldopen:+,foldsep:\|,foldclose:¬
1221 call s:mbyte_fillchar_tests('+', '¬', '|')
1222
Bram Moolenaar4fa11752021-03-03 13:26:02 +01001223 bw!
1224 set foldenable& fdc& fdm& fillchars&
1225endfunc
1226
Bram Moolenaar5c504f62021-04-01 13:39:51 +02001227" Test for calling foldlevel() from a fold expression
1228let g:FoldLevels = []
1229func FoldExpr1(lnum)
1230 let f = [a:lnum]
1231 for i in range(1, line('$'))
1232 call add(f, foldlevel(i))
1233 endfor
1234 call add(g:FoldLevels, f)
1235 return getline(a:lnum)[0] == "\t"
1236endfunc
1237
1238func Test_foldexpr_foldlevel()
1239 new
1240 call setline(1, ['one', "\ttwo", "\tthree"])
1241 setlocal foldmethod=expr
1242 setlocal foldexpr=FoldExpr1(v:lnum)
1243 setlocal foldenable
1244 setlocal foldcolumn=3
1245 redraw!
1246 call assert_equal([[1, -1, -1, -1], [2, -1, -1, -1], [3, 0, 1, -1]],
1247 \ g:FoldLevels)
1248 set foldmethod& foldexpr& foldenable& foldcolumn&
1249 bw!
1250endfunc
1251
1252" Test for returning different values from a fold expression
1253func FoldExpr2(lnum)
1254 if a:lnum == 1 || a:lnum == 4
1255 return -2
1256 elseif a:lnum == 2
1257 return 'a1'
1258 elseif a:lnum == 3
1259 return 's4'
1260 endif
1261 return '='
1262endfunc
1263
1264func Test_foldexpr_2()
1265 new
1266 call setline(1, ['one', 'two', 'three', 'four'])
1267 setlocal foldexpr=FoldExpr2(v:lnum)
1268 setlocal foldmethod=expr
1269 call assert_equal([0, 1, 1, 0], [foldlevel(1), foldlevel(2), foldlevel(3),
1270 \ foldlevel(4)])
1271 bw!
1272endfunc
1273
1274" Test for the 'foldclose' option
1275func Test_foldclose_opt()
1276 CheckScreendump
1277
1278 let lines =<< trim END
1279 set foldmethod=manual foldclose=all foldopen=all
1280 call setline(1, ['one', 'two', 'three', 'four'])
1281 2,3fold
1282 func XsaveFoldLevels()
1283 redraw!
1284 call writefile([json_encode([foldclosed(1), foldclosed(2), foldclosed(3),
1285 \ foldclosed(4)])], 'Xoutput', 'a')
1286 endfunc
1287 END
Bram Moolenaar70e67252022-09-27 19:34:35 +01001288 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar5c504f62021-04-01 13:39:51 +02001289 let rows = 10
1290 let buf = RunVimInTerminal('-S Xscript', {'rows': rows})
1291 call term_wait(buf)
1292 call term_sendkeys(buf, ":set noruler\n")
1293 call term_wait(buf)
1294 call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1295 call term_sendkeys(buf, "2G")
1296 call WaitForAssert({-> assert_equal('two', term_getline(buf, 2))})
1297 call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1298 call term_sendkeys(buf, "4G")
1299 call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
1300 call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1301 call term_sendkeys(buf, "3G")
1302 call WaitForAssert({-> assert_equal('three', term_getline(buf, 3))})
1303 call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
1304 call term_sendkeys(buf, "1G")
1305 call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
1306 call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
Bram Moolenaar68ffe8c2021-04-05 12:47:25 +02001307 call term_sendkeys(buf, "2G")
1308 call WaitForAssert({-> assert_equal('two', term_getline(buf, 2))})
1309 call term_sendkeys(buf, "k")
1310 call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
Bram Moolenaar5c504f62021-04-01 13:39:51 +02001311
1312 " clean up
1313 call StopVimInTerminal(buf)
1314
1315 call assert_equal(['[-1,2,2,-1]', '[-1,-1,-1,-1]', '[-1,2,2,-1]',
1316 \ '[-1,-1,-1,-1]', '[-1,2,2,-1]'], readfile('Xoutput'))
Bram Moolenaar5c504f62021-04-01 13:39:51 +02001317 call delete('Xoutput')
1318endfunc
1319
1320" Test for foldtextresult()
1321func Test_foldtextresult()
1322 new
1323 call assert_equal('', foldtextresult(-1))
1324 call assert_equal('', foldtextresult(0))
1325 call assert_equal('', foldtextresult(1))
1326 call setline(1, ['one', 'two', 'three', 'four'])
1327 2,3fold
1328 call assert_equal('', foldtextresult(1))
1329 call assert_equal('+-- 2 lines: two', foldtextresult(2))
1330 setlocal foldtext=
1331 call assert_equal('+-- 2 lines folded ', foldtextresult(2))
1332
1333 " Fold text for a C comment fold
1334 %d _
1335 setlocal foldtext&
1336 call setline(1, ['', '/*', ' * Comment', ' */', ''])
1337 2,4fold
1338 call assert_equal('+-- 3 lines: Comment', foldtextresult(2))
1339
1340 bw!
1341endfunc
1342
1343" Test for merging two recursive folds when an intermediate line with no fold
1344" is removed
1345func Test_fold_merge_recrusive()
1346 new
1347 call setline(1, [' one', ' two', 'xxxx', ' three',
1348 \ ' four', "\tfive"])
1349 setlocal foldmethod=indent shiftwidth=2
1350 3d_
1351 %foldclose
1352 call assert_equal([1, 5], [foldclosed(5), foldclosedend(1)])
1353 bw!
1354endfunc
1355
1356" Test for moving a line which is the start of a fold from a recursive fold to
1357" outside. The fold length should reduce.
1358func Test_fold_move_foldlevel()
1359 new
1360 call setline(1, ['a{{{', 'b{{{', 'c{{{', 'd}}}', 'e}}}', 'f}}}', 'g'])
1361 setlocal foldmethod=marker
1362 normal zR
1363 call assert_equal([3, 2, 1], [foldlevel(4), foldlevel(5), foldlevel(6)])
1364 3move 7
1365 call assert_equal([2, 1, 0], [foldlevel(3), foldlevel(4), foldlevel(5)])
1366 call assert_equal(1, foldlevel(7))
1367
1368 " Move a line from outside a fold to inside the fold.
1369 %d _
1370 call setline(1, ['a', 'b{{{', 'c}}}'])
1371 normal zR
1372 1move 2
1373 call assert_equal([1, 1, 1], [foldlevel(1), foldlevel(2), foldlevel(3)])
1374
1375 " Move the start of one fold to inside another fold
1376 %d _
1377 call setline(1, ['a', 'b{{{', 'c}}}', 'd{{{', 'e}}}'])
1378 normal zR
1379 call assert_equal([0, 1, 1, 1, 1], [foldlevel(1), foldlevel(2),
1380 \ foldlevel(3), foldlevel(4), foldlevel(5)])
1381 1,2move 4
1382 call assert_equal([0, 1, 1, 2, 2], [foldlevel(1), foldlevel(2),
1383 \ foldlevel(3), foldlevel(4), foldlevel(5)])
1384
1385 bw!
1386endfunc
1387
Bram Moolenaar68ffe8c2021-04-05 12:47:25 +02001388" Test for using zj and zk to move downwards and upwards to the start and end
1389" of the next fold.
1390" Test for using [z and ]z in a closed fold to jump to the beginning and end
1391" of the fold.
1392func Test_fold_jump()
1393 new
1394 call setline(1, ["\t1", "\t2", "\t\t3", "\t\t4", "\t\t\t5", "\t\t\t6", "\t\t7", "\t\t8", "\t9", "\t10"])
1395 setlocal foldmethod=indent
1396 normal zR
1397 normal zj
1398 call assert_equal(3, line('.'))
1399 normal zj
1400 call assert_equal(5, line('.'))
1401 call assert_beeps('normal zj')
1402 call assert_equal(5, line('.'))
1403 call assert_beeps('normal 9Gzj')
1404 call assert_equal(9, line('.'))
1405 normal Gzk
1406 call assert_equal(8, line('.'))
1407 normal zk
1408 call assert_equal(6, line('.'))
1409 call assert_beeps('normal zk')
1410 call assert_equal(6, line('.'))
1411 call assert_beeps('normal 2Gzk')
1412 call assert_equal(2, line('.'))
1413
1414 " Using [z or ]z in a closed fold should not move the cursor
1415 %d _
1416 call setline(1, ["1", "\t2", "\t3", "\t4", "\t5", "\t6", "7"])
1417 normal zR4Gzc
1418 call assert_equal(4, line('.'))
1419 call assert_beeps('normal [z')
1420 call assert_equal(4, line('.'))
1421 call assert_beeps('normal ]z')
1422 call assert_equal(4, line('.'))
1423 bw!
1424endfunc
1425
Yegappan Lakshmanan8bb65f22021-12-26 10:51:39 +00001426" Test for using a script-local function for 'foldexpr'
1427func Test_foldexpr_scriptlocal_func()
1428 func! s:FoldFunc()
1429 let g:FoldLnum = v:lnum
1430 endfunc
1431 new | only
1432 call setline(1, 'abc')
1433 let g:FoldLnum = 0
1434 set foldmethod=expr foldexpr=s:FoldFunc()
1435 redraw!
1436 call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
1437 call assert_equal(1, g:FoldLnum)
1438 set foldmethod& foldexpr=
1439 bw!
1440 new | only
1441 call setline(1, 'abc')
1442 let g:FoldLnum = 0
1443 set foldmethod=expr foldexpr=<SID>FoldFunc()
1444 redraw!
1445 call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
1446 call assert_equal(1, g:FoldLnum)
1447 set foldmethod& foldexpr=
1448 delfunc s:FoldFunc
1449 bw!
1450endfunc
1451
Yegappan Lakshmanan27708e62021-12-26 21:54:43 +00001452" Test for using a script-local function for 'foldtext'
1453func Test_foldtext_scriptlocal_func()
1454 func! s:FoldText()
1455 let g:FoldTextArgs = [v:foldstart, v:foldend]
1456 return foldtext()
1457 endfunc
1458 new | only
1459 call setline(1, range(50))
1460 let g:FoldTextArgs = []
1461 set foldmethod=manual
1462 set foldtext=s:FoldText()
1463 norm! 4Gzf4j
1464 redraw!
1465 call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
1466 call assert_equal([4, 8], g:FoldTextArgs)
1467 set foldtext&
1468 bw!
1469 new | only
1470 call setline(1, range(50))
1471 let g:FoldTextArgs = []
1472 set foldmethod=manual
1473 set foldtext=<SID>FoldText()
1474 norm! 8Gzf4j
1475 redraw!
1476 call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
1477 call assert_equal([8, 12], g:FoldTextArgs)
1478 set foldtext&
1479 bw!
1480 delfunc s:FoldText
1481endfunc
1482
Brandon Simmons2c407072022-04-23 13:50:17 +01001483" Make sure a fold containing a nested fold is split correctly when using
1484" foldmethod=indent
1485func Test_fold_split()
1486 new
1487 let lines =<< trim END
1488 line 1
1489 line 2
1490 line 3
1491 line 4
1492 line 5
1493 END
1494 call setline(1, lines)
1495 setlocal sw=2
1496 setlocal foldmethod=indent foldenable
1497 call assert_equal([0, 1, 1, 2, 2], range(1, 5)->map('foldlevel(v:val)'))
1498 call append(2, 'line 2.5')
1499 call assert_equal([0, 1, 0, 1, 2, 2], range(1, 6)->map('foldlevel(v:val)'))
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +01001500 3d
1501 call assert_equal([0, 1, 1, 2, 2], range(1, 5)->map('foldlevel(v:val)'))
Brandon Simmons2c407072022-04-23 13:50:17 +01001502 bw!
1503endfunc
1504
Brandon Simmonsd98e75e2022-05-10 19:13:23 +01001505" Make sure that when you append under a blank line that is under a fold with
1506" the same indent level as your appended line, the fold expands across the
1507" blank line
1508func Test_indent_append_under_blank_line()
1509 new
1510 let lines =<< trim END
1511 line 1
1512 line 2
1513 line 3
1514 END
1515 call setline(1, lines)
1516 setlocal sw=2
1517 setlocal foldmethod=indent foldenable
1518 call assert_equal([0, 1, 1], range(1, 3)->map('foldlevel(v:val)'))
1519 call append(3, '')
1520 call append(4, ' line 5')
1521 call assert_equal([0, 1, 1, 1, 1], range(1, 5)->map('foldlevel(v:val)'))
1522 bw!
1523endfunc
1524
Brandon Simmons3fcccf92022-05-20 18:25:21 +01001525" Make sure that when you delete 1 line of a fold whose length is 2 lines, the
1526" fold can't be closed since its length (1) is now less than foldminlines.
1527func Test_indent_one_line_fold_close()
1528 let lines =<< trim END
1529 line 1
1530 line 2
1531 line 3
1532 END
1533
1534 new
1535 setlocal sw=2 foldmethod=indent
1536 call setline(1, lines)
1537 " open all folds, delete line, then close all folds
1538 normal zR
1539 3delete
1540 normal zM
1541 call assert_equal(-1, foldclosed(2)) " the fold should not be closed
1542
1543 " Now do the same, but delete line 2 this time; this covers different code.
1544 " (Combining this code with the above code doesn't expose both bugs.)
1545 1,$delete
1546 call setline(1, lines)
1547 normal zR
1548 2delete
1549 normal zM
1550 call assert_equal(-1, foldclosed(2))
1551 bw!
1552endfunc
1553
Brandon Simmonse8c4a642022-05-23 15:33:08 +01001554" Make sure that when appending [an indented line then a blank line] right
1555" before a single indented line, the resulting extended fold can be closed
1556func Test_indent_append_blank_small_fold_close()
1557 new
1558 setlocal sw=2 foldmethod=indent
1559 " at first, the fold at the second line can't be closed since it's smaller
1560 " than foldminlines
1561 let lines =<< trim END
1562 line 1
1563 line 4
1564 END
1565 call setline(1, lines)
1566 call append(1, [' line 2', ''])
1567 " close all folds
1568 normal zM
1569 call assert_notequal(-1, foldclosed(2)) " the fold should be closed now
1570 bw!
1571endfunc
1572
Bram Moolenaar9d8d0b52020-04-24 22:47:31 +02001573" vim: shiftwidth=2 sts=2 expandtab