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 Test_syn_iskeyword() 31 new 32 call setline(1, [ 33 \ 'CREATE TABLE FOOBAR(', 34 \ ' DLTD_BY VARCHAR2(100)', 35 \ ');', 36 \ '']) 37 38 syntax on 39 set ft=sql 40 syn match SYN /C\k\+\>/ 41 hi link SYN ErrorMsg 42 call assert_equal('DLTD_BY', GetSyntaxItem('DLTD')) 43 /\<D\k\+\>/:norm! ygn 44 call assert_equal('DLTD_BY', @0) 45 redir @c 46 syn iskeyword 47 redir END 48 call assert_equal("\nsyntax iskeyword not set", @c) 49 50 syn iskeyword @,48-57,_,192-255 51 redir @c 52 syn iskeyword 53 redir END 54 call assert_equal("\nsyntax iskeyword @,48-57,_,192-255", @c) 55 56 setlocal isk-=_ 57 call assert_equal('DLTD_BY', GetSyntaxItem('DLTD')) 58 /\<D\k\+\>/:norm! ygn 59 let b2 = @0 60 call assert_equal('DLTD', @0) 61 62 syn iskeyword clear 63 redir @c 64 syn iskeyword 65 redir END 66 call assert_equal("\nsyntax iskeyword not set", @c) 67 68 quit! 69endfunc 70 71func Test_syntax_after_reload() 72 split Xsomefile 73 call setline(1, ['hello', 'there']) 74 w! 75 only! 76 setl filetype=hello 77 au FileType hello let g:gotit = 1 78 call assert_false(exists('g:gotit')) 79 edit other 80 buf Xsomefile 81 call assert_equal('hello', &filetype) 82 call assert_true(exists('g:gotit')) 83 call delete('Xsomefile') 84endfunc 85 86func Test_syntime() 87 if !has('profile') 88 return 89 endif 90 91 syntax on 92 syntime on 93 let a = execute('syntime report') 94 call assert_equal("\nNo Syntax items defined for this buffer", a) 95 96 view ../memfile_test.c 97 setfiletype cpp 98 redraw 99 let a = execute('syntime report') 100 call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a) 101 call assert_match(' \d*\.\d* \+[^0]\d* .* cppRawString ', a) 102 call assert_match(' \d*\.\d* \+[^0]\d* .* cppNumber ', a) 103 104 syntime off 105 syntime clear 106 let a = execute('syntime report') 107 call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a) 108 call assert_notmatch('.* cppRawString *', a) 109 call assert_notmatch('.* cppNumber*', a) 110 call assert_notmatch('[1-9]', a) 111 112 call assert_fails('syntime abc', 'E475') 113 114 syntax clear 115 let a = execute('syntime report') 116 call assert_equal("\nNo Syntax items defined for this buffer", a) 117 118 bd 119endfunc 120 121func Test_syntime_completion() 122 if !has('profile') 123 return 124 endif 125 126 call feedkeys(":syntime \<C-A>\<C-B>\"\<CR>", 'tx') 127 call assert_equal('"syntime clear off on report', @:) 128endfunc 129 130func Test_syntax_list() 131 syntax on 132 let a = execute('syntax list') 133 call assert_equal("\nNo Syntax items defined for this buffer", a) 134 135 view ../memfile_test.c 136 setfiletype c 137 138 let a = execute('syntax list') 139 call assert_match('cInclude*', a) 140 call assert_match('cDefine', a) 141 142 let a = execute('syntax list cDefine') 143 call assert_notmatch('cInclude*', a) 144 call assert_match('cDefine', a) 145 call assert_match(' links to Macro$', a) 146 147 call assert_fails('syntax list ABCD', 'E28:') 148 call assert_fails('syntax list @ABCD', 'E392:') 149 150 syntax clear 151 let a = execute('syntax list') 152 call assert_equal("\nNo Syntax items defined for this buffer", a) 153 154 bd 155endfunc 156 157func Test_syntax_completion() 158 call feedkeys(":syn \<C-A>\<C-B>\"\<CR>", 'tx') 159 call assert_equal('"syn case clear cluster conceal enable include iskeyword keyword list manual match off on region reset spell sync', @:) 160 161 call feedkeys(":syn case \<C-A>\<C-B>\"\<CR>", 'tx') 162 call assert_equal('"syn case ignore match', @:) 163 164 call feedkeys(":syn spell \<C-A>\<C-B>\"\<CR>", 'tx') 165 call assert_equal('"syn spell default notoplevel toplevel', @:) 166 167 call feedkeys(":syn sync \<C-A>\<C-B>\"\<CR>", 'tx') 168 call assert_equal('"syn sync ccomment clear fromstart linebreaks= linecont lines= match maxlines= minlines= region', @:) 169 170 " Check that clearing "Aap" avoids it showing up before Boolean. 171 hi Aap ctermfg=blue 172 call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx') 173 call assert_match('^"syn list Aap Boolean Character ', @:) 174 hi clear Aap 175 176 call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx') 177 call assert_match('^"syn list Boolean Character ', @:) 178 179 call feedkeys(":syn match \<C-A>\<C-B>\"\<CR>", 'tx') 180 call assert_match('^"syn match Boolean Character ', @:) 181endfunc 182 183func Test_echohl_completion() 184 call feedkeys(":echohl no\<C-A>\<C-B>\"\<CR>", 'tx') 185 call assert_equal('"echohl NonText Normal none', @:) 186endfunc 187 188func Test_syntax_arg_skipped() 189 syn clear 190 syntax case ignore 191 if 0 192 syntax case match 193 endif 194 call assert_match('case ignore', execute('syntax case')) 195 196 syn keyword Foo foo 197 call assert_match('Foo', execute('syntax')) 198 syn clear 199 call assert_match('case match', execute('syntax case')) 200 call assert_notmatch('Foo', execute('syntax')) 201 202 if has('conceal') 203 syn clear 204 syntax conceal on 205 if 0 206 syntax conceal off 207 endif 208 call assert_match('conceal on', execute('syntax conceal')) 209 syn clear 210 call assert_match('conceal off', execute('syntax conceal')) 211 212 syntax conceal on 213 syntax conceal off 214 call assert_match('conceal off', execute('syntax conceal')) 215 endif 216 217 syntax region Bar start=/</ end=/>/ 218 if 0 219 syntax region NotTest start=/</ end=/>/ contains=@Spell 220 endif 221 call assert_match('Bar', execute('syntax')) 222 call assert_notmatch('NotTest', execute('syntax')) 223 call assert_notmatch('Spell', execute('syntax')) 224 225 hi Foo ctermfg=blue 226 let a = execute('hi Foo') 227 if 0 228 syntax rest 229 endif 230 call assert_equal(a, execute('hi Foo')) 231 hi clear Bar 232 hi clear Foo 233 234 set ft=tags 235 syn off 236 if 0 237 syntax enable 238 endif 239 call assert_match('No Syntax items defined', execute('syntax')) 240 syntax enable 241 call assert_match('tagComment', execute('syntax')) 242 set ft= 243 244 syn clear 245 if 0 246 syntax include @Spell nothing 247 endif 248 call assert_notmatch('Spell', execute('syntax')) 249 250 syn clear 251 syn iskeyword 48-57,$,_ 252 call assert_match('48-57,$,_', execute('syntax iskeyword')) 253 if 0 254 syn clear 255 syn iskeyword clear 256 endif 257 call assert_match('48-57,$,_', execute('syntax iskeyword')) 258 syn iskeyword clear 259 call assert_match('not set', execute('syntax iskeyword')) 260 syn iskeyword 48-57,$,_ 261 syn clear 262 call assert_match('not set', execute('syntax iskeyword')) 263 264 syn clear 265 syn keyword Foo foo 266 if 0 267 syn keyword NotAdded bar 268 endif 269 call assert_match('Foo', execute('syntax')) 270 call assert_notmatch('NotAdded', execute('highlight')) 271 272 syn clear 273 syn keyword Foo foo 274 call assert_match('Foo', execute('syntax')) 275 call assert_match('Foo', execute('syntax list')) 276 call assert_notmatch('Foo', execute('if 0 | syntax | endif')) 277 call assert_notmatch('Foo', execute('if 0 | syntax list | endif')) 278 279 syn clear 280 syn match Fopi /asdf/ 281 if 0 282 syn match Fopx /asdf/ 283 endif 284 call assert_match('Fopi', execute('syntax')) 285 call assert_notmatch('Fopx', execute('syntax')) 286 287 syn clear 288 syn spell toplevel 289 call assert_match('spell toplevel', execute('syntax spell')) 290 if 0 291 syn spell notoplevel 292 endif 293 call assert_match('spell toplevel', execute('syntax spell')) 294 syn spell notoplevel 295 call assert_match('spell notoplevel', execute('syntax spell')) 296 syn spell default 297 call assert_match('spell default', execute('syntax spell')) 298 299 syn clear 300 if 0 301 syntax cluster Spell 302 endif 303 call assert_notmatch('Spell', execute('syntax')) 304 305 syn clear 306 syn keyword Foo foo 307 syn sync ccomment 308 syn sync maxlines=5 309 if 0 310 syn sync maxlines=11 311 endif 312 call assert_match('on C-style comments', execute('syntax sync')) 313 call assert_match('maximal 5 lines', execute('syntax sync')) 314 syn sync clear 315 if 0 316 syn sync ccomment 317 endif 318 call assert_notmatch('on C-style comments', execute('syntax sync')) 319 320 syn clear 321endfunc 322 323func Test_syntax_invalid_arg() 324 call assert_fails('syntax case asdf', 'E390:') 325 if has('conceal') 326 call assert_fails('syntax conceal asdf', 'E390:') 327 endif 328 call assert_fails('syntax spell asdf', 'E390:') 329 call assert_fails('syntax clear @ABCD', 'E391:') 330 call assert_fails('syntax include @Xxx', 'E397:') 331 call assert_fails('syntax region X start="{"', 'E399:') 332 call assert_fails('syntax sync x', 'E404:') 333 call assert_fails('syntax keyword Abc a[', 'E789:') 334 call assert_fails('syntax keyword Abc a[bc]d', 'E890:') 335 336 let caught_393 = 0 337 try 338 syntax keyword cMyItem grouphere G1 339 catch /E393:/ 340 let caught_393 = 1 341 endtry 342 call assert_equal(1, caught_393) 343 344 let caught_394 = 0 345 try 346 syntax sync match Abc grouphere MyItem "abc"' 347 catch /E394:/ 348 let caught_394 = 1 349 endtry 350 call assert_equal(1, caught_394) 351 352 " Test for too many \z\( and unmatched \z\( 353 " Not able to use assert_fails() here because both E50:/E879: and E475: 354 " messages are emitted. 355 set regexpengine=1 356 let caught_52 = 0 357 try 358 syntax region MyRegion start='\z\(' end='\*/' 359 catch /E52:/ 360 let caught_52 = 1 361 endtry 362 call assert_equal(1, caught_52) 363 364 let caught_50 = 0 365 try 366 let cmd = "syntax region MyRegion start='" 367 let cmd ..= repeat("\\z\\(.\\)", 10) .. "' end='\*/'" 368 exe cmd 369 catch /E50:/ 370 let caught_50 = 1 371 endtry 372 call assert_equal(1, caught_50) 373 374 set regexpengine=2 375 let caught_54 = 0 376 try 377 syntax region MyRegion start='\z\(' end='\*/' 378 catch /E54:/ 379 let caught_54 = 1 380 endtry 381 call assert_equal(1, caught_54) 382 383 let caught_879 = 0 384 try 385 let cmd = "syntax region MyRegion start='" 386 let cmd ..= repeat("\\z\\(.\\)", 10) .. "' end='\*/'" 387 exe cmd 388 catch /E879:/ 389 let caught_879 = 1 390 endtry 391 call assert_equal(1, caught_879) 392 set regexpengine& 393endfunc 394 395func Test_syn_sync() 396 syntax region HereGroup start=/this/ end=/that/ 397 syntax sync match SyncHere grouphere HereGroup "pattern" 398 call assert_match('SyncHere', execute('syntax sync')) 399 syn sync clear 400 call assert_notmatch('SyncHere', execute('syntax sync')) 401 syn clear 402endfunc 403 404func Test_syn_clear() 405 syntax keyword Foo foo 406 syntax keyword Bar tar 407 call assert_match('Foo', execute('syntax')) 408 call assert_match('Bar', execute('syntax')) 409 call assert_equal('Foo', synIDattr(hlID("Foo"), "name")) 410 syn clear Foo 411 call assert_notmatch('Foo', execute('syntax')) 412 call assert_match('Bar', execute('syntax')) 413 call assert_equal('Foo', synIDattr(hlID("Foo"), "name")) 414 syn clear Foo Bar 415 call assert_notmatch('Foo', execute('syntax')) 416 call assert_notmatch('Bar', execute('syntax')) 417 hi clear Foo 418 call assert_equal('Foo', synIDattr(hlID("Foo"), "name")) 419 hi clear Bar 420endfunc 421 422func Test_invalid_name() 423 syn clear 424 syn keyword Nop yes 425 call assert_fails("syntax keyword Wr\x17ong bar", 'E669:') 426 syntax keyword @Wrong bar 427 call assert_match('W18:', execute('1messages')) 428 syn clear 429 hi clear Nop 430 hi clear @Wrong 431endfunc 432 433func Test_ownsyntax() 434 new Xfoo 435 call setline(1, '#define FOO') 436 syntax on 437 set filetype=c 438 ownsyntax perl 439 call assert_equal('perlComment', synIDattr(synID(line('.'), col('.'), 1), 'name')) 440 call assert_equal('c', b:current_syntax) 441 call assert_equal('perl', w:current_syntax) 442 443 " A new split window should have the original syntax. 444 split 445 call assert_equal('cDefine', synIDattr(synID(line('.'), col('.'), 1), 'name')) 446 call assert_equal('c', b:current_syntax) 447 call assert_equal(0, exists('w:current_syntax')) 448 449 wincmd x 450 call assert_equal('perlComment', synIDattr(synID(line("."), col("."), 1), "name")) 451 452 syntax off 453 set filetype& 454 %bw! 455endfunc 456 457func Test_ownsyntax_completion() 458 call feedkeys(":ownsyntax java\<C-A>\<C-B>\"\<CR>", 'tx') 459 call assert_equal('"ownsyntax java javacc javascript javascriptreact', @:) 460endfunc 461 462func Test_highlight_invalid_arg() 463 if has('gui_running') 464 call assert_fails('hi XXX guifg=xxx', 'E254:') 465 endif 466 call assert_fails('hi DoesNotExist', 'E411:') 467 call assert_fails('hi link', 'E412:') 468 call assert_fails('hi link a', 'E412:') 469 call assert_fails('hi link a b c', 'E413:') 470 call assert_fails('hi XXX =', 'E415:') 471 call assert_fails('hi XXX cterm', 'E416:') 472 call assert_fails('hi XXX cterm=', 'E417:') 473 call assert_fails('hi XXX cterm=DoesNotExist', 'E418:') 474 call assert_fails('hi XXX ctermfg=DoesNotExist', 'E421:') 475 call assert_fails('hi XXX xxx=White', 'E423:') 476endfunc 477 478func Test_bg_detection() 479 CheckNotGui 480 481 " auto-detection of &bg, make sure sure it isn't set anywhere before 482 " this test 483 hi Normal ctermbg=0 484 call assert_equal('dark', &bg) 485 hi Normal ctermbg=4 486 call assert_equal('dark', &bg) 487 hi Normal ctermbg=12 488 call assert_equal('light', &bg) 489 hi Normal ctermbg=15 490 call assert_equal('light', &bg) 491 492 " manually-set &bg takes precedence over auto-detection 493 set bg=light 494 hi Normal ctermbg=4 495 call assert_equal('light', &bg) 496 set bg=dark 497 hi Normal ctermbg=12 498 call assert_equal('dark', &bg) 499 500 hi Normal ctermbg=NONE 501endfunc 502 503func Test_syntax_hangs() 504 if !has('reltime') || !has('float') || !has('syntax') 505 return 506 endif 507 508 " This pattern takes a long time to match, it should timeout. 509 new 510 call setline(1, ['aaa', repeat('abc ', 1000), 'ccc']) 511 let start = reltime() 512 set nolazyredraw redrawtime=101 513 syn match Error /\%#=1a*.*X\@<=b*/ 514 redraw 515 let elapsed = reltimefloat(reltime(start)) 516 call assert_true(elapsed > 0.1) 517 call assert_true(elapsed < 1.0) 518 519 " second time syntax HL is disabled 520 let start = reltime() 521 redraw 522 let elapsed = reltimefloat(reltime(start)) 523 call assert_true(elapsed < 0.1) 524 525 " after CTRL-L the timeout flag is reset 526 let start = reltime() 527 exe "normal \<C-L>" 528 redraw 529 let elapsed = reltimefloat(reltime(start)) 530 call assert_true(elapsed > 0.1) 531 call assert_true(elapsed < 1.0) 532 533 set redrawtime& 534 bwipe! 535endfunc 536 537func Test_conceal() 538 if !has('conceal') 539 return 540 endif 541 542 new 543 call setline(1, ['', '123456']) 544 syn match test23 "23" conceal cchar=X 545 syn match test45 "45" conceal 546 547 set conceallevel=0 548 call assert_equal('123456 ', ScreenLines(2, 7)[0]) 549 call assert_equal([[0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)')) 550 551 set conceallevel=1 552 call assert_equal('1X 6 ', ScreenLines(2, 7)[0]) 553 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)')) 554 555 set conceallevel=1 556 set listchars=conceal:Y 557 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)')) 558 call assert_equal('1XY6 ', ScreenLines(2, 7)[0]) 559 560 set conceallevel=2 561 call assert_match('1X6 ', ScreenLines(2, 7)[0]) 562 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)')) 563 564 set conceallevel=3 565 call assert_match('16 ', ScreenLines(2, 7)[0]) 566 call assert_equal([[0, '', 0], [1, '', 1], [1, '', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)')) 567 568 syn clear 569 set conceallevel& 570 bw! 571endfunc 572 573func Test_synstack_synIDtrans() 574 new 575 setfiletype c 576 syntax on 577 call setline(1, ' /* A comment with a TODO */') 578 579 call assert_equal([], synstack(1, 1)) 580 581 norm f/ 582 eval synstack(line("."), col("."))->map('synIDattr(v:val, "name")')->assert_equal(['cComment', 'cCommentStart']) 583 eval synstack(line("."), col("."))->map('synIDattr(synIDtrans(v:val), "name")')->assert_equal(['Comment', 'Comment']) 584 585 norm fA 586 call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")')) 587 call assert_equal(['Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")')) 588 589 norm fT 590 call assert_equal(['cComment', 'cTodo'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")')) 591 call assert_equal(['Comment', 'Todo'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")')) 592 593 call assert_fails("let n=synIDtrans([])", 'E745:') 594 595 syn clear 596 bw! 597endfunc 598 599" Check highlighting for a small piece of C code with a screen dump. 600func Test_syntax_c() 601 if !CanRunVimInTerminal() 602 throw 'Skipped: cannot make screendumps' 603 endif 604 call writefile([ 605 \ '/* comment line at the top */', 606 \ 'int main(int argc, char **argv) { // another comment', 607 \ '#if 0', 608 \ ' int not_used;', 609 \ '#else', 610 \ ' int used;', 611 \ '#endif', 612 \ ' printf("Just an example piece of C code\n");', 613 \ ' return 0x0ff;', 614 \ '}', 615 \ "\t\t ", 616 \ ' static void', 617 \ 'myFunction(const double count, struct nothing, long there) {', 618 \ "\t// 123: nothing to endif here", 619 \ "\tfor (int i = 0; i < count; ++i) {", 620 \ "\t break;", 621 \ "\t}", 622 \ "\tNote: asdf", 623 \ '}', 624 \ ], 'Xtest.c') 625 626 " This makes the default for 'background' use "dark", check that the 627 " response to t_RB corrects it to "light". 628 let $COLORFGBG = '15;0' 629 630 let buf = RunVimInTerminal('Xtest.c', {}) 631 call term_sendkeys(buf, ":syn keyword Search Note\r") 632 call term_sendkeys(buf, ":syn match Error /^\\s\\+$/\r") 633 call term_sendkeys(buf, ":set hlsearch\r") 634 call term_sendkeys(buf, "/endif\r") 635 call term_sendkeys(buf, "vjfC") 636 call VerifyScreenDump(buf, 'Test_syntax_c_01', {}) 637 638 call term_sendkeys(buf, "\<Esc>") 639 call StopVimInTerminal(buf) 640 641 let $COLORFGBG = '' 642 call delete('Xtest.c') 643endfun 644 645" Using \z() in a region with NFA failing should not crash. 646func Test_syn_wrong_z_one() 647 new 648 call setline(1, ['just some text', 'with foo and bar to match with']) 649 syn region FooBar start="foo\z(.*\)bar" end="\z1" 650 call test_override("nfa_fail", 1) 651 redraw! 652 redraw! 653 call test_override("ALL", 0) 654 bwipe! 655endfunc 656 657func Test_syntax_after_bufdo() 658 call writefile(['/* aaa comment */'], 'Xaaa.c') 659 call writefile(['/* bbb comment */'], 'Xbbb.c') 660 call writefile(['/* ccc comment */'], 'Xccc.c') 661 call writefile(['/* ddd comment */'], 'Xddd.c') 662 663 let bnr = bufnr('%') 664 new Xaaa.c 665 badd Xbbb.c 666 badd Xccc.c 667 badd Xddd.c 668 exe "bwipe " . bnr 669 let l = [] 670 bufdo call add(l, bufnr('%')) 671 call assert_equal(4, len(l)) 672 673 syntax on 674 675 " This used to only enable syntax HL in the last buffer. 676 bufdo tab split 677 tabrewind 678 for tab in range(1, 4) 679 norm fm 680 call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")')) 681 tabnext 682 endfor 683 684 bwipe! Xaaa.c 685 bwipe! Xbbb.c 686 bwipe! Xccc.c 687 bwipe! Xddd.c 688 syntax off 689 call delete('Xaaa.c') 690 call delete('Xbbb.c') 691 call delete('Xccc.c') 692 call delete('Xddd.c') 693endfunc 694 695" vim: shiftwidth=2 sts=2 expandtab 696