neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

test_syntax.vim (29109B)


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