xref: /vim-8.2.3635/src/testdir/test_syntax.vim (revision e30d1025)
1" Test for syntax and syntax iskeyword option
2
3source check.vim
4CheckFeature syntax
5
6source view_util.vim
7source screendump.vim
8
9func GetSyntaxItem(pat)
10  let c = ''
11  let a = ['a', getreg('a'), getregtype('a')]
12  0
13  redraw!
14  call search(a:pat, 'W')
15  let synid = synID(line('.'), col('.'), 1)
16  while synid == synID(line('.'), col('.'), 1)
17    norm! v"ay
18    " stop at whitespace
19    if @a =~# '\s'
20      break
21    endif
22    let c .= @a
23    norm! l
24  endw
25  call call('setreg', a)
26  0
27  return c
28endfunc
29
30func AssertHighlightGroups(lnum, startcol, expected, trans = 1, msg = "")
31  " Assert that the characters starting at a given (line, col)
32  " sequentially match the expected highlight groups.
33  " If groups are provided as a string, each character is assumed to be a
34  " group and spaces represent no group, useful for visually describing tests.
35  let l:expectedGroups = type(a:expected) == v:t_string
36        \ ? a:expected->split('\zs')->map({_, v -> trim(v)})
37        \ : a:expected
38  let l:errors = 0
39  let l:msg = (a:msg->empty() ? "" : a:msg .. ": ")
40        \ .. "Wrong highlight group at " .. a:lnum .. ","
41
42  for l:i in range(a:startcol, a:startcol + l:expectedGroups->len() - 1)
43    let l:errors += synID(a:lnum, l:i, a:trans)
44          \ ->synIDattr("name")
45          \ ->assert_equal(l:expectedGroups[l:i - 1],
46          \    l:msg .. l:i)
47  endfor
48endfunc
49
50func Test_syn_iskeyword()
51  new
52  call setline(1, [
53	\ 'CREATE TABLE FOOBAR(',
54	\ '    DLTD_BY VARCHAR2(100)',
55	\ ');',
56	\ ''])
57
58  syntax on
59  set ft=sql
60  syn match SYN /C\k\+\>/
61  hi link SYN ErrorMsg
62  call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
63  /\<D\k\+\>/:norm! ygn
64  call assert_equal('DLTD_BY', @0)
65  redir @c
66  syn iskeyword
67  redir END
68  call assert_equal("\nsyntax iskeyword not set", @c)
69
70  syn iskeyword @,48-57,_,192-255
71  redir @c
72  syn iskeyword
73  redir END
74  call assert_equal("\nsyntax iskeyword @,48-57,_,192-255", @c)
75
76  setlocal isk-=_
77  call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
78  /\<D\k\+\>/:norm! ygn
79  let b2 = @0
80  call assert_equal('DLTD', @0)
81
82  syn iskeyword clear
83  redir @c
84  syn iskeyword
85  redir END
86  call assert_equal("\nsyntax iskeyword not set", @c)
87
88  quit!
89endfunc
90
91func Test_syntax_after_reload()
92  split Xsomefile
93  call setline(1, ['hello', 'there'])
94  w!
95  only!
96  setl filetype=hello
97  au FileType hello let g:gotit = 1
98  call assert_false(exists('g:gotit'))
99  edit other
100  buf Xsomefile
101  call assert_equal('hello', &filetype)
102  call assert_true(exists('g:gotit'))
103  call delete('Xsomefile')
104endfunc
105
106func Test_syntime()
107  CheckFeature profile
108
109  syntax on
110  syntime on
111  let a = execute('syntime report')
112  call assert_equal("\nNo Syntax items defined for this buffer", a)
113
114  let a = execute('syntime clear')
115  call assert_equal("\nNo Syntax items defined for this buffer", a)
116
117  view ../memfile_test.c
118  setfiletype cpp
119  redraw
120  let a = execute('syntime report')
121  call assert_match('^  TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
122  call assert_match(' \d*\.\d* \+[^0]\d* .* cppRawString ', a)
123  call assert_match(' \d*\.\d* \+[^0]\d* .* cppNumber ', a)
124
125  syntime off
126  syntime clear
127  let a = execute('syntime report')
128  call assert_match('^  TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
129  call assert_notmatch('.* cppRawString *', a)
130  call assert_notmatch('.* cppNumber*', a)
131  call assert_notmatch('[1-9]', a)
132
133  call assert_fails('syntime abc', 'E475:')
134
135  syntax clear
136  let a = execute('syntime report')
137  call assert_equal("\nNo Syntax items defined for this buffer", a)
138
139  bd
140endfunc
141
142func Test_syntime_completion()
143  CheckFeature profile
144
145  call feedkeys(":syntime \<C-A>\<C-B>\"\<CR>", 'tx')
146  call assert_equal('"syntime clear off on report', @:)
147endfunc
148
149func Test_syntax_list()
150  syntax on
151  let a = execute('syntax list')
152  call assert_equal("\nNo Syntax items defined for this buffer", a)
153
154  view ../memfile_test.c
155  setfiletype c
156
157  let a = execute('syntax list')
158  call assert_match('cInclude*', a)
159  call assert_match('cDefine', a)
160
161  let a = execute('syntax list cDefine')
162  call assert_notmatch('cInclude*', a)
163  call assert_match('cDefine', a)
164  call assert_match(' links to Macro$', a)
165
166  call assert_fails('syntax list ABCD', 'E28:')
167  call assert_fails('syntax list @ABCD', 'E392:')
168
169  syntax clear
170  let a = execute('syntax list')
171  call assert_equal("\nNo Syntax items defined for this buffer", a)
172
173  syntax keyword Type int containedin=g1 skipwhite skipempty skipnl nextgroup=Abc
174  let exp = "Type           xxx containedin=g1  nextgroup=Abc  skipnl skipwhite skipempty int"
175  call assert_equal(exp, split(execute("syntax list"), "\n")[1])
176
177  bd
178endfunc
179
180func Test_syntax_completion()
181  call feedkeys(":syn \<C-A>\<C-B>\"\<CR>", 'tx')
182  call assert_equal('"syn case clear cluster conceal enable foldlevel include iskeyword keyword list manual match off on region reset spell sync', @:)
183
184  call feedkeys(":syn case \<C-A>\<C-B>\"\<CR>", 'tx')
185  call assert_equal('"syn case ignore match', @:)
186
187  call feedkeys(":syn spell \<C-A>\<C-B>\"\<CR>", 'tx')
188  call assert_equal('"syn spell default notoplevel toplevel', @:)
189
190  call feedkeys(":syn sync \<C-A>\<C-B>\"\<CR>", 'tx')
191  call assert_equal('"syn sync ccomment clear fromstart linebreaks= linecont lines= match maxlines= minlines= region', @:)
192
193  " Check that clearing "Aap" avoids it showing up before Boolean.
194  hi Aap ctermfg=blue
195  call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
196  call assert_match('^"syn list Aap Boolean Character ', @:)
197  hi clear Aap
198
199  call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
200  call assert_match('^"syn list Boolean Character ', @:)
201
202  call feedkeys(":syn match \<C-A>\<C-B>\"\<CR>", 'tx')
203  call assert_match('^"syn match Boolean Character ', @:)
204endfunc
205
206func Test_echohl_completion()
207  call feedkeys(":echohl no\<C-A>\<C-B>\"\<CR>", 'tx')
208  call assert_equal('"echohl NonText Normal none', @:)
209endfunc
210
211func Test_syntax_arg_skipped()
212  syn clear
213  syntax case ignore
214  if 0
215    syntax case match
216  endif
217  call assert_match('case ignore', execute('syntax case'))
218
219  syn keyword Foo foo
220  call assert_match('Foo', execute('syntax'))
221  syn clear
222  call assert_match('case match', execute('syntax case'))
223  call assert_notmatch('Foo', execute('syntax'))
224
225  if has('conceal')
226    syn clear
227    syntax conceal on
228    if 0
229      syntax conceal off
230    endif
231    call assert_match('conceal on', execute('syntax conceal'))
232    syn clear
233    call assert_match('conceal off', execute('syntax conceal'))
234
235    syntax conceal on
236    syntax conceal off
237    call assert_match('conceal off', execute('syntax conceal'))
238  endif
239
240  syntax region Bar start=/</ end=/>/
241  if 0
242    syntax region NotTest start=/</ end=/>/ contains=@Spell
243  endif
244  call assert_match('Bar', execute('syntax'))
245  call assert_notmatch('NotTest', execute('syntax'))
246  call assert_notmatch('Spell', execute('syntax'))
247
248  hi Foo ctermfg=blue
249  let a = execute('hi Foo')
250  if 0
251    syntax rest
252  endif
253  call assert_equal(a, execute('hi Foo'))
254  hi clear Bar
255  hi clear Foo
256
257  set ft=tags
258  syn off
259  if 0
260    syntax enable
261  endif
262  call assert_match('No Syntax items defined', execute('syntax'))
263  syntax enable
264  call assert_match('tagComment', execute('syntax'))
265  set ft=
266
267  syn clear
268  if 0
269    syntax include @Spell nothing
270  endif
271  call assert_notmatch('Spell', execute('syntax'))
272
273  syn clear
274  syn iskeyword 48-57,$,_
275  call assert_match('48-57,$,_', execute('syntax iskeyword'))
276  if 0
277    syn clear
278    syn iskeyword clear
279  endif
280  call assert_match('48-57,$,_', execute('syntax iskeyword'))
281  syn iskeyword clear
282  call assert_match('not set', execute('syntax iskeyword'))
283  syn iskeyword 48-57,$,_
284  syn clear
285  call assert_match('not set', execute('syntax iskeyword'))
286
287  syn clear
288  syn keyword Foo foo
289  if 0
290    syn keyword NotAdded bar
291  endif
292  call assert_match('Foo', execute('syntax'))
293  call assert_notmatch('NotAdded', execute('highlight'))
294
295  syn clear
296  syn keyword Foo foo
297  call assert_match('Foo', execute('syntax'))
298  call assert_match('Foo', execute('syntax list'))
299  call assert_notmatch('Foo', execute('if 0 | syntax | endif'))
300  call assert_notmatch('Foo', execute('if 0 | syntax list | endif'))
301
302  syn clear
303  syn match Fopi /asdf/
304  if 0
305    syn match Fopx /asdf/
306  endif
307  call assert_match('Fopi', execute('syntax'))
308  call assert_notmatch('Fopx', execute('syntax'))
309
310  syn clear
311  syn spell toplevel
312  call assert_match('spell toplevel', execute('syntax spell'))
313  if 0
314    syn spell notoplevel
315  endif
316  call assert_match('spell toplevel', execute('syntax spell'))
317  syn spell notoplevel
318  call assert_match('spell notoplevel', execute('syntax spell'))
319  syn spell default
320  call assert_match('spell default', execute('syntax spell'))
321
322  syn clear
323  if 0
324    syntax cluster Spell
325  endif
326  call assert_notmatch('Spell', execute('syntax'))
327
328  syn clear
329  syn keyword Foo foo
330  syn sync ccomment
331  syn sync maxlines=5
332  if 0
333    syn sync maxlines=11
334  endif
335  call assert_match('on C-style comments', execute('syntax sync'))
336  call assert_match('maximal 5 lines', execute('syntax sync'))
337  syn sync clear
338  if 0
339    syn sync ccomment
340  endif
341  call assert_notmatch('on C-style comments', execute('syntax sync'))
342  syn sync fromstart
343  call assert_match('syncing starts at the first line', execute('syntax sync'))
344
345  syn clear
346endfunc
347
348" Check for an error. Used when multiple errors are thrown and we are checking
349" for an earliest error.
350func AssertFails(cmd, errcode)
351  let save_exception = ''
352  try
353    exe a:cmd
354  catch
355    let save_exception = v:exception
356  endtry
357  call assert_match(a:errcode, save_exception)
358endfunc
359
360func Test_syntax_invalid_arg()
361  call assert_fails('syntax case asdf', 'E390:')
362  if has('conceal')
363    call assert_fails('syntax conceal asdf', 'E390:')
364  endif
365  call assert_fails('syntax spell asdf', 'E390:')
366  call assert_fails('syntax clear @ABCD', 'E391:')
367  call assert_fails('syntax include random_file', 'E484:')
368  call assert_fails('syntax include <afile>', 'E495:')
369  call assert_fails('syntax sync x', 'E404:')
370  call assert_fails('syntax keyword Abc a[', 'E789:')
371  call assert_fails('syntax keyword Abc a[bc]d', 'E890:')
372  call assert_fails('syntax cluster Abc add=A add=', 'E406:')
373
374  " Test for too many \z\( and unmatched \z\(
375  " Not able to use assert_fails() here because both E50:/E879: and E475:
376  " messages are emitted.
377  set regexpengine=1
378  call AssertFails("syntax region MyRegion start='\\z\\(' end='\\*/'", 'E52:')
379
380  let cmd = "syntax region MyRegion start='"
381  let cmd ..= repeat("\\z\\(.\\)", 10) .. "' end='\*/'"
382  call AssertFails(cmd, 'E50:')
383
384  set regexpengine=2
385  call AssertFails("syntax region MyRegion start='\\z\\(' end='\\*/'", 'E54:')
386
387  let cmd = "syntax region MyRegion start='"
388  let cmd ..= repeat("\\z\\(.\\)", 10) .. "' end='\*/'"
389  call AssertFails(cmd, 'E879:')
390  set regexpengine&
391
392  call AssertFails('syntax keyword cMyItem grouphere G1', 'E393:')
393  call AssertFails('syntax sync match Abc grouphere MyItem "abc"', 'E394:')
394  call AssertFails('syn keyword Type contains int', 'E395:')
395  call assert_fails('syntax include @Xxx', 'E397:')
396  call AssertFails('syntax region X start', 'E398:')
397  call assert_fails('syntax region X start="{"', 'E399:')
398  call AssertFails('syntax cluster contains=Abc', 'E400:')
399  call AssertFails("syntax match Character /'.'", 'E401:')
400  call AssertFails("syntax match Character /'.'/a", 'E402:')
401  call assert_fails('syntax sync linecont /\%(/', 'E53:')
402  call assert_fails('syntax sync linecont /pat', 'E404:')
403  call assert_fails('syntax sync linecont', 'E404:')
404  call assert_fails('syntax sync linecont /pat1/ linecont /pat2/', 'E403:')
405  call assert_fails('syntax sync minlines=a', 'E404:')
406  call AssertFails('syntax match ABC /x/ contains=', 'E406:')
407  call AssertFails("syntax match Character contains /'.'/", 'E405:')
408  call AssertFails('syntax match ccFoo "Foo" nextgroup=ALLBUT,F', 'E407:')
409  call AssertFails('syntax region Block start="{" contains=F,ALLBUT', 'E408:')
410  call AssertFails("syntax match Characters contains=a.*x /'.'/", 'E409:')
411  call assert_fails('syntax match Search /abc/ contains=ALLBUT,/\%(/', 'E53:')
412endfunc
413
414func Test_syn_sync()
415  syntax region HereGroup start=/this/ end=/that/
416  syntax sync match SyncHere grouphere HereGroup "pattern"
417  call assert_match('SyncHere', execute('syntax sync'))
418  syn sync clear
419  call assert_notmatch('SyncHere', execute('syntax sync'))
420  syn clear
421endfunc
422
423func Test_syn_clear()
424  syntax keyword Foo foo
425  syntax keyword Bar tar
426  call assert_match('Foo', execute('syntax'))
427  call assert_match('Bar', execute('syntax'))
428  call assert_equal('Foo', synIDattr(hlID("Foo"), "name"))
429  syn clear Foo
430  call assert_notmatch('Foo', execute('syntax'))
431  call assert_match('Bar', execute('syntax'))
432  call assert_equal('Foo', synIDattr(hlID("Foo"), "name"))
433  syn clear Foo Bar
434  call assert_notmatch('Foo', execute('syntax'))
435  call assert_notmatch('Bar', execute('syntax'))
436  hi clear Foo
437  call assert_equal('Foo', synIDattr(hlID("Foo"), "name"))
438  hi clear Bar
439  call assert_fails('syntax clear invalid_syngroup', 'E28:')
440endfunc
441
442func Test_invalid_name()
443  syn clear
444  syn keyword Nop yes
445  call assert_fails("syntax keyword Wr\x17ong bar", 'E669:')
446  syntax keyword @Wrong bar
447  call assert_match('W18:', execute('1messages'))
448  syn clear
449  hi clear Nop
450  hi clear @Wrong
451endfunc
452
453func Test_ownsyntax()
454  new Xfoo
455  call setline(1, '#define FOO')
456  syntax on
457  set filetype=c
458
459  ownsyntax perl
460  " this should not crash
461  set
462
463  call assert_equal('perlComment', synIDattr(synID(line('.'), col('.'), 1), 'name'))
464  call assert_equal('c',    b:current_syntax)
465  call assert_equal('perl', w:current_syntax)
466
467  " A new split window should have the original syntax.
468  split
469  call assert_equal('cDefine', synIDattr(synID(line('.'), col('.'), 1), 'name'))
470  call assert_equal('c', b:current_syntax)
471  call assert_equal(0, exists('w:current_syntax'))
472
473  wincmd x
474  call assert_equal('perlComment', synIDattr(synID(line("."), col("."), 1), "name"))
475
476  syntax off
477  set filetype&
478  %bw!
479endfunc
480
481func Test_ownsyntax_completion()
482  call feedkeys(":ownsyntax java\<C-A>\<C-B>\"\<CR>", 'tx')
483  call assert_equal('"ownsyntax java javacc javascript javascriptreact', @:)
484endfunc
485
486func Test_highlight_invalid_arg()
487  if has('gui_running')
488    call assert_fails('hi XXX guifg=xxx', 'E254:')
489  endif
490  call assert_fails('hi DoesNotExist', 'E411:')
491  call assert_fails('hi link', 'E412:')
492  call assert_fails('hi link a', 'E412:')
493  call assert_fails('hi link a b c', 'E413:')
494  call assert_fails('hi XXX =', 'E415:')
495  call assert_fails('hi XXX cterm', 'E416:')
496  call assert_fails('hi XXX cterm=', 'E417:')
497  call assert_fails('hi XXX cterm=DoesNotExist', 'E418:')
498  call assert_fails('hi XXX ctermfg=DoesNotExist', 'E421:')
499  call assert_fails('hi XXX xxx=White', 'E423:')
500endfunc
501
502func Test_bg_detection()
503  CheckNotGui
504
505  " auto-detection of &bg, make sure sure it isn't set anywhere before
506  " this test
507  hi Normal ctermbg=0
508  call assert_equal('dark', &bg)
509  hi Normal ctermbg=4
510  call assert_equal('dark', &bg)
511  hi Normal ctermbg=12
512  call assert_equal('light', &bg)
513  hi Normal ctermbg=15
514  call assert_equal('light', &bg)
515
516  " manually-set &bg takes precedence over auto-detection
517  set bg=light
518  hi Normal ctermbg=4
519  call assert_equal('light', &bg)
520  set bg=dark
521  hi Normal ctermbg=12
522  call assert_equal('dark', &bg)
523
524  hi Normal ctermbg=NONE
525endfunc
526
527func Test_syntax_hangs()
528  CheckFunction reltimefloat
529  CheckFeature syntax
530
531  " This pattern takes a long time to match, it should timeout.
532  new
533  call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
534  let start = reltime()
535  set nolazyredraw redrawtime=101
536  syn match Error /\%#=1a*.*X\@<=b*/
537  redraw
538  let elapsed = reltimefloat(reltime(start))
539  call assert_true(elapsed > 0.1)
540  call assert_true(elapsed < 1.0)
541
542  " second time syntax HL is disabled
543  let start = reltime()
544  redraw
545  let elapsed = reltimefloat(reltime(start))
546  call assert_true(elapsed < 0.1)
547
548  " after CTRL-L the timeout flag is reset
549  let start = reltime()
550  exe "normal \<C-L>"
551  redraw
552  let elapsed = reltimefloat(reltime(start))
553  call assert_true(elapsed > 0.1)
554  call assert_true(elapsed < 1.0)
555
556  set redrawtime&
557  bwipe!
558endfunc
559
560func Test_conceal()
561  CheckFeature conceal
562
563  new
564  call setline(1, ['', '123456'])
565  syn match test23 "23" conceal cchar=X
566  syn match test45 "45" conceal
567
568  set conceallevel=0
569  call assert_equal('123456 ', ScreenLines(2, 7)[0])
570  call assert_equal([[0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
571
572  set conceallevel=1
573  call assert_equal('1X 6   ', ScreenLines(2, 7)[0])
574  call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, ' ', 2], [1, ' ', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
575
576  set conceallevel=1
577  set listchars=conceal:Y
578  call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, 'Y', 2], [1, 'Y', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
579  call assert_equal('1XY6   ', ScreenLines(2, 7)[0])
580
581  set conceallevel=2
582  call assert_match('1X6    ', ScreenLines(2, 7)[0])
583  call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
584
585  set conceallevel=3
586  call assert_match('16     ', ScreenLines(2, 7)[0])
587  call assert_equal([[0, '', 0], [1, '', 1], [1, '', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
588
589  call AssertFails("syntax match Entity '&amp;' conceal cchar=\<Tab>", 'E844:')
590
591  syn clear
592  set conceallevel&
593  bw!
594endfunc
595
596func Test_synstack_synIDtrans()
597  new
598  setfiletype c
599  syntax on
600  call setline(1, ' /* A comment with a TODO */')
601
602  call assert_equal([], synstack(1, 1))
603
604  norm f/
605  eval synstack(line("."), col("."))->map('synIDattr(v:val, "name")')->assert_equal(['cComment', 'cCommentStart'])
606  eval synstack(line("."), col("."))->map('synIDattr(synIDtrans(v:val), "name")')->assert_equal(['Comment', 'Comment'])
607
608  norm fA
609  call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
610  call assert_equal(['Comment'],  map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
611
612  norm fT
613  call assert_equal(['cComment', 'cTodo'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
614  call assert_equal(['Comment', 'Todo'],   map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
615
616  call assert_fails("let n=synIDtrans([])", 'E745:')
617
618  syn clear
619  bw!
620endfunc
621
622" Check highlighting for a small piece of C code with a screen dump.
623func Test_syntax_c()
624  CheckRunVimInTerminal
625  call writefile([
626	\ '/* comment line at the top */',
627	\ 'int main(int argc, char **argv) { // another comment',
628	\ '#if 0',
629	\ '   int   not_used;',
630	\ '#else',
631	\ '   int   used;',
632	\ '#endif',
633	\ '   printf("Just an example piece of C code\n");',
634	\ '   return 0x0ff;',
635	\ '}',
636	\ "\t\t ",
637	\ '   static void',
638	\ 'myFunction(const double count, struct nothing, long there) {',
639	\ "\t// 123: nothing to endif here",
640	\ "\tfor (int i = 0; i < count; ++i) {",
641	\ "\t   break;",
642	\ "\t}",
643	\ "\tNote: asdf",
644	\ '}',
645	\ ], 'Xtest.c')
646
647  " This makes the default for 'background' use "dark", check that the
648  " response to t_RB corrects it to "light".
649  let $COLORFGBG = '15;0'
650
651  let buf = RunVimInTerminal('Xtest.c', {})
652  call term_sendkeys(buf, ":syn keyword Search Note\r")
653  call term_sendkeys(buf, ":syn match Error /^\\s\\+$/\r")
654  call term_sendkeys(buf, ":set hlsearch\r")
655  call term_sendkeys(buf, "/endif\r")
656  call term_sendkeys(buf, "vjfC")
657  call VerifyScreenDump(buf, 'Test_syntax_c_01', {})
658
659  call term_sendkeys(buf, "\<Esc>")
660  call StopVimInTerminal(buf)
661
662  let $COLORFGBG = ''
663  call delete('Xtest.c')
664endfun
665
666" Using \z() in a region with NFA failing should not crash.
667func Test_syn_wrong_z_one()
668  new
669  call setline(1, ['just some text', 'with foo and bar to match with'])
670  syn region FooBar start="foo\z(.*\)bar" end="\z1"
671  call test_override("nfa_fail", 1)
672  redraw!
673  redraw!
674  call test_override("ALL", 0)
675  bwipe!
676endfunc
677
678func Test_syntax_after_bufdo()
679  call writefile(['/* aaa comment */'], 'Xaaa.c')
680  call writefile(['/* bbb comment */'], 'Xbbb.c')
681  call writefile(['/* ccc comment */'], 'Xccc.c')
682  call writefile(['/* ddd comment */'], 'Xddd.c')
683
684  let bnr = bufnr('%')
685  new Xaaa.c
686  badd Xbbb.c
687  badd Xccc.c
688  badd Xddd.c
689  exe "bwipe " . bnr
690  let l = []
691  bufdo call add(l, bufnr('%'))
692  call assert_equal(4, len(l))
693
694  syntax on
695
696  " This used to only enable syntax HL in the last buffer.
697  bufdo tab split
698  tabrewind
699  for tab in range(1, 4)
700    norm fm
701    call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
702    tabnext
703  endfor
704
705  bwipe! Xaaa.c
706  bwipe! Xbbb.c
707  bwipe! Xccc.c
708  bwipe! Xddd.c
709  syntax off
710  call delete('Xaaa.c')
711  call delete('Xbbb.c')
712  call delete('Xccc.c')
713  call delete('Xddd.c')
714endfunc
715
716func Test_syntax_foldlevel()
717  new
718  call setline(1, [
719   \ 'void f(int a)',
720   \ '{',
721   \ '    if (a == 1) {',
722   \ '        a = 0;',
723   \ '    } else if (a == 2) {',
724   \ '        a = 1;',
725   \ '    } else {',
726   \ '        a = 2;',
727   \ '    }',
728   \ '    if (a > 0) {',
729   \ '        if (a == 1) {',
730   \ '            a = 0;',
731   \ '        } /* missing newline */ } /* end of outer if */ else {',
732   \ '        a = 1;',
733   \ '    }',
734   \ '    if (a == 1)',
735   \ '    {',
736   \ '        a = 0;',
737   \ '    }',
738   \ '    else if (a == 2)',
739   \ '    {',
740   \ '        a = 1;',
741   \ '    }',
742   \ '    else',
743   \ '    {',
744   \ '        a = 2;',
745   \ '    }',
746   \ '}',
747   \ ])
748  setfiletype c
749  syntax on
750  set foldmethod=syntax
751
752  call assert_fails('syn foldlevel start start', 'E390:')
753  call assert_fails('syn foldlevel not_an_option', 'E390:')
754
755  set foldlevel=1
756
757  syn foldlevel start
758  redir @c
759  syn foldlevel
760  redir END
761  call assert_equal("\nsyntax foldlevel start", @c)
762  syn sync fromstart
763  call assert_match('from the first line$', execute('syn sync'))
764  let a = map(range(3,9), 'foldclosed(v:val)')
765  call assert_equal([3,3,3,3,3,3,3], a) " attached cascade folds together
766  let a = map(range(10,15), 'foldclosed(v:val)')
767  call assert_equal([10,10,10,10,10,10], a) " over-attached 'else' hidden
768  let a = map(range(16,27), 'foldclosed(v:val)')
769  let unattached_results = [-1,17,17,17,-1,21,21,21,-1,25,25,25]
770  call assert_equal(unattached_results, a) " unattached cascade folds separately
771
772  syn foldlevel minimum
773  redir @c
774  syn foldlevel
775  redir END
776  call assert_equal("\nsyntax foldlevel minimum", @c)
777  syn sync fromstart
778  let a = map(range(3,9), 'foldclosed(v:val)')
779  call assert_equal([3,3,5,5,7,7,7], a) " attached cascade folds separately
780  let a = map(range(10,15), 'foldclosed(v:val)')
781  call assert_equal([10,10,10,13,13,13], a) " over-attached 'else' visible
782  let a = map(range(16,27), 'foldclosed(v:val)')
783  call assert_equal(unattached_results, a) " unattached cascade folds separately
784
785  set foldlevel=2
786
787  syn foldlevel start
788  syn sync fromstart
789  let a = map(range(11,14), 'foldclosed(v:val)')
790  call assert_equal([11,11,11,-1], a) " over-attached 'else' hidden
791
792  syn foldlevel minimum
793  syn sync fromstart
794  let a = map(range(11,14), 'foldclosed(v:val)')
795  call assert_equal([11,11,-1,-1], a) " over-attached 'else' visible
796
797  quit!
798endfunc
799
800func Test_search_syntax_skip()
801  new
802  let lines =<< trim END
803
804        /* This is VIM */
805        Another Text for VIM
806         let a = "VIM"
807  END
808  call setline(1, lines)
809  syntax on
810  syntax match Comment "^/\*.*\*/"
811  syntax match String '".*"'
812
813  " Skip argument using string evaluation.
814  1
815  call search('VIM', 'w', '', 0, 'synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"')
816  call assert_equal('Another Text for VIM', getline('.'))
817  1
818  call search('VIM', 'w', '', 0, 'synIDattr(synID(line("."), col("."), 1), "name") !~? "string"')
819  call assert_equal(' let a = "VIM"', getline('.'))
820
821  " Skip argument using Lambda.
822  1
823  call search('VIM', 'w', '', 0, { -> synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"})
824  call assert_equal('Another Text for VIM', getline('.'))
825
826  1
827  call search('VIM', 'w', '', 0, { -> synIDattr(synID(line("."), col("."), 1), "name") !~? "string"})
828  call assert_equal(' let a = "VIM"', getline('.'))
829
830  " Skip argument using funcref.
831  func InComment()
832    return synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"
833  endfunc
834  func InString()
835    return synIDattr(synID(line("."), col("."), 1), "name") !~? "string"
836  endfunc
837  1
838  call search('VIM', 'w', '', 0, function('InComment'))
839  call assert_equal('Another Text for VIM', getline('.'))
840
841  1
842  call search('VIM', 'w', '', 0, function('InString'))
843  call assert_equal(' let a = "VIM"', getline('.'))
844
845  delfunc InComment
846  delfunc InString
847  bwipe!
848endfunc
849
850func Test_syn_contained_transparent()
851  " Comments starting with "Regression:" show the result when the highlighting
852  " span of the containing item is assigned to the contained region.
853  syntax on
854
855  let l:case = "Transparent region contained in region"
856  new
857  syntax region X start=/\[/ end=/\]/ contained transparent
858  syntax region Y start=/(/ end=/)/ contains=X
859
860  call setline(1,  "==(--[~~]--)==")
861  let l:expected = "  YYYYYYYYYY  "
862  eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
863  syntax clear Y X
864  bw!
865
866  let l:case = "Transparent region extends region"
867  new
868  syntax region X start=/\[/ end=/\]/ contained transparent
869  syntax region Y start=/(/ end=/)/ end=/e/ contains=X
870
871  call setline(1,  "==(--[~~e~~]--)==")
872  let l:expected = "  YYYYYYYYYYYYY  "
873  " Regression:    "  YYYYYYY   YYY  "
874  eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
875  syntax clear Y X
876  bw!
877
878  let l:case = "Nested transparent regions extend region"
879  new
880  syntax region X start=/\[/ end=/\]/ contained transparent
881  syntax region Y start=/(/ end=/)/ end=/e/ contains=X
882
883  call setline(1,  "==(--[~~e~~[~~e~~]~~e~~]--)==")
884  let l:expected = "  YYYYYYYYYYYYYYYYYYYYYYYYY  "
885  " Regression:    "  YYYYYYY         YYYYYYYYY  "
886  eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
887  syntax clear Y X
888  bw!
889
890  let l:case = "Transparent region contained in match"
891  new
892  syntax region X start=/\[/ end=/\]/ contained transparent
893  syntax match Y /(.\{-})/ contains=X
894
895  call setline(1,  "==(--[~~]--)==")
896  let l:expected = "  YYYYYYYYYY  "
897  eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
898  syntax clear Y X
899  bw!
900
901  let l:case = "Transparent region extends match"
902  new
903  syntax region X start=/\[/ end=/\]/ contained transparent
904  syntax match Y /(.\{-}[e)]/ contains=X
905
906  call setline(1,  "==(--[~~e~~]--)==")
907  let l:expected = "  YYYYYYYYYY     "
908  " Regression:    "  YYYYYYY        "
909  eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
910  syntax clear Y X
911  bw!
912
913  let l:case = "Nested transparent regions extend match"
914  new
915  syntax region X start=/\[/ end=/\]/ contained transparent
916  syntax match Y /(.\{-}[e)]/ contains=X
917
918  call setline(1,  "==(--[~~e~~[~~e~~]~~e~~]--)==")
919  let l:expected = "  YYYYYYYYYYYYYYYYYYYYYY     "
920  " Regression:    "  YYYYYYY         YYYYYY     "
921  eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
922  syntax clear Y X
923  bw!
924endfunc
925
926func Test_syn_include_contains_TOP()
927  let l:case = "TOP in included syntax means its group list name"
928  new
929  syntax include @INCLUDED syntax/c.vim
930  syntax region FencedCodeBlockC start=/```c/ end=/```/ contains=@INCLUDED
931
932  call setline(1,  ['```c', '#if 0', 'int', '#else', 'int', '#endif', '```' ])
933  let l:expected = ["cCppOutIf2"]
934  eval AssertHighlightGroups(3, 1, l:expected, 1)
935  " cCppOutElse has contains=TOP
936  let l:expected = ["cType"]
937  eval AssertHighlightGroups(5, 1, l:expected, 1, l:case)
938  syntax clear
939  bw!
940endfunc
941
942
943" vim: shiftwidth=2 sts=2 expandtab
944